PCI: pciehp: Rename duplicate slot name N as N-1, N-2, N-M...

Commit 3800345f723fd130d50434d4717b99d4a9f383c8 (pciehp: fix slot name)
introduces the pciehp_slot_with_bus module parameter, which was intended
to help work around broken firmware that assigns the same name to multiple
slots.

Commit 9e4f2e8d4ddb04ad16a3828cd9a369a5a5287009 (pciehp: add message about
pciehp_slot_with_bus option) tells the user to use the above parameter
in the event of a name collision.

This approach is sub-optimal because it requires too much work from
the user.

Instead, let's rename the slot 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
The Mth registered slot becomes N-M

In the event we overflow the slot->name parameter, we report an
error to the user.

This is a temporary fix until the entire PCI core can be reworked
such that individual drivers no longer have to manage their own
slot names.

Tested-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>
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>

authored by Alex Chiang and committed by Jesse Barnes 167e782e 6a55617e

+15 -18
-1
drivers/pci/hotplug/pciehp.h
··· 43 43 extern int pciehp_poll_time; 44 44 extern int pciehp_debug; 45 45 extern int pciehp_force; 46 - extern int pciehp_slot_with_bus; 47 46 extern struct workqueue_struct *pciehp_wq; 48 47 49 48 #define dbg(format, arg...) \
+14 -7
drivers/pci/hotplug/pciehp_core.c
··· 41 41 int pciehp_poll_mode; 42 42 int pciehp_poll_time; 43 43 int pciehp_force; 44 - int pciehp_slot_with_bus; 45 44 struct workqueue_struct *pciehp_wq; 46 45 47 46 #define DRIVER_VERSION "0.4" ··· 55 56 module_param(pciehp_poll_mode, bool, 0644); 56 57 module_param(pciehp_poll_time, int, 0644); 57 58 module_param(pciehp_force, bool, 0644); 58 - module_param(pciehp_slot_with_bus, bool, 0644); 59 59 MODULE_PARM_DESC(pciehp_debug, "Debugging mode enabled or not"); 60 60 MODULE_PARM_DESC(pciehp_poll_mode, "Using polling mechanism for hot-plug events or not"); 61 61 MODULE_PARM_DESC(pciehp_poll_time, "Polling mechanism frequency, in seconds"); 62 62 MODULE_PARM_DESC(pciehp_force, "Force pciehp, even if _OSC and OSHP are missing"); 63 - MODULE_PARM_DESC(pciehp_slot_with_bus, "Use bus number in the slot name"); 64 63 65 64 #define PCIE_MODULE_NAME "pciehp" 66 65 ··· 191 194 struct slot *slot; 192 195 struct hotplug_slot *hotplug_slot; 193 196 struct hotplug_slot_info *info; 197 + int len, dup = 1; 194 198 int retval = -ENOMEM; 195 199 196 200 list_for_each_entry(slot, &ctrl->slot_list, slot_list) { ··· 218 220 dbg("Registering bus=%x dev=%x hp_slot=%x sun=%x " 219 221 "slot_device_offset=%x\n", slot->bus, slot->device, 220 222 slot->hp_slot, slot->number, ctrl->slot_device_offset); 223 + duplicate_name: 221 224 retval = pci_hp_register(hotplug_slot, 222 225 ctrl->pci_dev->subordinate, 223 226 slot->device); 224 227 if (retval) { 228 + /* 229 + * If slot N already exists, we'll try to create 230 + * slot N-1, N-2 ... N-M, until we overflow. 231 + */ 232 + if (retval == -EEXIST) { 233 + len = snprintf(slot->name, SLOT_NAME_SIZE, 234 + "%d-%d", slot->number, dup++); 235 + if (len < SLOT_NAME_SIZE) 236 + goto duplicate_name; 237 + else 238 + err("duplicate slot name overflow\n"); 239 + } 225 240 err("pci_hp_register failed with error %d\n", retval); 226 - if (retval == -EEXIST) 227 - err("Failed to register slot because of name " 228 - "collision. Try \'pciehp_slot_with_bus\' " 229 - "module option.\n"); 230 241 goto error_info; 231 242 } 232 243 /* create additional sysfs entries */
+1 -10
drivers/pci/hotplug/pciehp_hpc.c
··· 1030 1030 pciehp_free_irq(ctrl); 1031 1031 } 1032 1032 1033 - static void make_slot_name(struct slot *slot) 1034 - { 1035 - if (pciehp_slot_with_bus) 1036 - snprintf(slot->name, SLOT_NAME_SIZE, "%04d_%04d", 1037 - slot->bus, slot->number); 1038 - else 1039 - snprintf(slot->name, SLOT_NAME_SIZE, "%d", slot->number); 1040 - } 1041 - 1042 1033 static int pcie_init_slot(struct controller *ctrl) 1043 1034 { 1044 1035 struct slot *slot; ··· 1044 1053 slot->device = ctrl->slot_device_offset + slot->hp_slot; 1045 1054 slot->hpc_ops = ctrl->hpc_ops; 1046 1055 slot->number = ctrl->first_slot; 1047 - make_slot_name(slot); 1056 + snprintf(slot->name, SLOT_NAME_SIZE, "%d", slot->number); 1048 1057 mutex_init(&slot->lock); 1049 1058 INIT_DELAYED_WORK(&slot->work, pciehp_queue_pushbutton_work); 1050 1059 list_add(&slot->slot_list, &ctrl->slot_list);