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