xref: /linux/drivers/pci/xen-pcifront.c (revision 956a9202cd1220397933a07beda9f96b3df1fa24)
1*956a9202SRyan Wilson /*
2*956a9202SRyan Wilson  * Xen PCI Frontend.
3*956a9202SRyan Wilson  *
4*956a9202SRyan Wilson  *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
5*956a9202SRyan Wilson  */
6*956a9202SRyan Wilson #include <linux/module.h>
7*956a9202SRyan Wilson #include <linux/init.h>
8*956a9202SRyan Wilson #include <linux/mm.h>
9*956a9202SRyan Wilson #include <xen/xenbus.h>
10*956a9202SRyan Wilson #include <xen/events.h>
11*956a9202SRyan Wilson #include <xen/grant_table.h>
12*956a9202SRyan Wilson #include <xen/page.h>
13*956a9202SRyan Wilson #include <linux/spinlock.h>
14*956a9202SRyan Wilson #include <linux/pci.h>
15*956a9202SRyan Wilson #include <linux/msi.h>
16*956a9202SRyan Wilson #include <xen/xenbus.h>
17*956a9202SRyan Wilson #include <xen/interface/io/pciif.h>
18*956a9202SRyan Wilson #include <asm/xen/pci.h>
19*956a9202SRyan Wilson #include <linux/interrupt.h>
20*956a9202SRyan Wilson #include <asm/atomic.h>
21*956a9202SRyan Wilson #include <linux/workqueue.h>
22*956a9202SRyan Wilson #include <linux/bitops.h>
23*956a9202SRyan Wilson #include <linux/time.h>
24*956a9202SRyan Wilson 
25*956a9202SRyan Wilson #define INVALID_GRANT_REF (0)
26*956a9202SRyan Wilson #define INVALID_EVTCHN    (-1)
27*956a9202SRyan Wilson 
28*956a9202SRyan Wilson struct pci_bus_entry {
29*956a9202SRyan Wilson 	struct list_head list;
30*956a9202SRyan Wilson 	struct pci_bus *bus;
31*956a9202SRyan Wilson };
32*956a9202SRyan Wilson 
33*956a9202SRyan Wilson #define _PDEVB_op_active		(0)
34*956a9202SRyan Wilson #define PDEVB_op_active			(1 << (_PDEVB_op_active))
35*956a9202SRyan Wilson 
36*956a9202SRyan Wilson struct pcifront_device {
37*956a9202SRyan Wilson 	struct xenbus_device *xdev;
38*956a9202SRyan Wilson 	struct list_head root_buses;
39*956a9202SRyan Wilson 
40*956a9202SRyan Wilson 	int evtchn;
41*956a9202SRyan Wilson 	int gnt_ref;
42*956a9202SRyan Wilson 
43*956a9202SRyan Wilson 	int irq;
44*956a9202SRyan Wilson 
45*956a9202SRyan Wilson 	/* Lock this when doing any operations in sh_info */
46*956a9202SRyan Wilson 	spinlock_t sh_info_lock;
47*956a9202SRyan Wilson 	struct xen_pci_sharedinfo *sh_info;
48*956a9202SRyan Wilson 	struct work_struct op_work;
49*956a9202SRyan Wilson 	unsigned long flags;
50*956a9202SRyan Wilson 
51*956a9202SRyan Wilson };
52*956a9202SRyan Wilson 
53*956a9202SRyan Wilson struct pcifront_sd {
54*956a9202SRyan Wilson 	int domain;
55*956a9202SRyan Wilson 	struct pcifront_device *pdev;
56*956a9202SRyan Wilson };
57*956a9202SRyan Wilson 
58*956a9202SRyan Wilson static inline struct pcifront_device *
59*956a9202SRyan Wilson pcifront_get_pdev(struct pcifront_sd *sd)
60*956a9202SRyan Wilson {
61*956a9202SRyan Wilson 	return sd->pdev;
62*956a9202SRyan Wilson }
63*956a9202SRyan Wilson 
64*956a9202SRyan Wilson static inline void pcifront_init_sd(struct pcifront_sd *sd,
65*956a9202SRyan Wilson 				    unsigned int domain, unsigned int bus,
66*956a9202SRyan Wilson 				    struct pcifront_device *pdev)
67*956a9202SRyan Wilson {
68*956a9202SRyan Wilson 	sd->domain = domain;
69*956a9202SRyan Wilson 	sd->pdev = pdev;
70*956a9202SRyan Wilson }
71*956a9202SRyan Wilson 
72*956a9202SRyan Wilson static DEFINE_SPINLOCK(pcifront_dev_lock);
73*956a9202SRyan Wilson static struct pcifront_device *pcifront_dev;
74*956a9202SRyan Wilson 
75*956a9202SRyan Wilson static int verbose_request;
76*956a9202SRyan Wilson module_param(verbose_request, int, 0644);
77*956a9202SRyan Wilson 
78*956a9202SRyan Wilson static int errno_to_pcibios_err(int errno)
79*956a9202SRyan Wilson {
80*956a9202SRyan Wilson 	switch (errno) {
81*956a9202SRyan Wilson 	case XEN_PCI_ERR_success:
82*956a9202SRyan Wilson 		return PCIBIOS_SUCCESSFUL;
83*956a9202SRyan Wilson 
84*956a9202SRyan Wilson 	case XEN_PCI_ERR_dev_not_found:
85*956a9202SRyan Wilson 		return PCIBIOS_DEVICE_NOT_FOUND;
86*956a9202SRyan Wilson 
87*956a9202SRyan Wilson 	case XEN_PCI_ERR_invalid_offset:
88*956a9202SRyan Wilson 	case XEN_PCI_ERR_op_failed:
89*956a9202SRyan Wilson 		return PCIBIOS_BAD_REGISTER_NUMBER;
90*956a9202SRyan Wilson 
91*956a9202SRyan Wilson 	case XEN_PCI_ERR_not_implemented:
92*956a9202SRyan Wilson 		return PCIBIOS_FUNC_NOT_SUPPORTED;
93*956a9202SRyan Wilson 
94*956a9202SRyan Wilson 	case XEN_PCI_ERR_access_denied:
95*956a9202SRyan Wilson 		return PCIBIOS_SET_FAILED;
96*956a9202SRyan Wilson 	}
97*956a9202SRyan Wilson 	return errno;
98*956a9202SRyan Wilson }
99*956a9202SRyan Wilson 
100*956a9202SRyan Wilson static inline void schedule_pcifront_aer_op(struct pcifront_device *pdev)
101*956a9202SRyan Wilson {
102*956a9202SRyan Wilson 	if (test_bit(_XEN_PCIB_active, (unsigned long *)&pdev->sh_info->flags)
103*956a9202SRyan Wilson 		&& !test_and_set_bit(_PDEVB_op_active, &pdev->flags)) {
104*956a9202SRyan Wilson 		dev_dbg(&pdev->xdev->dev, "schedule aer frontend job\n");
105*956a9202SRyan Wilson 		schedule_work(&pdev->op_work);
106*956a9202SRyan Wilson 	}
107*956a9202SRyan Wilson }
108*956a9202SRyan Wilson 
109*956a9202SRyan Wilson static int do_pci_op(struct pcifront_device *pdev, struct xen_pci_op *op)
110*956a9202SRyan Wilson {
111*956a9202SRyan Wilson 	int err = 0;
112*956a9202SRyan Wilson 	struct xen_pci_op *active_op = &pdev->sh_info->op;
113*956a9202SRyan Wilson 	unsigned long irq_flags;
114*956a9202SRyan Wilson 	evtchn_port_t port = pdev->evtchn;
115*956a9202SRyan Wilson 	unsigned irq = pdev->irq;
116*956a9202SRyan Wilson 	s64 ns, ns_timeout;
117*956a9202SRyan Wilson 	struct timeval tv;
118*956a9202SRyan Wilson 
119*956a9202SRyan Wilson 	spin_lock_irqsave(&pdev->sh_info_lock, irq_flags);
120*956a9202SRyan Wilson 
121*956a9202SRyan Wilson 	memcpy(active_op, op, sizeof(struct xen_pci_op));
122*956a9202SRyan Wilson 
123*956a9202SRyan Wilson 	/* Go */
124*956a9202SRyan Wilson 	wmb();
125*956a9202SRyan Wilson 	set_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags);
126*956a9202SRyan Wilson 	notify_remote_via_evtchn(port);
127*956a9202SRyan Wilson 
128*956a9202SRyan Wilson 	/*
129*956a9202SRyan Wilson 	 * We set a poll timeout of 3 seconds but give up on return after
130*956a9202SRyan Wilson 	 * 2 seconds. It is better to time out too late rather than too early
131*956a9202SRyan Wilson 	 * (in the latter case we end up continually re-executing poll() with a
132*956a9202SRyan Wilson 	 * timeout in the past). 1s difference gives plenty of slack for error.
133*956a9202SRyan Wilson 	 */
134*956a9202SRyan Wilson 	do_gettimeofday(&tv);
135*956a9202SRyan Wilson 	ns_timeout = timeval_to_ns(&tv) + 2 * (s64)NSEC_PER_SEC;
136*956a9202SRyan Wilson 
137*956a9202SRyan Wilson 	xen_clear_irq_pending(irq);
138*956a9202SRyan Wilson 
139*956a9202SRyan Wilson 	while (test_bit(_XEN_PCIF_active,
140*956a9202SRyan Wilson 			(unsigned long *)&pdev->sh_info->flags)) {
141*956a9202SRyan Wilson 		xen_poll_irq_timeout(irq, jiffies + 3*HZ);
142*956a9202SRyan Wilson 		xen_clear_irq_pending(irq);
143*956a9202SRyan Wilson 		do_gettimeofday(&tv);
144*956a9202SRyan Wilson 		ns = timeval_to_ns(&tv);
145*956a9202SRyan Wilson 		if (ns > ns_timeout) {
146*956a9202SRyan Wilson 			dev_err(&pdev->xdev->dev,
147*956a9202SRyan Wilson 				"pciback not responding!!!\n");
148*956a9202SRyan Wilson 			clear_bit(_XEN_PCIF_active,
149*956a9202SRyan Wilson 				  (unsigned long *)&pdev->sh_info->flags);
150*956a9202SRyan Wilson 			err = XEN_PCI_ERR_dev_not_found;
151*956a9202SRyan Wilson 			goto out;
152*956a9202SRyan Wilson 		}
153*956a9202SRyan Wilson 	}
154*956a9202SRyan Wilson 
155*956a9202SRyan Wilson 	/*
156*956a9202SRyan Wilson 	* We might lose backend service request since we
157*956a9202SRyan Wilson 	* reuse same evtchn with pci_conf backend response. So re-schedule
158*956a9202SRyan Wilson 	* aer pcifront service.
159*956a9202SRyan Wilson 	*/
160*956a9202SRyan Wilson 	if (test_bit(_XEN_PCIB_active,
161*956a9202SRyan Wilson 			(unsigned long *)&pdev->sh_info->flags)) {
162*956a9202SRyan Wilson 		dev_err(&pdev->xdev->dev,
163*956a9202SRyan Wilson 			"schedule aer pcifront service\n");
164*956a9202SRyan Wilson 		schedule_pcifront_aer_op(pdev);
165*956a9202SRyan Wilson 	}
166*956a9202SRyan Wilson 
167*956a9202SRyan Wilson 	memcpy(op, active_op, sizeof(struct xen_pci_op));
168*956a9202SRyan Wilson 
169*956a9202SRyan Wilson 	err = op->err;
170*956a9202SRyan Wilson out:
171*956a9202SRyan Wilson 	spin_unlock_irqrestore(&pdev->sh_info_lock, irq_flags);
172*956a9202SRyan Wilson 	return err;
173*956a9202SRyan Wilson }
174*956a9202SRyan Wilson 
175*956a9202SRyan Wilson /* Access to this function is spinlocked in drivers/pci/access.c */
176*956a9202SRyan Wilson static int pcifront_bus_read(struct pci_bus *bus, unsigned int devfn,
177*956a9202SRyan Wilson 			     int where, int size, u32 *val)
178*956a9202SRyan Wilson {
179*956a9202SRyan Wilson 	int err = 0;
180*956a9202SRyan Wilson 	struct xen_pci_op op = {
181*956a9202SRyan Wilson 		.cmd    = XEN_PCI_OP_conf_read,
182*956a9202SRyan Wilson 		.domain = pci_domain_nr(bus),
183*956a9202SRyan Wilson 		.bus    = bus->number,
184*956a9202SRyan Wilson 		.devfn  = devfn,
185*956a9202SRyan Wilson 		.offset = where,
186*956a9202SRyan Wilson 		.size   = size,
187*956a9202SRyan Wilson 	};
188*956a9202SRyan Wilson 	struct pcifront_sd *sd = bus->sysdata;
189*956a9202SRyan Wilson 	struct pcifront_device *pdev = pcifront_get_pdev(sd);
190*956a9202SRyan Wilson 
191*956a9202SRyan Wilson 	if (verbose_request)
192*956a9202SRyan Wilson 		dev_info(&pdev->xdev->dev,
193*956a9202SRyan Wilson 			 "read dev=%04x:%02x:%02x.%01x - offset %x size %d\n",
194*956a9202SRyan Wilson 			 pci_domain_nr(bus), bus->number, PCI_SLOT(devfn),
195*956a9202SRyan Wilson 			 PCI_FUNC(devfn), where, size);
196*956a9202SRyan Wilson 
197*956a9202SRyan Wilson 	err = do_pci_op(pdev, &op);
198*956a9202SRyan Wilson 
199*956a9202SRyan Wilson 	if (likely(!err)) {
200*956a9202SRyan Wilson 		if (verbose_request)
201*956a9202SRyan Wilson 			dev_info(&pdev->xdev->dev, "read got back value %x\n",
202*956a9202SRyan Wilson 				 op.value);
203*956a9202SRyan Wilson 
204*956a9202SRyan Wilson 		*val = op.value;
205*956a9202SRyan Wilson 	} else if (err == -ENODEV) {
206*956a9202SRyan Wilson 		/* No device here, pretend that it just returned 0 */
207*956a9202SRyan Wilson 		err = 0;
208*956a9202SRyan Wilson 		*val = 0;
209*956a9202SRyan Wilson 	}
210*956a9202SRyan Wilson 
211*956a9202SRyan Wilson 	return errno_to_pcibios_err(err);
212*956a9202SRyan Wilson }
213*956a9202SRyan Wilson 
214*956a9202SRyan Wilson /* Access to this function is spinlocked in drivers/pci/access.c */
215*956a9202SRyan Wilson static int pcifront_bus_write(struct pci_bus *bus, unsigned int devfn,
216*956a9202SRyan Wilson 			      int where, int size, u32 val)
217*956a9202SRyan Wilson {
218*956a9202SRyan Wilson 	struct xen_pci_op op = {
219*956a9202SRyan Wilson 		.cmd    = XEN_PCI_OP_conf_write,
220*956a9202SRyan Wilson 		.domain = pci_domain_nr(bus),
221*956a9202SRyan Wilson 		.bus    = bus->number,
222*956a9202SRyan Wilson 		.devfn  = devfn,
223*956a9202SRyan Wilson 		.offset = where,
224*956a9202SRyan Wilson 		.size   = size,
225*956a9202SRyan Wilson 		.value  = val,
226*956a9202SRyan Wilson 	};
227*956a9202SRyan Wilson 	struct pcifront_sd *sd = bus->sysdata;
228*956a9202SRyan Wilson 	struct pcifront_device *pdev = pcifront_get_pdev(sd);
229*956a9202SRyan Wilson 
230*956a9202SRyan Wilson 	if (verbose_request)
231*956a9202SRyan Wilson 		dev_info(&pdev->xdev->dev,
232*956a9202SRyan Wilson 			 "write dev=%04x:%02x:%02x.%01x - "
233*956a9202SRyan Wilson 			 "offset %x size %d val %x\n",
234*956a9202SRyan Wilson 			 pci_domain_nr(bus), bus->number,
235*956a9202SRyan Wilson 			 PCI_SLOT(devfn), PCI_FUNC(devfn), where, size, val);
236*956a9202SRyan Wilson 
237*956a9202SRyan Wilson 	return errno_to_pcibios_err(do_pci_op(pdev, &op));
238*956a9202SRyan Wilson }
239*956a9202SRyan Wilson 
240*956a9202SRyan Wilson struct pci_ops pcifront_bus_ops = {
241*956a9202SRyan Wilson 	.read = pcifront_bus_read,
242*956a9202SRyan Wilson 	.write = pcifront_bus_write,
243*956a9202SRyan Wilson };
244*956a9202SRyan Wilson 
245*956a9202SRyan Wilson #ifdef CONFIG_PCI_MSI
246*956a9202SRyan Wilson static int pci_frontend_enable_msix(struct pci_dev *dev,
247*956a9202SRyan Wilson 				    int **vector, int nvec)
248*956a9202SRyan Wilson {
249*956a9202SRyan Wilson 	int err;
250*956a9202SRyan Wilson 	int i;
251*956a9202SRyan Wilson 	struct xen_pci_op op = {
252*956a9202SRyan Wilson 		.cmd    = XEN_PCI_OP_enable_msix,
253*956a9202SRyan Wilson 		.domain = pci_domain_nr(dev->bus),
254*956a9202SRyan Wilson 		.bus = dev->bus->number,
255*956a9202SRyan Wilson 		.devfn = dev->devfn,
256*956a9202SRyan Wilson 		.value = nvec,
257*956a9202SRyan Wilson 	};
258*956a9202SRyan Wilson 	struct pcifront_sd *sd = dev->bus->sysdata;
259*956a9202SRyan Wilson 	struct pcifront_device *pdev = pcifront_get_pdev(sd);
260*956a9202SRyan Wilson 	struct msi_desc *entry;
261*956a9202SRyan Wilson 
262*956a9202SRyan Wilson 	if (nvec > SH_INFO_MAX_VEC) {
263*956a9202SRyan Wilson 		dev_err(&dev->dev, "too much vector for pci frontend: %x."
264*956a9202SRyan Wilson 				   " Increase SH_INFO_MAX_VEC.\n", nvec);
265*956a9202SRyan Wilson 		return -EINVAL;
266*956a9202SRyan Wilson 	}
267*956a9202SRyan Wilson 
268*956a9202SRyan Wilson 	i = 0;
269*956a9202SRyan Wilson 	list_for_each_entry(entry, &dev->msi_list, list) {
270*956a9202SRyan Wilson 		op.msix_entries[i].entry = entry->msi_attrib.entry_nr;
271*956a9202SRyan Wilson 		/* Vector is useless at this point. */
272*956a9202SRyan Wilson 		op.msix_entries[i].vector = -1;
273*956a9202SRyan Wilson 		i++;
274*956a9202SRyan Wilson 	}
275*956a9202SRyan Wilson 
276*956a9202SRyan Wilson 	err = do_pci_op(pdev, &op);
277*956a9202SRyan Wilson 
278*956a9202SRyan Wilson 	if (likely(!err)) {
279*956a9202SRyan Wilson 		if (likely(!op.value)) {
280*956a9202SRyan Wilson 			/* we get the result */
281*956a9202SRyan Wilson 			for (i = 0; i < nvec; i++)
282*956a9202SRyan Wilson 				*(*vector+i) = op.msix_entries[i].vector;
283*956a9202SRyan Wilson 			return 0;
284*956a9202SRyan Wilson 		} else {
285*956a9202SRyan Wilson 			printk(KERN_DEBUG "enable msix get value %x\n",
286*956a9202SRyan Wilson 				op.value);
287*956a9202SRyan Wilson 			return op.value;
288*956a9202SRyan Wilson 		}
289*956a9202SRyan Wilson 	} else {
290*956a9202SRyan Wilson 		dev_err(&dev->dev, "enable msix get err %x\n", err);
291*956a9202SRyan Wilson 		return err;
292*956a9202SRyan Wilson 	}
293*956a9202SRyan Wilson }
294*956a9202SRyan Wilson 
295*956a9202SRyan Wilson static void pci_frontend_disable_msix(struct pci_dev *dev)
296*956a9202SRyan Wilson {
297*956a9202SRyan Wilson 	int err;
298*956a9202SRyan Wilson 	struct xen_pci_op op = {
299*956a9202SRyan Wilson 		.cmd    = XEN_PCI_OP_disable_msix,
300*956a9202SRyan Wilson 		.domain = pci_domain_nr(dev->bus),
301*956a9202SRyan Wilson 		.bus = dev->bus->number,
302*956a9202SRyan Wilson 		.devfn = dev->devfn,
303*956a9202SRyan Wilson 	};
304*956a9202SRyan Wilson 	struct pcifront_sd *sd = dev->bus->sysdata;
305*956a9202SRyan Wilson 	struct pcifront_device *pdev = pcifront_get_pdev(sd);
306*956a9202SRyan Wilson 
307*956a9202SRyan Wilson 	err = do_pci_op(pdev, &op);
308*956a9202SRyan Wilson 
309*956a9202SRyan Wilson 	/* What should do for error ? */
310*956a9202SRyan Wilson 	if (err)
311*956a9202SRyan Wilson 		dev_err(&dev->dev, "pci_disable_msix get err %x\n", err);
312*956a9202SRyan Wilson }
313*956a9202SRyan Wilson 
314*956a9202SRyan Wilson static int pci_frontend_enable_msi(struct pci_dev *dev, int **vector)
315*956a9202SRyan Wilson {
316*956a9202SRyan Wilson 	int err;
317*956a9202SRyan Wilson 	struct xen_pci_op op = {
318*956a9202SRyan Wilson 		.cmd    = XEN_PCI_OP_enable_msi,
319*956a9202SRyan Wilson 		.domain = pci_domain_nr(dev->bus),
320*956a9202SRyan Wilson 		.bus = dev->bus->number,
321*956a9202SRyan Wilson 		.devfn = dev->devfn,
322*956a9202SRyan Wilson 	};
323*956a9202SRyan Wilson 	struct pcifront_sd *sd = dev->bus->sysdata;
324*956a9202SRyan Wilson 	struct pcifront_device *pdev = pcifront_get_pdev(sd);
325*956a9202SRyan Wilson 
326*956a9202SRyan Wilson 	err = do_pci_op(pdev, &op);
327*956a9202SRyan Wilson 	if (likely(!err)) {
328*956a9202SRyan Wilson 		*(*vector) = op.value;
329*956a9202SRyan Wilson 	} else {
330*956a9202SRyan Wilson 		dev_err(&dev->dev, "pci frontend enable msi failed for dev "
331*956a9202SRyan Wilson 				    "%x:%x\n", op.bus, op.devfn);
332*956a9202SRyan Wilson 		err = -EINVAL;
333*956a9202SRyan Wilson 	}
334*956a9202SRyan Wilson 	return err;
335*956a9202SRyan Wilson }
336*956a9202SRyan Wilson 
337*956a9202SRyan Wilson static void pci_frontend_disable_msi(struct pci_dev *dev)
338*956a9202SRyan Wilson {
339*956a9202SRyan Wilson 	int err;
340*956a9202SRyan Wilson 	struct xen_pci_op op = {
341*956a9202SRyan Wilson 		.cmd    = XEN_PCI_OP_disable_msi,
342*956a9202SRyan Wilson 		.domain = pci_domain_nr(dev->bus),
343*956a9202SRyan Wilson 		.bus = dev->bus->number,
344*956a9202SRyan Wilson 		.devfn = dev->devfn,
345*956a9202SRyan Wilson 	};
346*956a9202SRyan Wilson 	struct pcifront_sd *sd = dev->bus->sysdata;
347*956a9202SRyan Wilson 	struct pcifront_device *pdev = pcifront_get_pdev(sd);
348*956a9202SRyan Wilson 
349*956a9202SRyan Wilson 	err = do_pci_op(pdev, &op);
350*956a9202SRyan Wilson 	if (err == XEN_PCI_ERR_dev_not_found) {
351*956a9202SRyan Wilson 		/* XXX No response from backend, what shall we do? */
352*956a9202SRyan Wilson 		printk(KERN_DEBUG "get no response from backend for disable MSI\n");
353*956a9202SRyan Wilson 		return;
354*956a9202SRyan Wilson 	}
355*956a9202SRyan Wilson 	if (err)
356*956a9202SRyan Wilson 		/* how can pciback notify us fail? */
357*956a9202SRyan Wilson 		printk(KERN_DEBUG "get fake response frombackend\n");
358*956a9202SRyan Wilson }
359*956a9202SRyan Wilson 
360*956a9202SRyan Wilson static struct xen_pci_frontend_ops pci_frontend_ops = {
361*956a9202SRyan Wilson 	.enable_msi = pci_frontend_enable_msi,
362*956a9202SRyan Wilson 	.disable_msi = pci_frontend_disable_msi,
363*956a9202SRyan Wilson 	.enable_msix = pci_frontend_enable_msix,
364*956a9202SRyan Wilson 	.disable_msix = pci_frontend_disable_msix,
365*956a9202SRyan Wilson };
366*956a9202SRyan Wilson 
367*956a9202SRyan Wilson static void pci_frontend_registrar(int enable)
368*956a9202SRyan Wilson {
369*956a9202SRyan Wilson 	if (enable)
370*956a9202SRyan Wilson 		xen_pci_frontend = &pci_frontend_ops;
371*956a9202SRyan Wilson 	else
372*956a9202SRyan Wilson 		xen_pci_frontend = NULL;
373*956a9202SRyan Wilson };
374*956a9202SRyan Wilson #else
375*956a9202SRyan Wilson static inline void pci_frontend_registrar(int enable) { };
376*956a9202SRyan Wilson #endif /* CONFIG_PCI_MSI */
377*956a9202SRyan Wilson 
378*956a9202SRyan Wilson /* Claim resources for the PCI frontend as-is, backend won't allow changes */
379*956a9202SRyan Wilson static int pcifront_claim_resource(struct pci_dev *dev, void *data)
380*956a9202SRyan Wilson {
381*956a9202SRyan Wilson 	struct pcifront_device *pdev = data;
382*956a9202SRyan Wilson 	int i;
383*956a9202SRyan Wilson 	struct resource *r;
384*956a9202SRyan Wilson 
385*956a9202SRyan Wilson 	for (i = 0; i < PCI_NUM_RESOURCES; i++) {
386*956a9202SRyan Wilson 		r = &dev->resource[i];
387*956a9202SRyan Wilson 
388*956a9202SRyan Wilson 		if (!r->parent && r->start && r->flags) {
389*956a9202SRyan Wilson 			dev_info(&pdev->xdev->dev, "claiming resource %s/%d\n",
390*956a9202SRyan Wilson 				pci_name(dev), i);
391*956a9202SRyan Wilson 			if (pci_claim_resource(dev, i)) {
392*956a9202SRyan Wilson 				dev_err(&pdev->xdev->dev, "Could not claim "
393*956a9202SRyan Wilson 					"resource %s/%d! Device offline. Try "
394*956a9202SRyan Wilson 					"giving less than 4GB to domain.\n",
395*956a9202SRyan Wilson 					pci_name(dev), i);
396*956a9202SRyan Wilson 			}
397*956a9202SRyan Wilson 		}
398*956a9202SRyan Wilson 	}
399*956a9202SRyan Wilson 
400*956a9202SRyan Wilson 	return 0;
401*956a9202SRyan Wilson }
402*956a9202SRyan Wilson 
403*956a9202SRyan Wilson static int __devinit pcifront_scan_bus(struct pcifront_device *pdev,
404*956a9202SRyan Wilson 				unsigned int domain, unsigned int bus,
405*956a9202SRyan Wilson 				struct pci_bus *b)
406*956a9202SRyan Wilson {
407*956a9202SRyan Wilson 	struct pci_dev *d;
408*956a9202SRyan Wilson 	unsigned int devfn;
409*956a9202SRyan Wilson 
410*956a9202SRyan Wilson 	/* Scan the bus for functions and add.
411*956a9202SRyan Wilson 	 * We omit handling of PCI bridge attachment because pciback prevents
412*956a9202SRyan Wilson 	 * bridges from being exported.
413*956a9202SRyan Wilson 	 */
414*956a9202SRyan Wilson 	for (devfn = 0; devfn < 0x100; devfn++) {
415*956a9202SRyan Wilson 		d = pci_get_slot(b, devfn);
416*956a9202SRyan Wilson 		if (d) {
417*956a9202SRyan Wilson 			/* Device is already known. */
418*956a9202SRyan Wilson 			pci_dev_put(d);
419*956a9202SRyan Wilson 			continue;
420*956a9202SRyan Wilson 		}
421*956a9202SRyan Wilson 
422*956a9202SRyan Wilson 		d = pci_scan_single_device(b, devfn);
423*956a9202SRyan Wilson 		if (d)
424*956a9202SRyan Wilson 			dev_info(&pdev->xdev->dev, "New device on "
425*956a9202SRyan Wilson 				 "%04x:%02x:%02x.%02x found.\n", domain, bus,
426*956a9202SRyan Wilson 				 PCI_SLOT(devfn), PCI_FUNC(devfn));
427*956a9202SRyan Wilson 	}
428*956a9202SRyan Wilson 
429*956a9202SRyan Wilson 	return 0;
430*956a9202SRyan Wilson }
431*956a9202SRyan Wilson 
432*956a9202SRyan Wilson static int __devinit pcifront_scan_root(struct pcifront_device *pdev,
433*956a9202SRyan Wilson 				 unsigned int domain, unsigned int bus)
434*956a9202SRyan Wilson {
435*956a9202SRyan Wilson 	struct pci_bus *b;
436*956a9202SRyan Wilson 	struct pcifront_sd *sd = NULL;
437*956a9202SRyan Wilson 	struct pci_bus_entry *bus_entry = NULL;
438*956a9202SRyan Wilson 	int err = 0;
439*956a9202SRyan Wilson 
440*956a9202SRyan Wilson #ifndef CONFIG_PCI_DOMAINS
441*956a9202SRyan Wilson 	if (domain != 0) {
442*956a9202SRyan Wilson 		dev_err(&pdev->xdev->dev,
443*956a9202SRyan Wilson 			"PCI Root in non-zero PCI Domain! domain=%d\n", domain);
444*956a9202SRyan Wilson 		dev_err(&pdev->xdev->dev,
445*956a9202SRyan Wilson 			"Please compile with CONFIG_PCI_DOMAINS\n");
446*956a9202SRyan Wilson 		err = -EINVAL;
447*956a9202SRyan Wilson 		goto err_out;
448*956a9202SRyan Wilson 	}
449*956a9202SRyan Wilson #endif
450*956a9202SRyan Wilson 
451*956a9202SRyan Wilson 	dev_info(&pdev->xdev->dev, "Creating PCI Frontend Bus %04x:%02x\n",
452*956a9202SRyan Wilson 		 domain, bus);
453*956a9202SRyan Wilson 
454*956a9202SRyan Wilson 	bus_entry = kmalloc(sizeof(*bus_entry), GFP_KERNEL);
455*956a9202SRyan Wilson 	sd = kmalloc(sizeof(*sd), GFP_KERNEL);
456*956a9202SRyan Wilson 	if (!bus_entry || !sd) {
457*956a9202SRyan Wilson 		err = -ENOMEM;
458*956a9202SRyan Wilson 		goto err_out;
459*956a9202SRyan Wilson 	}
460*956a9202SRyan Wilson 	pcifront_init_sd(sd, domain, bus, pdev);
461*956a9202SRyan Wilson 
462*956a9202SRyan Wilson 	b = pci_scan_bus_parented(&pdev->xdev->dev, bus,
463*956a9202SRyan Wilson 				  &pcifront_bus_ops, sd);
464*956a9202SRyan Wilson 	if (!b) {
465*956a9202SRyan Wilson 		dev_err(&pdev->xdev->dev,
466*956a9202SRyan Wilson 			"Error creating PCI Frontend Bus!\n");
467*956a9202SRyan Wilson 		err = -ENOMEM;
468*956a9202SRyan Wilson 		goto err_out;
469*956a9202SRyan Wilson 	}
470*956a9202SRyan Wilson 
471*956a9202SRyan Wilson 	bus_entry->bus = b;
472*956a9202SRyan Wilson 
473*956a9202SRyan Wilson 	list_add(&bus_entry->list, &pdev->root_buses);
474*956a9202SRyan Wilson 
475*956a9202SRyan Wilson 	/* pci_scan_bus_parented skips devices which do not have a have
476*956a9202SRyan Wilson 	* devfn==0. The pcifront_scan_bus enumerates all devfn. */
477*956a9202SRyan Wilson 	err = pcifront_scan_bus(pdev, domain, bus, b);
478*956a9202SRyan Wilson 
479*956a9202SRyan Wilson 	/* Claim resources before going "live" with our devices */
480*956a9202SRyan Wilson 	pci_walk_bus(b, pcifront_claim_resource, pdev);
481*956a9202SRyan Wilson 
482*956a9202SRyan Wilson 	/* Create SysFS and notify udev of the devices. Aka: "going live" */
483*956a9202SRyan Wilson 	pci_bus_add_devices(b);
484*956a9202SRyan Wilson 
485*956a9202SRyan Wilson 	return err;
486*956a9202SRyan Wilson 
487*956a9202SRyan Wilson err_out:
488*956a9202SRyan Wilson 	kfree(bus_entry);
489*956a9202SRyan Wilson 	kfree(sd);
490*956a9202SRyan Wilson 
491*956a9202SRyan Wilson 	return err;
492*956a9202SRyan Wilson }
493*956a9202SRyan Wilson 
494*956a9202SRyan Wilson static int __devinit pcifront_rescan_root(struct pcifront_device *pdev,
495*956a9202SRyan Wilson 				   unsigned int domain, unsigned int bus)
496*956a9202SRyan Wilson {
497*956a9202SRyan Wilson 	int err;
498*956a9202SRyan Wilson 	struct pci_bus *b;
499*956a9202SRyan Wilson 
500*956a9202SRyan Wilson #ifndef CONFIG_PCI_DOMAINS
501*956a9202SRyan Wilson 	if (domain != 0) {
502*956a9202SRyan Wilson 		dev_err(&pdev->xdev->dev,
503*956a9202SRyan Wilson 			"PCI Root in non-zero PCI Domain! domain=%d\n", domain);
504*956a9202SRyan Wilson 		dev_err(&pdev->xdev->dev,
505*956a9202SRyan Wilson 			"Please compile with CONFIG_PCI_DOMAINS\n");
506*956a9202SRyan Wilson 		return -EINVAL;
507*956a9202SRyan Wilson 	}
508*956a9202SRyan Wilson #endif
509*956a9202SRyan Wilson 
510*956a9202SRyan Wilson 	dev_info(&pdev->xdev->dev, "Rescanning PCI Frontend Bus %04x:%02x\n",
511*956a9202SRyan Wilson 		 domain, bus);
512*956a9202SRyan Wilson 
513*956a9202SRyan Wilson 	b = pci_find_bus(domain, bus);
514*956a9202SRyan Wilson 	if (!b)
515*956a9202SRyan Wilson 		/* If the bus is unknown, create it. */
516*956a9202SRyan Wilson 		return pcifront_scan_root(pdev, domain, bus);
517*956a9202SRyan Wilson 
518*956a9202SRyan Wilson 	err = pcifront_scan_bus(pdev, domain, bus, b);
519*956a9202SRyan Wilson 
520*956a9202SRyan Wilson 	/* Claim resources before going "live" with our devices */
521*956a9202SRyan Wilson 	pci_walk_bus(b, pcifront_claim_resource, pdev);
522*956a9202SRyan Wilson 
523*956a9202SRyan Wilson 	/* Create SysFS and notify udev of the devices. Aka: "going live" */
524*956a9202SRyan Wilson 	pci_bus_add_devices(b);
525*956a9202SRyan Wilson 
526*956a9202SRyan Wilson 	return err;
527*956a9202SRyan Wilson }
528*956a9202SRyan Wilson 
529*956a9202SRyan Wilson static void free_root_bus_devs(struct pci_bus *bus)
530*956a9202SRyan Wilson {
531*956a9202SRyan Wilson 	struct pci_dev *dev;
532*956a9202SRyan Wilson 
533*956a9202SRyan Wilson 	while (!list_empty(&bus->devices)) {
534*956a9202SRyan Wilson 		dev = container_of(bus->devices.next, struct pci_dev,
535*956a9202SRyan Wilson 				   bus_list);
536*956a9202SRyan Wilson 		dev_dbg(&dev->dev, "removing device\n");
537*956a9202SRyan Wilson 		pci_remove_bus_device(dev);
538*956a9202SRyan Wilson 	}
539*956a9202SRyan Wilson }
540*956a9202SRyan Wilson 
541*956a9202SRyan Wilson static void pcifront_free_roots(struct pcifront_device *pdev)
542*956a9202SRyan Wilson {
543*956a9202SRyan Wilson 	struct pci_bus_entry *bus_entry, *t;
544*956a9202SRyan Wilson 
545*956a9202SRyan Wilson 	dev_dbg(&pdev->xdev->dev, "cleaning up root buses\n");
546*956a9202SRyan Wilson 
547*956a9202SRyan Wilson 	list_for_each_entry_safe(bus_entry, t, &pdev->root_buses, list) {
548*956a9202SRyan Wilson 		list_del(&bus_entry->list);
549*956a9202SRyan Wilson 
550*956a9202SRyan Wilson 		free_root_bus_devs(bus_entry->bus);
551*956a9202SRyan Wilson 
552*956a9202SRyan Wilson 		kfree(bus_entry->bus->sysdata);
553*956a9202SRyan Wilson 
554*956a9202SRyan Wilson 		device_unregister(bus_entry->bus->bridge);
555*956a9202SRyan Wilson 		pci_remove_bus(bus_entry->bus);
556*956a9202SRyan Wilson 
557*956a9202SRyan Wilson 		kfree(bus_entry);
558*956a9202SRyan Wilson 	}
559*956a9202SRyan Wilson }
560*956a9202SRyan Wilson 
561*956a9202SRyan Wilson static pci_ers_result_t pcifront_common_process(int cmd,
562*956a9202SRyan Wilson 						struct pcifront_device *pdev,
563*956a9202SRyan Wilson 						pci_channel_state_t state)
564*956a9202SRyan Wilson {
565*956a9202SRyan Wilson 	pci_ers_result_t result;
566*956a9202SRyan Wilson 	struct pci_driver *pdrv;
567*956a9202SRyan Wilson 	int bus = pdev->sh_info->aer_op.bus;
568*956a9202SRyan Wilson 	int devfn = pdev->sh_info->aer_op.devfn;
569*956a9202SRyan Wilson 	struct pci_dev *pcidev;
570*956a9202SRyan Wilson 	int flag = 0;
571*956a9202SRyan Wilson 
572*956a9202SRyan Wilson 	dev_dbg(&pdev->xdev->dev,
573*956a9202SRyan Wilson 		"pcifront AER process: cmd %x (bus:%x, devfn%x)",
574*956a9202SRyan Wilson 		cmd, bus, devfn);
575*956a9202SRyan Wilson 	result = PCI_ERS_RESULT_NONE;
576*956a9202SRyan Wilson 
577*956a9202SRyan Wilson 	pcidev = pci_get_bus_and_slot(bus, devfn);
578*956a9202SRyan Wilson 	if (!pcidev || !pcidev->driver) {
579*956a9202SRyan Wilson 		dev_err(&pcidev->dev,
580*956a9202SRyan Wilson 			"device or driver is NULL\n");
581*956a9202SRyan Wilson 		return result;
582*956a9202SRyan Wilson 	}
583*956a9202SRyan Wilson 	pdrv = pcidev->driver;
584*956a9202SRyan Wilson 
585*956a9202SRyan Wilson 	if (get_driver(&pdrv->driver)) {
586*956a9202SRyan Wilson 		if (pdrv->err_handler && pdrv->err_handler->error_detected) {
587*956a9202SRyan Wilson 			dev_dbg(&pcidev->dev,
588*956a9202SRyan Wilson 				"trying to call AER service\n");
589*956a9202SRyan Wilson 			if (pcidev) {
590*956a9202SRyan Wilson 				flag = 1;
591*956a9202SRyan Wilson 				switch (cmd) {
592*956a9202SRyan Wilson 				case XEN_PCI_OP_aer_detected:
593*956a9202SRyan Wilson 					result = pdrv->err_handler->
594*956a9202SRyan Wilson 						 error_detected(pcidev, state);
595*956a9202SRyan Wilson 					break;
596*956a9202SRyan Wilson 				case XEN_PCI_OP_aer_mmio:
597*956a9202SRyan Wilson 					result = pdrv->err_handler->
598*956a9202SRyan Wilson 						 mmio_enabled(pcidev);
599*956a9202SRyan Wilson 					break;
600*956a9202SRyan Wilson 				case XEN_PCI_OP_aer_slotreset:
601*956a9202SRyan Wilson 					result = pdrv->err_handler->
602*956a9202SRyan Wilson 						 slot_reset(pcidev);
603*956a9202SRyan Wilson 					break;
604*956a9202SRyan Wilson 				case XEN_PCI_OP_aer_resume:
605*956a9202SRyan Wilson 					pdrv->err_handler->resume(pcidev);
606*956a9202SRyan Wilson 					break;
607*956a9202SRyan Wilson 				default:
608*956a9202SRyan Wilson 					dev_err(&pdev->xdev->dev,
609*956a9202SRyan Wilson 						"bad request in aer recovery "
610*956a9202SRyan Wilson 						"operation!\n");
611*956a9202SRyan Wilson 
612*956a9202SRyan Wilson 				}
613*956a9202SRyan Wilson 			}
614*956a9202SRyan Wilson 		}
615*956a9202SRyan Wilson 		put_driver(&pdrv->driver);
616*956a9202SRyan Wilson 	}
617*956a9202SRyan Wilson 	if (!flag)
618*956a9202SRyan Wilson 		result = PCI_ERS_RESULT_NONE;
619*956a9202SRyan Wilson 
620*956a9202SRyan Wilson 	return result;
621*956a9202SRyan Wilson }
622*956a9202SRyan Wilson 
623*956a9202SRyan Wilson 
624*956a9202SRyan Wilson static void pcifront_do_aer(struct work_struct *data)
625*956a9202SRyan Wilson {
626*956a9202SRyan Wilson 	struct pcifront_device *pdev =
627*956a9202SRyan Wilson 		container_of(data, struct pcifront_device, op_work);
628*956a9202SRyan Wilson 	int cmd = pdev->sh_info->aer_op.cmd;
629*956a9202SRyan Wilson 	pci_channel_state_t state =
630*956a9202SRyan Wilson 		(pci_channel_state_t)pdev->sh_info->aer_op.err;
631*956a9202SRyan Wilson 
632*956a9202SRyan Wilson 	/*If a pci_conf op is in progress,
633*956a9202SRyan Wilson 		we have to wait until it is done before service aer op*/
634*956a9202SRyan Wilson 	dev_dbg(&pdev->xdev->dev,
635*956a9202SRyan Wilson 		"pcifront service aer bus %x devfn %x\n",
636*956a9202SRyan Wilson 		pdev->sh_info->aer_op.bus, pdev->sh_info->aer_op.devfn);
637*956a9202SRyan Wilson 
638*956a9202SRyan Wilson 	pdev->sh_info->aer_op.err = pcifront_common_process(cmd, pdev, state);
639*956a9202SRyan Wilson 
640*956a9202SRyan Wilson 	/* Post the operation to the guest. */
641*956a9202SRyan Wilson 	wmb();
642*956a9202SRyan Wilson 	clear_bit(_XEN_PCIB_active, (unsigned long *)&pdev->sh_info->flags);
643*956a9202SRyan Wilson 	notify_remote_via_evtchn(pdev->evtchn);
644*956a9202SRyan Wilson 
645*956a9202SRyan Wilson 	/*in case of we lost an aer request in four lines time_window*/
646*956a9202SRyan Wilson 	smp_mb__before_clear_bit();
647*956a9202SRyan Wilson 	clear_bit(_PDEVB_op_active, &pdev->flags);
648*956a9202SRyan Wilson 	smp_mb__after_clear_bit();
649*956a9202SRyan Wilson 
650*956a9202SRyan Wilson 	schedule_pcifront_aer_op(pdev);
651*956a9202SRyan Wilson 
652*956a9202SRyan Wilson }
653*956a9202SRyan Wilson 
654*956a9202SRyan Wilson static irqreturn_t pcifront_handler_aer(int irq, void *dev)
655*956a9202SRyan Wilson {
656*956a9202SRyan Wilson 	struct pcifront_device *pdev = dev;
657*956a9202SRyan Wilson 	schedule_pcifront_aer_op(pdev);
658*956a9202SRyan Wilson 	return IRQ_HANDLED;
659*956a9202SRyan Wilson }
660*956a9202SRyan Wilson static int pcifront_connect(struct pcifront_device *pdev)
661*956a9202SRyan Wilson {
662*956a9202SRyan Wilson 	int err = 0;
663*956a9202SRyan Wilson 
664*956a9202SRyan Wilson 	spin_lock(&pcifront_dev_lock);
665*956a9202SRyan Wilson 
666*956a9202SRyan Wilson 	if (!pcifront_dev) {
667*956a9202SRyan Wilson 		dev_info(&pdev->xdev->dev, "Installing PCI frontend\n");
668*956a9202SRyan Wilson 		pcifront_dev = pdev;
669*956a9202SRyan Wilson 	} else {
670*956a9202SRyan Wilson 		dev_err(&pdev->xdev->dev, "PCI frontend already installed!\n");
671*956a9202SRyan Wilson 		err = -EEXIST;
672*956a9202SRyan Wilson 	}
673*956a9202SRyan Wilson 
674*956a9202SRyan Wilson 	spin_unlock(&pcifront_dev_lock);
675*956a9202SRyan Wilson 
676*956a9202SRyan Wilson 	return err;
677*956a9202SRyan Wilson }
678*956a9202SRyan Wilson 
679*956a9202SRyan Wilson static void pcifront_disconnect(struct pcifront_device *pdev)
680*956a9202SRyan Wilson {
681*956a9202SRyan Wilson 	spin_lock(&pcifront_dev_lock);
682*956a9202SRyan Wilson 
683*956a9202SRyan Wilson 	if (pdev == pcifront_dev) {
684*956a9202SRyan Wilson 		dev_info(&pdev->xdev->dev,
685*956a9202SRyan Wilson 			 "Disconnecting PCI Frontend Buses\n");
686*956a9202SRyan Wilson 		pcifront_dev = NULL;
687*956a9202SRyan Wilson 	}
688*956a9202SRyan Wilson 
689*956a9202SRyan Wilson 	spin_unlock(&pcifront_dev_lock);
690*956a9202SRyan Wilson }
691*956a9202SRyan Wilson static struct pcifront_device *alloc_pdev(struct xenbus_device *xdev)
692*956a9202SRyan Wilson {
693*956a9202SRyan Wilson 	struct pcifront_device *pdev;
694*956a9202SRyan Wilson 
695*956a9202SRyan Wilson 	pdev = kzalloc(sizeof(struct pcifront_device), GFP_KERNEL);
696*956a9202SRyan Wilson 	if (pdev == NULL)
697*956a9202SRyan Wilson 		goto out;
698*956a9202SRyan Wilson 
699*956a9202SRyan Wilson 	pdev->sh_info =
700*956a9202SRyan Wilson 	    (struct xen_pci_sharedinfo *)__get_free_page(GFP_KERNEL);
701*956a9202SRyan Wilson 	if (pdev->sh_info == NULL) {
702*956a9202SRyan Wilson 		kfree(pdev);
703*956a9202SRyan Wilson 		pdev = NULL;
704*956a9202SRyan Wilson 		goto out;
705*956a9202SRyan Wilson 	}
706*956a9202SRyan Wilson 	pdev->sh_info->flags = 0;
707*956a9202SRyan Wilson 
708*956a9202SRyan Wilson 	/*Flag for registering PV AER handler*/
709*956a9202SRyan Wilson 	set_bit(_XEN_PCIB_AERHANDLER, (void *)&pdev->sh_info->flags);
710*956a9202SRyan Wilson 
711*956a9202SRyan Wilson 	dev_set_drvdata(&xdev->dev, pdev);
712*956a9202SRyan Wilson 	pdev->xdev = xdev;
713*956a9202SRyan Wilson 
714*956a9202SRyan Wilson 	INIT_LIST_HEAD(&pdev->root_buses);
715*956a9202SRyan Wilson 
716*956a9202SRyan Wilson 	spin_lock_init(&pdev->sh_info_lock);
717*956a9202SRyan Wilson 
718*956a9202SRyan Wilson 	pdev->evtchn = INVALID_EVTCHN;
719*956a9202SRyan Wilson 	pdev->gnt_ref = INVALID_GRANT_REF;
720*956a9202SRyan Wilson 	pdev->irq = -1;
721*956a9202SRyan Wilson 
722*956a9202SRyan Wilson 	INIT_WORK(&pdev->op_work, pcifront_do_aer);
723*956a9202SRyan Wilson 
724*956a9202SRyan Wilson 	dev_dbg(&xdev->dev, "Allocated pdev @ 0x%p pdev->sh_info @ 0x%p\n",
725*956a9202SRyan Wilson 		pdev, pdev->sh_info);
726*956a9202SRyan Wilson out:
727*956a9202SRyan Wilson 	return pdev;
728*956a9202SRyan Wilson }
729*956a9202SRyan Wilson 
730*956a9202SRyan Wilson static void free_pdev(struct pcifront_device *pdev)
731*956a9202SRyan Wilson {
732*956a9202SRyan Wilson 	dev_dbg(&pdev->xdev->dev, "freeing pdev @ 0x%p\n", pdev);
733*956a9202SRyan Wilson 
734*956a9202SRyan Wilson 	pcifront_free_roots(pdev);
735*956a9202SRyan Wilson 
736*956a9202SRyan Wilson 	/*For PCIE_AER error handling job*/
737*956a9202SRyan Wilson 	flush_scheduled_work();
738*956a9202SRyan Wilson 
739*956a9202SRyan Wilson 	if (pdev->irq >= 0)
740*956a9202SRyan Wilson 		unbind_from_irqhandler(pdev->irq, pdev);
741*956a9202SRyan Wilson 
742*956a9202SRyan Wilson 	if (pdev->evtchn != INVALID_EVTCHN)
743*956a9202SRyan Wilson 		xenbus_free_evtchn(pdev->xdev, pdev->evtchn);
744*956a9202SRyan Wilson 
745*956a9202SRyan Wilson 	if (pdev->gnt_ref != INVALID_GRANT_REF)
746*956a9202SRyan Wilson 		gnttab_end_foreign_access(pdev->gnt_ref, 0 /* r/w page */,
747*956a9202SRyan Wilson 					  (unsigned long)pdev->sh_info);
748*956a9202SRyan Wilson 	else
749*956a9202SRyan Wilson 		free_page((unsigned long)pdev->sh_info);
750*956a9202SRyan Wilson 
751*956a9202SRyan Wilson 	dev_set_drvdata(&pdev->xdev->dev, NULL);
752*956a9202SRyan Wilson 
753*956a9202SRyan Wilson 	kfree(pdev);
754*956a9202SRyan Wilson }
755*956a9202SRyan Wilson 
756*956a9202SRyan Wilson static int pcifront_publish_info(struct pcifront_device *pdev)
757*956a9202SRyan Wilson {
758*956a9202SRyan Wilson 	int err = 0;
759*956a9202SRyan Wilson 	struct xenbus_transaction trans;
760*956a9202SRyan Wilson 
761*956a9202SRyan Wilson 	err = xenbus_grant_ring(pdev->xdev, virt_to_mfn(pdev->sh_info));
762*956a9202SRyan Wilson 	if (err < 0)
763*956a9202SRyan Wilson 		goto out;
764*956a9202SRyan Wilson 
765*956a9202SRyan Wilson 	pdev->gnt_ref = err;
766*956a9202SRyan Wilson 
767*956a9202SRyan Wilson 	err = xenbus_alloc_evtchn(pdev->xdev, &pdev->evtchn);
768*956a9202SRyan Wilson 	if (err)
769*956a9202SRyan Wilson 		goto out;
770*956a9202SRyan Wilson 
771*956a9202SRyan Wilson 	err = bind_evtchn_to_irqhandler(pdev->evtchn, pcifront_handler_aer,
772*956a9202SRyan Wilson 		0, "pcifront", pdev);
773*956a9202SRyan Wilson 
774*956a9202SRyan Wilson 	if (err < 0)
775*956a9202SRyan Wilson 		return err;
776*956a9202SRyan Wilson 
777*956a9202SRyan Wilson 	pdev->irq = err;
778*956a9202SRyan Wilson 
779*956a9202SRyan Wilson do_publish:
780*956a9202SRyan Wilson 	err = xenbus_transaction_start(&trans);
781*956a9202SRyan Wilson 	if (err) {
782*956a9202SRyan Wilson 		xenbus_dev_fatal(pdev->xdev, err,
783*956a9202SRyan Wilson 				 "Error writing configuration for backend "
784*956a9202SRyan Wilson 				 "(start transaction)");
785*956a9202SRyan Wilson 		goto out;
786*956a9202SRyan Wilson 	}
787*956a9202SRyan Wilson 
788*956a9202SRyan Wilson 	err = xenbus_printf(trans, pdev->xdev->nodename,
789*956a9202SRyan Wilson 			    "pci-op-ref", "%u", pdev->gnt_ref);
790*956a9202SRyan Wilson 	if (!err)
791*956a9202SRyan Wilson 		err = xenbus_printf(trans, pdev->xdev->nodename,
792*956a9202SRyan Wilson 				    "event-channel", "%u", pdev->evtchn);
793*956a9202SRyan Wilson 	if (!err)
794*956a9202SRyan Wilson 		err = xenbus_printf(trans, pdev->xdev->nodename,
795*956a9202SRyan Wilson 				    "magic", XEN_PCI_MAGIC);
796*956a9202SRyan Wilson 
797*956a9202SRyan Wilson 	if (err) {
798*956a9202SRyan Wilson 		xenbus_transaction_end(trans, 1);
799*956a9202SRyan Wilson 		xenbus_dev_fatal(pdev->xdev, err,
800*956a9202SRyan Wilson 				 "Error writing configuration for backend");
801*956a9202SRyan Wilson 		goto out;
802*956a9202SRyan Wilson 	} else {
803*956a9202SRyan Wilson 		err = xenbus_transaction_end(trans, 0);
804*956a9202SRyan Wilson 		if (err == -EAGAIN)
805*956a9202SRyan Wilson 			goto do_publish;
806*956a9202SRyan Wilson 		else if (err) {
807*956a9202SRyan Wilson 			xenbus_dev_fatal(pdev->xdev, err,
808*956a9202SRyan Wilson 					 "Error completing transaction "
809*956a9202SRyan Wilson 					 "for backend");
810*956a9202SRyan Wilson 			goto out;
811*956a9202SRyan Wilson 		}
812*956a9202SRyan Wilson 	}
813*956a9202SRyan Wilson 
814*956a9202SRyan Wilson 	xenbus_switch_state(pdev->xdev, XenbusStateInitialised);
815*956a9202SRyan Wilson 
816*956a9202SRyan Wilson 	dev_dbg(&pdev->xdev->dev, "publishing successful!\n");
817*956a9202SRyan Wilson 
818*956a9202SRyan Wilson out:
819*956a9202SRyan Wilson 	return err;
820*956a9202SRyan Wilson }
821*956a9202SRyan Wilson 
822*956a9202SRyan Wilson static int __devinit pcifront_try_connect(struct pcifront_device *pdev)
823*956a9202SRyan Wilson {
824*956a9202SRyan Wilson 	int err = -EFAULT;
825*956a9202SRyan Wilson 	int i, num_roots, len;
826*956a9202SRyan Wilson 	char str[64];
827*956a9202SRyan Wilson 	unsigned int domain, bus;
828*956a9202SRyan Wilson 
829*956a9202SRyan Wilson 
830*956a9202SRyan Wilson 	/* Only connect once */
831*956a9202SRyan Wilson 	if (xenbus_read_driver_state(pdev->xdev->nodename) !=
832*956a9202SRyan Wilson 	    XenbusStateInitialised)
833*956a9202SRyan Wilson 		goto out;
834*956a9202SRyan Wilson 
835*956a9202SRyan Wilson 	err = pcifront_connect(pdev);
836*956a9202SRyan Wilson 	if (err) {
837*956a9202SRyan Wilson 		xenbus_dev_fatal(pdev->xdev, err,
838*956a9202SRyan Wilson 				 "Error connecting PCI Frontend");
839*956a9202SRyan Wilson 		goto out;
840*956a9202SRyan Wilson 	}
841*956a9202SRyan Wilson 
842*956a9202SRyan Wilson 	err = xenbus_scanf(XBT_NIL, pdev->xdev->otherend,
843*956a9202SRyan Wilson 			   "root_num", "%d", &num_roots);
844*956a9202SRyan Wilson 	if (err == -ENOENT) {
845*956a9202SRyan Wilson 		xenbus_dev_error(pdev->xdev, err,
846*956a9202SRyan Wilson 				 "No PCI Roots found, trying 0000:00");
847*956a9202SRyan Wilson 		err = pcifront_scan_root(pdev, 0, 0);
848*956a9202SRyan Wilson 		num_roots = 0;
849*956a9202SRyan Wilson 	} else if (err != 1) {
850*956a9202SRyan Wilson 		if (err == 0)
851*956a9202SRyan Wilson 			err = -EINVAL;
852*956a9202SRyan Wilson 		xenbus_dev_fatal(pdev->xdev, err,
853*956a9202SRyan Wilson 				 "Error reading number of PCI roots");
854*956a9202SRyan Wilson 		goto out;
855*956a9202SRyan Wilson 	}
856*956a9202SRyan Wilson 
857*956a9202SRyan Wilson 	for (i = 0; i < num_roots; i++) {
858*956a9202SRyan Wilson 		len = snprintf(str, sizeof(str), "root-%d", i);
859*956a9202SRyan Wilson 		if (unlikely(len >= (sizeof(str) - 1))) {
860*956a9202SRyan Wilson 			err = -ENOMEM;
861*956a9202SRyan Wilson 			goto out;
862*956a9202SRyan Wilson 		}
863*956a9202SRyan Wilson 
864*956a9202SRyan Wilson 		err = xenbus_scanf(XBT_NIL, pdev->xdev->otherend, str,
865*956a9202SRyan Wilson 				   "%x:%x", &domain, &bus);
866*956a9202SRyan Wilson 		if (err != 2) {
867*956a9202SRyan Wilson 			if (err >= 0)
868*956a9202SRyan Wilson 				err = -EINVAL;
869*956a9202SRyan Wilson 			xenbus_dev_fatal(pdev->xdev, err,
870*956a9202SRyan Wilson 					 "Error reading PCI root %d", i);
871*956a9202SRyan Wilson 			goto out;
872*956a9202SRyan Wilson 		}
873*956a9202SRyan Wilson 
874*956a9202SRyan Wilson 		err = pcifront_scan_root(pdev, domain, bus);
875*956a9202SRyan Wilson 		if (err) {
876*956a9202SRyan Wilson 			xenbus_dev_fatal(pdev->xdev, err,
877*956a9202SRyan Wilson 					 "Error scanning PCI root %04x:%02x",
878*956a9202SRyan Wilson 					 domain, bus);
879*956a9202SRyan Wilson 			goto out;
880*956a9202SRyan Wilson 		}
881*956a9202SRyan Wilson 	}
882*956a9202SRyan Wilson 
883*956a9202SRyan Wilson 	err = xenbus_switch_state(pdev->xdev, XenbusStateConnected);
884*956a9202SRyan Wilson 
885*956a9202SRyan Wilson out:
886*956a9202SRyan Wilson 	return err;
887*956a9202SRyan Wilson }
888*956a9202SRyan Wilson 
889*956a9202SRyan Wilson static int pcifront_try_disconnect(struct pcifront_device *pdev)
890*956a9202SRyan Wilson {
891*956a9202SRyan Wilson 	int err = 0;
892*956a9202SRyan Wilson 	enum xenbus_state prev_state;
893*956a9202SRyan Wilson 
894*956a9202SRyan Wilson 
895*956a9202SRyan Wilson 	prev_state = xenbus_read_driver_state(pdev->xdev->nodename);
896*956a9202SRyan Wilson 
897*956a9202SRyan Wilson 	if (prev_state >= XenbusStateClosing)
898*956a9202SRyan Wilson 		goto out;
899*956a9202SRyan Wilson 
900*956a9202SRyan Wilson 	if (prev_state == XenbusStateConnected) {
901*956a9202SRyan Wilson 		pcifront_free_roots(pdev);
902*956a9202SRyan Wilson 		pcifront_disconnect(pdev);
903*956a9202SRyan Wilson 	}
904*956a9202SRyan Wilson 
905*956a9202SRyan Wilson 	err = xenbus_switch_state(pdev->xdev, XenbusStateClosed);
906*956a9202SRyan Wilson 
907*956a9202SRyan Wilson out:
908*956a9202SRyan Wilson 
909*956a9202SRyan Wilson 	return err;
910*956a9202SRyan Wilson }
911*956a9202SRyan Wilson 
912*956a9202SRyan Wilson static int __devinit pcifront_attach_devices(struct pcifront_device *pdev)
913*956a9202SRyan Wilson {
914*956a9202SRyan Wilson 	int err = -EFAULT;
915*956a9202SRyan Wilson 	int i, num_roots, len;
916*956a9202SRyan Wilson 	unsigned int domain, bus;
917*956a9202SRyan Wilson 	char str[64];
918*956a9202SRyan Wilson 
919*956a9202SRyan Wilson 	if (xenbus_read_driver_state(pdev->xdev->nodename) !=
920*956a9202SRyan Wilson 	    XenbusStateReconfiguring)
921*956a9202SRyan Wilson 		goto out;
922*956a9202SRyan Wilson 
923*956a9202SRyan Wilson 	err = xenbus_scanf(XBT_NIL, pdev->xdev->otherend,
924*956a9202SRyan Wilson 			   "root_num", "%d", &num_roots);
925*956a9202SRyan Wilson 	if (err == -ENOENT) {
926*956a9202SRyan Wilson 		xenbus_dev_error(pdev->xdev, err,
927*956a9202SRyan Wilson 				 "No PCI Roots found, trying 0000:00");
928*956a9202SRyan Wilson 		err = pcifront_rescan_root(pdev, 0, 0);
929*956a9202SRyan Wilson 		num_roots = 0;
930*956a9202SRyan Wilson 	} else if (err != 1) {
931*956a9202SRyan Wilson 		if (err == 0)
932*956a9202SRyan Wilson 			err = -EINVAL;
933*956a9202SRyan Wilson 		xenbus_dev_fatal(pdev->xdev, err,
934*956a9202SRyan Wilson 				 "Error reading number of PCI roots");
935*956a9202SRyan Wilson 		goto out;
936*956a9202SRyan Wilson 	}
937*956a9202SRyan Wilson 
938*956a9202SRyan Wilson 	for (i = 0; i < num_roots; i++) {
939*956a9202SRyan Wilson 		len = snprintf(str, sizeof(str), "root-%d", i);
940*956a9202SRyan Wilson 		if (unlikely(len >= (sizeof(str) - 1))) {
941*956a9202SRyan Wilson 			err = -ENOMEM;
942*956a9202SRyan Wilson 			goto out;
943*956a9202SRyan Wilson 		}
944*956a9202SRyan Wilson 
945*956a9202SRyan Wilson 		err = xenbus_scanf(XBT_NIL, pdev->xdev->otherend, str,
946*956a9202SRyan Wilson 				   "%x:%x", &domain, &bus);
947*956a9202SRyan Wilson 		if (err != 2) {
948*956a9202SRyan Wilson 			if (err >= 0)
949*956a9202SRyan Wilson 				err = -EINVAL;
950*956a9202SRyan Wilson 			xenbus_dev_fatal(pdev->xdev, err,
951*956a9202SRyan Wilson 					 "Error reading PCI root %d", i);
952*956a9202SRyan Wilson 			goto out;
953*956a9202SRyan Wilson 		}
954*956a9202SRyan Wilson 
955*956a9202SRyan Wilson 		err = pcifront_rescan_root(pdev, domain, bus);
956*956a9202SRyan Wilson 		if (err) {
957*956a9202SRyan Wilson 			xenbus_dev_fatal(pdev->xdev, err,
958*956a9202SRyan Wilson 					 "Error scanning PCI root %04x:%02x",
959*956a9202SRyan Wilson 					 domain, bus);
960*956a9202SRyan Wilson 			goto out;
961*956a9202SRyan Wilson 		}
962*956a9202SRyan Wilson 	}
963*956a9202SRyan Wilson 
964*956a9202SRyan Wilson 	xenbus_switch_state(pdev->xdev, XenbusStateConnected);
965*956a9202SRyan Wilson 
966*956a9202SRyan Wilson out:
967*956a9202SRyan Wilson 	return err;
968*956a9202SRyan Wilson }
969*956a9202SRyan Wilson 
970*956a9202SRyan Wilson static int pcifront_detach_devices(struct pcifront_device *pdev)
971*956a9202SRyan Wilson {
972*956a9202SRyan Wilson 	int err = 0;
973*956a9202SRyan Wilson 	int i, num_devs;
974*956a9202SRyan Wilson 	unsigned int domain, bus, slot, func;
975*956a9202SRyan Wilson 	struct pci_bus *pci_bus;
976*956a9202SRyan Wilson 	struct pci_dev *pci_dev;
977*956a9202SRyan Wilson 	char str[64];
978*956a9202SRyan Wilson 
979*956a9202SRyan Wilson 	if (xenbus_read_driver_state(pdev->xdev->nodename) !=
980*956a9202SRyan Wilson 	    XenbusStateConnected)
981*956a9202SRyan Wilson 		goto out;
982*956a9202SRyan Wilson 
983*956a9202SRyan Wilson 	err = xenbus_scanf(XBT_NIL, pdev->xdev->otherend, "num_devs", "%d",
984*956a9202SRyan Wilson 			   &num_devs);
985*956a9202SRyan Wilson 	if (err != 1) {
986*956a9202SRyan Wilson 		if (err >= 0)
987*956a9202SRyan Wilson 			err = -EINVAL;
988*956a9202SRyan Wilson 		xenbus_dev_fatal(pdev->xdev, err,
989*956a9202SRyan Wilson 				 "Error reading number of PCI devices");
990*956a9202SRyan Wilson 		goto out;
991*956a9202SRyan Wilson 	}
992*956a9202SRyan Wilson 
993*956a9202SRyan Wilson 	/* Find devices being detached and remove them. */
994*956a9202SRyan Wilson 	for (i = 0; i < num_devs; i++) {
995*956a9202SRyan Wilson 		int l, state;
996*956a9202SRyan Wilson 		l = snprintf(str, sizeof(str), "state-%d", i);
997*956a9202SRyan Wilson 		if (unlikely(l >= (sizeof(str) - 1))) {
998*956a9202SRyan Wilson 			err = -ENOMEM;
999*956a9202SRyan Wilson 			goto out;
1000*956a9202SRyan Wilson 		}
1001*956a9202SRyan Wilson 		err = xenbus_scanf(XBT_NIL, pdev->xdev->otherend, str, "%d",
1002*956a9202SRyan Wilson 				   &state);
1003*956a9202SRyan Wilson 		if (err != 1)
1004*956a9202SRyan Wilson 			state = XenbusStateUnknown;
1005*956a9202SRyan Wilson 
1006*956a9202SRyan Wilson 		if (state != XenbusStateClosing)
1007*956a9202SRyan Wilson 			continue;
1008*956a9202SRyan Wilson 
1009*956a9202SRyan Wilson 		/* Remove device. */
1010*956a9202SRyan Wilson 		l = snprintf(str, sizeof(str), "vdev-%d", i);
1011*956a9202SRyan Wilson 		if (unlikely(l >= (sizeof(str) - 1))) {
1012*956a9202SRyan Wilson 			err = -ENOMEM;
1013*956a9202SRyan Wilson 			goto out;
1014*956a9202SRyan Wilson 		}
1015*956a9202SRyan Wilson 		err = xenbus_scanf(XBT_NIL, pdev->xdev->otherend, str,
1016*956a9202SRyan Wilson 				   "%x:%x:%x.%x", &domain, &bus, &slot, &func);
1017*956a9202SRyan Wilson 		if (err != 4) {
1018*956a9202SRyan Wilson 			if (err >= 0)
1019*956a9202SRyan Wilson 				err = -EINVAL;
1020*956a9202SRyan Wilson 			xenbus_dev_fatal(pdev->xdev, err,
1021*956a9202SRyan Wilson 					 "Error reading PCI device %d", i);
1022*956a9202SRyan Wilson 			goto out;
1023*956a9202SRyan Wilson 		}
1024*956a9202SRyan Wilson 
1025*956a9202SRyan Wilson 		pci_bus = pci_find_bus(domain, bus);
1026*956a9202SRyan Wilson 		if (!pci_bus) {
1027*956a9202SRyan Wilson 			dev_dbg(&pdev->xdev->dev, "Cannot get bus %04x:%02x\n",
1028*956a9202SRyan Wilson 				domain, bus);
1029*956a9202SRyan Wilson 			continue;
1030*956a9202SRyan Wilson 		}
1031*956a9202SRyan Wilson 		pci_dev = pci_get_slot(pci_bus, PCI_DEVFN(slot, func));
1032*956a9202SRyan Wilson 		if (!pci_dev) {
1033*956a9202SRyan Wilson 			dev_dbg(&pdev->xdev->dev,
1034*956a9202SRyan Wilson 				"Cannot get PCI device %04x:%02x:%02x.%02x\n",
1035*956a9202SRyan Wilson 				domain, bus, slot, func);
1036*956a9202SRyan Wilson 			continue;
1037*956a9202SRyan Wilson 		}
1038*956a9202SRyan Wilson 		pci_remove_bus_device(pci_dev);
1039*956a9202SRyan Wilson 		pci_dev_put(pci_dev);
1040*956a9202SRyan Wilson 
1041*956a9202SRyan Wilson 		dev_dbg(&pdev->xdev->dev,
1042*956a9202SRyan Wilson 			"PCI device %04x:%02x:%02x.%02x removed.\n",
1043*956a9202SRyan Wilson 			domain, bus, slot, func);
1044*956a9202SRyan Wilson 	}
1045*956a9202SRyan Wilson 
1046*956a9202SRyan Wilson 	err = xenbus_switch_state(pdev->xdev, XenbusStateReconfiguring);
1047*956a9202SRyan Wilson 
1048*956a9202SRyan Wilson out:
1049*956a9202SRyan Wilson 	return err;
1050*956a9202SRyan Wilson }
1051*956a9202SRyan Wilson 
1052*956a9202SRyan Wilson static void __init_refok pcifront_backend_changed(struct xenbus_device *xdev,
1053*956a9202SRyan Wilson 						  enum xenbus_state be_state)
1054*956a9202SRyan Wilson {
1055*956a9202SRyan Wilson 	struct pcifront_device *pdev = dev_get_drvdata(&xdev->dev);
1056*956a9202SRyan Wilson 
1057*956a9202SRyan Wilson 	switch (be_state) {
1058*956a9202SRyan Wilson 	case XenbusStateUnknown:
1059*956a9202SRyan Wilson 	case XenbusStateInitialising:
1060*956a9202SRyan Wilson 	case XenbusStateInitWait:
1061*956a9202SRyan Wilson 	case XenbusStateInitialised:
1062*956a9202SRyan Wilson 	case XenbusStateClosed:
1063*956a9202SRyan Wilson 		break;
1064*956a9202SRyan Wilson 
1065*956a9202SRyan Wilson 	case XenbusStateConnected:
1066*956a9202SRyan Wilson 		pcifront_try_connect(pdev);
1067*956a9202SRyan Wilson 		break;
1068*956a9202SRyan Wilson 
1069*956a9202SRyan Wilson 	case XenbusStateClosing:
1070*956a9202SRyan Wilson 		dev_warn(&xdev->dev, "backend going away!\n");
1071*956a9202SRyan Wilson 		pcifront_try_disconnect(pdev);
1072*956a9202SRyan Wilson 		break;
1073*956a9202SRyan Wilson 
1074*956a9202SRyan Wilson 	case XenbusStateReconfiguring:
1075*956a9202SRyan Wilson 		pcifront_detach_devices(pdev);
1076*956a9202SRyan Wilson 		break;
1077*956a9202SRyan Wilson 
1078*956a9202SRyan Wilson 	case XenbusStateReconfigured:
1079*956a9202SRyan Wilson 		pcifront_attach_devices(pdev);
1080*956a9202SRyan Wilson 		break;
1081*956a9202SRyan Wilson 	}
1082*956a9202SRyan Wilson }
1083*956a9202SRyan Wilson 
1084*956a9202SRyan Wilson static int pcifront_xenbus_probe(struct xenbus_device *xdev,
1085*956a9202SRyan Wilson 				 const struct xenbus_device_id *id)
1086*956a9202SRyan Wilson {
1087*956a9202SRyan Wilson 	int err = 0;
1088*956a9202SRyan Wilson 	struct pcifront_device *pdev = alloc_pdev(xdev);
1089*956a9202SRyan Wilson 
1090*956a9202SRyan Wilson 	if (pdev == NULL) {
1091*956a9202SRyan Wilson 		err = -ENOMEM;
1092*956a9202SRyan Wilson 		xenbus_dev_fatal(xdev, err,
1093*956a9202SRyan Wilson 				 "Error allocating pcifront_device struct");
1094*956a9202SRyan Wilson 		goto out;
1095*956a9202SRyan Wilson 	}
1096*956a9202SRyan Wilson 
1097*956a9202SRyan Wilson 	err = pcifront_publish_info(pdev);
1098*956a9202SRyan Wilson 	if (err)
1099*956a9202SRyan Wilson 		free_pdev(pdev);
1100*956a9202SRyan Wilson 
1101*956a9202SRyan Wilson out:
1102*956a9202SRyan Wilson 	return err;
1103*956a9202SRyan Wilson }
1104*956a9202SRyan Wilson 
1105*956a9202SRyan Wilson static int pcifront_xenbus_remove(struct xenbus_device *xdev)
1106*956a9202SRyan Wilson {
1107*956a9202SRyan Wilson 	struct pcifront_device *pdev = dev_get_drvdata(&xdev->dev);
1108*956a9202SRyan Wilson 	if (pdev)
1109*956a9202SRyan Wilson 		free_pdev(pdev);
1110*956a9202SRyan Wilson 
1111*956a9202SRyan Wilson 	return 0;
1112*956a9202SRyan Wilson }
1113*956a9202SRyan Wilson 
1114*956a9202SRyan Wilson static const struct xenbus_device_id xenpci_ids[] = {
1115*956a9202SRyan Wilson 	{"pci"},
1116*956a9202SRyan Wilson 	{""},
1117*956a9202SRyan Wilson };
1118*956a9202SRyan Wilson 
1119*956a9202SRyan Wilson static struct xenbus_driver xenbus_pcifront_driver = {
1120*956a9202SRyan Wilson 	.name			= "pcifront",
1121*956a9202SRyan Wilson 	.owner			= THIS_MODULE,
1122*956a9202SRyan Wilson 	.ids			= xenpci_ids,
1123*956a9202SRyan Wilson 	.probe			= pcifront_xenbus_probe,
1124*956a9202SRyan Wilson 	.remove			= pcifront_xenbus_remove,
1125*956a9202SRyan Wilson 	.otherend_changed	= pcifront_backend_changed,
1126*956a9202SRyan Wilson };
1127*956a9202SRyan Wilson 
1128*956a9202SRyan Wilson static int __init pcifront_init(void)
1129*956a9202SRyan Wilson {
1130*956a9202SRyan Wilson 	if (!xen_pv_domain() || xen_initial_domain())
1131*956a9202SRyan Wilson 		return -ENODEV;
1132*956a9202SRyan Wilson 
1133*956a9202SRyan Wilson 	pci_frontend_registrar(1 /* enable */);
1134*956a9202SRyan Wilson 
1135*956a9202SRyan Wilson 	return xenbus_register_frontend(&xenbus_pcifront_driver);
1136*956a9202SRyan Wilson }
1137*956a9202SRyan Wilson 
1138*956a9202SRyan Wilson static void __exit pcifront_cleanup(void)
1139*956a9202SRyan Wilson {
1140*956a9202SRyan Wilson 	xenbus_unregister_driver(&xenbus_pcifront_driver);
1141*956a9202SRyan Wilson 	pci_frontend_registrar(0 /* disable */);
1142*956a9202SRyan Wilson }
1143*956a9202SRyan Wilson module_init(pcifront_init);
1144*956a9202SRyan Wilson module_exit(pcifront_cleanup);
1145*956a9202SRyan Wilson 
1146*956a9202SRyan Wilson MODULE_DESCRIPTION("Xen PCI passthrough frontend.");
1147*956a9202SRyan Wilson MODULE_LICENSE("GPL");
1148*956a9202SRyan Wilson MODULE_ALIAS("xen:pci");
1149