Skip to content

Commit

Permalink
PCI: Remove untested Electromechanical Interlock (EMI) support in pci…
Browse files Browse the repository at this point in the history
…ehp.

The EMI support in pciehp is obviously broken. It is implemented using
struct hotplug_slot_attribute, but sysfs_ops for pci_slot_ktype is NOT
for struct hotplug_slot_attribute, but for struct pci_slot_attribute.
This bug had been there for a long time, maybe it was introduced when
PCI slot framework was introduced. The reason why this bug didn't
cause any problem is maybe the EMI support is not tested at all
because of lack of test environment.

As described above, the EMI support in pciehp seems not to be tested
at all. So this patch removes EMI support from pciehp, instead of
fixing the bug.

Signed-off-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
  • Loading branch information
Kenji Kaneshige authored and Jesse Barnes committed Jun 16, 2009
1 parent 1298307 commit bd3d99c
Show file tree
Hide file tree
Showing 4 changed files with 1 addition and 152 deletions.
3 changes: 0 additions & 3 deletions drivers/pci/hotplug/pciehp.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ struct slot {
struct hpc_ops *hpc_ops;
struct hotplug_slot *hotplug_slot;
struct list_head slot_list;
unsigned long last_emi_toggle;
struct delayed_work work; /* work for button event */
struct mutex lock;
};
Expand Down Expand Up @@ -203,8 +202,6 @@ struct hpc_ops {
int (*set_attention_status)(struct slot *slot, u8 status);
int (*get_latch_status)(struct slot *slot, u8 *status);
int (*get_adapter_status)(struct slot *slot, u8 *status);
int (*get_emi_status)(struct slot *slot, u8 *status);
int (*toggle_emi)(struct slot *slot);
int (*get_max_bus_speed)(struct slot *slot, enum pci_bus_speed *speed);
int (*get_cur_bus_speed)(struct slot *slot, enum pci_bus_speed *speed);
int (*get_max_lnk_width)(struct slot *slot, enum pcie_link_width *val);
Expand Down
111 changes: 1 addition & 110 deletions drivers/pci/hotplug/pciehp_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,99 +85,6 @@ 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) {
mutex_unlock(&slot->ctrl->crit_sect);
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 *hotplug_slot,
const char *buf, size_t count)
{
struct slot *slot = hotplug_slot->private;
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(hotplug_slot, lock);
break;
default:
ctrl_err(slot->ctrl, "%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
Expand Down Expand Up @@ -236,17 +143,6 @@ static int init_slots(struct controller *ctrl)
get_attention_status(hotplug_slot, &info->attention_status);
get_latch_status(hotplug_slot, &info->latch_status);
get_adapter_status(hotplug_slot, &info->adapter_status);
/* create additional sysfs entries */
if (EMI(ctrl)) {
retval = sysfs_create_file(&hotplug_slot->pci_slot->kobj,
&hotplug_slot_attr_lock.attr);
if (retval) {
pci_hp_deregister(hotplug_slot);
ctrl_err(ctrl, "Cannot create additional sysfs "
"entries\n");
goto error_info;
}
}
}

return 0;
Expand All @@ -261,13 +157,8 @@ static int init_slots(struct controller *ctrl)
static void cleanup_slots(struct controller *ctrl)
{
struct slot *slot;

list_for_each_entry(slot, &ctrl->slot_list, slot_list) {
if (EMI(ctrl))
sysfs_remove_file(&slot->hotplug_slot->pci_slot->kobj,
&hotplug_slot_attr_lock.attr);
list_for_each_entry(slot, &ctrl->slot_list, slot_list)
pci_hp_deregister(slot->hotplug_slot);
}
}

/*
Expand Down
31 changes: 0 additions & 31 deletions drivers/pci/hotplug/pciehp_hpc.c
Original file line number Diff line number Diff line change
Expand Up @@ -422,35 +422,6 @@ static int hpc_query_power_fault(struct slot *slot)
return !!(slot_status & PCI_EXP_SLTSTA_PFD);
}

static int hpc_get_emi_status(struct slot *slot, u8 *status)
{
struct controller *ctrl = slot->ctrl;
u16 slot_status;
int retval;

retval = pciehp_readw(ctrl, PCI_EXP_SLTSTA, &slot_status);
if (retval) {
ctrl_err(ctrl, "Cannot check EMI status\n");
return retval;
}
*status = !!(slot_status & PCI_EXP_SLTSTA_EIS);
return retval;
}

static int hpc_toggle_emi(struct slot *slot)
{
u16 slot_cmd;
u16 cmd_mask;
int rc;

slot_cmd = PCI_EXP_SLTCTL_EIC;
cmd_mask = PCI_EXP_SLTCTL_EIC;
rc = pcie_write_cmd(slot->ctrl, slot_cmd, cmd_mask);
slot->last_emi_toggle = get_seconds();

return rc;
}

static int hpc_set_attention_status(struct slot *slot, u8 value)
{
struct controller *ctrl = slot->ctrl;
Expand Down Expand Up @@ -874,8 +845,6 @@ static struct hpc_ops pciehp_hpc_ops = {
.get_attention_status = hpc_get_attention_status,
.get_latch_status = hpc_get_latch_status,
.get_adapter_status = hpc_get_adapter_status,
.get_emi_status = hpc_get_emi_status,
.toggle_emi = hpc_toggle_emi,

.get_max_bus_speed = hpc_get_max_lnk_speed,
.get_cur_bus_speed = hpc_get_cur_lnk_speed,
Expand Down
8 changes: 0 additions & 8 deletions include/linux/pci_hotplug.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,6 @@ enum pcie_link_speed {
PCIE_LNK_SPEED_UNKNOWN = 0xFF,
};

struct hotplug_slot;
struct hotplug_slot_attribute {
struct attribute attr;
ssize_t (*show)(struct hotplug_slot *, char *);
ssize_t (*store)(struct hotplug_slot *, const char *, size_t);
};
#define to_hotplug_attr(n) container_of(n, struct hotplug_slot_attribute, attr);

/**
* struct hotplug_slot_ops -the callbacks that the hotplug pci core can use
* @owner: The module owner of this structure
Expand Down

0 comments on commit bd3d99c

Please sign in to comment.