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