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