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
54e24dcbef93dbbf529fbedfc6ce8ab22d2cef35f0Tejun Heo	queue_work(shpchp_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
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	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);
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, speed))) {
199f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi		ctrl_err(ctrl, "%s: Issue of set bus speed mode command "
200f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi			 "failed\n", __func__);
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return WRONG_BUS_FREQUENCY;
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return rc;
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
206ee138334d5eb5ca662b2d69228420c1ccc051e0eRajesh Shahstatic int fix_bus_speed(struct controller *ctrl, struct slot *pslot,
207ee138334d5eb5ca662b2d69228420c1ccc051e0eRajesh Shah		u8 flag, enum pci_bus_speed asp, enum pci_bus_speed bsp,
208ee138334d5eb5ca662b2d69228420c1ccc051e0eRajesh Shah		enum pci_bus_speed msp)
2099f593e30b318719b0e3889c730cc3a2d0729a707Kenji Kaneshige{
210ee138334d5eb5ca662b2d69228420c1ccc051e0eRajesh Shah	int rc = 0;
2110afabe906539b4e8b9e895f19ea31aabdf12f30bKenji Kaneshige
2120afabe906539b4e8b9e895f19ea31aabdf12f30bKenji Kaneshige	/*
2130afabe906539b4e8b9e895f19ea31aabdf12f30bKenji Kaneshige	 * If other slots on the same bus are occupied, we cannot
2140afabe906539b4e8b9e895f19ea31aabdf12f30bKenji Kaneshige	 * change the bus speed.
2150afabe906539b4e8b9e895f19ea31aabdf12f30bKenji Kaneshige	 */
2160afabe906539b4e8b9e895f19ea31aabdf12f30bKenji Kaneshige	if (flag) {
2170afabe906539b4e8b9e895f19ea31aabdf12f30bKenji Kaneshige		if (asp < bsp) {
218be7bce250a88fbbb5a67204eb148bce8b798780aTaku Izumi			ctrl_err(ctrl, "Speed of bus %x and adapter %x "
219be7bce250a88fbbb5a67204eb148bce8b798780aTaku Izumi				 "mismatch\n", bsp, asp);
2200afabe906539b4e8b9e895f19ea31aabdf12f30bKenji Kaneshige			rc = WRONG_BUS_FREQUENCY;
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2220afabe906539b4e8b9e895f19ea31aabdf12f30bKenji Kaneshige		return rc;
2230afabe906539b4e8b9e895f19ea31aabdf12f30bKenji Kaneshige	}
2240afabe906539b4e8b9e895f19ea31aabdf12f30bKenji Kaneshige
2250afabe906539b4e8b9e895f19ea31aabdf12f30bKenji Kaneshige	if (asp < msp) {
2260afabe906539b4e8b9e895f19ea31aabdf12f30bKenji Kaneshige		if (bsp != asp)
2270afabe906539b4e8b9e895f19ea31aabdf12f30bKenji Kaneshige			rc = change_bus_speed(ctrl, pslot, asp);
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
2290afabe906539b4e8b9e895f19ea31aabdf12f30bKenji Kaneshige		if (bsp != msp)
2300afabe906539b4e8b9e895f19ea31aabdf12f30bKenji Kaneshige			rc = change_bus_speed(ctrl, pslot, msp);
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return rc;
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * board_added - Called after a board has been added to the system.
23726e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * @p_slot: target &slot
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
23926e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * Turns power on for the board.
24026e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * Configures board.
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
242ee138334d5eb5ca662b2d69228420c1ccc051e0eRajesh Shahstatic int board_added(struct slot *p_slot)
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 hp_slot;
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 slots_not_empty = 0;
246ee138334d5eb5ca662b2d69228420c1ccc051e0eRajesh Shah	int rc = 0;
2470afabe906539b4e8b9e895f19ea31aabdf12f30bKenji Kaneshige	enum pci_bus_speed asp, bsp, msp;
2482178bfad9ccb0cbeb79599dd1dc349dd4567aa49Rajesh Shah	struct controller *ctrl = p_slot->ctrl;
249be7bce250a88fbbb5a67204eb148bce8b798780aTaku Izumi	struct pci_bus *parent = ctrl->pci_dev->subordinate;
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2512178bfad9ccb0cbeb79599dd1dc349dd4567aa49Rajesh Shah	hp_slot = p_slot->device - ctrl->slot_device_offset;
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
253f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi	ctrl_dbg(ctrl,
254f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi		 "%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)) {
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (slots_not_empty)
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return WRONG_BUS_FREQUENCY;
2679f593e30b318719b0e3889c730cc3a2d0729a707Kenji Kaneshige
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, PCI_SPEED_33MHz))) {
269f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi			ctrl_err(ctrl, "%s: Issue of set bus speed mode command"
270f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi				 " failed\n", __func__);
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return WRONG_BUS_FREQUENCY;
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2739f593e30b318719b0e3889c730cc3a2d0729a707Kenji Kaneshige
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* turn on board, blink green LED, turn off Amber LED */
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((rc = p_slot->hpc_ops->slot_enable(p_slot))) {
276be7bce250a88fbbb5a67204eb148bce8b798780aTaku Izumi			ctrl_err(ctrl, "Issue of Slot Enable command failed\n");
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return rc;
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2809f593e30b318719b0e3889c730cc3a2d0729a707Kenji Kaneshige
2810afabe906539b4e8b9e895f19ea31aabdf12f30bKenji Kaneshige	rc = p_slot->hpc_ops->get_adapter_speed(p_slot, &asp);
2820afabe906539b4e8b9e895f19ea31aabdf12f30bKenji Kaneshige	if (rc) {
283be7bce250a88fbbb5a67204eb148bce8b798780aTaku Izumi		ctrl_err(ctrl, "Can't get adapter speed or "
284be7bce250a88fbbb5a67204eb148bce8b798780aTaku Izumi			 "bus mode mismatch\n");
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return WRONG_BUS_FREQUENCY;
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2883749c51ac6c1560aa1cb1520066bed84c6f8152aMatthew Wilcox	bsp = ctrl->pci_dev->bus->cur_bus_speed;
2893749c51ac6c1560aa1cb1520066bed84c6f8152aMatthew Wilcox	msp = ctrl->pci_dev->bus->max_bus_speed;
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Check if there are other slots or devices on the same bus */
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!list_empty(&ctrl->pci_dev->subordinate->devices))
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		slots_not_empty = 1;
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
295f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi	ctrl_dbg(ctrl, "%s: slots_not_empty %d, adapter_speed %d, bus_speed %d,"
296f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi		 " max_bus_speed %d\n", __func__, slots_not_empty, asp,
297f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi		 bsp, msp);
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2990afabe906539b4e8b9e895f19ea31aabdf12f30bKenji Kaneshige	rc = fix_bus_speed(ctrl, p_slot, slots_not_empty, asp, bsp, msp);
3000afabe906539b4e8b9e895f19ea31aabdf12f30bKenji Kaneshige	if (rc)
3010afabe906539b4e8b9e895f19ea31aabdf12f30bKenji Kaneshige		return rc;
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* turn on board, blink green LED, turn off Amber LED */
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((rc = p_slot->hpc_ops->slot_enable(p_slot))) {
305be7bce250a88fbbb5a67204eb148bce8b798780aTaku Izumi		ctrl_err(ctrl, "Issue of Slot Enable command failed\n");
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return rc;
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Wait for ~1 second */
31068c0b671491088d79611fa965bbf94b3bc0024a4Kenji Kaneshige	msleep(1000);
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
312f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi	ctrl_dbg(ctrl, "%s: slot status = %x\n", __func__, p_slot->status);
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Check for a power fault */
3142178bfad9ccb0cbeb79599dd1dc349dd4567aa49Rajesh Shah	if (p_slot->status == 0xFF) {
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* power fault occurred, but it was benign */
316be7bce250a88fbbb5a67204eb148bce8b798780aTaku Izumi		ctrl_dbg(ctrl, "%s: Power fault\n", __func__);
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rc = POWER_FAILURE;
3182178bfad9ccb0cbeb79599dd1dc349dd4567aa49Rajesh Shah		p_slot->status = 0;
319dbd7a78818d125a0ebd5507d4edb4dd5900006abRajesh Shah		goto err_exit;
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
322dbd7a78818d125a0ebd5507d4edb4dd5900006abRajesh Shah	if (shpchp_configure_device(p_slot)) {
323be7bce250a88fbbb5a67204eb148bce8b798780aTaku Izumi		ctrl_err(ctrl, "Cannot add device at %04x:%02x:%02x\n",
324be7bce250a88fbbb5a67204eb148bce8b798780aTaku Izumi			 pci_domain_nr(parent), p_slot->bus, p_slot->device);
325dbd7a78818d125a0ebd5507d4edb4dd5900006abRajesh Shah		goto err_exit;
326dbd7a78818d125a0ebd5507d4edb4dd5900006abRajesh Shah	}
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3282178bfad9ccb0cbeb79599dd1dc349dd4567aa49Rajesh Shah	p_slot->status = 0;
3292178bfad9ccb0cbeb79599dd1dc349dd4567aa49Rajesh Shah	p_slot->is_a_board = 0x01;
3302178bfad9ccb0cbeb79599dd1dc349dd4567aa49Rajesh Shah	p_slot->pwr_save = 1;
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
332dbd7a78818d125a0ebd5507d4edb4dd5900006abRajesh Shah	p_slot->hpc_ops->green_led_on(p_slot);
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
334dbd7a78818d125a0ebd5507d4edb4dd5900006abRajesh Shah	return 0;
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
336dbd7a78818d125a0ebd5507d4edb4dd5900006abRajesh Shaherr_exit:
337dbd7a78818d125a0ebd5507d4edb4dd5900006abRajesh Shah	/* turn off slot, turn on Amber LED, turn off Green LED */
338dbd7a78818d125a0ebd5507d4edb4dd5900006abRajesh Shah	rc = p_slot->hpc_ops->slot_disable(p_slot);
339dbd7a78818d125a0ebd5507d4edb4dd5900006abRajesh Shah	if (rc) {
340f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi		ctrl_err(ctrl, "%s: Issue of Slot Disable command failed\n",
341f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi			 __func__);
342dbd7a78818d125a0ebd5507d4edb4dd5900006abRajesh Shah		return rc;
343dbd7a78818d125a0ebd5507d4edb4dd5900006abRajesh Shah	}
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
345dbd7a78818d125a0ebd5507d4edb4dd5900006abRajesh Shah	return(rc);
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
35026e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * remove_board - Turns off slot and LEDs
35126e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * @p_slot: target &slot
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
353ee138334d5eb5ca662b2d69228420c1ccc051e0eRajesh Shahstatic int remove_board(struct slot *p_slot)
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3552178bfad9ccb0cbeb79599dd1dc349dd4567aa49Rajesh Shah	struct controller *ctrl = p_slot->ctrl;
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 hp_slot;
357ee138334d5eb5ca662b2d69228420c1ccc051e0eRajesh Shah	int rc;
35870b6091946ab486c4dab8abeb4a3fc2bf7d3e7feRajesh Shah
3592178bfad9ccb0cbeb79599dd1dc349dd4567aa49Rajesh Shah	if (shpchp_unconfigure_device(p_slot))
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return(1);
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3622178bfad9ccb0cbeb79599dd1dc349dd4567aa49Rajesh Shah	hp_slot = p_slot->device - ctrl->slot_device_offset;
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
365be7bce250a88fbbb5a67204eb148bce8b798780aTaku Izumi	ctrl_dbg(ctrl, "%s: hp_slot = %d\n", __func__, hp_slot);
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Change status to shutdown */
3682178bfad9ccb0cbeb79599dd1dc349dd4567aa49Rajesh Shah	if (p_slot->is_a_board)
3692178bfad9ccb0cbeb79599dd1dc349dd4567aa49Rajesh Shah		p_slot->status = 0x01;
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* turn off slot, turn on Amber LED, turn off Green LED */
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc = p_slot->hpc_ops->slot_disable(p_slot);
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rc) {
374f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi		ctrl_err(ctrl, "%s: Issue of Slot Disable command failed\n",
375f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi			 __func__);
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return rc;
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3789f593e30b318719b0e3889c730cc3a2d0729a707Kenji Kaneshige
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc = p_slot->hpc_ops->set_attention_status(p_slot, 0);
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rc) {
381be7bce250a88fbbb5a67204eb148bce8b798780aTaku Izumi		ctrl_err(ctrl, "Issue of Set Attention command failed\n");
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return rc;
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3852178bfad9ccb0cbeb79599dd1dc349dd4567aa49Rajesh Shah	p_slot->pwr_save = 0;
3862178bfad9ccb0cbeb79599dd1dc349dd4567aa49Rajesh Shah	p_slot->is_a_board = 0;
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
392a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshigestruct pushbutton_work_info {
393a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	struct slot *p_slot;
394a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	struct work_struct work;
395a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige};
396a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
39826e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * shpchp_pushbutton_thread - handle pushbutton events
39926e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * @work: &struct work_struct to be handled
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
40126e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * Scheduled procedure to handle blocking stuff for the pushbuttons.
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Handles all pending events and exits.
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
404c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howellsstatic void shpchp_pushbutton_thread(struct work_struct *work)
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
406c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells	struct pushbutton_work_info *info =
407c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells		container_of(work, struct pushbutton_work_info, work);
408a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	struct slot *p_slot = info->p_slot;
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
410a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	mutex_lock(&p_slot->lock);
411a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	switch (p_slot->state) {
412a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	case POWEROFF_STATE:
413a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		mutex_unlock(&p_slot->lock);
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		shpchp_disable_slot(p_slot);
415a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		mutex_lock(&p_slot->lock);
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		p_slot->state = STATIC_STATE;
417a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		break;
418a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	case POWERON_STATE:
419a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		mutex_unlock(&p_slot->lock);
420d29aaddab3ef3bdaecf3c9c6d9423f0bf0452ccfKenji Kaneshige		if (shpchp_enable_slot(p_slot))
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			p_slot->hpc_ops->green_led_off(p_slot);
422a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		mutex_lock(&p_slot->lock);
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		p_slot->state = STATIC_STATE;
424a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		break;
425a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	default:
426a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		break;
427a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	}
428a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	mutex_unlock(&p_slot->lock);
429a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige
430a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	kfree(info);
431a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige}
432a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige
433e325e1f0783382298141c74737712637943c6063Kristen Carlson Accardivoid shpchp_queue_pushbutton_work(struct work_struct *work)
434a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige{
435c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells	struct slot *p_slot = container_of(work, struct slot, work.work);
436a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	struct pushbutton_work_info *info;
437a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige
438a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	info = kmalloc(sizeof(*info), GFP_KERNEL);
439a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	if (!info) {
440f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi		ctrl_err(p_slot->ctrl, "%s: Cannot allocate memory\n",
441f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi			 __func__);
442a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		return;
443a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	}
444a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	info->p_slot = p_slot;
445c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells	INIT_WORK(&info->work, shpchp_pushbutton_thread);
446a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige
447a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	mutex_lock(&p_slot->lock);
448a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	switch (p_slot->state) {
449a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	case BLINKINGOFF_STATE:
450a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		p_slot->state = POWEROFF_STATE;
451a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		break;
452a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	case BLINKINGON_STATE:
453a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		p_slot->state = POWERON_STATE;
454a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		break;
455a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	default:
4566fcaf17ac7a512227112ac81c0e1a5862bab57a6Jiri Slaby		kfree(info);
457a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		goto out;
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
459e24dcbef93dbbf529fbedfc6ce8ab22d2cef35f0Tejun Heo	queue_work(shpchp_ordered_wq, &info->work);
460a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige out:
461a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	mutex_unlock(&p_slot->lock);
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int update_slot_info (struct slot *slot)
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct hotplug_slot_info *info;
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result;
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info = kmalloc(sizeof(*info), GFP_KERNEL);
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!info)
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	slot->hpc_ops->get_power_status(slot, &(info->power_status));
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	slot->hpc_ops->get_attention_status(slot, &(info->attention_status));
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	slot->hpc_ops->get_latch_status(slot, &(info->latch_status));
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	slot->hpc_ops->get_adapter_status(slot, &(info->adapter_status));
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = pci_hp_change_slot_info(slot->hotplug_slot, info);
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree (info);
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return result;
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
483a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige/*
484a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige * Note: This function must be called with slot->lock held
485a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige */
486a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshigestatic void handle_button_press_event(struct slot *p_slot)
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 getstatus;
489f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi	struct controller *ctrl = p_slot->ctrl;
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
491a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	switch (p_slot->state) {
492a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	case STATIC_STATE:
493f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige		p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
494f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige		if (getstatus) {
495f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige			p_slot->state = BLINKINGOFF_STATE;
496f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi			ctrl_info(ctrl, "PCI slot #%s - powering off due to "
497f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi				  "button press.\n", slot_name(p_slot));
498f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige		} else {
499f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige			p_slot->state = BLINKINGON_STATE;
500f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi			ctrl_info(ctrl, "PCI slot #%s - powering on due to "
501f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi				  "button press.\n", slot_name(p_slot));
502f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige		}
503f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige		/* blink green LED and turn off amber */
504f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige		p_slot->hpc_ops->green_led_blink(p_slot);
505f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige		p_slot->hpc_ops->set_attention_status(p_slot, 0);
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
507e24dcbef93dbbf529fbedfc6ce8ab22d2cef35f0Tejun Heo		queue_delayed_work(shpchp_wq, &p_slot->work, 5*HZ);
508a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		break;
509a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	case BLINKINGOFF_STATE:
510a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	case BLINKINGON_STATE:
511a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		/*
512a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		 * Cancel if we are still blinking; this means that we
513a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		 * press the attention again before the 5 sec. limit
514a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		 * expires to cancel hot-add or hot-remove
515a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		 */
516f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi		ctrl_info(ctrl, "Button cancel on Slot(%s)\n",
517f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi			  slot_name(p_slot));
518a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		cancel_delayed_work(&p_slot->work);
519a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		if (p_slot->state == BLINKINGOFF_STATE)
520a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige			p_slot->hpc_ops->green_led_on(p_slot);
521a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		else
522a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige			p_slot->hpc_ops->green_led_off(p_slot);
523a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		p_slot->hpc_ops->set_attention_status(p_slot, 0);
524f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi		ctrl_info(ctrl, "PCI slot #%s - action canceled due to "
525f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi			  "button press\n", slot_name(p_slot));
526a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		p_slot->state = STATIC_STATE;
527a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		break;
528a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	case POWEROFF_STATE:
529a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	case POWERON_STATE:
530a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		/*
531a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		 * Ignore if the slot is on power-on or power-off state;
532a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		 * this means that the previous attention button action
533a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		 * to hot-add or hot-remove is undergoing
534a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		 */
535f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi		ctrl_info(ctrl, "Button ignore on Slot(%s)\n",
536f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi			  slot_name(p_slot));
537a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		update_slot_info(p_slot);
538a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		break;
539a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	default:
540f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi		ctrl_warn(ctrl, "Not a valid state\n");
541a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		break;
542a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	}
543a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige}
544a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige
545c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howellsstatic void interrupt_event_handler(struct work_struct *work)
546a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige{
547c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells	struct event_info *info = container_of(work, struct event_info, work);
548a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	struct slot *p_slot = info->p_slot;
549a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige
550a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	mutex_lock(&p_slot->lock);
551a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	switch (info->event_type) {
552a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	case INT_BUTTON_PRESS:
553a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		handle_button_press_event(p_slot);
554f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige		break;
555f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige	case INT_POWER_FAULT:
556be7bce250a88fbbb5a67204eb148bce8b798780aTaku Izumi		ctrl_dbg(p_slot->ctrl, "%s: Power fault\n", __func__);
557f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige		p_slot->hpc_ops->set_attention_status(p_slot, 1);
558f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige		p_slot->hpc_ops->green_led_off(p_slot);
559f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige		break;
560f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige	default:
561f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige		update_slot_info(p_slot);
562f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige		break;
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
564a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	mutex_unlock(&p_slot->lock);
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
566f7391f5325ea744f0632f7ef39a90085162743acKenji Kaneshige	kfree(info);
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
570a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshigestatic int shpchp_enable_slot (struct slot *p_slot)
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 getstatus = 0;
573ef3be54777901e570185089f21fbe4498453f67eKenji Kaneshige	int rc, retval = -ENODEV;
574f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi	struct controller *ctrl = p_slot->ctrl;
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Check to see if (latch closed, card present, power off) */
5776aa4cdd07139ba4d5b89139b0070d795cc4dea88Ingo Molnar	mutex_lock(&p_slot->ctrl->crit_sect);
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rc || !getstatus) {
580f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi		ctrl_info(ctrl, "No adapter on slot(%s)\n", slot_name(p_slot));
581ef3be54777901e570185089f21fbe4498453f67eKenji Kaneshige		goto out;
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rc || getstatus) {
585f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi		ctrl_info(ctrl, "Latch open on slot(%s)\n", slot_name(p_slot));
586ef3be54777901e570185089f21fbe4498453f67eKenji Kaneshige		goto out;
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rc || getstatus) {
590f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi		ctrl_info(ctrl, "Already enabled on slot(%s)\n",
591f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi			  slot_name(p_slot));
592ef3be54777901e570185089f21fbe4498453f67eKenji Kaneshige		goto out;
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5952178bfad9ccb0cbeb79599dd1dc349dd4567aa49Rajesh Shah	p_slot->is_a_board = 1;
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* We have to save the presence info for these slots */
5982178bfad9ccb0cbeb79599dd1dc349dd4567aa49Rajesh Shah	p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save));
5992178bfad9ccb0cbeb79599dd1dc349dd4567aa49Rajesh Shah	p_slot->hpc_ops->get_power_status(p_slot, &(p_slot->pwr_save));
600f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi	ctrl_dbg(ctrl, "%s: p_slot->pwr_save %x\n", __func__, p_slot->pwr_save);
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
60353044f357448693f218cc4f053affe92ed414f9dKeck, David	if(((p_slot->ctrl->pci_dev->vendor == PCI_VENDOR_ID_AMD) ||
60453044f357448693f218cc4f053affe92ed414f9dKeck, David	    (p_slot->ctrl->pci_dev->device == PCI_DEVICE_ID_AMD_POGO_7458))
60553044f357448693f218cc4f053affe92ed414f9dKeck, David	     && p_slot->ctrl->num_slots == 1) {
60653044f357448693f218cc4f053affe92ed414f9dKeck, David		/* handle amd pogo errata; this must be done before enable  */
60753044f357448693f218cc4f053affe92ed414f9dKeck, David		amd_pogo_errata_save_misc_reg(p_slot);
608ef3be54777901e570185089f21fbe4498453f67eKenji Kaneshige		retval = board_added(p_slot);
60953044f357448693f218cc4f053affe92ed414f9dKeck, David		/* handle amd pogo errata; this must be done after enable  */
61053044f357448693f218cc4f053affe92ed414f9dKeck, David		amd_pogo_errata_restore_misc_reg(p_slot);
61153044f357448693f218cc4f053affe92ed414f9dKeck, David	} else
612ef3be54777901e570185089f21fbe4498453f67eKenji Kaneshige		retval = board_added(p_slot);
61353044f357448693f218cc4f053affe92ed414f9dKeck, David
614ef3be54777901e570185089f21fbe4498453f67eKenji Kaneshige	if (retval) {
6152178bfad9ccb0cbeb79599dd1dc349dd4567aa49Rajesh Shah		p_slot->hpc_ops->get_adapter_status(p_slot,
6162178bfad9ccb0cbeb79599dd1dc349dd4567aa49Rajesh Shah				&(p_slot->presence_save));
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6202178bfad9ccb0cbeb79599dd1dc349dd4567aa49Rajesh Shah	update_slot_info(p_slot);
621ef3be54777901e570185089f21fbe4498453f67eKenji Kaneshige out:
622ef3be54777901e570185089f21fbe4498453f67eKenji Kaneshige	mutex_unlock(&p_slot->ctrl->crit_sect);
623ef3be54777901e570185089f21fbe4498453f67eKenji Kaneshige	return retval;
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
627a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshigestatic int shpchp_disable_slot (struct slot *p_slot)
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 getstatus = 0;
630ef3be54777901e570185089f21fbe4498453f67eKenji Kaneshige	int rc, retval = -ENODEV;
631f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi	struct controller *ctrl = p_slot->ctrl;
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!p_slot->ctrl)
634ee17fd93a5892c162b0a02d58cdfdb9c50cf8467Dely Sy		return -ENODEV;
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Check to see if (latch closed, card present, power on) */
6376aa4cdd07139ba4d5b89139b0070d795cc4dea88Ingo Molnar	mutex_lock(&p_slot->ctrl->crit_sect);
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
639ef3be54777901e570185089f21fbe4498453f67eKenji Kaneshige	rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
640ef3be54777901e570185089f21fbe4498453f67eKenji Kaneshige	if (rc || !getstatus) {
641f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi		ctrl_info(ctrl, "No adapter on slot(%s)\n", slot_name(p_slot));
642ef3be54777901e570185089f21fbe4498453f67eKenji Kaneshige		goto out;
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
644ef3be54777901e570185089f21fbe4498453f67eKenji Kaneshige	rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
645ef3be54777901e570185089f21fbe4498453f67eKenji Kaneshige	if (rc || getstatus) {
646f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi		ctrl_info(ctrl, "Latch open on slot(%s)\n", slot_name(p_slot));
647ef3be54777901e570185089f21fbe4498453f67eKenji Kaneshige		goto out;
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
649ef3be54777901e570185089f21fbe4498453f67eKenji Kaneshige	rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
650ef3be54777901e570185089f21fbe4498453f67eKenji Kaneshige	if (rc || !getstatus) {
651be7bce250a88fbbb5a67204eb148bce8b798780aTaku Izumi		ctrl_info(ctrl, "Already disabled on slot(%s)\n",
652f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi			  slot_name(p_slot));
653ef3be54777901e570185089f21fbe4498453f67eKenji Kaneshige		goto out;
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
656ef3be54777901e570185089f21fbe4498453f67eKenji Kaneshige	retval = remove_board(p_slot);
6572178bfad9ccb0cbeb79599dd1dc349dd4567aa49Rajesh Shah	update_slot_info(p_slot);
658ef3be54777901e570185089f21fbe4498453f67eKenji Kaneshige out:
659ef3be54777901e570185089f21fbe4498453f67eKenji Kaneshige	mutex_unlock(&p_slot->ctrl->crit_sect);
660ef3be54777901e570185089f21fbe4498453f67eKenji Kaneshige	return retval;
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
663a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshigeint shpchp_sysfs_enable_slot(struct slot *p_slot)
664a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige{
665a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	int retval = -ENODEV;
666f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi	struct controller *ctrl = p_slot->ctrl;
667a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige
668a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	mutex_lock(&p_slot->lock);
669a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	switch (p_slot->state) {
670a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	case BLINKINGON_STATE:
671a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		cancel_delayed_work(&p_slot->work);
672a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	case STATIC_STATE:
673a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		p_slot->state = POWERON_STATE;
674a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		mutex_unlock(&p_slot->lock);
675a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		retval = shpchp_enable_slot(p_slot);
676a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		mutex_lock(&p_slot->lock);
677a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		p_slot->state = STATIC_STATE;
678a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		break;
679a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	case POWERON_STATE:
680f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi		ctrl_info(ctrl, "Slot %s is already in powering on state\n",
681f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi			  slot_name(p_slot));
682a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		break;
683a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	case BLINKINGOFF_STATE:
684a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	case POWEROFF_STATE:
685f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi		ctrl_info(ctrl, "Already enabled on slot %s\n",
686f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi			  slot_name(p_slot));
687a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		break;
688a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	default:
689f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi		ctrl_err(ctrl, "Not a valid state on slot %s\n",
690f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi			 slot_name(p_slot));
691a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		break;
692a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	}
693a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	mutex_unlock(&p_slot->lock);
694a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige
695a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	return retval;
696a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige}
697a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige
698a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshigeint shpchp_sysfs_disable_slot(struct slot *p_slot)
699a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige{
700a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	int retval = -ENODEV;
701f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi	struct controller *ctrl = p_slot->ctrl;
702a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige
703a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	mutex_lock(&p_slot->lock);
704a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	switch (p_slot->state) {
705a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	case BLINKINGOFF_STATE:
706a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		cancel_delayed_work(&p_slot->work);
707a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	case STATIC_STATE:
708a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		p_slot->state = POWEROFF_STATE;
709a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		mutex_unlock(&p_slot->lock);
710a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		retval = shpchp_disable_slot(p_slot);
711a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		mutex_lock(&p_slot->lock);
712a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		p_slot->state = STATIC_STATE;
713a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		break;
714a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	case POWEROFF_STATE:
715f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi		ctrl_info(ctrl, "Slot %s is already in powering off state\n",
716f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi			  slot_name(p_slot));
717a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		break;
718a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	case BLINKINGON_STATE:
719a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	case POWERON_STATE:
720f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi		ctrl_info(ctrl, "Already disabled on slot %s\n",
721f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi			  slot_name(p_slot));
722a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		break;
723a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	default:
724f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi		ctrl_err(ctrl, "Not a valid state on slot %s\n",
725f98ca311f3a32e2adc229fecd6bf732db07fcca3Taku Izumi			 slot_name(p_slot));
726a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige		break;
727a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	}
728a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	mutex_unlock(&p_slot->lock);
729a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige
730a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige	return retval;
731a246fa4e9f0f1b5096a1cad0659d22fb10fb3732Kenji Kaneshige}
732