xref: /linux/drivers/pci/hotplug/pciehp_ctrl.c (revision 606d099cdd1080bbb50ea50dc52d98252f8f10a1)
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 
855