diff --git a/[refs] b/[refs] index 9acc04699a0c..5982c7fe84fc 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 32e2f63bcc8903487975506d8db5931a8c4bbb1f +refs/heads/master: 7af048dc7639db5202c56fecf2346c310647a218 diff --git a/trunk/arch/arm/mach-imx/mach-cpuimx27.c b/trunk/arch/arm/mach-imx/mach-cpuimx27.c index 339150ab0ea5..575ff1ae85a7 100644 --- a/trunk/arch/arm/mach-imx/mach-cpuimx27.c +++ b/trunk/arch/arm/mach-imx/mach-cpuimx27.c @@ -279,13 +279,13 @@ static void __init eukrea_cpuimx27_init(void) #if defined(CONFIG_USB_ULPI) if (otg_mode_host) { otg_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops, - ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT); + USB_OTG_DRV_VBUS | USB_OTG_DRV_VBUS_EXT); mxc_register_device(&mxc_otg_host, &otg_pdata); } usbh2_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops, - ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT); + USB_OTG_DRV_VBUS | USB_OTG_DRV_VBUS_EXT); mxc_register_device(&mxc_usbh2, &usbh2_pdata); #endif diff --git a/trunk/arch/arm/mach-imx/mach-pca100.c b/trunk/arch/arm/mach-imx/mach-pca100.c index 23c9e1f37b9c..a389d1148f18 100644 --- a/trunk/arch/arm/mach-imx/mach-pca100.c +++ b/trunk/arch/arm/mach-imx/mach-pca100.c @@ -419,13 +419,13 @@ static void __init pca100_init(void) #if defined(CONFIG_USB_ULPI) if (otg_mode_host) { otg_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops, - ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT); + USB_OTG_DRV_VBUS | USB_OTG_DRV_VBUS_EXT); mxc_register_device(&mxc_otg_host, &otg_pdata); } usbh2_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops, - ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT); + USB_OTG_DRV_VBUS | USB_OTG_DRV_VBUS_EXT); mxc_register_device(&mxc_usbh2, &usbh2_pdata); #endif diff --git a/trunk/arch/arm/mach-mx25/mach-cpuimx25.c b/trunk/arch/arm/mach-mx25/mach-cpuimx25.c index a5f0174290b4..56b2e26d23b4 100644 --- a/trunk/arch/arm/mach-mx25/mach-cpuimx25.c +++ b/trunk/arch/arm/mach-mx25/mach-cpuimx25.c @@ -138,7 +138,7 @@ static void __init eukrea_cpuimx25_init(void) #if defined(CONFIG_USB_ULPI) if (otg_mode_host) { otg_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops, - ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT); + USB_OTG_DRV_VBUS | USB_OTG_DRV_VBUS_EXT); mxc_register_device(&mxc_otg, &otg_pdata); } diff --git a/trunk/arch/arm/mach-mx3/mach-cpuimx35.c b/trunk/arch/arm/mach-mx3/mach-cpuimx35.c index 9770a6a973be..63f970f340a2 100644 --- a/trunk/arch/arm/mach-mx3/mach-cpuimx35.c +++ b/trunk/arch/arm/mach-mx3/mach-cpuimx35.c @@ -192,7 +192,7 @@ static void __init mxc_board_init(void) #if defined(CONFIG_USB_ULPI) if (otg_mode_host) { otg_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops, - ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT); + USB_OTG_DRV_VBUS | USB_OTG_DRV_VBUS_EXT); mxc_register_device(&mxc_otg_host, &otg_pdata); } diff --git a/trunk/arch/powerpc/Makefile b/trunk/arch/powerpc/Makefile index b7212b619c52..e3ea151c9597 100644 --- a/trunk/arch/powerpc/Makefile +++ b/trunk/arch/powerpc/Makefile @@ -164,7 +164,7 @@ drivers-$(CONFIG_OPROFILE) += arch/powerpc/oprofile/ all: zImage # With make 3.82 we cannot mix normal and wildcard targets -BOOT_TARGETS1 := zImage zImage.initrd uImage +BOOT_TARGETS1 := zImage zImage.initrd uImaged BOOT_TARGETS2 := zImage% dtbImage% treeImage.% cuImage.% simpleImage.% PHONY += $(BOOT_TARGETS1) $(BOOT_TARGETS2) diff --git a/trunk/arch/powerpc/boot/dts/canyonlands.dts b/trunk/arch/powerpc/boot/dts/canyonlands.dts index a30370396250..5806ef0b860b 100644 --- a/trunk/arch/powerpc/boot/dts/canyonlands.dts +++ b/trunk/arch/powerpc/boot/dts/canyonlands.dts @@ -163,14 +163,6 @@ interrupts = <0x1e 4>; }; - SATA0: sata@bffd1000 { - compatible = "amcc,sata-460ex"; - reg = <4 0xbffd1000 0x800 4 0xbffd0800 0x400>; - interrupt-parent = <&UIC3>; - interrupts = <0x0 0x4 /* SATA */ - 0x5 0x4>; /* AHBDMA */ - }; - POB0: opb { compatible = "ibm,opb-460ex", "ibm,opb"; #address-cells = <1>; diff --git a/trunk/arch/powerpc/include/asm/mmu-hash64.h b/trunk/arch/powerpc/include/asm/mmu-hash64.h index acac35d5b382..0e398cfee2c8 100644 --- a/trunk/arch/powerpc/include/asm/mmu-hash64.h +++ b/trunk/arch/powerpc/include/asm/mmu-hash64.h @@ -433,7 +433,7 @@ typedef struct { * with. However gcc is not clever enough to compute the * modulus (2^n-1) without a second multiply. */ -#define vsid_scramble(protovsid, size) \ +#define vsid_scrample(protovsid, size) \ ((((protovsid) * VSID_MULTIPLIER_##size) % VSID_MODULUS_##size)) #else /* 1 */ diff --git a/trunk/arch/powerpc/include/asm/reg.h b/trunk/arch/powerpc/include/asm/reg.h index ff0005eec7dd..d8be016d2ede 100644 --- a/trunk/arch/powerpc/include/asm/reg.h +++ b/trunk/arch/powerpc/include/asm/reg.h @@ -951,14 +951,7 @@ #ifdef CONFIG_PPC64 extern void ppc64_runlatch_on(void); -extern void __ppc64_runlatch_off(void); - -#define ppc64_runlatch_off() \ - do { \ - if (cpu_has_feature(CPU_FTR_CTRL) && \ - test_thread_flag(TIF_RUNLATCH)) \ - __ppc64_runlatch_off(); \ - } while (0) +extern void ppc64_runlatch_off(void); extern unsigned long scom970_read(unsigned int address); extern void scom970_write(unsigned int address, unsigned long value); diff --git a/trunk/arch/powerpc/include/asm/rwsem.h b/trunk/arch/powerpc/include/asm/rwsem.h index 8447d89fbe72..24cd9281ec37 100644 --- a/trunk/arch/powerpc/include/asm/rwsem.h +++ b/trunk/arch/powerpc/include/asm/rwsem.h @@ -21,20 +21,15 @@ /* * the semaphore definition */ -#ifdef CONFIG_PPC64 -# define RWSEM_ACTIVE_MASK 0xffffffffL -#else -# define RWSEM_ACTIVE_MASK 0x0000ffffL -#endif - -#define RWSEM_UNLOCKED_VALUE 0x00000000L -#define RWSEM_ACTIVE_BIAS 0x00000001L -#define RWSEM_WAITING_BIAS (-RWSEM_ACTIVE_MASK-1) +struct rw_semaphore { + /* XXX this should be able to be an atomic_t -- paulus */ + signed int count; +#define RWSEM_UNLOCKED_VALUE 0x00000000 +#define RWSEM_ACTIVE_BIAS 0x00000001 +#define RWSEM_ACTIVE_MASK 0x0000ffff +#define RWSEM_WAITING_BIAS (-0x00010000) #define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS #define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS) - -struct rw_semaphore { - long count; spinlock_t wait_lock; struct list_head wait_list; #ifdef CONFIG_DEBUG_LOCK_ALLOC @@ -48,13 +43,9 @@ struct rw_semaphore { # define __RWSEM_DEP_MAP_INIT(lockname) #endif -#define __RWSEM_INITIALIZER(name) \ -{ \ - RWSEM_UNLOCKED_VALUE, \ - __SPIN_LOCK_UNLOCKED((name).wait_lock), \ - LIST_HEAD_INIT((name).wait_list) \ - __RWSEM_DEP_MAP_INIT(name) \ -} +#define __RWSEM_INITIALIZER(name) \ + { RWSEM_UNLOCKED_VALUE, __SPIN_LOCK_UNLOCKED((name).wait_lock), \ + LIST_HEAD_INIT((name).wait_list) __RWSEM_DEP_MAP_INIT(name) } #define DECLARE_RWSEM(name) \ struct rw_semaphore name = __RWSEM_INITIALIZER(name) @@ -79,13 +70,13 @@ extern void __init_rwsem(struct rw_semaphore *sem, const char *name, */ static inline void __down_read(struct rw_semaphore *sem) { - if (unlikely(atomic_long_inc_return((atomic_long_t *)&sem->count) <= 0)) + if (unlikely(atomic_inc_return((atomic_t *)(&sem->count)) <= 0)) rwsem_down_read_failed(sem); } static inline int __down_read_trylock(struct rw_semaphore *sem) { - long tmp; + int tmp; while ((tmp = sem->count) >= 0) { if (tmp == cmpxchg(&sem->count, tmp, @@ -101,10 +92,10 @@ static inline int __down_read_trylock(struct rw_semaphore *sem) */ static inline void __down_write_nested(struct rw_semaphore *sem, int subclass) { - long tmp; + int tmp; - tmp = atomic_long_add_return(RWSEM_ACTIVE_WRITE_BIAS, - (atomic_long_t *)&sem->count); + tmp = atomic_add_return(RWSEM_ACTIVE_WRITE_BIAS, + (atomic_t *)(&sem->count)); if (unlikely(tmp != RWSEM_ACTIVE_WRITE_BIAS)) rwsem_down_write_failed(sem); } @@ -116,7 +107,7 @@ static inline void __down_write(struct rw_semaphore *sem) static inline int __down_write_trylock(struct rw_semaphore *sem) { - long tmp; + int tmp; tmp = cmpxchg(&sem->count, RWSEM_UNLOCKED_VALUE, RWSEM_ACTIVE_WRITE_BIAS); @@ -128,9 +119,9 @@ static inline int __down_write_trylock(struct rw_semaphore *sem) */ static inline void __up_read(struct rw_semaphore *sem) { - long tmp; + int tmp; - tmp = atomic_long_dec_return((atomic_long_t *)&sem->count); + tmp = atomic_dec_return((atomic_t *)(&sem->count)); if (unlikely(tmp < -1 && (tmp & RWSEM_ACTIVE_MASK) == 0)) rwsem_wake(sem); } @@ -140,17 +131,17 @@ static inline void __up_read(struct rw_semaphore *sem) */ static inline void __up_write(struct rw_semaphore *sem) { - if (unlikely(atomic_long_sub_return(RWSEM_ACTIVE_WRITE_BIAS, - (atomic_long_t *)&sem->count) < 0)) + if (unlikely(atomic_sub_return(RWSEM_ACTIVE_WRITE_BIAS, + (atomic_t *)(&sem->count)) < 0)) rwsem_wake(sem); } /* * implement atomic add functionality */ -static inline void rwsem_atomic_add(long delta, struct rw_semaphore *sem) +static inline void rwsem_atomic_add(int delta, struct rw_semaphore *sem) { - atomic_long_add(delta, (atomic_long_t *)&sem->count); + atomic_add(delta, (atomic_t *)(&sem->count)); } /* @@ -158,10 +149,9 @@ static inline void rwsem_atomic_add(long delta, struct rw_semaphore *sem) */ static inline void __downgrade_write(struct rw_semaphore *sem) { - long tmp; + int tmp; - tmp = atomic_long_add_return(-RWSEM_WAITING_BIAS, - (atomic_long_t *)&sem->count); + tmp = atomic_add_return(-RWSEM_WAITING_BIAS, (atomic_t *)(&sem->count)); if (tmp < 0) rwsem_downgrade_wake(sem); } @@ -169,14 +159,14 @@ static inline void __downgrade_write(struct rw_semaphore *sem) /* * implement exchange and add functionality */ -static inline long rwsem_atomic_update(long delta, struct rw_semaphore *sem) +static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem) { - return atomic_long_add_return(delta, (atomic_long_t *)&sem->count); + return atomic_add_return(delta, (atomic_t *)(&sem->count)); } static inline int rwsem_is_locked(struct rw_semaphore *sem) { - return sem->count != 0; + return (sem->count != 0); } #endif /* __KERNEL__ */ diff --git a/trunk/arch/powerpc/include/asm/systbl.h b/trunk/arch/powerpc/include/asm/systbl.h index 3d212669a130..a5ee345b6a5c 100644 --- a/trunk/arch/powerpc/include/asm/systbl.h +++ b/trunk/arch/powerpc/include/asm/systbl.h @@ -326,6 +326,3 @@ SYSCALL_SPU(perf_event_open) COMPAT_SYS_SPU(preadv) COMPAT_SYS_SPU(pwritev) COMPAT_SYS(rt_tgsigqueueinfo) -SYSCALL(fanotify_init) -COMPAT_SYS(fanotify_mark) -SYSCALL_SPU(prlimit64) diff --git a/trunk/arch/powerpc/include/asm/unistd.h b/trunk/arch/powerpc/include/asm/unistd.h index 597e6f9d094a..f0a10266e7f7 100644 --- a/trunk/arch/powerpc/include/asm/unistd.h +++ b/trunk/arch/powerpc/include/asm/unistd.h @@ -345,13 +345,10 @@ #define __NR_preadv 320 #define __NR_pwritev 321 #define __NR_rt_tgsigqueueinfo 322 -#define __NR_fanotify_init 323 -#define __NR_fanotify_mark 324 -#define __NR_prlimit64 325 #ifdef __KERNEL__ -#define __NR_syscalls 326 +#define __NR_syscalls 323 #define __NR__exit __NR_exit #define NR_syscalls __NR_syscalls diff --git a/trunk/arch/powerpc/kernel/cputable.c b/trunk/arch/powerpc/kernel/cputable.c index 1f9123f412ec..65e2b4e10f97 100644 --- a/trunk/arch/powerpc/kernel/cputable.c +++ b/trunk/arch/powerpc/kernel/cputable.c @@ -1826,6 +1826,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_features = CPU_FTRS_47X, .cpu_user_features = COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU, + .cpu_user_features = COMMON_USER_BOOKE, .mmu_features = MMU_FTR_TYPE_47x | MMU_FTR_USE_TLBIVAX_BCAST | MMU_FTR_LOCK_BCAST_INVAL, .icache_bsize = 32, diff --git a/trunk/arch/powerpc/kernel/crash.c b/trunk/arch/powerpc/kernel/crash.c index 4457382f8667..417f7b05a9ce 100644 --- a/trunk/arch/powerpc/kernel/crash.c +++ b/trunk/arch/powerpc/kernel/crash.c @@ -402,18 +402,6 @@ void default_machine_crash_shutdown(struct pt_regs *regs) */ hard_irq_disable(); - /* - * Make a note of crashing cpu. Will be used in machine_kexec - * such that another IPI will not be sent. - */ - crashing_cpu = smp_processor_id(); - crash_save_cpu(regs, crashing_cpu); - crash_kexec_prepare_cpus(crashing_cpu); - cpu_set(crashing_cpu, cpus_in_crash); -#if defined(CONFIG_PPC_STD_MMU_64) && defined(CONFIG_SMP) - crash_kexec_wait_realmode(crashing_cpu); -#endif - for_each_irq(i) { struct irq_desc *desc = irq_to_desc(i); @@ -450,8 +438,18 @@ void default_machine_crash_shutdown(struct pt_regs *regs) crash_shutdown_cpu = -1; __debugger_fault_handler = old_handler; + /* + * Make a note of crashing cpu. Will be used in machine_kexec + * such that another IPI will not be sent. + */ + crashing_cpu = smp_processor_id(); + crash_save_cpu(regs, crashing_cpu); + crash_kexec_prepare_cpus(crashing_cpu); + cpu_set(crashing_cpu, cpus_in_crash); crash_kexec_stop_spus(); - +#if defined(CONFIG_PPC_STD_MMU_64) && defined(CONFIG_SMP) + crash_kexec_wait_realmode(crashing_cpu); +#endif if (ppc_md.kexec_cpu_down) ppc_md.kexec_cpu_down(1, 0); } diff --git a/trunk/arch/powerpc/kernel/head_44x.S b/trunk/arch/powerpc/kernel/head_44x.S index 562305b40a8e..5ab484ef06a7 100644 --- a/trunk/arch/powerpc/kernel/head_44x.S +++ b/trunk/arch/powerpc/kernel/head_44x.S @@ -113,10 +113,6 @@ _ENTRY(_start); stw r5, 0(r4) /* Save abatron_pteptrs at a fixed location */ stw r6, 0(r5) - /* Clear the Machine Check Syndrome Register */ - li r0,0 - mtspr SPRN_MCSR,r0 - /* Let's move on */ lis r4,start_kernel@h ori r4,r4,start_kernel@l diff --git a/trunk/arch/powerpc/kernel/head_64.S b/trunk/arch/powerpc/kernel/head_64.S index 4d6681dce816..844a44b64472 100644 --- a/trunk/arch/powerpc/kernel/head_64.S +++ b/trunk/arch/powerpc/kernel/head_64.S @@ -572,6 +572,9 @@ __secondary_start: /* Set thread priority to MEDIUM */ HMT_MEDIUM + /* Do early setup for that CPU (stab, slb, hash table pointer) */ + bl .early_setup_secondary + /* Initialize the kernel stack. Just a repeat for iSeries. */ LOAD_REG_ADDR(r3, current_set) sldi r28,r24,3 /* get current_set[cpu#] */ @@ -579,9 +582,6 @@ __secondary_start: addi r1,r1,THREAD_SIZE-STACK_FRAME_OVERHEAD std r1,PACAKSAVE(r13) - /* Do early setup for that CPU (stab, slb, hash table pointer) */ - bl .early_setup_secondary - /* Clear backchain so we get nice backtraces */ li r7,0 mtlr r7 diff --git a/trunk/arch/powerpc/kernel/idle.c b/trunk/arch/powerpc/kernel/idle.c index 39a2baa6ad58..049dda60e475 100644 --- a/trunk/arch/powerpc/kernel/idle.c +++ b/trunk/arch/powerpc/kernel/idle.c @@ -94,9 +94,9 @@ void cpu_idle(void) HMT_medium(); ppc64_runlatch_on(); tick_nohz_restart_sched_tick(); - preempt_enable_no_resched(); if (cpu_should_die()) cpu_die(); + preempt_enable_no_resched(); schedule(); preempt_disable(); } diff --git a/trunk/arch/powerpc/kernel/irq.c b/trunk/arch/powerpc/kernel/irq.c index 4a65386995d7..d3ce67cf03be 100644 --- a/trunk/arch/powerpc/kernel/irq.c +++ b/trunk/arch/powerpc/kernel/irq.c @@ -67,7 +67,6 @@ #include #include #include -#include #ifdef CONFIG_PPC64 #include @@ -447,23 +446,22 @@ struct thread_info *mcheckirq_ctx[NR_CPUS] __read_mostly; void exc_lvl_ctx_init(void) { struct thread_info *tp; - int i, hw_cpu; + int i; for_each_possible_cpu(i) { - hw_cpu = get_hard_smp_processor_id(i); - memset((void *)critirq_ctx[hw_cpu], 0, THREAD_SIZE); - tp = critirq_ctx[hw_cpu]; + memset((void *)critirq_ctx[i], 0, THREAD_SIZE); + tp = critirq_ctx[i]; tp->cpu = i; tp->preempt_count = 0; #ifdef CONFIG_BOOKE - memset((void *)dbgirq_ctx[hw_cpu], 0, THREAD_SIZE); - tp = dbgirq_ctx[hw_cpu]; + memset((void *)dbgirq_ctx[i], 0, THREAD_SIZE); + tp = dbgirq_ctx[i]; tp->cpu = i; tp->preempt_count = 0; - memset((void *)mcheckirq_ctx[hw_cpu], 0, THREAD_SIZE); - tp = mcheckirq_ctx[hw_cpu]; + memset((void *)mcheckirq_ctx[i], 0, THREAD_SIZE); + tp = mcheckirq_ctx[i]; tp->cpu = i; tp->preempt_count = HARDIRQ_OFFSET; #endif diff --git a/trunk/arch/powerpc/kernel/pci_of_scan.c b/trunk/arch/powerpc/kernel/pci_of_scan.c index e751506323b4..6ddb795f83e8 100644 --- a/trunk/arch/powerpc/kernel/pci_of_scan.c +++ b/trunk/arch/powerpc/kernel/pci_of_scan.c @@ -336,7 +336,7 @@ static void __devinit __of_scan_bus(struct device_node *node, if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) { struct device_node *child = pci_device_to_OF_node(dev); - if (child) + if (dev) of_scan_pci_bridge(child, dev); } } diff --git a/trunk/arch/powerpc/kernel/process.c b/trunk/arch/powerpc/kernel/process.c index b1c648a36b03..91356ffda2ca 100644 --- a/trunk/arch/powerpc/kernel/process.c +++ b/trunk/arch/powerpc/kernel/process.c @@ -728,7 +728,7 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, p->thread.regs = childregs; if (clone_flags & CLONE_SETTLS) { #ifdef CONFIG_PPC64 - if (!is_32bit_task()) + if (!test_thread_flag(TIF_32BIT)) childregs->gpr[13] = childregs->gpr[6]; else #endif @@ -823,7 +823,7 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp) regs->nip = start; regs->msr = MSR_USER; #else - if (!is_32bit_task()) { + if (!test_thread_flag(TIF_32BIT)) { unsigned long entry, toc; /* start is a relocated pointer to the function descriptor for @@ -995,7 +995,7 @@ int sys_clone(unsigned long clone_flags, unsigned long usp, if (usp == 0) usp = regs->gpr[1]; /* stack pointer for child */ #ifdef CONFIG_PPC64 - if (is_32bit_task()) { + if (test_thread_flag(TIF_32BIT)) { parent_tidp = TRUNC_PTR(parent_tidp); child_tidp = TRUNC_PTR(child_tidp); } @@ -1199,17 +1199,19 @@ void ppc64_runlatch_on(void) } } -void __ppc64_runlatch_off(void) +void ppc64_runlatch_off(void) { unsigned long ctrl; - HMT_medium(); + if (cpu_has_feature(CPU_FTR_CTRL) && test_thread_flag(TIF_RUNLATCH)) { + HMT_medium(); - clear_thread_flag(TIF_RUNLATCH); + clear_thread_flag(TIF_RUNLATCH); - ctrl = mfspr(SPRN_CTRLF); - ctrl &= ~CTRL_RUNLATCH; - mtspr(SPRN_CTRLT, ctrl); + ctrl = mfspr(SPRN_CTRLF); + ctrl &= ~CTRL_RUNLATCH; + mtspr(SPRN_CTRLT, ctrl); + } } #endif diff --git a/trunk/arch/powerpc/kernel/setup_32.c b/trunk/arch/powerpc/kernel/setup_32.c index 93666f9cabf1..a10ffc85ada7 100644 --- a/trunk/arch/powerpc/kernel/setup_32.c +++ b/trunk/arch/powerpc/kernel/setup_32.c @@ -258,18 +258,17 @@ static void __init irqstack_early_init(void) #if defined(CONFIG_BOOKE) || defined(CONFIG_40x) static void __init exc_lvl_early_init(void) { - unsigned int i, hw_cpu; + unsigned int i; /* interrupt stacks must be in lowmem, we get that for free on ppc32 * as the memblock is limited to lowmem by MEMBLOCK_REAL_LIMIT */ for_each_possible_cpu(i) { - hw_cpu = get_hard_smp_processor_id(i); - critirq_ctx[hw_cpu] = (struct thread_info *) + critirq_ctx[i] = (struct thread_info *) __va(memblock_alloc(THREAD_SIZE, THREAD_SIZE)); #ifdef CONFIG_BOOKE - dbgirq_ctx[hw_cpu] = (struct thread_info *) + dbgirq_ctx[i] = (struct thread_info *) __va(memblock_alloc(THREAD_SIZE, THREAD_SIZE)); - mcheckirq_ctx[hw_cpu] = (struct thread_info *) + mcheckirq_ctx[i] = (struct thread_info *) __va(memblock_alloc(THREAD_SIZE, THREAD_SIZE)); #endif } diff --git a/trunk/arch/powerpc/kernel/setup_64.c b/trunk/arch/powerpc/kernel/setup_64.c index e72690ec9b87..1bee4b68fa45 100644 --- a/trunk/arch/powerpc/kernel/setup_64.c +++ b/trunk/arch/powerpc/kernel/setup_64.c @@ -95,7 +95,7 @@ int ucache_bsize; #ifdef CONFIG_SMP -static char *smt_enabled_cmdline; +static int smt_enabled_cmdline; /* Look for ibm,smt-enabled OF option */ static void check_smt_enabled(void) @@ -103,46 +103,37 @@ static void check_smt_enabled(void) struct device_node *dn; const char *smt_option; - /* Default to enabling all threads */ - smt_enabled_at_boot = threads_per_core; - /* Allow the command line to overrule the OF option */ - if (smt_enabled_cmdline) { - if (!strcmp(smt_enabled_cmdline, "on")) - smt_enabled_at_boot = threads_per_core; - else if (!strcmp(smt_enabled_cmdline, "off")) - smt_enabled_at_boot = 0; - else { - long smt; - int rc; - - rc = strict_strtol(smt_enabled_cmdline, 10, &smt); - if (!rc) - smt_enabled_at_boot = - min(threads_per_core, (int)smt); - } - } else { - dn = of_find_node_by_path("/options"); - if (dn) { - smt_option = of_get_property(dn, "ibm,smt-enabled", - NULL); - - if (smt_option) { - if (!strcmp(smt_option, "on")) - smt_enabled_at_boot = threads_per_core; - else if (!strcmp(smt_option, "off")) - smt_enabled_at_boot = 0; - } - - of_node_put(dn); - } - } + if (smt_enabled_cmdline) + return; + + dn = of_find_node_by_path("/options"); + + if (dn) { + smt_option = of_get_property(dn, "ibm,smt-enabled", NULL); + + if (smt_option) { + if (!strcmp(smt_option, "on")) + smt_enabled_at_boot = 1; + else if (!strcmp(smt_option, "off")) + smt_enabled_at_boot = 0; + } + } } /* Look for smt-enabled= cmdline option */ static int __init early_smt_enabled(char *p) { - smt_enabled_cmdline = p; + smt_enabled_cmdline = 1; + + if (!p) + return 0; + + if (!strcmp(p, "on") || !strcmp(p, "1")) + smt_enabled_at_boot = 1; + else if (!strcmp(p, "off") || !strcmp(p, "0")) + smt_enabled_at_boot = 0; + return 0; } early_param("smt-enabled", early_smt_enabled); @@ -389,8 +380,8 @@ void __init setup_system(void) */ xmon_setup(); - smp_setup_cpu_maps(); check_smt_enabled(); + smp_setup_cpu_maps(); #ifdef CONFIG_SMP /* Release secondary cpus out of their spinloops at 0x60 now that diff --git a/trunk/arch/powerpc/kernel/smp.c b/trunk/arch/powerpc/kernel/smp.c index 0008bc58e826..a61b3ddd7bb3 100644 --- a/trunk/arch/powerpc/kernel/smp.c +++ b/trunk/arch/powerpc/kernel/smp.c @@ -427,11 +427,11 @@ int __cpuinit __cpu_up(unsigned int cpu) #endif if (!cpu_callin_map[cpu]) { - printk(KERN_ERR "Processor %u is stuck.\n", cpu); + printk("Processor %u is stuck.\n", cpu); return -ENOENT; } - DBG("Processor %u found.\n", cpu); + printk("Processor %u found.\n", cpu); if (smp_ops->give_timebase) smp_ops->give_timebase(); diff --git a/trunk/arch/powerpc/kernel/sys_ppc32.c b/trunk/arch/powerpc/kernel/sys_ppc32.c index b1b6043a56c4..20fd701a686a 100644 --- a/trunk/arch/powerpc/kernel/sys_ppc32.c +++ b/trunk/arch/powerpc/kernel/sys_ppc32.c @@ -616,11 +616,3 @@ asmlinkage long compat_sys_sync_file_range2(int fd, unsigned int flags, return sys_sync_file_range(fd, offset, nbytes, flags); } - -asmlinkage long compat_sys_fanotify_mark(int fanotify_fd, unsigned int flags, - unsigned mask_hi, unsigned mask_lo, - int dfd, const char __user *pathname) -{ - u64 mask = ((u64)mask_hi << 32) | mask_lo; - return sys_fanotify_mark(fanotify_fd, flags, mask, dfd, pathname); -} diff --git a/trunk/arch/powerpc/kernel/vio.c b/trunk/arch/powerpc/kernel/vio.c index fa3469ddaef8..00b9436f7652 100644 --- a/trunk/arch/powerpc/kernel/vio.c +++ b/trunk/arch/powerpc/kernel/vio.c @@ -1059,7 +1059,7 @@ static struct iommu_table *vio_build_iommu_table(struct vio_dev *dev) if (!dma_window) return NULL; - tbl = kzalloc(sizeof(*tbl), GFP_KERNEL); + tbl = kmalloc(sizeof(*tbl), GFP_KERNEL); if (tbl == NULL) return NULL; @@ -1072,7 +1072,6 @@ static struct iommu_table *vio_build_iommu_table(struct vio_dev *dev) tbl->it_offset = offset >> IOMMU_PAGE_SHIFT; tbl->it_busno = 0; tbl->it_type = TCE_VB; - tbl->it_blocksize = 16; return iommu_init_table(tbl, -1); } diff --git a/trunk/arch/powerpc/mm/init_64.c b/trunk/arch/powerpc/mm/init_64.c index ace85fa74b29..71f1415e2472 100644 --- a/trunk/arch/powerpc/mm/init_64.c +++ b/trunk/arch/powerpc/mm/init_64.c @@ -79,9 +79,7 @@ #endif /* CONFIG_PPC_STD_MMU_64 */ phys_addr_t memstart_addr = ~0; -EXPORT_SYMBOL_GPL(memstart_addr); phys_addr_t kernstart_addr; -EXPORT_SYMBOL_GPL(kernstart_addr); void free_initmem(void) { diff --git a/trunk/arch/powerpc/mm/tlb_nohash_low.S b/trunk/arch/powerpc/mm/tlb_nohash_low.S index b9d9fed8f36e..cfa768203d08 100644 --- a/trunk/arch/powerpc/mm/tlb_nohash_low.S +++ b/trunk/arch/powerpc/mm/tlb_nohash_low.S @@ -200,7 +200,6 @@ _GLOBAL(_tlbivax_bcast) rlwimi r5,r4,0,16,31 wrteei 0 mtspr SPRN_MMUCR,r5 - isync /* tlbivax 0,r3 - use .long to avoid binutils deps */ .long 0x7c000624 | (r3 << 11) isync diff --git a/trunk/arch/powerpc/platforms/Kconfig b/trunk/arch/powerpc/platforms/Kconfig index 81c9208025fa..d1663db7810f 100644 --- a/trunk/arch/powerpc/platforms/Kconfig +++ b/trunk/arch/powerpc/platforms/Kconfig @@ -106,7 +106,8 @@ config MMIO_NVRAM config MPIC_U3_HT_IRQS bool - default n + depends on PPC_MAPLE + default y config MPIC_BROKEN_REGREAD bool diff --git a/trunk/arch/powerpc/platforms/cell/iommu.c b/trunk/arch/powerpc/platforms/cell/iommu.c index 26a067122a54..58b13ce3847e 100644 --- a/trunk/arch/powerpc/platforms/cell/iommu.c +++ b/trunk/arch/powerpc/platforms/cell/iommu.c @@ -477,7 +477,7 @@ cell_iommu_setup_window(struct cbe_iommu *iommu, struct device_node *np, ioid = cell_iommu_get_ioid(np); - window = kzalloc_node(sizeof(*window), GFP_KERNEL, iommu->nid); + window = kmalloc_node(sizeof(*window), GFP_KERNEL, iommu->nid); BUG_ON(window == NULL); window->offset = offset; diff --git a/trunk/arch/powerpc/platforms/iseries/iommu.c b/trunk/arch/powerpc/platforms/iseries/iommu.c index d8b76335bd13..ce61cea0afb5 100644 --- a/trunk/arch/powerpc/platforms/iseries/iommu.c +++ b/trunk/arch/powerpc/platforms/iseries/iommu.c @@ -184,7 +184,7 @@ static void pci_dma_dev_setup_iseries(struct pci_dev *pdev) BUG_ON(lsn == NULL); - tbl = kzalloc(sizeof(struct iommu_table), GFP_KERNEL); + tbl = kmalloc(sizeof(struct iommu_table), GFP_KERNEL); iommu_table_getparms_iSeries(pdn->busno, *lsn, 0, tbl); diff --git a/trunk/arch/powerpc/platforms/powermac/feature.c b/trunk/arch/powerpc/platforms/powermac/feature.c index df423993f175..39df6ab1735a 100644 --- a/trunk/arch/powerpc/platforms/powermac/feature.c +++ b/trunk/arch/powerpc/platforms/powermac/feature.c @@ -2873,11 +2873,12 @@ set_initial_features(void) /* Switch airport off */ for_each_node_by_name(np, "radio") { - if (np->parent == macio_chips[0].of_node) { + if (np && np->parent == macio_chips[0].of_node) { macio_chips[0].flags |= MACIO_FLAG_AIRPORT_ON; core99_airport_enable(np, 0, 0); } } + of_node_put(np); } /* On all machines that support sound PM, switch sound off */ diff --git a/trunk/arch/powerpc/platforms/powermac/pci.c b/trunk/arch/powerpc/platforms/powermac/pci.c index 3bc075c788ef..ab2027cdf893 100644 --- a/trunk/arch/powerpc/platforms/powermac/pci.c +++ b/trunk/arch/powerpc/platforms/powermac/pci.c @@ -1155,11 +1155,13 @@ void __init pmac_pcibios_after_init(void) pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, nd, 0, 0); } } + of_node_put(nd); for_each_node_by_name(nd, "ethernet") { if (nd->parent && of_device_is_compatible(nd, "gmac") && of_device_is_compatible(nd->parent, "uni-north")) pmac_call_feature(PMAC_FTR_GMAC_ENABLE, nd, 0, 0); } + of_node_put(nd); } void pmac_pci_fixup_cardbus(struct pci_dev* dev) diff --git a/trunk/arch/powerpc/platforms/pseries/iommu.c b/trunk/arch/powerpc/platforms/pseries/iommu.c index a77bcaed80af..395848e30c52 100644 --- a/trunk/arch/powerpc/platforms/pseries/iommu.c +++ b/trunk/arch/powerpc/platforms/pseries/iommu.c @@ -403,7 +403,7 @@ static void pci_dma_bus_setup_pSeries(struct pci_bus *bus) pci->phb->dma_window_size = 0x8000000ul; pci->phb->dma_window_base_cur = 0x8000000ul; - tbl = kzalloc_node(sizeof(struct iommu_table), GFP_KERNEL, + tbl = kmalloc_node(sizeof(struct iommu_table), GFP_KERNEL, pci->phb->node); iommu_table_setparms(pci->phb, dn, tbl); @@ -448,7 +448,7 @@ static void pci_dma_bus_setup_pSeriesLP(struct pci_bus *bus) pdn->full_name, ppci->iommu_table); if (!ppci->iommu_table) { - tbl = kzalloc_node(sizeof(struct iommu_table), GFP_KERNEL, + tbl = kmalloc_node(sizeof(struct iommu_table), GFP_KERNEL, ppci->phb->node); iommu_table_setparms_lpar(ppci->phb, pdn, tbl, dma_window, bus->number); @@ -478,7 +478,7 @@ static void pci_dma_dev_setup_pSeries(struct pci_dev *dev) struct pci_controller *phb = PCI_DN(dn)->phb; pr_debug(" --> first child, no bridge. Allocating iommu table.\n"); - tbl = kzalloc_node(sizeof(struct iommu_table), GFP_KERNEL, + tbl = kmalloc_node(sizeof(struct iommu_table), GFP_KERNEL, phb->node); iommu_table_setparms(phb, dn, tbl); PCI_DN(dn)->iommu_table = iommu_init_table(tbl, phb->node); @@ -544,7 +544,7 @@ static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev) pci = PCI_DN(pdn); if (!pci->iommu_table) { - tbl = kzalloc_node(sizeof(struct iommu_table), GFP_KERNEL, + tbl = kmalloc_node(sizeof(struct iommu_table), GFP_KERNEL, pci->phb->node); iommu_table_setparms_lpar(pci->phb, pdn, tbl, dma_window, pci->phb->bus->number); diff --git a/trunk/arch/powerpc/platforms/pseries/smp.c b/trunk/arch/powerpc/platforms/pseries/smp.c index 0317cce877c6..3b1bf61c45be 100644 --- a/trunk/arch/powerpc/platforms/pseries/smp.c +++ b/trunk/arch/powerpc/platforms/pseries/smp.c @@ -182,13 +182,10 @@ static int smp_pSeries_cpu_bootable(unsigned int nr) /* Special case - we inhibit secondary thread startup * during boot if the user requests it. */ - if (system_state < SYSTEM_RUNNING && cpu_has_feature(CPU_FTR_SMT)) { - if (!smt_enabled_at_boot && cpu_thread_in_core(nr) != 0) - return 0; - if (smt_enabled_at_boot - && cpu_thread_in_core(nr) >= smt_enabled_at_boot) - return 0; - } + if (system_state < SYSTEM_RUNNING && + cpu_has_feature(CPU_FTR_SMT) && + !smt_enabled_at_boot && cpu_thread_in_core(nr) != 0) + return 0; return 1; } diff --git a/trunk/arch/powerpc/platforms/pseries/xics.c b/trunk/arch/powerpc/platforms/pseries/xics.c index 93834b0d8272..5b22b07c8f67 100644 --- a/trunk/arch/powerpc/platforms/pseries/xics.c +++ b/trunk/arch/powerpc/platforms/pseries/xics.c @@ -928,10 +928,8 @@ void xics_migrate_irqs_away(void) if (xics_status[0] != hw_cpu) goto unlock; - /* This is expected during cpu offline. */ - if (cpu_online(cpu)) - printk(KERN_WARNING "IRQ %u affinity broken off cpu %u\n", - virq, cpu); + printk(KERN_WARNING "IRQ %u affinity broken off cpu %u\n", + virq, cpu); /* Reset affinity to all cpus */ cpumask_setall(irq_to_desc(virq)->affinity); diff --git a/trunk/arch/s390/kernel/entry.h b/trunk/arch/s390/kernel/entry.h index 403fb430a896..ff579b6bde06 100644 --- a/trunk/arch/s390/kernel/entry.h +++ b/trunk/arch/s390/kernel/entry.h @@ -42,8 +42,8 @@ long sys_clone(unsigned long newsp, unsigned long clone_flags, int __user *parent_tidptr, int __user *child_tidptr); long sys_vfork(void); void execve_tail(void); -long sys_execve(const char __user *name, char __user * __user *argv, - char __user * __user *envp); +long sys_execve(const char __user *name, const char __user *const __user *argv, + const char __user *const __user *envp); long sys_sigsuspend(int history0, int history1, old_sigset_t mask); long sys_sigaction(int sig, const struct old_sigaction __user *act, struct old_sigaction __user *oact); diff --git a/trunk/arch/sparc/include/asm/atomic_64.h b/trunk/arch/sparc/include/asm/atomic_64.h index bdb2ff880bdd..f0c74227c737 100644 --- a/trunk/arch/sparc/include/asm/atomic_64.h +++ b/trunk/arch/sparc/include/asm/atomic_64.h @@ -20,14 +20,14 @@ #define atomic64_set(v, i) (((v)->counter) = i) extern void atomic_add(int, atomic_t *); -extern void atomic64_add(long, atomic64_t *); +extern void atomic64_add(int, atomic64_t *); extern void atomic_sub(int, atomic_t *); -extern void atomic64_sub(long, atomic64_t *); +extern void atomic64_sub(int, atomic64_t *); extern int atomic_add_ret(int, atomic_t *); -extern long atomic64_add_ret(long, atomic64_t *); +extern long atomic64_add_ret(int, atomic64_t *); extern int atomic_sub_ret(int, atomic_t *); -extern long atomic64_sub_ret(long, atomic64_t *); +extern long atomic64_sub_ret(int, atomic64_t *); #define atomic_dec_return(v) atomic_sub_ret(1, v) #define atomic64_dec_return(v) atomic64_sub_ret(1, v) diff --git a/trunk/arch/sparc/include/asm/backoff.h b/trunk/arch/sparc/include/asm/backoff.h index db3af0d30fb1..fa1fdf67e350 100644 --- a/trunk/arch/sparc/include/asm/backoff.h +++ b/trunk/arch/sparc/include/asm/backoff.h @@ -8,9 +8,6 @@ #define BACKOFF_SETUP(reg) \ mov 1, reg -#define BACKOFF_LABEL(spin_label, continue_label) \ - spin_label - #define BACKOFF_SPIN(reg, tmp, label) \ mov reg, tmp; \ 88: brnz,pt tmp, 88b; \ @@ -25,11 +22,9 @@ #else #define BACKOFF_SETUP(reg) - -#define BACKOFF_LABEL(spin_label, continue_label) \ - continue_label - -#define BACKOFF_SPIN(reg, tmp, label) +#define BACKOFF_SPIN(reg, tmp, label) \ + ba,pt %xcc, label; \ + nop; #endif diff --git a/trunk/arch/sparc/include/asm/oplib_64.h b/trunk/arch/sparc/include/asm/oplib_64.h index 3e0b2d62303d..a5db0317b5fb 100644 --- a/trunk/arch/sparc/include/asm/oplib_64.h +++ b/trunk/arch/sparc/include/asm/oplib_64.h @@ -185,8 +185,9 @@ extern int prom_getunumber(int syndrome_code, char *buf, int buflen); /* Retain physical memory to the caller across soft resets. */ -extern int prom_retain(const char *name, unsigned long size, - unsigned long align, unsigned long *paddr); +extern unsigned long prom_retain(const char *name, + unsigned long pa_low, unsigned long pa_high, + long size, long align); /* Load explicit I/D TLB entries into the calling processor. */ extern long prom_itlb_load(unsigned long index, @@ -286,6 +287,26 @@ extern void prom_sun4v_guest_soft_state(void); extern int prom_ihandle2path(int handle, char *buffer, int bufsize); /* Client interface level routines. */ -extern void p1275_cmd_direct(unsigned long *); +extern long p1275_cmd(const char *, long, ...); + +#if 0 +#define P1275_SIZE(x) ((((long)((x) / 32)) << 32) | (x)) +#else +#define P1275_SIZE(x) x +#endif + +/* We support at most 16 input and 1 output argument */ +#define P1275_ARG_NUMBER 0 +#define P1275_ARG_IN_STRING 1 +#define P1275_ARG_OUT_BUF 2 +#define P1275_ARG_OUT_32B 3 +#define P1275_ARG_IN_FUNCTION 4 +#define P1275_ARG_IN_BUF 5 +#define P1275_ARG_IN_64B 6 + +#define P1275_IN(x) ((x) & 0xf) +#define P1275_OUT(x) (((x) << 4) & 0xf0) +#define P1275_INOUT(i,o) (P1275_IN(i)|P1275_OUT(o)) +#define P1275_ARG(n,x) ((x) << ((n)*3 + 8)) #endif /* !(__SPARC64_OPLIB_H) */ diff --git a/trunk/arch/sparc/include/asm/rwsem-const.h b/trunk/arch/sparc/include/asm/rwsem-const.h new file mode 100644 index 000000000000..e4c61a18bb28 --- /dev/null +++ b/trunk/arch/sparc/include/asm/rwsem-const.h @@ -0,0 +1,12 @@ +/* rwsem-const.h: RW semaphore counter constants. */ +#ifndef _SPARC64_RWSEM_CONST_H +#define _SPARC64_RWSEM_CONST_H + +#define RWSEM_UNLOCKED_VALUE 0x00000000 +#define RWSEM_ACTIVE_BIAS 0x00000001 +#define RWSEM_ACTIVE_MASK 0x0000ffff +#define RWSEM_WAITING_BIAS (-0x00010000) +#define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS +#define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS) + +#endif /* _SPARC64_RWSEM_CONST_H */ diff --git a/trunk/arch/sparc/include/asm/rwsem.h b/trunk/arch/sparc/include/asm/rwsem.h index a2b4302869bc..6e5621006f85 100644 --- a/trunk/arch/sparc/include/asm/rwsem.h +++ b/trunk/arch/sparc/include/asm/rwsem.h @@ -15,21 +15,16 @@ #include #include +#include struct rwsem_waiter; struct rw_semaphore { - signed long count; -#define RWSEM_UNLOCKED_VALUE 0x00000000L -#define RWSEM_ACTIVE_BIAS 0x00000001L -#define RWSEM_ACTIVE_MASK 0xffffffffL -#define RWSEM_WAITING_BIAS (-RWSEM_ACTIVE_MASK-1) -#define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS -#define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS) - spinlock_t wait_lock; - struct list_head wait_list; + signed int count; + spinlock_t wait_lock; + struct list_head wait_list; #ifdef CONFIG_DEBUG_LOCK_ALLOC - struct lockdep_map dep_map; + struct lockdep_map dep_map; #endif }; @@ -46,11 +41,6 @@ struct rw_semaphore { #define DECLARE_RWSEM(name) \ struct rw_semaphore name = __RWSEM_INITIALIZER(name) -extern struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *sem); -extern struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *sem); -extern struct rw_semaphore *rwsem_wake(struct rw_semaphore *sem); -extern struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *sem); - extern void __init_rwsem(struct rw_semaphore *sem, const char *name, struct lock_class_key *key); @@ -61,103 +51,27 @@ do { \ __init_rwsem((sem), #sem, &__key); \ } while (0) -/* - * lock for reading - */ -static inline void __down_read(struct rw_semaphore *sem) -{ - if (unlikely(atomic64_inc_return((atomic64_t *)(&sem->count)) <= 0L)) - rwsem_down_read_failed(sem); -} - -static inline int __down_read_trylock(struct rw_semaphore *sem) -{ - long tmp; - - while ((tmp = sem->count) >= 0L) { - if (tmp == cmpxchg(&sem->count, tmp, - tmp + RWSEM_ACTIVE_READ_BIAS)) { - return 1; - } - } - return 0; -} +extern void __down_read(struct rw_semaphore *sem); +extern int __down_read_trylock(struct rw_semaphore *sem); +extern void __down_write(struct rw_semaphore *sem); +extern int __down_write_trylock(struct rw_semaphore *sem); +extern void __up_read(struct rw_semaphore *sem); +extern void __up_write(struct rw_semaphore *sem); +extern void __downgrade_write(struct rw_semaphore *sem); -/* - * lock for writing - */ static inline void __down_write_nested(struct rw_semaphore *sem, int subclass) { - long tmp; - - tmp = atomic64_add_return(RWSEM_ACTIVE_WRITE_BIAS, - (atomic64_t *)(&sem->count)); - if (unlikely(tmp != RWSEM_ACTIVE_WRITE_BIAS)) - rwsem_down_write_failed(sem); + __down_write(sem); } -static inline void __down_write(struct rw_semaphore *sem) +static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem) { - __down_write_nested(sem, 0); -} - -static inline int __down_write_trylock(struct rw_semaphore *sem) -{ - long tmp; - - tmp = cmpxchg(&sem->count, RWSEM_UNLOCKED_VALUE, - RWSEM_ACTIVE_WRITE_BIAS); - return tmp == RWSEM_UNLOCKED_VALUE; + return atomic_add_return(delta, (atomic_t *)(&sem->count)); } -/* - * unlock after reading - */ -static inline void __up_read(struct rw_semaphore *sem) -{ - long tmp; - - tmp = atomic64_dec_return((atomic64_t *)(&sem->count)); - if (unlikely(tmp < -1L && (tmp & RWSEM_ACTIVE_MASK) == 0L)) - rwsem_wake(sem); -} - -/* - * unlock after writing - */ -static inline void __up_write(struct rw_semaphore *sem) -{ - if (unlikely(atomic64_sub_return(RWSEM_ACTIVE_WRITE_BIAS, - (atomic64_t *)(&sem->count)) < 0L)) - rwsem_wake(sem); -} - -/* - * implement atomic add functionality - */ -static inline void rwsem_atomic_add(long delta, struct rw_semaphore *sem) -{ - atomic64_add(delta, (atomic64_t *)(&sem->count)); -} - -/* - * downgrade write lock to read lock - */ -static inline void __downgrade_write(struct rw_semaphore *sem) -{ - long tmp; - - tmp = atomic64_add_return(-RWSEM_WAITING_BIAS, (atomic64_t *)(&sem->count)); - if (tmp < 0L) - rwsem_downgrade_wake(sem); -} - -/* - * implement exchange and add functionality - */ -static inline long rwsem_atomic_update(long delta, struct rw_semaphore *sem) +static inline void rwsem_atomic_add(int delta, struct rw_semaphore *sem) { - return atomic64_add_return(delta, (atomic64_t *)(&sem->count)); + atomic_add(delta, (atomic_t *)(&sem->count)); } static inline int rwsem_is_locked(struct rw_semaphore *sem) diff --git a/trunk/arch/sparc/include/asm/system_64.h b/trunk/arch/sparc/include/asm/system_64.h index e3b65d8cf41b..d24cfe16afc1 100644 --- a/trunk/arch/sparc/include/asm/system_64.h +++ b/trunk/arch/sparc/include/asm/system_64.h @@ -106,7 +106,6 @@ do { __asm__ __volatile__("ba,pt %%xcc, 1f\n\t" \ */ #define write_pic(__p) \ __asm__ __volatile__("ba,pt %%xcc, 99f\n\t" \ - " nop\n\t" \ ".align 64\n" \ "99:wr %0, 0x0, %%pic\n\t" \ "rd %%pic, %%g0" : : "r" (__p)) diff --git a/trunk/arch/sparc/lib/Makefile b/trunk/arch/sparc/lib/Makefile index 846d1c4374ea..c4b5e03af115 100644 --- a/trunk/arch/sparc/lib/Makefile +++ b/trunk/arch/sparc/lib/Makefile @@ -15,7 +15,7 @@ lib-$(CONFIG_SPARC32) += divdi3.o udivdi3.o lib-$(CONFIG_SPARC32) += copy_user.o locks.o lib-y += atomic_$(BITS).o lib-$(CONFIG_SPARC32) += lshrdi3.o ashldi3.o -lib-$(CONFIG_SPARC32) += rwsem_32.o +lib-y += rwsem_$(BITS).o lib-$(CONFIG_SPARC32) += muldi3.o bitext.o cmpdi2.o lib-$(CONFIG_SPARC64) += copy_page.o clear_page.o bzero.o diff --git a/trunk/arch/sparc/lib/atomic_64.S b/trunk/arch/sparc/lib/atomic_64.S index 59186e0fcf39..0268210ca168 100644 --- a/trunk/arch/sparc/lib/atomic_64.S +++ b/trunk/arch/sparc/lib/atomic_64.S @@ -21,7 +21,7 @@ atomic_add: /* %o0 = increment, %o1 = atomic_ptr */ add %g1, %o0, %g7 cas [%o1], %g1, %g7 cmp %g1, %g7 - bne,pn %icc, BACKOFF_LABEL(2f, 1b) + bne,pn %icc, 2f nop retl nop @@ -36,7 +36,7 @@ atomic_sub: /* %o0 = decrement, %o1 = atomic_ptr */ sub %g1, %o0, %g7 cas [%o1], %g1, %g7 cmp %g1, %g7 - bne,pn %icc, BACKOFF_LABEL(2f, 1b) + bne,pn %icc, 2f nop retl nop @@ -51,10 +51,11 @@ atomic_add_ret: /* %o0 = increment, %o1 = atomic_ptr */ add %g1, %o0, %g7 cas [%o1], %g1, %g7 cmp %g1, %g7 - bne,pn %icc, BACKOFF_LABEL(2f, 1b) - add %g1, %o0, %g1 + bne,pn %icc, 2f + add %g7, %o0, %g7 + sra %g7, 0, %o0 retl - sra %g1, 0, %o0 + nop 2: BACKOFF_SPIN(%o2, %o3, 1b) .size atomic_add_ret, .-atomic_add_ret @@ -66,10 +67,11 @@ atomic_sub_ret: /* %o0 = decrement, %o1 = atomic_ptr */ sub %g1, %o0, %g7 cas [%o1], %g1, %g7 cmp %g1, %g7 - bne,pn %icc, BACKOFF_LABEL(2f, 1b) - sub %g1, %o0, %g1 + bne,pn %icc, 2f + sub %g7, %o0, %g7 + sra %g7, 0, %o0 retl - sra %g1, 0, %o0 + nop 2: BACKOFF_SPIN(%o2, %o3, 1b) .size atomic_sub_ret, .-atomic_sub_ret @@ -81,7 +83,7 @@ atomic64_add: /* %o0 = increment, %o1 = atomic_ptr */ add %g1, %o0, %g7 casx [%o1], %g1, %g7 cmp %g1, %g7 - bne,pn %xcc, BACKOFF_LABEL(2f, 1b) + bne,pn %xcc, 2f nop retl nop @@ -96,7 +98,7 @@ atomic64_sub: /* %o0 = decrement, %o1 = atomic_ptr */ sub %g1, %o0, %g7 casx [%o1], %g1, %g7 cmp %g1, %g7 - bne,pn %xcc, BACKOFF_LABEL(2f, 1b) + bne,pn %xcc, 2f nop retl nop @@ -111,10 +113,11 @@ atomic64_add_ret: /* %o0 = increment, %o1 = atomic_ptr */ add %g1, %o0, %g7 casx [%o1], %g1, %g7 cmp %g1, %g7 - bne,pn %xcc, BACKOFF_LABEL(2f, 1b) - nop + bne,pn %xcc, 2f + add %g7, %o0, %g7 + mov %g7, %o0 retl - add %g1, %o0, %o0 + nop 2: BACKOFF_SPIN(%o2, %o3, 1b) .size atomic64_add_ret, .-atomic64_add_ret @@ -126,9 +129,10 @@ atomic64_sub_ret: /* %o0 = decrement, %o1 = atomic_ptr */ sub %g1, %o0, %g7 casx [%o1], %g1, %g7 cmp %g1, %g7 - bne,pn %xcc, BACKOFF_LABEL(2f, 1b) - nop + bne,pn %xcc, 2f + sub %g7, %o0, %g7 + mov %g7, %o0 retl - sub %g1, %o0, %o0 + nop 2: BACKOFF_SPIN(%o2, %o3, 1b) .size atomic64_sub_ret, .-atomic64_sub_ret diff --git a/trunk/arch/sparc/lib/bitops.S b/trunk/arch/sparc/lib/bitops.S index 3dc61d5537c0..2b7228cb8c22 100644 --- a/trunk/arch/sparc/lib/bitops.S +++ b/trunk/arch/sparc/lib/bitops.S @@ -22,7 +22,7 @@ test_and_set_bit: /* %o0=nr, %o1=addr */ or %g7, %o2, %g1 casx [%o1], %g7, %g1 cmp %g7, %g1 - bne,pn %xcc, BACKOFF_LABEL(2f, 1b) + bne,pn %xcc, 2f and %g7, %o2, %g2 clr %o0 movrne %g2, 1, %o0 @@ -45,7 +45,7 @@ test_and_clear_bit: /* %o0=nr, %o1=addr */ andn %g7, %o2, %g1 casx [%o1], %g7, %g1 cmp %g7, %g1 - bne,pn %xcc, BACKOFF_LABEL(2f, 1b) + bne,pn %xcc, 2f and %g7, %o2, %g2 clr %o0 movrne %g2, 1, %o0 @@ -68,7 +68,7 @@ test_and_change_bit: /* %o0=nr, %o1=addr */ xor %g7, %o2, %g1 casx [%o1], %g7, %g1 cmp %g7, %g1 - bne,pn %xcc, BACKOFF_LABEL(2f, 1b) + bne,pn %xcc, 2f and %g7, %o2, %g2 clr %o0 movrne %g2, 1, %o0 @@ -91,7 +91,7 @@ set_bit: /* %o0=nr, %o1=addr */ or %g7, %o2, %g1 casx [%o1], %g7, %g1 cmp %g7, %g1 - bne,pn %xcc, BACKOFF_LABEL(2f, 1b) + bne,pn %xcc, 2f nop retl nop @@ -112,7 +112,7 @@ clear_bit: /* %o0=nr, %o1=addr */ andn %g7, %o2, %g1 casx [%o1], %g7, %g1 cmp %g7, %g1 - bne,pn %xcc, BACKOFF_LABEL(2f, 1b) + bne,pn %xcc, 2f nop retl nop @@ -133,7 +133,7 @@ change_bit: /* %o0=nr, %o1=addr */ xor %g7, %o2, %g1 casx [%o1], %g7, %g1 cmp %g7, %g1 - bne,pn %xcc, BACKOFF_LABEL(2f, 1b) + bne,pn %xcc, 2f nop retl nop diff --git a/trunk/arch/sparc/lib/rwsem_64.S b/trunk/arch/sparc/lib/rwsem_64.S new file mode 100644 index 000000000000..91a7d29a79d5 --- /dev/null +++ b/trunk/arch/sparc/lib/rwsem_64.S @@ -0,0 +1,163 @@ +/* rwsem.S: RW semaphore assembler. + * + * Written by David S. Miller (davem@redhat.com), 2001. + * Derived from asm-i386/rwsem.h + */ + +#include + + .section .sched.text, "ax" + + .globl __down_read +__down_read: +1: lduw [%o0], %g1 + add %g1, 1, %g7 + cas [%o0], %g1, %g7 + cmp %g1, %g7 + bne,pn %icc, 1b + add %g7, 1, %g7 + cmp %g7, 0 + bl,pn %icc, 3f + nop +2: + retl + nop +3: + save %sp, -192, %sp + call rwsem_down_read_failed + mov %i0, %o0 + ret + restore + .size __down_read, .-__down_read + + .globl __down_read_trylock +__down_read_trylock: +1: lduw [%o0], %g1 + add %g1, 1, %g7 + cmp %g7, 0 + bl,pn %icc, 2f + mov 0, %o1 + cas [%o0], %g1, %g7 + cmp %g1, %g7 + bne,pn %icc, 1b + mov 1, %o1 +2: retl + mov %o1, %o0 + .size __down_read_trylock, .-__down_read_trylock + + .globl __down_write +__down_write: + sethi %hi(RWSEM_ACTIVE_WRITE_BIAS), %g1 + or %g1, %lo(RWSEM_ACTIVE_WRITE_BIAS), %g1 +1: + lduw [%o0], %g3 + add %g3, %g1, %g7 + cas [%o0], %g3, %g7 + cmp %g3, %g7 + bne,pn %icc, 1b + cmp %g7, 0 + bne,pn %icc, 3f + nop +2: retl + nop +3: + save %sp, -192, %sp + call rwsem_down_write_failed + mov %i0, %o0 + ret + restore + .size __down_write, .-__down_write + + .globl __down_write_trylock +__down_write_trylock: + sethi %hi(RWSEM_ACTIVE_WRITE_BIAS), %g1 + or %g1, %lo(RWSEM_ACTIVE_WRITE_BIAS), %g1 +1: + lduw [%o0], %g3 + cmp %g3, 0 + bne,pn %icc, 2f + mov 0, %o1 + add %g3, %g1, %g7 + cas [%o0], %g3, %g7 + cmp %g3, %g7 + bne,pn %icc, 1b + mov 1, %o1 +2: retl + mov %o1, %o0 + .size __down_write_trylock, .-__down_write_trylock + + .globl __up_read +__up_read: +1: + lduw [%o0], %g1 + sub %g1, 1, %g7 + cas [%o0], %g1, %g7 + cmp %g1, %g7 + bne,pn %icc, 1b + cmp %g7, 0 + bl,pn %icc, 3f + nop +2: retl + nop +3: sethi %hi(RWSEM_ACTIVE_MASK), %g1 + sub %g7, 1, %g7 + or %g1, %lo(RWSEM_ACTIVE_MASK), %g1 + andcc %g7, %g1, %g0 + bne,pn %icc, 2b + nop + save %sp, -192, %sp + call rwsem_wake + mov %i0, %o0 + ret + restore + .size __up_read, .-__up_read + + .globl __up_write +__up_write: + sethi %hi(RWSEM_ACTIVE_WRITE_BIAS), %g1 + or %g1, %lo(RWSEM_ACTIVE_WRITE_BIAS), %g1 +1: + lduw [%o0], %g3 + sub %g3, %g1, %g7 + cas [%o0], %g3, %g7 + cmp %g3, %g7 + bne,pn %icc, 1b + sub %g7, %g1, %g7 + cmp %g7, 0 + bl,pn %icc, 3f + nop +2: + retl + nop +3: + save %sp, -192, %sp + call rwsem_wake + mov %i0, %o0 + ret + restore + .size __up_write, .-__up_write + + .globl __downgrade_write +__downgrade_write: + sethi %hi(RWSEM_WAITING_BIAS), %g1 + or %g1, %lo(RWSEM_WAITING_BIAS), %g1 +1: + lduw [%o0], %g3 + sub %g3, %g1, %g7 + cas [%o0], %g3, %g7 + cmp %g3, %g7 + bne,pn %icc, 1b + sub %g7, %g1, %g7 + cmp %g7, 0 + bl,pn %icc, 3f + nop +2: + retl + nop +3: + save %sp, -192, %sp + call rwsem_downgrade_wake + mov %i0, %o0 + ret + restore + .size __downgrade_write, .-__downgrade_write diff --git a/trunk/arch/sparc/prom/cif.S b/trunk/arch/sparc/prom/cif.S index 9c86b4b7d429..5f27ad779c0c 100644 --- a/trunk/arch/sparc/prom/cif.S +++ b/trunk/arch/sparc/prom/cif.S @@ -9,18 +9,18 @@ #include .text - .globl prom_cif_direct -prom_cif_direct: - sethi %hi(p1275buf), %o1 - or %o1, %lo(p1275buf), %o1 - ldx [%o1 + 0x0010], %o2 ! prom_cif_stack - save %o2, -192, %sp - ldx [%i1 + 0x0008], %l2 ! prom_cif_handler + .globl prom_cif_interface +prom_cif_interface: + sethi %hi(p1275buf), %o0 + or %o0, %lo(p1275buf), %o0 + ldx [%o0 + 0x010], %o1 ! prom_cif_stack + save %o1, -192, %sp + ldx [%i0 + 0x008], %l2 ! prom_cif_handler mov %g4, %l0 mov %g5, %l1 mov %g6, %l3 call %l2 - mov %i0, %o0 ! prom_args + add %i0, 0x018, %o0 ! prom_args mov %l0, %g4 mov %l1, %g5 mov %l3, %g6 diff --git a/trunk/arch/sparc/prom/console_64.c b/trunk/arch/sparc/prom/console_64.c index 10322dc2f557..f55d58a8a156 100644 --- a/trunk/arch/sparc/prom/console_64.c +++ b/trunk/arch/sparc/prom/console_64.c @@ -21,22 +21,14 @@ extern int prom_stdin, prom_stdout; inline int prom_nbgetchar(void) { - unsigned long args[7]; char inc; - args[0] = (unsigned long) "read"; - args[1] = 3; - args[2] = 1; - args[3] = (unsigned int) prom_stdin; - args[4] = (unsigned long) &inc; - args[5] = 1; - args[6] = (unsigned long) -1; - - p1275_cmd_direct(args); - - if (args[6] == 1) + if (p1275_cmd("read", P1275_ARG(1,P1275_ARG_OUT_BUF)| + P1275_INOUT(3,1), + prom_stdin, &inc, P1275_SIZE(1)) == 1) return inc; - return -1; + else + return -1; } /* Non blocking put character to console device, returns -1 if @@ -45,22 +37,12 @@ prom_nbgetchar(void) inline int prom_nbputchar(char c) { - unsigned long args[7]; char outc; outc = c; - - args[0] = (unsigned long) "write"; - args[1] = 3; - args[2] = 1; - args[3] = (unsigned int) prom_stdout; - args[4] = (unsigned long) &outc; - args[5] = 1; - args[6] = (unsigned long) -1; - - p1275_cmd_direct(args); - - if (args[6] == 1) + if (p1275_cmd("write", P1275_ARG(1,P1275_ARG_IN_BUF)| + P1275_INOUT(3,1), + prom_stdout, &outc, P1275_SIZE(1)) == 1) return 0; else return -1; @@ -85,15 +67,7 @@ prom_putchar(char c) void prom_puts(const char *s, int len) { - unsigned long args[7]; - - args[0] = (unsigned long) "write"; - args[1] = 3; - args[2] = 1; - args[3] = (unsigned int) prom_stdout; - args[4] = (unsigned long) s; - args[5] = len; - args[6] = (unsigned long) -1; - - p1275_cmd_direct(args); + p1275_cmd("write", P1275_ARG(1,P1275_ARG_IN_BUF)| + P1275_INOUT(3,1), + prom_stdout, s, P1275_SIZE(len)); } diff --git a/trunk/arch/sparc/prom/devops_64.c b/trunk/arch/sparc/prom/devops_64.c index a017119e7ef1..9dbd803e46e1 100644 --- a/trunk/arch/sparc/prom/devops_64.c +++ b/trunk/arch/sparc/prom/devops_64.c @@ -18,32 +18,16 @@ int prom_devopen(const char *dstr) { - unsigned long args[5]; - - args[0] = (unsigned long) "open"; - args[1] = 1; - args[2] = 1; - args[3] = (unsigned long) dstr; - args[4] = (unsigned long) -1; - - p1275_cmd_direct(args); - - return (int) args[4]; + return p1275_cmd ("open", P1275_ARG(0,P1275_ARG_IN_STRING)| + P1275_INOUT(1,1), + dstr); } /* Close the device described by device handle 'dhandle'. */ int prom_devclose(int dhandle) { - unsigned long args[4]; - - args[0] = (unsigned long) "close"; - args[1] = 1; - args[2] = 0; - args[3] = (unsigned int) dhandle; - - p1275_cmd_direct(args); - + p1275_cmd ("close", P1275_INOUT(1,0), dhandle); return 0; } @@ -53,15 +37,5 @@ prom_devclose(int dhandle) void prom_seek(int dhandle, unsigned int seekhi, unsigned int seeklo) { - unsigned long args[7]; - - args[0] = (unsigned long) "seek"; - args[1] = 3; - args[2] = 1; - args[3] = (unsigned int) dhandle; - args[4] = seekhi; - args[5] = seeklo; - args[6] = (unsigned long) -1; - - p1275_cmd_direct(args); + p1275_cmd ("seek", P1275_INOUT(3,1), dhandle, seekhi, seeklo); } diff --git a/trunk/arch/sparc/prom/misc_64.c b/trunk/arch/sparc/prom/misc_64.c index 6cb1581d6aef..39fc6af21b7c 100644 --- a/trunk/arch/sparc/prom/misc_64.c +++ b/trunk/arch/sparc/prom/misc_64.c @@ -20,17 +20,10 @@ int prom_service_exists(const char *service_name) { - unsigned long args[5]; + int err = p1275_cmd("test", P1275_ARG(0, P1275_ARG_IN_STRING) | + P1275_INOUT(1, 1), service_name); - args[0] = (unsigned long) "test"; - args[1] = 1; - args[2] = 1; - args[3] = (unsigned long) service_name; - args[4] = (unsigned long) -1; - - p1275_cmd_direct(args); - - if (args[4]) + if (err) return 0; return 1; } @@ -38,47 +31,30 @@ int prom_service_exists(const char *service_name) void prom_sun4v_guest_soft_state(void) { const char *svc = "SUNW,soft-state-supported"; - unsigned long args[3]; if (!prom_service_exists(svc)) return; - args[0] = (unsigned long) svc; - args[1] = 0; - args[2] = 0; - p1275_cmd_direct(args); + p1275_cmd(svc, P1275_INOUT(0, 0)); } /* Reset and reboot the machine with the command 'bcommand'. */ void prom_reboot(const char *bcommand) { - unsigned long args[4]; - #ifdef CONFIG_SUN_LDOMS if (ldom_domaining_enabled) ldom_reboot(bcommand); #endif - args[0] = (unsigned long) "boot"; - args[1] = 1; - args[2] = 0; - args[3] = (unsigned long) bcommand; - - p1275_cmd_direct(args); + p1275_cmd("boot", P1275_ARG(0, P1275_ARG_IN_STRING) | + P1275_INOUT(1, 0), bcommand); } /* Forth evaluate the expression contained in 'fstring'. */ void prom_feval(const char *fstring) { - unsigned long args[5]; - if (!fstring || fstring[0] == 0) return; - args[0] = (unsigned long) "interpret"; - args[1] = 1; - args[2] = 1; - args[3] = (unsigned long) fstring; - args[4] = (unsigned long) -1; - - p1275_cmd_direct(args); + p1275_cmd("interpret", P1275_ARG(0, P1275_ARG_IN_STRING) | + P1275_INOUT(1, 1), fstring); } EXPORT_SYMBOL(prom_feval); @@ -92,7 +68,6 @@ extern void smp_release(void); */ void prom_cmdline(void) { - unsigned long args[3]; unsigned long flags; local_irq_save(flags); @@ -101,11 +76,7 @@ void prom_cmdline(void) smp_capture(); #endif - args[0] = (unsigned long) "enter"; - args[1] = 0; - args[2] = 0; - - p1275_cmd_direct(args); + p1275_cmd("enter", P1275_INOUT(0, 0)); #ifdef CONFIG_SMP smp_release(); @@ -119,32 +90,22 @@ void prom_cmdline(void) */ void notrace prom_halt(void) { - unsigned long args[3]; - #ifdef CONFIG_SUN_LDOMS if (ldom_domaining_enabled) ldom_power_off(); #endif again: - args[0] = (unsigned long) "exit"; - args[1] = 0; - args[2] = 0; - p1275_cmd_direct(args); + p1275_cmd("exit", P1275_INOUT(0, 0)); goto again; /* PROM is out to get me -DaveM */ } void prom_halt_power_off(void) { - unsigned long args[3]; - #ifdef CONFIG_SUN_LDOMS if (ldom_domaining_enabled) ldom_power_off(); #endif - args[0] = (unsigned long) "SUNW,power-off"; - args[1] = 0; - args[2] = 0; - p1275_cmd_direct(args); + p1275_cmd("SUNW,power-off", P1275_INOUT(0, 0)); /* if nothing else helps, we just halt */ prom_halt(); @@ -153,15 +114,10 @@ void prom_halt_power_off(void) /* Set prom sync handler to call function 'funcp'. */ void prom_setcallback(callback_func_t funcp) { - unsigned long args[5]; if (!funcp) return; - args[0] = (unsigned long) "set-callback"; - args[1] = 1; - args[2] = 1; - args[3] = (unsigned long) funcp; - args[4] = (unsigned long) -1; - p1275_cmd_direct(args); + p1275_cmd("set-callback", P1275_ARG(0, P1275_ARG_IN_FUNCTION) | + P1275_INOUT(1, 1), funcp); } /* Get the idprom and stuff it into buffer 'idbuf'. Returns the @@ -217,61 +173,57 @@ static int prom_get_memory_ihandle(void) } /* Load explicit I/D TLB entries. */ -static long tlb_load(const char *type, unsigned long index, - unsigned long tte_data, unsigned long vaddr) -{ - unsigned long args[9]; - - args[0] = (unsigned long) prom_callmethod_name; - args[1] = 5; - args[2] = 1; - args[3] = (unsigned long) type; - args[4] = (unsigned int) prom_get_mmu_ihandle(); - args[5] = vaddr; - args[6] = tte_data; - args[7] = index; - args[8] = (unsigned long) -1; - - p1275_cmd_direct(args); - - return (long) args[8]; -} - long prom_itlb_load(unsigned long index, unsigned long tte_data, unsigned long vaddr) { - return tlb_load("SUNW,itlb-load", index, tte_data, vaddr); + return p1275_cmd(prom_callmethod_name, + (P1275_ARG(0, P1275_ARG_IN_STRING) | + P1275_ARG(2, P1275_ARG_IN_64B) | + P1275_ARG(3, P1275_ARG_IN_64B) | + P1275_INOUT(5, 1)), + "SUNW,itlb-load", + prom_get_mmu_ihandle(), + /* And then our actual args are pushed backwards. */ + vaddr, + tte_data, + index); } long prom_dtlb_load(unsigned long index, unsigned long tte_data, unsigned long vaddr) { - return tlb_load("SUNW,dtlb-load", index, tte_data, vaddr); + return p1275_cmd(prom_callmethod_name, + (P1275_ARG(0, P1275_ARG_IN_STRING) | + P1275_ARG(2, P1275_ARG_IN_64B) | + P1275_ARG(3, P1275_ARG_IN_64B) | + P1275_INOUT(5, 1)), + "SUNW,dtlb-load", + prom_get_mmu_ihandle(), + /* And then our actual args are pushed backwards. */ + vaddr, + tte_data, + index); } int prom_map(int mode, unsigned long size, unsigned long vaddr, unsigned long paddr) { - unsigned long args[11]; - int ret; - - args[0] = (unsigned long) prom_callmethod_name; - args[1] = 7; - args[2] = 1; - args[3] = (unsigned long) prom_map_name; - args[4] = (unsigned int) prom_get_mmu_ihandle(); - args[5] = (unsigned int) mode; - args[6] = size; - args[7] = vaddr; - args[8] = 0; - args[9] = paddr; - args[10] = (unsigned long) -1; - - p1275_cmd_direct(args); - - ret = (int) args[10]; + int ret = p1275_cmd(prom_callmethod_name, + (P1275_ARG(0, P1275_ARG_IN_STRING) | + P1275_ARG(3, P1275_ARG_IN_64B) | + P1275_ARG(4, P1275_ARG_IN_64B) | + P1275_ARG(6, P1275_ARG_IN_64B) | + P1275_INOUT(7, 1)), + prom_map_name, + prom_get_mmu_ihandle(), + mode, + size, + vaddr, + 0, + paddr); + if (ret == 0) ret = -1; return ret; @@ -279,51 +231,40 @@ int prom_map(int mode, unsigned long size, void prom_unmap(unsigned long size, unsigned long vaddr) { - unsigned long args[7]; - - args[0] = (unsigned long) prom_callmethod_name; - args[1] = 4; - args[2] = 0; - args[3] = (unsigned long) prom_unmap_name; - args[4] = (unsigned int) prom_get_mmu_ihandle(); - args[5] = size; - args[6] = vaddr; - - p1275_cmd_direct(args); + p1275_cmd(prom_callmethod_name, + (P1275_ARG(0, P1275_ARG_IN_STRING) | + P1275_ARG(2, P1275_ARG_IN_64B) | + P1275_ARG(3, P1275_ARG_IN_64B) | + P1275_INOUT(4, 0)), + prom_unmap_name, + prom_get_mmu_ihandle(), + size, + vaddr); } /* Set aside physical memory which is not touched or modified * across soft resets. */ -int prom_retain(const char *name, unsigned long size, - unsigned long align, unsigned long *paddr) +unsigned long prom_retain(const char *name, + unsigned long pa_low, unsigned long pa_high, + long size, long align) { - unsigned long args[11]; - - args[0] = (unsigned long) prom_callmethod_name; - args[1] = 5; - args[2] = 3; - args[3] = (unsigned long) "SUNW,retain"; - args[4] = (unsigned int) prom_get_memory_ihandle(); - args[5] = align; - args[6] = size; - args[7] = (unsigned long) name; - args[8] = (unsigned long) -1; - args[9] = (unsigned long) -1; - args[10] = (unsigned long) -1; - - p1275_cmd_direct(args); - - if (args[8]) - return (int) args[8]; - - /* Next we get "phys_high" then "phys_low". On 64-bit - * the phys_high cell is don't care since the phys_low - * cell has the full value. + /* XXX I don't think we return multiple values correctly. + * XXX OBP supposedly returns pa_low/pa_high here, how does + * XXX it work? */ - *paddr = args[10]; - return 0; + /* If align is zero, the pa_low/pa_high args are passed, + * else they are not. + */ + if (align == 0) + return p1275_cmd("SUNW,retain", + (P1275_ARG(0, P1275_ARG_IN_BUF) | P1275_INOUT(5, 2)), + name, pa_low, pa_high, size, align); + else + return p1275_cmd("SUNW,retain", + (P1275_ARG(0, P1275_ARG_IN_BUF) | P1275_INOUT(3, 2)), + name, size, align); } /* Get "Unumber" string for the SIMM at the given @@ -336,129 +277,62 @@ int prom_getunumber(int syndrome_code, unsigned long phys_addr, char *buf, int buflen) { - unsigned long args[12]; - - args[0] = (unsigned long) prom_callmethod_name; - args[1] = 7; - args[2] = 2; - args[3] = (unsigned long) "SUNW,get-unumber"; - args[4] = (unsigned int) prom_get_memory_ihandle(); - args[5] = buflen; - args[6] = (unsigned long) buf; - args[7] = 0; - args[8] = phys_addr; - args[9] = (unsigned int) syndrome_code; - args[10] = (unsigned long) -1; - args[11] = (unsigned long) -1; - - p1275_cmd_direct(args); - - return (int) args[10]; + return p1275_cmd(prom_callmethod_name, + (P1275_ARG(0, P1275_ARG_IN_STRING) | + P1275_ARG(3, P1275_ARG_OUT_BUF) | + P1275_ARG(6, P1275_ARG_IN_64B) | + P1275_INOUT(8, 2)), + "SUNW,get-unumber", prom_get_memory_ihandle(), + buflen, buf, P1275_SIZE(buflen), + 0, phys_addr, syndrome_code); } /* Power management extensions. */ void prom_sleepself(void) { - unsigned long args[3]; - - args[0] = (unsigned long) "SUNW,sleep-self"; - args[1] = 0; - args[2] = 0; - p1275_cmd_direct(args); + p1275_cmd("SUNW,sleep-self", P1275_INOUT(0, 0)); } int prom_sleepsystem(void) { - unsigned long args[4]; - - args[0] = (unsigned long) "SUNW,sleep-system"; - args[1] = 0; - args[2] = 1; - args[3] = (unsigned long) -1; - p1275_cmd_direct(args); - - return (int) args[3]; + return p1275_cmd("SUNW,sleep-system", P1275_INOUT(0, 1)); } int prom_wakeupsystem(void) { - unsigned long args[4]; - - args[0] = (unsigned long) "SUNW,wakeup-system"; - args[1] = 0; - args[2] = 1; - args[3] = (unsigned long) -1; - p1275_cmd_direct(args); - - return (int) args[3]; + return p1275_cmd("SUNW,wakeup-system", P1275_INOUT(0, 1)); } #ifdef CONFIG_SMP void prom_startcpu(int cpunode, unsigned long pc, unsigned long arg) { - unsigned long args[6]; - - args[0] = (unsigned long) "SUNW,start-cpu"; - args[1] = 3; - args[2] = 0; - args[3] = (unsigned int) cpunode; - args[4] = pc; - args[5] = arg; - p1275_cmd_direct(args); + p1275_cmd("SUNW,start-cpu", P1275_INOUT(3, 0), cpunode, pc, arg); } void prom_startcpu_cpuid(int cpuid, unsigned long pc, unsigned long arg) { - unsigned long args[6]; - - args[0] = (unsigned long) "SUNW,start-cpu-by-cpuid"; - args[1] = 3; - args[2] = 0; - args[3] = (unsigned int) cpuid; - args[4] = pc; - args[5] = arg; - p1275_cmd_direct(args); + p1275_cmd("SUNW,start-cpu-by-cpuid", P1275_INOUT(3, 0), + cpuid, pc, arg); } void prom_stopcpu_cpuid(int cpuid) { - unsigned long args[4]; - - args[0] = (unsigned long) "SUNW,stop-cpu-by-cpuid"; - args[1] = 1; - args[2] = 0; - args[3] = (unsigned int) cpuid; - p1275_cmd_direct(args); + p1275_cmd("SUNW,stop-cpu-by-cpuid", P1275_INOUT(1, 0), + cpuid); } void prom_stopself(void) { - unsigned long args[3]; - - args[0] = (unsigned long) "SUNW,stop-self"; - args[1] = 0; - args[2] = 0; - p1275_cmd_direct(args); + p1275_cmd("SUNW,stop-self", P1275_INOUT(0, 0)); } void prom_idleself(void) { - unsigned long args[3]; - - args[0] = (unsigned long) "SUNW,idle-self"; - args[1] = 0; - args[2] = 0; - p1275_cmd_direct(args); + p1275_cmd("SUNW,idle-self", P1275_INOUT(0, 0)); } void prom_resumecpu(int cpunode) { - unsigned long args[4]; - - args[0] = (unsigned long) "SUNW,resume-cpu"; - args[1] = 1; - args[2] = 0; - args[3] = (unsigned int) cpunode; - p1275_cmd_direct(args); + p1275_cmd("SUNW,resume-cpu", P1275_INOUT(1, 0), cpunode); } #endif diff --git a/trunk/arch/sparc/prom/p1275.c b/trunk/arch/sparc/prom/p1275.c index fa6e4e219b9c..2d8b70d397f1 100644 --- a/trunk/arch/sparc/prom/p1275.c +++ b/trunk/arch/sparc/prom/p1275.c @@ -22,11 +22,13 @@ struct { long prom_callback; /* 0x00 */ void (*prom_cif_handler)(long *); /* 0x08 */ unsigned long prom_cif_stack; /* 0x10 */ + unsigned long prom_args [23]; /* 0x18 */ + char prom_buffer [3000]; } p1275buf; extern void prom_world(int); -extern void prom_cif_direct(unsigned long *args); +extern void prom_cif_interface(void); extern void prom_cif_callback(void); /* @@ -34,20 +36,114 @@ extern void prom_cif_callback(void); */ DEFINE_RAW_SPINLOCK(prom_entry_lock); -void p1275_cmd_direct(unsigned long *args) +long p1275_cmd(const char *service, long fmt, ...) { + char *p, *q; unsigned long flags; + int nargs, nrets, i; + va_list list; + long attrs, x; + + p = p1275buf.prom_buffer; raw_local_save_flags(flags); raw_local_irq_restore(PIL_NMI); raw_spin_lock(&prom_entry_lock); + p1275buf.prom_args[0] = (unsigned long)p; /* service */ + strcpy (p, service); + p = (char *)(((long)(strchr (p, 0) + 8)) & ~7); + p1275buf.prom_args[1] = nargs = (fmt & 0x0f); /* nargs */ + p1275buf.prom_args[2] = nrets = ((fmt & 0xf0) >> 4); /* nrets */ + attrs = fmt >> 8; + va_start(list, fmt); + for (i = 0; i < nargs; i++, attrs >>= 3) { + switch (attrs & 0x7) { + case P1275_ARG_NUMBER: + p1275buf.prom_args[i + 3] = + (unsigned)va_arg(list, long); + break; + case P1275_ARG_IN_64B: + p1275buf.prom_args[i + 3] = + va_arg(list, unsigned long); + break; + case P1275_ARG_IN_STRING: + strcpy (p, va_arg(list, char *)); + p1275buf.prom_args[i + 3] = (unsigned long)p; + p = (char *)(((long)(strchr (p, 0) + 8)) & ~7); + break; + case P1275_ARG_OUT_BUF: + (void) va_arg(list, char *); + p1275buf.prom_args[i + 3] = (unsigned long)p; + x = va_arg(list, long); + i++; attrs >>= 3; + p = (char *)(((long)(p + (int)x + 7)) & ~7); + p1275buf.prom_args[i + 3] = x; + break; + case P1275_ARG_IN_BUF: + q = va_arg(list, char *); + p1275buf.prom_args[i + 3] = (unsigned long)p; + x = va_arg(list, long); + i++; attrs >>= 3; + memcpy (p, q, (int)x); + p = (char *)(((long)(p + (int)x + 7)) & ~7); + p1275buf.prom_args[i + 3] = x; + break; + case P1275_ARG_OUT_32B: + (void) va_arg(list, char *); + p1275buf.prom_args[i + 3] = (unsigned long)p; + p += 32; + break; + case P1275_ARG_IN_FUNCTION: + p1275buf.prom_args[i + 3] = + (unsigned long)prom_cif_callback; + p1275buf.prom_callback = va_arg(list, long); + break; + } + } + va_end(list); + prom_world(1); - prom_cif_direct(args); + prom_cif_interface(); prom_world(0); + attrs = fmt >> 8; + va_start(list, fmt); + for (i = 0; i < nargs; i++, attrs >>= 3) { + switch (attrs & 0x7) { + case P1275_ARG_NUMBER: + (void) va_arg(list, long); + break; + case P1275_ARG_IN_STRING: + (void) va_arg(list, char *); + break; + case P1275_ARG_IN_FUNCTION: + (void) va_arg(list, long); + break; + case P1275_ARG_IN_BUF: + (void) va_arg(list, char *); + (void) va_arg(list, long); + i++; attrs >>= 3; + break; + case P1275_ARG_OUT_BUF: + p = va_arg(list, char *); + x = va_arg(list, long); + memcpy (p, (char *)(p1275buf.prom_args[i + 3]), (int)x); + i++; attrs >>= 3; + break; + case P1275_ARG_OUT_32B: + p = va_arg(list, char *); + memcpy (p, (char *)(p1275buf.prom_args[i + 3]), 32); + break; + } + } + va_end(list); + x = p1275buf.prom_args [nargs + 3]; + raw_spin_unlock(&prom_entry_lock); raw_local_irq_restore(flags); + + return x; } void prom_cif_init(void *cif_handler, void *cif_stack) diff --git a/trunk/arch/sparc/prom/tree_64.c b/trunk/arch/sparc/prom/tree_64.c index 9d3f9137a43a..3c0d2dd9f693 100644 --- a/trunk/arch/sparc/prom/tree_64.c +++ b/trunk/arch/sparc/prom/tree_64.c @@ -16,39 +16,22 @@ #include #include -static int prom_node_to_node(const char *type, int node) -{ - unsigned long args[5]; - - args[0] = (unsigned long) type; - args[1] = 1; - args[2] = 1; - args[3] = (unsigned int) node; - args[4] = (unsigned long) -1; - - p1275_cmd_direct(args); - - return (int) args[4]; -} - /* Return the child of node 'node' or zero if no this node has no * direct descendent. */ inline int __prom_getchild(int node) { - return prom_node_to_node("child", node); + return p1275_cmd ("child", P1275_INOUT(1, 1), node); } inline int prom_getchild(int node) { int cnode; - if (node == -1) - return 0; + if(node == -1) return 0; cnode = __prom_getchild(node); - if (cnode == -1) - return 0; - return cnode; + if(cnode == -1) return 0; + return (int)cnode; } EXPORT_SYMBOL(prom_getchild); @@ -56,12 +39,10 @@ inline int prom_getparent(int node) { int cnode; - if (node == -1) - return 0; - cnode = prom_node_to_node("parent", node); - if (cnode == -1) - return 0; - return cnode; + if(node == -1) return 0; + cnode = p1275_cmd ("parent", P1275_INOUT(1, 1), node); + if(cnode == -1) return 0; + return (int)cnode; } /* Return the next sibling of node 'node' or zero if no more siblings @@ -69,7 +50,7 @@ inline int prom_getparent(int node) */ inline int __prom_getsibling(int node) { - return prom_node_to_node(prom_peer_name, node); + return p1275_cmd(prom_peer_name, P1275_INOUT(1, 1), node); } inline int prom_getsibling(int node) @@ -91,21 +72,11 @@ EXPORT_SYMBOL(prom_getsibling); */ inline int prom_getproplen(int node, const char *prop) { - unsigned long args[6]; - - if (!node || !prop) - return -1; - - args[0] = (unsigned long) "getproplen"; - args[1] = 2; - args[2] = 1; - args[3] = (unsigned int) node; - args[4] = (unsigned long) prop; - args[5] = (unsigned long) -1; - - p1275_cmd_direct(args); - - return (int) args[5]; + if((!node) || (!prop)) return -1; + return p1275_cmd ("getproplen", + P1275_ARG(1,P1275_ARG_IN_STRING)| + P1275_INOUT(2, 1), + node, prop); } EXPORT_SYMBOL(prom_getproplen); @@ -116,25 +87,19 @@ EXPORT_SYMBOL(prom_getproplen); inline int prom_getproperty(int node, const char *prop, char *buffer, int bufsize) { - unsigned long args[8]; int plen; plen = prom_getproplen(node, prop); - if ((plen > bufsize) || (plen == 0) || (plen == -1)) + if ((plen > bufsize) || (plen == 0) || (plen == -1)) { return -1; - - args[0] = (unsigned long) prom_getprop_name; - args[1] = 4; - args[2] = 1; - args[3] = (unsigned int) node; - args[4] = (unsigned long) prop; - args[5] = (unsigned long) buffer; - args[6] = bufsize; - args[7] = (unsigned long) -1; - - p1275_cmd_direct(args); - - return (int) args[7]; + } else { + /* Ok, things seem all right. */ + return p1275_cmd(prom_getprop_name, + P1275_ARG(1,P1275_ARG_IN_STRING)| + P1275_ARG(2,P1275_ARG_OUT_BUF)| + P1275_INOUT(4, 1), + node, prop, buffer, P1275_SIZE(plen)); + } } EXPORT_SYMBOL(prom_getproperty); @@ -145,7 +110,7 @@ inline int prom_getint(int node, const char *prop) { int intprop; - if (prom_getproperty(node, prop, (char *) &intprop, sizeof(int)) != -1) + if(prom_getproperty(node, prop, (char *) &intprop, sizeof(int)) != -1) return intprop; return -1; @@ -161,8 +126,7 @@ int prom_getintdefault(int node, const char *property, int deflt) int retval; retval = prom_getint(node, property); - if (retval == -1) - return deflt; + if(retval == -1) return deflt; return retval; } @@ -174,8 +138,7 @@ int prom_getbool(int node, const char *prop) int retval; retval = prom_getproplen(node, prop); - if (retval == -1) - return 0; + if(retval == -1) return 0; return 1; } EXPORT_SYMBOL(prom_getbool); @@ -189,8 +152,7 @@ void prom_getstring(int node, const char *prop, char *user_buf, int ubuf_size) int len; len = prom_getproperty(node, prop, user_buf, ubuf_size); - if (len != -1) - return; + if(len != -1) return; user_buf[0] = 0; } EXPORT_SYMBOL(prom_getstring); @@ -202,8 +164,7 @@ int prom_nodematch(int node, const char *name) { char namebuf[128]; prom_getproperty(node, "name", namebuf, sizeof(namebuf)); - if (strcmp(namebuf, name) == 0) - return 1; + if(strcmp(namebuf, name) == 0) return 1; return 0; } @@ -229,29 +190,16 @@ int prom_searchsiblings(int node_start, const char *nodename) } EXPORT_SYMBOL(prom_searchsiblings); -static const char *prom_nextprop_name = "nextprop"; - /* Return the first property type for node 'node'. * buffer should be at least 32B in length */ inline char *prom_firstprop(int node, char *buffer) { - unsigned long args[7]; - *buffer = 0; - if (node == -1) - return buffer; - - args[0] = (unsigned long) prom_nextprop_name; - args[1] = 3; - args[2] = 1; - args[3] = (unsigned int) node; - args[4] = 0; - args[5] = (unsigned long) buffer; - args[6] = (unsigned long) -1; - - p1275_cmd_direct(args); - + if(node == -1) return buffer; + p1275_cmd ("nextprop", P1275_ARG(2,P1275_ARG_OUT_32B)| + P1275_INOUT(3, 0), + node, (char *) 0x0, buffer); return buffer; } EXPORT_SYMBOL(prom_firstprop); @@ -262,10 +210,9 @@ EXPORT_SYMBOL(prom_firstprop); */ inline char *prom_nextprop(int node, const char *oprop, char *buffer) { - unsigned long args[7]; char buf[32]; - if (node == -1) { + if(node == -1) { *buffer = 0; return buffer; } @@ -273,17 +220,10 @@ inline char *prom_nextprop(int node, const char *oprop, char *buffer) strcpy (buf, oprop); oprop = buf; } - - args[0] = (unsigned long) prom_nextprop_name; - args[1] = 3; - args[2] = 1; - args[3] = (unsigned int) node; - args[4] = (unsigned long) oprop; - args[5] = (unsigned long) buffer; - args[6] = (unsigned long) -1; - - p1275_cmd_direct(args); - + p1275_cmd ("nextprop", P1275_ARG(1,P1275_ARG_IN_STRING)| + P1275_ARG(2,P1275_ARG_OUT_32B)| + P1275_INOUT(3, 0), + node, oprop, buffer); return buffer; } EXPORT_SYMBOL(prom_nextprop); @@ -291,19 +231,12 @@ EXPORT_SYMBOL(prom_nextprop); int prom_finddevice(const char *name) { - unsigned long args[5]; - if (!name) return 0; - args[0] = (unsigned long) "finddevice"; - args[1] = 1; - args[2] = 1; - args[3] = (unsigned long) name; - args[4] = (unsigned long) -1; - - p1275_cmd_direct(args); - - return (int) args[4]; + return p1275_cmd(prom_finddev_name, + P1275_ARG(0,P1275_ARG_IN_STRING)| + P1275_INOUT(1, 1), + name); } EXPORT_SYMBOL(prom_finddevice); @@ -314,7 +247,7 @@ int prom_node_has_property(int node, const char *prop) *buf = 0; do { prom_nextprop(node, buf, buf); - if (!strcmp(buf, prop)) + if(!strcmp(buf, prop)) return 1; } while (*buf); return 0; @@ -327,8 +260,6 @@ EXPORT_SYMBOL(prom_node_has_property); int prom_setprop(int node, const char *pname, char *value, int size) { - unsigned long args[8]; - if (size == 0) return 0; if ((pname == 0) || (value == 0)) @@ -340,37 +271,19 @@ prom_setprop(int node, const char *pname, char *value, int size) return 0; } #endif - args[0] = (unsigned long) "setprop"; - args[1] = 4; - args[2] = 1; - args[3] = (unsigned int) node; - args[4] = (unsigned long) pname; - args[5] = (unsigned long) value; - args[6] = size; - args[7] = (unsigned long) -1; - - p1275_cmd_direct(args); - - return (int) args[7]; + return p1275_cmd ("setprop", P1275_ARG(1,P1275_ARG_IN_STRING)| + P1275_ARG(2,P1275_ARG_IN_BUF)| + P1275_INOUT(4, 1), + node, pname, value, P1275_SIZE(size)); } EXPORT_SYMBOL(prom_setprop); inline int prom_inst2pkg(int inst) { - unsigned long args[5]; int node; - args[0] = (unsigned long) "instance-to-package"; - args[1] = 1; - args[2] = 1; - args[3] = (unsigned int) inst; - args[4] = (unsigned long) -1; - - p1275_cmd_direct(args); - - node = (int) args[4]; - if (node == -1) - return 0; + node = p1275_cmd ("instance-to-package", P1275_INOUT(1, 1), inst); + if (node == -1) return 0; return node; } @@ -383,28 +296,17 @@ prom_pathtoinode(const char *path) int node, inst; inst = prom_devopen (path); - if (inst == 0) - return 0; - node = prom_inst2pkg(inst); - prom_devclose(inst); - if (node == -1) - return 0; + if (inst == 0) return 0; + node = prom_inst2pkg (inst); + prom_devclose (inst); + if (node == -1) return 0; return node; } int prom_ihandle2path(int handle, char *buffer, int bufsize) { - unsigned long args[7]; - - args[0] = (unsigned long) "instance-to-path"; - args[1] = 3; - args[2] = 1; - args[3] = (unsigned int) handle; - args[4] = (unsigned long) buffer; - args[5] = bufsize; - args[6] = (unsigned long) -1; - - p1275_cmd_direct(args); - - return (int) args[6]; + return p1275_cmd("instance-to-path", + P1275_ARG(1,P1275_ARG_OUT_BUF)| + P1275_INOUT(3, 1), + handle, buffer, P1275_SIZE(bufsize)); } diff --git a/trunk/drivers/base/firmware_class.c b/trunk/drivers/base/firmware_class.c index 40af43ebd92d..c8a44f5e0584 100644 --- a/trunk/drivers/base/firmware_class.c +++ b/trunk/drivers/base/firmware_class.c @@ -568,7 +568,7 @@ static int _request_firmware(const struct firmware **firmware_p, out: if (retval) { release_firmware(firmware); - *firmware_p = NULL; + firmware_p = NULL; } return retval; diff --git a/trunk/drivers/char/ip2/ip2main.c b/trunk/drivers/char/ip2/ip2main.c index d4b71e8d0d23..07f3ea38b582 100644 --- a/trunk/drivers/char/ip2/ip2main.c +++ b/trunk/drivers/char/ip2/ip2main.c @@ -1650,7 +1650,7 @@ ip2_close( PTTY tty, struct file *pFile ) /* disable DSS reporting */ i2QueueCommands(PTYPE_INLINE, pCh, 100, 4, CMD_DCD_NREP, CMD_CTS_NREP, CMD_DSR_NREP, CMD_RI_NREP); - if (tty->termios->c_cflag & HUPCL) { + if ( !tty || (tty->termios->c_cflag & HUPCL) ) { i2QueueCommands(PTYPE_INLINE, pCh, 100, 2, CMD_RTSDN, CMD_DTRDN); pCh->dataSetOut &= ~(I2_DTR | I2_RTS); i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_PAUSE(25)); @@ -2930,8 +2930,6 @@ ip2_ipl_ioctl (struct file *pFile, UINT cmd, ULONG arg ) if ( pCh ) { rc = copy_to_user(argp, pCh, sizeof(i2ChanStr)); - if (rc) - rc = -EFAULT; } else { rc = -ENODEV; } diff --git a/trunk/drivers/char/rocket.c b/trunk/drivers/char/rocket.c index 7c79d243acc9..79c3bc69165a 100644 --- a/trunk/drivers/char/rocket.c +++ b/trunk/drivers/char/rocket.c @@ -1244,7 +1244,6 @@ static int set_config(struct tty_struct *tty, struct r_port *info, } info->flags = ((info->flags & ~ROCKET_USR_MASK) | (new_serial.flags & ROCKET_USR_MASK)); configure_r_port(tty, info, NULL); - mutex_unlock(&info->port.mutex); return 0; } diff --git a/trunk/drivers/char/synclink_gt.c b/trunk/drivers/char/synclink_gt.c index e63b830c86cc..fef80cfcab5c 100644 --- a/trunk/drivers/char/synclink_gt.c +++ b/trunk/drivers/char/synclink_gt.c @@ -691,10 +691,8 @@ static int open(struct tty_struct *tty, struct file *filp) if (info->port.count == 1) { /* 1st open on this device, init hardware */ retval = startup(info); - if (retval < 0) { - mutex_unlock(&info->port.mutex); + if (retval < 0) goto cleanup; - } } mutex_unlock(&info->port.mutex); retval = block_til_ready(tty, filp, info); diff --git a/trunk/drivers/macintosh/via-pmu.c b/trunk/drivers/macintosh/via-pmu.c index 2d17e76066bd..35bc2737412f 100644 --- a/trunk/drivers/macintosh/via-pmu.c +++ b/trunk/drivers/macintosh/via-pmu.c @@ -45,7 +45,6 @@ #include #include #include -#include #include #include #include @@ -2350,52 +2349,11 @@ static long pmu_unlocked_ioctl(struct file *filp, return ret; } -#ifdef CONFIG_COMPAT -#define PMU_IOC_GET_BACKLIGHT32 _IOR('B', 1, compat_size_t) -#define PMU_IOC_SET_BACKLIGHT32 _IOW('B', 2, compat_size_t) -#define PMU_IOC_GET_MODEL32 _IOR('B', 3, compat_size_t) -#define PMU_IOC_HAS_ADB32 _IOR('B', 4, compat_size_t) -#define PMU_IOC_CAN_SLEEP32 _IOR('B', 5, compat_size_t) -#define PMU_IOC_GRAB_BACKLIGHT32 _IOR('B', 6, compat_size_t) - -static long compat_pmu_ioctl (struct file *filp, u_int cmd, u_long arg) -{ - switch (cmd) { - case PMU_IOC_SLEEP: - break; - case PMU_IOC_GET_BACKLIGHT32: - cmd = PMU_IOC_GET_BACKLIGHT; - break; - case PMU_IOC_SET_BACKLIGHT32: - cmd = PMU_IOC_SET_BACKLIGHT; - break; - case PMU_IOC_GET_MODEL32: - cmd = PMU_IOC_GET_MODEL; - break; - case PMU_IOC_HAS_ADB32: - cmd = PMU_IOC_HAS_ADB; - break; - case PMU_IOC_CAN_SLEEP32: - cmd = PMU_IOC_CAN_SLEEP; - break; - case PMU_IOC_GRAB_BACKLIGHT32: - cmd = PMU_IOC_GRAB_BACKLIGHT; - break; - default: - return -ENOIOCTLCMD; - } - return pmu_unlocked_ioctl(filp, cmd, (unsigned long)compat_ptr(arg)); -} -#endif - static const struct file_operations pmu_device_fops = { .read = pmu_read, .write = pmu_write, .poll = pmu_fpoll, .unlocked_ioctl = pmu_unlocked_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = compat_pmu_ioctl, -#endif .open = pmu_open, .release = pmu_release, }; diff --git a/trunk/drivers/media/dvb/mantis/Kconfig b/trunk/drivers/media/dvb/mantis/Kconfig index fd0830ed10d8..decdeda840d0 100644 --- a/trunk/drivers/media/dvb/mantis/Kconfig +++ b/trunk/drivers/media/dvb/mantis/Kconfig @@ -1,6 +1,6 @@ config MANTIS_CORE tristate "Mantis/Hopper PCI bridge based devices" - depends on PCI && I2C && INPUT && IR_CORE + depends on PCI && I2C && INPUT help Support for PCI cards based on the Mantis and Hopper PCi bridge. diff --git a/trunk/drivers/platform/x86/intel_rar_register.c b/trunk/drivers/platform/x86/intel_rar_register.c index 2b11a33325e6..73f8e6d72669 100644 --- a/trunk/drivers/platform/x86/intel_rar_register.c +++ b/trunk/drivers/platform/x86/intel_rar_register.c @@ -145,7 +145,7 @@ static void free_rar_device(struct rar_device *rar) */ static struct rar_device *_rar_to_device(int rar, int *off) { - if (rar >= 0 && rar < MRST_NUM_RAR) { + if (rar >= 0 && rar <= 3) { *off = rar; return &my_rar_device; } diff --git a/trunk/drivers/platform/x86/intel_scu_ipc.c b/trunk/drivers/platform/x86/intel_scu_ipc.c index 6abe18e638e9..943f9084dcb1 100644 --- a/trunk/drivers/platform/x86/intel_scu_ipc.c +++ b/trunk/drivers/platform/x86/intel_scu_ipc.c @@ -487,7 +487,7 @@ int intel_scu_ipc_i2c_cntrl(u32 addr, u32 *data) mdelay(1); *data = readl(ipcdev.i2c_base + I2C_DATA_ADDR); } else if (cmd == IPC_I2C_WRITE) { - writel(*data, ipcdev.i2c_base + I2C_DATA_ADDR); + writel(addr, ipcdev.i2c_base + I2C_DATA_ADDR); mdelay(1); writel(addr, ipcdev.i2c_base + IPC_I2C_CNTRL_ADDR); } else { diff --git a/trunk/drivers/serial/68328serial.c b/trunk/drivers/serial/68328serial.c index be0ebce36e54..7356a56ac458 100644 --- a/trunk/drivers/serial/68328serial.c +++ b/trunk/drivers/serial/68328serial.c @@ -869,9 +869,7 @@ static int get_serial_info(struct m68k_serial * info, tmp.close_delay = info->close_delay; tmp.closing_wait = info->closing_wait; tmp.custom_divisor = info->custom_divisor; - if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) - return -EFAULT; - + copy_to_user(retinfo,&tmp,sizeof(*retinfo)); return 0; } @@ -884,8 +882,7 @@ static int set_serial_info(struct m68k_serial * info, if (!new_info) return -EFAULT; - if (copy_from_user(&new_serial, new_info, sizeof(new_serial))) - return -EFAULT; + copy_from_user(&new_serial,new_info,sizeof(new_serial)); old_info = *info; if (!capable(CAP_SYS_ADMIN)) { @@ -946,7 +943,8 @@ static int get_lsr_info(struct m68k_serial * info, unsigned int *value) status = 0; #endif local_irq_restore(flags); - return put_user(status, value); + put_user(status,value); + return 0; } /* @@ -1001,18 +999,27 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file, send_break(info, arg ? arg*(100) : 250); return 0; case TIOCGSERIAL: - return get_serial_info(info, - (struct serial_struct *) arg); + if (access_ok(VERIFY_WRITE, (void *) arg, + sizeof(struct serial_struct))) + return get_serial_info(info, + (struct serial_struct *) arg); + return -EFAULT; case TIOCSSERIAL: return set_serial_info(info, (struct serial_struct *) arg); case TIOCSERGETLSR: /* Get line status register */ - return get_lsr_info(info, (unsigned int *) arg); + if (access_ok(VERIFY_WRITE, (void *) arg, + sizeof(unsigned int))) + return get_lsr_info(info, (unsigned int *) arg); + return -EFAULT; case TIOCSERGSTRUCT: - if (copy_to_user((struct m68k_serial *) arg, - info, sizeof(struct m68k_serial))) + if (!access_ok(VERIFY_WRITE, (void *) arg, + sizeof(struct m68k_serial))) return -EFAULT; + copy_to_user((struct m68k_serial *) arg, + info, sizeof(struct m68k_serial)); return 0; + default: return -ENOIOCTLCMD; } diff --git a/trunk/drivers/serial/8250_early.c b/trunk/drivers/serial/8250_early.c index eaafb98debed..b745792ec25a 100644 --- a/trunk/drivers/serial/8250_early.c +++ b/trunk/drivers/serial/8250_early.c @@ -203,13 +203,13 @@ static int __init parse_options(struct early_serial8250_device *device, if (mmio || mmio32) printk(KERN_INFO - "Early serial console at MMIO%s 0x%llx (options '%s')\n", + "Early serial console at MMIO%s 0x%llu (options '%s')\n", mmio32 ? "32" : "", (unsigned long long)port->mapbase, device->options); else printk(KERN_INFO - "Early serial console at I/O port 0x%lx (options '%s')\n", + "Early serial console at I/O port 0x%lu (options '%s')\n", port->iobase, device->options); diff --git a/trunk/drivers/staging/Kconfig b/trunk/drivers/staging/Kconfig index 335311a98fdc..4a7a7a7f11b6 100644 --- a/trunk/drivers/staging/Kconfig +++ b/trunk/drivers/staging/Kconfig @@ -113,6 +113,8 @@ source "drivers/staging/vme/Kconfig" source "drivers/staging/memrar/Kconfig" +source "drivers/staging/sep/Kconfig" + source "drivers/staging/iio/Kconfig" source "drivers/staging/zram/Kconfig" diff --git a/trunk/drivers/staging/Makefile b/trunk/drivers/staging/Makefile index e3f1e1b6095e..ca5c03eb3ce3 100644 --- a/trunk/drivers/staging/Makefile +++ b/trunk/drivers/staging/Makefile @@ -38,6 +38,7 @@ obj-$(CONFIG_FB_UDL) += udlfb/ obj-$(CONFIG_HYPERV) += hv/ obj-$(CONFIG_VME_BUS) += vme/ obj-$(CONFIG_MRST_RAR_HANDLER) += memrar/ +obj-$(CONFIG_DX_SEP) += sep/ obj-$(CONFIG_IIO) += iio/ obj-$(CONFIG_ZRAM) += zram/ obj-$(CONFIG_WLAGS49_H2) += wlags49_h2/ diff --git a/trunk/drivers/staging/batman-adv/bat_sysfs.c b/trunk/drivers/staging/batman-adv/bat_sysfs.c index 05ca15a6c9f8..b4a8d5eb64fa 100644 --- a/trunk/drivers/staging/batman-adv/bat_sysfs.c +++ b/trunk/drivers/staging/batman-adv/bat_sysfs.c @@ -267,10 +267,6 @@ static ssize_t store_log_level(struct kobject *kobj, struct attribute *attr, if (atomic_read(&bat_priv->log_level) == log_level_tmp) return count; - bat_info(net_dev, "Changing log level from: %i to: %li\n", - atomic_read(&bat_priv->log_level), - log_level_tmp); - atomic_set(&bat_priv->log_level, (unsigned)log_level_tmp); return count; } diff --git a/trunk/drivers/staging/batman-adv/hard-interface.c b/trunk/drivers/staging/batman-adv/hard-interface.c index baa8b05b9e8d..92c216a56885 100644 --- a/trunk/drivers/staging/batman-adv/hard-interface.c +++ b/trunk/drivers/staging/batman-adv/hard-interface.c @@ -129,9 +129,6 @@ static bool hardif_is_iface_up(struct batman_if *batman_if) static void update_mac_addresses(struct batman_if *batman_if) { - if (!batman_if || !batman_if->packet_buff) - return; - addr_to_string(batman_if->addr_str, batman_if->net_dev->dev_addr); memcpy(((struct batman_packet *)(batman_if->packet_buff))->orig, @@ -197,6 +194,8 @@ static void hardif_activate_interface(struct net_device *net_dev, if (batman_if->if_status != IF_INACTIVE) return; + dev_hold(batman_if->net_dev); + update_mac_addresses(batman_if); batman_if->if_status = IF_TO_BE_ACTIVATED; @@ -223,6 +222,8 @@ static void hardif_deactivate_interface(struct net_device *net_dev, (batman_if->if_status != IF_TO_BE_ACTIVATED)) return; + dev_put(batman_if->net_dev); + batman_if->if_status = IF_INACTIVE; bat_info(net_dev, "Interface deactivated: %s\n", batman_if->dev); @@ -317,13 +318,11 @@ static struct batman_if *hardif_add_interface(struct net_device *net_dev) if (ret != 1) goto out; - dev_hold(net_dev); - batman_if = kmalloc(sizeof(struct batman_if), GFP_ATOMIC); if (!batman_if) { pr_err("Can't add interface (%s): out of memory\n", net_dev->name); - goto release_dev; + goto out; } batman_if->dev = kstrdup(net_dev->name, GFP_ATOMIC); @@ -337,7 +336,6 @@ static struct batman_if *hardif_add_interface(struct net_device *net_dev) batman_if->if_num = -1; batman_if->net_dev = net_dev; batman_if->if_status = IF_NOT_IN_USE; - batman_if->packet_buff = NULL; INIT_LIST_HEAD(&batman_if->list); check_known_mac_addr(batman_if->net_dev->dev_addr); @@ -348,8 +346,6 @@ static struct batman_if *hardif_add_interface(struct net_device *net_dev) kfree(batman_if->dev); free_if: kfree(batman_if); -release_dev: - dev_put(net_dev); out: return NULL; } @@ -378,7 +374,6 @@ static void hardif_remove_interface(struct batman_if *batman_if) batman_if->if_status = IF_TO_BE_REMOVED; list_del_rcu(&batman_if->list); sysfs_del_hardif(&batman_if->hardif_obj); - dev_put(batman_if->net_dev); call_rcu(&batman_if->rcu, hardif_free_interface); } @@ -398,13 +393,15 @@ static int hard_if_event(struct notifier_block *this, /* FIXME: each batman_if will be attached to a softif */ struct bat_priv *bat_priv = netdev_priv(soft_device); - if (!batman_if && event == NETDEV_REGISTER) - batman_if = hardif_add_interface(net_dev); + if (!batman_if) + batman_if = hardif_add_interface(net_dev); if (!batman_if) goto out; switch (event) { + case NETDEV_REGISTER: + break; case NETDEV_UP: hardif_activate_interface(soft_device, bat_priv, batman_if); break; @@ -445,6 +442,8 @@ int batman_skb_recv(struct sk_buff *skb, struct net_device *dev, struct bat_priv *bat_priv = netdev_priv(soft_device); struct batman_packet *batman_packet; struct batman_if *batman_if; + struct net_device_stats *stats; + struct rtnl_link_stats64 temp; int ret; skb = skb_share_check(skb, GFP_ATOMIC); @@ -480,6 +479,12 @@ int batman_skb_recv(struct sk_buff *skb, struct net_device *dev, if (batman_if->if_status != IF_ACTIVE) goto err_free; + stats = (struct net_device_stats *)dev_get_stats(skb->dev, &temp); + if (stats) { + stats->rx_packets++; + stats->rx_bytes += skb->len; + } + batman_packet = (struct batman_packet *)skb->data; if (batman_packet->version != COMPAT_VERSION) { diff --git a/trunk/drivers/staging/batman-adv/icmp_socket.c b/trunk/drivers/staging/batman-adv/icmp_socket.c index 3ae7dd2d2d4d..fc3d32c12729 100644 --- a/trunk/drivers/staging/batman-adv/icmp_socket.c +++ b/trunk/drivers/staging/batman-adv/icmp_socket.c @@ -67,7 +67,6 @@ static int bat_socket_open(struct inode *inode, struct file *file) INIT_LIST_HEAD(&socket_client->queue_list); socket_client->queue_len = 0; socket_client->index = i; - socket_client->bat_priv = inode->i_private; spin_lock_init(&socket_client->lock); init_waitqueue_head(&socket_client->queue_wait); @@ -152,8 +151,9 @@ static ssize_t bat_socket_read(struct file *file, char __user *buf, static ssize_t bat_socket_write(struct file *file, const char __user *buff, size_t len, loff_t *off) { + /* FIXME: each orig_node->batman_if will be attached to a softif */ + struct bat_priv *bat_priv = netdev_priv(soft_device); struct socket_client *socket_client = file->private_data; - struct bat_priv *bat_priv = socket_client->bat_priv; struct icmp_packet_rr icmp_packet; struct orig_node *orig_node; struct batman_if *batman_if; @@ -168,9 +168,6 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff, return -EINVAL; } - if (!bat_priv->primary_if) - return -EFAULT; - if (len >= sizeof(struct icmp_packet_rr)) packet_len = sizeof(struct icmp_packet_rr); @@ -226,8 +223,7 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff, if (batman_if->if_status != IF_ACTIVE) goto dst_unreach; - memcpy(icmp_packet.orig, - bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); + memcpy(icmp_packet.orig, batman_if->net_dev->dev_addr, ETH_ALEN); if (packet_len == sizeof(struct icmp_packet_rr)) memcpy(icmp_packet.rr, batman_if->net_dev->dev_addr, ETH_ALEN); @@ -275,7 +271,7 @@ int bat_socket_setup(struct bat_priv *bat_priv) goto err; d = debugfs_create_file(ICMP_SOCKET, S_IFREG | S_IWUSR | S_IRUSR, - bat_priv->debug_dir, bat_priv, &fops); + bat_priv->debug_dir, NULL, &fops); if (d) goto err; diff --git a/trunk/drivers/staging/batman-adv/main.c b/trunk/drivers/staging/batman-adv/main.c index ef7c20ae7979..2686019fe4e1 100644 --- a/trunk/drivers/staging/batman-adv/main.c +++ b/trunk/drivers/staging/batman-adv/main.c @@ -250,13 +250,10 @@ int choose_orig(void *data, int32_t size) int is_my_mac(uint8_t *addr) { struct batman_if *batman_if; - rcu_read_lock(); list_for_each_entry_rcu(batman_if, &if_list, list) { - if (batman_if->if_status != IF_ACTIVE) - continue; - - if (compare_orig(batman_if->net_dev->dev_addr, addr)) { + if ((batman_if->net_dev) && + (compare_orig(batman_if->net_dev->dev_addr, addr))) { rcu_read_unlock(); return 1; } diff --git a/trunk/drivers/staging/batman-adv/originator.c b/trunk/drivers/staging/batman-adv/originator.c index de5a8c1a8104..28bb627ffa13 100644 --- a/trunk/drivers/staging/batman-adv/originator.c +++ b/trunk/drivers/staging/batman-adv/originator.c @@ -391,12 +391,11 @@ static int orig_node_add_if(struct orig_node *orig_node, int max_if_num) int orig_hash_add_if(struct batman_if *batman_if, int max_if_num) { struct orig_node *orig_node; - unsigned long flags; HASHIT(hashit); /* resize all orig nodes because orig_node->bcast_own(_sum) depend on * if_num */ - spin_lock_irqsave(&orig_hash_lock, flags); + spin_lock(&orig_hash_lock); while (hash_iterate(orig_hash, &hashit)) { orig_node = hashit.bucket->data; @@ -405,11 +404,11 @@ int orig_hash_add_if(struct batman_if *batman_if, int max_if_num) goto err; } - spin_unlock_irqrestore(&orig_hash_lock, flags); + spin_unlock(&orig_hash_lock); return 0; err: - spin_unlock_irqrestore(&orig_hash_lock, flags); + spin_unlock(&orig_hash_lock); return -ENOMEM; } @@ -469,13 +468,12 @@ int orig_hash_del_if(struct batman_if *batman_if, int max_if_num) { struct batman_if *batman_if_tmp; struct orig_node *orig_node; - unsigned long flags; HASHIT(hashit); int ret; /* resize all orig nodes because orig_node->bcast_own(_sum) depend on * if_num */ - spin_lock_irqsave(&orig_hash_lock, flags); + spin_lock(&orig_hash_lock); while (hash_iterate(orig_hash, &hashit)) { orig_node = hashit.bucket->data; @@ -502,10 +500,10 @@ int orig_hash_del_if(struct batman_if *batman_if, int max_if_num) rcu_read_unlock(); batman_if->if_num = -1; - spin_unlock_irqrestore(&orig_hash_lock, flags); + spin_unlock(&orig_hash_lock); return 0; err: - spin_unlock_irqrestore(&orig_hash_lock, flags); + spin_unlock(&orig_hash_lock); return -ENOMEM; } diff --git a/trunk/drivers/staging/batman-adv/routing.c b/trunk/drivers/staging/batman-adv/routing.c index 032195e6de94..066cc9149bf1 100644 --- a/trunk/drivers/staging/batman-adv/routing.c +++ b/trunk/drivers/staging/batman-adv/routing.c @@ -783,8 +783,6 @@ int recv_bat_packet(struct sk_buff *skb, static int recv_my_icmp_packet(struct sk_buff *skb, size_t icmp_len) { - /* FIXME: each batman_if will be attached to a softif */ - struct bat_priv *bat_priv = netdev_priv(soft_device); struct orig_node *orig_node; struct icmp_packet_rr *icmp_packet; struct ethhdr *ethhdr; @@ -803,9 +801,6 @@ static int recv_my_icmp_packet(struct sk_buff *skb, size_t icmp_len) return NET_RX_DROP; } - if (!bat_priv->primary_if) - return NET_RX_DROP; - /* answer echo request (ping) */ /* get routing information */ spin_lock_irqsave(&orig_hash_lock, flags); @@ -835,8 +830,7 @@ static int recv_my_icmp_packet(struct sk_buff *skb, size_t icmp_len) } memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN); - memcpy(icmp_packet->orig, - bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); + memcpy(icmp_packet->orig, ethhdr->h_dest, ETH_ALEN); icmp_packet->msg_type = ECHO_REPLY; icmp_packet->ttl = TTL; @@ -851,8 +845,6 @@ static int recv_my_icmp_packet(struct sk_buff *skb, size_t icmp_len) static int recv_icmp_ttl_exceeded(struct sk_buff *skb, size_t icmp_len) { - /* FIXME: each batman_if will be attached to a softif */ - struct bat_priv *bat_priv = netdev_priv(soft_device); struct orig_node *orig_node; struct icmp_packet *icmp_packet; struct ethhdr *ethhdr; @@ -873,9 +865,6 @@ static int recv_icmp_ttl_exceeded(struct sk_buff *skb, size_t icmp_len) return NET_RX_DROP; } - if (!bat_priv->primary_if) - return NET_RX_DROP; - /* get routing information */ spin_lock_irqsave(&orig_hash_lock, flags); orig_node = ((struct orig_node *) @@ -903,8 +892,7 @@ static int recv_icmp_ttl_exceeded(struct sk_buff *skb, size_t icmp_len) } memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN); - memcpy(icmp_packet->orig, - bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); + memcpy(icmp_packet->orig, ethhdr->h_dest, ETH_ALEN); icmp_packet->msg_type = TTL_EXCEEDED; icmp_packet->ttl = TTL; diff --git a/trunk/drivers/staging/batman-adv/types.h b/trunk/drivers/staging/batman-adv/types.h index 9aa9d369c752..21d0717afb09 100644 --- a/trunk/drivers/staging/batman-adv/types.h +++ b/trunk/drivers/staging/batman-adv/types.h @@ -126,7 +126,6 @@ struct socket_client { unsigned char index; spinlock_t lock; wait_queue_head_t queue_wait; - struct bat_priv *bat_priv; }; struct socket_packet { diff --git a/trunk/drivers/staging/sep/Kconfig b/trunk/drivers/staging/sep/Kconfig new file mode 100644 index 000000000000..0a9c39c7f2bd --- /dev/null +++ b/trunk/drivers/staging/sep/Kconfig @@ -0,0 +1,10 @@ +config DX_SEP + tristate "Discretix SEP driver" +# depends on MRST + depends on RAR_REGISTER && PCI + default y + help + Discretix SEP driver + + If unsure say M. The compiled module will be + called sep_driver.ko diff --git a/trunk/drivers/staging/sep/Makefile b/trunk/drivers/staging/sep/Makefile new file mode 100644 index 000000000000..628d5f919414 --- /dev/null +++ b/trunk/drivers/staging/sep/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_DX_SEP) := sep_driver.o + diff --git a/trunk/drivers/staging/sep/TODO b/trunk/drivers/staging/sep/TODO new file mode 100644 index 000000000000..ff0e931dab64 --- /dev/null +++ b/trunk/drivers/staging/sep/TODO @@ -0,0 +1,8 @@ +Todo's so far (from Alan Cox) +- Fix firmware loading +- Get firmware into firmware git tree +- Review and tidy each algorithm function +- Check whether it can be plugged into any of the kernel crypto API + interfaces +- Do something about the magic shared memory interface and replace it + with something saner (in Linux terms) diff --git a/trunk/drivers/staging/sep/sep_dev.h b/trunk/drivers/staging/sep/sep_dev.h new file mode 100644 index 000000000000..9200524bb64d --- /dev/null +++ b/trunk/drivers/staging/sep/sep_dev.h @@ -0,0 +1,110 @@ +#ifndef __SEP_DEV_H__ +#define __SEP_DEV_H__ + +/* + * + * sep_dev.h - Security Processor Device Structures + * + * Copyright(c) 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2009 Discretix. All rights reserved. + * + * 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. + * + * 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, write to the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * CONTACTS: + * + * Alan Cox alan@linux.intel.com + * + */ + +struct sep_device { + /* pointer to pci dev */ + struct pci_dev *pdev; + + unsigned long in_use; + + /* address of the shared memory allocated during init for SEP driver + (coherent alloc) */ + void *shared_addr; + /* the physical address of the shared area */ + dma_addr_t shared_bus; + + /* restricted access region (coherent alloc) */ + dma_addr_t rar_bus; + void *rar_addr; + /* firmware regions: cache is at rar_addr */ + unsigned long cache_size; + + /* follows the cache */ + dma_addr_t resident_bus; + unsigned long resident_size; + void *resident_addr; + + /* start address of the access to the SEP registers from driver */ + void __iomem *reg_addr; + /* transaction counter that coordinates the transactions between SEP and HOST */ + unsigned long send_ct; + /* counter for the messages from sep */ + unsigned long reply_ct; + /* counter for the number of bytes allocated in the pool for the current + transaction */ + unsigned long data_pool_bytes_allocated; + + /* array of pointers to the pages that represent input data for the synchronic + DMA action */ + struct page **in_page_array; + + /* array of pointers to the pages that represent out data for the synchronic + DMA action */ + struct page **out_page_array; + + /* number of pages in the sep_in_page_array */ + unsigned long in_num_pages; + + /* number of pages in the sep_out_page_array */ + unsigned long out_num_pages; + + /* global data for every flow */ + struct sep_flow_context_t flows[SEP_DRIVER_NUM_FLOWS]; + + /* pointer to the workqueue that handles the flow done interrupts */ + struct workqueue_struct *flow_wq; + +}; + +static struct sep_device *sep_dev; + +static inline void sep_write_reg(struct sep_device *dev, int reg, u32 value) +{ + void __iomem *addr = dev->reg_addr + reg; + writel(value, addr); +} + +static inline u32 sep_read_reg(struct sep_device *dev, int reg) +{ + void __iomem *addr = dev->reg_addr + reg; + return readl(addr); +} + +/* wait for SRAM write complete(indirect write */ +static inline void sep_wait_sram_write(struct sep_device *dev) +{ + u32 reg_val; + do + reg_val = sep_read_reg(dev, HW_SRAM_DATA_READY_REG_ADDR); + while (!(reg_val & 1)); +} + + +#endif diff --git a/trunk/drivers/staging/sep/sep_driver.c b/trunk/drivers/staging/sep/sep_driver.c new file mode 100644 index 000000000000..ecbde3467b1b --- /dev/null +++ b/trunk/drivers/staging/sep/sep_driver.c @@ -0,0 +1,2742 @@ +/* + * + * sep_driver.c - Security Processor Driver main group of functions + * + * Copyright(c) 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2009 Discretix. All rights reserved. + * + * 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. + * + * 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, write to the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * CONTACTS: + * + * Mark Allyn mark.a.allyn@intel.com + * + * CHANGES: + * + * 2009.06.26 Initial publish + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sep_driver_hw_defs.h" +#include "sep_driver_config.h" +#include "sep_driver_api.h" +#include "sep_dev.h" + +#if SEP_DRIVER_ARM_DEBUG_MODE + +#define CRYS_SEP_ROM_length 0x4000 +#define CRYS_SEP_ROM_start_address 0x8000C000UL +#define CRYS_SEP_ROM_start_address_offset 0xC000UL +#define SEP_ROM_BANK_register 0x80008420UL +#define SEP_ROM_BANK_register_offset 0x8420UL +#define SEP_RAR_IO_MEM_REGION_START_ADDRESS 0x82000000 + +/* + * THESE 2 definitions are specific to the board - must be + * defined during integration + */ +#define SEP_RAR_IO_MEM_REGION_START_ADDRESS 0xFF0D0000 + +/* 2M size */ + +static void sep_load_rom_code(struct sep_device *sep) +{ + /* Index variables */ + unsigned long i, k, j; + u32 reg; + u32 error; + u32 warning; + + /* Loading ROM from SEP_ROM_image.h file */ + k = sizeof(CRYS_SEP_ROM); + + edbg("SEP Driver: DX_CC_TST_SepRomLoader start\n"); + + edbg("SEP Driver: k is %lu\n", k); + edbg("SEP Driver: sep->reg_addr is %p\n", sep->reg_addr); + edbg("SEP Driver: CRYS_SEP_ROM_start_address_offset is %p\n", CRYS_SEP_ROM_start_address_offset); + + for (i = 0; i < 4; i++) { + /* write bank */ + sep_write_reg(sep, SEP_ROM_BANK_register_offset, i); + + for (j = 0; j < CRYS_SEP_ROM_length / 4; j++) { + sep_write_reg(sep, CRYS_SEP_ROM_start_address_offset + 4 * j, CRYS_SEP_ROM[i * 0x1000 + j]); + + k = k - 4; + + if (k == 0) { + j = CRYS_SEP_ROM_length; + i = 4; + } + } + } + + /* reset the SEP */ + sep_write_reg(sep, HW_HOST_SEP_SW_RST_REG_ADDR, 0x1); + + /* poll for SEP ROM boot finish */ + do + reg = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR3_REG_ADDR); + while (!reg); + + edbg("SEP Driver: ROM polling ended\n"); + + switch (reg) { + case 0x1: + /* fatal error - read erro status from GPRO */ + error = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR0_REG_ADDR); + edbg("SEP Driver: ROM polling case 1\n"); + break; + case 0x4: + /* Cold boot ended successfully */ + case 0x8: + /* Warmboot ended successfully */ + case 0x10: + /* ColdWarm boot ended successfully */ + error = 0; + case 0x2: + /* Boot First Phase ended */ + warning = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR0_REG_ADDR); + case 0x20: + edbg("SEP Driver: ROM polling case %d\n", reg); + break; + } + +} + +#else +static void sep_load_rom_code(struct sep_device *sep) { } +#endif /* SEP_DRIVER_ARM_DEBUG_MODE */ + + + +/*---------------------------------------- + DEFINES +-----------------------------------------*/ + +#define BASE_ADDRESS_FOR_SYSTEM 0xfffc0000 +#define SEP_RAR_IO_MEM_REGION_SIZE 0x40000 + +/*-------------------------------------------- + GLOBAL variables +--------------------------------------------*/ + +/* debug messages level */ +static int debug; +module_param(debug, int , 0); +MODULE_PARM_DESC(debug, "Flag to enable SEP debug messages"); + +/* Keep this a single static object for now to keep the conversion easy */ + +static struct sep_device sep_instance; +static struct sep_device *sep_dev = &sep_instance; + +/* + mutex for the access to the internals of the sep driver +*/ +static DEFINE_MUTEX(sep_mutex); + + +/* wait queue head (event) of the driver */ +static DECLARE_WAIT_QUEUE_HEAD(sep_event); + +/** + * sep_load_firmware - copy firmware cache/resident + * @sep: device we are loading + * + * This functions copies the cache and resident from their source + * location into destination shared memory. + */ + +static int sep_load_firmware(struct sep_device *sep) +{ + const struct firmware *fw; + char *cache_name = "sep/cache.image.bin"; + char *res_name = "sep/resident.image.bin"; + int error; + + edbg("SEP Driver:rar_virtual is %p\n", sep->rar_addr); + edbg("SEP Driver:rar_bus is %08llx\n", (unsigned long long)sep->rar_bus); + + /* load cache */ + error = request_firmware(&fw, cache_name, &sep->pdev->dev); + if (error) { + edbg("SEP Driver:cant request cache fw\n"); + return error; + } + edbg("SEP Driver:cache %08Zx@%p\n", fw->size, (void *) fw->data); + + memcpy(sep->rar_addr, (void *)fw->data, fw->size); + sep->cache_size = fw->size; + release_firmware(fw); + + sep->resident_bus = sep->rar_bus + sep->cache_size; + sep->resident_addr = sep->rar_addr + sep->cache_size; + + /* load resident */ + error = request_firmware(&fw, res_name, &sep->pdev->dev); + if (error) { + edbg("SEP Driver:cant request res fw\n"); + return error; + } + edbg("sep: res %08Zx@%p\n", fw->size, (void *)fw->data); + + memcpy(sep->resident_addr, (void *) fw->data, fw->size); + sep->resident_size = fw->size; + release_firmware(fw); + + edbg("sep: resident v %p b %08llx cache v %p b %08llx\n", + sep->resident_addr, (unsigned long long)sep->resident_bus, + sep->rar_addr, (unsigned long long)sep->rar_bus); + return 0; +} + +MODULE_FIRMWARE("sep/cache.image.bin"); +MODULE_FIRMWARE("sep/resident.image.bin"); + +/** + * sep_map_and_alloc_shared_area - allocate shared block + * @sep: security processor + * @size: size of shared area + * + * Allocate a shared buffer in host memory that can be used by both the + * kernel and also the hardware interface via DMA. + */ + +static int sep_map_and_alloc_shared_area(struct sep_device *sep, + unsigned long size) +{ + /* shared_addr = ioremap_nocache(0xda00000,shared_area_size); */ + sep->shared_addr = dma_alloc_coherent(&sep->pdev->dev, size, + &sep->shared_bus, GFP_KERNEL); + + if (!sep->shared_addr) { + edbg("sep_driver :shared memory dma_alloc_coherent failed\n"); + return -ENOMEM; + } + /* set the bus address of the shared area */ + edbg("sep: shared_addr %ld bytes @%p (bus %08llx)\n", + size, sep->shared_addr, (unsigned long long)sep->shared_bus); + return 0; +} + +/** + * sep_unmap_and_free_shared_area - free shared block + * @sep: security processor + * + * Free the shared area allocated to the security processor. The + * processor must have finished with this and any final posted + * writes cleared before we do so. + */ +static void sep_unmap_and_free_shared_area(struct sep_device *sep, int size) +{ + dma_free_coherent(&sep->pdev->dev, size, + sep->shared_addr, sep->shared_bus); +} + +/** + * sep_shared_virt_to_bus - convert bus/virt addresses + * + * Returns the bus address inside the shared area according + * to the virtual address. + */ + +static dma_addr_t sep_shared_virt_to_bus(struct sep_device *sep, + void *virt_address) +{ + dma_addr_t pa = sep->shared_bus + (virt_address - sep->shared_addr); + edbg("sep: virt to bus b %08llx v %p\n", (unsigned long long) pa, + virt_address); + return pa; +} + +/** + * sep_shared_bus_to_virt - convert bus/virt addresses + * + * Returns virtual address inside the shared area according + * to the bus address. + */ + +static void *sep_shared_bus_to_virt(struct sep_device *sep, + dma_addr_t bus_address) +{ + return sep->shared_addr + (bus_address - sep->shared_bus); +} + + +/** + * sep_try_open - attempt to open a SEP device + * @sep: device to attempt to open + * + * Atomically attempt to get ownership of a SEP device. + * Returns 1 if the device was opened, 0 on failure. + */ + +static int sep_try_open(struct sep_device *sep) +{ + if (!test_and_set_bit(0, &sep->in_use)) + return 1; + return 0; +} + +/** + * sep_open - device open method + * @inode: inode of sep device + * @filp: file handle to sep device + * + * Open method for the SEP device. Called when userspace opens + * the SEP device node. Must also release the memory data pool + * allocations. + * + * Returns zero on success otherwise an error code. + */ + +static int sep_open(struct inode *inode, struct file *filp) +{ + if (sep_dev == NULL) + return -ENODEV; + + /* check the blocking mode */ + if (filp->f_flags & O_NDELAY) { + if (sep_try_open(sep_dev) == 0) + return -EAGAIN; + } else + if (wait_event_interruptible(sep_event, sep_try_open(sep_dev)) < 0) + return -EINTR; + + /* Bind to the device, we only have one which makes it easy */ + filp->private_data = sep_dev; + /* release data pool allocations */ + sep_dev->data_pool_bytes_allocated = 0; + return 0; +} + + +/** + * sep_release - close a SEP device + * @inode: inode of SEP device + * @filp: file handle being closed + * + * Called on the final close of a SEP device. As the open protects against + * multiple simultaenous opens that means this method is called when the + * final reference to the open handle is dropped. + */ + +static int sep_release(struct inode *inode, struct file *filp) +{ + struct sep_device *sep = filp->private_data; +#if 0 /*!SEP_DRIVER_POLLING_MODE */ + /* close IMR */ + sep_write_reg(sep, HW_HOST_IMR_REG_ADDR, 0x7FFF); + /* release IRQ line */ + free_irq(SEP_DIRVER_IRQ_NUM, sep); + +#endif + /* Ensure any blocked open progresses */ + clear_bit(0, &sep->in_use); + wake_up(&sep_event); + return 0; +} + +/*--------------------------------------------------------------- + map function - this functions maps the message shared area +-----------------------------------------------------------------*/ +static int sep_mmap(struct file *filp, struct vm_area_struct *vma) +{ + dma_addr_t bus_addr; + struct sep_device *sep = filp->private_data; + + dbg("-------->SEP Driver: mmap start\n"); + + /* check that the size of the mapped range is as the size of the message + shared area */ + if ((vma->vm_end - vma->vm_start) > SEP_DRIVER_MMMAP_AREA_SIZE) { + edbg("SEP Driver mmap requested size is more than allowed\n"); + printk(KERN_WARNING "SEP Driver mmap requested size is more than allowed\n"); + printk(KERN_WARNING "SEP Driver vma->vm_end is %08lx\n", vma->vm_end); + printk(KERN_WARNING "SEP Driver vma->vm_end is %08lx\n", vma->vm_start); + return -EAGAIN; + } + + edbg("SEP Driver:sep->shared_addr is %p\n", sep->shared_addr); + + /* get bus address */ + bus_addr = sep->shared_bus; + + edbg("SEP Driver: phys_addr is %08llx\n", (unsigned long long)bus_addr); + + if (remap_pfn_range(vma, vma->vm_start, bus_addr >> PAGE_SHIFT, vma->vm_end - vma->vm_start, vma->vm_page_prot)) { + edbg("SEP Driver remap_page_range failed\n"); + printk(KERN_WARNING "SEP Driver remap_page_range failed\n"); + return -EAGAIN; + } + + dbg("SEP Driver:<-------- mmap end\n"); + + return 0; +} + + +/*----------------------------------------------- + poll function +*----------------------------------------------*/ +static unsigned int sep_poll(struct file *filp, poll_table * wait) +{ + unsigned long count; + unsigned int mask = 0; + unsigned long retval = 0; /* flow id */ + struct sep_device *sep = filp->private_data; + + dbg("---------->SEP Driver poll: start\n"); + + +#if SEP_DRIVER_POLLING_MODE + + while (sep->send_ct != (retval & 0x7FFFFFFF)) { + retval = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR2_REG_ADDR); + + for (count = 0; count < 10 * 4; count += 4) + edbg("Poll Debug Word %lu of the message is %lu\n", count, *((unsigned long *) (sep->shared_addr + SEP_DRIVER_MESSAGE_SHARED_AREA_SIZE_IN_BYTES + count))); + } + + sep->reply_ct++; +#else + /* add the event to the polling wait table */ + poll_wait(filp, &sep_event, wait); + +#endif + + edbg("sep->send_ct is %lu\n", sep->send_ct); + edbg("sep->reply_ct is %lu\n", sep->reply_ct); + + /* check if the data is ready */ + if (sep->send_ct == sep->reply_ct) { + for (count = 0; count < 12 * 4; count += 4) + edbg("Sep Mesg Word %lu of the message is %lu\n", count, *((unsigned long *) (sep->shared_addr + count))); + + for (count = 0; count < 10 * 4; count += 4) + edbg("Debug Data Word %lu of the message is %lu\n", count, *((unsigned long *) (sep->shared_addr + 0x1800 + count))); + + retval = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR2_REG_ADDR); + edbg("retval is %lu\n", retval); + /* check if the this is sep reply or request */ + if (retval >> 31) { + edbg("SEP Driver: sep request in\n"); + /* request */ + mask |= POLLOUT | POLLWRNORM; + } else { + edbg("SEP Driver: sep reply in\n"); + mask |= POLLIN | POLLRDNORM; + } + } + dbg("SEP Driver:<-------- poll exit\n"); + return mask; +} + +/** + * sep_time_address - address in SEP memory of time + * @sep: SEP device we want the address from + * + * Return the address of the two dwords in memory used for time + * setting. + */ + +static u32 *sep_time_address(struct sep_device *sep) +{ + return sep->shared_addr + SEP_DRIVER_SYSTEM_TIME_MEMORY_OFFSET_IN_BYTES; +} + +/** + * sep_set_time - set the SEP time + * @sep: the SEP we are setting the time for + * + * Calculates time and sets it at the predefined address. + * Called with the sep mutex held. + */ +static unsigned long sep_set_time(struct sep_device *sep) +{ + struct timeval time; + u32 *time_addr; /* address of time as seen by the kernel */ + + + dbg("sep:sep_set_time start\n"); + + do_gettimeofday(&time); + + /* set value in the SYSTEM MEMORY offset */ + time_addr = sep_time_address(sep); + + time_addr[0] = SEP_TIME_VAL_TOKEN; + time_addr[1] = time.tv_sec; + + edbg("SEP Driver:time.tv_sec is %lu\n", time.tv_sec); + edbg("SEP Driver:time_addr is %p\n", time_addr); + edbg("SEP Driver:sep->shared_addr is %p\n", sep->shared_addr); + + return time.tv_sec; +} + +/** + * sep_dump_message - dump the message that is pending + * @sep: sep device + * + * Dump out the message pending in the shared message area + */ + +static void sep_dump_message(struct sep_device *sep) +{ + int count; + for (count = 0; count < 12 * 4; count += 4) + edbg("Word %d of the message is %u\n", count, *((u32 *) (sep->shared_addr + count))); +} + +/** + * sep_send_command_handler - kick off a command + * @sep: sep being signalled + * + * This function raises interrupt to SEP that signals that is has a new + * command from the host + */ + +static void sep_send_command_handler(struct sep_device *sep) +{ + dbg("sep:sep_send_command_handler start\n"); + + mutex_lock(&sep_mutex); + sep_set_time(sep); + + /* FIXME: flush cache */ + flush_cache_all(); + + sep_dump_message(sep); + /* update counter */ + sep->send_ct++; + /* send interrupt to SEP */ + sep_write_reg(sep, HW_HOST_HOST_SEP_GPR0_REG_ADDR, 0x2); + dbg("SEP Driver:<-------- sep_send_command_handler end\n"); + mutex_unlock(&sep_mutex); + return; +} + +/** + * sep_send_reply_command_handler - kick off a command reply + * @sep: sep being signalled + * + * This function raises interrupt to SEP that signals that is has a new + * command from the host + */ + +static void sep_send_reply_command_handler(struct sep_device *sep) +{ + dbg("sep:sep_send_reply_command_handler start\n"); + + /* flash cache */ + flush_cache_all(); + + sep_dump_message(sep); + + mutex_lock(&sep_mutex); + sep->send_ct++; /* update counter */ + /* send the interrupt to SEP */ + sep_write_reg(sep, HW_HOST_HOST_SEP_GPR2_REG_ADDR, sep->send_ct); + /* update both counters */ + sep->send_ct++; + sep->reply_ct++; + mutex_unlock(&sep_mutex); + dbg("sep: sep_send_reply_command_handler end\n"); +} + +/* + This function handles the allocate data pool memory request + This function returns calculates the bus address of the + allocated memory, and the offset of this area from the mapped address. + Therefore, the FVOs in user space can calculate the exact virtual + address of this allocated memory +*/ +static int sep_allocate_data_pool_memory_handler(struct sep_device *sep, + unsigned long arg) +{ + int error; + struct sep_driver_alloc_t command_args; + + dbg("SEP Driver:--------> sep_allocate_data_pool_memory_handler start\n"); + + error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_alloc_t)); + if (error) { + error = -EFAULT; + goto end_function; + } + + /* allocate memory */ + if ((sep->data_pool_bytes_allocated + command_args.num_bytes) > SEP_DRIVER_DATA_POOL_SHARED_AREA_SIZE_IN_BYTES) { + error = -ENOMEM; + goto end_function; + } + + /* set the virtual and bus address */ + command_args.offset = SEP_DRIVER_DATA_POOL_AREA_OFFSET_IN_BYTES + sep->data_pool_bytes_allocated; + command_args.phys_address = sep->shared_bus + SEP_DRIVER_DATA_POOL_AREA_OFFSET_IN_BYTES + sep->data_pool_bytes_allocated; + + /* write the memory back to the user space */ + error = copy_to_user((void *) arg, (void *) &command_args, sizeof(struct sep_driver_alloc_t)); + if (error) { + error = -EFAULT; + goto end_function; + } + + /* set the allocation */ + sep->data_pool_bytes_allocated += command_args.num_bytes; + +end_function: + dbg("SEP Driver:<-------- sep_allocate_data_pool_memory_handler end\n"); + return error; +} + +/* + This function handles write into allocated data pool command +*/ +static int sep_write_into_data_pool_handler(struct sep_device *sep, unsigned long arg) +{ + int error; + void *virt_address; + unsigned long va; + unsigned long app_in_address; + unsigned long num_bytes; + void *data_pool_area_addr; + + dbg("SEP Driver:--------> sep_write_into_data_pool_handler start\n"); + + /* get the application address */ + error = get_user(app_in_address, &(((struct sep_driver_write_t *) arg)->app_address)); + if (error) + goto end_function; + + /* get the virtual kernel address address */ + error = get_user(va, &(((struct sep_driver_write_t *) arg)->datapool_address)); + if (error) + goto end_function; + virt_address = (void *)va; + + /* get the number of bytes */ + error = get_user(num_bytes, &(((struct sep_driver_write_t *) arg)->num_bytes)); + if (error) + goto end_function; + + /* calculate the start of the data pool */ + data_pool_area_addr = sep->shared_addr + SEP_DRIVER_DATA_POOL_AREA_OFFSET_IN_BYTES; + + + /* check that the range of the virtual kernel address is correct */ + if (virt_address < data_pool_area_addr || virt_address > (data_pool_area_addr + SEP_DRIVER_DATA_POOL_SHARED_AREA_SIZE_IN_BYTES)) { + error = -EINVAL; + goto end_function; + } + /* copy the application data */ + error = copy_from_user(virt_address, (void *) app_in_address, num_bytes); + if (error) + error = -EFAULT; +end_function: + dbg("SEP Driver:<-------- sep_write_into_data_pool_handler end\n"); + return error; +} + +/* + this function handles the read from data pool command +*/ +static int sep_read_from_data_pool_handler(struct sep_device *sep, unsigned long arg) +{ + int error; + /* virtual address of dest application buffer */ + unsigned long app_out_address; + /* virtual address of the data pool */ + unsigned long va; + void *virt_address; + unsigned long num_bytes; + void *data_pool_area_addr; + + dbg("SEP Driver:--------> sep_read_from_data_pool_handler start\n"); + + /* get the application address */ + error = get_user(app_out_address, &(((struct sep_driver_write_t *) arg)->app_address)); + if (error) + goto end_function; + + /* get the virtual kernel address address */ + error = get_user(va, &(((struct sep_driver_write_t *) arg)->datapool_address)); + if (error) + goto end_function; + virt_address = (void *)va; + + /* get the number of bytes */ + error = get_user(num_bytes, &(((struct sep_driver_write_t *) arg)->num_bytes)); + if (error) + goto end_function; + + /* calculate the start of the data pool */ + data_pool_area_addr = sep->shared_addr + SEP_DRIVER_DATA_POOL_AREA_OFFSET_IN_BYTES; + + /* FIXME: These are incomplete all over the driver: what about + len + and when doing that also overflows */ + /* check that the range of the virtual kernel address is correct */ + if (virt_address < data_pool_area_addr || virt_address > data_pool_area_addr + SEP_DRIVER_DATA_POOL_SHARED_AREA_SIZE_IN_BYTES) { + error = -EINVAL; + goto end_function; + } + + /* copy the application data */ + error = copy_to_user((void *) app_out_address, virt_address, num_bytes); + if (error) + error = -EFAULT; +end_function: + dbg("SEP Driver:<-------- sep_read_from_data_pool_handler end\n"); + return error; +} + +/* + This function releases all the application virtual buffer physical pages, + that were previously locked +*/ +static int sep_free_dma_pages(struct page **page_array_ptr, unsigned long num_pages, unsigned long dirtyFlag) +{ + unsigned long count; + + if (dirtyFlag) { + for (count = 0; count < num_pages; count++) { + /* the out array was written, therefore the data was changed */ + if (!PageReserved(page_array_ptr[count])) + SetPageDirty(page_array_ptr[count]); + page_cache_release(page_array_ptr[count]); + } + } else { + /* free in pages - the data was only read, therefore no update was done + on those pages */ + for (count = 0; count < num_pages; count++) + page_cache_release(page_array_ptr[count]); + } + + if (page_array_ptr) + /* free the array */ + kfree(page_array_ptr); + + return 0; +} + +/* + This function locks all the physical pages of the kernel virtual buffer + and construct a basic lli array, where each entry holds the physical + page address and the size that application data holds in this physical pages +*/ +static int sep_lock_kernel_pages(struct sep_device *sep, + unsigned long kernel_virt_addr, + unsigned long data_size, + unsigned long *num_pages_ptr, + struct sep_lli_entry_t **lli_array_ptr, + struct page ***page_array_ptr) +{ + int error = 0; + /* the the page of the end address of the user space buffer */ + unsigned long end_page; + /* the page of the start address of the user space buffer */ + unsigned long start_page; + /* the range in pages */ + unsigned long num_pages; + struct sep_lli_entry_t *lli_array; + /* next kernel address to map */ + unsigned long next_kernel_address; + unsigned long count; + + dbg("SEP Driver:--------> sep_lock_kernel_pages start\n"); + + /* set start and end pages and num pages */ + end_page = (kernel_virt_addr + data_size - 1) >> PAGE_SHIFT; + start_page = kernel_virt_addr >> PAGE_SHIFT; + num_pages = end_page - start_page + 1; + + edbg("SEP Driver: kernel_virt_addr is %08lx\n", kernel_virt_addr); + edbg("SEP Driver: data_size is %lu\n", data_size); + edbg("SEP Driver: start_page is %lx\n", start_page); + edbg("SEP Driver: end_page is %lx\n", end_page); + edbg("SEP Driver: num_pages is %lu\n", num_pages); + + lli_array = kmalloc(sizeof(struct sep_lli_entry_t) * num_pages, GFP_ATOMIC); + if (!lli_array) { + edbg("SEP Driver: kmalloc for lli_array failed\n"); + error = -ENOMEM; + goto end_function; + } + + /* set the start address of the first page - app data may start not at + the beginning of the page */ + lli_array[0].physical_address = (unsigned long) virt_to_phys((unsigned long *) kernel_virt_addr); + + /* check that not all the data is in the first page only */ + if ((PAGE_SIZE - (kernel_virt_addr & (~PAGE_MASK))) >= data_size) + lli_array[0].block_size = data_size; + else + lli_array[0].block_size = PAGE_SIZE - (kernel_virt_addr & (~PAGE_MASK)); + + /* debug print */ + dbg("lli_array[0].physical_address is %08lx, lli_array[0].block_size is %lu\n", lli_array[0].physical_address, lli_array[0].block_size); + + /* advance the address to the start of the next page */ + next_kernel_address = (kernel_virt_addr & PAGE_MASK) + PAGE_SIZE; + + /* go from the second page to the prev before last */ + for (count = 1; count < (num_pages - 1); count++) { + lli_array[count].physical_address = (unsigned long) virt_to_phys((unsigned long *) next_kernel_address); + lli_array[count].block_size = PAGE_SIZE; + + edbg("lli_array[%lu].physical_address is %08lx, lli_array[%lu].block_size is %lu\n", count, lli_array[count].physical_address, count, lli_array[count].block_size); + next_kernel_address += PAGE_SIZE; + } + + /* if more then 1 pages locked - then update for the last page size needed */ + if (num_pages > 1) { + /* update the address of the last page */ + lli_array[count].physical_address = (unsigned long) virt_to_phys((unsigned long *) next_kernel_address); + + /* set the size of the last page */ + lli_array[count].block_size = (kernel_virt_addr + data_size) & (~PAGE_MASK); + + if (lli_array[count].block_size == 0) { + dbg("app_virt_addr is %08lx\n", kernel_virt_addr); + dbg("data_size is %lu\n", data_size); + while (1); + } + + edbg("lli_array[%lu].physical_address is %08lx, lli_array[%lu].block_size is %lu\n", count, lli_array[count].physical_address, count, lli_array[count].block_size); + } + /* set output params */ + *lli_array_ptr = lli_array; + *num_pages_ptr = num_pages; + *page_array_ptr = 0; +end_function: + dbg("SEP Driver:<-------- sep_lock_kernel_pages end\n"); + return 0; +} + +/* + This function locks all the physical pages of the application virtual buffer + and construct a basic lli array, where each entry holds the physical page + address and the size that application data holds in this physical pages +*/ +static int sep_lock_user_pages(struct sep_device *sep, + unsigned long app_virt_addr, + unsigned long data_size, + unsigned long *num_pages_ptr, + struct sep_lli_entry_t **lli_array_ptr, + struct page ***page_array_ptr) +{ + int error = 0; + /* the the page of the end address of the user space buffer */ + unsigned long end_page; + /* the page of the start address of the user space buffer */ + unsigned long start_page; + /* the range in pages */ + unsigned long num_pages; + struct page **page_array; + struct sep_lli_entry_t *lli_array; + unsigned long count; + int result; + + dbg("SEP Driver:--------> sep_lock_user_pages start\n"); + + /* set start and end pages and num pages */ + end_page = (app_virt_addr + data_size - 1) >> PAGE_SHIFT; + start_page = app_virt_addr >> PAGE_SHIFT; + num_pages = end_page - start_page + 1; + + edbg("SEP Driver: app_virt_addr is %08lx\n", app_virt_addr); + edbg("SEP Driver: data_size is %lu\n", data_size); + edbg("SEP Driver: start_page is %lu\n", start_page); + edbg("SEP Driver: end_page is %lu\n", end_page); + edbg("SEP Driver: num_pages is %lu\n", num_pages); + + /* allocate array of pages structure pointers */ + page_array = kmalloc(sizeof(struct page *) * num_pages, GFP_ATOMIC); + if (!page_array) { + edbg("SEP Driver: kmalloc for page_array failed\n"); + + error = -ENOMEM; + goto end_function; + } + + lli_array = kmalloc(sizeof(struct sep_lli_entry_t) * num_pages, GFP_ATOMIC); + if (!lli_array) { + edbg("SEP Driver: kmalloc for lli_array failed\n"); + + error = -ENOMEM; + goto end_function_with_error1; + } + + /* convert the application virtual address into a set of physical */ + down_read(¤t->mm->mmap_sem); + result = get_user_pages(current, current->mm, app_virt_addr, num_pages, 1, 0, page_array, 0); + up_read(¤t->mm->mmap_sem); + + /* check the number of pages locked - if not all then exit with error */ + if (result != num_pages) { + dbg("SEP Driver: not all pages locked by get_user_pages\n"); + + error = -ENOMEM; + goto end_function_with_error2; + } + + /* flush the cache */ + for (count = 0; count < num_pages; count++) + flush_dcache_page(page_array[count]); + + /* set the start address of the first page - app data may start not at + the beginning of the page */ + lli_array[0].physical_address = ((unsigned long) page_to_phys(page_array[0])) + (app_virt_addr & (~PAGE_MASK)); + + /* check that not all the data is in the first page only */ + if ((PAGE_SIZE - (app_virt_addr & (~PAGE_MASK))) >= data_size) + lli_array[0].block_size = data_size; + else + lli_array[0].block_size = PAGE_SIZE - (app_virt_addr & (~PAGE_MASK)); + + /* debug print */ + dbg("lli_array[0].physical_address is %08lx, lli_array[0].block_size is %lu\n", lli_array[0].physical_address, lli_array[0].block_size); + + /* go from the second page to the prev before last */ + for (count = 1; count < (num_pages - 1); count++) { + lli_array[count].physical_address = (unsigned long) page_to_phys(page_array[count]); + lli_array[count].block_size = PAGE_SIZE; + + edbg("lli_array[%lu].physical_address is %08lx, lli_array[%lu].block_size is %lu\n", count, lli_array[count].physical_address, count, lli_array[count].block_size); + } + + /* if more then 1 pages locked - then update for the last page size needed */ + if (num_pages > 1) { + /* update the address of the last page */ + lli_array[count].physical_address = (unsigned long) page_to_phys(page_array[count]); + + /* set the size of the last page */ + lli_array[count].block_size = (app_virt_addr + data_size) & (~PAGE_MASK); + + if (lli_array[count].block_size == 0) { + dbg("app_virt_addr is %08lx\n", app_virt_addr); + dbg("data_size is %lu\n", data_size); + while (1); + } + edbg("lli_array[%lu].physical_address is %08lx, lli_array[%lu].block_size is %lu\n", + count, lli_array[count].physical_address, + count, lli_array[count].block_size); + } + + /* set output params */ + *lli_array_ptr = lli_array; + *num_pages_ptr = num_pages; + *page_array_ptr = page_array; + goto end_function; + +end_function_with_error2: + /* release the cache */ + for (count = 0; count < num_pages; count++) + page_cache_release(page_array[count]); + kfree(lli_array); +end_function_with_error1: + kfree(page_array); +end_function: + dbg("SEP Driver:<-------- sep_lock_user_pages end\n"); + return 0; +} + + +/* + this function calculates the size of data that can be inserted into the lli + table from this array the condition is that either the table is full + (all etnries are entered), or there are no more entries in the lli array +*/ +static unsigned long sep_calculate_lli_table_max_size(struct sep_lli_entry_t *lli_in_array_ptr, unsigned long num_array_entries) +{ + unsigned long table_data_size = 0; + unsigned long counter; + + /* calculate the data in the out lli table if till we fill the whole + table or till the data has ended */ + for (counter = 0; (counter < (SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP - 1)) && (counter < num_array_entries); counter++) + table_data_size += lli_in_array_ptr[counter].block_size; + return table_data_size; +} + +/* + this functions builds ont lli table from the lli_array according to + the given size of data +*/ +static void sep_build_lli_table(struct sep_lli_entry_t *lli_array_ptr, struct sep_lli_entry_t *lli_table_ptr, unsigned long *num_processed_entries_ptr, unsigned long *num_table_entries_ptr, unsigned long table_data_size) +{ + unsigned long curr_table_data_size; + /* counter of lli array entry */ + unsigned long array_counter; + + dbg("SEP Driver:--------> sep_build_lli_table start\n"); + + /* init currrent table data size and lli array entry counter */ + curr_table_data_size = 0; + array_counter = 0; + *num_table_entries_ptr = 1; + + edbg("SEP Driver:table_data_size is %lu\n", table_data_size); + + /* fill the table till table size reaches the needed amount */ + while (curr_table_data_size < table_data_size) { + /* update the number of entries in table */ + (*num_table_entries_ptr)++; + + lli_table_ptr->physical_address = lli_array_ptr[array_counter].physical_address; + lli_table_ptr->block_size = lli_array_ptr[array_counter].block_size; + curr_table_data_size += lli_table_ptr->block_size; + + edbg("SEP Driver:lli_table_ptr is %08lx\n", (unsigned long) lli_table_ptr); + edbg("SEP Driver:lli_table_ptr->physical_address is %08lx\n", lli_table_ptr->physical_address); + edbg("SEP Driver:lli_table_ptr->block_size is %lu\n", lli_table_ptr->block_size); + + /* check for overflow of the table data */ + if (curr_table_data_size > table_data_size) { + edbg("SEP Driver:curr_table_data_size > table_data_size\n"); + + /* update the size of block in the table */ + lli_table_ptr->block_size -= (curr_table_data_size - table_data_size); + + /* update the physical address in the lli array */ + lli_array_ptr[array_counter].physical_address += lli_table_ptr->block_size; + + /* update the block size left in the lli array */ + lli_array_ptr[array_counter].block_size = (curr_table_data_size - table_data_size); + } else + /* advance to the next entry in the lli_array */ + array_counter++; + + edbg("SEP Driver:lli_table_ptr->physical_address is %08lx\n", lli_table_ptr->physical_address); + edbg("SEP Driver:lli_table_ptr->block_size is %lu\n", lli_table_ptr->block_size); + + /* move to the next entry in table */ + lli_table_ptr++; + } + + /* set the info entry to default */ + lli_table_ptr->physical_address = 0xffffffff; + lli_table_ptr->block_size = 0; + + edbg("SEP Driver:lli_table_ptr is %08lx\n", (unsigned long) lli_table_ptr); + edbg("SEP Driver:lli_table_ptr->physical_address is %08lx\n", lli_table_ptr->physical_address); + edbg("SEP Driver:lli_table_ptr->block_size is %lu\n", lli_table_ptr->block_size); + + /* set the output parameter */ + *num_processed_entries_ptr += array_counter; + + edbg("SEP Driver:*num_processed_entries_ptr is %lu\n", *num_processed_entries_ptr); + dbg("SEP Driver:<-------- sep_build_lli_table end\n"); + return; +} + +/* + this function goes over the list of the print created tables and + prints all the data +*/ +static void sep_debug_print_lli_tables(struct sep_device *sep, struct sep_lli_entry_t *lli_table_ptr, unsigned long num_table_entries, unsigned long table_data_size) +{ + unsigned long table_count; + unsigned long entries_count; + + dbg("SEP Driver:--------> sep_debug_print_lli_tables start\n"); + + table_count = 1; + while ((unsigned long) lli_table_ptr != 0xffffffff) { + edbg("SEP Driver: lli table %08lx, table_data_size is %lu\n", table_count, table_data_size); + edbg("SEP Driver: num_table_entries is %lu\n", num_table_entries); + + /* print entries of the table (without info entry) */ + for (entries_count = 0; entries_count < num_table_entries; entries_count++, lli_table_ptr++) { + edbg("SEP Driver:lli_table_ptr address is %08lx\n", (unsigned long) lli_table_ptr); + edbg("SEP Driver:phys address is %08lx block size is %lu\n", lli_table_ptr->physical_address, lli_table_ptr->block_size); + } + + /* point to the info entry */ + lli_table_ptr--; + + edbg("SEP Driver:phys lli_table_ptr->block_size is %lu\n", lli_table_ptr->block_size); + edbg("SEP Driver:phys lli_table_ptr->physical_address is %08lx\n", lli_table_ptr->physical_address); + + + table_data_size = lli_table_ptr->block_size & 0xffffff; + num_table_entries = (lli_table_ptr->block_size >> 24) & 0xff; + lli_table_ptr = (struct sep_lli_entry_t *) + (lli_table_ptr->physical_address); + + edbg("SEP Driver:phys table_data_size is %lu num_table_entries is %lu lli_table_ptr is%lu\n", table_data_size, num_table_entries, (unsigned long) lli_table_ptr); + + if ((unsigned long) lli_table_ptr != 0xffffffff) + lli_table_ptr = (struct sep_lli_entry_t *) sep_shared_bus_to_virt(sep, (unsigned long) lli_table_ptr); + + table_count++; + } + dbg("SEP Driver:<-------- sep_debug_print_lli_tables end\n"); +} + + +/* + This function prepares only input DMA table for synhronic symmetric + operations (HASH) +*/ +static int sep_prepare_input_dma_table(struct sep_device *sep, + unsigned long app_virt_addr, + unsigned long data_size, + unsigned long block_size, + unsigned long *lli_table_ptr, + unsigned long *num_entries_ptr, + unsigned long *table_data_size_ptr, + bool isKernelVirtualAddress) +{ + /* pointer to the info entry of the table - the last entry */ + struct sep_lli_entry_t *info_entry_ptr; + /* array of pointers ot page */ + struct sep_lli_entry_t *lli_array_ptr; + /* points to the first entry to be processed in the lli_in_array */ + unsigned long current_entry; + /* num entries in the virtual buffer */ + unsigned long sep_lli_entries; + /* lli table pointer */ + struct sep_lli_entry_t *in_lli_table_ptr; + /* the total data in one table */ + unsigned long table_data_size; + /* number of entries in lli table */ + unsigned long num_entries_in_table; + /* next table address */ + void *lli_table_alloc_addr; + unsigned long result; + + dbg("SEP Driver:--------> sep_prepare_input_dma_table start\n"); + + edbg("SEP Driver:data_size is %lu\n", data_size); + edbg("SEP Driver:block_size is %lu\n", block_size); + + /* initialize the pages pointers */ + sep->in_page_array = 0; + sep->in_num_pages = 0; + + if (data_size == 0) { + /* special case - created 2 entries table with zero data */ + in_lli_table_ptr = (struct sep_lli_entry_t *) (sep->shared_addr + SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_OFFSET_IN_BYTES); + /* FIXME: Should the entry below not be for _bus */ + in_lli_table_ptr->physical_address = (unsigned long)sep->shared_addr + SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_OFFSET_IN_BYTES; + in_lli_table_ptr->block_size = 0; + + in_lli_table_ptr++; + in_lli_table_ptr->physical_address = 0xFFFFFFFF; + in_lli_table_ptr->block_size = 0; + + *lli_table_ptr = sep->shared_bus + SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_OFFSET_IN_BYTES; + *num_entries_ptr = 2; + *table_data_size_ptr = 0; + + goto end_function; + } + + /* check if the pages are in Kernel Virtual Address layout */ + if (isKernelVirtualAddress == true) + /* lock the pages of the kernel buffer and translate them to pages */ + result = sep_lock_kernel_pages(sep, app_virt_addr, data_size, &sep->in_num_pages, &lli_array_ptr, &sep->in_page_array); + else + /* lock the pages of the user buffer and translate them to pages */ + result = sep_lock_user_pages(sep, app_virt_addr, data_size, &sep->in_num_pages, &lli_array_ptr, &sep->in_page_array); + + if (result) + return result; + + edbg("SEP Driver:output sep->in_num_pages is %lu\n", sep->in_num_pages); + + current_entry = 0; + info_entry_ptr = 0; + sep_lli_entries = sep->in_num_pages; + + /* initiate to point after the message area */ + lli_table_alloc_addr = sep->shared_addr + SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_OFFSET_IN_BYTES; + + /* loop till all the entries in in array are not processed */ + while (current_entry < sep_lli_entries) { + /* set the new input and output tables */ + in_lli_table_ptr = (struct sep_lli_entry_t *) lli_table_alloc_addr; + + lli_table_alloc_addr += sizeof(struct sep_lli_entry_t) * SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP; + + /* calculate the maximum size of data for input table */ + table_data_size = sep_calculate_lli_table_max_size(&lli_array_ptr[current_entry], (sep_lli_entries - current_entry)); + + /* now calculate the table size so that it will be module block size */ + table_data_size = (table_data_size / block_size) * block_size; + + edbg("SEP Driver:output table_data_size is %lu\n", table_data_size); + + /* construct input lli table */ + sep_build_lli_table(&lli_array_ptr[current_entry], in_lli_table_ptr, ¤t_entry, &num_entries_in_table, table_data_size); + + if (info_entry_ptr == 0) { + /* set the output parameters to physical addresses */ + *lli_table_ptr = sep_shared_virt_to_bus(sep, in_lli_table_ptr); + *num_entries_ptr = num_entries_in_table; + *table_data_size_ptr = table_data_size; + + edbg("SEP Driver:output lli_table_in_ptr is %08lx\n", *lli_table_ptr); + } else { + /* update the info entry of the previous in table */ + info_entry_ptr->physical_address = sep_shared_virt_to_bus(sep, in_lli_table_ptr); + info_entry_ptr->block_size = ((num_entries_in_table) << 24) | (table_data_size); + } + + /* save the pointer to the info entry of the current tables */ + info_entry_ptr = in_lli_table_ptr + num_entries_in_table - 1; + } + + /* print input tables */ + sep_debug_print_lli_tables(sep, (struct sep_lli_entry_t *) + sep_shared_bus_to_virt(sep, *lli_table_ptr), *num_entries_ptr, *table_data_size_ptr); + + /* the array of the pages */ + kfree(lli_array_ptr); +end_function: + dbg("SEP Driver:<-------- sep_prepare_input_dma_table end\n"); + return 0; + +} + +/* + This function creates the input and output dma tables for + symmetric operations (AES/DES) according to the block size from LLI arays +*/ +static int sep_construct_dma_tables_from_lli(struct sep_device *sep, + struct sep_lli_entry_t *lli_in_array, + unsigned long sep_in_lli_entries, + struct sep_lli_entry_t *lli_out_array, + unsigned long sep_out_lli_entries, + unsigned long block_size, unsigned long *lli_table_in_ptr, unsigned long *lli_table_out_ptr, unsigned long *in_num_entries_ptr, unsigned long *out_num_entries_ptr, unsigned long *table_data_size_ptr) +{ + /* points to the area where next lli table can be allocated: keep void * + as there is pointer scaling to fix otherwise */ + void *lli_table_alloc_addr; + /* input lli table */ + struct sep_lli_entry_t *in_lli_table_ptr; + /* output lli table */ + struct sep_lli_entry_t *out_lli_table_ptr; + /* pointer to the info entry of the table - the last entry */ + struct sep_lli_entry_t *info_in_entry_ptr; + /* pointer to the info entry of the table - the last entry */ + struct sep_lli_entry_t *info_out_entry_ptr; + /* points to the first entry to be processed in the lli_in_array */ + unsigned long current_in_entry; + /* points to the first entry to be processed in the lli_out_array */ + unsigned long current_out_entry; + /* max size of the input table */ + unsigned long in_table_data_size; + /* max size of the output table */ + unsigned long out_table_data_size; + /* flag te signifies if this is the first tables build from the arrays */ + unsigned long first_table_flag; + /* the data size that should be in table */ + unsigned long table_data_size; + /* number of etnries in the input table */ + unsigned long num_entries_in_table; + /* number of etnries in the output table */ + unsigned long num_entries_out_table; + + dbg("SEP Driver:--------> sep_construct_dma_tables_from_lli start\n"); + + /* initiate to pint after the message area */ + lli_table_alloc_addr = sep->shared_addr + SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_OFFSET_IN_BYTES; + + current_in_entry = 0; + current_out_entry = 0; + first_table_flag = 1; + info_in_entry_ptr = 0; + info_out_entry_ptr = 0; + + /* loop till all the entries in in array are not processed */ + while (current_in_entry < sep_in_lli_entries) { + /* set the new input and output tables */ + in_lli_table_ptr = (struct sep_lli_entry_t *) lli_table_alloc_addr; + + lli_table_alloc_addr += sizeof(struct sep_lli_entry_t) * SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP; + + /* set the first output tables */ + out_lli_table_ptr = (struct sep_lli_entry_t *) lli_table_alloc_addr; + + lli_table_alloc_addr += sizeof(struct sep_lli_entry_t) * SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP; + + /* calculate the maximum size of data for input table */ + in_table_data_size = sep_calculate_lli_table_max_size(&lli_in_array[current_in_entry], (sep_in_lli_entries - current_in_entry)); + + /* calculate the maximum size of data for output table */ + out_table_data_size = sep_calculate_lli_table_max_size(&lli_out_array[current_out_entry], (sep_out_lli_entries - current_out_entry)); + + edbg("SEP Driver:in_table_data_size is %lu\n", in_table_data_size); + edbg("SEP Driver:out_table_data_size is %lu\n", out_table_data_size); + + /* check where the data is smallest */ + table_data_size = in_table_data_size; + if (table_data_size > out_table_data_size) + table_data_size = out_table_data_size; + + /* now calculate the table size so that it will be module block size */ + table_data_size = (table_data_size / block_size) * block_size; + + dbg("SEP Driver:table_data_size is %lu\n", table_data_size); + + /* construct input lli table */ + sep_build_lli_table(&lli_in_array[current_in_entry], in_lli_table_ptr, ¤t_in_entry, &num_entries_in_table, table_data_size); + + /* construct output lli table */ + sep_build_lli_table(&lli_out_array[current_out_entry], out_lli_table_ptr, ¤t_out_entry, &num_entries_out_table, table_data_size); + + /* if info entry is null - this is the first table built */ + if (info_in_entry_ptr == 0) { + /* set the output parameters to physical addresses */ + *lli_table_in_ptr = sep_shared_virt_to_bus(sep, in_lli_table_ptr); + *in_num_entries_ptr = num_entries_in_table; + *lli_table_out_ptr = sep_shared_virt_to_bus(sep, out_lli_table_ptr); + *out_num_entries_ptr = num_entries_out_table; + *table_data_size_ptr = table_data_size; + + edbg("SEP Driver:output lli_table_in_ptr is %08lx\n", *lli_table_in_ptr); + edbg("SEP Driver:output lli_table_out_ptr is %08lx\n", *lli_table_out_ptr); + } else { + /* update the info entry of the previous in table */ + info_in_entry_ptr->physical_address = sep_shared_virt_to_bus(sep, in_lli_table_ptr); + info_in_entry_ptr->block_size = ((num_entries_in_table) << 24) | (table_data_size); + + /* update the info entry of the previous in table */ + info_out_entry_ptr->physical_address = sep_shared_virt_to_bus(sep, out_lli_table_ptr); + info_out_entry_ptr->block_size = ((num_entries_out_table) << 24) | (table_data_size); + } + + /* save the pointer to the info entry of the current tables */ + info_in_entry_ptr = in_lli_table_ptr + num_entries_in_table - 1; + info_out_entry_ptr = out_lli_table_ptr + num_entries_out_table - 1; + + edbg("SEP Driver:output num_entries_out_table is %lu\n", (unsigned long) num_entries_out_table); + edbg("SEP Driver:output info_in_entry_ptr is %lu\n", (unsigned long) info_in_entry_ptr); + edbg("SEP Driver:output info_out_entry_ptr is %lu\n", (unsigned long) info_out_entry_ptr); + } + + /* print input tables */ + sep_debug_print_lli_tables(sep, (struct sep_lli_entry_t *) + sep_shared_bus_to_virt(sep, *lli_table_in_ptr), *in_num_entries_ptr, *table_data_size_ptr); + /* print output tables */ + sep_debug_print_lli_tables(sep, (struct sep_lli_entry_t *) + sep_shared_bus_to_virt(sep, *lli_table_out_ptr), *out_num_entries_ptr, *table_data_size_ptr); + dbg("SEP Driver:<-------- sep_construct_dma_tables_from_lli end\n"); + return 0; +} + + +/* + This function builds input and output DMA tables for synhronic + symmetric operations (AES, DES). It also checks that each table + is of the modular block size +*/ +static int sep_prepare_input_output_dma_table(struct sep_device *sep, + unsigned long app_virt_in_addr, + unsigned long app_virt_out_addr, + unsigned long data_size, + unsigned long block_size, + unsigned long *lli_table_in_ptr, unsigned long *lli_table_out_ptr, unsigned long *in_num_entries_ptr, unsigned long *out_num_entries_ptr, unsigned long *table_data_size_ptr, bool isKernelVirtualAddress) +{ + /* array of pointers of page */ + struct sep_lli_entry_t *lli_in_array; + /* array of pointers of page */ + struct sep_lli_entry_t *lli_out_array; + int result = 0; + + dbg("SEP Driver:--------> sep_prepare_input_output_dma_table start\n"); + + /* initialize the pages pointers */ + sep->in_page_array = 0; + sep->out_page_array = 0; + + /* check if the pages are in Kernel Virtual Address layout */ + if (isKernelVirtualAddress == true) { + /* lock the pages of the kernel buffer and translate them to pages */ + result = sep_lock_kernel_pages(sep, app_virt_in_addr, data_size, &sep->in_num_pages, &lli_in_array, &sep->in_page_array); + if (result) { + edbg("SEP Driver: sep_lock_kernel_pages for input virtual buffer failed\n"); + goto end_function; + } + } else { + /* lock the pages of the user buffer and translate them to pages */ + result = sep_lock_user_pages(sep, app_virt_in_addr, data_size, &sep->in_num_pages, &lli_in_array, &sep->in_page_array); + if (result) { + edbg("SEP Driver: sep_lock_user_pages for input virtual buffer failed\n"); + goto end_function; + } + } + + if (isKernelVirtualAddress == true) { + result = sep_lock_kernel_pages(sep, app_virt_out_addr, data_size, &sep->out_num_pages, &lli_out_array, &sep->out_page_array); + if (result) { + edbg("SEP Driver: sep_lock_kernel_pages for output virtual buffer failed\n"); + goto end_function_with_error1; + } + } else { + result = sep_lock_user_pages(sep, app_virt_out_addr, data_size, &sep->out_num_pages, &lli_out_array, &sep->out_page_array); + if (result) { + edbg("SEP Driver: sep_lock_user_pages for output virtual buffer failed\n"); + goto end_function_with_error1; + } + } + edbg("sep->in_num_pages is %lu\n", sep->in_num_pages); + edbg("sep->out_num_pages is %lu\n", sep->out_num_pages); + edbg("SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP is %x\n", SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP); + + + /* call the fucntion that creates table from the lli arrays */ + result = sep_construct_dma_tables_from_lli(sep, lli_in_array, sep->in_num_pages, lli_out_array, sep->out_num_pages, block_size, lli_table_in_ptr, lli_table_out_ptr, in_num_entries_ptr, out_num_entries_ptr, table_data_size_ptr); + if (result) { + edbg("SEP Driver: sep_construct_dma_tables_from_lli failed\n"); + goto end_function_with_error2; + } + + /* fall through - free the lli entry arrays */ + dbg("in_num_entries_ptr is %08lx\n", *in_num_entries_ptr); + dbg("out_num_entries_ptr is %08lx\n", *out_num_entries_ptr); + dbg("table_data_size_ptr is %08lx\n", *table_data_size_ptr); +end_function_with_error2: + kfree(lli_out_array); +end_function_with_error1: + kfree(lli_in_array); +end_function: + dbg("SEP Driver:<-------- sep_prepare_input_output_dma_table end result = %d\n", (int) result); + return result; + +} + +/* + this function handles tha request for creation of the DMA table + for the synchronic symmetric operations (AES,DES) +*/ +static int sep_create_sync_dma_tables_handler(struct sep_device *sep, + unsigned long arg) +{ + int error; + /* command arguments */ + struct sep_driver_build_sync_table_t command_args; + + dbg("SEP Driver:--------> sep_create_sync_dma_tables_handler start\n"); + + error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_build_sync_table_t)); + if (error) { + error = -EFAULT; + goto end_function; + } + + edbg("app_in_address is %08lx\n", command_args.app_in_address); + edbg("app_out_address is %08lx\n", command_args.app_out_address); + edbg("data_size is %lu\n", command_args.data_in_size); + edbg("block_size is %lu\n", command_args.block_size); + + /* check if we need to build only input table or input/output */ + if (command_args.app_out_address) + /* prepare input and output tables */ + error = sep_prepare_input_output_dma_table(sep, + command_args.app_in_address, + command_args.app_out_address, + command_args.data_in_size, + command_args.block_size, + &command_args.in_table_address, + &command_args.out_table_address, &command_args.in_table_num_entries, &command_args.out_table_num_entries, &command_args.table_data_size, command_args.isKernelVirtualAddress); + else + /* prepare input tables */ + error = sep_prepare_input_dma_table(sep, + command_args.app_in_address, + command_args.data_in_size, command_args.block_size, &command_args.in_table_address, &command_args.in_table_num_entries, &command_args.table_data_size, command_args.isKernelVirtualAddress); + + if (error) + goto end_function; + /* copy to user */ + if (copy_to_user((void *) arg, (void *) &command_args, sizeof(struct sep_driver_build_sync_table_t))) + error = -EFAULT; +end_function: + dbg("SEP Driver:<-------- sep_create_sync_dma_tables_handler end\n"); + return error; +} + +/* + this function handles the request for freeing dma table for synhronic actions +*/ +static int sep_free_dma_table_data_handler(struct sep_device *sep) +{ + dbg("SEP Driver:--------> sep_free_dma_table_data_handler start\n"); + + /* free input pages array */ + sep_free_dma_pages(sep->in_page_array, sep->in_num_pages, 0); + + /* free output pages array if needed */ + if (sep->out_page_array) + sep_free_dma_pages(sep->out_page_array, sep->out_num_pages, 1); + + /* reset all the values */ + sep->in_page_array = 0; + sep->out_page_array = 0; + sep->in_num_pages = 0; + sep->out_num_pages = 0; + dbg("SEP Driver:<-------- sep_free_dma_table_data_handler end\n"); + return 0; +} + +/* + this function find a space for the new flow dma table +*/ +static int sep_find_free_flow_dma_table_space(struct sep_device *sep, + unsigned long **table_address_ptr) +{ + int error = 0; + /* pointer to the id field of the flow dma table */ + unsigned long *start_table_ptr; + /* Do not make start_addr unsigned long * unless fixing the offset + computations ! */ + void *flow_dma_area_start_addr; + unsigned long *flow_dma_area_end_addr; + /* maximum table size in words */ + unsigned long table_size_in_words; + + /* find the start address of the flow DMA table area */ + flow_dma_area_start_addr = sep->shared_addr + SEP_DRIVER_FLOW_DMA_TABLES_AREA_OFFSET_IN_BYTES; + + /* set end address of the flow table area */ + flow_dma_area_end_addr = flow_dma_area_start_addr + SEP_DRIVER_FLOW_DMA_TABLES_AREA_SIZE_IN_BYTES; + + /* set table size in words */ + table_size_in_words = SEP_DRIVER_MAX_FLOW_NUM_ENTRIES_IN_TABLE * (sizeof(struct sep_lli_entry_t) / sizeof(long)) + 2; + + /* set the pointer to the start address of DMA area */ + start_table_ptr = flow_dma_area_start_addr; + + /* find the space for the next table */ + while (((*start_table_ptr & 0x7FFFFFFF) != 0) && start_table_ptr < flow_dma_area_end_addr) + start_table_ptr += table_size_in_words; + + /* check if we reached the end of floa tables area */ + if (start_table_ptr >= flow_dma_area_end_addr) + error = -1; + else + *table_address_ptr = start_table_ptr; + + return error; +} + +/* + This function creates one DMA table for flow and returns its data, + and pointer to its info entry +*/ +static int sep_prepare_one_flow_dma_table(struct sep_device *sep, + unsigned long virt_buff_addr, + unsigned long virt_buff_size, + struct sep_lli_entry_t *table_data, + struct sep_lli_entry_t **info_entry_ptr, + struct sep_flow_context_t *flow_data_ptr, + bool isKernelVirtualAddress) +{ + int error; + /* the range in pages */ + unsigned long lli_array_size; + struct sep_lli_entry_t *lli_array; + struct sep_lli_entry_t *flow_dma_table_entry_ptr; + unsigned long *start_dma_table_ptr; + /* total table data counter */ + unsigned long dma_table_data_count; + /* pointer that will keep the pointer to the pages of the virtual buffer */ + struct page **page_array_ptr; + unsigned long entry_count; + + /* find the space for the new table */ + error = sep_find_free_flow_dma_table_space(sep, &start_dma_table_ptr); + if (error) + goto end_function; + + /* check if the pages are in Kernel Virtual Address layout */ + if (isKernelVirtualAddress == true) + /* lock kernel buffer in the memory */ + error = sep_lock_kernel_pages(sep, virt_buff_addr, virt_buff_size, &lli_array_size, &lli_array, &page_array_ptr); + else + /* lock user buffer in the memory */ + error = sep_lock_user_pages(sep, virt_buff_addr, virt_buff_size, &lli_array_size, &lli_array, &page_array_ptr); + + if (error) + goto end_function; + + /* set the pointer to page array at the beginning of table - this table is + now considered taken */ + *start_dma_table_ptr = lli_array_size; + + /* point to the place of the pages pointers of the table */ + start_dma_table_ptr++; + + /* set the pages pointer */ + *start_dma_table_ptr = (unsigned long) page_array_ptr; + + /* set the pointer to the first entry */ + flow_dma_table_entry_ptr = (struct sep_lli_entry_t *) (++start_dma_table_ptr); + + /* now create the entries for table */ + for (dma_table_data_count = entry_count = 0; entry_count < lli_array_size; entry_count++) { + flow_dma_table_entry_ptr->physical_address = lli_array[entry_count].physical_address; + + flow_dma_table_entry_ptr->block_size = lli_array[entry_count].block_size; + + /* set the total data of a table */ + dma_table_data_count += lli_array[entry_count].block_size; + + flow_dma_table_entry_ptr++; + } + + /* set the physical address */ + table_data->physical_address = virt_to_phys(start_dma_table_ptr); + + /* set the num_entries and total data size */ + table_data->block_size = ((lli_array_size + 1) << SEP_NUM_ENTRIES_OFFSET_IN_BITS) | (dma_table_data_count); + + /* set the info entry */ + flow_dma_table_entry_ptr->physical_address = 0xffffffff; + flow_dma_table_entry_ptr->block_size = 0; + + /* set the pointer to info entry */ + *info_entry_ptr = flow_dma_table_entry_ptr; + + /* the array of the lli entries */ + kfree(lli_array); +end_function: + return error; +} + + + +/* + This function creates a list of tables for flow and returns the data for + the first and last tables of the list +*/ +static int sep_prepare_flow_dma_tables(struct sep_device *sep, + unsigned long num_virtual_buffers, + unsigned long first_buff_addr, struct sep_flow_context_t *flow_data_ptr, struct sep_lli_entry_t *first_table_data_ptr, struct sep_lli_entry_t *last_table_data_ptr, bool isKernelVirtualAddress) +{ + int error; + unsigned long virt_buff_addr; + unsigned long virt_buff_size; + struct sep_lli_entry_t table_data; + struct sep_lli_entry_t *info_entry_ptr; + struct sep_lli_entry_t *prev_info_entry_ptr; + unsigned long i; + + /* init vars */ + error = 0; + prev_info_entry_ptr = 0; + + /* init the first table to default */ + table_data.physical_address = 0xffffffff; + first_table_data_ptr->physical_address = 0xffffffff; + table_data.block_size = 0; + + for (i = 0; i < num_virtual_buffers; i++) { + /* get the virtual buffer address */ + error = get_user(virt_buff_addr, &first_buff_addr); + if (error) + goto end_function; + + /* get the virtual buffer size */ + first_buff_addr++; + error = get_user(virt_buff_size, &first_buff_addr); + if (error) + goto end_function; + + /* advance the address to point to the next pair of address|size */ + first_buff_addr++; + + /* now prepare the one flow LLI table from the data */ + error = sep_prepare_one_flow_dma_table(sep, virt_buff_addr, virt_buff_size, &table_data, &info_entry_ptr, flow_data_ptr, isKernelVirtualAddress); + if (error) + goto end_function; + + if (i == 0) { + /* if this is the first table - save it to return to the user + application */ + *first_table_data_ptr = table_data; + + /* set the pointer to info entry */ + prev_info_entry_ptr = info_entry_ptr; + } else { + /* not first table - the previous table info entry should + be updated */ + prev_info_entry_ptr->block_size = (0x1 << SEP_INT_FLAG_OFFSET_IN_BITS) | (table_data.block_size); + + /* set the pointer to info entry */ + prev_info_entry_ptr = info_entry_ptr; + } + } + + /* set the last table data */ + *last_table_data_ptr = table_data; +end_function: + return error; +} + +/* + this function goes over all the flow tables connected to the given + table and deallocate them +*/ +static void sep_deallocated_flow_tables(struct sep_lli_entry_t *first_table_ptr) +{ + /* id pointer */ + unsigned long *table_ptr; + /* end address of the flow dma area */ + unsigned long num_entries; + unsigned long num_pages; + struct page **pages_ptr; + /* maximum table size in words */ + struct sep_lli_entry_t *info_entry_ptr; + + /* set the pointer to the first table */ + table_ptr = (unsigned long *) first_table_ptr->physical_address; + + /* set the num of entries */ + num_entries = (first_table_ptr->block_size >> SEP_NUM_ENTRIES_OFFSET_IN_BITS) + & SEP_NUM_ENTRIES_MASK; + + /* go over all the connected tables */ + while (*table_ptr != 0xffffffff) { + /* get number of pages */ + num_pages = *(table_ptr - 2); + + /* get the pointer to the pages */ + pages_ptr = (struct page **) (*(table_ptr - 1)); + + /* free the pages */ + sep_free_dma_pages(pages_ptr, num_pages, 1); + + /* goto to the info entry */ + info_entry_ptr = ((struct sep_lli_entry_t *) table_ptr) + (num_entries - 1); + + table_ptr = (unsigned long *) info_entry_ptr->physical_address; + num_entries = (info_entry_ptr->block_size >> SEP_NUM_ENTRIES_OFFSET_IN_BITS) & SEP_NUM_ENTRIES_MASK; + } + + return; +} + +/** + * sep_find_flow_context - find a flow + * @sep: the SEP we are working with + * @flow_id: flow identifier + * + * Returns a pointer the matching flow, or NULL if the flow does not + * exist. + */ + +static struct sep_flow_context_t *sep_find_flow_context(struct sep_device *sep, + unsigned long flow_id) +{ + int count; + /* + * always search for flow with id default first - in case we + * already started working on the flow there can be no situation + * when 2 flows are with default flag + */ + for (count = 0; count < SEP_DRIVER_NUM_FLOWS; count++) { + if (sep->flows[count].flow_id == flow_id) + return &sep->flows[count]; + } + return NULL; +} + + +/* + this function handles the request to create the DMA tables for flow +*/ +static int sep_create_flow_dma_tables_handler(struct sep_device *sep, + unsigned long arg) +{ + int error = -ENOENT; + struct sep_driver_build_flow_table_t command_args; + /* first table - output */ + struct sep_lli_entry_t first_table_data; + /* dma table data */ + struct sep_lli_entry_t last_table_data; + /* pointer to the info entry of the previuos DMA table */ + struct sep_lli_entry_t *prev_info_entry_ptr; + /* pointer to the flow data strucutre */ + struct sep_flow_context_t *flow_context_ptr; + + dbg("SEP Driver:--------> sep_create_flow_dma_tables_handler start\n"); + + /* init variables */ + prev_info_entry_ptr = 0; + first_table_data.physical_address = 0xffffffff; + + /* find the free structure for flow data */ + error = -EINVAL; + flow_context_ptr = sep_find_flow_context(sep, SEP_FREE_FLOW_ID); + if (flow_context_ptr == NULL) + goto end_function; + + error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_build_flow_table_t)); + if (error) { + error = -EFAULT; + goto end_function; + } + + /* create flow tables */ + error = sep_prepare_flow_dma_tables(sep, command_args.num_virtual_buffers, command_args.virt_buff_data_addr, flow_context_ptr, &first_table_data, &last_table_data, command_args.isKernelVirtualAddress); + if (error) + goto end_function_with_error; + + /* check if flow is static */ + if (!command_args.flow_type) + /* point the info entry of the last to the info entry of the first */ + last_table_data = first_table_data; + + /* set output params */ + command_args.first_table_addr = first_table_data.physical_address; + command_args.first_table_num_entries = ((first_table_data.block_size >> SEP_NUM_ENTRIES_OFFSET_IN_BITS) & SEP_NUM_ENTRIES_MASK); + command_args.first_table_data_size = (first_table_data.block_size & SEP_TABLE_DATA_SIZE_MASK); + + /* send the parameters to user application */ + error = copy_to_user((void *) arg, &command_args, sizeof(struct sep_driver_build_flow_table_t)); + if (error) { + error = -EFAULT; + goto end_function_with_error; + } + + /* all the flow created - update the flow entry with temp id */ + flow_context_ptr->flow_id = SEP_TEMP_FLOW_ID; + + /* set the processing tables data in the context */ + if (command_args.input_output_flag == SEP_DRIVER_IN_FLAG) + flow_context_ptr->input_tables_in_process = first_table_data; + else + flow_context_ptr->output_tables_in_process = first_table_data; + + goto end_function; + +end_function_with_error: + /* free the allocated tables */ + sep_deallocated_flow_tables(&first_table_data); +end_function: + dbg("SEP Driver:<-------- sep_create_flow_dma_tables_handler end\n"); + return error; +} + +/* + this function handles add tables to flow +*/ +static int sep_add_flow_tables_handler(struct sep_device *sep, unsigned long arg) +{ + int error; + unsigned long num_entries; + struct sep_driver_add_flow_table_t command_args; + struct sep_flow_context_t *flow_context_ptr; + /* first dma table data */ + struct sep_lli_entry_t first_table_data; + /* last dma table data */ + struct sep_lli_entry_t last_table_data; + /* pointer to the info entry of the current DMA table */ + struct sep_lli_entry_t *info_entry_ptr; + + dbg("SEP Driver:--------> sep_add_flow_tables_handler start\n"); + + /* get input parameters */ + error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_add_flow_table_t)); + if (error) { + error = -EFAULT; + goto end_function; + } + + /* find the flow structure for the flow id */ + flow_context_ptr = sep_find_flow_context(sep, command_args.flow_id); + if (flow_context_ptr == NULL) + goto end_function; + + /* prepare the flow dma tables */ + error = sep_prepare_flow_dma_tables(sep, command_args.num_virtual_buffers, command_args.virt_buff_data_addr, flow_context_ptr, &first_table_data, &last_table_data, command_args.isKernelVirtualAddress); + if (error) + goto end_function_with_error; + + /* now check if there is already an existing add table for this flow */ + if (command_args.inputOutputFlag == SEP_DRIVER_IN_FLAG) { + /* this buffer was for input buffers */ + if (flow_context_ptr->input_tables_flag) { + /* add table already exists - add the new tables to the end + of the previous */ + num_entries = (flow_context_ptr->last_input_table.block_size >> SEP_NUM_ENTRIES_OFFSET_IN_BITS) & SEP_NUM_ENTRIES_MASK; + + info_entry_ptr = (struct sep_lli_entry_t *) + (flow_context_ptr->last_input_table.physical_address + (sizeof(struct sep_lli_entry_t) * (num_entries - 1))); + + /* connect to list of tables */ + *info_entry_ptr = first_table_data; + + /* set the first table data */ + first_table_data = flow_context_ptr->first_input_table; + } else { + /* set the input flag */ + flow_context_ptr->input_tables_flag = 1; + + /* set the first table data */ + flow_context_ptr->first_input_table = first_table_data; + } + /* set the last table data */ + flow_context_ptr->last_input_table = last_table_data; + } else { /* this is output tables */ + + /* this buffer was for input buffers */ + if (flow_context_ptr->output_tables_flag) { + /* add table already exists - add the new tables to + the end of the previous */ + num_entries = (flow_context_ptr->last_output_table.block_size >> SEP_NUM_ENTRIES_OFFSET_IN_BITS) & SEP_NUM_ENTRIES_MASK; + + info_entry_ptr = (struct sep_lli_entry_t *) + (flow_context_ptr->last_output_table.physical_address + (sizeof(struct sep_lli_entry_t) * (num_entries - 1))); + + /* connect to list of tables */ + *info_entry_ptr = first_table_data; + + /* set the first table data */ + first_table_data = flow_context_ptr->first_output_table; + } else { + /* set the input flag */ + flow_context_ptr->output_tables_flag = 1; + + /* set the first table data */ + flow_context_ptr->first_output_table = first_table_data; + } + /* set the last table data */ + flow_context_ptr->last_output_table = last_table_data; + } + + /* set output params */ + command_args.first_table_addr = first_table_data.physical_address; + command_args.first_table_num_entries = ((first_table_data.block_size >> SEP_NUM_ENTRIES_OFFSET_IN_BITS) & SEP_NUM_ENTRIES_MASK); + command_args.first_table_data_size = (first_table_data.block_size & SEP_TABLE_DATA_SIZE_MASK); + + /* send the parameters to user application */ + error = copy_to_user((void *) arg, &command_args, sizeof(struct sep_driver_add_flow_table_t)); + if (error) + error = -EFAULT; +end_function_with_error: + /* free the allocated tables */ + sep_deallocated_flow_tables(&first_table_data); +end_function: + dbg("SEP Driver:<-------- sep_add_flow_tables_handler end\n"); + return error; +} + +/* + this function add the flow add message to the specific flow +*/ +static int sep_add_flow_tables_message_handler(struct sep_device *sep, unsigned long arg) +{ + int error; + struct sep_driver_add_message_t command_args; + struct sep_flow_context_t *flow_context_ptr; + + dbg("SEP Driver:--------> sep_add_flow_tables_message_handler start\n"); + + error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_add_message_t)); + if (error) { + error = -EFAULT; + goto end_function; + } + + /* check input */ + if (command_args.message_size_in_bytes > SEP_MAX_ADD_MESSAGE_LENGTH_IN_BYTES) { + error = -ENOMEM; + goto end_function; + } + + /* find the flow context */ + flow_context_ptr = sep_find_flow_context(sep, command_args.flow_id); + if (flow_context_ptr == NULL) + goto end_function; + + /* copy the message into context */ + flow_context_ptr->message_size_in_bytes = command_args.message_size_in_bytes; + error = copy_from_user(flow_context_ptr->message, (void *) command_args.message_address, command_args.message_size_in_bytes); + if (error) + error = -EFAULT; +end_function: + dbg("SEP Driver:<-------- sep_add_flow_tables_message_handler end\n"); + return error; +} + + +/* + this function returns the bus and virtual addresses of the static pool +*/ +static int sep_get_static_pool_addr_handler(struct sep_device *sep, unsigned long arg) +{ + int error; + struct sep_driver_static_pool_addr_t command_args; + + dbg("SEP Driver:--------> sep_get_static_pool_addr_handler start\n"); + + /*prepare the output parameters in the struct */ + command_args.physical_static_address = sep->shared_bus + SEP_DRIVER_STATIC_AREA_OFFSET_IN_BYTES; + command_args.virtual_static_address = (unsigned long)sep->shared_addr + SEP_DRIVER_STATIC_AREA_OFFSET_IN_BYTES; + + edbg("SEP Driver:bus_static_address is %08lx, virtual_static_address %08lx\n", command_args.physical_static_address, command_args.virtual_static_address); + + /* send the parameters to user application */ + error = copy_to_user((void *) arg, &command_args, sizeof(struct sep_driver_static_pool_addr_t)); + if (error) + error = -EFAULT; + dbg("SEP Driver:<-------- sep_get_static_pool_addr_handler end\n"); + return error; +} + +/* + this address gets the offset of the physical address from the start + of the mapped area +*/ +static int sep_get_physical_mapped_offset_handler(struct sep_device *sep, unsigned long arg) +{ + int error; + struct sep_driver_get_mapped_offset_t command_args; + + dbg("SEP Driver:--------> sep_get_physical_mapped_offset_handler start\n"); + + error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_get_mapped_offset_t)); + if (error) { + error = -EFAULT; + goto end_function; + } + + if (command_args.physical_address < sep->shared_bus) { + error = -EINVAL; + goto end_function; + } + + /*prepare the output parameters in the struct */ + command_args.offset = command_args.physical_address - sep->shared_bus; + + edbg("SEP Driver:bus_address is %08lx, offset is %lu\n", command_args.physical_address, command_args.offset); + + /* send the parameters to user application */ + error = copy_to_user((void *) arg, &command_args, sizeof(struct sep_driver_get_mapped_offset_t)); + if (error) + error = -EFAULT; +end_function: + dbg("SEP Driver:<-------- sep_get_physical_mapped_offset_handler end\n"); + return error; +} + + +/* + ? +*/ +static int sep_start_handler(struct sep_device *sep) +{ + unsigned long reg_val; + unsigned long error = 0; + + dbg("SEP Driver:--------> sep_start_handler start\n"); + + /* wait in polling for message from SEP */ + do + reg_val = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR3_REG_ADDR); + while (!reg_val); + + /* check the value */ + if (reg_val == 0x1) + /* fatal error - read error status from GPRO */ + error = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR0_REG_ADDR); + dbg("SEP Driver:<-------- sep_start_handler end\n"); + return error; +} + +/* + this function handles the request for SEP initialization +*/ +static int sep_init_handler(struct sep_device *sep, unsigned long arg) +{ + unsigned long message_word; + unsigned long *message_ptr; + struct sep_driver_init_t command_args; + unsigned long counter; + unsigned long error; + unsigned long reg_val; + + dbg("SEP Driver:--------> sep_init_handler start\n"); + error = 0; + + error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_init_t)); + if (error) { + error = -EFAULT; + goto end_function; + } + dbg("SEP Driver:--------> sep_init_handler - finished copy_from_user\n"); + + /* PATCH - configure the DMA to single -burst instead of multi-burst */ + /*sep_configure_dma_burst(); */ + + dbg("SEP Driver:--------> sep_init_handler - finished sep_configure_dma_burst \n"); + + message_ptr = (unsigned long *) command_args.message_addr; + + /* set the base address of the SRAM */ + sep_write_reg(sep, HW_SRAM_ADDR_REG_ADDR, HW_CC_SRAM_BASE_ADDRESS); + + for (counter = 0; counter < command_args.message_size_in_words; counter++, message_ptr++) { + get_user(message_word, message_ptr); + /* write data to SRAM */ + sep_write_reg(sep, HW_SRAM_DATA_REG_ADDR, message_word); + edbg("SEP Driver:message_word is %lu\n", message_word); + /* wait for write complete */ + sep_wait_sram_write(sep); + } + dbg("SEP Driver:--------> sep_init_handler - finished getting messages from user space\n"); + /* signal SEP */ + sep_write_reg(sep, HW_HOST_HOST_SEP_GPR0_REG_ADDR, 0x1); + + do + reg_val = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR3_REG_ADDR); + while (!(reg_val & 0xFFFFFFFD)); + + dbg("SEP Driver:--------> sep_init_handler - finished waiting for reg_val & 0xFFFFFFFD \n"); + + /* check the value */ + if (reg_val == 0x1) { + edbg("SEP Driver:init failed\n"); + + error = sep_read_reg(sep, 0x8060); + edbg("SEP Driver:sw monitor is %lu\n", error); + + /* fatal error - read erro status from GPRO */ + error = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR0_REG_ADDR); + edbg("SEP Driver:error is %lu\n", error); + } +end_function: + dbg("SEP Driver:<-------- sep_init_handler end\n"); + return error; + +} + +/* + this function handles the request cache and resident reallocation +*/ +static int sep_realloc_cache_resident_handler(struct sep_device *sep, + unsigned long arg) +{ + struct sep_driver_realloc_cache_resident_t command_args; + int error; + + /* copy cache and resident to the their intended locations */ + error = sep_load_firmware(sep); + if (error) + return error; + + command_args.new_base_addr = sep->shared_bus; + + /* find the new base address according to the lowest address between + cache, resident and shared area */ + if (sep->resident_bus < command_args.new_base_addr) + command_args.new_base_addr = sep->resident_bus; + if (sep->rar_bus < command_args.new_base_addr) + command_args.new_base_addr = sep->rar_bus; + + /* set the return parameters */ + command_args.new_cache_addr = sep->rar_bus; + command_args.new_resident_addr = sep->resident_bus; + + /* set the new shared area */ + command_args.new_shared_area_addr = sep->shared_bus; + + edbg("SEP Driver:command_args.new_shared_addr is %08llx\n", command_args.new_shared_area_addr); + edbg("SEP Driver:command_args.new_base_addr is %08llx\n", command_args.new_base_addr); + edbg("SEP Driver:command_args.new_resident_addr is %08llx\n", command_args.new_resident_addr); + edbg("SEP Driver:command_args.new_rar_addr is %08llx\n", command_args.new_cache_addr); + + /* return to user */ + if (copy_to_user((void *) arg, &command_args, sizeof(struct sep_driver_realloc_cache_resident_t))) + return -EFAULT; + return 0; +} + +/** + * sep_get_time_handler - time request from user space + * @sep: sep we are to set the time for + * @arg: pointer to user space arg buffer + * + * This function reports back the time and the address in the SEP + * shared buffer at which it has been placed. (Do we really need this!!!) + */ + +static int sep_get_time_handler(struct sep_device *sep, unsigned long arg) +{ + struct sep_driver_get_time_t command_args; + + mutex_lock(&sep_mutex); + command_args.time_value = sep_set_time(sep); + command_args.time_physical_address = (unsigned long)sep_time_address(sep); + mutex_unlock(&sep_mutex); + if (copy_to_user((void __user *)arg, + &command_args, sizeof(struct sep_driver_get_time_t))) + return -EFAULT; + return 0; + +} + +/* + This API handles the end transaction request +*/ +static int sep_end_transaction_handler(struct sep_device *sep, unsigned long arg) +{ + dbg("SEP Driver:--------> sep_end_transaction_handler start\n"); + +#if 0 /*!SEP_DRIVER_POLLING_MODE */ + /* close IMR */ + sep_write_reg(sep, HW_HOST_IMR_REG_ADDR, 0x7FFF); + + /* release IRQ line */ + free_irq(SEP_DIRVER_IRQ_NUM, sep); + + /* lock the sep mutex */ + mutex_unlock(&sep_mutex); +#endif + + dbg("SEP Driver:<-------- sep_end_transaction_handler end\n"); + + return 0; +} + + +/** + * sep_set_flow_id_handler - handle flow setting + * @sep: the SEP we are configuring + * @flow_id: the flow we are setting + * + * This function handler the set flow id command + */ +static int sep_set_flow_id_handler(struct sep_device *sep, + unsigned long flow_id) +{ + int error = 0; + struct sep_flow_context_t *flow_data_ptr; + + /* find the flow data structure that was just used for creating new flow + - its id should be default */ + + mutex_lock(&sep_mutex); + flow_data_ptr = sep_find_flow_context(sep, SEP_TEMP_FLOW_ID); + if (flow_data_ptr) + flow_data_ptr->flow_id = flow_id; /* set flow id */ + else + error = -EINVAL; + mutex_unlock(&sep_mutex); + return error; +} + +static long sep_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + int error = 0; + struct sep_device *sep = filp->private_data; + + dbg("------------>SEP Driver: ioctl start\n"); + + edbg("SEP Driver: cmd is %x\n", cmd); + + switch (cmd) { + case SEP_IOCSENDSEPCOMMAND: + /* send command to SEP */ + sep_send_command_handler(sep); + edbg("SEP Driver: after sep_send_command_handler\n"); + break; + case SEP_IOCSENDSEPRPLYCOMMAND: + /* send reply command to SEP */ + sep_send_reply_command_handler(sep); + break; + case SEP_IOCALLOCDATAPOLL: + /* allocate data pool */ + error = sep_allocate_data_pool_memory_handler(sep, arg); + break; + case SEP_IOCWRITEDATAPOLL: + /* write data into memory pool */ + error = sep_write_into_data_pool_handler(sep, arg); + break; + case SEP_IOCREADDATAPOLL: + /* read data from data pool into application memory */ + error = sep_read_from_data_pool_handler(sep, arg); + break; + case SEP_IOCCREATESYMDMATABLE: + /* create dma table for synhronic operation */ + error = sep_create_sync_dma_tables_handler(sep, arg); + break; + case SEP_IOCCREATEFLOWDMATABLE: + /* create flow dma tables */ + error = sep_create_flow_dma_tables_handler(sep, arg); + break; + case SEP_IOCFREEDMATABLEDATA: + /* free the pages */ + error = sep_free_dma_table_data_handler(sep); + break; + case SEP_IOCSETFLOWID: + /* set flow id */ + error = sep_set_flow_id_handler(sep, (unsigned long)arg); + break; + case SEP_IOCADDFLOWTABLE: + /* add tables to the dynamic flow */ + error = sep_add_flow_tables_handler(sep, arg); + break; + case SEP_IOCADDFLOWMESSAGE: + /* add message of add tables to flow */ + error = sep_add_flow_tables_message_handler(sep, arg); + break; + case SEP_IOCSEPSTART: + /* start command to sep */ + error = sep_start_handler(sep); + break; + case SEP_IOCSEPINIT: + /* init command to sep */ + error = sep_init_handler(sep, arg); + break; + case SEP_IOCGETSTATICPOOLADDR: + /* get the physical and virtual addresses of the static pool */ + error = sep_get_static_pool_addr_handler(sep, arg); + break; + case SEP_IOCENDTRANSACTION: + error = sep_end_transaction_handler(sep, arg); + break; + case SEP_IOCREALLOCCACHERES: + error = sep_realloc_cache_resident_handler(sep, arg); + break; + case SEP_IOCGETMAPPEDADDROFFSET: + error = sep_get_physical_mapped_offset_handler(sep, arg); + break; + case SEP_IOCGETIME: + error = sep_get_time_handler(sep, arg); + break; + default: + error = -ENOTTY; + break; + } + dbg("SEP Driver:<-------- ioctl end\n"); + return error; +} + + + +#if !SEP_DRIVER_POLLING_MODE + +/* handler for flow done interrupt */ + +static void sep_flow_done_handler(struct work_struct *work) +{ + struct sep_flow_context_t *flow_data_ptr; + + /* obtain the mutex */ + mutex_lock(&sep_mutex); + + /* get the pointer to context */ + flow_data_ptr = (struct sep_flow_context_t *) work; + + /* free all the current input tables in sep */ + sep_deallocated_flow_tables(&flow_data_ptr->input_tables_in_process); + + /* free all the current tables output tables in SEP (if needed) */ + if (flow_data_ptr->output_tables_in_process.physical_address != 0xffffffff) + sep_deallocated_flow_tables(&flow_data_ptr->output_tables_in_process); + + /* check if we have additional tables to be sent to SEP only input + flag may be checked */ + if (flow_data_ptr->input_tables_flag) { + /* copy the message to the shared RAM and signal SEP */ + memcpy((void *) flow_data_ptr->message, (void *) sep->shared_addr, flow_data_ptr->message_size_in_bytes); + + sep_write_reg(sep, HW_HOST_HOST_SEP_GPR2_REG_ADDR, 0x2); + } + mutex_unlock(&sep_mutex); +} +/* + interrupt handler function +*/ +static irqreturn_t sep_inthandler(int irq, void *dev_id) +{ + irqreturn_t int_error; + unsigned long reg_val; + unsigned long flow_id; + struct sep_flow_context_t *flow_context_ptr; + struct sep_device *sep = dev_id; + + int_error = IRQ_HANDLED; + + /* read the IRR register to check if this is SEP interrupt */ + reg_val = sep_read_reg(sep, HW_HOST_IRR_REG_ADDR); + edbg("SEP Interrupt - reg is %08lx\n", reg_val); + + /* check if this is the flow interrupt */ + if (0 /*reg_val & (0x1 << 11) */ ) { + /* read GPRO to find out the which flow is done */ + flow_id = sep_read_reg(sep, HW_HOST_IRR_REG_ADDR); + + /* find the contex of the flow */ + flow_context_ptr = sep_find_flow_context(sep, flow_id >> 28); + if (flow_context_ptr == NULL) + goto end_function_with_error; + + /* queue the work */ + INIT_WORK(&flow_context_ptr->flow_wq, sep_flow_done_handler); + queue_work(sep->flow_wq, &flow_context_ptr->flow_wq); + + } else { + /* check if this is reply interrupt from SEP */ + if (reg_val & (0x1 << 13)) { + /* update the counter of reply messages */ + sep->reply_ct++; + /* wake up the waiting process */ + wake_up(&sep_event); + } else { + int_error = IRQ_NONE; + goto end_function; + } + } +end_function_with_error: + /* clear the interrupt */ + sep_write_reg(sep, HW_HOST_ICR_REG_ADDR, reg_val); +end_function: + return int_error; +} + +#endif + + + +#if 0 + +static void sep_wait_busy(struct sep_device *sep) +{ + u32 reg; + + do { + reg = sep_read_reg(sep, HW_HOST_SEP_BUSY_REG_ADDR); + } while (reg); +} + +/* + PATCH for configuring the DMA to single burst instead of multi-burst +*/ +static void sep_configure_dma_burst(struct sep_device *sep) +{ +#define HW_AHB_RD_WR_BURSTS_REG_ADDR 0x0E10UL + + dbg("SEP Driver:<-------- sep_configure_dma_burst start \n"); + + /* request access to registers from SEP */ + sep_write_reg(sep, HW_HOST_HOST_SEP_GPR0_REG_ADDR, 0x2); + + dbg("SEP Driver:<-------- sep_configure_dma_burst finished request access to registers from SEP (write reg) \n"); + + sep_wait_busy(sep); + + dbg("SEP Driver:<-------- sep_configure_dma_burst finished request access to registers from SEP (while(revVal) wait loop) \n"); + + /* set the DMA burst register to single burst */ + sep_write_reg(sep, HW_AHB_RD_WR_BURSTS_REG_ADDR, 0x0UL); + + /* release the sep busy */ + sep_write_reg(sep, HW_HOST_HOST_SEP_GPR0_REG_ADDR, 0x0UL); + sep_wait_busy(sep); + + dbg("SEP Driver:<-------- sep_configure_dma_burst done \n"); + +} + +#endif + +/* + Function that is activated on the successful probe of the SEP device +*/ +static int __devinit sep_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + int error = 0; + struct sep_device *sep; + int counter; + int size; /* size of memory for allocation */ + + edbg("Sep pci probe starting\n"); + if (sep_dev != NULL) { + dev_warn(&pdev->dev, "only one SEP supported.\n"); + return -EBUSY; + } + + /* enable the device */ + error = pci_enable_device(pdev); + if (error) { + edbg("error enabling pci device\n"); + goto end_function; + } + + /* set the pci dev pointer */ + sep_dev = &sep_instance; + sep = &sep_instance; + + edbg("sep->shared_addr = %p\n", sep->shared_addr); + /* transaction counter that coordinates the transactions between SEP + and HOST */ + sep->send_ct = 0; + /* counter for the messages from sep */ + sep->reply_ct = 0; + /* counter for the number of bytes allocated in the pool + for the current transaction */ + sep->data_pool_bytes_allocated = 0; + + /* calculate the total size for allocation */ + size = SEP_DRIVER_MESSAGE_SHARED_AREA_SIZE_IN_BYTES + + SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_SIZE_IN_BYTES + SEP_DRIVER_DATA_POOL_SHARED_AREA_SIZE_IN_BYTES + SEP_DRIVER_FLOW_DMA_TABLES_AREA_SIZE_IN_BYTES + SEP_DRIVER_STATIC_AREA_SIZE_IN_BYTES + SEP_DRIVER_SYSTEM_DATA_MEMORY_SIZE_IN_BYTES; + + /* allocate the shared area */ + if (sep_map_and_alloc_shared_area(sep, size)) { + error = -ENOMEM; + /* allocation failed */ + goto end_function_error; + } + /* now set the memory regions */ +#if (SEP_DRIVER_RECONFIG_MESSAGE_AREA == 1) + /* Note: this test section will need moving before it could ever + work as the registers are not yet mapped ! */ + /* send the new SHARED MESSAGE AREA to the SEP */ + sep_write_reg(sep, HW_HOST_HOST_SEP_GPR1_REG_ADDR, sep->shared_bus); + + /* poll for SEP response */ + retval = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR1_REG_ADDR); + while (retval != 0xffffffff && retval != sep->shared_bus) + retval = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR1_REG_ADDR); + + /* check the return value (register) */ + if (retval != sep->shared_bus) { + error = -ENOMEM; + goto end_function_deallocate_sep_shared_area; + } +#endif + /* init the flow contextes */ + for (counter = 0; counter < SEP_DRIVER_NUM_FLOWS; counter++) + sep->flows[counter].flow_id = SEP_FREE_FLOW_ID; + + sep->flow_wq = create_singlethread_workqueue("sepflowwq"); + if (sep->flow_wq == NULL) { + error = -ENOMEM; + edbg("sep_driver:flow queue creation failed\n"); + goto end_function_deallocate_sep_shared_area; + } + edbg("SEP Driver: create flow workqueue \n"); + sep->pdev = pci_dev_get(pdev); + + sep->reg_addr = pci_ioremap_bar(pdev, 0); + if (!sep->reg_addr) { + edbg("sep: ioremap of registers failed.\n"); + goto end_function_deallocate_sep_shared_area; + } + edbg("SEP Driver:reg_addr is %p\n", sep->reg_addr); + + /* load the rom code */ + sep_load_rom_code(sep); + + /* set up system base address and shared memory location */ + sep->rar_addr = dma_alloc_coherent(&sep->pdev->dev, + 2 * SEP_RAR_IO_MEM_REGION_SIZE, + &sep->rar_bus, GFP_KERNEL); + + if (!sep->rar_addr) { + edbg("SEP Driver:can't allocate rar\n"); + goto end_function_uniomap; + } + + + edbg("SEP Driver:rar_bus is %08llx\n", (unsigned long long)sep->rar_bus); + edbg("SEP Driver:rar_virtual is %p\n", sep->rar_addr); + +#if !SEP_DRIVER_POLLING_MODE + + edbg("SEP Driver: about to write IMR and ICR REG_ADDR\n"); + + /* clear ICR register */ + sep_write_reg(sep, HW_HOST_ICR_REG_ADDR, 0xFFFFFFFF); + + /* set the IMR register - open only GPR 2 */ + sep_write_reg(sep, HW_HOST_IMR_REG_ADDR, (~(0x1 << 13))); + + edbg("SEP Driver: about to call request_irq\n"); + /* get the interrupt line */ + error = request_irq(pdev->irq, sep_inthandler, IRQF_SHARED, "sep_driver", sep); + if (error) + goto end_function_free_res; + return 0; + edbg("SEP Driver: about to write IMR REG_ADDR"); + + /* set the IMR register - open only GPR 2 */ + sep_write_reg(sep, HW_HOST_IMR_REG_ADDR, (~(0x1 << 13))); + +end_function_free_res: + dma_free_coherent(&sep->pdev->dev, 2 * SEP_RAR_IO_MEM_REGION_SIZE, + sep->rar_addr, sep->rar_bus); +#endif /* SEP_DRIVER_POLLING_MODE */ +end_function_uniomap: + iounmap(sep->reg_addr); +end_function_deallocate_sep_shared_area: + /* de-allocate shared area */ + sep_unmap_and_free_shared_area(sep, size); +end_function_error: + sep_dev = NULL; +end_function: + return error; +} + +static const struct pci_device_id sep_pci_id_tbl[] = { + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x080c)}, + {0} +}; + +MODULE_DEVICE_TABLE(pci, sep_pci_id_tbl); + +/* field for registering driver to PCI device */ +static struct pci_driver sep_pci_driver = { + .name = "sep_sec_driver", + .id_table = sep_pci_id_tbl, + .probe = sep_probe + /* FIXME: remove handler */ +}; + +/* major and minor device numbers */ +static dev_t sep_devno; + +/* the files operations structure of the driver */ +static struct file_operations sep_file_operations = { + .owner = THIS_MODULE, + .unlocked_ioctl = sep_ioctl, + .poll = sep_poll, + .open = sep_open, + .release = sep_release, + .mmap = sep_mmap, +}; + + +/* cdev struct of the driver */ +static struct cdev sep_cdev; + +/* + this function registers the driver to the file system +*/ +static int sep_register_driver_to_fs(void) +{ + int ret_val = alloc_chrdev_region(&sep_devno, 0, 1, "sep_sec_driver"); + if (ret_val) { + edbg("sep: major number allocation failed, retval is %d\n", + ret_val); + return ret_val; + } + /* init cdev */ + cdev_init(&sep_cdev, &sep_file_operations); + sep_cdev.owner = THIS_MODULE; + + /* register the driver with the kernel */ + ret_val = cdev_add(&sep_cdev, sep_devno, 1); + if (ret_val) { + edbg("sep_driver:cdev_add failed, retval is %d\n", ret_val); + /* unregister dev numbers */ + unregister_chrdev_region(sep_devno, 1); + } + return ret_val; +} + + +/*-------------------------------------------------------------- + init function +----------------------------------------------------------------*/ +static int __init sep_init(void) +{ + int ret_val = 0; + dbg("SEP Driver:-------->Init start\n"); + /* FIXME: Probe can occur before we are ready to survive a probe */ + ret_val = pci_register_driver(&sep_pci_driver); + if (ret_val) { + edbg("sep_driver:sep_driver_to_device failed, ret_val is %d\n", ret_val); + goto end_function_unregister_from_fs; + } + /* register driver to fs */ + ret_val = sep_register_driver_to_fs(); + if (ret_val) + goto end_function_unregister_pci; + goto end_function; +end_function_unregister_pci: + pci_unregister_driver(&sep_pci_driver); +end_function_unregister_from_fs: + /* unregister from fs */ + cdev_del(&sep_cdev); + /* unregister dev numbers */ + unregister_chrdev_region(sep_devno, 1); +end_function: + dbg("SEP Driver:<-------- Init end\n"); + return ret_val; +} + + +/*------------------------------------------------------------- + exit function +--------------------------------------------------------------*/ +static void __exit sep_exit(void) +{ + int size; + + dbg("SEP Driver:--------> Exit start\n"); + + /* unregister from fs */ + cdev_del(&sep_cdev); + /* unregister dev numbers */ + unregister_chrdev_region(sep_devno, 1); + /* calculate the total size for de-allocation */ + size = SEP_DRIVER_MESSAGE_SHARED_AREA_SIZE_IN_BYTES + + SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_SIZE_IN_BYTES + SEP_DRIVER_DATA_POOL_SHARED_AREA_SIZE_IN_BYTES + SEP_DRIVER_FLOW_DMA_TABLES_AREA_SIZE_IN_BYTES + SEP_DRIVER_STATIC_AREA_SIZE_IN_BYTES + SEP_DRIVER_SYSTEM_DATA_MEMORY_SIZE_IN_BYTES; + /* FIXME: We need to do this in the unload for the device */ + /* free shared area */ + if (sep_dev) { + sep_unmap_and_free_shared_area(sep_dev, size); + edbg("SEP Driver: free pages SEP SHARED AREA \n"); + iounmap((void *) sep_dev->reg_addr); + edbg("SEP Driver: iounmap \n"); + } + edbg("SEP Driver: release_mem_region \n"); + dbg("SEP Driver:<-------- Exit end\n"); +} + + +module_init(sep_init); +module_exit(sep_exit); + +MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/staging/sep/sep_driver_api.h b/trunk/drivers/staging/sep/sep_driver_api.h new file mode 100644 index 000000000000..7ef16da7c4ef --- /dev/null +++ b/trunk/drivers/staging/sep/sep_driver_api.h @@ -0,0 +1,425 @@ +/* + * + * sep_driver_api.h - Security Processor Driver api definitions + * + * Copyright(c) 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2009 Discretix. All rights reserved. + * + * 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. + * + * 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, write to the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * CONTACTS: + * + * Mark Allyn mark.a.allyn@intel.com + * + * CHANGES: + * + * 2009.06.26 Initial publish + * + */ + +#ifndef __SEP_DRIVER_API_H__ +#define __SEP_DRIVER_API_H__ + + + +/*---------------------------------------------------------------- + IOCTL command defines + -----------------------------------------------------------------*/ + +/* magic number 1 of the sep IOCTL command */ +#define SEP_IOC_MAGIC_NUMBER 's' + +/* sends interrupt to sep that message is ready */ +#define SEP_IOCSENDSEPCOMMAND _IO(SEP_IOC_MAGIC_NUMBER , 0) + +/* sends interrupt to sep that message is ready */ +#define SEP_IOCSENDSEPRPLYCOMMAND _IO(SEP_IOC_MAGIC_NUMBER , 1) + +/* allocate memory in data pool */ +#define SEP_IOCALLOCDATAPOLL _IO(SEP_IOC_MAGIC_NUMBER , 2) + +/* write to pre-allocated memory in data pool */ +#define SEP_IOCWRITEDATAPOLL _IO(SEP_IOC_MAGIC_NUMBER , 3) + +/* read from pre-allocated memory in data pool */ +#define SEP_IOCREADDATAPOLL _IO(SEP_IOC_MAGIC_NUMBER , 4) + +/* create sym dma lli tables */ +#define SEP_IOCCREATESYMDMATABLE _IO(SEP_IOC_MAGIC_NUMBER , 5) + +/* create flow dma lli tables */ +#define SEP_IOCCREATEFLOWDMATABLE _IO(SEP_IOC_MAGIC_NUMBER , 6) + +/* free dynamic data aalocated during table creation */ +#define SEP_IOCFREEDMATABLEDATA _IO(SEP_IOC_MAGIC_NUMBER , 7) + +/* get the static pool area addresses (physical and virtual) */ +#define SEP_IOCGETSTATICPOOLADDR _IO(SEP_IOC_MAGIC_NUMBER , 8) + +/* set flow id command */ +#define SEP_IOCSETFLOWID _IO(SEP_IOC_MAGIC_NUMBER , 9) + +/* add tables to the dynamic flow */ +#define SEP_IOCADDFLOWTABLE _IO(SEP_IOC_MAGIC_NUMBER , 10) + +/* add flow add tables message */ +#define SEP_IOCADDFLOWMESSAGE _IO(SEP_IOC_MAGIC_NUMBER , 11) + +/* start sep command */ +#define SEP_IOCSEPSTART _IO(SEP_IOC_MAGIC_NUMBER , 12) + +/* init sep command */ +#define SEP_IOCSEPINIT _IO(SEP_IOC_MAGIC_NUMBER , 13) + +/* end transaction command */ +#define SEP_IOCENDTRANSACTION _IO(SEP_IOC_MAGIC_NUMBER , 15) + +/* reallocate cache and resident */ +#define SEP_IOCREALLOCCACHERES _IO(SEP_IOC_MAGIC_NUMBER , 16) + +/* get the offset of the address starting from the beginnnig of the map area */ +#define SEP_IOCGETMAPPEDADDROFFSET _IO(SEP_IOC_MAGIC_NUMBER , 17) + +/* get time address and value */ +#define SEP_IOCGETIME _IO(SEP_IOC_MAGIC_NUMBER , 19) + +/*------------------------------------------- + TYPEDEFS +----------------------------------------------*/ + +/* + init command struct +*/ +struct sep_driver_init_t { + /* start of the 1G of the host memory address that SEP can access */ + unsigned long message_addr; + + /* start address of resident */ + unsigned long message_size_in_words; + +}; + + +/* + realloc cache resident command +*/ +struct sep_driver_realloc_cache_resident_t { + /* new cache address */ + u64 new_cache_addr; + /* new resident address */ + u64 new_resident_addr; + /* new resident address */ + u64 new_shared_area_addr; + /* new base address */ + u64 new_base_addr; +}; + +struct sep_driver_alloc_t { + /* virtual address of allocated space */ + unsigned long offset; + + /* physical address of allocated space */ + unsigned long phys_address; + + /* number of bytes to allocate */ + unsigned long num_bytes; +}; + +/* + */ +struct sep_driver_write_t { + /* application space address */ + unsigned long app_address; + + /* address of the data pool */ + unsigned long datapool_address; + + /* number of bytes to write */ + unsigned long num_bytes; +}; + +/* + */ +struct sep_driver_read_t { + /* application space address */ + unsigned long app_address; + + /* address of the data pool */ + unsigned long datapool_address; + + /* number of bytes to read */ + unsigned long num_bytes; +}; + +/* +*/ +struct sep_driver_build_sync_table_t { + /* address value of the data in */ + unsigned long app_in_address; + + /* size of data in */ + unsigned long data_in_size; + + /* address of the data out */ + unsigned long app_out_address; + + /* the size of the block of the operation - if needed, + every table will be modulo this parameter */ + unsigned long block_size; + + /* the physical address of the first input DMA table */ + unsigned long in_table_address; + + /* number of entries in the first input DMA table */ + unsigned long in_table_num_entries; + + /* the physical address of the first output DMA table */ + unsigned long out_table_address; + + /* number of entries in the first output DMA table */ + unsigned long out_table_num_entries; + + /* data in the first input table */ + unsigned long table_data_size; + + /* distinct user/kernel layout */ + bool isKernelVirtualAddress; + +}; + +/* +*/ +struct sep_driver_build_flow_table_t { + /* flow type */ + unsigned long flow_type; + + /* flag for input output */ + unsigned long input_output_flag; + + /* address value of the data in */ + unsigned long virt_buff_data_addr; + + /* size of data in */ + unsigned long num_virtual_buffers; + + /* the physical address of the first input DMA table */ + unsigned long first_table_addr; + + /* number of entries in the first input DMA table */ + unsigned long first_table_num_entries; + + /* data in the first input table */ + unsigned long first_table_data_size; + + /* distinct user/kernel layout */ + bool isKernelVirtualAddress; +}; + + +struct sep_driver_add_flow_table_t { + /* flow id */ + unsigned long flow_id; + + /* flag for input output */ + unsigned long inputOutputFlag; + + /* address value of the data in */ + unsigned long virt_buff_data_addr; + + /* size of data in */ + unsigned long num_virtual_buffers; + + /* address of the first table */ + unsigned long first_table_addr; + + /* number of entries in the first table */ + unsigned long first_table_num_entries; + + /* data size of the first table */ + unsigned long first_table_data_size; + + /* distinct user/kernel layout */ + bool isKernelVirtualAddress; + +}; + +/* + command struct for set flow id +*/ +struct sep_driver_set_flow_id_t { + /* flow id to set */ + unsigned long flow_id; +}; + + +/* command struct for add tables message */ +struct sep_driver_add_message_t { + /* flow id to set */ + unsigned long flow_id; + + /* message size in bytes */ + unsigned long message_size_in_bytes; + + /* address of the message */ + unsigned long message_address; +}; + +/* command struct for static pool addresses */ +struct sep_driver_static_pool_addr_t { + /* physical address of the static pool */ + unsigned long physical_static_address; + + /* virtual address of the static pool */ + unsigned long virtual_static_address; +}; + +/* command struct for getiing offset of the physical address from + the start of the mapped area */ +struct sep_driver_get_mapped_offset_t { + /* physical address of the static pool */ + unsigned long physical_address; + + /* virtual address of the static pool */ + unsigned long offset; +}; + +/* command struct for getting time value and address */ +struct sep_driver_get_time_t { + /* physical address of stored time */ + unsigned long time_physical_address; + + /* value of the stored time */ + unsigned long time_value; +}; + + +/* + structure that represent one entry in the DMA LLI table +*/ +struct sep_lli_entry_t { + /* physical address */ + unsigned long physical_address; + + /* block size */ + unsigned long block_size; +}; + +/* + structure that reperesents data needed for lli table construction +*/ +struct sep_lli_prepare_table_data_t { + /* pointer to the memory where the first lli entry to be built */ + struct sep_lli_entry_t *lli_entry_ptr; + + /* pointer to the array of lli entries from which the table is to be built */ + struct sep_lli_entry_t *lli_array_ptr; + + /* number of elements in lli array */ + int lli_array_size; + + /* number of entries in the created table */ + int num_table_entries; + + /* number of array entries processed during table creation */ + int num_array_entries_processed; + + /* the totatl data size in the created table */ + int lli_table_total_data_size; +}; + +/* + structure that represent tone table - it is not used in code, jkust + to show what table looks like +*/ +struct sep_lli_table_t { + /* number of pages mapped in this tables. If 0 - means that the table + is not defined (used as a valid flag) */ + unsigned long num_pages; + /* + pointer to array of page pointers that represent the mapping of the + virtual buffer defined by the table to the physical memory. If this + pointer is NULL, it means that the table is not defined + (used as a valid flag) + */ + struct page **table_page_array_ptr; + + /* maximum flow entries in table */ + struct sep_lli_entry_t lli_entries[SEP_DRIVER_MAX_FLOW_NUM_ENTRIES_IN_TABLE]; +}; + + +/* + structure for keeping the mapping of the virtual buffer into physical pages +*/ +struct sep_flow_buffer_data { + /* pointer to the array of page structs pointers to the pages of the + virtual buffer */ + struct page **page_array_ptr; + + /* number of pages taken by the virtual buffer */ + unsigned long num_pages; + + /* this flag signals if this page_array is the last one among many that were + sent in one setting to SEP */ + unsigned long last_page_array_flag; +}; + +/* + struct that keeps all the data for one flow +*/ +struct sep_flow_context_t { + /* + work struct for handling the flow done interrupt in the workqueue + this structure must be in the first place, since it will be used + forcasting to the containing flow context + */ + struct work_struct flow_wq; + + /* flow id */ + unsigned long flow_id; + + /* additional input tables exists */ + unsigned long input_tables_flag; + + /* additional output tables exists */ + unsigned long output_tables_flag; + + /* data of the first input file */ + struct sep_lli_entry_t first_input_table; + + /* data of the first output table */ + struct sep_lli_entry_t first_output_table; + + /* last input table data */ + struct sep_lli_entry_t last_input_table; + + /* last output table data */ + struct sep_lli_entry_t last_output_table; + + /* first list of table */ + struct sep_lli_entry_t input_tables_in_process; + + /* output table in process (in sep) */ + struct sep_lli_entry_t output_tables_in_process; + + /* size of messages in bytes */ + unsigned long message_size_in_bytes; + + /* message */ + unsigned char message[SEP_MAX_ADD_MESSAGE_LENGTH_IN_BYTES]; +}; + + +#endif diff --git a/trunk/drivers/staging/sep/sep_driver_config.h b/trunk/drivers/staging/sep/sep_driver_config.h new file mode 100644 index 000000000000..6008fe5eca09 --- /dev/null +++ b/trunk/drivers/staging/sep/sep_driver_config.h @@ -0,0 +1,225 @@ +/* + * + * sep_driver_config.h - Security Processor Driver configuration + * + * Copyright(c) 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2009 Discretix. All rights reserved. + * + * 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. + * + * 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, write to the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * CONTACTS: + * + * Mark Allyn mark.a.allyn@intel.com + * + * CHANGES: + * + * 2009.06.26 Initial publish + * + */ + +#ifndef __SEP_DRIVER_CONFIG_H__ +#define __SEP_DRIVER_CONFIG_H__ + + +/*-------------------------------------- + DRIVER CONFIGURATION FLAGS + -------------------------------------*/ + +/* if flag is on , then the driver is running in polling and + not interrupt mode */ +#define SEP_DRIVER_POLLING_MODE 1 + +/* flag which defines if the shared area address should be + reconfiged (send to SEP anew) during init of the driver */ +#define SEP_DRIVER_RECONFIG_MESSAGE_AREA 0 + +/* the mode for running on the ARM1172 Evaluation platform (flag is 1) */ +#define SEP_DRIVER_ARM_DEBUG_MODE 0 + +/*------------------------------------------- + INTERNAL DATA CONFIGURATION + -------------------------------------------*/ + +/* flag for the input array */ +#define SEP_DRIVER_IN_FLAG 0 + +/* flag for output array */ +#define SEP_DRIVER_OUT_FLAG 1 + +/* maximum number of entries in one LLI tables */ +#define SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP 8 + + +/*-------------------------------------------------------- + SHARED AREA memory total size is 36K + it is divided is following: + + SHARED_MESSAGE_AREA 8K } + } + STATIC_POOL_AREA 4K } MAPPED AREA ( 24 K) + } + DATA_POOL_AREA 12K } + + SYNCHRONIC_DMA_TABLES_AREA 5K + + FLOW_DMA_TABLES_AREA 4K + + SYSTEM_MEMORY_AREA 3k + + SYSTEM_MEMORY total size is 3k + it is divided as following: + + TIME_MEMORY_AREA 8B +-----------------------------------------------------------*/ + + + +/* + the maximum length of the message - the rest of the message shared + area will be dedicated to the dma lli tables +*/ +#define SEP_DRIVER_MAX_MESSAGE_SIZE_IN_BYTES (8 * 1024) + +/* the size of the message shared area in pages */ +#define SEP_DRIVER_MESSAGE_SHARED_AREA_SIZE_IN_BYTES (8 * 1024) + +/* the size of the data pool static area in pages */ +#define SEP_DRIVER_STATIC_AREA_SIZE_IN_BYTES (4 * 1024) + +/* the size of the data pool shared area size in pages */ +#define SEP_DRIVER_DATA_POOL_SHARED_AREA_SIZE_IN_BYTES (12 * 1024) + +/* the size of the message shared area in pages */ +#define SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_SIZE_IN_BYTES (1024 * 5) + + +/* the size of the data pool shared area size in pages */ +#define SEP_DRIVER_FLOW_DMA_TABLES_AREA_SIZE_IN_BYTES (1024 * 4) + +/* system data (time, caller id etc') pool */ +#define SEP_DRIVER_SYSTEM_DATA_MEMORY_SIZE_IN_BYTES 100 + + +/* area size that is mapped - we map the MESSAGE AREA, STATIC POOL and + DATA POOL areas. area must be module 4k */ +#define SEP_DRIVER_MMMAP_AREA_SIZE (1024 * 24) + + +/*----------------------------------------------- + offsets of the areas starting from the shared area start address +*/ + +/* message area offset */ +#define SEP_DRIVER_MESSAGE_AREA_OFFSET_IN_BYTES 0 + +/* static pool area offset */ +#define SEP_DRIVER_STATIC_AREA_OFFSET_IN_BYTES \ + (SEP_DRIVER_MESSAGE_SHARED_AREA_SIZE_IN_BYTES) + +/* data pool area offset */ +#define SEP_DRIVER_DATA_POOL_AREA_OFFSET_IN_BYTES \ + (SEP_DRIVER_STATIC_AREA_OFFSET_IN_BYTES + \ + SEP_DRIVER_STATIC_AREA_SIZE_IN_BYTES) + +/* synhronic dma tables area offset */ +#define SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_OFFSET_IN_BYTES \ + (SEP_DRIVER_DATA_POOL_AREA_OFFSET_IN_BYTES + \ + SEP_DRIVER_DATA_POOL_SHARED_AREA_SIZE_IN_BYTES) + +/* sep driver flow dma tables area offset */ +#define SEP_DRIVER_FLOW_DMA_TABLES_AREA_OFFSET_IN_BYTES \ + (SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_OFFSET_IN_BYTES + \ + SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_SIZE_IN_BYTES) + +/* system memory offset in bytes */ +#define SEP_DRIVER_SYSTEM_DATA_MEMORY_OFFSET_IN_BYTES \ + (SEP_DRIVER_FLOW_DMA_TABLES_AREA_OFFSET_IN_BYTES + \ + SEP_DRIVER_FLOW_DMA_TABLES_AREA_SIZE_IN_BYTES) + +/* offset of the time area */ +#define SEP_DRIVER_SYSTEM_TIME_MEMORY_OFFSET_IN_BYTES \ + (SEP_DRIVER_SYSTEM_DATA_MEMORY_OFFSET_IN_BYTES) + + + +/* start physical address of the SEP registers memory in HOST */ +#define SEP_IO_MEM_REGION_START_ADDRESS 0x80000000 + +/* size of the SEP registers memory region in HOST (for now 100 registers) */ +#define SEP_IO_MEM_REGION_SIZE (2 * 0x100000) + +/* define the number of IRQ for SEP interrupts */ +#define SEP_DIRVER_IRQ_NUM 1 + +/* maximum number of add buffers */ +#define SEP_MAX_NUM_ADD_BUFFERS 100 + +/* number of flows */ +#define SEP_DRIVER_NUM_FLOWS 4 + +/* maximum number of entries in flow table */ +#define SEP_DRIVER_MAX_FLOW_NUM_ENTRIES_IN_TABLE 25 + +/* offset of the num entries in the block length entry of the LLI */ +#define SEP_NUM_ENTRIES_OFFSET_IN_BITS 24 + +/* offset of the interrupt flag in the block length entry of the LLI */ +#define SEP_INT_FLAG_OFFSET_IN_BITS 31 + +/* mask for extracting data size from LLI */ +#define SEP_TABLE_DATA_SIZE_MASK 0xFFFFFF + +/* mask for entries after being shifted left */ +#define SEP_NUM_ENTRIES_MASK 0x7F + +/* default flow id */ +#define SEP_FREE_FLOW_ID 0xFFFFFFFF + +/* temp flow id used during cretiong of new flow until receiving + real flow id from sep */ +#define SEP_TEMP_FLOW_ID (SEP_DRIVER_NUM_FLOWS + 1) + +/* maximum add buffers message length in bytes */ +#define SEP_MAX_ADD_MESSAGE_LENGTH_IN_BYTES (7 * 4) + +/* maximum number of concurrent virtual buffers */ +#define SEP_MAX_VIRT_BUFFERS_CONCURRENT 100 + +/* the token that defines the start of time address */ +#define SEP_TIME_VAL_TOKEN 0x12345678 + +/* DEBUG LEVEL MASKS */ +#define SEP_DEBUG_LEVEL_BASIC 0x1 + +#define SEP_DEBUG_LEVEL_EXTENDED 0x4 + + +/* Debug helpers */ + +#define dbg(fmt, args...) \ +do {\ + if (debug & SEP_DEBUG_LEVEL_BASIC) \ + printk(KERN_DEBUG fmt, ##args); \ +} while(0); + +#define edbg(fmt, args...) \ +do { \ + if (debug & SEP_DEBUG_LEVEL_EXTENDED) \ + printk(KERN_DEBUG fmt, ##args); \ +} while(0); + + + +#endif diff --git a/trunk/drivers/staging/sep/sep_driver_hw_defs.h b/trunk/drivers/staging/sep/sep_driver_hw_defs.h new file mode 100644 index 000000000000..ea6abd8a14b4 --- /dev/null +++ b/trunk/drivers/staging/sep/sep_driver_hw_defs.h @@ -0,0 +1,232 @@ +/* + * + * sep_driver_hw_defs.h - Security Processor Driver hardware definitions + * + * Copyright(c) 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2009 Discretix. All rights reserved. + * + * 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. + * + * 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, write to the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * CONTACTS: + * + * Mark Allyn mark.a.allyn@intel.com + * + * CHANGES: + * + * 2009.06.26 Initial publish + * + */ + +#ifndef SEP_DRIVER_HW_DEFS__H +#define SEP_DRIVER_HW_DEFS__H + +/*--------------------------------------------------------------------------*/ +/* Abstract: HW Registers Defines. */ +/* */ +/* Note: This file was automatically created !!! */ +/* DO NOT EDIT THIS FILE !!! */ +/*--------------------------------------------------------------------------*/ + + +/* cf registers */ +#define HW_R0B_ADDR_0_REG_ADDR 0x0000UL +#define HW_R0B_ADDR_1_REG_ADDR 0x0004UL +#define HW_R0B_ADDR_2_REG_ADDR 0x0008UL +#define HW_R0B_ADDR_3_REG_ADDR 0x000cUL +#define HW_R0B_ADDR_4_REG_ADDR 0x0010UL +#define HW_R0B_ADDR_5_REG_ADDR 0x0014UL +#define HW_R0B_ADDR_6_REG_ADDR 0x0018UL +#define HW_R0B_ADDR_7_REG_ADDR 0x001cUL +#define HW_R0B_ADDR_8_REG_ADDR 0x0020UL +#define HW_R2B_ADDR_0_REG_ADDR 0x0080UL +#define HW_R2B_ADDR_1_REG_ADDR 0x0084UL +#define HW_R2B_ADDR_2_REG_ADDR 0x0088UL +#define HW_R2B_ADDR_3_REG_ADDR 0x008cUL +#define HW_R2B_ADDR_4_REG_ADDR 0x0090UL +#define HW_R2B_ADDR_5_REG_ADDR 0x0094UL +#define HW_R2B_ADDR_6_REG_ADDR 0x0098UL +#define HW_R2B_ADDR_7_REG_ADDR 0x009cUL +#define HW_R2B_ADDR_8_REG_ADDR 0x00a0UL +#define HW_R3B_REG_ADDR 0x00C0UL +#define HW_R4B_REG_ADDR 0x0100UL +#define HW_CSA_ADDR_0_REG_ADDR 0x0140UL +#define HW_CSA_ADDR_1_REG_ADDR 0x0144UL +#define HW_CSA_ADDR_2_REG_ADDR 0x0148UL +#define HW_CSA_ADDR_3_REG_ADDR 0x014cUL +#define HW_CSA_ADDR_4_REG_ADDR 0x0150UL +#define HW_CSA_ADDR_5_REG_ADDR 0x0154UL +#define HW_CSA_ADDR_6_REG_ADDR 0x0158UL +#define HW_CSA_ADDR_7_REG_ADDR 0x015cUL +#define HW_CSA_ADDR_8_REG_ADDR 0x0160UL +#define HW_CSA_REG_ADDR 0x0140UL +#define HW_SINB_REG_ADDR 0x0180UL +#define HW_SOUTB_REG_ADDR 0x0184UL +#define HW_PKI_CONTROL_REG_ADDR 0x01C0UL +#define HW_PKI_STATUS_REG_ADDR 0x01C4UL +#define HW_PKI_BUSY_REG_ADDR 0x01C8UL +#define HW_PKI_A_1025_REG_ADDR 0x01CCUL +#define HW_PKI_SDMA_CTL_REG_ADDR 0x01D0UL +#define HW_PKI_SDMA_OFFSET_REG_ADDR 0x01D4UL +#define HW_PKI_SDMA_POINTERS_REG_ADDR 0x01D8UL +#define HW_PKI_SDMA_DLENG_REG_ADDR 0x01DCUL +#define HW_PKI_SDMA_EXP_POINTERS_REG_ADDR 0x01E0UL +#define HW_PKI_SDMA_RES_POINTERS_REG_ADDR 0x01E4UL +#define HW_PKI_CLR_REG_ADDR 0x01E8UL +#define HW_PKI_SDMA_BUSY_REG_ADDR 0x01E8UL +#define HW_PKI_SDMA_FIRST_EXP_N_REG_ADDR 0x01ECUL +#define HW_PKI_SDMA_MUL_BY1_REG_ADDR 0x01F0UL +#define HW_PKI_SDMA_RMUL_SEL_REG_ADDR 0x01F4UL +#define HW_DES_KEY_0_REG_ADDR 0x0208UL +#define HW_DES_KEY_1_REG_ADDR 0x020CUL +#define HW_DES_KEY_2_REG_ADDR 0x0210UL +#define HW_DES_KEY_3_REG_ADDR 0x0214UL +#define HW_DES_KEY_4_REG_ADDR 0x0218UL +#define HW_DES_KEY_5_REG_ADDR 0x021CUL +#define HW_DES_CONTROL_0_REG_ADDR 0x0220UL +#define HW_DES_CONTROL_1_REG_ADDR 0x0224UL +#define HW_DES_IV_0_REG_ADDR 0x0228UL +#define HW_DES_IV_1_REG_ADDR 0x022CUL +#define HW_AES_KEY_0_ADDR_0_REG_ADDR 0x0400UL +#define HW_AES_KEY_0_ADDR_1_REG_ADDR 0x0404UL +#define HW_AES_KEY_0_ADDR_2_REG_ADDR 0x0408UL +#define HW_AES_KEY_0_ADDR_3_REG_ADDR 0x040cUL +#define HW_AES_KEY_0_ADDR_4_REG_ADDR 0x0410UL +#define HW_AES_KEY_0_ADDR_5_REG_ADDR 0x0414UL +#define HW_AES_KEY_0_ADDR_6_REG_ADDR 0x0418UL +#define HW_AES_KEY_0_ADDR_7_REG_ADDR 0x041cUL +#define HW_AES_KEY_0_REG_ADDR 0x0400UL +#define HW_AES_IV_0_ADDR_0_REG_ADDR 0x0440UL +#define HW_AES_IV_0_ADDR_1_REG_ADDR 0x0444UL +#define HW_AES_IV_0_ADDR_2_REG_ADDR 0x0448UL +#define HW_AES_IV_0_ADDR_3_REG_ADDR 0x044cUL +#define HW_AES_IV_0_REG_ADDR 0x0440UL +#define HW_AES_CTR1_ADDR_0_REG_ADDR 0x0460UL +#define HW_AES_CTR1_ADDR_1_REG_ADDR 0x0464UL +#define HW_AES_CTR1_ADDR_2_REG_ADDR 0x0468UL +#define HW_AES_CTR1_ADDR_3_REG_ADDR 0x046cUL +#define HW_AES_CTR1_REG_ADDR 0x0460UL +#define HW_AES_SK_REG_ADDR 0x0478UL +#define HW_AES_MAC_OK_REG_ADDR 0x0480UL +#define HW_AES_PREV_IV_0_ADDR_0_REG_ADDR 0x0490UL +#define HW_AES_PREV_IV_0_ADDR_1_REG_ADDR 0x0494UL +#define HW_AES_PREV_IV_0_ADDR_2_REG_ADDR 0x0498UL +#define HW_AES_PREV_IV_0_ADDR_3_REG_ADDR 0x049cUL +#define HW_AES_PREV_IV_0_REG_ADDR 0x0490UL +#define HW_AES_CONTROL_REG_ADDR 0x04C0UL +#define HW_HASH_H0_REG_ADDR 0x0640UL +#define HW_HASH_H1_REG_ADDR 0x0644UL +#define HW_HASH_H2_REG_ADDR 0x0648UL +#define HW_HASH_H3_REG_ADDR 0x064CUL +#define HW_HASH_H4_REG_ADDR 0x0650UL +#define HW_HASH_H5_REG_ADDR 0x0654UL +#define HW_HASH_H6_REG_ADDR 0x0658UL +#define HW_HASH_H7_REG_ADDR 0x065CUL +#define HW_HASH_H8_REG_ADDR 0x0660UL +#define HW_HASH_H9_REG_ADDR 0x0664UL +#define HW_HASH_H10_REG_ADDR 0x0668UL +#define HW_HASH_H11_REG_ADDR 0x066CUL +#define HW_HASH_H12_REG_ADDR 0x0670UL +#define HW_HASH_H13_REG_ADDR 0x0674UL +#define HW_HASH_H14_REG_ADDR 0x0678UL +#define HW_HASH_H15_REG_ADDR 0x067CUL +#define HW_HASH_CONTROL_REG_ADDR 0x07C0UL +#define HW_HASH_PAD_EN_REG_ADDR 0x07C4UL +#define HW_HASH_PAD_CFG_REG_ADDR 0x07C8UL +#define HW_HASH_CUR_LEN_0_REG_ADDR 0x07CCUL +#define HW_HASH_CUR_LEN_1_REG_ADDR 0x07D0UL +#define HW_HASH_CUR_LEN_2_REG_ADDR 0x07D4UL +#define HW_HASH_CUR_LEN_3_REG_ADDR 0x07D8UL +#define HW_HASH_PARAM_REG_ADDR 0x07DCUL +#define HW_HASH_INT_BUSY_REG_ADDR 0x07E0UL +#define HW_HASH_SW_RESET_REG_ADDR 0x07E4UL +#define HW_HASH_ENDIANESS_REG_ADDR 0x07E8UL +#define HW_HASH_DATA_REG_ADDR 0x07ECUL +#define HW_DRNG_CONTROL_REG_ADDR 0x0800UL +#define HW_DRNG_VALID_REG_ADDR 0x0804UL +#define HW_DRNG_DATA_REG_ADDR 0x0808UL +#define HW_RND_SRC_EN_REG_ADDR 0x080CUL +#define HW_AES_CLK_ENABLE_REG_ADDR 0x0810UL +#define HW_DES_CLK_ENABLE_REG_ADDR 0x0814UL +#define HW_HASH_CLK_ENABLE_REG_ADDR 0x0818UL +#define HW_PKI_CLK_ENABLE_REG_ADDR 0x081CUL +#define HW_CLK_STATUS_REG_ADDR 0x0824UL +#define HW_CLK_ENABLE_REG_ADDR 0x0828UL +#define HW_DRNG_SAMPLE_REG_ADDR 0x0850UL +#define HW_RND_SRC_CTL_REG_ADDR 0x0858UL +#define HW_CRYPTO_CTL_REG_ADDR 0x0900UL +#define HW_CRYPTO_STATUS_REG_ADDR 0x090CUL +#define HW_CRYPTO_BUSY_REG_ADDR 0x0910UL +#define HW_AES_BUSY_REG_ADDR 0x0914UL +#define HW_DES_BUSY_REG_ADDR 0x0918UL +#define HW_HASH_BUSY_REG_ADDR 0x091CUL +#define HW_CONTENT_REG_ADDR 0x0924UL +#define HW_VERSION_REG_ADDR 0x0928UL +#define HW_CONTEXT_ID_REG_ADDR 0x0930UL +#define HW_DIN_BUFFER_REG_ADDR 0x0C00UL +#define HW_DIN_MEM_DMA_BUSY_REG_ADDR 0x0c20UL +#define HW_SRC_LLI_MEM_ADDR_REG_ADDR 0x0c24UL +#define HW_SRC_LLI_WORD0_REG_ADDR 0x0C28UL +#define HW_SRC_LLI_WORD1_REG_ADDR 0x0C2CUL +#define HW_SRAM_SRC_ADDR_REG_ADDR 0x0c30UL +#define HW_DIN_SRAM_BYTES_LEN_REG_ADDR 0x0c34UL +#define HW_DIN_SRAM_DMA_BUSY_REG_ADDR 0x0C38UL +#define HW_WRITE_ALIGN_REG_ADDR 0x0C3CUL +#define HW_OLD_DATA_REG_ADDR 0x0C48UL +#define HW_WRITE_ALIGN_LAST_REG_ADDR 0x0C4CUL +#define HW_DOUT_BUFFER_REG_ADDR 0x0C00UL +#define HW_DST_LLI_WORD0_REG_ADDR 0x0D28UL +#define HW_DST_LLI_WORD1_REG_ADDR 0x0D2CUL +#define HW_DST_LLI_MEM_ADDR_REG_ADDR 0x0D24UL +#define HW_DOUT_MEM_DMA_BUSY_REG_ADDR 0x0D20UL +#define HW_SRAM_DEST_ADDR_REG_ADDR 0x0D30UL +#define HW_DOUT_SRAM_BYTES_LEN_REG_ADDR 0x0D34UL +#define HW_DOUT_SRAM_DMA_BUSY_REG_ADDR 0x0D38UL +#define HW_READ_ALIGN_REG_ADDR 0x0D3CUL +#define HW_READ_LAST_DATA_REG_ADDR 0x0D44UL +#define HW_RC4_THRU_CPU_REG_ADDR 0x0D4CUL +#define HW_AHB_SINGLE_REG_ADDR 0x0E00UL +#define HW_SRAM_DATA_REG_ADDR 0x0F00UL +#define HW_SRAM_ADDR_REG_ADDR 0x0F04UL +#define HW_SRAM_DATA_READY_REG_ADDR 0x0F08UL +#define HW_HOST_IRR_REG_ADDR 0x0A00UL +#define HW_HOST_IMR_REG_ADDR 0x0A04UL +#define HW_HOST_ICR_REG_ADDR 0x0A08UL +#define HW_HOST_SEP_SRAM_THRESHOLD_REG_ADDR 0x0A10UL +#define HW_HOST_SEP_BUSY_REG_ADDR 0x0A14UL +#define HW_HOST_SEP_LCS_REG_ADDR 0x0A18UL +#define HW_HOST_CC_SW_RST_REG_ADDR 0x0A40UL +#define HW_HOST_SEP_SW_RST_REG_ADDR 0x0A44UL +#define HW_HOST_FLOW_DMA_SW_INT0_REG_ADDR 0x0A80UL +#define HW_HOST_FLOW_DMA_SW_INT1_REG_ADDR 0x0A84UL +#define HW_HOST_FLOW_DMA_SW_INT2_REG_ADDR 0x0A88UL +#define HW_HOST_FLOW_DMA_SW_INT3_REG_ADDR 0x0A8cUL +#define HW_HOST_FLOW_DMA_SW_INT4_REG_ADDR 0x0A90UL +#define HW_HOST_FLOW_DMA_SW_INT5_REG_ADDR 0x0A94UL +#define HW_HOST_FLOW_DMA_SW_INT6_REG_ADDR 0x0A98UL +#define HW_HOST_FLOW_DMA_SW_INT7_REG_ADDR 0x0A9cUL +#define HW_HOST_SEP_HOST_GPR0_REG_ADDR 0x0B00UL +#define HW_HOST_SEP_HOST_GPR1_REG_ADDR 0x0B04UL +#define HW_HOST_SEP_HOST_GPR2_REG_ADDR 0x0B08UL +#define HW_HOST_SEP_HOST_GPR3_REG_ADDR 0x0B0CUL +#define HW_HOST_HOST_SEP_GPR0_REG_ADDR 0x0B80UL +#define HW_HOST_HOST_SEP_GPR1_REG_ADDR 0x0B84UL +#define HW_HOST_HOST_SEP_GPR2_REG_ADDR 0x0B88UL +#define HW_HOST_HOST_SEP_GPR3_REG_ADDR 0x0B8CUL +#define HW_HOST_HOST_ENDIAN_REG_ADDR 0x0B90UL +#define HW_HOST_HOST_COMM_CLK_EN_REG_ADDR 0x0B94UL +#define HW_CLR_SRAM_BUSY_REG_REG_ADDR 0x0F0CUL +#define HW_CC_SRAM_BASE_ADDRESS 0x5800UL + +#endif /* ifndef HW_DEFS */ diff --git a/trunk/drivers/staging/spectra/ffsport.c b/trunk/drivers/staging/spectra/ffsport.c index 44a7fbe7eccd..d0c5c97eda3e 100644 --- a/trunk/drivers/staging/spectra/ffsport.c +++ b/trunk/drivers/staging/spectra/ffsport.c @@ -27,7 +27,6 @@ #include #include #include -#include /**** Helper functions used for Div, Remainder operation on u64 ****/ @@ -114,6 +113,7 @@ u64 GLOB_u64_Remainder(u64 addr, u32 divisor_type) #define GLOB_SBD_NAME "nd" #define GLOB_SBD_IRQ_NUM (29) +#define GLOB_VERSION "driver version 20091110" #define GLOB_SBD_IOCTL_GC (0x7701) #define GLOB_SBD_IOCTL_WL (0x7702) @@ -272,6 +272,13 @@ static int get_res_blk_num_os(void) return res_blks; } +static void SBD_prepare_flush(struct request_queue *q, struct request *rq) +{ + rq->cmd_type = REQ_TYPE_LINUX_BLOCK; + /* rq->timeout = 5 * HZ; */ + rq->cmd[0] = REQ_LB_OP_FLUSH; +} + /* Transfer a full request. */ static int do_transfer(struct spectra_nand_dev *tr, struct request *req) { @@ -289,7 +296,8 @@ static int do_transfer(struct spectra_nand_dev *tr, struct request *req) IdentifyDeviceData.PagesPerBlock * res_blks_os; - if (req->cmd_type & REQ_FLUSH) { + if (req->cmd_type == REQ_TYPE_LINUX_BLOCK && + req->cmd[0] == REQ_LB_OP_FLUSH) { if (force_flush_cache()) /* Fail to flush cache */ return -EIO; else @@ -589,23 +597,11 @@ int GLOB_SBD_ioctl(struct block_device *bdev, fmode_t mode, return -ENOTTY; } -int GLOB_SBD_unlocked_ioctl(struct block_device *bdev, fmode_t mode, - unsigned int cmd, unsigned long arg) -{ - int ret; - - lock_kernel(); - ret = GLOB_SBD_ioctl(bdev, mode, cmd, arg); - unlock_kernel(); - - return ret; -} - static struct block_device_operations GLOB_SBD_ops = { .owner = THIS_MODULE, .open = GLOB_SBD_open, .release = GLOB_SBD_release, - .ioctl = GLOB_SBD_unlocked_ioctl, + .locked_ioctl = GLOB_SBD_ioctl, .getgeo = GLOB_SBD_getgeo, }; @@ -654,7 +650,8 @@ static int SBD_setup_device(struct spectra_nand_dev *dev, int which) /* Here we force report 512 byte hardware sector size to Kernel */ blk_queue_logical_block_size(dev->queue, 512); - blk_queue_ordered(dev->queue, QUEUE_ORDERED_DRAIN_FLUSH); + blk_queue_ordered(dev->queue, QUEUE_ORDERED_DRAIN_FLUSH, + SBD_prepare_flush); dev->thread = kthread_run(spectra_trans_thread, dev, "nand_thd"); if (IS_ERR(dev->thread)) { diff --git a/trunk/drivers/staging/spectra/flash.c b/trunk/drivers/staging/spectra/flash.c index 9b5218b6ada8..134aa5166a8d 100644 --- a/trunk/drivers/staging/spectra/flash.c +++ b/trunk/drivers/staging/spectra/flash.c @@ -61,6 +61,7 @@ static void FTL_Cache_Read_Page(u8 *pData, u64 dwPageAddr, static void FTL_Cache_Write_Page(u8 *pData, u64 dwPageAddr, u8 cache_blk, u16 flag); static int FTL_Cache_Write(void); +static int FTL_Cache_Write_Back(u8 *pData, u64 blk_addr); static void FTL_Calculate_LRU(void); static u32 FTL_Get_Block_Index(u32 wBlockNum); @@ -85,6 +86,8 @@ static u32 FTL_Replace_MWBlock(void); static int FTL_Replace_Block(u64 blk_addr); static int FTL_Adjust_Relative_Erase_Count(u32 Index_of_MAX); +static int FTL_Flash_Error_Handle(u8 *pData, u64 old_page_addr, u64 blk_addr); + struct device_info_tag DeviceInfo; struct flash_cache_tag Cache; static struct spectra_l2_cache_info cache_l2; @@ -772,7 +775,7 @@ static void dump_cache_l2_table(void) { struct list_head *p; struct spectra_l2_cache_list *pnd; - int n; + int n, i; n = 0; list_for_each(p, &cache_l2.table.list) { @@ -1534,6 +1537,79 @@ static int FTL_Cache_Write_All(u8 *pData, u64 blk_addr) return wResult; } +/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& +* Function: FTL_Cache_Update_Block +* Inputs: pointer to buffer,page address,block address +* Outputs: PASS=0 / FAIL=1 +* Description: It updates the cache +*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ +static int FTL_Cache_Update_Block(u8 *pData, + u64 old_page_addr, u64 blk_addr) +{ + int i, j; + u8 *buf = pData; + int wResult = PASS; + int wFoundInCache; + u64 page_addr; + u64 addr; + u64 old_blk_addr; + u16 page_offset; + + nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", + __FILE__, __LINE__, __func__); + + old_blk_addr = (u64)(old_page_addr >> + DeviceInfo.nBitsInBlockDataSize) * DeviceInfo.wBlockDataSize; + page_offset = (u16)(GLOB_u64_Remainder(old_page_addr, 2) >> + DeviceInfo.nBitsInPageDataSize); + + for (i = 0; i < DeviceInfo.wPagesPerBlock; i += Cache.pages_per_item) { + page_addr = old_blk_addr + i * DeviceInfo.wPageDataSize; + if (i != page_offset) { + wFoundInCache = FAIL; + for (j = 0; j < CACHE_ITEM_NUM; j++) { + addr = Cache.array[j].address; + addr = FTL_Get_Physical_Block_Addr(addr) + + GLOB_u64_Remainder(addr, 2); + if ((addr >= page_addr) && addr < + (page_addr + Cache.cache_item_size)) { + wFoundInCache = PASS; + buf = Cache.array[j].buf; + Cache.array[j].changed = SET; +#if CMD_DMA +#if RESTORE_CACHE_ON_CDMA_CHAIN_FAILURE + int_cache[ftl_cmd_cnt].item = j; + int_cache[ftl_cmd_cnt].cache.address = + Cache.array[j].address; + int_cache[ftl_cmd_cnt].cache.changed = + Cache.array[j].changed; +#endif +#endif + break; + } + } + if (FAIL == wFoundInCache) { + if (ERR == FTL_Cache_Read_All(g_pTempBuf, + page_addr)) { + wResult = FAIL; + break; + } + buf = g_pTempBuf; + } + } else { + buf = pData; + } + + if (FAIL == FTL_Cache_Write_All(buf, + blk_addr + (page_addr - old_blk_addr))) { + wResult = FAIL; + break; + } + } + + return wResult; +} + /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& * Function: FTL_Copy_Block * Inputs: source block address @@ -1622,7 +1698,7 @@ static int get_l2_cache_blks(void) static int erase_l2_cache_blocks(void) { int i, ret = PASS; - u32 pblk, lblk = BAD_BLOCK; + u32 pblk, lblk; u64 addr; u32 *pbt = (u32 *)g_pBlockTable; @@ -1928,6 +2004,87 @@ static int search_l2_cache(u8 *buf, u64 logical_addr) return ret; } +/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& +* Function: FTL_Cache_Write_Back +* Inputs: pointer to data cached in sys memory +* address of free block in flash +* Outputs: PASS=0 / FAIL=1 +* Description: writes all the pages of Cache Block to flash +* +*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ +static int FTL_Cache_Write_Back(u8 *pData, u64 blk_addr) +{ + int i, j, iErase; + u64 old_page_addr, addr, phy_addr; + u32 *pbt = (u32 *)g_pBlockTable; + u32 lba; + + nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", + __FILE__, __LINE__, __func__); + + old_page_addr = FTL_Get_Physical_Block_Addr(blk_addr) + + GLOB_u64_Remainder(blk_addr, 2); + + iErase = (FAIL == FTL_Replace_Block(blk_addr)) ? PASS : FAIL; + + pbt[BLK_FROM_ADDR(blk_addr)] &= (~SPARE_BLOCK); + +#if CMD_DMA + p_BTableChangesDelta = (struct BTableChangesDelta *)g_pBTDelta_Free; + g_pBTDelta_Free += sizeof(struct BTableChangesDelta); + + p_BTableChangesDelta->ftl_cmd_cnt = ftl_cmd_cnt; + p_BTableChangesDelta->BT_Index = (u32)(blk_addr >> + DeviceInfo.nBitsInBlockDataSize); + p_BTableChangesDelta->BT_Entry_Value = + pbt[(u32)(blk_addr >> DeviceInfo.nBitsInBlockDataSize)]; + p_BTableChangesDelta->ValidFields = 0x0C; +#endif + + if (IN_PROGRESS_BLOCK_TABLE != g_cBlockTableStatus) { + g_cBlockTableStatus = IN_PROGRESS_BLOCK_TABLE; + FTL_Write_IN_Progress_Block_Table_Page(); + } + + for (i = 0; i < RETRY_TIMES; i++) { + if (PASS == iErase) { + phy_addr = FTL_Get_Physical_Block_Addr(blk_addr); + if (FAIL == GLOB_FTL_Block_Erase(phy_addr)) { + lba = BLK_FROM_ADDR(blk_addr); + MARK_BLOCK_AS_BAD(pbt[lba]); + i = RETRY_TIMES; + break; + } + } + + for (j = 0; j < CACHE_ITEM_NUM; j++) { + addr = Cache.array[j].address; + if ((addr <= blk_addr) && + ((addr + Cache.cache_item_size) > blk_addr)) + cache_block_to_write = j; + } + + phy_addr = FTL_Get_Physical_Block_Addr(blk_addr); + if (PASS == FTL_Cache_Update_Block(pData, + old_page_addr, phy_addr)) { + cache_block_to_write = UNHIT_CACHE_ITEM; + break; + } else { + iErase = PASS; + } + } + + if (i >= RETRY_TIMES) { + if (ERR == FTL_Flash_Error_Handle(pData, + old_page_addr, blk_addr)) + return ERR; + else + return FAIL; + } + + return PASS; +} + /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& * Function: FTL_Cache_Write_Page * Inputs: Pointer to buffer, page address, cache block number @@ -2213,6 +2370,159 @@ static int FTL_Write_Block_Table(int wForce) return 1; } +/****************************************************************** +* Function: GLOB_FTL_Flash_Format +* Inputs: none +* Outputs: PASS +* Description: The block table stores bad block info, including MDF+ +* blocks gone bad over the ages. Therefore, if we have a +* block table in place, then use it to scan for bad blocks +* If not, then scan for MDF. +* Now, a block table will only be found if spectra was already +* being used. For a fresh flash, we'll go thru scanning for +* MDF. If spectra was being used, then there is a chance that +* the MDF has been corrupted. Spectra avoids writing to the +* first 2 bytes of the spare area to all pages in a block. This +* covers all known flash devices. However, since flash +* manufacturers have no standard of where the MDF is stored, +* this cannot guarantee that the MDF is protected for future +* devices too. The initial scanning for the block table assures +* this. It is ok even if the block table is outdated, as all +* we're looking for are bad block markers. +* Use this when mounting a file system or starting a +* new flash. +* +*********************************************************************/ +static int FTL_Format_Flash(u8 valid_block_table) +{ + u32 i, j; + u32 *pbt = (u32 *)g_pBlockTable; + u32 tempNode; + int ret; + +#if CMD_DMA + u32 *pbtStartingCopy = (u32 *)g_pBTStartingCopy; + if (ftl_cmd_cnt) + return FAIL; +#endif + + if (FAIL == FTL_Check_Block_Table(FAIL)) + valid_block_table = 0; + + if (valid_block_table) { + u8 switched = 1; + u32 block, k; + + k = DeviceInfo.wSpectraStartBlock; + while (switched && (k < DeviceInfo.wSpectraEndBlock)) { + switched = 0; + k++; + for (j = DeviceInfo.wSpectraStartBlock, i = 0; + j <= DeviceInfo.wSpectraEndBlock; + j++, i++) { + block = (pbt[i] & ~BAD_BLOCK) - + DeviceInfo.wSpectraStartBlock; + if (block != i) { + switched = 1; + tempNode = pbt[i]; + pbt[i] = pbt[block]; + pbt[block] = tempNode; + } + } + } + if ((k == DeviceInfo.wSpectraEndBlock) && switched) + valid_block_table = 0; + } + + if (!valid_block_table) { + memset(g_pBlockTable, 0, + DeviceInfo.wDataBlockNum * sizeof(u32)); + memset(g_pWearCounter, 0, + DeviceInfo.wDataBlockNum * sizeof(u8)); + if (DeviceInfo.MLCDevice) + memset(g_pReadCounter, 0, + DeviceInfo.wDataBlockNum * sizeof(u16)); +#if CMD_DMA + memset(g_pBTStartingCopy, 0, + DeviceInfo.wDataBlockNum * sizeof(u32)); + memset(g_pWearCounterCopy, 0, + DeviceInfo.wDataBlockNum * sizeof(u8)); + if (DeviceInfo.MLCDevice) + memset(g_pReadCounterCopy, 0, + DeviceInfo.wDataBlockNum * sizeof(u16)); +#endif + for (j = DeviceInfo.wSpectraStartBlock, i = 0; + j <= DeviceInfo.wSpectraEndBlock; + j++, i++) { + if (GLOB_LLD_Get_Bad_Block((u32)j)) + pbt[i] = (u32)(BAD_BLOCK | j); + } + } + + nand_dbg_print(NAND_DBG_WARN, "Erasing all blocks in the NAND\n"); + + for (j = DeviceInfo.wSpectraStartBlock, i = 0; + j <= DeviceInfo.wSpectraEndBlock; + j++, i++) { + if ((pbt[i] & BAD_BLOCK) != BAD_BLOCK) { + ret = GLOB_LLD_Erase_Block(j); + if (FAIL == ret) { + pbt[i] = (u32)(j); + MARK_BLOCK_AS_BAD(pbt[i]); + nand_dbg_print(NAND_DBG_WARN, + "NAND Program fail in %s, Line %d, " + "Function: %s, new Bad Block %d generated!\n", + __FILE__, __LINE__, __func__, (int)j); + } else { + pbt[i] = (u32)(SPARE_BLOCK | j); + } + } +#if CMD_DMA + pbtStartingCopy[i] = pbt[i]; +#endif + } + + g_wBlockTableOffset = 0; + for (i = 0; (i <= (DeviceInfo.wSpectraEndBlock - + DeviceInfo.wSpectraStartBlock)) + && ((pbt[i] & BAD_BLOCK) == BAD_BLOCK); i++) + ; + if (i > (DeviceInfo.wSpectraEndBlock - DeviceInfo.wSpectraStartBlock)) { + printk(KERN_ERR "All blocks bad!\n"); + return FAIL; + } else { + g_wBlockTableIndex = pbt[i] & ~BAD_BLOCK; + if (i != BLOCK_TABLE_INDEX) { + tempNode = pbt[i]; + pbt[i] = pbt[BLOCK_TABLE_INDEX]; + pbt[BLOCK_TABLE_INDEX] = tempNode; + } + } + pbt[BLOCK_TABLE_INDEX] &= (~SPARE_BLOCK); + +#if CMD_DMA + pbtStartingCopy[BLOCK_TABLE_INDEX] &= (~SPARE_BLOCK); +#endif + + g_cBlockTableStatus = IN_PROGRESS_BLOCK_TABLE; + memset(g_pBTBlocks, 0xFF, + (1 + LAST_BT_ID - FIRST_BT_ID) * sizeof(u32)); + g_pBTBlocks[FIRST_BT_ID-FIRST_BT_ID] = g_wBlockTableIndex; + FTL_Write_Block_Table(FAIL); + + for (i = 0; i < CACHE_ITEM_NUM; i++) { + Cache.array[i].address = NAND_CACHE_INIT_ADDR; + Cache.array[i].use_cnt = 0; + Cache.array[i].changed = CLEAR; + } + +#if (RESTORE_CACHE_ON_CDMA_CHAIN_FAILURE && CMD_DMA) + memcpy((void *)&cache_start_copy, (void *)&Cache, + sizeof(struct flash_cache_tag)); +#endif + return PASS; +} + static int force_format_nand(void) { u32 i; @@ -2721,6 +3031,112 @@ static int FTL_Read_Block_Table(void) return wResult; } + +/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& +* Function: FTL_Flash_Error_Handle +* Inputs: Pointer to data +* Page address +* Block address +* Outputs: PASS=0 / FAIL=1 +* Description: It handles any error occured during Spectra operation +*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ +static int FTL_Flash_Error_Handle(u8 *pData, u64 old_page_addr, + u64 blk_addr) +{ + u32 i; + int j; + u32 tmp_node, blk_node = BLK_FROM_ADDR(blk_addr); + u64 phy_addr; + int wErase = FAIL; + int wResult = FAIL; + u32 *pbt = (u32 *)g_pBlockTable; + + nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", + __FILE__, __LINE__, __func__); + + if (ERR == GLOB_FTL_Garbage_Collection()) + return ERR; + + do { + for (i = DeviceInfo.wSpectraEndBlock - + DeviceInfo.wSpectraStartBlock; + i > 0; i--) { + if (IS_SPARE_BLOCK(i)) { + tmp_node = (u32)(BAD_BLOCK | + pbt[blk_node]); + pbt[blk_node] = (u32)(pbt[i] & + (~SPARE_BLOCK)); + pbt[i] = tmp_node; +#if CMD_DMA + p_BTableChangesDelta = + (struct BTableChangesDelta *) + g_pBTDelta_Free; + g_pBTDelta_Free += + sizeof(struct BTableChangesDelta); + + p_BTableChangesDelta->ftl_cmd_cnt = + ftl_cmd_cnt; + p_BTableChangesDelta->BT_Index = + blk_node; + p_BTableChangesDelta->BT_Entry_Value = + pbt[blk_node]; + p_BTableChangesDelta->ValidFields = 0x0C; + + p_BTableChangesDelta = + (struct BTableChangesDelta *) + g_pBTDelta_Free; + g_pBTDelta_Free += + sizeof(struct BTableChangesDelta); + + p_BTableChangesDelta->ftl_cmd_cnt = + ftl_cmd_cnt; + p_BTableChangesDelta->BT_Index = i; + p_BTableChangesDelta->BT_Entry_Value = pbt[i]; + p_BTableChangesDelta->ValidFields = 0x0C; +#endif + wResult = PASS; + break; + } + } + + if (FAIL == wResult) { + if (FAIL == GLOB_FTL_Garbage_Collection()) + break; + else + continue; + } + + if (IN_PROGRESS_BLOCK_TABLE != g_cBlockTableStatus) { + g_cBlockTableStatus = IN_PROGRESS_BLOCK_TABLE; + FTL_Write_IN_Progress_Block_Table_Page(); + } + + phy_addr = FTL_Get_Physical_Block_Addr(blk_addr); + + for (j = 0; j < RETRY_TIMES; j++) { + if (PASS == wErase) { + if (FAIL == GLOB_FTL_Block_Erase(phy_addr)) { + MARK_BLOCK_AS_BAD(pbt[blk_node]); + break; + } + } + if (PASS == FTL_Cache_Update_Block(pData, + old_page_addr, + phy_addr)) { + wResult = PASS; + break; + } else { + wResult = FAIL; + wErase = PASS; + } + } + } while (FAIL == wResult); + + FTL_Write_Block_Table(FAIL); + + return wResult; +} + /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& * Function: FTL_Get_Page_Num * Inputs: Size in bytes diff --git a/trunk/drivers/usb/gadget/composite.c b/trunk/drivers/usb/gadget/composite.c index 1160c55de7f2..e483f80822d2 100644 --- a/trunk/drivers/usb/gadget/composite.c +++ b/trunk/drivers/usb/gadget/composite.c @@ -723,12 +723,12 @@ int usb_string_ids_tab(struct usb_composite_dev *cdev, struct usb_string *str) /** * usb_string_ids_n() - allocate unused string IDs in batch - * @c: the device whose string descriptor IDs are being allocated + * @cdev: the device whose string descriptor IDs are being allocated * @n: number of string IDs to allocate * Context: single threaded during gadget setup * * Returns the first requested ID. This ID and next @n-1 IDs are now - * valid IDs. At least provided that @n is non-zero because if it + * valid IDs. At least providind that @n is non zore because if it * is, returns last requested ID which is now very useful information. * * @usb_string_ids_n() is called from bind() callbacks to allocate diff --git a/trunk/drivers/usb/gadget/m66592-udc.c b/trunk/drivers/usb/gadget/m66592-udc.c index e03058fe23cb..166bf71fd348 100644 --- a/trunk/drivers/usb/gadget/m66592-udc.c +++ b/trunk/drivers/usb/gadget/m66592-udc.c @@ -1609,7 +1609,6 @@ static int __init m66592_probe(struct platform_device *pdev) /* initialize ucd */ m66592 = kzalloc(sizeof(struct m66592), GFP_KERNEL); if (m66592 == NULL) { - ret = -ENOMEM; pr_err("kzalloc error\n"); goto clean_up; } diff --git a/trunk/drivers/usb/gadget/r8a66597-udc.c b/trunk/drivers/usb/gadget/r8a66597-udc.c index 2456ccd9965e..70a817842755 100644 --- a/trunk/drivers/usb/gadget/r8a66597-udc.c +++ b/trunk/drivers/usb/gadget/r8a66597-udc.c @@ -1557,7 +1557,6 @@ static int __init r8a66597_probe(struct platform_device *pdev) /* initialize ucd */ r8a66597 = kzalloc(sizeof(struct r8a66597), GFP_KERNEL); if (r8a66597 == NULL) { - ret = -ENOMEM; printk(KERN_ERR "kzalloc error\n"); goto clean_up; } diff --git a/trunk/drivers/usb/gadget/uvc_v4l2.c b/trunk/drivers/usb/gadget/uvc_v4l2.c index 5e807f083bc8..2dcffdac86d2 100644 --- a/trunk/drivers/usb/gadget/uvc_v4l2.c +++ b/trunk/drivers/usb/gadget/uvc_v4l2.c @@ -94,7 +94,7 @@ uvc_v4l2_set_format(struct uvc_video *video, struct v4l2_format *fmt) break; } - if (i == ARRAY_SIZE(uvc_formats)) { + if (format == NULL || format->fcc != fmt->fmt.pix.pixelformat) { printk(KERN_INFO "Unsupported format 0x%08x.\n", fmt->fmt.pix.pixelformat); return -EINVAL; diff --git a/trunk/drivers/usb/host/isp1760-hcd.c b/trunk/drivers/usb/host/isp1760-hcd.c index bdba8c5d844a..d1a3dfc9a408 100644 --- a/trunk/drivers/usb/host/isp1760-hcd.c +++ b/trunk/drivers/usb/host/isp1760-hcd.c @@ -829,7 +829,6 @@ static void enqueue_an_ATL_packet(struct usb_hcd *hcd, struct isp1760_qh *qh, * almost immediately. With ISP1761, this register requires a delay of * 195ns between a write and subsequent read (see section 15.1.1.3). */ - mmiowb(); ndelay(195); skip_map = isp1760_readl(hcd->regs + HC_ATL_PTD_SKIPMAP_REG); @@ -871,7 +870,6 @@ static void enqueue_an_INT_packet(struct usb_hcd *hcd, struct isp1760_qh *qh, * almost immediately. With ISP1761, this register requires a delay of * 195ns between a write and subsequent read (see section 15.1.1.3). */ - mmiowb(); ndelay(195); skip_map = isp1760_readl(hcd->regs + HC_INT_PTD_SKIPMAP_REG); diff --git a/trunk/drivers/usb/host/xhci-ring.c b/trunk/drivers/usb/host/xhci-ring.c index 48e60d166ff0..bc3f4f427065 100644 --- a/trunk/drivers/usb/host/xhci-ring.c +++ b/trunk/drivers/usb/host/xhci-ring.c @@ -131,7 +131,7 @@ static void next_trb(struct xhci_hcd *xhci, *seg = (*seg)->next; *trb = ((*seg)->trbs); } else { - (*trb)++; + *trb = (*trb)++; } } @@ -1551,10 +1551,6 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, /* calc actual length */ if (ep->skip) { td->urb->iso_frame_desc[idx].actual_length = 0; - /* Update ring dequeue pointer */ - while (ep_ring->dequeue != td->last_trb) - inc_deq(xhci, ep_ring, false); - inc_deq(xhci, ep_ring, false); return finish_td(xhci, td, event_trb, event, ep, status, true); } diff --git a/trunk/drivers/usb/misc/adutux.c b/trunk/drivers/usb/misc/adutux.c index 801324af9470..d240de097c62 100644 --- a/trunk/drivers/usb/misc/adutux.c +++ b/trunk/drivers/usb/misc/adutux.c @@ -439,7 +439,7 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count, /* drain secondary buffer */ int amount = bytes_to_read < data_in_secondary ? bytes_to_read : data_in_secondary; i = copy_to_user(buffer, dev->read_buffer_secondary+dev->secondary_head, amount); - if (i) { + if (i < 0) { retval = -EFAULT; goto exit; } diff --git a/trunk/drivers/usb/misc/iowarrior.c b/trunk/drivers/usb/misc/iowarrior.c index bc88c79875a1..2de49c8887c5 100644 --- a/trunk/drivers/usb/misc/iowarrior.c +++ b/trunk/drivers/usb/misc/iowarrior.c @@ -542,7 +542,7 @@ static long iowarrior_ioctl(struct file *file, unsigned int cmd, retval = io_res; else { io_res = copy_to_user(user_buffer, buffer, dev->report_size); - if (io_res) + if (io_res < 0) retval = -EFAULT; } break; @@ -574,7 +574,7 @@ static long iowarrior_ioctl(struct file *file, unsigned int cmd, } io_res = copy_to_user((struct iowarrior_info __user *)arg, &info, sizeof(struct iowarrior_info)); - if (io_res) + if (io_res < 0) retval = -EFAULT; break; } diff --git a/trunk/drivers/usb/otg/twl4030-usb.c b/trunk/drivers/usb/otg/twl4030-usb.c index 05aaac1c3861..0e8888588d4e 100644 --- a/trunk/drivers/usb/otg/twl4030-usb.c +++ b/trunk/drivers/usb/otg/twl4030-usb.c @@ -550,7 +550,6 @@ static int __devinit twl4030_usb_probe(struct platform_device *pdev) struct twl4030_usb_data *pdata = pdev->dev.platform_data; struct twl4030_usb *twl; int status, err; - u8 pwr; if (!pdata) { dev_dbg(&pdev->dev, "platform_data not available\n"); @@ -569,10 +568,7 @@ static int __devinit twl4030_usb_probe(struct platform_device *pdev) twl->otg.set_peripheral = twl4030_set_peripheral; twl->otg.set_suspend = twl4030_set_suspend; twl->usb_mode = pdata->usb_mode; - - pwr = twl4030_usb_read(twl, PHY_PWR_CTRL); - - twl->asleep = (pwr & PHY_PWR_PHYPWD); + twl->asleep = 1; /* init spinlock for workqueue */ spin_lock_init(&twl->lock); diff --git a/trunk/drivers/usb/serial/cp210x.c b/trunk/drivers/usb/serial/cp210x.c index 80bf8333bb03..2bef4415c19c 100644 --- a/trunk/drivers/usb/serial/cp210x.c +++ b/trunk/drivers/usb/serial/cp210x.c @@ -222,8 +222,8 @@ static struct usb_serial_driver cp210x_device = { #define BITS_STOP_2 0x0002 /* CP210X_SET_BREAK */ -#define BREAK_ON 0x0001 -#define BREAK_OFF 0x0000 +#define BREAK_ON 0x0000 +#define BREAK_OFF 0x0001 /* CP210X_(SET_MHS|GET_MDMSTS) */ #define CONTROL_DTR 0x0001 diff --git a/trunk/drivers/usb/serial/ftdi_sio.c b/trunk/drivers/usb/serial/ftdi_sio.c index 63ddb2f65cee..eb12d9b096b4 100644 --- a/trunk/drivers/usb/serial/ftdi_sio.c +++ b/trunk/drivers/usb/serial/ftdi_sio.c @@ -180,7 +180,6 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_IOBOARD_PID) }, { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_MINI_IOBOARD_PID) }, { USB_DEVICE(FTDI_VID, FTDI_SPROG_II) }, - { USB_DEVICE(FTDI_VID, FTDI_LENZ_LIUSB_PID) }, { USB_DEVICE(FTDI_VID, FTDI_XF_632_PID) }, { USB_DEVICE(FTDI_VID, FTDI_XF_634_PID) }, { USB_DEVICE(FTDI_VID, FTDI_XF_547_PID) }, @@ -751,8 +750,6 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, XVERVE_SIGNALYZER_SH4_PID), .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { USB_DEVICE(FTDI_VID, SEGWAY_RMP200_PID) }, - { USB_DEVICE(IONICS_VID, IONICS_PLUGCOMPUTER_PID), - .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { }, /* Optional parameter entry */ { } /* Terminating entry */ }; @@ -1379,7 +1376,7 @@ static void ftdi_set_max_packet_size(struct usb_serial_port *port) } /* set max packet size based on descriptor */ - priv->max_packet_size = le16_to_cpu(ep_desc->wMaxPacketSize); + priv->max_packet_size = ep_desc->wMaxPacketSize; dev_info(&udev->dev, "Setting MaxPacketSize %d\n", priv->max_packet_size); } diff --git a/trunk/drivers/usb/serial/ftdi_sio_ids.h b/trunk/drivers/usb/serial/ftdi_sio_ids.h index 2e95857c9633..6e612c52e763 100644 --- a/trunk/drivers/usb/serial/ftdi_sio_ids.h +++ b/trunk/drivers/usb/serial/ftdi_sio_ids.h @@ -110,9 +110,6 @@ /* Propox devices */ #define FTDI_PROPOX_JTAGCABLEII_PID 0xD738 -/* Lenz LI-USB Computer Interface. */ -#define FTDI_LENZ_LIUSB_PID 0xD780 - /* * Xsens Technologies BV products (http://www.xsens.com). */ @@ -991,12 +988,6 @@ #define ALTI2_VID 0x1BC9 #define ALTI2_N3_PID 0x6001 /* Neptune 3 */ -/* - * Ionics PlugComputer - */ -#define IONICS_VID 0x1c0c -#define IONICS_PLUGCOMPUTER_PID 0x0102 - /* * Dresden Elektronik Sensor Terminal Board */ diff --git a/trunk/drivers/usb/serial/generic.c b/trunk/drivers/usb/serial/generic.c index 0b1a13384c6d..ca92f67747cc 100644 --- a/trunk/drivers/usb/serial/generic.c +++ b/trunk/drivers/usb/serial/generic.c @@ -518,7 +518,6 @@ void usb_serial_generic_disconnect(struct usb_serial *serial) for (i = 0; i < serial->num_ports; ++i) generic_cleanup(serial->port[i]); } -EXPORT_SYMBOL_GPL(usb_serial_generic_disconnect); void usb_serial_generic_release(struct usb_serial *serial) { diff --git a/trunk/drivers/usb/serial/io_ti.c b/trunk/drivers/usb/serial/io_ti.c index a7cfc5952937..dc47f986df57 100644 --- a/trunk/drivers/usb/serial/io_ti.c +++ b/trunk/drivers/usb/serial/io_ti.c @@ -1151,7 +1151,7 @@ static int download_fw(struct edgeport_serial *serial) /* Check if we have an old version in the I2C and update if necessary */ - if (download_cur_ver < download_new_ver) { + if (download_cur_ver != download_new_ver) { dbg("%s - Update I2C dld from %d.%d to %d.%d", __func__, firmware_version->Ver_Major, @@ -1284,7 +1284,7 @@ static int download_fw(struct edgeport_serial *serial) kfree(header); kfree(rom_desc); kfree(ti_manuf_desc); - return -EINVAL; + return status; } /* Update I2C with type 0xf2 record with correct diff --git a/trunk/drivers/usb/serial/navman.c b/trunk/drivers/usb/serial/navman.c index 1f00f243c26c..a6b207c84917 100644 --- a/trunk/drivers/usb/serial/navman.c +++ b/trunk/drivers/usb/serial/navman.c @@ -25,7 +25,6 @@ static int debug; static const struct usb_device_id id_table[] = { { USB_DEVICE(0x0a99, 0x0001) }, /* Talon Technology device */ - { USB_DEVICE(0x0df7, 0x0900) }, /* Mobile Action i-gotU */ { }, }; MODULE_DEVICE_TABLE(usb, id_table); diff --git a/trunk/drivers/usb/serial/option.c b/trunk/drivers/usb/serial/option.c index adcbdb994de3..9fc6ea2c681f 100644 --- a/trunk/drivers/usb/serial/option.c +++ b/trunk/drivers/usb/serial/option.c @@ -365,10 +365,6 @@ static void option_instat_callback(struct urb *urb); #define OLIVETTI_VENDOR_ID 0x0b3c #define OLIVETTI_PRODUCT_OLICARD100 0xc000 -/* Celot products */ -#define CELOT_VENDOR_ID 0x211f -#define CELOT_PRODUCT_CT680M 0x6801 - /* some devices interfaces need special handling due to a number of reasons */ enum option_blacklist_reason { OPTION_BLACKLIST_NONE = 0, @@ -891,9 +887,10 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_100F) }, { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1011)}, { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1012)}, + { USB_DEVICE(CINTERION_VENDOR_ID, 0x0047) }, + { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD100) }, - { USB_DEVICE(CELOT_VENDOR_ID, CELOT_PRODUCT_CT680M) }, /* CT-650 CDMA 450 1xEVDO modem */ { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, option_ids); diff --git a/trunk/drivers/usb/serial/pl2303.c b/trunk/drivers/usb/serial/pl2303.c index c98f0fb675ba..6b6001822279 100644 --- a/trunk/drivers/usb/serial/pl2303.c +++ b/trunk/drivers/usb/serial/pl2303.c @@ -86,7 +86,6 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(SUPERIAL_VENDOR_ID, SUPERIAL_PRODUCT_ID) }, { USB_DEVICE(HP_VENDOR_ID, HP_LD220_PRODUCT_ID) }, { USB_DEVICE(CRESSI_VENDOR_ID, CRESSI_EDY_PRODUCT_ID) }, - { USB_DEVICE(ZEAGLE_VENDOR_ID, ZEAGLE_N2ITION3_PRODUCT_ID) }, { USB_DEVICE(SONY_VENDOR_ID, SONY_QN3USB_PRODUCT_ID) }, { USB_DEVICE(SANWA_VENDOR_ID, SANWA_PRODUCT_ID) }, { USB_DEVICE(ADLINK_VENDOR_ID, ADLINK_ND6530_PRODUCT_ID) }, diff --git a/trunk/drivers/usb/serial/pl2303.h b/trunk/drivers/usb/serial/pl2303.h index 43eb9bdad422..a871645389dd 100644 --- a/trunk/drivers/usb/serial/pl2303.h +++ b/trunk/drivers/usb/serial/pl2303.h @@ -128,10 +128,6 @@ #define CRESSI_VENDOR_ID 0x04b8 #define CRESSI_EDY_PRODUCT_ID 0x0521 -/* Zeagle dive computer interface */ -#define ZEAGLE_VENDOR_ID 0x04b8 -#define ZEAGLE_N2ITION3_PRODUCT_ID 0x0522 - /* Sony, USB data cable for CMD-Jxx mobile phones */ #define SONY_VENDOR_ID 0x054c #define SONY_QN3USB_PRODUCT_ID 0x0437 diff --git a/trunk/drivers/usb/serial/ssu100.c b/trunk/drivers/usb/serial/ssu100.c index 660c31f14999..6e82d4f54bc8 100644 --- a/trunk/drivers/usb/serial/ssu100.c +++ b/trunk/drivers/usb/serial/ssu100.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #define QT_OPEN_CLOSE_CHANNEL 0xca @@ -28,11 +27,36 @@ #define QT_HW_FLOW_CONTROL_MASK 0xc5 #define QT_SW_FLOW_CONTROL_MASK 0xc6 +#define MODEM_CTL_REGISTER 0x04 +#define MODEM_STATUS_REGISTER 0x06 + + +#define SERIAL_LSR_OE 0x02 +#define SERIAL_LSR_PE 0x04 +#define SERIAL_LSR_FE 0x08 +#define SERIAL_LSR_BI 0x10 + +#define SERIAL_LSR_TEMT 0x40 + +#define SERIAL_MCR_DTR 0x01 +#define SERIAL_MCR_RTS 0x02 +#define SERIAL_MCR_LOOP 0x10 + +#define SERIAL_MSR_CTS 0x10 +#define SERIAL_MSR_CD 0x80 +#define SERIAL_MSR_RI 0x40 +#define SERIAL_MSR_DSR 0x20 #define SERIAL_MSR_MASK 0xf0 -#define SERIAL_CRTSCTS ((UART_MCR_RTS << 8) | UART_MSR_CTS) +#define SERIAL_CRTSCTS ((SERIAL_MCR_RTS << 8) | SERIAL_MSR_CTS) -#define SERIAL_EVEN_PARITY (UART_LCR_PARITY | UART_LCR_EPAR) +#define SERIAL_8_DATA 0x03 +#define SERIAL_7_DATA 0x02 +#define SERIAL_6_DATA 0x01 +#define SERIAL_5_DATA 0x00 + +#define SERIAL_ODD_PARITY 0X08 +#define SERIAL_EVEN_PARITY 0X18 #define MAX_BAUD_RATE 460800 @@ -75,12 +99,10 @@ static struct usb_driver ssu100_driver = { }; struct ssu100_port_private { - spinlock_t status_lock; u8 shadowLSR; u8 shadowMSR; wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */ unsigned short max_packet_size; - struct async_icount icount; }; static void ssu100_release(struct usb_serial *serial) @@ -128,10 +150,9 @@ static inline int ssu100_getregister(struct usb_device *dev, static inline int ssu100_setregister(struct usb_device *dev, unsigned short uart, - unsigned short reg, u16 data) { - u16 value = (data << 8) | reg; + u16 value = (data << 8) | MODEM_CTL_REGISTER; return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), QT_SET_GET_REGISTER, 0x40, value, uart, @@ -157,11 +178,11 @@ static inline int update_mctrl(struct usb_device *dev, unsigned int set, clear &= ~set; /* 'set' takes precedence over 'clear' */ urb_value = 0; if (set & TIOCM_DTR) - urb_value |= UART_MCR_DTR; + urb_value |= SERIAL_MCR_DTR; if (set & TIOCM_RTS) - urb_value |= UART_MCR_RTS; + urb_value |= SERIAL_MCR_RTS; - result = ssu100_setregister(dev, 0, UART_MCR, urb_value); + result = ssu100_setregister(dev, 0, urb_value); if (result < 0) dbg("%s Error from MODEM_CTRL urb", __func__); @@ -243,24 +264,24 @@ static void ssu100_set_termios(struct tty_struct *tty, if (cflag & PARENB) { if (cflag & PARODD) - urb_value |= UART_LCR_PARITY; + urb_value |= SERIAL_ODD_PARITY; else urb_value |= SERIAL_EVEN_PARITY; } switch (cflag & CSIZE) { case CS5: - urb_value |= UART_LCR_WLEN5; + urb_value |= SERIAL_5_DATA; break; case CS6: - urb_value |= UART_LCR_WLEN6; + urb_value |= SERIAL_6_DATA; break; case CS7: - urb_value |= UART_LCR_WLEN7; + urb_value |= SERIAL_7_DATA; break; default: case CS8: - urb_value |= UART_LCR_WLEN8; + urb_value |= SERIAL_8_DATA; break; } @@ -312,7 +333,6 @@ static int ssu100_open(struct tty_struct *tty, struct usb_serial_port *port) struct ssu100_port_private *priv = usb_get_serial_port_data(port); u8 *data; int result; - unsigned long flags; dbg("%s - port %d", __func__, port->number); @@ -330,10 +350,11 @@ static int ssu100_open(struct tty_struct *tty, struct usb_serial_port *port) return result; } - spin_lock_irqsave(&priv->status_lock, flags); - priv->shadowLSR = data[0]; - priv->shadowMSR = data[1]; - spin_unlock_irqrestore(&priv->status_lock, flags); + priv->shadowLSR = data[0] & (SERIAL_LSR_OE | SERIAL_LSR_PE | + SERIAL_LSR_FE | SERIAL_LSR_BI); + + priv->shadowMSR = data[1] & (SERIAL_MSR_CTS | SERIAL_MSR_DSR | + SERIAL_MSR_RI | SERIAL_MSR_CD); kfree(data); @@ -377,51 +398,11 @@ static int get_serial_info(struct usb_serial_port *port, return 0; } -static int wait_modem_info(struct usb_serial_port *port, unsigned int arg) -{ - struct ssu100_port_private *priv = usb_get_serial_port_data(port); - struct async_icount prev, cur; - unsigned long flags; - - spin_lock_irqsave(&priv->status_lock, flags); - prev = priv->icount; - spin_unlock_irqrestore(&priv->status_lock, flags); - - while (1) { - wait_event_interruptible(priv->delta_msr_wait, - ((priv->icount.rng != prev.rng) || - (priv->icount.dsr != prev.dsr) || - (priv->icount.dcd != prev.dcd) || - (priv->icount.cts != prev.cts))); - - if (signal_pending(current)) - return -ERESTARTSYS; - - spin_lock_irqsave(&priv->status_lock, flags); - cur = priv->icount; - spin_unlock_irqrestore(&priv->status_lock, flags); - - if ((prev.rng == cur.rng) && - (prev.dsr == cur.dsr) && - (prev.dcd == cur.dcd) && - (prev.cts == cur.cts)) - return -EIO; - - if ((arg & TIOCM_RNG && (prev.rng != cur.rng)) || - (arg & TIOCM_DSR && (prev.dsr != cur.dsr)) || - (arg & TIOCM_CD && (prev.dcd != cur.dcd)) || - (arg & TIOCM_CTS && (prev.cts != cur.cts))) - return 0; - } - return 0; -} - static int ssu100_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) { struct usb_serial_port *port = tty->driver_data; struct ssu100_port_private *priv = usb_get_serial_port_data(port); - void __user *user_arg = (void __user *)arg; dbg("%s cmd 0x%04x", __func__, cmd); @@ -431,28 +412,28 @@ static int ssu100_ioctl(struct tty_struct *tty, struct file *file, (struct serial_struct __user *) arg); case TIOCMIWAIT: - return wait_modem_info(port, arg); - - case TIOCGICOUNT: - { - struct serial_icounter_struct icount; - struct async_icount cnow = priv->icount; - memset(&icount, 0, sizeof(icount)); - icount.cts = cnow.cts; - icount.dsr = cnow.dsr; - icount.rng = cnow.rng; - icount.dcd = cnow.dcd; - icount.rx = cnow.rx; - icount.tx = cnow.tx; - icount.frame = cnow.frame; - icount.overrun = cnow.overrun; - icount.parity = cnow.parity; - icount.brk = cnow.brk; - icount.buf_overrun = cnow.buf_overrun; - if (copy_to_user(user_arg, &icount, sizeof(icount))) - return -EFAULT; + while (priv != NULL) { + u8 prevMSR = priv->shadowMSR & SERIAL_MSR_MASK; + interruptible_sleep_on(&priv->delta_msr_wait); + /* see if a signal did it */ + if (signal_pending(current)) + return -ERESTARTSYS; + else { + u8 diff = (priv->shadowMSR & SERIAL_MSR_MASK) ^ prevMSR; + if (!diff) + return -EIO; /* no change => error */ + + /* Return 0 if caller wanted to know about + these bits */ + + if (((arg & TIOCM_RNG) && (diff & SERIAL_MSR_RI)) || + ((arg & TIOCM_DSR) && (diff & SERIAL_MSR_DSR)) || + ((arg & TIOCM_CD) && (diff & SERIAL_MSR_CD)) || + ((arg & TIOCM_CTS) && (diff & SERIAL_MSR_CTS))) + return 0; + } + } return 0; - } default: break; @@ -474,7 +455,6 @@ static void ssu100_set_max_packet_size(struct usb_serial_port *port) unsigned num_endpoints; int i; - unsigned long flags; num_endpoints = interface->cur_altsetting->desc.bNumEndpoints; dev_info(&udev->dev, "Number of endpoints %d\n", num_endpoints); @@ -486,9 +466,7 @@ static void ssu100_set_max_packet_size(struct usb_serial_port *port) } /* set max packet size based on descriptor */ - spin_lock_irqsave(&priv->status_lock, flags); priv->max_packet_size = ep_desc->wMaxPacketSize; - spin_unlock_irqrestore(&priv->status_lock, flags); dev_info(&udev->dev, "Setting MaxPacketSize %d\n", priv->max_packet_size); } @@ -507,9 +485,9 @@ static int ssu100_attach(struct usb_serial *serial) return -ENOMEM; } - spin_lock_init(&priv->status_lock); init_waitqueue_head(&priv->delta_msr_wait); usb_set_serial_port_data(port, priv); + ssu100_set_max_packet_size(port); return ssu100_initdevice(serial->dev); @@ -528,20 +506,20 @@ static int ssu100_tiocmget(struct tty_struct *tty, struct file *file) if (!d) return -ENOMEM; - r = ssu100_getregister(dev, 0, UART_MCR, d); + r = ssu100_getregister(dev, 0, MODEM_CTL_REGISTER, d); if (r < 0) goto mget_out; - r = ssu100_getregister(dev, 0, UART_MSR, d+1); + r = ssu100_getregister(dev, 0, MODEM_STATUS_REGISTER, d+1); if (r < 0) goto mget_out; - r = (d[0] & UART_MCR_DTR ? TIOCM_DTR : 0) | - (d[0] & UART_MCR_RTS ? TIOCM_RTS : 0) | - (d[1] & UART_MSR_CTS ? TIOCM_CTS : 0) | - (d[1] & UART_MSR_DCD ? TIOCM_CAR : 0) | - (d[1] & UART_MSR_RI ? TIOCM_RI : 0) | - (d[1] & UART_MSR_DSR ? TIOCM_DSR : 0); + r = (d[0] & SERIAL_MCR_DTR ? TIOCM_DTR : 0) | + (d[0] & SERIAL_MCR_RTS ? TIOCM_RTS : 0) | + (d[1] & SERIAL_MSR_CTS ? TIOCM_CTS : 0) | + (d[1] & SERIAL_MSR_CD ? TIOCM_CAR : 0) | + (d[1] & SERIAL_MSR_RI ? TIOCM_RI : 0) | + (d[1] & SERIAL_MSR_DSR ? TIOCM_DSR : 0); mget_out: kfree(d); @@ -568,7 +546,7 @@ static void ssu100_dtr_rts(struct usb_serial_port *port, int on) if (!port->serial->disconnected) { /* Disable flow control */ if (!on && - ssu100_setregister(dev, 0, UART_MCR, 0) < 0) + ssu100_setregister(dev, 0, 0) < 0) dev_err(&port->dev, "error from flowcontrol urb\n"); /* drop RTS and DTR */ if (on) @@ -579,88 +557,34 @@ static void ssu100_dtr_rts(struct usb_serial_port *port, int on) mutex_unlock(&port->serial->disc_mutex); } -static void ssu100_update_msr(struct usb_serial_port *port, u8 msr) -{ - struct ssu100_port_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - - spin_lock_irqsave(&priv->status_lock, flags); - priv->shadowMSR = msr; - spin_unlock_irqrestore(&priv->status_lock, flags); - - if (msr & UART_MSR_ANY_DELTA) { - /* update input line counters */ - if (msr & UART_MSR_DCTS) - priv->icount.cts++; - if (msr & UART_MSR_DDSR) - priv->icount.dsr++; - if (msr & UART_MSR_DDCD) - priv->icount.dcd++; - if (msr & UART_MSR_TERI) - priv->icount.rng++; - wake_up_interruptible(&priv->delta_msr_wait); - } -} - -static void ssu100_update_lsr(struct usb_serial_port *port, u8 lsr, - char *tty_flag) -{ - struct ssu100_port_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - - spin_lock_irqsave(&priv->status_lock, flags); - priv->shadowLSR = lsr; - spin_unlock_irqrestore(&priv->status_lock, flags); - - *tty_flag = TTY_NORMAL; - if (lsr & UART_LSR_BRK_ERROR_BITS) { - /* we always want to update icount, but we only want to - * update tty_flag for one case */ - if (lsr & UART_LSR_BI) { - priv->icount.brk++; - *tty_flag = TTY_BREAK; - usb_serial_handle_break(port); - } - if (lsr & UART_LSR_PE) { - priv->icount.parity++; - if (*tty_flag == TTY_NORMAL) - *tty_flag = TTY_PARITY; - } - if (lsr & UART_LSR_FE) { - priv->icount.frame++; - if (*tty_flag == TTY_NORMAL) - *tty_flag = TTY_FRAME; - } - if (lsr & UART_LSR_OE){ - priv->icount.overrun++; - if (*tty_flag == TTY_NORMAL) - *tty_flag = TTY_OVERRUN; - } - } - -} - static int ssu100_process_packet(struct tty_struct *tty, struct usb_serial_port *port, struct ssu100_port_private *priv, char *packet, int len) { int i; - char flag = TTY_NORMAL; + char flag; char *ch; dbg("%s - port %d", __func__, port->number); - if ((len >= 4) && - (packet[0] == 0x1b) && (packet[1] == 0x1b) && + if (len < 4) { + dbg("%s - malformed packet", __func__); + return 0; + } + + if ((packet[0] == 0x1b) && (packet[1] == 0x1b) && ((packet[2] == 0x00) || (packet[2] == 0x01))) { - if (packet[2] == 0x00) { - ssu100_update_lsr(port, packet[3], &flag); - if (flag == TTY_OVERRUN) - tty_insert_flip_char(tty, 0, TTY_OVERRUN); + if (packet[2] == 0x00) + priv->shadowLSR = packet[3] & (SERIAL_LSR_OE | + SERIAL_LSR_PE | + SERIAL_LSR_FE | + SERIAL_LSR_BI); + + if (packet[2] == 0x01) { + priv->shadowMSR = packet[3]; + wake_up_interruptible(&priv->delta_msr_wait); } - if (packet[2] == 0x01) - ssu100_update_msr(port, packet[3]); len -= 4; ch = packet + 4; @@ -707,6 +631,7 @@ static void ssu100_process_read_urb(struct urb *urb) tty_kref_put(tty); } + static struct usb_serial_driver ssu100_device = { .driver = { .owner = THIS_MODULE, @@ -728,7 +653,6 @@ static struct usb_serial_driver ssu100_device = { .tiocmset = ssu100_tiocmset, .ioctl = ssu100_ioctl, .set_termios = ssu100_set_termios, - .disconnect = usb_serial_generic_disconnect, }; static int __init ssu100_init(void) diff --git a/trunk/drivers/usb/serial/usb-serial.c b/trunk/drivers/usb/serial/usb-serial.c index 7a2177c79bde..2a982e62963b 100644 --- a/trunk/drivers/usb/serial/usb-serial.c +++ b/trunk/drivers/usb/serial/usb-serial.c @@ -736,7 +736,6 @@ int usb_serial_probe(struct usb_interface *interface, serial = create_serial(dev, interface, type); if (!serial) { - module_put(type->driver.owner); dev_err(&interface->dev, "%s - out of memory\n", __func__); return -ENOMEM; } @@ -747,11 +746,11 @@ int usb_serial_probe(struct usb_interface *interface, id = get_iface_id(type, interface); retval = type->probe(serial, id); + module_put(type->driver.owner); if (retval) { dbg("sub driver rejected device"); kfree(serial); - module_put(type->driver.owner); return retval; } } @@ -823,7 +822,6 @@ int usb_serial_probe(struct usb_interface *interface, if (num_bulk_in == 0 || num_bulk_out == 0) { dev_info(&interface->dev, "PL-2303 hack: descriptors matched but endpoints did not\n"); kfree(serial); - module_put(type->driver.owner); return -ENODEV; } } @@ -837,15 +835,22 @@ int usb_serial_probe(struct usb_interface *interface, dev_err(&interface->dev, "Generic device with no bulk out, not allowed.\n"); kfree(serial); - module_put(type->driver.owner); return -EIO; } } #endif if (!num_ports) { /* if this device type has a calc_num_ports function, call it */ - if (type->calc_num_ports) + if (type->calc_num_ports) { + if (!try_module_get(type->driver.owner)) { + dev_err(&interface->dev, + "module get failed, exiting\n"); + kfree(serial); + return -EIO; + } num_ports = type->calc_num_ports(serial); + module_put(type->driver.owner); + } if (!num_ports) num_ports = type->num_ports; } @@ -1034,7 +1039,13 @@ int usb_serial_probe(struct usb_interface *interface, /* if this device type has an attach function, call it */ if (type->attach) { + if (!try_module_get(type->driver.owner)) { + dev_err(&interface->dev, + "module get failed, exiting\n"); + goto probe_error; + } retval = type->attach(serial); + module_put(type->driver.owner); if (retval < 0) goto probe_error; serial->attached = 1; @@ -1077,12 +1088,10 @@ int usb_serial_probe(struct usb_interface *interface, exit: /* success */ usb_set_intfdata(interface, serial); - module_put(type->driver.owner); return 0; probe_error: usb_serial_put(serial); - module_put(type->driver.owner); return -EIO; } EXPORT_SYMBOL_GPL(usb_serial_probe); diff --git a/trunk/include/linux/kobject.h b/trunk/include/linux/kobject.h index 7950a37a7146..cf343a852534 100644 --- a/trunk/include/linux/kobject.h +++ b/trunk/include/linux/kobject.h @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -137,8 +136,42 @@ struct kobj_attribute { extern const struct sysfs_ops kobj_sysfs_ops; +/* + * Namespace types which are used to tag kobjects and sysfs entries. + * Network namespace will likely be the first. + */ +enum kobj_ns_type { + KOBJ_NS_TYPE_NONE = 0, + KOBJ_NS_TYPE_NET, + KOBJ_NS_TYPES +}; + struct sock; +/* + * Callbacks so sysfs can determine namespaces + * @current_ns: return calling task's namespace + * @netlink_ns: return namespace to which a sock belongs (right?) + * @initial_ns: return the initial namespace (i.e. init_net_ns) + */ +struct kobj_ns_type_operations { + enum kobj_ns_type type; + const void *(*current_ns)(void); + const void *(*netlink_ns)(struct sock *sk); + const void *(*initial_ns)(void); +}; + +int kobj_ns_type_register(const struct kobj_ns_type_operations *ops); +int kobj_ns_type_registered(enum kobj_ns_type type); +const struct kobj_ns_type_operations *kobj_child_ns_ops(struct kobject *parent); +const struct kobj_ns_type_operations *kobj_ns_ops(struct kobject *kobj); + +const void *kobj_ns_current(enum kobj_ns_type type); +const void *kobj_ns_netlink(enum kobj_ns_type type, struct sock *sk); +const void *kobj_ns_initial(enum kobj_ns_type type); +void kobj_ns_exit(enum kobj_ns_type type, const void *ns); + + /** * struct kset - a set of kobjects of a specific type, belonging to a specific subsystem. * diff --git a/trunk/include/linux/kobject_ns.h b/trunk/include/linux/kobject_ns.h deleted file mode 100644 index 82cb5bf461fb..000000000000 --- a/trunk/include/linux/kobject_ns.h +++ /dev/null @@ -1,56 +0,0 @@ -/* Kernel object name space definitions - * - * Copyright (c) 2002-2003 Patrick Mochel - * Copyright (c) 2002-2003 Open Source Development Labs - * Copyright (c) 2006-2008 Greg Kroah-Hartman - * Copyright (c) 2006-2008 Novell Inc. - * - * Split from kobject.h by David Howells (dhowells@redhat.com) - * - * This file is released under the GPLv2. - * - * Please read Documentation/kobject.txt before using the kobject - * interface, ESPECIALLY the parts about reference counts and object - * destructors. - */ - -#ifndef _LINUX_KOBJECT_NS_H -#define _LINUX_KOBJECT_NS_H - -struct sock; -struct kobject; - -/* - * Namespace types which are used to tag kobjects and sysfs entries. - * Network namespace will likely be the first. - */ -enum kobj_ns_type { - KOBJ_NS_TYPE_NONE = 0, - KOBJ_NS_TYPE_NET, - KOBJ_NS_TYPES -}; - -/* - * Callbacks so sysfs can determine namespaces - * @current_ns: return calling task's namespace - * @netlink_ns: return namespace to which a sock belongs (right?) - * @initial_ns: return the initial namespace (i.e. init_net_ns) - */ -struct kobj_ns_type_operations { - enum kobj_ns_type type; - const void *(*current_ns)(void); - const void *(*netlink_ns)(struct sock *sk); - const void *(*initial_ns)(void); -}; - -int kobj_ns_type_register(const struct kobj_ns_type_operations *ops); -int kobj_ns_type_registered(enum kobj_ns_type type); -const struct kobj_ns_type_operations *kobj_child_ns_ops(struct kobject *parent); -const struct kobj_ns_type_operations *kobj_ns_ops(struct kobject *kobj); - -const void *kobj_ns_current(enum kobj_ns_type type); -const void *kobj_ns_netlink(enum kobj_ns_type type, struct sock *sk); -const void *kobj_ns_initial(enum kobj_ns_type type); -void kobj_ns_exit(enum kobj_ns_type type, const void *ns); - -#endif /* _LINUX_KOBJECT_NS_H */ diff --git a/trunk/include/linux/sysfs.h b/trunk/include/linux/sysfs.h index 96eb576d82fd..3c92121ba9af 100644 --- a/trunk/include/linux/sysfs.h +++ b/trunk/include/linux/sysfs.h @@ -16,7 +16,6 @@ #include #include #include -#include #include struct kobject; diff --git a/trunk/include/linux/usb/composite.h b/trunk/include/linux/usb/composite.h index 617068134ae8..890bc1472190 100644 --- a/trunk/include/linux/usb/composite.h +++ b/trunk/include/linux/usb/composite.h @@ -247,7 +247,6 @@ int usb_add_config(struct usb_composite_dev *, * value; it should return zero on successful initialization. * @unbind: Reverses @bind(); called as a side effect of unregistering * this driver. - * @disconnect: optional driver disconnect method * @suspend: Notifies when the host stops sending USB traffic, * after function notifications * @resume: Notifies configuration when the host restarts USB traffic, diff --git a/trunk/lib/kobject_uevent.c b/trunk/lib/kobject_uevent.c index 70af0a7f97c0..b93579504dfa 100644 --- a/trunk/lib/kobject_uevent.c +++ b/trunk/lib/kobject_uevent.c @@ -123,7 +123,7 @@ static int kobj_usermode_filter(struct kobject *kobj) * @kobj: struct kobject that the action is happening to * @envp_ext: pointer to environmental data * - * Returns 0 if kobject_uevent_env() is completed with success or the + * Returns 0 if kobject_uevent() is completed with success or the * corresponding error when it fails. */ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, @@ -317,7 +317,7 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, EXPORT_SYMBOL_GPL(kobject_uevent_env); /** - * kobject_uevent - notify userspace by sending an uevent + * kobject_uevent - notify userspace by ending an uevent * * @action: action that is happening * @kobj: struct kobject that the action is happening to