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