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