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