diff options
Diffstat (limited to 'drivers/pci/hotplug/shpchp_ctrl.c')
-rw-r--r-- | drivers/pci/hotplug/shpchp_ctrl.c | 808 |
1 files changed, 287 insertions, 521 deletions
diff --git a/drivers/pci/hotplug/shpchp_ctrl.c b/drivers/pci/hotplug/shpchp_ctrl.c index 643252d9bf3b..4e6381481c55 100644 --- a/drivers/pci/hotplug/shpchp_ctrl.c +++ b/drivers/pci/hotplug/shpchp_ctrl.c | |||
@@ -32,65 +32,50 @@ | |||
32 | #include <linux/types.h> | 32 | #include <linux/types.h> |
33 | #include <linux/smp_lock.h> | 33 | #include <linux/smp_lock.h> |
34 | #include <linux/pci.h> | 34 | #include <linux/pci.h> |
35 | #include <linux/workqueue.h> | ||
35 | #include "../pci.h" | 36 | #include "../pci.h" |
36 | #include "shpchp.h" | 37 | #include "shpchp.h" |
37 | 38 | ||
38 | static void interrupt_event_handler(struct controller *ctrl); | 39 | static void interrupt_event_handler(void *data); |
40 | static int shpchp_enable_slot(struct slot *p_slot); | ||
41 | static int shpchp_disable_slot(struct slot *p_slot); | ||
39 | 42 | ||
40 | static struct semaphore event_semaphore; /* mutex for process loop (up if something to process) */ | 43 | static int queue_interrupt_event(struct slot *p_slot, u32 event_type) |
41 | static struct semaphore event_exit; /* guard ensure thread has exited before calling it quits */ | 44 | { |
42 | static int event_finished; | 45 | struct event_info *info; |
43 | static unsigned long pushbutton_pending; /* = 0 */ | 46 | |
47 | info = kmalloc(sizeof(*info), GFP_ATOMIC); | ||
48 | if (!info) | ||
49 | return -ENOMEM; | ||
50 | |||
51 | info->event_type = event_type; | ||
52 | info->p_slot = p_slot; | ||
53 | INIT_WORK(&info->work, interrupt_event_handler, info); | ||
54 | |||
55 | schedule_work(&info->work); | ||
56 | |||
57 | return 0; | ||
58 | } | ||
44 | 59 | ||
45 | u8 shpchp_handle_attention_button(u8 hp_slot, void *inst_id) | 60 | u8 shpchp_handle_attention_button(u8 hp_slot, void *inst_id) |
46 | { | 61 | { |
47 | struct controller *ctrl = (struct controller *) inst_id; | 62 | struct controller *ctrl = (struct controller *) inst_id; |
48 | struct slot *p_slot; | 63 | struct slot *p_slot; |
49 | u8 rc = 0; | 64 | u32 event_type; |
50 | u8 getstatus; | ||
51 | struct event_info *taskInfo; | ||
52 | 65 | ||
53 | /* Attention Button Change */ | 66 | /* Attention Button Change */ |
54 | dbg("shpchp: Attention button interrupt received.\n"); | 67 | dbg("shpchp: Attention button interrupt received.\n"); |
55 | 68 | ||
56 | /* This is the structure that tells the worker thread what to do */ | ||
57 | taskInfo = &(ctrl->event_queue[ctrl->next_event]); | ||
58 | p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); | 69 | p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); |
59 | |||
60 | p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save)); | 70 | p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save)); |
61 | p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); | ||
62 | |||
63 | ctrl->next_event = (ctrl->next_event + 1) % 10; | ||
64 | taskInfo->hp_slot = hp_slot; | ||
65 | |||
66 | rc++; | ||
67 | 71 | ||
68 | /* | 72 | /* |
69 | * Button pressed - See if need to TAKE ACTION!!! | 73 | * Button pressed - See if need to TAKE ACTION!!! |
70 | */ | 74 | */ |
71 | info("Button pressed on Slot(%d)\n", ctrl->first_slot + hp_slot); | 75 | info("Button pressed on Slot(%d)\n", ctrl->first_slot + hp_slot); |
72 | taskInfo->event_type = INT_BUTTON_PRESS; | 76 | event_type = INT_BUTTON_PRESS; |
73 | |||
74 | if ((p_slot->state == BLINKINGON_STATE) | ||
75 | || (p_slot->state == BLINKINGOFF_STATE)) { | ||
76 | /* Cancel if we are still blinking; this means that we press the | ||
77 | * attention again before the 5 sec. limit expires to cancel hot-add | ||
78 | * or hot-remove | ||
79 | */ | ||
80 | taskInfo->event_type = INT_BUTTON_CANCEL; | ||
81 | info("Button cancel on Slot(%d)\n", ctrl->first_slot + hp_slot); | ||
82 | } else if ((p_slot->state == POWERON_STATE) | ||
83 | || (p_slot->state == POWEROFF_STATE)) { | ||
84 | /* Ignore if the slot is on power-on or power-off state; this | ||
85 | * means that the previous attention button action to hot-add or | ||
86 | * hot-remove is undergoing | ||
87 | */ | ||
88 | taskInfo->event_type = INT_BUTTON_IGNORE; | ||
89 | info("Button ignore on Slot(%d)\n", ctrl->first_slot + hp_slot); | ||
90 | } | ||
91 | 77 | ||
92 | if (rc) | 78 | queue_interrupt_event(p_slot, event_type); |
93 | up(&event_semaphore); /* signal event thread that new event is posted */ | ||
94 | 79 | ||
95 | return 0; | 80 | return 0; |
96 | 81 | ||
@@ -100,21 +85,12 @@ u8 shpchp_handle_switch_change(u8 hp_slot, void *inst_id) | |||
100 | { | 85 | { |
101 | struct controller *ctrl = (struct controller *) inst_id; | 86 | struct controller *ctrl = (struct controller *) inst_id; |
102 | struct slot *p_slot; | 87 | struct slot *p_slot; |
103 | u8 rc = 0; | ||
104 | u8 getstatus; | 88 | u8 getstatus; |
105 | struct event_info *taskInfo; | 89 | u32 event_type; |
106 | 90 | ||
107 | /* Switch Change */ | 91 | /* Switch Change */ |
108 | dbg("shpchp: Switch interrupt received.\n"); | 92 | dbg("shpchp: Switch interrupt received.\n"); |
109 | 93 | ||
110 | /* This is the structure that tells the worker thread | ||
111 | * what to do | ||
112 | */ | ||
113 | taskInfo = &(ctrl->event_queue[ctrl->next_event]); | ||
114 | ctrl->next_event = (ctrl->next_event + 1) % 10; | ||
115 | taskInfo->hp_slot = hp_slot; | ||
116 | |||
117 | rc++; | ||
118 | p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); | 94 | p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); |
119 | p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save)); | 95 | p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save)); |
120 | p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); | 96 | p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); |
@@ -126,9 +102,9 @@ u8 shpchp_handle_switch_change(u8 hp_slot, void *inst_id) | |||
126 | * Switch opened | 102 | * Switch opened |
127 | */ | 103 | */ |
128 | info("Latch open on Slot(%d)\n", ctrl->first_slot + hp_slot); | 104 | info("Latch open on Slot(%d)\n", ctrl->first_slot + hp_slot); |
129 | taskInfo->event_type = INT_SWITCH_OPEN; | 105 | event_type = INT_SWITCH_OPEN; |
130 | if (p_slot->pwr_save && p_slot->presence_save) { | 106 | if (p_slot->pwr_save && p_slot->presence_save) { |
131 | taskInfo->event_type = INT_POWER_FAULT; | 107 | event_type = INT_POWER_FAULT; |
132 | err("Surprise Removal of card\n"); | 108 | err("Surprise Removal of card\n"); |
133 | } | 109 | } |
134 | } else { | 110 | } else { |
@@ -136,34 +112,23 @@ u8 shpchp_handle_switch_change(u8 hp_slot, void *inst_id) | |||
136 | * Switch closed | 112 | * Switch closed |
137 | */ | 113 | */ |
138 | info("Latch close on Slot(%d)\n", ctrl->first_slot + hp_slot); | 114 | info("Latch close on Slot(%d)\n", ctrl->first_slot + hp_slot); |
139 | taskInfo->event_type = INT_SWITCH_CLOSE; | 115 | event_type = INT_SWITCH_CLOSE; |
140 | } | 116 | } |
141 | 117 | ||
142 | if (rc) | 118 | queue_interrupt_event(p_slot, event_type); |
143 | up(&event_semaphore); /* signal event thread that new event is posted */ | ||
144 | 119 | ||
145 | return rc; | 120 | return 1; |
146 | } | 121 | } |
147 | 122 | ||
148 | u8 shpchp_handle_presence_change(u8 hp_slot, void *inst_id) | 123 | u8 shpchp_handle_presence_change(u8 hp_slot, void *inst_id) |
149 | { | 124 | { |
150 | struct controller *ctrl = (struct controller *) inst_id; | 125 | struct controller *ctrl = (struct controller *) inst_id; |
151 | struct slot *p_slot; | 126 | struct slot *p_slot; |
152 | u8 rc = 0; | 127 | u32 event_type; |
153 | /*u8 temp_byte;*/ | ||
154 | struct event_info *taskInfo; | ||
155 | 128 | ||
156 | /* Presence Change */ | 129 | /* Presence Change */ |
157 | dbg("shpchp: Presence/Notify input change.\n"); | 130 | dbg("shpchp: Presence/Notify input change.\n"); |
158 | 131 | ||
159 | /* This is the structure that tells the worker thread | ||
160 | * what to do | ||
161 | */ | ||
162 | taskInfo = &(ctrl->event_queue[ctrl->next_event]); | ||
163 | ctrl->next_event = (ctrl->next_event + 1) % 10; | ||
164 | taskInfo->hp_slot = hp_slot; | ||
165 | |||
166 | rc++; | ||
167 | p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); | 132 | p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); |
168 | 133 | ||
169 | /* | 134 | /* |
@@ -175,39 +140,29 @@ u8 shpchp_handle_presence_change(u8 hp_slot, void *inst_id) | |||
175 | * Card Present | 140 | * Card Present |
176 | */ | 141 | */ |
177 | info("Card present on Slot(%d)\n", ctrl->first_slot + hp_slot); | 142 | info("Card present on Slot(%d)\n", ctrl->first_slot + hp_slot); |
178 | taskInfo->event_type = INT_PRESENCE_ON; | 143 | event_type = INT_PRESENCE_ON; |
179 | } else { | 144 | } else { |
180 | /* | 145 | /* |
181 | * Not Present | 146 | * Not Present |
182 | */ | 147 | */ |
183 | info("Card not present on Slot(%d)\n", ctrl->first_slot + hp_slot); | 148 | info("Card not present on Slot(%d)\n", ctrl->first_slot + hp_slot); |
184 | taskInfo->event_type = INT_PRESENCE_OFF; | 149 | event_type = INT_PRESENCE_OFF; |
185 | } | 150 | } |
186 | 151 | ||
187 | if (rc) | 152 | queue_interrupt_event(p_slot, event_type); |
188 | up(&event_semaphore); /* signal event thread that new event is posted */ | ||
189 | 153 | ||
190 | return rc; | 154 | return 1; |
191 | } | 155 | } |
192 | 156 | ||
193 | u8 shpchp_handle_power_fault(u8 hp_slot, void *inst_id) | 157 | u8 shpchp_handle_power_fault(u8 hp_slot, void *inst_id) |
194 | { | 158 | { |
195 | struct controller *ctrl = (struct controller *) inst_id; | 159 | struct controller *ctrl = (struct controller *) inst_id; |
196 | struct slot *p_slot; | 160 | struct slot *p_slot; |
197 | u8 rc = 0; | 161 | u32 event_type; |
198 | struct event_info *taskInfo; | ||
199 | 162 | ||
200 | /* Power fault */ | 163 | /* Power fault */ |
201 | dbg("shpchp: Power fault interrupt received.\n"); | 164 | dbg("shpchp: Power fault interrupt received.\n"); |
202 | 165 | ||
203 | /* This is the structure that tells the worker thread | ||
204 | * what to do | ||
205 | */ | ||
206 | taskInfo = &(ctrl->event_queue[ctrl->next_event]); | ||
207 | ctrl->next_event = (ctrl->next_event + 1) % 10; | ||
208 | taskInfo->hp_slot = hp_slot; | ||
209 | |||
210 | rc++; | ||
211 | p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); | 166 | p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); |
212 | 167 | ||
213 | if ( !(p_slot->hpc_ops->query_power_fault(p_slot))) { | 168 | if ( !(p_slot->hpc_ops->query_power_fault(p_slot))) { |
@@ -216,21 +171,21 @@ u8 shpchp_handle_power_fault(u8 hp_slot, void *inst_id) | |||
216 | */ | 171 | */ |
217 | info("Power fault cleared on Slot(%d)\n", ctrl->first_slot + hp_slot); | 172 | info("Power fault cleared on Slot(%d)\n", ctrl->first_slot + hp_slot); |
218 | p_slot->status = 0x00; | 173 | p_slot->status = 0x00; |
219 | taskInfo->event_type = INT_POWER_FAULT_CLEAR; | 174 | event_type = INT_POWER_FAULT_CLEAR; |
220 | } else { | 175 | } else { |
221 | /* | 176 | /* |
222 | * Power fault | 177 | * Power fault |
223 | */ | 178 | */ |
224 | info("Power fault on Slot(%d)\n", ctrl->first_slot + hp_slot); | 179 | info("Power fault on Slot(%d)\n", ctrl->first_slot + hp_slot); |
225 | taskInfo->event_type = INT_POWER_FAULT; | 180 | event_type = INT_POWER_FAULT; |
226 | /* set power fault status for this board */ | 181 | /* set power fault status for this board */ |
227 | p_slot->status = 0xFF; | 182 | p_slot->status = 0xFF; |
228 | info("power fault bit %x set\n", hp_slot); | 183 | info("power fault bit %x set\n", hp_slot); |
229 | } | 184 | } |
230 | if (rc) | ||
231 | up(&event_semaphore); /* signal event thread that new event is posted */ | ||
232 | 185 | ||
233 | return rc; | 186 | queue_interrupt_event(p_slot, event_type); |
187 | |||
188 | return 1; | ||
234 | } | 189 | } |
235 | 190 | ||
236 | /* The following routines constitute the bulk of the | 191 | /* The following routines constitute the bulk of the |
@@ -242,21 +197,11 @@ static int change_bus_speed(struct controller *ctrl, struct slot *p_slot, | |||
242 | int rc = 0; | 197 | int rc = 0; |
243 | 198 | ||
244 | dbg("%s: change to speed %d\n", __FUNCTION__, speed); | 199 | dbg("%s: change to speed %d\n", __FUNCTION__, speed); |
245 | down(&ctrl->crit_sect); | ||
246 | if ((rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, speed))) { | 200 | if ((rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, speed))) { |
247 | err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__); | 201 | err("%s: Issue of set bus speed mode command failed\n", |
248 | up(&ctrl->crit_sect); | 202 | __FUNCTION__); |
249 | return WRONG_BUS_FREQUENCY; | 203 | return WRONG_BUS_FREQUENCY; |
250 | } | 204 | } |
251 | |||
252 | if ((rc = p_slot->hpc_ops->check_cmd_status(ctrl))) { | ||
253 | err("%s: Can't set bus speed/mode in the case of adapter & bus mismatch\n", | ||
254 | __FUNCTION__); | ||
255 | err("%s: Error code (%d)\n", __FUNCTION__, rc); | ||
256 | up(&ctrl->crit_sect); | ||
257 | return WRONG_BUS_FREQUENCY; | ||
258 | } | ||
259 | up(&ctrl->crit_sect); | ||
260 | return rc; | 205 | return rc; |
261 | } | 206 | } |
262 | 207 | ||
@@ -265,33 +210,26 @@ static int fix_bus_speed(struct controller *ctrl, struct slot *pslot, | |||
265 | enum pci_bus_speed msp) | 210 | enum pci_bus_speed msp) |
266 | { | 211 | { |
267 | int rc = 0; | 212 | int rc = 0; |
268 | 213 | ||
269 | if (flag != 0) { /* Other slots on the same bus are occupied */ | 214 | /* |
270 | if ( asp < bsp ) { | 215 | * If other slots on the same bus are occupied, we cannot |
271 | err("%s: speed of bus %x and adapter %x mismatch\n", __FUNCTION__, bsp, asp); | 216 | * change the bus speed. |
272 | return WRONG_BUS_FREQUENCY; | 217 | */ |
218 | if (flag) { | ||
219 | if (asp < bsp) { | ||
220 | err("%s: speed of bus %x and adapter %x mismatch\n", | ||
221 | __FUNCTION__, bsp, asp); | ||
222 | rc = WRONG_BUS_FREQUENCY; | ||
273 | } | 223 | } |
224 | return rc; | ||
225 | } | ||
226 | |||
227 | if (asp < msp) { | ||
228 | if (bsp != asp) | ||
229 | rc = change_bus_speed(ctrl, pslot, asp); | ||
274 | } else { | 230 | } else { |
275 | /* Other slots on the same bus are empty */ | 231 | if (bsp != msp) |
276 | if (msp == bsp) { | 232 | rc = change_bus_speed(ctrl, pslot, msp); |
277 | /* if adapter_speed >= bus_speed, do nothing */ | ||
278 | if (asp < bsp) { | ||
279 | /* | ||
280 | * Try to lower bus speed to accommodate the adapter if other slots | ||
281 | * on the same controller are empty | ||
282 | */ | ||
283 | if ((rc = change_bus_speed(ctrl, pslot, asp))) | ||
284 | return rc; | ||
285 | } | ||
286 | } else { | ||
287 | if (asp < msp) { | ||
288 | if ((rc = change_bus_speed(ctrl, pslot, asp))) | ||
289 | return rc; | ||
290 | } else { | ||
291 | if ((rc = change_bus_speed(ctrl, pslot, msp))) | ||
292 | return rc; | ||
293 | } | ||
294 | } | ||
295 | } | 233 | } |
296 | return rc; | 234 | return rc; |
297 | } | 235 | } |
@@ -308,8 +246,7 @@ static int board_added(struct slot *p_slot) | |||
308 | u8 hp_slot; | 246 | u8 hp_slot; |
309 | u8 slots_not_empty = 0; | 247 | u8 slots_not_empty = 0; |
310 | int rc = 0; | 248 | int rc = 0; |
311 | enum pci_bus_speed adapter_speed, bus_speed, max_bus_speed; | 249 | enum pci_bus_speed asp, bsp, msp; |
312 | u8 pi, mode; | ||
313 | struct controller *ctrl = p_slot->ctrl; | 250 | struct controller *ctrl = p_slot->ctrl; |
314 | 251 | ||
315 | hp_slot = p_slot->device - ctrl->slot_device_offset; | 252 | hp_slot = p_slot->device - ctrl->slot_device_offset; |
@@ -318,187 +255,68 @@ static int board_added(struct slot *p_slot) | |||
318 | __FUNCTION__, p_slot->device, | 255 | __FUNCTION__, p_slot->device, |
319 | ctrl->slot_device_offset, hp_slot); | 256 | ctrl->slot_device_offset, hp_slot); |
320 | 257 | ||
321 | /* Wait for exclusive access to hardware */ | ||
322 | down(&ctrl->crit_sect); | ||
323 | |||
324 | /* Power on slot without connecting to bus */ | 258 | /* Power on slot without connecting to bus */ |
325 | rc = p_slot->hpc_ops->power_on_slot(p_slot); | 259 | rc = p_slot->hpc_ops->power_on_slot(p_slot); |
326 | if (rc) { | 260 | if (rc) { |
327 | err("%s: Failed to power on slot\n", __FUNCTION__); | 261 | err("%s: Failed to power on slot\n", __FUNCTION__); |
328 | /* Done with exclusive hardware access */ | ||
329 | up(&ctrl->crit_sect); | ||
330 | return -1; | 262 | return -1; |
331 | } | 263 | } |
332 | 264 | ||
333 | rc = p_slot->hpc_ops->check_cmd_status(ctrl); | ||
334 | if (rc) { | ||
335 | err("%s: Failed to power on slot, error code(%d)\n", __FUNCTION__, rc); | ||
336 | /* Done with exclusive hardware access */ | ||
337 | up(&ctrl->crit_sect); | ||
338 | return -1; | ||
339 | } | ||
340 | |||
341 | |||
342 | if ((ctrl->pci_dev->vendor == 0x8086) && (ctrl->pci_dev->device == 0x0332)) { | 265 | if ((ctrl->pci_dev->vendor == 0x8086) && (ctrl->pci_dev->device == 0x0332)) { |
343 | if (slots_not_empty) | 266 | if (slots_not_empty) |
344 | return WRONG_BUS_FREQUENCY; | 267 | return WRONG_BUS_FREQUENCY; |
345 | 268 | ||
346 | if ((rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, PCI_SPEED_33MHz))) { | 269 | if ((rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, PCI_SPEED_33MHz))) { |
347 | err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__); | 270 | err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__); |
348 | up(&ctrl->crit_sect); | ||
349 | return WRONG_BUS_FREQUENCY; | 271 | return WRONG_BUS_FREQUENCY; |
350 | } | 272 | } |
351 | 273 | ||
352 | if ((rc = p_slot->hpc_ops->check_cmd_status(ctrl))) { | ||
353 | err("%s: Can't set bus speed/mode in the case of adapter & bus mismatch\n", | ||
354 | __FUNCTION__); | ||
355 | err("%s: Error code (%d)\n", __FUNCTION__, rc); | ||
356 | up(&ctrl->crit_sect); | ||
357 | return WRONG_BUS_FREQUENCY; | ||
358 | } | ||
359 | /* turn on board, blink green LED, turn off Amber LED */ | 274 | /* turn on board, blink green LED, turn off Amber LED */ |
360 | if ((rc = p_slot->hpc_ops->slot_enable(p_slot))) { | 275 | if ((rc = p_slot->hpc_ops->slot_enable(p_slot))) { |
361 | err("%s: Issue of Slot Enable command failed\n", __FUNCTION__); | 276 | err("%s: Issue of Slot Enable command failed\n", __FUNCTION__); |
362 | up(&ctrl->crit_sect); | ||
363 | return rc; | 277 | return rc; |
364 | } | 278 | } |
365 | |||
366 | if ((rc = p_slot->hpc_ops->check_cmd_status(ctrl))) { | ||
367 | err("%s: Failed to enable slot, error code(%d)\n", __FUNCTION__, rc); | ||
368 | up(&ctrl->crit_sect); | ||
369 | return rc; | ||
370 | } | ||
371 | } | 279 | } |
372 | 280 | ||
373 | rc = p_slot->hpc_ops->get_adapter_speed(p_slot, &adapter_speed); | 281 | rc = p_slot->hpc_ops->get_adapter_speed(p_slot, &asp); |
374 | /* 0 = PCI 33Mhz, 1 = PCI 66 Mhz, 2 = PCI-X 66 PA, 4 = PCI-X 66 ECC, */ | 282 | if (rc) { |
375 | /* 5 = PCI-X 133 PA, 7 = PCI-X 133 ECC, 0xa = PCI-X 133 Mhz 266, */ | 283 | err("%s: Can't get adapter speed or bus mode mismatch\n", |
376 | /* 0xd = PCI-X 133 Mhz 533 */ | 284 | __FUNCTION__); |
377 | /* This encoding is different from the one used in cur_bus_speed & */ | ||
378 | /* max_bus_speed */ | ||
379 | |||
380 | if (rc || adapter_speed == PCI_SPEED_UNKNOWN) { | ||
381 | err("%s: Can't get adapter speed or bus mode mismatch\n", __FUNCTION__); | ||
382 | /* Done with exclusive hardware access */ | ||
383 | up(&ctrl->crit_sect); | ||
384 | return WRONG_BUS_FREQUENCY; | 285 | return WRONG_BUS_FREQUENCY; |
385 | } | 286 | } |
386 | 287 | ||
387 | rc = p_slot->hpc_ops->get_cur_bus_speed(p_slot, &bus_speed); | 288 | rc = p_slot->hpc_ops->get_cur_bus_speed(p_slot, &bsp); |
388 | if (rc || bus_speed == PCI_SPEED_UNKNOWN) { | 289 | if (rc) { |
389 | err("%s: Can't get bus operation speed\n", __FUNCTION__); | 290 | err("%s: Can't get bus operation speed\n", __FUNCTION__); |
390 | /* Done with exclusive hardware access */ | ||
391 | up(&ctrl->crit_sect); | ||
392 | return WRONG_BUS_FREQUENCY; | 291 | return WRONG_BUS_FREQUENCY; |
393 | } | 292 | } |
394 | 293 | ||
395 | rc = p_slot->hpc_ops->get_max_bus_speed(p_slot, &max_bus_speed); | 294 | rc = p_slot->hpc_ops->get_max_bus_speed(p_slot, &msp); |
396 | if (rc || max_bus_speed == PCI_SPEED_UNKNOWN) { | 295 | if (rc) { |
397 | err("%s: Can't get max bus operation speed\n", __FUNCTION__); | 296 | err("%s: Can't get max bus operation speed\n", __FUNCTION__); |
398 | max_bus_speed = bus_speed; | 297 | msp = bsp; |
399 | } | ||
400 | |||
401 | /* Done with exclusive hardware access */ | ||
402 | up(&ctrl->crit_sect); | ||
403 | |||
404 | if ((rc = p_slot->hpc_ops->get_prog_int(p_slot, &pi))) { | ||
405 | err("%s: Can't get controller programming interface, set it to 1\n", __FUNCTION__); | ||
406 | pi = 1; | ||
407 | } | 298 | } |
408 | 299 | ||
409 | /* Check if there are other slots or devices on the same bus */ | 300 | /* Check if there are other slots or devices on the same bus */ |
410 | if (!list_empty(&ctrl->pci_dev->subordinate->devices)) | 301 | if (!list_empty(&ctrl->pci_dev->subordinate->devices)) |
411 | slots_not_empty = 1; | 302 | slots_not_empty = 1; |
412 | 303 | ||
413 | dbg("%s: slots_not_empty %d, pi %d\n", __FUNCTION__, | 304 | dbg("%s: slots_not_empty %d, adapter_speed %d, bus_speed %d, " |
414 | slots_not_empty, pi); | 305 | "max_bus_speed %d\n", __FUNCTION__, slots_not_empty, asp, |
415 | dbg("adapter_speed %d, bus_speed %d, max_bus_speed %d\n", | 306 | bsp, msp); |
416 | adapter_speed, bus_speed, max_bus_speed); | ||
417 | |||
418 | if (pi == 2) { | ||
419 | dbg("%s: In PI = %d\n", __FUNCTION__, pi); | ||
420 | if ((rc = p_slot->hpc_ops->get_mode1_ECC_cap(p_slot, &mode))) { | ||
421 | err("%s: Can't get Mode1_ECC, set mode to 0\n", __FUNCTION__); | ||
422 | mode = 0; | ||
423 | } | ||
424 | 307 | ||
425 | switch (adapter_speed) { | 308 | rc = fix_bus_speed(ctrl, p_slot, slots_not_empty, asp, bsp, msp); |
426 | case PCI_SPEED_133MHz_PCIX_533: | 309 | if (rc) |
427 | case PCI_SPEED_133MHz_PCIX_266: | 310 | return rc; |
428 | if ((bus_speed != adapter_speed) && | ||
429 | ((rc = fix_bus_speed(ctrl, p_slot, slots_not_empty, adapter_speed, bus_speed, max_bus_speed)))) | ||
430 | return rc; | ||
431 | break; | ||
432 | case PCI_SPEED_133MHz_PCIX_ECC: | ||
433 | case PCI_SPEED_133MHz_PCIX: | ||
434 | if (mode) { /* Bus - Mode 1 ECC */ | ||
435 | if ((bus_speed != 0x7) && | ||
436 | ((rc = fix_bus_speed(ctrl, p_slot, slots_not_empty, adapter_speed, bus_speed, max_bus_speed)))) | ||
437 | return rc; | ||
438 | } else { | ||
439 | if ((bus_speed != 0x4) && | ||
440 | ((rc = fix_bus_speed(ctrl, p_slot, slots_not_empty, adapter_speed, bus_speed, max_bus_speed)))) | ||
441 | return rc; | ||
442 | } | ||
443 | break; | ||
444 | case PCI_SPEED_66MHz_PCIX_ECC: | ||
445 | case PCI_SPEED_66MHz_PCIX: | ||
446 | if (mode) { /* Bus - Mode 1 ECC */ | ||
447 | if ((bus_speed != 0x5) && | ||
448 | ((rc = fix_bus_speed(ctrl, p_slot, slots_not_empty, adapter_speed, bus_speed, max_bus_speed)))) | ||
449 | return rc; | ||
450 | } else { | ||
451 | if ((bus_speed != 0x2) && | ||
452 | ((rc = fix_bus_speed(ctrl, p_slot, slots_not_empty, adapter_speed, bus_speed, max_bus_speed)))) | ||
453 | return rc; | ||
454 | } | ||
455 | break; | ||
456 | case PCI_SPEED_66MHz: | ||
457 | if ((bus_speed != 0x1) && | ||
458 | ((rc = fix_bus_speed(ctrl, p_slot, slots_not_empty, adapter_speed, bus_speed, max_bus_speed)))) | ||
459 | return rc; | ||
460 | break; | ||
461 | case PCI_SPEED_33MHz: | ||
462 | if (bus_speed > 0x0) { | ||
463 | if (slots_not_empty == 0) { | ||
464 | if ((rc = change_bus_speed(ctrl, p_slot, adapter_speed))) | ||
465 | return rc; | ||
466 | } else { | ||
467 | err("%s: speed of bus %x and adapter %x mismatch\n", __FUNCTION__, bus_speed, adapter_speed); | ||
468 | return WRONG_BUS_FREQUENCY; | ||
469 | } | ||
470 | } | ||
471 | break; | ||
472 | default: | ||
473 | err("%s: speed of bus %x and adapter %x mismatch\n", __FUNCTION__, bus_speed, adapter_speed); | ||
474 | return WRONG_BUS_FREQUENCY; | ||
475 | } | ||
476 | } else { | ||
477 | /* If adpater_speed == bus_speed, nothing to do here */ | ||
478 | dbg("%s: In PI = %d\n", __FUNCTION__, pi); | ||
479 | if ((adapter_speed != bus_speed) && | ||
480 | ((rc = fix_bus_speed(ctrl, p_slot, slots_not_empty, adapter_speed, bus_speed, max_bus_speed)))) | ||
481 | return rc; | ||
482 | } | ||
483 | 311 | ||
484 | down(&ctrl->crit_sect); | ||
485 | /* turn on board, blink green LED, turn off Amber LED */ | 312 | /* turn on board, blink green LED, turn off Amber LED */ |
486 | if ((rc = p_slot->hpc_ops->slot_enable(p_slot))) { | 313 | if ((rc = p_slot->hpc_ops->slot_enable(p_slot))) { |
487 | err("%s: Issue of Slot Enable command failed\n", __FUNCTION__); | 314 | err("%s: Issue of Slot Enable command failed\n", __FUNCTION__); |
488 | up(&ctrl->crit_sect); | ||
489 | return rc; | 315 | return rc; |
490 | } | 316 | } |
491 | 317 | ||
492 | if ((rc = p_slot->hpc_ops->check_cmd_status(ctrl))) { | ||
493 | err("%s: Failed to enable slot, error code(%d)\n", __FUNCTION__, rc); | ||
494 | up(&ctrl->crit_sect); | ||
495 | return rc; | ||
496 | } | ||
497 | |||
498 | up(&ctrl->crit_sect); | ||
499 | |||
500 | /* Wait for ~1 second */ | 318 | /* Wait for ~1 second */ |
501 | wait_for_ctrl_irq (ctrl); | 319 | msleep(1000); |
502 | 320 | ||
503 | dbg("%s: slot status = %x\n", __FUNCTION__, p_slot->status); | 321 | dbg("%s: slot status = %x\n", __FUNCTION__, p_slot->status); |
504 | /* Check for a power fault */ | 322 | /* Check for a power fault */ |
@@ -520,40 +338,18 @@ static int board_added(struct slot *p_slot) | |||
520 | p_slot->is_a_board = 0x01; | 338 | p_slot->is_a_board = 0x01; |
521 | p_slot->pwr_save = 1; | 339 | p_slot->pwr_save = 1; |
522 | 340 | ||
523 | /* Wait for exclusive access to hardware */ | ||
524 | down(&ctrl->crit_sect); | ||
525 | |||
526 | p_slot->hpc_ops->green_led_on(p_slot); | 341 | p_slot->hpc_ops->green_led_on(p_slot); |
527 | 342 | ||
528 | /* Done with exclusive hardware access */ | ||
529 | up(&ctrl->crit_sect); | ||
530 | |||
531 | return 0; | 343 | return 0; |
532 | 344 | ||
533 | err_exit: | 345 | err_exit: |
534 | /* Wait for exclusive access to hardware */ | ||
535 | down(&ctrl->crit_sect); | ||
536 | |||
537 | /* turn off slot, turn on Amber LED, turn off Green LED */ | 346 | /* turn off slot, turn on Amber LED, turn off Green LED */ |
538 | rc = p_slot->hpc_ops->slot_disable(p_slot); | 347 | rc = p_slot->hpc_ops->slot_disable(p_slot); |
539 | if (rc) { | 348 | if (rc) { |
540 | err("%s: Issue of Slot Disable command failed\n", __FUNCTION__); | 349 | err("%s: Issue of Slot Disable command failed\n", __FUNCTION__); |
541 | /* Done with exclusive hardware access */ | ||
542 | up(&ctrl->crit_sect); | ||
543 | return rc; | ||
544 | } | ||
545 | |||
546 | rc = p_slot->hpc_ops->check_cmd_status(ctrl); | ||
547 | if (rc) { | ||
548 | err("%s: Failed to disable slot, error code(%d)\n", __FUNCTION__, rc); | ||
549 | /* Done with exclusive hardware access */ | ||
550 | up(&ctrl->crit_sect); | ||
551 | return rc; | 350 | return rc; |
552 | } | 351 | } |
553 | 352 | ||
554 | /* Done with exclusive hardware access */ | ||
555 | up(&ctrl->crit_sect); | ||
556 | |||
557 | return(rc); | 353 | return(rc); |
558 | } | 354 | } |
559 | 355 | ||
@@ -580,37 +376,19 @@ static int remove_board(struct slot *p_slot) | |||
580 | if (p_slot->is_a_board) | 376 | if (p_slot->is_a_board) |
581 | p_slot->status = 0x01; | 377 | p_slot->status = 0x01; |
582 | 378 | ||
583 | /* Wait for exclusive access to hardware */ | ||
584 | down(&ctrl->crit_sect); | ||
585 | |||
586 | /* turn off slot, turn on Amber LED, turn off Green LED */ | 379 | /* turn off slot, turn on Amber LED, turn off Green LED */ |
587 | rc = p_slot->hpc_ops->slot_disable(p_slot); | 380 | rc = p_slot->hpc_ops->slot_disable(p_slot); |
588 | if (rc) { | 381 | if (rc) { |
589 | err("%s: Issue of Slot Disable command failed\n", __FUNCTION__); | 382 | err("%s: Issue of Slot Disable command failed\n", __FUNCTION__); |
590 | /* Done with exclusive hardware access */ | ||
591 | up(&ctrl->crit_sect); | ||
592 | return rc; | 383 | return rc; |
593 | } | 384 | } |
594 | |||
595 | rc = p_slot->hpc_ops->check_cmd_status(ctrl); | ||
596 | if (rc) { | ||
597 | err("%s: Failed to disable slot, error code(%d)\n", __FUNCTION__, rc); | ||
598 | /* Done with exclusive hardware access */ | ||
599 | up(&ctrl->crit_sect); | ||
600 | return rc; | ||
601 | } | ||
602 | 385 | ||
603 | rc = p_slot->hpc_ops->set_attention_status(p_slot, 0); | 386 | rc = p_slot->hpc_ops->set_attention_status(p_slot, 0); |
604 | if (rc) { | 387 | if (rc) { |
605 | err("%s: Issue of Set Attention command failed\n", __FUNCTION__); | 388 | err("%s: Issue of Set Attention command failed\n", __FUNCTION__); |
606 | /* Done with exclusive hardware access */ | ||
607 | up(&ctrl->crit_sect); | ||
608 | return rc; | 389 | return rc; |
609 | } | 390 | } |
610 | 391 | ||
611 | /* Done with exclusive hardware access */ | ||
612 | up(&ctrl->crit_sect); | ||
613 | |||
614 | p_slot->pwr_save = 0; | 392 | p_slot->pwr_save = 0; |
615 | p_slot->is_a_board = 0; | 393 | p_slot->is_a_board = 0; |
616 | 394 | ||
@@ -618,13 +396,10 @@ static int remove_board(struct slot *p_slot) | |||
618 | } | 396 | } |
619 | 397 | ||
620 | 398 | ||
621 | static void pushbutton_helper_thread (unsigned long data) | 399 | struct pushbutton_work_info { |
622 | { | 400 | struct slot *p_slot; |
623 | pushbutton_pending = data; | 401 | struct work_struct work; |
624 | 402 | }; | |
625 | up(&event_semaphore); | ||
626 | } | ||
627 | |||
628 | 403 | ||
629 | /** | 404 | /** |
630 | * shpchp_pushbutton_thread | 405 | * shpchp_pushbutton_thread |
@@ -633,96 +408,63 @@ static void pushbutton_helper_thread (unsigned long data) | |||
633 | * Handles all pending events and exits. | 408 | * Handles all pending events and exits. |
634 | * | 409 | * |
635 | */ | 410 | */ |
636 | static void shpchp_pushbutton_thread (unsigned long slot) | 411 | static void shpchp_pushbutton_thread(void *data) |
637 | { | 412 | { |
638 | struct slot *p_slot = (struct slot *) slot; | 413 | struct pushbutton_work_info *info = data; |
639 | u8 getstatus; | 414 | struct slot *p_slot = info->p_slot; |
640 | |||
641 | pushbutton_pending = 0; | ||
642 | |||
643 | if (!p_slot) { | ||
644 | dbg("%s: Error! slot NULL\n", __FUNCTION__); | ||
645 | return; | ||
646 | } | ||
647 | |||
648 | p_slot->hpc_ops->get_power_status(p_slot, &getstatus); | ||
649 | if (getstatus) { | ||
650 | p_slot->state = POWEROFF_STATE; | ||
651 | 415 | ||
416 | mutex_lock(&p_slot->lock); | ||
417 | switch (p_slot->state) { | ||
418 | case POWEROFF_STATE: | ||
419 | mutex_unlock(&p_slot->lock); | ||
652 | shpchp_disable_slot(p_slot); | 420 | shpchp_disable_slot(p_slot); |
421 | mutex_lock(&p_slot->lock); | ||
653 | p_slot->state = STATIC_STATE; | 422 | p_slot->state = STATIC_STATE; |
654 | } else { | 423 | break; |
655 | p_slot->state = POWERON_STATE; | 424 | case POWERON_STATE: |
656 | 425 | mutex_unlock(&p_slot->lock); | |
657 | if (shpchp_enable_slot(p_slot)) { | 426 | if (shpchp_enable_slot(p_slot)) |
658 | /* Wait for exclusive access to hardware */ | ||
659 | down(&p_slot->ctrl->crit_sect); | ||
660 | |||
661 | p_slot->hpc_ops->green_led_off(p_slot); | 427 | p_slot->hpc_ops->green_led_off(p_slot); |
662 | 428 | mutex_lock(&p_slot->lock); | |
663 | /* Done with exclusive hardware access */ | ||
664 | up(&p_slot->ctrl->crit_sect); | ||
665 | } | ||
666 | p_slot->state = STATIC_STATE; | 429 | p_slot->state = STATIC_STATE; |
430 | break; | ||
431 | default: | ||
432 | break; | ||
667 | } | 433 | } |
434 | mutex_unlock(&p_slot->lock); | ||
668 | 435 | ||
669 | return; | 436 | kfree(info); |
670 | } | ||
671 | |||
672 | |||
673 | /* this is the main worker thread */ | ||
674 | static int event_thread(void* data) | ||
675 | { | ||
676 | struct controller *ctrl; | ||
677 | lock_kernel(); | ||
678 | daemonize("shpchpd_event"); | ||
679 | unlock_kernel(); | ||
680 | |||
681 | while (1) { | ||
682 | dbg("!!!!event_thread sleeping\n"); | ||
683 | down_interruptible (&event_semaphore); | ||
684 | dbg("event_thread woken finished = %d\n", event_finished); | ||
685 | if (event_finished || signal_pending(current)) | ||
686 | break; | ||
687 | /* Do stuff here */ | ||
688 | if (pushbutton_pending) | ||
689 | shpchp_pushbutton_thread(pushbutton_pending); | ||
690 | else | ||
691 | for (ctrl = shpchp_ctrl_list; ctrl; ctrl=ctrl->next) | ||
692 | interrupt_event_handler(ctrl); | ||
693 | } | ||
694 | dbg("event_thread signals exit\n"); | ||
695 | up(&event_exit); | ||
696 | return 0; | ||
697 | } | 437 | } |
698 | 438 | ||
699 | int shpchp_event_start_thread (void) | 439 | void queue_pushbutton_work(void *data) |
700 | { | 440 | { |
701 | int pid; | 441 | struct slot *p_slot = data; |
442 | struct pushbutton_work_info *info; | ||
702 | 443 | ||
703 | /* initialize our semaphores */ | 444 | info = kmalloc(sizeof(*info), GFP_KERNEL); |
704 | init_MUTEX_LOCKED(&event_exit); | 445 | if (!info) { |
705 | event_finished=0; | 446 | err("%s: Cannot allocate memory\n", __FUNCTION__); |
706 | 447 | return; | |
707 | init_MUTEX_LOCKED(&event_semaphore); | ||
708 | pid = kernel_thread(event_thread, NULL, 0); | ||
709 | |||
710 | if (pid < 0) { | ||
711 | err ("Can't start up our event thread\n"); | ||
712 | return -1; | ||
713 | } | 448 | } |
714 | return 0; | 449 | info->p_slot = p_slot; |
715 | } | 450 | INIT_WORK(&info->work, shpchp_pushbutton_thread, info); |
716 | |||
717 | 451 | ||
718 | void shpchp_event_stop_thread (void) | 452 | mutex_lock(&p_slot->lock); |
719 | { | 453 | switch (p_slot->state) { |
720 | event_finished = 1; | 454 | case BLINKINGOFF_STATE: |
721 | up(&event_semaphore); | 455 | p_slot->state = POWEROFF_STATE; |
722 | down(&event_exit); | 456 | break; |
457 | case BLINKINGON_STATE: | ||
458 | p_slot->state = POWERON_STATE; | ||
459 | break; | ||
460 | default: | ||
461 | goto out; | ||
462 | } | ||
463 | queue_work(shpchp_wq, &info->work); | ||
464 | out: | ||
465 | mutex_unlock(&p_slot->lock); | ||
723 | } | 466 | } |
724 | 467 | ||
725 | |||
726 | static int update_slot_info (struct slot *slot) | 468 | static int update_slot_info (struct slot *slot) |
727 | { | 469 | { |
728 | struct hotplug_slot_info *info; | 470 | struct hotplug_slot_info *info; |
@@ -742,149 +484,110 @@ static int update_slot_info (struct slot *slot) | |||
742 | return result; | 484 | return result; |
743 | } | 485 | } |
744 | 486 | ||
745 | static void interrupt_event_handler(struct controller *ctrl) | 487 | /* |
488 | * Note: This function must be called with slot->lock held | ||
489 | */ | ||
490 | static void handle_button_press_event(struct slot *p_slot) | ||
746 | { | 491 | { |
747 | int loop = 0; | ||
748 | int change = 1; | ||
749 | u8 hp_slot; | ||
750 | u8 getstatus; | 492 | u8 getstatus; |
751 | struct slot *p_slot; | ||
752 | 493 | ||
753 | while (change) { | 494 | switch (p_slot->state) { |
754 | change = 0; | 495 | case STATIC_STATE: |
755 | 496 | p_slot->hpc_ops->get_power_status(p_slot, &getstatus); | |
756 | for (loop = 0; loop < 10; loop++) { | 497 | if (getstatus) { |
757 | if (ctrl->event_queue[loop].event_type != 0) { | 498 | p_slot->state = BLINKINGOFF_STATE; |
758 | dbg("%s:loop %x event_type %x\n", __FUNCTION__, loop, | 499 | info(msg_button_off, p_slot->number); |
759 | ctrl->event_queue[loop].event_type); | 500 | } else { |
760 | hp_slot = ctrl->event_queue[loop].hp_slot; | 501 | p_slot->state = BLINKINGON_STATE; |
761 | 502 | info(msg_button_on, p_slot->number); | |
762 | p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); | 503 | } |
763 | 504 | /* blink green LED and turn off amber */ | |
764 | if (ctrl->event_queue[loop].event_type == INT_BUTTON_CANCEL) { | 505 | p_slot->hpc_ops->green_led_blink(p_slot); |
765 | dbg("%s: button cancel\n", __FUNCTION__); | 506 | p_slot->hpc_ops->set_attention_status(p_slot, 0); |
766 | del_timer(&p_slot->task_event); | 507 | |
767 | 508 | schedule_delayed_work(&p_slot->work, 5*HZ); | |
768 | switch (p_slot->state) { | 509 | break; |
769 | case BLINKINGOFF_STATE: | 510 | case BLINKINGOFF_STATE: |
770 | /* Wait for exclusive access to hardware */ | 511 | case BLINKINGON_STATE: |
771 | down(&ctrl->crit_sect); | 512 | /* |
772 | 513 | * Cancel if we are still blinking; this means that we | |
773 | p_slot->hpc_ops->green_led_on(p_slot); | 514 | * press the attention again before the 5 sec. limit |
774 | 515 | * expires to cancel hot-add or hot-remove | |
775 | p_slot->hpc_ops->set_attention_status(p_slot, 0); | 516 | */ |
776 | 517 | info("Button cancel on Slot(%s)\n", p_slot->name); | |
777 | /* Done with exclusive hardware access */ | 518 | dbg("%s: button cancel\n", __FUNCTION__); |
778 | up(&ctrl->crit_sect); | 519 | cancel_delayed_work(&p_slot->work); |
779 | break; | 520 | if (p_slot->state == BLINKINGOFF_STATE) |
780 | case BLINKINGON_STATE: | 521 | p_slot->hpc_ops->green_led_on(p_slot); |
781 | /* Wait for exclusive access to hardware */ | 522 | else |
782 | down(&ctrl->crit_sect); | 523 | p_slot->hpc_ops->green_led_off(p_slot); |
783 | 524 | p_slot->hpc_ops->set_attention_status(p_slot, 0); | |
784 | p_slot->hpc_ops->green_led_off(p_slot); | 525 | info(msg_button_cancel, p_slot->number); |
785 | 526 | p_slot->state = STATIC_STATE; | |
786 | p_slot->hpc_ops->set_attention_status(p_slot, 0); | 527 | break; |
787 | 528 | case POWEROFF_STATE: | |
788 | /* Done with exclusive hardware access */ | 529 | case POWERON_STATE: |
789 | up(&ctrl->crit_sect); | 530 | /* |
790 | 531 | * Ignore if the slot is on power-on or power-off state; | |
791 | break; | 532 | * this means that the previous attention button action |
792 | default: | 533 | * to hot-add or hot-remove is undergoing |
793 | warn("Not a valid state\n"); | 534 | */ |
794 | return; | 535 | info("Button ignore on Slot(%s)\n", p_slot->name); |
795 | } | 536 | update_slot_info(p_slot); |
796 | info(msg_button_cancel, p_slot->number); | 537 | break; |
797 | p_slot->state = STATIC_STATE; | 538 | default: |
798 | } else if (ctrl->event_queue[loop].event_type == INT_BUTTON_PRESS) { | 539 | warn("Not a valid state\n"); |
799 | /* Button Pressed (No action on 1st press...) */ | 540 | break; |
800 | dbg("%s: Button pressed\n", __FUNCTION__); | ||
801 | |||
802 | p_slot->hpc_ops->get_power_status(p_slot, &getstatus); | ||
803 | if (getstatus) { | ||
804 | /* slot is on */ | ||
805 | dbg("%s: slot is on\n", __FUNCTION__); | ||
806 | p_slot->state = BLINKINGOFF_STATE; | ||
807 | info(msg_button_off, p_slot->number); | ||
808 | } else { | ||
809 | /* slot is off */ | ||
810 | dbg("%s: slot is off\n", __FUNCTION__); | ||
811 | p_slot->state = BLINKINGON_STATE; | ||
812 | info(msg_button_on, p_slot->number); | ||
813 | } | ||
814 | |||
815 | /* Wait for exclusive access to hardware */ | ||
816 | down(&ctrl->crit_sect); | ||
817 | |||
818 | /* blink green LED and turn off amber */ | ||
819 | p_slot->hpc_ops->green_led_blink(p_slot); | ||
820 | |||
821 | p_slot->hpc_ops->set_attention_status(p_slot, 0); | ||
822 | |||
823 | /* Done with exclusive hardware access */ | ||
824 | up(&ctrl->crit_sect); | ||
825 | |||
826 | init_timer(&p_slot->task_event); | ||
827 | p_slot->task_event.expires = jiffies + 5 * HZ; /* 5 second delay */ | ||
828 | p_slot->task_event.function = (void (*)(unsigned long)) pushbutton_helper_thread; | ||
829 | p_slot->task_event.data = (unsigned long) p_slot; | ||
830 | |||
831 | dbg("%s: add_timer p_slot = %p\n", __FUNCTION__,(void *) p_slot); | ||
832 | add_timer(&p_slot->task_event); | ||
833 | } else if (ctrl->event_queue[loop].event_type == INT_POWER_FAULT) { | ||
834 | /***********POWER FAULT********************/ | ||
835 | dbg("%s: power fault\n", __FUNCTION__); | ||
836 | /* Wait for exclusive access to hardware */ | ||
837 | down(&ctrl->crit_sect); | ||
838 | |||
839 | p_slot->hpc_ops->set_attention_status(p_slot, 1); | ||
840 | |||
841 | p_slot->hpc_ops->green_led_off(p_slot); | ||
842 | |||
843 | /* Done with exclusive hardware access */ | ||
844 | up(&ctrl->crit_sect); | ||
845 | } else { | ||
846 | /* refresh notification */ | ||
847 | if (p_slot) | ||
848 | update_slot_info(p_slot); | ||
849 | } | ||
850 | |||
851 | ctrl->event_queue[loop].event_type = 0; | ||
852 | |||
853 | change = 1; | ||
854 | } | ||
855 | } /* End of FOR loop */ | ||
856 | } | 541 | } |
542 | } | ||
543 | |||
544 | static void interrupt_event_handler(void *data) | ||
545 | { | ||
546 | struct event_info *info = data; | ||
547 | struct slot *p_slot = info->p_slot; | ||
548 | |||
549 | mutex_lock(&p_slot->lock); | ||
550 | switch (info->event_type) { | ||
551 | case INT_BUTTON_PRESS: | ||
552 | handle_button_press_event(p_slot); | ||
553 | break; | ||
554 | case INT_POWER_FAULT: | ||
555 | dbg("%s: power fault\n", __FUNCTION__); | ||
556 | p_slot->hpc_ops->set_attention_status(p_slot, 1); | ||
557 | p_slot->hpc_ops->green_led_off(p_slot); | ||
558 | break; | ||
559 | default: | ||
560 | update_slot_info(p_slot); | ||
561 | break; | ||
562 | } | ||
563 | mutex_unlock(&p_slot->lock); | ||
857 | 564 | ||
858 | return; | 565 | kfree(info); |
859 | } | 566 | } |
860 | 567 | ||
861 | 568 | ||
862 | int shpchp_enable_slot (struct slot *p_slot) | 569 | static int shpchp_enable_slot (struct slot *p_slot) |
863 | { | 570 | { |
864 | u8 getstatus = 0; | 571 | u8 getstatus = 0; |
865 | int rc; | 572 | int rc, retval = -ENODEV; |
866 | 573 | ||
867 | /* Check to see if (latch closed, card present, power off) */ | 574 | /* Check to see if (latch closed, card present, power off) */ |
868 | down(&p_slot->ctrl->crit_sect); | 575 | mutex_lock(&p_slot->ctrl->crit_sect); |
869 | rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); | 576 | rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); |
870 | if (rc || !getstatus) { | 577 | if (rc || !getstatus) { |
871 | info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number); | 578 | info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number); |
872 | up(&p_slot->ctrl->crit_sect); | 579 | goto out; |
873 | return -ENODEV; | ||
874 | } | 580 | } |
875 | rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); | 581 | rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); |
876 | if (rc || getstatus) { | 582 | if (rc || getstatus) { |
877 | info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number); | 583 | info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number); |
878 | up(&p_slot->ctrl->crit_sect); | 584 | goto out; |
879 | return -ENODEV; | ||
880 | } | 585 | } |
881 | rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); | 586 | rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); |
882 | if (rc || getstatus) { | 587 | if (rc || getstatus) { |
883 | info("%s: already enabled on slot(%x)\n", __FUNCTION__, p_slot->number); | 588 | info("%s: already enabled on slot(%x)\n", __FUNCTION__, p_slot->number); |
884 | up(&p_slot->ctrl->crit_sect); | 589 | goto out; |
885 | return -ENODEV; | ||
886 | } | 590 | } |
887 | up(&p_slot->ctrl->crit_sect); | ||
888 | 591 | ||
889 | p_slot->is_a_board = 1; | 592 | p_slot->is_a_board = 1; |
890 | 593 | ||
@@ -899,56 +602,119 @@ int shpchp_enable_slot (struct slot *p_slot) | |||
899 | && p_slot->ctrl->num_slots == 1) { | 602 | && p_slot->ctrl->num_slots == 1) { |
900 | /* handle amd pogo errata; this must be done before enable */ | 603 | /* handle amd pogo errata; this must be done before enable */ |
901 | amd_pogo_errata_save_misc_reg(p_slot); | 604 | amd_pogo_errata_save_misc_reg(p_slot); |
902 | rc = board_added(p_slot); | 605 | retval = board_added(p_slot); |
903 | /* handle amd pogo errata; this must be done after enable */ | 606 | /* handle amd pogo errata; this must be done after enable */ |
904 | amd_pogo_errata_restore_misc_reg(p_slot); | 607 | amd_pogo_errata_restore_misc_reg(p_slot); |
905 | } else | 608 | } else |
906 | rc = board_added(p_slot); | 609 | retval = board_added(p_slot); |
907 | 610 | ||
908 | if (rc) { | 611 | if (retval) { |
909 | p_slot->hpc_ops->get_adapter_status(p_slot, | 612 | p_slot->hpc_ops->get_adapter_status(p_slot, |
910 | &(p_slot->presence_save)); | 613 | &(p_slot->presence_save)); |
911 | p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); | 614 | p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); |
912 | } | 615 | } |
913 | 616 | ||
914 | update_slot_info(p_slot); | 617 | update_slot_info(p_slot); |
915 | return rc; | 618 | out: |
619 | mutex_unlock(&p_slot->ctrl->crit_sect); | ||
620 | return retval; | ||
916 | } | 621 | } |
917 | 622 | ||
918 | 623 | ||
919 | int shpchp_disable_slot (struct slot *p_slot) | 624 | static int shpchp_disable_slot (struct slot *p_slot) |
920 | { | 625 | { |
921 | u8 getstatus = 0; | 626 | u8 getstatus = 0; |
922 | int ret = 0; | 627 | int rc, retval = -ENODEV; |
923 | 628 | ||
924 | if (!p_slot->ctrl) | 629 | if (!p_slot->ctrl) |
925 | return -ENODEV; | 630 | return -ENODEV; |
926 | 631 | ||
927 | /* Check to see if (latch closed, card present, power on) */ | 632 | /* Check to see if (latch closed, card present, power on) */ |
928 | down(&p_slot->ctrl->crit_sect); | 633 | mutex_lock(&p_slot->ctrl->crit_sect); |
929 | 634 | ||
930 | ret = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); | 635 | rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); |
931 | if (ret || !getstatus) { | 636 | if (rc || !getstatus) { |
932 | info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number); | 637 | info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number); |
933 | up(&p_slot->ctrl->crit_sect); | 638 | goto out; |
934 | return -ENODEV; | ||
935 | } | 639 | } |
936 | ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); | 640 | rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); |
937 | if (ret || getstatus) { | 641 | if (rc || getstatus) { |
938 | info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number); | 642 | info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number); |
939 | up(&p_slot->ctrl->crit_sect); | 643 | goto out; |
940 | return -ENODEV; | ||
941 | } | 644 | } |
942 | ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); | 645 | rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); |
943 | if (ret || !getstatus) { | 646 | if (rc || !getstatus) { |
944 | info("%s: already disabled slot(%x)\n", __FUNCTION__, p_slot->number); | 647 | info("%s: already disabled slot(%x)\n", __FUNCTION__, p_slot->number); |
945 | up(&p_slot->ctrl->crit_sect); | 648 | goto out; |
946 | return -ENODEV; | ||
947 | } | 649 | } |
948 | up(&p_slot->ctrl->crit_sect); | ||
949 | 650 | ||
950 | ret = remove_board(p_slot); | 651 | retval = remove_board(p_slot); |
951 | update_slot_info(p_slot); | 652 | update_slot_info(p_slot); |
952 | return ret; | 653 | out: |
654 | mutex_unlock(&p_slot->ctrl->crit_sect); | ||
655 | return retval; | ||
953 | } | 656 | } |
954 | 657 | ||
658 | int shpchp_sysfs_enable_slot(struct slot *p_slot) | ||
659 | { | ||
660 | int retval = -ENODEV; | ||
661 | |||
662 | mutex_lock(&p_slot->lock); | ||
663 | switch (p_slot->state) { | ||
664 | case BLINKINGON_STATE: | ||
665 | cancel_delayed_work(&p_slot->work); | ||
666 | case STATIC_STATE: | ||
667 | p_slot->state = POWERON_STATE; | ||
668 | mutex_unlock(&p_slot->lock); | ||
669 | retval = shpchp_enable_slot(p_slot); | ||
670 | mutex_lock(&p_slot->lock); | ||
671 | p_slot->state = STATIC_STATE; | ||
672 | break; | ||
673 | case POWERON_STATE: | ||
674 | info("Slot %s is already in powering on state\n", | ||
675 | p_slot->name); | ||
676 | break; | ||
677 | case BLINKINGOFF_STATE: | ||
678 | case POWEROFF_STATE: | ||
679 | info("Already enabled on slot %s\n", p_slot->name); | ||
680 | break; | ||
681 | default: | ||
682 | err("Not a valid state on slot %s\n", p_slot->name); | ||
683 | break; | ||
684 | } | ||
685 | mutex_unlock(&p_slot->lock); | ||
686 | |||
687 | return retval; | ||
688 | } | ||
689 | |||
690 | int shpchp_sysfs_disable_slot(struct slot *p_slot) | ||
691 | { | ||
692 | int retval = -ENODEV; | ||
693 | |||
694 | mutex_lock(&p_slot->lock); | ||
695 | switch (p_slot->state) { | ||
696 | case BLINKINGOFF_STATE: | ||
697 | cancel_delayed_work(&p_slot->work); | ||
698 | case STATIC_STATE: | ||
699 | p_slot->state = POWEROFF_STATE; | ||
700 | mutex_unlock(&p_slot->lock); | ||
701 | retval = shpchp_disable_slot(p_slot); | ||
702 | mutex_lock(&p_slot->lock); | ||
703 | p_slot->state = STATIC_STATE; | ||
704 | break; | ||
705 | case POWEROFF_STATE: | ||
706 | info("Slot %s is already in powering off state\n", | ||
707 | p_slot->name); | ||
708 | break; | ||
709 | case BLINKINGON_STATE: | ||
710 | case POWERON_STATE: | ||
711 | info("Already disabled on slot %s\n", p_slot->name); | ||
712 | break; | ||
713 | default: | ||
714 | err("Not a valid state on slot %s\n", p_slot->name); | ||
715 | break; | ||
716 | } | ||
717 | mutex_unlock(&p_slot->lock); | ||
718 | |||
719 | return retval; | ||
720 | } | ||