162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2006 Matthew Wilcox <matthew@wil.cx>
462306a36Sopenharmony_ci * Copyright (C) 2006-2009 Hewlett-Packard Development Company, L.P.
562306a36Sopenharmony_ci *	Alex Chiang <achiang@hp.com>
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/kobject.h>
962306a36Sopenharmony_ci#include <linux/slab.h>
1062306a36Sopenharmony_ci#include <linux/module.h>
1162306a36Sopenharmony_ci#include <linux/pci.h>
1262306a36Sopenharmony_ci#include <linux/err.h>
1362306a36Sopenharmony_ci#include "pci.h"
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_cistruct kset *pci_slots_kset;
1662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_slots_kset);
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_cistatic ssize_t pci_slot_attr_show(struct kobject *kobj,
1962306a36Sopenharmony_ci					struct attribute *attr, char *buf)
2062306a36Sopenharmony_ci{
2162306a36Sopenharmony_ci	struct pci_slot *slot = to_pci_slot(kobj);
2262306a36Sopenharmony_ci	struct pci_slot_attribute *attribute = to_pci_slot_attr(attr);
2362306a36Sopenharmony_ci	return attribute->show ? attribute->show(slot, buf) : -EIO;
2462306a36Sopenharmony_ci}
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_cistatic ssize_t pci_slot_attr_store(struct kobject *kobj,
2762306a36Sopenharmony_ci			struct attribute *attr, const char *buf, size_t len)
2862306a36Sopenharmony_ci{
2962306a36Sopenharmony_ci	struct pci_slot *slot = to_pci_slot(kobj);
3062306a36Sopenharmony_ci	struct pci_slot_attribute *attribute = to_pci_slot_attr(attr);
3162306a36Sopenharmony_ci	return attribute->store ? attribute->store(slot, buf, len) : -EIO;
3262306a36Sopenharmony_ci}
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_cistatic const struct sysfs_ops pci_slot_sysfs_ops = {
3562306a36Sopenharmony_ci	.show = pci_slot_attr_show,
3662306a36Sopenharmony_ci	.store = pci_slot_attr_store,
3762306a36Sopenharmony_ci};
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_cistatic ssize_t address_read_file(struct pci_slot *slot, char *buf)
4062306a36Sopenharmony_ci{
4162306a36Sopenharmony_ci	if (slot->number == 0xff)
4262306a36Sopenharmony_ci		return sysfs_emit(buf, "%04x:%02x\n",
4362306a36Sopenharmony_ci				  pci_domain_nr(slot->bus),
4462306a36Sopenharmony_ci				  slot->bus->number);
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	return sysfs_emit(buf, "%04x:%02x:%02x\n",
4762306a36Sopenharmony_ci			  pci_domain_nr(slot->bus),
4862306a36Sopenharmony_ci			  slot->bus->number,
4962306a36Sopenharmony_ci			  slot->number);
5062306a36Sopenharmony_ci}
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cistatic ssize_t bus_speed_read(enum pci_bus_speed speed, char *buf)
5362306a36Sopenharmony_ci{
5462306a36Sopenharmony_ci	return sysfs_emit(buf, "%s\n", pci_speed_string(speed));
5562306a36Sopenharmony_ci}
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_cistatic ssize_t max_speed_read_file(struct pci_slot *slot, char *buf)
5862306a36Sopenharmony_ci{
5962306a36Sopenharmony_ci	return bus_speed_read(slot->bus->max_bus_speed, buf);
6062306a36Sopenharmony_ci}
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_cistatic ssize_t cur_speed_read_file(struct pci_slot *slot, char *buf)
6362306a36Sopenharmony_ci{
6462306a36Sopenharmony_ci	return bus_speed_read(slot->bus->cur_bus_speed, buf);
6562306a36Sopenharmony_ci}
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_cistatic void pci_slot_release(struct kobject *kobj)
6862306a36Sopenharmony_ci{
6962306a36Sopenharmony_ci	struct pci_dev *dev;
7062306a36Sopenharmony_ci	struct pci_slot *slot = to_pci_slot(kobj);
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	dev_dbg(&slot->bus->dev, "dev %02x, released physical slot %s\n",
7362306a36Sopenharmony_ci		slot->number, pci_slot_name(slot));
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	down_read(&pci_bus_sem);
7662306a36Sopenharmony_ci	list_for_each_entry(dev, &slot->bus->devices, bus_list)
7762306a36Sopenharmony_ci		if (PCI_SLOT(dev->devfn) == slot->number)
7862306a36Sopenharmony_ci			dev->slot = NULL;
7962306a36Sopenharmony_ci	up_read(&pci_bus_sem);
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	list_del(&slot->list);
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	kfree(slot);
8462306a36Sopenharmony_ci}
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_cistatic struct pci_slot_attribute pci_slot_attr_address =
8762306a36Sopenharmony_ci	__ATTR(address, S_IRUGO, address_read_file, NULL);
8862306a36Sopenharmony_cistatic struct pci_slot_attribute pci_slot_attr_max_speed =
8962306a36Sopenharmony_ci	__ATTR(max_bus_speed, S_IRUGO, max_speed_read_file, NULL);
9062306a36Sopenharmony_cistatic struct pci_slot_attribute pci_slot_attr_cur_speed =
9162306a36Sopenharmony_ci	__ATTR(cur_bus_speed, S_IRUGO, cur_speed_read_file, NULL);
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_cistatic struct attribute *pci_slot_default_attrs[] = {
9462306a36Sopenharmony_ci	&pci_slot_attr_address.attr,
9562306a36Sopenharmony_ci	&pci_slot_attr_max_speed.attr,
9662306a36Sopenharmony_ci	&pci_slot_attr_cur_speed.attr,
9762306a36Sopenharmony_ci	NULL,
9862306a36Sopenharmony_ci};
9962306a36Sopenharmony_ciATTRIBUTE_GROUPS(pci_slot_default);
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_cistatic const struct kobj_type pci_slot_ktype = {
10262306a36Sopenharmony_ci	.sysfs_ops = &pci_slot_sysfs_ops,
10362306a36Sopenharmony_ci	.release = &pci_slot_release,
10462306a36Sopenharmony_ci	.default_groups = pci_slot_default_groups,
10562306a36Sopenharmony_ci};
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_cistatic char *make_slot_name(const char *name)
10862306a36Sopenharmony_ci{
10962306a36Sopenharmony_ci	char *new_name;
11062306a36Sopenharmony_ci	int len, max, dup;
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	new_name = kstrdup(name, GFP_KERNEL);
11362306a36Sopenharmony_ci	if (!new_name)
11462306a36Sopenharmony_ci		return NULL;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	/*
11762306a36Sopenharmony_ci	 * Make sure we hit the realloc case the first time through the
11862306a36Sopenharmony_ci	 * loop.  'len' will be strlen(name) + 3 at that point which is
11962306a36Sopenharmony_ci	 * enough space for "name-X" and the trailing NUL.
12062306a36Sopenharmony_ci	 */
12162306a36Sopenharmony_ci	len = strlen(name) + 2;
12262306a36Sopenharmony_ci	max = 1;
12362306a36Sopenharmony_ci	dup = 1;
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	for (;;) {
12662306a36Sopenharmony_ci		struct kobject *dup_slot;
12762306a36Sopenharmony_ci		dup_slot = kset_find_obj(pci_slots_kset, new_name);
12862306a36Sopenharmony_ci		if (!dup_slot)
12962306a36Sopenharmony_ci			break;
13062306a36Sopenharmony_ci		kobject_put(dup_slot);
13162306a36Sopenharmony_ci		if (dup == max) {
13262306a36Sopenharmony_ci			len++;
13362306a36Sopenharmony_ci			max *= 10;
13462306a36Sopenharmony_ci			kfree(new_name);
13562306a36Sopenharmony_ci			new_name = kmalloc(len, GFP_KERNEL);
13662306a36Sopenharmony_ci			if (!new_name)
13762306a36Sopenharmony_ci				break;
13862306a36Sopenharmony_ci		}
13962306a36Sopenharmony_ci		sprintf(new_name, "%s-%d", name, dup++);
14062306a36Sopenharmony_ci	}
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	return new_name;
14362306a36Sopenharmony_ci}
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_cistatic int rename_slot(struct pci_slot *slot, const char *name)
14662306a36Sopenharmony_ci{
14762306a36Sopenharmony_ci	int result = 0;
14862306a36Sopenharmony_ci	char *slot_name;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	if (strcmp(pci_slot_name(slot), name) == 0)
15162306a36Sopenharmony_ci		return result;
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	slot_name = make_slot_name(name);
15462306a36Sopenharmony_ci	if (!slot_name)
15562306a36Sopenharmony_ci		return -ENOMEM;
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	result = kobject_rename(&slot->kobj, slot_name);
15862306a36Sopenharmony_ci	kfree(slot_name);
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	return result;
16162306a36Sopenharmony_ci}
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_civoid pci_dev_assign_slot(struct pci_dev *dev)
16462306a36Sopenharmony_ci{
16562306a36Sopenharmony_ci	struct pci_slot *slot;
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	mutex_lock(&pci_slot_mutex);
16862306a36Sopenharmony_ci	list_for_each_entry(slot, &dev->bus->slots, list)
16962306a36Sopenharmony_ci		if (PCI_SLOT(dev->devfn) == slot->number)
17062306a36Sopenharmony_ci			dev->slot = slot;
17162306a36Sopenharmony_ci	mutex_unlock(&pci_slot_mutex);
17262306a36Sopenharmony_ci}
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_cistatic struct pci_slot *get_slot(struct pci_bus *parent, int slot_nr)
17562306a36Sopenharmony_ci{
17662306a36Sopenharmony_ci	struct pci_slot *slot;
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	/* We already hold pci_slot_mutex */
17962306a36Sopenharmony_ci	list_for_each_entry(slot, &parent->slots, list)
18062306a36Sopenharmony_ci		if (slot->number == slot_nr) {
18162306a36Sopenharmony_ci			kobject_get(&slot->kobj);
18262306a36Sopenharmony_ci			return slot;
18362306a36Sopenharmony_ci		}
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	return NULL;
18662306a36Sopenharmony_ci}
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci/**
18962306a36Sopenharmony_ci * pci_create_slot - create or increment refcount for physical PCI slot
19062306a36Sopenharmony_ci * @parent: struct pci_bus of parent bridge
19162306a36Sopenharmony_ci * @slot_nr: PCI_SLOT(pci_dev->devfn) or -1 for placeholder
19262306a36Sopenharmony_ci * @name: user visible string presented in /sys/bus/pci/slots/<name>
19362306a36Sopenharmony_ci * @hotplug: set if caller is hotplug driver, NULL otherwise
19462306a36Sopenharmony_ci *
19562306a36Sopenharmony_ci * PCI slots have first class attributes such as address, speed, width,
19662306a36Sopenharmony_ci * and a &struct pci_slot is used to manage them. This interface will
19762306a36Sopenharmony_ci * either return a new &struct pci_slot to the caller, or if the pci_slot
19862306a36Sopenharmony_ci * already exists, its refcount will be incremented.
19962306a36Sopenharmony_ci *
20062306a36Sopenharmony_ci * Slots are uniquely identified by a @pci_bus, @slot_nr tuple.
20162306a36Sopenharmony_ci *
20262306a36Sopenharmony_ci * There are known platforms with broken firmware that assign the same
20362306a36Sopenharmony_ci * name to multiple slots. Workaround these broken platforms by renaming
20462306a36Sopenharmony_ci * the slots on behalf of the caller. If firmware assigns name N to
20562306a36Sopenharmony_ci * multiple slots:
20662306a36Sopenharmony_ci *
20762306a36Sopenharmony_ci * The first slot is assigned N
20862306a36Sopenharmony_ci * The second slot is assigned N-1
20962306a36Sopenharmony_ci * The third slot is assigned N-2
21062306a36Sopenharmony_ci * etc.
21162306a36Sopenharmony_ci *
21262306a36Sopenharmony_ci * Placeholder slots:
21362306a36Sopenharmony_ci * In most cases, @pci_bus, @slot_nr will be sufficient to uniquely identify
21462306a36Sopenharmony_ci * a slot. There is one notable exception - pSeries (rpaphp), where the
21562306a36Sopenharmony_ci * @slot_nr cannot be determined until a device is actually inserted into
21662306a36Sopenharmony_ci * the slot. In this scenario, the caller may pass -1 for @slot_nr.
21762306a36Sopenharmony_ci *
21862306a36Sopenharmony_ci * The following semantics are imposed when the caller passes @slot_nr ==
21962306a36Sopenharmony_ci * -1. First, we no longer check for an existing %struct pci_slot, as there
22062306a36Sopenharmony_ci * may be many slots with @slot_nr of -1.  The other change in semantics is
22162306a36Sopenharmony_ci * user-visible, which is the 'address' parameter presented in sysfs will
22262306a36Sopenharmony_ci * consist solely of a dddd:bb tuple, where dddd is the PCI domain of the
22362306a36Sopenharmony_ci * %struct pci_bus and bb is the bus number. In other words, the devfn of
22462306a36Sopenharmony_ci * the 'placeholder' slot will not be displayed.
22562306a36Sopenharmony_ci */
22662306a36Sopenharmony_cistruct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr,
22762306a36Sopenharmony_ci				 const char *name,
22862306a36Sopenharmony_ci				 struct hotplug_slot *hotplug)
22962306a36Sopenharmony_ci{
23062306a36Sopenharmony_ci	struct pci_dev *dev;
23162306a36Sopenharmony_ci	struct pci_slot *slot;
23262306a36Sopenharmony_ci	int err = 0;
23362306a36Sopenharmony_ci	char *slot_name = NULL;
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	mutex_lock(&pci_slot_mutex);
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	if (slot_nr == -1)
23862306a36Sopenharmony_ci		goto placeholder;
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	/*
24162306a36Sopenharmony_ci	 * Hotplug drivers are allowed to rename an existing slot,
24262306a36Sopenharmony_ci	 * but only if not already claimed.
24362306a36Sopenharmony_ci	 */
24462306a36Sopenharmony_ci	slot = get_slot(parent, slot_nr);
24562306a36Sopenharmony_ci	if (slot) {
24662306a36Sopenharmony_ci		if (hotplug) {
24762306a36Sopenharmony_ci			if ((err = slot->hotplug ? -EBUSY : 0)
24862306a36Sopenharmony_ci			     || (err = rename_slot(slot, name))) {
24962306a36Sopenharmony_ci				kobject_put(&slot->kobj);
25062306a36Sopenharmony_ci				slot = NULL;
25162306a36Sopenharmony_ci				goto err;
25262306a36Sopenharmony_ci			}
25362306a36Sopenharmony_ci		}
25462306a36Sopenharmony_ci		goto out;
25562306a36Sopenharmony_ci	}
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ciplaceholder:
25862306a36Sopenharmony_ci	slot = kzalloc(sizeof(*slot), GFP_KERNEL);
25962306a36Sopenharmony_ci	if (!slot) {
26062306a36Sopenharmony_ci		err = -ENOMEM;
26162306a36Sopenharmony_ci		goto err;
26262306a36Sopenharmony_ci	}
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	slot->bus = parent;
26562306a36Sopenharmony_ci	slot->number = slot_nr;
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	slot->kobj.kset = pci_slots_kset;
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	slot_name = make_slot_name(name);
27062306a36Sopenharmony_ci	if (!slot_name) {
27162306a36Sopenharmony_ci		err = -ENOMEM;
27262306a36Sopenharmony_ci		kfree(slot);
27362306a36Sopenharmony_ci		goto err;
27462306a36Sopenharmony_ci	}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	INIT_LIST_HEAD(&slot->list);
27762306a36Sopenharmony_ci	list_add(&slot->list, &parent->slots);
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	err = kobject_init_and_add(&slot->kobj, &pci_slot_ktype, NULL,
28062306a36Sopenharmony_ci				   "%s", slot_name);
28162306a36Sopenharmony_ci	if (err) {
28262306a36Sopenharmony_ci		kobject_put(&slot->kobj);
28362306a36Sopenharmony_ci		goto err;
28462306a36Sopenharmony_ci	}
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	down_read(&pci_bus_sem);
28762306a36Sopenharmony_ci	list_for_each_entry(dev, &parent->devices, bus_list)
28862306a36Sopenharmony_ci		if (PCI_SLOT(dev->devfn) == slot_nr)
28962306a36Sopenharmony_ci			dev->slot = slot;
29062306a36Sopenharmony_ci	up_read(&pci_bus_sem);
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	dev_dbg(&parent->dev, "dev %02x, created physical slot %s\n",
29362306a36Sopenharmony_ci		slot_nr, pci_slot_name(slot));
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ciout:
29662306a36Sopenharmony_ci	kfree(slot_name);
29762306a36Sopenharmony_ci	mutex_unlock(&pci_slot_mutex);
29862306a36Sopenharmony_ci	return slot;
29962306a36Sopenharmony_cierr:
30062306a36Sopenharmony_ci	slot = ERR_PTR(err);
30162306a36Sopenharmony_ci	goto out;
30262306a36Sopenharmony_ci}
30362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_create_slot);
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci/**
30662306a36Sopenharmony_ci * pci_destroy_slot - decrement refcount for physical PCI slot
30762306a36Sopenharmony_ci * @slot: struct pci_slot to decrement
30862306a36Sopenharmony_ci *
30962306a36Sopenharmony_ci * %struct pci_slot is refcounted, so destroying them is really easy; we
31062306a36Sopenharmony_ci * just call kobject_put on its kobj and let our release methods do the
31162306a36Sopenharmony_ci * rest.
31262306a36Sopenharmony_ci */
31362306a36Sopenharmony_civoid pci_destroy_slot(struct pci_slot *slot)
31462306a36Sopenharmony_ci{
31562306a36Sopenharmony_ci	dev_dbg(&slot->bus->dev, "dev %02x, dec refcount to %d\n",
31662306a36Sopenharmony_ci		slot->number, kref_read(&slot->kobj.kref) - 1);
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	mutex_lock(&pci_slot_mutex);
31962306a36Sopenharmony_ci	kobject_put(&slot->kobj);
32062306a36Sopenharmony_ci	mutex_unlock(&pci_slot_mutex);
32162306a36Sopenharmony_ci}
32262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_destroy_slot);
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci#if defined(CONFIG_HOTPLUG_PCI) || defined(CONFIG_HOTPLUG_PCI_MODULE)
32562306a36Sopenharmony_ci#include <linux/pci_hotplug.h>
32662306a36Sopenharmony_ci/**
32762306a36Sopenharmony_ci * pci_hp_create_module_link - create symbolic link to hotplug driver module
32862306a36Sopenharmony_ci * @pci_slot: struct pci_slot
32962306a36Sopenharmony_ci *
33062306a36Sopenharmony_ci * Helper function for pci_hotplug_core.c to create symbolic link to
33162306a36Sopenharmony_ci * the hotplug driver module.
33262306a36Sopenharmony_ci */
33362306a36Sopenharmony_civoid pci_hp_create_module_link(struct pci_slot *pci_slot)
33462306a36Sopenharmony_ci{
33562306a36Sopenharmony_ci	struct hotplug_slot *slot = pci_slot->hotplug;
33662306a36Sopenharmony_ci	struct kobject *kobj = NULL;
33762306a36Sopenharmony_ci	int ret;
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	if (!slot || !slot->ops)
34062306a36Sopenharmony_ci		return;
34162306a36Sopenharmony_ci	kobj = kset_find_obj(module_kset, slot->mod_name);
34262306a36Sopenharmony_ci	if (!kobj)
34362306a36Sopenharmony_ci		return;
34462306a36Sopenharmony_ci	ret = sysfs_create_link(&pci_slot->kobj, kobj, "module");
34562306a36Sopenharmony_ci	if (ret)
34662306a36Sopenharmony_ci		dev_err(&pci_slot->bus->dev, "Error creating sysfs link (%d)\n",
34762306a36Sopenharmony_ci			ret);
34862306a36Sopenharmony_ci	kobject_put(kobj);
34962306a36Sopenharmony_ci}
35062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_hp_create_module_link);
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci/**
35362306a36Sopenharmony_ci * pci_hp_remove_module_link - remove symbolic link to the hotplug driver
35462306a36Sopenharmony_ci * 	module.
35562306a36Sopenharmony_ci * @pci_slot: struct pci_slot
35662306a36Sopenharmony_ci *
35762306a36Sopenharmony_ci * Helper function for pci_hotplug_core.c to remove symbolic link to
35862306a36Sopenharmony_ci * the hotplug driver module.
35962306a36Sopenharmony_ci */
36062306a36Sopenharmony_civoid pci_hp_remove_module_link(struct pci_slot *pci_slot)
36162306a36Sopenharmony_ci{
36262306a36Sopenharmony_ci	sysfs_remove_link(&pci_slot->kobj, "module");
36362306a36Sopenharmony_ci}
36462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_hp_remove_module_link);
36562306a36Sopenharmony_ci#endif
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_cistatic int pci_slot_init(void)
36862306a36Sopenharmony_ci{
36962306a36Sopenharmony_ci	struct kset *pci_bus_kset;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	pci_bus_kset = bus_get_kset(&pci_bus_type);
37262306a36Sopenharmony_ci	pci_slots_kset = kset_create_and_add("slots", NULL,
37362306a36Sopenharmony_ci						&pci_bus_kset->kobj);
37462306a36Sopenharmony_ci	if (!pci_slots_kset) {
37562306a36Sopenharmony_ci		pr_err("PCI: Slot initialization failure\n");
37662306a36Sopenharmony_ci		return -ENOMEM;
37762306a36Sopenharmony_ci	}
37862306a36Sopenharmony_ci	return 0;
37962306a36Sopenharmony_ci}
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_cisubsys_initcall(pci_slot_init);
382