This is a minor bugfix and a set of small cleanups; as it is not clear whether this needs splitting into pieces (and if so, at what granularity), it is a single combined patch. - add a missing return statement to an error path in kill_domain_by_device() - use pci_is_enabled() rather than raw atomic_read() - remove a bogus attempt to zero-terminate an already zero-terminated string - #define DRV_NAME once uniformly in the shared local header - make DRIVER_ATTR() variables static - eliminate a pointless use of list_for_each_entry_safe() - add MODULE_ALIAS() - a little bit of constification - adjust a few messages - remove stray semicolons from inline function definitions Signed-off-by: Jan Beulich <jbeulich@suse.com> [v1: Dropped the resource_size fix, altered the description] [v2: Fixed cleanpatch.pl comments] Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
		
			
				
	
	
		
			188 lines
		
	
	
	
		
			4.6 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			188 lines
		
	
	
	
		
			4.6 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * PCI Backend - Provides restricted access to the real PCI bus topology
 | 
						|
 *               to the frontend
 | 
						|
 *
 | 
						|
 *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
 | 
						|
 */
 | 
						|
 | 
						|
#include <linux/list.h>
 | 
						|
#include <linux/pci.h>
 | 
						|
#include <linux/mutex.h>
 | 
						|
#include "pciback.h"
 | 
						|
 | 
						|
struct passthrough_dev_data {
 | 
						|
	/* Access to dev_list must be protected by lock */
 | 
						|
	struct list_head dev_list;
 | 
						|
	struct mutex lock;
 | 
						|
};
 | 
						|
 | 
						|
static struct pci_dev *__xen_pcibk_get_pci_dev(struct xen_pcibk_device *pdev,
 | 
						|
					       unsigned int domain,
 | 
						|
					       unsigned int bus,
 | 
						|
					       unsigned int devfn)
 | 
						|
{
 | 
						|
	struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
 | 
						|
	struct pci_dev_entry *dev_entry;
 | 
						|
	struct pci_dev *dev = NULL;
 | 
						|
 | 
						|
	mutex_lock(&dev_data->lock);
 | 
						|
 | 
						|
	list_for_each_entry(dev_entry, &dev_data->dev_list, list) {
 | 
						|
		if (domain == (unsigned int)pci_domain_nr(dev_entry->dev->bus)
 | 
						|
		    && bus == (unsigned int)dev_entry->dev->bus->number
 | 
						|
		    && devfn == dev_entry->dev->devfn) {
 | 
						|
			dev = dev_entry->dev;
 | 
						|
			break;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	mutex_unlock(&dev_data->lock);
 | 
						|
 | 
						|
	return dev;
 | 
						|
}
 | 
						|
 | 
						|
static int __xen_pcibk_add_pci_dev(struct xen_pcibk_device *pdev,
 | 
						|
				   struct pci_dev *dev,
 | 
						|
				   int devid, publish_pci_dev_cb publish_cb)
 | 
						|
{
 | 
						|
	struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
 | 
						|
	struct pci_dev_entry *dev_entry;
 | 
						|
	unsigned int domain, bus, devfn;
 | 
						|
	int err;
 | 
						|
 | 
						|
	dev_entry = kmalloc(sizeof(*dev_entry), GFP_KERNEL);
 | 
						|
	if (!dev_entry)
 | 
						|
		return -ENOMEM;
 | 
						|
	dev_entry->dev = dev;
 | 
						|
 | 
						|
	mutex_lock(&dev_data->lock);
 | 
						|
	list_add_tail(&dev_entry->list, &dev_data->dev_list);
 | 
						|
	mutex_unlock(&dev_data->lock);
 | 
						|
 | 
						|
	/* Publish this device. */
 | 
						|
	domain = (unsigned int)pci_domain_nr(dev->bus);
 | 
						|
	bus = (unsigned int)dev->bus->number;
 | 
						|
	devfn = dev->devfn;
 | 
						|
	err = publish_cb(pdev, domain, bus, devfn, devid);
 | 
						|
 | 
						|
	return err;
 | 
						|
}
 | 
						|
 | 
						|
static void __xen_pcibk_release_pci_dev(struct xen_pcibk_device *pdev,
 | 
						|
					struct pci_dev *dev)
 | 
						|
{
 | 
						|
	struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
 | 
						|
	struct pci_dev_entry *dev_entry, *t;
 | 
						|
	struct pci_dev *found_dev = NULL;
 | 
						|
 | 
						|
	mutex_lock(&dev_data->lock);
 | 
						|
 | 
						|
	list_for_each_entry_safe(dev_entry, t, &dev_data->dev_list, list) {
 | 
						|
		if (dev_entry->dev == dev) {
 | 
						|
			list_del(&dev_entry->list);
 | 
						|
			found_dev = dev_entry->dev;
 | 
						|
			kfree(dev_entry);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	mutex_unlock(&dev_data->lock);
 | 
						|
 | 
						|
	if (found_dev)
 | 
						|
		pcistub_put_pci_dev(found_dev);
 | 
						|
}
 | 
						|
 | 
						|
static int __xen_pcibk_init_devices(struct xen_pcibk_device *pdev)
 | 
						|
{
 | 
						|
	struct passthrough_dev_data *dev_data;
 | 
						|
 | 
						|
	dev_data = kmalloc(sizeof(*dev_data), GFP_KERNEL);
 | 
						|
	if (!dev_data)
 | 
						|
		return -ENOMEM;
 | 
						|
 | 
						|
	mutex_init(&dev_data->lock);
 | 
						|
 | 
						|
	INIT_LIST_HEAD(&dev_data->dev_list);
 | 
						|
 | 
						|
	pdev->pci_dev_data = dev_data;
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int __xen_pcibk_publish_pci_roots(struct xen_pcibk_device *pdev,
 | 
						|
					 publish_pci_root_cb publish_root_cb)
 | 
						|
{
 | 
						|
	int err = 0;
 | 
						|
	struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
 | 
						|
	struct pci_dev_entry *dev_entry, *e;
 | 
						|
	struct pci_dev *dev;
 | 
						|
	int found;
 | 
						|
	unsigned int domain, bus;
 | 
						|
 | 
						|
	mutex_lock(&dev_data->lock);
 | 
						|
 | 
						|
	list_for_each_entry(dev_entry, &dev_data->dev_list, list) {
 | 
						|
		/* Only publish this device as a root if none of its
 | 
						|
		 * parent bridges are exported
 | 
						|
		 */
 | 
						|
		found = 0;
 | 
						|
		dev = dev_entry->dev->bus->self;
 | 
						|
		for (; !found && dev != NULL; dev = dev->bus->self) {
 | 
						|
			list_for_each_entry(e, &dev_data->dev_list, list) {
 | 
						|
				if (dev == e->dev) {
 | 
						|
					found = 1;
 | 
						|
					break;
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		domain = (unsigned int)pci_domain_nr(dev_entry->dev->bus);
 | 
						|
		bus = (unsigned int)dev_entry->dev->bus->number;
 | 
						|
 | 
						|
		if (!found) {
 | 
						|
			err = publish_root_cb(pdev, domain, bus);
 | 
						|
			if (err)
 | 
						|
				break;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	mutex_unlock(&dev_data->lock);
 | 
						|
 | 
						|
	return err;
 | 
						|
}
 | 
						|
 | 
						|
static void __xen_pcibk_release_devices(struct xen_pcibk_device *pdev)
 | 
						|
{
 | 
						|
	struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
 | 
						|
	struct pci_dev_entry *dev_entry, *t;
 | 
						|
 | 
						|
	list_for_each_entry_safe(dev_entry, t, &dev_data->dev_list, list) {
 | 
						|
		list_del(&dev_entry->list);
 | 
						|
		pcistub_put_pci_dev(dev_entry->dev);
 | 
						|
		kfree(dev_entry);
 | 
						|
	}
 | 
						|
 | 
						|
	kfree(dev_data);
 | 
						|
	pdev->pci_dev_data = NULL;
 | 
						|
}
 | 
						|
 | 
						|
static int __xen_pcibk_get_pcifront_dev(struct pci_dev *pcidev,
 | 
						|
					struct xen_pcibk_device *pdev,
 | 
						|
					unsigned int *domain, unsigned int *bus,
 | 
						|
					unsigned int *devfn)
 | 
						|
{
 | 
						|
	*domain = pci_domain_nr(pcidev->bus);
 | 
						|
	*bus = pcidev->bus->number;
 | 
						|
	*devfn = pcidev->devfn;
 | 
						|
	return 1;
 | 
						|
}
 | 
						|
 | 
						|
const struct xen_pcibk_backend xen_pcibk_passthrough_backend = {
 | 
						|
	.name           = "passthrough",
 | 
						|
	.init           = __xen_pcibk_init_devices,
 | 
						|
	.free		= __xen_pcibk_release_devices,
 | 
						|
	.find           = __xen_pcibk_get_pcifront_dev,
 | 
						|
	.publish        = __xen_pcibk_publish_pci_roots,
 | 
						|
	.release        = __xen_pcibk_release_pci_dev,
 | 
						|
	.add            = __xen_pcibk_add_pci_dev,
 | 
						|
	.get            = __xen_pcibk_get_pci_dev,
 | 
						|
};
 |