11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Standard Hot Plug Controller Driver
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 1995,2001 Compaq Computer Corporation
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2001 IBM Corp.
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2003-2004 Intel Corporation
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * All rights reserved.
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License as published by
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the Free Software Foundation; either version 2 of the License, or (at
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * your option) any later version.
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is distributed in the hope that it will be useful, but
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * WITHOUT ANY WARRANTY; without even the implied warranty of
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * NON INFRINGEMENT.  See the GNU General Public License for more
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * details.
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * You should have received a copy of the GNU General Public License
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * along with this program; if not, write to the Free Software
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
268cf4c19523b7694c88bba716d88fb659fa702411Kristen Accardi * Send feedback to <greg@kroah.com>, <kristen.c.accardi@intel.com>
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h>
335a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pci.h>
35dbd7a78818d125a0ebd5507d4edb4dd5900006abRajesh Shah#include "../pci.h"
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "shpchp.h"
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
38c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howellsstatic void interrupt_event_handler(struct work_struct *work);
39a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshigestatic int shpchp_enable_slot(struct slot *p_slot);
40a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshigestatic int shpchp_disable_slot(struct slot *p_slot);
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshigestatic int queue_interrupt_event(struct slot *p_slot, u32 event_type)
43f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige{
44f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige	struct event_info *info;
45f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige
46f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige	info = kmalloc(sizeof(*info), GFP_ATOMIC);
47f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige	if (!info)
48f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige		return -ENOMEM;
49f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige
50f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige	info->event_type = event_type;
51f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige	info->p_slot = p_slot;
52c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells	INIT_WORK(&info->work, interrupt_event_handler);
53f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige
54f652e7d2916fe2fcf9e7d709aa5b7476b431e2ddBjorn Helgaas	queue_work(p_slot->wq, &info->work);
55f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige
56f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige	return 0;
57f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige}
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
590abe68ce24973a23fcc6cbce80343f68656de7b6Kenji Kaneshigeu8 shpchp_handle_attention_button(u8 hp_slot, struct controller *ctrl)
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct slot *p_slot;
62f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige	u32 event_type;
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Attention Button Change */
65be7bce250a88fbbb5a67204eb148bce8b798780aTaku Izumi	ctrl_dbg(ctrl, "Attention button interrupt received\n");
669f593e30b318719b0e3889c730cc3a2d0729a707Kenji Kaneshige
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
682178bfad9ccb0cbeb79599dd1dc349dd4567aa49Rajesh Shah	p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save));
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *  Button pressed - See if need to TAKE ACTION!!!
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
73f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi	ctrl_info(ctrl, "Button pressed on Slot(%s)\n", slot_name(p_slot));
74f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige	event_type = INT_BUTTON_PRESS;
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
76f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige	queue_interrupt_event(p_slot, event_type);
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
820abe68ce24973a23fcc6cbce80343f68656de7b6Kenji Kaneshigeu8 shpchp_handle_switch_change(u8 hp_slot, struct controller *ctrl)
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct slot *p_slot;
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 getstatus;
86f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige	u32 event_type;
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Switch Change */
89be7bce250a88fbbb5a67204eb148bce8b798780aTaku Izumi	ctrl_dbg(ctrl, "Switch interrupt received\n");
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
922178bfad9ccb0cbeb79599dd1dc349dd4567aa49Rajesh Shah	p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save));
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
94be7bce250a88fbbb5a67204eb148bce8b798780aTaku Izumi	ctrl_dbg(ctrl, "Card present %x Power status %x\n",
95be7bce250a88fbbb5a67204eb148bce8b798780aTaku Izumi		 p_slot->presence_save, p_slot->pwr_save);
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (getstatus) {
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Switch opened
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
101f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi		ctrl_info(ctrl, "Latch open on Slot(%s)\n", slot_name(p_slot));
102f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige		event_type = INT_SWITCH_OPEN;
1032178bfad9ccb0cbeb79599dd1dc349dd4567aa49Rajesh Shah		if (p_slot->pwr_save && p_slot->presence_save) {
104f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige			event_type = INT_POWER_FAULT;
105f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi			ctrl_err(ctrl, "Surprise Removal of card\n");
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 *  Switch closed
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
111f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi		ctrl_info(ctrl, "Latch close on Slot(%s)\n", slot_name(p_slot));
112f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige		event_type = INT_SWITCH_CLOSE;
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
115f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige	queue_interrupt_event(p_slot, event_type);
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
117f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige	return 1;
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1200abe68ce24973a23fcc6cbce80343f68656de7b6Kenji Kaneshigeu8 shpchp_handle_presence_change(u8 hp_slot, struct controller *ctrl)
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct slot *p_slot;
123f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige	u32 event_type;
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Presence Change */
126be7bce250a88fbbb5a67204eb148bce8b798780aTaku Izumi	ctrl_dbg(ctrl, "Presence/Notify input change\n");
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1309f593e30b318719b0e3889c730cc3a2d0729a707Kenji Kaneshige	/*
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Save the presence state
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
1332178bfad9ccb0cbeb79599dd1dc349dd4567aa49Rajesh Shah	p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save));
1342178bfad9ccb0cbeb79599dd1dc349dd4567aa49Rajesh Shah	if (p_slot->presence_save) {
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Card Present
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
138f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi		ctrl_info(ctrl, "Card present on Slot(%s)\n",
139f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi			  slot_name(p_slot));
140f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige		event_type = INT_PRESENCE_ON;
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Not Present
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
145f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi		ctrl_info(ctrl, "Card not present on Slot(%s)\n",
146f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi			  slot_name(p_slot));
147f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige		event_type = INT_PRESENCE_OFF;
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
150f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige	queue_interrupt_event(p_slot, event_type);
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
152f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige	return 1;
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1550abe68ce24973a23fcc6cbce80343f68656de7b6Kenji Kaneshigeu8 shpchp_handle_power_fault(u8 hp_slot, struct controller *ctrl)
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct slot *p_slot;
158f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige	u32 event_type;
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Power fault */
161be7bce250a88fbbb5a67204eb148bce8b798780aTaku Izumi	ctrl_dbg(ctrl, "Power fault interrupt received\n");
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1653c78bc61f5ef3bc87e7f94f67ec737d2273f120bRyan Desfosses	if (!(p_slot->hpc_ops->query_power_fault(p_slot))) {
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Power fault Cleared
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
169f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi		ctrl_info(ctrl, "Power fault cleared on Slot(%s)\n",
170f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi			  slot_name(p_slot));
1712178bfad9ccb0cbeb79599dd1dc349dd4567aa49Rajesh Shah		p_slot->status = 0x00;
172f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige		event_type = INT_POWER_FAULT_CLEAR;
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 *   Power fault
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
177f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi		ctrl_info(ctrl, "Power fault on Slot(%s)\n", slot_name(p_slot));
178f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige		event_type = INT_POWER_FAULT;
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* set power fault status for this board */
1802178bfad9ccb0cbeb79599dd1dc349dd4567aa49Rajesh Shah		p_slot->status = 0xFF;
181be7bce250a88fbbb5a67204eb148bce8b798780aTaku Izumi		ctrl_info(ctrl, "Power fault bit %x set\n", hp_slot);
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
184f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige	queue_interrupt_event(p_slot, event_type);
185f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige
186f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige	return 1;
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1899f593e30b318719b0e3889c730cc3a2d0729a707Kenji Kaneshige/* The following routines constitute the bulk of the
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   hotplug controller logic
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
192ee138334d5eb5ca662b2d69228420c1ccc051e0eRajesh Shahstatic int change_bus_speed(struct controller *ctrl, struct slot *p_slot,
193ee138334d5eb5ca662b2d69228420c1ccc051e0eRajesh Shah		enum pci_bus_speed speed)
1949f593e30b318719b0e3889c730cc3a2d0729a707Kenji Kaneshige{
195ee138334d5eb5ca662b2d69228420c1ccc051e0eRajesh Shah	int rc = 0;
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
197be7bce250a88fbbb5a67204eb148bce8b798780aTaku Izumi	ctrl_dbg(ctrl, "Change speed to %d\n", speed);
19879e50e72986c9fcb06d707ce587cfd24fefa33e3Quentin Lambert	rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, speed);
19979e50e72986c9fcb06d707ce587cfd24fefa33e3Quentin Lambert	if (rc) {
200227f06470502c4fea3d93df1f12a77e3e37f6263Ryan Desfosses		ctrl_err(ctrl, "%s: Issue of set bus speed mode command failed\n",
201227f06470502c4fea3d93df1f12a77e3e37f6263Ryan Desfosses			 __func__);
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return WRONG_BUS_FREQUENCY;
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return rc;
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
207ee138334d5eb5ca662b2d69228420c1ccc051e0eRajesh Shahstatic int fix_bus_speed(struct controller *ctrl, struct slot *pslot,
208ee138334d5eb5ca662b2d69228420c1ccc051e0eRajesh Shah		u8 flag, enum pci_bus_speed asp, enum pci_bus_speed bsp,
209ee138334d5eb5ca662b2d69228420c1ccc051e0eRajesh Shah		enum pci_bus_speed msp)
2109f593e30b318719b0e3889c730cc3a2d0729a707Kenji Kaneshige{
211ee138334d5eb5ca662b2d69228420c1ccc051e0eRajesh Shah	int rc = 0;
2120afabe906539b4e8b9e895f19ea31aabdf12f30bKenji Kaneshige
2130afabe906539b4e8b9e895f19ea31aabdf12f30bKenji Kaneshige	/*
2140afabe906539b4e8b9e895f19ea31aabdf12f30bKenji Kaneshige	 * If other slots on the same bus are occupied, we cannot
2150afabe906539b4e8b9e895f19ea31aabdf12f30bKenji Kaneshige	 * change the bus speed.
2160afabe906539b4e8b9e895f19ea31aabdf12f30bKenji Kaneshige	 */
2170afabe906539b4e8b9e895f19ea31aabdf12f30bKenji Kaneshige	if (flag) {
2180afabe906539b4e8b9e895f19ea31aabdf12f30bKenji Kaneshige		if (asp < bsp) {
219227f06470502c4fea3d93df1f12a77e3e37f6263Ryan Desfosses			ctrl_err(ctrl, "Speed of bus %x and adapter %x mismatch\n",
220227f06470502c4fea3d93df1f12a77e3e37f6263Ryan Desfosses				 bsp, asp);
2210afabe906539b4e8b9e895f19ea31aabdf12f30bKenji Kaneshige			rc = WRONG_BUS_FREQUENCY;
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2230afabe906539b4e8b9e895f19ea31aabdf12f30bKenji Kaneshige		return rc;
2240afabe906539b4e8b9e895f19ea31aabdf12f30bKenji Kaneshige	}
2250afabe906539b4e8b9e895f19ea31aabdf12f30bKenji Kaneshige
2260afabe906539b4e8b9e895f19ea31aabdf12f30bKenji Kaneshige	if (asp < msp) {
2270afabe906539b4e8b9e895f19ea31aabdf12f30bKenji Kaneshige		if (bsp != asp)
2280afabe906539b4e8b9e895f19ea31aabdf12f30bKenji Kaneshige			rc = change_bus_speed(ctrl, pslot, asp);
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
2300afabe906539b4e8b9e895f19ea31aabdf12f30bKenji Kaneshige		if (bsp != msp)
2310afabe906539b4e8b9e895f19ea31aabdf12f30bKenji Kaneshige			rc = change_bus_speed(ctrl, pslot, msp);
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return rc;
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * board_added - Called after a board has been added to the system.
23826e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * @p_slot: target &slot
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
24026e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * Turns power on for the board.
24126e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * Configures board.
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
243ee138334d5eb5ca662b2d69228420c1ccc051e0eRajesh Shahstatic int board_added(struct slot *p_slot)
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 hp_slot;
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 slots_not_empty = 0;
247ee138334d5eb5ca662b2d69228420c1ccc051e0eRajesh Shah	int rc = 0;
2480afabe906539b4e8b9e895f19ea31aabdf12f30bKenji Kaneshige	enum pci_bus_speed asp, bsp, msp;
2492178bfad9ccb0cbeb79599dd1dc349dd4567aa49Rajesh Shah	struct controller *ctrl = p_slot->ctrl;
250be7bce250a88fbbb5a67204eb148bce8b798780aTaku Izumi	struct pci_bus *parent = ctrl->pci_dev->subordinate;
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2522178bfad9ccb0cbeb79599dd1dc349dd4567aa49Rajesh Shah	hp_slot = p_slot->device - ctrl->slot_device_offset;
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
254227f06470502c4fea3d93df1f12a77e3e37f6263Ryan Desfosses	ctrl_dbg(ctrl, "%s: p_slot->device, slot_offset, hp_slot = %d, %d ,%d\n",
255f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi		 __func__, p_slot->device, ctrl->slot_device_offset, hp_slot);
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Power on slot without connecting to bus */
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc = p_slot->hpc_ops->power_on_slot(p_slot);
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rc) {
260be7bce250a88fbbb5a67204eb148bce8b798780aTaku Izumi		ctrl_err(ctrl, "Failed to power on slot\n");
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1;
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2639f593e30b318719b0e3889c730cc3a2d0729a707Kenji Kaneshige
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((ctrl->pci_dev->vendor == 0x8086) && (ctrl->pci_dev->device == 0x0332)) {
26579e50e72986c9fcb06d707ce587cfd24fefa33e3Quentin Lambert		rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, PCI_SPEED_33MHz);
26679e50e72986c9fcb06d707ce587cfd24fefa33e3Quentin Lambert		if (rc) {
267227f06470502c4fea3d93df1f12a77e3e37f6263Ryan Desfosses			ctrl_err(ctrl, "%s: Issue of set bus speed mode command failed\n",
268227f06470502c4fea3d93df1f12a77e3e37f6263Ryan Desfosses				 __func__);
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return WRONG_BUS_FREQUENCY;
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2719f593e30b318719b0e3889c730cc3a2d0729a707Kenji Kaneshige
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* turn on board, blink green LED, turn off Amber LED */
27379e50e72986c9fcb06d707ce587cfd24fefa33e3Quentin Lambert		rc = p_slot->hpc_ops->slot_enable(p_slot);
27479e50e72986c9fcb06d707ce587cfd24fefa33e3Quentin Lambert		if (rc) {
275be7bce250a88fbbb5a67204eb148bce8b798780aTaku Izumi			ctrl_err(ctrl, "Issue of Slot Enable command failed\n");
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return rc;
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2799f593e30b318719b0e3889c730cc3a2d0729a707Kenji Kaneshige
2800afabe906539b4e8b9e895f19ea31aabdf12f30bKenji Kaneshige	rc = p_slot->hpc_ops->get_adapter_speed(p_slot, &asp);
2810afabe906539b4e8b9e895f19ea31aabdf12f30bKenji Kaneshige	if (rc) {
282227f06470502c4fea3d93df1f12a77e3e37f6263Ryan Desfosses		ctrl_err(ctrl, "Can't get adapter speed or bus mode mismatch\n");
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return WRONG_BUS_FREQUENCY;
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28693fa9d32670f5592c8e56abc9928fc194e1e72fcMarcel Apfelbaum	bsp = ctrl->pci_dev->subordinate->cur_bus_speed;
28793fa9d32670f5592c8e56abc9928fc194e1e72fcMarcel Apfelbaum	msp = ctrl->pci_dev->subordinate->max_bus_speed;
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Check if there are other slots or devices on the same bus */
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!list_empty(&ctrl->pci_dev->subordinate->devices))
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		slots_not_empty = 1;
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
293227f06470502c4fea3d93df1f12a77e3e37f6263Ryan Desfosses	ctrl_dbg(ctrl, "%s: slots_not_empty %d, adapter_speed %d, bus_speed %d, max_bus_speed %d\n",
294227f06470502c4fea3d93df1f12a77e3e37f6263Ryan Desfosses		 __func__, slots_not_empty, asp,
295f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi		 bsp, msp);
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2970afabe906539b4e8b9e895f19ea31aabdf12f30bKenji Kaneshige	rc = fix_bus_speed(ctrl, p_slot, slots_not_empty, asp, bsp, msp);
2980afabe906539b4e8b9e895f19ea31aabdf12f30bKenji Kaneshige	if (rc)
2990afabe906539b4e8b9e895f19ea31aabdf12f30bKenji Kaneshige		return rc;
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* turn on board, blink green LED, turn off Amber LED */
30279e50e72986c9fcb06d707ce587cfd24fefa33e3Quentin Lambert	rc = p_slot->hpc_ops->slot_enable(p_slot);
30379e50e72986c9fcb06d707ce587cfd24fefa33e3Quentin Lambert	if (rc) {
304be7bce250a88fbbb5a67204eb148bce8b798780aTaku Izumi		ctrl_err(ctrl, "Issue of Slot Enable command failed\n");
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return rc;
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Wait for ~1 second */
30968c0b671491088d79611fa965bbf94b3bc0024a4Kenji Kaneshige	msleep(1000);
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
311f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi	ctrl_dbg(ctrl, "%s: slot status = %x\n", __func__, p_slot->status);
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Check for a power fault */
3132178bfad9ccb0cbeb79599dd1dc349dd4567aa49Rajesh Shah	if (p_slot->status == 0xFF) {
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* power fault occurred, but it was benign */
315be7bce250a88fbbb5a67204eb148bce8b798780aTaku Izumi		ctrl_dbg(ctrl, "%s: Power fault\n", __func__);
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rc = POWER_FAILURE;
3172178bfad9ccb0cbeb79599dd1dc349dd4567aa49Rajesh Shah		p_slot->status = 0;
318dbd7a78818d125a0ebd5507d4edb4dd5900006abRajesh Shah		goto err_exit;
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
321dbd7a78818d125a0ebd5507d4edb4dd5900006abRajesh Shah	if (shpchp_configure_device(p_slot)) {
322be7bce250a88fbbb5a67204eb148bce8b798780aTaku Izumi		ctrl_err(ctrl, "Cannot add device at %04x:%02x:%02x\n",
323be7bce250a88fbbb5a67204eb148bce8b798780aTaku Izumi			 pci_domain_nr(parent), p_slot->bus, p_slot->device);
324dbd7a78818d125a0ebd5507d4edb4dd5900006abRajesh Shah		goto err_exit;
325dbd7a78818d125a0ebd5507d4edb4dd5900006abRajesh Shah	}
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3272178bfad9ccb0cbeb79599dd1dc349dd4567aa49Rajesh Shah	p_slot->status = 0;
3282178bfad9ccb0cbeb79599dd1dc349dd4567aa49Rajesh Shah	p_slot->is_a_board = 0x01;
3292178bfad9ccb0cbeb79599dd1dc349dd4567aa49Rajesh Shah	p_slot->pwr_save = 1;
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
331dbd7a78818d125a0ebd5507d4edb4dd5900006abRajesh Shah	p_slot->hpc_ops->green_led_on(p_slot);
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
333dbd7a78818d125a0ebd5507d4edb4dd5900006abRajesh Shah	return 0;
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
335dbd7a78818d125a0ebd5507d4edb4dd5900006abRajesh Shaherr_exit:
336dbd7a78818d125a0ebd5507d4edb4dd5900006abRajesh Shah	/* turn off slot, turn on Amber LED, turn off Green LED */
337dbd7a78818d125a0ebd5507d4edb4dd5900006abRajesh Shah	rc = p_slot->hpc_ops->slot_disable(p_slot);
338dbd7a78818d125a0ebd5507d4edb4dd5900006abRajesh Shah	if (rc) {
339f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi		ctrl_err(ctrl, "%s: Issue of Slot Disable command failed\n",
340f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi			 __func__);
341dbd7a78818d125a0ebd5507d4edb4dd5900006abRajesh Shah		return rc;
342dbd7a78818d125a0ebd5507d4edb4dd5900006abRajesh Shah	}
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
344dbd7a78818d125a0ebd5507d4edb4dd5900006abRajesh Shah	return(rc);
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
34926e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * remove_board - Turns off slot and LEDs
35026e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * @p_slot: target &slot
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
352ee138334d5eb5ca662b2d69228420c1ccc051e0eRajesh Shahstatic int remove_board(struct slot *p_slot)
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3542178bfad9ccb0cbeb79599dd1dc349dd4567aa49Rajesh Shah	struct controller *ctrl = p_slot->ctrl;
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 hp_slot;
356ee138334d5eb5ca662b2d69228420c1ccc051e0eRajesh Shah	int rc;
35770b6091946ab486c4dab8abeb4a3fc2bf7d3e7feRajesh Shah
3582178bfad9ccb0cbeb79599dd1dc349dd4567aa49Rajesh Shah	if (shpchp_unconfigure_device(p_slot))
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return(1);
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3612178bfad9ccb0cbeb79599dd1dc349dd4567aa49Rajesh Shah	hp_slot = p_slot->device - ctrl->slot_device_offset;
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
364be7bce250a88fbbb5a67204eb148bce8b798780aTaku Izumi	ctrl_dbg(ctrl, "%s: hp_slot = %d\n", __func__, hp_slot);
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Change status to shutdown */
3672178bfad9ccb0cbeb79599dd1dc349dd4567aa49Rajesh Shah	if (p_slot->is_a_board)
3682178bfad9ccb0cbeb79599dd1dc349dd4567aa49Rajesh Shah		p_slot->status = 0x01;
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* turn off slot, turn on Amber LED, turn off Green LED */
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc = p_slot->hpc_ops->slot_disable(p_slot);
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rc) {
373f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi		ctrl_err(ctrl, "%s: Issue of Slot Disable command failed\n",
374f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi			 __func__);
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return rc;
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3779f593e30b318719b0e3889c730cc3a2d0729a707Kenji Kaneshige
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc = p_slot->hpc_ops->set_attention_status(p_slot, 0);
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rc) {
380be7bce250a88fbbb5a67204eb148bce8b798780aTaku Izumi		ctrl_err(ctrl, "Issue of Set Attention command failed\n");
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return rc;
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3842178bfad9ccb0cbeb79599dd1dc349dd4567aa49Rajesh Shah	p_slot->pwr_save = 0;
3852178bfad9ccb0cbeb79599dd1dc349dd4567aa49Rajesh Shah	p_slot->is_a_board = 0;
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
391a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshigestruct pushbutton_work_info {
392a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	struct slot *p_slot;
393a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	struct work_struct work;
394a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige};
395a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
39726e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * shpchp_pushbutton_thread - handle pushbutton events
39826e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * @work: &struct work_struct to be handled
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
40026e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * Scheduled procedure to handle blocking stuff for the pushbuttons.
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Handles all pending events and exits.
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
403c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howellsstatic void shpchp_pushbutton_thread(struct work_struct *work)
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
405c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells	struct pushbutton_work_info *info =
406c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells		container_of(work, struct pushbutton_work_info, work);
407a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	struct slot *p_slot = info->p_slot;
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
409a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	mutex_lock(&p_slot->lock);
410a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	switch (p_slot->state) {
411a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	case POWEROFF_STATE:
412a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		mutex_unlock(&p_slot->lock);
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		shpchp_disable_slot(p_slot);
414a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		mutex_lock(&p_slot->lock);
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		p_slot->state = STATIC_STATE;
416a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		break;
417a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	case POWERON_STATE:
418a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		mutex_unlock(&p_slot->lock);
419d29aaddab3ef3bdaecf3c9c6d9423f0bf0452ccfKenji Kaneshige		if (shpchp_enable_slot(p_slot))
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			p_slot->hpc_ops->green_led_off(p_slot);
421a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		mutex_lock(&p_slot->lock);
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		p_slot->state = STATIC_STATE;
423a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		break;
424a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	default:
425a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		break;
426a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	}
427a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	mutex_unlock(&p_slot->lock);
428a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige
429a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	kfree(info);
430a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige}
431a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige
432e325e1f0783382298141c74737712637943c6063Kristen Carlson Accardivoid shpchp_queue_pushbutton_work(struct work_struct *work)
433a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige{
434c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells	struct slot *p_slot = container_of(work, struct slot, work.work);
435a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	struct pushbutton_work_info *info;
436a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige
437a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	info = kmalloc(sizeof(*info), GFP_KERNEL);
438a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	if (!info) {
439f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi		ctrl_err(p_slot->ctrl, "%s: Cannot allocate memory\n",
440f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi			 __func__);
441a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		return;
442a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	}
443a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	info->p_slot = p_slot;
444c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells	INIT_WORK(&info->work, shpchp_pushbutton_thread);
445a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige
446a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	mutex_lock(&p_slot->lock);
447a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	switch (p_slot->state) {
448a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	case BLINKINGOFF_STATE:
449a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		p_slot->state = POWEROFF_STATE;
450a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		break;
451a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	case BLINKINGON_STATE:
452a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		p_slot->state = POWERON_STATE;
453a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		break;
454a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	default:
4556fcaf17ac7a512227112ac81c0e1a5862bab57a6Jiri Slaby		kfree(info);
456a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		goto out;
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
458f652e7d2916fe2fcf9e7d709aa5b7476b431e2ddBjorn Helgaas	queue_work(p_slot->wq, &info->work);
459a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige out:
460a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	mutex_unlock(&p_slot->lock);
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int update_slot_info (struct slot *slot)
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct hotplug_slot_info *info;
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result;
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info = kmalloc(sizeof(*info), GFP_KERNEL);
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!info)
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	slot->hpc_ops->get_power_status(slot, &(info->power_status));
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	slot->hpc_ops->get_attention_status(slot, &(info->attention_status));
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	slot->hpc_ops->get_latch_status(slot, &(info->latch_status));
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	slot->hpc_ops->get_adapter_status(slot, &(info->adapter_status));
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = pci_hp_change_slot_info(slot->hotplug_slot, info);
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree (info);
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return result;
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
482a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige/*
483a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige * Note: This function must be called with slot->lock held
484a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige */
485a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshigestatic void handle_button_press_event(struct slot *p_slot)
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 getstatus;
488f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi	struct controller *ctrl = p_slot->ctrl;
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
490a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	switch (p_slot->state) {
491a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	case STATIC_STATE:
492f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige		p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
493f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige		if (getstatus) {
494f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige			p_slot->state = BLINKINGOFF_STATE;
495227f06470502c4fea3d93df1f12a77e3e37f6263Ryan Desfosses			ctrl_info(ctrl, "PCI slot #%s - powering off due to button press\n",
496227f06470502c4fea3d93df1f12a77e3e37f6263Ryan Desfosses				  slot_name(p_slot));
497f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige		} else {
498f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige			p_slot->state = BLINKINGON_STATE;
499227f06470502c4fea3d93df1f12a77e3e37f6263Ryan Desfosses			ctrl_info(ctrl, "PCI slot #%s - powering on due to button press\n",
500227f06470502c4fea3d93df1f12a77e3e37f6263Ryan Desfosses				  slot_name(p_slot));
501f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige		}
502f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige		/* blink green LED and turn off amber */
503f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige		p_slot->hpc_ops->green_led_blink(p_slot);
504f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige		p_slot->hpc_ops->set_attention_status(p_slot, 0);
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
506f652e7d2916fe2fcf9e7d709aa5b7476b431e2ddBjorn Helgaas		queue_delayed_work(p_slot->wq, &p_slot->work, 5*HZ);
507a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		break;
508a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	case BLINKINGOFF_STATE:
509a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	case BLINKINGON_STATE:
510a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		/*
511a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		 * Cancel if we are still blinking; this means that we
512a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		 * press the attention again before the 5 sec. limit
513a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		 * expires to cancel hot-add or hot-remove
514a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		 */
515f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi		ctrl_info(ctrl, "Button cancel on Slot(%s)\n",
516f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi			  slot_name(p_slot));
517a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		cancel_delayed_work(&p_slot->work);
518a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		if (p_slot->state == BLINKINGOFF_STATE)
519a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige			p_slot->hpc_ops->green_led_on(p_slot);
520a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		else
521a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige			p_slot->hpc_ops->green_led_off(p_slot);
522a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		p_slot->hpc_ops->set_attention_status(p_slot, 0);
523227f06470502c4fea3d93df1f12a77e3e37f6263Ryan Desfosses		ctrl_info(ctrl, "PCI slot #%s - action canceled due to button press\n",
524227f06470502c4fea3d93df1f12a77e3e37f6263Ryan Desfosses			  slot_name(p_slot));
525a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		p_slot->state = STATIC_STATE;
526a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		break;
527a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	case POWEROFF_STATE:
528a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	case POWERON_STATE:
529a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		/*
530a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		 * Ignore if the slot is on power-on or power-off state;
531a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		 * this means that the previous attention button action
532a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		 * to hot-add or hot-remove is undergoing
533a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		 */
534f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi		ctrl_info(ctrl, "Button ignore on Slot(%s)\n",
535f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi			  slot_name(p_slot));
536a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		update_slot_info(p_slot);
537a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		break;
538a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	default:
539f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi		ctrl_warn(ctrl, "Not a valid state\n");
540a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		break;
541a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	}
542a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige}
543a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige
544c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howellsstatic void interrupt_event_handler(struct work_struct *work)
545a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige{
546c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells	struct event_info *info = container_of(work, struct event_info, work);
547a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	struct slot *p_slot = info->p_slot;
548a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige
549a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	mutex_lock(&p_slot->lock);
550a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	switch (info->event_type) {
551a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	case INT_BUTTON_PRESS:
552a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		handle_button_press_event(p_slot);
553f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige		break;
554f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige	case INT_POWER_FAULT:
555be7bce250a88fbbb5a67204eb148bce8b798780aTaku Izumi		ctrl_dbg(p_slot->ctrl, "%s: Power fault\n", __func__);
556f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige		p_slot->hpc_ops->set_attention_status(p_slot, 1);
557f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige		p_slot->hpc_ops->green_led_off(p_slot);
558f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige		break;
559f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige	default:
560f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige		update_slot_info(p_slot);
561f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige		break;
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
563a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	mutex_unlock(&p_slot->lock);
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
565f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige	kfree(info);
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
569a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshigestatic int shpchp_enable_slot (struct slot *p_slot)
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 getstatus = 0;
572ef3be54777901e570185089f21fbe4498453f67eKenji Kaneshige	int rc, retval = -ENODEV;
573f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi	struct controller *ctrl = p_slot->ctrl;
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Check to see if (latch closed, card present, power off) */
5766aa4cdd07139ba4d5b89139b0070d795cc4dea88Ingo Molnar	mutex_lock(&p_slot->ctrl->crit_sect);
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rc || !getstatus) {
579f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi		ctrl_info(ctrl, "No adapter on slot(%s)\n", slot_name(p_slot));
580ef3be54777901e570185089f21fbe4498453f67eKenji Kaneshige		goto out;
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rc || getstatus) {
584f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi		ctrl_info(ctrl, "Latch open on slot(%s)\n", slot_name(p_slot));
585ef3be54777901e570185089f21fbe4498453f67eKenji Kaneshige		goto out;
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rc || getstatus) {
589f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi		ctrl_info(ctrl, "Already enabled on slot(%s)\n",
590f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi			  slot_name(p_slot));
591ef3be54777901e570185089f21fbe4498453f67eKenji Kaneshige		goto out;
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5942178bfad9ccb0cbeb79599dd1dc349dd4567aa49Rajesh Shah	p_slot->is_a_board = 1;
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* We have to save the presence info for these slots */
5972178bfad9ccb0cbeb79599dd1dc349dd4567aa49Rajesh Shah	p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save));
5982178bfad9ccb0cbeb79599dd1dc349dd4567aa49Rajesh Shah	p_slot->hpc_ops->get_power_status(p_slot, &(p_slot->pwr_save));
599f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi	ctrl_dbg(ctrl, "%s: p_slot->pwr_save %x\n", __func__, p_slot->pwr_save);
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
602382a9c9adc1cd540f5b714b65db315fc1c0b553dQuentin Lambert	if (((p_slot->ctrl->pci_dev->vendor == PCI_VENDOR_ID_AMD) ||
60353044f357448693f218cc4f053affe92ed414f9dKeck, David	    (p_slot->ctrl->pci_dev->device == PCI_DEVICE_ID_AMD_POGO_7458))
60453044f357448693f218cc4f053affe92ed414f9dKeck, David	     && p_slot->ctrl->num_slots == 1) {
60553044f357448693f218cc4f053affe92ed414f9dKeck, David		/* handle amd pogo errata; this must be done before enable  */
60653044f357448693f218cc4f053affe92ed414f9dKeck, David		amd_pogo_errata_save_misc_reg(p_slot);
607ef3be54777901e570185089f21fbe4498453f67eKenji Kaneshige		retval = board_added(p_slot);
60853044f357448693f218cc4f053affe92ed414f9dKeck, David		/* handle amd pogo errata; this must be done after enable  */
60953044f357448693f218cc4f053affe92ed414f9dKeck, David		amd_pogo_errata_restore_misc_reg(p_slot);
61053044f357448693f218cc4f053affe92ed414f9dKeck, David	} else
611ef3be54777901e570185089f21fbe4498453f67eKenji Kaneshige		retval = board_added(p_slot);
61253044f357448693f218cc4f053affe92ed414f9dKeck, David
613ef3be54777901e570185089f21fbe4498453f67eKenji Kaneshige	if (retval) {
6142178bfad9ccb0cbeb79599dd1dc349dd4567aa49Rajesh Shah		p_slot->hpc_ops->get_adapter_status(p_slot,
6152178bfad9ccb0cbeb79599dd1dc349dd4567aa49Rajesh Shah				&(p_slot->presence_save));
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6192178bfad9ccb0cbeb79599dd1dc349dd4567aa49Rajesh Shah	update_slot_info(p_slot);
620ef3be54777901e570185089f21fbe4498453f67eKenji Kaneshige out:
621ef3be54777901e570185089f21fbe4498453f67eKenji Kaneshige	mutex_unlock(&p_slot->ctrl->crit_sect);
622ef3be54777901e570185089f21fbe4498453f67eKenji Kaneshige	return retval;
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
626a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshigestatic int shpchp_disable_slot (struct slot *p_slot)
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 getstatus = 0;
629ef3be54777901e570185089f21fbe4498453f67eKenji Kaneshige	int rc, retval = -ENODEV;
630f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi	struct controller *ctrl = p_slot->ctrl;
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!p_slot->ctrl)
633ee17fd93a5892c162b0a02d58cdfdb9c50cf8467Dely Sy		return -ENODEV;
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Check to see if (latch closed, card present, power on) */
6366aa4cdd07139ba4d5b89139b0070d795cc4dea88Ingo Molnar	mutex_lock(&p_slot->ctrl->crit_sect);
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
638ef3be54777901e570185089f21fbe4498453f67eKenji Kaneshige	rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
639ef3be54777901e570185089f21fbe4498453f67eKenji Kaneshige	if (rc || !getstatus) {
640f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi		ctrl_info(ctrl, "No adapter on slot(%s)\n", slot_name(p_slot));
641ef3be54777901e570185089f21fbe4498453f67eKenji Kaneshige		goto out;
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
643ef3be54777901e570185089f21fbe4498453f67eKenji Kaneshige	rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
644ef3be54777901e570185089f21fbe4498453f67eKenji Kaneshige	if (rc || getstatus) {
645f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi		ctrl_info(ctrl, "Latch open on slot(%s)\n", slot_name(p_slot));
646ef3be54777901e570185089f21fbe4498453f67eKenji Kaneshige		goto out;
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
648ef3be54777901e570185089f21fbe4498453f67eKenji Kaneshige	rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
649ef3be54777901e570185089f21fbe4498453f67eKenji Kaneshige	if (rc || !getstatus) {
650be7bce250a88fbbb5a67204eb148bce8b798780aTaku Izumi		ctrl_info(ctrl, "Already disabled on slot(%s)\n",
651f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi			  slot_name(p_slot));
652ef3be54777901e570185089f21fbe4498453f67eKenji Kaneshige		goto out;
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
655ef3be54777901e570185089f21fbe4498453f67eKenji Kaneshige	retval = remove_board(p_slot);
6562178bfad9ccb0cbeb79599dd1dc349dd4567aa49Rajesh Shah	update_slot_info(p_slot);
657ef3be54777901e570185089f21fbe4498453f67eKenji Kaneshige out:
658ef3be54777901e570185089f21fbe4498453f67eKenji Kaneshige	mutex_unlock(&p_slot->ctrl->crit_sect);
659ef3be54777901e570185089f21fbe4498453f67eKenji Kaneshige	return retval;
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
662a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshigeint shpchp_sysfs_enable_slot(struct slot *p_slot)
663a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige{
664a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	int retval = -ENODEV;
665f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi	struct controller *ctrl = p_slot->ctrl;
666a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige
667a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	mutex_lock(&p_slot->lock);
668a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	switch (p_slot->state) {
669a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	case BLINKINGON_STATE:
670a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		cancel_delayed_work(&p_slot->work);
671a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	case STATIC_STATE:
672a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		p_slot->state = POWERON_STATE;
673a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		mutex_unlock(&p_slot->lock);
674a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		retval = shpchp_enable_slot(p_slot);
675a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		mutex_lock(&p_slot->lock);
676a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		p_slot->state = STATIC_STATE;
677a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		break;
678a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	case POWERON_STATE:
679f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi		ctrl_info(ctrl, "Slot %s is already in powering on state\n",
680f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi			  slot_name(p_slot));
681a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		break;
682a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	case BLINKINGOFF_STATE:
683a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	case POWEROFF_STATE:
684f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi		ctrl_info(ctrl, "Already enabled on slot %s\n",
685f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi			  slot_name(p_slot));
686a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		break;
687a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	default:
688f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi		ctrl_err(ctrl, "Not a valid state on slot %s\n",
689f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi			 slot_name(p_slot));
690a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		break;
691a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	}
692a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	mutex_unlock(&p_slot->lock);
693a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige
694a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	return retval;
695a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige}
696a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige
697a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshigeint shpchp_sysfs_disable_slot(struct slot *p_slot)
698a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige{
699a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	int retval = -ENODEV;
700f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi	struct controller *ctrl = p_slot->ctrl;
701a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige
702a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	mutex_lock(&p_slot->lock);
703a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	switch (p_slot->state) {
704a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	case BLINKINGOFF_STATE:
705a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		cancel_delayed_work(&p_slot->work);
706a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	case STATIC_STATE:
707a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		p_slot->state = POWEROFF_STATE;
708a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		mutex_unlock(&p_slot->lock);
709a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		retval = shpchp_disable_slot(p_slot);
710a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		mutex_lock(&p_slot->lock);
711a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		p_slot->state = STATIC_STATE;
712a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		break;
713a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	case POWEROFF_STATE:
714f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi		ctrl_info(ctrl, "Slot %s is already in powering off state\n",
715f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi			  slot_name(p_slot));
716a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		break;
717a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	case BLINKINGON_STATE:
718a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	case POWERON_STATE:
719f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi		ctrl_info(ctrl, "Already disabled on slot %s\n",
720f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi			  slot_name(p_slot));
721a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		break;
722a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	default:
723f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi		ctrl_err(ctrl, "Not a valid state on slot %s\n",
724f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi			 slot_name(p_slot));
725a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		break;
726a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	}
727a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	mutex_unlock(&p_slot->lock);
728a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige
729a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	return retval;
730a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige}
731