diff options
37 files changed, 873 insertions, 527 deletions
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 93a6189..9fb344d 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 @@ -129,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/boot/install.sh b/arch/powerpc/boot/install.sh index 51b2387..98312d1 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 diff --git a/arch/powerpc/include/asm/atomic.h b/arch/powerpc/include/asm/atomic.h index b7d2d07..4012483 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 <asm-generic/atomic64.h> + #endif /* __powerpc64__ */ #include <asm-generic/atomic-long.h> diff --git a/arch/powerpc/include/asm/hw_irq.h b/arch/powerpc/include/asm/hw_irq.h index 5351237..b7f8f4a 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/iommu.h b/arch/powerpc/include/asm/iommu.h index 7464c0d..7ead7c1 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/include/asm/ps3.h b/arch/powerpc/include/asm/ps3.h index cdb6fd8..7f065e1 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 { @@ -418,15 +425,15 @@ 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->core.driver_data = 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->core.driver_data; + return dev_get_drvdata(&dev->core); } /* These two need global scope for get_dma_ops(). */ @@ -520,7 +527,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 0000000..b2b8959 --- /dev/null +++ b/arch/powerpc/include/asm/ps3gpu.h @@ -0,0 +1,86 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef _ASM_POWERPC_PS3GPU_H +#define _ASM_POWERPC_PS3GPU_H + +#include <linux/mutex.h> + +#include <asm/lv1call.h> + + +#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_CONTEXT_ATTRIBUTE_FB_CLOSE 0x603 + +#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); +} + +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/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index fb359b0..a3c28e4 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; \ diff --git a/arch/powerpc/include/asm/systbl.h b/arch/powerpc/include/asm/systbl.h index a0b92de..370600c 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 4badac2..cef080b 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 diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index a7def5f..612b0c4 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 diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index f46548e..1f68160 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"); diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index bee1443..15391c2 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -52,6 +52,7 @@ #include <linux/jiffies.h> #include <linux/posix-timers.h> #include <linux/irq.h> +#include <linux/delay.h> #include <asm/io.h> #include <asm/processor.h> @@ -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; diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c index 0ce45c2..c71498d 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; diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c index bed4690..5b34fc2 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/iseries/dt.c b/arch/powerpc/platforms/iseries/dt.c index 4543c4b..c5a87a7 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)); diff --git a/arch/powerpc/platforms/iseries/mf.c b/arch/powerpc/platforms/iseries/mf.c index 3689c24..fef4d51 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; diff --git a/arch/powerpc/platforms/ps3/mm.c b/arch/powerpc/platforms/ps3/mm.c index 9a2b6d9..846eb8b 100644 --- a/arch/powerpc/platforms/ps3/mm.c +++ b/arch/powerpc/platforms/ps3/mm.c @@ -24,6 +24,7 @@ #include <linux/lmb.h> #include <asm/firmware.h> +#include <asm/iommu.h> #include <asm/prom.h> #include <asm/udbg.h> #include <asm/lv1call.h> @@ -605,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__, @@ -1001,7 +1001,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 +1015,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/os-area.c b/arch/powerpc/platforms/ps3/os-area.c index cf1cd0f..d6487a9 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__); } @@ -808,7 +820,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 +836,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. diff --git a/arch/powerpc/platforms/ps3/platform.h b/arch/powerpc/platforms/ps3/platform.h index 136aa06..9a196a8 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/setup.c b/arch/powerpc/platforms/ps3/setup.c index 1a7b5ae..149bea2 100644 --- a/arch/powerpc/platforms/ps3/setup.c +++ b/arch/powerpc/platforms/ps3/setup.c @@ -32,6 +32,7 @@ #include <asm/udbg.h> #include <asm/prom.h> #include <asm/lv1call.h> +#include <asm/ps3gpu.h> #include "platform.h" diff --git a/arch/powerpc/platforms/ps3/system-bus.c b/arch/powerpc/platforms/ps3/system-bus.c index 9a73d02..9fead0f 100644 --- a/arch/powerpc/platforms/ps3/system-bus.c +++ b/arch/powerpc/platforms/ps3/system-bus.c @@ -27,6 +27,7 @@ #include <asm/udbg.h> #include <asm/lv1call.h> #include <asm/firmware.h> +#include <asm/iommu.h> #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 */ diff --git a/drivers/block/ps3disk.c b/drivers/block/ps3disk.c index aaeeb54..34cbb7f 100644 --- a/drivers/block/ps3disk.c +++ b/drivers/block/ps3disk.c @@ -120,7 +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 = dev->sbd.core.driver_data; + 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; @@ -168,7 +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 = dev->sbd.core.driver_data; + 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__); @@ -213,7 +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 = dev->sbd.core.driver_data; + 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__); @@ -245,7 +245,7 @@ static irqreturn_t ps3disk_interrupt(int irq, void *data) return IRQ_HANDLED; } - priv = dev->sbd.core.driver_data; + priv = ps3_system_bus_get_drvdata(&dev->sbd); req = priv->req; if (!req) { dev_dbg(&dev->sbd.core, @@ -364,7 +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 = dev->sbd.core.driver_data; + 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; @@ -445,7 +445,7 @@ static int __devinit ps3disk_probe(struct ps3_system_bus_device *_dev) goto fail; } - dev->sbd.core.driver_data = priv; + ps3_system_bus_set_drvdata(_dev, priv); spin_lock_init(&priv->lock); dev->bounce_size = BOUNCE_SIZE; @@ -523,7 +523,7 @@ fail_free_bounce: kfree(dev->bounce_buf); fail_free_priv: kfree(priv); - dev->sbd.core.driver_data = NULL; + ps3_system_bus_set_drvdata(_dev, NULL); fail: mutex_lock(&ps3disk_mask_mutex); __clear_bit(devidx, &ps3disk_mask); @@ -534,7 +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 = dev->sbd.core.driver_data; + 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, @@ -548,7 +548,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_drvdata(_dev, NULL); return 0; } diff --git a/drivers/block/ps3vram.c b/drivers/block/ps3vram.c index 8eddef3..095f97e 100644 --- a/drivers/block/ps3vram.c +++ b/drivers/block/ps3vram.c @@ -14,8 +14,10 @@ #include <linux/seq_file.h> #include <asm/firmware.h> +#include <asm/iommu.h> #include <asm/lv1call.h> #include <asm/ps3.h> +#include <asm/ps3gpu.h> #define DEVICE_NAME "ps3vram" @@ -45,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 @@ -72,8 +72,7 @@ struct ps3vram_priv { u64 memory_handle; u64 context_handle; u32 *ctrl; - u32 *reports; - u8 __iomem *ddr_base; + void *reports; u8 *xdr_buf; u32 *fifo_base; @@ -81,8 +80,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; }; @@ -103,15 +102,15 @@ 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; } 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_drvdata(dev); u32 *notify = ps3vram_get_notifier(priv->reports, NOTIFIER); int i; @@ -122,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_drvdata(dev); u32 *notify = ps3vram_get_notifier(priv->reports, NOTIFIER); unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms); @@ -137,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_drvdata(dev); priv->ctrl[CTRL_PUT] = FIFO_BASE + FIFO_OFFSET; priv->ctrl[CTRL_GET] = FIFO_BASE + FIFO_OFFSET; @@ -146,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_drvdata(dev); unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms); do { @@ -175,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_drvdata(dev); int status; ps3vram_out_ring(priv, 0x20000000 | (FIFO_BASE + FIFO_OFFSET)); @@ -183,20 +182,17 @@ 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; } 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_drvdata(dev); int status; mutex_lock(&ps3_gpu_mutex); @@ -205,13 +201,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) { @@ -225,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_drvdata(dev); ps3vram_begin_ring(priv, UPLOAD_SUBCH, 0, 1); ps3vram_out_ring(priv, 0x31337303); @@ -248,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_drvdata(dev); ps3vram_begin_ring(priv, UPLOAD_SUBCH, NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8); @@ -280,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_drvdata(dev); ps3vram_begin_ring(priv, DOWNLOAD_SUBCH, NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8); @@ -310,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_drvdata(dev); struct ps3vram_cache *cache = &priv->cache; if (!(cache->tags[entry].flags & CACHE_PAGE_DIRTY)) @@ -332,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_drvdata(dev); struct ps3vram_cache *cache = &priv->cache; dev_dbg(&dev->core, "Fetching %d: 0x%08x\n", entry, address); @@ -352,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_drvdata(dev); struct ps3vram_cache *cache = &priv->cache; int i; @@ -366,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_drvdata(dev); struct ps3vram_cache *cache = &priv->cache; unsigned int base; unsigned int offset; @@ -400,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_drvdata(dev); priv->cache.page_count = CACHE_PAGE_COUNT; priv->cache.page_size = CACHE_PAGE_SIZE; @@ -419,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_drvdata(dev); ps3vram_cache_flush(dev); kfree(priv->cache.tags); @@ -428,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_drvdata(dev); unsigned int cached, count; dev_dbg(&dev->core, "%s: from=0x%08x len=0x%zx\n", __func__, @@ -449,8 +442,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; @@ -462,8 +453,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; @@ -476,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_drvdata(dev); unsigned int cached, count; if (to >= priv->size) @@ -494,8 +483,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; @@ -509,8 +496,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; @@ -543,28 +528,26 @@ 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_drvdata(dev); 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) +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 = 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; 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 */ @@ -585,6 +568,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; } @@ -594,7 +578,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 = ps3_system_bus_get_drvdata(dev); + 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; } @@ -604,8 +616,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); @@ -614,10 +626,9 @@ static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev) goto fail; } - mutex_init(&priv->lock); - dev->core.driver_data = priv; - - priv = dev->core.driver_data; + spin_lock_init(&priv->lock); + bio_list_init(&priv->list); + ps3_system_bus_set_drvdata(dev, priv); /* Allocate XDR buffer (1MiB aligned) */ priv->xdr_buf = (void *)__get_free_pages(GFP_KERNEL, @@ -636,7 +647,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 */ @@ -660,7 +671,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 */ @@ -676,9 +687,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); @@ -686,19 +699,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_free_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); @@ -775,8 +780,9 @@ 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); out_free_context: lv1_gpu_context_free(priv->context_handle); out_free_memory: @@ -787,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_drvdata(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_drvdata(dev); del_gendisk(priv->gendisk); put_disk(priv->gendisk); @@ -803,13 +809,15 @@ 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); lv1_gpu_context_free(priv->context_handle); lv1_gpu_memory_free(priv->memory_handle); 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_drvdata(dev, NULL); return 0; } diff --git a/drivers/char/ps3flash.c b/drivers/char/ps3flash.c index afbe456..f424d39 100644 --- a/drivers/char/ps3flash.c +++ b/drivers/char/ps3flash.c @@ -33,48 +33,64 @@ 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 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__, __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, priv->tag, 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 = 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); + int res; + + if (start_sector == priv->tag) + return 0; + + res = ps3flash_writeback(dev); + if (res) + return res; + + priv->tag = -1; + + res = ps3flash_read_write_sectors(dev, start_sector, 0); + if (res) + return res; + + priv->tag = start_sector; + return 0; } static loff_t ps3flash_llseek(struct file *file, loff_t offset, int origin) @@ -104,18 +120,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 = dev->sbd.core.driver_data; - u64 size, start_sector, end_sector, offset; - ssize_t sectors_read; + struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); + u64 size, sector, offset; + int res; 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) @@ -128,61 +145,63 @@ static ssize_t ps3flash_read(struct file *file, char __user *buf, size_t count, count = size - *pos; } - start_sector = *pos / dev->blk_size; - offset = *pos % dev->blk_size; - end_sector = DIV_ROUND_UP(*pos + count, dev->blk_size); + sector = *pos / dev->bounce_size * priv->chunk_sectors; + offset = *pos % dev->bounce_size; remaining = count; do { + n = min_t(u64, remaining, dev->bounce_size - offset); + src = dev->bounce_buf + offset; + 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, sector); + if (res) goto fail; - } - n = min_t(u64, remaining, sectors_read*dev->blk_size-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)) { + res = -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; + sector += priv->chunk_sectors; offset = 0; } while (remaining > 0); return count; fail: - return sectors_read; + mutex_unlock(&priv->mutex); + return res; } -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 = dev->sbd.core.driver_data; - u64 size, chunk_sectors, start_write_sector, end_write_sector, - end_read_sector, start_read_sector, head, tail, offset; - ssize_t res; + struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); + u64 size, sector, offset; + int res = 0; 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) @@ -195,89 +214,46 @@ static ssize_t ps3flash_write(struct file *file, const char __user *buf, 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); + dst = dev->bounce_buf + 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) + if (n != dev->bounce_size) + res = ps3flash_fetch(dev, sector); + else if (sector != priv->tag) + res = ps3flash_writeback(dev); + if (res) + goto fail; + + 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); + if (userbuf) { + if (copy_from_user(dst, userbuf, n)) { + res = -EFAULT; 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; } + userbuf += n; } - - n = min_t(u64, remaining, dev->bounce_size-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; + if (kernelbuf) { + memcpy(dst, kernelbuf, n); + 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; - buf += n; remaining -= n; - start_write_sector += chunk_sectors; - head = 0; + sector += priv->chunk_sectors; offset = 0; } while (remaining > 0); @@ -288,6 +264,51 @@ 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) +{ + 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) { @@ -312,12 +333,18 @@ 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, + .flush = ps3flash_flush, + .fsync = ps3flash_fsync, +}; + +static const struct ps3_os_area_flash_ops ps3flash_kernel_ops = { + .read = ps3flash_kernel_read, + .write = ps3flash_kernel_write, }; static struct miscdevice ps3flash_misc = { @@ -366,11 +393,13 @@ 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); + 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) @@ -386,13 +415,15 @@ 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: 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; @@ -402,10 +433,11 @@ 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(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; } diff --git a/drivers/net/ps3_gelic_net.c b/drivers/net/ps3_gelic_net.c index 30900b3..2b38f39 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/ps3/ps3-sys-manager.c b/drivers/ps3/ps3-sys-manager.c index f17513d..88cb740 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 235e87f..e82d8c9 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}, @@ -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; diff --git a/drivers/ps3/ps3av_cmd.c b/drivers/ps3/ps3av_cmd.c index 716596e..f555fed 100644 --- a/drivers/ps3/ps3av_cmd.c +++ b/drivers/ps3/ps3av_cmd.c @@ -21,9 +21,10 @@ #include <linux/module.h> #include <linux/kernel.h> #include <linux/delay.h> + #include <asm/ps3av.h> -#include <asm/ps3fb.h> #include <asm/ps3.h> +#include <asm/ps3gpu.h> #include "vuart.h" diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c index 1ba9f9a..bb870b8 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 3d19103..1d56259 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); diff --git a/drivers/video/ps3fb.c b/drivers/video/ps3fb.c index e00c1df..c0af638 100644 --- a/drivers/video/ps3fb.c +++ b/drivers/video/ps3fb.c @@ -32,25 +32,16 @@ #include <linux/init.h> #include <asm/abs_addr.h> +#include <asm/iommu.h> #include <asm/lv1call.h> #include <asm/ps3av.h> #include <asm/ps3fb.h> #include <asm/ps3.h> +#include <asm/ps3gpu.h> #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) @@ -462,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 } @@ -956,73 +941,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,49 +966,18 @@ 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; struct ps3fb_par *par; - int retval = -ENOMEM; + int retval; u64 ddr_lpar = 0; u64 lpar_dma_control = 0; u64 lpar_driver_info = 0; 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; @@ -1101,8 +988,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; @@ -1116,7 +1003,24 @@ 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_display_sync(0x0, 0, L1GPU_DISPLAY_SYNC_VSYNC); + if (status) { + 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_display_sync(0x0, 1, L1GPU_DISPLAY_SYNC_VSYNC); + if (status) { + dev_err(&dev->core, "%s: lv1_gpu_display_sync failed: %d\n", + __func__, status); + retval = -ENODEV; + goto err_close_device; + } +#endif max_ps3fb_size = _ALIGN_UP(GPU_IOIF, 256*1024*1024) - GPU_IOIF; if (ps3fb_videomemory.size > max_ps3fb_size) { @@ -1131,7 +1035,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); @@ -1141,33 +1045,85 @@ 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; } /* 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, + 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); + 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_fb_setup(ps3fb.context_handle, xdr_lpar, + GPU_CMD_BUF_SIZE, GPU_IOIF); + if (status) { + dev_err(&dev->core, "%s: lv1_gpu_fb_setup failed: %d\n", + __func__, status); + retval = -ENXIO; + goto err_context_unmap; + } info = framebuffer_alloc(sizeof(struct ps3fb_par), &dev->core); if (!info) - goto err_free_irq; + goto err_context_fb_close; par = info->par; par->mode_id = ~ps3fb_mode; /* != ps3fb_mode, to trigger change */ @@ -1210,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), @@ -1232,8 +1188,14 @@ 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); 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); @@ -1241,14 +1203,16 @@ 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; } static int ps3fb_shutdown(struct ps3_system_bus_device *dev) { - int status; - 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__); @@ -1268,20 +1232,14 @@ 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); - - 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_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); + lv1_gpu_memory_free(ps3fb.memory_handle); ps3_close_hv_device(dev); dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__); diff --git a/include/asm-generic/atomic64.h b/include/asm-generic/atomic64.h new file mode 100644 index 0000000..b18ce4f --- /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. <paulus@au1.ibm.com> + * + * 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/include/linux/bio.h b/include/linux/bio.h index 12737be..2a04eb5 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; diff --git a/lib/Kconfig b/lib/Kconfig index 9960be0..bb1326d 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 34c5c0e..8e9bcf9 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 0000000..c5e7255 --- /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. <paulus@au1.ibm.com> + * + * 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 <linux/types.h> +#include <linux/cache.h> +#include <linux/spinlock.h> +#include <linux/init.h> +#include <asm/atomic.h> + +/* + * 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); |