162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * PCI Backend - Provides restricted access to the real PCI bus topology
462306a36Sopenharmony_ci *               to the frontend
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/list.h>
1062306a36Sopenharmony_ci#include <linux/pci.h>
1162306a36Sopenharmony_ci#include <linux/mutex.h>
1262306a36Sopenharmony_ci#include "pciback.h"
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_cistruct passthrough_dev_data {
1562306a36Sopenharmony_ci	/* Access to dev_list must be protected by lock */
1662306a36Sopenharmony_ci	struct list_head dev_list;
1762306a36Sopenharmony_ci	struct mutex lock;
1862306a36Sopenharmony_ci};
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_cistatic struct pci_dev *__xen_pcibk_get_pci_dev(struct xen_pcibk_device *pdev,
2162306a36Sopenharmony_ci					       unsigned int domain,
2262306a36Sopenharmony_ci					       unsigned int bus,
2362306a36Sopenharmony_ci					       unsigned int devfn)
2462306a36Sopenharmony_ci{
2562306a36Sopenharmony_ci	struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
2662306a36Sopenharmony_ci	struct pci_dev_entry *dev_entry;
2762306a36Sopenharmony_ci	struct pci_dev *dev = NULL;
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci	mutex_lock(&dev_data->lock);
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci	list_for_each_entry(dev_entry, &dev_data->dev_list, list) {
3262306a36Sopenharmony_ci		if (domain == (unsigned int)pci_domain_nr(dev_entry->dev->bus)
3362306a36Sopenharmony_ci		    && bus == (unsigned int)dev_entry->dev->bus->number
3462306a36Sopenharmony_ci		    && devfn == dev_entry->dev->devfn) {
3562306a36Sopenharmony_ci			dev = dev_entry->dev;
3662306a36Sopenharmony_ci			break;
3762306a36Sopenharmony_ci		}
3862306a36Sopenharmony_ci	}
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	mutex_unlock(&dev_data->lock);
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	return dev;
4362306a36Sopenharmony_ci}
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cistatic int __xen_pcibk_add_pci_dev(struct xen_pcibk_device *pdev,
4662306a36Sopenharmony_ci				   struct pci_dev *dev,
4762306a36Sopenharmony_ci				   int devid, publish_pci_dev_cb publish_cb)
4862306a36Sopenharmony_ci{
4962306a36Sopenharmony_ci	struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
5062306a36Sopenharmony_ci	struct pci_dev_entry *dev_entry;
5162306a36Sopenharmony_ci	unsigned int domain, bus, devfn;
5262306a36Sopenharmony_ci	int err;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	dev_entry = kmalloc(sizeof(*dev_entry), GFP_KERNEL);
5562306a36Sopenharmony_ci	if (!dev_entry)
5662306a36Sopenharmony_ci		return -ENOMEM;
5762306a36Sopenharmony_ci	dev_entry->dev = dev;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	mutex_lock(&dev_data->lock);
6062306a36Sopenharmony_ci	list_add_tail(&dev_entry->list, &dev_data->dev_list);
6162306a36Sopenharmony_ci	mutex_unlock(&dev_data->lock);
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	/* Publish this device. */
6462306a36Sopenharmony_ci	domain = (unsigned int)pci_domain_nr(dev->bus);
6562306a36Sopenharmony_ci	bus = (unsigned int)dev->bus->number;
6662306a36Sopenharmony_ci	devfn = dev->devfn;
6762306a36Sopenharmony_ci	err = publish_cb(pdev, domain, bus, devfn, devid);
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	return err;
7062306a36Sopenharmony_ci}
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_cistatic void __xen_pcibk_release_pci_dev(struct xen_pcibk_device *pdev,
7362306a36Sopenharmony_ci					struct pci_dev *dev, bool lock)
7462306a36Sopenharmony_ci{
7562306a36Sopenharmony_ci	struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
7662306a36Sopenharmony_ci	struct pci_dev_entry *dev_entry, *t;
7762306a36Sopenharmony_ci	struct pci_dev *found_dev = NULL;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	mutex_lock(&dev_data->lock);
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	list_for_each_entry_safe(dev_entry, t, &dev_data->dev_list, list) {
8262306a36Sopenharmony_ci		if (dev_entry->dev == dev) {
8362306a36Sopenharmony_ci			list_del(&dev_entry->list);
8462306a36Sopenharmony_ci			found_dev = dev_entry->dev;
8562306a36Sopenharmony_ci			kfree(dev_entry);
8662306a36Sopenharmony_ci		}
8762306a36Sopenharmony_ci	}
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	mutex_unlock(&dev_data->lock);
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	if (found_dev) {
9262306a36Sopenharmony_ci		if (lock)
9362306a36Sopenharmony_ci			device_lock(&found_dev->dev);
9462306a36Sopenharmony_ci		pcistub_put_pci_dev(found_dev);
9562306a36Sopenharmony_ci		if (lock)
9662306a36Sopenharmony_ci			device_unlock(&found_dev->dev);
9762306a36Sopenharmony_ci	}
9862306a36Sopenharmony_ci}
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_cistatic int __xen_pcibk_init_devices(struct xen_pcibk_device *pdev)
10162306a36Sopenharmony_ci{
10262306a36Sopenharmony_ci	struct passthrough_dev_data *dev_data;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	dev_data = kmalloc(sizeof(*dev_data), GFP_KERNEL);
10562306a36Sopenharmony_ci	if (!dev_data)
10662306a36Sopenharmony_ci		return -ENOMEM;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	mutex_init(&dev_data->lock);
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	INIT_LIST_HEAD(&dev_data->dev_list);
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	pdev->pci_dev_data = dev_data;
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	return 0;
11562306a36Sopenharmony_ci}
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_cistatic int __xen_pcibk_publish_pci_roots(struct xen_pcibk_device *pdev,
11862306a36Sopenharmony_ci					 publish_pci_root_cb publish_root_cb)
11962306a36Sopenharmony_ci{
12062306a36Sopenharmony_ci	int err = 0;
12162306a36Sopenharmony_ci	struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
12262306a36Sopenharmony_ci	struct pci_dev_entry *dev_entry, *e;
12362306a36Sopenharmony_ci	struct pci_dev *dev;
12462306a36Sopenharmony_ci	int found;
12562306a36Sopenharmony_ci	unsigned int domain, bus;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	mutex_lock(&dev_data->lock);
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	list_for_each_entry(dev_entry, &dev_data->dev_list, list) {
13062306a36Sopenharmony_ci		/* Only publish this device as a root if none of its
13162306a36Sopenharmony_ci		 * parent bridges are exported
13262306a36Sopenharmony_ci		 */
13362306a36Sopenharmony_ci		found = 0;
13462306a36Sopenharmony_ci		dev = dev_entry->dev->bus->self;
13562306a36Sopenharmony_ci		for (; !found && dev != NULL; dev = dev->bus->self) {
13662306a36Sopenharmony_ci			list_for_each_entry(e, &dev_data->dev_list, list) {
13762306a36Sopenharmony_ci				if (dev == e->dev) {
13862306a36Sopenharmony_ci					found = 1;
13962306a36Sopenharmony_ci					break;
14062306a36Sopenharmony_ci				}
14162306a36Sopenharmony_ci			}
14262306a36Sopenharmony_ci		}
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci		domain = (unsigned int)pci_domain_nr(dev_entry->dev->bus);
14562306a36Sopenharmony_ci		bus = (unsigned int)dev_entry->dev->bus->number;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci		if (!found) {
14862306a36Sopenharmony_ci			err = publish_root_cb(pdev, domain, bus);
14962306a36Sopenharmony_ci			if (err)
15062306a36Sopenharmony_ci				break;
15162306a36Sopenharmony_ci		}
15262306a36Sopenharmony_ci	}
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	mutex_unlock(&dev_data->lock);
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	return err;
15762306a36Sopenharmony_ci}
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_cistatic void __xen_pcibk_release_devices(struct xen_pcibk_device *pdev)
16062306a36Sopenharmony_ci{
16162306a36Sopenharmony_ci	struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
16262306a36Sopenharmony_ci	struct pci_dev_entry *dev_entry, *t;
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	list_for_each_entry_safe(dev_entry, t, &dev_data->dev_list, list) {
16562306a36Sopenharmony_ci		struct pci_dev *dev = dev_entry->dev;
16662306a36Sopenharmony_ci		list_del(&dev_entry->list);
16762306a36Sopenharmony_ci		device_lock(&dev->dev);
16862306a36Sopenharmony_ci		pcistub_put_pci_dev(dev);
16962306a36Sopenharmony_ci		device_unlock(&dev->dev);
17062306a36Sopenharmony_ci		kfree(dev_entry);
17162306a36Sopenharmony_ci	}
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	kfree(dev_data);
17462306a36Sopenharmony_ci	pdev->pci_dev_data = NULL;
17562306a36Sopenharmony_ci}
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_cistatic int __xen_pcibk_get_pcifront_dev(struct pci_dev *pcidev,
17862306a36Sopenharmony_ci					struct xen_pcibk_device *pdev,
17962306a36Sopenharmony_ci					unsigned int *domain, unsigned int *bus,
18062306a36Sopenharmony_ci					unsigned int *devfn)
18162306a36Sopenharmony_ci{
18262306a36Sopenharmony_ci	*domain = pci_domain_nr(pcidev->bus);
18362306a36Sopenharmony_ci	*bus = pcidev->bus->number;
18462306a36Sopenharmony_ci	*devfn = pcidev->devfn;
18562306a36Sopenharmony_ci	return 1;
18662306a36Sopenharmony_ci}
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ciconst struct xen_pcibk_backend xen_pcibk_passthrough_backend = {
18962306a36Sopenharmony_ci	.name           = "passthrough",
19062306a36Sopenharmony_ci	.init           = __xen_pcibk_init_devices,
19162306a36Sopenharmony_ci	.free		= __xen_pcibk_release_devices,
19262306a36Sopenharmony_ci	.find           = __xen_pcibk_get_pcifront_dev,
19362306a36Sopenharmony_ci	.publish        = __xen_pcibk_publish_pci_roots,
19462306a36Sopenharmony_ci	.release        = __xen_pcibk_release_pci_dev,
19562306a36Sopenharmony_ci	.add            = __xen_pcibk_add_pci_dev,
19662306a36Sopenharmony_ci	.get            = __xen_pcibk_get_pci_dev,
19762306a36Sopenharmony_ci};
198