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 */
37static bool debug;
38
39/* Weee, fun with macros... */
40#define GET_STATUS(name, type) \
41static 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
50GET_STATUS(power_status, u8)
51GET_STATUS(attention_status, u8)
52GET_STATUS(latch_status, u8)
53GET_STATUS(adapter_status, u8)
54
55static 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(slot: pci_slot->hotplug, value: &value);
61 if (retval)
62 return retval;
63
64 return sysfs_emit(buf, fmt: "%d\n", value);
65}
66
67static 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
100static 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
106static 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(slot: pci_slot->hotplug, value: &value);
112 if (retval)
113 return retval;
114
115 return sysfs_emit(buf, fmt: "%d\n", value);
116}
117
118static 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
139static 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
145static 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(slot: pci_slot->hotplug, value: &value);
151 if (retval)
152 return retval;
153
154 return sysfs_emit(buf, fmt: "%d\n", value);
155}
156
157static struct pci_slot_attribute hotplug_slot_attr_latch = {
158 .attr = {.name = "latch", .mode = S_IFREG | S_IRUGO},
159 .show = latch_read_file,
160};
161
162static 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(slot: pci_slot->hotplug, value: &value);
168 if (retval)
169 return retval;
170
171 return sysfs_emit(buf, fmt: "%d\n", value);
172}
173
174static struct pci_slot_attribute hotplug_slot_attr_presence = {
175 .attr = {.name = "adapter", .mode = S_IFREG | S_IRUGO},
176 .show = presence_read_file,
177};
178
179static 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
199static 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
204static 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
213static 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
221static bool has_latch_file(struct hotplug_slot *slot)
222{
223 if (slot->ops->get_latch_status)
224 return true;
225 return false;
226}
227
228static bool has_adapter_file(struct hotplug_slot *slot)
229{
230 if (slot->ops->get_adapter_status)
231 return true;
232 return false;
233}
234
235static bool has_test_file(struct hotplug_slot *slot)
236{
237 if (slot->ops->hardware_test)
238 return true;
239 return false;
240}
241
242static 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(kobj: &pci_slot->kobj, target: kobj, name: "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(kobj: &pci_slot->kobj,
259 attr: &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(kobj: &pci_slot->kobj,
266 attr: &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(kobj: &pci_slot->kobj,
273 attr: &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(kobj: &pci_slot->kobj,
280 attr: &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(kobj: &pci_slot->kobj,
287 attr: &hotplug_slot_attr_test.attr);
288 if (retval)
289 goto exit_test;
290 }
291
292 goto exit;
293
294exit_test:
295 if (has_adapter_file(slot))
296 sysfs_remove_file(kobj: &pci_slot->kobj,
297 attr: &hotplug_slot_attr_presence.attr);
298exit_adapter:
299 if (has_latch_file(slot))
300 sysfs_remove_file(kobj: &pci_slot->kobj, attr: &hotplug_slot_attr_latch.attr);
301exit_latch:
302 if (has_attention_file(slot))
303 sysfs_remove_file(kobj: &pci_slot->kobj,
304 attr: &hotplug_slot_attr_attention.attr);
305exit_attention:
306 if (has_power_file(slot))
307 sysfs_remove_file(kobj: &pci_slot->kobj, attr: &hotplug_slot_attr_power.attr);
308exit_power:
309 sysfs_remove_link(kobj: &pci_slot->kobj, name: "module");
310exit:
311 return retval;
312}
313
314static void fs_remove_slot(struct hotplug_slot *slot, struct pci_slot *pci_slot)
315{
316 if (has_power_file(slot))
317 sysfs_remove_file(kobj: &pci_slot->kobj, attr: &hotplug_slot_attr_power.attr);
318
319 if (has_attention_file(slot))
320 sysfs_remove_file(kobj: &pci_slot->kobj,
321 attr: &hotplug_slot_attr_attention.attr);
322
323 if (has_latch_file(slot))
324 sysfs_remove_file(kobj: &pci_slot->kobj, attr: &hotplug_slot_attr_latch.attr);
325
326 if (has_adapter_file(slot))
327 sysfs_remove_file(kobj: &pci_slot->kobj,
328 attr: &hotplug_slot_attr_presence.attr);
329
330 if (has_test_file(slot))
331 sysfs_remove_file(kobj: &pci_slot->kobj, attr: &hotplug_slot_attr_test.attr);
332
333 sysfs_remove_link(kobj: &pci_slot->kobj, name: "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 */
351int __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, nr: 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}
367EXPORT_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 */
385int __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(parent: bus, slot_nr: devnr, name, hotplug: slot);
405 if (IS_ERR(ptr: pci_slot))
406 return PTR_ERR(ptr: pci_slot);
407
408 slot->pci_slot = pci_slot;
409 pci_slot->hotplug = slot;
410 return 0;
411}
412EXPORT_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 */
424int 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(kobj: &pci_slot->kobj, action: KOBJ_ADD);
439 return 0;
440}
441EXPORT_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 */
450void pci_hp_deregister(struct hotplug_slot *slot)
451{
452 pci_hp_del(slot);
453 pci_hp_destroy(slot);
454}
455EXPORT_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 */
463void pci_hp_del(struct hotplug_slot *slot)
464{
465 if (WARN_ON(!slot))
466 return;
467
468 fs_remove_slot(slot, pci_slot: slot->pci_slot);
469}
470EXPORT_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 */
481void 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(slot: pci_slot);
488}
489EXPORT_SYMBOL_GPL(pci_hp_destroy);
490
491static 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 */
510void pci_hp_ignore_link_change(struct pci_dev *pdev)
511{
512 set_bit(PCI_LINK_CHANGING, addr: &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 */
523void pci_hp_unignore_link_change(struct pci_dev *pdev)
524{
525 set_bit(PCI_LINK_CHANGED, addr: &pdev->priv_flags);
526 mb(); /* ensure pci_hp_spurious_link_change() sees either bit set */
527 clear_bit(PCI_LINK_CHANGING, addr: &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 */
552bool 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, addr: &pdev->priv_flags);
558}
559
560static 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}
572device_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 */
578module_param(debug, bool, 0644);
579MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
580