1/*
2 * PCI Backend - Provides a Virtual PCI bus (with real devices)
3 *               to the frontend
4 *
5 *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
6 */
7
8#include <linux/list.h>
9#include <linux/slab.h>
10#include <linux/pci.h>
11#include <linux/mutex.h>
12#include "pciback.h"
13
14#define PCI_SLOT_MAX 32
15
16struct vpci_dev_data {
17	/* Access to dev_list must be protected by lock */
18	struct list_head dev_list[PCI_SLOT_MAX];
19	struct mutex lock;
20};
21
22static inline struct list_head *list_first(struct list_head *head)
23{
24	return head->next;
25}
26
27static struct pci_dev *__xen_pcibk_get_pci_dev(struct xen_pcibk_device *pdev,
28					       unsigned int domain,
29					       unsigned int bus,
30					       unsigned int devfn)
31{
32	struct pci_dev_entry *entry;
33	struct pci_dev *dev = NULL;
34	struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
35
36	if (domain != 0 || bus != 0)
37		return NULL;
38
39	if (PCI_SLOT(devfn) < PCI_SLOT_MAX) {
40		mutex_lock(&vpci_dev->lock);
41
42		list_for_each_entry(entry,
43				    &vpci_dev->dev_list[PCI_SLOT(devfn)],
44				    list) {
45			if (PCI_FUNC(entry->dev->devfn) == PCI_FUNC(devfn)) {
46				dev = entry->dev;
47				break;
48			}
49		}
50
51		mutex_unlock(&vpci_dev->lock);
52	}
53	return dev;
54}
55
56static inline int match_slot(struct pci_dev *l, struct pci_dev *r)
57{
58	if (pci_domain_nr(l->bus) == pci_domain_nr(r->bus)
59	    && l->bus == r->bus && PCI_SLOT(l->devfn) == PCI_SLOT(r->devfn))
60		return 1;
61
62	return 0;
63}
64
65static int __xen_pcibk_add_pci_dev(struct xen_pcibk_device *pdev,
66				   struct pci_dev *dev, int devid,
67				   publish_pci_dev_cb publish_cb)
68{
69	int err = 0, slot, func = -1;
70	struct pci_dev_entry *t, *dev_entry;
71	struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
72
73	if ((dev->class >> 24) == PCI_BASE_CLASS_BRIDGE) {
74		err = -EFAULT;
75		xenbus_dev_fatal(pdev->xdev, err,
76				 "Can't export bridges on the virtual PCI bus");
77		goto out;
78	}
79
80	dev_entry = kmalloc(sizeof(*dev_entry), GFP_KERNEL);
81	if (!dev_entry) {
82		err = -ENOMEM;
83		xenbus_dev_fatal(pdev->xdev, err,
84				 "Error adding entry to virtual PCI bus");
85		goto out;
86	}
87
88	dev_entry->dev = dev;
89
90	mutex_lock(&vpci_dev->lock);
91
92	/* Keep multi-function devices together on the virtual PCI bus */
93	for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
94		if (!list_empty(&vpci_dev->dev_list[slot])) {
95			t = list_entry(list_first(&vpci_dev->dev_list[slot]),
96				       struct pci_dev_entry, list);
97
98			if (match_slot(dev, t->dev)) {
99				pr_info(DRV_NAME ": vpci: %s: "
100					"assign to virtual slot %d func %d\n",
101					pci_name(dev), slot,
102					PCI_FUNC(dev->devfn));
103				list_add_tail(&dev_entry->list,
104					      &vpci_dev->dev_list[slot]);
105				func = PCI_FUNC(dev->devfn);
106				goto unlock;
107			}
108		}
109	}
110
111	/* Assign to a new slot on the virtual PCI bus */
112	for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
113		if (list_empty(&vpci_dev->dev_list[slot])) {
114			printk(KERN_INFO DRV_NAME
115			       ": vpci: %s: assign to virtual slot %d\n",
116			       pci_name(dev), slot);
117			list_add_tail(&dev_entry->list,
118				      &vpci_dev->dev_list[slot]);
119			func = PCI_FUNC(dev->devfn);
120			goto unlock;
121		}
122	}
123
124	err = -ENOMEM;
125	xenbus_dev_fatal(pdev->xdev, err,
126			 "No more space on root virtual PCI bus");
127
128unlock:
129	mutex_unlock(&vpci_dev->lock);
130
131	/* Publish this device. */
132	if (!err)
133		err = publish_cb(pdev, 0, 0, PCI_DEVFN(slot, func), devid);
134
135out:
136	return err;
137}
138
139static void __xen_pcibk_release_pci_dev(struct xen_pcibk_device *pdev,
140					struct pci_dev *dev)
141{
142	int slot;
143	struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
144	struct pci_dev *found_dev = NULL;
145
146	mutex_lock(&vpci_dev->lock);
147
148	for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
149		struct pci_dev_entry *e;
150
151		list_for_each_entry(e, &vpci_dev->dev_list[slot], list) {
152			if (e->dev == dev) {
153				list_del(&e->list);
154				found_dev = e->dev;
155				kfree(e);
156				goto out;
157			}
158		}
159	}
160
161out:
162	mutex_unlock(&vpci_dev->lock);
163
164	if (found_dev)
165		pcistub_put_pci_dev(found_dev);
166}
167
168static int __xen_pcibk_init_devices(struct xen_pcibk_device *pdev)
169{
170	int slot;
171	struct vpci_dev_data *vpci_dev;
172
173	vpci_dev = kmalloc(sizeof(*vpci_dev), GFP_KERNEL);
174	if (!vpci_dev)
175		return -ENOMEM;
176
177	mutex_init(&vpci_dev->lock);
178
179	for (slot = 0; slot < PCI_SLOT_MAX; slot++)
180		INIT_LIST_HEAD(&vpci_dev->dev_list[slot]);
181
182	pdev->pci_dev_data = vpci_dev;
183
184	return 0;
185}
186
187static int __xen_pcibk_publish_pci_roots(struct xen_pcibk_device *pdev,
188					 publish_pci_root_cb publish_cb)
189{
190	/* The Virtual PCI bus has only one root */
191	return publish_cb(pdev, 0, 0);
192}
193
194static void __xen_pcibk_release_devices(struct xen_pcibk_device *pdev)
195{
196	int slot;
197	struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
198
199	for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
200		struct pci_dev_entry *e, *tmp;
201		list_for_each_entry_safe(e, tmp, &vpci_dev->dev_list[slot],
202					 list) {
203			list_del(&e->list);
204			pcistub_put_pci_dev(e->dev);
205			kfree(e);
206		}
207	}
208
209	kfree(vpci_dev);
210	pdev->pci_dev_data = NULL;
211}
212
213static int __xen_pcibk_get_pcifront_dev(struct pci_dev *pcidev,
214					struct xen_pcibk_device *pdev,
215					unsigned int *domain, unsigned int *bus,
216					unsigned int *devfn)
217{
218	struct pci_dev_entry *entry;
219	struct pci_dev *dev = NULL;
220	struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
221	int found = 0, slot;
222
223	mutex_lock(&vpci_dev->lock);
224	for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
225		list_for_each_entry(entry,
226			    &vpci_dev->dev_list[slot],
227			    list) {
228			dev = entry->dev;
229			if (dev && dev->bus->number == pcidev->bus->number
230				&& pci_domain_nr(dev->bus) ==
231					pci_domain_nr(pcidev->bus)
232				&& dev->devfn == pcidev->devfn) {
233				found = 1;
234				*domain = 0;
235				*bus = 0;
236				*devfn = PCI_DEVFN(slot,
237					 PCI_FUNC(pcidev->devfn));
238			}
239		}
240	}
241	mutex_unlock(&vpci_dev->lock);
242	return found;
243}
244
245const struct xen_pcibk_backend xen_pcibk_vpci_backend = {
246	.name		= "vpci",
247	.init		= __xen_pcibk_init_devices,
248	.free		= __xen_pcibk_release_devices,
249	.find		= __xen_pcibk_get_pcifront_dev,
250	.publish	= __xen_pcibk_publish_pci_roots,
251	.release	= __xen_pcibk_release_pci_dev,
252	.add		= __xen_pcibk_add_pci_dev,
253	.get		= __xen_pcibk_get_pci_dev,
254};
255