18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2006 Matthew Wilcox <matthew@wil.cx> 48c2ecf20Sopenharmony_ci * Copyright (C) 2006-2009 Hewlett-Packard Development Company, L.P. 58c2ecf20Sopenharmony_ci * Alex Chiang <achiang@hp.com> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/kobject.h> 98c2ecf20Sopenharmony_ci#include <linux/slab.h> 108c2ecf20Sopenharmony_ci#include <linux/module.h> 118c2ecf20Sopenharmony_ci#include <linux/pci.h> 128c2ecf20Sopenharmony_ci#include <linux/err.h> 138c2ecf20Sopenharmony_ci#include "pci.h" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_cistruct kset *pci_slots_kset; 168c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_slots_kset); 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_cistatic ssize_t pci_slot_attr_show(struct kobject *kobj, 198c2ecf20Sopenharmony_ci struct attribute *attr, char *buf) 208c2ecf20Sopenharmony_ci{ 218c2ecf20Sopenharmony_ci struct pci_slot *slot = to_pci_slot(kobj); 228c2ecf20Sopenharmony_ci struct pci_slot_attribute *attribute = to_pci_slot_attr(attr); 238c2ecf20Sopenharmony_ci return attribute->show ? attribute->show(slot, buf) : -EIO; 248c2ecf20Sopenharmony_ci} 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistatic ssize_t pci_slot_attr_store(struct kobject *kobj, 278c2ecf20Sopenharmony_ci struct attribute *attr, const char *buf, size_t len) 288c2ecf20Sopenharmony_ci{ 298c2ecf20Sopenharmony_ci struct pci_slot *slot = to_pci_slot(kobj); 308c2ecf20Sopenharmony_ci struct pci_slot_attribute *attribute = to_pci_slot_attr(attr); 318c2ecf20Sopenharmony_ci return attribute->store ? attribute->store(slot, buf, len) : -EIO; 328c2ecf20Sopenharmony_ci} 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic const struct sysfs_ops pci_slot_sysfs_ops = { 358c2ecf20Sopenharmony_ci .show = pci_slot_attr_show, 368c2ecf20Sopenharmony_ci .store = pci_slot_attr_store, 378c2ecf20Sopenharmony_ci}; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic ssize_t address_read_file(struct pci_slot *slot, char *buf) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci if (slot->number == 0xff) 428c2ecf20Sopenharmony_ci return sprintf(buf, "%04x:%02x\n", 438c2ecf20Sopenharmony_ci pci_domain_nr(slot->bus), 448c2ecf20Sopenharmony_ci slot->bus->number); 458c2ecf20Sopenharmony_ci else 468c2ecf20Sopenharmony_ci return sprintf(buf, "%04x:%02x:%02x\n", 478c2ecf20Sopenharmony_ci pci_domain_nr(slot->bus), 488c2ecf20Sopenharmony_ci slot->bus->number, 498c2ecf20Sopenharmony_ci slot->number); 508c2ecf20Sopenharmony_ci} 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistatic ssize_t bus_speed_read(enum pci_bus_speed speed, char *buf) 538c2ecf20Sopenharmony_ci{ 548c2ecf20Sopenharmony_ci return sprintf(buf, "%s\n", pci_speed_string(speed)); 558c2ecf20Sopenharmony_ci} 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic ssize_t max_speed_read_file(struct pci_slot *slot, char *buf) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci return bus_speed_read(slot->bus->max_bus_speed, buf); 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic ssize_t cur_speed_read_file(struct pci_slot *slot, char *buf) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci return bus_speed_read(slot->bus->cur_bus_speed, buf); 658c2ecf20Sopenharmony_ci} 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistatic void pci_slot_release(struct kobject *kobj) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci struct pci_dev *dev; 708c2ecf20Sopenharmony_ci struct pci_slot *slot = to_pci_slot(kobj); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci dev_dbg(&slot->bus->dev, "dev %02x, released physical slot %s\n", 738c2ecf20Sopenharmony_ci slot->number, pci_slot_name(slot)); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci down_read(&pci_bus_sem); 768c2ecf20Sopenharmony_ci list_for_each_entry(dev, &slot->bus->devices, bus_list) 778c2ecf20Sopenharmony_ci if (PCI_SLOT(dev->devfn) == slot->number) 788c2ecf20Sopenharmony_ci dev->slot = NULL; 798c2ecf20Sopenharmony_ci up_read(&pci_bus_sem); 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci list_del(&slot->list); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci kfree(slot); 848c2ecf20Sopenharmony_ci} 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistatic struct pci_slot_attribute pci_slot_attr_address = 878c2ecf20Sopenharmony_ci __ATTR(address, S_IRUGO, address_read_file, NULL); 888c2ecf20Sopenharmony_cistatic struct pci_slot_attribute pci_slot_attr_max_speed = 898c2ecf20Sopenharmony_ci __ATTR(max_bus_speed, S_IRUGO, max_speed_read_file, NULL); 908c2ecf20Sopenharmony_cistatic struct pci_slot_attribute pci_slot_attr_cur_speed = 918c2ecf20Sopenharmony_ci __ATTR(cur_bus_speed, S_IRUGO, cur_speed_read_file, NULL); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistatic struct attribute *pci_slot_default_attrs[] = { 948c2ecf20Sopenharmony_ci &pci_slot_attr_address.attr, 958c2ecf20Sopenharmony_ci &pci_slot_attr_max_speed.attr, 968c2ecf20Sopenharmony_ci &pci_slot_attr_cur_speed.attr, 978c2ecf20Sopenharmony_ci NULL, 988c2ecf20Sopenharmony_ci}; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic struct kobj_type pci_slot_ktype = { 1018c2ecf20Sopenharmony_ci .sysfs_ops = &pci_slot_sysfs_ops, 1028c2ecf20Sopenharmony_ci .release = &pci_slot_release, 1038c2ecf20Sopenharmony_ci .default_attrs = pci_slot_default_attrs, 1048c2ecf20Sopenharmony_ci}; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic char *make_slot_name(const char *name) 1078c2ecf20Sopenharmony_ci{ 1088c2ecf20Sopenharmony_ci char *new_name; 1098c2ecf20Sopenharmony_ci int len, max, dup; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci new_name = kstrdup(name, GFP_KERNEL); 1128c2ecf20Sopenharmony_ci if (!new_name) 1138c2ecf20Sopenharmony_ci return NULL; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci /* 1168c2ecf20Sopenharmony_ci * Make sure we hit the realloc case the first time through the 1178c2ecf20Sopenharmony_ci * loop. 'len' will be strlen(name) + 3 at that point which is 1188c2ecf20Sopenharmony_ci * enough space for "name-X" and the trailing NUL. 1198c2ecf20Sopenharmony_ci */ 1208c2ecf20Sopenharmony_ci len = strlen(name) + 2; 1218c2ecf20Sopenharmony_ci max = 1; 1228c2ecf20Sopenharmony_ci dup = 1; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci for (;;) { 1258c2ecf20Sopenharmony_ci struct kobject *dup_slot; 1268c2ecf20Sopenharmony_ci dup_slot = kset_find_obj(pci_slots_kset, new_name); 1278c2ecf20Sopenharmony_ci if (!dup_slot) 1288c2ecf20Sopenharmony_ci break; 1298c2ecf20Sopenharmony_ci kobject_put(dup_slot); 1308c2ecf20Sopenharmony_ci if (dup == max) { 1318c2ecf20Sopenharmony_ci len++; 1328c2ecf20Sopenharmony_ci max *= 10; 1338c2ecf20Sopenharmony_ci kfree(new_name); 1348c2ecf20Sopenharmony_ci new_name = kmalloc(len, GFP_KERNEL); 1358c2ecf20Sopenharmony_ci if (!new_name) 1368c2ecf20Sopenharmony_ci break; 1378c2ecf20Sopenharmony_ci } 1388c2ecf20Sopenharmony_ci sprintf(new_name, "%s-%d", name, dup++); 1398c2ecf20Sopenharmony_ci } 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci return new_name; 1428c2ecf20Sopenharmony_ci} 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_cistatic int rename_slot(struct pci_slot *slot, const char *name) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci int result = 0; 1478c2ecf20Sopenharmony_ci char *slot_name; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci if (strcmp(pci_slot_name(slot), name) == 0) 1508c2ecf20Sopenharmony_ci return result; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci slot_name = make_slot_name(name); 1538c2ecf20Sopenharmony_ci if (!slot_name) 1548c2ecf20Sopenharmony_ci return -ENOMEM; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci result = kobject_rename(&slot->kobj, slot_name); 1578c2ecf20Sopenharmony_ci kfree(slot_name); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci return result; 1608c2ecf20Sopenharmony_ci} 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_civoid pci_dev_assign_slot(struct pci_dev *dev) 1638c2ecf20Sopenharmony_ci{ 1648c2ecf20Sopenharmony_ci struct pci_slot *slot; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci mutex_lock(&pci_slot_mutex); 1678c2ecf20Sopenharmony_ci list_for_each_entry(slot, &dev->bus->slots, list) 1688c2ecf20Sopenharmony_ci if (PCI_SLOT(dev->devfn) == slot->number) 1698c2ecf20Sopenharmony_ci dev->slot = slot; 1708c2ecf20Sopenharmony_ci mutex_unlock(&pci_slot_mutex); 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cistatic struct pci_slot *get_slot(struct pci_bus *parent, int slot_nr) 1748c2ecf20Sopenharmony_ci{ 1758c2ecf20Sopenharmony_ci struct pci_slot *slot; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci /* We already hold pci_slot_mutex */ 1788c2ecf20Sopenharmony_ci list_for_each_entry(slot, &parent->slots, list) 1798c2ecf20Sopenharmony_ci if (slot->number == slot_nr) { 1808c2ecf20Sopenharmony_ci kobject_get(&slot->kobj); 1818c2ecf20Sopenharmony_ci return slot; 1828c2ecf20Sopenharmony_ci } 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci return NULL; 1858c2ecf20Sopenharmony_ci} 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci/** 1888c2ecf20Sopenharmony_ci * pci_create_slot - create or increment refcount for physical PCI slot 1898c2ecf20Sopenharmony_ci * @parent: struct pci_bus of parent bridge 1908c2ecf20Sopenharmony_ci * @slot_nr: PCI_SLOT(pci_dev->devfn) or -1 for placeholder 1918c2ecf20Sopenharmony_ci * @name: user visible string presented in /sys/bus/pci/slots/<name> 1928c2ecf20Sopenharmony_ci * @hotplug: set if caller is hotplug driver, NULL otherwise 1938c2ecf20Sopenharmony_ci * 1948c2ecf20Sopenharmony_ci * PCI slots have first class attributes such as address, speed, width, 1958c2ecf20Sopenharmony_ci * and a &struct pci_slot is used to manage them. This interface will 1968c2ecf20Sopenharmony_ci * either return a new &struct pci_slot to the caller, or if the pci_slot 1978c2ecf20Sopenharmony_ci * already exists, its refcount will be incremented. 1988c2ecf20Sopenharmony_ci * 1998c2ecf20Sopenharmony_ci * Slots are uniquely identified by a @pci_bus, @slot_nr tuple. 2008c2ecf20Sopenharmony_ci * 2018c2ecf20Sopenharmony_ci * There are known platforms with broken firmware that assign the same 2028c2ecf20Sopenharmony_ci * name to multiple slots. Workaround these broken platforms by renaming 2038c2ecf20Sopenharmony_ci * the slots on behalf of the caller. If firmware assigns name N to 2048c2ecf20Sopenharmony_ci * multiple slots: 2058c2ecf20Sopenharmony_ci * 2068c2ecf20Sopenharmony_ci * The first slot is assigned N 2078c2ecf20Sopenharmony_ci * The second slot is assigned N-1 2088c2ecf20Sopenharmony_ci * The third slot is assigned N-2 2098c2ecf20Sopenharmony_ci * etc. 2108c2ecf20Sopenharmony_ci * 2118c2ecf20Sopenharmony_ci * Placeholder slots: 2128c2ecf20Sopenharmony_ci * In most cases, @pci_bus, @slot_nr will be sufficient to uniquely identify 2138c2ecf20Sopenharmony_ci * a slot. There is one notable exception - pSeries (rpaphp), where the 2148c2ecf20Sopenharmony_ci * @slot_nr cannot be determined until a device is actually inserted into 2158c2ecf20Sopenharmony_ci * the slot. In this scenario, the caller may pass -1 for @slot_nr. 2168c2ecf20Sopenharmony_ci * 2178c2ecf20Sopenharmony_ci * The following semantics are imposed when the caller passes @slot_nr == 2188c2ecf20Sopenharmony_ci * -1. First, we no longer check for an existing %struct pci_slot, as there 2198c2ecf20Sopenharmony_ci * may be many slots with @slot_nr of -1. The other change in semantics is 2208c2ecf20Sopenharmony_ci * user-visible, which is the 'address' parameter presented in sysfs will 2218c2ecf20Sopenharmony_ci * consist solely of a dddd:bb tuple, where dddd is the PCI domain of the 2228c2ecf20Sopenharmony_ci * %struct pci_bus and bb is the bus number. In other words, the devfn of 2238c2ecf20Sopenharmony_ci * the 'placeholder' slot will not be displayed. 2248c2ecf20Sopenharmony_ci */ 2258c2ecf20Sopenharmony_cistruct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr, 2268c2ecf20Sopenharmony_ci const char *name, 2278c2ecf20Sopenharmony_ci struct hotplug_slot *hotplug) 2288c2ecf20Sopenharmony_ci{ 2298c2ecf20Sopenharmony_ci struct pci_dev *dev; 2308c2ecf20Sopenharmony_ci struct pci_slot *slot; 2318c2ecf20Sopenharmony_ci int err = 0; 2328c2ecf20Sopenharmony_ci char *slot_name = NULL; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci mutex_lock(&pci_slot_mutex); 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci if (slot_nr == -1) 2378c2ecf20Sopenharmony_ci goto placeholder; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci /* 2408c2ecf20Sopenharmony_ci * Hotplug drivers are allowed to rename an existing slot, 2418c2ecf20Sopenharmony_ci * but only if not already claimed. 2428c2ecf20Sopenharmony_ci */ 2438c2ecf20Sopenharmony_ci slot = get_slot(parent, slot_nr); 2448c2ecf20Sopenharmony_ci if (slot) { 2458c2ecf20Sopenharmony_ci if (hotplug) { 2468c2ecf20Sopenharmony_ci if ((err = slot->hotplug ? -EBUSY : 0) 2478c2ecf20Sopenharmony_ci || (err = rename_slot(slot, name))) { 2488c2ecf20Sopenharmony_ci kobject_put(&slot->kobj); 2498c2ecf20Sopenharmony_ci slot = NULL; 2508c2ecf20Sopenharmony_ci goto err; 2518c2ecf20Sopenharmony_ci } 2528c2ecf20Sopenharmony_ci } 2538c2ecf20Sopenharmony_ci goto out; 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ciplaceholder: 2578c2ecf20Sopenharmony_ci slot = kzalloc(sizeof(*slot), GFP_KERNEL); 2588c2ecf20Sopenharmony_ci if (!slot) { 2598c2ecf20Sopenharmony_ci err = -ENOMEM; 2608c2ecf20Sopenharmony_ci goto err; 2618c2ecf20Sopenharmony_ci } 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci slot->bus = parent; 2648c2ecf20Sopenharmony_ci slot->number = slot_nr; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci slot->kobj.kset = pci_slots_kset; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci slot_name = make_slot_name(name); 2698c2ecf20Sopenharmony_ci if (!slot_name) { 2708c2ecf20Sopenharmony_ci err = -ENOMEM; 2718c2ecf20Sopenharmony_ci kfree(slot); 2728c2ecf20Sopenharmony_ci goto err; 2738c2ecf20Sopenharmony_ci } 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&slot->list); 2768c2ecf20Sopenharmony_ci list_add(&slot->list, &parent->slots); 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci err = kobject_init_and_add(&slot->kobj, &pci_slot_ktype, NULL, 2798c2ecf20Sopenharmony_ci "%s", slot_name); 2808c2ecf20Sopenharmony_ci if (err) { 2818c2ecf20Sopenharmony_ci kobject_put(&slot->kobj); 2828c2ecf20Sopenharmony_ci goto err; 2838c2ecf20Sopenharmony_ci } 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci down_read(&pci_bus_sem); 2868c2ecf20Sopenharmony_ci list_for_each_entry(dev, &parent->devices, bus_list) 2878c2ecf20Sopenharmony_ci if (PCI_SLOT(dev->devfn) == slot_nr) 2888c2ecf20Sopenharmony_ci dev->slot = slot; 2898c2ecf20Sopenharmony_ci up_read(&pci_bus_sem); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci dev_dbg(&parent->dev, "dev %02x, created physical slot %s\n", 2928c2ecf20Sopenharmony_ci slot_nr, pci_slot_name(slot)); 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ciout: 2958c2ecf20Sopenharmony_ci kfree(slot_name); 2968c2ecf20Sopenharmony_ci mutex_unlock(&pci_slot_mutex); 2978c2ecf20Sopenharmony_ci return slot; 2988c2ecf20Sopenharmony_cierr: 2998c2ecf20Sopenharmony_ci slot = ERR_PTR(err); 3008c2ecf20Sopenharmony_ci goto out; 3018c2ecf20Sopenharmony_ci} 3028c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_create_slot); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci/** 3058c2ecf20Sopenharmony_ci * pci_destroy_slot - decrement refcount for physical PCI slot 3068c2ecf20Sopenharmony_ci * @slot: struct pci_slot to decrement 3078c2ecf20Sopenharmony_ci * 3088c2ecf20Sopenharmony_ci * %struct pci_slot is refcounted, so destroying them is really easy; we 3098c2ecf20Sopenharmony_ci * just call kobject_put on its kobj and let our release methods do the 3108c2ecf20Sopenharmony_ci * rest. 3118c2ecf20Sopenharmony_ci */ 3128c2ecf20Sopenharmony_civoid pci_destroy_slot(struct pci_slot *slot) 3138c2ecf20Sopenharmony_ci{ 3148c2ecf20Sopenharmony_ci dev_dbg(&slot->bus->dev, "dev %02x, dec refcount to %d\n", 3158c2ecf20Sopenharmony_ci slot->number, kref_read(&slot->kobj.kref) - 1); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci mutex_lock(&pci_slot_mutex); 3188c2ecf20Sopenharmony_ci kobject_put(&slot->kobj); 3198c2ecf20Sopenharmony_ci mutex_unlock(&pci_slot_mutex); 3208c2ecf20Sopenharmony_ci} 3218c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_destroy_slot); 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci#if defined(CONFIG_HOTPLUG_PCI) || defined(CONFIG_HOTPLUG_PCI_MODULE) 3248c2ecf20Sopenharmony_ci#include <linux/pci_hotplug.h> 3258c2ecf20Sopenharmony_ci/** 3268c2ecf20Sopenharmony_ci * pci_hp_create_link - create symbolic link to the hotplug driver module. 3278c2ecf20Sopenharmony_ci * @pci_slot: struct pci_slot 3288c2ecf20Sopenharmony_ci * 3298c2ecf20Sopenharmony_ci * Helper function for pci_hotplug_core.c to create symbolic link to 3308c2ecf20Sopenharmony_ci * the hotplug driver module. 3318c2ecf20Sopenharmony_ci */ 3328c2ecf20Sopenharmony_civoid pci_hp_create_module_link(struct pci_slot *pci_slot) 3338c2ecf20Sopenharmony_ci{ 3348c2ecf20Sopenharmony_ci struct hotplug_slot *slot = pci_slot->hotplug; 3358c2ecf20Sopenharmony_ci struct kobject *kobj = NULL; 3368c2ecf20Sopenharmony_ci int ret; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci if (!slot || !slot->ops) 3398c2ecf20Sopenharmony_ci return; 3408c2ecf20Sopenharmony_ci kobj = kset_find_obj(module_kset, slot->mod_name); 3418c2ecf20Sopenharmony_ci if (!kobj) 3428c2ecf20Sopenharmony_ci return; 3438c2ecf20Sopenharmony_ci ret = sysfs_create_link(&pci_slot->kobj, kobj, "module"); 3448c2ecf20Sopenharmony_ci if (ret) 3458c2ecf20Sopenharmony_ci dev_err(&pci_slot->bus->dev, "Error creating sysfs link (%d)\n", 3468c2ecf20Sopenharmony_ci ret); 3478c2ecf20Sopenharmony_ci kobject_put(kobj); 3488c2ecf20Sopenharmony_ci} 3498c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_hp_create_module_link); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci/** 3528c2ecf20Sopenharmony_ci * pci_hp_remove_link - remove symbolic link to the hotplug driver module. 3538c2ecf20Sopenharmony_ci * @pci_slot: struct pci_slot 3548c2ecf20Sopenharmony_ci * 3558c2ecf20Sopenharmony_ci * Helper function for pci_hotplug_core.c to remove symbolic link to 3568c2ecf20Sopenharmony_ci * the hotplug driver module. 3578c2ecf20Sopenharmony_ci */ 3588c2ecf20Sopenharmony_civoid pci_hp_remove_module_link(struct pci_slot *pci_slot) 3598c2ecf20Sopenharmony_ci{ 3608c2ecf20Sopenharmony_ci sysfs_remove_link(&pci_slot->kobj, "module"); 3618c2ecf20Sopenharmony_ci} 3628c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_hp_remove_module_link); 3638c2ecf20Sopenharmony_ci#endif 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_cistatic int pci_slot_init(void) 3668c2ecf20Sopenharmony_ci{ 3678c2ecf20Sopenharmony_ci struct kset *pci_bus_kset; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci pci_bus_kset = bus_get_kset(&pci_bus_type); 3708c2ecf20Sopenharmony_ci pci_slots_kset = kset_create_and_add("slots", NULL, 3718c2ecf20Sopenharmony_ci &pci_bus_kset->kobj); 3728c2ecf20Sopenharmony_ci if (!pci_slots_kset) { 3738c2ecf20Sopenharmony_ci pr_err("PCI: Slot initialization failure\n"); 3748c2ecf20Sopenharmony_ci return -ENOMEM; 3758c2ecf20Sopenharmony_ci } 3768c2ecf20Sopenharmony_ci return 0; 3778c2ecf20Sopenharmony_ci} 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_cisubsys_initcall(pci_slot_init); 380