From 6dc2f0c7df6cefda5932ac8bcd9ca5ef45de36ee Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Thu, 2 Jun 2005 14:02:02 -0700 Subject: [PATCH] ppc64: cleanup iseries runlight support The iseries has a bar graph on the front panel that shows how busy it is. The operating system sets and clears a bit in the CTRL register to control it. Instead of going to the complexity of using a thread info bit, just set and clear it in the idle loop. Also create two helper functions, ppc64_runlatch_on and ppc64_runlatch_off. Finally don't use the short form of the SPR defines. Signed-off-by: Anton Blanchard Acked-by: Stephen Rothwell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/ppc64/kernel/entry.S | 9 --------- arch/ppc64/kernel/head.S | 10 +++++----- arch/ppc64/kernel/idle.c | 8 +++----- arch/ppc64/kernel/process.c | 3 --- arch/ppc64/kernel/sysfs.c | 8 ++------ 5 files changed, 10 insertions(+), 28 deletions(-) (limited to 'arch') diff --git a/arch/ppc64/kernel/entry.S b/arch/ppc64/kernel/entry.S index d3604056e1a9..b61572eb2a71 100644 --- a/arch/ppc64/kernel/entry.S +++ b/arch/ppc64/kernel/entry.S @@ -436,15 +436,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) REST_8GPRS(14, r1) REST_10GPRS(22, r1) -#ifdef CONFIG_PPC_ISERIES - clrrdi r7,r1,THREAD_SHIFT /* get current_thread_info() */ - ld r7,TI_FLAGS(r7) /* Get run light flag */ - mfspr r9,CTRLF - srdi r7,r7,TIF_RUN_LIGHT - insrdi r9,r7,1,63 /* Insert run light into CTRL */ - mtspr CTRLT,r9 -#endif - /* convert old thread to its task_struct for return value */ addi r3,r3,-THREAD ld r7,_NIP(r1) /* Return to _switch caller in new task */ diff --git a/arch/ppc64/kernel/head.S b/arch/ppc64/kernel/head.S index 92a744c31ab1..346dbf606b5d 100644 --- a/arch/ppc64/kernel/head.S +++ b/arch/ppc64/kernel/head.S @@ -626,10 +626,10 @@ system_reset_iSeries: lhz r24,PACAPACAINDEX(r13) /* Get processor # */ cmpwi 0,r24,0 /* Are we processor 0? */ beq .__start_initialization_iSeries /* Start up the first processor */ - mfspr r4,CTRLF - li r5,RUNLATCH /* Turn off the run light */ + mfspr r4,SPRN_CTRLF + li r5,CTRL_RUNLATCH /* Turn off the run light */ andc r4,r4,r5 - mtspr CTRLT,r4 + mtspr SPRN_CTRLT,r4 1: HMT_LOW @@ -2082,9 +2082,9 @@ _GLOBAL(hmt_start_secondary) mfspr r4, HID0 ori r4, r4, 0x1 mtspr HID0, r4 - mfspr r4, CTRLF + mfspr r4, SPRN_CTRLF oris r4, r4, 0x40 - mtspr CTRLT, r4 + mtspr SPRN_CTRLT, r4 blr #endif diff --git a/arch/ppc64/kernel/idle.c b/arch/ppc64/kernel/idle.c index 6abc621d3ba0..f24ce2b87200 100644 --- a/arch/ppc64/kernel/idle.c +++ b/arch/ppc64/kernel/idle.c @@ -75,13 +75,9 @@ static int iSeries_idle(void) { struct paca_struct *lpaca; long oldval; - unsigned long CTRL; /* ensure iSeries run light will be out when idle */ - clear_thread_flag(TIF_RUN_LIGHT); - CTRL = mfspr(CTRLF); - CTRL &= ~RUNLATCH; - mtspr(CTRLT, CTRL); + ppc64_runlatch_off(); lpaca = get_paca(); @@ -111,7 +107,9 @@ static int iSeries_idle(void) } } + ppc64_runlatch_on(); schedule(); + ppc64_runlatch_off(); } return 0; diff --git a/arch/ppc64/kernel/process.c b/arch/ppc64/kernel/process.c index 8b0686122738..cdfecbeb331f 100644 --- a/arch/ppc64/kernel/process.c +++ b/arch/ppc64/kernel/process.c @@ -378,9 +378,6 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp, childregs->gpr[1] = sp + sizeof(struct pt_regs); p->thread.regs = NULL; /* no user register state */ clear_ti_thread_flag(p->thread_info, TIF_32BIT); -#ifdef CONFIG_PPC_ISERIES - set_ti_thread_flag(p->thread_info, TIF_RUN_LIGHT); -#endif } else { childregs->gpr[1] = usp; p->thread.regs = childregs; diff --git a/arch/ppc64/kernel/sysfs.c b/arch/ppc64/kernel/sysfs.c index 0925694c3ce5..c8fa6569b2fd 100644 --- a/arch/ppc64/kernel/sysfs.c +++ b/arch/ppc64/kernel/sysfs.c @@ -113,7 +113,6 @@ void ppc64_enable_pmcs(void) #ifdef CONFIG_PPC_PSERIES unsigned long set, reset; int ret; - unsigned int ctrl; #endif /* CONFIG_PPC_PSERIES */ /* Only need to enable them once */ @@ -167,11 +166,8 @@ void ppc64_enable_pmcs(void) * On SMT machines we have to set the run latch in the ctrl register * in order to make PMC6 spin. */ - if (cpu_has_feature(CPU_FTR_SMT)) { - ctrl = mfspr(CTRLF); - ctrl |= RUNLATCH; - mtspr(CTRLT, ctrl); - } + if (cpu_has_feature(CPU_FTR_SMT)) + ppc64_runlatch_on(); #endif /* CONFIG_PPC_PSERIES */ } -- cgit v1.2.2 From c4eb2a93319d61923635c84a5f5e68965b14c754 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Thu, 2 Jun 2005 14:02:03 -0700 Subject: [PATCH] ppc64: remove decr_overclock Now that we have HZ=1000 there is much less of a need for decr_overclock. Remove it. Leave spread_lpevents but move it into iSeries_setup.c. We should look at making event spreading the default some day. Signed-off-by: Anton Blanchard Acked-by: Stephen Rothwell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/ppc64/kernel/iSeries_setup.c | 22 +++++++++++++++ arch/ppc64/kernel/setup.c | 56 +-------------------------------------- arch/ppc64/kernel/smp.c | 3 +-- 3 files changed, 24 insertions(+), 57 deletions(-) (limited to 'arch') diff --git a/arch/ppc64/kernel/iSeries_setup.c b/arch/ppc64/kernel/iSeries_setup.c index da20120f2261..6d06eb550a3f 100644 --- a/arch/ppc64/kernel/iSeries_setup.c +++ b/arch/ppc64/kernel/iSeries_setup.c @@ -852,6 +852,28 @@ static int __init iSeries_src_init(void) late_initcall(iSeries_src_init); +static int set_spread_lpevents(char *str) +{ + unsigned long i; + unsigned long val = simple_strtoul(str, NULL, 0); + + /* + * The parameter is the number of processors to share in processing + * lp events. + */ + if (( val > 0) && (val <= NR_CPUS)) { + for (i = 1; i < val; ++i) + paca[i].lpqueue_ptr = paca[0].lpqueue_ptr; + + printk("lpevent processing spread over %ld processors\n", val); + } else { + printk("invalid spread_lpevents %ld\n", val); + } + + return 1; +} +__setup("spread_lpevents=", set_spread_lpevents); + void __init iSeries_early_setup(void) { iSeries_fixup_klimit(); diff --git a/arch/ppc64/kernel/setup.c b/arch/ppc64/kernel/setup.c index 21c57f539c29..dce198d39328 100644 --- a/arch/ppc64/kernel/setup.c +++ b/arch/ppc64/kernel/setup.c @@ -103,11 +103,6 @@ extern void unflatten_device_tree(void); extern void smp_release_cpus(void); -unsigned long decr_overclock = 1; -unsigned long decr_overclock_proc0 = 1; -unsigned long decr_overclock_set = 0; -unsigned long decr_overclock_proc0_set = 0; - int have_of = 1; int boot_cpuid = 0; int boot_cpuid_phys = 0; @@ -1120,64 +1115,15 @@ void ppc64_dump_msg(unsigned int src, const char *msg) printk("[dump]%04x %s\n", src, msg); } -int set_spread_lpevents( char * str ) -{ - /* The parameter is the number of processors to share in processing lp events */ - unsigned long i; - unsigned long val = simple_strtoul( str, NULL, 0 ); - if ( ( val > 0 ) && ( val <= NR_CPUS ) ) { - for ( i=1; idefault_decr = tb_ticks_per_jiffy / decr_overclock_proc0; + lpaca->default_decr = tb_ticks_per_jiffy; lpaca->next_jiffy_update_tb = get_tb() + tb_ticks_per_jiffy; } -int set_decr_overclock_proc0( char * str ) -{ - unsigned long val = simple_strtoul( str, NULL, 0 ); - if ( ( val >= 1 ) && ( val <= 48 ) ) { - decr_overclock_proc0_set = 1; - decr_overclock_proc0 = val; - printk("proc 0 decrementer overclock factor of %ld\n", val); - } - else - printk("invalid proc 0 decrementer overclock factor of %ld\n", val); - return 1; -} - -int set_decr_overclock( char * str ) -{ - unsigned long val = simple_strtoul( str, NULL, 0 ); - if ( ( val >= 1 ) && ( val <= 48 ) ) { - decr_overclock_set = 1; - decr_overclock = val; - printk("decrementer overclock factor of %ld\n", val); - } - else - printk("invalid decrementer overclock factor of %ld\n", val); - return 1; - -} - -__setup("spread_lpevents=", set_spread_lpevents ); -__setup("decr_overclock_proc0=", set_decr_overclock_proc0 ); -__setup("decr_overclock=", set_decr_overclock ); - #ifndef CONFIG_PPC_ISERIES /* * This function can be used by platforms to "find" legacy serial ports. diff --git a/arch/ppc64/kernel/smp.c b/arch/ppc64/kernel/smp.c index 3b906cd94037..9ef5d36d6b25 100644 --- a/arch/ppc64/kernel/smp.c +++ b/arch/ppc64/kernel/smp.c @@ -334,7 +334,6 @@ void smp_call_function_interrupt(void) } } -extern unsigned long decr_overclock; extern struct gettimeofday_struct do_gtod; struct thread_info *current_set[NR_CPUS]; @@ -491,7 +490,7 @@ int __devinit __cpu_up(unsigned int cpu) if (smp_ops->cpu_bootable && !smp_ops->cpu_bootable(cpu)) return -EINVAL; - paca[cpu].default_decr = tb_ticks_per_jiffy / decr_overclock; + paca[cpu].default_decr = tb_ticks_per_jiffy; if (!cpu_has_feature(CPU_FTR_SLB)) { void *tmp; -- cgit v1.2.2 From b05a720b374ac6af05b2fd4c70bb2c61a9f461ca Mon Sep 17 00:00:00 2001 From: Greg Ungerer Date: Fri, 3 Jun 2005 11:35:20 +1000 Subject: [PATCH] m68knommu: fix scheduling and race problems in idle loop Re-work the m68knommu specific idle code according to suggestions from Nick Piggin . A couple of rules that we need to follow: 1. Preempt should now disabled over idle routines. Should only be enabled to call schedule() then disabled again. 3. When cpu_idle finds (need_resched() == 'true'), it should call schedule(). It should not call schedule() otherwise. Also fix interrupt locking around the need_resched() and cpu stop state so that there is no race condition. Signed-off-by: Greg Ungerer Signed-off-by: Linus Torvalds --- arch/m68knommu/kernel/process.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) (limited to 'arch') diff --git a/arch/m68knommu/kernel/process.c b/arch/m68knommu/kernel/process.c index 2b6c9d32b7a6..c4a33f265dc0 100644 --- a/arch/m68knommu/kernel/process.c +++ b/arch/m68knommu/kernel/process.c @@ -45,11 +45,13 @@ asmlinkage void ret_from_fork(void); */ void default_idle(void) { - while(1) { - if (need_resched()) - __asm__("stop #0x2000" : : : "cc"); - schedule(); + local_irq_disable(); + while (!need_resched()) { + /* This stop will re-enable interrupts */ + __asm__("stop #0x2000" : : : "cc"); + local_irq_disable(); } + local_irq_enable(); } void (*idle)(void) = default_idle; @@ -63,7 +65,12 @@ void (*idle)(void) = default_idle; void cpu_idle(void) { /* endless idle loop with no priority at all */ - idle(); + while (1) { + idle(); + preempt_enable_no_resched(); + schedule(); + preempt_disable(); + } } void machine_restart(char * __unused) -- cgit v1.2.2 From 8be3de3fd8469154a2b3e18a4712032dac5b4a53 Mon Sep 17 00:00:00 2001 From: Nathan Lynch Date: Fri, 3 Jun 2005 14:25:25 -0500 Subject: [PATCH] prom_find_machine_type typo breaks pSeries lpar boot A typo in prom_find_machine_type from Ben's recent patch "ppc64: Fix result code handling in prom_init" prevents pSeries LPAR systems from booting. Tested on a pSeries 570 and OpenPower 720 (both Power5 LPAR). Signed-off-by: Nathan Lynch Signed-off-by: Linus Torvalds --- arch/ppc64/kernel/prom_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/ppc64/kernel/prom_init.c b/arch/ppc64/kernel/prom_init.c index 1ac531ba7056..b7683abfbe6a 100644 --- a/arch/ppc64/kernel/prom_init.c +++ b/arch/ppc64/kernel/prom_init.c @@ -1370,7 +1370,7 @@ static int __init prom_find_machine_type(void) } /* Default to pSeries. We need to know if we are running LPAR */ rtas = call_prom("finddevice", 1, 1, ADDR("/rtas")); - if (!PHANDLE_VALID(rtas)) { + if (PHANDLE_VALID(rtas)) { int x = prom_getproplen(rtas, "ibm,hypertas-functions"); if (x != PROM_ERROR) { prom_printf("Hypertas detected, assuming LPAR !\n"); -- cgit v1.2.2 From 778959db97c7ed8eed4025916916b17a4629ce3d Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Sat, 4 Jun 2005 15:43:30 -0700 Subject: [PATCH] s390: ptrace peek and poke The special cases of peek and poke on acrs[15] and the fpc register are not handled correctly. A poke on acrs[15] will clobber the 4 bytes after the access registers in the thread_info structure. That happens to be the kernel stack pointer. A poke on the fpc with an invalid value is not caught by the validity check. On the next context switch the broken fpc value will cause a program check in the kernel. Improving the checks in peek and poke fixes this. Signed-off-by: Martin Schwidefsky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/s390/kernel/ptrace.c | 48 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 43 insertions(+), 5 deletions(-) (limited to 'arch') diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index 26889366929a..329d9391c83d 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c @@ -40,6 +40,7 @@ #include #include #include +#include #ifdef CONFIG_S390_SUPPORT #include "compat_ptrace.h" @@ -130,13 +131,19 @@ static int peek_user(struct task_struct *child, addr_t addr, addr_t data) { struct user *dummy = NULL; - addr_t offset, tmp; + addr_t offset, tmp, mask; /* * Stupid gdb peeks/pokes the access registers in 64 bit with * an alignment of 4. Programmers from hell... */ - if ((addr & 3) || addr > sizeof(struct user) - __ADDR_MASK) + mask = __ADDR_MASK; +#ifdef CONFIG_ARCH_S390X + if (addr >= (addr_t) &dummy->regs.acrs && + addr < (addr_t) &dummy->regs.orig_gpr2) + mask = 3; +#endif + if ((addr & mask) || addr > sizeof(struct user) - __ADDR_MASK) return -EIO; if (addr < (addr_t) &dummy->regs.acrs) { @@ -153,6 +160,16 @@ peek_user(struct task_struct *child, addr_t addr, addr_t data) * access registers are stored in the thread structure */ offset = addr - (addr_t) &dummy->regs.acrs; +#ifdef CONFIG_ARCH_S390X + /* + * Very special case: old & broken 64 bit gdb reading + * from acrs[15]. Result is a 64 bit value. Read the + * 32 bit acrs[15] value and shift it by 32. Sick... + */ + if (addr == (addr_t) &dummy->regs.acrs[15]) + tmp = ((unsigned long) child->thread.acrs[15]) << 32; + else +#endif tmp = *(addr_t *)((addr_t) &child->thread.acrs + offset); } else if (addr == (addr_t) &dummy->regs.orig_gpr2) { @@ -167,6 +184,9 @@ peek_user(struct task_struct *child, addr_t addr, addr_t data) */ offset = addr - (addr_t) &dummy->regs.fp_regs; tmp = *(addr_t *)((addr_t) &child->thread.fp_regs + offset); + if (addr == (addr_t) &dummy->regs.fp_regs.fpc) + tmp &= (unsigned long) FPC_VALID_MASK + << (BITS_PER_LONG - 32); } else if (addr < (addr_t) (&dummy->regs.per_info + 1)) { /* @@ -191,13 +211,19 @@ static int poke_user(struct task_struct *child, addr_t addr, addr_t data) { struct user *dummy = NULL; - addr_t offset; + addr_t offset, mask; /* * Stupid gdb peeks/pokes the access registers in 64 bit with * an alignment of 4. Programmers from hell indeed... */ - if ((addr & 3) || addr > sizeof(struct user) - __ADDR_MASK) + mask = __ADDR_MASK; +#ifdef CONFIG_ARCH_S390X + if (addr >= (addr_t) &dummy->regs.acrs && + addr < (addr_t) &dummy->regs.orig_gpr2) + mask = 3; +#endif + if ((addr & mask) || addr > sizeof(struct user) - __ADDR_MASK) return -EIO; if (addr < (addr_t) &dummy->regs.acrs) { @@ -224,6 +250,17 @@ poke_user(struct task_struct *child, addr_t addr, addr_t data) * access registers are stored in the thread structure */ offset = addr - (addr_t) &dummy->regs.acrs; +#ifdef CONFIG_ARCH_S390X + /* + * Very special case: old & broken 64 bit gdb writing + * to acrs[15] with a 64 bit value. Ignore the lower + * half of the value and write the upper 32 bit to + * acrs[15]. Sick... + */ + if (addr == (addr_t) &dummy->regs.acrs[15]) + child->thread.acrs[15] = (unsigned int) (data >> 32); + else +#endif *(addr_t *)((addr_t) &child->thread.acrs + offset) = data; } else if (addr == (addr_t) &dummy->regs.orig_gpr2) { @@ -237,7 +274,8 @@ poke_user(struct task_struct *child, addr_t addr, addr_t data) * floating point regs. are stored in the thread structure */ if (addr == (addr_t) &dummy->regs.fp_regs.fpc && - (data & ~FPC_VALID_MASK) != 0) + (data & ~((unsigned long) FPC_VALID_MASK + << (BITS_PER_LONG - 32))) != 0) return -EINVAL; offset = addr - (addr_t) &dummy->regs.fp_regs; *(addr_t *)((addr_t) &child->thread.fp_regs + offset) = data; -- cgit v1.2.2 From c5c3a6d8fe923b8780b9cd10e72344b8cf8518b5 Mon Sep 17 00:00:00 2001 From: Bodo Stroesser Date: Sat, 4 Jun 2005 15:43:32 -0700 Subject: [PATCH] s390: uml ptrace fixes To make UML build and run on s390, I needed to do these two little changes: 1) UML includes some of the subarch's (s390) headers. I had to change one of them with the following one-liner, to make this compile. AFAICS, this change doesn't break compilation of s390 itself. 2) UML needs to intercept syscalls via ptrace to invalidate the syscall, read syscall's parameters and write the result with the result of UML's syscall processing. Also, UML needs to make sure, that the host does no syscall restart processing. On i386 for example, this can be done by writing -1 to orig_eax on the 2nd syscall interception (orig_eax is the syscall number, which after the interception is used as a "interrupt was a syscall" flag only. Unfortunately, s390 holds syscall number and syscall result in gpr2 and its "interrupt was a syscall" flag (trap) is unreachable via ptrace. So I changed the host to set trap to -1, if the syscall number is changed to an invalid value on the first syscall interception. Signed-off-by: Martin Schwidefsky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/s390/kernel/ptrace.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'arch') diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index 329d9391c83d..06afa3103ace 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c @@ -760,6 +760,13 @@ syscall_trace(struct pt_regs *regs, int entryexit) ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ? 0x80 : 0)); + /* + * If the debuffer has set an invalid system call number, + * we prepare to skip the system call restart handling. + */ + if (!entryexit && regs->gprs[2] >= NR_syscalls) + regs->trap = -1; + /* * this isn't the same as continuing with a signal, but it will do * for normal use. strace only continues with a signal if the -- cgit v1.2.2 From 595bf2aacae96d0f87352a1ff5476b79e52e212f Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Sat, 4 Jun 2005 15:43:32 -0700 Subject: [PATCH] s390: in_interrupt vs. in_atomic The condition for no context in do_exception checks for hard and soft interrupts by using in_interrupt() but not for preemption. This is bad for the users of __copy_from/to_user_inatomic because the fault handler might call schedule although the preemption count is != 0. Use in_atomic() instead in_interrupt(). Signed-off-by: Martin Schwidefsky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/s390/mm/fault.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index 80306bc8c799..75fde949d125 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c @@ -207,7 +207,7 @@ do_exception(struct pt_regs *regs, unsigned long error_code, int is_protection) * we are not in an interrupt and that there is a * user context. */ - if (user_address == 0 || in_interrupt() || !mm) + if (user_address == 0 || in_atomic() || !mm) goto no_context; /* -- cgit v1.2.2 From f26d583e41aedad8159acf9533fa287d7209dfbf Mon Sep 17 00:00:00 2001 From: Gerald Schaefer Date: Sat, 4 Jun 2005 15:43:33 -0700 Subject: [PATCH] s390: deadlock in appldata The system might hang when using appldata_mem with high I/O traffic and a large number of devices. The spinlocks bdev_lock and swaplock are acquired via calls to si_meminfo() and si_swapinfo() from a tasklet, i.e. interrupt context, which can lead to a deadlock. Replace tasklet with work queue. Signed-off-by: Martin Schwidefsky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/s390/appldata/appldata_base.c | 72 ++++++++++++++++++++--------------- arch/s390/appldata/appldata_mem.c | 2 +- arch/s390/appldata/appldata_net_sum.c | 2 +- arch/s390/appldata/appldata_os.c | 4 +- 4 files changed, 45 insertions(+), 35 deletions(-) (limited to 'arch') diff --git a/arch/s390/appldata/appldata_base.c b/arch/s390/appldata/appldata_base.c index 01ae1964c938..c067435bae45 100644 --- a/arch/s390/appldata/appldata_base.c +++ b/arch/s390/appldata/appldata_base.c @@ -28,6 +28,7 @@ //#include #include #include +#include #include "appldata.h" @@ -133,9 +134,12 @@ static int appldata_interval = APPLDATA_CPU_INTERVAL; static int appldata_timer_active; /* - * Tasklet + * Work queue */ -static struct tasklet_struct appldata_tasklet_struct; +static struct workqueue_struct *appldata_wq; +static void appldata_work_fn(void *data); +static DECLARE_WORK(appldata_work, appldata_work_fn, NULL); + /* * Ops list @@ -144,11 +148,11 @@ static DEFINE_SPINLOCK(appldata_ops_lock); static LIST_HEAD(appldata_ops_list); -/************************* timer, tasklet, DIAG ******************************/ +/*************************** timer, work, DIAG *******************************/ /* * appldata_timer_function() * - * schedule tasklet and reschedule timer + * schedule work and reschedule timer */ static void appldata_timer_function(unsigned long data, struct pt_regs *regs) { @@ -157,22 +161,22 @@ static void appldata_timer_function(unsigned long data, struct pt_regs *regs) atomic_read(&appldata_expire_count)); if (atomic_dec_and_test(&appldata_expire_count)) { atomic_set(&appldata_expire_count, num_online_cpus()); - tasklet_schedule((struct tasklet_struct *) data); + queue_work(appldata_wq, (struct work_struct *) data); } } /* - * appldata_tasklet_function() + * appldata_work_fn() * * call data gathering function for each (active) module */ -static void appldata_tasklet_function(unsigned long data) +static void appldata_work_fn(void *data) { struct list_head *lh; struct appldata_ops *ops; int i; - P_DEBUG(" -= Tasklet =-\n"); + P_DEBUG(" -= Work Queue =-\n"); i = 0; spin_lock(&appldata_ops_lock); list_for_each(lh, &appldata_ops_list) { @@ -231,7 +235,7 @@ static int appldata_diag(char record_nr, u16 function, unsigned long buffer, : "=d" (ry) : "d" (&(appldata_parameter_list)) : "cc"); return (int) ry; } -/********************** timer, tasklet, DIAG ***************************/ +/************************ timer, work, DIAG ****************************/ /****************************** /proc stuff **********************************/ @@ -411,7 +415,7 @@ appldata_generic_handler(ctl_table *ctl, int write, struct file *filp, struct list_head *lh; found = 0; - spin_lock_bh(&appldata_ops_lock); + spin_lock(&appldata_ops_lock); list_for_each(lh, &appldata_ops_list) { tmp_ops = list_entry(lh, struct appldata_ops, list); if (&tmp_ops->ctl_table[2] == ctl) { @@ -419,15 +423,15 @@ appldata_generic_handler(ctl_table *ctl, int write, struct file *filp, } } if (!found) { - spin_unlock_bh(&appldata_ops_lock); + spin_unlock(&appldata_ops_lock); return -ENODEV; } ops = ctl->data; if (!try_module_get(ops->owner)) { // protect this function - spin_unlock_bh(&appldata_ops_lock); + spin_unlock(&appldata_ops_lock); return -ENODEV; } - spin_unlock_bh(&appldata_ops_lock); + spin_unlock(&appldata_ops_lock); if (!*lenp || *ppos) { *lenp = 0; @@ -451,10 +455,11 @@ appldata_generic_handler(ctl_table *ctl, int write, struct file *filp, return -EFAULT; } - spin_lock_bh(&appldata_ops_lock); + spin_lock(&appldata_ops_lock); if ((buf[0] == '1') && (ops->active == 0)) { - if (!try_module_get(ops->owner)) { // protect tasklet - spin_unlock_bh(&appldata_ops_lock); + // protect work queue callback + if (!try_module_get(ops->owner)) { + spin_unlock(&appldata_ops_lock); module_put(ops->owner); return -ENODEV; } @@ -485,7 +490,7 @@ appldata_generic_handler(ctl_table *ctl, int write, struct file *filp, } module_put(ops->owner); } - spin_unlock_bh(&appldata_ops_lock); + spin_unlock(&appldata_ops_lock); out: *lenp = len; *ppos += len; @@ -529,7 +534,7 @@ int appldata_register_ops(struct appldata_ops *ops) } memset(ops->ctl_table, 0, 4*sizeof(struct ctl_table)); - spin_lock_bh(&appldata_ops_lock); + spin_lock(&appldata_ops_lock); list_for_each(lh, &appldata_ops_list) { tmp_ops = list_entry(lh, struct appldata_ops, list); P_DEBUG("register_ops loop: %i) name = %s, ctl = %i\n", @@ -541,18 +546,18 @@ int appldata_register_ops(struct appldata_ops *ops) APPLDATA_PROC_NAME_LENGTH) == 0) { P_ERROR("Name \"%s\" already registered!\n", ops->name); kfree(ops->ctl_table); - spin_unlock_bh(&appldata_ops_lock); + spin_unlock(&appldata_ops_lock); return -EBUSY; } if (tmp_ops->ctl_nr == ops->ctl_nr) { P_ERROR("ctl_nr %i already registered!\n", ops->ctl_nr); kfree(ops->ctl_table); - spin_unlock_bh(&appldata_ops_lock); + spin_unlock(&appldata_ops_lock); return -EBUSY; } } list_add(&ops->list, &appldata_ops_list); - spin_unlock_bh(&appldata_ops_lock); + spin_unlock(&appldata_ops_lock); ops->ctl_table[0].ctl_name = CTL_APPLDATA; ops->ctl_table[0].procname = appldata_proc_name; @@ -583,12 +588,12 @@ int appldata_register_ops(struct appldata_ops *ops) */ void appldata_unregister_ops(struct appldata_ops *ops) { - spin_lock_bh(&appldata_ops_lock); + spin_lock(&appldata_ops_lock); unregister_sysctl_table(ops->sysctl_header); list_del(&ops->list); kfree(ops->ctl_table); ops->ctl_table = NULL; - spin_unlock_bh(&appldata_ops_lock); + spin_unlock(&appldata_ops_lock); P_INFO("%s-ops unregistered!\n", ops->name); } /********************** module-ops management **************************/ @@ -602,7 +607,7 @@ appldata_online_cpu(int cpu) init_virt_timer(&per_cpu(appldata_timer, cpu)); per_cpu(appldata_timer, cpu).function = appldata_timer_function; per_cpu(appldata_timer, cpu).data = (unsigned long) - &appldata_tasklet_struct; + &appldata_work; atomic_inc(&appldata_expire_count); spin_lock(&appldata_timer_lock); __appldata_vtimer_setup(APPLDATA_MOD_TIMER); @@ -615,7 +620,7 @@ appldata_offline_cpu(int cpu) del_virt_timer(&per_cpu(appldata_timer, cpu)); if (atomic_dec_and_test(&appldata_expire_count)) { atomic_set(&appldata_expire_count, num_online_cpus()); - tasklet_schedule(&appldata_tasklet_struct); + queue_work(appldata_wq, &appldata_work); } spin_lock(&appldata_timer_lock); __appldata_vtimer_setup(APPLDATA_MOD_TIMER); @@ -648,7 +653,7 @@ static struct notifier_block __devinitdata appldata_nb = { /* * appldata_init() * - * init timer and tasklet, register /proc entries + * init timer, register /proc entries */ static int __init appldata_init(void) { @@ -657,6 +662,12 @@ static int __init appldata_init(void) P_DEBUG("sizeof(parameter_list) = %lu\n", sizeof(struct appldata_parameter_list)); + appldata_wq = create_singlethread_workqueue("appldata"); + if (!appldata_wq) { + P_ERROR("Could not create work queue\n"); + return -ENOMEM; + } + for_each_online_cpu(i) appldata_online_cpu(i); @@ -670,7 +681,6 @@ static int __init appldata_init(void) appldata_table[1].de->owner = THIS_MODULE; #endif - tasklet_init(&appldata_tasklet_struct, appldata_tasklet_function, 0); P_DEBUG("Base interface initialized.\n"); return 0; } @@ -678,7 +688,7 @@ static int __init appldata_init(void) /* * appldata_exit() * - * stop timer and tasklet, unregister /proc entries + * stop timer, unregister /proc entries */ static void __exit appldata_exit(void) { @@ -690,7 +700,7 @@ static void __exit appldata_exit(void) /* * ops list should be empty, but just in case something went wrong... */ - spin_lock_bh(&appldata_ops_lock); + spin_lock(&appldata_ops_lock); list_for_each(lh, &appldata_ops_list) { ops = list_entry(lh, struct appldata_ops, list); rc = appldata_diag(ops->record_nr, APPLDATA_STOP_REC, @@ -700,7 +710,7 @@ static void __exit appldata_exit(void) "return code: %d\n", ops->name, rc); } } - spin_unlock_bh(&appldata_ops_lock); + spin_unlock(&appldata_ops_lock); for_each_online_cpu(i) appldata_offline_cpu(i); @@ -709,7 +719,7 @@ static void __exit appldata_exit(void) unregister_sysctl_table(appldata_sysctl_header); - tasklet_kill(&appldata_tasklet_struct); + destroy_workqueue(appldata_wq); P_DEBUG("... module unloaded!\n"); } /**************************** init / exit ******************************/ diff --git a/arch/s390/appldata/appldata_mem.c b/arch/s390/appldata/appldata_mem.c index 462ee9a84e76..f0e2fbed3d4c 100644 --- a/arch/s390/appldata/appldata_mem.c +++ b/arch/s390/appldata/appldata_mem.c @@ -68,7 +68,7 @@ struct appldata_mem_data { u64 pgmajfault; /* page faults (major only) */ // <-- New in 2.6 -} appldata_mem_data; +} __attribute__((packed)) appldata_mem_data; static inline void appldata_debug_print(struct appldata_mem_data *mem_data) diff --git a/arch/s390/appldata/appldata_net_sum.c b/arch/s390/appldata/appldata_net_sum.c index dd61638d3027..2a4c7432db4a 100644 --- a/arch/s390/appldata/appldata_net_sum.c +++ b/arch/s390/appldata/appldata_net_sum.c @@ -57,7 +57,7 @@ struct appldata_net_sum_data { u64 rx_dropped; /* no space in linux buffers */ u64 tx_dropped; /* no space available in linux */ u64 collisions; /* collisions while transmitting */ -} appldata_net_sum_data; +} __attribute__((packed)) appldata_net_sum_data; static inline void appldata_print_debug(struct appldata_net_sum_data *net_data) diff --git a/arch/s390/appldata/appldata_os.c b/arch/s390/appldata/appldata_os.c index b83f07484551..e0a476bf4fd6 100644 --- a/arch/s390/appldata/appldata_os.c +++ b/arch/s390/appldata/appldata_os.c @@ -49,7 +49,7 @@ struct appldata_os_per_cpu { u32 per_cpu_softirq; /* ... spent in softirqs */ u32 per_cpu_iowait; /* ... spent while waiting for I/O */ // <-- New in 2.6 -}; +} __attribute__((packed)); struct appldata_os_data { u64 timestamp; @@ -75,7 +75,7 @@ struct appldata_os_data { /* per cpu data */ struct appldata_os_per_cpu os_cpu[0]; -}; +} __attribute__((packed)); static struct appldata_os_data *appldata_os_data; -- cgit v1.2.2