On Thu, 2004-03-25 at 17:47, Benjamin Herrenschmidt wrote: > Hi ! > > I've start looking into the various issues of running > CONFIG_PREEMPT on ppc32. I found some problems, there > may be more, but here's a first patch that should apply on a > recent 2.6.x. > > I suggest if you want to try this out that you run with the > various kernel debugging options enabled. Report me remaining > problems.
And here's an updated version of that patch that doesn't break sleep on laptops. Ben. ===== arch/ppc/kernel/entry.S 1.44 vs edited ===== --- 1.44/arch/ppc/kernel/entry.S Mon Feb 16 18:06:27 2004 +++ edited/arch/ppc/kernel/entry.S Thu Mar 25 14:10:41 2004 @@ -171,9 +171,10 @@ bl do_show_syscall #endif /* SHOW_SYSCALLS */ rlwinm r10,r1,0,0,18 /* current_thread_info() */ + lwz r11,TI_LOCAL_FLAGS(r10) + rlwinm r11,r11,0,~_TIFL_FORCE_NOERROR + stw r11,TI_LOCAL_FLAGS(r10) lwz r11,TI_FLAGS(r10) - rlwinm r11,r11,0,~_TIF_FORCE_NOERROR - stw r11,TI_FLAGS(r10) andi. r11,r11,_TIF_SYSCALL_TRACE bne- syscall_dotrace syscall_dotrace_cont: @@ -196,8 +197,8 @@ cmpl 0,r3,r11 rlwinm r12,r1,0,0,18 /* current_thread_info() */ blt+ 30f - lwz r11,TI_FLAGS(r12) - andi. r11,r11,_TIF_FORCE_NOERROR + lwz r11,TI_LOCAL_FLAGS(r12) + andi. r11,r11,_TIFL_FORCE_NOERROR bne 30f neg r3,r3 lwz r10,_CCR(r1) /* Set SO bit in CR */ ===== arch/ppc/kernel/pci.c 1.57 vs edited ===== --- 1.57/arch/ppc/kernel/pci.c Tue Mar 23 16:42:53 2004 +++ edited/arch/ppc/kernel/pci.c Thu Mar 25 15:09:51 2004 @@ -1557,6 +1557,7 @@ } vma->vm_pgoff = offset >> PAGE_SHIFT; + return ret; } ===== arch/ppc/kernel/process.c 1.57 vs edited ===== --- 1.57/arch/ppc/kernel/process.c Mon Nov 17 12:29:47 2003 +++ edited/arch/ppc/kernel/process.c Thu Mar 25 14:35:07 2004 @@ -164,6 +164,7 @@ void enable_kernel_altivec(void) { + preempt_disable(); #ifdef CONFIG_SMP if (current->thread.regs && (current->thread.regs->msr & MSR_VEC)) giveup_altivec(current); @@ -172,12 +173,14 @@ #else giveup_altivec(last_task_used_altivec); #endif /* __SMP __ */ + preempt_enable(); } #endif /* CONFIG_ALTIVEC */ void enable_kernel_fp(void) { + preempt_disable(); #ifdef CONFIG_SMP if (current->thread.regs && (current->thread.regs->msr & MSR_FP)) giveup_fpu(current); @@ -186,13 +189,16 @@ #else giveup_fpu(last_task_used_math); #endif /* CONFIG_SMP */ + preempt_enable(); } int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs) { + preempt_disable(); if (regs->msr & MSR_FP) giveup_fpu(current); + preempt_enable(); memcpy(fpregs, ¤t->thread.fpr[0], sizeof(*fpregs)); return 1; } @@ -330,12 +336,14 @@ if (regs == NULL) return; + preempt_disable(); if (regs->msr & MSR_FP) giveup_fpu(current); #ifdef CONFIG_ALTIVEC if (regs->msr & MSR_VEC) giveup_altivec(current); #endif /* CONFIG_ALTIVEC */ + preempt_enable(); } /* @@ -480,12 +488,14 @@ error = PTR_ERR(filename); if (IS_ERR(filename)) goto out; + preempt_disable(); if (regs->msr & MSR_FP) giveup_fpu(current); #ifdef CONFIG_ALTIVEC if (regs->msr & MSR_VEC) giveup_altivec(current); #endif /* CONFIG_ALTIVEC */ + preempt_enable(); error = do_execve(filename, (char __user *__user *) a1, (char __user *__user *) a2, regs); if (error == 0) ===== arch/ppc/kernel/traps.c 1.44 vs edited ===== --- 1.44/arch/ppc/kernel/traps.c Tue Mar 23 12:46:58 2004 +++ edited/arch/ppc/kernel/traps.c Thu Mar 25 13:21:47 2004 @@ -438,8 +438,14 @@ int code = 0; u32 fpscr; + /* We must make sure the FP state is consistent with + * our MSR_FP in regs + */ + preempt_disable(); if (regs->msr & MSR_FP) giveup_fpu(current); + preempt_enable(); + fpscr = current->thread.fpscr; fpscr &= fpscr << 22; /* mask summary bits with enables */ if (fpscr & FPSCR_VX) @@ -603,8 +609,11 @@ void AltivecAssistException(struct pt_regs *regs) { + preempt_disable(); if (regs->msr & MSR_VEC) giveup_altivec(current); + preempt_enable(); + /* XXX quick hack for now: set the non-Java bit in the VSCR */ current->thread.vscr.u[3] |= 0x10000; } ===== arch/ppc/syslib/prom_init.c 1.26 vs edited ===== --- 1.26/arch/ppc/syslib/prom_init.c Sat Feb 14 19:29:14 2004 +++ edited/arch/ppc/syslib/prom_init.c Wed Mar 24 12:35:20 2004 @@ -44,8 +44,12 @@ * things like "driver,AAPL,MacOS,PowerPC" properties. But this value * does need to be big enough to ensure that we don't lose things * like the interrupt-map property on a PCI-PCI bridge. + * + * 24/03/2004 - BenH: Bump that limitation to 512k and remove the + * filter for the MacOS drivers as we may now run + * those in a shell */ -#define MAX_PROPERTY_LENGTH 4096 +#define MAX_PROPERTY_LENGTH (512 * 1024) #ifndef FB_MAX /* avoid pulling in all of the fb stuff */ #define FB_MAX 8 ===== drivers/macintosh/adbhid.c 1.33 vs edited ===== --- 1.33/drivers/macintosh/adbhid.c Sat Feb 14 19:29:16 2004 +++ edited/drivers/macintosh/adbhid.c Thu Mar 25 16:16:56 2004 @@ -107,7 +107,6 @@ static void adbhid_probe(void); static void adbhid_input_keycode(int, int, int, struct pt_regs *); -static void leds_done(struct adb_request *); static void init_trackpad(int id); static void init_trackball(int id); @@ -446,24 +445,54 @@ static struct adb_request led_request; static int leds_pending[16]; +static int leds_req_pending; static int pending_devs[16]; static int pending_led_start=0; static int pending_led_end=0; +static spinlock_t leds_lock = SPIN_LOCK_UNLOCKED; + +static void leds_done(struct adb_request *req) +{ + int leds, device; + unsigned long flags; + + spin_lock_irqsave(&leds_lock, flags); + + if (pending_led_start != pending_led_end) { + device = pending_devs[pending_led_start]; + leds = leds_pending[device] & 0xff; + leds_pending[device] = 0; + pending_led_start++; + pending_led_start = (pending_led_start < 16) ? pending_led_start : 0; + } else + leds_req_pending = 0; + + spin_unlock_irqrestore(&leds_lock, flags); + if (leds_req_pending) + adb_request(&led_request, leds_done, 0, 3, + ADB_WRITEREG(device, KEYB_LEDREG), 0xff, ~leds); +} static void real_leds(unsigned char leds, int device) { - if (led_request.complete) { - adb_request(&led_request, leds_done, 0, 3, - ADB_WRITEREG(device, KEYB_LEDREG), 0xff, - ~leds); - } else { - if (!(leds_pending[device] & 0x100)) { - pending_devs[pending_led_end] = device; - pending_led_end++; - pending_led_end = (pending_led_end < 16) ? pending_led_end : 0; + unsigned long flags; + + spin_lock_irqsave(&leds_lock, flags); + if (!leds_req_pending) { + leds_req_pending = 1; + spin_unlock_irqrestore(&leds_lock, flags); + adb_request(&led_request, leds_done, 0, 3, + ADB_WRITEREG(device, KEYB_LEDREG), 0xff, ~leds); + return; + } else { + if (!(leds_pending[device] & 0x100)) { + pending_devs[pending_led_end] = device; + pending_led_end++; + pending_led_end = (pending_led_end < 16) ? pending_led_end : 0; + } + leds_pending[device] = leds | 0x100; } - leds_pending[device] = leds | 0x100; - } + spin_unlock_irqrestore(&leds_lock, flags); } /* @@ -487,21 +516,6 @@ return -1; } -static void leds_done(struct adb_request *req) -{ - int leds,device; - - if (pending_led_start != pending_led_end) { - device = pending_devs[pending_led_start]; - leds = leds_pending[device] & 0xff; - leds_pending[device] = 0; - pending_led_start++; - pending_led_start = (pending_led_start < 16) ? pending_led_start : 0; - real_leds(leds,device); - } - -} - static int adb_message_handler(struct notifier_block *this, unsigned long code, void *x) { @@ -518,7 +532,7 @@ } /* Stop pending led requests */ - while(!led_request.complete) + while(leds_req_pending) adb_poll(); break; ===== drivers/macintosh/via-pmu.c 1.61 vs edited ===== --- 1.61/drivers/macintosh/via-pmu.c Thu Mar 4 13:04:36 2004 +++ edited/drivers/macintosh/via-pmu.c Thu Mar 25 18:52:00 2004 @@ -137,7 +137,8 @@ static int data_len; static volatile int adb_int_pending; static volatile int disable_poll; -static struct adb_request bright_req_1, bright_req_2, bright_req_3; +static struct adb_request bright_req_1, bright_req_2; +static unsigned long async_req_locks; static struct device_node *vias; static int pmu_kind = PMU_UNKNOWN; static int pmu_fully_inited = 0; @@ -404,7 +405,6 @@ bright_req_1.complete = 1; bright_req_2.complete = 1; - bright_req_3.complete = 1; #ifdef CONFIG_PMAC_PBOOK batt_req.complete = 1; if (pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) >= 0) @@ -710,6 +710,8 @@ pmu_batteries[pmu_cur_battery].amperage = amperage; pmu_batteries[pmu_cur_battery].voltage = voltage; pmu_batteries[pmu_cur_battery].time_remaining = time; + + clear_bit(0, &async_req_locks); } static void __pmac @@ -785,12 +787,14 @@ pmu_batteries[pmu_cur_battery].time_remaining = 0; pmu_cur_battery = (pmu_cur_battery + 1) % pmu_battery_count; + + clear_bit(0, &async_req_locks); } static void __pmac query_battery_state(void) { - if (!batt_req.complete) + if (test_and_set_bit(0, &async_req_locks)) return; if (pmu_kind == PMU_OHARE_BASED) pmu_request(&batt_req, done_battery_state_ohare, @@ -1690,20 +1694,30 @@ return 0; } +static void __openfirmware +pmu_bright_complete(struct adb_request *req) +{ + if (req == &bright_req_1) + clear_bit(1, &async_req_locks); + if (req == &bright_req_2) + clear_bit(2, &async_req_locks); +} + static int __openfirmware pmu_set_backlight_level(int level, void* data) { if (vias == NULL) return -ENODEV; - if (!bright_req_1.complete) + if (test_and_set_bit(1, &async_req_locks)) return -EAGAIN; - pmu_request(&bright_req_1, NULL, 2, PMU_BACKLIGHT_BRIGHT, + pmu_request(&bright_req_1, pmu_bright_complete, 2, PMU_BACKLIGHT_BRIGHT, backlight_to_bright[level]); - if (!bright_req_2.complete) + if (test_and_set_bit(2, &async_req_locks)) return -EAGAIN; - pmu_request(&bright_req_2, NULL, 2, PMU_POWER_CTRL, PMU_POW_BACKLIGHT - | (level > BACKLIGHT_OFF ? PMU_POW_ON : PMU_POW_OFF)); + pmu_request(&bright_req_2, pmu_bright_complete, 2, PMU_POWER_CTRL, + PMU_POW_BACKLIGHT | (level > BACKLIGHT_OFF ? + PMU_POW_ON : PMU_POW_OFF)); return 0; } @@ -2330,6 +2344,8 @@ return -EBUSY; } + preempt_disable(); + /* Make sure the decrementer won't interrupt us */ asm volatile("mtdec %0" : : "r" (0x7fffffff)); /* Make sure any pending DEC interrupt occurring while we did @@ -2352,6 +2368,7 @@ if (ret) { wakeup_decrementer(); local_irq_enable(); + preempt_enable(); device_resume(); broadcast_wake(); printk(KERN_ERR "Driver powerdown failed\n"); @@ -2360,7 +2377,8 @@ /* Wait for completion of async backlight requests */ while (!bright_req_1.complete || !bright_req_2.complete || - !bright_req_3.complete || !batt_req.complete) + + !batt_req.complete) pmu_poll(); /* Giveup the lazy FPU & vec so we don't have to back them @@ -2398,6 +2416,8 @@ pmu_blink(1); + preempt_enable(); + /* Resume devices */ device_resume(); @@ -2673,9 +2693,9 @@ mb(); pmac_wakeup_devices(); - pbook_free_pci_save(); iounmap(mem_ctrl); + return 0; } ===== include/asm-ppc/ptrace.h 1.11 vs edited ===== --- 1.11/include/asm-ppc/ptrace.h Tue Jun 24 14:45:56 2003 +++ edited/include/asm-ppc/ptrace.h Thu Mar 25 14:02:44 2004 @@ -49,7 +49,10 @@ #define instruction_pointer(regs) ((regs)->nip) #define user_mode(regs) (((regs)->msr & MSR_PR) != 0) -#define force_successful_syscall_return() set_thread_flag(TIF_FORCE_NOERROR) +#define force_successful_syscall_return() \ + do { \ + current_thread_info()->local_flags |= _TIFL_FORCE_NOERROR; \ + } while(0) /* * We use the least-significant bit of the trap field to indicate ===== include/asm-ppc/thread_info.h 1.17 vs edited ===== --- 1.17/include/asm-ppc/thread_info.h Tue Oct 14 17:28:08 2003 +++ edited/include/asm-ppc/thread_info.h Thu Mar 25 14:03:56 2004 @@ -18,6 +18,7 @@ struct task_struct *task; /* main task structure */ struct exec_domain *exec_domain; /* execution domain */ unsigned long flags; /* low level flags */ + unsigned long local_flags; /* non-racy flags */ int cpu; /* cpu we're on */ int preempt_count; struct restart_block restart_block; @@ -28,6 +29,7 @@ .task = &tsk, \ .exec_domain = &default_exec_domain, \ .flags = 0, \ + .local_flags = 0, \ .cpu = 0, \ .preempt_count = 1, \ .restart_block = { \ @@ -69,8 +71,9 @@ #define TI_TASK 0 #define TI_EXECDOMAIN 4 #define TI_FLAGS 8 -#define TI_CPU 12 -#define TI_PREEMPT 16 +#define TI_LOCAL_FLAGS 12 +#define TI_CPU 16 +#define TI_PREEMPT 20 #define PREEMPT_ACTIVE 0x4000000 @@ -83,16 +86,22 @@ #define TIF_NEED_RESCHED 3 /* rescheduling necessary */ #define TIF_POLLING_NRFLAG 4 /* true if poll_idle() is polling TIF_NEED_RESCHED */ -#define TIF_FORCE_NOERROR 5 /* don't return error from current - syscall even if result < 0 */ - /* as above, but as bit values */ #define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE) #define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME) #define _TIF_SIGPENDING (1<<TIF_SIGPENDING) #define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED) #define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG) -#define _TIF_FORCE_NOERROR (1<<TIF_FORCE_NOERROR) + +/* + * Non racy (local) flags bit numbers + */ +#define TIFL_FORCE_NOERROR 0 /* don't return error from current + syscall even if result < 0 */ + +/* as above, but as bit values */ +#define _TIFL_FORCE_NOERROR (1<<TIFL_FORCE_NOERROR) + #endif /* __KERNEL__ */ ===== sound/oss/dmasound/dmasound_core.c 1.22 vs edited ===== --- 1.22/sound/oss/dmasound/dmasound_core.c Mon Feb 9 13:18:52 2004 +++ edited/sound/oss/dmasound/dmasound_core.c Thu Mar 25 18:41:02 2004 @@ -1004,6 +1004,7 @@ static int sq_fsync(struct file *filp, struct dentry *dentry) { int rc = 0; + int timeout = 5; write_sq.syncing |= 1; sq_play(); /* there may be an incomplete frame waiting */ @@ -1016,6 +1017,12 @@ * and clear the queue. */ sq_reset_output(); rc = -EINTR; + break; + } + if (!--timeout) { + printk(KERN_WARNING "dmasound: Timeout draining output\n"); + sq_reset_output(); + rc = -EIO; break; } }