diff options
author | Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com> | 2009-06-02 00:52:26 -0400 |
---|---|---|
committer | Jesse Barnes <jbarnes@virtuousgeek.org> | 2009-06-16 17:30:10 -0400 |
commit | bd3d99c17039fd05a29587db3f4a180c48da115a (patch) | |
tree | 9eb211ae93977297f56f6e09c628de16d26f1bdb | |
parent | 1298307736a5882352418b4dc7c65442ab3b8bd4 (diff) |
PCI: Remove untested Electromechanical Interlock (EMI) support in pciehp.
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>
-rw-r--r-- | drivers/pci/hotplug/pciehp.h | 3 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehp_core.c | 111 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehp_hpc.c | 31 | ||||
-rw-r--r-- | include/linux/pci_hotplug.h | 8 |
4 files changed, 1 insertions, 152 deletions
diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index 0a368547e63..e6cf096498b 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h | |||
@@ -81,7 +81,6 @@ struct slot { | |||
81 | struct hpc_ops *hpc_ops; | 81 | struct hpc_ops *hpc_ops; |
82 | struct hotplug_slot *hotplug_slot; | 82 | struct hotplug_slot *hotplug_slot; |
83 | struct list_head slot_list; | 83 | struct list_head slot_list; |
84 | unsigned long last_emi_toggle; | ||
85 | struct delayed_work work; /* work for button event */ | 84 | struct delayed_work work; /* work for button event */ |
86 | struct mutex lock; | 85 | struct mutex lock; |
87 | }; | 86 | }; |
@@ -203,8 +202,6 @@ struct hpc_ops { | |||
203 | int (*set_attention_status)(struct slot *slot, u8 status); | 202 | int (*set_attention_status)(struct slot *slot, u8 status); |
204 | int (*get_latch_status)(struct slot *slot, u8 *status); | 203 | int (*get_latch_status)(struct slot *slot, u8 *status); |
205 | int (*get_adapter_status)(struct slot *slot, u8 *status); | 204 | int (*get_adapter_status)(struct slot *slot, u8 *status); |
206 | int (*get_emi_status)(struct slot *slot, u8 *status); | ||
207 | int (*toggle_emi)(struct slot *slot); | ||
208 | int (*get_max_bus_speed)(struct slot *slot, enum pci_bus_speed *speed); | 205 | int (*get_max_bus_speed)(struct slot *slot, enum pci_bus_speed *speed); |
209 | int (*get_cur_bus_speed)(struct slot *slot, enum pci_bus_speed *speed); | 206 | int (*get_cur_bus_speed)(struct slot *slot, enum pci_bus_speed *speed); |
210 | int (*get_max_lnk_width)(struct slot *slot, enum pcie_link_width *val); | 207 | int (*get_max_lnk_width)(struct slot *slot, enum pcie_link_width *val); |
diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index fb254b2454d..eb183d1d091 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c | |||
@@ -85,99 +85,6 @@ static struct hotplug_slot_ops pciehp_hotplug_slot_ops = { | |||
85 | .get_cur_bus_speed = get_cur_bus_speed, | 85 | .get_cur_bus_speed = get_cur_bus_speed, |
86 | }; | 86 | }; |
87 | 87 | ||
88 | /* | ||
89 | * Check the status of the Electro Mechanical Interlock (EMI) | ||
90 | */ | ||
91 | static int get_lock_status(struct hotplug_slot *hotplug_slot, u8 *value) | ||
92 | { | ||
93 | struct slot *slot = hotplug_slot->private; | ||
94 | return (slot->hpc_ops->get_emi_status(slot, value)); | ||
95 | } | ||
96 | |||
97 | /* | ||
98 | * sysfs interface for the Electro Mechanical Interlock (EMI) | ||
99 | * 1 == locked, 0 == unlocked | ||
100 | */ | ||
101 | static ssize_t lock_read_file(struct hotplug_slot *slot, char *buf) | ||
102 | { | ||
103 | int retval; | ||
104 | u8 value; | ||
105 | |||
106 | retval = get_lock_status(slot, &value); | ||
107 | if (retval) | ||
108 | goto lock_read_exit; | ||
109 | retval = sprintf (buf, "%d\n", value); | ||
110 | |||
111 | lock_read_exit: | ||
112 | return retval; | ||
113 | } | ||
114 | |||
115 | /* | ||
116 | * Change the status of the Electro Mechanical Interlock (EMI) | ||
117 | * This is a toggle - in addition there must be at least 1 second | ||
118 | * in between toggles. | ||
119 | */ | ||
120 | static int set_lock_status(struct hotplug_slot *hotplug_slot, u8 status) | ||
121 | { | ||
122 | struct slot *slot = hotplug_slot->private; | ||
123 | int retval; | ||
124 | u8 value; | ||
125 | |||
126 | mutex_lock(&slot->ctrl->crit_sect); | ||
127 | |||
128 | /* has it been >1 sec since our last toggle? */ | ||
129 | if ((get_seconds() - slot->last_emi_toggle) < 1) { | ||
130 | mutex_unlock(&slot->ctrl->crit_sect); | ||
131 | return -EINVAL; | ||
132 | } | ||
133 | |||
134 | /* see what our current state is */ | ||
135 | retval = get_lock_status(hotplug_slot, &value); | ||
136 | if (retval || (value == status)) | ||
137 | goto set_lock_exit; | ||
138 | |||
139 | slot->hpc_ops->toggle_emi(slot); | ||
140 | set_lock_exit: | ||
141 | mutex_unlock(&slot->ctrl->crit_sect); | ||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | /* | ||
146 | * sysfs interface which allows the user to toggle the Electro Mechanical | ||
147 | * Interlock. Valid values are either 0 or 1. 0 == unlock, 1 == lock | ||
148 | */ | ||
149 | static ssize_t lock_write_file(struct hotplug_slot *hotplug_slot, | ||
150 | const char *buf, size_t count) | ||
151 | { | ||
152 | struct slot *slot = hotplug_slot->private; | ||
153 | unsigned long llock; | ||
154 | u8 lock; | ||
155 | int retval = 0; | ||
156 | |||
157 | llock = simple_strtoul(buf, NULL, 10); | ||
158 | lock = (u8)(llock & 0xff); | ||
159 | |||
160 | switch (lock) { | ||
161 | case 0: | ||
162 | case 1: | ||
163 | retval = set_lock_status(hotplug_slot, lock); | ||
164 | break; | ||
165 | default: | ||
166 | ctrl_err(slot->ctrl, "%d is an invalid lock value\n", | ||
167 | lock); | ||
168 | retval = -EINVAL; | ||
169 | } | ||
170 | if (retval) | ||
171 | return retval; | ||
172 | return count; | ||
173 | } | ||
174 | |||
175 | static struct hotplug_slot_attribute hotplug_slot_attr_lock = { | ||
176 | .attr = {.name = "lock", .mode = S_IFREG | S_IRUGO | S_IWUSR}, | ||
177 | .show = lock_read_file, | ||
178 | .store = lock_write_file | ||
179 | }; | ||
180 | |||
181 | /** | 88 | /** |
182 | * release_slot - free up the memory used by a slot | 89 | * release_slot - free up the memory used by a slot |
183 | * @hotplug_slot: slot to free | 90 | * @hotplug_slot: slot to free |
@@ -236,17 +143,6 @@ static int init_slots(struct controller *ctrl) | |||
236 | get_attention_status(hotplug_slot, &info->attention_status); | 143 | get_attention_status(hotplug_slot, &info->attention_status); |
237 | get_latch_status(hotplug_slot, &info->latch_status); | 144 | get_latch_status(hotplug_slot, &info->latch_status); |
238 | get_adapter_status(hotplug_slot, &info->adapter_status); | 145 | get_adapter_status(hotplug_slot, &info->adapter_status); |
239 | /* create additional sysfs entries */ | ||
240 | if (EMI(ctrl)) { | ||
241 | retval = sysfs_create_file(&hotplug_slot->pci_slot->kobj, | ||
242 | &hotplug_slot_attr_lock.attr); | ||
243 | if (retval) { | ||
244 | pci_hp_deregister(hotplug_slot); | ||
245 | ctrl_err(ctrl, "Cannot create additional sysfs " | ||
246 | "entries\n"); | ||
247 | goto error_info; | ||
248 | } | ||
249 | } | ||
250 | } | 146 | } |
251 | 147 | ||
252 | return 0; | 148 | return 0; |
@@ -261,13 +157,8 @@ error: | |||
261 | static void cleanup_slots(struct controller *ctrl) | 157 | static void cleanup_slots(struct controller *ctrl) |
262 | { | 158 | { |
263 | struct slot *slot; | 159 | struct slot *slot; |
264 | 160 | list_for_each_entry(slot, &ctrl->slot_list, slot_list) | |
265 | list_for_each_entry(slot, &ctrl->slot_list, slot_list) { | ||
266 | if (EMI(ctrl)) | ||
267 | sysfs_remove_file(&slot->hotplug_slot->pci_slot->kobj, | ||
268 | &hotplug_slot_attr_lock.attr); | ||
269 | pci_hp_deregister(slot->hotplug_slot); | 161 | pci_hp_deregister(slot->hotplug_slot); |
270 | } | ||
271 | } | 162 | } |
272 | 163 | ||
273 | /* | 164 | /* |
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 07bd3215114..52813257e5b 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c | |||
@@ -422,35 +422,6 @@ static int hpc_query_power_fault(struct slot *slot) | |||
422 | return !!(slot_status & PCI_EXP_SLTSTA_PFD); | 422 | return !!(slot_status & PCI_EXP_SLTSTA_PFD); |
423 | } | 423 | } |
424 | 424 | ||
425 | static int hpc_get_emi_status(struct slot *slot, u8 *status) | ||
426 | { | ||
427 | struct controller *ctrl = slot->ctrl; | ||
428 | u16 slot_status; | ||
429 | int retval; | ||
430 | |||
431 | retval = pciehp_readw(ctrl, PCI_EXP_SLTSTA, &slot_status); | ||
432 | if (retval) { | ||
433 | ctrl_err(ctrl, "Cannot check EMI status\n"); | ||
434 | return retval; | ||
435 | } | ||
436 | *status = !!(slot_status & PCI_EXP_SLTSTA_EIS); | ||
437 | return retval; | ||
438 | } | ||
439 | |||
440 | static int hpc_toggle_emi(struct slot *slot) | ||
441 | { | ||
442 | u16 slot_cmd; | ||
443 | u16 cmd_mask; | ||
444 | int rc; | ||
445 | |||
446 | slot_cmd = PCI_EXP_SLTCTL_EIC; | ||
447 | cmd_mask = PCI_EXP_SLTCTL_EIC; | ||
448 | rc = pcie_write_cmd(slot->ctrl, slot_cmd, cmd_mask); | ||
449 | slot->last_emi_toggle = get_seconds(); | ||
450 | |||
451 | return rc; | ||
452 | } | ||
453 | |||
454 | static int hpc_set_attention_status(struct slot *slot, u8 value) | 425 | static int hpc_set_attention_status(struct slot *slot, u8 value) |
455 | { | 426 | { |
456 | struct controller *ctrl = slot->ctrl; | 427 | struct controller *ctrl = slot->ctrl; |
@@ -874,8 +845,6 @@ static struct hpc_ops pciehp_hpc_ops = { | |||
874 | .get_attention_status = hpc_get_attention_status, | 845 | .get_attention_status = hpc_get_attention_status, |
875 | .get_latch_status = hpc_get_latch_status, | 846 | .get_latch_status = hpc_get_latch_status, |
876 | .get_adapter_status = hpc_get_adapter_status, | 847 | .get_adapter_status = hpc_get_adapter_status, |
877 | .get_emi_status = hpc_get_emi_status, | ||
878 | .toggle_emi = hpc_toggle_emi, | ||
879 | 848 | ||
880 | .get_max_bus_speed = hpc_get_max_lnk_speed, | 849 | .get_max_bus_speed = hpc_get_max_lnk_speed, |
881 | .get_cur_bus_speed = hpc_get_cur_lnk_speed, | 850 | .get_cur_bus_speed = hpc_get_cur_lnk_speed, |
diff --git a/include/linux/pci_hotplug.h b/include/linux/pci_hotplug.h index 20998746518..11936fd0b56 100644 --- a/include/linux/pci_hotplug.h +++ b/include/linux/pci_hotplug.h | |||
@@ -66,14 +66,6 @@ enum pcie_link_speed { | |||
66 | PCIE_LNK_SPEED_UNKNOWN = 0xFF, | 66 | PCIE_LNK_SPEED_UNKNOWN = 0xFF, |
67 | }; | 67 | }; |
68 | 68 | ||
69 | struct hotplug_slot; | ||
70 | struct hotplug_slot_attribute { | ||
71 | struct attribute attr; | ||
72 | ssize_t (*show)(struct hotplug_slot *, char *); | ||
73 | ssize_t (*store)(struct hotplug_slot *, const char *, size_t); | ||
74 | }; | ||
75 | #define to_hotplug_attr(n) container_of(n, struct hotplug_slot_attribute, attr); | ||
76 | |||
77 | /** | 69 | /** |
78 | * struct hotplug_slot_ops -the callbacks that the hotplug pci core can use | 70 | * struct hotplug_slot_ops -the callbacks that the hotplug pci core can use |
79 | * @owner: The module owner of this structure | 71 | * @owner: The module owner of this structure |