1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * PCI HotPlug Controller Core
4 *
5 * Copyright (C) 2001-2002 Greg Kroah-Hartman (greg@kroah.com)
6 * Copyright (C) 2001-2002 IBM Corp.
7 *
8 * All rights reserved.
9 *
10 * Send feedback to <kristen.c.accardi@intel.com>
11 *
12 * Authors:
13 * Greg Kroah-Hartman <greg@kroah.com>
14 * Scott Murray <scottm@somanetworks.com>
15 */
16
17 #include <linux/module.h>
18 #include <linux/moduleparam.h>
19 #include <linux/kernel.h>
20 #include <linux/types.h>
21 #include <linux/kobject.h>
22 #include <linux/sysfs.h>
23 #include <linux/init.h>
24 #include <linux/pci.h>
25 #include <linux/pci_hotplug.h>
26 #include "../pci.h"
27 #include "cpci_hotplug.h"
28
29 #define MY_NAME "pci_hotplug"
30
31 #define dbg(fmt, arg...) do { if (debug) printk(KERN_DEBUG "%s: %s: " fmt, MY_NAME, __func__, ## arg); } while (0)
32 #define err(format, arg...) printk(KERN_ERR "%s: " format, MY_NAME, ## arg)
33 #define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME, ## arg)
34 #define warn(format, arg...) printk(KERN_WARNING "%s: " format, MY_NAME, ## arg)
35
36 /* local variables */
37 static bool debug;
38
39 /* Weee, fun with macros... */
40 #define GET_STATUS(name, type) \
41 static int get_##name(struct hotplug_slot *slot, type *value) \
42 { \
43 const struct hotplug_slot_ops *ops = slot->ops; \
44 int retval = 0; \
45 if (ops->get_##name) \
46 retval = ops->get_##name(slot, value); \
47 return retval; \
48 }
49
GET_STATUS(power_status,u8)50 GET_STATUS(power_status, u8)
51 GET_STATUS(attention_status, u8)
52 GET_STATUS(latch_status, u8)
53 GET_STATUS(adapter_status, u8)
54
55 static ssize_t power_read_file(struct pci_slot *pci_slot, char *buf)
56 {
57 int retval;
58 u8 value;
59
60 retval = get_power_status(pci_slot->hotplug, &value);
61 if (retval)
62 return retval;
63
64 return sysfs_emit(buf, "%d\n", value);
65 }
66
power_write_file(struct pci_slot * pci_slot,const char * buf,size_t count)67 static ssize_t power_write_file(struct pci_slot *pci_slot, const char *buf,
68 size_t count)
69 {
70 struct hotplug_slot *slot = pci_slot->hotplug;
71 unsigned long lpower;
72 u8 power;
73 int retval = 0;
74
75 lpower = simple_strtoul(buf, NULL, 10);
76 power = (u8)(lpower & 0xff);
77 dbg("power = %d\n", power);
78
79 switch (power) {
80 case 0:
81 if (slot->ops->disable_slot)
82 retval = slot->ops->disable_slot(slot);
83 break;
84
85 case 1:
86 if (slot->ops->enable_slot)
87 retval = slot->ops->enable_slot(slot);
88 break;
89
90 default:
91 err("Illegal value specified for power\n");
92 retval = -EINVAL;
93 }
94
95 if (retval)
96 return retval;
97 return count;
98 }
99
100 static struct pci_slot_attribute hotplug_slot_attr_power = {
101 .attr = {.name = "power", .mode = S_IFREG | S_IRUGO | S_IWUSR},
102 .show = power_read_file,
103 .store = power_write_file
104 };
105
attention_read_file(struct pci_slot * pci_slot,char * buf)106 static ssize_t attention_read_file(struct pci_slot *pci_slot, char *buf)
107 {
108 int retval;
109 u8 value;
110
111 retval = get_attention_status(pci_slot->hotplug, &value);
112 if (retval)
113 return retval;
114
115 return sysfs_emit(buf, "%d\n", value);
116 }
117
attention_write_file(struct pci_slot * pci_slot,const char * buf,size_t count)118 static ssize_t attention_write_file(struct pci_slot *pci_slot, const char *buf,
119 size_t count)
120 {
121 struct hotplug_slot *slot = pci_slot->hotplug;
122 const struct hotplug_slot_ops *ops = slot->ops;
123 unsigned long lattention;
124 u8 attention;
125 int retval = 0;
126
127 lattention = simple_strtoul(buf, NULL, 10);
128 attention = (u8)(lattention & 0xff);
129 dbg(" - attention = %d\n", attention);
130
131 if (ops->set_attention_status)
132 retval = ops->set_attention_status(slot, attention);
133
134 if (retval)
135 return retval;
136 return count;
137 }
138
139 static struct pci_slot_attribute hotplug_slot_attr_attention = {
140 .attr = {.name = "attention", .mode = S_IFREG | S_IRUGO | S_IWUSR},
141 .show = attention_read_file,
142 .store = attention_write_file
143 };
144
latch_read_file(struct pci_slot * pci_slot,char * buf)145 static ssize_t latch_read_file(struct pci_slot *pci_slot, char *buf)
146 {
147 int retval;
148 u8 value;
149
150 retval = get_latch_status(pci_slot->hotplug, &value);
151 if (retval)
152 return retval;
153
154 return sysfs_emit(buf, "%d\n", value);
155 }
156
157 static struct pci_slot_attribute hotplug_slot_attr_latch = {
158 .attr = {.name = "latch", .mode = S_IFREG | S_IRUGO},
159 .show = latch_read_file,
160 };
161
presence_read_file(struct pci_slot * pci_slot,char * buf)162 static ssize_t presence_read_file(struct pci_slot *pci_slot, char *buf)
163 {
164 int retval;
165 u8 value;
166
167 retval = get_adapter_status(pci_slot->hotplug, &value);
168 if (retval)
169 return retval;
170
171 return sysfs_emit(buf, "%d\n", value);
172 }
173
174 static struct pci_slot_attribute hotplug_slot_attr_presence = {
175 .attr = {.name = "adapter", .mode = S_IFREG | S_IRUGO},
176 .show = presence_read_file,
177 };
178
test_write_file(struct pci_slot * pci_slot,const char * buf,size_t count)179 static ssize_t test_write_file(struct pci_slot *pci_slot, const char *buf,
180 size_t count)
181 {
182 struct hotplug_slot *slot = pci_slot->hotplug;
183 unsigned long ltest;
184 u32 test;
185 int retval = 0;
186
187 ltest = simple_strtoul(buf, NULL, 10);
188 test = (u32)(ltest & 0xffffffff);
189 dbg("test = %d\n", test);
190
191 if (slot->ops->hardware_test)
192 retval = slot->ops->hardware_test(slot, test);
193
194 if (retval)
195 return retval;
196 return count;
197 }
198
199 static struct pci_slot_attribute hotplug_slot_attr_test = {
200 .attr = {.name = "test", .mode = S_IFREG | S_IRUGO | S_IWUSR},
201 .store = test_write_file
202 };
203
has_power_file(struct hotplug_slot * slot)204 static bool has_power_file(struct hotplug_slot *slot)
205 {
206 if ((slot->ops->enable_slot) ||
207 (slot->ops->disable_slot) ||
208 (slot->ops->get_power_status))
209 return true;
210 return false;
211 }
212
has_attention_file(struct hotplug_slot * slot)213 static bool has_attention_file(struct hotplug_slot *slot)
214 {
215 if ((slot->ops->set_attention_status) ||
216 (slot->ops->get_attention_status))
217 return true;
218 return false;
219 }
220
has_latch_file(struct hotplug_slot * slot)221 static bool has_latch_file(struct hotplug_slot *slot)
222 {
223 if (slot->ops->get_latch_status)
224 return true;
225 return false;
226 }
227
has_adapter_file(struct hotplug_slot * slot)228 static bool has_adapter_file(struct hotplug_slot *slot)
229 {
230 if (slot->ops->get_adapter_status)
231 return true;
232 return false;
233 }
234
has_test_file(struct hotplug_slot * slot)235 static bool has_test_file(struct hotplug_slot *slot)
236 {
237 if (slot->ops->hardware_test)
238 return true;
239 return false;
240 }
241
fs_add_slot(struct hotplug_slot * slot,struct pci_slot * pci_slot)242 static int fs_add_slot(struct hotplug_slot *slot, struct pci_slot *pci_slot)
243 {
244 struct kobject *kobj;
245 int retval = 0;
246
247 /* Create symbolic link to the hotplug driver module */
248 kobj = kset_find_obj(module_kset, slot->mod_name);
249 if (kobj) {
250 retval = sysfs_create_link(&pci_slot->kobj, kobj, "module");
251 if (retval)
252 dev_err(&pci_slot->bus->dev,
253 "Error creating sysfs link (%d)\n", retval);
254 kobject_put(kobj);
255 }
256
257 if (has_power_file(slot)) {
258 retval = sysfs_create_file(&pci_slot->kobj,
259 &hotplug_slot_attr_power.attr);
260 if (retval)
261 goto exit_power;
262 }
263
264 if (has_attention_file(slot)) {
265 retval = sysfs_create_file(&pci_slot->kobj,
266 &hotplug_slot_attr_attention.attr);
267 if (retval)
268 goto exit_attention;
269 }
270
271 if (has_latch_file(slot)) {
272 retval = sysfs_create_file(&pci_slot->kobj,
273 &hotplug_slot_attr_latch.attr);
274 if (retval)
275 goto exit_latch;
276 }
277
278 if (has_adapter_file(slot)) {
279 retval = sysfs_create_file(&pci_slot->kobj,
280 &hotplug_slot_attr_presence.attr);
281 if (retval)
282 goto exit_adapter;
283 }
284
285 if (has_test_file(slot)) {
286 retval = sysfs_create_file(&pci_slot->kobj,
287 &hotplug_slot_attr_test.attr);
288 if (retval)
289 goto exit_test;
290 }
291
292 goto exit;
293
294 exit_test:
295 if (has_adapter_file(slot))
296 sysfs_remove_file(&pci_slot->kobj,
297 &hotplug_slot_attr_presence.attr);
298 exit_adapter:
299 if (has_latch_file(slot))
300 sysfs_remove_file(&pci_slot->kobj, &hotplug_slot_attr_latch.attr);
301 exit_latch:
302 if (has_attention_file(slot))
303 sysfs_remove_file(&pci_slot->kobj,
304 &hotplug_slot_attr_attention.attr);
305 exit_attention:
306 if (has_power_file(slot))
307 sysfs_remove_file(&pci_slot->kobj, &hotplug_slot_attr_power.attr);
308 exit_power:
309 sysfs_remove_link(&pci_slot->kobj, "module");
310 exit:
311 return retval;
312 }
313
fs_remove_slot(struct hotplug_slot * slot,struct pci_slot * pci_slot)314 static void fs_remove_slot(struct hotplug_slot *slot, struct pci_slot *pci_slot)
315 {
316 if (has_power_file(slot))
317 sysfs_remove_file(&pci_slot->kobj, &hotplug_slot_attr_power.attr);
318
319 if (has_attention_file(slot))
320 sysfs_remove_file(&pci_slot->kobj,
321 &hotplug_slot_attr_attention.attr);
322
323 if (has_latch_file(slot))
324 sysfs_remove_file(&pci_slot->kobj, &hotplug_slot_attr_latch.attr);
325
326 if (has_adapter_file(slot))
327 sysfs_remove_file(&pci_slot->kobj,
328 &hotplug_slot_attr_presence.attr);
329
330 if (has_test_file(slot))
331 sysfs_remove_file(&pci_slot->kobj, &hotplug_slot_attr_test.attr);
332
333 sysfs_remove_link(&pci_slot->kobj, "module");
334 }
335
336 /**
337 * __pci_hp_register - register a hotplug_slot with the PCI hotplug subsystem
338 * @slot: pointer to the &struct hotplug_slot to register
339 * @bus: bus this slot is on
340 * @devnr: device number
341 * @name: name registered with kobject core
342 * @owner: caller module owner
343 * @mod_name: caller module name
344 *
345 * Prepares a hotplug slot for in-kernel use and immediately publishes it to
346 * user space in one go. Drivers may alternatively carry out the two steps
347 * separately by invoking pci_hp_initialize() and pci_hp_add().
348 *
349 * Returns 0 if successful, anything else for an error.
350 */
__pci_hp_register(struct hotplug_slot * slot,struct pci_bus * bus,int devnr,const char * name,struct module * owner,const char * mod_name)351 int __pci_hp_register(struct hotplug_slot *slot, struct pci_bus *bus,
352 int devnr, const char *name,
353 struct module *owner, const char *mod_name)
354 {
355 int result;
356
357 result = __pci_hp_initialize(slot, bus, devnr, name, owner, mod_name);
358 if (result)
359 return result;
360
361 result = pci_hp_add(slot);
362 if (result)
363 pci_hp_destroy(slot);
364
365 return result;
366 }
367 EXPORT_SYMBOL_GPL(__pci_hp_register);
368
369 /**
370 * __pci_hp_initialize - prepare hotplug slot for in-kernel use
371 * @slot: pointer to the &struct hotplug_slot to initialize
372 * @bus: bus this slot is on
373 * @devnr: slot number
374 * @name: name registered with kobject core
375 * @owner: caller module owner
376 * @mod_name: caller module name
377 *
378 * Allocate and fill in a PCI slot for use by a hotplug driver. Once this has
379 * been called, the driver may invoke hotplug_slot_name() to get the slot's
380 * unique name. The driver must be prepared to handle a ->reset_slot callback
381 * from this point on.
382 *
383 * Returns 0 on success or a negative int on error.
384 */
__pci_hp_initialize(struct hotplug_slot * slot,struct pci_bus * bus,int devnr,const char * name,struct module * owner,const char * mod_name)385 int __pci_hp_initialize(struct hotplug_slot *slot, struct pci_bus *bus,
386 int devnr, const char *name, struct module *owner,
387 const char *mod_name)
388 {
389 struct pci_slot *pci_slot;
390
391 if (slot == NULL)
392 return -ENODEV;
393 if (slot->ops == NULL)
394 return -EINVAL;
395
396 slot->owner = owner;
397 slot->mod_name = mod_name;
398
399 /*
400 * No problems if we call this interface from both ACPI_PCI_SLOT
401 * driver and call it here again. If we've already created the
402 * pci_slot, the interface will simply bump the refcount.
403 */
404 pci_slot = pci_create_slot(bus, devnr, name, slot);
405 if (IS_ERR(pci_slot))
406 return PTR_ERR(pci_slot);
407
408 slot->pci_slot = pci_slot;
409 pci_slot->hotplug = slot;
410 return 0;
411 }
412 EXPORT_SYMBOL_GPL(__pci_hp_initialize);
413
414 /**
415 * pci_hp_add - publish hotplug slot to user space
416 * @slot: pointer to the &struct hotplug_slot to publish
417 *
418 * Make a hotplug slot's sysfs interface available and inform user space of its
419 * addition by sending a uevent. The hotplug driver must be prepared to handle
420 * all &struct hotplug_slot_ops callbacks from this point on.
421 *
422 * Returns 0 on success or a negative int on error.
423 */
pci_hp_add(struct hotplug_slot * slot)424 int pci_hp_add(struct hotplug_slot *slot)
425 {
426 struct pci_slot *pci_slot;
427 int result;
428
429 if (WARN_ON(!slot))
430 return -EINVAL;
431
432 pci_slot = slot->pci_slot;
433
434 result = fs_add_slot(slot, pci_slot);
435 if (result)
436 return result;
437
438 kobject_uevent(&pci_slot->kobj, KOBJ_ADD);
439 return 0;
440 }
441 EXPORT_SYMBOL_GPL(pci_hp_add);
442
443 /**
444 * pci_hp_deregister - deregister a hotplug_slot with the PCI hotplug subsystem
445 * @slot: pointer to the &struct hotplug_slot to deregister
446 *
447 * The @slot must have been registered with the pci hotplug subsystem
448 * previously with a call to pci_hp_register().
449 */
pci_hp_deregister(struct hotplug_slot * slot)450 void pci_hp_deregister(struct hotplug_slot *slot)
451 {
452 pci_hp_del(slot);
453 pci_hp_destroy(slot);
454 }
455 EXPORT_SYMBOL_GPL(pci_hp_deregister);
456
457 /**
458 * pci_hp_del - unpublish hotplug slot from user space
459 * @slot: pointer to the &struct hotplug_slot to unpublish
460 *
461 * Remove a hotplug slot's sysfs interface.
462 */
pci_hp_del(struct hotplug_slot * slot)463 void pci_hp_del(struct hotplug_slot *slot)
464 {
465 if (WARN_ON(!slot))
466 return;
467
468 fs_remove_slot(slot, slot->pci_slot);
469 }
470 EXPORT_SYMBOL_GPL(pci_hp_del);
471
472 /**
473 * pci_hp_destroy - remove hotplug slot from in-kernel use
474 * @slot: pointer to the &struct hotplug_slot to destroy
475 *
476 * Destroy a PCI slot used by a hotplug driver. Once this has been called,
477 * the driver may no longer invoke hotplug_slot_name() to get the slot's
478 * unique name. The driver no longer needs to handle a ->reset_slot callback
479 * from this point on.
480 */
pci_hp_destroy(struct hotplug_slot * slot)481 void pci_hp_destroy(struct hotplug_slot *slot)
482 {
483 struct pci_slot *pci_slot = slot->pci_slot;
484
485 slot->pci_slot = NULL;
486 pci_slot->hotplug = NULL;
487 pci_destroy_slot(pci_slot);
488 }
489 EXPORT_SYMBOL_GPL(pci_hp_destroy);
490
491 static DECLARE_WAIT_QUEUE_HEAD(pci_hp_link_change_wq);
492
493 /**
494 * pci_hp_ignore_link_change - begin code section causing spurious link changes
495 * @pdev: PCI hotplug bridge
496 *
497 * Mark the beginning of a code section causing spurious link changes on the
498 * Secondary Bus of @pdev, e.g. as a side effect of a Secondary Bus Reset,
499 * D3cold transition, firmware update or FPGA reconfiguration.
500 *
501 * Hotplug drivers can thus check whether such a code section is executing
502 * concurrently, await it with pci_hp_spurious_link_change() and ignore the
503 * resulting link change events.
504 *
505 * Must be paired with pci_hp_unignore_link_change(). May be called both
506 * from the PCI core and from Endpoint drivers. May be called for bridges
507 * which are not hotplug-capable, in which case it has no effect because
508 * no hotplug driver is bound to the bridge.
509 */
pci_hp_ignore_link_change(struct pci_dev * pdev)510 void pci_hp_ignore_link_change(struct pci_dev *pdev)
511 {
512 set_bit(PCI_LINK_CHANGING, &pdev->priv_flags);
513 smp_mb__after_atomic(); /* pairs with implied barrier of wait_event() */
514 }
515
516 /**
517 * pci_hp_unignore_link_change - end code section causing spurious link changes
518 * @pdev: PCI hotplug bridge
519 *
520 * Mark the end of a code section causing spurious link changes on the
521 * Secondary Bus of @pdev. Must be paired with pci_hp_ignore_link_change().
522 */
pci_hp_unignore_link_change(struct pci_dev * pdev)523 void pci_hp_unignore_link_change(struct pci_dev *pdev)
524 {
525 set_bit(PCI_LINK_CHANGED, &pdev->priv_flags);
526 mb(); /* ensure pci_hp_spurious_link_change() sees either bit set */
527 clear_bit(PCI_LINK_CHANGING, &pdev->priv_flags);
528 wake_up_all(&pci_hp_link_change_wq);
529 }
530
531 /**
532 * pci_hp_spurious_link_change - check for spurious link changes
533 * @pdev: PCI hotplug bridge
534 *
535 * Check whether a code section is executing concurrently which is causing
536 * spurious link changes on the Secondary Bus of @pdev. Await the end of the
537 * code section if so.
538 *
539 * May be called by hotplug drivers to check whether a link change is spurious
540 * and can be ignored.
541 *
542 * Because a genuine link change may have occurred in-between a spurious link
543 * change and the invocation of this function, hotplug drivers should perform
544 * sanity checks such as retrieving the current link state and bringing down
545 * the slot if the link is down.
546 *
547 * Return: %true if such a code section has been executing concurrently,
548 * otherwise %false. Also return %true if such a code section has not been
549 * executing concurrently, but at least once since the last invocation of this
550 * function.
551 */
pci_hp_spurious_link_change(struct pci_dev * pdev)552 bool pci_hp_spurious_link_change(struct pci_dev *pdev)
553 {
554 wait_event(pci_hp_link_change_wq,
555 !test_bit(PCI_LINK_CHANGING, &pdev->priv_flags));
556
557 return test_and_clear_bit(PCI_LINK_CHANGED, &pdev->priv_flags);
558 }
559
pci_hotplug_init(void)560 static int __init pci_hotplug_init(void)
561 {
562 int result;
563
564 result = cpci_hotplug_init(debug);
565 if (result) {
566 err("cpci_hotplug_init with error %d\n", result);
567 return result;
568 }
569
570 return result;
571 }
572 device_initcall(pci_hotplug_init);
573
574 /*
575 * not really modular, but the easiest way to keep compat with existing
576 * bootargs behaviour is to continue using module_param here.
577 */
578 module_param(debug, bool, 0644);
579 MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
580