]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - drivers/pci/hotplug/pciehp_ctrl.c
072befa345a7519138df15ec4d9b72eb1a62ce96
[linux-2.6-omap-h63xx.git] / drivers / pci / hotplug / pciehp_ctrl.c
1 /*
2  * PCI Express 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/module.h>
31 #include <linux/kernel.h>
32 #include <linux/types.h>
33 #include <linux/smp_lock.h>
34 #include <linux/pci.h>
35 #include "../pci.h"
36 #include "pciehp.h"
37
38 static void interrupt_event_handler(struct controller *ctrl);
39
40 static struct semaphore event_semaphore;        /* mutex for process loop (up if something to process) */
41 static struct semaphore event_exit;             /* guard ensure thread has exited before calling it quits */
42 static int event_finished;
43 static unsigned long pushbutton_pending;        /* = 0 */
44 static unsigned long surprise_rm_pending;       /* = 0 */
45
46 static inline char *slot_name(struct slot *p_slot)
47 {
48         return p_slot->hotplug_slot->name;
49 }
50
51 u8 pciehp_handle_attention_button(u8 hp_slot, struct controller *ctrl)
52 {
53         struct slot *p_slot;
54         u8 rc = 0;
55         u8 getstatus;
56         struct event_info *taskInfo;
57
58         /* Attention Button Change */
59         dbg("pciehp:  Attention button interrupt received.\n");
60         
61         /* This is the structure that tells the worker thread what to do */
62         taskInfo = &(ctrl->event_queue[ctrl->next_event]);
63         p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
64
65         p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
66         
67         ctrl->next_event = (ctrl->next_event + 1) % MAX_EVENTS;
68         taskInfo->hp_slot = hp_slot;
69
70         rc++;
71
72         /*
73          *  Button pressed - See if need to TAKE ACTION!!!
74          */
75         info("Button pressed on Slot(%s)\n", slot_name(p_slot));
76         taskInfo->event_type = INT_BUTTON_PRESS;
77
78         if ((p_slot->state == BLINKINGON_STATE)
79             || (p_slot->state == BLINKINGOFF_STATE)) {
80                 /* Cancel if we are still blinking; this means that we press the
81                  * attention again before the 5 sec. limit expires to cancel hot-add
82                  * or hot-remove
83                  */
84                 taskInfo->event_type = INT_BUTTON_CANCEL;
85                 info("Button cancel on Slot(%s)\n", slot_name(p_slot));
86         } else if ((p_slot->state == POWERON_STATE)
87                    || (p_slot->state == POWEROFF_STATE)) {
88                 /* Ignore if the slot is on power-on or power-off state; this 
89                  * means that the previous attention button action to hot-add or
90                  * hot-remove is undergoing
91                  */
92                 taskInfo->event_type = INT_BUTTON_IGNORE;
93                 info("Button ignore on Slot(%s)\n", slot_name(p_slot));
94         }
95
96         if (rc)
97                 up(&event_semaphore);   /* signal event thread that new event is posted */
98
99         return 0;
100
101 }
102
103 u8 pciehp_handle_switch_change(u8 hp_slot, struct controller *ctrl)
104 {
105         struct slot *p_slot;
106         u8 rc = 0;
107         u8 getstatus;
108         struct event_info *taskInfo;
109
110         /* Switch Change */
111         dbg("pciehp:  Switch interrupt received.\n");
112
113         /* This is the structure that tells the worker thread
114          * what to do
115          */
116         taskInfo = &(ctrl->event_queue[ctrl->next_event]);
117         ctrl->next_event = (ctrl->next_event + 1) % MAX_EVENTS;
118         taskInfo->hp_slot = hp_slot;
119
120         rc++;
121         p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
122         p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
123
124         if (getstatus) {
125                 /*
126                  * Switch opened
127                  */
128                 info("Latch open on Slot(%s)\n", slot_name(p_slot));
129                 taskInfo->event_type = INT_SWITCH_OPEN;
130         } else {
131                 /*
132                  *  Switch closed
133                  */
134                 info("Latch close on Slot(%s)\n", slot_name(p_slot));
135                 taskInfo->event_type = INT_SWITCH_CLOSE;
136         }
137
138         if (rc)
139                 up(&event_semaphore);   /* signal event thread that new event is posted */
140
141         return rc;
142 }
143
144 u8 pciehp_handle_presence_change(u8 hp_slot, struct controller *ctrl)
145 {
146         struct slot *p_slot;
147         u8 presence_save, rc = 0;
148         struct event_info *taskInfo;
149
150         /* Presence Change */
151         dbg("pciehp:  Presence/Notify input change.\n");
152
153         /* This is the structure that tells the worker thread
154          * what to do
155          */
156         taskInfo = &(ctrl->event_queue[ctrl->next_event]);
157         ctrl->next_event = (ctrl->next_event + 1) % MAX_EVENTS;
158         taskInfo->hp_slot = hp_slot;
159
160         rc++;
161         p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
162
163         /* Switch is open, assume a presence change
164          * Save the presence state
165          */
166         p_slot->hpc_ops->get_adapter_status(p_slot, &presence_save);
167         if (presence_save) {
168                 /*
169                  * Card Present
170                  */
171                 info("Card present on Slot(%s)\n", slot_name(p_slot));
172                 taskInfo->event_type = INT_PRESENCE_ON;
173         } else {
174                 /*
175                  * Not Present
176                  */
177                 info("Card not present on Slot(%s)\n", slot_name(p_slot));
178                 taskInfo->event_type = INT_PRESENCE_OFF;
179         }
180
181         if (rc)
182                 up(&event_semaphore);   /* signal event thread that new event is posted */
183
184         return rc;
185 }
186
187 u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl)
188 {
189         struct slot *p_slot;
190         u8 rc = 0;
191         struct event_info *taskInfo;
192
193         /* power fault */
194         dbg("pciehp:  Power fault interrupt received.\n");
195
196         /* this is the structure that tells the worker thread
197          * what to do
198          */
199         taskInfo = &(ctrl->event_queue[ctrl->next_event]);
200         ctrl->next_event = (ctrl->next_event + 1) % MAX_EVENTS;
201         taskInfo->hp_slot = hp_slot;
202
203         rc++;
204         p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
205
206         if ( !(p_slot->hpc_ops->query_power_fault(p_slot))) {
207                 /*
208                  * power fault Cleared
209                  */
210                 info("Power fault cleared on Slot(%s)\n", slot_name(p_slot));
211                 taskInfo->event_type = INT_POWER_FAULT_CLEAR;
212         } else {
213                 /*
214                  *   power fault
215                  */
216                 info("Power fault on Slot(%s)\n", slot_name(p_slot));
217                 taskInfo->event_type = INT_POWER_FAULT;
218                 info("power fault bit %x set\n", hp_slot);
219         }
220         if (rc)
221                 up(&event_semaphore);   /* signal event thread that new event is posted */
222
223         return rc;
224 }
225
226 /* The following routines constitute the bulk of the 
227    hotplug controller logic
228  */
229
230 static void set_slot_off(struct controller *ctrl, struct slot * pslot)
231 {
232         /* Wait for exclusive access to hardware */
233         mutex_lock(&ctrl->ctrl_lock);
234
235         /* turn off slot, turn on Amber LED, turn off Green LED if supported*/
236         if (POWER_CTRL(ctrl->ctrlcap)) {
237                 if (pslot->hpc_ops->power_off_slot(pslot)) {   
238                         err("%s: Issue of Slot Power Off command failed\n", __FUNCTION__);
239                         mutex_unlock(&ctrl->ctrl_lock);
240                         return;
241                 }
242                 wait_for_ctrl_irq (ctrl);
243         }
244
245         if (PWR_LED(ctrl->ctrlcap)) {
246                 pslot->hpc_ops->green_led_off(pslot);   
247                 wait_for_ctrl_irq (ctrl);
248         }
249
250         if (ATTN_LED(ctrl->ctrlcap)) { 
251                 if (pslot->hpc_ops->set_attention_status(pslot, 1)) {   
252                         err("%s: Issue of Set Attention Led command failed\n", __FUNCTION__);
253                         mutex_unlock(&ctrl->ctrl_lock);
254                         return;
255                 }
256                 wait_for_ctrl_irq (ctrl);
257         }
258
259         /* Done with exclusive hardware access */
260         mutex_unlock(&ctrl->ctrl_lock);
261 }
262
263 /**
264  * board_added - Called after a board has been added to the system.
265  *
266  * Turns power on for the board
267  * Configures board
268  *
269  */
270 static int board_added(struct slot *p_slot)
271 {
272         u8 hp_slot;
273         int rc = 0;
274         struct controller *ctrl = p_slot->ctrl;
275
276         hp_slot = p_slot->device - ctrl->slot_device_offset;
277
278         dbg("%s: slot device, slot offset, hp slot = %d, %d ,%d\n",
279                         __FUNCTION__, p_slot->device,
280                         ctrl->slot_device_offset, hp_slot);
281
282         /* Wait for exclusive access to hardware */
283         mutex_lock(&ctrl->ctrl_lock);
284
285         if (POWER_CTRL(ctrl->ctrlcap)) {
286                 /* Power on slot */
287                 rc = p_slot->hpc_ops->power_on_slot(p_slot);
288                 if (rc) {
289                         mutex_unlock(&ctrl->ctrl_lock);
290                         return -1;
291                 }
292
293                 /* Wait for the command to complete */
294                 wait_for_ctrl_irq (ctrl);
295         }
296         
297         if (PWR_LED(ctrl->ctrlcap)) {
298                 p_slot->hpc_ops->green_led_blink(p_slot);
299                         
300                 /* Wait for the command to complete */
301                 wait_for_ctrl_irq (ctrl);
302         }
303
304         /* Done with exclusive hardware access */
305         mutex_unlock(&ctrl->ctrl_lock);
306
307         /* Wait for ~1 second */
308         wait_for_ctrl_irq (ctrl);
309
310         /*  Check link training status */
311         rc = p_slot->hpc_ops->check_lnk_status(ctrl);  
312         if (rc) {
313                 err("%s: Failed to check link status\n", __FUNCTION__);
314                 set_slot_off(ctrl, p_slot);
315                 return rc;
316         }
317
318         /* Check for a power fault */
319         if (p_slot->hpc_ops->query_power_fault(p_slot)) {
320                 dbg("%s: power fault detected\n", __FUNCTION__);
321                 rc = POWER_FAILURE;
322                 goto err_exit;
323         }
324
325         rc = pciehp_configure_device(p_slot);
326         if (rc) {
327                 err("Cannot add device 0x%x:%x\n", p_slot->bus,
328                                 p_slot->device);
329                 goto err_exit;
330         }
331
332         /*
333          * Some PCI Express root ports require fixup after hot-plug operation.
334          */
335         if (pcie_mch_quirk)
336                 pci_fixup_device(pci_fixup_final, ctrl->pci_dev);
337         if (PWR_LED(ctrl->ctrlcap)) {
338                 /* Wait for exclusive access to hardware */
339                 mutex_lock(&ctrl->ctrl_lock);
340
341                 p_slot->hpc_ops->green_led_on(p_slot);
342   
343                 /* Wait for the command to complete */
344                 wait_for_ctrl_irq (ctrl);
345         
346                 /* Done with exclusive hardware access */
347                 mutex_unlock(&ctrl->ctrl_lock);
348         }
349         return 0;
350
351 err_exit:
352         set_slot_off(ctrl, p_slot);
353         return -1;
354 }
355
356
357 /**
358  * remove_board - Turns off slot and LED's
359  *
360  */
361 static int remove_board(struct slot *p_slot)
362 {
363         u8 device;
364         u8 hp_slot;
365         int rc;
366         struct controller *ctrl = p_slot->ctrl;
367
368         if (pciehp_unconfigure_device(p_slot))
369                 return 1;
370
371         device = p_slot->device;
372
373         hp_slot = p_slot->device - ctrl->slot_device_offset;
374         p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
375
376         dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot);
377
378         /* Wait for exclusive access to hardware */
379         mutex_lock(&ctrl->ctrl_lock);
380
381         if (POWER_CTRL(ctrl->ctrlcap)) {
382                 /* power off slot */
383                 rc = p_slot->hpc_ops->power_off_slot(p_slot);
384                 if (rc) {
385                         err("%s: Issue of Slot Disable command failed\n", __FUNCTION__);
386                         mutex_unlock(&ctrl->ctrl_lock);
387                         return rc;
388                 }
389                 /* Wait for the command to complete */
390                 wait_for_ctrl_irq (ctrl);
391         }
392
393         if (PWR_LED(ctrl->ctrlcap)) {
394                 /* turn off Green LED */
395                 p_slot->hpc_ops->green_led_off(p_slot);
396         
397                 /* Wait for the command to complete */
398                 wait_for_ctrl_irq (ctrl);
399         }
400
401         /* Done with exclusive hardware access */
402         mutex_unlock(&ctrl->ctrl_lock);
403
404         return 0;
405 }
406
407
408 static void pushbutton_helper_thread(unsigned long data)
409 {
410         pushbutton_pending = data;
411
412         up(&event_semaphore);
413 }
414
415 /**
416  * pciehp_pushbutton_thread
417  *
418  * Scheduled procedure to handle blocking stuff for the pushbuttons
419  * Handles all pending events and exits.
420  *
421  */
422 static void pciehp_pushbutton_thread(unsigned long slot)
423 {
424         struct slot *p_slot = (struct slot *) slot;
425         u8 getstatus;
426         
427         pushbutton_pending = 0;
428
429         if (!p_slot) {
430                 dbg("%s: Error! slot NULL\n", __FUNCTION__);
431                 return;
432         }
433
434         p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
435         if (getstatus) {
436                 p_slot->state = POWEROFF_STATE;
437                 dbg("%s: disabling bus:device(%x:%x)\n", __FUNCTION__,
438                                 p_slot->bus, p_slot->device);
439
440                 pciehp_disable_slot(p_slot);
441                 p_slot->state = STATIC_STATE;
442         } else {
443                 p_slot->state = POWERON_STATE;
444                 dbg("%s: adding bus:device(%x:%x)\n", __FUNCTION__,
445                                 p_slot->bus, p_slot->device);
446
447                 if (pciehp_enable_slot(p_slot) && PWR_LED(p_slot->ctrl->ctrlcap)) {
448                         /* Wait for exclusive access to hardware */
449                         mutex_lock(&p_slot->ctrl->ctrl_lock);
450
451                         p_slot->hpc_ops->green_led_off(p_slot);
452
453                         /* Wait for the command to complete */
454                         wait_for_ctrl_irq (p_slot->ctrl);
455
456                         /* Done with exclusive hardware access */
457                         mutex_unlock(&p_slot->ctrl->ctrl_lock);
458                 }
459                 p_slot->state = STATIC_STATE;
460         }
461
462         return;
463 }
464
465 /**
466  * pciehp_surprise_rm_thread
467  *
468  * Scheduled procedure to handle blocking stuff for the surprise removal
469  * Handles all pending events and exits.
470  *
471  */
472 static void pciehp_surprise_rm_thread(unsigned long slot)
473 {
474         struct slot *p_slot = (struct slot *) slot;
475         u8 getstatus;
476         
477         surprise_rm_pending = 0;
478
479         if (!p_slot) {
480                 dbg("%s: Error! slot NULL\n", __FUNCTION__);
481                 return;
482         }
483
484         p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
485         if (!getstatus) {
486                 p_slot->state = POWEROFF_STATE;
487                 dbg("%s: removing bus:device(%x:%x)\n",
488                                 __FUNCTION__, p_slot->bus, p_slot->device);
489
490                 pciehp_disable_slot(p_slot);
491                 p_slot->state = STATIC_STATE;
492         } else {
493                 p_slot->state = POWERON_STATE;
494                 dbg("%s: adding bus:device(%x:%x)\n",
495                                 __FUNCTION__, p_slot->bus, p_slot->device);
496
497                 if (pciehp_enable_slot(p_slot) && PWR_LED(p_slot->ctrl->ctrlcap)) {
498                         /* Wait for exclusive access to hardware */
499                         mutex_lock(&p_slot->ctrl->ctrl_lock);
500
501                         p_slot->hpc_ops->green_led_off(p_slot);
502
503                         /* Wait for the command to complete */
504                         wait_for_ctrl_irq (p_slot->ctrl);
505
506                         /* Done with exclusive hardware access */
507                         mutex_unlock(&p_slot->ctrl->ctrl_lock);
508                 }
509                 p_slot->state = STATIC_STATE;
510         }
511
512         return;
513 }
514
515
516
517 /* this is the main worker thread */
518 static int event_thread(void* data)
519 {
520         struct controller *ctrl;
521         lock_kernel();
522         daemonize("pciehpd_event");
523
524         unlock_kernel();
525
526         while (1) {
527                 dbg("!!!!event_thread sleeping\n");
528                 down_interruptible (&event_semaphore);
529                 dbg("event_thread woken finished = %d\n", event_finished);
530                 if (event_finished || signal_pending(current))
531                         break;
532                 /* Do stuff here */
533                 if (pushbutton_pending)
534                         pciehp_pushbutton_thread(pushbutton_pending);
535                 else if (surprise_rm_pending)
536                         pciehp_surprise_rm_thread(surprise_rm_pending);
537                 else
538                         for (ctrl = pciehp_ctrl_list; ctrl; ctrl=ctrl->next)
539                                 interrupt_event_handler(ctrl);
540         }
541         dbg("event_thread signals exit\n");
542         up(&event_exit);
543         return 0;
544 }
545
546 int pciehp_event_start_thread(void)
547 {
548         int pid;
549
550         /* initialize our semaphores */
551         init_MUTEX_LOCKED(&event_exit);
552         event_finished=0;
553
554         init_MUTEX_LOCKED(&event_semaphore);
555         pid = kernel_thread(event_thread, NULL, 0);
556
557         if (pid < 0) {
558                 err ("Can't start up our event thread\n");
559                 return -1;
560         }
561         return 0;
562 }
563
564
565 void pciehp_event_stop_thread(void)
566 {
567         event_finished = 1;
568         up(&event_semaphore);
569         down(&event_exit);
570 }
571
572
573 static int update_slot_info(struct slot *slot)
574 {
575         struct hotplug_slot_info *info;
576         /* char buffer[SLOT_NAME_SIZE]; */
577         int result;
578
579         info = kmalloc(sizeof(struct hotplug_slot_info), GFP_KERNEL);
580         if (!info)
581                 return -ENOMEM;
582
583         /* make_slot_name (&buffer[0], SLOT_NAME_SIZE, slot); */
584
585         slot->hpc_ops->get_power_status(slot, &(info->power_status));
586         slot->hpc_ops->get_attention_status(slot, &(info->attention_status));
587         slot->hpc_ops->get_latch_status(slot, &(info->latch_status));
588         slot->hpc_ops->get_adapter_status(slot, &(info->adapter_status));
589
590         /* result = pci_hp_change_slot_info(buffer, info); */
591         result = pci_hp_change_slot_info(slot->hotplug_slot, info);
592         kfree (info);
593         return result;
594 }
595
596 static void interrupt_event_handler(struct controller *ctrl)
597 {
598         int loop = 0;
599         int change = 1;
600         u8 hp_slot;
601         u8 getstatus;
602         struct slot *p_slot;
603
604         while (change) {
605                 change = 0;
606
607                 for (loop = 0; loop < MAX_EVENTS; loop++) {
608                         if (ctrl->event_queue[loop].event_type != 0) {
609                                 hp_slot = ctrl->event_queue[loop].hp_slot;
610
611                                 p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
612
613                                 if (ctrl->event_queue[loop].event_type == INT_BUTTON_CANCEL) {
614                                         dbg("button cancel\n");
615                                         del_timer(&p_slot->task_event);
616
617                                         switch (p_slot->state) {
618                                         case BLINKINGOFF_STATE:
619                                                 /* Wait for exclusive access to hardware */
620                                                 mutex_lock(&ctrl->ctrl_lock);
621                                                 
622                                                 if (PWR_LED(ctrl->ctrlcap)) {
623                                                         p_slot->hpc_ops->green_led_on(p_slot);
624                                                         /* Wait for the command to complete */
625                                                         wait_for_ctrl_irq (ctrl);
626                                                 }
627                                                 if (ATTN_LED(ctrl->ctrlcap)) {
628                                                         p_slot->hpc_ops->set_attention_status(p_slot, 0);
629
630                                                         /* Wait for the command to complete */
631                                                         wait_for_ctrl_irq (ctrl);
632                                                 }
633                                                 /* Done with exclusive hardware access */
634                                                 mutex_unlock(&ctrl->ctrl_lock);
635                                                 break;
636                                         case BLINKINGON_STATE:
637                                                 /* Wait for exclusive access to hardware */
638                                                 mutex_lock(&ctrl->ctrl_lock);
639
640                                                 if (PWR_LED(ctrl->ctrlcap)) {
641                                                         p_slot->hpc_ops->green_led_off(p_slot);
642                                                         /* Wait for the command to complete */
643                                                         wait_for_ctrl_irq (ctrl);
644                                                 }
645                                                 if (ATTN_LED(ctrl->ctrlcap)){
646                                                         p_slot->hpc_ops->set_attention_status(p_slot, 0);
647                                                         /* Wait for the command to complete */
648                                                         wait_for_ctrl_irq (ctrl);
649                                                 }
650                                                 /* Done with exclusive hardware access */
651                                                 mutex_unlock(&ctrl->ctrl_lock);
652
653                                                 break;
654                                         default:
655                                                 warn("Not a valid state\n");
656                                                 return;
657                                         }
658                                         info("PCI slot #%s - action canceled due to button press.\n", slot_name(p_slot));
659                                         p_slot->state = STATIC_STATE;
660                                 }
661                                 /* ***********Button Pressed (No action on 1st press...) */
662                                 else if (ctrl->event_queue[loop].event_type == INT_BUTTON_PRESS) {
663                                         
664                                         if (ATTN_BUTTN(ctrl->ctrlcap)) {
665                                                 dbg("Button pressed\n");
666                                                 p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
667                                                 if (getstatus) {
668                                                         /* slot is on */
669                                                         dbg("slot is on\n");
670                                                         p_slot->state = BLINKINGOFF_STATE;
671                                                         info("PCI slot #%s - powering off due to button press.\n", slot_name(p_slot));
672                                                 } else {
673                                                         /* slot is off */
674                                                         dbg("slot is off\n");
675                                                         p_slot->state = BLINKINGON_STATE;
676                                                         info("PCI slot #%s - powering on due to button press.\n", slot_name(p_slot));
677                                                 }
678
679                                                 /* Wait for exclusive access to hardware */
680                                                 mutex_lock(&ctrl->ctrl_lock);
681
682                                                 /* blink green LED and turn off amber */
683                                                 if (PWR_LED(ctrl->ctrlcap)) {
684                                                         p_slot->hpc_ops->green_led_blink(p_slot);
685                                                         /* Wait for the command to complete */
686                                                         wait_for_ctrl_irq (ctrl);
687                                                 }
688
689                                                 if (ATTN_LED(ctrl->ctrlcap)) {
690                                                         p_slot->hpc_ops->set_attention_status(p_slot, 0);
691
692                                                         /* Wait for the command to complete */
693                                                         wait_for_ctrl_irq (ctrl);
694                                                 }
695
696                                                 /* Done with exclusive hardware access */
697                                                 mutex_unlock(&ctrl->ctrl_lock);
698
699                                                 init_timer(&p_slot->task_event);
700                                                 p_slot->task_event.expires = jiffies + 5 * HZ;   /* 5 second delay */
701                                                 p_slot->task_event.function = (void (*)(unsigned long)) pushbutton_helper_thread;
702                                                 p_slot->task_event.data = (unsigned long) p_slot;
703
704                                                 add_timer(&p_slot->task_event);
705                                         }
706                                 }
707                                 /***********POWER FAULT********************/
708                                 else if (ctrl->event_queue[loop].event_type == INT_POWER_FAULT) {
709                                         if (POWER_CTRL(ctrl->ctrlcap)) {
710                                                 dbg("power fault\n");
711                                                 /* Wait for exclusive access to hardware */
712                                                 mutex_lock(&ctrl->ctrl_lock);
713
714                                                 if (ATTN_LED(ctrl->ctrlcap)) {
715                                                         p_slot->hpc_ops->set_attention_status(p_slot, 1);
716                                                         wait_for_ctrl_irq (ctrl);
717                                                 }
718
719                                                 if (PWR_LED(ctrl->ctrlcap)) {
720                                                         p_slot->hpc_ops->green_led_off(p_slot);
721                                                         wait_for_ctrl_irq (ctrl);
722                                                 }
723
724                                                 /* Done with exclusive hardware access */
725                                                 mutex_unlock(&ctrl->ctrl_lock);
726                                         }
727                                 }
728                                 /***********SURPRISE REMOVAL********************/
729                                 else if ((ctrl->event_queue[loop].event_type == INT_PRESENCE_ON) || 
730                                         (ctrl->event_queue[loop].event_type == INT_PRESENCE_OFF)) {
731                                         if (HP_SUPR_RM(ctrl->ctrlcap)) {
732                                                 dbg("Surprise Removal\n");
733                                                 if (p_slot) {
734                                                         surprise_rm_pending = (unsigned long) p_slot;
735                                                         up(&event_semaphore);
736                                                         update_slot_info(p_slot);
737                                                 }
738                                         }
739                                 } else {
740                                         /* refresh notification */
741                                         if (p_slot)
742                                                 update_slot_info(p_slot);
743                                 }
744
745                                 ctrl->event_queue[loop].event_type = 0;
746
747                                 change = 1;
748                         }
749                 }               /* End of FOR loop */
750         }
751 }
752
753
754 int pciehp_enable_slot(struct slot *p_slot)
755 {
756         u8 getstatus = 0;
757         int rc;
758
759         /* Check to see if (latch closed, card present, power off) */
760         mutex_lock(&p_slot->ctrl->crit_sect);
761
762         rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
763         if (rc || !getstatus) {
764                 info("%s: no adapter on slot(%s)\n", __FUNCTION__,
765                      slot_name(p_slot));
766                 mutex_unlock(&p_slot->ctrl->crit_sect);
767                 return -ENODEV;
768         }
769         if (MRL_SENS(p_slot->ctrl->ctrlcap)) {  
770                 rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
771                 if (rc || getstatus) {
772                         info("%s: latch open on slot(%s)\n", __FUNCTION__,
773                              slot_name(p_slot));
774                         mutex_unlock(&p_slot->ctrl->crit_sect);
775                         return -ENODEV;
776                 }
777         }
778         
779         if (POWER_CTRL(p_slot->ctrl->ctrlcap)) {        
780                 rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
781                 if (rc || getstatus) {
782                         info("%s: already enabled on slot(%s)\n", __FUNCTION__,
783                              slot_name(p_slot));
784                         mutex_unlock(&p_slot->ctrl->crit_sect);
785                         return -EINVAL;
786                 }
787         }
788
789         p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
790
791         rc = board_added(p_slot);
792         if (rc) {
793                 p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
794         }
795
796         update_slot_info(p_slot);
797
798         mutex_unlock(&p_slot->ctrl->crit_sect);
799         return rc;
800 }
801
802
803 int pciehp_disable_slot(struct slot *p_slot)
804 {
805         u8 getstatus = 0;
806         int ret = 0;
807
808         if (!p_slot->ctrl)
809                 return 1;
810
811         /* Check to see if (latch closed, card present, power on) */
812         mutex_lock(&p_slot->ctrl->crit_sect);
813
814         if (!HP_SUPR_RM(p_slot->ctrl->ctrlcap)) {       
815                 ret = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
816                 if (ret || !getstatus) {
817                         info("%s: no adapter on slot(%s)\n", __FUNCTION__,
818                              slot_name(p_slot));
819                         mutex_unlock(&p_slot->ctrl->crit_sect);
820                         return -ENODEV;
821                 }
822         }
823
824         if (MRL_SENS(p_slot->ctrl->ctrlcap)) {  
825                 ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
826                 if (ret || getstatus) {
827                         info("%s: latch open on slot(%s)\n", __FUNCTION__,
828                              slot_name(p_slot));
829                         mutex_unlock(&p_slot->ctrl->crit_sect);
830                         return -ENODEV;
831                 }
832         }
833
834         if (POWER_CTRL(p_slot->ctrl->ctrlcap)) {        
835                 ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
836                 if (ret || !getstatus) {
837                         info("%s: already disabled slot(%s)\n", __FUNCTION__,
838                              slot_name(p_slot));
839                         mutex_unlock(&p_slot->ctrl->crit_sect);
840                         return -EINVAL;
841                 }
842         }
843
844         ret = remove_board(p_slot);
845         update_slot_info(p_slot);
846
847         mutex_unlock(&p_slot->ctrl->crit_sect);
848         return ret;
849 }
850