Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ps3/block: Replace mtd/ps3vram by block/ps3vram

Convert the PS3 Video RAM Storage Driver from an MTD driver to a plain block
device driver.

The ps3vram driver exposes unused video RAM on the PS3 as a block device
suitable for storage or swap. Fast data transfer is achieved using a local
cache in system RAM and DMA transfers via the GPU.

The new driver is ca. 50% faster for reading, and ca. 10% for writing.

Signed-off-by: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>
Acked-by: Geoff Levand <geoffrey.levand@am.sony.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

authored by

Geert Uytterhoeven and committed by
Benjamin Herrenschmidt
f507cd22 9ead6497

+873 -776
+7
arch/powerpc/platforms/ps3/Kconfig
··· 128 128 be disabled on the kernel command line using "ps3flash=off", to 129 129 not allocate this fixed buffer. 130 130 131 + config PS3_VRAM 132 + tristate "PS3 Video RAM Storage Driver" 133 + depends on FB_PS3=y && BLOCK && m 134 + help 135 + This driver allows you to use excess PS3 video RAM as volatile 136 + storage or system swap. 137 + 131 138 config PS3_LPM 132 139 tristate "PS3 Logical Performance Monitor support" 133 140 depends on PPC_PS3
+1
drivers/block/Makefile
··· 9 9 obj-$(CONFIG_BLK_DEV_FD) += floppy.o 10 10 obj-$(CONFIG_AMIGA_FLOPPY) += amiflop.o 11 11 obj-$(CONFIG_PS3_DISK) += ps3disk.o 12 + obj-$(CONFIG_PS3_VRAM) += ps3vram.o 12 13 obj-$(CONFIG_ATARI_FLOPPY) += ataflop.o 13 14 obj-$(CONFIG_AMIGA_Z2RAM) += z2ram.o 14 15 obj-$(CONFIG_BLK_DEV_RAM) += brd.o
+865
drivers/block/ps3vram.c
··· 1 + /* 2 + * ps3vram - Use extra PS3 video ram as MTD block device. 3 + * 4 + * Copyright 2009 Sony Corporation 5 + * 6 + * Based on the MTD ps3vram driver, which is 7 + * Copyright (c) 2007-2008 Jim Paris <jim@jtan.com> 8 + * Added support RSX DMA Vivien Chappelier <vivien.chappelier@free.fr> 9 + */ 10 + 11 + #include <linux/blkdev.h> 12 + #include <linux/delay.h> 13 + #include <linux/proc_fs.h> 14 + #include <linux/seq_file.h> 15 + 16 + #include <asm/firmware.h> 17 + #include <asm/lv1call.h> 18 + #include <asm/ps3.h> 19 + 20 + 21 + #define DEVICE_NAME "ps3vram" 22 + 23 + 24 + #define XDR_BUF_SIZE (2 * 1024 * 1024) /* XDR buffer (must be 1MiB aligned) */ 25 + #define XDR_IOIF 0x0c000000 26 + 27 + #define FIFO_BASE XDR_IOIF 28 + #define FIFO_SIZE (64 * 1024) 29 + 30 + #define DMA_PAGE_SIZE (4 * 1024) 31 + 32 + #define CACHE_PAGE_SIZE (256 * 1024) 33 + #define CACHE_PAGE_COUNT ((XDR_BUF_SIZE - FIFO_SIZE) / CACHE_PAGE_SIZE) 34 + 35 + #define CACHE_OFFSET CACHE_PAGE_SIZE 36 + #define FIFO_OFFSET 0 37 + 38 + #define CTRL_PUT 0x10 39 + #define CTRL_GET 0x11 40 + #define CTRL_TOP 0x15 41 + 42 + #define UPLOAD_SUBCH 1 43 + #define DOWNLOAD_SUBCH 2 44 + 45 + #define NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN 0x0000030c 46 + #define NV_MEMORY_TO_MEMORY_FORMAT_NOTIFY 0x00000104 47 + 48 + #define L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT 0x601 49 + 50 + #define CACHE_PAGE_PRESENT 1 51 + #define CACHE_PAGE_DIRTY 2 52 + 53 + struct ps3vram_tag { 54 + unsigned int address; 55 + unsigned int flags; 56 + }; 57 + 58 + struct ps3vram_cache { 59 + unsigned int page_count; 60 + unsigned int page_size; 61 + struct ps3vram_tag *tags; 62 + unsigned int hit; 63 + unsigned int miss; 64 + }; 65 + 66 + struct ps3vram_priv { 67 + struct request_queue *queue; 68 + struct gendisk *gendisk; 69 + 70 + u64 size; 71 + 72 + u64 memory_handle; 73 + u64 context_handle; 74 + u32 *ctrl; 75 + u32 *reports; 76 + u8 __iomem *ddr_base; 77 + u8 *xdr_buf; 78 + 79 + u32 *fifo_base; 80 + u32 *fifo_ptr; 81 + 82 + struct ps3vram_cache cache; 83 + 84 + /* Used to serialize cache/DMA operations */ 85 + struct mutex lock; 86 + }; 87 + 88 + 89 + static int ps3vram_major; 90 + 91 + 92 + static struct block_device_operations ps3vram_fops = { 93 + .owner = THIS_MODULE, 94 + }; 95 + 96 + 97 + #define DMA_NOTIFIER_HANDLE_BASE 0x66604200 /* first DMA notifier handle */ 98 + #define DMA_NOTIFIER_OFFSET_BASE 0x1000 /* first DMA notifier offset */ 99 + #define DMA_NOTIFIER_SIZE 0x40 100 + #define NOTIFIER 7 /* notifier used for completion report */ 101 + 102 + static char *size = "256M"; 103 + module_param(size, charp, 0); 104 + MODULE_PARM_DESC(size, "memory size"); 105 + 106 + static u32 *ps3vram_get_notifier(u32 *reports, int notifier) 107 + { 108 + return (void *)reports + DMA_NOTIFIER_OFFSET_BASE + 109 + DMA_NOTIFIER_SIZE * notifier; 110 + } 111 + 112 + static void ps3vram_notifier_reset(struct ps3_system_bus_device *dev) 113 + { 114 + struct ps3vram_priv *priv = dev->core.driver_data; 115 + u32 *notify = ps3vram_get_notifier(priv->reports, NOTIFIER); 116 + int i; 117 + 118 + for (i = 0; i < 4; i++) 119 + notify[i] = 0xffffffff; 120 + } 121 + 122 + static int ps3vram_notifier_wait(struct ps3_system_bus_device *dev, 123 + unsigned int timeout_ms) 124 + { 125 + struct ps3vram_priv *priv = dev->core.driver_data; 126 + u32 *notify = ps3vram_get_notifier(priv->reports, NOTIFIER); 127 + unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms); 128 + 129 + do { 130 + if (!notify[3]) 131 + return 0; 132 + msleep(1); 133 + } while (time_before(jiffies, timeout)); 134 + 135 + return -ETIMEDOUT; 136 + } 137 + 138 + static void ps3vram_init_ring(struct ps3_system_bus_device *dev) 139 + { 140 + struct ps3vram_priv *priv = dev->core.driver_data; 141 + 142 + priv->ctrl[CTRL_PUT] = FIFO_BASE + FIFO_OFFSET; 143 + priv->ctrl[CTRL_GET] = FIFO_BASE + FIFO_OFFSET; 144 + } 145 + 146 + static int ps3vram_wait_ring(struct ps3_system_bus_device *dev, 147 + unsigned int timeout_ms) 148 + { 149 + struct ps3vram_priv *priv = dev->core.driver_data; 150 + unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms); 151 + 152 + do { 153 + if (priv->ctrl[CTRL_PUT] == priv->ctrl[CTRL_GET]) 154 + return 0; 155 + msleep(1); 156 + } while (time_before(jiffies, timeout)); 157 + 158 + dev_warn(&dev->core, "FIFO timeout (%08x/%08x/%08x)\n", 159 + priv->ctrl[CTRL_PUT], priv->ctrl[CTRL_GET], 160 + priv->ctrl[CTRL_TOP]); 161 + 162 + return -ETIMEDOUT; 163 + } 164 + 165 + static void ps3vram_out_ring(struct ps3vram_priv *priv, u32 data) 166 + { 167 + *(priv->fifo_ptr)++ = data; 168 + } 169 + 170 + static void ps3vram_begin_ring(struct ps3vram_priv *priv, u32 chan, u32 tag, 171 + u32 size) 172 + { 173 + ps3vram_out_ring(priv, (size << 18) | (chan << 13) | tag); 174 + } 175 + 176 + static void ps3vram_rewind_ring(struct ps3_system_bus_device *dev) 177 + { 178 + struct ps3vram_priv *priv = dev->core.driver_data; 179 + int status; 180 + 181 + ps3vram_out_ring(priv, 0x20000000 | (FIFO_BASE + FIFO_OFFSET)); 182 + 183 + priv->ctrl[CTRL_PUT] = FIFO_BASE + FIFO_OFFSET; 184 + 185 + /* asking the HV for a blit will kick the FIFO */ 186 + status = lv1_gpu_context_attribute(priv->context_handle, 187 + L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT, 0, 188 + 0, 0, 0); 189 + if (status) 190 + dev_err(&dev->core, 191 + "%s: lv1_gpu_context_attribute failed %d\n", __func__, 192 + status); 193 + 194 + priv->fifo_ptr = priv->fifo_base; 195 + } 196 + 197 + static void ps3vram_fire_ring(struct ps3_system_bus_device *dev) 198 + { 199 + struct ps3vram_priv *priv = dev->core.driver_data; 200 + int status; 201 + 202 + mutex_lock(&ps3_gpu_mutex); 203 + 204 + priv->ctrl[CTRL_PUT] = FIFO_BASE + FIFO_OFFSET + 205 + (priv->fifo_ptr - priv->fifo_base) * sizeof(u32); 206 + 207 + /* asking the HV for a blit will kick the FIFO */ 208 + status = lv1_gpu_context_attribute(priv->context_handle, 209 + L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT, 0, 210 + 0, 0, 0); 211 + if (status) 212 + dev_err(&dev->core, 213 + "%s: lv1_gpu_context_attribute failed %d\n", __func__, 214 + status); 215 + 216 + if ((priv->fifo_ptr - priv->fifo_base) * sizeof(u32) > 217 + FIFO_SIZE - 1024) { 218 + dev_dbg(&dev->core, "FIFO full, rewinding\n"); 219 + ps3vram_wait_ring(dev, 200); 220 + ps3vram_rewind_ring(dev); 221 + } 222 + 223 + mutex_unlock(&ps3_gpu_mutex); 224 + } 225 + 226 + static void ps3vram_bind(struct ps3_system_bus_device *dev) 227 + { 228 + struct ps3vram_priv *priv = dev->core.driver_data; 229 + 230 + ps3vram_begin_ring(priv, UPLOAD_SUBCH, 0, 1); 231 + ps3vram_out_ring(priv, 0x31337303); 232 + ps3vram_begin_ring(priv, UPLOAD_SUBCH, 0x180, 3); 233 + ps3vram_out_ring(priv, DMA_NOTIFIER_HANDLE_BASE + NOTIFIER); 234 + ps3vram_out_ring(priv, 0xfeed0001); /* DMA system RAM instance */ 235 + ps3vram_out_ring(priv, 0xfeed0000); /* DMA video RAM instance */ 236 + 237 + ps3vram_begin_ring(priv, DOWNLOAD_SUBCH, 0, 1); 238 + ps3vram_out_ring(priv, 0x3137c0de); 239 + ps3vram_begin_ring(priv, DOWNLOAD_SUBCH, 0x180, 3); 240 + ps3vram_out_ring(priv, DMA_NOTIFIER_HANDLE_BASE + NOTIFIER); 241 + ps3vram_out_ring(priv, 0xfeed0000); /* DMA video RAM instance */ 242 + ps3vram_out_ring(priv, 0xfeed0001); /* DMA system RAM instance */ 243 + 244 + ps3vram_fire_ring(dev); 245 + } 246 + 247 + static int ps3vram_upload(struct ps3_system_bus_device *dev, 248 + unsigned int src_offset, unsigned int dst_offset, 249 + int len, int count) 250 + { 251 + struct ps3vram_priv *priv = dev->core.driver_data; 252 + 253 + ps3vram_begin_ring(priv, UPLOAD_SUBCH, 254 + NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8); 255 + ps3vram_out_ring(priv, XDR_IOIF + src_offset); 256 + ps3vram_out_ring(priv, dst_offset); 257 + ps3vram_out_ring(priv, len); 258 + ps3vram_out_ring(priv, len); 259 + ps3vram_out_ring(priv, len); 260 + ps3vram_out_ring(priv, count); 261 + ps3vram_out_ring(priv, (1 << 8) | 1); 262 + ps3vram_out_ring(priv, 0); 263 + 264 + ps3vram_notifier_reset(dev); 265 + ps3vram_begin_ring(priv, UPLOAD_SUBCH, 266 + NV_MEMORY_TO_MEMORY_FORMAT_NOTIFY, 1); 267 + ps3vram_out_ring(priv, 0); 268 + ps3vram_begin_ring(priv, UPLOAD_SUBCH, 0x100, 1); 269 + ps3vram_out_ring(priv, 0); 270 + ps3vram_fire_ring(dev); 271 + if (ps3vram_notifier_wait(dev, 200) < 0) { 272 + dev_warn(&dev->core, "%s: Notifier timeout\n", __func__); 273 + return -1; 274 + } 275 + 276 + return 0; 277 + } 278 + 279 + static int ps3vram_download(struct ps3_system_bus_device *dev, 280 + unsigned int src_offset, unsigned int dst_offset, 281 + int len, int count) 282 + { 283 + struct ps3vram_priv *priv = dev->core.driver_data; 284 + 285 + ps3vram_begin_ring(priv, DOWNLOAD_SUBCH, 286 + NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8); 287 + ps3vram_out_ring(priv, src_offset); 288 + ps3vram_out_ring(priv, XDR_IOIF + dst_offset); 289 + ps3vram_out_ring(priv, len); 290 + ps3vram_out_ring(priv, len); 291 + ps3vram_out_ring(priv, len); 292 + ps3vram_out_ring(priv, count); 293 + ps3vram_out_ring(priv, (1 << 8) | 1); 294 + ps3vram_out_ring(priv, 0); 295 + 296 + ps3vram_notifier_reset(dev); 297 + ps3vram_begin_ring(priv, DOWNLOAD_SUBCH, 298 + NV_MEMORY_TO_MEMORY_FORMAT_NOTIFY, 1); 299 + ps3vram_out_ring(priv, 0); 300 + ps3vram_begin_ring(priv, DOWNLOAD_SUBCH, 0x100, 1); 301 + ps3vram_out_ring(priv, 0); 302 + ps3vram_fire_ring(dev); 303 + if (ps3vram_notifier_wait(dev, 200) < 0) { 304 + dev_warn(&dev->core, "%s: Notifier timeout\n", __func__); 305 + return -1; 306 + } 307 + 308 + return 0; 309 + } 310 + 311 + static void ps3vram_cache_evict(struct ps3_system_bus_device *dev, int entry) 312 + { 313 + struct ps3vram_priv *priv = dev->core.driver_data; 314 + struct ps3vram_cache *cache = &priv->cache; 315 + 316 + if (!(cache->tags[entry].flags & CACHE_PAGE_DIRTY)) 317 + return; 318 + 319 + dev_dbg(&dev->core, "Flushing %d: 0x%08x\n", entry, 320 + cache->tags[entry].address); 321 + if (ps3vram_upload(dev, CACHE_OFFSET + entry * cache->page_size, 322 + cache->tags[entry].address, DMA_PAGE_SIZE, 323 + cache->page_size / DMA_PAGE_SIZE) < 0) { 324 + dev_err(&dev->core, 325 + "Failed to upload from 0x%x to " "0x%x size 0x%x\n", 326 + entry * cache->page_size, cache->tags[entry].address, 327 + cache->page_size); 328 + } 329 + cache->tags[entry].flags &= ~CACHE_PAGE_DIRTY; 330 + } 331 + 332 + static void ps3vram_cache_load(struct ps3_system_bus_device *dev, int entry, 333 + unsigned int address) 334 + { 335 + struct ps3vram_priv *priv = dev->core.driver_data; 336 + struct ps3vram_cache *cache = &priv->cache; 337 + 338 + dev_dbg(&dev->core, "Fetching %d: 0x%08x\n", entry, address); 339 + if (ps3vram_download(dev, address, 340 + CACHE_OFFSET + entry * cache->page_size, 341 + DMA_PAGE_SIZE, 342 + cache->page_size / DMA_PAGE_SIZE) < 0) { 343 + dev_err(&dev->core, 344 + "Failed to download from 0x%x to 0x%x size 0x%x\n", 345 + address, entry * cache->page_size, cache->page_size); 346 + } 347 + 348 + cache->tags[entry].address = address; 349 + cache->tags[entry].flags |= CACHE_PAGE_PRESENT; 350 + } 351 + 352 + 353 + static void ps3vram_cache_flush(struct ps3_system_bus_device *dev) 354 + { 355 + struct ps3vram_priv *priv = dev->core.driver_data; 356 + struct ps3vram_cache *cache = &priv->cache; 357 + int i; 358 + 359 + dev_dbg(&dev->core, "FLUSH\n"); 360 + for (i = 0; i < cache->page_count; i++) { 361 + ps3vram_cache_evict(dev, i); 362 + cache->tags[i].flags = 0; 363 + } 364 + } 365 + 366 + static unsigned int ps3vram_cache_match(struct ps3_system_bus_device *dev, 367 + loff_t address) 368 + { 369 + struct ps3vram_priv *priv = dev->core.driver_data; 370 + struct ps3vram_cache *cache = &priv->cache; 371 + unsigned int base; 372 + unsigned int offset; 373 + int i; 374 + static int counter; 375 + 376 + offset = (unsigned int) (address & (cache->page_size - 1)); 377 + base = (unsigned int) (address - offset); 378 + 379 + /* fully associative check */ 380 + for (i = 0; i < cache->page_count; i++) { 381 + if ((cache->tags[i].flags & CACHE_PAGE_PRESENT) && 382 + cache->tags[i].address == base) { 383 + cache->hit++; 384 + dev_dbg(&dev->core, "Found entry %d: 0x%08x\n", i, 385 + cache->tags[i].address); 386 + return i; 387 + } 388 + } 389 + 390 + /* choose a random entry */ 391 + i = (jiffies + (counter++)) % cache->page_count; 392 + dev_dbg(&dev->core, "Using entry %d\n", i); 393 + 394 + ps3vram_cache_evict(dev, i); 395 + ps3vram_cache_load(dev, i, base); 396 + 397 + cache->miss++; 398 + return i; 399 + } 400 + 401 + static int ps3vram_cache_init(struct ps3_system_bus_device *dev) 402 + { 403 + struct ps3vram_priv *priv = dev->core.driver_data; 404 + 405 + priv->cache.page_count = CACHE_PAGE_COUNT; 406 + priv->cache.page_size = CACHE_PAGE_SIZE; 407 + priv->cache.tags = kzalloc(sizeof(struct ps3vram_tag) * 408 + CACHE_PAGE_COUNT, GFP_KERNEL); 409 + if (priv->cache.tags == NULL) { 410 + dev_err(&dev->core, "Could not allocate cache tags\n"); 411 + return -ENOMEM; 412 + } 413 + 414 + dev_info(&dev->core, "Created ram cache: %d entries, %d KiB each\n", 415 + CACHE_PAGE_COUNT, CACHE_PAGE_SIZE / 1024); 416 + 417 + return 0; 418 + } 419 + 420 + static void ps3vram_cache_cleanup(struct ps3_system_bus_device *dev) 421 + { 422 + struct ps3vram_priv *priv = dev->core.driver_data; 423 + 424 + ps3vram_cache_flush(dev); 425 + kfree(priv->cache.tags); 426 + } 427 + 428 + static int ps3vram_read(struct ps3_system_bus_device *dev, loff_t from, 429 + size_t len, size_t *retlen, u_char *buf) 430 + { 431 + struct ps3vram_priv *priv = dev->core.driver_data; 432 + unsigned int cached, count; 433 + 434 + dev_dbg(&dev->core, "%s: from=0x%08x len=0x%zx\n", __func__, 435 + (unsigned int)from, len); 436 + 437 + if (from >= priv->size) 438 + return -EIO; 439 + 440 + if (len > priv->size - from) 441 + len = priv->size - from; 442 + 443 + /* Copy from vram to buf */ 444 + count = len; 445 + while (count) { 446 + unsigned int offset, avail; 447 + unsigned int entry; 448 + 449 + offset = (unsigned int) (from & (priv->cache.page_size - 1)); 450 + avail = priv->cache.page_size - offset; 451 + 452 + mutex_lock(&priv->lock); 453 + 454 + entry = ps3vram_cache_match(dev, from); 455 + cached = CACHE_OFFSET + entry * priv->cache.page_size + offset; 456 + 457 + dev_dbg(&dev->core, "%s: from=%08x cached=%08x offset=%08x " 458 + "avail=%08x count=%08x\n", __func__, 459 + (unsigned int)from, cached, offset, avail, count); 460 + 461 + if (avail > count) 462 + avail = count; 463 + memcpy(buf, priv->xdr_buf + cached, avail); 464 + 465 + mutex_unlock(&priv->lock); 466 + 467 + buf += avail; 468 + count -= avail; 469 + from += avail; 470 + } 471 + 472 + *retlen = len; 473 + return 0; 474 + } 475 + 476 + static int ps3vram_write(struct ps3_system_bus_device *dev, loff_t to, 477 + size_t len, size_t *retlen, const u_char *buf) 478 + { 479 + struct ps3vram_priv *priv = dev->core.driver_data; 480 + unsigned int cached, count; 481 + 482 + if (to >= priv->size) 483 + return -EIO; 484 + 485 + if (len > priv->size - to) 486 + len = priv->size - to; 487 + 488 + /* Copy from buf to vram */ 489 + count = len; 490 + while (count) { 491 + unsigned int offset, avail; 492 + unsigned int entry; 493 + 494 + offset = (unsigned int) (to & (priv->cache.page_size - 1)); 495 + avail = priv->cache.page_size - offset; 496 + 497 + mutex_lock(&priv->lock); 498 + 499 + entry = ps3vram_cache_match(dev, to); 500 + cached = CACHE_OFFSET + entry * priv->cache.page_size + offset; 501 + 502 + dev_dbg(&dev->core, "%s: to=%08x cached=%08x offset=%08x " 503 + "avail=%08x count=%08x\n", __func__, (unsigned int)to, 504 + cached, offset, avail, count); 505 + 506 + if (avail > count) 507 + avail = count; 508 + memcpy(priv->xdr_buf + cached, buf, avail); 509 + 510 + priv->cache.tags[entry].flags |= CACHE_PAGE_DIRTY; 511 + 512 + mutex_unlock(&priv->lock); 513 + 514 + buf += avail; 515 + count -= avail; 516 + to += avail; 517 + } 518 + 519 + *retlen = len; 520 + return 0; 521 + } 522 + 523 + static int ps3vram_proc_show(struct seq_file *m, void *v) 524 + { 525 + struct ps3vram_priv *priv = m->private; 526 + 527 + seq_printf(m, "hit:%u\nmiss:%u\n", priv->cache.hit, priv->cache.miss); 528 + return 0; 529 + } 530 + 531 + static int ps3vram_proc_open(struct inode *inode, struct file *file) 532 + { 533 + return single_open(file, ps3vram_proc_show, PDE(inode)->data); 534 + } 535 + 536 + static const struct file_operations ps3vram_proc_fops = { 537 + .owner = THIS_MODULE, 538 + .open = ps3vram_proc_open, 539 + .read = seq_read, 540 + .llseek = seq_lseek, 541 + .release = single_release, 542 + }; 543 + 544 + static void __devinit ps3vram_proc_init(struct ps3_system_bus_device *dev) 545 + { 546 + struct ps3vram_priv *priv = dev->core.driver_data; 547 + struct proc_dir_entry *pde; 548 + 549 + pde = proc_create(DEVICE_NAME, 0444, NULL, &ps3vram_proc_fops); 550 + if (!pde) { 551 + dev_warn(&dev->core, "failed to create /proc entry\n"); 552 + return; 553 + } 554 + 555 + pde->owner = THIS_MODULE; 556 + pde->data = priv; 557 + } 558 + 559 + static int ps3vram_make_request(struct request_queue *q, struct bio *bio) 560 + { 561 + struct ps3_system_bus_device *dev = q->queuedata; 562 + int write = bio_data_dir(bio) == WRITE; 563 + const char *op = write ? "write" : "read"; 564 + loff_t offset = bio->bi_sector << 9; 565 + int error = 0; 566 + struct bio_vec *bvec; 567 + unsigned int i; 568 + 569 + dev_dbg(&dev->core, "%s\n", __func__); 570 + 571 + bio_for_each_segment(bvec, bio, i) { 572 + /* PS3 is ppc64, so we don't handle highmem */ 573 + char *ptr = page_address(bvec->bv_page) + bvec->bv_offset; 574 + size_t len = bvec->bv_len, retlen; 575 + 576 + dev_dbg(&dev->core, " %s %zu bytes at offset %llu\n", op, 577 + len, offset); 578 + if (write) 579 + error = ps3vram_write(dev, offset, len, &retlen, ptr); 580 + else 581 + error = ps3vram_read(dev, offset, len, &retlen, ptr); 582 + 583 + if (error) { 584 + dev_err(&dev->core, "%s failed\n", op); 585 + goto out; 586 + } 587 + 588 + if (retlen != len) { 589 + dev_err(&dev->core, "Short %s\n", op); 590 + goto out; 591 + } 592 + 593 + offset += len; 594 + } 595 + 596 + dev_dbg(&dev->core, "%s completed\n", op); 597 + 598 + out: 599 + bio_endio(bio, error); 600 + return 0; 601 + } 602 + 603 + static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev) 604 + { 605 + struct ps3vram_priv *priv; 606 + int error, status; 607 + struct request_queue *queue; 608 + struct gendisk *gendisk; 609 + u64 ddr_lpar, ctrl_lpar, info_lpar, reports_lpar, ddr_size, 610 + reports_size; 611 + char *rest; 612 + 613 + priv = kzalloc(sizeof(*priv), GFP_KERNEL); 614 + if (!priv) { 615 + error = -ENOMEM; 616 + goto fail; 617 + } 618 + 619 + mutex_init(&priv->lock); 620 + dev->core.driver_data = priv; 621 + 622 + priv = dev->core.driver_data; 623 + 624 + /* Allocate XDR buffer (1MiB aligned) */ 625 + priv->xdr_buf = (void *)__get_free_pages(GFP_KERNEL, 626 + get_order(XDR_BUF_SIZE)); 627 + if (priv->xdr_buf == NULL) { 628 + dev_err(&dev->core, "Could not allocate XDR buffer\n"); 629 + error = -ENOMEM; 630 + goto fail_free_priv; 631 + } 632 + 633 + /* Put FIFO at begginning of XDR buffer */ 634 + priv->fifo_base = (u32 *) (priv->xdr_buf + FIFO_OFFSET); 635 + priv->fifo_ptr = priv->fifo_base; 636 + 637 + /* XXX: Need to open GPU, in case ps3fb or snd_ps3 aren't loaded */ 638 + if (ps3_open_hv_device(dev)) { 639 + dev_err(&dev->core, "ps3_open_hv_device failed\n"); 640 + error = -EAGAIN; 641 + goto out_close_gpu; 642 + } 643 + 644 + /* Request memory */ 645 + status = -1; 646 + ddr_size = ALIGN(memparse(size, &rest), 1024*1024); 647 + if (!ddr_size) { 648 + dev_err(&dev->core, "Specified size is too small\n"); 649 + error = -EINVAL; 650 + goto out_close_gpu; 651 + } 652 + 653 + while (ddr_size > 0) { 654 + status = lv1_gpu_memory_allocate(ddr_size, 0, 0, 0, 0, 655 + &priv->memory_handle, 656 + &ddr_lpar); 657 + if (!status) 658 + break; 659 + ddr_size -= 1024*1024; 660 + } 661 + if (status) { 662 + dev_err(&dev->core, "lv1_gpu_memory_allocate failed %d\n", 663 + status); 664 + error = -ENOMEM; 665 + goto out_free_xdr_buf; 666 + } 667 + 668 + /* Request context */ 669 + status = lv1_gpu_context_allocate(priv->memory_handle, 0, 670 + &priv->context_handle, &ctrl_lpar, 671 + &info_lpar, &reports_lpar, 672 + &reports_size); 673 + if (status) { 674 + dev_err(&dev->core, "lv1_gpu_context_allocate failed %d\n", 675 + status); 676 + error = -ENOMEM; 677 + goto out_free_memory; 678 + } 679 + 680 + /* Map XDR buffer to RSX */ 681 + status = lv1_gpu_context_iomap(priv->context_handle, XDR_IOIF, 682 + ps3_mm_phys_to_lpar(__pa(priv->xdr_buf)), 683 + XDR_BUF_SIZE, 0); 684 + if (status) { 685 + dev_err(&dev->core, "lv1_gpu_context_iomap failed %d\n", 686 + status); 687 + error = -ENOMEM; 688 + goto out_free_context; 689 + } 690 + 691 + priv->ddr_base = ioremap_flags(ddr_lpar, ddr_size, _PAGE_NO_CACHE); 692 + 693 + if (!priv->ddr_base) { 694 + dev_err(&dev->core, "ioremap DDR failed\n"); 695 + error = -ENOMEM; 696 + goto out_free_context; 697 + } 698 + 699 + priv->ctrl = ioremap(ctrl_lpar, 64 * 1024); 700 + if (!priv->ctrl) { 701 + dev_err(&dev->core, "ioremap CTRL failed\n"); 702 + error = -ENOMEM; 703 + goto out_unmap_vram; 704 + } 705 + 706 + priv->reports = ioremap(reports_lpar, reports_size); 707 + if (!priv->reports) { 708 + dev_err(&dev->core, "ioremap REPORTS failed\n"); 709 + error = -ENOMEM; 710 + goto out_unmap_ctrl; 711 + } 712 + 713 + mutex_lock(&ps3_gpu_mutex); 714 + ps3vram_init_ring(dev); 715 + mutex_unlock(&ps3_gpu_mutex); 716 + 717 + priv->size = ddr_size; 718 + 719 + ps3vram_bind(dev); 720 + 721 + mutex_lock(&ps3_gpu_mutex); 722 + error = ps3vram_wait_ring(dev, 100); 723 + mutex_unlock(&ps3_gpu_mutex); 724 + if (error < 0) { 725 + dev_err(&dev->core, "Failed to initialize channels\n"); 726 + error = -ETIMEDOUT; 727 + goto out_unmap_reports; 728 + } 729 + 730 + ps3vram_cache_init(dev); 731 + ps3vram_proc_init(dev); 732 + 733 + queue = blk_alloc_queue(GFP_KERNEL); 734 + if (!queue) { 735 + dev_err(&dev->core, "blk_alloc_queue failed\n"); 736 + error = -ENOMEM; 737 + goto out_cache_cleanup; 738 + } 739 + 740 + priv->queue = queue; 741 + queue->queuedata = dev; 742 + blk_queue_make_request(queue, ps3vram_make_request); 743 + blk_queue_max_phys_segments(queue, MAX_PHYS_SEGMENTS); 744 + blk_queue_max_hw_segments(queue, MAX_HW_SEGMENTS); 745 + blk_queue_max_segment_size(queue, MAX_SEGMENT_SIZE); 746 + blk_queue_max_sectors(queue, SAFE_MAX_SECTORS); 747 + 748 + gendisk = alloc_disk(1); 749 + if (!gendisk) { 750 + dev_err(&dev->core, "alloc_disk failed\n"); 751 + error = -ENOMEM; 752 + goto fail_cleanup_queue; 753 + } 754 + 755 + priv->gendisk = gendisk; 756 + gendisk->major = ps3vram_major; 757 + gendisk->first_minor = 0; 758 + gendisk->fops = &ps3vram_fops; 759 + gendisk->queue = queue; 760 + gendisk->private_data = dev; 761 + gendisk->driverfs_dev = &dev->core; 762 + strlcpy(gendisk->disk_name, DEVICE_NAME, sizeof(gendisk->disk_name)); 763 + set_capacity(gendisk, priv->size >> 9); 764 + 765 + dev_info(&dev->core, "%s: Using %lu MiB of GPU memory\n", 766 + gendisk->disk_name, get_capacity(gendisk) >> 11); 767 + 768 + add_disk(gendisk); 769 + return 0; 770 + 771 + fail_cleanup_queue: 772 + blk_cleanup_queue(queue); 773 + out_cache_cleanup: 774 + remove_proc_entry(DEVICE_NAME, NULL); 775 + ps3vram_cache_cleanup(dev); 776 + out_unmap_reports: 777 + iounmap(priv->reports); 778 + out_unmap_ctrl: 779 + iounmap(priv->ctrl); 780 + out_unmap_vram: 781 + iounmap(priv->ddr_base); 782 + out_free_context: 783 + lv1_gpu_context_free(priv->context_handle); 784 + out_free_memory: 785 + lv1_gpu_memory_free(priv->memory_handle); 786 + out_close_gpu: 787 + ps3_close_hv_device(dev); 788 + out_free_xdr_buf: 789 + free_pages((unsigned long) priv->xdr_buf, get_order(XDR_BUF_SIZE)); 790 + fail_free_priv: 791 + kfree(priv); 792 + dev->core.driver_data = NULL; 793 + fail: 794 + return error; 795 + } 796 + 797 + static int ps3vram_remove(struct ps3_system_bus_device *dev) 798 + { 799 + struct ps3vram_priv *priv = dev->core.driver_data; 800 + 801 + del_gendisk(priv->gendisk); 802 + put_disk(priv->gendisk); 803 + blk_cleanup_queue(priv->queue); 804 + remove_proc_entry(DEVICE_NAME, NULL); 805 + ps3vram_cache_cleanup(dev); 806 + iounmap(priv->reports); 807 + iounmap(priv->ctrl); 808 + iounmap(priv->ddr_base); 809 + lv1_gpu_context_free(priv->context_handle); 810 + lv1_gpu_memory_free(priv->memory_handle); 811 + ps3_close_hv_device(dev); 812 + free_pages((unsigned long) priv->xdr_buf, get_order(XDR_BUF_SIZE)); 813 + kfree(priv); 814 + dev->core.driver_data = NULL; 815 + return 0; 816 + } 817 + 818 + static struct ps3_system_bus_driver ps3vram = { 819 + .match_id = PS3_MATCH_ID_GPU, 820 + .match_sub_id = PS3_MATCH_SUB_ID_GPU_RAMDISK, 821 + .core.name = DEVICE_NAME, 822 + .core.owner = THIS_MODULE, 823 + .probe = ps3vram_probe, 824 + .remove = ps3vram_remove, 825 + .shutdown = ps3vram_remove, 826 + }; 827 + 828 + 829 + static int __init ps3vram_init(void) 830 + { 831 + int error; 832 + 833 + if (!firmware_has_feature(FW_FEATURE_PS3_LV1)) 834 + return -ENODEV; 835 + 836 + error = register_blkdev(0, DEVICE_NAME); 837 + if (error <= 0) { 838 + pr_err("%s: register_blkdev failed %d\n", DEVICE_NAME, error); 839 + return error; 840 + } 841 + ps3vram_major = error; 842 + 843 + pr_info("%s: registered block device major %d\n", DEVICE_NAME, 844 + ps3vram_major); 845 + 846 + error = ps3_system_bus_driver_register(&ps3vram); 847 + if (error) 848 + unregister_blkdev(ps3vram_major, DEVICE_NAME); 849 + 850 + return error; 851 + } 852 + 853 + static void __exit ps3vram_exit(void) 854 + { 855 + ps3_system_bus_driver_unregister(&ps3vram); 856 + unregister_blkdev(ps3vram_major, DEVICE_NAME); 857 + } 858 + 859 + module_init(ps3vram_init); 860 + module_exit(ps3vram_exit); 861 + 862 + MODULE_LICENSE("GPL"); 863 + MODULE_DESCRIPTION("PS3 Video RAM Storage Driver"); 864 + MODULE_AUTHOR("Sony Corporation"); 865 + MODULE_ALIAS(PS3_MODULE_ALIAS_GPU_RAMDISK);
-7
drivers/mtd/devices/Kconfig
··· 120 120 doesn't have access to, memory beyond the mem=xxx limit, nvram, 121 121 memory on the video card, etc... 122 122 123 - config MTD_PS3VRAM 124 - tristate "PS3 video RAM" 125 - depends on FB_PS3 126 - help 127 - This driver allows you to use excess PS3 video RAM as volatile 128 - storage or system swap. 129 - 130 123 config MTD_LART 131 124 tristate "28F160xx flash driver for LART" 132 125 depends on SA1100_LART
-1
drivers/mtd/devices/Makefile
··· 16 16 obj-$(CONFIG_MTD_BLOCK2MTD) += block2mtd.o 17 17 obj-$(CONFIG_MTD_DATAFLASH) += mtd_dataflash.o 18 18 obj-$(CONFIG_MTD_M25P80) += m25p80.o 19 - obj-$(CONFIG_MTD_PS3VRAM) += ps3vram.o
-768
drivers/mtd/devices/ps3vram.c
··· 1 - /** 2 - * ps3vram - Use extra PS3 video ram as MTD block device. 3 - * 4 - * Copyright (c) 2007-2008 Jim Paris <jim@jtan.com> 5 - * Added support RSX DMA Vivien Chappelier <vivien.chappelier@free.fr> 6 - */ 7 - 8 - #include <linux/io.h> 9 - #include <linux/mm.h> 10 - #include <linux/init.h> 11 - #include <linux/kernel.h> 12 - #include <linux/list.h> 13 - #include <linux/module.h> 14 - #include <linux/moduleparam.h> 15 - #include <linux/slab.h> 16 - #include <linux/version.h> 17 - #include <linux/gfp.h> 18 - #include <linux/delay.h> 19 - #include <linux/mtd/mtd.h> 20 - 21 - #include <asm/lv1call.h> 22 - #include <asm/ps3.h> 23 - 24 - #define DEVICE_NAME "ps3vram" 25 - 26 - #define XDR_BUF_SIZE (2 * 1024 * 1024) /* XDR buffer (must be 1MiB aligned) */ 27 - #define XDR_IOIF 0x0c000000 28 - 29 - #define FIFO_BASE XDR_IOIF 30 - #define FIFO_SIZE (64 * 1024) 31 - 32 - #define DMA_PAGE_SIZE (4 * 1024) 33 - 34 - #define CACHE_PAGE_SIZE (256 * 1024) 35 - #define CACHE_PAGE_COUNT ((XDR_BUF_SIZE - FIFO_SIZE) / CACHE_PAGE_SIZE) 36 - 37 - #define CACHE_OFFSET CACHE_PAGE_SIZE 38 - #define FIFO_OFFSET 0 39 - 40 - #define CTRL_PUT 0x10 41 - #define CTRL_GET 0x11 42 - #define CTRL_TOP 0x15 43 - 44 - #define UPLOAD_SUBCH 1 45 - #define DOWNLOAD_SUBCH 2 46 - 47 - #define NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN 0x0000030c 48 - #define NV_MEMORY_TO_MEMORY_FORMAT_NOTIFY 0x00000104 49 - 50 - #define L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT 0x601 51 - 52 - struct mtd_info ps3vram_mtd; 53 - 54 - #define CACHE_PAGE_PRESENT 1 55 - #define CACHE_PAGE_DIRTY 2 56 - 57 - struct ps3vram_tag { 58 - unsigned int address; 59 - unsigned int flags; 60 - }; 61 - 62 - struct ps3vram_cache { 63 - unsigned int page_count; 64 - unsigned int page_size; 65 - struct ps3vram_tag *tags; 66 - }; 67 - 68 - struct ps3vram_priv { 69 - u64 memory_handle; 70 - u64 context_handle; 71 - u32 *ctrl; 72 - u32 *reports; 73 - u8 __iomem *ddr_base; 74 - u8 *xdr_buf; 75 - 76 - u32 *fifo_base; 77 - u32 *fifo_ptr; 78 - 79 - struct device *dev; 80 - struct ps3vram_cache cache; 81 - 82 - /* Used to serialize cache/DMA operations */ 83 - struct mutex lock; 84 - }; 85 - 86 - #define DMA_NOTIFIER_HANDLE_BASE 0x66604200 /* first DMA notifier handle */ 87 - #define DMA_NOTIFIER_OFFSET_BASE 0x1000 /* first DMA notifier offset */ 88 - #define DMA_NOTIFIER_SIZE 0x40 89 - #define NOTIFIER 7 /* notifier used for completion report */ 90 - 91 - /* A trailing '-' means to subtract off ps3fb_videomemory.size */ 92 - char *size = "256M-"; 93 - module_param(size, charp, 0); 94 - MODULE_PARM_DESC(size, "memory size"); 95 - 96 - static u32 *ps3vram_get_notifier(u32 *reports, int notifier) 97 - { 98 - return (void *) reports + 99 - DMA_NOTIFIER_OFFSET_BASE + 100 - DMA_NOTIFIER_SIZE * notifier; 101 - } 102 - 103 - static void ps3vram_notifier_reset(struct mtd_info *mtd) 104 - { 105 - int i; 106 - 107 - struct ps3vram_priv *priv = mtd->priv; 108 - u32 *notify = ps3vram_get_notifier(priv->reports, NOTIFIER); 109 - for (i = 0; i < 4; i++) 110 - notify[i] = 0xffffffff; 111 - } 112 - 113 - static int ps3vram_notifier_wait(struct mtd_info *mtd, unsigned int timeout_ms) 114 - { 115 - struct ps3vram_priv *priv = mtd->priv; 116 - u32 *notify = ps3vram_get_notifier(priv->reports, NOTIFIER); 117 - unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms); 118 - 119 - do { 120 - if (!notify[3]) 121 - return 0; 122 - msleep(1); 123 - } while (time_before(jiffies, timeout)); 124 - 125 - return -ETIMEDOUT; 126 - } 127 - 128 - static void ps3vram_init_ring(struct mtd_info *mtd) 129 - { 130 - struct ps3vram_priv *priv = mtd->priv; 131 - 132 - priv->ctrl[CTRL_PUT] = FIFO_BASE + FIFO_OFFSET; 133 - priv->ctrl[CTRL_GET] = FIFO_BASE + FIFO_OFFSET; 134 - } 135 - 136 - static int ps3vram_wait_ring(struct mtd_info *mtd, unsigned int timeout_ms) 137 - { 138 - struct ps3vram_priv *priv = mtd->priv; 139 - unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms); 140 - 141 - do { 142 - if (priv->ctrl[CTRL_PUT] == priv->ctrl[CTRL_GET]) 143 - return 0; 144 - msleep(1); 145 - } while (time_before(jiffies, timeout)); 146 - 147 - dev_dbg(priv->dev, "%s:%d: FIFO timeout (%08x/%08x/%08x)\n", __func__, 148 - __LINE__, priv->ctrl[CTRL_PUT], priv->ctrl[CTRL_GET], 149 - priv->ctrl[CTRL_TOP]); 150 - 151 - return -ETIMEDOUT; 152 - } 153 - 154 - static void ps3vram_out_ring(struct ps3vram_priv *priv, u32 data) 155 - { 156 - *(priv->fifo_ptr)++ = data; 157 - } 158 - 159 - static void ps3vram_begin_ring(struct ps3vram_priv *priv, u32 chan, 160 - u32 tag, u32 size) 161 - { 162 - ps3vram_out_ring(priv, (size << 18) | (chan << 13) | tag); 163 - } 164 - 165 - static void ps3vram_rewind_ring(struct mtd_info *mtd) 166 - { 167 - struct ps3vram_priv *priv = mtd->priv; 168 - u64 status; 169 - 170 - ps3vram_out_ring(priv, 0x20000000 | (FIFO_BASE + FIFO_OFFSET)); 171 - 172 - priv->ctrl[CTRL_PUT] = FIFO_BASE + FIFO_OFFSET; 173 - 174 - /* asking the HV for a blit will kick the fifo */ 175 - status = lv1_gpu_context_attribute(priv->context_handle, 176 - L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT, 177 - 0, 0, 0, 0); 178 - if (status) 179 - dev_err(priv->dev, "%s:%d: lv1_gpu_context_attribute failed\n", 180 - __func__, __LINE__); 181 - 182 - priv->fifo_ptr = priv->fifo_base; 183 - } 184 - 185 - static void ps3vram_fire_ring(struct mtd_info *mtd) 186 - { 187 - struct ps3vram_priv *priv = mtd->priv; 188 - u64 status; 189 - 190 - mutex_lock(&ps3_gpu_mutex); 191 - 192 - priv->ctrl[CTRL_PUT] = FIFO_BASE + FIFO_OFFSET + 193 - (priv->fifo_ptr - priv->fifo_base) * sizeof(u32); 194 - 195 - /* asking the HV for a blit will kick the fifo */ 196 - status = lv1_gpu_context_attribute(priv->context_handle, 197 - L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT, 198 - 0, 0, 0, 0); 199 - if (status) 200 - dev_err(priv->dev, "%s:%d: lv1_gpu_context_attribute failed\n", 201 - __func__, __LINE__); 202 - 203 - if ((priv->fifo_ptr - priv->fifo_base) * sizeof(u32) > 204 - FIFO_SIZE - 1024) { 205 - dev_dbg(priv->dev, "%s:%d: fifo full, rewinding\n", __func__, 206 - __LINE__); 207 - ps3vram_wait_ring(mtd, 200); 208 - ps3vram_rewind_ring(mtd); 209 - } 210 - 211 - mutex_unlock(&ps3_gpu_mutex); 212 - } 213 - 214 - static void ps3vram_bind(struct mtd_info *mtd) 215 - { 216 - struct ps3vram_priv *priv = mtd->priv; 217 - 218 - ps3vram_begin_ring(priv, UPLOAD_SUBCH, 0, 1); 219 - ps3vram_out_ring(priv, 0x31337303); 220 - ps3vram_begin_ring(priv, UPLOAD_SUBCH, 0x180, 3); 221 - ps3vram_out_ring(priv, DMA_NOTIFIER_HANDLE_BASE + NOTIFIER); 222 - ps3vram_out_ring(priv, 0xfeed0001); /* DMA system RAM instance */ 223 - ps3vram_out_ring(priv, 0xfeed0000); /* DMA video RAM instance */ 224 - 225 - ps3vram_begin_ring(priv, DOWNLOAD_SUBCH, 0, 1); 226 - ps3vram_out_ring(priv, 0x3137c0de); 227 - ps3vram_begin_ring(priv, DOWNLOAD_SUBCH, 0x180, 3); 228 - ps3vram_out_ring(priv, DMA_NOTIFIER_HANDLE_BASE + NOTIFIER); 229 - ps3vram_out_ring(priv, 0xfeed0000); /* DMA video RAM instance */ 230 - ps3vram_out_ring(priv, 0xfeed0001); /* DMA system RAM instance */ 231 - 232 - ps3vram_fire_ring(mtd); 233 - } 234 - 235 - static int ps3vram_upload(struct mtd_info *mtd, unsigned int src_offset, 236 - unsigned int dst_offset, int len, int count) 237 - { 238 - struct ps3vram_priv *priv = mtd->priv; 239 - 240 - ps3vram_begin_ring(priv, UPLOAD_SUBCH, 241 - NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8); 242 - ps3vram_out_ring(priv, XDR_IOIF + src_offset); 243 - ps3vram_out_ring(priv, dst_offset); 244 - ps3vram_out_ring(priv, len); 245 - ps3vram_out_ring(priv, len); 246 - ps3vram_out_ring(priv, len); 247 - ps3vram_out_ring(priv, count); 248 - ps3vram_out_ring(priv, (1 << 8) | 1); 249 - ps3vram_out_ring(priv, 0); 250 - 251 - ps3vram_notifier_reset(mtd); 252 - ps3vram_begin_ring(priv, UPLOAD_SUBCH, 253 - NV_MEMORY_TO_MEMORY_FORMAT_NOTIFY, 1); 254 - ps3vram_out_ring(priv, 0); 255 - ps3vram_begin_ring(priv, UPLOAD_SUBCH, 0x100, 1); 256 - ps3vram_out_ring(priv, 0); 257 - ps3vram_fire_ring(mtd); 258 - if (ps3vram_notifier_wait(mtd, 200) < 0) { 259 - dev_dbg(priv->dev, "%s:%d: notifier timeout\n", __func__, 260 - __LINE__); 261 - return -1; 262 - } 263 - 264 - return 0; 265 - } 266 - 267 - static int ps3vram_download(struct mtd_info *mtd, unsigned int src_offset, 268 - unsigned int dst_offset, int len, int count) 269 - { 270 - struct ps3vram_priv *priv = mtd->priv; 271 - 272 - ps3vram_begin_ring(priv, DOWNLOAD_SUBCH, 273 - NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8); 274 - ps3vram_out_ring(priv, src_offset); 275 - ps3vram_out_ring(priv, XDR_IOIF + dst_offset); 276 - ps3vram_out_ring(priv, len); 277 - ps3vram_out_ring(priv, len); 278 - ps3vram_out_ring(priv, len); 279 - ps3vram_out_ring(priv, count); 280 - ps3vram_out_ring(priv, (1 << 8) | 1); 281 - ps3vram_out_ring(priv, 0); 282 - 283 - ps3vram_notifier_reset(mtd); 284 - ps3vram_begin_ring(priv, DOWNLOAD_SUBCH, 285 - NV_MEMORY_TO_MEMORY_FORMAT_NOTIFY, 1); 286 - ps3vram_out_ring(priv, 0); 287 - ps3vram_begin_ring(priv, DOWNLOAD_SUBCH, 0x100, 1); 288 - ps3vram_out_ring(priv, 0); 289 - ps3vram_fire_ring(mtd); 290 - if (ps3vram_notifier_wait(mtd, 200) < 0) { 291 - dev_dbg(priv->dev, "%s:%d: notifier timeout\n", __func__, 292 - __LINE__); 293 - return -1; 294 - } 295 - 296 - return 0; 297 - } 298 - 299 - static void ps3vram_cache_evict(struct mtd_info *mtd, int entry) 300 - { 301 - struct ps3vram_priv *priv = mtd->priv; 302 - struct ps3vram_cache *cache = &priv->cache; 303 - 304 - if (cache->tags[entry].flags & CACHE_PAGE_DIRTY) { 305 - dev_dbg(priv->dev, "%s:%d: flushing %d : 0x%08x\n", __func__, 306 - __LINE__, entry, cache->tags[entry].address); 307 - if (ps3vram_upload(mtd, 308 - CACHE_OFFSET + entry * cache->page_size, 309 - cache->tags[entry].address, 310 - DMA_PAGE_SIZE, 311 - cache->page_size / DMA_PAGE_SIZE) < 0) { 312 - dev_dbg(priv->dev, "%s:%d: failed to upload from " 313 - "0x%x to 0x%x size 0x%x\n", __func__, __LINE__, 314 - entry * cache->page_size, 315 - cache->tags[entry].address, cache->page_size); 316 - } 317 - cache->tags[entry].flags &= ~CACHE_PAGE_DIRTY; 318 - } 319 - } 320 - 321 - static void ps3vram_cache_load(struct mtd_info *mtd, int entry, 322 - unsigned int address) 323 - { 324 - struct ps3vram_priv *priv = mtd->priv; 325 - struct ps3vram_cache *cache = &priv->cache; 326 - 327 - dev_dbg(priv->dev, "%s:%d: fetching %d : 0x%08x\n", __func__, __LINE__, 328 - entry, address); 329 - if (ps3vram_download(mtd, 330 - address, 331 - CACHE_OFFSET + entry * cache->page_size, 332 - DMA_PAGE_SIZE, 333 - cache->page_size / DMA_PAGE_SIZE) < 0) { 334 - dev_err(priv->dev, "%s:%d: failed to download from " 335 - "0x%x to 0x%x size 0x%x\n", __func__, __LINE__, address, 336 - entry * cache->page_size, cache->page_size); 337 - } 338 - 339 - cache->tags[entry].address = address; 340 - cache->tags[entry].flags |= CACHE_PAGE_PRESENT; 341 - } 342 - 343 - 344 - static void ps3vram_cache_flush(struct mtd_info *mtd) 345 - { 346 - struct ps3vram_priv *priv = mtd->priv; 347 - struct ps3vram_cache *cache = &priv->cache; 348 - int i; 349 - 350 - dev_dbg(priv->dev, "%s:%d: FLUSH\n", __func__, __LINE__); 351 - for (i = 0; i < cache->page_count; i++) { 352 - ps3vram_cache_evict(mtd, i); 353 - cache->tags[i].flags = 0; 354 - } 355 - } 356 - 357 - static unsigned int ps3vram_cache_match(struct mtd_info *mtd, loff_t address) 358 - { 359 - struct ps3vram_priv *priv = mtd->priv; 360 - struct ps3vram_cache *cache = &priv->cache; 361 - unsigned int base; 362 - unsigned int offset; 363 - int i; 364 - static int counter; 365 - 366 - offset = (unsigned int) (address & (cache->page_size - 1)); 367 - base = (unsigned int) (address - offset); 368 - 369 - /* fully associative check */ 370 - for (i = 0; i < cache->page_count; i++) { 371 - if ((cache->tags[i].flags & CACHE_PAGE_PRESENT) && 372 - cache->tags[i].address == base) { 373 - dev_dbg(priv->dev, "%s:%d: found entry %d : 0x%08x\n", 374 - __func__, __LINE__, i, cache->tags[i].address); 375 - return i; 376 - } 377 - } 378 - 379 - /* choose a random entry */ 380 - i = (jiffies + (counter++)) % cache->page_count; 381 - dev_dbg(priv->dev, "%s:%d: using entry %d\n", __func__, __LINE__, i); 382 - 383 - ps3vram_cache_evict(mtd, i); 384 - ps3vram_cache_load(mtd, i, base); 385 - 386 - return i; 387 - } 388 - 389 - static int ps3vram_cache_init(struct mtd_info *mtd) 390 - { 391 - struct ps3vram_priv *priv = mtd->priv; 392 - 393 - priv->cache.page_count = CACHE_PAGE_COUNT; 394 - priv->cache.page_size = CACHE_PAGE_SIZE; 395 - priv->cache.tags = kzalloc(sizeof(struct ps3vram_tag) * 396 - CACHE_PAGE_COUNT, GFP_KERNEL); 397 - if (priv->cache.tags == NULL) { 398 - dev_err(priv->dev, "%s:%d: could not allocate cache tags\n", 399 - __func__, __LINE__); 400 - return -ENOMEM; 401 - } 402 - 403 - dev_info(priv->dev, "created ram cache: %d entries, %d KiB each\n", 404 - CACHE_PAGE_COUNT, CACHE_PAGE_SIZE / 1024); 405 - 406 - return 0; 407 - } 408 - 409 - static void ps3vram_cache_cleanup(struct mtd_info *mtd) 410 - { 411 - struct ps3vram_priv *priv = mtd->priv; 412 - 413 - ps3vram_cache_flush(mtd); 414 - kfree(priv->cache.tags); 415 - } 416 - 417 - static int ps3vram_erase(struct mtd_info *mtd, struct erase_info *instr) 418 - { 419 - struct ps3vram_priv *priv = mtd->priv; 420 - 421 - if (instr->addr + instr->len > mtd->size) 422 - return -EINVAL; 423 - 424 - mutex_lock(&priv->lock); 425 - 426 - ps3vram_cache_flush(mtd); 427 - 428 - /* Set bytes to 0xFF */ 429 - memset_io(priv->ddr_base + instr->addr, 0xFF, instr->len); 430 - 431 - mutex_unlock(&priv->lock); 432 - 433 - instr->state = MTD_ERASE_DONE; 434 - mtd_erase_callback(instr); 435 - 436 - return 0; 437 - } 438 - 439 - static int ps3vram_read(struct mtd_info *mtd, loff_t from, size_t len, 440 - size_t *retlen, u_char *buf) 441 - { 442 - struct ps3vram_priv *priv = mtd->priv; 443 - unsigned int cached, count; 444 - 445 - dev_dbg(priv->dev, "%s:%d: from=0x%08x len=0x%zx\n", __func__, __LINE__, 446 - (unsigned int)from, len); 447 - 448 - if (from >= mtd->size) 449 - return -EINVAL; 450 - 451 - if (len > mtd->size - from) 452 - len = mtd->size - from; 453 - 454 - /* Copy from vram to buf */ 455 - count = len; 456 - while (count) { 457 - unsigned int offset, avail; 458 - unsigned int entry; 459 - 460 - offset = (unsigned int) (from & (priv->cache.page_size - 1)); 461 - avail = priv->cache.page_size - offset; 462 - 463 - mutex_lock(&priv->lock); 464 - 465 - entry = ps3vram_cache_match(mtd, from); 466 - cached = CACHE_OFFSET + entry * priv->cache.page_size + offset; 467 - 468 - dev_dbg(priv->dev, "%s:%d: from=%08x cached=%08x offset=%08x " 469 - "avail=%08x count=%08x\n", __func__, __LINE__, 470 - (unsigned int)from, cached, offset, avail, count); 471 - 472 - if (avail > count) 473 - avail = count; 474 - memcpy(buf, priv->xdr_buf + cached, avail); 475 - 476 - mutex_unlock(&priv->lock); 477 - 478 - buf += avail; 479 - count -= avail; 480 - from += avail; 481 - } 482 - 483 - *retlen = len; 484 - return 0; 485 - } 486 - 487 - static int ps3vram_write(struct mtd_info *mtd, loff_t to, size_t len, 488 - size_t *retlen, const u_char *buf) 489 - { 490 - struct ps3vram_priv *priv = mtd->priv; 491 - unsigned int cached, count; 492 - 493 - if (to >= mtd->size) 494 - return -EINVAL; 495 - 496 - if (len > mtd->size - to) 497 - len = mtd->size - to; 498 - 499 - /* Copy from buf to vram */ 500 - count = len; 501 - while (count) { 502 - unsigned int offset, avail; 503 - unsigned int entry; 504 - 505 - offset = (unsigned int) (to & (priv->cache.page_size - 1)); 506 - avail = priv->cache.page_size - offset; 507 - 508 - mutex_lock(&priv->lock); 509 - 510 - entry = ps3vram_cache_match(mtd, to); 511 - cached = CACHE_OFFSET + entry * priv->cache.page_size + offset; 512 - 513 - dev_dbg(priv->dev, "%s:%d: to=%08x cached=%08x offset=%08x " 514 - "avail=%08x count=%08x\n", __func__, __LINE__, 515 - (unsigned int)to, cached, offset, avail, count); 516 - 517 - if (avail > count) 518 - avail = count; 519 - memcpy(priv->xdr_buf + cached, buf, avail); 520 - 521 - priv->cache.tags[entry].flags |= CACHE_PAGE_DIRTY; 522 - 523 - mutex_unlock(&priv->lock); 524 - 525 - buf += avail; 526 - count -= avail; 527 - to += avail; 528 - } 529 - 530 - *retlen = len; 531 - return 0; 532 - } 533 - 534 - static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev) 535 - { 536 - struct ps3vram_priv *priv; 537 - int status; 538 - u64 ddr_lpar; 539 - u64 ctrl_lpar; 540 - u64 info_lpar; 541 - u64 reports_lpar; 542 - u64 ddr_size; 543 - u64 reports_size; 544 - int ret = -ENOMEM; 545 - char *rest; 546 - 547 - ret = -EIO; 548 - ps3vram_mtd.priv = kzalloc(sizeof(struct ps3vram_priv), GFP_KERNEL); 549 - if (!ps3vram_mtd.priv) 550 - goto out; 551 - priv = ps3vram_mtd.priv; 552 - 553 - mutex_init(&priv->lock); 554 - priv->dev = &dev->core; 555 - 556 - /* Allocate XDR buffer (1MiB aligned) */ 557 - priv->xdr_buf = (void *)__get_free_pages(GFP_KERNEL, 558 - get_order(XDR_BUF_SIZE)); 559 - if (priv->xdr_buf == NULL) { 560 - dev_dbg(&dev->core, "%s:%d: could not allocate XDR buffer\n", 561 - __func__, __LINE__); 562 - ret = -ENOMEM; 563 - goto out_free_priv; 564 - } 565 - 566 - /* Put FIFO at begginning of XDR buffer */ 567 - priv->fifo_base = (u32 *) (priv->xdr_buf + FIFO_OFFSET); 568 - priv->fifo_ptr = priv->fifo_base; 569 - 570 - /* XXX: Need to open GPU, in case ps3fb or snd_ps3 aren't loaded */ 571 - if (ps3_open_hv_device(dev)) { 572 - dev_err(&dev->core, "%s:%d: ps3_open_hv_device failed\n", 573 - __func__, __LINE__); 574 - ret = -EAGAIN; 575 - goto out_close_gpu; 576 - } 577 - 578 - /* Request memory */ 579 - status = -1; 580 - ddr_size = memparse(size, &rest); 581 - if (*rest == '-') 582 - ddr_size -= ps3fb_videomemory.size; 583 - ddr_size = ALIGN(ddr_size, 1024*1024); 584 - if (ddr_size <= 0) { 585 - dev_err(&dev->core, "%s:%d: specified size is too small\n", 586 - __func__, __LINE__); 587 - ret = -EINVAL; 588 - goto out_close_gpu; 589 - } 590 - 591 - while (ddr_size > 0) { 592 - status = lv1_gpu_memory_allocate(ddr_size, 0, 0, 0, 0, 593 - &priv->memory_handle, 594 - &ddr_lpar); 595 - if (!status) 596 - break; 597 - ddr_size -= 1024*1024; 598 - } 599 - if (status || ddr_size <= 0) { 600 - dev_err(&dev->core, "%s:%d: lv1_gpu_memory_allocate failed\n", 601 - __func__, __LINE__); 602 - ret = -ENOMEM; 603 - goto out_free_xdr_buf; 604 - } 605 - 606 - /* Request context */ 607 - status = lv1_gpu_context_allocate(priv->memory_handle, 608 - 0, 609 - &priv->context_handle, 610 - &ctrl_lpar, 611 - &info_lpar, 612 - &reports_lpar, 613 - &reports_size); 614 - if (status) { 615 - dev_err(&dev->core, "%s:%d: lv1_gpu_context_allocate failed\n", 616 - __func__, __LINE__); 617 - ret = -ENOMEM; 618 - goto out_free_memory; 619 - } 620 - 621 - /* Map XDR buffer to RSX */ 622 - status = lv1_gpu_context_iomap(priv->context_handle, XDR_IOIF, 623 - ps3_mm_phys_to_lpar(__pa(priv->xdr_buf)), 624 - XDR_BUF_SIZE, 0); 625 - if (status) { 626 - dev_err(&dev->core, "%s:%d: lv1_gpu_context_iomap failed\n", 627 - __func__, __LINE__); 628 - ret = -ENOMEM; 629 - goto out_free_context; 630 - } 631 - 632 - priv->ddr_base = ioremap_flags(ddr_lpar, ddr_size, _PAGE_NO_CACHE); 633 - 634 - if (!priv->ddr_base) { 635 - dev_err(&dev->core, "%s:%d: ioremap failed\n", __func__, 636 - __LINE__); 637 - ret = -ENOMEM; 638 - goto out_free_context; 639 - } 640 - 641 - priv->ctrl = ioremap(ctrl_lpar, 64 * 1024); 642 - if (!priv->ctrl) { 643 - dev_err(&dev->core, "%s:%d: ioremap failed\n", __func__, 644 - __LINE__); 645 - ret = -ENOMEM; 646 - goto out_unmap_vram; 647 - } 648 - 649 - priv->reports = ioremap(reports_lpar, reports_size); 650 - if (!priv->reports) { 651 - dev_err(&dev->core, "%s:%d: ioremap failed\n", __func__, 652 - __LINE__); 653 - ret = -ENOMEM; 654 - goto out_unmap_ctrl; 655 - } 656 - 657 - mutex_lock(&ps3_gpu_mutex); 658 - ps3vram_init_ring(&ps3vram_mtd); 659 - mutex_unlock(&ps3_gpu_mutex); 660 - 661 - ps3vram_mtd.name = "ps3vram"; 662 - ps3vram_mtd.size = ddr_size; 663 - ps3vram_mtd.flags = MTD_CAP_RAM; 664 - ps3vram_mtd.erase = ps3vram_erase; 665 - ps3vram_mtd.point = NULL; 666 - ps3vram_mtd.unpoint = NULL; 667 - ps3vram_mtd.read = ps3vram_read; 668 - ps3vram_mtd.write = ps3vram_write; 669 - ps3vram_mtd.owner = THIS_MODULE; 670 - ps3vram_mtd.type = MTD_RAM; 671 - ps3vram_mtd.erasesize = CACHE_PAGE_SIZE; 672 - ps3vram_mtd.writesize = 1; 673 - 674 - ps3vram_bind(&ps3vram_mtd); 675 - 676 - mutex_lock(&ps3_gpu_mutex); 677 - ret = ps3vram_wait_ring(&ps3vram_mtd, 100); 678 - mutex_unlock(&ps3_gpu_mutex); 679 - if (ret < 0) { 680 - dev_err(&dev->core, "%s:%d: failed to initialize channels\n", 681 - __func__, __LINE__); 682 - ret = -ETIMEDOUT; 683 - goto out_unmap_reports; 684 - } 685 - 686 - ps3vram_cache_init(&ps3vram_mtd); 687 - 688 - if (add_mtd_device(&ps3vram_mtd)) { 689 - dev_err(&dev->core, "%s:%d: add_mtd_device failed\n", 690 - __func__, __LINE__); 691 - ret = -EAGAIN; 692 - goto out_cache_cleanup; 693 - } 694 - 695 - dev_info(&dev->core, "reserved %u MiB of gpu memory\n", 696 - (unsigned int)(ddr_size / 1024 / 1024)); 697 - 698 - return 0; 699 - 700 - out_cache_cleanup: 701 - ps3vram_cache_cleanup(&ps3vram_mtd); 702 - out_unmap_reports: 703 - iounmap(priv->reports); 704 - out_unmap_ctrl: 705 - iounmap(priv->ctrl); 706 - out_unmap_vram: 707 - iounmap(priv->ddr_base); 708 - out_free_context: 709 - lv1_gpu_context_free(priv->context_handle); 710 - out_free_memory: 711 - lv1_gpu_memory_free(priv->memory_handle); 712 - out_close_gpu: 713 - ps3_close_hv_device(dev); 714 - out_free_xdr_buf: 715 - free_pages((unsigned long) priv->xdr_buf, get_order(XDR_BUF_SIZE)); 716 - out_free_priv: 717 - kfree(ps3vram_mtd.priv); 718 - ps3vram_mtd.priv = NULL; 719 - out: 720 - return ret; 721 - } 722 - 723 - static int ps3vram_shutdown(struct ps3_system_bus_device *dev) 724 - { 725 - struct ps3vram_priv *priv; 726 - 727 - priv = ps3vram_mtd.priv; 728 - 729 - del_mtd_device(&ps3vram_mtd); 730 - ps3vram_cache_cleanup(&ps3vram_mtd); 731 - iounmap(priv->reports); 732 - iounmap(priv->ctrl); 733 - iounmap(priv->ddr_base); 734 - lv1_gpu_context_free(priv->context_handle); 735 - lv1_gpu_memory_free(priv->memory_handle); 736 - ps3_close_hv_device(dev); 737 - free_pages((unsigned long) priv->xdr_buf, get_order(XDR_BUF_SIZE)); 738 - kfree(priv); 739 - return 0; 740 - } 741 - 742 - static struct ps3_system_bus_driver ps3vram_driver = { 743 - .match_id = PS3_MATCH_ID_GPU, 744 - .match_sub_id = PS3_MATCH_SUB_ID_GPU_RAMDISK, 745 - .core.name = DEVICE_NAME, 746 - .core.owner = THIS_MODULE, 747 - .probe = ps3vram_probe, 748 - .remove = ps3vram_shutdown, 749 - .shutdown = ps3vram_shutdown, 750 - }; 751 - 752 - static int __init ps3vram_init(void) 753 - { 754 - return ps3_system_bus_driver_register(&ps3vram_driver); 755 - } 756 - 757 - static void __exit ps3vram_exit(void) 758 - { 759 - ps3_system_bus_driver_unregister(&ps3vram_driver); 760 - } 761 - 762 - module_init(ps3vram_init); 763 - module_exit(ps3vram_exit); 764 - 765 - MODULE_LICENSE("GPL"); 766 - MODULE_AUTHOR("Jim Paris <jim@jtan.com>"); 767 - MODULE_DESCRIPTION("MTD driver for PS3 video RAM"); 768 - MODULE_ALIAS(PS3_MODULE_ALIAS_GPU_RAMDISK);