dcfbfffa17c6b9660c31127e8e1ede19af754241
[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: p_slot->device, slot_offset, hp_slot = %d, %d ,%d\n", __FUNCTION__, p_slot->device, ctrl->slot_device_offset, hp_slot);
281
282         /* Wait for exclusive access to hardware */
283         down(&ctrl->crit_sect);
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                         up(&ctrl->crit_sect);
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         up(&ctrl->crit_sect);
306
307         /* Wait for ~1 second */
308         dbg("%s: before long_delay\n", __FUNCTION__);
309         wait_for_ctrl_irq (ctrl);
310         dbg("%s: afterlong_delay\n", __FUNCTION__);
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("In power_down_board, b:d(%x:%x)\n", p_slot->bus, p_slot->device);
448
449                 pciehp_disable_slot(p_slot);
450                 p_slot->state = STATIC_STATE;
451         } else {
452                 p_slot->state = POWERON_STATE;
453                 dbg("In add_board, b:d(%x:%x)\n", p_slot->bus, p_slot->device);
454
455                 if (pciehp_enable_slot(p_slot) && PWR_LED(p_slot->ctrl->ctrlcap)) {
456                         /* Wait for exclusive access to hardware */
457                         down(&p_slot->ctrl->crit_sect);
458
459                         p_slot->hpc_ops->green_led_off(p_slot);
460
461                         /* Wait for the command to complete */
462                         wait_for_ctrl_irq (p_slot->ctrl);
463
464                         /* Done with exclusive hardware access */
465                         up(&p_slot->ctrl->crit_sect);
466                 }
467                 p_slot->state = STATIC_STATE;
468         }
469
470         return;
471 }
472
473 /**
474  * pciehp_surprise_rm_thread
475  *
476  * Scheduled procedure to handle blocking stuff for the surprise removal
477  * Handles all pending events and exits.
478  *
479  */
480 static void pciehp_surprise_rm_thread(unsigned long slot)
481 {
482         struct slot *p_slot = (struct slot *) slot;
483         u8 getstatus;
484         
485         surprise_rm_pending = 0;
486
487         if (!p_slot) {
488                 dbg("%s: Error! slot NULL\n", __FUNCTION__);
489                 return;
490         }
491
492         p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
493         if (!getstatus) {
494                 p_slot->state = POWEROFF_STATE;
495                 dbg("In removing board, b:d(%x:%x)\n", p_slot->bus, p_slot->device);
496
497                 pciehp_disable_slot(p_slot);
498                 p_slot->state = STATIC_STATE;
499         } else {
500                 p_slot->state = POWERON_STATE;
501                 dbg("In add_board, b:d(%x:%x)\n", p_slot->bus, p_slot->device);
502
503                 if (pciehp_enable_slot(p_slot) && PWR_LED(p_slot->ctrl->ctrlcap)) {
504                         /* Wait for exclusive access to hardware */
505                         down(&p_slot->ctrl->crit_sect);
506
507                         p_slot->hpc_ops->green_led_off(p_slot);
508
509                         /* Wait for the command to complete */
510                         wait_for_ctrl_irq (p_slot->ctrl);
511
512                         /* Done with exclusive hardware access */
513                         up(&p_slot->ctrl->crit_sect);
514                 }
515                 p_slot->state = STATIC_STATE;
516         }
517
518         return;
519 }
520
521
522
523 /* this is the main worker thread */
524 static int event_thread(void* data)
525 {
526         struct controller *ctrl;
527         lock_kernel();
528         daemonize("pciehpd_event");
529
530         unlock_kernel();
531
532         while (1) {
533                 dbg("!!!!event_thread sleeping\n");
534                 down_interruptible (&event_semaphore);
535                 dbg("event_thread woken finished = %d\n", event_finished);
536                 if (event_finished || signal_pending(current))
537                         break;
538                 /* Do stuff here */
539                 if (pushbutton_pending)
540                         pciehp_pushbutton_thread(pushbutton_pending);
541                 else if (surprise_rm_pending)
542                         pciehp_surprise_rm_thread(surprise_rm_pending);
543                 else
544                         for (ctrl = pciehp_ctrl_list; ctrl; ctrl=ctrl->next)
545                                 interrupt_event_handler(ctrl);
546         }
547         dbg("event_thread signals exit\n");
548         up(&event_exit);
549         return 0;
550 }
551
552 int pciehp_event_start_thread(void)
553 {
554         int pid;
555
556         /* initialize our semaphores */
557         init_MUTEX_LOCKED(&event_exit);
558         event_finished=0;
559
560         init_MUTEX_LOCKED(&event_semaphore);
561         pid = kernel_thread(event_thread, NULL, 0);
562
563         if (pid < 0) {
564                 err ("Can't start up our event thread\n");
565                 return -1;
566         }
567         dbg("Our event thread pid = %d\n", pid);
568         return 0;
569 }
570
571
572 void pciehp_event_stop_thread(void)
573 {
574         event_finished = 1;
575         dbg("event_thread finish command given\n");
576         up(&event_semaphore);
577         dbg("wait for event_thread to exit\n");
578         down(&event_exit);
579 }
580
581
582 static int update_slot_info(struct slot *slot)
583 {
584         struct hotplug_slot_info *info;
585         /* char buffer[SLOT_NAME_SIZE]; */
586         int result;
587
588         info = kmalloc(sizeof(struct hotplug_slot_info), GFP_KERNEL);
589         if (!info)
590                 return -ENOMEM;
591
592         /* make_slot_name (&buffer[0], SLOT_NAME_SIZE, slot); */
593
594         slot->hpc_ops->get_power_status(slot, &(info->power_status));
595         slot->hpc_ops->get_attention_status(slot, &(info->attention_status));
596         slot->hpc_ops->get_latch_status(slot, &(info->latch_status));
597         slot->hpc_ops->get_adapter_status(slot, &(info->adapter_status));
598
599         /* result = pci_hp_change_slot_info(buffer, info); */
600         result = pci_hp_change_slot_info(slot->hotplug_slot, info);
601         kfree (info);
602         return result;
603 }
604
605 static void interrupt_event_handler(struct controller *ctrl)
606 {
607         int loop = 0;
608         int change = 1;
609         u8 hp_slot;
610         u8 getstatus;
611         struct slot *p_slot;
612
613         while (change) {
614                 change = 0;
615
616                 for (loop = 0; loop < MAX_EVENTS; loop++) {
617                         if (ctrl->event_queue[loop].event_type != 0) {
618                                 hp_slot = ctrl->event_queue[loop].hp_slot;
619
620                                 p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
621
622                                 dbg("hp_slot %d, p_slot %p\n", hp_slot, p_slot);
623
624                                 if (ctrl->event_queue[loop].event_type == INT_BUTTON_CANCEL) {
625                                         dbg("button cancel\n");
626                                         del_timer(&p_slot->task_event);
627
628                                         switch (p_slot->state) {
629                                         case BLINKINGOFF_STATE:
630                                                 /* Wait for exclusive access to hardware */
631                                                 down(&ctrl->crit_sect);
632                                                 
633                                                 if (PWR_LED(ctrl->ctrlcap)) {
634                                                         p_slot->hpc_ops->green_led_on(p_slot);
635                                                         /* Wait for the command to complete */
636                                                         wait_for_ctrl_irq (ctrl);
637                                                 }
638                                                 if (ATTN_LED(ctrl->ctrlcap)) {
639                                                         p_slot->hpc_ops->set_attention_status(p_slot, 0);
640
641                                                         /* Wait for the command to complete */
642                                                         wait_for_ctrl_irq (ctrl);
643                                                 }
644                                                 /* Done with exclusive hardware access */
645                                                 up(&ctrl->crit_sect);
646                                                 break;
647                                         case BLINKINGON_STATE:
648                                                 /* Wait for exclusive access to hardware */
649                                                 down(&ctrl->crit_sect);
650
651                                                 if (PWR_LED(ctrl->ctrlcap)) {
652                                                         p_slot->hpc_ops->green_led_off(p_slot);
653                                                         /* Wait for the command to complete */
654                                                         wait_for_ctrl_irq (ctrl);
655                                                 }
656                                                 if (ATTN_LED(ctrl->ctrlcap)){
657                                                         p_slot->hpc_ops->set_attention_status(p_slot, 0);
658                                                         /* Wait for the command to complete */
659                                                         wait_for_ctrl_irq (ctrl);
660                                                 }
661                                                 /* Done with exclusive hardware access */
662                                                 up(&ctrl->crit_sect);
663
664                                                 break;
665                                         default:
666                                                 warn("Not a valid state\n");
667                                                 return;
668                                         }
669                                         info(msg_button_cancel, p_slot->number);
670                                         p_slot->state = STATIC_STATE;
671                                 }
672                                 /* ***********Button Pressed (No action on 1st press...) */
673                                 else if (ctrl->event_queue[loop].event_type == INT_BUTTON_PRESS) {
674                                         
675                                         if (ATTN_BUTTN(ctrl->ctrlcap)) {
676                                                 dbg("Button pressed\n");
677                                                 p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
678                                                 if (getstatus) {
679                                                         /* slot is on */
680                                                         dbg("slot is on\n");
681                                                         p_slot->state = BLINKINGOFF_STATE;
682                                                         info(msg_button_off, p_slot->number);
683                                                 } else {
684                                                         /* slot is off */
685                                                         dbg("slot is off\n");
686                                                         p_slot->state = BLINKINGON_STATE;
687                                                         info(msg_button_on, p_slot->number);
688                                                 }
689
690                                                 /* Wait for exclusive access to hardware */
691                                                 down(&ctrl->crit_sect);
692
693                                                 /* blink green LED and turn off amber */
694                                                 if (PWR_LED(ctrl->ctrlcap)) {
695                                                         p_slot->hpc_ops->green_led_blink(p_slot);
696                                                         /* Wait for the command to complete */
697                                                         wait_for_ctrl_irq (ctrl);
698                                                 }
699
700                                                 if (ATTN_LED(ctrl->ctrlcap)) {
701                                                         p_slot->hpc_ops->set_attention_status(p_slot, 0);
702
703                                                         /* Wait for the command to complete */
704                                                         wait_for_ctrl_irq (ctrl);
705                                                 }
706
707                                                 /* Done with exclusive hardware access */
708                                                 up(&ctrl->crit_sect);
709
710                                                 init_timer(&p_slot->task_event);
711                                                 p_slot->task_event.expires = jiffies + 5 * HZ;   /* 5 second delay */
712                                                 p_slot->task_event.function = (void (*)(unsigned long)) pushbutton_helper_thread;
713                                                 p_slot->task_event.data = (unsigned long) p_slot;
714
715                                                 dbg("add_timer p_slot = %p\n", (void *) p_slot);
716                                                 add_timer(&p_slot->task_event);
717                                         }
718                                 }
719                                 /***********POWER FAULT********************/
720                                 else if (ctrl->event_queue[loop].event_type == INT_POWER_FAULT) {
721                                         if (POWER_CTRL(ctrl->ctrlcap)) {
722                                                 dbg("power fault\n");
723                                                 /* Wait for exclusive access to hardware */
724                                                 down(&ctrl->crit_sect);
725
726                                                 if (ATTN_LED(ctrl->ctrlcap)) {
727                                                         p_slot->hpc_ops->set_attention_status(p_slot, 1);
728                                                         wait_for_ctrl_irq (ctrl);
729                                                 }
730
731                                                 if (PWR_LED(ctrl->ctrlcap)) {
732                                                         p_slot->hpc_ops->green_led_off(p_slot);
733                                                         wait_for_ctrl_irq (ctrl);
734                                                 }
735
736                                                 /* Done with exclusive hardware access */
737                                                 up(&ctrl->crit_sect);
738                                         }
739                                 }
740                                 /***********SURPRISE REMOVAL********************/
741                                 else if ((ctrl->event_queue[loop].event_type == INT_PRESENCE_ON) || 
742                                         (ctrl->event_queue[loop].event_type == INT_PRESENCE_OFF)) {
743                                         if (HP_SUPR_RM(ctrl->ctrlcap)) {
744                                                 dbg("Surprise Removal\n");
745                                                 if (p_slot) {
746                                                         surprise_rm_pending = (unsigned long) p_slot;
747                                                         up(&event_semaphore);
748                                                         update_slot_info(p_slot);
749                                                 }
750                                         }
751                                 } else {
752                                         /* refresh notification */
753                                         if (p_slot)
754                                                 update_slot_info(p_slot);
755                                 }
756
757                                 ctrl->event_queue[loop].event_type = 0;
758
759                                 change = 1;
760                         }
761                 }               /* End of FOR loop */
762         }
763 }
764
765
766 int pciehp_enable_slot(struct slot *p_slot)
767 {
768         u8 getstatus = 0;
769         int rc;
770
771         /* Check to see if (latch closed, card present, power off) */
772         down(&p_slot->ctrl->crit_sect);
773
774         rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
775         if (rc || !getstatus) {
776                 info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number);
777                 up(&p_slot->ctrl->crit_sect);
778                 return 1;
779         }
780         if (MRL_SENS(p_slot->ctrl->ctrlcap)) {  
781                 rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
782                 if (rc || getstatus) {
783                         info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number);
784                         up(&p_slot->ctrl->crit_sect);
785                         return 1;
786                 }
787         }
788         
789         if (POWER_CTRL(p_slot->ctrl->ctrlcap)) {        
790                 rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
791                 if (rc || getstatus) {
792                         info("%s: already enabled on slot(%x)\n", __FUNCTION__, p_slot->number);
793                         up(&p_slot->ctrl->crit_sect);
794                         return 1;
795                 }
796         }
797         up(&p_slot->ctrl->crit_sect);
798
799         p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
800
801         rc = board_added(p_slot);
802         if (rc) {
803                 p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
804         }
805
806         if (p_slot)
807                 update_slot_info(p_slot);
808
809         return rc;
810 }
811
812
813 int pciehp_disable_slot(struct slot *p_slot)
814 {
815         u8 getstatus = 0;
816         int ret = 0;
817
818         if (!p_slot->ctrl)
819                 return 1;
820
821         /* Check to see if (latch closed, card present, power on) */
822         down(&p_slot->ctrl->crit_sect);
823
824         if (!HP_SUPR_RM(p_slot->ctrl->ctrlcap)) {       
825                 ret = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
826                 if (ret || !getstatus) {
827                         info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number);
828                         up(&p_slot->ctrl->crit_sect);
829                         return 1;
830                 }
831         }
832
833         if (MRL_SENS(p_slot->ctrl->ctrlcap)) {  
834                 ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
835                 if (ret || getstatus) {
836                         info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number);
837                         up(&p_slot->ctrl->crit_sect);
838                         return 1;
839                 }
840         }
841
842         if (POWER_CTRL(p_slot->ctrl->ctrlcap)) {        
843                 ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
844                 if (ret || !getstatus) {
845                         info("%s: already disabled slot(%x)\n", __FUNCTION__, p_slot->number);
846                         up(&p_slot->ctrl->crit_sect);
847                         return 1;
848                 }
849         }
850
851         up(&p_slot->ctrl->crit_sect);
852
853         ret = remove_board(p_slot);
854         update_slot_info(p_slot);
855         return ret;
856 }
857