Commit 0d925852 authored by Benjamin Herrenschmidt's avatar Benjamin Herrenschmidt Committed by Linus Torvalds

[PATCH] powerbook via-pmu races

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 :)
parent 8631d753
...@@ -137,7 +137,8 @@ static int data_index; ...@@ -137,7 +137,8 @@ static int data_index;
static int data_len; static int data_len;
static volatile int adb_int_pending; static volatile int adb_int_pending;
static volatile int disable_poll; 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 struct device_node *vias;
static int pmu_kind = PMU_UNKNOWN; static int pmu_kind = PMU_UNKNOWN;
static int pmu_fully_inited = 0; static int pmu_fully_inited = 0;
...@@ -404,7 +405,6 @@ static int __init via_pmu_start(void) ...@@ -404,7 +405,6 @@ static int __init via_pmu_start(void)
bright_req_1.complete = 1; bright_req_1.complete = 1;
bright_req_2.complete = 1; bright_req_2.complete = 1;
bright_req_3.complete = 1;
#ifdef CONFIG_PMAC_PBOOK #ifdef CONFIG_PMAC_PBOOK
batt_req.complete = 1; batt_req.complete = 1;
if (pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) >= 0) if (pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) >= 0)
...@@ -710,6 +710,8 @@ done_battery_state_ohare(struct adb_request* req) ...@@ -710,6 +710,8 @@ done_battery_state_ohare(struct adb_request* req)
pmu_batteries[pmu_cur_battery].amperage = amperage; pmu_batteries[pmu_cur_battery].amperage = amperage;
pmu_batteries[pmu_cur_battery].voltage = voltage; pmu_batteries[pmu_cur_battery].voltage = voltage;
pmu_batteries[pmu_cur_battery].time_remaining = time; pmu_batteries[pmu_cur_battery].time_remaining = time;
clear_bit(0, &async_req_locks);
} }
static void __pmac static void __pmac
...@@ -785,12 +787,14 @@ done_battery_state_smart(struct adb_request* req) ...@@ -785,12 +787,14 @@ done_battery_state_smart(struct adb_request* req)
pmu_batteries[pmu_cur_battery].time_remaining = 0; pmu_batteries[pmu_cur_battery].time_remaining = 0;
pmu_cur_battery = (pmu_cur_battery + 1) % pmu_battery_count; pmu_cur_battery = (pmu_cur_battery + 1) % pmu_battery_count;
clear_bit(0, &async_req_locks);
} }
static void __pmac static void __pmac
query_battery_state(void) query_battery_state(void)
{ {
if (!batt_req.complete) if (test_and_set_bit(0, &async_req_locks))
return; return;
if (pmu_kind == PMU_OHARE_BASED) if (pmu_kind == PMU_OHARE_BASED)
pmu_request(&batt_req, done_battery_state_ohare, pmu_request(&batt_req, done_battery_state_ohare,
...@@ -1690,20 +1694,30 @@ pmu_set_backlight_enable(int on, int level, void* data) ...@@ -1690,20 +1694,30 @@ pmu_set_backlight_enable(int on, int level, void* data)
return 0; 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 static int __openfirmware
pmu_set_backlight_level(int level, void* data) pmu_set_backlight_level(int level, void* data)
{ {
if (vias == NULL) if (vias == NULL)
return -ENODEV; return -ENODEV;
if (!bright_req_1.complete) if (test_and_set_bit(1, &async_req_locks))
return -EAGAIN; 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]); backlight_to_bright[level]);
if (!bright_req_2.complete) if (test_and_set_bit(2, &async_req_locks))
return -EAGAIN; return -EAGAIN;
pmu_request(&bright_req_2, NULL, 2, PMU_POWER_CTRL, PMU_POW_BACKLIGHT pmu_request(&bright_req_2, pmu_bright_complete, 2, PMU_POWER_CTRL,
| (level > BACKLIGHT_OFF ? PMU_POW_ON : PMU_POW_OFF)); PMU_POW_BACKLIGHT | (level > BACKLIGHT_OFF ?
PMU_POW_ON : PMU_POW_OFF));
return 0; return 0;
} }
...@@ -2330,6 +2344,8 @@ pmac_suspend_devices(void) ...@@ -2330,6 +2344,8 @@ pmac_suspend_devices(void)
return -EBUSY; return -EBUSY;
} }
preempt_disable();
/* Make sure the decrementer won't interrupt us */ /* Make sure the decrementer won't interrupt us */
asm volatile("mtdec %0" : : "r" (0x7fffffff)); asm volatile("mtdec %0" : : "r" (0x7fffffff));
/* Make sure any pending DEC interrupt occurring while we did /* Make sure any pending DEC interrupt occurring while we did
...@@ -2352,6 +2368,7 @@ pmac_suspend_devices(void) ...@@ -2352,6 +2368,7 @@ pmac_suspend_devices(void)
if (ret) { if (ret) {
wakeup_decrementer(); wakeup_decrementer();
local_irq_enable(); local_irq_enable();
preempt_enable();
device_resume(); device_resume();
broadcast_wake(); broadcast_wake();
printk(KERN_ERR "Driver powerdown failed\n"); printk(KERN_ERR "Driver powerdown failed\n");
...@@ -2360,7 +2377,8 @@ pmac_suspend_devices(void) ...@@ -2360,7 +2377,8 @@ pmac_suspend_devices(void)
/* Wait for completion of async backlight requests */ /* Wait for completion of async backlight requests */
while (!bright_req_1.complete || !bright_req_2.complete || while (!bright_req_1.complete || !bright_req_2.complete ||
!bright_req_3.complete || !batt_req.complete)
!batt_req.complete)
pmu_poll(); pmu_poll();
/* Giveup the lazy FPU & vec so we don't have to back them /* Giveup the lazy FPU & vec so we don't have to back them
...@@ -2398,6 +2416,8 @@ pmac_wakeup_devices(void) ...@@ -2398,6 +2416,8 @@ pmac_wakeup_devices(void)
pmu_blink(1); pmu_blink(1);
preempt_enable();
/* Resume devices */ /* Resume devices */
device_resume(); device_resume();
...@@ -2673,9 +2693,9 @@ powerbook_sleep_3400(void) ...@@ -2673,9 +2693,9 @@ powerbook_sleep_3400(void)
mb(); mb();
pmac_wakeup_devices(); pmac_wakeup_devices();
pbook_free_pci_save(); pbook_free_pci_save();
iounmap(mem_ctrl); iounmap(mem_ctrl);
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment