aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/hotplug
diff options
context:
space:
mode:
authorAlex Chiang <achiang@hp.com>2008-10-20 19:41:02 -0400
committerJesse Barnes <jbarnes@virtuousgeek.org>2008-10-22 19:42:39 -0400
commit5fe6cc60680d29740b85278e17a002fa27b7e642 (patch)
tree3815152b48be7f02bb13b765ea8784ff60bfffcb /drivers/pci/hotplug
parent95cb9093960b6249fdbe7417bf513a1358aaa51a (diff)
PCI: prevent duplicate slot names
Prevent callers of pci_create_slot() from registering slots with duplicate names. This condition occurs most often when PCI hotplug drivers are loaded on platforms with broken firmware that assigns identical names to multiple slots. We now rename these duplicate slots on behalf of the user. If firmware assigns the name N to multiple slots, then: The first registered slot is assigned N The second registered slot is assigned N-1 The third registered slot is assigned N-2 etc. This is the permanent fix mentioned in earlier commits d6a9e9b4 and 167e782e (shpchp/pciehp: Rename duplicate slot name...). We take advantage of the new 'hotplug' parameter in pci_create_slot() to prevent a slot create/rename race between hotplug drivers and detection drivers. Scenario A: hotplug driver detection driver -------------- ---------------- pci_create_slot(hotplug=set) pci_create_slot(hotplug=NULL) The hotplug driver creates the slot with its desired name, and then releases the semaphore. Now, the detection driver tries to create the same slot, but it already exists. We don't care about renaming, so return the existing slot. Scenario B: hotplug driver detection driver -------------- ---------------- pci_create_slot(hotplug=NULL) pci_create_slot(hotplug=set) The detection driver creates the slot with name "X". Then the hotplug driver tries to create the same slot, but wants the name "Y" instead. We detect that we're trying to create the same slot and that we also want a rename, so rename the slot to "Y" and return. Scenario C: hotplug driver hotplug driver -------------- ---------------- pci_create_slot(hotplug=set) pci_create_slot(hotplug=set) Two separate hotplug drivers are attempting to claim the slot and are passing valid hotplug_slot args to pci_create_slot(). We detect that the slot already has a ->hotplug callback, prevent a rename, and return -EBUSY. Cc: kristen.c.accardi@intel.com Cc: matthew@wil.cx Acked-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com> Signed-off-by: Alex Chiang <achiang@hp.com> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers/pci/hotplug')
-rw-r--r--drivers/pci/hotplug/pci_hotplug_core.c26
-rw-r--r--drivers/pci/hotplug/pciehp_core.c15
-rw-r--r--drivers/pci/hotplug/shpchp_core.c15
3 files changed, 2 insertions, 54 deletions
diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c
index e71524825180..a6f1f282b683 100644
--- a/drivers/pci/hotplug/pci_hotplug_core.c
+++ b/drivers/pci/hotplug/pci_hotplug_core.c
@@ -569,12 +569,6 @@ int pci_hp_register(struct hotplug_slot *slot, struct pci_bus *bus, int slot_nr,
569 569
570 mutex_lock(&pci_hp_mutex); 570 mutex_lock(&pci_hp_mutex);
571 571
572 /* Check if we have already registered a slot with the same name. */
573 if (get_slot_from_name(name)) {
574 result = -EEXIST;
575 goto out;
576 }
577
578 /* 572 /*
579 * No problems if we call this interface from both ACPI_PCI_SLOT 573 * No problems if we call this interface from both ACPI_PCI_SLOT
580 * driver and call it here again. If we've already created the 574 * driver and call it here again. If we've already created the
@@ -583,27 +577,12 @@ int pci_hp_register(struct hotplug_slot *slot, struct pci_bus *bus, int slot_nr,
583 pci_slot = pci_create_slot(bus, slot_nr, name, slot); 577 pci_slot = pci_create_slot(bus, slot_nr, name, slot);
584 if (IS_ERR(pci_slot)) { 578 if (IS_ERR(pci_slot)) {
585 result = PTR_ERR(pci_slot); 579 result = PTR_ERR(pci_slot);
586 goto cleanup; 580 goto out;
587 }
588
589 if (pci_slot->hotplug) {
590 dbg("%s: already claimed\n", __func__);
591 result = -EBUSY;
592 goto cleanup;
593 } 581 }
594 582
595 slot->pci_slot = pci_slot; 583 slot->pci_slot = pci_slot;
596 pci_slot->hotplug = slot; 584 pci_slot->hotplug = slot;
597 585
598 /*
599 * Allow pcihp drivers to override the ACPI_PCI_SLOT name.
600 */
601 if (strcmp(kobject_name(&pci_slot->kobj), name)) {
602 result = kobject_rename(&pci_slot->kobj, name);
603 if (result)
604 goto cleanup;
605 }
606
607 list_add(&slot->slot_list, &pci_hotplug_slot_list); 586 list_add(&slot->slot_list, &pci_hotplug_slot_list);
608 587
609 result = fs_add_slot(pci_slot); 588 result = fs_add_slot(pci_slot);
@@ -612,9 +591,6 @@ int pci_hp_register(struct hotplug_slot *slot, struct pci_bus *bus, int slot_nr,
612out: 591out:
613 mutex_unlock(&pci_hp_mutex); 592 mutex_unlock(&pci_hp_mutex);
614 return result; 593 return result;
615cleanup:
616 pci_destroy_slot(pci_slot);
617 goto out;
618} 594}
619 595
620/** 596/**
diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c
index 3ace5e057601..af89d7bd1edd 100644
--- a/drivers/pci/hotplug/pciehp_core.c
+++ b/drivers/pci/hotplug/pciehp_core.c
@@ -196,7 +196,6 @@ static int init_slots(struct controller *ctrl)
196 struct slot *slot; 196 struct slot *slot;
197 struct hotplug_slot *hotplug_slot; 197 struct hotplug_slot *hotplug_slot;
198 struct hotplug_slot_info *info; 198 struct hotplug_slot_info *info;
199 int len, dup = 1;
200 int retval = -ENOMEM; 199 int retval = -ENOMEM;
201 200
202 list_for_each_entry(slot, &ctrl->slot_list, slot_list) { 201 list_for_each_entry(slot, &ctrl->slot_list, slot_list) {
@@ -223,25 +222,11 @@ static int init_slots(struct controller *ctrl)
223 ctrl_dbg(ctrl, "Registering bus=%x dev=%x hp_slot=%x sun=%x " 222 ctrl_dbg(ctrl, "Registering bus=%x dev=%x hp_slot=%x sun=%x "
224 "slot_device_offset=%x\n", slot->bus, slot->device, 223 "slot_device_offset=%x\n", slot->bus, slot->device,
225 slot->hp_slot, slot->number, ctrl->slot_device_offset); 224 slot->hp_slot, slot->number, ctrl->slot_device_offset);
226duplicate_name:
227 retval = pci_hp_register(hotplug_slot, 225 retval = pci_hp_register(hotplug_slot,
228 ctrl->pci_dev->subordinate, 226 ctrl->pci_dev->subordinate,
229 slot->device, 227 slot->device,
230 slot->name); 228 slot->name);
231 if (retval) { 229 if (retval) {
232 /*
233 * If slot N already exists, we'll try to create
234 * slot N-1, N-2 ... N-M, until we overflow.
235 */
236 if (retval == -EEXIST) {
237 len = snprintf(slot->name, SLOT_NAME_SIZE,
238 "%d-%d", slot->number, dup++);
239 if (len < SLOT_NAME_SIZE)
240 goto duplicate_name;
241 else
242 ctrl_err(ctrl, "duplicate slot name "
243 "overflow\n");
244 }
245 ctrl_err(ctrl, "pci_hp_register failed with error %d\n", 230 ctrl_err(ctrl, "pci_hp_register failed with error %d\n",
246 retval); 231 retval);
247 goto error_info; 232 goto error_info;
diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c
index bf5096612aab..cfdd07963641 100644
--- a/drivers/pci/hotplug/shpchp_core.c
+++ b/drivers/pci/hotplug/shpchp_core.c
@@ -102,7 +102,7 @@ static int init_slots(struct controller *ctrl)
102 struct hotplug_slot *hotplug_slot; 102 struct hotplug_slot *hotplug_slot;
103 struct hotplug_slot_info *info; 103 struct hotplug_slot_info *info;
104 int retval = -ENOMEM; 104 int retval = -ENOMEM;
105 int i, len, dup = 1; 105 int i;
106 106
107 for (i = 0; i < ctrl->num_slots; i++) { 107 for (i = 0; i < ctrl->num_slots; i++) {
108 slot = kzalloc(sizeof(*slot), GFP_KERNEL); 108 slot = kzalloc(sizeof(*slot), GFP_KERNEL);
@@ -144,23 +144,10 @@ static int init_slots(struct controller *ctrl)
144 dbg("Registering bus=%x dev=%x hp_slot=%x sun=%x " 144 dbg("Registering bus=%x dev=%x hp_slot=%x sun=%x "
145 "slot_device_offset=%x\n", slot->bus, slot->device, 145 "slot_device_offset=%x\n", slot->bus, slot->device,
146 slot->hp_slot, slot->number, ctrl->slot_device_offset); 146 slot->hp_slot, slot->number, ctrl->slot_device_offset);
147duplicate_name:
148 retval = pci_hp_register(slot->hotplug_slot, 147 retval = pci_hp_register(slot->hotplug_slot,
149 ctrl->pci_dev->subordinate, slot->device, 148 ctrl->pci_dev->subordinate, slot->device,
150 hotplug_slot->name); 149 hotplug_slot->name);
151 if (retval) { 150 if (retval) {
152 /*
153 * If slot N already exists, we'll try to create
154 * slot N-1, N-2 ... N-M, until we overflow.
155 */
156 if (retval == -EEXIST) {
157 len = snprintf(slot->name, SLOT_NAME_SIZE,
158 "%d-%d", slot->number, dup++);
159 if (len < SLOT_NAME_SIZE)
160 goto duplicate_name;
161 else
162 err("duplicate slot name overflow\n");
163 }
164 err("pci_hp_register failed with error %d\n", retval); 151 err("pci_hp_register failed with error %d\n", retval);
165 goto error_info; 152 goto error_info;
166 } 153 }