PageRenderTime 25ms CodeModel.GetById 10ms app.highlight 12ms RepoModel.GetById 0ms app.codeStats 1ms

/drivers/xen/xen-pciback/passthrough.c

https://bitbucket.org/cyanogenmod/android_kernel_asus_tf300t
C | 194 lines | 148 code | 35 blank | 11 comment | 19 complexity | db8e2a406e21edafe8fd9002c5e2cbf0 MD5 | raw file
Possible License(s): LGPL-2.0, AGPL-1.0, GPL-2.0
  1/*
  2 * PCI Backend - Provides restricted access to the real PCI bus topology
  3 *               to the frontend
  4 *
  5 *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
  6 */
  7
  8#include <linux/list.h>
  9#include <linux/pci.h>
 10#include <linux/spinlock.h>
 11#include "pciback.h"
 12
 13struct passthrough_dev_data {
 14	/* Access to dev_list must be protected by lock */
 15	struct list_head dev_list;
 16	spinlock_t lock;
 17};
 18
 19static struct pci_dev *__xen_pcibk_get_pci_dev(struct xen_pcibk_device *pdev,
 20					       unsigned int domain,
 21					       unsigned int bus,
 22					       unsigned int devfn)
 23{
 24	struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
 25	struct pci_dev_entry *dev_entry;
 26	struct pci_dev *dev = NULL;
 27	unsigned long flags;
 28
 29	spin_lock_irqsave(&dev_data->lock, flags);
 30
 31	list_for_each_entry(dev_entry, &dev_data->dev_list, list) {
 32		if (domain == (unsigned int)pci_domain_nr(dev_entry->dev->bus)
 33		    && bus == (unsigned int)dev_entry->dev->bus->number
 34		    && devfn == dev_entry->dev->devfn) {
 35			dev = dev_entry->dev;
 36			break;
 37		}
 38	}
 39
 40	spin_unlock_irqrestore(&dev_data->lock, flags);
 41
 42	return dev;
 43}
 44
 45static int __xen_pcibk_add_pci_dev(struct xen_pcibk_device *pdev,
 46				   struct pci_dev *dev,
 47				   int devid, publish_pci_dev_cb publish_cb)
 48{
 49	struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
 50	struct pci_dev_entry *dev_entry;
 51	unsigned long flags;
 52	unsigned int domain, bus, devfn;
 53	int err;
 54
 55	dev_entry = kmalloc(sizeof(*dev_entry), GFP_KERNEL);
 56	if (!dev_entry)
 57		return -ENOMEM;
 58	dev_entry->dev = dev;
 59
 60	spin_lock_irqsave(&dev_data->lock, flags);
 61	list_add_tail(&dev_entry->list, &dev_data->dev_list);
 62	spin_unlock_irqrestore(&dev_data->lock, flags);
 63
 64	/* Publish this device. */
 65	domain = (unsigned int)pci_domain_nr(dev->bus);
 66	bus = (unsigned int)dev->bus->number;
 67	devfn = dev->devfn;
 68	err = publish_cb(pdev, domain, bus, devfn, devid);
 69
 70	return err;
 71}
 72
 73static void __xen_pcibk_release_pci_dev(struct xen_pcibk_device *pdev,
 74					struct pci_dev *dev)
 75{
 76	struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
 77	struct pci_dev_entry *dev_entry, *t;
 78	struct pci_dev *found_dev = NULL;
 79	unsigned long flags;
 80
 81	spin_lock_irqsave(&dev_data->lock, flags);
 82
 83	list_for_each_entry_safe(dev_entry, t, &dev_data->dev_list, list) {
 84		if (dev_entry->dev == dev) {
 85			list_del(&dev_entry->list);
 86			found_dev = dev_entry->dev;
 87			kfree(dev_entry);
 88		}
 89	}
 90
 91	spin_unlock_irqrestore(&dev_data->lock, flags);
 92
 93	if (found_dev)
 94		pcistub_put_pci_dev(found_dev);
 95}
 96
 97static int __xen_pcibk_init_devices(struct xen_pcibk_device *pdev)
 98{
 99	struct passthrough_dev_data *dev_data;
100
101	dev_data = kmalloc(sizeof(*dev_data), GFP_KERNEL);
102	if (!dev_data)
103		return -ENOMEM;
104
105	spin_lock_init(&dev_data->lock);
106
107	INIT_LIST_HEAD(&dev_data->dev_list);
108
109	pdev->pci_dev_data = dev_data;
110
111	return 0;
112}
113
114static int __xen_pcibk_publish_pci_roots(struct xen_pcibk_device *pdev,
115					 publish_pci_root_cb publish_root_cb)
116{
117	int err = 0;
118	struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
119	struct pci_dev_entry *dev_entry, *e, *tmp;
120	struct pci_dev *dev;
121	int found;
122	unsigned int domain, bus;
123
124	spin_lock(&dev_data->lock);
125
126	list_for_each_entry_safe(dev_entry, tmp, &dev_data->dev_list, list) {
127		/* Only publish this device as a root if none of its
128		 * parent bridges are exported
129		 */
130		found = 0;
131		dev = dev_entry->dev->bus->self;
132		for (; !found && dev != NULL; dev = dev->bus->self) {
133			list_for_each_entry(e, &dev_data->dev_list, list) {
134				if (dev == e->dev) {
135					found = 1;
136					break;
137				}
138			}
139		}
140
141		domain = (unsigned int)pci_domain_nr(dev_entry->dev->bus);
142		bus = (unsigned int)dev_entry->dev->bus->number;
143
144		if (!found) {
145			spin_unlock(&dev_data->lock);
146			err = publish_root_cb(pdev, domain, bus);
147			if (err)
148				break;
149			spin_lock(&dev_data->lock);
150		}
151	}
152
153	if (!err)
154		spin_unlock(&dev_data->lock);
155
156	return err;
157}
158
159static void __xen_pcibk_release_devices(struct xen_pcibk_device *pdev)
160{
161	struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
162	struct pci_dev_entry *dev_entry, *t;
163
164	list_for_each_entry_safe(dev_entry, t, &dev_data->dev_list, list) {
165		list_del(&dev_entry->list);
166		pcistub_put_pci_dev(dev_entry->dev);
167		kfree(dev_entry);
168	}
169
170	kfree(dev_data);
171	pdev->pci_dev_data = NULL;
172}
173
174static int __xen_pcibk_get_pcifront_dev(struct pci_dev *pcidev,
175					struct xen_pcibk_device *pdev,
176					unsigned int *domain, unsigned int *bus,
177					unsigned int *devfn)
178{
179	*domain = pci_domain_nr(pcidev->bus);
180	*bus = pcidev->bus->number;
181	*devfn = pcidev->devfn;
182	return 1;
183}
184
185struct xen_pcibk_backend xen_pcibk_passthrough_backend = {
186	.name           = "passthrough",
187	.init           = __xen_pcibk_init_devices,
188	.free		= __xen_pcibk_release_devices,
189	.find           = __xen_pcibk_get_pcifront_dev,
190	.publish        = __xen_pcibk_publish_pci_roots,
191	.release        = __xen_pcibk_release_pci_dev,
192	.add            = __xen_pcibk_add_pci_dev,
193	.get            = __xen_pcibk_get_pci_dev,
194};