PCIEHP: Add Electro Mechanical Interlock (EMI) support to the PCIE hotplug driver.
Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
262303fe32
commit
34d03419f0
@@ -34,6 +34,7 @@
|
||||
#include <linux/pci.h>
|
||||
#include "pciehp.h"
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/time.h>
|
||||
|
||||
/* Global variables */
|
||||
int pciehp_debug;
|
||||
@@ -87,6 +88,95 @@ static struct hotplug_slot_ops pciehp_hotplug_slot_ops = {
|
||||
.get_cur_bus_speed = get_cur_bus_speed,
|
||||
};
|
||||
|
||||
/*
|
||||
* Check the status of the Electro Mechanical Interlock (EMI)
|
||||
*/
|
||||
static int get_lock_status(struct hotplug_slot *hotplug_slot, u8 *value)
|
||||
{
|
||||
struct slot *slot = hotplug_slot->private;
|
||||
return (slot->hpc_ops->get_emi_status(slot, value));
|
||||
}
|
||||
|
||||
/*
|
||||
* sysfs interface for the Electro Mechanical Interlock (EMI)
|
||||
* 1 == locked, 0 == unlocked
|
||||
*/
|
||||
static ssize_t lock_read_file(struct hotplug_slot *slot, char *buf)
|
||||
{
|
||||
int retval;
|
||||
u8 value;
|
||||
|
||||
retval = get_lock_status(slot, &value);
|
||||
if (retval)
|
||||
goto lock_read_exit;
|
||||
retval = sprintf (buf, "%d\n", value);
|
||||
|
||||
lock_read_exit:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* Change the status of the Electro Mechanical Interlock (EMI)
|
||||
* This is a toggle - in addition there must be at least 1 second
|
||||
* in between toggles.
|
||||
*/
|
||||
static int set_lock_status(struct hotplug_slot *hotplug_slot, u8 status)
|
||||
{
|
||||
struct slot *slot = hotplug_slot->private;
|
||||
int retval;
|
||||
u8 value;
|
||||
|
||||
mutex_lock(&slot->ctrl->crit_sect);
|
||||
|
||||
/* has it been >1 sec since our last toggle? */
|
||||
if ((get_seconds() - slot->last_emi_toggle) < 1)
|
||||
return -EINVAL;
|
||||
|
||||
/* see what our current state is */
|
||||
retval = get_lock_status(hotplug_slot, &value);
|
||||
if (retval || (value == status))
|
||||
goto set_lock_exit;
|
||||
|
||||
slot->hpc_ops->toggle_emi(slot);
|
||||
set_lock_exit:
|
||||
mutex_unlock(&slot->ctrl->crit_sect);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* sysfs interface which allows the user to toggle the Electro Mechanical
|
||||
* Interlock. Valid values are either 0 or 1. 0 == unlock, 1 == lock
|
||||
*/
|
||||
static ssize_t lock_write_file(struct hotplug_slot *slot, const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
unsigned long llock;
|
||||
u8 lock;
|
||||
int retval = 0;
|
||||
|
||||
llock = simple_strtoul(buf, NULL, 10);
|
||||
lock = (u8)(llock & 0xff);
|
||||
|
||||
switch (lock) {
|
||||
case 0:
|
||||
case 1:
|
||||
retval = set_lock_status(slot, lock);
|
||||
break;
|
||||
default:
|
||||
err ("%d is an invalid lock value\n", lock);
|
||||
retval = -EINVAL;
|
||||
}
|
||||
if (retval)
|
||||
return retval;
|
||||
return count;
|
||||
}
|
||||
|
||||
static struct hotplug_slot_attribute hotplug_slot_attr_lock = {
|
||||
.attr = {.name = "lock", .mode = S_IFREG | S_IRUGO | S_IWUSR},
|
||||
.show = lock_read_file,
|
||||
.store = lock_write_file
|
||||
};
|
||||
|
||||
/**
|
||||
* release_slot - free up the memory used by a slot
|
||||
* @hotplug_slot: slot to free
|
||||
@@ -159,6 +249,16 @@ static int init_slots(struct controller *ctrl)
|
||||
err ("pci_hp_register failed with error %d\n", retval);
|
||||
goto error_info;
|
||||
}
|
||||
/* create additional sysfs entries */
|
||||
if (EMI(ctrl->ctrlcap)) {
|
||||
retval = sysfs_create_file(&hotplug_slot->kobj,
|
||||
&hotplug_slot_attr_lock.attr);
|
||||
if (retval) {
|
||||
pci_hp_deregister(hotplug_slot);
|
||||
err("cannot create additional sysfs entries\n");
|
||||
goto error_info;
|
||||
}
|
||||
}
|
||||
|
||||
list_add(&slot->slot_list, &ctrl->slot_list);
|
||||
}
|
||||
@@ -183,6 +283,9 @@ static void cleanup_slots(struct controller *ctrl)
|
||||
list_for_each_safe(tmp, next, &ctrl->slot_list) {
|
||||
slot = list_entry(tmp, struct slot, slot_list);
|
||||
list_del(&slot->slot_list);
|
||||
if (EMI(ctrl->ctrlcap))
|
||||
sysfs_remove_file(&slot->hotplug_slot->kobj,
|
||||
&hotplug_slot_attr_lock.attr);
|
||||
pci_hp_deregister(slot->hotplug_slot);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user