130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk/*
230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk * PCI Backend Xenbus Setup - handles setup with frontend and xend
330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk *
430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk */
630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk#include <linux/module.h>
730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk#include <linux/init.h>
830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk#include <linux/list.h>
930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk#include <linux/vmalloc.h>
1030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk#include <linux/workqueue.h>
1130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk#include <xen/xenbus.h>
1230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk#include <xen/events.h>
136221a9b2a11acfb54e7b41da425e961b31e88553Konrad Rzeszutek Wilk#include <asm/xen/pci.h>
1430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk#include "pciback.h"
1530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
1630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk#define INVALID_EVTCHN_IRQ  (-1)
17a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilkstruct workqueue_struct *xen_pcibk_wq;
1830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
1990ab5ee94171b3e28de6bb42ee30b527014e0be7Rusty Russellstatic bool __read_mostly passthrough;
202ebdc4263022e0015341016b123fe7f44f9cf396Konrad Rzeszutek Wilkmodule_param(passthrough, bool, S_IRUGO);
212ebdc4263022e0015341016b123fe7f44f9cf396Konrad Rzeszutek WilkMODULE_PARM_DESC(passthrough,
222ebdc4263022e0015341016b123fe7f44f9cf396Konrad Rzeszutek Wilk	"Option to specify how to export PCI topology to guest:\n"\
232ebdc4263022e0015341016b123fe7f44f9cf396Konrad Rzeszutek Wilk	" 0 - (default) Hide the true PCI topology and makes the frontend\n"\
242ebdc4263022e0015341016b123fe7f44f9cf396Konrad Rzeszutek Wilk	"   there is a single PCI bus with only the exported devices on it.\n"\
252ebdc4263022e0015341016b123fe7f44f9cf396Konrad Rzeszutek Wilk	"   For example, a device at 03:05.0 will be re-assigned to 00:00.0\n"\
262ebdc4263022e0015341016b123fe7f44f9cf396Konrad Rzeszutek Wilk	"   while second device at 02:1a.1 will be re-assigned to 00:01.1.\n"\
272ebdc4263022e0015341016b123fe7f44f9cf396Konrad Rzeszutek Wilk	" 1 - Passthrough provides a real view of the PCI topology to the\n"\
282ebdc4263022e0015341016b123fe7f44f9cf396Konrad Rzeszutek Wilk	"   frontend (for example, a device at 06:01.b will still appear at\n"\
292ebdc4263022e0015341016b123fe7f44f9cf396Konrad Rzeszutek Wilk	"   06:01.b to the frontend). This is similar to how Xen 2.0.x\n"\
302ebdc4263022e0015341016b123fe7f44f9cf396Konrad Rzeszutek Wilk	"   exposed PCI devices to its driver domains. This may be required\n"\
312ebdc4263022e0015341016b123fe7f44f9cf396Konrad Rzeszutek Wilk	"   for drivers which depend on finding their hardward in certain\n"\
322ebdc4263022e0015341016b123fe7f44f9cf396Konrad Rzeszutek Wilk	"   bus/slot locations.");
332ebdc4263022e0015341016b123fe7f44f9cf396Konrad Rzeszutek Wilk
34a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilkstatic struct xen_pcibk_device *alloc_pdev(struct xenbus_device *xdev)
3530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk{
36a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk	struct xen_pcibk_device *pdev;
3730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
38a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk	pdev = kzalloc(sizeof(struct xen_pcibk_device), GFP_KERNEL);
3930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (pdev == NULL)
4030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		goto out;
4130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	dev_dbg(&xdev->dev, "allocated pdev @ 0x%p\n", pdev);
4230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
4330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	pdev->xdev = xdev;
4430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	dev_set_drvdata(&xdev->dev, pdev);
4530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
46b1766b62890e3bba1a778a20ef8bf9348d6096c2Konrad Rzeszutek Wilk	mutex_init(&pdev->dev_lock);
4730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
4830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	pdev->sh_info = NULL;
4930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	pdev->evtchn_irq = INVALID_EVTCHN_IRQ;
5030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	pdev->be_watching = 0;
5130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
52a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk	INIT_WORK(&pdev->op_work, xen_pcibk_do_op);
5330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
54a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk	if (xen_pcibk_init_devices(pdev)) {
5530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		kfree(pdev);
5630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		pdev = NULL;
5730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	}
5830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilkout:
5930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	return pdev;
6030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk}
6130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
62a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilkstatic void xen_pcibk_disconnect(struct xen_pcibk_device *pdev)
6330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk{
64b1766b62890e3bba1a778a20ef8bf9348d6096c2Konrad Rzeszutek Wilk	mutex_lock(&pdev->dev_lock);
6530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	/* Ensure the guest can't trigger our handler before removing devices */
6630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (pdev->evtchn_irq != INVALID_EVTCHN_IRQ) {
6730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		unbind_from_irqhandler(pdev->evtchn_irq, pdev);
6830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		pdev->evtchn_irq = INVALID_EVTCHN_IRQ;
6930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	}
7030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
7130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	/* If the driver domain started an op, make sure we complete it
7230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	 * before releasing the shared memory */
73494ef20db6ea2e2ab1c3a45a1461e6e717fdcf48Konrad Rzeszutek Wilk
74494ef20db6ea2e2ab1c3a45a1461e6e717fdcf48Konrad Rzeszutek Wilk	/* Note, the workqueue does not use spinlocks at all.*/
75a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk	flush_workqueue(xen_pcibk_wq);
7630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
7730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (pdev->sh_info != NULL) {
7830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		xenbus_unmap_ring_vfree(pdev->xdev, pdev->sh_info);
7930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		pdev->sh_info = NULL;
8030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	}
81b1766b62890e3bba1a778a20ef8bf9348d6096c2Konrad Rzeszutek Wilk	mutex_unlock(&pdev->dev_lock);
8230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk}
8330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
84a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilkstatic void free_pdev(struct xen_pcibk_device *pdev)
8530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk{
86494ef20db6ea2e2ab1c3a45a1461e6e717fdcf48Konrad Rzeszutek Wilk	if (pdev->be_watching) {
8730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		unregister_xenbus_watch(&pdev->be_watch);
88494ef20db6ea2e2ab1c3a45a1461e6e717fdcf48Konrad Rzeszutek Wilk		pdev->be_watching = 0;
89494ef20db6ea2e2ab1c3a45a1461e6e717fdcf48Konrad Rzeszutek Wilk	}
9030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
91a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk	xen_pcibk_disconnect(pdev);
9230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
93a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk	xen_pcibk_release_devices(pdev);
9430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
9530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	dev_set_drvdata(&pdev->xdev->dev, NULL);
9630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	pdev->xdev = NULL;
9730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
9830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	kfree(pdev);
9930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk}
10030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
101a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilkstatic int xen_pcibk_do_attach(struct xen_pcibk_device *pdev, int gnt_ref,
10230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			     int remote_evtchn)
10330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk{
10430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	int err = 0;
10530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	void *vaddr;
10630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
10730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	dev_dbg(&pdev->xdev->dev,
10830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		"Attaching to frontend resources - gnt_ref=%d evtchn=%d\n",
10930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		gnt_ref, remote_evtchn);
11030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
11130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	err = xenbus_map_ring_valloc(pdev->xdev, gnt_ref, &vaddr);
11230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (err < 0) {
11330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		xenbus_dev_fatal(pdev->xdev, err,
11430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				"Error mapping other domain page in ours.");
11530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		goto out;
11630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	}
117494ef20db6ea2e2ab1c3a45a1461e6e717fdcf48Konrad Rzeszutek Wilk
11830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	pdev->sh_info = vaddr;
11930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
12030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	err = bind_interdomain_evtchn_to_irqhandler(
121a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk		pdev->xdev->otherend_id, remote_evtchn, xen_pcibk_handle_event,
122a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk		0, DRV_NAME, pdev);
12330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (err < 0) {
12430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		xenbus_dev_fatal(pdev->xdev, err,
12530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				 "Error binding event channel to IRQ");
12630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		goto out;
12730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	}
12830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	pdev->evtchn_irq = err;
12930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	err = 0;
13030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
13130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	dev_dbg(&pdev->xdev->dev, "Attached!\n");
13230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilkout:
13330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	return err;
13430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk}
13530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
136a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilkstatic int xen_pcibk_attach(struct xen_pcibk_device *pdev)
13730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk{
13830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	int err = 0;
13930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	int gnt_ref, remote_evtchn;
14030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	char *magic = NULL;
14130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
14230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
143b1766b62890e3bba1a778a20ef8bf9348d6096c2Konrad Rzeszutek Wilk	mutex_lock(&pdev->dev_lock);
14430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	/* Make sure we only do this setup once */
14530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (xenbus_read_driver_state(pdev->xdev->nodename) !=
14630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	    XenbusStateInitialised)
14730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		goto out;
14830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
14930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	/* Wait for frontend to state that it has published the configuration */
15030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (xenbus_read_driver_state(pdev->xdev->otherend) !=
15130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	    XenbusStateInitialised)
15230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		goto out;
15330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
15430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	dev_dbg(&pdev->xdev->dev, "Reading frontend config\n");
15530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
15630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	err = xenbus_gather(XBT_NIL, pdev->xdev->otherend,
15730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			    "pci-op-ref", "%u", &gnt_ref,
15830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			    "event-channel", "%u", &remote_evtchn,
15930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			    "magic", NULL, &magic, NULL);
16030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (err) {
16130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		/* If configuration didn't get read correctly, wait longer */
16230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		xenbus_dev_fatal(pdev->xdev, err,
16330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				 "Error reading configuration from frontend");
16430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		goto out;
16530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	}
16630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
16730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (magic == NULL || strcmp(magic, XEN_PCI_MAGIC) != 0) {
16830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		xenbus_dev_fatal(pdev->xdev, -EFAULT,
16930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				 "version mismatch (%s/%s) with pcifront - "
170402c5e15b44070461dcc2f41536c16d0cfbca9c3Jan Beulich				 "halting " DRV_NAME,
17130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				 magic, XEN_PCI_MAGIC);
17230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		goto out;
17330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	}
17430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
175a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk	err = xen_pcibk_do_attach(pdev, gnt_ref, remote_evtchn);
17630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (err)
17730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		goto out;
17830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
17930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	dev_dbg(&pdev->xdev->dev, "Connecting...\n");
18030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
18130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	err = xenbus_switch_state(pdev->xdev, XenbusStateConnected);
18230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (err)
18330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		xenbus_dev_fatal(pdev->xdev, err,
18430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				 "Error switching to connected state!");
18530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
18630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	dev_dbg(&pdev->xdev->dev, "Connected? %d\n", err);
18730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilkout:
188b1766b62890e3bba1a778a20ef8bf9348d6096c2Konrad Rzeszutek Wilk	mutex_unlock(&pdev->dev_lock);
18930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
19030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	kfree(magic);
19130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
19230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	return err;
19330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk}
19430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
195a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilkstatic int xen_pcibk_publish_pci_dev(struct xen_pcibk_device *pdev,
19630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				   unsigned int domain, unsigned int bus,
19730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				   unsigned int devfn, unsigned int devid)
19830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk{
19930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	int err;
20030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	int len;
20130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	char str[64];
20230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
20330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	len = snprintf(str, sizeof(str), "vdev-%d", devid);
20430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (unlikely(len >= (sizeof(str) - 1))) {
20530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		err = -ENOMEM;
20630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		goto out;
20730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	}
20830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
209e4de866a834620ef974f5ba86d394a13d2f0cf66Konrad Rzeszutek Wilk	/* Note: The PV protocol uses %02x, don't change it */
21030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, str,
21130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			    "%04x:%02x:%02x.%02x", domain, bus,
21230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			    PCI_SLOT(devfn), PCI_FUNC(devfn));
21330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
21430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilkout:
21530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	return err;
21630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk}
21730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
218a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilkstatic int xen_pcibk_export_device(struct xen_pcibk_device *pdev,
21930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				 int domain, int bus, int slot, int func,
22030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				 int devid)
22130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk{
22230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	struct pci_dev *dev;
22330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	int err = 0;
22430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
22530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	dev_dbg(&pdev->xdev->dev, "exporting dom %x bus %x slot %x func %x\n",
22630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		domain, bus, slot, func);
22730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
22830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	dev = pcistub_get_pci_dev_by_slot(pdev, domain, bus, slot, func);
22930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (!dev) {
23030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		err = -EINVAL;
23130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		xenbus_dev_fatal(pdev->xdev, err,
23230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				 "Couldn't locate PCI device "
233e4de866a834620ef974f5ba86d394a13d2f0cf66Konrad Rzeszutek Wilk				 "(%04x:%02x:%02x.%d)! "
23430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				 "perhaps already in-use?",
23530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				 domain, bus, slot, func);
23630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		goto out;
23730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	}
23830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
239a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk	err = xen_pcibk_add_pci_dev(pdev, dev, devid,
240a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk				    xen_pcibk_publish_pci_dev);
24130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (err)
24230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		goto out;
24330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
2446221a9b2a11acfb54e7b41da425e961b31e88553Konrad Rzeszutek Wilk	dev_dbg(&dev->dev, "registering for %d\n", pdev->xdev->otherend_id);
2456221a9b2a11acfb54e7b41da425e961b31e88553Konrad Rzeszutek Wilk	if (xen_register_device_domain_owner(dev,
2466221a9b2a11acfb54e7b41da425e961b31e88553Konrad Rzeszutek Wilk					     pdev->xdev->otherend_id) != 0) {
2476c254de16a1d14c1ac931d3aa08dc88ac9fc582bKonrad Rzeszutek Wilk		dev_err(&dev->dev, "Stealing ownership from dom%d.\n",
2486c254de16a1d14c1ac931d3aa08dc88ac9fc582bKonrad Rzeszutek Wilk			xen_find_device_domain_owner(dev));
2496221a9b2a11acfb54e7b41da425e961b31e88553Konrad Rzeszutek Wilk		xen_unregister_device_domain_owner(dev);
2506221a9b2a11acfb54e7b41da425e961b31e88553Konrad Rzeszutek Wilk		xen_register_device_domain_owner(dev, pdev->xdev->otherend_id);
2516221a9b2a11acfb54e7b41da425e961b31e88553Konrad Rzeszutek Wilk	}
2526221a9b2a11acfb54e7b41da425e961b31e88553Konrad Rzeszutek Wilk
25330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	/* TODO: It'd be nice to export a bridge and have all of its children
25430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	 * get exported with it. This may be best done in xend (which will
25530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	 * have to calculate resource usage anyway) but we probably want to
25630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	 * put something in here to ensure that if a bridge gets given to a
25730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	 * driver domain, that all devices under that bridge are not given
25830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	 * to other driver domains (as he who controls the bridge can disable
25930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	 * it and stop the other devices from working).
26030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	 */
26130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilkout:
26230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	return err;
26330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk}
26430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
265a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilkstatic int xen_pcibk_remove_device(struct xen_pcibk_device *pdev,
26630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				 int domain, int bus, int slot, int func)
26730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk{
26830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	int err = 0;
26930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	struct pci_dev *dev;
27030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
27130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	dev_dbg(&pdev->xdev->dev, "removing dom %x bus %x slot %x func %x\n",
27230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		domain, bus, slot, func);
27330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
274a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk	dev = xen_pcibk_get_pci_dev(pdev, domain, bus, PCI_DEVFN(slot, func));
27530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (!dev) {
27630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		err = -EINVAL;
27730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		dev_dbg(&pdev->xdev->dev, "Couldn't locate PCI device "
278e4de866a834620ef974f5ba86d394a13d2f0cf66Konrad Rzeszutek Wilk			"(%04x:%02x:%02x.%d)! not owned by this domain\n",
27930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			domain, bus, slot, func);
28030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		goto out;
28130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	}
28230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
2836221a9b2a11acfb54e7b41da425e961b31e88553Konrad Rzeszutek Wilk	dev_dbg(&dev->dev, "unregistering for %d\n", pdev->xdev->otherend_id);
2846221a9b2a11acfb54e7b41da425e961b31e88553Konrad Rzeszutek Wilk	xen_unregister_device_domain_owner(dev);
2856221a9b2a11acfb54e7b41da425e961b31e88553Konrad Rzeszutek Wilk
286a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk	xen_pcibk_release_pci_dev(pdev, dev);
28730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
28830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilkout:
28930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	return err;
29030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk}
29130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
292a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilkstatic int xen_pcibk_publish_pci_root(struct xen_pcibk_device *pdev,
29330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				    unsigned int domain, unsigned int bus)
29430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk{
29530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	unsigned int d, b;
29630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	int i, root_num, len, err;
29730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	char str[64];
29830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
29930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	dev_dbg(&pdev->xdev->dev, "Publishing pci roots\n");
30030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
30130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename,
30230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			   "root_num", "%d", &root_num);
30330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (err == 0 || err == -ENOENT)
30430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		root_num = 0;
30530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	else if (err < 0)
30630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		goto out;
30730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
30830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	/* Verify that we haven't already published this pci root */
30930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	for (i = 0; i < root_num; i++) {
31030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		len = snprintf(str, sizeof(str), "root-%d", i);
31130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		if (unlikely(len >= (sizeof(str) - 1))) {
31230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			err = -ENOMEM;
31330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			goto out;
31430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		}
31530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
31630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename,
31730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				   str, "%x:%x", &d, &b);
31830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		if (err < 0)
31930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			goto out;
32030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		if (err != 2) {
32130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			err = -EINVAL;
32230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			goto out;
32330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		}
32430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
32530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		if (d == domain && b == bus) {
32630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			err = 0;
32730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			goto out;
32830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		}
32930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	}
33030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
33130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	len = snprintf(str, sizeof(str), "root-%d", root_num);
33230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (unlikely(len >= (sizeof(str) - 1))) {
33330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		err = -ENOMEM;
33430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		goto out;
33530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	}
33630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
33730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	dev_dbg(&pdev->xdev->dev, "writing root %d at %04x:%02x\n",
33830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		root_num, domain, bus);
33930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
34030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, str,
34130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			    "%04x:%02x", domain, bus);
34230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (err)
34330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		goto out;
34430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
34530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	err = xenbus_printf(XBT_NIL, pdev->xdev->nodename,
34630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			    "root_num", "%d", (root_num + 1));
34730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
34830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilkout:
34930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	return err;
35030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk}
35130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
352a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilkstatic int xen_pcibk_reconfigure(struct xen_pcibk_device *pdev)
35330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk{
35430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	int err = 0;
35530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	int num_devs;
35630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	int domain, bus, slot, func;
35730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	int substate;
35830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	int i, len;
35930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	char state_str[64];
36030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	char dev_str[64];
36130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
36230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
36330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	dev_dbg(&pdev->xdev->dev, "Reconfiguring device ...\n");
36430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
365b1766b62890e3bba1a778a20ef8bf9348d6096c2Konrad Rzeszutek Wilk	mutex_lock(&pdev->dev_lock);
36630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	/* Make sure we only reconfigure once */
36730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (xenbus_read_driver_state(pdev->xdev->nodename) !=
36830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	    XenbusStateReconfiguring)
36930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		goto out;
37030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
37130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, "num_devs", "%d",
37230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			   &num_devs);
37330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (err != 1) {
37430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		if (err >= 0)
37530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			err = -EINVAL;
37630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		xenbus_dev_fatal(pdev->xdev, err,
37730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				 "Error reading number of devices");
37830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		goto out;
37930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	}
38030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
38130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	for (i = 0; i < num_devs; i++) {
38230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		len = snprintf(state_str, sizeof(state_str), "state-%d", i);
38330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		if (unlikely(len >= (sizeof(state_str) - 1))) {
38430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			err = -ENOMEM;
38530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			xenbus_dev_fatal(pdev->xdev, err,
38630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk					 "String overflow while reading "
38730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk					 "configuration");
38830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			goto out;
38930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		}
39030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, state_str,
39130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				   "%d", &substate);
39230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		if (err != 1)
39330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			substate = XenbusStateUnknown;
39430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
39530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		switch (substate) {
39630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		case XenbusStateInitialising:
39730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			dev_dbg(&pdev->xdev->dev, "Attaching dev-%d ...\n", i);
39830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
39930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			len = snprintf(dev_str, sizeof(dev_str), "dev-%d", i);
40030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			if (unlikely(len >= (sizeof(dev_str) - 1))) {
40130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				err = -ENOMEM;
40230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				xenbus_dev_fatal(pdev->xdev, err,
40330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk						 "String overflow while "
40430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk						 "reading configuration");
40530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				goto out;
40630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			}
40730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename,
40830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk					   dev_str, "%x:%x:%x.%x",
40930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk					   &domain, &bus, &slot, &func);
41030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			if (err < 0) {
41130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				xenbus_dev_fatal(pdev->xdev, err,
41230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk						 "Error reading device "
41330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk						 "configuration");
41430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				goto out;
41530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			}
41630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			if (err != 4) {
41730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				err = -EINVAL;
41830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				xenbus_dev_fatal(pdev->xdev, err,
41930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk						 "Error parsing pci device "
42030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk						 "configuration");
42130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				goto out;
42230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			}
42330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
424a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk			err = xen_pcibk_export_device(pdev, domain, bus, slot,
42530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk						    func, i);
42630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			if (err)
42730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				goto out;
42830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
42930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			/* Publish pci roots. */
430a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk			err = xen_pcibk_publish_pci_roots(pdev,
431a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk						xen_pcibk_publish_pci_root);
43230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			if (err) {
43330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				xenbus_dev_fatal(pdev->xdev, err,
43430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk						 "Error while publish PCI root"
43530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk						 "buses for frontend");
43630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				goto out;
43730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			}
43830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
43930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			err = xenbus_printf(XBT_NIL, pdev->xdev->nodename,
44030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk					    state_str, "%d",
44130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk					    XenbusStateInitialised);
44230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			if (err) {
44330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				xenbus_dev_fatal(pdev->xdev, err,
44430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk						 "Error switching substate of "
44530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk						 "dev-%d\n", i);
44630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				goto out;
44730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			}
44830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			break;
44930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
45030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		case XenbusStateClosing:
45130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			dev_dbg(&pdev->xdev->dev, "Detaching dev-%d ...\n", i);
45230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
45330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			len = snprintf(dev_str, sizeof(dev_str), "vdev-%d", i);
45430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			if (unlikely(len >= (sizeof(dev_str) - 1))) {
45530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				err = -ENOMEM;
45630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				xenbus_dev_fatal(pdev->xdev, err,
45730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk						 "String overflow while "
45830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk						 "reading configuration");
45930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				goto out;
46030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			}
46130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename,
46230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk					   dev_str, "%x:%x:%x.%x",
46330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk					   &domain, &bus, &slot, &func);
46430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			if (err < 0) {
46530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				xenbus_dev_fatal(pdev->xdev, err,
46630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk						 "Error reading device "
46730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk						 "configuration");
46830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				goto out;
46930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			}
47030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			if (err != 4) {
47130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				err = -EINVAL;
47230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				xenbus_dev_fatal(pdev->xdev, err,
47330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk						 "Error parsing pci device "
47430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk						 "configuration");
47530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				goto out;
47630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			}
47730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
478a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk			err = xen_pcibk_remove_device(pdev, domain, bus, slot,
47930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk						    func);
48030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			if (err)
48130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				goto out;
48230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
48330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			/* TODO: If at some point we implement support for pci
48430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			 * root hot-remove on pcifront side, we'll need to
48530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			 * remove unnecessary xenstore nodes of pci roots here.
48630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			 */
48730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
48830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			break;
48930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
49030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		default:
49130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			break;
49230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		}
49330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	}
49430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
49530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	err = xenbus_switch_state(pdev->xdev, XenbusStateReconfigured);
49630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (err) {
49730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		xenbus_dev_fatal(pdev->xdev, err,
49830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				 "Error switching to reconfigured state!");
49930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		goto out;
50030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	}
50130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
50230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilkout:
503b1766b62890e3bba1a778a20ef8bf9348d6096c2Konrad Rzeszutek Wilk	mutex_unlock(&pdev->dev_lock);
50430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	return 0;
50530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk}
50630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
507a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilkstatic void xen_pcibk_frontend_changed(struct xenbus_device *xdev,
50830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				     enum xenbus_state fe_state)
50930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk{
510a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk	struct xen_pcibk_device *pdev = dev_get_drvdata(&xdev->dev);
51130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
51230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	dev_dbg(&xdev->dev, "fe state changed %d\n", fe_state);
51330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
51430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	switch (fe_state) {
51530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	case XenbusStateInitialised:
516a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk		xen_pcibk_attach(pdev);
51730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		break;
51830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
51930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	case XenbusStateReconfiguring:
520a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk		xen_pcibk_reconfigure(pdev);
52130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		break;
52230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
52330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	case XenbusStateConnected:
52430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		/* pcifront switched its state from reconfiguring to connected.
52530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		 * Then switch to connected state.
52630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		 */
52730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		xenbus_switch_state(xdev, XenbusStateConnected);
52830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		break;
52930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
53030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	case XenbusStateClosing:
531a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk		xen_pcibk_disconnect(pdev);
53230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		xenbus_switch_state(xdev, XenbusStateClosing);
53330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		break;
53430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
53530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	case XenbusStateClosed:
536a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk		xen_pcibk_disconnect(pdev);
53730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		xenbus_switch_state(xdev, XenbusStateClosed);
53830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		if (xenbus_dev_is_online(xdev))
53930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			break;
54030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		/* fall through if not online */
54130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	case XenbusStateUnknown:
54230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		dev_dbg(&xdev->dev, "frontend is gone! unregister device\n");
54330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		device_unregister(&xdev->dev);
54430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		break;
54530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
54630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	default:
54730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		break;
54830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	}
54930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk}
55030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
551a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilkstatic int xen_pcibk_setup_backend(struct xen_pcibk_device *pdev)
55230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk{
55330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	/* Get configuration from xend (if available now) */
55430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	int domain, bus, slot, func;
55530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	int err = 0;
55630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	int i, num_devs;
55730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	char dev_str[64];
55830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	char state_str[64];
55930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
560b1766b62890e3bba1a778a20ef8bf9348d6096c2Konrad Rzeszutek Wilk	mutex_lock(&pdev->dev_lock);
56130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	/* It's possible we could get the call to setup twice, so make sure
56230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	 * we're not already connected.
56330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	 */
56430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (xenbus_read_driver_state(pdev->xdev->nodename) !=
56530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	    XenbusStateInitWait)
56630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		goto out;
56730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
56830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	dev_dbg(&pdev->xdev->dev, "getting be setup\n");
56930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
57030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, "num_devs", "%d",
57130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			   &num_devs);
57230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (err != 1) {
57330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		if (err >= 0)
57430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			err = -EINVAL;
57530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		xenbus_dev_fatal(pdev->xdev, err,
57630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				 "Error reading number of devices");
57730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		goto out;
57830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	}
57930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
58030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	for (i = 0; i < num_devs; i++) {
58130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		int l = snprintf(dev_str, sizeof(dev_str), "dev-%d", i);
58230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		if (unlikely(l >= (sizeof(dev_str) - 1))) {
58330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			err = -ENOMEM;
58430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			xenbus_dev_fatal(pdev->xdev, err,
58530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk					 "String overflow while reading "
58630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk					 "configuration");
58730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			goto out;
58830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		}
58930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
59030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, dev_str,
59130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				   "%x:%x:%x.%x", &domain, &bus, &slot, &func);
59230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		if (err < 0) {
59330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			xenbus_dev_fatal(pdev->xdev, err,
59430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk					 "Error reading device configuration");
59530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			goto out;
59630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		}
59730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		if (err != 4) {
59830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			err = -EINVAL;
59930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			xenbus_dev_fatal(pdev->xdev, err,
60030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk					 "Error parsing pci device "
60130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk					 "configuration");
60230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			goto out;
60330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		}
60430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
605a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk		err = xen_pcibk_export_device(pdev, domain, bus, slot, func, i);
60630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		if (err)
60730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			goto out;
60830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
60930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		/* Switch substate of this device. */
61030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		l = snprintf(state_str, sizeof(state_str), "state-%d", i);
61130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		if (unlikely(l >= (sizeof(state_str) - 1))) {
61230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			err = -ENOMEM;
61330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			xenbus_dev_fatal(pdev->xdev, err,
61430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk					 "String overflow while reading "
61530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk					 "configuration");
61630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			goto out;
61730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		}
61830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, state_str,
61930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				    "%d", XenbusStateInitialised);
62030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		if (err) {
62130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			xenbus_dev_fatal(pdev->xdev, err, "Error switching "
62230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk					 "substate of dev-%d\n", i);
62330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			goto out;
62430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		}
62530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	}
62630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
627a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk	err = xen_pcibk_publish_pci_roots(pdev, xen_pcibk_publish_pci_root);
62830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (err) {
62930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		xenbus_dev_fatal(pdev->xdev, err,
63030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				 "Error while publish PCI root buses "
63130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				 "for frontend");
63230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		goto out;
63330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	}
63430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
63530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	err = xenbus_switch_state(pdev->xdev, XenbusStateInitialised);
63630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (err)
63730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		xenbus_dev_fatal(pdev->xdev, err,
63830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				 "Error switching to initialised state!");
63930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
64030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilkout:
641b1766b62890e3bba1a778a20ef8bf9348d6096c2Konrad Rzeszutek Wilk	mutex_unlock(&pdev->dev_lock);
64230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (!err)
64330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		/* see if pcifront is already configured (if not, we'll wait) */
644a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk		xen_pcibk_attach(pdev);
64530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	return err;
64630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk}
64730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
648a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilkstatic void xen_pcibk_be_watch(struct xenbus_watch *watch,
64930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			     const char **vec, unsigned int len)
65030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk{
651a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk	struct xen_pcibk_device *pdev =
652a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk	    container_of(watch, struct xen_pcibk_device, be_watch);
65330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
65430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	switch (xenbus_read_driver_state(pdev->xdev->nodename)) {
65530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	case XenbusStateInitWait:
656a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk		xen_pcibk_setup_backend(pdev);
65730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		break;
65830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
65930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	default:
66030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		break;
66130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	}
66230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk}
66330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
664a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilkstatic int xen_pcibk_xenbus_probe(struct xenbus_device *dev,
66530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				const struct xenbus_device_id *id)
66630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk{
66730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	int err = 0;
668a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk	struct xen_pcibk_device *pdev = alloc_pdev(dev);
66930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
67030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (pdev == NULL) {
67130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		err = -ENOMEM;
67230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		xenbus_dev_fatal(dev, err,
673a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk				 "Error allocating xen_pcibk_device struct");
67430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		goto out;
67530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	}
67630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
67730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	/* wait for xend to configure us */
67830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	err = xenbus_switch_state(dev, XenbusStateInitWait);
67930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (err)
68030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		goto out;
68130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
68230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	/* watch the backend node for backend configuration information */
68330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	err = xenbus_watch_path(dev, dev->nodename, &pdev->be_watch,
684a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk				xen_pcibk_be_watch);
68530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (err)
68630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		goto out;
687494ef20db6ea2e2ab1c3a45a1461e6e717fdcf48Konrad Rzeszutek Wilk
68830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	pdev->be_watching = 1;
68930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
69030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	/* We need to force a call to our callback here in case
69130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	 * xend already configured us!
69230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	 */
693a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk	xen_pcibk_be_watch(&pdev->be_watch, NULL, 0);
69430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
69530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilkout:
69630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	return err;
69730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk}
69830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
699a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilkstatic int xen_pcibk_xenbus_remove(struct xenbus_device *dev)
70030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk{
701a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk	struct xen_pcibk_device *pdev = dev_get_drvdata(&dev->dev);
70230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
70330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (pdev != NULL)
70430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		free_pdev(pdev);
70530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
70630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	return 0;
70730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk}
70830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
70973db144b58a32fc39733db6a7e1fe582072ad26aJan Beulichstatic const struct xenbus_device_id xen_pcibk_ids[] = {
71030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	{"pci"},
71130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	{""},
71230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk};
71330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
71473db144b58a32fc39733db6a7e1fe582072ad26aJan Beulichstatic DEFINE_XENBUS_DRIVER(xen_pcibk, DRV_NAME,
715a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk	.probe			= xen_pcibk_xenbus_probe,
716a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk	.remove			= xen_pcibk_xenbus_remove,
717a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk	.otherend_changed	= xen_pcibk_frontend_changed,
71873db144b58a32fc39733db6a7e1fe582072ad26aJan Beulich);
71930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
720402c5e15b44070461dcc2f41536c16d0cfbca9c3Jan Beulichconst struct xen_pcibk_backend *__read_mostly xen_pcibk_backend;
7212ebdc4263022e0015341016b123fe7f44f9cf396Konrad Rzeszutek Wilk
722a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilkint __init xen_pcibk_xenbus_register(void)
72330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk{
724a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk	xen_pcibk_wq = create_workqueue("xen_pciback_workqueue");
725a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk	if (!xen_pcibk_wq) {
7268bfd4e023f5fb5793d7d7483b6e17e04933c53e9Konrad Rzeszutek Wilk		printk(KERN_ERR "%s: create"
727a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk			"xen_pciback_workqueue failed\n", __func__);
72830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		return -EFAULT;
72930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	}
7302ebdc4263022e0015341016b123fe7f44f9cf396Konrad Rzeszutek Wilk	xen_pcibk_backend = &xen_pcibk_vpci_backend;
7312ebdc4263022e0015341016b123fe7f44f9cf396Konrad Rzeszutek Wilk	if (passthrough)
7322ebdc4263022e0015341016b123fe7f44f9cf396Konrad Rzeszutek Wilk		xen_pcibk_backend = &xen_pcibk_passthrough_backend;
7332ebdc4263022e0015341016b123fe7f44f9cf396Konrad Rzeszutek Wilk	pr_info(DRV_NAME ": backend is %s\n", xen_pcibk_backend->name);
73473db144b58a32fc39733db6a7e1fe582072ad26aJan Beulich	return xenbus_register_backend(&xen_pcibk_driver);
73530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk}
73630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
737a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilkvoid __exit xen_pcibk_xenbus_unregister(void)
73830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk{
739a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk	destroy_workqueue(xen_pcibk_wq);
74073db144b58a32fc39733db6a7e1fe582072ad26aJan Beulich	xenbus_unregister_driver(&xen_pcibk_driver);
74130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk}
742