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, &current->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;
                }
        }


Reply via email to