xref: /linux/drivers/pci/hotplug/shpchp_ctrl.c (revision 858259cf7d1c443c836a2022b78cb281f0a9b95e)
1 /*
2  * Standard 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 "shpchp.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 
45 u8 shpchp_handle_attention_button(u8 hp_slot, void *inst_id)
46 {
47 	struct controller *ctrl = (struct controller *) inst_id;
48 	struct slot *p_slot;
49 	u8 rc = 0;
50 	u8 getstatus;
51 	struct event_info *taskInfo;
52 
53 	/* Attention Button Change */
54 	dbg("shpchp:  Attention button interrupt received.\n");
55 
56 	/* This is the structure that tells the worker thread what to do */
57 	taskInfo = &(ctrl->event_queue[ctrl->next_event]);
58 	p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
59 
60 	p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save));
61 	p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
62 
63 	ctrl->next_event = (ctrl->next_event + 1) % 10;
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 shpchp_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("shpchp:  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) % 10;
115 	taskInfo->hp_slot = hp_slot;
116 
117 	rc++;
118 	p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
119 	p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save));
120 	p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
121 	dbg("%s: Card present %x Power status %x\n", __FUNCTION__,
122 		p_slot->presence_save, p_slot->pwr_save);
123 
124 	if (getstatus) {
125 		/*
126 		 * Switch opened
127 		 */
128 		info("Latch open on Slot(%d)\n", ctrl->first_slot + hp_slot);
129 		taskInfo->event_type = INT_SWITCH_OPEN;
130 		if (p_slot->pwr_save && p_slot->presence_save) {
131 			taskInfo->event_type = INT_POWER_FAULT;
132 			err("Surprise Removal of card\n");
133 		}
134 	} else {
135 		/*
136 		 *  Switch closed
137 		 */
138 		info("Latch close on Slot(%d)\n", ctrl->first_slot + hp_slot);
139 		taskInfo->event_type = INT_SWITCH_CLOSE;
140 	}
141 
142 	if (rc)
143 		up(&event_semaphore);	/* signal event thread that new event is posted */
144 
145 	return rc;
146 }
147 
148 u8 shpchp_handle_presence_change(u8 hp_slot, void *inst_id)
149 {
150 	struct controller *ctrl = (struct controller *) inst_id;
151 	struct slot *p_slot;
152 	u8 rc = 0;
153 	/*u8 temp_byte;*/
154 	struct event_info *taskInfo;
155 
156 	/* Presence Change */
157 	dbg("shpchp:  Presence/Notify input change.\n");
158 
159 	/* This is the structure that tells the worker thread
160 	 * what to do
161 	 */
162 	taskInfo = &(ctrl->event_queue[ctrl->next_event]);
163 	ctrl->next_event = (ctrl->next_event + 1) % 10;
164 	taskInfo->hp_slot = hp_slot;
165 
166 	rc++;
167 	p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
168 
169 	/*
170 	 * Save the presence state
171 	 */
172 	p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save));
173 	if (p_slot->presence_save) {
174 		/*
175 		 * Card Present
176 		 */
177 		info("Card present on Slot(%d)\n", ctrl->first_slot + hp_slot);
178 		taskInfo->event_type = INT_PRESENCE_ON;
179 	} else {
180 		/*
181 		 * Not Present
182 		 */
183 		info("Card not present on Slot(%d)\n", ctrl->first_slot + hp_slot);
184 		taskInfo->event_type = INT_PRESENCE_OFF;
185 	}
186 
187 	if (rc)
188 		up(&event_semaphore);	/* signal event thread that new event is posted */
189 
190 	return rc;
191 }
192 
193 u8 shpchp_handle_power_fault(u8 hp_slot, void *inst_id)
194 {
195 	struct controller *ctrl = (struct controller *) inst_id;
196 	struct slot *p_slot;
197 	u8 rc = 0;
198 	struct event_info *taskInfo;
199 
200 	/* Power fault */
201 	dbg("shpchp:  Power fault interrupt received.\n");
202 
203 	/* This is the structure that tells the worker thread
204 	 * what to do
205 	 */
206 	taskInfo = &(ctrl->event_queue[ctrl->next_event]);
207 	ctrl->next_event = (ctrl->next_event + 1) % 10;
208 	taskInfo->hp_slot = hp_slot;
209 
210 	rc++;
211 	p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
212 
213 	if ( !(p_slot->hpc_ops->query_power_fault(p_slot))) {
214 		/*
215 		 * Power fault Cleared
216 		 */
217 		info("Power fault cleared on Slot(%d)\n", ctrl->first_slot + hp_slot);
218 		p_slot->status = 0x00;
219 		taskInfo->event_type = INT_POWER_FAULT_CLEAR;
220 	} else {
221 		/*
222 		 *   Power fault
223 		 */
224 		info("Power fault on Slot(%d)\n", ctrl->first_slot + hp_slot);
225 		taskInfo->event_type = INT_POWER_FAULT;
226 		/* set power fault status for this board */
227 		p_slot->status = 0xFF;
228 		info("power fault bit %x set\n", hp_slot);
229 	}
230 	if (rc)
231 		up(&event_semaphore);	/* signal event thread that new event is posted */
232 
233 	return rc;
234 }
235 
236 /* The following routines constitute the bulk of the
237    hotplug controller logic
238  */
239 static int change_bus_speed(struct controller *ctrl, struct slot *p_slot,
240 		enum pci_bus_speed speed)
241 {
242 	int rc = 0;
243 
244 	dbg("%s: change to speed %d\n", __FUNCTION__, speed);
245 	down(&ctrl->crit_sect);
246 	if ((rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, speed))) {
247 		err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__);
248 		up(&ctrl->crit_sect);
249 		return WRONG_BUS_FREQUENCY;
250 	}
251 	wait_for_ctrl_irq (ctrl);
252 
253 	if ((rc = p_slot->hpc_ops->check_cmd_status(ctrl))) {
254 		err("%s: Can't set bus speed/mode in the case of adapter & bus mismatch\n",
255 			  __FUNCTION__);
256 		err("%s: Error code (%d)\n", __FUNCTION__, rc);
257 		up(&ctrl->crit_sect);
258 		return WRONG_BUS_FREQUENCY;
259 	}
260 	up(&ctrl->crit_sect);
261 	return rc;
262 }
263 
264 static int fix_bus_speed(struct controller *ctrl, struct slot *pslot,
265 		u8 flag, enum pci_bus_speed asp, enum pci_bus_speed bsp,
266 		enum pci_bus_speed msp)
267 {
268 	int rc = 0;
269 
270 	if (flag != 0) { /* Other slots on the same bus are occupied */
271 		if ( asp < bsp ) {
272 			err("%s: speed of bus %x and adapter %x mismatch\n", __FUNCTION__, bsp, asp);
273 			return WRONG_BUS_FREQUENCY;
274 		}
275 	} else {
276 		/* Other slots on the same bus are empty */
277 		if (msp == bsp) {
278 		/* if adapter_speed >= bus_speed, do nothing */
279 			if (asp < bsp) {
280 				/*
281 				* Try to lower bus speed to accommodate the adapter if other slots
282 				* on the same controller are empty
283 				*/
284 				if ((rc = change_bus_speed(ctrl, pslot, asp)))
285 					return rc;
286 			}
287 		} else {
288 			if (asp < msp) {
289 				if ((rc = change_bus_speed(ctrl, pslot, asp)))
290 					return rc;
291 			} else {
292 				if ((rc = change_bus_speed(ctrl, pslot, msp)))
293 					return rc;
294 			}
295 		}
296 	}
297 	return rc;
298 }
299 
300 /**
301  * board_added - Called after a board has been added to the system.
302  *
303  * Turns power on for the board
304  * Configures board
305  *
306  */
307 static int board_added(struct slot *p_slot)
308 {
309 	u8 hp_slot;
310 	u8 slots_not_empty = 0;
311 	int rc = 0;
312 	enum pci_bus_speed adapter_speed, bus_speed, max_bus_speed;
313 	u8 pi, mode;
314 	struct controller *ctrl = p_slot->ctrl;
315 
316 	hp_slot = p_slot->device - ctrl->slot_device_offset;
317 
318 	dbg("%s: p_slot->device, slot_offset, hp_slot = %d, %d ,%d\n",
319 			__FUNCTION__, p_slot->device,
320 			ctrl->slot_device_offset, hp_slot);
321 
322 	/* Wait for exclusive access to hardware */
323 	down(&ctrl->crit_sect);
324 
325 	/* Power on slot without connecting to bus */
326 	rc = p_slot->hpc_ops->power_on_slot(p_slot);
327 	if (rc) {
328 		err("%s: Failed to power on slot\n", __FUNCTION__);
329 		/* Done with exclusive hardware access */
330 		up(&ctrl->crit_sect);
331 		return -1;
332 	}
333 
334 	/* Wait for the command to complete */
335 	wait_for_ctrl_irq (ctrl);
336 
337 	rc = p_slot->hpc_ops->check_cmd_status(ctrl);
338 	if (rc) {
339 		err("%s: Failed to power on slot, error code(%d)\n", __FUNCTION__, rc);
340 		/* Done with exclusive hardware access */
341 		up(&ctrl->crit_sect);
342 		return -1;
343 	}
344 
345 
346 	if ((ctrl->pci_dev->vendor == 0x8086) && (ctrl->pci_dev->device == 0x0332)) {
347 		if (slots_not_empty)
348 			return WRONG_BUS_FREQUENCY;
349 
350 		if ((rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, PCI_SPEED_33MHz))) {
351 			err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__);
352 			up(&ctrl->crit_sect);
353 			return WRONG_BUS_FREQUENCY;
354 		}
355 		wait_for_ctrl_irq (ctrl);
356 
357 		if ((rc = p_slot->hpc_ops->check_cmd_status(ctrl))) {
358 			err("%s: Can't set bus speed/mode in the case of adapter & bus mismatch\n",
359 				  __FUNCTION__);
360 			err("%s: Error code (%d)\n", __FUNCTION__, rc);
361 			up(&ctrl->crit_sect);
362 			return WRONG_BUS_FREQUENCY;
363 		}
364 		/* turn on board, blink green LED, turn off Amber LED */
365 		if ((rc = p_slot->hpc_ops->slot_enable(p_slot))) {
366 			err("%s: Issue of Slot Enable command failed\n", __FUNCTION__);
367 			up(&ctrl->crit_sect);
368 			return rc;
369 		}
370 		wait_for_ctrl_irq (ctrl);
371 
372 		if ((rc = p_slot->hpc_ops->check_cmd_status(ctrl))) {
373 			err("%s: Failed to enable slot, error code(%d)\n", __FUNCTION__, rc);
374 			up(&ctrl->crit_sect);
375 			return rc;
376 		}
377 	}
378 
379 	rc = p_slot->hpc_ops->get_adapter_speed(p_slot, &adapter_speed);
380 	/* 0 = PCI 33Mhz, 1 = PCI 66 Mhz, 2 = PCI-X 66 PA, 4 = PCI-X 66 ECC, */
381 	/* 5 = PCI-X 133 PA, 7 = PCI-X 133 ECC,  0xa = PCI-X 133 Mhz 266, */
382 	/* 0xd = PCI-X 133 Mhz 533 */
383 	/* This encoding is different from the one used in cur_bus_speed & */
384 	/* max_bus_speed */
385 
386 	if (rc  || adapter_speed == PCI_SPEED_UNKNOWN) {
387 		err("%s: Can't get adapter speed or bus mode mismatch\n", __FUNCTION__);
388 		/* Done with exclusive hardware access */
389 		up(&ctrl->crit_sect);
390 		return WRONG_BUS_FREQUENCY;
391 	}
392 
393 	rc = p_slot->hpc_ops->get_cur_bus_speed(p_slot, &bus_speed);
394 	if (rc || bus_speed == PCI_SPEED_UNKNOWN) {
395 		err("%s: Can't get bus operation speed\n", __FUNCTION__);
396 		/* Done with exclusive hardware access */
397 		up(&ctrl->crit_sect);
398 		return WRONG_BUS_FREQUENCY;
399 	}
400 
401 	rc = p_slot->hpc_ops->get_max_bus_speed(p_slot, &max_bus_speed);
402 	if (rc || max_bus_speed == PCI_SPEED_UNKNOWN) {
403 		err("%s: Can't get max bus operation speed\n", __FUNCTION__);
404 		max_bus_speed = bus_speed;
405 	}
406 
407 	/* Done with exclusive hardware access */
408 	up(&ctrl->crit_sect);
409 
410 	if ((rc  = p_slot->hpc_ops->get_prog_int(p_slot, &pi))) {
411 		err("%s: Can't get controller programming interface, set it to 1\n", __FUNCTION__);
412 		pi = 1;
413 	}
414 
415 	/* Check if there are other slots or devices on the same bus */
416 	if (!list_empty(&ctrl->pci_dev->subordinate->devices))
417 		slots_not_empty = 1;
418 
419 	dbg("%s: slots_not_empty %d, pi %d\n", __FUNCTION__,
420 		slots_not_empty, pi);
421 	dbg("adapter_speed %d, bus_speed %d, max_bus_speed %d\n",
422 		adapter_speed, bus_speed, max_bus_speed);
423 
424 	if (pi == 2) {
425 		dbg("%s: In PI = %d\n", __FUNCTION__, pi);
426 		if ((rc = p_slot->hpc_ops->get_mode1_ECC_cap(p_slot, &mode))) {
427 			err("%s: Can't get Mode1_ECC, set mode to 0\n", __FUNCTION__);
428 			mode = 0;
429 		}
430 
431 		switch (adapter_speed) {
432 		case PCI_SPEED_133MHz_PCIX_533:
433 		case PCI_SPEED_133MHz_PCIX_266:
434 			if ((bus_speed != adapter_speed) &&
435 			   ((rc = fix_bus_speed(ctrl, p_slot, slots_not_empty, adapter_speed, bus_speed, max_bus_speed))))
436 				return rc;
437 			break;
438 		case PCI_SPEED_133MHz_PCIX_ECC:
439 		case PCI_SPEED_133MHz_PCIX:
440 			if (mode) { /* Bus - Mode 1 ECC */
441 				if ((bus_speed != 0x7) &&
442 				   ((rc = fix_bus_speed(ctrl, p_slot, slots_not_empty, adapter_speed, bus_speed, max_bus_speed))))
443 					return rc;
444 			} else {
445 				if ((bus_speed != 0x4) &&
446 				   ((rc = fix_bus_speed(ctrl, p_slot, slots_not_empty, adapter_speed, bus_speed, max_bus_speed))))
447 					return rc;
448 			}
449 			break;
450 		case PCI_SPEED_66MHz_PCIX_ECC:
451 		case PCI_SPEED_66MHz_PCIX:
452 			if (mode) { /* Bus - Mode 1 ECC */
453 				if ((bus_speed != 0x5) &&
454 				   ((rc = fix_bus_speed(ctrl, p_slot, slots_not_empty, adapter_speed, bus_speed, max_bus_speed))))
455 					return rc;
456 			} else {
457 				if ((bus_speed != 0x2) &&
458 				   ((rc = fix_bus_speed(ctrl, p_slot, slots_not_empty, adapter_speed, bus_speed, max_bus_speed))))
459 					return rc;
460 			}
461 			break;
462 		case PCI_SPEED_66MHz:
463 			if ((bus_speed != 0x1) &&
464 			   ((rc = fix_bus_speed(ctrl, p_slot, slots_not_empty, adapter_speed, bus_speed, max_bus_speed))))
465 				return rc;
466 			break;
467 		case PCI_SPEED_33MHz:
468 			if (bus_speed > 0x0) {
469 				if (slots_not_empty == 0) {
470 					if ((rc = change_bus_speed(ctrl, p_slot, adapter_speed)))
471 						return rc;
472 				} else {
473 					err("%s: speed of bus %x and adapter %x mismatch\n", __FUNCTION__, bus_speed, adapter_speed);
474 					return WRONG_BUS_FREQUENCY;
475 				}
476 			}
477 			break;
478 		default:
479 			err("%s: speed of bus %x and adapter %x mismatch\n", __FUNCTION__, bus_speed, adapter_speed);
480 			return WRONG_BUS_FREQUENCY;
481 		}
482 	} else {
483 		/* If adpater_speed == bus_speed, nothing to do here */
484 		dbg("%s: In PI = %d\n", __FUNCTION__, pi);
485 		if ((adapter_speed != bus_speed) &&
486 		   ((rc = fix_bus_speed(ctrl, p_slot, slots_not_empty, adapter_speed, bus_speed, max_bus_speed))))
487 				return rc;
488 	}
489 
490 	down(&ctrl->crit_sect);
491 	/* turn on board, blink green LED, turn off Amber LED */
492 	if ((rc = p_slot->hpc_ops->slot_enable(p_slot))) {
493 		err("%s: Issue of Slot Enable command failed\n", __FUNCTION__);
494 		up(&ctrl->crit_sect);
495 		return rc;
496 	}
497 	wait_for_ctrl_irq (ctrl);
498 
499 	if ((rc = p_slot->hpc_ops->check_cmd_status(ctrl))) {
500 		err("%s: Failed to enable slot, error code(%d)\n", __FUNCTION__, rc);
501 		up(&ctrl->crit_sect);
502 		return rc;
503 	}
504 
505 	up(&ctrl->crit_sect);
506 
507 	/* Wait for ~1 second */
508 	wait_for_ctrl_irq (ctrl);
509 
510 	dbg("%s: slot status = %x\n", __FUNCTION__, p_slot->status);
511 	/* Check for a power fault */
512 	if (p_slot->status == 0xFF) {
513 		/* power fault occurred, but it was benign */
514 		dbg("%s: power fault\n", __FUNCTION__);
515 		rc = POWER_FAILURE;
516 		p_slot->status = 0;
517 		goto err_exit;
518 	}
519 
520 	if (shpchp_configure_device(p_slot)) {
521 		err("Cannot add device at 0x%x:0x%x\n", p_slot->bus,
522 				p_slot->device);
523 		goto err_exit;
524 	}
525 
526 	p_slot->status = 0;
527 	p_slot->is_a_board = 0x01;
528 	p_slot->pwr_save = 1;
529 
530 	/* Wait for exclusive access to hardware */
531 	down(&ctrl->crit_sect);
532 
533 	p_slot->hpc_ops->green_led_on(p_slot);
534 
535 	/* Wait for the command to complete */
536 	wait_for_ctrl_irq (ctrl);
537 
538 	/* Done with exclusive hardware access */
539 	up(&ctrl->crit_sect);
540 
541 	return 0;
542 
543 err_exit:
544 	/* Wait for exclusive access to hardware */
545 	down(&ctrl->crit_sect);
546 
547 	/* turn off slot, turn on Amber LED, turn off Green LED */
548 	rc = p_slot->hpc_ops->slot_disable(p_slot);
549 	if (rc) {
550 		err("%s: Issue of Slot Disable command failed\n", __FUNCTION__);
551 		/* Done with exclusive hardware access */
552 		up(&ctrl->crit_sect);
553 		return rc;
554 	}
555 	/* Wait for the command to complete */
556 	wait_for_ctrl_irq (ctrl);
557 
558 	rc = p_slot->hpc_ops->check_cmd_status(ctrl);
559 	if (rc) {
560 		err("%s: Failed to disable slot, error code(%d)\n", __FUNCTION__, rc);
561 		/* Done with exclusive hardware access */
562 		up(&ctrl->crit_sect);
563 		return rc;
564 	}
565 
566 	/* Done with exclusive hardware access */
567 	up(&ctrl->crit_sect);
568 
569 	return(rc);
570 }
571 
572 
573 /**
574  * remove_board - Turns off slot and LED's
575  *
576  */
577 static int remove_board(struct slot *p_slot)
578 {
579 	struct controller *ctrl = p_slot->ctrl;
580 	u8 hp_slot;
581 	int rc;
582 
583 	if (shpchp_unconfigure_device(p_slot))
584 		return(1);
585 
586 	hp_slot = p_slot->device - ctrl->slot_device_offset;
587 	p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
588 
589 	dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot);
590 
591 	/* Change status to shutdown */
592 	if (p_slot->is_a_board)
593 		p_slot->status = 0x01;
594 
595 	/* Wait for exclusive access to hardware */
596 	down(&ctrl->crit_sect);
597 
598 	/* turn off slot, turn on Amber LED, turn off Green LED */
599 	rc = p_slot->hpc_ops->slot_disable(p_slot);
600 	if (rc) {
601 		err("%s: Issue of Slot Disable command failed\n", __FUNCTION__);
602 		/* Done with exclusive hardware access */
603 		up(&ctrl->crit_sect);
604 		return rc;
605 	}
606 	/* Wait for the command to complete */
607 	wait_for_ctrl_irq (ctrl);
608 
609 	rc = p_slot->hpc_ops->check_cmd_status(ctrl);
610 	if (rc) {
611 		err("%s: Failed to disable slot, error code(%d)\n", __FUNCTION__, rc);
612 		/* Done with exclusive hardware access */
613 		up(&ctrl->crit_sect);
614 		return rc;
615 	}
616 
617 	rc = p_slot->hpc_ops->set_attention_status(p_slot, 0);
618 	if (rc) {
619 		err("%s: Issue of Set Attention command failed\n", __FUNCTION__);
620 		/* Done with exclusive hardware access */
621 		up(&ctrl->crit_sect);
622 		return rc;
623 	}
624 	/* Wait for the command to complete */
625 	wait_for_ctrl_irq (ctrl);
626 
627 	/* Done with exclusive hardware access */
628 	up(&ctrl->crit_sect);
629 
630 	p_slot->pwr_save = 0;
631 	p_slot->is_a_board = 0;
632 
633 	return 0;
634 }
635 
636 
637 static void pushbutton_helper_thread (unsigned long data)
638 {
639 	pushbutton_pending = data;
640 
641 	up(&event_semaphore);
642 }
643 
644 
645 /**
646  * shpchp_pushbutton_thread
647  *
648  * Scheduled procedure to handle blocking stuff for the pushbuttons
649  * Handles all pending events and exits.
650  *
651  */
652 static void shpchp_pushbutton_thread (unsigned long slot)
653 {
654 	struct slot *p_slot = (struct slot *) slot;
655 	u8 getstatus;
656 
657 	pushbutton_pending = 0;
658 
659 	if (!p_slot) {
660 		dbg("%s: Error! slot NULL\n", __FUNCTION__);
661 		return;
662 	}
663 
664 	p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
665 	if (getstatus) {
666 		p_slot->state = POWEROFF_STATE;
667 
668 		shpchp_disable_slot(p_slot);
669 		p_slot->state = STATIC_STATE;
670 	} else {
671 		p_slot->state = POWERON_STATE;
672 
673 		if (shpchp_enable_slot(p_slot)) {
674 			/* Wait for exclusive access to hardware */
675 			down(&p_slot->ctrl->crit_sect);
676 
677 			p_slot->hpc_ops->green_led_off(p_slot);
678 
679 			/* Wait for the command to complete */
680 			wait_for_ctrl_irq (p_slot->ctrl);
681 
682 			/* Done with exclusive hardware access */
683 			up(&p_slot->ctrl->crit_sect);
684 		}
685 		p_slot->state = STATIC_STATE;
686 	}
687 
688 	return;
689 }
690 
691 
692 /* this is the main worker thread */
693 static int event_thread(void* data)
694 {
695 	struct controller *ctrl;
696 	lock_kernel();
697 	daemonize("shpchpd_event");
698 	unlock_kernel();
699 
700 	while (1) {
701 		dbg("!!!!event_thread sleeping\n");
702 		down_interruptible (&event_semaphore);
703 		dbg("event_thread woken finished = %d\n", event_finished);
704 		if (event_finished || signal_pending(current))
705 			break;
706 		/* Do stuff here */
707 		if (pushbutton_pending)
708 			shpchp_pushbutton_thread(pushbutton_pending);
709 		else
710 			for (ctrl = shpchp_ctrl_list; ctrl; ctrl=ctrl->next)
711 				interrupt_event_handler(ctrl);
712 	}
713 	dbg("event_thread signals exit\n");
714 	up(&event_exit);
715 	return 0;
716 }
717 
718 int shpchp_event_start_thread (void)
719 {
720 	int pid;
721 
722 	/* initialize our semaphores */
723 	init_MUTEX_LOCKED(&event_exit);
724 	event_finished=0;
725 
726 	init_MUTEX_LOCKED(&event_semaphore);
727 	pid = kernel_thread(event_thread, NULL, 0);
728 
729 	if (pid < 0) {
730 		err ("Can't start up our event thread\n");
731 		return -1;
732 	}
733 	return 0;
734 }
735 
736 
737 void shpchp_event_stop_thread (void)
738 {
739 	event_finished = 1;
740 	up(&event_semaphore);
741 	down(&event_exit);
742 }
743 
744 
745 static int update_slot_info (struct slot *slot)
746 {
747 	struct hotplug_slot_info *info;
748 	int result;
749 
750 	info = kmalloc(sizeof(*info), GFP_KERNEL);
751 	if (!info)
752 		return -ENOMEM;
753 
754 	slot->hpc_ops->get_power_status(slot, &(info->power_status));
755 	slot->hpc_ops->get_attention_status(slot, &(info->attention_status));
756 	slot->hpc_ops->get_latch_status(slot, &(info->latch_status));
757 	slot->hpc_ops->get_adapter_status(slot, &(info->adapter_status));
758 
759 	result = pci_hp_change_slot_info(slot->hotplug_slot, info);
760 	kfree (info);
761 	return result;
762 }
763 
764 static void interrupt_event_handler(struct controller *ctrl)
765 {
766 	int loop = 0;
767 	int change = 1;
768 	u8 hp_slot;
769 	u8 getstatus;
770 	struct slot *p_slot;
771 
772 	while (change) {
773 		change = 0;
774 
775 		for (loop = 0; loop < 10; loop++) {
776 			if (ctrl->event_queue[loop].event_type != 0) {
777 				dbg("%s:loop %x event_type %x\n", __FUNCTION__, loop,
778 					ctrl->event_queue[loop].event_type);
779 				hp_slot = ctrl->event_queue[loop].hp_slot;
780 
781 				p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
782 
783 				if (ctrl->event_queue[loop].event_type == INT_BUTTON_CANCEL) {
784 					dbg("%s: button cancel\n", __FUNCTION__);
785 					del_timer(&p_slot->task_event);
786 
787 					switch (p_slot->state) {
788 					case BLINKINGOFF_STATE:
789 						/* Wait for exclusive access to hardware */
790 						down(&ctrl->crit_sect);
791 
792 						p_slot->hpc_ops->green_led_on(p_slot);
793 						/* Wait for the command to complete */
794 						wait_for_ctrl_irq (ctrl);
795 
796 						p_slot->hpc_ops->set_attention_status(p_slot, 0);
797 
798 						/* Wait for the command to complete */
799 						wait_for_ctrl_irq (ctrl);
800 
801 						/* Done with exclusive hardware access */
802 						up(&ctrl->crit_sect);
803 						break;
804 					case BLINKINGON_STATE:
805 						/* Wait for exclusive access to hardware */
806 						down(&ctrl->crit_sect);
807 
808 						p_slot->hpc_ops->green_led_off(p_slot);
809 						/* Wait for the command to complete */
810 						wait_for_ctrl_irq (ctrl);
811 
812 						p_slot->hpc_ops->set_attention_status(p_slot, 0);
813 						/* Wait for the command to complete */
814 						wait_for_ctrl_irq (ctrl);
815 
816 						/* Done with exclusive hardware access */
817 						up(&ctrl->crit_sect);
818 
819 						break;
820 					default:
821 						warn("Not a valid state\n");
822 						return;
823 					}
824 					info(msg_button_cancel, p_slot->number);
825 					p_slot->state = STATIC_STATE;
826 				} else if (ctrl->event_queue[loop].event_type == INT_BUTTON_PRESS) {
827 					/* Button Pressed (No action on 1st press...) */
828 					dbg("%s: Button pressed\n", __FUNCTION__);
829 
830 					p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
831 					if (getstatus) {
832 						/* slot is on */
833 						dbg("%s: slot is on\n", __FUNCTION__);
834 						p_slot->state = BLINKINGOFF_STATE;
835 						info(msg_button_off, p_slot->number);
836 					} else {
837 						/* slot is off */
838 						dbg("%s: slot is off\n", __FUNCTION__);
839 						p_slot->state = BLINKINGON_STATE;
840 						info(msg_button_on, p_slot->number);
841 					}
842 
843 					/* Wait for exclusive access to hardware */
844 					down(&ctrl->crit_sect);
845 
846 					/* blink green LED and turn off amber */
847 					p_slot->hpc_ops->green_led_blink(p_slot);
848 					/* Wait for the command to complete */
849 					wait_for_ctrl_irq (ctrl);
850 
851 					p_slot->hpc_ops->set_attention_status(p_slot, 0);
852 
853 					/* Wait for the command to complete */
854 					wait_for_ctrl_irq (ctrl);
855 
856 					/* Done with exclusive hardware access */
857 					up(&ctrl->crit_sect);
858 
859 					init_timer(&p_slot->task_event);
860 					p_slot->task_event.expires = jiffies + 5 * HZ;   /* 5 second delay */
861 					p_slot->task_event.function = (void (*)(unsigned long)) pushbutton_helper_thread;
862 					p_slot->task_event.data = (unsigned long) p_slot;
863 
864 					dbg("%s: add_timer p_slot = %p\n", __FUNCTION__,(void *) p_slot);
865 					add_timer(&p_slot->task_event);
866 				} else if (ctrl->event_queue[loop].event_type == INT_POWER_FAULT) {
867 					/***********POWER FAULT********************/
868 					dbg("%s: power fault\n", __FUNCTION__);
869 					/* Wait for exclusive access to hardware */
870 					down(&ctrl->crit_sect);
871 
872 					p_slot->hpc_ops->set_attention_status(p_slot, 1);
873 					/* Wait for the command to complete */
874 					wait_for_ctrl_irq (ctrl);
875 
876 					p_slot->hpc_ops->green_led_off(p_slot);
877 					/* Wait for the command to complete */
878 					wait_for_ctrl_irq (ctrl);
879 
880 					/* Done with exclusive hardware access */
881 					up(&ctrl->crit_sect);
882 				} else {
883 					/* refresh notification */
884 					if (p_slot)
885 						update_slot_info(p_slot);
886 				}
887 
888 				ctrl->event_queue[loop].event_type = 0;
889 
890 				change = 1;
891 			}
892 		}		/* End of FOR loop */
893 	}
894 
895 	return;
896 }
897 
898 
899 int shpchp_enable_slot (struct slot *p_slot)
900 {
901 	u8 getstatus = 0;
902 	int rc;
903 
904 	/* Check to see if (latch closed, card present, power off) */
905 	down(&p_slot->ctrl->crit_sect);
906 	rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
907 	if (rc || !getstatus) {
908 		info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number);
909 		up(&p_slot->ctrl->crit_sect);
910 		return -ENODEV;
911 	}
912 	rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
913 	if (rc || getstatus) {
914 		info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number);
915 		up(&p_slot->ctrl->crit_sect);
916 		return -ENODEV;
917 	}
918 	rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
919 	if (rc || getstatus) {
920 		info("%s: already enabled on slot(%x)\n", __FUNCTION__, p_slot->number);
921 		up(&p_slot->ctrl->crit_sect);
922 		return -ENODEV;
923 	}
924 	up(&p_slot->ctrl->crit_sect);
925 
926 	p_slot->is_a_board = 1;
927 
928 	/* We have to save the presence info for these slots */
929 	p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save));
930 	p_slot->hpc_ops->get_power_status(p_slot, &(p_slot->pwr_save));
931 	dbg("%s: p_slot->pwr_save %x\n", __FUNCTION__, p_slot->pwr_save);
932 	p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
933 
934 	rc = board_added(p_slot);
935 	if (rc) {
936 		p_slot->hpc_ops->get_adapter_status(p_slot,
937 				&(p_slot->presence_save));
938 		p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
939 	}
940 
941 	update_slot_info(p_slot);
942 	return rc;
943 }
944 
945 
946 int shpchp_disable_slot (struct slot *p_slot)
947 {
948 	u8 getstatus = 0;
949 	int ret = 0;
950 
951 	if (!p_slot->ctrl)
952 		return -ENODEV;
953 
954 	/* Check to see if (latch closed, card present, power on) */
955 	down(&p_slot->ctrl->crit_sect);
956 
957 	ret = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
958 	if (ret || !getstatus) {
959 		info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number);
960 		up(&p_slot->ctrl->crit_sect);
961 		return -ENODEV;
962 	}
963 	ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
964 	if (ret || getstatus) {
965 		info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number);
966 		up(&p_slot->ctrl->crit_sect);
967 		return -ENODEV;
968 	}
969 	ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
970 	if (ret || !getstatus) {
971 		info("%s: already disabled slot(%x)\n", __FUNCTION__, p_slot->number);
972 		up(&p_slot->ctrl->crit_sect);
973 		return -ENODEV;
974 	}
975 	up(&p_slot->ctrl->crit_sect);
976 
977 	ret = remove_board(p_slot);
978 	update_slot_info(p_slot);
979 	return ret;
980 }
981 
982