xref: /openbmc/linux/drivers/xen/xen-pciback/xenbus.c (revision 515762b9)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
230edc14bSKonrad Rzeszutek Wilk /*
330edc14bSKonrad Rzeszutek Wilk  * PCI Backend Xenbus Setup - handles setup with frontend and xend
430edc14bSKonrad Rzeszutek Wilk  *
530edc14bSKonrad Rzeszutek Wilk  *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
630edc14bSKonrad Rzeszutek Wilk  */
7283c0972SJoe Perches 
8283c0972SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
9283c0972SJoe Perches 
1059aa56bfSPaul Gortmaker #include <linux/moduleparam.h>
1130edc14bSKonrad Rzeszutek Wilk #include <linux/init.h>
1230edc14bSKonrad Rzeszutek Wilk #include <linux/list.h>
1330edc14bSKonrad Rzeszutek Wilk #include <linux/vmalloc.h>
1430edc14bSKonrad Rzeszutek Wilk #include <linux/workqueue.h>
1530edc14bSKonrad Rzeszutek Wilk #include <xen/xenbus.h>
1630edc14bSKonrad Rzeszutek Wilk #include <xen/events.h>
176221a9b2SKonrad Rzeszutek Wilk #include <asm/xen/pci.h>
1830edc14bSKonrad Rzeszutek Wilk #include "pciback.h"
1930edc14bSKonrad Rzeszutek Wilk 
2030edc14bSKonrad Rzeszutek Wilk #define INVALID_EVTCHN_IRQ  (-1)
2130edc14bSKonrad Rzeszutek Wilk 
2290ab5ee9SRusty Russell static bool __read_mostly passthrough;
232ebdc426SKonrad Rzeszutek Wilk module_param(passthrough, bool, S_IRUGO);
242ebdc426SKonrad Rzeszutek Wilk MODULE_PARM_DESC(passthrough,
252ebdc426SKonrad Rzeszutek Wilk 	"Option to specify how to export PCI topology to guest:\n"\
262ebdc426SKonrad Rzeszutek Wilk 	" 0 - (default) Hide the true PCI topology and makes the frontend\n"\
272ebdc426SKonrad Rzeszutek Wilk 	"   there is a single PCI bus with only the exported devices on it.\n"\
282ebdc426SKonrad Rzeszutek Wilk 	"   For example, a device at 03:05.0 will be re-assigned to 00:00.0\n"\
292ebdc426SKonrad Rzeszutek Wilk 	"   while second device at 02:1a.1 will be re-assigned to 00:01.1.\n"\
302ebdc426SKonrad Rzeszutek Wilk 	" 1 - Passthrough provides a real view of the PCI topology to the\n"\
312ebdc426SKonrad Rzeszutek Wilk 	"   frontend (for example, a device at 06:01.b will still appear at\n"\
322ebdc426SKonrad Rzeszutek Wilk 	"   06:01.b to the frontend). This is similar to how Xen 2.0.x\n"\
332ebdc426SKonrad Rzeszutek Wilk 	"   exposed PCI devices to its driver domains. This may be required\n"\
342ebdc426SKonrad Rzeszutek Wilk 	"   for drivers which depend on finding their hardward in certain\n"\
352ebdc426SKonrad Rzeszutek Wilk 	"   bus/slot locations.");
362ebdc426SKonrad Rzeszutek Wilk 
37a92336a1SKonrad Rzeszutek Wilk static struct xen_pcibk_device *alloc_pdev(struct xenbus_device *xdev)
3830edc14bSKonrad Rzeszutek Wilk {
39a92336a1SKonrad Rzeszutek Wilk 	struct xen_pcibk_device *pdev;
4030edc14bSKonrad Rzeszutek Wilk 
41a92336a1SKonrad Rzeszutek Wilk 	pdev = kzalloc(sizeof(struct xen_pcibk_device), GFP_KERNEL);
4230edc14bSKonrad Rzeszutek Wilk 	if (pdev == NULL)
4330edc14bSKonrad Rzeszutek Wilk 		goto out;
4430edc14bSKonrad Rzeszutek Wilk 	dev_dbg(&xdev->dev, "allocated pdev @ 0x%p\n", pdev);
4530edc14bSKonrad Rzeszutek Wilk 
4630edc14bSKonrad Rzeszutek Wilk 	pdev->xdev = xdev;
4730edc14bSKonrad Rzeszutek Wilk 
48b1766b62SKonrad Rzeszutek Wilk 	mutex_init(&pdev->dev_lock);
4930edc14bSKonrad Rzeszutek Wilk 
5030edc14bSKonrad Rzeszutek Wilk 	pdev->sh_info = NULL;
5130edc14bSKonrad Rzeszutek Wilk 	pdev->evtchn_irq = INVALID_EVTCHN_IRQ;
5230edc14bSKonrad Rzeszutek Wilk 	pdev->be_watching = 0;
5330edc14bSKonrad Rzeszutek Wilk 
54a92336a1SKonrad Rzeszutek Wilk 	INIT_WORK(&pdev->op_work, xen_pcibk_do_op);
5530edc14bSKonrad Rzeszutek Wilk 
56a92336a1SKonrad Rzeszutek Wilk 	if (xen_pcibk_init_devices(pdev)) {
5730edc14bSKonrad Rzeszutek Wilk 		kfree(pdev);
5830edc14bSKonrad Rzeszutek Wilk 		pdev = NULL;
5930edc14bSKonrad Rzeszutek Wilk 	}
60584a561aSDoug Goldstein 
61584a561aSDoug Goldstein 	dev_set_drvdata(&xdev->dev, pdev);
62584a561aSDoug Goldstein 
6330edc14bSKonrad Rzeszutek Wilk out:
6430edc14bSKonrad Rzeszutek Wilk 	return pdev;
6530edc14bSKonrad Rzeszutek Wilk }
6630edc14bSKonrad Rzeszutek Wilk 
67a92336a1SKonrad Rzeszutek Wilk static void xen_pcibk_disconnect(struct xen_pcibk_device *pdev)
6830edc14bSKonrad Rzeszutek Wilk {
69b1766b62SKonrad Rzeszutek Wilk 	mutex_lock(&pdev->dev_lock);
7030edc14bSKonrad Rzeszutek Wilk 	/* Ensure the guest can't trigger our handler before removing devices */
7130edc14bSKonrad Rzeszutek Wilk 	if (pdev->evtchn_irq != INVALID_EVTCHN_IRQ) {
7230edc14bSKonrad Rzeszutek Wilk 		unbind_from_irqhandler(pdev->evtchn_irq, pdev);
7330edc14bSKonrad Rzeszutek Wilk 		pdev->evtchn_irq = INVALID_EVTCHN_IRQ;
7430edc14bSKonrad Rzeszutek Wilk 	}
7530edc14bSKonrad Rzeszutek Wilk 
7630edc14bSKonrad Rzeszutek Wilk 	/* If the driver domain started an op, make sure we complete it
7730edc14bSKonrad Rzeszutek Wilk 	 * before releasing the shared memory */
78494ef20dSKonrad Rzeszutek Wilk 
79429eafe6SBhaktipriya Shridhar 	flush_work(&pdev->op_work);
8030edc14bSKonrad Rzeszutek Wilk 
8130edc14bSKonrad Rzeszutek Wilk 	if (pdev->sh_info != NULL) {
8230edc14bSKonrad Rzeszutek Wilk 		xenbus_unmap_ring_vfree(pdev->xdev, pdev->sh_info);
8330edc14bSKonrad Rzeszutek Wilk 		pdev->sh_info = NULL;
8430edc14bSKonrad Rzeszutek Wilk 	}
85b1766b62SKonrad Rzeszutek Wilk 	mutex_unlock(&pdev->dev_lock);
8630edc14bSKonrad Rzeszutek Wilk }
8730edc14bSKonrad Rzeszutek Wilk 
88a92336a1SKonrad Rzeszutek Wilk static void free_pdev(struct xen_pcibk_device *pdev)
8930edc14bSKonrad Rzeszutek Wilk {
90494ef20dSKonrad Rzeszutek Wilk 	if (pdev->be_watching) {
9130edc14bSKonrad Rzeszutek Wilk 		unregister_xenbus_watch(&pdev->be_watch);
92494ef20dSKonrad Rzeszutek Wilk 		pdev->be_watching = 0;
93494ef20dSKonrad Rzeszutek Wilk 	}
9430edc14bSKonrad Rzeszutek Wilk 
95a92336a1SKonrad Rzeszutek Wilk 	xen_pcibk_disconnect(pdev);
9630edc14bSKonrad Rzeszutek Wilk 
978be9df6dSKonrad Rzeszutek Wilk 	/* N.B. This calls pcistub_put_pci_dev which does the FLR on all
988be9df6dSKonrad Rzeszutek Wilk 	 * of the PCIe devices. */
99a92336a1SKonrad Rzeszutek Wilk 	xen_pcibk_release_devices(pdev);
10030edc14bSKonrad Rzeszutek Wilk 
10130edc14bSKonrad Rzeszutek Wilk 	dev_set_drvdata(&pdev->xdev->dev, NULL);
10230edc14bSKonrad Rzeszutek Wilk 	pdev->xdev = NULL;
10330edc14bSKonrad Rzeszutek Wilk 
10430edc14bSKonrad Rzeszutek Wilk 	kfree(pdev);
10530edc14bSKonrad Rzeszutek Wilk }
10630edc14bSKonrad Rzeszutek Wilk 
107a92336a1SKonrad Rzeszutek Wilk static int xen_pcibk_do_attach(struct xen_pcibk_device *pdev, int gnt_ref,
10830edc14bSKonrad Rzeszutek Wilk 			     int remote_evtchn)
10930edc14bSKonrad Rzeszutek Wilk {
11030edc14bSKonrad Rzeszutek Wilk 	int err = 0;
11130edc14bSKonrad Rzeszutek Wilk 	void *vaddr;
11230edc14bSKonrad Rzeszutek Wilk 
11330edc14bSKonrad Rzeszutek Wilk 	dev_dbg(&pdev->xdev->dev,
11430edc14bSKonrad Rzeszutek Wilk 		"Attaching to frontend resources - gnt_ref=%d evtchn=%d\n",
11530edc14bSKonrad Rzeszutek Wilk 		gnt_ref, remote_evtchn);
11630edc14bSKonrad Rzeszutek Wilk 
117ccc9d90aSWei Liu 	err = xenbus_map_ring_valloc(pdev->xdev, &gnt_ref, 1, &vaddr);
11830edc14bSKonrad Rzeszutek Wilk 	if (err < 0) {
11930edc14bSKonrad Rzeszutek Wilk 		xenbus_dev_fatal(pdev->xdev, err,
12030edc14bSKonrad Rzeszutek Wilk 				"Error mapping other domain page in ours.");
12130edc14bSKonrad Rzeszutek Wilk 		goto out;
12230edc14bSKonrad Rzeszutek Wilk 	}
123494ef20dSKonrad Rzeszutek Wilk 
12430edc14bSKonrad Rzeszutek Wilk 	pdev->sh_info = vaddr;
12530edc14bSKonrad Rzeszutek Wilk 
12630edc14bSKonrad Rzeszutek Wilk 	err = bind_interdomain_evtchn_to_irqhandler(
127a92336a1SKonrad Rzeszutek Wilk 		pdev->xdev->otherend_id, remote_evtchn, xen_pcibk_handle_event,
128a92336a1SKonrad Rzeszutek Wilk 		0, DRV_NAME, pdev);
12930edc14bSKonrad Rzeszutek Wilk 	if (err < 0) {
13030edc14bSKonrad Rzeszutek Wilk 		xenbus_dev_fatal(pdev->xdev, err,
13130edc14bSKonrad Rzeszutek Wilk 				 "Error binding event channel to IRQ");
13230edc14bSKonrad Rzeszutek Wilk 		goto out;
13330edc14bSKonrad Rzeszutek Wilk 	}
13430edc14bSKonrad Rzeszutek Wilk 	pdev->evtchn_irq = err;
13530edc14bSKonrad Rzeszutek Wilk 	err = 0;
13630edc14bSKonrad Rzeszutek Wilk 
13730edc14bSKonrad Rzeszutek Wilk 	dev_dbg(&pdev->xdev->dev, "Attached!\n");
13830edc14bSKonrad Rzeszutek Wilk out:
13930edc14bSKonrad Rzeszutek Wilk 	return err;
14030edc14bSKonrad Rzeszutek Wilk }
14130edc14bSKonrad Rzeszutek Wilk 
142a92336a1SKonrad Rzeszutek Wilk static int xen_pcibk_attach(struct xen_pcibk_device *pdev)
14330edc14bSKonrad Rzeszutek Wilk {
14430edc14bSKonrad Rzeszutek Wilk 	int err = 0;
14530edc14bSKonrad Rzeszutek Wilk 	int gnt_ref, remote_evtchn;
14630edc14bSKonrad Rzeszutek Wilk 	char *magic = NULL;
14730edc14bSKonrad Rzeszutek Wilk 
14830edc14bSKonrad Rzeszutek Wilk 
149b1766b62SKonrad Rzeszutek Wilk 	mutex_lock(&pdev->dev_lock);
15030edc14bSKonrad Rzeszutek Wilk 	/* Make sure we only do this setup once */
15130edc14bSKonrad Rzeszutek Wilk 	if (xenbus_read_driver_state(pdev->xdev->nodename) !=
15230edc14bSKonrad Rzeszutek Wilk 	    XenbusStateInitialised)
15330edc14bSKonrad Rzeszutek Wilk 		goto out;
15430edc14bSKonrad Rzeszutek Wilk 
15530edc14bSKonrad Rzeszutek Wilk 	/* Wait for frontend to state that it has published the configuration */
15630edc14bSKonrad Rzeszutek Wilk 	if (xenbus_read_driver_state(pdev->xdev->otherend) !=
15730edc14bSKonrad Rzeszutek Wilk 	    XenbusStateInitialised)
15830edc14bSKonrad Rzeszutek Wilk 		goto out;
15930edc14bSKonrad Rzeszutek Wilk 
16030edc14bSKonrad Rzeszutek Wilk 	dev_dbg(&pdev->xdev->dev, "Reading frontend config\n");
16130edc14bSKonrad Rzeszutek Wilk 
16230edc14bSKonrad Rzeszutek Wilk 	err = xenbus_gather(XBT_NIL, pdev->xdev->otherend,
16330edc14bSKonrad Rzeszutek Wilk 			    "pci-op-ref", "%u", &gnt_ref,
16430edc14bSKonrad Rzeszutek Wilk 			    "event-channel", "%u", &remote_evtchn,
16530edc14bSKonrad Rzeszutek Wilk 			    "magic", NULL, &magic, NULL);
16630edc14bSKonrad Rzeszutek Wilk 	if (err) {
16730edc14bSKonrad Rzeszutek Wilk 		/* If configuration didn't get read correctly, wait longer */
16830edc14bSKonrad Rzeszutek Wilk 		xenbus_dev_fatal(pdev->xdev, err,
16930edc14bSKonrad Rzeszutek Wilk 				 "Error reading configuration from frontend");
17030edc14bSKonrad Rzeszutek Wilk 		goto out;
17130edc14bSKonrad Rzeszutek Wilk 	}
17230edc14bSKonrad Rzeszutek Wilk 
17330edc14bSKonrad Rzeszutek Wilk 	if (magic == NULL || strcmp(magic, XEN_PCI_MAGIC) != 0) {
17430edc14bSKonrad Rzeszutek Wilk 		xenbus_dev_fatal(pdev->xdev, -EFAULT,
17530edc14bSKonrad Rzeszutek Wilk 				 "version mismatch (%s/%s) with pcifront - "
176402c5e15SJan Beulich 				 "halting " DRV_NAME,
17730edc14bSKonrad Rzeszutek Wilk 				 magic, XEN_PCI_MAGIC);
1782ef76032SWei Yongjun 		err = -EFAULT;
17930edc14bSKonrad Rzeszutek Wilk 		goto out;
18030edc14bSKonrad Rzeszutek Wilk 	}
18130edc14bSKonrad Rzeszutek Wilk 
182a92336a1SKonrad Rzeszutek Wilk 	err = xen_pcibk_do_attach(pdev, gnt_ref, remote_evtchn);
18330edc14bSKonrad Rzeszutek Wilk 	if (err)
18430edc14bSKonrad Rzeszutek Wilk 		goto out;
18530edc14bSKonrad Rzeszutek Wilk 
18630edc14bSKonrad Rzeszutek Wilk 	dev_dbg(&pdev->xdev->dev, "Connecting...\n");
18730edc14bSKonrad Rzeszutek Wilk 
18830edc14bSKonrad Rzeszutek Wilk 	err = xenbus_switch_state(pdev->xdev, XenbusStateConnected);
18930edc14bSKonrad Rzeszutek Wilk 	if (err)
19030edc14bSKonrad Rzeszutek Wilk 		xenbus_dev_fatal(pdev->xdev, err,
19130edc14bSKonrad Rzeszutek Wilk 				 "Error switching to connected state!");
19230edc14bSKonrad Rzeszutek Wilk 
19330edc14bSKonrad Rzeszutek Wilk 	dev_dbg(&pdev->xdev->dev, "Connected? %d\n", err);
19430edc14bSKonrad Rzeszutek Wilk out:
195b1766b62SKonrad Rzeszutek Wilk 	mutex_unlock(&pdev->dev_lock);
19630edc14bSKonrad Rzeszutek Wilk 
19730edc14bSKonrad Rzeszutek Wilk 	kfree(magic);
19830edc14bSKonrad Rzeszutek Wilk 
19930edc14bSKonrad Rzeszutek Wilk 	return err;
20030edc14bSKonrad Rzeszutek Wilk }
20130edc14bSKonrad Rzeszutek Wilk 
202a92336a1SKonrad Rzeszutek Wilk static int xen_pcibk_publish_pci_dev(struct xen_pcibk_device *pdev,
20330edc14bSKonrad Rzeszutek Wilk 				   unsigned int domain, unsigned int bus,
20430edc14bSKonrad Rzeszutek Wilk 				   unsigned int devfn, unsigned int devid)
20530edc14bSKonrad Rzeszutek Wilk {
20630edc14bSKonrad Rzeszutek Wilk 	int err;
20730edc14bSKonrad Rzeszutek Wilk 	int len;
20830edc14bSKonrad Rzeszutek Wilk 	char str[64];
20930edc14bSKonrad Rzeszutek Wilk 
21030edc14bSKonrad Rzeszutek Wilk 	len = snprintf(str, sizeof(str), "vdev-%d", devid);
21130edc14bSKonrad Rzeszutek Wilk 	if (unlikely(len >= (sizeof(str) - 1))) {
21230edc14bSKonrad Rzeszutek Wilk 		err = -ENOMEM;
21330edc14bSKonrad Rzeszutek Wilk 		goto out;
21430edc14bSKonrad Rzeszutek Wilk 	}
21530edc14bSKonrad Rzeszutek Wilk 
216e4de866aSKonrad Rzeszutek Wilk 	/* Note: The PV protocol uses %02x, don't change it */
21730edc14bSKonrad Rzeszutek Wilk 	err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, str,
21830edc14bSKonrad Rzeszutek Wilk 			    "%04x:%02x:%02x.%02x", domain, bus,
21930edc14bSKonrad Rzeszutek Wilk 			    PCI_SLOT(devfn), PCI_FUNC(devfn));
22030edc14bSKonrad Rzeszutek Wilk 
22130edc14bSKonrad Rzeszutek Wilk out:
22230edc14bSKonrad Rzeszutek Wilk 	return err;
22330edc14bSKonrad Rzeszutek Wilk }
22430edc14bSKonrad Rzeszutek Wilk 
225a92336a1SKonrad Rzeszutek Wilk static int xen_pcibk_export_device(struct xen_pcibk_device *pdev,
22630edc14bSKonrad Rzeszutek Wilk 				 int domain, int bus, int slot, int func,
22730edc14bSKonrad Rzeszutek Wilk 				 int devid)
22830edc14bSKonrad Rzeszutek Wilk {
22930edc14bSKonrad Rzeszutek Wilk 	struct pci_dev *dev;
23030edc14bSKonrad Rzeszutek Wilk 	int err = 0;
23130edc14bSKonrad Rzeszutek Wilk 
23230edc14bSKonrad Rzeszutek Wilk 	dev_dbg(&pdev->xdev->dev, "exporting dom %x bus %x slot %x func %x\n",
23330edc14bSKonrad Rzeszutek Wilk 		domain, bus, slot, func);
23430edc14bSKonrad Rzeszutek Wilk 
23530edc14bSKonrad Rzeszutek Wilk 	dev = pcistub_get_pci_dev_by_slot(pdev, domain, bus, slot, func);
23630edc14bSKonrad Rzeszutek Wilk 	if (!dev) {
23730edc14bSKonrad Rzeszutek Wilk 		err = -EINVAL;
23830edc14bSKonrad Rzeszutek Wilk 		xenbus_dev_fatal(pdev->xdev, err,
23930edc14bSKonrad Rzeszutek Wilk 				 "Couldn't locate PCI device "
240e4de866aSKonrad Rzeszutek Wilk 				 "(%04x:%02x:%02x.%d)! "
24130edc14bSKonrad Rzeszutek Wilk 				 "perhaps already in-use?",
24230edc14bSKonrad Rzeszutek Wilk 				 domain, bus, slot, func);
24330edc14bSKonrad Rzeszutek Wilk 		goto out;
24430edc14bSKonrad Rzeszutek Wilk 	}
24530edc14bSKonrad Rzeszutek Wilk 
246a92336a1SKonrad Rzeszutek Wilk 	err = xen_pcibk_add_pci_dev(pdev, dev, devid,
247a92336a1SKonrad Rzeszutek Wilk 				    xen_pcibk_publish_pci_dev);
24830edc14bSKonrad Rzeszutek Wilk 	if (err)
24930edc14bSKonrad Rzeszutek Wilk 		goto out;
25030edc14bSKonrad Rzeszutek Wilk 
25115390613SKonrad Rzeszutek Wilk 	dev_info(&dev->dev, "registering for %d\n", pdev->xdev->otherend_id);
2526221a9b2SKonrad Rzeszutek Wilk 	if (xen_register_device_domain_owner(dev,
2536221a9b2SKonrad Rzeszutek Wilk 					     pdev->xdev->otherend_id) != 0) {
2546c254de1SKonrad Rzeszutek Wilk 		dev_err(&dev->dev, "Stealing ownership from dom%d.\n",
2556c254de1SKonrad Rzeszutek Wilk 			xen_find_device_domain_owner(dev));
2566221a9b2SKonrad Rzeszutek Wilk 		xen_unregister_device_domain_owner(dev);
2576221a9b2SKonrad Rzeszutek Wilk 		xen_register_device_domain_owner(dev, pdev->xdev->otherend_id);
2586221a9b2SKonrad Rzeszutek Wilk 	}
2596221a9b2SKonrad Rzeszutek Wilk 
26030edc14bSKonrad Rzeszutek Wilk 	/* TODO: It'd be nice to export a bridge and have all of its children
26130edc14bSKonrad Rzeszutek Wilk 	 * get exported with it. This may be best done in xend (which will
26230edc14bSKonrad Rzeszutek Wilk 	 * have to calculate resource usage anyway) but we probably want to
26330edc14bSKonrad Rzeszutek Wilk 	 * put something in here to ensure that if a bridge gets given to a
26430edc14bSKonrad Rzeszutek Wilk 	 * driver domain, that all devices under that bridge are not given
26530edc14bSKonrad Rzeszutek Wilk 	 * to other driver domains (as he who controls the bridge can disable
26630edc14bSKonrad Rzeszutek Wilk 	 * it and stop the other devices from working).
26730edc14bSKonrad Rzeszutek Wilk 	 */
26830edc14bSKonrad Rzeszutek Wilk out:
26930edc14bSKonrad Rzeszutek Wilk 	return err;
27030edc14bSKonrad Rzeszutek Wilk }
27130edc14bSKonrad Rzeszutek Wilk 
272a92336a1SKonrad Rzeszutek Wilk static int xen_pcibk_remove_device(struct xen_pcibk_device *pdev,
27330edc14bSKonrad Rzeszutek Wilk 				 int domain, int bus, int slot, int func)
27430edc14bSKonrad Rzeszutek Wilk {
27530edc14bSKonrad Rzeszutek Wilk 	int err = 0;
27630edc14bSKonrad Rzeszutek Wilk 	struct pci_dev *dev;
27730edc14bSKonrad Rzeszutek Wilk 
27830edc14bSKonrad Rzeszutek Wilk 	dev_dbg(&pdev->xdev->dev, "removing dom %x bus %x slot %x func %x\n",
27930edc14bSKonrad Rzeszutek Wilk 		domain, bus, slot, func);
28030edc14bSKonrad Rzeszutek Wilk 
281a92336a1SKonrad Rzeszutek Wilk 	dev = xen_pcibk_get_pci_dev(pdev, domain, bus, PCI_DEVFN(slot, func));
28230edc14bSKonrad Rzeszutek Wilk 	if (!dev) {
28330edc14bSKonrad Rzeszutek Wilk 		err = -EINVAL;
28430edc14bSKonrad Rzeszutek Wilk 		dev_dbg(&pdev->xdev->dev, "Couldn't locate PCI device "
285e4de866aSKonrad Rzeszutek Wilk 			"(%04x:%02x:%02x.%d)! not owned by this domain\n",
28630edc14bSKonrad Rzeszutek Wilk 			domain, bus, slot, func);
28730edc14bSKonrad Rzeszutek Wilk 		goto out;
28830edc14bSKonrad Rzeszutek Wilk 	}
28930edc14bSKonrad Rzeszutek Wilk 
2906221a9b2SKonrad Rzeszutek Wilk 	dev_dbg(&dev->dev, "unregistering for %d\n", pdev->xdev->otherend_id);
2916221a9b2SKonrad Rzeszutek Wilk 	xen_unregister_device_domain_owner(dev);
2926221a9b2SKonrad Rzeszutek Wilk 
2938be9df6dSKonrad Rzeszutek Wilk 	/* N.B. This ends up calling pcistub_put_pci_dev which ends up
2948be9df6dSKonrad Rzeszutek Wilk 	 * doing the FLR. */
295e8801a74SKonrad Rzeszutek Wilk 	xen_pcibk_release_pci_dev(pdev, dev, true /* use the lock. */);
29630edc14bSKonrad Rzeszutek Wilk 
29730edc14bSKonrad Rzeszutek Wilk out:
29830edc14bSKonrad Rzeszutek Wilk 	return err;
29930edc14bSKonrad Rzeszutek Wilk }
30030edc14bSKonrad Rzeszutek Wilk 
301a92336a1SKonrad Rzeszutek Wilk static int xen_pcibk_publish_pci_root(struct xen_pcibk_device *pdev,
30230edc14bSKonrad Rzeszutek Wilk 				    unsigned int domain, unsigned int bus)
30330edc14bSKonrad Rzeszutek Wilk {
30430edc14bSKonrad Rzeszutek Wilk 	unsigned int d, b;
30530edc14bSKonrad Rzeszutek Wilk 	int i, root_num, len, err;
30630edc14bSKonrad Rzeszutek Wilk 	char str[64];
30730edc14bSKonrad Rzeszutek Wilk 
30830edc14bSKonrad Rzeszutek Wilk 	dev_dbg(&pdev->xdev->dev, "Publishing pci roots\n");
30930edc14bSKonrad Rzeszutek Wilk 
31030edc14bSKonrad Rzeszutek Wilk 	err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename,
31130edc14bSKonrad Rzeszutek Wilk 			   "root_num", "%d", &root_num);
31230edc14bSKonrad Rzeszutek Wilk 	if (err == 0 || err == -ENOENT)
31330edc14bSKonrad Rzeszutek Wilk 		root_num = 0;
31430edc14bSKonrad Rzeszutek Wilk 	else if (err < 0)
31530edc14bSKonrad Rzeszutek Wilk 		goto out;
31630edc14bSKonrad Rzeszutek Wilk 
31730edc14bSKonrad Rzeszutek Wilk 	/* Verify that we haven't already published this pci root */
31830edc14bSKonrad Rzeszutek Wilk 	for (i = 0; i < root_num; i++) {
31930edc14bSKonrad Rzeszutek Wilk 		len = snprintf(str, sizeof(str), "root-%d", i);
32030edc14bSKonrad Rzeszutek Wilk 		if (unlikely(len >= (sizeof(str) - 1))) {
32130edc14bSKonrad Rzeszutek Wilk 			err = -ENOMEM;
32230edc14bSKonrad Rzeszutek Wilk 			goto out;
32330edc14bSKonrad Rzeszutek Wilk 		}
32430edc14bSKonrad Rzeszutek Wilk 
32530edc14bSKonrad Rzeszutek Wilk 		err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename,
32630edc14bSKonrad Rzeszutek Wilk 				   str, "%x:%x", &d, &b);
32730edc14bSKonrad Rzeszutek Wilk 		if (err < 0)
32830edc14bSKonrad Rzeszutek Wilk 			goto out;
32930edc14bSKonrad Rzeszutek Wilk 		if (err != 2) {
33030edc14bSKonrad Rzeszutek Wilk 			err = -EINVAL;
33130edc14bSKonrad Rzeszutek Wilk 			goto out;
33230edc14bSKonrad Rzeszutek Wilk 		}
33330edc14bSKonrad Rzeszutek Wilk 
33430edc14bSKonrad Rzeszutek Wilk 		if (d == domain && b == bus) {
33530edc14bSKonrad Rzeszutek Wilk 			err = 0;
33630edc14bSKonrad Rzeszutek Wilk 			goto out;
33730edc14bSKonrad Rzeszutek Wilk 		}
33830edc14bSKonrad Rzeszutek Wilk 	}
33930edc14bSKonrad Rzeszutek Wilk 
34030edc14bSKonrad Rzeszutek Wilk 	len = snprintf(str, sizeof(str), "root-%d", root_num);
34130edc14bSKonrad Rzeszutek Wilk 	if (unlikely(len >= (sizeof(str) - 1))) {
34230edc14bSKonrad Rzeszutek Wilk 		err = -ENOMEM;
34330edc14bSKonrad Rzeszutek Wilk 		goto out;
34430edc14bSKonrad Rzeszutek Wilk 	}
34530edc14bSKonrad Rzeszutek Wilk 
34630edc14bSKonrad Rzeszutek Wilk 	dev_dbg(&pdev->xdev->dev, "writing root %d at %04x:%02x\n",
34730edc14bSKonrad Rzeszutek Wilk 		root_num, domain, bus);
34830edc14bSKonrad Rzeszutek Wilk 
34930edc14bSKonrad Rzeszutek Wilk 	err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, str,
35030edc14bSKonrad Rzeszutek Wilk 			    "%04x:%02x", domain, bus);
35130edc14bSKonrad Rzeszutek Wilk 	if (err)
35230edc14bSKonrad Rzeszutek Wilk 		goto out;
35330edc14bSKonrad Rzeszutek Wilk 
35430edc14bSKonrad Rzeszutek Wilk 	err = xenbus_printf(XBT_NIL, pdev->xdev->nodename,
35530edc14bSKonrad Rzeszutek Wilk 			    "root_num", "%d", (root_num + 1));
35630edc14bSKonrad Rzeszutek Wilk 
35730edc14bSKonrad Rzeszutek Wilk out:
35830edc14bSKonrad Rzeszutek Wilk 	return err;
35930edc14bSKonrad Rzeszutek Wilk }
36030edc14bSKonrad Rzeszutek Wilk 
361a92336a1SKonrad Rzeszutek Wilk static int xen_pcibk_reconfigure(struct xen_pcibk_device *pdev)
36230edc14bSKonrad Rzeszutek Wilk {
36330edc14bSKonrad Rzeszutek Wilk 	int err = 0;
36430edc14bSKonrad Rzeszutek Wilk 	int num_devs;
36530edc14bSKonrad Rzeszutek Wilk 	int domain, bus, slot, func;
3664e81f1caSJuergen Gross 	unsigned int substate;
36730edc14bSKonrad Rzeszutek Wilk 	int i, len;
36830edc14bSKonrad Rzeszutek Wilk 	char state_str[64];
36930edc14bSKonrad Rzeszutek Wilk 	char dev_str[64];
37030edc14bSKonrad Rzeszutek Wilk 
37130edc14bSKonrad Rzeszutek Wilk 
37230edc14bSKonrad Rzeszutek Wilk 	dev_dbg(&pdev->xdev->dev, "Reconfiguring device ...\n");
37330edc14bSKonrad Rzeszutek Wilk 
374b1766b62SKonrad Rzeszutek Wilk 	mutex_lock(&pdev->dev_lock);
37530edc14bSKonrad Rzeszutek Wilk 	/* Make sure we only reconfigure once */
37630edc14bSKonrad Rzeszutek Wilk 	if (xenbus_read_driver_state(pdev->xdev->nodename) !=
37730edc14bSKonrad Rzeszutek Wilk 	    XenbusStateReconfiguring)
37830edc14bSKonrad Rzeszutek Wilk 		goto out;
37930edc14bSKonrad Rzeszutek Wilk 
38030edc14bSKonrad Rzeszutek Wilk 	err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, "num_devs", "%d",
38130edc14bSKonrad Rzeszutek Wilk 			   &num_devs);
38230edc14bSKonrad Rzeszutek Wilk 	if (err != 1) {
38330edc14bSKonrad Rzeszutek Wilk 		if (err >= 0)
38430edc14bSKonrad Rzeszutek Wilk 			err = -EINVAL;
38530edc14bSKonrad Rzeszutek Wilk 		xenbus_dev_fatal(pdev->xdev, err,
38630edc14bSKonrad Rzeszutek Wilk 				 "Error reading number of devices");
38730edc14bSKonrad Rzeszutek Wilk 		goto out;
38830edc14bSKonrad Rzeszutek Wilk 	}
38930edc14bSKonrad Rzeszutek Wilk 
39030edc14bSKonrad Rzeszutek Wilk 	for (i = 0; i < num_devs; i++) {
39130edc14bSKonrad Rzeszutek Wilk 		len = snprintf(state_str, sizeof(state_str), "state-%d", i);
39230edc14bSKonrad Rzeszutek Wilk 		if (unlikely(len >= (sizeof(state_str) - 1))) {
39330edc14bSKonrad Rzeszutek Wilk 			err = -ENOMEM;
39430edc14bSKonrad Rzeszutek Wilk 			xenbus_dev_fatal(pdev->xdev, err,
39530edc14bSKonrad Rzeszutek Wilk 					 "String overflow while reading "
39630edc14bSKonrad Rzeszutek Wilk 					 "configuration");
39730edc14bSKonrad Rzeszutek Wilk 			goto out;
39830edc14bSKonrad Rzeszutek Wilk 		}
3994e81f1caSJuergen Gross 		substate = xenbus_read_unsigned(pdev->xdev->nodename, state_str,
4004e81f1caSJuergen Gross 						XenbusStateUnknown);
40130edc14bSKonrad Rzeszutek Wilk 
40230edc14bSKonrad Rzeszutek Wilk 		switch (substate) {
40330edc14bSKonrad Rzeszutek Wilk 		case XenbusStateInitialising:
40430edc14bSKonrad Rzeszutek Wilk 			dev_dbg(&pdev->xdev->dev, "Attaching dev-%d ...\n", i);
40530edc14bSKonrad Rzeszutek Wilk 
40630edc14bSKonrad Rzeszutek Wilk 			len = snprintf(dev_str, sizeof(dev_str), "dev-%d", i);
40730edc14bSKonrad Rzeszutek Wilk 			if (unlikely(len >= (sizeof(dev_str) - 1))) {
40830edc14bSKonrad Rzeszutek Wilk 				err = -ENOMEM;
40930edc14bSKonrad Rzeszutek Wilk 				xenbus_dev_fatal(pdev->xdev, err,
41030edc14bSKonrad Rzeszutek Wilk 						 "String overflow while "
41130edc14bSKonrad Rzeszutek Wilk 						 "reading configuration");
41230edc14bSKonrad Rzeszutek Wilk 				goto out;
41330edc14bSKonrad Rzeszutek Wilk 			}
41430edc14bSKonrad Rzeszutek Wilk 			err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename,
41530edc14bSKonrad Rzeszutek Wilk 					   dev_str, "%x:%x:%x.%x",
41630edc14bSKonrad Rzeszutek Wilk 					   &domain, &bus, &slot, &func);
41730edc14bSKonrad Rzeszutek Wilk 			if (err < 0) {
41830edc14bSKonrad Rzeszutek Wilk 				xenbus_dev_fatal(pdev->xdev, err,
41930edc14bSKonrad Rzeszutek Wilk 						 "Error reading device "
42030edc14bSKonrad Rzeszutek Wilk 						 "configuration");
42130edc14bSKonrad Rzeszutek Wilk 				goto out;
42230edc14bSKonrad Rzeszutek Wilk 			}
42330edc14bSKonrad Rzeszutek Wilk 			if (err != 4) {
42430edc14bSKonrad Rzeszutek Wilk 				err = -EINVAL;
42530edc14bSKonrad Rzeszutek Wilk 				xenbus_dev_fatal(pdev->xdev, err,
42630edc14bSKonrad Rzeszutek Wilk 						 "Error parsing pci device "
42730edc14bSKonrad Rzeszutek Wilk 						 "configuration");
42830edc14bSKonrad Rzeszutek Wilk 				goto out;
42930edc14bSKonrad Rzeszutek Wilk 			}
43030edc14bSKonrad Rzeszutek Wilk 
431a92336a1SKonrad Rzeszutek Wilk 			err = xen_pcibk_export_device(pdev, domain, bus, slot,
43230edc14bSKonrad Rzeszutek Wilk 						    func, i);
43330edc14bSKonrad Rzeszutek Wilk 			if (err)
43430edc14bSKonrad Rzeszutek Wilk 				goto out;
43530edc14bSKonrad Rzeszutek Wilk 
43630edc14bSKonrad Rzeszutek Wilk 			/* Publish pci roots. */
437a92336a1SKonrad Rzeszutek Wilk 			err = xen_pcibk_publish_pci_roots(pdev,
438a92336a1SKonrad Rzeszutek Wilk 						xen_pcibk_publish_pci_root);
43930edc14bSKonrad Rzeszutek Wilk 			if (err) {
44030edc14bSKonrad Rzeszutek Wilk 				xenbus_dev_fatal(pdev->xdev, err,
44130edc14bSKonrad Rzeszutek Wilk 						 "Error while publish PCI root"
44230edc14bSKonrad Rzeszutek Wilk 						 "buses for frontend");
44330edc14bSKonrad Rzeszutek Wilk 				goto out;
44430edc14bSKonrad Rzeszutek Wilk 			}
44530edc14bSKonrad Rzeszutek Wilk 
44630edc14bSKonrad Rzeszutek Wilk 			err = xenbus_printf(XBT_NIL, pdev->xdev->nodename,
44730edc14bSKonrad Rzeszutek Wilk 					    state_str, "%d",
44830edc14bSKonrad Rzeszutek Wilk 					    XenbusStateInitialised);
44930edc14bSKonrad Rzeszutek Wilk 			if (err) {
45030edc14bSKonrad Rzeszutek Wilk 				xenbus_dev_fatal(pdev->xdev, err,
45130edc14bSKonrad Rzeszutek Wilk 						 "Error switching substate of "
45230edc14bSKonrad Rzeszutek Wilk 						 "dev-%d\n", i);
45330edc14bSKonrad Rzeszutek Wilk 				goto out;
45430edc14bSKonrad Rzeszutek Wilk 			}
45530edc14bSKonrad Rzeszutek Wilk 			break;
45630edc14bSKonrad Rzeszutek Wilk 
45730edc14bSKonrad Rzeszutek Wilk 		case XenbusStateClosing:
45830edc14bSKonrad Rzeszutek Wilk 			dev_dbg(&pdev->xdev->dev, "Detaching dev-%d ...\n", i);
45930edc14bSKonrad Rzeszutek Wilk 
46030edc14bSKonrad Rzeszutek Wilk 			len = snprintf(dev_str, sizeof(dev_str), "vdev-%d", i);
46130edc14bSKonrad Rzeszutek Wilk 			if (unlikely(len >= (sizeof(dev_str) - 1))) {
46230edc14bSKonrad Rzeszutek Wilk 				err = -ENOMEM;
46330edc14bSKonrad Rzeszutek Wilk 				xenbus_dev_fatal(pdev->xdev, err,
46430edc14bSKonrad Rzeszutek Wilk 						 "String overflow while "
46530edc14bSKonrad Rzeszutek Wilk 						 "reading configuration");
46630edc14bSKonrad Rzeszutek Wilk 				goto out;
46730edc14bSKonrad Rzeszutek Wilk 			}
46830edc14bSKonrad Rzeszutek Wilk 			err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename,
46930edc14bSKonrad Rzeszutek Wilk 					   dev_str, "%x:%x:%x.%x",
47030edc14bSKonrad Rzeszutek Wilk 					   &domain, &bus, &slot, &func);
47130edc14bSKonrad Rzeszutek Wilk 			if (err < 0) {
47230edc14bSKonrad Rzeszutek Wilk 				xenbus_dev_fatal(pdev->xdev, err,
47330edc14bSKonrad Rzeszutek Wilk 						 "Error reading device "
47430edc14bSKonrad Rzeszutek Wilk 						 "configuration");
47530edc14bSKonrad Rzeszutek Wilk 				goto out;
47630edc14bSKonrad Rzeszutek Wilk 			}
47730edc14bSKonrad Rzeszutek Wilk 			if (err != 4) {
47830edc14bSKonrad Rzeszutek Wilk 				err = -EINVAL;
47930edc14bSKonrad Rzeszutek Wilk 				xenbus_dev_fatal(pdev->xdev, err,
48030edc14bSKonrad Rzeszutek Wilk 						 "Error parsing pci device "
48130edc14bSKonrad Rzeszutek Wilk 						 "configuration");
48230edc14bSKonrad Rzeszutek Wilk 				goto out;
48330edc14bSKonrad Rzeszutek Wilk 			}
48430edc14bSKonrad Rzeszutek Wilk 
485a92336a1SKonrad Rzeszutek Wilk 			err = xen_pcibk_remove_device(pdev, domain, bus, slot,
48630edc14bSKonrad Rzeszutek Wilk 						    func);
48730edc14bSKonrad Rzeszutek Wilk 			if (err)
48830edc14bSKonrad Rzeszutek Wilk 				goto out;
48930edc14bSKonrad Rzeszutek Wilk 
49030edc14bSKonrad Rzeszutek Wilk 			/* TODO: If at some point we implement support for pci
49130edc14bSKonrad Rzeszutek Wilk 			 * root hot-remove on pcifront side, we'll need to
49230edc14bSKonrad Rzeszutek Wilk 			 * remove unnecessary xenstore nodes of pci roots here.
49330edc14bSKonrad Rzeszutek Wilk 			 */
49430edc14bSKonrad Rzeszutek Wilk 
49530edc14bSKonrad Rzeszutek Wilk 			break;
49630edc14bSKonrad Rzeszutek Wilk 
49730edc14bSKonrad Rzeszutek Wilk 		default:
49830edc14bSKonrad Rzeszutek Wilk 			break;
49930edc14bSKonrad Rzeszutek Wilk 		}
50030edc14bSKonrad Rzeszutek Wilk 	}
50130edc14bSKonrad Rzeszutek Wilk 
50230edc14bSKonrad Rzeszutek Wilk 	err = xenbus_switch_state(pdev->xdev, XenbusStateReconfigured);
50330edc14bSKonrad Rzeszutek Wilk 	if (err) {
50430edc14bSKonrad Rzeszutek Wilk 		xenbus_dev_fatal(pdev->xdev, err,
50530edc14bSKonrad Rzeszutek Wilk 				 "Error switching to reconfigured state!");
50630edc14bSKonrad Rzeszutek Wilk 		goto out;
50730edc14bSKonrad Rzeszutek Wilk 	}
50830edc14bSKonrad Rzeszutek Wilk 
50930edc14bSKonrad Rzeszutek Wilk out:
510b1766b62SKonrad Rzeszutek Wilk 	mutex_unlock(&pdev->dev_lock);
51130edc14bSKonrad Rzeszutek Wilk 	return 0;
51230edc14bSKonrad Rzeszutek Wilk }
51330edc14bSKonrad Rzeszutek Wilk 
514a92336a1SKonrad Rzeszutek Wilk static void xen_pcibk_frontend_changed(struct xenbus_device *xdev,
51530edc14bSKonrad Rzeszutek Wilk 				     enum xenbus_state fe_state)
51630edc14bSKonrad Rzeszutek Wilk {
517a92336a1SKonrad Rzeszutek Wilk 	struct xen_pcibk_device *pdev = dev_get_drvdata(&xdev->dev);
51830edc14bSKonrad Rzeszutek Wilk 
51930edc14bSKonrad Rzeszutek Wilk 	dev_dbg(&xdev->dev, "fe state changed %d\n", fe_state);
52030edc14bSKonrad Rzeszutek Wilk 
52130edc14bSKonrad Rzeszutek Wilk 	switch (fe_state) {
52230edc14bSKonrad Rzeszutek Wilk 	case XenbusStateInitialised:
523a92336a1SKonrad Rzeszutek Wilk 		xen_pcibk_attach(pdev);
52430edc14bSKonrad Rzeszutek Wilk 		break;
52530edc14bSKonrad Rzeszutek Wilk 
52630edc14bSKonrad Rzeszutek Wilk 	case XenbusStateReconfiguring:
527a92336a1SKonrad Rzeszutek Wilk 		xen_pcibk_reconfigure(pdev);
52830edc14bSKonrad Rzeszutek Wilk 		break;
52930edc14bSKonrad Rzeszutek Wilk 
53030edc14bSKonrad Rzeszutek Wilk 	case XenbusStateConnected:
53130edc14bSKonrad Rzeszutek Wilk 		/* pcifront switched its state from reconfiguring to connected.
53230edc14bSKonrad Rzeszutek Wilk 		 * Then switch to connected state.
53330edc14bSKonrad Rzeszutek Wilk 		 */
53430edc14bSKonrad Rzeszutek Wilk 		xenbus_switch_state(xdev, XenbusStateConnected);
53530edc14bSKonrad Rzeszutek Wilk 		break;
53630edc14bSKonrad Rzeszutek Wilk 
53730edc14bSKonrad Rzeszutek Wilk 	case XenbusStateClosing:
538a92336a1SKonrad Rzeszutek Wilk 		xen_pcibk_disconnect(pdev);
53930edc14bSKonrad Rzeszutek Wilk 		xenbus_switch_state(xdev, XenbusStateClosing);
54030edc14bSKonrad Rzeszutek Wilk 		break;
54130edc14bSKonrad Rzeszutek Wilk 
54230edc14bSKonrad Rzeszutek Wilk 	case XenbusStateClosed:
543a92336a1SKonrad Rzeszutek Wilk 		xen_pcibk_disconnect(pdev);
54430edc14bSKonrad Rzeszutek Wilk 		xenbus_switch_state(xdev, XenbusStateClosed);
54530edc14bSKonrad Rzeszutek Wilk 		if (xenbus_dev_is_online(xdev))
54630edc14bSKonrad Rzeszutek Wilk 			break;
547c9f19b67SGustavo A. R. Silva 		/* fall through - if not online */
54830edc14bSKonrad Rzeszutek Wilk 	case XenbusStateUnknown:
54930edc14bSKonrad Rzeszutek Wilk 		dev_dbg(&xdev->dev, "frontend is gone! unregister device\n");
55030edc14bSKonrad Rzeszutek Wilk 		device_unregister(&xdev->dev);
55130edc14bSKonrad Rzeszutek Wilk 		break;
55230edc14bSKonrad Rzeszutek Wilk 
55330edc14bSKonrad Rzeszutek Wilk 	default:
55430edc14bSKonrad Rzeszutek Wilk 		break;
55530edc14bSKonrad Rzeszutek Wilk 	}
55630edc14bSKonrad Rzeszutek Wilk }
55730edc14bSKonrad Rzeszutek Wilk 
558a92336a1SKonrad Rzeszutek Wilk static int xen_pcibk_setup_backend(struct xen_pcibk_device *pdev)
55930edc14bSKonrad Rzeszutek Wilk {
56030edc14bSKonrad Rzeszutek Wilk 	/* Get configuration from xend (if available now) */
56130edc14bSKonrad Rzeszutek Wilk 	int domain, bus, slot, func;
56230edc14bSKonrad Rzeszutek Wilk 	int err = 0;
56330edc14bSKonrad Rzeszutek Wilk 	int i, num_devs;
56430edc14bSKonrad Rzeszutek Wilk 	char dev_str[64];
56530edc14bSKonrad Rzeszutek Wilk 	char state_str[64];
56630edc14bSKonrad Rzeszutek Wilk 
567b1766b62SKonrad Rzeszutek Wilk 	mutex_lock(&pdev->dev_lock);
56830edc14bSKonrad Rzeszutek Wilk 	/* It's possible we could get the call to setup twice, so make sure
56930edc14bSKonrad Rzeszutek Wilk 	 * we're not already connected.
57030edc14bSKonrad Rzeszutek Wilk 	 */
57130edc14bSKonrad Rzeszutek Wilk 	if (xenbus_read_driver_state(pdev->xdev->nodename) !=
57230edc14bSKonrad Rzeszutek Wilk 	    XenbusStateInitWait)
57330edc14bSKonrad Rzeszutek Wilk 		goto out;
57430edc14bSKonrad Rzeszutek Wilk 
57530edc14bSKonrad Rzeszutek Wilk 	dev_dbg(&pdev->xdev->dev, "getting be setup\n");
57630edc14bSKonrad Rzeszutek Wilk 
57730edc14bSKonrad Rzeszutek Wilk 	err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, "num_devs", "%d",
57830edc14bSKonrad Rzeszutek Wilk 			   &num_devs);
57930edc14bSKonrad Rzeszutek Wilk 	if (err != 1) {
58030edc14bSKonrad Rzeszutek Wilk 		if (err >= 0)
58130edc14bSKonrad Rzeszutek Wilk 			err = -EINVAL;
58230edc14bSKonrad Rzeszutek Wilk 		xenbus_dev_fatal(pdev->xdev, err,
58330edc14bSKonrad Rzeszutek Wilk 				 "Error reading number of devices");
58430edc14bSKonrad Rzeszutek Wilk 		goto out;
58530edc14bSKonrad Rzeszutek Wilk 	}
58630edc14bSKonrad Rzeszutek Wilk 
58730edc14bSKonrad Rzeszutek Wilk 	for (i = 0; i < num_devs; i++) {
58830edc14bSKonrad Rzeszutek Wilk 		int l = snprintf(dev_str, sizeof(dev_str), "dev-%d", i);
58930edc14bSKonrad Rzeszutek Wilk 		if (unlikely(l >= (sizeof(dev_str) - 1))) {
59030edc14bSKonrad Rzeszutek Wilk 			err = -ENOMEM;
59130edc14bSKonrad Rzeszutek Wilk 			xenbus_dev_fatal(pdev->xdev, err,
59230edc14bSKonrad Rzeszutek Wilk 					 "String overflow while reading "
59330edc14bSKonrad Rzeszutek Wilk 					 "configuration");
59430edc14bSKonrad Rzeszutek Wilk 			goto out;
59530edc14bSKonrad Rzeszutek Wilk 		}
59630edc14bSKonrad Rzeszutek Wilk 
59730edc14bSKonrad Rzeszutek Wilk 		err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, dev_str,
59830edc14bSKonrad Rzeszutek Wilk 				   "%x:%x:%x.%x", &domain, &bus, &slot, &func);
59930edc14bSKonrad Rzeszutek Wilk 		if (err < 0) {
60030edc14bSKonrad Rzeszutek Wilk 			xenbus_dev_fatal(pdev->xdev, err,
60130edc14bSKonrad Rzeszutek Wilk 					 "Error reading device configuration");
60230edc14bSKonrad Rzeszutek Wilk 			goto out;
60330edc14bSKonrad Rzeszutek Wilk 		}
60430edc14bSKonrad Rzeszutek Wilk 		if (err != 4) {
60530edc14bSKonrad Rzeszutek Wilk 			err = -EINVAL;
60630edc14bSKonrad Rzeszutek Wilk 			xenbus_dev_fatal(pdev->xdev, err,
60730edc14bSKonrad Rzeszutek Wilk 					 "Error parsing pci device "
60830edc14bSKonrad Rzeszutek Wilk 					 "configuration");
60930edc14bSKonrad Rzeszutek Wilk 			goto out;
61030edc14bSKonrad Rzeszutek Wilk 		}
61130edc14bSKonrad Rzeszutek Wilk 
612a92336a1SKonrad Rzeszutek Wilk 		err = xen_pcibk_export_device(pdev, domain, bus, slot, func, i);
61330edc14bSKonrad Rzeszutek Wilk 		if (err)
61430edc14bSKonrad Rzeszutek Wilk 			goto out;
61530edc14bSKonrad Rzeszutek Wilk 
61630edc14bSKonrad Rzeszutek Wilk 		/* Switch substate of this device. */
61730edc14bSKonrad Rzeszutek Wilk 		l = snprintf(state_str, sizeof(state_str), "state-%d", i);
61830edc14bSKonrad Rzeszutek Wilk 		if (unlikely(l >= (sizeof(state_str) - 1))) {
61930edc14bSKonrad Rzeszutek Wilk 			err = -ENOMEM;
62030edc14bSKonrad Rzeszutek Wilk 			xenbus_dev_fatal(pdev->xdev, err,
62130edc14bSKonrad Rzeszutek Wilk 					 "String overflow while reading "
62230edc14bSKonrad Rzeszutek Wilk 					 "configuration");
62330edc14bSKonrad Rzeszutek Wilk 			goto out;
62430edc14bSKonrad Rzeszutek Wilk 		}
62530edc14bSKonrad Rzeszutek Wilk 		err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, state_str,
62630edc14bSKonrad Rzeszutek Wilk 				    "%d", XenbusStateInitialised);
62730edc14bSKonrad Rzeszutek Wilk 		if (err) {
62830edc14bSKonrad Rzeszutek Wilk 			xenbus_dev_fatal(pdev->xdev, err, "Error switching "
62930edc14bSKonrad Rzeszutek Wilk 					 "substate of dev-%d\n", i);
63030edc14bSKonrad Rzeszutek Wilk 			goto out;
63130edc14bSKonrad Rzeszutek Wilk 		}
63230edc14bSKonrad Rzeszutek Wilk 	}
63330edc14bSKonrad Rzeszutek Wilk 
634a92336a1SKonrad Rzeszutek Wilk 	err = xen_pcibk_publish_pci_roots(pdev, xen_pcibk_publish_pci_root);
63530edc14bSKonrad Rzeszutek Wilk 	if (err) {
63630edc14bSKonrad Rzeszutek Wilk 		xenbus_dev_fatal(pdev->xdev, err,
63730edc14bSKonrad Rzeszutek Wilk 				 "Error while publish PCI root buses "
63830edc14bSKonrad Rzeszutek Wilk 				 "for frontend");
63930edc14bSKonrad Rzeszutek Wilk 		goto out;
64030edc14bSKonrad Rzeszutek Wilk 	}
64130edc14bSKonrad Rzeszutek Wilk 
64230edc14bSKonrad Rzeszutek Wilk 	err = xenbus_switch_state(pdev->xdev, XenbusStateInitialised);
64330edc14bSKonrad Rzeszutek Wilk 	if (err)
64430edc14bSKonrad Rzeszutek Wilk 		xenbus_dev_fatal(pdev->xdev, err,
64530edc14bSKonrad Rzeszutek Wilk 				 "Error switching to initialised state!");
64630edc14bSKonrad Rzeszutek Wilk 
64730edc14bSKonrad Rzeszutek Wilk out:
648b1766b62SKonrad Rzeszutek Wilk 	mutex_unlock(&pdev->dev_lock);
64930edc14bSKonrad Rzeszutek Wilk 	if (!err)
65030edc14bSKonrad Rzeszutek Wilk 		/* see if pcifront is already configured (if not, we'll wait) */
651a92336a1SKonrad Rzeszutek Wilk 		xen_pcibk_attach(pdev);
65230edc14bSKonrad Rzeszutek Wilk 	return err;
65330edc14bSKonrad Rzeszutek Wilk }
65430edc14bSKonrad Rzeszutek Wilk 
655a92336a1SKonrad Rzeszutek Wilk static void xen_pcibk_be_watch(struct xenbus_watch *watch,
6565584ea25SJuergen Gross 			       const char *path, const char *token)
65730edc14bSKonrad Rzeszutek Wilk {
658a92336a1SKonrad Rzeszutek Wilk 	struct xen_pcibk_device *pdev =
659a92336a1SKonrad Rzeszutek Wilk 	    container_of(watch, struct xen_pcibk_device, be_watch);
66030edc14bSKonrad Rzeszutek Wilk 
66130edc14bSKonrad Rzeszutek Wilk 	switch (xenbus_read_driver_state(pdev->xdev->nodename)) {
66230edc14bSKonrad Rzeszutek Wilk 	case XenbusStateInitWait:
663a92336a1SKonrad Rzeszutek Wilk 		xen_pcibk_setup_backend(pdev);
66430edc14bSKonrad Rzeszutek Wilk 		break;
66530edc14bSKonrad Rzeszutek Wilk 
66630edc14bSKonrad Rzeszutek Wilk 	default:
66730edc14bSKonrad Rzeszutek Wilk 		break;
66830edc14bSKonrad Rzeszutek Wilk 	}
66930edc14bSKonrad Rzeszutek Wilk }
67030edc14bSKonrad Rzeszutek Wilk 
671a92336a1SKonrad Rzeszutek Wilk static int xen_pcibk_xenbus_probe(struct xenbus_device *dev,
67230edc14bSKonrad Rzeszutek Wilk 				const struct xenbus_device_id *id)
67330edc14bSKonrad Rzeszutek Wilk {
67430edc14bSKonrad Rzeszutek Wilk 	int err = 0;
675a92336a1SKonrad Rzeszutek Wilk 	struct xen_pcibk_device *pdev = alloc_pdev(dev);
67630edc14bSKonrad Rzeszutek Wilk 
67730edc14bSKonrad Rzeszutek Wilk 	if (pdev == NULL) {
67830edc14bSKonrad Rzeszutek Wilk 		err = -ENOMEM;
67930edc14bSKonrad Rzeszutek Wilk 		xenbus_dev_fatal(dev, err,
680a92336a1SKonrad Rzeszutek Wilk 				 "Error allocating xen_pcibk_device struct");
68130edc14bSKonrad Rzeszutek Wilk 		goto out;
68230edc14bSKonrad Rzeszutek Wilk 	}
68330edc14bSKonrad Rzeszutek Wilk 
68430edc14bSKonrad Rzeszutek Wilk 	/* wait for xend to configure us */
68530edc14bSKonrad Rzeszutek Wilk 	err = xenbus_switch_state(dev, XenbusStateInitWait);
68630edc14bSKonrad Rzeszutek Wilk 	if (err)
68730edc14bSKonrad Rzeszutek Wilk 		goto out;
68830edc14bSKonrad Rzeszutek Wilk 
68930edc14bSKonrad Rzeszutek Wilk 	/* watch the backend node for backend configuration information */
69030edc14bSKonrad Rzeszutek Wilk 	err = xenbus_watch_path(dev, dev->nodename, &pdev->be_watch,
691a92336a1SKonrad Rzeszutek Wilk 				xen_pcibk_be_watch);
69230edc14bSKonrad Rzeszutek Wilk 	if (err)
69330edc14bSKonrad Rzeszutek Wilk 		goto out;
694494ef20dSKonrad Rzeszutek Wilk 
69530edc14bSKonrad Rzeszutek Wilk 	pdev->be_watching = 1;
69630edc14bSKonrad Rzeszutek Wilk 
69730edc14bSKonrad Rzeszutek Wilk 	/* We need to force a call to our callback here in case
69830edc14bSKonrad Rzeszutek Wilk 	 * xend already configured us!
69930edc14bSKonrad Rzeszutek Wilk 	 */
700515762b9SHariprasad Kelam 	xen_pcibk_be_watch(&pdev->be_watch, NULL, NULL);
70130edc14bSKonrad Rzeszutek Wilk 
70230edc14bSKonrad Rzeszutek Wilk out:
70330edc14bSKonrad Rzeszutek Wilk 	return err;
70430edc14bSKonrad Rzeszutek Wilk }
70530edc14bSKonrad Rzeszutek Wilk 
706a92336a1SKonrad Rzeszutek Wilk static int xen_pcibk_xenbus_remove(struct xenbus_device *dev)
70730edc14bSKonrad Rzeszutek Wilk {
708a92336a1SKonrad Rzeszutek Wilk 	struct xen_pcibk_device *pdev = dev_get_drvdata(&dev->dev);
70930edc14bSKonrad Rzeszutek Wilk 
71030edc14bSKonrad Rzeszutek Wilk 	if (pdev != NULL)
71130edc14bSKonrad Rzeszutek Wilk 		free_pdev(pdev);
71230edc14bSKonrad Rzeszutek Wilk 
71330edc14bSKonrad Rzeszutek Wilk 	return 0;
71430edc14bSKonrad Rzeszutek Wilk }
71530edc14bSKonrad Rzeszutek Wilk 
71673db144bSJan Beulich static const struct xenbus_device_id xen_pcibk_ids[] = {
71730edc14bSKonrad Rzeszutek Wilk 	{"pci"},
71830edc14bSKonrad Rzeszutek Wilk 	{""},
71930edc14bSKonrad Rzeszutek Wilk };
72030edc14bSKonrad Rzeszutek Wilk 
72195afae48SDavid Vrabel static struct xenbus_driver xen_pcibk_driver = {
72295afae48SDavid Vrabel 	.name                   = DRV_NAME,
72395afae48SDavid Vrabel 	.ids                    = xen_pcibk_ids,
724a92336a1SKonrad Rzeszutek Wilk 	.probe			= xen_pcibk_xenbus_probe,
725a92336a1SKonrad Rzeszutek Wilk 	.remove			= xen_pcibk_xenbus_remove,
726a92336a1SKonrad Rzeszutek Wilk 	.otherend_changed	= xen_pcibk_frontend_changed,
72795afae48SDavid Vrabel };
72830edc14bSKonrad Rzeszutek Wilk 
729402c5e15SJan Beulich const struct xen_pcibk_backend *__read_mostly xen_pcibk_backend;
7302ebdc426SKonrad Rzeszutek Wilk 
731a92336a1SKonrad Rzeszutek Wilk int __init xen_pcibk_xenbus_register(void)
73230edc14bSKonrad Rzeszutek Wilk {
7332ebdc426SKonrad Rzeszutek Wilk 	xen_pcibk_backend = &xen_pcibk_vpci_backend;
7342ebdc426SKonrad Rzeszutek Wilk 	if (passthrough)
7352ebdc426SKonrad Rzeszutek Wilk 		xen_pcibk_backend = &xen_pcibk_passthrough_backend;
736283c0972SJoe Perches 	pr_info("backend is %s\n", xen_pcibk_backend->name);
73773db144bSJan Beulich 	return xenbus_register_backend(&xen_pcibk_driver);
73830edc14bSKonrad Rzeszutek Wilk }
73930edc14bSKonrad Rzeszutek Wilk 
740a92336a1SKonrad Rzeszutek Wilk void __exit xen_pcibk_xenbus_unregister(void)
74130edc14bSKonrad Rzeszutek Wilk {
74273db144bSJan Beulich 	xenbus_unregister_driver(&xen_pcibk_driver);
74330edc14bSKonrad Rzeszutek Wilk }
744