]> git.hungrycats.org Git - linux/commitdiff
[PATCH] powerbook via-pmu races
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>
Thu, 25 Mar 2004 14:00:19 +0000 (06:00 -0800)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Thu, 25 Mar 2004 14:00:19 +0000 (06:00 -0800)
This fixes some racy code in the management of asynchronous brightness
and battery requests in the via-pmu driver used on powerbooks.  This
should fix some preempt related problems (there is no SMP powerbook yet :)

drivers/macintosh/via-pmu.c

index f3e644bbab196b8d0cfce7e9c7c39bb6fc972548..b9831678b7ccb392b29b27e6252f0bb5b2d5e800 100644 (file)
@@ -137,7 +137,8 @@ static int data_index;
 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 @@ static int __init via_pmu_start(void)
 
        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 @@ done_battery_state_ohare(struct adb_request* req)
        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 @@ done_battery_state_smart(struct adb_request* req)
                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 @@ pmu_set_backlight_enable(int on, int level, void* data)
        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 @@ pmac_suspend_devices(void)
                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 @@ pmac_suspend_devices(void)
        if (ret) {
                wakeup_decrementer();
                local_irq_enable();
+               preempt_enable();
                device_resume();
                broadcast_wake();
                printk(KERN_ERR "Driver powerdown failed\n");
@@ -2360,7 +2377,8 @@ pmac_suspend_devices(void)
 
        /* 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 @@ pmac_wakeup_devices(void)
 
        pmu_blink(1);
 
+       preempt_enable();
+
        /* Resume devices */
        device_resume();
 
@@ -2673,9 +2693,9 @@ powerbook_sleep_3400(void)
                mb();
 
        pmac_wakeup_devices();
-
        pbook_free_pci_save();
        iounmap(mem_ctrl);
+
        return 0;
 }