aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/slot.c
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/slot.c
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/slot.c')
-rw-r--r--drivers/pci/slot.c141
1 files changed, 113 insertions, 28 deletions
diff --git a/drivers/pci/slot.c b/drivers/pci/slot.c
index 0e009c3ba5f..b6ee352ae45 100644
--- a/drivers/pci/slot.c
+++ b/drivers/pci/slot.c
@@ -78,6 +78,77 @@ static struct kobj_type pci_slot_ktype = {
78 .default_attrs = pci_slot_default_attrs, 78 .default_attrs = pci_slot_default_attrs,
79}; 79};
80 80
81static char *make_slot_name(const char *name)
82{
83 char *new_name;
84 int len, max, dup;
85
86 new_name = kstrdup(name, GFP_KERNEL);
87 if (!new_name)
88 return NULL;
89
90 /*
91 * Make sure we hit the realloc case the first time through the
92 * loop. 'len' will be strlen(name) + 3 at that point which is
93 * enough space for "name-X" and the trailing NUL.
94 */
95 len = strlen(name) + 2;
96 max = 1;
97 dup = 1;
98
99 for (;;) {
100 struct kobject *dup_slot;
101 dup_slot = kset_find_obj(pci_slots_kset, new_name);
102 if (!dup_slot)
103 break;
104 kobject_put(dup_slot);
105 if (dup == max) {
106 len++;
107 max *= 10;
108 kfree(new_name);
109 new_name = kmalloc(len, GFP_KERNEL);
110 if (!new_name)
111 break;
112 }
113 sprintf(new_name, "%s-%d", name, dup++);
114 }
115
116 return new_name;
117}
118
119static int rename_slot(struct pci_slot *slot, const char *name)
120{
121 int result = 0;
122 char *slot_name;
123
124 if (strcmp(kobject_name(&slot->kobj), name) == 0)
125 return result;
126
127 slot_name = make_slot_name(name);
128 if (!slot_name)
129 return -ENOMEM;
130
131 result = kobject_rename(&slot->kobj, slot_name);
132 kfree(slot_name);
133
134 return result;
135}
136
137static struct pci_slot *get_slot(struct pci_bus *parent, int slot_nr)
138{
139 struct pci_slot *slot;
140 /*
141 * We already hold pci_bus_sem so don't worry
142 */
143 list_for_each_entry(slot, &parent->slots, list)
144 if (slot->number == slot_nr) {
145 kobject_get(&slot->kobj);
146 return slot;
147 }
148
149 return NULL;
150}
151
81/** 152/**
82 * pci_create_slot - create or increment refcount for physical PCI slot 153 * pci_create_slot - create or increment refcount for physical PCI slot
83 * @parent: struct pci_bus of parent bridge 154 * @parent: struct pci_bus of parent bridge
@@ -90,7 +161,17 @@ static struct kobj_type pci_slot_ktype = {
90 * either return a new &struct pci_slot to the caller, or if the pci_slot 161 * either return a new &struct pci_slot to the caller, or if the pci_slot
91 * already exists, its refcount will be incremented. 162 * already exists, its refcount will be incremented.
92 * 163 *
93 * Slots are uniquely identified by a @pci_bus, @slot_nr, @name tuple. 164 * Slots are uniquely identified by a @pci_bus, @slot_nr tuple.
165 *
166 * There are known platforms with broken firmware that assign the same
167 * name to multiple slots. Workaround these broken platforms by renaming
168 * the slots on behalf of the caller. If firmware assigns name N to
169 * multiple slots:
170 *
171 * The first slot is assigned N
172 * The second slot is assigned N-1
173 * The third slot is assigned N-2
174 * etc.
94 * 175 *
95 * Placeholder slots: 176 * Placeholder slots:
96 * In most cases, @pci_bus, @slot_nr will be sufficient to uniquely identify 177 * In most cases, @pci_bus, @slot_nr will be sufficient to uniquely identify
@@ -99,62 +180,67 @@ static struct kobj_type pci_slot_ktype = {
99 * the slot. In this scenario, the caller may pass -1 for @slot_nr. 180 * the slot. In this scenario, the caller may pass -1 for @slot_nr.
100 * 181 *
101 * The following semantics are imposed when the caller passes @slot_nr == 182 * The following semantics are imposed when the caller passes @slot_nr ==
102 * -1. First, the check for existing %struct pci_slot is skipped, as the 183 * -1. First, we no longer check for an existing %struct pci_slot, as there
103 * caller may know about several unpopulated slots on a given %struct 184 * may be many slots with @slot_nr of -1. The other change in semantics is
104 * pci_bus, and each slot would have a @slot_nr of -1. Uniqueness for
105 * these slots is then determined by the @name parameter. We expect
106 * kobject_init_and_add() to warn us if the caller attempts to create
107 * multiple slots with the same name. The other change in semantics is
108 * user-visible, which is the 'address' parameter presented in sysfs will 185 * user-visible, which is the 'address' parameter presented in sysfs will
109 * consist solely of a dddd:bb tuple, where dddd is the PCI domain of the 186 * consist solely of a dddd:bb tuple, where dddd is the PCI domain of the
110 * %struct pci_bus and bb is the bus number. In other words, the devfn of 187 * %struct pci_bus and bb is the bus number. In other words, the devfn of
111 * the 'placeholder' slot will not be displayed. 188 * the 'placeholder' slot will not be displayed.
112 */ 189 */
113
114struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr, 190struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr,
115 const char *name, 191 const char *name,
116 struct hotplug_slot *hotplug) 192 struct hotplug_slot *hotplug)
117{ 193{
118 struct pci_dev *dev; 194 struct pci_dev *dev;
119 struct pci_slot *slot; 195 struct pci_slot *slot;
120 int err; 196 int err = 0;
197 char *slot_name = NULL;
121 198
122 down_write(&pci_bus_sem); 199 down_write(&pci_bus_sem);
123 200
124 if (slot_nr == -1) 201 if (slot_nr == -1)
125 goto placeholder; 202 goto placeholder;
126 203
127 /* If we've already created this slot, bump refcount and return. */ 204 /*
128 list_for_each_entry(slot, &parent->slots, list) { 205 * Hotplug drivers are allowed to rename an existing slot,
129 if (slot->number == slot_nr) { 206 * but only if not already claimed.
130 kobject_get(&slot->kobj); 207 */
131 pr_debug("%s: inc refcount to %d on %04x:%02x:%02x\n", 208 slot = get_slot(parent, slot_nr);
132 __func__, 209 if (slot) {
133 atomic_read(&slot->kobj.kref.refcount), 210 if (hotplug) {
134 pci_domain_nr(parent), parent->number, 211 if ((err = slot->hotplug ? -EBUSY : 0)
135 slot_nr); 212 || (err = rename_slot(slot, name))) {
136 goto out; 213 kobject_put(&slot->kobj);
214 slot = NULL;
215 goto err;
216 }
137 } 217 }
218 goto out;
138 } 219 }
139 220
140placeholder: 221placeholder:
141 slot = kzalloc(sizeof(*slot), GFP_KERNEL); 222 slot = kzalloc(sizeof(*slot), GFP_KERNEL);
142 if (!slot) { 223 if (!slot) {
143 slot = ERR_PTR(-ENOMEM); 224 err = -ENOMEM;
144 goto out; 225 goto err;
145 } 226 }
146 227
147 slot->bus = parent; 228 slot->bus = parent;
148 slot->number = slot_nr; 229 slot->number = slot_nr;
149 230
150 slot->kobj.kset = pci_slots_kset; 231 slot->kobj.kset = pci_slots_kset;
151 err = kobject_init_and_add(&slot->kobj, &pci_slot_ktype, NULL, 232
152 "%s", name); 233 slot_name = make_slot_name(name);
153 if (err) { 234 if (!slot_name) {
154 printk(KERN_ERR "Unable to register kobject %s\n", name); 235 err = -ENOMEM;
155 goto err; 236 goto err;
156 } 237 }
157 238
239 err = kobject_init_and_add(&slot->kobj, &pci_slot_ktype, NULL,
240 "%s", slot_name);
241 if (err)
242 goto err;
243
158 INIT_LIST_HEAD(&slot->list); 244 INIT_LIST_HEAD(&slot->list);
159 list_add(&slot->list, &parent->slots); 245 list_add(&slot->list, &parent->slots);
160 246
@@ -166,10 +252,10 @@ placeholder:
166 pr_debug("%s: created pci_slot on %04x:%02x:%02x\n", 252 pr_debug("%s: created pci_slot on %04x:%02x:%02x\n",
167 __func__, pci_domain_nr(parent), parent->number, slot_nr); 253 __func__, pci_domain_nr(parent), parent->number, slot_nr);
168 254
169 out: 255out:
170 up_write(&pci_bus_sem); 256 up_write(&pci_bus_sem);
171 return slot; 257 return slot;
172 err: 258err:
173 kfree(slot); 259 kfree(slot);
174 slot = ERR_PTR(err); 260 slot = ERR_PTR(err);
175 goto out; 261 goto out;
@@ -210,7 +296,6 @@ EXPORT_SYMBOL_GPL(pci_renumber_slot);
210 * just call kobject_put on its kobj and let our release methods do the 296 * just call kobject_put on its kobj and let our release methods do the
211 * rest. 297 * rest.
212 */ 298 */
213
214void pci_destroy_slot(struct pci_slot *slot) 299void pci_destroy_slot(struct pci_slot *slot)
215{ 300{
216 pr_debug("%s: dec refcount to %d on %04x:%02x:%02x\n", __func__, 301 pr_debug("%s: dec refcount to %d on %04x:%02x:%02x\n", __func__,