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