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