aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/hotplug/pciehp_core.c
diff options
context:
space:
mode:
authorKenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>2008-06-19 23:07:08 -0400
committerJesse Barnes <jbarnes@virtuousgeek.org>2008-06-27 16:00:43 -0400
commitc4635eb06af700820d658a163f06aff12e17cfb2 (patch)
tree97bae8af21e7dc26374de8d9ed45e9f112b7de5a /drivers/pci/hotplug/pciehp_core.c
parente4ec7a00ed30429030112e5591cf3138645727c2 (diff)
pciehp: fix interrupt initialization
Current pciehp driver's intialization sequence is as follows: (1) initialize controller data structure (2) install interrupt handler (3) enable software notification (4) initialize controller specific slot data structure (5) initialize generic slot data structure and register it to pci hotplug core The interrupt handler of pciehp assumes that controller specific slot data structure is already initialized. However, it is installed at (2) before initializing controller specific slot data structure at (4). Because of this, pciehp driver cannot handle the following cases properly. - If devices that shares IRQ with pciehp raise interrupts between (2) and (4). - If hotplug events (e.g. MRL open) happen between (3) and (4). We already have a workaround for this problem ("pciehp: fix NULL dereference in interrupt handler: dbd79aed1aea2bece0bf43cc2ff3b2f9baf48a08). But we still need fundamental fix. This patch fix the problem by changing the initilization sequence as follows: (1) initialize controller data structure (2) initialize controller specific slot data structure (3) install interrupt handler (4) enable software notification (5) initialize generic slot data structure and register it to pci hotplug core Signed-off-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com> Acked-by: Alex Chiang <achiang@hp.com> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers/pci/hotplug/pciehp_core.c')
-rw-r--r--drivers/pci/hotplug/pciehp_core.c80
1 files changed, 12 insertions, 68 deletions
diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c
index 7b21c86e4bff..d0fb56936911 100644
--- a/drivers/pci/hotplug/pciehp_core.c
+++ b/drivers/pci/hotplug/pciehp_core.c
@@ -41,7 +41,7 @@ int pciehp_debug;
41int pciehp_poll_mode; 41int pciehp_poll_mode;
42int pciehp_poll_time; 42int pciehp_poll_time;
43int pciehp_force; 43int pciehp_force;
44static int pciehp_slot_with_bus; 44int pciehp_slot_with_bus;
45struct workqueue_struct *pciehp_wq; 45struct workqueue_struct *pciehp_wq;
46 46
47#define DRIVER_VERSION "0.4" 47#define DRIVER_VERSION "0.4"
@@ -183,23 +183,10 @@ static struct hotplug_slot_attribute hotplug_slot_attr_lock = {
183 */ 183 */
184static void release_slot(struct hotplug_slot *hotplug_slot) 184static void release_slot(struct hotplug_slot *hotplug_slot)
185{ 185{
186 struct slot *slot = hotplug_slot->private;
187
188 dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); 186 dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
189 187
190 kfree(slot->hotplug_slot->info); 188 kfree(hotplug_slot->info);
191 kfree(slot->hotplug_slot); 189 kfree(hotplug_slot);
192 kfree(slot);
193}
194
195static void make_slot_name(struct slot *slot)
196{
197 if (pciehp_slot_with_bus)
198 snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "%04d_%04d",
199 slot->bus, slot->number);
200 else
201 snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "%d",
202 slot->number);
203} 190}
204 191
205static int init_slots(struct controller *ctrl) 192static int init_slots(struct controller *ctrl)
@@ -208,44 +195,27 @@ static int init_slots(struct controller *ctrl)
208 struct hotplug_slot *hotplug_slot; 195 struct hotplug_slot *hotplug_slot;
209 struct hotplug_slot_info *info; 196 struct hotplug_slot_info *info;
210 int retval = -ENOMEM; 197 int retval = -ENOMEM;
211 int i;
212
213 for (i = 0; i < ctrl->num_slots; i++) {
214 slot = kzalloc(sizeof(*slot), GFP_KERNEL);
215 if (!slot)
216 goto error;
217 198
199 list_for_each_entry(slot, &ctrl->slot_list, slot_list) {
218 hotplug_slot = kzalloc(sizeof(*hotplug_slot), GFP_KERNEL); 200 hotplug_slot = kzalloc(sizeof(*hotplug_slot), GFP_KERNEL);
219 if (!hotplug_slot) 201 if (!hotplug_slot)
220 goto error_slot; 202 goto error;
221 slot->hotplug_slot = hotplug_slot;
222 203
223 info = kzalloc(sizeof(*info), GFP_KERNEL); 204 info = kzalloc(sizeof(*info), GFP_KERNEL);
224 if (!info) 205 if (!info)
225 goto error_hpslot; 206 goto error_hpslot;
226 hotplug_slot->info = info;
227
228 hotplug_slot->name = slot->name;
229
230 slot->hp_slot = i;
231 slot->ctrl = ctrl;
232 slot->bus = ctrl->pci_dev->subordinate->number;
233 slot->device = ctrl->slot_device_offset + i;
234 slot->hpc_ops = ctrl->hpc_ops;
235 slot->number = ctrl->first_slot;
236 mutex_init(&slot->lock);
237 INIT_DELAYED_WORK(&slot->work, pciehp_queue_pushbutton_work);
238 207
239 /* register this slot with the hotplug pci core */ 208 /* register this slot with the hotplug pci core */
209 hotplug_slot->info = info;
210 hotplug_slot->name = slot->name;
240 hotplug_slot->private = slot; 211 hotplug_slot->private = slot;
241 hotplug_slot->release = &release_slot; 212 hotplug_slot->release = &release_slot;
242 make_slot_name(slot);
243 hotplug_slot->ops = &pciehp_hotplug_slot_ops; 213 hotplug_slot->ops = &pciehp_hotplug_slot_ops;
244
245 get_power_status(hotplug_slot, &info->power_status); 214 get_power_status(hotplug_slot, &info->power_status);
246 get_attention_status(hotplug_slot, &info->attention_status); 215 get_attention_status(hotplug_slot, &info->attention_status);
247 get_latch_status(hotplug_slot, &info->latch_status); 216 get_latch_status(hotplug_slot, &info->latch_status);
248 get_adapter_status(hotplug_slot, &info->adapter_status); 217 get_adapter_status(hotplug_slot, &info->adapter_status);
218 slot->hotplug_slot = hotplug_slot;
249 219
250 dbg("Registering bus=%x dev=%x hp_slot=%x sun=%x " 220 dbg("Registering bus=%x dev=%x hp_slot=%x sun=%x "
251 "slot_device_offset=%x\n", slot->bus, slot->device, 221 "slot_device_offset=%x\n", slot->bus, slot->device,
@@ -271,8 +241,6 @@ static int init_slots(struct controller *ctrl)
271 goto error_info; 241 goto error_info;
272 } 242 }
273 } 243 }
274
275 list_add(&slot->slot_list, &ctrl->slot_list);
276 } 244 }
277 245
278 return 0; 246 return 0;
@@ -280,27 +248,18 @@ error_info:
280 kfree(info); 248 kfree(info);
281error_hpslot: 249error_hpslot:
282 kfree(hotplug_slot); 250 kfree(hotplug_slot);
283error_slot:
284 kfree(slot);
285error: 251error:
286 return retval; 252 return retval;
287} 253}
288 254
289static void cleanup_slots(struct controller *ctrl) 255static void cleanup_slots(struct controller *ctrl)
290{ 256{
291 struct list_head *tmp;
292 struct list_head *next;
293 struct slot *slot; 257 struct slot *slot;
294 258
295 list_for_each_safe(tmp, next, &ctrl->slot_list) { 259 list_for_each_entry(slot, &ctrl->slot_list, slot_list) {
296 slot = list_entry(tmp, struct slot, slot_list);
297 list_del(&slot->slot_list);
298 if (EMI(ctrl)) 260 if (EMI(ctrl))
299 sysfs_remove_file(&slot->hotplug_slot->pci_slot->kobj, 261 sysfs_remove_file(&slot->hotplug_slot->pci_slot->kobj,
300 &hotplug_slot_attr_lock.attr); 262 &hotplug_slot_attr_lock.attr);
301 cancel_delayed_work(&slot->work);
302 flush_scheduled_work();
303 flush_workqueue(pciehp_wq);
304 pci_hp_deregister(slot->hotplug_slot); 263 pci_hp_deregister(slot->hotplug_slot);
305 } 264 }
306} 265}
@@ -441,25 +400,13 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_
441 else if (pciehp_get_hp_hw_control_from_firmware(pdev)) 400 else if (pciehp_get_hp_hw_control_from_firmware(pdev))
442 goto err_out_none; 401 goto err_out_none;
443 402
444 ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL); 403 ctrl = pcie_init(dev);
445 if (!ctrl) { 404 if (!ctrl) {
446 err("%s : out of memory\n", __func__);
447 goto err_out_none;
448 }
449 INIT_LIST_HEAD(&ctrl->slot_list);
450
451 rc = pcie_init(ctrl, dev);
452 if (rc) {
453 dbg("%s: controller initialization failed\n", PCIE_MODULE_NAME); 405 dbg("%s: controller initialization failed\n", PCIE_MODULE_NAME);
454 goto err_out_free_ctrl; 406 goto err_out_none;
455 } 407 }
456
457 pci_set_drvdata(pdev, ctrl); 408 pci_set_drvdata(pdev, ctrl);
458 409
459 dbg("%s: ctrl bus=0x%x, device=%x, function=%x, irq=%x\n",
460 __func__, pdev->bus->number, PCI_SLOT(pdev->devfn),
461 PCI_FUNC(pdev->devfn), pdev->irq);
462
463 /* Setup the slot information structures */ 410 /* Setup the slot information structures */
464 rc = init_slots(ctrl); 411 rc = init_slots(ctrl);
465 if (rc) { 412 if (rc) {
@@ -492,8 +439,6 @@ err_out_free_ctrl_slot:
492 cleanup_slots(ctrl); 439 cleanup_slots(ctrl);
493err_out_release_ctlr: 440err_out_release_ctlr:
494 ctrl->hpc_ops->release_ctlr(ctrl); 441 ctrl->hpc_ops->release_ctlr(ctrl);
495err_out_free_ctrl:
496 kfree(ctrl);
497err_out_none: 442err_out_none:
498 return -ENODEV; 443 return -ENODEV;
499} 444}
@@ -505,7 +450,6 @@ static void pciehp_remove (struct pcie_device *dev)
505 450
506 cleanup_slots(ctrl); 451 cleanup_slots(ctrl);
507 ctrl->hpc_ops->release_ctlr(ctrl); 452 ctrl->hpc_ops->release_ctlr(ctrl);
508 kfree(ctrl);
509} 453}
510 454
511#ifdef CONFIG_PM 455#ifdef CONFIG_PM
@@ -525,7 +469,7 @@ static int pciehp_resume (struct pcie_device *dev)
525 u8 status; 469 u8 status;
526 470
527 /* reinitialize the chipset's event detection logic */ 471 /* reinitialize the chipset's event detection logic */
528 pcie_init_hardware_part2(ctrl, dev); 472 pcie_enable_notification(ctrl);
529 473
530 t_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset); 474 t_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset);
531 475