162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright IBM Corp. 2020
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Author(s):
662306a36Sopenharmony_ci *   Pierre Morel <pmorel@linux.ibm.com>
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#define KMSG_COMPONENT "zpci"
1162306a36Sopenharmony_ci#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <linux/kernel.h>
1462306a36Sopenharmony_ci#include <linux/slab.h>
1562306a36Sopenharmony_ci#include <linux/err.h>
1662306a36Sopenharmony_ci#include <linux/export.h>
1762306a36Sopenharmony_ci#include <linux/delay.h>
1862306a36Sopenharmony_ci#include <linux/seq_file.h>
1962306a36Sopenharmony_ci#include <linux/jump_label.h>
2062306a36Sopenharmony_ci#include <linux/pci.h>
2162306a36Sopenharmony_ci#include <linux/printk.h>
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#include <asm/pci_clp.h>
2462306a36Sopenharmony_ci#include <asm/pci_dma.h>
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#include "pci_bus.h"
2762306a36Sopenharmony_ci#include "pci_iov.h"
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_cistatic LIST_HEAD(zbus_list);
3062306a36Sopenharmony_cistatic DEFINE_MUTEX(zbus_list_lock);
3162306a36Sopenharmony_cistatic int zpci_nb_devices;
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci/* zpci_bus_prepare_device - Prepare a zPCI function for scanning
3462306a36Sopenharmony_ci * @zdev: the zPCI function to be prepared
3562306a36Sopenharmony_ci *
3662306a36Sopenharmony_ci * The PCI resources for the function are set up and added to its zbus and the
3762306a36Sopenharmony_ci * function is enabled. The function must be added to a zbus which must have
3862306a36Sopenharmony_ci * a PCI bus created. If an error occurs the zPCI function is not enabled.
3962306a36Sopenharmony_ci *
4062306a36Sopenharmony_ci * Return: 0 on success, an error code otherwise
4162306a36Sopenharmony_ci */
4262306a36Sopenharmony_cistatic int zpci_bus_prepare_device(struct zpci_dev *zdev)
4362306a36Sopenharmony_ci{
4462306a36Sopenharmony_ci	int rc, i;
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	if (!zdev_enabled(zdev)) {
4762306a36Sopenharmony_ci		rc = zpci_enable_device(zdev);
4862306a36Sopenharmony_ci		if (rc)
4962306a36Sopenharmony_ci			return rc;
5062306a36Sopenharmony_ci		rc = zpci_dma_init_device(zdev);
5162306a36Sopenharmony_ci		if (rc) {
5262306a36Sopenharmony_ci			zpci_disable_device(zdev);
5362306a36Sopenharmony_ci			return rc;
5462306a36Sopenharmony_ci		}
5562306a36Sopenharmony_ci	}
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	if (!zdev->has_resources) {
5862306a36Sopenharmony_ci		zpci_setup_bus_resources(zdev);
5962306a36Sopenharmony_ci		for (i = 0; i < PCI_STD_NUM_BARS; i++) {
6062306a36Sopenharmony_ci			if (zdev->bars[i].res)
6162306a36Sopenharmony_ci				pci_bus_add_resource(zdev->zbus->bus, zdev->bars[i].res, 0);
6262306a36Sopenharmony_ci		}
6362306a36Sopenharmony_ci	}
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	return 0;
6662306a36Sopenharmony_ci}
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci/* zpci_bus_scan_device - Scan a single device adding it to the PCI core
6962306a36Sopenharmony_ci * @zdev: the zdev to be scanned
7062306a36Sopenharmony_ci *
7162306a36Sopenharmony_ci * Scans the PCI function making it available to the common PCI code.
7262306a36Sopenharmony_ci *
7362306a36Sopenharmony_ci * Return: 0 on success, an error value otherwise
7462306a36Sopenharmony_ci */
7562306a36Sopenharmony_ciint zpci_bus_scan_device(struct zpci_dev *zdev)
7662306a36Sopenharmony_ci{
7762306a36Sopenharmony_ci	struct pci_dev *pdev;
7862306a36Sopenharmony_ci	int rc;
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	rc = zpci_bus_prepare_device(zdev);
8162306a36Sopenharmony_ci	if (rc)
8262306a36Sopenharmony_ci		return rc;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	pdev = pci_scan_single_device(zdev->zbus->bus, zdev->devfn);
8562306a36Sopenharmony_ci	if (!pdev)
8662306a36Sopenharmony_ci		return -ENODEV;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	pci_lock_rescan_remove();
8962306a36Sopenharmony_ci	pci_bus_add_device(pdev);
9062306a36Sopenharmony_ci	pci_unlock_rescan_remove();
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	return 0;
9362306a36Sopenharmony_ci}
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci/* zpci_bus_remove_device - Removes the given zdev from the PCI core
9662306a36Sopenharmony_ci * @zdev: the zdev to be removed from the PCI core
9762306a36Sopenharmony_ci * @set_error: if true the device's error state is set to permanent failure
9862306a36Sopenharmony_ci *
9962306a36Sopenharmony_ci * Sets a zPCI device to a configured but offline state; the zPCI
10062306a36Sopenharmony_ci * device is still accessible through its hotplug slot and the zPCI
10162306a36Sopenharmony_ci * API but is removed from the common code PCI bus, making it
10262306a36Sopenharmony_ci * no longer available to drivers.
10362306a36Sopenharmony_ci */
10462306a36Sopenharmony_civoid zpci_bus_remove_device(struct zpci_dev *zdev, bool set_error)
10562306a36Sopenharmony_ci{
10662306a36Sopenharmony_ci	struct zpci_bus *zbus = zdev->zbus;
10762306a36Sopenharmony_ci	struct pci_dev *pdev;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	if (!zdev->zbus->bus)
11062306a36Sopenharmony_ci		return;
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	pdev = pci_get_slot(zbus->bus, zdev->devfn);
11362306a36Sopenharmony_ci	if (pdev) {
11462306a36Sopenharmony_ci		if (set_error)
11562306a36Sopenharmony_ci			pdev->error_state = pci_channel_io_perm_failure;
11662306a36Sopenharmony_ci		if (pdev->is_virtfn) {
11762306a36Sopenharmony_ci			zpci_iov_remove_virtfn(pdev, zdev->vfn);
11862306a36Sopenharmony_ci			/* balance pci_get_slot */
11962306a36Sopenharmony_ci			pci_dev_put(pdev);
12062306a36Sopenharmony_ci			return;
12162306a36Sopenharmony_ci		}
12262306a36Sopenharmony_ci		pci_stop_and_remove_bus_device_locked(pdev);
12362306a36Sopenharmony_ci		/* balance pci_get_slot */
12462306a36Sopenharmony_ci		pci_dev_put(pdev);
12562306a36Sopenharmony_ci	}
12662306a36Sopenharmony_ci}
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci/* zpci_bus_scan_bus - Scan all configured zPCI functions on the bus
12962306a36Sopenharmony_ci * @zbus: the zbus to be scanned
13062306a36Sopenharmony_ci *
13162306a36Sopenharmony_ci * Enables and scans all PCI functions on the bus making them available to the
13262306a36Sopenharmony_ci * common PCI code. If a PCI function fails to be initialized an error will be
13362306a36Sopenharmony_ci * returned but attempts will still be made for all other functions on the bus.
13462306a36Sopenharmony_ci *
13562306a36Sopenharmony_ci * Return: 0 on success, an error value otherwise
13662306a36Sopenharmony_ci */
13762306a36Sopenharmony_ciint zpci_bus_scan_bus(struct zpci_bus *zbus)
13862306a36Sopenharmony_ci{
13962306a36Sopenharmony_ci	struct zpci_dev *zdev;
14062306a36Sopenharmony_ci	int devfn, rc, ret = 0;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	for (devfn = 0; devfn < ZPCI_FUNCTIONS_PER_BUS; devfn++) {
14362306a36Sopenharmony_ci		zdev = zbus->function[devfn];
14462306a36Sopenharmony_ci		if (zdev && zdev->state == ZPCI_FN_STATE_CONFIGURED) {
14562306a36Sopenharmony_ci			rc = zpci_bus_prepare_device(zdev);
14662306a36Sopenharmony_ci			if (rc)
14762306a36Sopenharmony_ci				ret = -EIO;
14862306a36Sopenharmony_ci		}
14962306a36Sopenharmony_ci	}
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	pci_lock_rescan_remove();
15262306a36Sopenharmony_ci	pci_scan_child_bus(zbus->bus);
15362306a36Sopenharmony_ci	pci_bus_add_devices(zbus->bus);
15462306a36Sopenharmony_ci	pci_unlock_rescan_remove();
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	return ret;
15762306a36Sopenharmony_ci}
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci/* zpci_bus_scan_busses - Scan all registered busses
16062306a36Sopenharmony_ci *
16162306a36Sopenharmony_ci * Scan all available zbusses
16262306a36Sopenharmony_ci *
16362306a36Sopenharmony_ci */
16462306a36Sopenharmony_civoid zpci_bus_scan_busses(void)
16562306a36Sopenharmony_ci{
16662306a36Sopenharmony_ci	struct zpci_bus *zbus = NULL;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	mutex_lock(&zbus_list_lock);
16962306a36Sopenharmony_ci	list_for_each_entry(zbus, &zbus_list, bus_next) {
17062306a36Sopenharmony_ci		zpci_bus_scan_bus(zbus);
17162306a36Sopenharmony_ci		cond_resched();
17262306a36Sopenharmony_ci	}
17362306a36Sopenharmony_ci	mutex_unlock(&zbus_list_lock);
17462306a36Sopenharmony_ci}
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci/* zpci_bus_create_pci_bus - Create the PCI bus associated with this zbus
17762306a36Sopenharmony_ci * @zbus: the zbus holding the zdevices
17862306a36Sopenharmony_ci * @fr: PCI root function that will determine the bus's domain, and bus speeed
17962306a36Sopenharmony_ci * @ops: the pci operations
18062306a36Sopenharmony_ci *
18162306a36Sopenharmony_ci * The PCI function @fr determines the domain (its UID), multifunction property
18262306a36Sopenharmony_ci * and maximum bus speed of the entire bus.
18362306a36Sopenharmony_ci *
18462306a36Sopenharmony_ci * Return: 0 on success, an error code otherwise
18562306a36Sopenharmony_ci */
18662306a36Sopenharmony_cistatic int zpci_bus_create_pci_bus(struct zpci_bus *zbus, struct zpci_dev *fr, struct pci_ops *ops)
18762306a36Sopenharmony_ci{
18862306a36Sopenharmony_ci	struct pci_bus *bus;
18962306a36Sopenharmony_ci	int domain;
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	domain = zpci_alloc_domain((u16)fr->uid);
19262306a36Sopenharmony_ci	if (domain < 0)
19362306a36Sopenharmony_ci		return domain;
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	zbus->domain_nr = domain;
19662306a36Sopenharmony_ci	zbus->multifunction = fr->rid_available;
19762306a36Sopenharmony_ci	zbus->max_bus_speed = fr->max_bus_speed;
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	/*
20062306a36Sopenharmony_ci	 * Note that the zbus->resources are taken over and zbus->resources
20162306a36Sopenharmony_ci	 * is empty after a successful call
20262306a36Sopenharmony_ci	 */
20362306a36Sopenharmony_ci	bus = pci_create_root_bus(NULL, ZPCI_BUS_NR, ops, zbus, &zbus->resources);
20462306a36Sopenharmony_ci	if (!bus) {
20562306a36Sopenharmony_ci		zpci_free_domain(zbus->domain_nr);
20662306a36Sopenharmony_ci		return -EFAULT;
20762306a36Sopenharmony_ci	}
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	zbus->bus = bus;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	return 0;
21262306a36Sopenharmony_ci}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_cistatic void zpci_bus_release(struct kref *kref)
21562306a36Sopenharmony_ci{
21662306a36Sopenharmony_ci	struct zpci_bus *zbus = container_of(kref, struct zpci_bus, kref);
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	if (zbus->bus) {
21962306a36Sopenharmony_ci		pci_lock_rescan_remove();
22062306a36Sopenharmony_ci		pci_stop_root_bus(zbus->bus);
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci		zpci_free_domain(zbus->domain_nr);
22362306a36Sopenharmony_ci		pci_free_resource_list(&zbus->resources);
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci		pci_remove_root_bus(zbus->bus);
22662306a36Sopenharmony_ci		pci_unlock_rescan_remove();
22762306a36Sopenharmony_ci	}
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	mutex_lock(&zbus_list_lock);
23062306a36Sopenharmony_ci	list_del(&zbus->bus_next);
23162306a36Sopenharmony_ci	mutex_unlock(&zbus_list_lock);
23262306a36Sopenharmony_ci	kfree(zbus);
23362306a36Sopenharmony_ci}
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_cistatic void zpci_bus_put(struct zpci_bus *zbus)
23662306a36Sopenharmony_ci{
23762306a36Sopenharmony_ci	kref_put(&zbus->kref, zpci_bus_release);
23862306a36Sopenharmony_ci}
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_cistatic struct zpci_bus *zpci_bus_get(int pchid)
24162306a36Sopenharmony_ci{
24262306a36Sopenharmony_ci	struct zpci_bus *zbus;
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	mutex_lock(&zbus_list_lock);
24562306a36Sopenharmony_ci	list_for_each_entry(zbus, &zbus_list, bus_next) {
24662306a36Sopenharmony_ci		if (pchid == zbus->pchid) {
24762306a36Sopenharmony_ci			kref_get(&zbus->kref);
24862306a36Sopenharmony_ci			goto out_unlock;
24962306a36Sopenharmony_ci		}
25062306a36Sopenharmony_ci	}
25162306a36Sopenharmony_ci	zbus = NULL;
25262306a36Sopenharmony_ciout_unlock:
25362306a36Sopenharmony_ci	mutex_unlock(&zbus_list_lock);
25462306a36Sopenharmony_ci	return zbus;
25562306a36Sopenharmony_ci}
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_cistatic struct zpci_bus *zpci_bus_alloc(int pchid)
25862306a36Sopenharmony_ci{
25962306a36Sopenharmony_ci	struct zpci_bus *zbus;
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	zbus = kzalloc(sizeof(*zbus), GFP_KERNEL);
26262306a36Sopenharmony_ci	if (!zbus)
26362306a36Sopenharmony_ci		return NULL;
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	zbus->pchid = pchid;
26662306a36Sopenharmony_ci	INIT_LIST_HEAD(&zbus->bus_next);
26762306a36Sopenharmony_ci	mutex_lock(&zbus_list_lock);
26862306a36Sopenharmony_ci	list_add_tail(&zbus->bus_next, &zbus_list);
26962306a36Sopenharmony_ci	mutex_unlock(&zbus_list_lock);
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	kref_init(&zbus->kref);
27262306a36Sopenharmony_ci	INIT_LIST_HEAD(&zbus->resources);
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	zbus->bus_resource.start = 0;
27562306a36Sopenharmony_ci	zbus->bus_resource.end = ZPCI_BUS_NR;
27662306a36Sopenharmony_ci	zbus->bus_resource.flags = IORESOURCE_BUS;
27762306a36Sopenharmony_ci	pci_add_resource(&zbus->resources, &zbus->bus_resource);
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	return zbus;
28062306a36Sopenharmony_ci}
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_civoid pcibios_bus_add_device(struct pci_dev *pdev)
28362306a36Sopenharmony_ci{
28462306a36Sopenharmony_ci	struct zpci_dev *zdev = to_zpci(pdev);
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	/*
28762306a36Sopenharmony_ci	 * With pdev->no_vf_scan the common PCI probing code does not
28862306a36Sopenharmony_ci	 * perform PF/VF linking.
28962306a36Sopenharmony_ci	 */
29062306a36Sopenharmony_ci	if (zdev->vfn) {
29162306a36Sopenharmony_ci		zpci_iov_setup_virtfn(zdev->zbus, pdev, zdev->vfn);
29262306a36Sopenharmony_ci		pdev->no_command_memory = 1;
29362306a36Sopenharmony_ci	}
29462306a36Sopenharmony_ci}
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_cistatic int zpci_bus_add_device(struct zpci_bus *zbus, struct zpci_dev *zdev)
29762306a36Sopenharmony_ci{
29862306a36Sopenharmony_ci	int rc = -EINVAL;
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	if (zbus->function[zdev->devfn]) {
30162306a36Sopenharmony_ci		pr_err("devfn %04x is already assigned\n", zdev->devfn);
30262306a36Sopenharmony_ci		return rc;
30362306a36Sopenharmony_ci	}
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	zdev->zbus = zbus;
30662306a36Sopenharmony_ci	zbus->function[zdev->devfn] = zdev;
30762306a36Sopenharmony_ci	zpci_nb_devices++;
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	if (zbus->multifunction && !zdev->rid_available) {
31062306a36Sopenharmony_ci		WARN_ONCE(1, "rid_available not set for multifunction\n");
31162306a36Sopenharmony_ci		goto error;
31262306a36Sopenharmony_ci	}
31362306a36Sopenharmony_ci	rc = zpci_init_slot(zdev);
31462306a36Sopenharmony_ci	if (rc)
31562306a36Sopenharmony_ci		goto error;
31662306a36Sopenharmony_ci	zdev->has_hp_slot = 1;
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	return 0;
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_cierror:
32162306a36Sopenharmony_ci	zbus->function[zdev->devfn] = NULL;
32262306a36Sopenharmony_ci	zdev->zbus = NULL;
32362306a36Sopenharmony_ci	zpci_nb_devices--;
32462306a36Sopenharmony_ci	return rc;
32562306a36Sopenharmony_ci}
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ciint zpci_bus_device_register(struct zpci_dev *zdev, struct pci_ops *ops)
32862306a36Sopenharmony_ci{
32962306a36Sopenharmony_ci	struct zpci_bus *zbus = NULL;
33062306a36Sopenharmony_ci	int rc = -EBADF;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	if (zpci_nb_devices == ZPCI_NR_DEVICES) {
33362306a36Sopenharmony_ci		pr_warn("Adding PCI function %08x failed because the configured limit of %d is reached\n",
33462306a36Sopenharmony_ci			zdev->fid, ZPCI_NR_DEVICES);
33562306a36Sopenharmony_ci		return -ENOSPC;
33662306a36Sopenharmony_ci	}
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	if (zdev->devfn >= ZPCI_FUNCTIONS_PER_BUS)
33962306a36Sopenharmony_ci		return -EINVAL;
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	if (!s390_pci_no_rid && zdev->rid_available)
34262306a36Sopenharmony_ci		zbus = zpci_bus_get(zdev->pchid);
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	if (!zbus) {
34562306a36Sopenharmony_ci		zbus = zpci_bus_alloc(zdev->pchid);
34662306a36Sopenharmony_ci		if (!zbus)
34762306a36Sopenharmony_ci			return -ENOMEM;
34862306a36Sopenharmony_ci	}
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	if (!zbus->bus) {
35162306a36Sopenharmony_ci		/* The UID of the first PCI function registered with a zpci_bus
35262306a36Sopenharmony_ci		 * is used as the domain number for that bus. Currently there
35362306a36Sopenharmony_ci		 * is exactly one zpci_bus per domain.
35462306a36Sopenharmony_ci		 */
35562306a36Sopenharmony_ci		rc = zpci_bus_create_pci_bus(zbus, zdev, ops);
35662306a36Sopenharmony_ci		if (rc)
35762306a36Sopenharmony_ci			goto error;
35862306a36Sopenharmony_ci	}
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	rc = zpci_bus_add_device(zbus, zdev);
36162306a36Sopenharmony_ci	if (rc)
36262306a36Sopenharmony_ci		goto error;
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	return 0;
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_cierror:
36762306a36Sopenharmony_ci	pr_err("Adding PCI function %08x failed\n", zdev->fid);
36862306a36Sopenharmony_ci	zpci_bus_put(zbus);
36962306a36Sopenharmony_ci	return rc;
37062306a36Sopenharmony_ci}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_civoid zpci_bus_device_unregister(struct zpci_dev *zdev)
37362306a36Sopenharmony_ci{
37462306a36Sopenharmony_ci	struct zpci_bus *zbus = zdev->zbus;
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	zpci_nb_devices--;
37762306a36Sopenharmony_ci	zbus->function[zdev->devfn] = NULL;
37862306a36Sopenharmony_ci	zpci_bus_put(zbus);
37962306a36Sopenharmony_ci}
380