From 529273c1ad5f591d066a9d90a6bd6affa19c5461 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Sat, 6 Jun 2009 06:39:46 +0000 Subject: [PATCH 01/38] powerpc/install: Bail with error code on error in install script If anything goes wrong when copying images into the install path, then the install script should exit with an error code so that 'make' knows about it and tells the user. Signed-off-by: Grant Likely Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/boot/install.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/powerpc/boot/install.sh b/arch/powerpc/boot/install.sh index 51b2387bdba0..98312d169c85 100644 --- a/arch/powerpc/boot/install.sh +++ b/arch/powerpc/boot/install.sh @@ -18,6 +18,9 @@ # $5 and more - kernel boot files; zImage*, uImage, cuImage.*, etc. # +# Bail with error code if anything goes wrong +set -e + # User may have a custom install script if [ -x ~/bin/${CROSS_COMPILE}installkernel ]; then exec ~/bin/${CROSS_COMPILE}installkernel "$@"; fi From 177996e6e20f15004d6757d9b859f57d181ef443 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Tue, 9 Jun 2009 21:12:00 +0000 Subject: [PATCH 02/38] powerpc: Don't do generic calibrate_delay() Currently we are wasting time calling the generic calibrate_delay() function. We don't need it since our implementation of __delay() is based on the CPU timebase. So instead, we use our own small implementation that initializes loops_per_jiffy to something sensible to make the few users like spinlock debug be happy Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/Kconfig | 4 ---- arch/powerpc/kernel/time.c | 10 ++++++++++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 93a61898b259..eae0c2bbbf38 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -93,10 +93,6 @@ config GENERIC_HWEIGHT bool default y -config GENERIC_CALIBRATE_DELAY - bool - default y - config GENERIC_FIND_NEXT_BIT bool default y diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index bee1443da763..15391c2ab013 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -52,6 +52,7 @@ #include #include #include +#include #include #include @@ -1143,6 +1144,15 @@ void div128_by_32(u64 dividend_high, u64 dividend_low, } +/* We don't need to calibrate delay, we use the CPU timebase for that */ +void calibrate_delay(void) +{ + /* Some generic code (such as spinlock debug) use loops_per_jiffy + * as the number of __delay(1) in a jiffy, so make it so + */ + loops_per_jiffy = tb_ticks_per_jiffy; +} + static int __init rtc_init(void) { struct platform_device *pdev; From 7a4a89c38960591fa6555d287f793bd592c07ebd Mon Sep 17 00:00:00 2001 From: "sebastian.blanes@gmail.com" Date: Wed, 10 Jun 2009 04:38:36 +0000 Subject: [PATCH 03/38] ps3av: Set 16:9 aspect ratio for 720p video modes Signed-off-by: Geert Uytterhoeven Cc: linux-fbdev-devel@lists.sourceforge.net Signed-off-by: Benjamin Herrenschmidt --- drivers/ps3/ps3av.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/ps3/ps3av.c b/drivers/ps3/ps3av.c index 235e87fcb49f..4e4611e99afe 100644 --- a/drivers/ps3/ps3av.c +++ b/drivers/ps3/ps3av.c @@ -80,12 +80,12 @@ static const struct avset_video_mode { { 0, }, /* auto */ {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_480I, A_N, 720, 480}, {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_480P, A_N, 720, 480}, - {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_60HZ, A_N, 1280, 720}, + {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_60HZ, A_W, 1280, 720}, {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080I_60HZ, A_W, 1920, 1080}, {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080P_60HZ, A_W, 1920, 1080}, {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_576I, A_N, 720, 576}, {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_576P, A_N, 720, 576}, - {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_50HZ, A_N, 1280, 720}, + {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_50HZ, A_W, 1280, 720}, {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080I_50HZ, A_W, 1920, 1080}, {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080P_50HZ, A_W, 1920, 1080}, { RGB8, XRGB, PS3AV_CMD_VIDEO_VID_WXGA, A_W, 1280, 768}, From 734957c89794971c874f9d3ccd9eb49dc3325f65 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 10 Jun 2009 04:38:37 +0000 Subject: [PATCH 04/38] ps3vram: Fix error path (return -EIO) for short read/write Signed-off-by: Geert Uytterhoeven Cc: Jim Paris Cc: Jens Axboe Signed-off-by: Benjamin Herrenschmidt --- drivers/block/ps3vram.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/block/ps3vram.c b/drivers/block/ps3vram.c index 8eddef373a91..2e79d2cfa023 100644 --- a/drivers/block/ps3vram.c +++ b/drivers/block/ps3vram.c @@ -585,6 +585,7 @@ static int ps3vram_make_request(struct request_queue *q, struct bio *bio) if (retlen != len) { dev_err(&dev->core, "Short %s\n", op); + error = -EIO; goto out; } From 3c20e2f2793380add92dacce63395a8503b6c7c9 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 10 Jun 2009 04:38:38 +0000 Subject: [PATCH 05/38] ps3vram: Use proc_create_data() instead of proc_create() Use proc_create_data() to avoid race conditions. Reported-by: Alexey Dobriyan Signed-off-by: Geert Uytterhoeven Cc: Jim Paris Cc: Jens Axboe Signed-off-by: Benjamin Herrenschmidt --- drivers/block/ps3vram.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/block/ps3vram.c b/drivers/block/ps3vram.c index 2e79d2cfa023..6e738684a158 100644 --- a/drivers/block/ps3vram.c +++ b/drivers/block/ps3vram.c @@ -546,12 +546,10 @@ static void __devinit ps3vram_proc_init(struct ps3_system_bus_device *dev) struct ps3vram_priv *priv = dev->core.driver_data; struct proc_dir_entry *pde; - pde = proc_create(DEVICE_NAME, 0444, NULL, &ps3vram_proc_fops); - if (!pde) { + pde = proc_create_data(DEVICE_NAME, 0444, NULL, &ps3vram_proc_fops, + priv); + if (!pde) dev_warn(&dev->core, "failed to create /proc entry\n"); - return; - } - pde->data = priv; } static int ps3vram_make_request(struct request_queue *q, struct bio *bio) From 3273d8778f90457a495603945e95b47c2c139f22 Mon Sep 17 00:00:00 2001 From: Jim Paris Date: Wed, 10 Jun 2009 04:38:39 +0000 Subject: [PATCH 06/38] ps3vram: Correct exchanged gotos in ps3vram_probe() error path Signed-off-by: Geert Uytterhoeven Cc: Jim Paris Cc: Jens Axboe Signed-off-by: Benjamin Herrenschmidt --- drivers/block/ps3vram.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/block/ps3vram.c b/drivers/block/ps3vram.c index 6e738684a158..3c9ad1959a69 100644 --- a/drivers/block/ps3vram.c +++ b/drivers/block/ps3vram.c @@ -635,7 +635,7 @@ static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev) if (ps3_open_hv_device(dev)) { dev_err(&dev->core, "ps3_open_hv_device failed\n"); error = -EAGAIN; - goto out_close_gpu; + goto out_free_xdr_buf; } /* Request memory */ @@ -659,7 +659,7 @@ static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev) dev_err(&dev->core, "lv1_gpu_memory_allocate failed %d\n", status); error = -ENOMEM; - goto out_free_xdr_buf; + goto out_close_gpu; } /* Request context */ From 02aad32c32691b63a47d8e7c098c1822faf88c35 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 10 Jun 2009 04:38:42 +0000 Subject: [PATCH 07/38] ps3fb: Remove useless debug checks in ps3fb_shutdown() Signed-off-by: Geert Uytterhoeven Cc: linux-fbdev-devel@lists.sourceforge.net Signed-off-by: Benjamin Herrenschmidt --- drivers/video/ps3fb.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/drivers/video/ps3fb.c b/drivers/video/ps3fb.c index e00c1dff55de..ce0f8735ae08 100644 --- a/drivers/video/ps3fb.c +++ b/drivers/video/ps3fb.c @@ -1247,7 +1247,6 @@ err: static int ps3fb_shutdown(struct ps3_system_bus_device *dev) { - int status; struct fb_info *info = dev->core.driver_data; dev_dbg(&dev->core, " -> %s:%d\n", __func__, __LINE__); @@ -1271,17 +1270,8 @@ static int ps3fb_shutdown(struct ps3_system_bus_device *dev) info = dev->core.driver_data = NULL; } iounmap((u8 __force __iomem *)ps3fb.dinfo); - - status = lv1_gpu_context_free(ps3fb.context_handle); - if (status) - dev_dbg(&dev->core, "lv1_gpu_context_free failed: %d\n", - status); - - status = lv1_gpu_memory_free(ps3fb.memory_handle); - if (status) - dev_dbg(&dev->core, "lv1_gpu_memory_free failed: %d\n", - status); - + lv1_gpu_context_free(ps3fb.context_handle); + lv1_gpu_memory_free(ps3fb.memory_handle); ps3_close_hv_device(dev); dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__); From bb94f077e5c1d3276fe656665c2574fdd3483e75 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 10 Jun 2009 04:38:43 +0000 Subject: [PATCH 08/38] ps3fb: Inline functions in ps3fb_probe(), to ease cleanup in the error path Signed-off-by: Geert Uytterhoeven Cc: linux-fbdev-devel@lists.sourceforge.net Signed-off-by: Benjamin Herrenschmidt --- drivers/video/ps3fb.c | 192 +++++++++++++++++++----------------------- 1 file changed, 86 insertions(+), 106 deletions(-) diff --git a/drivers/video/ps3fb.c b/drivers/video/ps3fb.c index ce0f8735ae08..a74501815333 100644 --- a/drivers/video/ps3fb.c +++ b/drivers/video/ps3fb.c @@ -956,73 +956,6 @@ static irqreturn_t ps3fb_vsync_interrupt(int irq, void *ptr) } -static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo, - struct device *dev) -{ - int error; - - dev_dbg(dev, "version_driver:%x\n", dinfo->version_driver); - dev_dbg(dev, "irq outlet:%x\n", dinfo->irq.irq_outlet); - dev_dbg(dev, - "version_gpu: %x memory_size: %x ch: %x core_freq: %d " - "mem_freq:%d\n", - dinfo->version_gpu, dinfo->memory_size, dinfo->hardware_channel, - dinfo->nvcore_frequency/1000000, dinfo->memory_frequency/1000000); - - if (dinfo->version_driver != GPU_DRIVER_INFO_VERSION) { - dev_err(dev, "%s: version_driver err:%x\n", __func__, - dinfo->version_driver); - return -EINVAL; - } - - error = ps3_irq_plug_setup(PS3_BINDING_CPU_ANY, dinfo->irq.irq_outlet, - &ps3fb.irq_no); - if (error) { - dev_err(dev, "%s: ps3_alloc_irq failed %d\n", __func__, error); - return error; - } - - error = request_irq(ps3fb.irq_no, ps3fb_vsync_interrupt, IRQF_DISABLED, - DEVICE_NAME, dev); - if (error) { - dev_err(dev, "%s: request_irq failed %d\n", __func__, error); - ps3_irq_plug_destroy(ps3fb.irq_no); - return error; - } - - dinfo->irq.mask = (1 << GPU_INTR_STATUS_VSYNC_1) | - (1 << GPU_INTR_STATUS_FLIP_1); - return 0; -} - -static int ps3fb_xdr_settings(u64 xdr_lpar, struct device *dev) -{ - int status; - - status = lv1_gpu_context_iomap(ps3fb.context_handle, GPU_IOIF, - xdr_lpar, ps3fb_videomemory.size, 0); - if (status) { - dev_err(dev, "%s: lv1_gpu_context_iomap failed: %d\n", - __func__, status); - return -ENXIO; - } - dev_dbg(dev, "video:%p ioif:%lx lpar:%llx size:%lx\n", - ps3fb_videomemory.address, GPU_IOIF, xdr_lpar, - ps3fb_videomemory.size); - - status = lv1_gpu_context_attribute(ps3fb.context_handle, - L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP, - xdr_lpar, GPU_CMD_BUF_SIZE, - GPU_IOIF, 0); - if (status) { - dev_err(dev, - "%s: lv1_gpu_context_attribute FB_SETUP failed: %d\n", - __func__, status); - return -ENXIO; - } - return 0; -} - static struct fb_ops ps3fb_ops = { .fb_open = ps3fb_open, .fb_release = ps3fb_release, @@ -1048,38 +981,6 @@ static struct fb_fix_screeninfo ps3fb_fix __initdata = { .accel = FB_ACCEL_NONE, }; -static int ps3fb_set_sync(struct device *dev) -{ - int status; - -#ifdef HEAD_A - status = lv1_gpu_context_attribute(0x0, - L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC, - 0, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0); - if (status) { - dev_err(dev, - "%s: lv1_gpu_context_attribute DISPLAY_SYNC failed: " - "%d\n", - __func__, status); - return -1; - } -#endif -#ifdef HEAD_B - status = lv1_gpu_context_attribute(0x0, - L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC, - 1, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0); - - if (status) { - dev_err(dev, - "%s: lv1_gpu_context_attribute DISPLAY_SYNC failed: " - "%d\n", - __func__, status); - return -1; - } -#endif - return 0; -} - static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) { struct fb_info *info; @@ -1091,6 +992,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) u64 lpar_reports = 0; u64 lpar_reports_size = 0; u64 xdr_lpar; + struct gpu_driver_info *dinfo; void *fb_start; int status; struct task_struct *task; @@ -1116,7 +1018,31 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) atomic_set(&ps3fb.ext_flip, 0); /* for flip with vsync */ init_waitqueue_head(&ps3fb.wait_vsync); - ps3fb_set_sync(&dev->core); +#ifdef HEAD_A + status = lv1_gpu_context_attribute(0x0, + L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC, + 0, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0); + if (status) { + dev_err(&dev->core, + "%s: lv1_gpu_context_attribute DISPLAY_SYNC failed: " + "%d\n", + __func__, status); + goto err; + } +#endif +#ifdef HEAD_B + status = lv1_gpu_context_attribute(0x0, + L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC, + 1, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0); + + if (status) { + dev_err(&dev->core, + "%s: lv1_gpu_context_attribute DISPLAY_SYNC failed: " + "%d\n", + __func__, status); + goto err; + } +#endif max_ps3fb_size = _ALIGN_UP(GPU_IOIF, 256*1024*1024) - GPU_IOIF; if (ps3fb_videomemory.size > max_ps3fb_size) { @@ -1147,23 +1073,76 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) } /* vsync interrupt */ - ps3fb.dinfo = (void __force *)ioremap(lpar_driver_info, 128 * 1024); - if (!ps3fb.dinfo) { + dinfo = (void __force *)ioremap(lpar_driver_info, 128 * 1024); + if (!dinfo) { dev_err(&dev->core, "%s: ioremap failed\n", __func__); goto err_gpu_context_free; } - retval = ps3fb_vsync_settings(ps3fb.dinfo, &dev->core); - if (retval) + ps3fb.dinfo = dinfo; + dev_dbg(&dev->core, "version_driver:%x\n", dinfo->version_driver); + dev_dbg(&dev->core, "irq outlet:%x\n", dinfo->irq.irq_outlet); + dev_dbg(&dev->core, "version_gpu: %x memory_size: %x ch: %x " + "core_freq: %d mem_freq:%d\n", dinfo->version_gpu, + dinfo->memory_size, dinfo->hardware_channel, + dinfo->nvcore_frequency/1000000, + dinfo->memory_frequency/1000000); + + if (dinfo->version_driver != GPU_DRIVER_INFO_VERSION) { + dev_err(&dev->core, "%s: version_driver err:%x\n", __func__, + dinfo->version_driver); + retval = -EINVAL; goto err_iounmap_dinfo; + } + + retval = ps3_irq_plug_setup(PS3_BINDING_CPU_ANY, dinfo->irq.irq_outlet, + &ps3fb.irq_no); + if (retval) { + dev_err(&dev->core, "%s: ps3_alloc_irq failed %d\n", __func__, + retval); + goto err_iounmap_dinfo; + } + + retval = request_irq(ps3fb.irq_no, ps3fb_vsync_interrupt, + IRQF_DISABLED, DEVICE_NAME, &dev->core); + if (retval) { + dev_err(&dev->core, "%s: request_irq failed %d\n", __func__, + retval); + goto err_destroy_plug; + } + + dinfo->irq.mask = (1 << GPU_INTR_STATUS_VSYNC_1) | + (1 << GPU_INTR_STATUS_FLIP_1); /* Clear memory to prevent kernel info leakage into userspace */ memset(ps3fb_videomemory.address, 0, ps3fb_videomemory.size); xdr_lpar = ps3_mm_phys_to_lpar(__pa(ps3fb_videomemory.address)); - retval = ps3fb_xdr_settings(xdr_lpar, &dev->core); - if (retval) + + status = lv1_gpu_context_iomap(ps3fb.context_handle, GPU_IOIF, + xdr_lpar, ps3fb_videomemory.size, 0); + if (status) { + dev_err(&dev->core, "%s: lv1_gpu_context_iomap failed: %d\n", + __func__, status); + retval = -ENXIO; goto err_free_irq; + } + + dev_dbg(&dev->core, "video:%p ioif:%lx lpar:%llx size:%lx\n", + ps3fb_videomemory.address, GPU_IOIF, xdr_lpar, + ps3fb_videomemory.size); + + status = lv1_gpu_context_attribute(ps3fb.context_handle, + L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP, + xdr_lpar, GPU_CMD_BUF_SIZE, + GPU_IOIF, 0); + if (status) { + dev_err(&dev->core, + "%s: lv1_gpu_context_attribute FB_SETUP failed: %d\n", + __func__, status); + retval = -ENXIO; + goto err_free_irq; + } info = framebuffer_alloc(sizeof(struct ps3fb_par), &dev->core); if (!info) @@ -1234,6 +1213,7 @@ err_framebuffer_release: framebuffer_release(info); err_free_irq: free_irq(ps3fb.irq_no, &dev->core); +err_destroy_plug: ps3_irq_plug_destroy(ps3fb.irq_no); err_iounmap_dinfo: iounmap((u8 __force __iomem *)ps3fb.dinfo); From ca971ea39fa92add0fa596ad80affd7db781d762 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 10 Jun 2009 04:38:44 +0000 Subject: [PATCH 09/38] ps3fb: Correct handling of device opening in ps3fb_probe() - ps3_open_hv_device() returns a standard error value, - Add missing call to ps3_close_hv_device() in the error path. Signed-off-by: Geert Uytterhoeven Cc: linux-fbdev-devel@lists.sourceforge.net Signed-off-by: Benjamin Herrenschmidt --- drivers/video/ps3fb.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/video/ps3fb.c b/drivers/video/ps3fb.c index a74501815333..542ffc306c72 100644 --- a/drivers/video/ps3fb.c +++ b/drivers/video/ps3fb.c @@ -985,7 +985,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) { struct fb_info *info; struct ps3fb_par *par; - int retval = -ENOMEM; + int retval; u64 ddr_lpar = 0; u64 lpar_dma_control = 0; u64 lpar_driver_info = 0; @@ -1003,8 +1003,8 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) return -ENOMEM; } - status = ps3_open_hv_device(dev); - if (status) { + retval = ps3_open_hv_device(dev); + if (retval) { dev_err(&dev->core, "%s: ps3_open_hv_device failed\n", __func__); goto err; @@ -1027,7 +1027,8 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) "%s: lv1_gpu_context_attribute DISPLAY_SYNC failed: " "%d\n", __func__, status); - goto err; + retval = -ENODEV; + goto err_close_device; } #endif #ifdef HEAD_B @@ -1040,7 +1041,8 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) "%s: lv1_gpu_context_attribute DISPLAY_SYNC failed: " "%d\n", __func__, status); - goto err; + retval = -ENODEV; + goto err_close_device; } #endif @@ -1057,7 +1059,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) if (status) { dev_err(&dev->core, "%s: lv1_gpu_memory_allocate failed: %d\n", __func__, status); - goto err; + goto err_close_device; } dev_dbg(&dev->core, "ddr:lpar:0x%llx\n", ddr_lpar); @@ -1221,6 +1223,8 @@ err_gpu_context_free: lv1_gpu_context_free(ps3fb.context_handle); err_gpu_memory_free: lv1_gpu_memory_free(ps3fb.memory_handle); +err_close_device: + ps3_close_hv_device(dev); err: return retval; } From 5c6fc8db768fb9990ee67ab052896fd46fbe2651 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 10 Jun 2009 04:38:45 +0000 Subject: [PATCH 10/38] powerpc/cell: Extract duplicated IOPTE_* to Both arch/powerpc/platforms/cell/iommu.c and arch/powerpc/platforms/ps3/mm.c contain the same Cell IOMMU page table entry definitions. Extract them and move them to , while adding a CBE_ prefix. This also allows them to be used by drivers. Signed-off-by: Geert Uytterhoeven Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/include/asm/iommu.h | 10 +++++++ arch/powerpc/platforms/cell/iommu.c | 37 ++++++++++--------------- arch/powerpc/platforms/ps3/mm.c | 7 +++-- arch/powerpc/platforms/ps3/platform.h | 10 ------- arch/powerpc/platforms/ps3/system-bus.c | 15 ++++++---- 5 files changed, 39 insertions(+), 40 deletions(-) diff --git a/arch/powerpc/include/asm/iommu.h b/arch/powerpc/include/asm/iommu.h index 7464c0daddd1..7ead7c16fb7c 100644 --- a/arch/powerpc/include/asm/iommu.h +++ b/arch/powerpc/include/asm/iommu.h @@ -35,6 +35,16 @@ #define IOMMU_PAGE_MASK (~((1 << IOMMU_PAGE_SHIFT) - 1)) #define IOMMU_PAGE_ALIGN(addr) _ALIGN_UP(addr, IOMMU_PAGE_SIZE) +/* Cell page table entries */ +#define CBE_IOPTE_PP_W 0x8000000000000000ul /* protection: write */ +#define CBE_IOPTE_PP_R 0x4000000000000000ul /* protection: read */ +#define CBE_IOPTE_M 0x2000000000000000ul /* coherency required */ +#define CBE_IOPTE_SO_R 0x1000000000000000ul /* ordering: writes */ +#define CBE_IOPTE_SO_RW 0x1800000000000000ul /* ordering: r & w */ +#define CBE_IOPTE_RPN_Mask 0x07fffffffffff000ul /* RPN */ +#define CBE_IOPTE_H 0x0000000000000800ul /* cache hint */ +#define CBE_IOPTE_IOID_Mask 0x00000000000007fful /* ioid */ + /* Boot time flags */ extern int iommu_is_off; extern int iommu_force_on; diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c index bed4690de394..5b34fc211f35 100644 --- a/arch/powerpc/platforms/cell/iommu.c +++ b/arch/powerpc/platforms/cell/iommu.c @@ -100,16 +100,6 @@ #define IOSTE_PS_1M 0x0000000000000005ul /* - 1MB */ #define IOSTE_PS_16M 0x0000000000000007ul /* - 16MB */ -/* Page table entries */ -#define IOPTE_PP_W 0x8000000000000000ul /* protection: write */ -#define IOPTE_PP_R 0x4000000000000000ul /* protection: read */ -#define IOPTE_M 0x2000000000000000ul /* coherency required */ -#define IOPTE_SO_R 0x1000000000000000ul /* ordering: writes */ -#define IOPTE_SO_RW 0x1800000000000000ul /* ordering: r & w */ -#define IOPTE_RPN_Mask 0x07fffffffffff000ul /* RPN */ -#define IOPTE_H 0x0000000000000800ul /* cache hint */ -#define IOPTE_IOID_Mask 0x00000000000007fful /* ioid */ - /* IOMMU sizing */ #define IO_SEGMENT_SHIFT 28 @@ -193,19 +183,21 @@ static int tce_build_cell(struct iommu_table *tbl, long index, long npages, */ const unsigned long prot = 0xc48; base_pte = - ((prot << (52 + 4 * direction)) & (IOPTE_PP_W | IOPTE_PP_R)) - | IOPTE_M | IOPTE_SO_RW | (window->ioid & IOPTE_IOID_Mask); + ((prot << (52 + 4 * direction)) & + (CBE_IOPTE_PP_W | CBE_IOPTE_PP_R)) | + CBE_IOPTE_M | CBE_IOPTE_SO_RW | + (window->ioid & CBE_IOPTE_IOID_Mask); #else - base_pte = IOPTE_PP_W | IOPTE_PP_R | IOPTE_M | IOPTE_SO_RW | - (window->ioid & IOPTE_IOID_Mask); + base_pte = CBE_IOPTE_PP_W | CBE_IOPTE_PP_R | CBE_IOPTE_M | + CBE_IOPTE_SO_RW | (window->ioid & CBE_IOPTE_IOID_Mask); #endif if (unlikely(dma_get_attr(DMA_ATTR_WEAK_ORDERING, attrs))) - base_pte &= ~IOPTE_SO_RW; + base_pte &= ~CBE_IOPTE_SO_RW; io_pte = (unsigned long *)tbl->it_base + (index - tbl->it_offset); for (i = 0; i < npages; i++, uaddr += IOMMU_PAGE_SIZE) - io_pte[i] = base_pte | (__pa(uaddr) & IOPTE_RPN_Mask); + io_pte[i] = base_pte | (__pa(uaddr) & CBE_IOPTE_RPN_Mask); mb(); @@ -231,8 +223,9 @@ static void tce_free_cell(struct iommu_table *tbl, long index, long npages) #else /* spider bridge does PCI reads after freeing - insert a mapping * to a scratch page instead of an invalid entry */ - pte = IOPTE_PP_R | IOPTE_M | IOPTE_SO_RW | __pa(window->iommu->pad_page) - | (window->ioid & IOPTE_IOID_Mask); + pte = CBE_IOPTE_PP_R | CBE_IOPTE_M | CBE_IOPTE_SO_RW | + __pa(window->iommu->pad_page) | + (window->ioid & CBE_IOPTE_IOID_Mask); #endif io_pte = (unsigned long *)tbl->it_base + (index - tbl->it_offset); @@ -1001,7 +994,7 @@ static void insert_16M_pte(unsigned long addr, unsigned long *ptab, pr_debug("iommu: addr %lx ptab %p segment %lx offset %lx\n", addr, ptab, segment, offset); - ptab[offset] = base_pte | (__pa(addr) & IOPTE_RPN_Mask); + ptab[offset] = base_pte | (__pa(addr) & CBE_IOPTE_RPN_Mask); } static void cell_iommu_setup_fixed_ptab(struct cbe_iommu *iommu, @@ -1016,14 +1009,14 @@ static void cell_iommu_setup_fixed_ptab(struct cbe_iommu *iommu, pr_debug("iommu: mapping 0x%lx pages from 0x%lx\n", fsize, fbase); - base_pte = IOPTE_PP_W | IOPTE_PP_R | IOPTE_M - | (cell_iommu_get_ioid(np) & IOPTE_IOID_Mask); + base_pte = CBE_IOPTE_PP_W | CBE_IOPTE_PP_R | CBE_IOPTE_M | + (cell_iommu_get_ioid(np) & CBE_IOPTE_IOID_Mask); if (iommu_fixed_is_weak) pr_info("IOMMU: Using weak ordering for fixed mapping\n"); else { pr_info("IOMMU: Using strong ordering for fixed mapping\n"); - base_pte |= IOPTE_SO_RW; + base_pte |= CBE_IOPTE_SO_RW; } for (uaddr = 0; uaddr < fsize; uaddr += (1 << 24)) { diff --git a/arch/powerpc/platforms/ps3/mm.c b/arch/powerpc/platforms/ps3/mm.c index 9a2b6d948610..017b6142caca 100644 --- a/arch/powerpc/platforms/ps3/mm.c +++ b/arch/powerpc/platforms/ps3/mm.c @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -1001,7 +1002,8 @@ static int dma_sb_region_create_linear(struct ps3_dma_region *r) if (len > r->len) len = r->len; result = dma_sb_map_area(r, virt_addr, len, &tmp, - IOPTE_PP_W | IOPTE_PP_R | IOPTE_SO_RW | IOPTE_M); + CBE_IOPTE_PP_W | CBE_IOPTE_PP_R | CBE_IOPTE_SO_RW | + CBE_IOPTE_M); BUG_ON(result); } @@ -1014,7 +1016,8 @@ static int dma_sb_region_create_linear(struct ps3_dma_region *r) else len -= map.rm.size - r->offset; result = dma_sb_map_area(r, virt_addr, len, &tmp, - IOPTE_PP_W | IOPTE_PP_R | IOPTE_SO_RW | IOPTE_M); + CBE_IOPTE_PP_W | CBE_IOPTE_PP_R | CBE_IOPTE_SO_RW | + CBE_IOPTE_M); BUG_ON(result); } diff --git a/arch/powerpc/platforms/ps3/platform.h b/arch/powerpc/platforms/ps3/platform.h index 136aa0637d9c..9a196a88eda7 100644 --- a/arch/powerpc/platforms/ps3/platform.h +++ b/arch/powerpc/platforms/ps3/platform.h @@ -232,14 +232,4 @@ int ps3_repository_read_spu_resource_id(unsigned int res_index, int ps3_repository_read_vuart_av_port(unsigned int *port); int ps3_repository_read_vuart_sysmgr_port(unsigned int *port); -/* Page table entries */ -#define IOPTE_PP_W 0x8000000000000000ul /* protection: write */ -#define IOPTE_PP_R 0x4000000000000000ul /* protection: read */ -#define IOPTE_M 0x2000000000000000ul /* coherency required */ -#define IOPTE_SO_R 0x1000000000000000ul /* ordering: writes */ -#define IOPTE_SO_RW 0x1800000000000000ul /* ordering: r & w */ -#define IOPTE_RPN_Mask 0x07fffffffffff000ul /* RPN */ -#define IOPTE_H 0x0000000000000800ul /* cache hint */ -#define IOPTE_IOID_Mask 0x00000000000007fful /* ioid */ - #endif diff --git a/arch/powerpc/platforms/ps3/system-bus.c b/arch/powerpc/platforms/ps3/system-bus.c index 9a73d0238639..9fead0faf38b 100644 --- a/arch/powerpc/platforms/ps3/system-bus.c +++ b/arch/powerpc/platforms/ps3/system-bus.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "platform.h" @@ -531,7 +532,8 @@ static void * ps3_alloc_coherent(struct device *_dev, size_t size, } result = ps3_dma_map(dev->d_region, virt_addr, size, dma_handle, - IOPTE_PP_W | IOPTE_PP_R | IOPTE_SO_RW | IOPTE_M); + CBE_IOPTE_PP_W | CBE_IOPTE_PP_R | + CBE_IOPTE_SO_RW | CBE_IOPTE_M); if (result) { pr_debug("%s:%d: ps3_dma_map failed (%d)\n", @@ -575,7 +577,8 @@ static dma_addr_t ps3_sb_map_page(struct device *_dev, struct page *page, result = ps3_dma_map(dev->d_region, (unsigned long)ptr, size, &bus_addr, - IOPTE_PP_R | IOPTE_PP_W | IOPTE_SO_RW | IOPTE_M); + CBE_IOPTE_PP_R | CBE_IOPTE_PP_W | + CBE_IOPTE_SO_RW | CBE_IOPTE_M); if (result) { pr_debug("%s:%d: ps3_dma_map failed (%d)\n", @@ -596,16 +599,16 @@ static dma_addr_t ps3_ioc0_map_page(struct device *_dev, struct page *page, u64 iopte_flag; void *ptr = page_address(page) + offset; - iopte_flag = IOPTE_M; + iopte_flag = CBE_IOPTE_M; switch (direction) { case DMA_BIDIRECTIONAL: - iopte_flag |= IOPTE_PP_R | IOPTE_PP_W | IOPTE_SO_RW; + iopte_flag |= CBE_IOPTE_PP_R | CBE_IOPTE_PP_W | CBE_IOPTE_SO_RW; break; case DMA_TO_DEVICE: - iopte_flag |= IOPTE_PP_R | IOPTE_SO_R; + iopte_flag |= CBE_IOPTE_PP_R | CBE_IOPTE_SO_R; break; case DMA_FROM_DEVICE: - iopte_flag |= IOPTE_PP_W | IOPTE_SO_RW; + iopte_flag |= CBE_IOPTE_PP_W | CBE_IOPTE_SO_RW; break; default: /* not happned */ From e78d0c5c14ab91648274b2c5e6c4c35f072cea64 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 10 Jun 2009 04:38:46 +0000 Subject: [PATCH 11/38] ps3fb: GPU memory mapping cleanup - Make the IOMMU flags used for mapping main memory into the GPU's I/O space explicit, instead of relying on the default in the hypervisor, - Add missing calls to lv1_gpu_context_iomap(..., CBE_IOPTE_M) to unmap the memory during cleanup. Signed-off-by: Geert Uytterhoeven Cc: linux-fbdev-devel@lists.sourceforge.net Signed-off-by: Benjamin Herrenschmidt --- drivers/video/ps3fb.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/video/ps3fb.c b/drivers/video/ps3fb.c index 542ffc306c72..a61c1d89bd87 100644 --- a/drivers/video/ps3fb.c +++ b/drivers/video/ps3fb.c @@ -32,6 +32,7 @@ #include #include +#include #include #include #include @@ -1122,7 +1123,9 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) xdr_lpar = ps3_mm_phys_to_lpar(__pa(ps3fb_videomemory.address)); status = lv1_gpu_context_iomap(ps3fb.context_handle, GPU_IOIF, - xdr_lpar, ps3fb_videomemory.size, 0); + xdr_lpar, ps3fb_videomemory.size, + CBE_IOPTE_PP_W | CBE_IOPTE_PP_R | + CBE_IOPTE_M); if (status) { dev_err(&dev->core, "%s: lv1_gpu_context_iomap failed: %d\n", __func__, status); @@ -1143,12 +1146,12 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) "%s: lv1_gpu_context_attribute FB_SETUP failed: %d\n", __func__, status); retval = -ENXIO; - goto err_free_irq; + goto err_context_unmap; } info = framebuffer_alloc(sizeof(struct ps3fb_par), &dev->core); if (!info) - goto err_free_irq; + goto err_context_unmap; par = info->par; par->mode_id = ~ps3fb_mode; /* != ps3fb_mode, to trigger change */ @@ -1213,6 +1216,9 @@ err_fb_dealloc: fb_dealloc_cmap(&info->cmap); err_framebuffer_release: framebuffer_release(info); +err_context_unmap: + lv1_gpu_context_iomap(ps3fb.context_handle, GPU_IOIF, xdr_lpar, + ps3fb_videomemory.size, CBE_IOPTE_M); err_free_irq: free_irq(ps3fb.irq_no, &dev->core); err_destroy_plug: @@ -1232,6 +1238,7 @@ err: static int ps3fb_shutdown(struct ps3_system_bus_device *dev) { struct fb_info *info = dev->core.driver_data; + u64 xdr_lpar = ps3_mm_phys_to_lpar(__pa(ps3fb_videomemory.address)); dev_dbg(&dev->core, " -> %s:%d\n", __func__, __LINE__); @@ -1254,6 +1261,8 @@ static int ps3fb_shutdown(struct ps3_system_bus_device *dev) info = dev->core.driver_data = NULL; } iounmap((u8 __force __iomem *)ps3fb.dinfo); + lv1_gpu_context_iomap(ps3fb.context_handle, GPU_IOIF, xdr_lpar, + ps3fb_videomemory.size, CBE_IOPTE_M); lv1_gpu_context_free(ps3fb.context_handle); lv1_gpu_memory_free(ps3fb.memory_handle); ps3_close_hv_device(dev); From 56ac72dba5d24a477d281b985797d5e62d3f5c2e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 10 Jun 2009 04:38:47 +0000 Subject: [PATCH 12/38] ps3vram: GPU memory mapping cleanup - Make the IOMMU flags used for mapping main memory into the GPU's I/O space explicit, instead of relying on the default in the hypervisor, - Add missing calls to lv1_gpu_context_iomap(..., CBE_IOPTE_M) to unmap the memory during cleanup. Signed-off-by: Geert Uytterhoeven Cc: Jim Paris Cc: Jens Axboe Signed-off-by: Benjamin Herrenschmidt --- drivers/block/ps3vram.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/drivers/block/ps3vram.c b/drivers/block/ps3vram.c index 3c9ad1959a69..83c14533aea5 100644 --- a/drivers/block/ps3vram.c +++ b/drivers/block/ps3vram.c @@ -14,6 +14,7 @@ #include #include +#include #include #include @@ -603,8 +604,8 @@ static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev) int error, status; struct request_queue *queue; struct gendisk *gendisk; - u64 ddr_lpar, ctrl_lpar, info_lpar, reports_lpar, ddr_size, - reports_size; + u64 ddr_size, ddr_lpar, ctrl_lpar, info_lpar, reports_lpar, + reports_size, xdr_lpar; char *rest; priv = kzalloc(sizeof(*priv), GFP_KERNEL); @@ -675,9 +676,11 @@ static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev) } /* Map XDR buffer to RSX */ + xdr_lpar = ps3_mm_phys_to_lpar(__pa(priv->xdr_buf)); status = lv1_gpu_context_iomap(priv->context_handle, XDR_IOIF, - ps3_mm_phys_to_lpar(__pa(priv->xdr_buf)), - XDR_BUF_SIZE, 0); + xdr_lpar, XDR_BUF_SIZE, + CBE_IOPTE_PP_W | CBE_IOPTE_PP_R | + CBE_IOPTE_M); if (status) { dev_err(&dev->core, "lv1_gpu_context_iomap failed %d\n", status); @@ -690,7 +693,7 @@ static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev) if (!priv->ddr_base) { dev_err(&dev->core, "ioremap DDR failed\n"); error = -ENOMEM; - goto out_free_context; + goto out_unmap_context; } priv->ctrl = ioremap(ctrl_lpar, 64 * 1024); @@ -776,6 +779,9 @@ out_unmap_ctrl: iounmap(priv->ctrl); out_unmap_vram: iounmap(priv->ddr_base); +out_unmap_context: + lv1_gpu_context_iomap(priv->context_handle, XDR_IOIF, xdr_lpar, + XDR_BUF_SIZE, CBE_IOPTE_M); out_free_context: lv1_gpu_context_free(priv->context_handle); out_free_memory: @@ -803,6 +809,9 @@ static int ps3vram_remove(struct ps3_system_bus_device *dev) iounmap(priv->reports); iounmap(priv->ctrl); iounmap(priv->ddr_base); + lv1_gpu_context_iomap(priv->context_handle, XDR_IOIF, + ps3_mm_phys_to_lpar(__pa(priv->xdr_buf)), + XDR_BUF_SIZE, CBE_IOPTE_M); lv1_gpu_context_free(priv->context_handle); lv1_gpu_memory_free(priv->memory_handle); ps3_close_hv_device(dev); From d3352c9f1e8e2f2989d9686c8aa8acb4842fe75e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 10 Jun 2009 04:38:48 +0000 Subject: [PATCH 13/38] ps3fb/vram: Extract common GPU stuff into Signed-off-by: Geert Uytterhoeven Cc: linux-fbdev-devel@lists.sourceforge.net Cc: Jim Paris Cc: Jens Axboe Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/include/asm/ps3.h | 3 -- arch/powerpc/include/asm/ps3gpu.h | 78 ++++++++++++++++++++++++++++++ arch/powerpc/platforms/ps3/setup.c | 1 + drivers/block/ps3vram.c | 21 +++----- drivers/ps3/ps3av_cmd.c | 3 +- drivers/video/ps3fb.c | 72 +++++++++------------------ 6 files changed, 110 insertions(+), 68 deletions(-) create mode 100644 arch/powerpc/include/asm/ps3gpu.h diff --git a/arch/powerpc/include/asm/ps3.h b/arch/powerpc/include/asm/ps3.h index cdb6fd814de8..b9e4987986dd 100644 --- a/arch/powerpc/include/asm/ps3.h +++ b/arch/powerpc/include/asm/ps3.h @@ -520,7 +520,4 @@ void ps3_sync_irq(int node); u32 ps3_get_hw_thread_id(int cpu); u64 ps3_get_spe_id(void *arg); -/* mutex synchronizing GPU accesses and video mode changes */ -extern struct mutex ps3_gpu_mutex; - #endif diff --git a/arch/powerpc/include/asm/ps3gpu.h b/arch/powerpc/include/asm/ps3gpu.h new file mode 100644 index 000000000000..1037efae4a51 --- /dev/null +++ b/arch/powerpc/include/asm/ps3gpu.h @@ -0,0 +1,78 @@ +/* + * PS3 GPU declarations. + * + * Copyright 2009 Sony Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. + * If not, see . + */ + +#ifndef _ASM_POWERPC_PS3GPU_H +#define _ASM_POWERPC_PS3GPU_H + +#include + +#include + + +#define L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC 0x101 +#define L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP 0x102 + +#define L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP 0x600 +#define L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT 0x601 +#define L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT_SYNC 0x602 + +#define L1GPU_FB_BLIT_WAIT_FOR_COMPLETION (1ULL << 32) + +#define L1GPU_DISPLAY_SYNC_HSYNC 1 +#define L1GPU_DISPLAY_SYNC_VSYNC 2 + + +/* mutex synchronizing GPU accesses and video mode changes */ +extern struct mutex ps3_gpu_mutex; + + +static inline int lv1_gpu_display_sync(u64 context_handle, u64 head, + u64 ddr_offset) +{ + return lv1_gpu_context_attribute(context_handle, + L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC, + head, ddr_offset, 0, 0); +} + +static inline int lv1_gpu_display_flip(u64 context_handle, u64 head, + u64 ddr_offset) +{ + return lv1_gpu_context_attribute(context_handle, + L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP, + head, ddr_offset, 0, 0); +} + +static inline int lv1_gpu_fb_setup(u64 context_handle, u64 xdr_lpar, + u64 xdr_size, u64 ioif_offset) +{ + return lv1_gpu_context_attribute(context_handle, + L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP, + xdr_lpar, xdr_size, ioif_offset, 0); +} + +static inline int lv1_gpu_fb_blit(u64 context_handle, u64 ddr_offset, + u64 ioif_offset, u64 sync_width, u64 pitch) +{ + return lv1_gpu_context_attribute(context_handle, + L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT, + ddr_offset, ioif_offset, sync_width, + pitch); +} + +#endif /* _ASM_POWERPC_PS3GPU_H */ diff --git a/arch/powerpc/platforms/ps3/setup.c b/arch/powerpc/platforms/ps3/setup.c index 1a7b5ae0c83e..149bea2ce583 100644 --- a/arch/powerpc/platforms/ps3/setup.c +++ b/arch/powerpc/platforms/ps3/setup.c @@ -32,6 +32,7 @@ #include #include #include +#include #include "platform.h" diff --git a/drivers/block/ps3vram.c b/drivers/block/ps3vram.c index 83c14533aea5..2c2ea9cb207b 100644 --- a/drivers/block/ps3vram.c +++ b/drivers/block/ps3vram.c @@ -17,6 +17,7 @@ #include #include #include +#include #define DEVICE_NAME "ps3vram" @@ -46,8 +47,6 @@ #define NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN 0x0000030c #define NV_MEMORY_TO_MEMORY_FORMAT_NOTIFY 0x00000104 -#define L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT 0x601 - #define CACHE_PAGE_PRESENT 1 #define CACHE_PAGE_DIRTY 2 @@ -184,13 +183,10 @@ static void ps3vram_rewind_ring(struct ps3_system_bus_device *dev) priv->ctrl[CTRL_PUT] = FIFO_BASE + FIFO_OFFSET; /* asking the HV for a blit will kick the FIFO */ - status = lv1_gpu_context_attribute(priv->context_handle, - L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT, 0, - 0, 0, 0); + status = lv1_gpu_fb_blit(priv->context_handle, 0, 0, 0, 0); if (status) - dev_err(&dev->core, - "%s: lv1_gpu_context_attribute failed %d\n", __func__, - status); + dev_err(&dev->core, "%s: lv1_gpu_fb_blit failed %d\n", + __func__, status); priv->fifo_ptr = priv->fifo_base; } @@ -206,13 +202,10 @@ static void ps3vram_fire_ring(struct ps3_system_bus_device *dev) (priv->fifo_ptr - priv->fifo_base) * sizeof(u32); /* asking the HV for a blit will kick the FIFO */ - status = lv1_gpu_context_attribute(priv->context_handle, - L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT, 0, - 0, 0, 0); + status = lv1_gpu_fb_blit(priv->context_handle, 0, 0, 0, 0); if (status) - dev_err(&dev->core, - "%s: lv1_gpu_context_attribute failed %d\n", __func__, - status); + dev_err(&dev->core, "%s: lv1_gpu_fb_blit failed %d\n", + __func__, status); if ((priv->fifo_ptr - priv->fifo_base) * sizeof(u32) > FIFO_SIZE - 1024) { diff --git a/drivers/ps3/ps3av_cmd.c b/drivers/ps3/ps3av_cmd.c index 716596e8e5b0..f555fedd5073 100644 --- a/drivers/ps3/ps3av_cmd.c +++ b/drivers/ps3/ps3av_cmd.c @@ -21,9 +21,10 @@ #include #include #include + #include -#include #include +#include #include "vuart.h" diff --git a/drivers/video/ps3fb.c b/drivers/video/ps3fb.c index a61c1d89bd87..13c876c6e32c 100644 --- a/drivers/video/ps3fb.c +++ b/drivers/video/ps3fb.c @@ -37,21 +37,11 @@ #include #include #include +#include #define DEVICE_NAME "ps3fb" -#define L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC 0x101 -#define L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP 0x102 -#define L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP 0x600 -#define L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT 0x601 -#define L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT_SYNC 0x602 - -#define L1GPU_FB_BLIT_WAIT_FOR_COMPLETION (1ULL << 32) - -#define L1GPU_DISPLAY_SYNC_HSYNC 1 -#define L1GPU_DISPLAY_SYNC_VSYNC 2 - #define GPU_CMD_BUF_SIZE (2 * 1024 * 1024) #define GPU_FB_START (64 * 1024) #define GPU_IOIF (0x0d000000UL) @@ -463,33 +453,27 @@ static void ps3fb_sync_image(struct device *dev, u64 frame_offset, src_offset += GPU_FB_START; mutex_lock(&ps3_gpu_mutex); - status = lv1_gpu_context_attribute(ps3fb.context_handle, - L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT, - dst_offset, GPU_IOIF + src_offset, - L1GPU_FB_BLIT_WAIT_FOR_COMPLETION | - (width << 16) | height, - line_length); + status = lv1_gpu_fb_blit(ps3fb.context_handle, dst_offset, + GPU_IOIF + src_offset, + L1GPU_FB_BLIT_WAIT_FOR_COMPLETION | + (width << 16) | height, + line_length); mutex_unlock(&ps3_gpu_mutex); if (status) - dev_err(dev, - "%s: lv1_gpu_context_attribute FB_BLIT failed: %d\n", - __func__, status); + dev_err(dev, "%s: lv1_gpu_fb_blit failed: %d\n", __func__, + status); #ifdef HEAD_A - status = lv1_gpu_context_attribute(ps3fb.context_handle, - L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP, - 0, frame_offset, 0, 0); + status = lv1_gpu_display_flip(ps3fb.context_handle, 0, frame_offset); if (status) - dev_err(dev, "%s: lv1_gpu_context_attribute FLIP failed: %d\n", - __func__, status); + dev_err(dev, "%s: lv1_gpu_display_flip failed: %d\n", __func__, + status); #endif #ifdef HEAD_B - status = lv1_gpu_context_attribute(ps3fb.context_handle, - L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP, - 1, frame_offset, 0, 0); + status = lv1_gpu_display_flip(ps3fb.context_handle, 1, frame_offset); if (status) - dev_err(dev, "%s: lv1_gpu_context_attribute FLIP failed: %d\n", - __func__, status); + dev_err(dev, "%s: lv1_gpu_display_flip failed: %d\n", __func__, + status); #endif } @@ -1020,27 +1004,18 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) init_waitqueue_head(&ps3fb.wait_vsync); #ifdef HEAD_A - status = lv1_gpu_context_attribute(0x0, - L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC, - 0, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0); + status = lv1_gpu_display_sync(0x0, 0, L1GPU_DISPLAY_SYNC_VSYNC); if (status) { - dev_err(&dev->core, - "%s: lv1_gpu_context_attribute DISPLAY_SYNC failed: " - "%d\n", + dev_err(&dev->core, "%s: lv1_gpu_display_sync failed: %d\n", __func__, status); retval = -ENODEV; goto err_close_device; } #endif #ifdef HEAD_B - status = lv1_gpu_context_attribute(0x0, - L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC, - 1, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0); - + status = lv1_gpu_display_sync(0x0, 1, L1GPU_DISPLAY_SYNC_VSYNC); if (status) { - dev_err(&dev->core, - "%s: lv1_gpu_context_attribute DISPLAY_SYNC failed: " - "%d\n", + dev_err(&dev->core, "%s: lv1_gpu_display_sync failed: %d\n", __func__, status); retval = -ENODEV; goto err_close_device; @@ -1070,7 +1045,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) &lpar_reports, &lpar_reports_size); if (status) { dev_err(&dev->core, - "%s: lv1_gpu_context_attribute failed: %d\n", __func__, + "%s: lv1_gpu_context_allocate failed: %d\n", __func__, status); goto err_gpu_memory_free; } @@ -1137,13 +1112,10 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) ps3fb_videomemory.address, GPU_IOIF, xdr_lpar, ps3fb_videomemory.size); - status = lv1_gpu_context_attribute(ps3fb.context_handle, - L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP, - xdr_lpar, GPU_CMD_BUF_SIZE, - GPU_IOIF, 0); + status = lv1_gpu_fb_setup(ps3fb.context_handle, xdr_lpar, + GPU_CMD_BUF_SIZE, GPU_IOIF); if (status) { - dev_err(&dev->core, - "%s: lv1_gpu_context_attribute FB_SETUP failed: %d\n", + dev_err(&dev->core, "%s: lv1_gpu_fb_setup failed: %d\n", __func__, status); retval = -ENXIO; goto err_context_unmap; From c204ff65590837e6a9c50ca549497b4682682ec6 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 10 Jun 2009 04:38:49 +0000 Subject: [PATCH 14/38] ps3fb: Tear down FB setup during cleanup During cleanup, use L1GPU_CONTEXT_ATTRIBUTE_FB_CLOSE to tear down the setup done by L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP. This allows unloading and reloading of ps3fb while the sound driver keeps the GPU open. Signed-off-by: Geert Uytterhoeven Cc: linux-fbdev-devel@lists.sourceforge.net Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/include/asm/ps3gpu.h | 8 ++++++++ drivers/video/ps3fb.c | 5 ++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/include/asm/ps3gpu.h b/arch/powerpc/include/asm/ps3gpu.h index 1037efae4a51..b2b89591907c 100644 --- a/arch/powerpc/include/asm/ps3gpu.h +++ b/arch/powerpc/include/asm/ps3gpu.h @@ -31,6 +31,7 @@ #define L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP 0x600 #define L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT 0x601 #define L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT_SYNC 0x602 +#define L1GPU_CONTEXT_ATTRIBUTE_FB_CLOSE 0x603 #define L1GPU_FB_BLIT_WAIT_FOR_COMPLETION (1ULL << 32) @@ -75,4 +76,11 @@ static inline int lv1_gpu_fb_blit(u64 context_handle, u64 ddr_offset, pitch); } +static inline int lv1_gpu_fb_close(u64 context_handle) +{ + return lv1_gpu_context_attribute(context_handle, + L1GPU_CONTEXT_ATTRIBUTE_FB_CLOSE, 0, + 0, 0, 0); +} + #endif /* _ASM_POWERPC_PS3GPU_H */ diff --git a/drivers/video/ps3fb.c b/drivers/video/ps3fb.c index 13c876c6e32c..1baa1c93a224 100644 --- a/drivers/video/ps3fb.c +++ b/drivers/video/ps3fb.c @@ -1123,7 +1123,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) info = framebuffer_alloc(sizeof(struct ps3fb_par), &dev->core); if (!info) - goto err_context_unmap; + goto err_context_fb_close; par = info->par; par->mode_id = ~ps3fb_mode; /* != ps3fb_mode, to trigger change */ @@ -1188,6 +1188,8 @@ err_fb_dealloc: fb_dealloc_cmap(&info->cmap); err_framebuffer_release: framebuffer_release(info); +err_context_fb_close: + lv1_gpu_fb_close(ps3fb.context_handle); err_context_unmap: lv1_gpu_context_iomap(ps3fb.context_handle, GPU_IOIF, xdr_lpar, ps3fb_videomemory.size, CBE_IOPTE_M); @@ -1233,6 +1235,7 @@ static int ps3fb_shutdown(struct ps3_system_bus_device *dev) info = dev->core.driver_data = NULL; } iounmap((u8 __force __iomem *)ps3fb.dinfo); + lv1_gpu_fb_close(ps3fb.context_handle); lv1_gpu_context_iomap(ps3fb.context_handle, GPU_IOIF, xdr_lpar, ps3fb_videomemory.size, CBE_IOPTE_M); lv1_gpu_context_free(ps3fb.context_handle); From e468455e5845f83950d1271a6cd0425b9c7290ab Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Wed, 10 Jun 2009 19:05:00 +0000 Subject: [PATCH 15/38] powerpc: Fix warning in setup_64.c when CONFIG_RELOCATABLE=y When CONFIG_RELOCATABLE is enabled, PHYSICAL_START is actually a variable of type phys_addr_t. That means to print it we need to cast to unsigned long long and use llx. Signed-off-by: Michael Ellerman Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/setup_64.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index f46548e66045..1f6816003ebe 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -424,8 +424,8 @@ void __init setup_system(void) printk("htab_hash_mask = 0x%lx\n", htab_hash_mask); #endif /* CONFIG_PPC_STD_MMU_64 */ if (PHYSICAL_START > 0) - printk("physical_start = 0x%lx\n", - PHYSICAL_START); + printk("physical_start = 0x%llx\n", + (unsigned long long)PHYSICAL_START); printk("-----------------------------------------------------\n"); DBG(" <- setup_system()\n"); From 86c276560a22915c92cd0b0179556b7f3dac6f7a Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Wed, 10 Jun 2009 19:06:34 +0000 Subject: [PATCH 16/38] powerpc/cell: Use driver_data acessors, not platform_data in Axon MSI The Axon MSI driver incorrectly uses platform_data, rather than the proper accessors for driver_data. Signed-off-by: Michael Ellerman Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/platforms/cell/axon_msi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c index 0ce45c2b42f8..c71498dbf211 100644 --- a/arch/powerpc/platforms/cell/axon_msi.c +++ b/arch/powerpc/platforms/cell/axon_msi.c @@ -329,7 +329,7 @@ static struct irq_host_ops msic_host_ops = { static int axon_msi_shutdown(struct of_device *device) { - struct axon_msic *msic = device->dev.platform_data; + struct axon_msic *msic = dev_get_drvdata(&device->dev); u32 tmp; pr_debug("axon_msi: disabling %s\n", @@ -416,7 +416,7 @@ static int axon_msi_probe(struct of_device *device, msic->read_offset = dcr_read(msic->dcr_host, MSIC_WRITE_OFFSET_REG) & MSIC_FIFO_SIZE_MASK; - device->dev.platform_data = msic; + dev_set_drvdata(&device->dev, msic); ppc_md.setup_msi_irqs = axon_msi_setup_msi_irqs; ppc_md.teardown_msi_irqs = axon_msi_teardown_msi_irqs; From 3240776ce290a3be4ca77bacf8b1e8d36b4a691d Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Wed, 10 Jun 2009 22:22:08 +0000 Subject: [PATCH 17/38] powerpc: Wire up sys_rt_tgsigqueueinfo Signed-off-by: Stephen Rothwell Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/include/asm/systbl.h | 1 + arch/powerpc/include/asm/unistd.h | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/include/asm/systbl.h b/arch/powerpc/include/asm/systbl.h index a0b92de51c7e..370600ca2765 100644 --- a/arch/powerpc/include/asm/systbl.h +++ b/arch/powerpc/include/asm/systbl.h @@ -325,3 +325,4 @@ SYSCALL(inotify_init1) SYSCALL_SPU(perf_counter_open) COMPAT_SYS_SPU(preadv) COMPAT_SYS_SPU(pwritev) +COMPAT_SYS(rt_tgsigqueueinfo) diff --git a/arch/powerpc/include/asm/unistd.h b/arch/powerpc/include/asm/unistd.h index 4badac2d11d1..cef080bfc607 100644 --- a/arch/powerpc/include/asm/unistd.h +++ b/arch/powerpc/include/asm/unistd.h @@ -344,10 +344,11 @@ #define __NR_perf_counter_open 319 #define __NR_preadv 320 #define __NR_pwritev 321 +#define __NR_rt_tgsigqueueinfo 322 #ifdef __KERNEL__ -#define __NR_syscalls 322 +#define __NR_syscalls 323 #define __NR__exit __NR_exit #define NR_syscalls __NR_syscalls From 7719ed7ce814aa89c6af082f6773dddc93c6f237 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Thu, 11 Jun 2009 02:12:28 +0000 Subject: [PATCH 18/38] powerpc: Only build prom_init.o when CONFIG_PPC_OF_BOOT_TRAMPOLINE=y Commit 28794d34 ("powerpc/kconfig: Kill PPC_MULTIPLATFORM"), added CONFIG_PPC_OF_BOOT_TRAMPOLINE to control the buliding of prom_init.o However the Makefile still unconditionally builds prom_init_check, the script that checks prom_init.o for symbol usage, and so in turn prom_init.o is still always being built. (it's not linked though) So surround all the prom_init_check logic with an ifeq block testing if CONFIG_PPC_OF_BOOT_TRAMPOLINE is set. Signed-off-by: Michael Ellerman Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index a7def5f90cad..612b0c4dc26d 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -125,6 +125,7 @@ PHONY += systbl_chk systbl_chk: $(src)/systbl_chk.sh $(obj)/systbl_chk.i $(call cmd,systbl_chk) +ifeq ($(CONFIG_PPC_OF_BOOT_TRAMPOLINE),y) $(obj)/built-in.o: prom_init_check quiet_cmd_prom_init_check = CALL $< @@ -133,5 +134,6 @@ quiet_cmd_prom_init_check = CALL $< PHONY += prom_init_check prom_init_check: $(src)/prom_init_check.sh $(obj)/prom_init.o $(call cmd,prom_init_check) +endif clean-files := vmlinux.lds From 27167c7e9bc3b4b93d1b567e0cf9a3744dd4f1f2 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Thu, 11 Jun 2009 02:18:26 +0000 Subject: [PATCH 19/38] powerpc/iseries: Fix unused function warning in iSeries DT code If CONFIG_BLK_DEV_INITRD is unset dt_prop_u64() is unused, which causes a warning. We don't really want to tie the definition to BLK_DEV_INITRD, so mark it as maybe unused. Signed-off-by: Michael Ellerman Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/platforms/iseries/dt.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/iseries/dt.c b/arch/powerpc/platforms/iseries/dt.c index 4543c4bc3a56..c5a87a72057b 100644 --- a/arch/powerpc/platforms/iseries/dt.c +++ b/arch/powerpc/platforms/iseries/dt.c @@ -204,7 +204,8 @@ static void __init dt_prop_u32(struct iseries_flat_dt *dt, const char *name, dt_prop(dt, name, &data, sizeof(u32)); } -static void __init dt_prop_u64(struct iseries_flat_dt *dt, const char *name, +static void __init __maybe_unused dt_prop_u64(struct iseries_flat_dt *dt, + const char *name, u64 data) { dt_prop(dt, name, &data, sizeof(u64)); From e8d1673b9720ec72d85916c6b7d5d476abb2c861 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Thu, 11 Jun 2009 02:18:49 +0000 Subject: [PATCH 20/38] powerpc/iseries: Mark signal_vsp_instruction() as maybe unused signal_vsp_instruction() is currently only used if CONFIG_PROC_FS is enabled. However logically it has nothing to do with PROC_FS, so rather than making it depend on that mark it as maybe unused. Signed-off-by: Michael Ellerman Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/platforms/iseries/mf.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/iseries/mf.c b/arch/powerpc/platforms/iseries/mf.c index 3689c2413d24..fef4d5150517 100644 --- a/arch/powerpc/platforms/iseries/mf.c +++ b/arch/powerpc/platforms/iseries/mf.c @@ -267,7 +267,8 @@ static struct pending_event *new_pending_event(void) return ev; } -static int signal_vsp_instruction(struct vsp_cmd_data *vsp_cmd) +static int __maybe_unused +signal_vsp_instruction(struct vsp_cmd_data *vsp_cmd) { struct pending_event *ev = new_pending_event(); int rc; From 4c75f84f2c781beb230031234ed961d28771a764 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Fri, 12 Jun 2009 02:00:50 +0000 Subject: [PATCH 21/38] powerpc: Add compiler memory barrier to mtmsr macro On 32-bit non-Book E, local_irq_restore() turns into just mtmsr(), which doesn't currently have a compiler memory barrier. This means that accesses to memory inside a local_irq_save/restore section, or a spin_lock_irqsave/spin_unlock_irqrestore section on UP, can be reordered by the compiler to occur outside that section. To fix this, this adds a compiler memory barrier to mtmsr for both 32-bit and 64-bit. Having a compiler memory barrier in mtmsr makes sense because it will almost always be changing something about the context in which memory accesses are done, so in general we don't want memory accesses getting moved from one side of an mtmsr to the other. With the barrier in mtmsr(), some of the explicit barriers in hw_irq.h are now redundant, so this removes them. Signed-off-by: Paul Mackerras Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/include/asm/hw_irq.h | 5 ++--- arch/powerpc/include/asm/reg.h | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/arch/powerpc/include/asm/hw_irq.h b/arch/powerpc/include/asm/hw_irq.h index 53512374e1c9..b7f8f4a87cc0 100644 --- a/arch/powerpc/include/asm/hw_irq.h +++ b/arch/powerpc/include/asm/hw_irq.h @@ -80,7 +80,7 @@ static inline void local_irq_disable(void) __asm__ __volatile__("wrteei 0": : :"memory"); #else unsigned long msr; - __asm__ __volatile__("": : :"memory"); + msr = mfmsr(); SET_MSR_EE(msr & ~MSR_EE); #endif @@ -92,7 +92,7 @@ static inline void local_irq_enable(void) __asm__ __volatile__("wrteei 1": : :"memory"); #else unsigned long msr; - __asm__ __volatile__("": : :"memory"); + msr = mfmsr(); SET_MSR_EE(msr | MSR_EE); #endif @@ -108,7 +108,6 @@ static inline void local_irq_save_ptr(unsigned long *flags) #else SET_MSR_EE(msr & ~MSR_EE); #endif - __asm__ __volatile__("": : :"memory"); } #define local_save_flags(flags) ((flags) = mfmsr()) diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index fb359b0a6937..a3c28e46947c 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h @@ -745,11 +745,11 @@ asm volatile("mfmsr %0" : "=r" (rval)); rval;}) #ifdef CONFIG_PPC64 #define __mtmsrd(v, l) asm volatile("mtmsrd %0," __stringify(l) \ - : : "r" (v)) + : : "r" (v) : "memory") #define mtmsrd(v) __mtmsrd((v), 0) #define mtmsr(v) mtmsrd(v) #else -#define mtmsr(v) asm volatile("mtmsr %0" : : "r" (v)) +#define mtmsr(v) asm volatile("mtmsr %0" : : "r" (v) : "memory") #endif #define mfspr(rn) ({unsigned long rval; \ From 09d4e0edd4614e787393acc582ac701c6ec3565b Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Fri, 12 Jun 2009 21:10:05 +0000 Subject: [PATCH 22/38] lib: Provide generic atomic64_t implementation Many processor architectures have no 64-bit atomic instructions, but we need atomic64_t in order to support the perf_counter subsystem. This adds an implementation of 64-bit atomic operations using hashed spinlocks to provide atomicity. For each atomic operation, the address of the atomic64_t variable is hashed to an index into an array of 16 spinlocks. That spinlock is taken (with interrupts disabled) around the operation, which can then be coded non-atomically within the lock. On UP, all the spinlock manipulation goes away and we simply disable interrupts around each operation. In fact gcc eliminates the whole atomic64_lock variable as well. Signed-off-by: Paul Mackerras Signed-off-by: Benjamin Herrenschmidt --- include/asm-generic/atomic64.h | 42 ++++++++ lib/Kconfig | 6 ++ lib/Makefile | 2 + lib/atomic64.c | 175 +++++++++++++++++++++++++++++++++ 4 files changed, 225 insertions(+) create mode 100644 include/asm-generic/atomic64.h create mode 100644 lib/atomic64.c diff --git a/include/asm-generic/atomic64.h b/include/asm-generic/atomic64.h new file mode 100644 index 000000000000..b18ce4f9ee3d --- /dev/null +++ b/include/asm-generic/atomic64.h @@ -0,0 +1,42 @@ +/* + * Generic implementation of 64-bit atomics using spinlocks, + * useful on processors that don't have 64-bit atomic instructions. + * + * Copyright © 2009 Paul Mackerras, IBM Corp. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#ifndef _ASM_GENERIC_ATOMIC64_H +#define _ASM_GENERIC_ATOMIC64_H + +typedef struct { + long long counter; +} atomic64_t; + +#define ATOMIC64_INIT(i) { (i) } + +extern long long atomic64_read(const atomic64_t *v); +extern void atomic64_set(atomic64_t *v, long long i); +extern void atomic64_add(long long a, atomic64_t *v); +extern long long atomic64_add_return(long long a, atomic64_t *v); +extern void atomic64_sub(long long a, atomic64_t *v); +extern long long atomic64_sub_return(long long a, atomic64_t *v); +extern long long atomic64_dec_if_positive(atomic64_t *v); +extern long long atomic64_cmpxchg(atomic64_t *v, long long o, long long n); +extern long long atomic64_xchg(atomic64_t *v, long long new); +extern int atomic64_add_unless(atomic64_t *v, long long a, long long u); + +#define atomic64_add_negative(a, v) (atomic64_add_return((a), (v)) < 0) +#define atomic64_inc(v) atomic64_add(1LL, (v)) +#define atomic64_inc_return(v) atomic64_add_return(1LL, (v)) +#define atomic64_inc_and_test(v) (atomic64_inc_return(v) == 0) +#define atomic64_sub_and_test(a, v) (atomic64_sub_return((a), (v)) == 0) +#define atomic64_dec(v) atomic64_sub(1LL, (v)) +#define atomic64_dec_return(v) atomic64_sub_return(1LL, (v)) +#define atomic64_dec_and_test(v) (atomic64_dec_return((v)) == 0) +#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1LL, 0LL) + +#endif /* _ASM_GENERIC_ATOMIC64_H */ diff --git a/lib/Kconfig b/lib/Kconfig index 9960be04cbbe..bb1326d3839c 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -194,4 +194,10 @@ config DISABLE_OBSOLETE_CPUMASK_FUNCTIONS config NLATTR bool +# +# Generic 64-bit atomic support is selected if needed +# +config GENERIC_ATOMIC64 + bool + endmenu diff --git a/lib/Makefile b/lib/Makefile index 34c5c0e6222e..8e9bcf9d3261 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -95,6 +95,8 @@ obj-$(CONFIG_DMA_API_DEBUG) += dma-debug.o obj-$(CONFIG_GENERIC_CSUM) += checksum.o +obj-$(CONFIG_GENERIC_ATOMIC64) += atomic64.o + hostprogs-y := gen_crc32table clean-files := crc32table.h diff --git a/lib/atomic64.c b/lib/atomic64.c new file mode 100644 index 000000000000..c5e725562416 --- /dev/null +++ b/lib/atomic64.c @@ -0,0 +1,175 @@ +/* + * Generic implementation of 64-bit atomics using spinlocks, + * useful on processors that don't have 64-bit atomic instructions. + * + * Copyright © 2009 Paul Mackerras, IBM Corp. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include +#include +#include +#include +#include + +/* + * We use a hashed array of spinlocks to provide exclusive access + * to each atomic64_t variable. Since this is expected to used on + * systems with small numbers of CPUs (<= 4 or so), we use a + * relatively small array of 16 spinlocks to avoid wasting too much + * memory on the spinlock array. + */ +#define NR_LOCKS 16 + +/* + * Ensure each lock is in a separate cacheline. + */ +static union { + spinlock_t lock; + char pad[L1_CACHE_BYTES]; +} atomic64_lock[NR_LOCKS] __cacheline_aligned_in_smp; + +static inline spinlock_t *lock_addr(const atomic64_t *v) +{ + unsigned long addr = (unsigned long) v; + + addr >>= L1_CACHE_SHIFT; + addr ^= (addr >> 8) ^ (addr >> 16); + return &atomic64_lock[addr & (NR_LOCKS - 1)].lock; +} + +long long atomic64_read(const atomic64_t *v) +{ + unsigned long flags; + spinlock_t *lock = lock_addr(v); + long long val; + + spin_lock_irqsave(lock, flags); + val = v->counter; + spin_unlock_irqrestore(lock, flags); + return val; +} + +void atomic64_set(atomic64_t *v, long long i) +{ + unsigned long flags; + spinlock_t *lock = lock_addr(v); + + spin_lock_irqsave(lock, flags); + v->counter = i; + spin_unlock_irqrestore(lock, flags); +} + +void atomic64_add(long long a, atomic64_t *v) +{ + unsigned long flags; + spinlock_t *lock = lock_addr(v); + + spin_lock_irqsave(lock, flags); + v->counter += a; + spin_unlock_irqrestore(lock, flags); +} + +long long atomic64_add_return(long long a, atomic64_t *v) +{ + unsigned long flags; + spinlock_t *lock = lock_addr(v); + long long val; + + spin_lock_irqsave(lock, flags); + val = v->counter += a; + spin_unlock_irqrestore(lock, flags); + return val; +} + +void atomic64_sub(long long a, atomic64_t *v) +{ + unsigned long flags; + spinlock_t *lock = lock_addr(v); + + spin_lock_irqsave(lock, flags); + v->counter -= a; + spin_unlock_irqrestore(lock, flags); +} + +long long atomic64_sub_return(long long a, atomic64_t *v) +{ + unsigned long flags; + spinlock_t *lock = lock_addr(v); + long long val; + + spin_lock_irqsave(lock, flags); + val = v->counter -= a; + spin_unlock_irqrestore(lock, flags); + return val; +} + +long long atomic64_dec_if_positive(atomic64_t *v) +{ + unsigned long flags; + spinlock_t *lock = lock_addr(v); + long long val; + + spin_lock_irqsave(lock, flags); + val = v->counter - 1; + if (val >= 0) + v->counter = val; + spin_unlock_irqrestore(lock, flags); + return val; +} + +long long atomic64_cmpxchg(atomic64_t *v, long long o, long long n) +{ + unsigned long flags; + spinlock_t *lock = lock_addr(v); + long long val; + + spin_lock_irqsave(lock, flags); + val = v->counter; + if (val == o) + v->counter = n; + spin_unlock_irqrestore(lock, flags); + return val; +} + +long long atomic64_xchg(atomic64_t *v, long long new) +{ + unsigned long flags; + spinlock_t *lock = lock_addr(v); + long long val; + + spin_lock_irqsave(lock, flags); + val = v->counter; + v->counter = new; + spin_unlock_irqrestore(lock, flags); + return val; +} + +int atomic64_add_unless(atomic64_t *v, long long a, long long u) +{ + unsigned long flags; + spinlock_t *lock = lock_addr(v); + int ret = 1; + + spin_lock_irqsave(lock, flags); + if (v->counter != u) { + v->counter += a; + ret = 0; + } + spin_unlock_irqrestore(lock, flags); + return ret; +} + +static int init_atomic64_lock(void) +{ + int i; + + for (i = 0; i < NR_LOCKS; ++i) + spin_lock_init(&atomic64_lock[i].lock); + return 0; +} + +pure_initcall(init_atomic64_lock); From c2e95c6d7a9b9d8f023c3639edbb1da65ccd15ac Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Fri, 12 Jun 2009 21:10:41 +0000 Subject: [PATCH 23/38] powerpc: Use generic atomic64_t implementation on 32-bit processors This makes 32-bit powerpc use the generic atomic64_t implementation. Signed-off-by: Paul Mackerras Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/Kconfig | 1 + arch/powerpc/include/asm/atomic.h | 3 +++ 2 files changed, 4 insertions(+) diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index eae0c2bbbf38..9fb344d5a86a 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -125,6 +125,7 @@ config PPC select USE_GENERIC_SMP_HELPERS if SMP select HAVE_OPROFILE select HAVE_SYSCALL_WRAPPERS if PPC64 + select GENERIC_ATOMIC64 if PPC32 config EARLY_PRINTK bool diff --git a/arch/powerpc/include/asm/atomic.h b/arch/powerpc/include/asm/atomic.h index b7d2d07b6f96..4012483b1899 100644 --- a/arch/powerpc/include/asm/atomic.h +++ b/arch/powerpc/include/asm/atomic.h @@ -470,6 +470,9 @@ static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u) #define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0) +#else /* __powerpc64__ */ +#include + #endif /* __powerpc64__ */ #include From 13685a1654b65357fb34066a98ef40445f7820fc Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 10 Jun 2009 04:38:40 +0000 Subject: [PATCH 24/38] block: Add bio_list_peek() Introduce bio_list_peek(), to obtain a pointer to the first bio on the bio_list without actually removing it from the list. This is needed when you want to serialize based on the list being empty or not. Signed-off-by: Geert Uytterhoeven Acked-by: Jens Axboe Signed-off-by: Benjamin Herrenschmidt --- include/linux/bio.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/linux/bio.h b/include/linux/bio.h index 12737be58601..2a04eb54c0dd 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -590,6 +590,11 @@ static inline void bio_list_merge_head(struct bio_list *bl, bl->head = bl2->head; } +static inline struct bio *bio_list_peek(struct bio_list *bl) +{ + return bl->head; +} + static inline struct bio *bio_list_pop(struct bio_list *bl) { struct bio *bio = bl->head; From fb89e89d0ff6142f0616eb8260ea89d6fd924982 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 10 Jun 2009 04:38:41 +0000 Subject: [PATCH 25/38] ps3vram: Replace mutex by spinlock + bio_list Remove the mutex serializing access to the cache. Instead, queue up new requests on a bio_list if the driver is busy. This improves sequential write performance by ca. 2%. Signed-off-by: Geert Uytterhoeven Cc: Jim Paris Cc: Jens Axboe Signed-off-by: Benjamin Herrenschmidt --- drivers/block/ps3vram.c | 51 +++++++++++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 15 deletions(-) diff --git a/drivers/block/ps3vram.c b/drivers/block/ps3vram.c index 2c2ea9cb207b..7d1c742d6d66 100644 --- a/drivers/block/ps3vram.c +++ b/drivers/block/ps3vram.c @@ -81,8 +81,8 @@ struct ps3vram_priv { struct ps3vram_cache cache; - /* Used to serialize cache/DMA operations */ - struct mutex lock; + spinlock_t lock; /* protecting list of bios */ + struct bio_list list; }; @@ -443,8 +443,6 @@ static int ps3vram_read(struct ps3_system_bus_device *dev, loff_t from, offset = (unsigned int) (from & (priv->cache.page_size - 1)); avail = priv->cache.page_size - offset; - mutex_lock(&priv->lock); - entry = ps3vram_cache_match(dev, from); cached = CACHE_OFFSET + entry * priv->cache.page_size + offset; @@ -456,8 +454,6 @@ static int ps3vram_read(struct ps3_system_bus_device *dev, loff_t from, avail = count; memcpy(buf, priv->xdr_buf + cached, avail); - mutex_unlock(&priv->lock); - buf += avail; count -= avail; from += avail; @@ -488,8 +484,6 @@ static int ps3vram_write(struct ps3_system_bus_device *dev, loff_t to, offset = (unsigned int) (to & (priv->cache.page_size - 1)); avail = priv->cache.page_size - offset; - mutex_lock(&priv->lock); - entry = ps3vram_cache_match(dev, to); cached = CACHE_OFFSET + entry * priv->cache.page_size + offset; @@ -503,8 +497,6 @@ static int ps3vram_write(struct ps3_system_bus_device *dev, loff_t to, priv->cache.tags[entry].flags |= CACHE_PAGE_DIRTY; - mutex_unlock(&priv->lock); - buf += avail; count -= avail; to += avail; @@ -546,17 +538,17 @@ static void __devinit ps3vram_proc_init(struct ps3_system_bus_device *dev) dev_warn(&dev->core, "failed to create /proc entry\n"); } -static int ps3vram_make_request(struct request_queue *q, struct bio *bio) +static struct bio *ps3vram_do_bio(struct ps3_system_bus_device *dev, + struct bio *bio) { - struct ps3_system_bus_device *dev = q->queuedata; + struct ps3vram_priv *priv = dev->core.driver_data; int write = bio_data_dir(bio) == WRITE; const char *op = write ? "write" : "read"; loff_t offset = bio->bi_sector << 9; int error = 0; struct bio_vec *bvec; unsigned int i; - - dev_dbg(&dev->core, "%s\n", __func__); + struct bio *next; bio_for_each_segment(bvec, bio, i) { /* PS3 is ppc64, so we don't handle highmem */ @@ -587,7 +579,35 @@ static int ps3vram_make_request(struct request_queue *q, struct bio *bio) dev_dbg(&dev->core, "%s completed\n", op); out: + spin_lock_irq(&priv->lock); + bio_list_pop(&priv->list); + next = bio_list_peek(&priv->list); + spin_unlock_irq(&priv->lock); + bio_endio(bio, error); + return next; +} + +static int ps3vram_make_request(struct request_queue *q, struct bio *bio) +{ + struct ps3_system_bus_device *dev = q->queuedata; + struct ps3vram_priv *priv = dev->core.driver_data; + int busy; + + dev_dbg(&dev->core, "%s\n", __func__); + + spin_lock_irq(&priv->lock); + busy = !bio_list_empty(&priv->list); + bio_list_add(&priv->list, bio); + spin_unlock_irq(&priv->lock); + + if (busy) + return 0; + + do { + bio = ps3vram_do_bio(dev, bio); + } while (bio); + return 0; } @@ -607,7 +627,8 @@ static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev) goto fail; } - mutex_init(&priv->lock); + spin_lock_init(&priv->lock); + bio_list_init(&priv->list); dev->core.driver_data = priv; priv = dev->core.driver_data; From c3b94fd800cc7eb59c91ccb55326cdaf589b0e88 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 10 Jun 2009 04:38:50 +0000 Subject: [PATCH 26/38] ps3vram: Remove no longer used ps3vram_priv.ddr_base Signed-off-by: Geert Uytterhoeven Cc: Jim Paris Cc: Jens Axboe Signed-off-by: Benjamin Herrenschmidt --- drivers/block/ps3vram.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/drivers/block/ps3vram.c b/drivers/block/ps3vram.c index 7d1c742d6d66..5f408c6e5b20 100644 --- a/drivers/block/ps3vram.c +++ b/drivers/block/ps3vram.c @@ -73,7 +73,6 @@ struct ps3vram_priv { u64 context_handle; u32 *ctrl; u32 *reports; - u8 __iomem *ddr_base; u8 *xdr_buf; u32 *fifo_base; @@ -702,19 +701,11 @@ static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev) goto out_free_context; } - priv->ddr_base = ioremap_flags(ddr_lpar, ddr_size, _PAGE_NO_CACHE); - - if (!priv->ddr_base) { - dev_err(&dev->core, "ioremap DDR failed\n"); - error = -ENOMEM; - goto out_unmap_context; - } - priv->ctrl = ioremap(ctrl_lpar, 64 * 1024); if (!priv->ctrl) { dev_err(&dev->core, "ioremap CTRL failed\n"); error = -ENOMEM; - goto out_unmap_vram; + goto out_unmap_context; } priv->reports = ioremap(reports_lpar, reports_size); @@ -791,8 +782,6 @@ out_unmap_reports: iounmap(priv->reports); out_unmap_ctrl: iounmap(priv->ctrl); -out_unmap_vram: - iounmap(priv->ddr_base); out_unmap_context: lv1_gpu_context_iomap(priv->context_handle, XDR_IOIF, xdr_lpar, XDR_BUF_SIZE, CBE_IOPTE_M); @@ -822,7 +811,6 @@ static int ps3vram_remove(struct ps3_system_bus_device *dev) ps3vram_cache_cleanup(dev); iounmap(priv->reports); iounmap(priv->ctrl); - iounmap(priv->ddr_base); lv1_gpu_context_iomap(priv->context_handle, XDR_IOIF, ps3_mm_phys_to_lpar(__pa(priv->xdr_buf)), XDR_BUF_SIZE, CBE_IOPTE_M); From 1bd9784f5ebb5b1b5a1efb8302d7b57c6483e2e6 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 10 Jun 2009 04:38:51 +0000 Subject: [PATCH 27/38] ps3vram: Make ps3vram_priv.reports a void * So we can kill a cast. Signed-off-by: Geert Uytterhoeven Cc: Jim Paris Cc: Jens Axboe Signed-off-by: Benjamin Herrenschmidt --- drivers/block/ps3vram.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/block/ps3vram.c b/drivers/block/ps3vram.c index 5f408c6e5b20..fbbdd5ca5720 100644 --- a/drivers/block/ps3vram.c +++ b/drivers/block/ps3vram.c @@ -72,7 +72,7 @@ struct ps3vram_priv { u64 memory_handle; u64 context_handle; u32 *ctrl; - u32 *reports; + void *reports; u8 *xdr_buf; u32 *fifo_base; @@ -102,9 +102,9 @@ static char *size = "256M"; module_param(size, charp, 0); MODULE_PARM_DESC(size, "memory size"); -static u32 *ps3vram_get_notifier(u32 *reports, int notifier) +static u32 *ps3vram_get_notifier(void *reports, int notifier) { - return (void *)reports + DMA_NOTIFIER_OFFSET_BASE + + return reports + DMA_NOTIFIER_OFFSET_BASE + DMA_NOTIFIER_SIZE * notifier; } From 6dee2c87ebbe5d7ce8c4c163966a0bd9c02c75ef Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Wed, 10 Jun 2009 04:38:52 +0000 Subject: [PATCH 28/38] block/ps3: remove driver_data direct access of struct device In the near future, the driver core is going to not allow direct access to the driver_data pointer in struct device. Instead, the functions dev_get_drvdata() and dev_set_drvdata() should be used. These functions have been around since the beginning, so are backwards compatible with all older kernel versions. [Geert: Use ps3_system_bus_[gs]et_driver_data() for ps3_system_bus_device] Signed-off-by: Roel Kluin Signed-off-by: Geert Uytterhoeven Cc: Jim Paris Cc: Jens Axboe Signed-off-by: Benjamin Herrenschmidt --- drivers/block/ps3disk.c | 23 +++++++++++-------- drivers/block/ps3vram.c | 50 ++++++++++++++++++++--------------------- 2 files changed, 38 insertions(+), 35 deletions(-) diff --git a/drivers/block/ps3disk.c b/drivers/block/ps3disk.c index aaeeb544228a..fdd2d7a00338 100644 --- a/drivers/block/ps3disk.c +++ b/drivers/block/ps3disk.c @@ -120,7 +120,8 @@ static void ps3disk_scatter_gather(struct ps3_storage_device *dev, static int ps3disk_submit_request_sg(struct ps3_storage_device *dev, struct request *req) { - struct ps3disk_private *priv = dev->sbd.core.driver_data; + struct ps3disk_private *priv = + ps3_system_bus_get_driver_data(&dev->sbd); int write = rq_data_dir(req), res; const char *op = write ? "write" : "read"; u64 start_sector, sectors; @@ -168,7 +169,8 @@ static int ps3disk_submit_request_sg(struct ps3_storage_device *dev, static int ps3disk_submit_flush_request(struct ps3_storage_device *dev, struct request *req) { - struct ps3disk_private *priv = dev->sbd.core.driver_data; + struct ps3disk_private *priv = + ps3_system_bus_get_driver_data(&dev->sbd); u64 res; dev_dbg(&dev->sbd.core, "%s:%u: flush request\n", __func__, __LINE__); @@ -213,7 +215,8 @@ static void ps3disk_do_request(struct ps3_storage_device *dev, static void ps3disk_request(struct request_queue *q) { struct ps3_storage_device *dev = q->queuedata; - struct ps3disk_private *priv = dev->sbd.core.driver_data; + struct ps3disk_private *priv = + ps3_system_bus_get_driver_data(&dev->sbd); if (priv->req) { dev_dbg(&dev->sbd.core, "%s:%u busy\n", __func__, __LINE__); @@ -245,7 +248,7 @@ static irqreturn_t ps3disk_interrupt(int irq, void *data) return IRQ_HANDLED; } - priv = dev->sbd.core.driver_data; + priv = ps3_system_bus_get_driver_data(&dev->sbd); req = priv->req; if (!req) { dev_dbg(&dev->sbd.core, @@ -364,7 +367,8 @@ static void ata_id_c_string(const u16 *id, unsigned char *s, unsigned int ofs, static int ps3disk_identify(struct ps3_storage_device *dev) { - struct ps3disk_private *priv = dev->sbd.core.driver_data; + struct ps3disk_private *priv = + ps3_system_bus_get_driver_data(&dev->sbd); struct lv1_ata_cmnd_block ata_cmnd; u16 *id = dev->bounce_buf; u64 res; @@ -445,7 +449,7 @@ static int __devinit ps3disk_probe(struct ps3_system_bus_device *_dev) goto fail; } - dev->sbd.core.driver_data = priv; + ps3_system_bus_set_driver_data(_dev, priv); spin_lock_init(&priv->lock); dev->bounce_size = BOUNCE_SIZE; @@ -523,7 +527,7 @@ fail_free_bounce: kfree(dev->bounce_buf); fail_free_priv: kfree(priv); - dev->sbd.core.driver_data = NULL; + ps3_system_bus_set_driver_data(_dev, NULL); fail: mutex_lock(&ps3disk_mask_mutex); __clear_bit(devidx, &ps3disk_mask); @@ -534,7 +538,8 @@ fail: static int ps3disk_remove(struct ps3_system_bus_device *_dev) { struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core); - struct ps3disk_private *priv = dev->sbd.core.driver_data; + struct ps3disk_private *priv = + ps3_system_bus_get_driver_data(&dev->sbd); mutex_lock(&ps3disk_mask_mutex); __clear_bit(MINOR(disk_devt(priv->gendisk)) / PS3DISK_MINORS, @@ -548,7 +553,7 @@ static int ps3disk_remove(struct ps3_system_bus_device *_dev) ps3stor_teardown(dev); kfree(dev->bounce_buf); kfree(priv); - dev->sbd.core.driver_data = NULL; + ps3_system_bus_set_driver_data(_dev, NULL); return 0; } diff --git a/drivers/block/ps3vram.c b/drivers/block/ps3vram.c index fbbdd5ca5720..fcecc7f897e4 100644 --- a/drivers/block/ps3vram.c +++ b/drivers/block/ps3vram.c @@ -110,7 +110,7 @@ static u32 *ps3vram_get_notifier(void *reports, int notifier) static void ps3vram_notifier_reset(struct ps3_system_bus_device *dev) { - struct ps3vram_priv *priv = dev->core.driver_data; + struct ps3vram_priv *priv = ps3_system_bus_get_driver_data(dev); u32 *notify = ps3vram_get_notifier(priv->reports, NOTIFIER); int i; @@ -121,7 +121,7 @@ static void ps3vram_notifier_reset(struct ps3_system_bus_device *dev) static int ps3vram_notifier_wait(struct ps3_system_bus_device *dev, unsigned int timeout_ms) { - struct ps3vram_priv *priv = dev->core.driver_data; + struct ps3vram_priv *priv = ps3_system_bus_get_driver_data(dev); u32 *notify = ps3vram_get_notifier(priv->reports, NOTIFIER); unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms); @@ -136,7 +136,7 @@ static int ps3vram_notifier_wait(struct ps3_system_bus_device *dev, static void ps3vram_init_ring(struct ps3_system_bus_device *dev) { - struct ps3vram_priv *priv = dev->core.driver_data; + struct ps3vram_priv *priv = ps3_system_bus_get_driver_data(dev); priv->ctrl[CTRL_PUT] = FIFO_BASE + FIFO_OFFSET; priv->ctrl[CTRL_GET] = FIFO_BASE + FIFO_OFFSET; @@ -145,7 +145,7 @@ static void ps3vram_init_ring(struct ps3_system_bus_device *dev) static int ps3vram_wait_ring(struct ps3_system_bus_device *dev, unsigned int timeout_ms) { - struct ps3vram_priv *priv = dev->core.driver_data; + struct ps3vram_priv *priv = ps3_system_bus_get_driver_data(dev); unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms); do { @@ -174,7 +174,7 @@ static void ps3vram_begin_ring(struct ps3vram_priv *priv, u32 chan, u32 tag, static void ps3vram_rewind_ring(struct ps3_system_bus_device *dev) { - struct ps3vram_priv *priv = dev->core.driver_data; + struct ps3vram_priv *priv = ps3_system_bus_get_driver_data(dev); int status; ps3vram_out_ring(priv, 0x20000000 | (FIFO_BASE + FIFO_OFFSET)); @@ -192,7 +192,7 @@ static void ps3vram_rewind_ring(struct ps3_system_bus_device *dev) static void ps3vram_fire_ring(struct ps3_system_bus_device *dev) { - struct ps3vram_priv *priv = dev->core.driver_data; + struct ps3vram_priv *priv = ps3_system_bus_get_driver_data(dev); int status; mutex_lock(&ps3_gpu_mutex); @@ -218,7 +218,7 @@ static void ps3vram_fire_ring(struct ps3_system_bus_device *dev) static void ps3vram_bind(struct ps3_system_bus_device *dev) { - struct ps3vram_priv *priv = dev->core.driver_data; + struct ps3vram_priv *priv = ps3_system_bus_get_driver_data(dev); ps3vram_begin_ring(priv, UPLOAD_SUBCH, 0, 1); ps3vram_out_ring(priv, 0x31337303); @@ -241,7 +241,7 @@ static int ps3vram_upload(struct ps3_system_bus_device *dev, unsigned int src_offset, unsigned int dst_offset, int len, int count) { - struct ps3vram_priv *priv = dev->core.driver_data; + struct ps3vram_priv *priv = ps3_system_bus_get_driver_data(dev); ps3vram_begin_ring(priv, UPLOAD_SUBCH, NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8); @@ -273,7 +273,7 @@ static int ps3vram_download(struct ps3_system_bus_device *dev, unsigned int src_offset, unsigned int dst_offset, int len, int count) { - struct ps3vram_priv *priv = dev->core.driver_data; + struct ps3vram_priv *priv = ps3_system_bus_get_driver_data(dev); ps3vram_begin_ring(priv, DOWNLOAD_SUBCH, NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8); @@ -303,7 +303,7 @@ static int ps3vram_download(struct ps3_system_bus_device *dev, static void ps3vram_cache_evict(struct ps3_system_bus_device *dev, int entry) { - struct ps3vram_priv *priv = dev->core.driver_data; + struct ps3vram_priv *priv = ps3_system_bus_get_driver_data(dev); struct ps3vram_cache *cache = &priv->cache; if (!(cache->tags[entry].flags & CACHE_PAGE_DIRTY)) @@ -325,7 +325,7 @@ static void ps3vram_cache_evict(struct ps3_system_bus_device *dev, int entry) static void ps3vram_cache_load(struct ps3_system_bus_device *dev, int entry, unsigned int address) { - struct ps3vram_priv *priv = dev->core.driver_data; + struct ps3vram_priv *priv = ps3_system_bus_get_driver_data(dev); struct ps3vram_cache *cache = &priv->cache; dev_dbg(&dev->core, "Fetching %d: 0x%08x\n", entry, address); @@ -345,7 +345,7 @@ static void ps3vram_cache_load(struct ps3_system_bus_device *dev, int entry, static void ps3vram_cache_flush(struct ps3_system_bus_device *dev) { - struct ps3vram_priv *priv = dev->core.driver_data; + struct ps3vram_priv *priv = ps3_system_bus_get_driver_data(dev); struct ps3vram_cache *cache = &priv->cache; int i; @@ -359,7 +359,7 @@ static void ps3vram_cache_flush(struct ps3_system_bus_device *dev) static unsigned int ps3vram_cache_match(struct ps3_system_bus_device *dev, loff_t address) { - struct ps3vram_priv *priv = dev->core.driver_data; + struct ps3vram_priv *priv = ps3_system_bus_get_driver_data(dev); struct ps3vram_cache *cache = &priv->cache; unsigned int base; unsigned int offset; @@ -393,7 +393,7 @@ static unsigned int ps3vram_cache_match(struct ps3_system_bus_device *dev, static int ps3vram_cache_init(struct ps3_system_bus_device *dev) { - struct ps3vram_priv *priv = dev->core.driver_data; + struct ps3vram_priv *priv = ps3_system_bus_get_driver_data(dev); priv->cache.page_count = CACHE_PAGE_COUNT; priv->cache.page_size = CACHE_PAGE_SIZE; @@ -412,7 +412,7 @@ static int ps3vram_cache_init(struct ps3_system_bus_device *dev) static void ps3vram_cache_cleanup(struct ps3_system_bus_device *dev) { - struct ps3vram_priv *priv = dev->core.driver_data; + struct ps3vram_priv *priv = ps3_system_bus_get_driver_data(dev); ps3vram_cache_flush(dev); kfree(priv->cache.tags); @@ -421,7 +421,7 @@ static void ps3vram_cache_cleanup(struct ps3_system_bus_device *dev) static int ps3vram_read(struct ps3_system_bus_device *dev, loff_t from, size_t len, size_t *retlen, u_char *buf) { - struct ps3vram_priv *priv = dev->core.driver_data; + struct ps3vram_priv *priv = ps3_system_bus_get_driver_data(dev); unsigned int cached, count; dev_dbg(&dev->core, "%s: from=0x%08x len=0x%zx\n", __func__, @@ -465,7 +465,7 @@ static int ps3vram_read(struct ps3_system_bus_device *dev, loff_t from, static int ps3vram_write(struct ps3_system_bus_device *dev, loff_t to, size_t len, size_t *retlen, const u_char *buf) { - struct ps3vram_priv *priv = dev->core.driver_data; + struct ps3vram_priv *priv = ps3_system_bus_get_driver_data(dev); unsigned int cached, count; if (to >= priv->size) @@ -528,7 +528,7 @@ static const struct file_operations ps3vram_proc_fops = { static void __devinit ps3vram_proc_init(struct ps3_system_bus_device *dev) { - struct ps3vram_priv *priv = dev->core.driver_data; + struct ps3vram_priv *priv = ps3_system_bus_get_driver_data(dev); struct proc_dir_entry *pde; pde = proc_create_data(DEVICE_NAME, 0444, NULL, &ps3vram_proc_fops, @@ -540,7 +540,7 @@ static void __devinit ps3vram_proc_init(struct ps3_system_bus_device *dev) static struct bio *ps3vram_do_bio(struct ps3_system_bus_device *dev, struct bio *bio) { - struct ps3vram_priv *priv = dev->core.driver_data; + struct ps3vram_priv *priv = ps3_system_bus_get_driver_data(dev); int write = bio_data_dir(bio) == WRITE; const char *op = write ? "write" : "read"; loff_t offset = bio->bi_sector << 9; @@ -590,7 +590,7 @@ out: static int ps3vram_make_request(struct request_queue *q, struct bio *bio) { struct ps3_system_bus_device *dev = q->queuedata; - struct ps3vram_priv *priv = dev->core.driver_data; + struct ps3vram_priv *priv = ps3_system_bus_get_driver_data(dev); int busy; dev_dbg(&dev->core, "%s\n", __func__); @@ -628,9 +628,7 @@ static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev) spin_lock_init(&priv->lock); bio_list_init(&priv->list); - dev->core.driver_data = priv; - - priv = dev->core.driver_data; + ps3_system_bus_set_driver_data(dev, priv); /* Allocate XDR buffer (1MiB aligned) */ priv->xdr_buf = (void *)__get_free_pages(GFP_KERNEL, @@ -795,14 +793,14 @@ out_free_xdr_buf: free_pages((unsigned long) priv->xdr_buf, get_order(XDR_BUF_SIZE)); fail_free_priv: kfree(priv); - dev->core.driver_data = NULL; + ps3_system_bus_set_driver_data(dev, NULL); fail: return error; } static int ps3vram_remove(struct ps3_system_bus_device *dev) { - struct ps3vram_priv *priv = dev->core.driver_data; + struct ps3vram_priv *priv = ps3_system_bus_get_driver_data(dev); del_gendisk(priv->gendisk); put_disk(priv->gendisk); @@ -819,7 +817,7 @@ static int ps3vram_remove(struct ps3_system_bus_device *dev) ps3_close_hv_device(dev); free_pages((unsigned long) priv->xdr_buf, get_order(XDR_BUF_SIZE)); kfree(priv); - dev->core.driver_data = NULL; + ps3_system_bus_set_driver_data(dev, NULL); return 0; } From 9f08e9db84c1e9234e07b9b595f5b2508c621823 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 10 Jun 2009 04:38:53 +0000 Subject: [PATCH 29/38] ps3: Use dev_[gs]et_drvdata() instead of direct access for system bus devices Signed-off-by: Geert Uytterhoeven Cc: Geoff Levand Acked-by: Geoff Levand Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/include/asm/ps3.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/include/asm/ps3.h b/arch/powerpc/include/asm/ps3.h index b9e4987986dd..dcd302f489f6 100644 --- a/arch/powerpc/include/asm/ps3.h +++ b/arch/powerpc/include/asm/ps3.h @@ -421,12 +421,12 @@ static inline struct ps3_system_bus_driver * static inline void ps3_system_bus_set_driver_data( struct ps3_system_bus_device *dev, void *data) { - dev->core.driver_data = data; + dev_set_drvdata(&dev->core, data); } static inline void *ps3_system_bus_get_driver_data( struct ps3_system_bus_device *dev) { - return dev->core.driver_data; + return dev_get_drvdata(&dev->core); } /* These two need global scope for get_dma_ops(). */ From 03fa68c245cccbcb99035cbabaa13b408ba91ab5 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 10 Jun 2009 04:38:54 +0000 Subject: [PATCH 30/38] ps3: shorten ps3_system_bus_[gs]et_driver_data to ps3_system_bus_[gs]et_drvdata Signed-off-by: Geert Uytterhoeven Cc: Geoff Levand Cc: Jim Paris Acked-by: Geoff Levand Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/include/asm/ps3.h | 4 +-- drivers/block/ps3disk.c | 23 +++++++--------- drivers/block/ps3vram.c | 48 +++++++++++++++++----------------- drivers/net/ps3_gelic_net.c | 8 +++--- drivers/usb/host/ehci-ps3.c | 7 +++-- drivers/usb/host/ohci-ps3.c | 7 +++-- 6 files changed, 45 insertions(+), 52 deletions(-) diff --git a/arch/powerpc/include/asm/ps3.h b/arch/powerpc/include/asm/ps3.h index dcd302f489f6..7660694ab3ca 100644 --- a/arch/powerpc/include/asm/ps3.h +++ b/arch/powerpc/include/asm/ps3.h @@ -418,12 +418,12 @@ static inline struct ps3_system_bus_driver * * @data: Data to set */ -static inline void ps3_system_bus_set_driver_data( +static inline void ps3_system_bus_set_drvdata( struct ps3_system_bus_device *dev, void *data) { dev_set_drvdata(&dev->core, data); } -static inline void *ps3_system_bus_get_driver_data( +static inline void *ps3_system_bus_get_drvdata( struct ps3_system_bus_device *dev) { return dev_get_drvdata(&dev->core); diff --git a/drivers/block/ps3disk.c b/drivers/block/ps3disk.c index fdd2d7a00338..34cbb7f3efa8 100644 --- a/drivers/block/ps3disk.c +++ b/drivers/block/ps3disk.c @@ -120,8 +120,7 @@ static void ps3disk_scatter_gather(struct ps3_storage_device *dev, static int ps3disk_submit_request_sg(struct ps3_storage_device *dev, struct request *req) { - struct ps3disk_private *priv = - ps3_system_bus_get_driver_data(&dev->sbd); + struct ps3disk_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); int write = rq_data_dir(req), res; const char *op = write ? "write" : "read"; u64 start_sector, sectors; @@ -169,8 +168,7 @@ static int ps3disk_submit_request_sg(struct ps3_storage_device *dev, static int ps3disk_submit_flush_request(struct ps3_storage_device *dev, struct request *req) { - struct ps3disk_private *priv = - ps3_system_bus_get_driver_data(&dev->sbd); + struct ps3disk_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); u64 res; dev_dbg(&dev->sbd.core, "%s:%u: flush request\n", __func__, __LINE__); @@ -215,8 +213,7 @@ static void ps3disk_do_request(struct ps3_storage_device *dev, static void ps3disk_request(struct request_queue *q) { struct ps3_storage_device *dev = q->queuedata; - struct ps3disk_private *priv = - ps3_system_bus_get_driver_data(&dev->sbd); + struct ps3disk_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); if (priv->req) { dev_dbg(&dev->sbd.core, "%s:%u busy\n", __func__, __LINE__); @@ -248,7 +245,7 @@ static irqreturn_t ps3disk_interrupt(int irq, void *data) return IRQ_HANDLED; } - priv = ps3_system_bus_get_driver_data(&dev->sbd); + priv = ps3_system_bus_get_drvdata(&dev->sbd); req = priv->req; if (!req) { dev_dbg(&dev->sbd.core, @@ -367,8 +364,7 @@ static void ata_id_c_string(const u16 *id, unsigned char *s, unsigned int ofs, static int ps3disk_identify(struct ps3_storage_device *dev) { - struct ps3disk_private *priv = - ps3_system_bus_get_driver_data(&dev->sbd); + struct ps3disk_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); struct lv1_ata_cmnd_block ata_cmnd; u16 *id = dev->bounce_buf; u64 res; @@ -449,7 +445,7 @@ static int __devinit ps3disk_probe(struct ps3_system_bus_device *_dev) goto fail; } - ps3_system_bus_set_driver_data(_dev, priv); + ps3_system_bus_set_drvdata(_dev, priv); spin_lock_init(&priv->lock); dev->bounce_size = BOUNCE_SIZE; @@ -527,7 +523,7 @@ fail_free_bounce: kfree(dev->bounce_buf); fail_free_priv: kfree(priv); - ps3_system_bus_set_driver_data(_dev, NULL); + ps3_system_bus_set_drvdata(_dev, NULL); fail: mutex_lock(&ps3disk_mask_mutex); __clear_bit(devidx, &ps3disk_mask); @@ -538,8 +534,7 @@ fail: static int ps3disk_remove(struct ps3_system_bus_device *_dev) { struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core); - struct ps3disk_private *priv = - ps3_system_bus_get_driver_data(&dev->sbd); + struct ps3disk_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); mutex_lock(&ps3disk_mask_mutex); __clear_bit(MINOR(disk_devt(priv->gendisk)) / PS3DISK_MINORS, @@ -553,7 +548,7 @@ static int ps3disk_remove(struct ps3_system_bus_device *_dev) ps3stor_teardown(dev); kfree(dev->bounce_buf); kfree(priv); - ps3_system_bus_set_driver_data(_dev, NULL); + ps3_system_bus_set_drvdata(_dev, NULL); return 0; } diff --git a/drivers/block/ps3vram.c b/drivers/block/ps3vram.c index fcecc7f897e4..095f97e60665 100644 --- a/drivers/block/ps3vram.c +++ b/drivers/block/ps3vram.c @@ -110,7 +110,7 @@ static u32 *ps3vram_get_notifier(void *reports, int notifier) static void ps3vram_notifier_reset(struct ps3_system_bus_device *dev) { - struct ps3vram_priv *priv = ps3_system_bus_get_driver_data(dev); + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); u32 *notify = ps3vram_get_notifier(priv->reports, NOTIFIER); int i; @@ -121,7 +121,7 @@ static void ps3vram_notifier_reset(struct ps3_system_bus_device *dev) static int ps3vram_notifier_wait(struct ps3_system_bus_device *dev, unsigned int timeout_ms) { - struct ps3vram_priv *priv = ps3_system_bus_get_driver_data(dev); + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); u32 *notify = ps3vram_get_notifier(priv->reports, NOTIFIER); unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms); @@ -136,7 +136,7 @@ static int ps3vram_notifier_wait(struct ps3_system_bus_device *dev, static void ps3vram_init_ring(struct ps3_system_bus_device *dev) { - struct ps3vram_priv *priv = ps3_system_bus_get_driver_data(dev); + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); priv->ctrl[CTRL_PUT] = FIFO_BASE + FIFO_OFFSET; priv->ctrl[CTRL_GET] = FIFO_BASE + FIFO_OFFSET; @@ -145,7 +145,7 @@ static void ps3vram_init_ring(struct ps3_system_bus_device *dev) static int ps3vram_wait_ring(struct ps3_system_bus_device *dev, unsigned int timeout_ms) { - struct ps3vram_priv *priv = ps3_system_bus_get_driver_data(dev); + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms); do { @@ -174,7 +174,7 @@ static void ps3vram_begin_ring(struct ps3vram_priv *priv, u32 chan, u32 tag, static void ps3vram_rewind_ring(struct ps3_system_bus_device *dev) { - struct ps3vram_priv *priv = ps3_system_bus_get_driver_data(dev); + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); int status; ps3vram_out_ring(priv, 0x20000000 | (FIFO_BASE + FIFO_OFFSET)); @@ -192,7 +192,7 @@ static void ps3vram_rewind_ring(struct ps3_system_bus_device *dev) static void ps3vram_fire_ring(struct ps3_system_bus_device *dev) { - struct ps3vram_priv *priv = ps3_system_bus_get_driver_data(dev); + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); int status; mutex_lock(&ps3_gpu_mutex); @@ -218,7 +218,7 @@ static void ps3vram_fire_ring(struct ps3_system_bus_device *dev) static void ps3vram_bind(struct ps3_system_bus_device *dev) { - struct ps3vram_priv *priv = ps3_system_bus_get_driver_data(dev); + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); ps3vram_begin_ring(priv, UPLOAD_SUBCH, 0, 1); ps3vram_out_ring(priv, 0x31337303); @@ -241,7 +241,7 @@ static int ps3vram_upload(struct ps3_system_bus_device *dev, unsigned int src_offset, unsigned int dst_offset, int len, int count) { - struct ps3vram_priv *priv = ps3_system_bus_get_driver_data(dev); + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); ps3vram_begin_ring(priv, UPLOAD_SUBCH, NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8); @@ -273,7 +273,7 @@ static int ps3vram_download(struct ps3_system_bus_device *dev, unsigned int src_offset, unsigned int dst_offset, int len, int count) { - struct ps3vram_priv *priv = ps3_system_bus_get_driver_data(dev); + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); ps3vram_begin_ring(priv, DOWNLOAD_SUBCH, NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8); @@ -303,7 +303,7 @@ static int ps3vram_download(struct ps3_system_bus_device *dev, static void ps3vram_cache_evict(struct ps3_system_bus_device *dev, int entry) { - struct ps3vram_priv *priv = ps3_system_bus_get_driver_data(dev); + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); struct ps3vram_cache *cache = &priv->cache; if (!(cache->tags[entry].flags & CACHE_PAGE_DIRTY)) @@ -325,7 +325,7 @@ static void ps3vram_cache_evict(struct ps3_system_bus_device *dev, int entry) static void ps3vram_cache_load(struct ps3_system_bus_device *dev, int entry, unsigned int address) { - struct ps3vram_priv *priv = ps3_system_bus_get_driver_data(dev); + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); struct ps3vram_cache *cache = &priv->cache; dev_dbg(&dev->core, "Fetching %d: 0x%08x\n", entry, address); @@ -345,7 +345,7 @@ static void ps3vram_cache_load(struct ps3_system_bus_device *dev, int entry, static void ps3vram_cache_flush(struct ps3_system_bus_device *dev) { - struct ps3vram_priv *priv = ps3_system_bus_get_driver_data(dev); + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); struct ps3vram_cache *cache = &priv->cache; int i; @@ -359,7 +359,7 @@ static void ps3vram_cache_flush(struct ps3_system_bus_device *dev) static unsigned int ps3vram_cache_match(struct ps3_system_bus_device *dev, loff_t address) { - struct ps3vram_priv *priv = ps3_system_bus_get_driver_data(dev); + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); struct ps3vram_cache *cache = &priv->cache; unsigned int base; unsigned int offset; @@ -393,7 +393,7 @@ static unsigned int ps3vram_cache_match(struct ps3_system_bus_device *dev, static int ps3vram_cache_init(struct ps3_system_bus_device *dev) { - struct ps3vram_priv *priv = ps3_system_bus_get_driver_data(dev); + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); priv->cache.page_count = CACHE_PAGE_COUNT; priv->cache.page_size = CACHE_PAGE_SIZE; @@ -412,7 +412,7 @@ static int ps3vram_cache_init(struct ps3_system_bus_device *dev) static void ps3vram_cache_cleanup(struct ps3_system_bus_device *dev) { - struct ps3vram_priv *priv = ps3_system_bus_get_driver_data(dev); + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); ps3vram_cache_flush(dev); kfree(priv->cache.tags); @@ -421,7 +421,7 @@ static void ps3vram_cache_cleanup(struct ps3_system_bus_device *dev) static int ps3vram_read(struct ps3_system_bus_device *dev, loff_t from, size_t len, size_t *retlen, u_char *buf) { - struct ps3vram_priv *priv = ps3_system_bus_get_driver_data(dev); + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); unsigned int cached, count; dev_dbg(&dev->core, "%s: from=0x%08x len=0x%zx\n", __func__, @@ -465,7 +465,7 @@ static int ps3vram_read(struct ps3_system_bus_device *dev, loff_t from, static int ps3vram_write(struct ps3_system_bus_device *dev, loff_t to, size_t len, size_t *retlen, const u_char *buf) { - struct ps3vram_priv *priv = ps3_system_bus_get_driver_data(dev); + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); unsigned int cached, count; if (to >= priv->size) @@ -528,7 +528,7 @@ static const struct file_operations ps3vram_proc_fops = { static void __devinit ps3vram_proc_init(struct ps3_system_bus_device *dev) { - struct ps3vram_priv *priv = ps3_system_bus_get_driver_data(dev); + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); struct proc_dir_entry *pde; pde = proc_create_data(DEVICE_NAME, 0444, NULL, &ps3vram_proc_fops, @@ -540,7 +540,7 @@ static void __devinit ps3vram_proc_init(struct ps3_system_bus_device *dev) static struct bio *ps3vram_do_bio(struct ps3_system_bus_device *dev, struct bio *bio) { - struct ps3vram_priv *priv = ps3_system_bus_get_driver_data(dev); + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); int write = bio_data_dir(bio) == WRITE; const char *op = write ? "write" : "read"; loff_t offset = bio->bi_sector << 9; @@ -590,7 +590,7 @@ out: static int ps3vram_make_request(struct request_queue *q, struct bio *bio) { struct ps3_system_bus_device *dev = q->queuedata; - struct ps3vram_priv *priv = ps3_system_bus_get_driver_data(dev); + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); int busy; dev_dbg(&dev->core, "%s\n", __func__); @@ -628,7 +628,7 @@ static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev) spin_lock_init(&priv->lock); bio_list_init(&priv->list); - ps3_system_bus_set_driver_data(dev, priv); + ps3_system_bus_set_drvdata(dev, priv); /* Allocate XDR buffer (1MiB aligned) */ priv->xdr_buf = (void *)__get_free_pages(GFP_KERNEL, @@ -793,14 +793,14 @@ out_free_xdr_buf: free_pages((unsigned long) priv->xdr_buf, get_order(XDR_BUF_SIZE)); fail_free_priv: kfree(priv); - ps3_system_bus_set_driver_data(dev, NULL); + ps3_system_bus_set_drvdata(dev, NULL); fail: return error; } static int ps3vram_remove(struct ps3_system_bus_device *dev) { - struct ps3vram_priv *priv = ps3_system_bus_get_driver_data(dev); + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); del_gendisk(priv->gendisk); put_disk(priv->gendisk); @@ -817,7 +817,7 @@ static int ps3vram_remove(struct ps3_system_bus_device *dev) ps3_close_hv_device(dev); free_pages((unsigned long) priv->xdr_buf, get_order(XDR_BUF_SIZE)); kfree(priv); - ps3_system_bus_set_driver_data(dev, NULL); + ps3_system_bus_set_drvdata(dev, NULL); return 0; } diff --git a/drivers/net/ps3_gelic_net.c b/drivers/net/ps3_gelic_net.c index 30900b30d532..2b38f39924a6 100644 --- a/drivers/net/ps3_gelic_net.c +++ b/drivers/net/ps3_gelic_net.c @@ -1648,7 +1648,7 @@ static int ps3_gelic_driver_probe(struct ps3_system_bus_device *dev) result = -ENOMEM; goto fail_alloc_card; } - ps3_system_bus_set_driver_data(dev, card); + ps3_system_bus_set_drvdata(dev, card); card->dev = dev; /* get internal vlan info */ @@ -1749,7 +1749,7 @@ fail_alloc_irq: bus_id(card), 0, 0); fail_status_indicator: - ps3_system_bus_set_driver_data(dev, NULL); + ps3_system_bus_set_drvdata(dev, NULL); kfree(netdev_card(netdev)->unalign); free_netdev(netdev); fail_alloc_card: @@ -1766,7 +1766,7 @@ fail_open: static int ps3_gelic_driver_remove(struct ps3_system_bus_device *dev) { - struct gelic_card *card = ps3_system_bus_get_driver_data(dev); + struct gelic_card *card = ps3_system_bus_get_drvdata(dev); struct net_device *netdev0; pr_debug("%s: called\n", __func__); @@ -1803,7 +1803,7 @@ static int ps3_gelic_driver_remove(struct ps3_system_bus_device *dev) kfree(netdev_card(netdev0)->unalign); free_netdev(netdev0); - ps3_system_bus_set_driver_data(dev, NULL); + ps3_system_bus_set_drvdata(dev, NULL); ps3_dma_region_free(dev->d_region); diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c index 1ba9f9a8c308..bb870b8f81bc 100644 --- a/drivers/usb/host/ehci-ps3.c +++ b/drivers/usb/host/ehci-ps3.c @@ -162,7 +162,7 @@ static int ps3_ehci_probe(struct ps3_system_bus_device *dev) dev_dbg(&dev->core, "%s:%d: virq %lu\n", __func__, __LINE__, (unsigned long)virq); - ps3_system_bus_set_driver_data(dev, hcd); + ps3_system_bus_set_drvdata(dev, hcd); result = usb_add_hcd(hcd, virq, IRQF_DISABLED); @@ -195,8 +195,7 @@ fail_start: static int ps3_ehci_remove(struct ps3_system_bus_device *dev) { unsigned int tmp; - struct usb_hcd *hcd = - (struct usb_hcd *)ps3_system_bus_get_driver_data(dev); + struct usb_hcd *hcd = ps3_system_bus_get_drvdata(dev); BUG_ON(!hcd); @@ -208,7 +207,7 @@ static int ps3_ehci_remove(struct ps3_system_bus_device *dev) ehci_shutdown(hcd); usb_remove_hcd(hcd); - ps3_system_bus_set_driver_data(dev, NULL); + ps3_system_bus_set_drvdata(dev, NULL); BUG_ON(!hcd->regs); iounmap(hcd->regs); diff --git a/drivers/usb/host/ohci-ps3.c b/drivers/usb/host/ohci-ps3.c index 3d1910317328..1d56259c5db1 100644 --- a/drivers/usb/host/ohci-ps3.c +++ b/drivers/usb/host/ohci-ps3.c @@ -162,7 +162,7 @@ static int ps3_ohci_probe(struct ps3_system_bus_device *dev) dev_dbg(&dev->core, "%s:%d: virq %lu\n", __func__, __LINE__, (unsigned long)virq); - ps3_system_bus_set_driver_data(dev, hcd); + ps3_system_bus_set_drvdata(dev, hcd); result = usb_add_hcd(hcd, virq, IRQF_DISABLED); @@ -195,8 +195,7 @@ fail_start: static int ps3_ohci_remove(struct ps3_system_bus_device *dev) { unsigned int tmp; - struct usb_hcd *hcd = - (struct usb_hcd *)ps3_system_bus_get_driver_data(dev); + struct usb_hcd *hcd = ps3_system_bus_get_drvdata(dev); BUG_ON(!hcd); @@ -208,7 +207,7 @@ static int ps3_ohci_remove(struct ps3_system_bus_device *dev) ohci_shutdown(hcd); usb_remove_hcd(hcd); - ps3_system_bus_set_driver_data(dev, NULL); + ps3_system_bus_set_drvdata(dev, NULL); BUG_ON(!hcd->regs); iounmap(hcd->regs); From 559dc87f50d062d881fed406efb76925aa1f30e7 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 10 Jun 2009 04:38:55 +0000 Subject: [PATCH 31/38] ps3flash: Use ps3_system_bus_[gs]et_drvdata() instead of direct access Signed-off-by: Geert Uytterhoeven Signed-off-by: Benjamin Herrenschmidt --- drivers/char/ps3flash.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/char/ps3flash.c b/drivers/char/ps3flash.c index afbe45676d71..184e6ed2393d 100644 --- a/drivers/char/ps3flash.c +++ b/drivers/char/ps3flash.c @@ -108,7 +108,7 @@ static ssize_t ps3flash_read(struct file *file, char __user *buf, size_t count, loff_t *pos) { struct ps3_storage_device *dev = ps3flash_dev; - struct ps3flash_private *priv = dev->sbd.core.driver_data; + struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); u64 size, start_sector, end_sector, offset; ssize_t sectors_read; size_t remaining, n; @@ -173,7 +173,7 @@ static ssize_t ps3flash_write(struct file *file, const char __user *buf, size_t count, loff_t *pos) { struct ps3_storage_device *dev = ps3flash_dev; - struct ps3flash_private *priv = dev->sbd.core.driver_data; + struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); u64 size, chunk_sectors, start_write_sector, end_write_sector, end_read_sector, start_read_sector, head, tail, offset; ssize_t res; @@ -366,7 +366,7 @@ static int __devinit ps3flash_probe(struct ps3_system_bus_device *_dev) goto fail; } - dev->sbd.core.driver_data = priv; + ps3_system_bus_set_drvdata(&dev->sbd, priv); mutex_init(&priv->mutex); dev->bounce_size = ps3flash_bounce_buffer.size; @@ -392,7 +392,7 @@ fail_teardown: ps3stor_teardown(dev); fail_free_priv: kfree(priv); - dev->sbd.core.driver_data = NULL; + ps3_system_bus_set_drvdata(&dev->sbd, NULL); fail: ps3flash_dev = NULL; return error; @@ -404,8 +404,8 @@ static int ps3flash_remove(struct ps3_system_bus_device *_dev) misc_deregister(&ps3flash_misc); ps3stor_teardown(dev); - kfree(dev->sbd.core.driver_data); - dev->sbd.core.driver_data = NULL; + kfree(ps3_system_bus_get_drvdata(&dev->sbd)); + ps3_system_bus_set_drvdata(&dev->sbd, NULL); ps3flash_dev = NULL; return 0; } From cd4a157d769311964717d5c7cfc0c34426d090b4 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 10 Jun 2009 04:38:57 +0000 Subject: [PATCH 32/38] ps3fb: Use ps3_system_bus_[gs]et_drvdata() instead of direct access Signed-off-by: Geert Uytterhoeven Cc: linux-fbdev-devel@lists.sourceforge.net Signed-off-by: Benjamin Herrenschmidt --- drivers/video/ps3fb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/video/ps3fb.c b/drivers/video/ps3fb.c index 1baa1c93a224..c0af638fe702 100644 --- a/drivers/video/ps3fb.c +++ b/drivers/video/ps3fb.c @@ -1166,7 +1166,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) if (retval < 0) goto err_fb_dealloc; - dev->core.driver_data = info; + ps3_system_bus_set_drvdata(dev, info); dev_info(info->device, "%s %s, using %u KiB of video memory\n", dev_driver_string(info->dev), dev_name(info->dev), @@ -1211,7 +1211,7 @@ err: static int ps3fb_shutdown(struct ps3_system_bus_device *dev) { - struct fb_info *info = dev->core.driver_data; + struct fb_info *info = ps3_system_bus_get_drvdata(dev); u64 xdr_lpar = ps3_mm_phys_to_lpar(__pa(ps3fb_videomemory.address)); dev_dbg(&dev->core, " -> %s:%d\n", __func__, __LINE__); @@ -1232,7 +1232,7 @@ static int ps3fb_shutdown(struct ps3_system_bus_device *dev) unregister_framebuffer(info); fb_dealloc_cmap(&info->cmap); framebuffer_release(info); - info = dev->core.driver_data = NULL; + ps3_system_bus_set_drvdata(dev, NULL); } iounmap((u8 __force __iomem *)ps3fb.dinfo); lv1_gpu_fb_close(ps3fb.context_handle); From a469f563d6eec9ef68da9b4aed708e7f6ecabd51 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 10 Jun 2009 04:39:00 +0000 Subject: [PATCH 33/38] drivers/ps3: Add missing annotations probe functions should be __devinit initialization functions should be __init Signed-off-by: Geert Uytterhoeven Cc: Geoff Levand Acked-by: Geoff Levand Signed-off-by: Benjamin Herrenschmidt --- drivers/ps3/ps3-sys-manager.c | 2 +- drivers/ps3/ps3av.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/ps3/ps3-sys-manager.c b/drivers/ps3/ps3-sys-manager.c index f17513dd9d4b..88cb74088611 100644 --- a/drivers/ps3/ps3-sys-manager.c +++ b/drivers/ps3/ps3-sys-manager.c @@ -706,7 +706,7 @@ static void ps3_sys_manager_work(struct ps3_system_bus_device *dev) ps3_vuart_read_async(dev, PS3_SM_RX_MSG_LEN_MIN); } -static int ps3_sys_manager_probe(struct ps3_system_bus_device *dev) +static int __devinit ps3_sys_manager_probe(struct ps3_system_bus_device *dev) { int result; struct ps3_sys_manager_ops ops; diff --git a/drivers/ps3/ps3av.c b/drivers/ps3/ps3av.c index 4e4611e99afe..e82d8c9c6cda 100644 --- a/drivers/ps3/ps3av.c +++ b/drivers/ps3/ps3av.c @@ -937,7 +937,7 @@ int ps3av_audio_mute(int mute) EXPORT_SYMBOL_GPL(ps3av_audio_mute); -static int ps3av_probe(struct ps3_system_bus_device *dev) +static int __devinit ps3av_probe(struct ps3_system_bus_device *dev) { int res; int id; @@ -1048,7 +1048,7 @@ static struct ps3_vuart_port_driver ps3av_driver = { .shutdown = ps3av_shutdown, }; -static int ps3av_module_init(void) +static int __init ps3av_module_init(void) { int error; From 7e28060a5e04966d20c04c232b2f438f96e0a29e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 10 Jun 2009 04:39:04 +0000 Subject: [PATCH 34/38] ps3: Correct debug message in dma_ioc0_map_pages() It reports the failure of a call to lv1_put_iopte(), not lv1_map_device_dma_region(). Signed-off-by: Geert Uytterhoeven Cc: Geoff Levand Acked-by: Geoff Levand Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/platforms/ps3/mm.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/platforms/ps3/mm.c b/arch/powerpc/platforms/ps3/mm.c index 017b6142caca..846eb8b57fd1 100644 --- a/arch/powerpc/platforms/ps3/mm.c +++ b/arch/powerpc/platforms/ps3/mm.c @@ -606,9 +606,8 @@ static int dma_ioc0_map_pages(struct ps3_dma_region *r, unsigned long phys_addr, r->ioid, iopte_flag); if (result) { - printk(KERN_WARNING "%s:%d: lv1_map_device_dma_region " - "failed: %s\n", __func__, __LINE__, - ps3_result(result)); + pr_warning("%s:%d: lv1_put_iopte failed: %s\n", + __func__, __LINE__, ps3_result(result)); goto fail_map; } DBG("%s: pg=%d bus=%#lx, lpar=%#lx, ioid=%#x\n", __func__, From 47cb996b059e0e5696b8daa1f62881a6462a251a Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 10 Jun 2009 04:39:05 +0000 Subject: [PATCH 35/38] ps3: Switch ps3_os_area_[gs]et_rtc_diff to EXPORT_SYMBOL_GPL() They were never intended to be exported using EXPORT_SYMBOL() anyway Signed-off-by: Geert Uytterhoeven Cc: Geoff Levand Acked-by: Geoff Levand Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/platforms/ps3/os-area.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/platforms/ps3/os-area.c b/arch/powerpc/platforms/ps3/os-area.c index cf1cd0f8c18f..6e4125d6150f 100644 --- a/arch/powerpc/platforms/ps3/os-area.c +++ b/arch/powerpc/platforms/ps3/os-area.c @@ -808,7 +808,7 @@ u64 ps3_os_area_get_rtc_diff(void) { return saved_params.rtc_diff; } -EXPORT_SYMBOL(ps3_os_area_get_rtc_diff); +EXPORT_SYMBOL_GPL(ps3_os_area_get_rtc_diff); /** * ps3_os_area_set_rtc_diff - Set the rtc diff value. @@ -824,7 +824,7 @@ void ps3_os_area_set_rtc_diff(u64 rtc_diff) os_area_queue_work(); } } -EXPORT_SYMBOL(ps3_os_area_set_rtc_diff); +EXPORT_SYMBOL_GPL(ps3_os_area_set_rtc_diff); /** * ps3_os_area_get_av_multi_out - Returns the default video mode. From a4e623fbc9b201930abcf78df6db5e49aa8e00cb Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 10 Jun 2009 04:39:06 +0000 Subject: [PATCH 36/38] ps3: Replace direct file operations by callback Currently the FLASH database is updated by the kernel using file operations, meant for userspace only. While this works for us because copy_{from,to}_user() on powerpc can handle kernel pointers, this is unportable and a bad example. Replace the file operations by callbacks, registered by the ps3flash driver. Signed-off-by: Geert Uytterhoeven Cc: Geoff Levand Acked-by: Geoff Levand Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/include/asm/ps3.h | 7 ++ arch/powerpc/platforms/ps3/os-area.c | 138 +++++++++++++++------------ drivers/char/ps3flash.c | 94 +++++++++++++----- 3 files changed, 152 insertions(+), 87 deletions(-) diff --git a/arch/powerpc/include/asm/ps3.h b/arch/powerpc/include/asm/ps3.h index 7660694ab3ca..7f065e178ec4 100644 --- a/arch/powerpc/include/asm/ps3.h +++ b/arch/powerpc/include/asm/ps3.h @@ -53,6 +53,13 @@ enum ps3_param_av_multi_out ps3_os_area_get_av_multi_out(void); extern u64 ps3_os_area_get_rtc_diff(void); extern void ps3_os_area_set_rtc_diff(u64 rtc_diff); +struct ps3_os_area_flash_ops { + ssize_t (*read)(void *buf, size_t count, loff_t pos); + ssize_t (*write)(const void *buf, size_t count, loff_t pos); +}; + +extern void ps3_os_area_flash_register(const struct ps3_os_area_flash_ops *ops); + /* dma routines */ enum ps3_dma_page_size { diff --git a/arch/powerpc/platforms/ps3/os-area.c b/arch/powerpc/platforms/ps3/os-area.c index 6e4125d6150f..d6487a9c8019 100644 --- a/arch/powerpc/platforms/ps3/os-area.c +++ b/arch/powerpc/platforms/ps3/os-area.c @@ -226,6 +226,44 @@ static struct property property_av_multi_out = { .value = &saved_params.av_multi_out, }; + +static DEFINE_MUTEX(os_area_flash_mutex); + +static const struct ps3_os_area_flash_ops *os_area_flash_ops; + +void ps3_os_area_flash_register(const struct ps3_os_area_flash_ops *ops) +{ + mutex_lock(&os_area_flash_mutex); + os_area_flash_ops = ops; + mutex_unlock(&os_area_flash_mutex); +} +EXPORT_SYMBOL_GPL(ps3_os_area_flash_register); + +static ssize_t os_area_flash_read(void *buf, size_t count, loff_t pos) +{ + ssize_t res = -ENODEV; + + mutex_lock(&os_area_flash_mutex); + if (os_area_flash_ops) + res = os_area_flash_ops->read(buf, count, pos); + mutex_unlock(&os_area_flash_mutex); + + return res; +} + +static ssize_t os_area_flash_write(const void *buf, size_t count, loff_t pos) +{ + ssize_t res = -ENODEV; + + mutex_lock(&os_area_flash_mutex); + if (os_area_flash_ops) + res = os_area_flash_ops->write(buf, count, pos); + mutex_unlock(&os_area_flash_mutex); + + return res; +} + + /** * os_area_set_property - Add or overwrite a saved_params value to the device tree. * @@ -352,12 +390,12 @@ static int db_verify(const struct os_area_db *db) if (memcmp(db->magic_num, OS_AREA_DB_MAGIC_NUM, sizeof(db->magic_num))) { pr_debug("%s:%d magic_num failed\n", __func__, __LINE__); - return -1; + return -EINVAL; } if (db->version != 1) { pr_debug("%s:%d version failed\n", __func__, __LINE__); - return -1; + return -EINVAL; } return 0; @@ -578,59 +616,48 @@ static void os_area_db_init(struct os_area_db *db) * */ -static void __maybe_unused update_flash_db(void) +static int update_flash_db(void) { - int result; - int file; - off_t offset; + const unsigned int buf_len = 8 * OS_AREA_SEGMENT_SIZE; + struct os_area_header *header; ssize_t count; - static const unsigned int buf_len = 8 * OS_AREA_SEGMENT_SIZE; - const struct os_area_header *header; + int error; + loff_t pos; struct os_area_db* db; /* Read in header and db from flash. */ - file = sys_open("/dev/ps3flash", O_RDWR, 0); - - if (file < 0) { - pr_debug("%s:%d sys_open failed\n", __func__, __LINE__); - goto fail_open; - } - header = kmalloc(buf_len, GFP_KERNEL); - if (!header) { - pr_debug("%s:%d kmalloc failed\n", __func__, __LINE__); - goto fail_malloc; + pr_debug("%s: kmalloc failed\n", __func__); + return -ENOMEM; } - offset = sys_lseek(file, 0, SEEK_SET); - - if (offset != 0) { - pr_debug("%s:%d sys_lseek failed\n", __func__, __LINE__); - goto fail_header_seek; + count = os_area_flash_read(header, buf_len, 0); + if (count < 0) { + pr_debug("%s: os_area_flash_read failed %zd\n", __func__, + count); + error = count; + goto fail; } - count = sys_read(file, (char __user *)header, buf_len); - - result = count < OS_AREA_SEGMENT_SIZE || verify_header(header) - || count < header->db_area_offset * OS_AREA_SEGMENT_SIZE; - - if (result) { - pr_debug("%s:%d verify_header failed\n", __func__, __LINE__); + pos = header->db_area_offset * OS_AREA_SEGMENT_SIZE; + if (count < OS_AREA_SEGMENT_SIZE || verify_header(header) || + count < pos) { + pr_debug("%s: verify_header failed\n", __func__); dump_header(header); - goto fail_header; + error = -EINVAL; + goto fail; } /* Now got a good db offset and some maybe good db data. */ - db = (void*)header + header->db_area_offset * OS_AREA_SEGMENT_SIZE; + db = (void *)header + pos; - result = db_verify(db); - - if (result) { - printk(KERN_NOTICE "%s:%d: Verify of flash database failed, " - "formatting.\n", __func__, __LINE__); + error = db_verify(db); + if (error) { + pr_notice("%s: Verify of flash database failed, formatting.\n", + __func__); dump_db(db); os_area_db_init(db); } @@ -639,29 +666,16 @@ static void __maybe_unused update_flash_db(void) db_set_64(db, &os_area_db_id_rtc_diff, saved_params.rtc_diff); - offset = sys_lseek(file, header->db_area_offset * OS_AREA_SEGMENT_SIZE, - SEEK_SET); - - if (offset != header->db_area_offset * OS_AREA_SEGMENT_SIZE) { - pr_debug("%s:%d sys_lseek failed\n", __func__, __LINE__); - goto fail_db_seek; - } - - count = sys_write(file, (const char __user *)db, - sizeof(struct os_area_db)); - + count = os_area_flash_write(db, sizeof(struct os_area_db), pos); if (count < sizeof(struct os_area_db)) { - pr_debug("%s:%d sys_write failed\n", __func__, __LINE__); + pr_debug("%s: os_area_flash_write failed %zd\n", __func__, + count); + error = count < 0 ? count : -EIO; } -fail_db_seek: -fail_header: -fail_header_seek: +fail: kfree(header); -fail_malloc: - sys_close(file); -fail_open: - return; + return error; } /** @@ -674,11 +688,11 @@ fail_open: static void os_area_queue_work_handler(struct work_struct *work) { struct device_node *node; + int error; pr_debug(" -> %s:%d\n", __func__, __LINE__); node = of_find_node_by_path("/"); - if (node) { os_area_set_property(node, &property_rtc_diff); of_node_put(node); @@ -686,12 +700,10 @@ static void os_area_queue_work_handler(struct work_struct *work) pr_debug("%s:%d of_find_node_by_path failed\n", __func__, __LINE__); -#if defined(CONFIG_PS3_FLASH) || defined(CONFIG_PS3_FLASH_MODULE) - update_flash_db(); -#else - printk(KERN_WARNING "%s:%d: No flash rom driver configured.\n", - __func__, __LINE__); -#endif + error = update_flash_db(); + if (error) + pr_warning("%s: Could not update FLASH ROM\n", __func__); + pr_debug(" <- %s:%d\n", __func__, __LINE__); } diff --git a/drivers/char/ps3flash.c b/drivers/char/ps3flash.c index 184e6ed2393d..f7f21f47ea02 100644 --- a/drivers/char/ps3flash.c +++ b/drivers/char/ps3flash.c @@ -104,18 +104,19 @@ out: return res; } -static ssize_t ps3flash_read(struct file *file, char __user *buf, size_t count, - loff_t *pos) +static ssize_t ps3flash_read(char __user *userbuf, void *kernelbuf, + size_t count, loff_t *pos) { struct ps3_storage_device *dev = ps3flash_dev; struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); u64 size, start_sector, end_sector, offset; ssize_t sectors_read; size_t remaining, n; + const void *src; dev_dbg(&dev->sbd.core, - "%s:%u: Reading %zu bytes at position %lld to user 0x%p\n", - __func__, __LINE__, count, *pos, buf); + "%s:%u: Reading %zu bytes at position %lld to U0x%p/K0x%p\n", + __func__, __LINE__, count, *pos, userbuf, kernelbuf); size = dev->regions[dev->region_idx].size*dev->blk_size; if (*pos >= size || !count) @@ -145,19 +146,26 @@ static ssize_t ps3flash_read(struct file *file, char __user *buf, size_t count, } n = min_t(u64, remaining, sectors_read*dev->blk_size-offset); + src = dev->bounce_buf+offset; dev_dbg(&dev->sbd.core, - "%s:%u: copy %lu bytes from 0x%p to user 0x%p\n", - __func__, __LINE__, n, dev->bounce_buf+offset, buf); - if (copy_to_user(buf, dev->bounce_buf+offset, n)) { - mutex_unlock(&priv->mutex); - sectors_read = -EFAULT; - goto fail; + "%s:%u: copy %lu bytes from 0x%p to U0x%p/K0x%p\n", + __func__, __LINE__, n, src, userbuf, kernelbuf); + if (userbuf) { + if (copy_to_user(userbuf, src, n)) { + mutex_unlock(&priv->mutex); + sectors_read = -EFAULT; + goto fail; + } + userbuf += n; + } + if (kernelbuf) { + memcpy(kernelbuf, src, n); + kernelbuf += n; } mutex_unlock(&priv->mutex); *pos += n; - buf += n; remaining -= n; start_sector += sectors_read; offset = 0; @@ -169,8 +177,8 @@ fail: return sectors_read; } -static ssize_t ps3flash_write(struct file *file, const char __user *buf, - size_t count, loff_t *pos) +static ssize_t ps3flash_write(const char __user *userbuf, + const void *kernelbuf, size_t count, loff_t *pos) { struct ps3_storage_device *dev = ps3flash_dev; struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); @@ -179,10 +187,11 @@ static ssize_t ps3flash_write(struct file *file, const char __user *buf, ssize_t res; size_t remaining, n; unsigned int sec_off; + void *dst; dev_dbg(&dev->sbd.core, - "%s:%u: Writing %zu bytes at position %lld from user 0x%p\n", - __func__, __LINE__, count, *pos, buf); + "%s:%u: Writing %zu bytes at position %lld from U0x%p/K0x%p\n", + __func__, __LINE__, count, *pos, userbuf, kernelbuf); size = dev->regions[dev->region_idx].size*dev->blk_size; if (*pos >= size || !count) @@ -259,12 +268,20 @@ static ssize_t ps3flash_write(struct file *file, const char __user *buf, } n = min_t(u64, remaining, dev->bounce_size-offset); + dst = dev->bounce_buf+offset; dev_dbg(&dev->sbd.core, - "%s:%u: copy %lu bytes from user 0x%p to 0x%p\n", - __func__, __LINE__, n, buf, dev->bounce_buf+offset); - if (copy_from_user(dev->bounce_buf+offset, buf, n)) { - res = -EFAULT; - goto fail; + "%s:%u: copy %lu bytes from U0x%p/K0x%p to 0x%p\n", + __func__, __LINE__, n, userbuf, kernelbuf, dst); + if (userbuf) { + if (copy_from_user(dst, userbuf, n)) { + res = -EFAULT; + goto fail; + } + userbuf += n; + } + if (kernelbuf) { + memcpy(dst, kernelbuf, n); + kernelbuf += n; } res = ps3flash_write_chunk(dev, start_write_sector); @@ -274,7 +291,6 @@ static ssize_t ps3flash_write(struct file *file, const char __user *buf, mutex_unlock(&priv->mutex); *pos += n; - buf += n; remaining -= n; start_write_sector += chunk_sectors; head = 0; @@ -288,6 +304,29 @@ fail: return res; } +static ssize_t ps3flash_user_read(struct file *file, char __user *buf, + size_t count, loff_t *pos) +{ + return ps3flash_read(buf, NULL, count, pos); +} + +static ssize_t ps3flash_user_write(struct file *file, const char __user *buf, + size_t count, loff_t *pos) +{ + return ps3flash_write(buf, NULL, count, pos); +} + +static ssize_t ps3flash_kernel_read(void *buf, size_t count, loff_t pos) +{ + return ps3flash_read(NULL, buf, count, &pos); +} + +static ssize_t ps3flash_kernel_write(const void *buf, size_t count, + loff_t pos) +{ + return ps3flash_write(NULL, buf, count, &pos); +} + static irqreturn_t ps3flash_interrupt(int irq, void *data) { @@ -312,12 +351,16 @@ static irqreturn_t ps3flash_interrupt(int irq, void *data) return IRQ_HANDLED; } - static const struct file_operations ps3flash_fops = { .owner = THIS_MODULE, .llseek = ps3flash_llseek, - .read = ps3flash_read, - .write = ps3flash_write, + .read = ps3flash_user_read, + .write = ps3flash_user_write, +}; + +static const struct ps3_os_area_flash_ops ps3flash_kernel_ops = { + .read = ps3flash_kernel_read, + .write = ps3flash_kernel_write, }; static struct miscdevice ps3flash_misc = { @@ -386,6 +429,8 @@ static int __devinit ps3flash_probe(struct ps3_system_bus_device *_dev) dev_info(&dev->sbd.core, "%s:%u: registered misc device %d\n", __func__, __LINE__, ps3flash_misc.minor); + + ps3_os_area_flash_register(&ps3flash_kernel_ops); return 0; fail_teardown: @@ -402,6 +447,7 @@ static int ps3flash_remove(struct ps3_system_bus_device *_dev) { struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core); + ps3_os_area_flash_register(NULL); misc_deregister(&ps3flash_misc); ps3stor_teardown(dev); kfree(ps3_system_bus_get_drvdata(&dev->sbd)); From 6bd57f2e5db408e0dfdb3bf052d58c4e7b18ed3c Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 10 Jun 2009 04:39:07 +0000 Subject: [PATCH 37/38] ps3flash: Cache the last accessed FLASH chunk Add support for caching, to reduce FLASH wear when writing using small blocksizes. As we also don't care anymore about heads and tails in case of partial writes, this greatly simplifies the code for handling writes. Note: We don't bother caching reads smaller than the FLASH chunk size (256 KiB). Signed-off-by: Geert Uytterhoeven Signed-off-by: Benjamin Herrenschmidt --- drivers/char/ps3flash.c | 209 ++++++++++++++++++++-------------------- 1 file changed, 104 insertions(+), 105 deletions(-) diff --git a/drivers/char/ps3flash.c b/drivers/char/ps3flash.c index f7f21f47ea02..d884d31491d2 100644 --- a/drivers/char/ps3flash.c +++ b/drivers/char/ps3flash.c @@ -33,13 +33,16 @@ struct ps3flash_private { struct mutex mutex; /* Bounce buffer mutex */ + u64 chunk_sectors; + int tag; /* Start sector of buffer, -1 if invalid */ + bool dirty; }; static struct ps3_storage_device *ps3flash_dev; -static ssize_t ps3flash_read_write_sectors(struct ps3_storage_device *dev, - u64 lpar, u64 start_sector, - u64 sectors, int write) +static int ps3flash_read_write_sectors(struct ps3_storage_device *dev, + u64 lpar, u64 start_sector, u64 sectors, + int write) { u64 res = ps3stor_read_write_sectors(dev, lpar, start_sector, sectors, write); @@ -48,33 +51,55 @@ static ssize_t ps3flash_read_write_sectors(struct ps3_storage_device *dev, __LINE__, write ? "write" : "read", res); return -EIO; } - return sectors; + return 0; } -static ssize_t ps3flash_read_sectors(struct ps3_storage_device *dev, - u64 start_sector, u64 sectors, - unsigned int sector_offset) +static int ps3flash_writeback(struct ps3_storage_device *dev) { - u64 max_sectors, lpar; + struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); + int res; - max_sectors = dev->bounce_size / dev->blk_size; - if (sectors > max_sectors) { - dev_dbg(&dev->sbd.core, "%s:%u Limiting sectors to %llu\n", - __func__, __LINE__, max_sectors); - sectors = max_sectors; - } + if (!priv->dirty || priv->tag < 0) + return 0; - lpar = dev->bounce_lpar + sector_offset * dev->blk_size; - return ps3flash_read_write_sectors(dev, lpar, start_sector, sectors, - 0); + res = ps3flash_read_write_sectors(dev, dev->bounce_lpar, priv->tag, + priv->chunk_sectors, 1); + if (res) + return res; + + priv->dirty = false; + return 0; } -static ssize_t ps3flash_write_chunk(struct ps3_storage_device *dev, - u64 start_sector) +static int ps3flash_fetch(struct ps3_storage_device *dev, u64 start_sector, + u64 sectors) { - u64 sectors = dev->bounce_size / dev->blk_size; - return ps3flash_read_write_sectors(dev, dev->bounce_lpar, start_sector, - sectors, 1); + struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); + unsigned int tag, offset; + u64 lpar; + int res; + + offset = start_sector % priv->chunk_sectors; + tag = start_sector - offset; + if (tag == priv->tag) + return 0; + + res = ps3flash_writeback(dev); + if (res) + return res; + + priv->tag = -1; + + lpar = dev->bounce_lpar + offset * dev->blk_size; + res = ps3flash_read_write_sectors(dev, lpar, start_sector, sectors, 0); + if (res) + return res; + + /* We don't bother caching reads smaller than the chunk size */ + if (sectors == priv->chunk_sectors) + priv->tag = tag; + + return 0; } static loff_t ps3flash_llseek(struct file *file, loff_t offset, int origin) @@ -109,8 +134,8 @@ static ssize_t ps3flash_read(char __user *userbuf, void *kernelbuf, { struct ps3_storage_device *dev = ps3flash_dev; struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); - u64 size, start_sector, end_sector, offset; - ssize_t sectors_read; + u64 size, start_sector, end_sector, offset, sectors; + int res; size_t remaining, n; const void *src; @@ -130,30 +155,29 @@ static ssize_t ps3flash_read(char __user *userbuf, void *kernelbuf, } start_sector = *pos / dev->blk_size; - offset = *pos % dev->blk_size; + offset = *pos % dev->bounce_size; end_sector = DIV_ROUND_UP(*pos + count, dev->blk_size); remaining = count; do { + sectors = min(end_sector - start_sector, + priv->chunk_sectors - + start_sector % priv->chunk_sectors); + mutex_lock(&priv->mutex); - sectors_read = ps3flash_read_sectors(dev, start_sector, - end_sector-start_sector, - 0); - if (sectors_read < 0) { - mutex_unlock(&priv->mutex); + res = ps3flash_fetch(dev, start_sector, sectors); + if (res) goto fail; - } - n = min_t(u64, remaining, sectors_read*dev->blk_size-offset); - src = dev->bounce_buf+offset; + n = min_t(u64, remaining, dev->bounce_size - offset); + src = dev->bounce_buf + offset; dev_dbg(&dev->sbd.core, "%s:%u: copy %lu bytes from 0x%p to U0x%p/K0x%p\n", __func__, __LINE__, n, src, userbuf, kernelbuf); if (userbuf) { if (copy_to_user(userbuf, src, n)) { - mutex_unlock(&priv->mutex); - sectors_read = -EFAULT; + res = -EFAULT; goto fail; } userbuf += n; @@ -167,14 +191,15 @@ static ssize_t ps3flash_read(char __user *userbuf, void *kernelbuf, *pos += n; remaining -= n; - start_sector += sectors_read; + start_sector += sectors; offset = 0; } while (remaining > 0); return count; fail: - return sectors_read; + mutex_unlock(&priv->mutex); + return res; } static ssize_t ps3flash_write(const char __user *userbuf, @@ -182,11 +207,9 @@ static ssize_t ps3flash_write(const char __user *userbuf, { struct ps3_storage_device *dev = ps3flash_dev; struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); - u64 size, chunk_sectors, start_write_sector, end_write_sector, - end_read_sector, start_read_sector, head, tail, offset; - ssize_t res; + u64 size, sector, offset; + int res = 0; size_t remaining, n; - unsigned int sec_off; void *dst; dev_dbg(&dev->sbd.core, @@ -204,71 +227,23 @@ static ssize_t ps3flash_write(const char __user *userbuf, count = size - *pos; } - chunk_sectors = dev->bounce_size / dev->blk_size; - - start_write_sector = *pos / dev->bounce_size * chunk_sectors; + sector = *pos / dev->bounce_size * priv->chunk_sectors; offset = *pos % dev->bounce_size; - end_write_sector = DIV_ROUND_UP(*pos + count, dev->bounce_size) * - chunk_sectors; - - end_read_sector = DIV_ROUND_UP(*pos, dev->blk_size); - start_read_sector = (*pos + count) / dev->blk_size; - - /* - * As we have to write in 256 KiB chunks, while we can read in blk_size - * (usually 512 bytes) chunks, we perform the following steps: - * 1. Read from start_write_sector to end_read_sector ("head") - * 2. Read from start_read_sector to end_write_sector ("tail") - * 3. Copy data to buffer - * 4. Write from start_write_sector to end_write_sector - * All of this is complicated by using only one 256 KiB bounce buffer. - */ - - head = end_read_sector - start_write_sector; - tail = end_write_sector - start_read_sector; remaining = count; do { + n = min_t(u64, remaining, dev->bounce_size - offset); + mutex_lock(&priv->mutex); - if (end_read_sector >= start_read_sector) { - /* Merge head and tail */ - dev_dbg(&dev->sbd.core, - "Merged head and tail: %llu sectors at %llu\n", - chunk_sectors, start_write_sector); - res = ps3flash_read_sectors(dev, start_write_sector, - chunk_sectors, 0); - if (res < 0) - goto fail; - } else { - if (head) { - /* Read head */ - dev_dbg(&dev->sbd.core, - "head: %llu sectors at %llu\n", head, - start_write_sector); - res = ps3flash_read_sectors(dev, - start_write_sector, - head, 0); - if (res < 0) - goto fail; - } - if (start_read_sector < - start_write_sector+chunk_sectors) { - /* Read tail */ - dev_dbg(&dev->sbd.core, - "tail: %llu sectors at %llu\n", tail, - start_read_sector); - sec_off = start_read_sector-start_write_sector; - res = ps3flash_read_sectors(dev, - start_read_sector, - tail, sec_off); - if (res < 0) - goto fail; - } - } + if (n != dev->bounce_size) + res = ps3flash_fetch(dev, sector, priv->chunk_sectors); + else if (sector != priv->tag) + res = ps3flash_writeback(dev); + if (res) + goto fail; - n = min_t(u64, remaining, dev->bounce_size-offset); - dst = dev->bounce_buf+offset; + dst = dev->bounce_buf + offset; dev_dbg(&dev->sbd.core, "%s:%u: copy %lu bytes from U0x%p/K0x%p to 0x%p\n", __func__, __LINE__, n, userbuf, kernelbuf, dst); @@ -284,16 +259,14 @@ static ssize_t ps3flash_write(const char __user *userbuf, kernelbuf += n; } - res = ps3flash_write_chunk(dev, start_write_sector); - if (res < 0) - goto fail; + priv->tag = sector; + priv->dirty = true; mutex_unlock(&priv->mutex); *pos += n; remaining -= n; - start_write_sector += chunk_sectors; - head = 0; + sector += priv->chunk_sectors; offset = 0; } while (remaining > 0); @@ -324,9 +297,31 @@ static ssize_t ps3flash_kernel_read(void *buf, size_t count, loff_t pos) static ssize_t ps3flash_kernel_write(const void *buf, size_t count, loff_t pos) { - return ps3flash_write(NULL, buf, count, &pos); + ssize_t res; + int wb; + + res = ps3flash_write(NULL, buf, count, &pos); + if (res < 0) + return res; + + /* Make kernel writes synchronous */ + wb = ps3flash_writeback(ps3flash_dev); + if (wb) + return wb; + + return res; } +static int ps3flash_flush(struct file *file, fl_owner_t id) +{ + return ps3flash_writeback(ps3flash_dev); +} + +static int ps3flash_fsync(struct file *file, struct dentry *dentry, + int datasync) +{ + return ps3flash_writeback(ps3flash_dev); +} static irqreturn_t ps3flash_interrupt(int irq, void *data) { @@ -356,6 +351,8 @@ static const struct file_operations ps3flash_fops = { .llseek = ps3flash_llseek, .read = ps3flash_user_read, .write = ps3flash_user_write, + .flush = ps3flash_flush, + .fsync = ps3flash_fsync, }; static const struct ps3_os_area_flash_ops ps3flash_kernel_ops = { @@ -411,9 +408,11 @@ static int __devinit ps3flash_probe(struct ps3_system_bus_device *_dev) ps3_system_bus_set_drvdata(&dev->sbd, priv); mutex_init(&priv->mutex); + priv->tag = -1; dev->bounce_size = ps3flash_bounce_buffer.size; dev->bounce_buf = ps3flash_bounce_buffer.address; + priv->chunk_sectors = dev->bounce_size / dev->blk_size; error = ps3stor_setup(dev, ps3flash_interrupt); if (error) From 42e27bfc4bfa42bd905e53be93d862b8e3d80a00 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 10 Jun 2009 04:39:08 +0000 Subject: [PATCH 38/38] ps3flash: Always read chunks of 256 KiB, and cache them Signed-off-by: Geert Uytterhoeven Signed-off-by: Benjamin Herrenschmidt --- drivers/char/ps3flash.c | 47 +++++++++++++++-------------------------- 1 file changed, 17 insertions(+), 30 deletions(-) diff --git a/drivers/char/ps3flash.c b/drivers/char/ps3flash.c index d884d31491d2..f424d394a286 100644 --- a/drivers/char/ps3flash.c +++ b/drivers/char/ps3flash.c @@ -41,10 +41,11 @@ struct ps3flash_private { static struct ps3_storage_device *ps3flash_dev; static int ps3flash_read_write_sectors(struct ps3_storage_device *dev, - u64 lpar, u64 start_sector, u64 sectors, - int write) + u64 start_sector, int write) { - u64 res = ps3stor_read_write_sectors(dev, lpar, start_sector, sectors, + struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); + u64 res = ps3stor_read_write_sectors(dev, dev->bounce_lpar, + start_sector, priv->chunk_sectors, write); if (res) { dev_err(&dev->sbd.core, "%s:%u: %s failed 0x%llx\n", __func__, @@ -62,8 +63,7 @@ static int ps3flash_writeback(struct ps3_storage_device *dev) if (!priv->dirty || priv->tag < 0) return 0; - res = ps3flash_read_write_sectors(dev, dev->bounce_lpar, priv->tag, - priv->chunk_sectors, 1); + res = ps3flash_read_write_sectors(dev, priv->tag, 1); if (res) return res; @@ -71,17 +71,12 @@ static int ps3flash_writeback(struct ps3_storage_device *dev) return 0; } -static int ps3flash_fetch(struct ps3_storage_device *dev, u64 start_sector, - u64 sectors) +static int ps3flash_fetch(struct ps3_storage_device *dev, u64 start_sector) { struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); - unsigned int tag, offset; - u64 lpar; int res; - offset = start_sector % priv->chunk_sectors; - tag = start_sector - offset; - if (tag == priv->tag) + if (start_sector == priv->tag) return 0; res = ps3flash_writeback(dev); @@ -90,15 +85,11 @@ static int ps3flash_fetch(struct ps3_storage_device *dev, u64 start_sector, priv->tag = -1; - lpar = dev->bounce_lpar + offset * dev->blk_size; - res = ps3flash_read_write_sectors(dev, lpar, start_sector, sectors, 0); + res = ps3flash_read_write_sectors(dev, start_sector, 0); if (res) return res; - /* We don't bother caching reads smaller than the chunk size */ - if (sectors == priv->chunk_sectors) - priv->tag = tag; - + priv->tag = start_sector; return 0; } @@ -134,7 +125,7 @@ static ssize_t ps3flash_read(char __user *userbuf, void *kernelbuf, { struct ps3_storage_device *dev = ps3flash_dev; struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); - u64 size, start_sector, end_sector, offset, sectors; + u64 size, sector, offset; int res; size_t remaining, n; const void *src; @@ -154,24 +145,20 @@ static ssize_t ps3flash_read(char __user *userbuf, void *kernelbuf, count = size - *pos; } - start_sector = *pos / dev->blk_size; + sector = *pos / dev->bounce_size * priv->chunk_sectors; offset = *pos % dev->bounce_size; - end_sector = DIV_ROUND_UP(*pos + count, dev->blk_size); remaining = count; do { - sectors = min(end_sector - start_sector, - priv->chunk_sectors - - start_sector % priv->chunk_sectors); + n = min_t(u64, remaining, dev->bounce_size - offset); + src = dev->bounce_buf + offset; mutex_lock(&priv->mutex); - res = ps3flash_fetch(dev, start_sector, sectors); + res = ps3flash_fetch(dev, sector); if (res) goto fail; - n = min_t(u64, remaining, dev->bounce_size - offset); - src = dev->bounce_buf + offset; dev_dbg(&dev->sbd.core, "%s:%u: copy %lu bytes from 0x%p to U0x%p/K0x%p\n", __func__, __LINE__, n, src, userbuf, kernelbuf); @@ -191,7 +178,7 @@ static ssize_t ps3flash_read(char __user *userbuf, void *kernelbuf, *pos += n; remaining -= n; - start_sector += sectors; + sector += priv->chunk_sectors; offset = 0; } while (remaining > 0); @@ -233,17 +220,17 @@ static ssize_t ps3flash_write(const char __user *userbuf, remaining = count; do { n = min_t(u64, remaining, dev->bounce_size - offset); + dst = dev->bounce_buf + offset; mutex_lock(&priv->mutex); if (n != dev->bounce_size) - res = ps3flash_fetch(dev, sector, priv->chunk_sectors); + res = ps3flash_fetch(dev, sector); else if (sector != priv->tag) res = ps3flash_writeback(dev); if (res) goto fail; - dst = dev->bounce_buf + offset; dev_dbg(&dev->sbd.core, "%s:%u: copy %lu bytes from U0x%p/K0x%p to 0x%p\n", __func__, __LINE__, n, userbuf, kernelbuf, dst);