| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 |  * | 
| Kristen Accardi | 8cf4c19 | 2005-08-16 15:16:10 -0700 | [diff] [blame] | 26 |  * Send feedback to <greg@kroah.com>, <kristen.c.accardi@intel.com> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 27 |  * | 
 | 28 |  */ | 
 | 29 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 30 | #include <linux/module.h> | 
 | 31 | #include <linux/kernel.h> | 
 | 32 | #include <linux/types.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 33 | #include <linux/pci.h> | 
| Kenji Kaneshige | f7391f5 | 2006-02-21 15:45:45 -0800 | [diff] [blame] | 34 | #include <linux/workqueue.h> | 
| rajesh.shah@intel.com | dbd7a78 | 2005-10-13 12:05:36 -0700 | [diff] [blame] | 35 | #include "../pci.h" | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 36 | #include "shpchp.h" | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 37 |  | 
| David Howells | c402895 | 2006-11-22 14:57:56 +0000 | [diff] [blame] | 38 | static void interrupt_event_handler(struct work_struct *work); | 
| Kenji Kaneshige | a246fa4 | 2006-02-21 15:45:48 -0800 | [diff] [blame] | 39 | static int shpchp_enable_slot(struct slot *p_slot); | 
 | 40 | static int shpchp_disable_slot(struct slot *p_slot); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 41 |  | 
| Kenji Kaneshige | f7391f5 | 2006-02-21 15:45:45 -0800 | [diff] [blame] | 42 | static int queue_interrupt_event(struct slot *p_slot, u32 event_type) | 
 | 43 | { | 
 | 44 | 	struct event_info *info; | 
 | 45 |  | 
 | 46 | 	info = kmalloc(sizeof(*info), GFP_ATOMIC); | 
 | 47 | 	if (!info) | 
 | 48 | 		return -ENOMEM; | 
 | 49 |  | 
 | 50 | 	info->event_type = event_type; | 
 | 51 | 	info->p_slot = p_slot; | 
| David Howells | c402895 | 2006-11-22 14:57:56 +0000 | [diff] [blame] | 52 | 	INIT_WORK(&info->work, interrupt_event_handler); | 
| Kenji Kaneshige | f7391f5 | 2006-02-21 15:45:45 -0800 | [diff] [blame] | 53 |  | 
| Kenji Kaneshige | a246fa4 | 2006-02-21 15:45:48 -0800 | [diff] [blame] | 54 | 	schedule_work(&info->work); | 
| Kenji Kaneshige | f7391f5 | 2006-02-21 15:45:45 -0800 | [diff] [blame] | 55 |  | 
 | 56 | 	return 0; | 
 | 57 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 58 |  | 
| Kenji Kaneshige | 0abe68c | 2006-12-16 15:25:34 -0800 | [diff] [blame] | 59 | u8 shpchp_handle_attention_button(u8 hp_slot, struct controller *ctrl) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 60 | { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 61 | 	struct slot *p_slot; | 
| Kenji Kaneshige | f7391f5 | 2006-02-21 15:45:45 -0800 | [diff] [blame] | 62 | 	u32 event_type; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 63 |  | 
 | 64 | 	/* Attention Button Change */ | 
 | 65 | 	dbg("shpchp:  Attention button interrupt received.\n"); | 
| Kenji Kaneshige | 9f593e3 | 2007-01-09 13:03:10 -0800 | [diff] [blame] | 66 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 67 | 	p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); | 
| rajesh.shah@intel.com | 2178bfa | 2005-10-13 12:05:41 -0700 | [diff] [blame] | 68 | 	p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 69 |  | 
 | 70 | 	/* | 
 | 71 | 	 *  Button pressed - See if need to TAKE ACTION!!! | 
 | 72 | 	 */ | 
| Kenji Kaneshige | 99ff124 | 2006-05-12 11:13:50 +0900 | [diff] [blame] | 73 | 	info("Button pressed on Slot(%s)\n", p_slot->name); | 
| Kenji Kaneshige | f7391f5 | 2006-02-21 15:45:45 -0800 | [diff] [blame] | 74 | 	event_type = INT_BUTTON_PRESS; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 75 |  | 
| Kenji Kaneshige | f7391f5 | 2006-02-21 15:45:45 -0800 | [diff] [blame] | 76 | 	queue_interrupt_event(p_slot, event_type); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 77 |  | 
 | 78 | 	return 0; | 
 | 79 |  | 
 | 80 | } | 
 | 81 |  | 
| Kenji Kaneshige | 0abe68c | 2006-12-16 15:25:34 -0800 | [diff] [blame] | 82 | u8 shpchp_handle_switch_change(u8 hp_slot, struct controller *ctrl) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 83 | { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 84 | 	struct slot *p_slot; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 85 | 	u8 getstatus; | 
| Kenji Kaneshige | f7391f5 | 2006-02-21 15:45:45 -0800 | [diff] [blame] | 86 | 	u32 event_type; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 87 |  | 
 | 88 | 	/* Switch Change */ | 
 | 89 | 	dbg("shpchp:  Switch interrupt received.\n"); | 
 | 90 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 91 | 	p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); | 
| rajesh.shah@intel.com | 2178bfa | 2005-10-13 12:05:41 -0700 | [diff] [blame] | 92 | 	p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 93 | 	p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); | 
| Harvey Harrison | 66bef8c | 2008-03-03 19:09:46 -0800 | [diff] [blame] | 94 | 	dbg("%s: Card present %x Power status %x\n", __func__, | 
| rajesh.shah@intel.com | 2178bfa | 2005-10-13 12:05:41 -0700 | [diff] [blame] | 95 | 		p_slot->presence_save, p_slot->pwr_save); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 96 |  | 
 | 97 | 	if (getstatus) { | 
 | 98 | 		/* | 
 | 99 | 		 * Switch opened | 
 | 100 | 		 */ | 
| Kenji Kaneshige | 99ff124 | 2006-05-12 11:13:50 +0900 | [diff] [blame] | 101 | 		info("Latch open on Slot(%s)\n", p_slot->name); | 
| Kenji Kaneshige | f7391f5 | 2006-02-21 15:45:45 -0800 | [diff] [blame] | 102 | 		event_type = INT_SWITCH_OPEN; | 
| rajesh.shah@intel.com | 2178bfa | 2005-10-13 12:05:41 -0700 | [diff] [blame] | 103 | 		if (p_slot->pwr_save && p_slot->presence_save) { | 
| Kenji Kaneshige | f7391f5 | 2006-02-21 15:45:45 -0800 | [diff] [blame] | 104 | 			event_type = INT_POWER_FAULT; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 105 | 			err("Surprise Removal of card\n"); | 
 | 106 | 		} | 
 | 107 | 	} else { | 
 | 108 | 		/* | 
 | 109 | 		 *  Switch closed | 
 | 110 | 		 */ | 
| Kenji Kaneshige | 99ff124 | 2006-05-12 11:13:50 +0900 | [diff] [blame] | 111 | 		info("Latch close on Slot(%s)\n", p_slot->name); | 
| Kenji Kaneshige | f7391f5 | 2006-02-21 15:45:45 -0800 | [diff] [blame] | 112 | 		event_type = INT_SWITCH_CLOSE; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 113 | 	} | 
 | 114 |  | 
| Kenji Kaneshige | f7391f5 | 2006-02-21 15:45:45 -0800 | [diff] [blame] | 115 | 	queue_interrupt_event(p_slot, event_type); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 116 |  | 
| Kenji Kaneshige | f7391f5 | 2006-02-21 15:45:45 -0800 | [diff] [blame] | 117 | 	return 1; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 118 | } | 
 | 119 |  | 
| Kenji Kaneshige | 0abe68c | 2006-12-16 15:25:34 -0800 | [diff] [blame] | 120 | u8 shpchp_handle_presence_change(u8 hp_slot, struct controller *ctrl) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 121 | { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 122 | 	struct slot *p_slot; | 
| Kenji Kaneshige | f7391f5 | 2006-02-21 15:45:45 -0800 | [diff] [blame] | 123 | 	u32 event_type; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 124 |  | 
 | 125 | 	/* Presence Change */ | 
 | 126 | 	dbg("shpchp:  Presence/Notify input change.\n"); | 
 | 127 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 128 | 	p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); | 
 | 129 |  | 
| Kenji Kaneshige | 9f593e3 | 2007-01-09 13:03:10 -0800 | [diff] [blame] | 130 | 	/* | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 131 | 	 * Save the presence state | 
 | 132 | 	 */ | 
| rajesh.shah@intel.com | 2178bfa | 2005-10-13 12:05:41 -0700 | [diff] [blame] | 133 | 	p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save)); | 
 | 134 | 	if (p_slot->presence_save) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 135 | 		/* | 
 | 136 | 		 * Card Present | 
 | 137 | 		 */ | 
| Kenji Kaneshige | 99ff124 | 2006-05-12 11:13:50 +0900 | [diff] [blame] | 138 | 		info("Card present on Slot(%s)\n", p_slot->name); | 
| Kenji Kaneshige | f7391f5 | 2006-02-21 15:45:45 -0800 | [diff] [blame] | 139 | 		event_type = INT_PRESENCE_ON; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 140 | 	} else { | 
 | 141 | 		/* | 
 | 142 | 		 * Not Present | 
 | 143 | 		 */ | 
| Kenji Kaneshige | 99ff124 | 2006-05-12 11:13:50 +0900 | [diff] [blame] | 144 | 		info("Card not present on Slot(%s)\n", p_slot->name); | 
| Kenji Kaneshige | f7391f5 | 2006-02-21 15:45:45 -0800 | [diff] [blame] | 145 | 		event_type = INT_PRESENCE_OFF; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 146 | 	} | 
 | 147 |  | 
| Kenji Kaneshige | f7391f5 | 2006-02-21 15:45:45 -0800 | [diff] [blame] | 148 | 	queue_interrupt_event(p_slot, event_type); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 149 |  | 
| Kenji Kaneshige | f7391f5 | 2006-02-21 15:45:45 -0800 | [diff] [blame] | 150 | 	return 1; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 151 | } | 
 | 152 |  | 
| Kenji Kaneshige | 0abe68c | 2006-12-16 15:25:34 -0800 | [diff] [blame] | 153 | u8 shpchp_handle_power_fault(u8 hp_slot, struct controller *ctrl) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 154 | { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 155 | 	struct slot *p_slot; | 
| Kenji Kaneshige | f7391f5 | 2006-02-21 15:45:45 -0800 | [diff] [blame] | 156 | 	u32 event_type; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 157 |  | 
 | 158 | 	/* Power fault */ | 
 | 159 | 	dbg("shpchp:  Power fault interrupt received.\n"); | 
 | 160 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 161 | 	p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); | 
 | 162 |  | 
 | 163 | 	if ( !(p_slot->hpc_ops->query_power_fault(p_slot))) { | 
 | 164 | 		/* | 
 | 165 | 		 * Power fault Cleared | 
 | 166 | 		 */ | 
| Kenji Kaneshige | 99ff124 | 2006-05-12 11:13:50 +0900 | [diff] [blame] | 167 | 		info("Power fault cleared on Slot(%s)\n", p_slot->name); | 
| rajesh.shah@intel.com | 2178bfa | 2005-10-13 12:05:41 -0700 | [diff] [blame] | 168 | 		p_slot->status = 0x00; | 
| Kenji Kaneshige | f7391f5 | 2006-02-21 15:45:45 -0800 | [diff] [blame] | 169 | 		event_type = INT_POWER_FAULT_CLEAR; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 170 | 	} else { | 
 | 171 | 		/* | 
 | 172 | 		 *   Power fault | 
 | 173 | 		 */ | 
| Kenji Kaneshige | 99ff124 | 2006-05-12 11:13:50 +0900 | [diff] [blame] | 174 | 		info("Power fault on Slot(%s)\n", p_slot->name); | 
| Kenji Kaneshige | f7391f5 | 2006-02-21 15:45:45 -0800 | [diff] [blame] | 175 | 		event_type = INT_POWER_FAULT; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 176 | 		/* set power fault status for this board */ | 
| rajesh.shah@intel.com | 2178bfa | 2005-10-13 12:05:41 -0700 | [diff] [blame] | 177 | 		p_slot->status = 0xFF; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 178 | 		info("power fault bit %x set\n", hp_slot); | 
 | 179 | 	} | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 180 |  | 
| Kenji Kaneshige | f7391f5 | 2006-02-21 15:45:45 -0800 | [diff] [blame] | 181 | 	queue_interrupt_event(p_slot, event_type); | 
 | 182 |  | 
 | 183 | 	return 1; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 184 | } | 
 | 185 |  | 
| Kenji Kaneshige | 9f593e3 | 2007-01-09 13:03:10 -0800 | [diff] [blame] | 186 | /* The following routines constitute the bulk of the | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 187 |    hotplug controller logic | 
 | 188 |  */ | 
| rajesh.shah@intel.com | ee13833 | 2005-10-13 12:05:42 -0700 | [diff] [blame] | 189 | static int change_bus_speed(struct controller *ctrl, struct slot *p_slot, | 
 | 190 | 		enum pci_bus_speed speed) | 
| Kenji Kaneshige | 9f593e3 | 2007-01-09 13:03:10 -0800 | [diff] [blame] | 191 | { | 
| rajesh.shah@intel.com | ee13833 | 2005-10-13 12:05:42 -0700 | [diff] [blame] | 192 | 	int rc = 0; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 193 |  | 
| Harvey Harrison | 66bef8c | 2008-03-03 19:09:46 -0800 | [diff] [blame] | 194 | 	dbg("%s: change to speed %d\n", __func__, speed); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 195 | 	if ((rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, speed))) { | 
| Kenji Kaneshige | 0afabe9 | 2006-03-01 14:55:11 +0900 | [diff] [blame] | 196 | 		err("%s: Issue of set bus speed mode command failed\n", | 
| Harvey Harrison | 66bef8c | 2008-03-03 19:09:46 -0800 | [diff] [blame] | 197 | 		    __func__); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 198 | 		return WRONG_BUS_FREQUENCY; | 
 | 199 | 	} | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 200 | 	return rc; | 
 | 201 | } | 
 | 202 |  | 
| rajesh.shah@intel.com | ee13833 | 2005-10-13 12:05:42 -0700 | [diff] [blame] | 203 | static int fix_bus_speed(struct controller *ctrl, struct slot *pslot, | 
 | 204 | 		u8 flag, enum pci_bus_speed asp, enum pci_bus_speed bsp, | 
 | 205 | 		enum pci_bus_speed msp) | 
| Kenji Kaneshige | 9f593e3 | 2007-01-09 13:03:10 -0800 | [diff] [blame] | 206 | { | 
| rajesh.shah@intel.com | ee13833 | 2005-10-13 12:05:42 -0700 | [diff] [blame] | 207 | 	int rc = 0; | 
| Kenji Kaneshige | 0afabe9 | 2006-03-01 14:55:11 +0900 | [diff] [blame] | 208 |  | 
 | 209 | 	/* | 
 | 210 | 	 * If other slots on the same bus are occupied, we cannot | 
 | 211 | 	 * change the bus speed. | 
 | 212 | 	 */ | 
 | 213 | 	if (flag) { | 
 | 214 | 		if (asp < bsp) { | 
 | 215 | 			err("%s: speed of bus %x and adapter %x mismatch\n", | 
| Harvey Harrison | 66bef8c | 2008-03-03 19:09:46 -0800 | [diff] [blame] | 216 | 			    __func__, bsp, asp); | 
| Kenji Kaneshige | 0afabe9 | 2006-03-01 14:55:11 +0900 | [diff] [blame] | 217 | 			rc = WRONG_BUS_FREQUENCY; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 218 | 		} | 
| Kenji Kaneshige | 0afabe9 | 2006-03-01 14:55:11 +0900 | [diff] [blame] | 219 | 		return rc; | 
 | 220 | 	} | 
 | 221 |  | 
 | 222 | 	if (asp < msp) { | 
 | 223 | 		if (bsp != asp) | 
 | 224 | 			rc = change_bus_speed(ctrl, pslot, asp); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 225 | 	} else { | 
| Kenji Kaneshige | 0afabe9 | 2006-03-01 14:55:11 +0900 | [diff] [blame] | 226 | 		if (bsp != msp) | 
 | 227 | 			rc = change_bus_speed(ctrl, pslot, msp); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 228 | 	} | 
 | 229 | 	return rc; | 
 | 230 | } | 
 | 231 |  | 
 | 232 | /** | 
 | 233 |  * board_added - Called after a board has been added to the system. | 
| Randy Dunlap | 26e6c66 | 2007-11-28 09:04:30 -0800 | [diff] [blame] | 234 |  * @p_slot: target &slot | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 235 |  * | 
| Randy Dunlap | 26e6c66 | 2007-11-28 09:04:30 -0800 | [diff] [blame] | 236 |  * Turns power on for the board. | 
 | 237 |  * Configures board. | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 238 |  */ | 
| rajesh.shah@intel.com | ee13833 | 2005-10-13 12:05:42 -0700 | [diff] [blame] | 239 | static int board_added(struct slot *p_slot) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 240 | { | 
 | 241 | 	u8 hp_slot; | 
 | 242 | 	u8 slots_not_empty = 0; | 
| rajesh.shah@intel.com | ee13833 | 2005-10-13 12:05:42 -0700 | [diff] [blame] | 243 | 	int rc = 0; | 
| Kenji Kaneshige | 0afabe9 | 2006-03-01 14:55:11 +0900 | [diff] [blame] | 244 | 	enum pci_bus_speed asp, bsp, msp; | 
| rajesh.shah@intel.com | 2178bfa | 2005-10-13 12:05:41 -0700 | [diff] [blame] | 245 | 	struct controller *ctrl = p_slot->ctrl; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 246 |  | 
| rajesh.shah@intel.com | 2178bfa | 2005-10-13 12:05:41 -0700 | [diff] [blame] | 247 | 	hp_slot = p_slot->device - ctrl->slot_device_offset; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 248 |  | 
| rajesh.shah@intel.com | 2178bfa | 2005-10-13 12:05:41 -0700 | [diff] [blame] | 249 | 	dbg("%s: p_slot->device, slot_offset, hp_slot = %d, %d ,%d\n", | 
| Harvey Harrison | 66bef8c | 2008-03-03 19:09:46 -0800 | [diff] [blame] | 250 | 			__func__, p_slot->device, | 
| rajesh.shah@intel.com | 2178bfa | 2005-10-13 12:05:41 -0700 | [diff] [blame] | 251 | 			ctrl->slot_device_offset, hp_slot); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 252 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 253 | 	/* Power on slot without connecting to bus */ | 
 | 254 | 	rc = p_slot->hpc_ops->power_on_slot(p_slot); | 
 | 255 | 	if (rc) { | 
| Harvey Harrison | 66bef8c | 2008-03-03 19:09:46 -0800 | [diff] [blame] | 256 | 		err("%s: Failed to power on slot\n", __func__); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 257 | 		return -1; | 
 | 258 | 	} | 
| Kenji Kaneshige | 9f593e3 | 2007-01-09 13:03:10 -0800 | [diff] [blame] | 259 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 260 | 	if ((ctrl->pci_dev->vendor == 0x8086) && (ctrl->pci_dev->device == 0x0332)) { | 
 | 261 | 		if (slots_not_empty) | 
 | 262 | 			return WRONG_BUS_FREQUENCY; | 
| Kenji Kaneshige | 9f593e3 | 2007-01-09 13:03:10 -0800 | [diff] [blame] | 263 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 264 | 		if ((rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, PCI_SPEED_33MHz))) { | 
| Harvey Harrison | 66bef8c | 2008-03-03 19:09:46 -0800 | [diff] [blame] | 265 | 			err("%s: Issue of set bus speed mode command failed\n", __func__); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 266 | 			return WRONG_BUS_FREQUENCY; | 
 | 267 | 		} | 
| Kenji Kaneshige | 9f593e3 | 2007-01-09 13:03:10 -0800 | [diff] [blame] | 268 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 269 | 		/* turn on board, blink green LED, turn off Amber LED */ | 
 | 270 | 		if ((rc = p_slot->hpc_ops->slot_enable(p_slot))) { | 
| Harvey Harrison | 66bef8c | 2008-03-03 19:09:46 -0800 | [diff] [blame] | 271 | 			err("%s: Issue of Slot Enable command failed\n", __func__); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 272 | 			return rc; | 
 | 273 | 		} | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 274 | 	} | 
| Kenji Kaneshige | 9f593e3 | 2007-01-09 13:03:10 -0800 | [diff] [blame] | 275 |  | 
| Kenji Kaneshige | 0afabe9 | 2006-03-01 14:55:11 +0900 | [diff] [blame] | 276 | 	rc = p_slot->hpc_ops->get_adapter_speed(p_slot, &asp); | 
 | 277 | 	if (rc) { | 
 | 278 | 		err("%s: Can't get adapter speed or bus mode mismatch\n", | 
| Harvey Harrison | 66bef8c | 2008-03-03 19:09:46 -0800 | [diff] [blame] | 279 | 		    __func__); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 280 | 		return WRONG_BUS_FREQUENCY; | 
 | 281 | 	} | 
 | 282 |  | 
| Kenji Kaneshige | 0afabe9 | 2006-03-01 14:55:11 +0900 | [diff] [blame] | 283 | 	rc = p_slot->hpc_ops->get_cur_bus_speed(p_slot, &bsp); | 
 | 284 | 	if (rc) { | 
| Harvey Harrison | 66bef8c | 2008-03-03 19:09:46 -0800 | [diff] [blame] | 285 | 		err("%s: Can't get bus operation speed\n", __func__); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 286 | 		return WRONG_BUS_FREQUENCY; | 
 | 287 | 	} | 
 | 288 |  | 
| Kenji Kaneshige | 0afabe9 | 2006-03-01 14:55:11 +0900 | [diff] [blame] | 289 | 	rc = p_slot->hpc_ops->get_max_bus_speed(p_slot, &msp); | 
 | 290 | 	if (rc) { | 
| Harvey Harrison | 66bef8c | 2008-03-03 19:09:46 -0800 | [diff] [blame] | 291 | 		err("%s: Can't get max bus operation speed\n", __func__); | 
| Kenji Kaneshige | 0afabe9 | 2006-03-01 14:55:11 +0900 | [diff] [blame] | 292 | 		msp = bsp; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 293 | 	} | 
 | 294 |  | 
 | 295 | 	/* Check if there are other slots or devices on the same bus */ | 
 | 296 | 	if (!list_empty(&ctrl->pci_dev->subordinate->devices)) | 
 | 297 | 		slots_not_empty = 1; | 
 | 298 |  | 
| Kenji Kaneshige | 0afabe9 | 2006-03-01 14:55:11 +0900 | [diff] [blame] | 299 | 	dbg("%s: slots_not_empty %d, adapter_speed %d, bus_speed %d, " | 
| Harvey Harrison | 66bef8c | 2008-03-03 19:09:46 -0800 | [diff] [blame] | 300 | 	    "max_bus_speed %d\n", __func__, slots_not_empty, asp, | 
| Kenji Kaneshige | 0afabe9 | 2006-03-01 14:55:11 +0900 | [diff] [blame] | 301 | 	    bsp, msp); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 302 |  | 
| Kenji Kaneshige | 0afabe9 | 2006-03-01 14:55:11 +0900 | [diff] [blame] | 303 | 	rc = fix_bus_speed(ctrl, p_slot, slots_not_empty, asp, bsp, msp); | 
 | 304 | 	if (rc) | 
 | 305 | 		return rc; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 306 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 307 | 	/* turn on board, blink green LED, turn off Amber LED */ | 
 | 308 | 	if ((rc = p_slot->hpc_ops->slot_enable(p_slot))) { | 
| Harvey Harrison | 66bef8c | 2008-03-03 19:09:46 -0800 | [diff] [blame] | 309 | 		err("%s: Issue of Slot Enable command failed\n", __func__); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 310 | 		return rc; | 
 | 311 | 	} | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 312 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 313 | 	/* Wait for ~1 second */ | 
| Kenji Kaneshige | 68c0b67 | 2006-02-21 15:45:42 -0800 | [diff] [blame] | 314 | 	msleep(1000); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 315 |  | 
| Harvey Harrison | 66bef8c | 2008-03-03 19:09:46 -0800 | [diff] [blame] | 316 | 	dbg("%s: slot status = %x\n", __func__, p_slot->status); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 317 | 	/* Check for a power fault */ | 
| rajesh.shah@intel.com | 2178bfa | 2005-10-13 12:05:41 -0700 | [diff] [blame] | 318 | 	if (p_slot->status == 0xFF) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 319 | 		/* power fault occurred, but it was benign */ | 
| Harvey Harrison | 66bef8c | 2008-03-03 19:09:46 -0800 | [diff] [blame] | 320 | 		dbg("%s: power fault\n", __func__); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 321 | 		rc = POWER_FAILURE; | 
| rajesh.shah@intel.com | 2178bfa | 2005-10-13 12:05:41 -0700 | [diff] [blame] | 322 | 		p_slot->status = 0; | 
| rajesh.shah@intel.com | dbd7a78 | 2005-10-13 12:05:36 -0700 | [diff] [blame] | 323 | 		goto err_exit; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 324 | 	} | 
 | 325 |  | 
| rajesh.shah@intel.com | dbd7a78 | 2005-10-13 12:05:36 -0700 | [diff] [blame] | 326 | 	if (shpchp_configure_device(p_slot)) { | 
 | 327 | 		err("Cannot add device at 0x%x:0x%x\n", p_slot->bus, | 
 | 328 | 				p_slot->device); | 
 | 329 | 		goto err_exit; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 330 | 	} | 
| rajesh.shah@intel.com | dbd7a78 | 2005-10-13 12:05:36 -0700 | [diff] [blame] | 331 |  | 
| rajesh.shah@intel.com | 2178bfa | 2005-10-13 12:05:41 -0700 | [diff] [blame] | 332 | 	p_slot->status = 0; | 
 | 333 | 	p_slot->is_a_board = 0x01; | 
 | 334 | 	p_slot->pwr_save = 1; | 
| rajesh.shah@intel.com | dbd7a78 | 2005-10-13 12:05:36 -0700 | [diff] [blame] | 335 |  | 
| rajesh.shah@intel.com | dbd7a78 | 2005-10-13 12:05:36 -0700 | [diff] [blame] | 336 | 	p_slot->hpc_ops->green_led_on(p_slot); | 
 | 337 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 338 | 	return 0; | 
| rajesh.shah@intel.com | dbd7a78 | 2005-10-13 12:05:36 -0700 | [diff] [blame] | 339 |  | 
 | 340 | err_exit: | 
| rajesh.shah@intel.com | dbd7a78 | 2005-10-13 12:05:36 -0700 | [diff] [blame] | 341 | 	/* turn off slot, turn on Amber LED, turn off Green LED */ | 
 | 342 | 	rc = p_slot->hpc_ops->slot_disable(p_slot); | 
 | 343 | 	if (rc) { | 
| Harvey Harrison | 66bef8c | 2008-03-03 19:09:46 -0800 | [diff] [blame] | 344 | 		err("%s: Issue of Slot Disable command failed\n", __func__); | 
| rajesh.shah@intel.com | dbd7a78 | 2005-10-13 12:05:36 -0700 | [diff] [blame] | 345 | 		return rc; | 
 | 346 | 	} | 
| rajesh.shah@intel.com | dbd7a78 | 2005-10-13 12:05:36 -0700 | [diff] [blame] | 347 |  | 
| rajesh.shah@intel.com | dbd7a78 | 2005-10-13 12:05:36 -0700 | [diff] [blame] | 348 | 	return(rc); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 349 | } | 
 | 350 |  | 
 | 351 |  | 
 | 352 | /** | 
| Randy Dunlap | 26e6c66 | 2007-11-28 09:04:30 -0800 | [diff] [blame] | 353 |  * remove_board - Turns off slot and LEDs | 
 | 354 |  * @p_slot: target &slot | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 355 |  */ | 
| rajesh.shah@intel.com | ee13833 | 2005-10-13 12:05:42 -0700 | [diff] [blame] | 356 | static int remove_board(struct slot *p_slot) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 357 | { | 
| rajesh.shah@intel.com | 2178bfa | 2005-10-13 12:05:41 -0700 | [diff] [blame] | 358 | 	struct controller *ctrl = p_slot->ctrl; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 359 | 	u8 hp_slot; | 
| rajesh.shah@intel.com | ee13833 | 2005-10-13 12:05:42 -0700 | [diff] [blame] | 360 | 	int rc; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 361 |  | 
| rajesh.shah@intel.com | 2178bfa | 2005-10-13 12:05:41 -0700 | [diff] [blame] | 362 | 	if (shpchp_unconfigure_device(p_slot)) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 363 | 		return(1); | 
 | 364 |  | 
| rajesh.shah@intel.com | 2178bfa | 2005-10-13 12:05:41 -0700 | [diff] [blame] | 365 | 	hp_slot = p_slot->device - ctrl->slot_device_offset; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 366 | 	p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); | 
 | 367 |  | 
| Harvey Harrison | 66bef8c | 2008-03-03 19:09:46 -0800 | [diff] [blame] | 368 | 	dbg("In %s, hp_slot = %d\n", __func__, hp_slot); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 369 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 370 | 	/* Change status to shutdown */ | 
| rajesh.shah@intel.com | 2178bfa | 2005-10-13 12:05:41 -0700 | [diff] [blame] | 371 | 	if (p_slot->is_a_board) | 
 | 372 | 		p_slot->status = 0x01; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 373 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 374 | 	/* turn off slot, turn on Amber LED, turn off Green LED */ | 
 | 375 | 	rc = p_slot->hpc_ops->slot_disable(p_slot); | 
 | 376 | 	if (rc) { | 
| Harvey Harrison | 66bef8c | 2008-03-03 19:09:46 -0800 | [diff] [blame] | 377 | 		err("%s: Issue of Slot Disable command failed\n", __func__); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 378 | 		return rc; | 
 | 379 | 	} | 
| Kenji Kaneshige | 9f593e3 | 2007-01-09 13:03:10 -0800 | [diff] [blame] | 380 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 381 | 	rc = p_slot->hpc_ops->set_attention_status(p_slot, 0); | 
 | 382 | 	if (rc) { | 
| Harvey Harrison | 66bef8c | 2008-03-03 19:09:46 -0800 | [diff] [blame] | 383 | 		err("%s: Issue of Set Attention command failed\n", __func__); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 384 | 		return rc; | 
 | 385 | 	} | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 386 |  | 
| rajesh.shah@intel.com | 2178bfa | 2005-10-13 12:05:41 -0700 | [diff] [blame] | 387 | 	p_slot->pwr_save = 0; | 
 | 388 | 	p_slot->is_a_board = 0; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 389 |  | 
 | 390 | 	return 0; | 
 | 391 | } | 
 | 392 |  | 
 | 393 |  | 
| Kenji Kaneshige | a246fa4 | 2006-02-21 15:45:48 -0800 | [diff] [blame] | 394 | struct pushbutton_work_info { | 
 | 395 | 	struct slot *p_slot; | 
 | 396 | 	struct work_struct work; | 
 | 397 | }; | 
 | 398 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 399 | /** | 
| Randy Dunlap | 26e6c66 | 2007-11-28 09:04:30 -0800 | [diff] [blame] | 400 |  * shpchp_pushbutton_thread - handle pushbutton events | 
 | 401 |  * @work: &struct work_struct to be handled | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 402 |  * | 
| Randy Dunlap | 26e6c66 | 2007-11-28 09:04:30 -0800 | [diff] [blame] | 403 |  * Scheduled procedure to handle blocking stuff for the pushbuttons. | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 404 |  * Handles all pending events and exits. | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 405 |  */ | 
| David Howells | c402895 | 2006-11-22 14:57:56 +0000 | [diff] [blame] | 406 | static void shpchp_pushbutton_thread(struct work_struct *work) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 407 | { | 
| David Howells | c402895 | 2006-11-22 14:57:56 +0000 | [diff] [blame] | 408 | 	struct pushbutton_work_info *info = | 
 | 409 | 		container_of(work, struct pushbutton_work_info, work); | 
| Kenji Kaneshige | a246fa4 | 2006-02-21 15:45:48 -0800 | [diff] [blame] | 410 | 	struct slot *p_slot = info->p_slot; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 411 |  | 
| Kenji Kaneshige | a246fa4 | 2006-02-21 15:45:48 -0800 | [diff] [blame] | 412 | 	mutex_lock(&p_slot->lock); | 
 | 413 | 	switch (p_slot->state) { | 
 | 414 | 	case POWEROFF_STATE: | 
 | 415 | 		mutex_unlock(&p_slot->lock); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 416 | 		shpchp_disable_slot(p_slot); | 
| Kenji Kaneshige | a246fa4 | 2006-02-21 15:45:48 -0800 | [diff] [blame] | 417 | 		mutex_lock(&p_slot->lock); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 418 | 		p_slot->state = STATIC_STATE; | 
| Kenji Kaneshige | a246fa4 | 2006-02-21 15:45:48 -0800 | [diff] [blame] | 419 | 		break; | 
 | 420 | 	case POWERON_STATE: | 
 | 421 | 		mutex_unlock(&p_slot->lock); | 
| Kenji Kaneshige | d29aadd | 2006-01-26 09:59:24 +0900 | [diff] [blame] | 422 | 		if (shpchp_enable_slot(p_slot)) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 423 | 			p_slot->hpc_ops->green_led_off(p_slot); | 
| Kenji Kaneshige | a246fa4 | 2006-02-21 15:45:48 -0800 | [diff] [blame] | 424 | 		mutex_lock(&p_slot->lock); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 425 | 		p_slot->state = STATIC_STATE; | 
| Kenji Kaneshige | a246fa4 | 2006-02-21 15:45:48 -0800 | [diff] [blame] | 426 | 		break; | 
 | 427 | 	default: | 
 | 428 | 		break; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 429 | 	} | 
| Kenji Kaneshige | a246fa4 | 2006-02-21 15:45:48 -0800 | [diff] [blame] | 430 | 	mutex_unlock(&p_slot->lock); | 
 | 431 |  | 
 | 432 | 	kfree(info); | 
 | 433 | } | 
 | 434 |  | 
| Kristen Carlson Accardi | e325e1f | 2007-03-21 11:45:31 -0700 | [diff] [blame] | 435 | void shpchp_queue_pushbutton_work(struct work_struct *work) | 
| Kenji Kaneshige | a246fa4 | 2006-02-21 15:45:48 -0800 | [diff] [blame] | 436 | { | 
| David Howells | c402895 | 2006-11-22 14:57:56 +0000 | [diff] [blame] | 437 | 	struct slot *p_slot = container_of(work, struct slot, work.work); | 
| Kenji Kaneshige | a246fa4 | 2006-02-21 15:45:48 -0800 | [diff] [blame] | 438 | 	struct pushbutton_work_info *info; | 
 | 439 |  | 
 | 440 | 	info = kmalloc(sizeof(*info), GFP_KERNEL); | 
 | 441 | 	if (!info) { | 
| Harvey Harrison | 66bef8c | 2008-03-03 19:09:46 -0800 | [diff] [blame] | 442 | 		err("%s: Cannot allocate memory\n", __func__); | 
| Kenji Kaneshige | a246fa4 | 2006-02-21 15:45:48 -0800 | [diff] [blame] | 443 | 		return; | 
 | 444 | 	} | 
 | 445 | 	info->p_slot = p_slot; | 
| David Howells | c402895 | 2006-11-22 14:57:56 +0000 | [diff] [blame] | 446 | 	INIT_WORK(&info->work, shpchp_pushbutton_thread); | 
| Kenji Kaneshige | a246fa4 | 2006-02-21 15:45:48 -0800 | [diff] [blame] | 447 |  | 
 | 448 | 	mutex_lock(&p_slot->lock); | 
 | 449 | 	switch (p_slot->state) { | 
 | 450 | 	case BLINKINGOFF_STATE: | 
 | 451 | 		p_slot->state = POWEROFF_STATE; | 
 | 452 | 		break; | 
 | 453 | 	case BLINKINGON_STATE: | 
 | 454 | 		p_slot->state = POWERON_STATE; | 
 | 455 | 		break; | 
 | 456 | 	default: | 
 | 457 | 		goto out; | 
 | 458 | 	} | 
 | 459 | 	queue_work(shpchp_wq, &info->work); | 
 | 460 |  out: | 
 | 461 | 	mutex_unlock(&p_slot->lock); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 462 | } | 
 | 463 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 464 | static int update_slot_info (struct slot *slot) | 
 | 465 | { | 
 | 466 | 	struct hotplug_slot_info *info; | 
 | 467 | 	int result; | 
 | 468 |  | 
 | 469 | 	info = kmalloc(sizeof(*info), GFP_KERNEL); | 
 | 470 | 	if (!info) | 
 | 471 | 		return -ENOMEM; | 
 | 472 |  | 
 | 473 | 	slot->hpc_ops->get_power_status(slot, &(info->power_status)); | 
 | 474 | 	slot->hpc_ops->get_attention_status(slot, &(info->attention_status)); | 
 | 475 | 	slot->hpc_ops->get_latch_status(slot, &(info->latch_status)); | 
 | 476 | 	slot->hpc_ops->get_adapter_status(slot, &(info->adapter_status)); | 
 | 477 |  | 
 | 478 | 	result = pci_hp_change_slot_info(slot->hotplug_slot, info); | 
 | 479 | 	kfree (info); | 
 | 480 | 	return result; | 
 | 481 | } | 
 | 482 |  | 
| Kenji Kaneshige | a246fa4 | 2006-02-21 15:45:48 -0800 | [diff] [blame] | 483 | /* | 
 | 484 |  * Note: This function must be called with slot->lock held | 
 | 485 |  */ | 
 | 486 | static void handle_button_press_event(struct slot *p_slot) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 487 | { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 488 | 	u8 getstatus; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 489 |  | 
| Kenji Kaneshige | a246fa4 | 2006-02-21 15:45:48 -0800 | [diff] [blame] | 490 | 	switch (p_slot->state) { | 
 | 491 | 	case STATIC_STATE: | 
| Kenji Kaneshige | f7391f5 | 2006-02-21 15:45:45 -0800 | [diff] [blame] | 492 | 		p_slot->hpc_ops->get_power_status(p_slot, &getstatus); | 
 | 493 | 		if (getstatus) { | 
 | 494 | 			p_slot->state = BLINKINGOFF_STATE; | 
| Kenji Kaneshige | 8352e04 | 2006-12-16 15:25:57 -0800 | [diff] [blame] | 495 | 			info("PCI slot #%s - powering off due to button " | 
 | 496 | 			     "press.\n", p_slot->name); | 
| Kenji Kaneshige | f7391f5 | 2006-02-21 15:45:45 -0800 | [diff] [blame] | 497 | 		} else { | 
 | 498 | 			p_slot->state = BLINKINGON_STATE; | 
| Kenji Kaneshige | 8352e04 | 2006-12-16 15:25:57 -0800 | [diff] [blame] | 499 | 			info("PCI slot #%s - powering on due to button " | 
 | 500 | 			     "press.\n", p_slot->name); | 
| Kenji Kaneshige | f7391f5 | 2006-02-21 15:45:45 -0800 | [diff] [blame] | 501 | 		} | 
 | 502 | 		/* blink green LED and turn off amber */ | 
 | 503 | 		p_slot->hpc_ops->green_led_blink(p_slot); | 
 | 504 | 		p_slot->hpc_ops->set_attention_status(p_slot, 0); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 505 |  | 
| Kenji Kaneshige | a246fa4 | 2006-02-21 15:45:48 -0800 | [diff] [blame] | 506 | 		schedule_delayed_work(&p_slot->work, 5*HZ); | 
 | 507 | 		break; | 
 | 508 | 	case BLINKINGOFF_STATE: | 
 | 509 | 	case BLINKINGON_STATE: | 
 | 510 | 		/* | 
 | 511 | 		 * Cancel if we are still blinking; this means that we | 
 | 512 | 		 * press the attention again before the 5 sec. limit | 
 | 513 | 		 * expires to cancel hot-add or hot-remove | 
 | 514 | 		 */ | 
 | 515 | 		info("Button cancel on Slot(%s)\n", p_slot->name); | 
| Harvey Harrison | 66bef8c | 2008-03-03 19:09:46 -0800 | [diff] [blame] | 516 | 		dbg("%s: button cancel\n", __func__); | 
| Kenji Kaneshige | a246fa4 | 2006-02-21 15:45:48 -0800 | [diff] [blame] | 517 | 		cancel_delayed_work(&p_slot->work); | 
 | 518 | 		if (p_slot->state == BLINKINGOFF_STATE) | 
 | 519 | 			p_slot->hpc_ops->green_led_on(p_slot); | 
 | 520 | 		else | 
 | 521 | 			p_slot->hpc_ops->green_led_off(p_slot); | 
 | 522 | 		p_slot->hpc_ops->set_attention_status(p_slot, 0); | 
| Kenji Kaneshige | 8352e04 | 2006-12-16 15:25:57 -0800 | [diff] [blame] | 523 | 		info("PCI slot #%s - action canceled due to button press\n", | 
 | 524 | 		     p_slot->name); | 
| Kenji Kaneshige | a246fa4 | 2006-02-21 15:45:48 -0800 | [diff] [blame] | 525 | 		p_slot->state = STATIC_STATE; | 
 | 526 | 		break; | 
 | 527 | 	case POWEROFF_STATE: | 
 | 528 | 	case POWERON_STATE: | 
 | 529 | 		/* | 
 | 530 | 		 * Ignore if the slot is on power-on or power-off state; | 
 | 531 | 		 * this means that the previous attention button action | 
 | 532 | 		 * to hot-add or hot-remove is undergoing | 
 | 533 | 		 */ | 
 | 534 | 		info("Button ignore on Slot(%s)\n", p_slot->name); | 
 | 535 | 		update_slot_info(p_slot); | 
 | 536 | 		break; | 
 | 537 | 	default: | 
 | 538 | 		warn("Not a valid state\n"); | 
 | 539 | 		break; | 
 | 540 | 	} | 
 | 541 | } | 
 | 542 |  | 
| David Howells | c402895 | 2006-11-22 14:57:56 +0000 | [diff] [blame] | 543 | static void interrupt_event_handler(struct work_struct *work) | 
| Kenji Kaneshige | a246fa4 | 2006-02-21 15:45:48 -0800 | [diff] [blame] | 544 | { | 
| David Howells | c402895 | 2006-11-22 14:57:56 +0000 | [diff] [blame] | 545 | 	struct event_info *info = container_of(work, struct event_info, work); | 
| Kenji Kaneshige | a246fa4 | 2006-02-21 15:45:48 -0800 | [diff] [blame] | 546 | 	struct slot *p_slot = info->p_slot; | 
 | 547 |  | 
 | 548 | 	mutex_lock(&p_slot->lock); | 
 | 549 | 	switch (info->event_type) { | 
 | 550 | 	case INT_BUTTON_PRESS: | 
 | 551 | 		handle_button_press_event(p_slot); | 
| Kenji Kaneshige | f7391f5 | 2006-02-21 15:45:45 -0800 | [diff] [blame] | 552 | 		break; | 
 | 553 | 	case INT_POWER_FAULT: | 
| Harvey Harrison | 66bef8c | 2008-03-03 19:09:46 -0800 | [diff] [blame] | 554 | 		dbg("%s: power fault\n", __func__); | 
| Kenji Kaneshige | f7391f5 | 2006-02-21 15:45:45 -0800 | [diff] [blame] | 555 | 		p_slot->hpc_ops->set_attention_status(p_slot, 1); | 
 | 556 | 		p_slot->hpc_ops->green_led_off(p_slot); | 
 | 557 | 		break; | 
 | 558 | 	default: | 
 | 559 | 		update_slot_info(p_slot); | 
 | 560 | 		break; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 561 | 	} | 
| Kenji Kaneshige | a246fa4 | 2006-02-21 15:45:48 -0800 | [diff] [blame] | 562 | 	mutex_unlock(&p_slot->lock); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 563 |  | 
| Kenji Kaneshige | f7391f5 | 2006-02-21 15:45:45 -0800 | [diff] [blame] | 564 | 	kfree(info); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 565 | } | 
 | 566 |  | 
 | 567 |  | 
| Kenji Kaneshige | a246fa4 | 2006-02-21 15:45:48 -0800 | [diff] [blame] | 568 | static int shpchp_enable_slot (struct slot *p_slot) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 569 | { | 
 | 570 | 	u8 getstatus = 0; | 
| Kenji Kaneshige | ef3be54 | 2006-01-26 10:00:33 +0900 | [diff] [blame] | 571 | 	int rc, retval = -ENODEV; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 572 |  | 
 | 573 | 	/* Check to see if (latch closed, card present, power off) */ | 
| Ingo Molnar | 6aa4cdd | 2006-01-13 16:02:15 +0100 | [diff] [blame] | 574 | 	mutex_lock(&p_slot->ctrl->crit_sect); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 575 | 	rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); | 
 | 576 | 	if (rc || !getstatus) { | 
| Kenji Kaneshige | 99ff124 | 2006-05-12 11:13:50 +0900 | [diff] [blame] | 577 | 		info("No adapter on slot(%s)\n", p_slot->name); | 
| Kenji Kaneshige | ef3be54 | 2006-01-26 10:00:33 +0900 | [diff] [blame] | 578 | 		goto out; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 579 | 	} | 
 | 580 | 	rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); | 
 | 581 | 	if (rc || getstatus) { | 
| Kenji Kaneshige | 99ff124 | 2006-05-12 11:13:50 +0900 | [diff] [blame] | 582 | 		info("Latch open on slot(%s)\n", p_slot->name); | 
| Kenji Kaneshige | ef3be54 | 2006-01-26 10:00:33 +0900 | [diff] [blame] | 583 | 		goto out; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 584 | 	} | 
 | 585 | 	rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); | 
 | 586 | 	if (rc || getstatus) { | 
| Kenji Kaneshige | 99ff124 | 2006-05-12 11:13:50 +0900 | [diff] [blame] | 587 | 		info("Already enabled on slot(%s)\n", p_slot->name); | 
| Kenji Kaneshige | ef3be54 | 2006-01-26 10:00:33 +0900 | [diff] [blame] | 588 | 		goto out; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 589 | 	} | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 590 |  | 
| rajesh.shah@intel.com | 2178bfa | 2005-10-13 12:05:41 -0700 | [diff] [blame] | 591 | 	p_slot->is_a_board = 1; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 592 |  | 
 | 593 | 	/* We have to save the presence info for these slots */ | 
| rajesh.shah@intel.com | 2178bfa | 2005-10-13 12:05:41 -0700 | [diff] [blame] | 594 | 	p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save)); | 
 | 595 | 	p_slot->hpc_ops->get_power_status(p_slot, &(p_slot->pwr_save)); | 
| Harvey Harrison | 66bef8c | 2008-03-03 19:09:46 -0800 | [diff] [blame] | 596 | 	dbg("%s: p_slot->pwr_save %x\n", __func__, p_slot->pwr_save); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 597 | 	p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 598 |  | 
| Keck, David | 53044f3 | 2006-01-16 15:22:36 -0600 | [diff] [blame] | 599 | 	if(((p_slot->ctrl->pci_dev->vendor == PCI_VENDOR_ID_AMD) || | 
 | 600 | 	    (p_slot->ctrl->pci_dev->device == PCI_DEVICE_ID_AMD_POGO_7458)) | 
 | 601 | 	     && p_slot->ctrl->num_slots == 1) { | 
 | 602 | 		/* handle amd pogo errata; this must be done before enable  */ | 
 | 603 | 		amd_pogo_errata_save_misc_reg(p_slot); | 
| Kenji Kaneshige | ef3be54 | 2006-01-26 10:00:33 +0900 | [diff] [blame] | 604 | 		retval = board_added(p_slot); | 
| Keck, David | 53044f3 | 2006-01-16 15:22:36 -0600 | [diff] [blame] | 605 | 		/* handle amd pogo errata; this must be done after enable  */ | 
 | 606 | 		amd_pogo_errata_restore_misc_reg(p_slot); | 
 | 607 | 	} else | 
| Kenji Kaneshige | ef3be54 | 2006-01-26 10:00:33 +0900 | [diff] [blame] | 608 | 		retval = board_added(p_slot); | 
| Keck, David | 53044f3 | 2006-01-16 15:22:36 -0600 | [diff] [blame] | 609 |  | 
| Kenji Kaneshige | ef3be54 | 2006-01-26 10:00:33 +0900 | [diff] [blame] | 610 | 	if (retval) { | 
| rajesh.shah@intel.com | 2178bfa | 2005-10-13 12:05:41 -0700 | [diff] [blame] | 611 | 		p_slot->hpc_ops->get_adapter_status(p_slot, | 
 | 612 | 				&(p_slot->presence_save)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 613 | 		p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 614 | 	} | 
 | 615 |  | 
| rajesh.shah@intel.com | 2178bfa | 2005-10-13 12:05:41 -0700 | [diff] [blame] | 616 | 	update_slot_info(p_slot); | 
| Kenji Kaneshige | ef3be54 | 2006-01-26 10:00:33 +0900 | [diff] [blame] | 617 |  out: | 
 | 618 | 	mutex_unlock(&p_slot->ctrl->crit_sect); | 
 | 619 | 	return retval; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 620 | } | 
 | 621 |  | 
 | 622 |  | 
| Kenji Kaneshige | a246fa4 | 2006-02-21 15:45:48 -0800 | [diff] [blame] | 623 | static int shpchp_disable_slot (struct slot *p_slot) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 624 | { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 625 | 	u8 getstatus = 0; | 
| Kenji Kaneshige | ef3be54 | 2006-01-26 10:00:33 +0900 | [diff] [blame] | 626 | 	int rc, retval = -ENODEV; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 627 |  | 
 | 628 | 	if (!p_slot->ctrl) | 
| Dely Sy | ee17fd9 | 2005-05-05 11:57:25 -0700 | [diff] [blame] | 629 | 		return -ENODEV; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 630 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 631 | 	/* Check to see if (latch closed, card present, power on) */ | 
| Ingo Molnar | 6aa4cdd | 2006-01-13 16:02:15 +0100 | [diff] [blame] | 632 | 	mutex_lock(&p_slot->ctrl->crit_sect); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 633 |  | 
| Kenji Kaneshige | ef3be54 | 2006-01-26 10:00:33 +0900 | [diff] [blame] | 634 | 	rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); | 
 | 635 | 	if (rc || !getstatus) { | 
| Kenji Kaneshige | 99ff124 | 2006-05-12 11:13:50 +0900 | [diff] [blame] | 636 | 		info("No adapter on slot(%s)\n", p_slot->name); | 
| Kenji Kaneshige | ef3be54 | 2006-01-26 10:00:33 +0900 | [diff] [blame] | 637 | 		goto out; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 638 | 	} | 
| Kenji Kaneshige | ef3be54 | 2006-01-26 10:00:33 +0900 | [diff] [blame] | 639 | 	rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); | 
 | 640 | 	if (rc || getstatus) { | 
| Kenji Kaneshige | 99ff124 | 2006-05-12 11:13:50 +0900 | [diff] [blame] | 641 | 		info("Latch open on slot(%s)\n", p_slot->name); | 
| Kenji Kaneshige | ef3be54 | 2006-01-26 10:00:33 +0900 | [diff] [blame] | 642 | 		goto out; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 643 | 	} | 
| Kenji Kaneshige | ef3be54 | 2006-01-26 10:00:33 +0900 | [diff] [blame] | 644 | 	rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); | 
 | 645 | 	if (rc || !getstatus) { | 
| Kenji Kaneshige | 99ff124 | 2006-05-12 11:13:50 +0900 | [diff] [blame] | 646 | 		info("Already disabled slot(%s)\n", p_slot->name); | 
| Kenji Kaneshige | ef3be54 | 2006-01-26 10:00:33 +0900 | [diff] [blame] | 647 | 		goto out; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 648 | 	} | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 649 |  | 
| Kenji Kaneshige | ef3be54 | 2006-01-26 10:00:33 +0900 | [diff] [blame] | 650 | 	retval = remove_board(p_slot); | 
| rajesh.shah@intel.com | 2178bfa | 2005-10-13 12:05:41 -0700 | [diff] [blame] | 651 | 	update_slot_info(p_slot); | 
| Kenji Kaneshige | ef3be54 | 2006-01-26 10:00:33 +0900 | [diff] [blame] | 652 |  out: | 
 | 653 | 	mutex_unlock(&p_slot->ctrl->crit_sect); | 
 | 654 | 	return retval; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 655 | } | 
 | 656 |  | 
| Kenji Kaneshige | a246fa4 | 2006-02-21 15:45:48 -0800 | [diff] [blame] | 657 | int shpchp_sysfs_enable_slot(struct slot *p_slot) | 
 | 658 | { | 
 | 659 | 	int retval = -ENODEV; | 
 | 660 |  | 
 | 661 | 	mutex_lock(&p_slot->lock); | 
 | 662 | 	switch (p_slot->state) { | 
 | 663 | 	case BLINKINGON_STATE: | 
 | 664 | 		cancel_delayed_work(&p_slot->work); | 
 | 665 | 	case STATIC_STATE: | 
 | 666 | 		p_slot->state = POWERON_STATE; | 
 | 667 | 		mutex_unlock(&p_slot->lock); | 
 | 668 | 		retval = shpchp_enable_slot(p_slot); | 
 | 669 | 		mutex_lock(&p_slot->lock); | 
 | 670 | 		p_slot->state = STATIC_STATE; | 
 | 671 | 		break; | 
 | 672 | 	case POWERON_STATE: | 
 | 673 | 		info("Slot %s is already in powering on state\n", | 
 | 674 | 		     p_slot->name); | 
 | 675 | 		break; | 
 | 676 | 	case BLINKINGOFF_STATE: | 
 | 677 | 	case POWEROFF_STATE: | 
 | 678 | 		info("Already enabled on slot %s\n", p_slot->name); | 
 | 679 | 		break; | 
 | 680 | 	default: | 
 | 681 | 		err("Not a valid state on slot %s\n", p_slot->name); | 
 | 682 | 		break; | 
 | 683 | 	} | 
 | 684 | 	mutex_unlock(&p_slot->lock); | 
 | 685 |  | 
 | 686 | 	return retval; | 
 | 687 | } | 
 | 688 |  | 
 | 689 | int shpchp_sysfs_disable_slot(struct slot *p_slot) | 
 | 690 | { | 
 | 691 | 	int retval = -ENODEV; | 
 | 692 |  | 
 | 693 | 	mutex_lock(&p_slot->lock); | 
 | 694 | 	switch (p_slot->state) { | 
 | 695 | 	case BLINKINGOFF_STATE: | 
 | 696 | 		cancel_delayed_work(&p_slot->work); | 
 | 697 | 	case STATIC_STATE: | 
 | 698 | 		p_slot->state = POWEROFF_STATE; | 
 | 699 | 		mutex_unlock(&p_slot->lock); | 
 | 700 | 		retval = shpchp_disable_slot(p_slot); | 
 | 701 | 		mutex_lock(&p_slot->lock); | 
 | 702 | 		p_slot->state = STATIC_STATE; | 
 | 703 | 		break; | 
 | 704 | 	case POWEROFF_STATE: | 
 | 705 | 		info("Slot %s is already in powering off state\n", | 
 | 706 | 		     p_slot->name); | 
 | 707 | 		break; | 
 | 708 | 	case BLINKINGON_STATE: | 
 | 709 | 	case POWERON_STATE: | 
 | 710 | 		info("Already disabled on slot %s\n", p_slot->name); | 
 | 711 | 		break; | 
 | 712 | 	default: | 
 | 713 | 		err("Not a valid state on slot %s\n", p_slot->name); | 
 | 714 | 		break; | 
 | 715 | 	} | 
 | 716 | 	mutex_unlock(&p_slot->lock); | 
 | 717 |  | 
 | 718 | 	return retval; | 
 | 719 | } |