shpchp_ctrl.c revision ee138334d5eb5ca662b2d69228420c1ccc051e0e
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
38static void interrupt_event_handler(struct controller *ctrl);
39
40static struct semaphore event_semaphore;	/* mutex for process loop (up if something to process) */
41static struct semaphore event_exit;		/* guard ensure thread has exited before calling it quits */
42static int event_finished;
43static unsigned long pushbutton_pending;	/* = 0 */
44
45u8 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
99u8 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
148u8 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
193u8 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 */
239static 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
264static 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 */
307static 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	dbg("%s: before long_delay\n", __FUNCTION__);
509	wait_for_ctrl_irq (ctrl);
510	dbg("%s: after long_delay\n", __FUNCTION__);
511
512	dbg("%s: slot status = %x\n", __FUNCTION__, p_slot->status);
513	/* Check for a power fault */
514	if (p_slot->status == 0xFF) {
515		/* power fault occurred, but it was benign */
516		dbg("%s: power fault\n", __FUNCTION__);
517		rc = POWER_FAILURE;
518		p_slot->status = 0;
519		goto err_exit;
520	}
521
522	if (shpchp_configure_device(p_slot)) {
523		err("Cannot add device at 0x%x:0x%x\n", p_slot->bus,
524				p_slot->device);
525		goto err_exit;
526	}
527
528	p_slot->status = 0;
529	p_slot->is_a_board = 0x01;
530	p_slot->pwr_save = 1;
531
532	/* Wait for exclusive access to hardware */
533	down(&ctrl->crit_sect);
534
535	p_slot->hpc_ops->green_led_on(p_slot);
536
537	/* Wait for the command to complete */
538	wait_for_ctrl_irq (ctrl);
539
540	/* Done with exclusive hardware access */
541	up(&ctrl->crit_sect);
542
543	return 0;
544
545err_exit:
546	/* Wait for exclusive access to hardware */
547	down(&ctrl->crit_sect);
548
549	/* turn off slot, turn on Amber LED, turn off Green LED */
550	rc = p_slot->hpc_ops->slot_disable(p_slot);
551	if (rc) {
552		err("%s: Issue of Slot Disable command failed\n", __FUNCTION__);
553		/* Done with exclusive hardware access */
554		up(&ctrl->crit_sect);
555		return rc;
556	}
557	/* Wait for the command to complete */
558	wait_for_ctrl_irq (ctrl);
559
560	rc = p_slot->hpc_ops->check_cmd_status(ctrl);
561	if (rc) {
562		err("%s: Failed to disable slot, error code(%d)\n", __FUNCTION__, rc);
563		/* Done with exclusive hardware access */
564		up(&ctrl->crit_sect);
565		return rc;
566	}
567
568	/* Done with exclusive hardware access */
569	up(&ctrl->crit_sect);
570
571	return(rc);
572}
573
574
575/**
576 * remove_board - Turns off slot and LED's
577 *
578 */
579static int remove_board(struct slot *p_slot)
580{
581	struct controller *ctrl = p_slot->ctrl;
582	u8 hp_slot;
583	int rc;
584
585	if (shpchp_unconfigure_device(p_slot))
586		return(1);
587
588	hp_slot = p_slot->device - ctrl->slot_device_offset;
589	p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
590
591	dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot);
592
593	/* Change status to shutdown */
594	if (p_slot->is_a_board)
595		p_slot->status = 0x01;
596
597	/* Wait for exclusive access to hardware */
598	down(&ctrl->crit_sect);
599
600	/* turn off slot, turn on Amber LED, turn off Green LED */
601	rc = p_slot->hpc_ops->slot_disable(p_slot);
602	if (rc) {
603		err("%s: Issue of Slot Disable command failed\n", __FUNCTION__);
604		/* Done with exclusive hardware access */
605		up(&ctrl->crit_sect);
606		return rc;
607	}
608	/* Wait for the command to complete */
609	wait_for_ctrl_irq (ctrl);
610
611	rc = p_slot->hpc_ops->check_cmd_status(ctrl);
612	if (rc) {
613		err("%s: Failed to disable slot, error code(%d)\n", __FUNCTION__, rc);
614		/* Done with exclusive hardware access */
615		up(&ctrl->crit_sect);
616		return rc;
617	}
618
619	rc = p_slot->hpc_ops->set_attention_status(p_slot, 0);
620	if (rc) {
621		err("%s: Issue of Set Attention command failed\n", __FUNCTION__);
622		/* Done with exclusive hardware access */
623		up(&ctrl->crit_sect);
624		return rc;
625	}
626	/* Wait for the command to complete */
627	wait_for_ctrl_irq (ctrl);
628
629	/* Done with exclusive hardware access */
630	up(&ctrl->crit_sect);
631
632	p_slot->pwr_save = 0;
633	p_slot->is_a_board = 0;
634
635	return 0;
636}
637
638
639static void pushbutton_helper_thread (unsigned long data)
640{
641	pushbutton_pending = data;
642
643	up(&event_semaphore);
644}
645
646
647/**
648 * shpchp_pushbutton_thread
649 *
650 * Scheduled procedure to handle blocking stuff for the pushbuttons
651 * Handles all pending events and exits.
652 *
653 */
654static void shpchp_pushbutton_thread (unsigned long slot)
655{
656	struct slot *p_slot = (struct slot *) slot;
657	u8 getstatus;
658
659	pushbutton_pending = 0;
660
661	if (!p_slot) {
662		dbg("%s: Error! slot NULL\n", __FUNCTION__);
663		return;
664	}
665
666	p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
667	if (getstatus) {
668		p_slot->state = POWEROFF_STATE;
669		dbg("In power_down_board, b:d(%x:%x)\n", p_slot->bus, p_slot->device);
670
671		shpchp_disable_slot(p_slot);
672		p_slot->state = STATIC_STATE;
673	} else {
674		p_slot->state = POWERON_STATE;
675		dbg("In add_board, b:d(%x:%x)\n", p_slot->bus, p_slot->device);
676
677		if (shpchp_enable_slot(p_slot)) {
678			/* Wait for exclusive access to hardware */
679			down(&p_slot->ctrl->crit_sect);
680
681			p_slot->hpc_ops->green_led_off(p_slot);
682
683			/* Wait for the command to complete */
684			wait_for_ctrl_irq (p_slot->ctrl);
685
686			/* Done with exclusive hardware access */
687			up(&p_slot->ctrl->crit_sect);
688		}
689		p_slot->state = STATIC_STATE;
690	}
691
692	return;
693}
694
695
696/* this is the main worker thread */
697static int event_thread(void* data)
698{
699	struct controller *ctrl;
700	lock_kernel();
701	daemonize("shpchpd_event");
702	unlock_kernel();
703
704	while (1) {
705		dbg("!!!!event_thread sleeping\n");
706		down_interruptible (&event_semaphore);
707		dbg("event_thread woken finished = %d\n", event_finished);
708		if (event_finished || signal_pending(current))
709			break;
710		/* Do stuff here */
711		if (pushbutton_pending)
712			shpchp_pushbutton_thread(pushbutton_pending);
713		else
714			for (ctrl = shpchp_ctrl_list; ctrl; ctrl=ctrl->next)
715				interrupt_event_handler(ctrl);
716	}
717	dbg("event_thread signals exit\n");
718	up(&event_exit);
719	return 0;
720}
721
722int shpchp_event_start_thread (void)
723{
724	int pid;
725
726	/* initialize our semaphores */
727	init_MUTEX_LOCKED(&event_exit);
728	event_finished=0;
729
730	init_MUTEX_LOCKED(&event_semaphore);
731	pid = kernel_thread(event_thread, NULL, 0);
732
733	if (pid < 0) {
734		err ("Can't start up our event thread\n");
735		return -1;
736	}
737	dbg("Our event thread pid = %d\n", pid);
738	return 0;
739}
740
741
742void shpchp_event_stop_thread (void)
743{
744	event_finished = 1;
745	dbg("event_thread finish command given\n");
746	up(&event_semaphore);
747	dbg("wait for event_thread to exit\n");
748	down(&event_exit);
749}
750
751
752static int update_slot_info (struct slot *slot)
753{
754	struct hotplug_slot_info *info;
755	int result;
756
757	info = kmalloc(sizeof(*info), GFP_KERNEL);
758	if (!info)
759		return -ENOMEM;
760
761	slot->hpc_ops->get_power_status(slot, &(info->power_status));
762	slot->hpc_ops->get_attention_status(slot, &(info->attention_status));
763	slot->hpc_ops->get_latch_status(slot, &(info->latch_status));
764	slot->hpc_ops->get_adapter_status(slot, &(info->adapter_status));
765
766	result = pci_hp_change_slot_info(slot->hotplug_slot, info);
767	kfree (info);
768	return result;
769}
770
771static void interrupt_event_handler(struct controller *ctrl)
772{
773	int loop = 0;
774	int change = 1;
775	u8 hp_slot;
776	u8 getstatus;
777	struct slot *p_slot;
778
779	dbg("%s:\n", __FUNCTION__);
780	while (change) {
781		change = 0;
782
783		for (loop = 0; loop < 10; loop++) {
784			if (ctrl->event_queue[loop].event_type != 0) {
785				dbg("%s:loop %x event_type %x\n", __FUNCTION__, loop,
786					ctrl->event_queue[loop].event_type);
787				hp_slot = ctrl->event_queue[loop].hp_slot;
788
789				p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
790
791				dbg("%s: hp_slot %d, p_slot %p\n",
792						__FUNCTION__, hp_slot, p_slot);
793
794				if (ctrl->event_queue[loop].event_type == INT_BUTTON_CANCEL) {
795					dbg("%s: button cancel\n", __FUNCTION__);
796					del_timer(&p_slot->task_event);
797
798					switch (p_slot->state) {
799					case BLINKINGOFF_STATE:
800						/* Wait for exclusive access to hardware */
801						down(&ctrl->crit_sect);
802
803						p_slot->hpc_ops->green_led_on(p_slot);
804						/* Wait for the command to complete */
805						wait_for_ctrl_irq (ctrl);
806
807						p_slot->hpc_ops->set_attention_status(p_slot, 0);
808
809						/* Wait for the command to complete */
810						wait_for_ctrl_irq (ctrl);
811
812						/* Done with exclusive hardware access */
813						up(&ctrl->crit_sect);
814						break;
815					case BLINKINGON_STATE:
816						/* Wait for exclusive access to hardware */
817						down(&ctrl->crit_sect);
818
819						p_slot->hpc_ops->green_led_off(p_slot);
820						/* Wait for the command to complete */
821						wait_for_ctrl_irq (ctrl);
822
823						p_slot->hpc_ops->set_attention_status(p_slot, 0);
824						/* Wait for the command to complete */
825						wait_for_ctrl_irq (ctrl);
826
827						/* Done with exclusive hardware access */
828						up(&ctrl->crit_sect);
829
830						break;
831					default:
832						warn("Not a valid state\n");
833						return;
834					}
835					info(msg_button_cancel, p_slot->number);
836					p_slot->state = STATIC_STATE;
837				} else if (ctrl->event_queue[loop].event_type == INT_BUTTON_PRESS) {
838					/* Button Pressed (No action on 1st press...) */
839					dbg("%s: Button pressed\n", __FUNCTION__);
840
841					p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
842					if (getstatus) {
843						/* slot is on */
844						dbg("%s: slot is on\n", __FUNCTION__);
845						p_slot->state = BLINKINGOFF_STATE;
846						info(msg_button_off, p_slot->number);
847					} else {
848						/* slot is off */
849						dbg("%s: slot is off\n", __FUNCTION__);
850						p_slot->state = BLINKINGON_STATE;
851						info(msg_button_on, p_slot->number);
852					}
853
854					/* Wait for exclusive access to hardware */
855					down(&ctrl->crit_sect);
856
857					/* blink green LED and turn off amber */
858					p_slot->hpc_ops->green_led_blink(p_slot);
859					/* Wait for the command to complete */
860					wait_for_ctrl_irq (ctrl);
861
862					p_slot->hpc_ops->set_attention_status(p_slot, 0);
863
864					/* Wait for the command to complete */
865					wait_for_ctrl_irq (ctrl);
866
867					/* Done with exclusive hardware access */
868					up(&ctrl->crit_sect);
869
870					init_timer(&p_slot->task_event);
871					p_slot->task_event.expires = jiffies + 5 * HZ;   /* 5 second delay */
872					p_slot->task_event.function = (void (*)(unsigned long)) pushbutton_helper_thread;
873					p_slot->task_event.data = (unsigned long) p_slot;
874
875					dbg("%s: add_timer p_slot = %p\n", __FUNCTION__,(void *) p_slot);
876					add_timer(&p_slot->task_event);
877				} else if (ctrl->event_queue[loop].event_type == INT_POWER_FAULT) {
878					/***********POWER FAULT********************/
879					dbg("%s: power fault\n", __FUNCTION__);
880					/* Wait for exclusive access to hardware */
881					down(&ctrl->crit_sect);
882
883					p_slot->hpc_ops->set_attention_status(p_slot, 1);
884					/* Wait for the command to complete */
885					wait_for_ctrl_irq (ctrl);
886
887					p_slot->hpc_ops->green_led_off(p_slot);
888					/* Wait for the command to complete */
889					wait_for_ctrl_irq (ctrl);
890
891					/* Done with exclusive hardware access */
892					up(&ctrl->crit_sect);
893				} else {
894					/* refresh notification */
895					if (p_slot)
896						update_slot_info(p_slot);
897				}
898
899				ctrl->event_queue[loop].event_type = 0;
900
901				change = 1;
902			}
903		}		/* End of FOR loop */
904	}
905
906	return;
907}
908
909
910int shpchp_enable_slot (struct slot *p_slot)
911{
912	u8 getstatus = 0;
913	int rc;
914
915	/* Check to see if (latch closed, card present, power off) */
916	down(&p_slot->ctrl->crit_sect);
917	rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
918	if (rc || !getstatus) {
919		info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number);
920		up(&p_slot->ctrl->crit_sect);
921		return -ENODEV;
922	}
923	rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
924	if (rc || getstatus) {
925		info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number);
926		up(&p_slot->ctrl->crit_sect);
927		return -ENODEV;
928	}
929	rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
930	if (rc || getstatus) {
931		info("%s: already enabled on slot(%x)\n", __FUNCTION__, p_slot->number);
932		up(&p_slot->ctrl->crit_sect);
933		return -ENODEV;
934	}
935	up(&p_slot->ctrl->crit_sect);
936
937	p_slot->is_a_board = 1;
938
939	/* We have to save the presence info for these slots */
940	p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save));
941	p_slot->hpc_ops->get_power_status(p_slot, &(p_slot->pwr_save));
942	dbg("%s: p_slot->pwr_save %x\n", __FUNCTION__, p_slot->pwr_save);
943	p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
944
945	rc = board_added(p_slot);
946	if (rc) {
947		p_slot->hpc_ops->get_adapter_status(p_slot,
948				&(p_slot->presence_save));
949		p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
950	}
951
952	update_slot_info(p_slot);
953	return rc;
954}
955
956
957int shpchp_disable_slot (struct slot *p_slot)
958{
959	u8 getstatus = 0;
960	int ret = 0;
961
962	if (!p_slot->ctrl)
963		return -ENODEV;
964
965	/* Check to see if (latch closed, card present, power on) */
966	down(&p_slot->ctrl->crit_sect);
967
968	ret = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
969	if (ret || !getstatus) {
970		info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number);
971		up(&p_slot->ctrl->crit_sect);
972		return -ENODEV;
973	}
974	ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
975	if (ret || getstatus) {
976		info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number);
977		up(&p_slot->ctrl->crit_sect);
978		return -ENODEV;
979	}
980	ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
981	if (ret || !getstatus) {
982		info("%s: already disabled slot(%x)\n", __FUNCTION__, p_slot->number);
983		up(&p_slot->ctrl->crit_sect);
984		return -ENODEV;
985	}
986	up(&p_slot->ctrl->crit_sect);
987
988	ret = remove_board(p_slot);
989	update_slot_info(p_slot);
990	return ret;
991}
992
993