xref: /openbmc/linux/drivers/xen/xen-pciback/xenbus.c (revision 7cffcade)
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>
17a67efff2SOleksandr Andrushchenko #include <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"\
3406c62f8cSColin Ian King 	"   for drivers which depend on finding their hardware in certain\n"\
352ebdc426SKonrad Rzeszutek Wilk 	"   bus/slot locations.");
362ebdc426SKonrad Rzeszutek Wilk 
alloc_pdev(struct xenbus_device * xdev)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 
xen_pcibk_disconnect(struct xen_pcibk_device * pdev)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 
free_pdev(struct xen_pcibk_device * pdev)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 
xen_pcibk_do_attach(struct xen_pcibk_device * pdev,int gnt_ref,evtchn_port_t remote_evtchn)107a92336a1SKonrad Rzeszutek Wilk static int xen_pcibk_do_attach(struct xen_pcibk_device *pdev, int gnt_ref,
1080102e4efSYan Yankovskyi 			     evtchn_port_t 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,
1140102e4efSYan Yankovskyi 		"Attaching to frontend resources - gnt_ref=%d evtchn=%u\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 
126c2711441SJuergen Gross 	err = bind_interdomain_evtchn_to_irqhandler_lateeoi(
127f2fa0e5eSJuergen Gross 		pdev->xdev, 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 
xen_pcibk_attach(struct xen_pcibk_device * pdev)142a92336a1SKonrad Rzeszutek Wilk static int xen_pcibk_attach(struct xen_pcibk_device *pdev)
14330edc14bSKonrad Rzeszutek Wilk {
14430edc14bSKonrad Rzeszutek Wilk 	int err = 0;
1450102e4efSYan Yankovskyi 	int gnt_ref;
1460102e4efSYan Yankovskyi 	evtchn_port_t remote_evtchn;
14730edc14bSKonrad Rzeszutek Wilk 	char *magic = NULL;
14830edc14bSKonrad Rzeszutek Wilk 
14930edc14bSKonrad Rzeszutek Wilk 
150b1766b62SKonrad Rzeszutek Wilk 	mutex_lock(&pdev->dev_lock);
15130edc14bSKonrad Rzeszutek Wilk 	/* Make sure we only do this setup once */
15230edc14bSKonrad Rzeszutek Wilk 	if (xenbus_read_driver_state(pdev->xdev->nodename) !=
15330edc14bSKonrad Rzeszutek Wilk 	    XenbusStateInitialised)
15430edc14bSKonrad Rzeszutek Wilk 		goto out;
15530edc14bSKonrad Rzeszutek Wilk 
15630edc14bSKonrad Rzeszutek Wilk 	/* Wait for frontend to state that it has published the configuration */
15730edc14bSKonrad Rzeszutek Wilk 	if (xenbus_read_driver_state(pdev->xdev->otherend) !=
15830edc14bSKonrad Rzeszutek Wilk 	    XenbusStateInitialised)
15930edc14bSKonrad Rzeszutek Wilk 		goto out;
16030edc14bSKonrad Rzeszutek Wilk 
16130edc14bSKonrad Rzeszutek Wilk 	dev_dbg(&pdev->xdev->dev, "Reading frontend config\n");
16230edc14bSKonrad Rzeszutek Wilk 
16330edc14bSKonrad Rzeszutek Wilk 	err = xenbus_gather(XBT_NIL, pdev->xdev->otherend,
16430edc14bSKonrad Rzeszutek Wilk 			    "pci-op-ref", "%u", &gnt_ref,
16530edc14bSKonrad Rzeszutek Wilk 			    "event-channel", "%u", &remote_evtchn,
16630edc14bSKonrad Rzeszutek Wilk 			    "magic", NULL, &magic, NULL);
16730edc14bSKonrad Rzeszutek Wilk 	if (err) {
16830edc14bSKonrad Rzeszutek Wilk 		/* If configuration didn't get read correctly, wait longer */
16930edc14bSKonrad Rzeszutek Wilk 		xenbus_dev_fatal(pdev->xdev, err,
17030edc14bSKonrad Rzeszutek Wilk 				 "Error reading configuration from frontend");
17130edc14bSKonrad Rzeszutek Wilk 		goto out;
17230edc14bSKonrad Rzeszutek Wilk 	}
17330edc14bSKonrad Rzeszutek Wilk 
17430edc14bSKonrad Rzeszutek Wilk 	if (magic == NULL || strcmp(magic, XEN_PCI_MAGIC) != 0) {
17530edc14bSKonrad Rzeszutek Wilk 		xenbus_dev_fatal(pdev->xdev, -EFAULT,
17630edc14bSKonrad Rzeszutek Wilk 				 "version mismatch (%s/%s) with pcifront - "
177402c5e15SJan Beulich 				 "halting " DRV_NAME,
17830edc14bSKonrad Rzeszutek Wilk 				 magic, XEN_PCI_MAGIC);
1792ef76032SWei Yongjun 		err = -EFAULT;
18030edc14bSKonrad Rzeszutek Wilk 		goto out;
18130edc14bSKonrad Rzeszutek Wilk 	}
18230edc14bSKonrad Rzeszutek Wilk 
183a92336a1SKonrad Rzeszutek Wilk 	err = xen_pcibk_do_attach(pdev, gnt_ref, remote_evtchn);
18430edc14bSKonrad Rzeszutek Wilk 	if (err)
18530edc14bSKonrad Rzeszutek Wilk 		goto out;
18630edc14bSKonrad Rzeszutek Wilk 
18730edc14bSKonrad Rzeszutek Wilk 	dev_dbg(&pdev->xdev->dev, "Connecting...\n");
18830edc14bSKonrad Rzeszutek Wilk 
18930edc14bSKonrad Rzeszutek Wilk 	err = xenbus_switch_state(pdev->xdev, XenbusStateConnected);
19030edc14bSKonrad Rzeszutek Wilk 	if (err)
19130edc14bSKonrad Rzeszutek Wilk 		xenbus_dev_fatal(pdev->xdev, err,
19230edc14bSKonrad Rzeszutek Wilk 				 "Error switching to connected state!");
19330edc14bSKonrad Rzeszutek Wilk 
19430edc14bSKonrad Rzeszutek Wilk 	dev_dbg(&pdev->xdev->dev, "Connected? %d\n", err);
19530edc14bSKonrad Rzeszutek Wilk out:
196b1766b62SKonrad Rzeszutek Wilk 	mutex_unlock(&pdev->dev_lock);
19730edc14bSKonrad Rzeszutek Wilk 
19830edc14bSKonrad Rzeszutek Wilk 	kfree(magic);
19930edc14bSKonrad Rzeszutek Wilk 
20030edc14bSKonrad Rzeszutek Wilk 	return err;
20130edc14bSKonrad Rzeszutek Wilk }
20230edc14bSKonrad Rzeszutek Wilk 
xen_pcibk_publish_pci_dev(struct xen_pcibk_device * pdev,unsigned int domain,unsigned int bus,unsigned int devfn,unsigned int devid)203a92336a1SKonrad Rzeszutek Wilk static int xen_pcibk_publish_pci_dev(struct xen_pcibk_device *pdev,
20430edc14bSKonrad Rzeszutek Wilk 				   unsigned int domain, unsigned int bus,
20530edc14bSKonrad Rzeszutek Wilk 				   unsigned int devfn, unsigned int devid)
20630edc14bSKonrad Rzeszutek Wilk {
20730edc14bSKonrad Rzeszutek Wilk 	int err;
20830edc14bSKonrad Rzeszutek Wilk 	int len;
20930edc14bSKonrad Rzeszutek Wilk 	char str[64];
21030edc14bSKonrad Rzeszutek Wilk 
21130edc14bSKonrad Rzeszutek Wilk 	len = snprintf(str, sizeof(str), "vdev-%d", devid);
21230edc14bSKonrad Rzeszutek Wilk 	if (unlikely(len >= (sizeof(str) - 1))) {
21330edc14bSKonrad Rzeszutek Wilk 		err = -ENOMEM;
21430edc14bSKonrad Rzeszutek Wilk 		goto out;
21530edc14bSKonrad Rzeszutek Wilk 	}
21630edc14bSKonrad Rzeszutek Wilk 
217e4de866aSKonrad Rzeszutek Wilk 	/* Note: The PV protocol uses %02x, don't change it */
21830edc14bSKonrad Rzeszutek Wilk 	err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, str,
21930edc14bSKonrad Rzeszutek Wilk 			    "%04x:%02x:%02x.%02x", domain, bus,
22030edc14bSKonrad Rzeszutek Wilk 			    PCI_SLOT(devfn), PCI_FUNC(devfn));
22130edc14bSKonrad Rzeszutek Wilk 
22230edc14bSKonrad Rzeszutek Wilk out:
22330edc14bSKonrad Rzeszutek Wilk 	return err;
22430edc14bSKonrad Rzeszutek Wilk }
22530edc14bSKonrad Rzeszutek Wilk 
xen_pcibk_export_device(struct xen_pcibk_device * pdev,int domain,int bus,int slot,int func,int devid)226a92336a1SKonrad Rzeszutek Wilk static int xen_pcibk_export_device(struct xen_pcibk_device *pdev,
22730edc14bSKonrad Rzeszutek Wilk 				 int domain, int bus, int slot, int func,
22830edc14bSKonrad Rzeszutek Wilk 				 int devid)
22930edc14bSKonrad Rzeszutek Wilk {
23030edc14bSKonrad Rzeszutek Wilk 	struct pci_dev *dev;
23130edc14bSKonrad Rzeszutek Wilk 	int err = 0;
23230edc14bSKonrad Rzeszutek Wilk 
23330edc14bSKonrad Rzeszutek Wilk 	dev_dbg(&pdev->xdev->dev, "exporting dom %x bus %x slot %x func %x\n",
23430edc14bSKonrad Rzeszutek Wilk 		domain, bus, slot, func);
23530edc14bSKonrad Rzeszutek Wilk 
23630edc14bSKonrad Rzeszutek Wilk 	dev = pcistub_get_pci_dev_by_slot(pdev, domain, bus, slot, func);
23730edc14bSKonrad Rzeszutek Wilk 	if (!dev) {
23830edc14bSKonrad Rzeszutek Wilk 		err = -EINVAL;
23930edc14bSKonrad Rzeszutek Wilk 		xenbus_dev_fatal(pdev->xdev, err,
24030edc14bSKonrad Rzeszutek Wilk 				 "Couldn't locate PCI device "
241e4de866aSKonrad Rzeszutek Wilk 				 "(%04x:%02x:%02x.%d)! "
24230edc14bSKonrad Rzeszutek Wilk 				 "perhaps already in-use?",
24330edc14bSKonrad Rzeszutek Wilk 				 domain, bus, slot, func);
24430edc14bSKonrad Rzeszutek Wilk 		goto out;
24530edc14bSKonrad Rzeszutek Wilk 	}
24630edc14bSKonrad Rzeszutek Wilk 
247a92336a1SKonrad Rzeszutek Wilk 	err = xen_pcibk_add_pci_dev(pdev, dev, devid,
248a92336a1SKonrad Rzeszutek Wilk 				    xen_pcibk_publish_pci_dev);
24930edc14bSKonrad Rzeszutek Wilk 	if (err)
25030edc14bSKonrad Rzeszutek Wilk 		goto out;
25130edc14bSKonrad Rzeszutek Wilk 
25215390613SKonrad Rzeszutek Wilk 	dev_info(&dev->dev, "registering for %d\n", pdev->xdev->otherend_id);
2536221a9b2SKonrad Rzeszutek Wilk 	if (xen_register_device_domain_owner(dev,
2546221a9b2SKonrad Rzeszutek Wilk 					     pdev->xdev->otherend_id) != 0) {
2556c254de1SKonrad Rzeszutek Wilk 		dev_err(&dev->dev, "Stealing ownership from dom%d.\n",
2566c254de1SKonrad Rzeszutek Wilk 			xen_find_device_domain_owner(dev));
2576221a9b2SKonrad Rzeszutek Wilk 		xen_unregister_device_domain_owner(dev);
2586221a9b2SKonrad Rzeszutek Wilk 		xen_register_device_domain_owner(dev, pdev->xdev->otherend_id);
2596221a9b2SKonrad Rzeszutek Wilk 	}
2606221a9b2SKonrad Rzeszutek Wilk 
26130edc14bSKonrad Rzeszutek Wilk 	/* TODO: It'd be nice to export a bridge and have all of its children
26230edc14bSKonrad Rzeszutek Wilk 	 * get exported with it. This may be best done in xend (which will
26330edc14bSKonrad Rzeszutek Wilk 	 * have to calculate resource usage anyway) but we probably want to
26430edc14bSKonrad Rzeszutek Wilk 	 * put something in here to ensure that if a bridge gets given to a
26530edc14bSKonrad Rzeszutek Wilk 	 * driver domain, that all devices under that bridge are not given
26630edc14bSKonrad Rzeszutek Wilk 	 * to other driver domains (as he who controls the bridge can disable
26730edc14bSKonrad Rzeszutek Wilk 	 * it and stop the other devices from working).
26830edc14bSKonrad Rzeszutek Wilk 	 */
26930edc14bSKonrad Rzeszutek Wilk out:
27030edc14bSKonrad Rzeszutek Wilk 	return err;
27130edc14bSKonrad Rzeszutek Wilk }
27230edc14bSKonrad Rzeszutek Wilk 
xen_pcibk_remove_device(struct xen_pcibk_device * pdev,int domain,int bus,int slot,int func)273a92336a1SKonrad Rzeszutek Wilk static int xen_pcibk_remove_device(struct xen_pcibk_device *pdev,
27430edc14bSKonrad Rzeszutek Wilk 				 int domain, int bus, int slot, int func)
27530edc14bSKonrad Rzeszutek Wilk {
27630edc14bSKonrad Rzeszutek Wilk 	int err = 0;
27730edc14bSKonrad Rzeszutek Wilk 	struct pci_dev *dev;
27830edc14bSKonrad Rzeszutek Wilk 
27930edc14bSKonrad Rzeszutek Wilk 	dev_dbg(&pdev->xdev->dev, "removing dom %x bus %x slot %x func %x\n",
28030edc14bSKonrad Rzeszutek Wilk 		domain, bus, slot, func);
28130edc14bSKonrad Rzeszutek Wilk 
282a92336a1SKonrad Rzeszutek Wilk 	dev = xen_pcibk_get_pci_dev(pdev, domain, bus, PCI_DEVFN(slot, func));
28330edc14bSKonrad Rzeszutek Wilk 	if (!dev) {
28430edc14bSKonrad Rzeszutek Wilk 		err = -EINVAL;
28530edc14bSKonrad Rzeszutek Wilk 		dev_dbg(&pdev->xdev->dev, "Couldn't locate PCI device "
286e4de866aSKonrad Rzeszutek Wilk 			"(%04x:%02x:%02x.%d)! not owned by this domain\n",
28730edc14bSKonrad Rzeszutek Wilk 			domain, bus, slot, func);
28830edc14bSKonrad Rzeszutek Wilk 		goto out;
28930edc14bSKonrad Rzeszutek Wilk 	}
29030edc14bSKonrad Rzeszutek Wilk 
2916221a9b2SKonrad Rzeszutek Wilk 	dev_dbg(&dev->dev, "unregistering for %d\n", pdev->xdev->otherend_id);
2926221a9b2SKonrad Rzeszutek Wilk 	xen_unregister_device_domain_owner(dev);
2936221a9b2SKonrad Rzeszutek Wilk 
2948be9df6dSKonrad Rzeszutek Wilk 	/* N.B. This ends up calling pcistub_put_pci_dev which ends up
2958be9df6dSKonrad Rzeszutek Wilk 	 * doing the FLR. */
296e8801a74SKonrad Rzeszutek Wilk 	xen_pcibk_release_pci_dev(pdev, dev, true /* use the lock. */);
29730edc14bSKonrad Rzeszutek Wilk 
29830edc14bSKonrad Rzeszutek Wilk out:
29930edc14bSKonrad Rzeszutek Wilk 	return err;
30030edc14bSKonrad Rzeszutek Wilk }
30130edc14bSKonrad Rzeszutek Wilk 
xen_pcibk_publish_pci_root(struct xen_pcibk_device * pdev,unsigned int domain,unsigned int bus)302a92336a1SKonrad Rzeszutek Wilk static int xen_pcibk_publish_pci_root(struct xen_pcibk_device *pdev,
30330edc14bSKonrad Rzeszutek Wilk 				    unsigned int domain, unsigned int bus)
30430edc14bSKonrad Rzeszutek Wilk {
30530edc14bSKonrad Rzeszutek Wilk 	unsigned int d, b;
30630edc14bSKonrad Rzeszutek Wilk 	int i, root_num, len, err;
30730edc14bSKonrad Rzeszutek Wilk 	char str[64];
30830edc14bSKonrad Rzeszutek Wilk 
30930edc14bSKonrad Rzeszutek Wilk 	dev_dbg(&pdev->xdev->dev, "Publishing pci roots\n");
31030edc14bSKonrad Rzeszutek Wilk 
31130edc14bSKonrad Rzeszutek Wilk 	err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename,
31230edc14bSKonrad Rzeszutek Wilk 			   "root_num", "%d", &root_num);
31330edc14bSKonrad Rzeszutek Wilk 	if (err == 0 || err == -ENOENT)
31430edc14bSKonrad Rzeszutek Wilk 		root_num = 0;
31530edc14bSKonrad Rzeszutek Wilk 	else if (err < 0)
31630edc14bSKonrad Rzeszutek Wilk 		goto out;
31730edc14bSKonrad Rzeszutek Wilk 
31830edc14bSKonrad Rzeszutek Wilk 	/* Verify that we haven't already published this pci root */
31930edc14bSKonrad Rzeszutek Wilk 	for (i = 0; i < root_num; i++) {
32030edc14bSKonrad Rzeszutek Wilk 		len = snprintf(str, sizeof(str), "root-%d", i);
32130edc14bSKonrad Rzeszutek Wilk 		if (unlikely(len >= (sizeof(str) - 1))) {
32230edc14bSKonrad Rzeszutek Wilk 			err = -ENOMEM;
32330edc14bSKonrad Rzeszutek Wilk 			goto out;
32430edc14bSKonrad Rzeszutek Wilk 		}
32530edc14bSKonrad Rzeszutek Wilk 
32630edc14bSKonrad Rzeszutek Wilk 		err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename,
32730edc14bSKonrad Rzeszutek Wilk 				   str, "%x:%x", &d, &b);
32830edc14bSKonrad Rzeszutek Wilk 		if (err < 0)
32930edc14bSKonrad Rzeszutek Wilk 			goto out;
33030edc14bSKonrad Rzeszutek Wilk 		if (err != 2) {
33130edc14bSKonrad Rzeszutek Wilk 			err = -EINVAL;
33230edc14bSKonrad Rzeszutek Wilk 			goto out;
33330edc14bSKonrad Rzeszutek Wilk 		}
33430edc14bSKonrad Rzeszutek Wilk 
33530edc14bSKonrad Rzeszutek Wilk 		if (d == domain && b == bus) {
33630edc14bSKonrad Rzeszutek Wilk 			err = 0;
33730edc14bSKonrad Rzeszutek Wilk 			goto out;
33830edc14bSKonrad Rzeszutek Wilk 		}
33930edc14bSKonrad Rzeszutek Wilk 	}
34030edc14bSKonrad Rzeszutek Wilk 
34130edc14bSKonrad Rzeszutek Wilk 	len = snprintf(str, sizeof(str), "root-%d", root_num);
34230edc14bSKonrad Rzeszutek Wilk 	if (unlikely(len >= (sizeof(str) - 1))) {
34330edc14bSKonrad Rzeszutek Wilk 		err = -ENOMEM;
34430edc14bSKonrad Rzeszutek Wilk 		goto out;
34530edc14bSKonrad Rzeszutek Wilk 	}
34630edc14bSKonrad Rzeszutek Wilk 
34730edc14bSKonrad Rzeszutek Wilk 	dev_dbg(&pdev->xdev->dev, "writing root %d at %04x:%02x\n",
34830edc14bSKonrad Rzeszutek Wilk 		root_num, domain, bus);
34930edc14bSKonrad Rzeszutek Wilk 
35030edc14bSKonrad Rzeszutek Wilk 	err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, str,
35130edc14bSKonrad Rzeszutek Wilk 			    "%04x:%02x", domain, bus);
35230edc14bSKonrad Rzeszutek Wilk 	if (err)
35330edc14bSKonrad Rzeszutek Wilk 		goto out;
35430edc14bSKonrad Rzeszutek Wilk 
35530edc14bSKonrad Rzeszutek Wilk 	err = xenbus_printf(XBT_NIL, pdev->xdev->nodename,
35630edc14bSKonrad Rzeszutek Wilk 			    "root_num", "%d", (root_num + 1));
35730edc14bSKonrad Rzeszutek Wilk 
35830edc14bSKonrad Rzeszutek Wilk out:
35930edc14bSKonrad Rzeszutek Wilk 	return err;
36030edc14bSKonrad Rzeszutek Wilk }
36130edc14bSKonrad Rzeszutek Wilk 
xen_pcibk_reconfigure(struct xen_pcibk_device * pdev,enum xenbus_state state)362c81d3d24SJan Beulich static int xen_pcibk_reconfigure(struct xen_pcibk_device *pdev,
363c81d3d24SJan Beulich 				 enum xenbus_state state)
36430edc14bSKonrad Rzeszutek Wilk {
36530edc14bSKonrad Rzeszutek Wilk 	int err = 0;
36630edc14bSKonrad Rzeszutek Wilk 	int num_devs;
36730edc14bSKonrad Rzeszutek Wilk 	int domain, bus, slot, func;
3684e81f1caSJuergen Gross 	unsigned int substate;
36930edc14bSKonrad Rzeszutek Wilk 	int i, len;
37030edc14bSKonrad Rzeszutek Wilk 	char state_str[64];
37130edc14bSKonrad Rzeszutek Wilk 	char dev_str[64];
37230edc14bSKonrad Rzeszutek Wilk 
37330edc14bSKonrad Rzeszutek Wilk 
37430edc14bSKonrad Rzeszutek Wilk 	dev_dbg(&pdev->xdev->dev, "Reconfiguring device ...\n");
37530edc14bSKonrad Rzeszutek Wilk 
376b1766b62SKonrad Rzeszutek Wilk 	mutex_lock(&pdev->dev_lock);
377c81d3d24SJan Beulich 	if (xenbus_read_driver_state(pdev->xdev->nodename) != state)
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 
502c81d3d24SJan Beulich 	if (state != XenbusStateReconfiguring)
503c81d3d24SJan Beulich 		/* Make sure we only reconfigure once. */
504c81d3d24SJan Beulich 		goto out;
505c81d3d24SJan Beulich 
50630edc14bSKonrad Rzeszutek Wilk 	err = xenbus_switch_state(pdev->xdev, XenbusStateReconfigured);
50730edc14bSKonrad Rzeszutek Wilk 	if (err) {
50830edc14bSKonrad Rzeszutek Wilk 		xenbus_dev_fatal(pdev->xdev, err,
50930edc14bSKonrad Rzeszutek Wilk 				 "Error switching to reconfigured state!");
51030edc14bSKonrad Rzeszutek Wilk 		goto out;
51130edc14bSKonrad Rzeszutek Wilk 	}
51230edc14bSKonrad Rzeszutek Wilk 
51330edc14bSKonrad Rzeszutek Wilk out:
514b1766b62SKonrad Rzeszutek Wilk 	mutex_unlock(&pdev->dev_lock);
51530edc14bSKonrad Rzeszutek Wilk 	return 0;
51630edc14bSKonrad Rzeszutek Wilk }
51730edc14bSKonrad Rzeszutek Wilk 
xen_pcibk_frontend_changed(struct xenbus_device * xdev,enum xenbus_state fe_state)518a92336a1SKonrad Rzeszutek Wilk static void xen_pcibk_frontend_changed(struct xenbus_device *xdev,
51930edc14bSKonrad Rzeszutek Wilk 				     enum xenbus_state fe_state)
52030edc14bSKonrad Rzeszutek Wilk {
521a92336a1SKonrad Rzeszutek Wilk 	struct xen_pcibk_device *pdev = dev_get_drvdata(&xdev->dev);
52230edc14bSKonrad Rzeszutek Wilk 
52330edc14bSKonrad Rzeszutek Wilk 	dev_dbg(&xdev->dev, "fe state changed %d\n", fe_state);
52430edc14bSKonrad Rzeszutek Wilk 
52530edc14bSKonrad Rzeszutek Wilk 	switch (fe_state) {
52630edc14bSKonrad Rzeszutek Wilk 	case XenbusStateInitialised:
527a92336a1SKonrad Rzeszutek Wilk 		xen_pcibk_attach(pdev);
52830edc14bSKonrad Rzeszutek Wilk 		break;
52930edc14bSKonrad Rzeszutek Wilk 
53030edc14bSKonrad Rzeszutek Wilk 	case XenbusStateReconfiguring:
531c81d3d24SJan Beulich 		xen_pcibk_reconfigure(pdev, XenbusStateReconfiguring);
53230edc14bSKonrad Rzeszutek Wilk 		break;
53330edc14bSKonrad Rzeszutek Wilk 
53430edc14bSKonrad Rzeszutek Wilk 	case XenbusStateConnected:
53530edc14bSKonrad Rzeszutek Wilk 		/* pcifront switched its state from reconfiguring to connected.
53630edc14bSKonrad Rzeszutek Wilk 		 * Then switch to connected state.
53730edc14bSKonrad Rzeszutek Wilk 		 */
53830edc14bSKonrad Rzeszutek Wilk 		xenbus_switch_state(xdev, XenbusStateConnected);
53930edc14bSKonrad Rzeszutek Wilk 		break;
54030edc14bSKonrad Rzeszutek Wilk 
54130edc14bSKonrad Rzeszutek Wilk 	case XenbusStateClosing:
542a92336a1SKonrad Rzeszutek Wilk 		xen_pcibk_disconnect(pdev);
54330edc14bSKonrad Rzeszutek Wilk 		xenbus_switch_state(xdev, XenbusStateClosing);
54430edc14bSKonrad Rzeszutek Wilk 		break;
54530edc14bSKonrad Rzeszutek Wilk 
54630edc14bSKonrad Rzeszutek Wilk 	case XenbusStateClosed:
547a92336a1SKonrad Rzeszutek Wilk 		xen_pcibk_disconnect(pdev);
54830edc14bSKonrad Rzeszutek Wilk 		xenbus_switch_state(xdev, XenbusStateClosed);
54930edc14bSKonrad Rzeszutek Wilk 		if (xenbus_dev_is_online(xdev))
55030edc14bSKonrad Rzeszutek Wilk 			break;
551df561f66SGustavo A. R. Silva 		fallthrough;	/* if not online */
55230edc14bSKonrad Rzeszutek Wilk 	case XenbusStateUnknown:
55330edc14bSKonrad Rzeszutek Wilk 		dev_dbg(&xdev->dev, "frontend is gone! unregister device\n");
55430edc14bSKonrad Rzeszutek Wilk 		device_unregister(&xdev->dev);
55530edc14bSKonrad Rzeszutek Wilk 		break;
55630edc14bSKonrad Rzeszutek Wilk 
55730edc14bSKonrad Rzeszutek Wilk 	default:
55830edc14bSKonrad Rzeszutek Wilk 		break;
55930edc14bSKonrad Rzeszutek Wilk 	}
56030edc14bSKonrad Rzeszutek Wilk }
56130edc14bSKonrad Rzeszutek Wilk 
xen_pcibk_setup_backend(struct xen_pcibk_device * pdev)562a92336a1SKonrad Rzeszutek Wilk static int xen_pcibk_setup_backend(struct xen_pcibk_device *pdev)
56330edc14bSKonrad Rzeszutek Wilk {
56430edc14bSKonrad Rzeszutek Wilk 	/* Get configuration from xend (if available now) */
56530edc14bSKonrad Rzeszutek Wilk 	int domain, bus, slot, func;
56630edc14bSKonrad Rzeszutek Wilk 	int err = 0;
56730edc14bSKonrad Rzeszutek Wilk 	int i, num_devs;
56830edc14bSKonrad Rzeszutek Wilk 	char dev_str[64];
56930edc14bSKonrad Rzeszutek Wilk 	char state_str[64];
57030edc14bSKonrad Rzeszutek Wilk 
571b1766b62SKonrad Rzeszutek Wilk 	mutex_lock(&pdev->dev_lock);
57230edc14bSKonrad Rzeszutek Wilk 	/* It's possible we could get the call to setup twice, so make sure
57330edc14bSKonrad Rzeszutek Wilk 	 * we're not already connected.
57430edc14bSKonrad Rzeszutek Wilk 	 */
57530edc14bSKonrad Rzeszutek Wilk 	if (xenbus_read_driver_state(pdev->xdev->nodename) !=
57630edc14bSKonrad Rzeszutek Wilk 	    XenbusStateInitWait)
57730edc14bSKonrad Rzeszutek Wilk 		goto out;
57830edc14bSKonrad Rzeszutek Wilk 
57930edc14bSKonrad Rzeszutek Wilk 	dev_dbg(&pdev->xdev->dev, "getting be setup\n");
58030edc14bSKonrad Rzeszutek Wilk 
58130edc14bSKonrad Rzeszutek Wilk 	err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, "num_devs", "%d",
58230edc14bSKonrad Rzeszutek Wilk 			   &num_devs);
58330edc14bSKonrad Rzeszutek Wilk 	if (err != 1) {
58430edc14bSKonrad Rzeszutek Wilk 		if (err >= 0)
58530edc14bSKonrad Rzeszutek Wilk 			err = -EINVAL;
58630edc14bSKonrad Rzeszutek Wilk 		xenbus_dev_fatal(pdev->xdev, err,
58730edc14bSKonrad Rzeszutek Wilk 				 "Error reading number of devices");
58830edc14bSKonrad Rzeszutek Wilk 		goto out;
58930edc14bSKonrad Rzeszutek Wilk 	}
59030edc14bSKonrad Rzeszutek Wilk 
59130edc14bSKonrad Rzeszutek Wilk 	for (i = 0; i < num_devs; i++) {
59230edc14bSKonrad Rzeszutek Wilk 		int l = snprintf(dev_str, sizeof(dev_str), "dev-%d", i);
59330edc14bSKonrad Rzeszutek Wilk 		if (unlikely(l >= (sizeof(dev_str) - 1))) {
59430edc14bSKonrad Rzeszutek Wilk 			err = -ENOMEM;
59530edc14bSKonrad Rzeszutek Wilk 			xenbus_dev_fatal(pdev->xdev, err,
59630edc14bSKonrad Rzeszutek Wilk 					 "String overflow while reading "
59730edc14bSKonrad Rzeszutek Wilk 					 "configuration");
59830edc14bSKonrad Rzeszutek Wilk 			goto out;
59930edc14bSKonrad Rzeszutek Wilk 		}
60030edc14bSKonrad Rzeszutek Wilk 
60130edc14bSKonrad Rzeszutek Wilk 		err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, dev_str,
60230edc14bSKonrad Rzeszutek Wilk 				   "%x:%x:%x.%x", &domain, &bus, &slot, &func);
60330edc14bSKonrad Rzeszutek Wilk 		if (err < 0) {
60430edc14bSKonrad Rzeszutek Wilk 			xenbus_dev_fatal(pdev->xdev, err,
60530edc14bSKonrad Rzeszutek Wilk 					 "Error reading device configuration");
60630edc14bSKonrad Rzeszutek Wilk 			goto out;
60730edc14bSKonrad Rzeszutek Wilk 		}
60830edc14bSKonrad Rzeszutek Wilk 		if (err != 4) {
60930edc14bSKonrad Rzeszutek Wilk 			err = -EINVAL;
61030edc14bSKonrad Rzeszutek Wilk 			xenbus_dev_fatal(pdev->xdev, err,
61130edc14bSKonrad Rzeszutek Wilk 					 "Error parsing pci device "
61230edc14bSKonrad Rzeszutek Wilk 					 "configuration");
61330edc14bSKonrad Rzeszutek Wilk 			goto out;
61430edc14bSKonrad Rzeszutek Wilk 		}
61530edc14bSKonrad Rzeszutek Wilk 
616a92336a1SKonrad Rzeszutek Wilk 		err = xen_pcibk_export_device(pdev, domain, bus, slot, func, i);
61730edc14bSKonrad Rzeszutek Wilk 		if (err)
61830edc14bSKonrad Rzeszutek Wilk 			goto out;
61930edc14bSKonrad Rzeszutek Wilk 
62030edc14bSKonrad Rzeszutek Wilk 		/* Switch substate of this device. */
62130edc14bSKonrad Rzeszutek Wilk 		l = snprintf(state_str, sizeof(state_str), "state-%d", i);
62230edc14bSKonrad Rzeszutek Wilk 		if (unlikely(l >= (sizeof(state_str) - 1))) {
62330edc14bSKonrad Rzeszutek Wilk 			err = -ENOMEM;
62430edc14bSKonrad Rzeszutek Wilk 			xenbus_dev_fatal(pdev->xdev, err,
62530edc14bSKonrad Rzeszutek Wilk 					 "String overflow while reading "
62630edc14bSKonrad Rzeszutek Wilk 					 "configuration");
62730edc14bSKonrad Rzeszutek Wilk 			goto out;
62830edc14bSKonrad Rzeszutek Wilk 		}
62930edc14bSKonrad Rzeszutek Wilk 		err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, state_str,
63030edc14bSKonrad Rzeszutek Wilk 				    "%d", XenbusStateInitialised);
63130edc14bSKonrad Rzeszutek Wilk 		if (err) {
63230edc14bSKonrad Rzeszutek Wilk 			xenbus_dev_fatal(pdev->xdev, err, "Error switching "
63330edc14bSKonrad Rzeszutek Wilk 					 "substate of dev-%d\n", i);
63430edc14bSKonrad Rzeszutek Wilk 			goto out;
63530edc14bSKonrad Rzeszutek Wilk 		}
63630edc14bSKonrad Rzeszutek Wilk 	}
63730edc14bSKonrad Rzeszutek Wilk 
638a92336a1SKonrad Rzeszutek Wilk 	err = xen_pcibk_publish_pci_roots(pdev, xen_pcibk_publish_pci_root);
63930edc14bSKonrad Rzeszutek Wilk 	if (err) {
64030edc14bSKonrad Rzeszutek Wilk 		xenbus_dev_fatal(pdev->xdev, err,
64130edc14bSKonrad Rzeszutek Wilk 				 "Error while publish PCI root buses "
64230edc14bSKonrad Rzeszutek Wilk 				 "for frontend");
64330edc14bSKonrad Rzeszutek Wilk 		goto out;
64430edc14bSKonrad Rzeszutek Wilk 	}
64530edc14bSKonrad Rzeszutek Wilk 
64630edc14bSKonrad Rzeszutek Wilk 	err = xenbus_switch_state(pdev->xdev, XenbusStateInitialised);
64730edc14bSKonrad Rzeszutek Wilk 	if (err)
64830edc14bSKonrad Rzeszutek Wilk 		xenbus_dev_fatal(pdev->xdev, err,
64930edc14bSKonrad Rzeszutek Wilk 				 "Error switching to initialised state!");
65030edc14bSKonrad Rzeszutek Wilk 
65130edc14bSKonrad Rzeszutek Wilk out:
652b1766b62SKonrad Rzeszutek Wilk 	mutex_unlock(&pdev->dev_lock);
65330edc14bSKonrad Rzeszutek Wilk 	if (!err)
65430edc14bSKonrad Rzeszutek Wilk 		/* see if pcifront is already configured (if not, we'll wait) */
655a92336a1SKonrad Rzeszutek Wilk 		xen_pcibk_attach(pdev);
65630edc14bSKonrad Rzeszutek Wilk 	return err;
65730edc14bSKonrad Rzeszutek Wilk }
65830edc14bSKonrad Rzeszutek Wilk 
xen_pcibk_be_watch(struct xenbus_watch * watch,const char * path,const char * token)659a92336a1SKonrad Rzeszutek Wilk static void xen_pcibk_be_watch(struct xenbus_watch *watch,
6605584ea25SJuergen Gross 			       const char *path, const char *token)
66130edc14bSKonrad Rzeszutek Wilk {
662a92336a1SKonrad Rzeszutek Wilk 	struct xen_pcibk_device *pdev =
663a92336a1SKonrad Rzeszutek Wilk 	    container_of(watch, struct xen_pcibk_device, be_watch);
66430edc14bSKonrad Rzeszutek Wilk 
66530edc14bSKonrad Rzeszutek Wilk 	switch (xenbus_read_driver_state(pdev->xdev->nodename)) {
66630edc14bSKonrad Rzeszutek Wilk 	case XenbusStateInitWait:
667a92336a1SKonrad Rzeszutek Wilk 		xen_pcibk_setup_backend(pdev);
66830edc14bSKonrad Rzeszutek Wilk 		break;
66930edc14bSKonrad Rzeszutek Wilk 
670c81d3d24SJan Beulich 	case XenbusStateInitialised:
671c81d3d24SJan Beulich 		/*
672c81d3d24SJan Beulich 		 * We typically move to Initialised when the first device was
673c81d3d24SJan Beulich 		 * added. Hence subsequent devices getting added may need
674c81d3d24SJan Beulich 		 * reconfiguring.
675c81d3d24SJan Beulich 		 */
676c81d3d24SJan Beulich 		xen_pcibk_reconfigure(pdev, XenbusStateInitialised);
677c81d3d24SJan Beulich 		break;
678c81d3d24SJan Beulich 
67930edc14bSKonrad Rzeszutek Wilk 	default:
68030edc14bSKonrad Rzeszutek Wilk 		break;
68130edc14bSKonrad Rzeszutek Wilk 	}
68230edc14bSKonrad Rzeszutek Wilk }
68330edc14bSKonrad Rzeszutek Wilk 
xen_pcibk_xenbus_probe(struct xenbus_device * dev,const struct xenbus_device_id * id)684a92336a1SKonrad Rzeszutek Wilk static int xen_pcibk_xenbus_probe(struct xenbus_device *dev,
68530edc14bSKonrad Rzeszutek Wilk 				const struct xenbus_device_id *id)
68630edc14bSKonrad Rzeszutek Wilk {
68730edc14bSKonrad Rzeszutek Wilk 	int err = 0;
688a92336a1SKonrad Rzeszutek Wilk 	struct xen_pcibk_device *pdev = alloc_pdev(dev);
68930edc14bSKonrad Rzeszutek Wilk 
69030edc14bSKonrad Rzeszutek Wilk 	if (pdev == NULL) {
69130edc14bSKonrad Rzeszutek Wilk 		err = -ENOMEM;
69230edc14bSKonrad Rzeszutek Wilk 		xenbus_dev_fatal(dev, err,
693a92336a1SKonrad Rzeszutek Wilk 				 "Error allocating xen_pcibk_device struct");
69430edc14bSKonrad Rzeszutek Wilk 		goto out;
69530edc14bSKonrad Rzeszutek Wilk 	}
69630edc14bSKonrad Rzeszutek Wilk 
69730edc14bSKonrad Rzeszutek Wilk 	/* wait for xend to configure us */
69830edc14bSKonrad Rzeszutek Wilk 	err = xenbus_switch_state(dev, XenbusStateInitWait);
69930edc14bSKonrad Rzeszutek Wilk 	if (err)
70030edc14bSKonrad Rzeszutek Wilk 		goto out;
70130edc14bSKonrad Rzeszutek Wilk 
70230edc14bSKonrad Rzeszutek Wilk 	/* watch the backend node for backend configuration information */
70330edc14bSKonrad Rzeszutek Wilk 	err = xenbus_watch_path(dev, dev->nodename, &pdev->be_watch,
7042e85d32bSSeongJae Park 				NULL, xen_pcibk_be_watch);
70530edc14bSKonrad Rzeszutek Wilk 	if (err)
70630edc14bSKonrad Rzeszutek Wilk 		goto out;
707494ef20dSKonrad Rzeszutek Wilk 
70830edc14bSKonrad Rzeszutek Wilk 	pdev->be_watching = 1;
70930edc14bSKonrad Rzeszutek Wilk 
71030edc14bSKonrad Rzeszutek Wilk 	/* We need to force a call to our callback here in case
71130edc14bSKonrad Rzeszutek Wilk 	 * xend already configured us!
71230edc14bSKonrad Rzeszutek Wilk 	 */
713515762b9SHariprasad Kelam 	xen_pcibk_be_watch(&pdev->be_watch, NULL, NULL);
71430edc14bSKonrad Rzeszutek Wilk 
71530edc14bSKonrad Rzeszutek Wilk out:
71630edc14bSKonrad Rzeszutek Wilk 	return err;
71730edc14bSKonrad Rzeszutek Wilk }
71830edc14bSKonrad Rzeszutek Wilk 
xen_pcibk_xenbus_remove(struct xenbus_device * dev)719*7cffcadeSDawei Li static void xen_pcibk_xenbus_remove(struct xenbus_device *dev)
72030edc14bSKonrad Rzeszutek Wilk {
721a92336a1SKonrad Rzeszutek Wilk 	struct xen_pcibk_device *pdev = dev_get_drvdata(&dev->dev);
72230edc14bSKonrad Rzeszutek Wilk 
72330edc14bSKonrad Rzeszutek Wilk 	if (pdev != NULL)
72430edc14bSKonrad Rzeszutek Wilk 		free_pdev(pdev);
72530edc14bSKonrad Rzeszutek Wilk }
72630edc14bSKonrad Rzeszutek Wilk 
72773db144bSJan Beulich static const struct xenbus_device_id xen_pcibk_ids[] = {
72830edc14bSKonrad Rzeszutek Wilk 	{"pci"},
72930edc14bSKonrad Rzeszutek Wilk 	{""},
73030edc14bSKonrad Rzeszutek Wilk };
73130edc14bSKonrad Rzeszutek Wilk 
73295afae48SDavid Vrabel static struct xenbus_driver xen_pcibk_driver = {
73395afae48SDavid Vrabel 	.name                   = DRV_NAME,
73495afae48SDavid Vrabel 	.ids                    = xen_pcibk_ids,
735a92336a1SKonrad Rzeszutek Wilk 	.probe			= xen_pcibk_xenbus_probe,
736a92336a1SKonrad Rzeszutek Wilk 	.remove			= xen_pcibk_xenbus_remove,
737a92336a1SKonrad Rzeszutek Wilk 	.otherend_changed	= xen_pcibk_frontend_changed,
73895afae48SDavid Vrabel };
73930edc14bSKonrad Rzeszutek Wilk 
740402c5e15SJan Beulich const struct xen_pcibk_backend *__read_mostly xen_pcibk_backend;
7412ebdc426SKonrad Rzeszutek Wilk 
xen_pcibk_xenbus_register(void)742a92336a1SKonrad Rzeszutek Wilk int __init xen_pcibk_xenbus_register(void)
74330edc14bSKonrad Rzeszutek Wilk {
744a67efff2SOleksandr Andrushchenko 	if (!xen_pcibk_pv_support())
745a67efff2SOleksandr Andrushchenko 		return 0;
746a67efff2SOleksandr Andrushchenko 
7472ebdc426SKonrad Rzeszutek Wilk 	xen_pcibk_backend = &xen_pcibk_vpci_backend;
7482ebdc426SKonrad Rzeszutek Wilk 	if (passthrough)
7492ebdc426SKonrad Rzeszutek Wilk 		xen_pcibk_backend = &xen_pcibk_passthrough_backend;
750283c0972SJoe Perches 	pr_info("backend is %s\n", xen_pcibk_backend->name);
75173db144bSJan Beulich 	return xenbus_register_backend(&xen_pcibk_driver);
75230edc14bSKonrad Rzeszutek Wilk }
75330edc14bSKonrad Rzeszutek Wilk 
xen_pcibk_xenbus_unregister(void)754a92336a1SKonrad Rzeszutek Wilk void __exit xen_pcibk_xenbus_unregister(void)
75530edc14bSKonrad Rzeszutek Wilk {
756a67efff2SOleksandr Andrushchenko 	if (xen_pcibk_pv_support())
75773db144bSJan Beulich 		xenbus_unregister_driver(&xen_pcibk_driver);
75830edc14bSKonrad Rzeszutek Wilk }
759