Merge branch 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc
* 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc: (38 commits) ps3flash: Always read chunks of 256 KiB, and cache them ps3flash: Cache the last accessed FLASH chunk ps3: Replace direct file operations by callback ps3: Switch ps3_os_area_[gs]et_rtc_diff to EXPORT_SYMBOL_GPL() ps3: Correct debug message in dma_ioc0_map_pages() drivers/ps3: Add missing annotations ps3fb: Use ps3_system_bus_[gs]et_drvdata() instead of direct access ps3flash: Use ps3_system_bus_[gs]et_drvdata() instead of direct access ps3: shorten ps3_system_bus_[gs]et_driver_data to ps3_system_bus_[gs]et_drvdata ps3: Use dev_[gs]et_drvdata() instead of direct access for system bus devices block/ps3: remove driver_data direct access of struct device ps3vram: Make ps3vram_priv.reports a void * ps3vram: Remove no longer used ps3vram_priv.ddr_base ps3vram: Replace mutex by spinlock + bio_list block: Add bio_list_peek() powerpc: Use generic atomic64_t implementation on 32-bit processors lib: Provide generic atomic64_t implementation powerpc: Add compiler memory barrier to mtmsr macro powerpc/iseries: Mark signal_vsp_instruction() as maybe unused powerpc/iseries: Fix unused function warning in iSeries DT code ...
This commit is contained in:
commit
609106b9ac
|
@ -93,10 +93,6 @@ config GENERIC_HWEIGHT
|
||||||
bool
|
bool
|
||||||
default y
|
default y
|
||||||
|
|
||||||
config GENERIC_CALIBRATE_DELAY
|
|
||||||
bool
|
|
||||||
default y
|
|
||||||
|
|
||||||
config GENERIC_FIND_NEXT_BIT
|
config GENERIC_FIND_NEXT_BIT
|
||||||
bool
|
bool
|
||||||
default y
|
default y
|
||||||
|
@ -129,6 +125,7 @@ config PPC
|
||||||
select USE_GENERIC_SMP_HELPERS if SMP
|
select USE_GENERIC_SMP_HELPERS if SMP
|
||||||
select HAVE_OPROFILE
|
select HAVE_OPROFILE
|
||||||
select HAVE_SYSCALL_WRAPPERS if PPC64
|
select HAVE_SYSCALL_WRAPPERS if PPC64
|
||||||
|
select GENERIC_ATOMIC64 if PPC32
|
||||||
|
|
||||||
config EARLY_PRINTK
|
config EARLY_PRINTK
|
||||||
bool
|
bool
|
||||||
|
|
|
@ -18,6 +18,9 @@
|
||||||
# $5 and more - kernel boot files; zImage*, uImage, cuImage.*, etc.
|
# $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
|
# User may have a custom install script
|
||||||
|
|
||||||
if [ -x ~/bin/${CROSS_COMPILE}installkernel ]; then exec ~/bin/${CROSS_COMPILE}installkernel "$@"; fi
|
if [ -x ~/bin/${CROSS_COMPILE}installkernel ]; then exec ~/bin/${CROSS_COMPILE}installkernel "$@"; fi
|
||||||
|
|
|
@ -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)
|
#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
|
||||||
|
|
||||||
|
#else /* __powerpc64__ */
|
||||||
|
#include <asm-generic/atomic64.h>
|
||||||
|
|
||||||
#endif /* __powerpc64__ */
|
#endif /* __powerpc64__ */
|
||||||
|
|
||||||
#include <asm-generic/atomic-long.h>
|
#include <asm-generic/atomic-long.h>
|
||||||
|
|
|
@ -80,7 +80,7 @@ static inline void local_irq_disable(void)
|
||||||
__asm__ __volatile__("wrteei 0": : :"memory");
|
__asm__ __volatile__("wrteei 0": : :"memory");
|
||||||
#else
|
#else
|
||||||
unsigned long msr;
|
unsigned long msr;
|
||||||
__asm__ __volatile__("": : :"memory");
|
|
||||||
msr = mfmsr();
|
msr = mfmsr();
|
||||||
SET_MSR_EE(msr & ~MSR_EE);
|
SET_MSR_EE(msr & ~MSR_EE);
|
||||||
#endif
|
#endif
|
||||||
|
@ -92,7 +92,7 @@ static inline void local_irq_enable(void)
|
||||||
__asm__ __volatile__("wrteei 1": : :"memory");
|
__asm__ __volatile__("wrteei 1": : :"memory");
|
||||||
#else
|
#else
|
||||||
unsigned long msr;
|
unsigned long msr;
|
||||||
__asm__ __volatile__("": : :"memory");
|
|
||||||
msr = mfmsr();
|
msr = mfmsr();
|
||||||
SET_MSR_EE(msr | MSR_EE);
|
SET_MSR_EE(msr | MSR_EE);
|
||||||
#endif
|
#endif
|
||||||
|
@ -108,7 +108,6 @@ static inline void local_irq_save_ptr(unsigned long *flags)
|
||||||
#else
|
#else
|
||||||
SET_MSR_EE(msr & ~MSR_EE);
|
SET_MSR_EE(msr & ~MSR_EE);
|
||||||
#endif
|
#endif
|
||||||
__asm__ __volatile__("": : :"memory");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define local_save_flags(flags) ((flags) = mfmsr())
|
#define local_save_flags(flags) ((flags) = mfmsr())
|
||||||
|
|
|
@ -35,6 +35,16 @@
|
||||||
#define IOMMU_PAGE_MASK (~((1 << IOMMU_PAGE_SHIFT) - 1))
|
#define IOMMU_PAGE_MASK (~((1 << IOMMU_PAGE_SHIFT) - 1))
|
||||||
#define IOMMU_PAGE_ALIGN(addr) _ALIGN_UP(addr, IOMMU_PAGE_SIZE)
|
#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 */
|
/* Boot time flags */
|
||||||
extern int iommu_is_off;
|
extern int iommu_is_off;
|
||||||
extern int iommu_force_on;
|
extern int iommu_force_on;
|
||||||
|
|
|
@ -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 u64 ps3_os_area_get_rtc_diff(void);
|
||||||
extern void ps3_os_area_set_rtc_diff(u64 rtc_diff);
|
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 */
|
/* dma routines */
|
||||||
|
|
||||||
enum ps3_dma_page_size {
|
enum ps3_dma_page_size {
|
||||||
|
@ -418,15 +425,15 @@ static inline struct ps3_system_bus_driver *
|
||||||
* @data: Data to set
|
* @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)
|
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)
|
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(). */
|
/* 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);
|
u32 ps3_get_hw_thread_id(int cpu);
|
||||||
u64 ps3_get_spe_id(void *arg);
|
u64 ps3_get_spe_id(void *arg);
|
||||||
|
|
||||||
/* mutex synchronizing GPU accesses and video mode changes */
|
|
||||||
extern struct mutex ps3_gpu_mutex;
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -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 */
|
|
@ -745,11 +745,11 @@
|
||||||
asm volatile("mfmsr %0" : "=r" (rval)); rval;})
|
asm volatile("mfmsr %0" : "=r" (rval)); rval;})
|
||||||
#ifdef CONFIG_PPC64
|
#ifdef CONFIG_PPC64
|
||||||
#define __mtmsrd(v, l) asm volatile("mtmsrd %0," __stringify(l) \
|
#define __mtmsrd(v, l) asm volatile("mtmsrd %0," __stringify(l) \
|
||||||
: : "r" (v))
|
: : "r" (v) : "memory")
|
||||||
#define mtmsrd(v) __mtmsrd((v), 0)
|
#define mtmsrd(v) __mtmsrd((v), 0)
|
||||||
#define mtmsr(v) mtmsrd(v)
|
#define mtmsr(v) mtmsrd(v)
|
||||||
#else
|
#else
|
||||||
#define mtmsr(v) asm volatile("mtmsr %0" : : "r" (v))
|
#define mtmsr(v) asm volatile("mtmsr %0" : : "r" (v) : "memory")
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define mfspr(rn) ({unsigned long rval; \
|
#define mfspr(rn) ({unsigned long rval; \
|
||||||
|
|
|
@ -325,3 +325,4 @@ SYSCALL(inotify_init1)
|
||||||
SYSCALL_SPU(perf_counter_open)
|
SYSCALL_SPU(perf_counter_open)
|
||||||
COMPAT_SYS_SPU(preadv)
|
COMPAT_SYS_SPU(preadv)
|
||||||
COMPAT_SYS_SPU(pwritev)
|
COMPAT_SYS_SPU(pwritev)
|
||||||
|
COMPAT_SYS(rt_tgsigqueueinfo)
|
||||||
|
|
|
@ -344,10 +344,11 @@
|
||||||
#define __NR_perf_counter_open 319
|
#define __NR_perf_counter_open 319
|
||||||
#define __NR_preadv 320
|
#define __NR_preadv 320
|
||||||
#define __NR_pwritev 321
|
#define __NR_pwritev 321
|
||||||
|
#define __NR_rt_tgsigqueueinfo 322
|
||||||
|
|
||||||
#ifdef __KERNEL__
|
#ifdef __KERNEL__
|
||||||
|
|
||||||
#define __NR_syscalls 322
|
#define __NR_syscalls 323
|
||||||
|
|
||||||
#define __NR__exit __NR_exit
|
#define __NR__exit __NR_exit
|
||||||
#define NR_syscalls __NR_syscalls
|
#define NR_syscalls __NR_syscalls
|
||||||
|
|
|
@ -125,6 +125,7 @@ PHONY += systbl_chk
|
||||||
systbl_chk: $(src)/systbl_chk.sh $(obj)/systbl_chk.i
|
systbl_chk: $(src)/systbl_chk.sh $(obj)/systbl_chk.i
|
||||||
$(call cmd,systbl_chk)
|
$(call cmd,systbl_chk)
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_PPC_OF_BOOT_TRAMPOLINE),y)
|
||||||
$(obj)/built-in.o: prom_init_check
|
$(obj)/built-in.o: prom_init_check
|
||||||
|
|
||||||
quiet_cmd_prom_init_check = CALL $<
|
quiet_cmd_prom_init_check = CALL $<
|
||||||
|
@ -133,5 +134,6 @@ quiet_cmd_prom_init_check = CALL $<
|
||||||
PHONY += prom_init_check
|
PHONY += prom_init_check
|
||||||
prom_init_check: $(src)/prom_init_check.sh $(obj)/prom_init.o
|
prom_init_check: $(src)/prom_init_check.sh $(obj)/prom_init.o
|
||||||
$(call cmd,prom_init_check)
|
$(call cmd,prom_init_check)
|
||||||
|
endif
|
||||||
|
|
||||||
clean-files := vmlinux.lds
|
clean-files := vmlinux.lds
|
||||||
|
|
|
@ -424,8 +424,8 @@ void __init setup_system(void)
|
||||||
printk("htab_hash_mask = 0x%lx\n", htab_hash_mask);
|
printk("htab_hash_mask = 0x%lx\n", htab_hash_mask);
|
||||||
#endif /* CONFIG_PPC_STD_MMU_64 */
|
#endif /* CONFIG_PPC_STD_MMU_64 */
|
||||||
if (PHYSICAL_START > 0)
|
if (PHYSICAL_START > 0)
|
||||||
printk("physical_start = 0x%lx\n",
|
printk("physical_start = 0x%llx\n",
|
||||||
PHYSICAL_START);
|
(unsigned long long)PHYSICAL_START);
|
||||||
printk("-----------------------------------------------------\n");
|
printk("-----------------------------------------------------\n");
|
||||||
|
|
||||||
DBG(" <- setup_system()\n");
|
DBG(" <- setup_system()\n");
|
||||||
|
|
|
@ -52,6 +52,7 @@
|
||||||
#include <linux/jiffies.h>
|
#include <linux/jiffies.h>
|
||||||
#include <linux/posix-timers.h>
|
#include <linux/posix-timers.h>
|
||||||
#include <linux/irq.h>
|
#include <linux/irq.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
|
||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
#include <asm/processor.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)
|
static int __init rtc_init(void)
|
||||||
{
|
{
|
||||||
struct platform_device *pdev;
|
struct platform_device *pdev;
|
||||||
|
|
|
@ -329,7 +329,7 @@ static struct irq_host_ops msic_host_ops = {
|
||||||
|
|
||||||
static int axon_msi_shutdown(struct of_device *device)
|
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;
|
u32 tmp;
|
||||||
|
|
||||||
pr_debug("axon_msi: disabling %s\n",
|
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->read_offset = dcr_read(msic->dcr_host, MSIC_WRITE_OFFSET_REG)
|
||||||
& MSIC_FIFO_SIZE_MASK;
|
& 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.setup_msi_irqs = axon_msi_setup_msi_irqs;
|
||||||
ppc_md.teardown_msi_irqs = axon_msi_teardown_msi_irqs;
|
ppc_md.teardown_msi_irqs = axon_msi_teardown_msi_irqs;
|
||||||
|
|
|
@ -100,16 +100,6 @@
|
||||||
#define IOSTE_PS_1M 0x0000000000000005ul /* - 1MB */
|
#define IOSTE_PS_1M 0x0000000000000005ul /* - 1MB */
|
||||||
#define IOSTE_PS_16M 0x0000000000000007ul /* - 16MB */
|
#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 */
|
/* IOMMU sizing */
|
||||||
#define IO_SEGMENT_SHIFT 28
|
#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;
|
const unsigned long prot = 0xc48;
|
||||||
base_pte =
|
base_pte =
|
||||||
((prot << (52 + 4 * direction)) & (IOPTE_PP_W | IOPTE_PP_R))
|
((prot << (52 + 4 * direction)) &
|
||||||
| IOPTE_M | IOPTE_SO_RW | (window->ioid & IOPTE_IOID_Mask);
|
(CBE_IOPTE_PP_W | CBE_IOPTE_PP_R)) |
|
||||||
|
CBE_IOPTE_M | CBE_IOPTE_SO_RW |
|
||||||
|
(window->ioid & CBE_IOPTE_IOID_Mask);
|
||||||
#else
|
#else
|
||||||
base_pte = IOPTE_PP_W | IOPTE_PP_R | IOPTE_M | IOPTE_SO_RW |
|
base_pte = CBE_IOPTE_PP_W | CBE_IOPTE_PP_R | CBE_IOPTE_M |
|
||||||
(window->ioid & IOPTE_IOID_Mask);
|
CBE_IOPTE_SO_RW | (window->ioid & CBE_IOPTE_IOID_Mask);
|
||||||
#endif
|
#endif
|
||||||
if (unlikely(dma_get_attr(DMA_ATTR_WEAK_ORDERING, attrs)))
|
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);
|
io_pte = (unsigned long *)tbl->it_base + (index - tbl->it_offset);
|
||||||
|
|
||||||
for (i = 0; i < npages; i++, uaddr += IOMMU_PAGE_SIZE)
|
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();
|
mb();
|
||||||
|
|
||||||
|
@ -231,8 +223,9 @@ static void tce_free_cell(struct iommu_table *tbl, long index, long npages)
|
||||||
#else
|
#else
|
||||||
/* spider bridge does PCI reads after freeing - insert a mapping
|
/* spider bridge does PCI reads after freeing - insert a mapping
|
||||||
* to a scratch page instead of an invalid entry */
|
* to a scratch page instead of an invalid entry */
|
||||||
pte = IOPTE_PP_R | IOPTE_M | IOPTE_SO_RW | __pa(window->iommu->pad_page)
|
pte = CBE_IOPTE_PP_R | CBE_IOPTE_M | CBE_IOPTE_SO_RW |
|
||||||
| (window->ioid & IOPTE_IOID_Mask);
|
__pa(window->iommu->pad_page) |
|
||||||
|
(window->ioid & CBE_IOPTE_IOID_Mask);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
io_pte = (unsigned long *)tbl->it_base + (index - tbl->it_offset);
|
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",
|
pr_debug("iommu: addr %lx ptab %p segment %lx offset %lx\n",
|
||||||
addr, ptab, segment, offset);
|
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,
|
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);
|
pr_debug("iommu: mapping 0x%lx pages from 0x%lx\n", fsize, fbase);
|
||||||
|
|
||||||
base_pte = IOPTE_PP_W | IOPTE_PP_R | IOPTE_M
|
base_pte = CBE_IOPTE_PP_W | CBE_IOPTE_PP_R | CBE_IOPTE_M |
|
||||||
| (cell_iommu_get_ioid(np) & IOPTE_IOID_Mask);
|
(cell_iommu_get_ioid(np) & CBE_IOPTE_IOID_Mask);
|
||||||
|
|
||||||
if (iommu_fixed_is_weak)
|
if (iommu_fixed_is_weak)
|
||||||
pr_info("IOMMU: Using weak ordering for fixed mapping\n");
|
pr_info("IOMMU: Using weak ordering for fixed mapping\n");
|
||||||
else {
|
else {
|
||||||
pr_info("IOMMU: Using strong ordering for fixed mapping\n");
|
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)) {
|
for (uaddr = 0; uaddr < fsize; uaddr += (1 << 24)) {
|
||||||
|
|
|
@ -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));
|
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)
|
u64 data)
|
||||||
{
|
{
|
||||||
dt_prop(dt, name, &data, sizeof(u64));
|
dt_prop(dt, name, &data, sizeof(u64));
|
||||||
|
|
|
@ -267,7 +267,8 @@ static struct pending_event *new_pending_event(void)
|
||||||
return ev;
|
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();
|
struct pending_event *ev = new_pending_event();
|
||||||
int rc;
|
int rc;
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include <linux/lmb.h>
|
#include <linux/lmb.h>
|
||||||
|
|
||||||
#include <asm/firmware.h>
|
#include <asm/firmware.h>
|
||||||
|
#include <asm/iommu.h>
|
||||||
#include <asm/prom.h>
|
#include <asm/prom.h>
|
||||||
#include <asm/udbg.h>
|
#include <asm/udbg.h>
|
||||||
#include <asm/lv1call.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,
|
r->ioid,
|
||||||
iopte_flag);
|
iopte_flag);
|
||||||
if (result) {
|
if (result) {
|
||||||
printk(KERN_WARNING "%s:%d: lv1_map_device_dma_region "
|
pr_warning("%s:%d: lv1_put_iopte failed: %s\n",
|
||||||
"failed: %s\n", __func__, __LINE__,
|
__func__, __LINE__, ps3_result(result));
|
||||||
ps3_result(result));
|
|
||||||
goto fail_map;
|
goto fail_map;
|
||||||
}
|
}
|
||||||
DBG("%s: pg=%d bus=%#lx, lpar=%#lx, ioid=%#x\n", __func__,
|
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)
|
if (len > r->len)
|
||||||
len = r->len;
|
len = r->len;
|
||||||
result = dma_sb_map_area(r, virt_addr, len, &tmp,
|
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);
|
BUG_ON(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1014,7 +1015,8 @@ static int dma_sb_region_create_linear(struct ps3_dma_region *r)
|
||||||
else
|
else
|
||||||
len -= map.rm.size - r->offset;
|
len -= map.rm.size - r->offset;
|
||||||
result = dma_sb_map_area(r, virt_addr, len, &tmp,
|
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);
|
BUG_ON(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -226,6 +226,44 @@ static struct property property_av_multi_out = {
|
||||||
.value = &saved_params.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.
|
* 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,
|
if (memcmp(db->magic_num, OS_AREA_DB_MAGIC_NUM,
|
||||||
sizeof(db->magic_num))) {
|
sizeof(db->magic_num))) {
|
||||||
pr_debug("%s:%d magic_num failed\n", __func__, __LINE__);
|
pr_debug("%s:%d magic_num failed\n", __func__, __LINE__);
|
||||||
return -1;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (db->version != 1) {
|
if (db->version != 1) {
|
||||||
pr_debug("%s:%d version failed\n", __func__, __LINE__);
|
pr_debug("%s:%d version failed\n", __func__, __LINE__);
|
||||||
return -1;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
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;
|
const unsigned int buf_len = 8 * OS_AREA_SEGMENT_SIZE;
|
||||||
int file;
|
struct os_area_header *header;
|
||||||
off_t offset;
|
|
||||||
ssize_t count;
|
ssize_t count;
|
||||||
static const unsigned int buf_len = 8 * OS_AREA_SEGMENT_SIZE;
|
int error;
|
||||||
const struct os_area_header *header;
|
loff_t pos;
|
||||||
struct os_area_db* db;
|
struct os_area_db* db;
|
||||||
|
|
||||||
/* Read in header and db from flash. */
|
/* 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);
|
header = kmalloc(buf_len, GFP_KERNEL);
|
||||||
|
|
||||||
if (!header) {
|
if (!header) {
|
||||||
pr_debug("%s:%d kmalloc failed\n", __func__, __LINE__);
|
pr_debug("%s: kmalloc failed\n", __func__);
|
||||||
goto fail_malloc;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
offset = sys_lseek(file, 0, SEEK_SET);
|
count = os_area_flash_read(header, buf_len, 0);
|
||||||
|
if (count < 0) {
|
||||||
if (offset != 0) {
|
pr_debug("%s: os_area_flash_read failed %zd\n", __func__,
|
||||||
pr_debug("%s:%d sys_lseek failed\n", __func__, __LINE__);
|
count);
|
||||||
goto fail_header_seek;
|
error = count;
|
||||||
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
count = sys_read(file, (char __user *)header, buf_len);
|
pos = header->db_area_offset * OS_AREA_SEGMENT_SIZE;
|
||||||
|
if (count < OS_AREA_SEGMENT_SIZE || verify_header(header) ||
|
||||||
result = count < OS_AREA_SEGMENT_SIZE || verify_header(header)
|
count < pos) {
|
||||||
|| count < header->db_area_offset * OS_AREA_SEGMENT_SIZE;
|
pr_debug("%s: verify_header failed\n", __func__);
|
||||||
|
|
||||||
if (result) {
|
|
||||||
pr_debug("%s:%d verify_header failed\n", __func__, __LINE__);
|
|
||||||
dump_header(header);
|
dump_header(header);
|
||||||
goto fail_header;
|
error = -EINVAL;
|
||||||
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now got a good db offset and some maybe good db data. */
|
/* 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);
|
error = db_verify(db);
|
||||||
|
if (error) {
|
||||||
if (result) {
|
pr_notice("%s: Verify of flash database failed, formatting.\n",
|
||||||
printk(KERN_NOTICE "%s:%d: Verify of flash database failed, "
|
__func__);
|
||||||
"formatting.\n", __func__, __LINE__);
|
|
||||||
dump_db(db);
|
dump_db(db);
|
||||||
os_area_db_init(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);
|
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,
|
count = os_area_flash_write(db, sizeof(struct os_area_db), pos);
|
||||||
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));
|
|
||||||
|
|
||||||
if (count < sizeof(struct os_area_db)) {
|
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:
|
||||||
fail_header:
|
|
||||||
fail_header_seek:
|
|
||||||
kfree(header);
|
kfree(header);
|
||||||
fail_malloc:
|
return error;
|
||||||
sys_close(file);
|
|
||||||
fail_open:
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -674,11 +688,11 @@ fail_open:
|
||||||
static void os_area_queue_work_handler(struct work_struct *work)
|
static void os_area_queue_work_handler(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct device_node *node;
|
struct device_node *node;
|
||||||
|
int error;
|
||||||
|
|
||||||
pr_debug(" -> %s:%d\n", __func__, __LINE__);
|
pr_debug(" -> %s:%d\n", __func__, __LINE__);
|
||||||
|
|
||||||
node = of_find_node_by_path("/");
|
node = of_find_node_by_path("/");
|
||||||
|
|
||||||
if (node) {
|
if (node) {
|
||||||
os_area_set_property(node, &property_rtc_diff);
|
os_area_set_property(node, &property_rtc_diff);
|
||||||
of_node_put(node);
|
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",
|
pr_debug("%s:%d of_find_node_by_path failed\n",
|
||||||
__func__, __LINE__);
|
__func__, __LINE__);
|
||||||
|
|
||||||
#if defined(CONFIG_PS3_FLASH) || defined(CONFIG_PS3_FLASH_MODULE)
|
error = update_flash_db();
|
||||||
update_flash_db();
|
if (error)
|
||||||
#else
|
pr_warning("%s: Could not update FLASH ROM\n", __func__);
|
||||||
printk(KERN_WARNING "%s:%d: No flash rom driver configured.\n",
|
|
||||||
__func__, __LINE__);
|
|
||||||
#endif
|
|
||||||
pr_debug(" <- %s:%d\n", __func__, __LINE__);
|
pr_debug(" <- %s:%d\n", __func__, __LINE__);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -808,7 +820,7 @@ u64 ps3_os_area_get_rtc_diff(void)
|
||||||
{
|
{
|
||||||
return saved_params.rtc_diff;
|
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.
|
* 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();
|
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.
|
* ps3_os_area_get_av_multi_out - Returns the default video mode.
|
||||||
|
|
|
@ -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_av_port(unsigned int *port);
|
||||||
int ps3_repository_read_vuart_sysmgr_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
|
#endif
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
#include <asm/udbg.h>
|
#include <asm/udbg.h>
|
||||||
#include <asm/prom.h>
|
#include <asm/prom.h>
|
||||||
#include <asm/lv1call.h>
|
#include <asm/lv1call.h>
|
||||||
|
#include <asm/ps3gpu.h>
|
||||||
|
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include <asm/udbg.h>
|
#include <asm/udbg.h>
|
||||||
#include <asm/lv1call.h>
|
#include <asm/lv1call.h>
|
||||||
#include <asm/firmware.h>
|
#include <asm/firmware.h>
|
||||||
|
#include <asm/iommu.h>
|
||||||
|
|
||||||
#include "platform.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,
|
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) {
|
if (result) {
|
||||||
pr_debug("%s:%d: ps3_dma_map failed (%d)\n",
|
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,
|
result = ps3_dma_map(dev->d_region, (unsigned long)ptr, size,
|
||||||
&bus_addr,
|
&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) {
|
if (result) {
|
||||||
pr_debug("%s:%d: ps3_dma_map failed (%d)\n",
|
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;
|
u64 iopte_flag;
|
||||||
void *ptr = page_address(page) + offset;
|
void *ptr = page_address(page) + offset;
|
||||||
|
|
||||||
iopte_flag = IOPTE_M;
|
iopte_flag = CBE_IOPTE_M;
|
||||||
switch (direction) {
|
switch (direction) {
|
||||||
case DMA_BIDIRECTIONAL:
|
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;
|
break;
|
||||||
case DMA_TO_DEVICE:
|
case DMA_TO_DEVICE:
|
||||||
iopte_flag |= IOPTE_PP_R | IOPTE_SO_R;
|
iopte_flag |= CBE_IOPTE_PP_R | CBE_IOPTE_SO_R;
|
||||||
break;
|
break;
|
||||||
case DMA_FROM_DEVICE:
|
case DMA_FROM_DEVICE:
|
||||||
iopte_flag |= IOPTE_PP_W | IOPTE_SO_RW;
|
iopte_flag |= CBE_IOPTE_PP_W | CBE_IOPTE_SO_RW;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* not happned */
|
/* not happned */
|
||||||
|
|
|
@ -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,
|
static int ps3disk_submit_request_sg(struct ps3_storage_device *dev,
|
||||||
struct request *req)
|
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;
|
int write = rq_data_dir(req), res;
|
||||||
const char *op = write ? "write" : "read";
|
const char *op = write ? "write" : "read";
|
||||||
u64 start_sector, sectors;
|
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,
|
static int ps3disk_submit_flush_request(struct ps3_storage_device *dev,
|
||||||
struct request *req)
|
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;
|
u64 res;
|
||||||
|
|
||||||
dev_dbg(&dev->sbd.core, "%s:%u: flush request\n", __func__, __LINE__);
|
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)
|
static void ps3disk_request(struct request_queue *q)
|
||||||
{
|
{
|
||||||
struct ps3_storage_device *dev = q->queuedata;
|
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) {
|
if (priv->req) {
|
||||||
dev_dbg(&dev->sbd.core, "%s:%u busy\n", __func__, __LINE__);
|
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;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
priv = dev->sbd.core.driver_data;
|
priv = ps3_system_bus_get_drvdata(&dev->sbd);
|
||||||
req = priv->req;
|
req = priv->req;
|
||||||
if (!req) {
|
if (!req) {
|
||||||
dev_dbg(&dev->sbd.core,
|
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)
|
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;
|
struct lv1_ata_cmnd_block ata_cmnd;
|
||||||
u16 *id = dev->bounce_buf;
|
u16 *id = dev->bounce_buf;
|
||||||
u64 res;
|
u64 res;
|
||||||
|
@ -445,7 +445,7 @@ static int __devinit ps3disk_probe(struct ps3_system_bus_device *_dev)
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev->sbd.core.driver_data = priv;
|
ps3_system_bus_set_drvdata(_dev, priv);
|
||||||
spin_lock_init(&priv->lock);
|
spin_lock_init(&priv->lock);
|
||||||
|
|
||||||
dev->bounce_size = BOUNCE_SIZE;
|
dev->bounce_size = BOUNCE_SIZE;
|
||||||
|
@ -523,7 +523,7 @@ fail_free_bounce:
|
||||||
kfree(dev->bounce_buf);
|
kfree(dev->bounce_buf);
|
||||||
fail_free_priv:
|
fail_free_priv:
|
||||||
kfree(priv);
|
kfree(priv);
|
||||||
dev->sbd.core.driver_data = NULL;
|
ps3_system_bus_set_drvdata(_dev, NULL);
|
||||||
fail:
|
fail:
|
||||||
mutex_lock(&ps3disk_mask_mutex);
|
mutex_lock(&ps3disk_mask_mutex);
|
||||||
__clear_bit(devidx, &ps3disk_mask);
|
__clear_bit(devidx, &ps3disk_mask);
|
||||||
|
@ -534,7 +534,7 @@ fail:
|
||||||
static int ps3disk_remove(struct ps3_system_bus_device *_dev)
|
static int ps3disk_remove(struct ps3_system_bus_device *_dev)
|
||||||
{
|
{
|
||||||
struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
|
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);
|
mutex_lock(&ps3disk_mask_mutex);
|
||||||
__clear_bit(MINOR(disk_devt(priv->gendisk)) / PS3DISK_MINORS,
|
__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);
|
ps3stor_teardown(dev);
|
||||||
kfree(dev->bounce_buf);
|
kfree(dev->bounce_buf);
|
||||||
kfree(priv);
|
kfree(priv);
|
||||||
dev->sbd.core.driver_data = NULL;
|
ps3_system_bus_set_drvdata(_dev, NULL);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,8 +14,10 @@
|
||||||
#include <linux/seq_file.h>
|
#include <linux/seq_file.h>
|
||||||
|
|
||||||
#include <asm/firmware.h>
|
#include <asm/firmware.h>
|
||||||
|
#include <asm/iommu.h>
|
||||||
#include <asm/lv1call.h>
|
#include <asm/lv1call.h>
|
||||||
#include <asm/ps3.h>
|
#include <asm/ps3.h>
|
||||||
|
#include <asm/ps3gpu.h>
|
||||||
|
|
||||||
|
|
||||||
#define DEVICE_NAME "ps3vram"
|
#define DEVICE_NAME "ps3vram"
|
||||||
|
@ -45,8 +47,6 @@
|
||||||
#define NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN 0x0000030c
|
#define NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN 0x0000030c
|
||||||
#define NV_MEMORY_TO_MEMORY_FORMAT_NOTIFY 0x00000104
|
#define NV_MEMORY_TO_MEMORY_FORMAT_NOTIFY 0x00000104
|
||||||
|
|
||||||
#define L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT 0x601
|
|
||||||
|
|
||||||
#define CACHE_PAGE_PRESENT 1
|
#define CACHE_PAGE_PRESENT 1
|
||||||
#define CACHE_PAGE_DIRTY 2
|
#define CACHE_PAGE_DIRTY 2
|
||||||
|
|
||||||
|
@ -72,8 +72,7 @@ struct ps3vram_priv {
|
||||||
u64 memory_handle;
|
u64 memory_handle;
|
||||||
u64 context_handle;
|
u64 context_handle;
|
||||||
u32 *ctrl;
|
u32 *ctrl;
|
||||||
u32 *reports;
|
void *reports;
|
||||||
u8 __iomem *ddr_base;
|
|
||||||
u8 *xdr_buf;
|
u8 *xdr_buf;
|
||||||
|
|
||||||
u32 *fifo_base;
|
u32 *fifo_base;
|
||||||
|
@ -81,8 +80,8 @@ struct ps3vram_priv {
|
||||||
|
|
||||||
struct ps3vram_cache cache;
|
struct ps3vram_cache cache;
|
||||||
|
|
||||||
/* Used to serialize cache/DMA operations */
|
spinlock_t lock; /* protecting list of bios */
|
||||||
struct mutex lock;
|
struct bio_list list;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -103,15 +102,15 @@ static char *size = "256M";
|
||||||
module_param(size, charp, 0);
|
module_param(size, charp, 0);
|
||||||
MODULE_PARM_DESC(size, "memory size");
|
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;
|
DMA_NOTIFIER_SIZE * notifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ps3vram_notifier_reset(struct ps3_system_bus_device *dev)
|
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);
|
u32 *notify = ps3vram_get_notifier(priv->reports, NOTIFIER);
|
||||||
int i;
|
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,
|
static int ps3vram_notifier_wait(struct ps3_system_bus_device *dev,
|
||||||
unsigned int timeout_ms)
|
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);
|
u32 *notify = ps3vram_get_notifier(priv->reports, NOTIFIER);
|
||||||
unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms);
|
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)
|
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_PUT] = FIFO_BASE + FIFO_OFFSET;
|
||||||
priv->ctrl[CTRL_GET] = 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,
|
static int ps3vram_wait_ring(struct ps3_system_bus_device *dev,
|
||||||
unsigned int timeout_ms)
|
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);
|
unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms);
|
||||||
|
|
||||||
do {
|
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)
|
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;
|
int status;
|
||||||
|
|
||||||
ps3vram_out_ring(priv, 0x20000000 | (FIFO_BASE + FIFO_OFFSET));
|
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;
|
priv->ctrl[CTRL_PUT] = FIFO_BASE + FIFO_OFFSET;
|
||||||
|
|
||||||
/* asking the HV for a blit will kick the FIFO */
|
/* asking the HV for a blit will kick the FIFO */
|
||||||
status = lv1_gpu_context_attribute(priv->context_handle,
|
status = lv1_gpu_fb_blit(priv->context_handle, 0, 0, 0, 0);
|
||||||
L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT, 0,
|
|
||||||
0, 0, 0);
|
|
||||||
if (status)
|
if (status)
|
||||||
dev_err(&dev->core,
|
dev_err(&dev->core, "%s: lv1_gpu_fb_blit failed %d\n",
|
||||||
"%s: lv1_gpu_context_attribute failed %d\n", __func__,
|
__func__, status);
|
||||||
status);
|
|
||||||
|
|
||||||
priv->fifo_ptr = priv->fifo_base;
|
priv->fifo_ptr = priv->fifo_base;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ps3vram_fire_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_drvdata(dev);
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
mutex_lock(&ps3_gpu_mutex);
|
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);
|
(priv->fifo_ptr - priv->fifo_base) * sizeof(u32);
|
||||||
|
|
||||||
/* asking the HV for a blit will kick the FIFO */
|
/* asking the HV for a blit will kick the FIFO */
|
||||||
status = lv1_gpu_context_attribute(priv->context_handle,
|
status = lv1_gpu_fb_blit(priv->context_handle, 0, 0, 0, 0);
|
||||||
L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT, 0,
|
|
||||||
0, 0, 0);
|
|
||||||
if (status)
|
if (status)
|
||||||
dev_err(&dev->core,
|
dev_err(&dev->core, "%s: lv1_gpu_fb_blit failed %d\n",
|
||||||
"%s: lv1_gpu_context_attribute failed %d\n", __func__,
|
__func__, status);
|
||||||
status);
|
|
||||||
|
|
||||||
if ((priv->fifo_ptr - priv->fifo_base) * sizeof(u32) >
|
if ((priv->fifo_ptr - priv->fifo_base) * sizeof(u32) >
|
||||||
FIFO_SIZE - 1024) {
|
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)
|
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_begin_ring(priv, UPLOAD_SUBCH, 0, 1);
|
||||||
ps3vram_out_ring(priv, 0x31337303);
|
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,
|
unsigned int src_offset, unsigned int dst_offset,
|
||||||
int len, int count)
|
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,
|
ps3vram_begin_ring(priv, UPLOAD_SUBCH,
|
||||||
NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
|
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,
|
unsigned int src_offset, unsigned int dst_offset,
|
||||||
int len, int count)
|
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,
|
ps3vram_begin_ring(priv, DOWNLOAD_SUBCH,
|
||||||
NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
|
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)
|
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;
|
struct ps3vram_cache *cache = &priv->cache;
|
||||||
|
|
||||||
if (!(cache->tags[entry].flags & CACHE_PAGE_DIRTY))
|
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,
|
static void ps3vram_cache_load(struct ps3_system_bus_device *dev, int entry,
|
||||||
unsigned int address)
|
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;
|
struct ps3vram_cache *cache = &priv->cache;
|
||||||
|
|
||||||
dev_dbg(&dev->core, "Fetching %d: 0x%08x\n", entry, address);
|
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)
|
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;
|
struct ps3vram_cache *cache = &priv->cache;
|
||||||
int i;
|
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,
|
static unsigned int ps3vram_cache_match(struct ps3_system_bus_device *dev,
|
||||||
loff_t address)
|
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;
|
struct ps3vram_cache *cache = &priv->cache;
|
||||||
unsigned int base;
|
unsigned int base;
|
||||||
unsigned int offset;
|
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)
|
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_count = CACHE_PAGE_COUNT;
|
||||||
priv->cache.page_size = CACHE_PAGE_SIZE;
|
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)
|
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);
|
ps3vram_cache_flush(dev);
|
||||||
kfree(priv->cache.tags);
|
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,
|
static int ps3vram_read(struct ps3_system_bus_device *dev, loff_t from,
|
||||||
size_t len, size_t *retlen, u_char *buf)
|
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;
|
unsigned int cached, count;
|
||||||
|
|
||||||
dev_dbg(&dev->core, "%s: from=0x%08x len=0x%zx\n", __func__,
|
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));
|
offset = (unsigned int) (from & (priv->cache.page_size - 1));
|
||||||
avail = priv->cache.page_size - offset;
|
avail = priv->cache.page_size - offset;
|
||||||
|
|
||||||
mutex_lock(&priv->lock);
|
|
||||||
|
|
||||||
entry = ps3vram_cache_match(dev, from);
|
entry = ps3vram_cache_match(dev, from);
|
||||||
cached = CACHE_OFFSET + entry * priv->cache.page_size + offset;
|
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;
|
avail = count;
|
||||||
memcpy(buf, priv->xdr_buf + cached, avail);
|
memcpy(buf, priv->xdr_buf + cached, avail);
|
||||||
|
|
||||||
mutex_unlock(&priv->lock);
|
|
||||||
|
|
||||||
buf += avail;
|
buf += avail;
|
||||||
count -= avail;
|
count -= avail;
|
||||||
from += 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,
|
static int ps3vram_write(struct ps3_system_bus_device *dev, loff_t to,
|
||||||
size_t len, size_t *retlen, const u_char *buf)
|
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;
|
unsigned int cached, count;
|
||||||
|
|
||||||
if (to >= priv->size)
|
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));
|
offset = (unsigned int) (to & (priv->cache.page_size - 1));
|
||||||
avail = priv->cache.page_size - offset;
|
avail = priv->cache.page_size - offset;
|
||||||
|
|
||||||
mutex_lock(&priv->lock);
|
|
||||||
|
|
||||||
entry = ps3vram_cache_match(dev, to);
|
entry = ps3vram_cache_match(dev, to);
|
||||||
cached = CACHE_OFFSET + entry * priv->cache.page_size + offset;
|
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;
|
priv->cache.tags[entry].flags |= CACHE_PAGE_DIRTY;
|
||||||
|
|
||||||
mutex_unlock(&priv->lock);
|
|
||||||
|
|
||||||
buf += avail;
|
buf += avail;
|
||||||
count -= avail;
|
count -= avail;
|
||||||
to += 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)
|
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;
|
struct proc_dir_entry *pde;
|
||||||
|
|
||||||
pde = proc_create(DEVICE_NAME, 0444, NULL, &ps3vram_proc_fops);
|
pde = proc_create_data(DEVICE_NAME, 0444, NULL, &ps3vram_proc_fops,
|
||||||
if (!pde) {
|
priv);
|
||||||
|
if (!pde)
|
||||||
dev_warn(&dev->core, "failed to create /proc entry\n");
|
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;
|
int write = bio_data_dir(bio) == WRITE;
|
||||||
const char *op = write ? "write" : "read";
|
const char *op = write ? "write" : "read";
|
||||||
loff_t offset = bio->bi_sector << 9;
|
loff_t offset = bio->bi_sector << 9;
|
||||||
int error = 0;
|
int error = 0;
|
||||||
struct bio_vec *bvec;
|
struct bio_vec *bvec;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
struct bio *next;
|
||||||
dev_dbg(&dev->core, "%s\n", __func__);
|
|
||||||
|
|
||||||
bio_for_each_segment(bvec, bio, i) {
|
bio_for_each_segment(bvec, bio, i) {
|
||||||
/* PS3 is ppc64, so we don't handle highmem */
|
/* 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) {
|
if (retlen != len) {
|
||||||
dev_err(&dev->core, "Short %s\n", op);
|
dev_err(&dev->core, "Short %s\n", op);
|
||||||
|
error = -EIO;
|
||||||
goto out;
|
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);
|
dev_dbg(&dev->core, "%s completed\n", op);
|
||||||
|
|
||||||
out:
|
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);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -604,8 +616,8 @@ static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev)
|
||||||
int error, status;
|
int error, status;
|
||||||
struct request_queue *queue;
|
struct request_queue *queue;
|
||||||
struct gendisk *gendisk;
|
struct gendisk *gendisk;
|
||||||
u64 ddr_lpar, ctrl_lpar, info_lpar, reports_lpar, ddr_size,
|
u64 ddr_size, ddr_lpar, ctrl_lpar, info_lpar, reports_lpar,
|
||||||
reports_size;
|
reports_size, xdr_lpar;
|
||||||
char *rest;
|
char *rest;
|
||||||
|
|
||||||
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
|
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
|
||||||
|
@ -614,10 +626,9 @@ static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev)
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_init(&priv->lock);
|
spin_lock_init(&priv->lock);
|
||||||
dev->core.driver_data = priv;
|
bio_list_init(&priv->list);
|
||||||
|
ps3_system_bus_set_drvdata(dev, priv);
|
||||||
priv = dev->core.driver_data;
|
|
||||||
|
|
||||||
/* Allocate XDR buffer (1MiB aligned) */
|
/* Allocate XDR buffer (1MiB aligned) */
|
||||||
priv->xdr_buf = (void *)__get_free_pages(GFP_KERNEL,
|
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)) {
|
if (ps3_open_hv_device(dev)) {
|
||||||
dev_err(&dev->core, "ps3_open_hv_device failed\n");
|
dev_err(&dev->core, "ps3_open_hv_device failed\n");
|
||||||
error = -EAGAIN;
|
error = -EAGAIN;
|
||||||
goto out_close_gpu;
|
goto out_free_xdr_buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Request memory */
|
/* 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",
|
dev_err(&dev->core, "lv1_gpu_memory_allocate failed %d\n",
|
||||||
status);
|
status);
|
||||||
error = -ENOMEM;
|
error = -ENOMEM;
|
||||||
goto out_free_xdr_buf;
|
goto out_close_gpu;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Request context */
|
/* Request context */
|
||||||
|
@ -676,9 +687,11 @@ static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Map XDR buffer to RSX */
|
/* 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,
|
status = lv1_gpu_context_iomap(priv->context_handle, XDR_IOIF,
|
||||||
ps3_mm_phys_to_lpar(__pa(priv->xdr_buf)),
|
xdr_lpar, XDR_BUF_SIZE,
|
||||||
XDR_BUF_SIZE, 0);
|
CBE_IOPTE_PP_W | CBE_IOPTE_PP_R |
|
||||||
|
CBE_IOPTE_M);
|
||||||
if (status) {
|
if (status) {
|
||||||
dev_err(&dev->core, "lv1_gpu_context_iomap failed %d\n",
|
dev_err(&dev->core, "lv1_gpu_context_iomap failed %d\n",
|
||||||
status);
|
status);
|
||||||
|
@ -686,19 +699,11 @@ static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev)
|
||||||
goto out_free_context;
|
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);
|
priv->ctrl = ioremap(ctrl_lpar, 64 * 1024);
|
||||||
if (!priv->ctrl) {
|
if (!priv->ctrl) {
|
||||||
dev_err(&dev->core, "ioremap CTRL failed\n");
|
dev_err(&dev->core, "ioremap CTRL failed\n");
|
||||||
error = -ENOMEM;
|
error = -ENOMEM;
|
||||||
goto out_unmap_vram;
|
goto out_unmap_context;
|
||||||
}
|
}
|
||||||
|
|
||||||
priv->reports = ioremap(reports_lpar, reports_size);
|
priv->reports = ioremap(reports_lpar, reports_size);
|
||||||
|
@ -775,8 +780,9 @@ out_unmap_reports:
|
||||||
iounmap(priv->reports);
|
iounmap(priv->reports);
|
||||||
out_unmap_ctrl:
|
out_unmap_ctrl:
|
||||||
iounmap(priv->ctrl);
|
iounmap(priv->ctrl);
|
||||||
out_unmap_vram:
|
out_unmap_context:
|
||||||
iounmap(priv->ddr_base);
|
lv1_gpu_context_iomap(priv->context_handle, XDR_IOIF, xdr_lpar,
|
||||||
|
XDR_BUF_SIZE, CBE_IOPTE_M);
|
||||||
out_free_context:
|
out_free_context:
|
||||||
lv1_gpu_context_free(priv->context_handle);
|
lv1_gpu_context_free(priv->context_handle);
|
||||||
out_free_memory:
|
out_free_memory:
|
||||||
|
@ -787,14 +793,14 @@ out_free_xdr_buf:
|
||||||
free_pages((unsigned long) priv->xdr_buf, get_order(XDR_BUF_SIZE));
|
free_pages((unsigned long) priv->xdr_buf, get_order(XDR_BUF_SIZE));
|
||||||
fail_free_priv:
|
fail_free_priv:
|
||||||
kfree(priv);
|
kfree(priv);
|
||||||
dev->core.driver_data = NULL;
|
ps3_system_bus_set_drvdata(dev, NULL);
|
||||||
fail:
|
fail:
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ps3vram_remove(struct ps3_system_bus_device *dev)
|
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);
|
del_gendisk(priv->gendisk);
|
||||||
put_disk(priv->gendisk);
|
put_disk(priv->gendisk);
|
||||||
|
@ -803,13 +809,15 @@ static int ps3vram_remove(struct ps3_system_bus_device *dev)
|
||||||
ps3vram_cache_cleanup(dev);
|
ps3vram_cache_cleanup(dev);
|
||||||
iounmap(priv->reports);
|
iounmap(priv->reports);
|
||||||
iounmap(priv->ctrl);
|
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_context_free(priv->context_handle);
|
||||||
lv1_gpu_memory_free(priv->memory_handle);
|
lv1_gpu_memory_free(priv->memory_handle);
|
||||||
ps3_close_hv_device(dev);
|
ps3_close_hv_device(dev);
|
||||||
free_pages((unsigned long) priv->xdr_buf, get_order(XDR_BUF_SIZE));
|
free_pages((unsigned long) priv->xdr_buf, get_order(XDR_BUF_SIZE));
|
||||||
kfree(priv);
|
kfree(priv);
|
||||||
dev->core.driver_data = NULL;
|
ps3_system_bus_set_drvdata(dev, NULL);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,48 +33,64 @@
|
||||||
|
|
||||||
struct ps3flash_private {
|
struct ps3flash_private {
|
||||||
struct mutex mutex; /* Bounce buffer mutex */
|
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 struct ps3_storage_device *ps3flash_dev;
|
||||||
|
|
||||||
static ssize_t ps3flash_read_write_sectors(struct ps3_storage_device *dev,
|
static int ps3flash_read_write_sectors(struct ps3_storage_device *dev,
|
||||||
u64 lpar, u64 start_sector,
|
u64 start_sector, int write)
|
||||||
u64 sectors, 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);
|
write);
|
||||||
if (res) {
|
if (res) {
|
||||||
dev_err(&dev->sbd.core, "%s:%u: %s failed 0x%llx\n", __func__,
|
dev_err(&dev->sbd.core, "%s:%u: %s failed 0x%llx\n", __func__,
|
||||||
__LINE__, write ? "write" : "read", res);
|
__LINE__, write ? "write" : "read", res);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
return sectors;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t ps3flash_read_sectors(struct ps3_storage_device *dev,
|
static int ps3flash_writeback(struct ps3_storage_device *dev)
|
||||||
u64 start_sector, u64 sectors,
|
|
||||||
unsigned int sector_offset)
|
|
||||||
{
|
{
|
||||||
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 (!priv->dirty || priv->tag < 0)
|
||||||
if (sectors > max_sectors) {
|
return 0;
|
||||||
dev_dbg(&dev->sbd.core, "%s:%u Limiting sectors to %llu\n",
|
|
||||||
__func__, __LINE__, max_sectors);
|
|
||||||
sectors = max_sectors;
|
|
||||||
}
|
|
||||||
|
|
||||||
lpar = dev->bounce_lpar + sector_offset * dev->blk_size;
|
res = ps3flash_read_write_sectors(dev, priv->tag, 1);
|
||||||
return ps3flash_read_write_sectors(dev, lpar, start_sector, sectors,
|
if (res)
|
||||||
0);
|
return res;
|
||||||
|
|
||||||
|
priv->dirty = false;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t ps3flash_write_chunk(struct ps3_storage_device *dev,
|
static int ps3flash_fetch(struct ps3_storage_device *dev, u64 start_sector)
|
||||||
u64 start_sector)
|
|
||||||
{
|
{
|
||||||
u64 sectors = dev->bounce_size / dev->blk_size;
|
struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
|
||||||
return ps3flash_read_write_sectors(dev, dev->bounce_lpar, start_sector,
|
int res;
|
||||||
sectors, 1);
|
|
||||||
|
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)
|
static loff_t ps3flash_llseek(struct file *file, loff_t offset, int origin)
|
||||||
|
@ -104,85 +120,19 @@ out:
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t ps3flash_read(struct file *file, char __user *buf, size_t count,
|
static ssize_t ps3flash_read(char __user *userbuf, void *kernelbuf,
|
||||||
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;
|
|
||||||
size_t remaining, n;
|
|
||||||
|
|
||||||
dev_dbg(&dev->sbd.core,
|
|
||||||
"%s:%u: Reading %zu bytes at position %lld to user 0x%p\n",
|
|
||||||
__func__, __LINE__, count, *pos, buf);
|
|
||||||
|
|
||||||
size = dev->regions[dev->region_idx].size*dev->blk_size;
|
|
||||||
if (*pos >= size || !count)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (*pos + count > size) {
|
|
||||||
dev_dbg(&dev->sbd.core,
|
|
||||||
"%s:%u Truncating count from %zu to %llu\n", __func__,
|
|
||||||
__LINE__, count, size - *pos);
|
|
||||||
count = size - *pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
start_sector = *pos / dev->blk_size;
|
|
||||||
offset = *pos % dev->blk_size;
|
|
||||||
end_sector = DIV_ROUND_UP(*pos + count, dev->blk_size);
|
|
||||||
|
|
||||||
remaining = count;
|
|
||||||
do {
|
|
||||||
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);
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex_unlock(&priv->mutex);
|
|
||||||
|
|
||||||
*pos += n;
|
|
||||||
buf += n;
|
|
||||||
remaining -= n;
|
|
||||||
start_sector += sectors_read;
|
|
||||||
offset = 0;
|
|
||||||
} while (remaining > 0);
|
|
||||||
|
|
||||||
return count;
|
|
||||||
|
|
||||||
fail:
|
|
||||||
return sectors_read;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t ps3flash_write(struct file *file, const char __user *buf,
|
|
||||||
size_t count, loff_t *pos)
|
size_t count, loff_t *pos)
|
||||||
{
|
{
|
||||||
struct ps3_storage_device *dev = ps3flash_dev;
|
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,
|
u64 size, sector, offset;
|
||||||
end_read_sector, start_read_sector, head, tail, offset;
|
int res;
|
||||||
ssize_t res;
|
|
||||||
size_t remaining, n;
|
size_t remaining, n;
|
||||||
unsigned int sec_off;
|
const void *src;
|
||||||
|
|
||||||
dev_dbg(&dev->sbd.core,
|
dev_dbg(&dev->sbd.core,
|
||||||
"%s:%u: Writing %zu bytes at position %lld from user 0x%p\n",
|
"%s:%u: Reading %zu bytes at position %lld to U0x%p/K0x%p\n",
|
||||||
__func__, __LINE__, count, *pos, buf);
|
__func__, __LINE__, count, *pos, userbuf, kernelbuf);
|
||||||
|
|
||||||
size = dev->regions[dev->region_idx].size*dev->blk_size;
|
size = dev->regions[dev->region_idx].size*dev->blk_size;
|
||||||
if (*pos >= size || !count)
|
if (*pos >= size || !count)
|
||||||
|
@ -195,89 +145,40 @@ static ssize_t ps3flash_write(struct file *file, const char __user *buf,
|
||||||
count = size - *pos;
|
count = size - *pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
chunk_sectors = dev->bounce_size / dev->blk_size;
|
sector = *pos / dev->bounce_size * priv->chunk_sectors;
|
||||||
|
|
||||||
start_write_sector = *pos / dev->bounce_size * chunk_sectors;
|
|
||||||
offset = *pos % dev->bounce_size;
|
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;
|
remaining = count;
|
||||||
do {
|
do {
|
||||||
|
n = min_t(u64, remaining, dev->bounce_size - offset);
|
||||||
|
src = dev->bounce_buf + offset;
|
||||||
|
|
||||||
mutex_lock(&priv->mutex);
|
mutex_lock(&priv->mutex);
|
||||||
|
|
||||||
if (end_read_sector >= start_read_sector) {
|
res = ps3flash_fetch(dev, sector);
|
||||||
/* Merge head and tail */
|
if (res)
|
||||||
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;
|
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
n = min_t(u64, remaining, dev->bounce_size-offset);
|
|
||||||
dev_dbg(&dev->sbd.core,
|
dev_dbg(&dev->sbd.core,
|
||||||
"%s:%u: copy %lu bytes from user 0x%p to 0x%p\n",
|
"%s:%u: copy %lu bytes from 0x%p to U0x%p/K0x%p\n",
|
||||||
__func__, __LINE__, n, buf, dev->bounce_buf+offset);
|
__func__, __LINE__, n, src, userbuf, kernelbuf);
|
||||||
if (copy_from_user(dev->bounce_buf+offset, buf, n)) {
|
if (userbuf) {
|
||||||
|
if (copy_to_user(userbuf, src, n)) {
|
||||||
res = -EFAULT;
|
res = -EFAULT;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
userbuf += n;
|
||||||
res = ps3flash_write_chunk(dev, start_write_sector);
|
}
|
||||||
if (res < 0)
|
if (kernelbuf) {
|
||||||
goto fail;
|
memcpy(kernelbuf, src, n);
|
||||||
|
kernelbuf += n;
|
||||||
|
}
|
||||||
|
|
||||||
mutex_unlock(&priv->mutex);
|
mutex_unlock(&priv->mutex);
|
||||||
|
|
||||||
*pos += n;
|
*pos += n;
|
||||||
buf += n;
|
|
||||||
remaining -= n;
|
remaining -= n;
|
||||||
start_write_sector += chunk_sectors;
|
sector += priv->chunk_sectors;
|
||||||
head = 0;
|
|
||||||
offset = 0;
|
offset = 0;
|
||||||
} while (remaining > 0);
|
} while (remaining > 0);
|
||||||
|
|
||||||
|
@ -288,6 +189,126 @@ fail:
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
u64 size, sector, offset;
|
||||||
|
int res = 0;
|
||||||
|
size_t remaining, n;
|
||||||
|
void *dst;
|
||||||
|
|
||||||
|
dev_dbg(&dev->sbd.core,
|
||||||
|
"%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)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (*pos + count > size) {
|
||||||
|
dev_dbg(&dev->sbd.core,
|
||||||
|
"%s:%u Truncating count from %zu to %llu\n", __func__,
|
||||||
|
__LINE__, count, size - *pos);
|
||||||
|
count = size - *pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
dst = dev->bounce_buf + offset;
|
||||||
|
|
||||||
|
mutex_lock(&priv->mutex);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
userbuf += n;
|
||||||
|
}
|
||||||
|
if (kernelbuf) {
|
||||||
|
memcpy(dst, kernelbuf, n);
|
||||||
|
kernelbuf += n;
|
||||||
|
}
|
||||||
|
|
||||||
|
priv->tag = sector;
|
||||||
|
priv->dirty = true;
|
||||||
|
|
||||||
|
mutex_unlock(&priv->mutex);
|
||||||
|
|
||||||
|
*pos += n;
|
||||||
|
remaining -= n;
|
||||||
|
sector += priv->chunk_sectors;
|
||||||
|
offset = 0;
|
||||||
|
} while (remaining > 0);
|
||||||
|
|
||||||
|
return count;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
mutex_unlock(&priv->mutex);
|
||||||
|
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)
|
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;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static const struct file_operations ps3flash_fops = {
|
static const struct file_operations ps3flash_fops = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.llseek = ps3flash_llseek,
|
.llseek = ps3flash_llseek,
|
||||||
.read = ps3flash_read,
|
.read = ps3flash_user_read,
|
||||||
.write = ps3flash_write,
|
.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 = {
|
static struct miscdevice ps3flash_misc = {
|
||||||
|
@ -366,11 +393,13 @@ static int __devinit ps3flash_probe(struct ps3_system_bus_device *_dev)
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev->sbd.core.driver_data = priv;
|
ps3_system_bus_set_drvdata(&dev->sbd, priv);
|
||||||
mutex_init(&priv->mutex);
|
mutex_init(&priv->mutex);
|
||||||
|
priv->tag = -1;
|
||||||
|
|
||||||
dev->bounce_size = ps3flash_bounce_buffer.size;
|
dev->bounce_size = ps3flash_bounce_buffer.size;
|
||||||
dev->bounce_buf = ps3flash_bounce_buffer.address;
|
dev->bounce_buf = ps3flash_bounce_buffer.address;
|
||||||
|
priv->chunk_sectors = dev->bounce_size / dev->blk_size;
|
||||||
|
|
||||||
error = ps3stor_setup(dev, ps3flash_interrupt);
|
error = ps3stor_setup(dev, ps3flash_interrupt);
|
||||||
if (error)
|
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",
|
dev_info(&dev->sbd.core, "%s:%u: registered misc device %d\n",
|
||||||
__func__, __LINE__, ps3flash_misc.minor);
|
__func__, __LINE__, ps3flash_misc.minor);
|
||||||
|
|
||||||
|
ps3_os_area_flash_register(&ps3flash_kernel_ops);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
fail_teardown:
|
fail_teardown:
|
||||||
ps3stor_teardown(dev);
|
ps3stor_teardown(dev);
|
||||||
fail_free_priv:
|
fail_free_priv:
|
||||||
kfree(priv);
|
kfree(priv);
|
||||||
dev->sbd.core.driver_data = NULL;
|
ps3_system_bus_set_drvdata(&dev->sbd, NULL);
|
||||||
fail:
|
fail:
|
||||||
ps3flash_dev = NULL;
|
ps3flash_dev = NULL;
|
||||||
return error;
|
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);
|
struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
|
||||||
|
|
||||||
|
ps3_os_area_flash_register(NULL);
|
||||||
misc_deregister(&ps3flash_misc);
|
misc_deregister(&ps3flash_misc);
|
||||||
ps3stor_teardown(dev);
|
ps3stor_teardown(dev);
|
||||||
kfree(dev->sbd.core.driver_data);
|
kfree(ps3_system_bus_get_drvdata(&dev->sbd));
|
||||||
dev->sbd.core.driver_data = NULL;
|
ps3_system_bus_set_drvdata(&dev->sbd, NULL);
|
||||||
ps3flash_dev = NULL;
|
ps3flash_dev = NULL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1648,7 +1648,7 @@ static int ps3_gelic_driver_probe(struct ps3_system_bus_device *dev)
|
||||||
result = -ENOMEM;
|
result = -ENOMEM;
|
||||||
goto fail_alloc_card;
|
goto fail_alloc_card;
|
||||||
}
|
}
|
||||||
ps3_system_bus_set_driver_data(dev, card);
|
ps3_system_bus_set_drvdata(dev, card);
|
||||||
card->dev = dev;
|
card->dev = dev;
|
||||||
|
|
||||||
/* get internal vlan info */
|
/* get internal vlan info */
|
||||||
|
@ -1749,7 +1749,7 @@ fail_alloc_irq:
|
||||||
bus_id(card),
|
bus_id(card),
|
||||||
0, 0);
|
0, 0);
|
||||||
fail_status_indicator:
|
fail_status_indicator:
|
||||||
ps3_system_bus_set_driver_data(dev, NULL);
|
ps3_system_bus_set_drvdata(dev, NULL);
|
||||||
kfree(netdev_card(netdev)->unalign);
|
kfree(netdev_card(netdev)->unalign);
|
||||||
free_netdev(netdev);
|
free_netdev(netdev);
|
||||||
fail_alloc_card:
|
fail_alloc_card:
|
||||||
|
@ -1766,7 +1766,7 @@ fail_open:
|
||||||
|
|
||||||
static int ps3_gelic_driver_remove(struct ps3_system_bus_device *dev)
|
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;
|
struct net_device *netdev0;
|
||||||
pr_debug("%s: called\n", __func__);
|
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);
|
kfree(netdev_card(netdev0)->unalign);
|
||||||
free_netdev(netdev0);
|
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);
|
ps3_dma_region_free(dev->d_region);
|
||||||
|
|
||||||
|
|
|
@ -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);
|
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;
|
int result;
|
||||||
struct ps3_sys_manager_ops ops;
|
struct ps3_sys_manager_ops ops;
|
||||||
|
|
|
@ -80,12 +80,12 @@ static const struct avset_video_mode {
|
||||||
{ 0, }, /* auto */
|
{ 0, }, /* auto */
|
||||||
{YUV444, XRGB, PS3AV_CMD_VIDEO_VID_480I, A_N, 720, 480},
|
{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_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_1080I_60HZ, A_W, 1920, 1080},
|
||||||
{YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080P_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_576I, A_N, 720, 576},
|
||||||
{YUV444, XRGB, PS3AV_CMD_VIDEO_VID_576P, 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_1080I_50HZ, A_W, 1920, 1080},
|
||||||
{YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080P_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},
|
{ 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);
|
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 res;
|
||||||
int id;
|
int id;
|
||||||
|
@ -1048,7 +1048,7 @@ static struct ps3_vuart_port_driver ps3av_driver = {
|
||||||
.shutdown = ps3av_shutdown,
|
.shutdown = ps3av_shutdown,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int ps3av_module_init(void)
|
static int __init ps3av_module_init(void)
|
||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
|
|
|
@ -21,9 +21,10 @@
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
|
|
||||||
#include <asm/ps3av.h>
|
#include <asm/ps3av.h>
|
||||||
#include <asm/ps3fb.h>
|
|
||||||
#include <asm/ps3.h>
|
#include <asm/ps3.h>
|
||||||
|
#include <asm/ps3gpu.h>
|
||||||
|
|
||||||
#include "vuart.h"
|
#include "vuart.h"
|
||||||
|
|
||||||
|
|
|
@ -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__,
|
dev_dbg(&dev->core, "%s:%d: virq %lu\n", __func__, __LINE__,
|
||||||
(unsigned long)virq);
|
(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);
|
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)
|
static int ps3_ehci_remove(struct ps3_system_bus_device *dev)
|
||||||
{
|
{
|
||||||
unsigned int tmp;
|
unsigned int tmp;
|
||||||
struct usb_hcd *hcd =
|
struct usb_hcd *hcd = ps3_system_bus_get_drvdata(dev);
|
||||||
(struct usb_hcd *)ps3_system_bus_get_driver_data(dev);
|
|
||||||
|
|
||||||
BUG_ON(!hcd);
|
BUG_ON(!hcd);
|
||||||
|
|
||||||
|
@ -208,7 +207,7 @@ static int ps3_ehci_remove(struct ps3_system_bus_device *dev)
|
||||||
ehci_shutdown(hcd);
|
ehci_shutdown(hcd);
|
||||||
usb_remove_hcd(hcd);
|
usb_remove_hcd(hcd);
|
||||||
|
|
||||||
ps3_system_bus_set_driver_data(dev, NULL);
|
ps3_system_bus_set_drvdata(dev, NULL);
|
||||||
|
|
||||||
BUG_ON(!hcd->regs);
|
BUG_ON(!hcd->regs);
|
||||||
iounmap(hcd->regs);
|
iounmap(hcd->regs);
|
||||||
|
|
|
@ -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__,
|
dev_dbg(&dev->core, "%s:%d: virq %lu\n", __func__, __LINE__,
|
||||||
(unsigned long)virq);
|
(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);
|
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)
|
static int ps3_ohci_remove(struct ps3_system_bus_device *dev)
|
||||||
{
|
{
|
||||||
unsigned int tmp;
|
unsigned int tmp;
|
||||||
struct usb_hcd *hcd =
|
struct usb_hcd *hcd = ps3_system_bus_get_drvdata(dev);
|
||||||
(struct usb_hcd *)ps3_system_bus_get_driver_data(dev);
|
|
||||||
|
|
||||||
BUG_ON(!hcd);
|
BUG_ON(!hcd);
|
||||||
|
|
||||||
|
@ -208,7 +207,7 @@ static int ps3_ohci_remove(struct ps3_system_bus_device *dev)
|
||||||
ohci_shutdown(hcd);
|
ohci_shutdown(hcd);
|
||||||
usb_remove_hcd(hcd);
|
usb_remove_hcd(hcd);
|
||||||
|
|
||||||
ps3_system_bus_set_driver_data(dev, NULL);
|
ps3_system_bus_set_drvdata(dev, NULL);
|
||||||
|
|
||||||
BUG_ON(!hcd->regs);
|
BUG_ON(!hcd->regs);
|
||||||
iounmap(hcd->regs);
|
iounmap(hcd->regs);
|
||||||
|
|
|
@ -32,25 +32,16 @@
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
|
|
||||||
#include <asm/abs_addr.h>
|
#include <asm/abs_addr.h>
|
||||||
|
#include <asm/iommu.h>
|
||||||
#include <asm/lv1call.h>
|
#include <asm/lv1call.h>
|
||||||
#include <asm/ps3av.h>
|
#include <asm/ps3av.h>
|
||||||
#include <asm/ps3fb.h>
|
#include <asm/ps3fb.h>
|
||||||
#include <asm/ps3.h>
|
#include <asm/ps3.h>
|
||||||
|
#include <asm/ps3gpu.h>
|
||||||
|
|
||||||
|
|
||||||
#define DEVICE_NAME "ps3fb"
|
#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_CMD_BUF_SIZE (2 * 1024 * 1024)
|
||||||
#define GPU_FB_START (64 * 1024)
|
#define GPU_FB_START (64 * 1024)
|
||||||
#define GPU_IOIF (0x0d000000UL)
|
#define GPU_IOIF (0x0d000000UL)
|
||||||
|
@ -462,33 +453,27 @@ static void ps3fb_sync_image(struct device *dev, u64 frame_offset,
|
||||||
src_offset += GPU_FB_START;
|
src_offset += GPU_FB_START;
|
||||||
|
|
||||||
mutex_lock(&ps3_gpu_mutex);
|
mutex_lock(&ps3_gpu_mutex);
|
||||||
status = lv1_gpu_context_attribute(ps3fb.context_handle,
|
status = lv1_gpu_fb_blit(ps3fb.context_handle, dst_offset,
|
||||||
L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT,
|
GPU_IOIF + src_offset,
|
||||||
dst_offset, GPU_IOIF + src_offset,
|
|
||||||
L1GPU_FB_BLIT_WAIT_FOR_COMPLETION |
|
L1GPU_FB_BLIT_WAIT_FOR_COMPLETION |
|
||||||
(width << 16) | height,
|
(width << 16) | height,
|
||||||
line_length);
|
line_length);
|
||||||
mutex_unlock(&ps3_gpu_mutex);
|
mutex_unlock(&ps3_gpu_mutex);
|
||||||
|
|
||||||
if (status)
|
if (status)
|
||||||
dev_err(dev,
|
dev_err(dev, "%s: lv1_gpu_fb_blit failed: %d\n", __func__,
|
||||||
"%s: lv1_gpu_context_attribute FB_BLIT failed: %d\n",
|
status);
|
||||||
__func__, status);
|
|
||||||
#ifdef HEAD_A
|
#ifdef HEAD_A
|
||||||
status = lv1_gpu_context_attribute(ps3fb.context_handle,
|
status = lv1_gpu_display_flip(ps3fb.context_handle, 0, frame_offset);
|
||||||
L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP,
|
|
||||||
0, frame_offset, 0, 0);
|
|
||||||
if (status)
|
if (status)
|
||||||
dev_err(dev, "%s: lv1_gpu_context_attribute FLIP failed: %d\n",
|
dev_err(dev, "%s: lv1_gpu_display_flip failed: %d\n", __func__,
|
||||||
__func__, status);
|
status);
|
||||||
#endif
|
#endif
|
||||||
#ifdef HEAD_B
|
#ifdef HEAD_B
|
||||||
status = lv1_gpu_context_attribute(ps3fb.context_handle,
|
status = lv1_gpu_display_flip(ps3fb.context_handle, 1, frame_offset);
|
||||||
L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP,
|
|
||||||
1, frame_offset, 0, 0);
|
|
||||||
if (status)
|
if (status)
|
||||||
dev_err(dev, "%s: lv1_gpu_context_attribute FLIP failed: %d\n",
|
dev_err(dev, "%s: lv1_gpu_display_flip failed: %d\n", __func__,
|
||||||
__func__, status);
|
status);
|
||||||
#endif
|
#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 = {
|
static struct fb_ops ps3fb_ops = {
|
||||||
.fb_open = ps3fb_open,
|
.fb_open = ps3fb_open,
|
||||||
.fb_release = ps3fb_release,
|
.fb_release = ps3fb_release,
|
||||||
|
@ -1048,49 +966,18 @@ static struct fb_fix_screeninfo ps3fb_fix __initdata = {
|
||||||
.accel = FB_ACCEL_NONE,
|
.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)
|
static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
|
||||||
{
|
{
|
||||||
struct fb_info *info;
|
struct fb_info *info;
|
||||||
struct ps3fb_par *par;
|
struct ps3fb_par *par;
|
||||||
int retval = -ENOMEM;
|
int retval;
|
||||||
u64 ddr_lpar = 0;
|
u64 ddr_lpar = 0;
|
||||||
u64 lpar_dma_control = 0;
|
u64 lpar_dma_control = 0;
|
||||||
u64 lpar_driver_info = 0;
|
u64 lpar_driver_info = 0;
|
||||||
u64 lpar_reports = 0;
|
u64 lpar_reports = 0;
|
||||||
u64 lpar_reports_size = 0;
|
u64 lpar_reports_size = 0;
|
||||||
u64 xdr_lpar;
|
u64 xdr_lpar;
|
||||||
|
struct gpu_driver_info *dinfo;
|
||||||
void *fb_start;
|
void *fb_start;
|
||||||
int status;
|
int status;
|
||||||
struct task_struct *task;
|
struct task_struct *task;
|
||||||
|
@ -1101,8 +988,8 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
status = ps3_open_hv_device(dev);
|
retval = ps3_open_hv_device(dev);
|
||||||
if (status) {
|
if (retval) {
|
||||||
dev_err(&dev->core, "%s: ps3_open_hv_device failed\n",
|
dev_err(&dev->core, "%s: ps3_open_hv_device failed\n",
|
||||||
__func__);
|
__func__);
|
||||||
goto err;
|
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 */
|
atomic_set(&ps3fb.ext_flip, 0); /* for flip with vsync */
|
||||||
init_waitqueue_head(&ps3fb.wait_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;
|
max_ps3fb_size = _ALIGN_UP(GPU_IOIF, 256*1024*1024) - GPU_IOIF;
|
||||||
if (ps3fb_videomemory.size > max_ps3fb_size) {
|
if (ps3fb_videomemory.size > max_ps3fb_size) {
|
||||||
|
@ -1131,7 +1035,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
|
||||||
if (status) {
|
if (status) {
|
||||||
dev_err(&dev->core, "%s: lv1_gpu_memory_allocate failed: %d\n",
|
dev_err(&dev->core, "%s: lv1_gpu_memory_allocate failed: %d\n",
|
||||||
__func__, status);
|
__func__, status);
|
||||||
goto err;
|
goto err_close_device;
|
||||||
}
|
}
|
||||||
dev_dbg(&dev->core, "ddr:lpar:0x%llx\n", ddr_lpar);
|
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);
|
&lpar_reports, &lpar_reports_size);
|
||||||
if (status) {
|
if (status) {
|
||||||
dev_err(&dev->core,
|
dev_err(&dev->core,
|
||||||
"%s: lv1_gpu_context_attribute failed: %d\n", __func__,
|
"%s: lv1_gpu_context_allocate failed: %d\n", __func__,
|
||||||
status);
|
status);
|
||||||
goto err_gpu_memory_free;
|
goto err_gpu_memory_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* vsync interrupt */
|
/* vsync interrupt */
|
||||||
ps3fb.dinfo = (void __force *)ioremap(lpar_driver_info, 128 * 1024);
|
dinfo = (void __force *)ioremap(lpar_driver_info, 128 * 1024);
|
||||||
if (!ps3fb.dinfo) {
|
if (!dinfo) {
|
||||||
dev_err(&dev->core, "%s: ioremap failed\n", __func__);
|
dev_err(&dev->core, "%s: ioremap failed\n", __func__);
|
||||||
goto err_gpu_context_free;
|
goto err_gpu_context_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
retval = ps3fb_vsync_settings(ps3fb.dinfo, &dev->core);
|
ps3fb.dinfo = dinfo;
|
||||||
if (retval)
|
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;
|
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 */
|
/* Clear memory to prevent kernel info leakage into userspace */
|
||||||
memset(ps3fb_videomemory.address, 0, ps3fb_videomemory.size);
|
memset(ps3fb_videomemory.address, 0, ps3fb_videomemory.size);
|
||||||
|
|
||||||
xdr_lpar = ps3_mm_phys_to_lpar(__pa(ps3fb_videomemory.address));
|
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;
|
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);
|
info = framebuffer_alloc(sizeof(struct ps3fb_par), &dev->core);
|
||||||
if (!info)
|
if (!info)
|
||||||
goto err_free_irq;
|
goto err_context_fb_close;
|
||||||
|
|
||||||
par = info->par;
|
par = info->par;
|
||||||
par->mode_id = ~ps3fb_mode; /* != ps3fb_mode, to trigger change */
|
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)
|
if (retval < 0)
|
||||||
goto err_fb_dealloc;
|
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_info(info->device, "%s %s, using %u KiB of video memory\n",
|
||||||
dev_driver_string(info->dev), dev_name(info->dev),
|
dev_driver_string(info->dev), dev_name(info->dev),
|
||||||
|
@ -1232,8 +1188,14 @@ err_fb_dealloc:
|
||||||
fb_dealloc_cmap(&info->cmap);
|
fb_dealloc_cmap(&info->cmap);
|
||||||
err_framebuffer_release:
|
err_framebuffer_release:
|
||||||
framebuffer_release(info);
|
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:
|
err_free_irq:
|
||||||
free_irq(ps3fb.irq_no, &dev->core);
|
free_irq(ps3fb.irq_no, &dev->core);
|
||||||
|
err_destroy_plug:
|
||||||
ps3_irq_plug_destroy(ps3fb.irq_no);
|
ps3_irq_plug_destroy(ps3fb.irq_no);
|
||||||
err_iounmap_dinfo:
|
err_iounmap_dinfo:
|
||||||
iounmap((u8 __force __iomem *)ps3fb.dinfo);
|
iounmap((u8 __force __iomem *)ps3fb.dinfo);
|
||||||
|
@ -1241,14 +1203,16 @@ err_gpu_context_free:
|
||||||
lv1_gpu_context_free(ps3fb.context_handle);
|
lv1_gpu_context_free(ps3fb.context_handle);
|
||||||
err_gpu_memory_free:
|
err_gpu_memory_free:
|
||||||
lv1_gpu_memory_free(ps3fb.memory_handle);
|
lv1_gpu_memory_free(ps3fb.memory_handle);
|
||||||
|
err_close_device:
|
||||||
|
ps3_close_hv_device(dev);
|
||||||
err:
|
err:
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ps3fb_shutdown(struct ps3_system_bus_device *dev)
|
static int ps3fb_shutdown(struct ps3_system_bus_device *dev)
|
||||||
{
|
{
|
||||||
int status;
|
struct fb_info *info = ps3_system_bus_get_drvdata(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__);
|
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);
|
unregister_framebuffer(info);
|
||||||
fb_dealloc_cmap(&info->cmap);
|
fb_dealloc_cmap(&info->cmap);
|
||||||
framebuffer_release(info);
|
framebuffer_release(info);
|
||||||
info = dev->core.driver_data = NULL;
|
ps3_system_bus_set_drvdata(dev, NULL);
|
||||||
}
|
}
|
||||||
iounmap((u8 __force __iomem *)ps3fb.dinfo);
|
iounmap((u8 __force __iomem *)ps3fb.dinfo);
|
||||||
|
lv1_gpu_fb_close(ps3fb.context_handle);
|
||||||
status = lv1_gpu_context_free(ps3fb.context_handle);
|
lv1_gpu_context_iomap(ps3fb.context_handle, GPU_IOIF, xdr_lpar,
|
||||||
if (status)
|
ps3fb_videomemory.size, CBE_IOPTE_M);
|
||||||
dev_dbg(&dev->core, "lv1_gpu_context_free failed: %d\n",
|
lv1_gpu_context_free(ps3fb.context_handle);
|
||||||
status);
|
lv1_gpu_memory_free(ps3fb.memory_handle);
|
||||||
|
|
||||||
status = lv1_gpu_memory_free(ps3fb.memory_handle);
|
|
||||||
if (status)
|
|
||||||
dev_dbg(&dev->core, "lv1_gpu_memory_free failed: %d\n",
|
|
||||||
status);
|
|
||||||
|
|
||||||
ps3_close_hv_device(dev);
|
ps3_close_hv_device(dev);
|
||||||
dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__);
|
dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__);
|
||||||
|
|
||||||
|
|
|
@ -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 */
|
|
@ -590,6 +590,11 @@ static inline void bio_list_merge_head(struct bio_list *bl,
|
||||||
bl->head = bl2->head;
|
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)
|
static inline struct bio *bio_list_pop(struct bio_list *bl)
|
||||||
{
|
{
|
||||||
struct bio *bio = bl->head;
|
struct bio *bio = bl->head;
|
||||||
|
|
|
@ -194,4 +194,10 @@ config DISABLE_OBSOLETE_CPUMASK_FUNCTIONS
|
||||||
config NLATTR
|
config NLATTR
|
||||||
bool
|
bool
|
||||||
|
|
||||||
|
#
|
||||||
|
# Generic 64-bit atomic support is selected if needed
|
||||||
|
#
|
||||||
|
config GENERIC_ATOMIC64
|
||||||
|
bool
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|
|
@ -95,6 +95,8 @@ obj-$(CONFIG_DMA_API_DEBUG) += dma-debug.o
|
||||||
|
|
||||||
obj-$(CONFIG_GENERIC_CSUM) += checksum.o
|
obj-$(CONFIG_GENERIC_CSUM) += checksum.o
|
||||||
|
|
||||||
|
obj-$(CONFIG_GENERIC_ATOMIC64) += atomic64.o
|
||||||
|
|
||||||
hostprogs-y := gen_crc32table
|
hostprogs-y := gen_crc32table
|
||||||
clean-files := crc32table.h
|
clean-files := crc32table.h
|
||||||
|
|
||||||
|
|
|
@ -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);
|
Loading…
Reference in New Issue