xenbus.c revision a92336a1176b2119eaa990a1e8bf3109665fdbc6
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 <linux/workqueue.h>
1530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk#include "pciback.h"
1630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
17a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk#define	DRV_NAME	"xen-pciback"
1830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk#define INVALID_EVTCHN_IRQ  (-1)
19a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilkstruct workqueue_struct *xen_pcibk_wq;
2030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
21a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilkstatic struct xen_pcibk_device *alloc_pdev(struct xenbus_device *xdev)
2230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk{
23a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk	struct xen_pcibk_device *pdev;
2430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
25a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk	pdev = kzalloc(sizeof(struct xen_pcibk_device), GFP_KERNEL);
2630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (pdev == NULL)
2730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		goto out;
2830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	dev_dbg(&xdev->dev, "allocated pdev @ 0x%p\n", pdev);
2930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
3030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	pdev->xdev = xdev;
3130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	dev_set_drvdata(&xdev->dev, pdev);
3230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
3330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	spin_lock_init(&pdev->dev_lock);
3430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
3530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	pdev->sh_info = NULL;
3630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	pdev->evtchn_irq = INVALID_EVTCHN_IRQ;
3730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	pdev->be_watching = 0;
3830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
39a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk	INIT_WORK(&pdev->op_work, xen_pcibk_do_op);
4030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
41a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk	if (xen_pcibk_init_devices(pdev)) {
4230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		kfree(pdev);
4330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		pdev = NULL;
4430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	}
4530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilkout:
4630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	return pdev;
4730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk}
4830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
49a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilkstatic void xen_pcibk_disconnect(struct xen_pcibk_device *pdev)
5030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk{
5130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	spin_lock(&pdev->dev_lock);
5230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
5330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	/* Ensure the guest can't trigger our handler before removing devices */
5430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (pdev->evtchn_irq != INVALID_EVTCHN_IRQ) {
5530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		unbind_from_irqhandler(pdev->evtchn_irq, pdev);
5630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		pdev->evtchn_irq = INVALID_EVTCHN_IRQ;
5730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	}
58494ef20db6ea2e2ab1c3a45a1461e6e717fdcf48Konrad Rzeszutek Wilk	spin_unlock(&pdev->dev_lock);
5930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
6030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	/* If the driver domain started an op, make sure we complete it
6130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	 * before releasing the shared memory */
62494ef20db6ea2e2ab1c3a45a1461e6e717fdcf48Konrad Rzeszutek Wilk
63494ef20db6ea2e2ab1c3a45a1461e6e717fdcf48Konrad Rzeszutek Wilk	/* Note, the workqueue does not use spinlocks at all.*/
64a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk	flush_workqueue(xen_pcibk_wq);
6530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
66494ef20db6ea2e2ab1c3a45a1461e6e717fdcf48Konrad Rzeszutek Wilk	spin_lock(&pdev->dev_lock);
6730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (pdev->sh_info != NULL) {
6830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		xenbus_unmap_ring_vfree(pdev->xdev, pdev->sh_info);
6930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		pdev->sh_info = NULL;
7030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	}
7130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	spin_unlock(&pdev->dev_lock);
72494ef20db6ea2e2ab1c3a45a1461e6e717fdcf48Konrad Rzeszutek Wilk
7330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk}
7430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
75a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilkstatic void free_pdev(struct xen_pcibk_device *pdev)
7630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk{
77494ef20db6ea2e2ab1c3a45a1461e6e717fdcf48Konrad Rzeszutek Wilk	if (pdev->be_watching) {
7830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		unregister_xenbus_watch(&pdev->be_watch);
79494ef20db6ea2e2ab1c3a45a1461e6e717fdcf48Konrad Rzeszutek Wilk		pdev->be_watching = 0;
80494ef20db6ea2e2ab1c3a45a1461e6e717fdcf48Konrad Rzeszutek Wilk	}
8130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
82a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk	xen_pcibk_disconnect(pdev);
8330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
84a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk	xen_pcibk_release_devices(pdev);
8530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
8630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	dev_set_drvdata(&pdev->xdev->dev, NULL);
8730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	pdev->xdev = NULL;
8830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
8930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	kfree(pdev);
9030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk}
9130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
92a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilkstatic int xen_pcibk_do_attach(struct xen_pcibk_device *pdev, int gnt_ref,
9330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			     int remote_evtchn)
9430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk{
9530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	int err = 0;
9630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	void *vaddr;
9730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
9830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	dev_dbg(&pdev->xdev->dev,
9930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		"Attaching to frontend resources - gnt_ref=%d evtchn=%d\n",
10030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		gnt_ref, remote_evtchn);
10130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
10230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	err = xenbus_map_ring_valloc(pdev->xdev, gnt_ref, &vaddr);
10330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (err < 0) {
10430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		xenbus_dev_fatal(pdev->xdev, err,
10530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				"Error mapping other domain page in ours.");
10630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		goto out;
10730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	}
108494ef20db6ea2e2ab1c3a45a1461e6e717fdcf48Konrad Rzeszutek Wilk
109494ef20db6ea2e2ab1c3a45a1461e6e717fdcf48Konrad Rzeszutek Wilk	spin_lock(&pdev->dev_lock);
11030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	pdev->sh_info = vaddr;
111494ef20db6ea2e2ab1c3a45a1461e6e717fdcf48Konrad Rzeszutek Wilk	spin_unlock(&pdev->dev_lock);
11230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
11330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	err = bind_interdomain_evtchn_to_irqhandler(
114a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk		pdev->xdev->otherend_id, remote_evtchn, xen_pcibk_handle_event,
115a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk		0, DRV_NAME, pdev);
11630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (err < 0) {
11730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		xenbus_dev_fatal(pdev->xdev, err,
11830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				 "Error binding event channel to IRQ");
11930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		goto out;
12030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	}
121494ef20db6ea2e2ab1c3a45a1461e6e717fdcf48Konrad Rzeszutek Wilk
122494ef20db6ea2e2ab1c3a45a1461e6e717fdcf48Konrad Rzeszutek Wilk	spin_lock(&pdev->dev_lock);
12330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	pdev->evtchn_irq = err;
124494ef20db6ea2e2ab1c3a45a1461e6e717fdcf48Konrad Rzeszutek Wilk	spin_unlock(&pdev->dev_lock);
12530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	err = 0;
12630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
12730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	dev_dbg(&pdev->xdev->dev, "Attached!\n");
12830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilkout:
12930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	return err;
13030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk}
13130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
132a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilkstatic int xen_pcibk_attach(struct xen_pcibk_device *pdev)
13330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk{
13430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	int err = 0;
13530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	int gnt_ref, remote_evtchn;
13630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	char *magic = NULL;
13730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
13830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
13930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	/* Make sure we only do this setup once */
14030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (xenbus_read_driver_state(pdev->xdev->nodename) !=
14130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	    XenbusStateInitialised)
14230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		goto out;
14330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
14430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	/* Wait for frontend to state that it has published the configuration */
14530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (xenbus_read_driver_state(pdev->xdev->otherend) !=
14630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	    XenbusStateInitialised)
14730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		goto out;
14830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
14930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	dev_dbg(&pdev->xdev->dev, "Reading frontend config\n");
15030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
15130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	err = xenbus_gather(XBT_NIL, pdev->xdev->otherend,
15230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			    "pci-op-ref", "%u", &gnt_ref,
15330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			    "event-channel", "%u", &remote_evtchn,
15430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			    "magic", NULL, &magic, NULL);
15530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (err) {
15630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		/* If configuration didn't get read correctly, wait longer */
15730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		xenbus_dev_fatal(pdev->xdev, err,
15830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				 "Error reading configuration from frontend");
15930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		goto out;
16030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	}
16130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
16230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (magic == NULL || strcmp(magic, XEN_PCI_MAGIC) != 0) {
16330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		xenbus_dev_fatal(pdev->xdev, -EFAULT,
16430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				 "version mismatch (%s/%s) with pcifront - "
165a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk				 "halting xen_pcibk",
16630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				 magic, XEN_PCI_MAGIC);
16730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		goto out;
16830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	}
16930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
170a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk	err = xen_pcibk_do_attach(pdev, gnt_ref, remote_evtchn);
17130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (err)
17230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		goto out;
17330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
17430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	dev_dbg(&pdev->xdev->dev, "Connecting...\n");
17530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
17630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	err = xenbus_switch_state(pdev->xdev, XenbusStateConnected);
17730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (err)
17830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		xenbus_dev_fatal(pdev->xdev, err,
17930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				 "Error switching to connected state!");
18030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
18130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	dev_dbg(&pdev->xdev->dev, "Connected? %d\n", err);
18230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilkout:
18330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
18430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	kfree(magic);
18530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
18630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	return err;
18730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk}
18830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
189a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilkstatic int xen_pcibk_publish_pci_dev(struct xen_pcibk_device *pdev,
19030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				   unsigned int domain, unsigned int bus,
19130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				   unsigned int devfn, unsigned int devid)
19230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk{
19330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	int err;
19430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	int len;
19530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	char str[64];
19630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
19730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	len = snprintf(str, sizeof(str), "vdev-%d", devid);
19830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (unlikely(len >= (sizeof(str) - 1))) {
19930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		err = -ENOMEM;
20030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		goto out;
20130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	}
20230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
20330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, str,
20430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			    "%04x:%02x:%02x.%02x", domain, bus,
20530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			    PCI_SLOT(devfn), PCI_FUNC(devfn));
20630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
20730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilkout:
20830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	return err;
20930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk}
21030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
211a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilkstatic int xen_pcibk_export_device(struct xen_pcibk_device *pdev,
21230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				 int domain, int bus, int slot, int func,
21330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				 int devid)
21430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk{
21530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	struct pci_dev *dev;
21630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	int err = 0;
21730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
21830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	dev_dbg(&pdev->xdev->dev, "exporting dom %x bus %x slot %x func %x\n",
21930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		domain, bus, slot, func);
22030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
22130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	dev = pcistub_get_pci_dev_by_slot(pdev, domain, bus, slot, func);
22230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (!dev) {
22330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		err = -EINVAL;
22430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		xenbus_dev_fatal(pdev->xdev, err,
22530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				 "Couldn't locate PCI device "
22630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				 "(%04x:%02x:%02x.%01x)! "
22730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				 "perhaps already in-use?",
22830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				 domain, bus, slot, func);
22930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		goto out;
23030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	}
23130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
232a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk	err = xen_pcibk_add_pci_dev(pdev, dev, devid,
233a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk				    xen_pcibk_publish_pci_dev);
23430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (err)
23530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		goto out;
23630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
2376221a9b2a11acfb54e7b41da425e961b31e88553Konrad Rzeszutek Wilk	dev_dbg(&dev->dev, "registering for %d\n", pdev->xdev->otherend_id);
2386221a9b2a11acfb54e7b41da425e961b31e88553Konrad Rzeszutek Wilk	if (xen_register_device_domain_owner(dev,
2396221a9b2a11acfb54e7b41da425e961b31e88553Konrad Rzeszutek Wilk					     pdev->xdev->otherend_id) != 0) {
2406221a9b2a11acfb54e7b41da425e961b31e88553Konrad Rzeszutek Wilk		dev_err(&dev->dev, "device has been assigned to another " \
2416221a9b2a11acfb54e7b41da425e961b31e88553Konrad Rzeszutek Wilk			"domain! Over-writting the ownership, but beware.\n");
2426221a9b2a11acfb54e7b41da425e961b31e88553Konrad Rzeszutek Wilk		xen_unregister_device_domain_owner(dev);
2436221a9b2a11acfb54e7b41da425e961b31e88553Konrad Rzeszutek Wilk		xen_register_device_domain_owner(dev, pdev->xdev->otherend_id);
2446221a9b2a11acfb54e7b41da425e961b31e88553Konrad Rzeszutek Wilk	}
2456221a9b2a11acfb54e7b41da425e961b31e88553Konrad Rzeszutek Wilk
24630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	/* TODO: It'd be nice to export a bridge and have all of its children
24730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	 * get exported with it. This may be best done in xend (which will
24830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	 * have to calculate resource usage anyway) but we probably want to
24930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	 * put something in here to ensure that if a bridge gets given to a
25030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	 * driver domain, that all devices under that bridge are not given
25130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	 * to other driver domains (as he who controls the bridge can disable
25230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	 * it and stop the other devices from working).
25330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	 */
25430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilkout:
25530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	return err;
25630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk}
25730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
258a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilkstatic int xen_pcibk_remove_device(struct xen_pcibk_device *pdev,
25930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				 int domain, int bus, int slot, int func)
26030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk{
26130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	int err = 0;
26230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	struct pci_dev *dev;
26330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
26430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	dev_dbg(&pdev->xdev->dev, "removing dom %x bus %x slot %x func %x\n",
26530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		domain, bus, slot, func);
26630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
267a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk	dev = xen_pcibk_get_pci_dev(pdev, domain, bus, PCI_DEVFN(slot, func));
26830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (!dev) {
26930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		err = -EINVAL;
27030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		dev_dbg(&pdev->xdev->dev, "Couldn't locate PCI device "
27130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			"(%04x:%02x:%02x.%01x)! not owned by this domain\n",
27230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			domain, bus, slot, func);
27330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		goto out;
27430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	}
27530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
2766221a9b2a11acfb54e7b41da425e961b31e88553Konrad Rzeszutek Wilk	dev_dbg(&dev->dev, "unregistering for %d\n", pdev->xdev->otherend_id);
2776221a9b2a11acfb54e7b41da425e961b31e88553Konrad Rzeszutek Wilk	xen_unregister_device_domain_owner(dev);
2786221a9b2a11acfb54e7b41da425e961b31e88553Konrad Rzeszutek Wilk
279a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk	xen_pcibk_release_pci_dev(pdev, dev);
28030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
28130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilkout:
28230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	return err;
28330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk}
28430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
285a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilkstatic int xen_pcibk_publish_pci_root(struct xen_pcibk_device *pdev,
28630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				    unsigned int domain, unsigned int bus)
28730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk{
28830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	unsigned int d, b;
28930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	int i, root_num, len, err;
29030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	char str[64];
29130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
29230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	dev_dbg(&pdev->xdev->dev, "Publishing pci roots\n");
29330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
29430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename,
29530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			   "root_num", "%d", &root_num);
29630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (err == 0 || err == -ENOENT)
29730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		root_num = 0;
29830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	else if (err < 0)
29930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		goto out;
30030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
30130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	/* Verify that we haven't already published this pci root */
30230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	for (i = 0; i < root_num; i++) {
30330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		len = snprintf(str, sizeof(str), "root-%d", i);
30430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		if (unlikely(len >= (sizeof(str) - 1))) {
30530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			err = -ENOMEM;
30630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			goto out;
30730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		}
30830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
30930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename,
31030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				   str, "%x:%x", &d, &b);
31130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		if (err < 0)
31230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			goto out;
31330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		if (err != 2) {
31430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			err = -EINVAL;
31530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			goto out;
31630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		}
31730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
31830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		if (d == domain && b == bus) {
31930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			err = 0;
32030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			goto out;
32130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		}
32230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	}
32330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
32430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	len = snprintf(str, sizeof(str), "root-%d", root_num);
32530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (unlikely(len >= (sizeof(str) - 1))) {
32630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		err = -ENOMEM;
32730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		goto out;
32830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	}
32930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
33030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	dev_dbg(&pdev->xdev->dev, "writing root %d at %04x:%02x\n",
33130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		root_num, domain, bus);
33230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
33330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, str,
33430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			    "%04x:%02x", domain, bus);
33530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (err)
33630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		goto out;
33730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
33830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	err = xenbus_printf(XBT_NIL, pdev->xdev->nodename,
33930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			    "root_num", "%d", (root_num + 1));
34030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
34130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilkout:
34230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	return err;
34330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk}
34430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
345a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilkstatic int xen_pcibk_reconfigure(struct xen_pcibk_device *pdev)
34630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk{
34730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	int err = 0;
34830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	int num_devs;
34930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	int domain, bus, slot, func;
35030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	int substate;
35130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	int i, len;
35230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	char state_str[64];
35330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	char dev_str[64];
35430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
35530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
35630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	dev_dbg(&pdev->xdev->dev, "Reconfiguring device ...\n");
35730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
35830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	/* Make sure we only reconfigure once */
35930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (xenbus_read_driver_state(pdev->xdev->nodename) !=
36030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	    XenbusStateReconfiguring)
36130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		goto out;
36230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
36330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, "num_devs", "%d",
36430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			   &num_devs);
36530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (err != 1) {
36630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		if (err >= 0)
36730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			err = -EINVAL;
36830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		xenbus_dev_fatal(pdev->xdev, err,
36930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				 "Error reading number of devices");
37030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		goto out;
37130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	}
37230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
37330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	for (i = 0; i < num_devs; i++) {
37430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		len = snprintf(state_str, sizeof(state_str), "state-%d", i);
37530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		if (unlikely(len >= (sizeof(state_str) - 1))) {
37630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			err = -ENOMEM;
37730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			xenbus_dev_fatal(pdev->xdev, err,
37830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk					 "String overflow while reading "
37930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk					 "configuration");
38030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			goto out;
38130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		}
38230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, state_str,
38330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				   "%d", &substate);
38430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		if (err != 1)
38530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			substate = XenbusStateUnknown;
38630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
38730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		switch (substate) {
38830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		case XenbusStateInitialising:
38930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			dev_dbg(&pdev->xdev->dev, "Attaching dev-%d ...\n", i);
39030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
39130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			len = snprintf(dev_str, sizeof(dev_str), "dev-%d", i);
39230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			if (unlikely(len >= (sizeof(dev_str) - 1))) {
39330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				err = -ENOMEM;
39430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				xenbus_dev_fatal(pdev->xdev, err,
39530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk						 "String overflow while "
39630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk						 "reading configuration");
39730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				goto out;
39830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			}
39930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename,
40030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk					   dev_str, "%x:%x:%x.%x",
40130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk					   &domain, &bus, &slot, &func);
40230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			if (err < 0) {
40330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				xenbus_dev_fatal(pdev->xdev, err,
40430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk						 "Error reading device "
40530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk						 "configuration");
40630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				goto out;
40730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			}
40830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			if (err != 4) {
40930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				err = -EINVAL;
41030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				xenbus_dev_fatal(pdev->xdev, err,
41130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk						 "Error parsing pci device "
41230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk						 "configuration");
41330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				goto out;
41430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			}
41530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
416a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk			err = xen_pcibk_export_device(pdev, domain, bus, slot,
41730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk						    func, i);
41830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			if (err)
41930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				goto out;
42030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
42130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			/* Publish pci roots. */
422a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk			err = xen_pcibk_publish_pci_roots(pdev,
423a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk						xen_pcibk_publish_pci_root);
42430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			if (err) {
42530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				xenbus_dev_fatal(pdev->xdev, err,
42630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk						 "Error while publish PCI root"
42730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk						 "buses for frontend");
42830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				goto out;
42930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			}
43030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
43130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			err = xenbus_printf(XBT_NIL, pdev->xdev->nodename,
43230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk					    state_str, "%d",
43330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk					    XenbusStateInitialised);
43430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			if (err) {
43530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				xenbus_dev_fatal(pdev->xdev, err,
43630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk						 "Error switching substate of "
43730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk						 "dev-%d\n", i);
43830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				goto out;
43930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			}
44030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			break;
44130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
44230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		case XenbusStateClosing:
44330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			dev_dbg(&pdev->xdev->dev, "Detaching dev-%d ...\n", i);
44430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
44530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			len = snprintf(dev_str, sizeof(dev_str), "vdev-%d", i);
44630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			if (unlikely(len >= (sizeof(dev_str) - 1))) {
44730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				err = -ENOMEM;
44830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				xenbus_dev_fatal(pdev->xdev, err,
44930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk						 "String overflow while "
45030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk						 "reading configuration");
45130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				goto out;
45230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			}
45330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename,
45430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk					   dev_str, "%x:%x:%x.%x",
45530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk					   &domain, &bus, &slot, &func);
45630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			if (err < 0) {
45730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				xenbus_dev_fatal(pdev->xdev, err,
45830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk						 "Error reading device "
45930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk						 "configuration");
46030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				goto out;
46130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			}
46230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			if (err != 4) {
46330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				err = -EINVAL;
46430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				xenbus_dev_fatal(pdev->xdev, err,
46530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk						 "Error parsing pci device "
46630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk						 "configuration");
46730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				goto out;
46830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			}
46930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
470a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk			err = xen_pcibk_remove_device(pdev, domain, bus, slot,
47130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk						    func);
47230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			if (err)
47330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				goto out;
47430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
47530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			/* TODO: If at some point we implement support for pci
47630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			 * root hot-remove on pcifront side, we'll need to
47730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			 * remove unnecessary xenstore nodes of pci roots here.
47830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			 */
47930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
48030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			break;
48130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
48230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		default:
48330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			break;
48430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		}
48530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	}
48630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
48730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	err = xenbus_switch_state(pdev->xdev, XenbusStateReconfigured);
48830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (err) {
48930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		xenbus_dev_fatal(pdev->xdev, err,
49030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				 "Error switching to reconfigured state!");
49130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		goto out;
49230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	}
49330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
49430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilkout:
49530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	return 0;
49630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk}
49730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
498a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilkstatic void xen_pcibk_frontend_changed(struct xenbus_device *xdev,
49930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				     enum xenbus_state fe_state)
50030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk{
501a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk	struct xen_pcibk_device *pdev = dev_get_drvdata(&xdev->dev);
50230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
50330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	dev_dbg(&xdev->dev, "fe state changed %d\n", fe_state);
50430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
50530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	switch (fe_state) {
50630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	case XenbusStateInitialised:
507a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk		xen_pcibk_attach(pdev);
50830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		break;
50930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
51030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	case XenbusStateReconfiguring:
511a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk		xen_pcibk_reconfigure(pdev);
51230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		break;
51330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
51430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	case XenbusStateConnected:
51530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		/* pcifront switched its state from reconfiguring to connected.
51630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		 * Then switch to connected state.
51730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		 */
51830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		xenbus_switch_state(xdev, XenbusStateConnected);
51930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		break;
52030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
52130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	case XenbusStateClosing:
522a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk		xen_pcibk_disconnect(pdev);
52330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		xenbus_switch_state(xdev, XenbusStateClosing);
52430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		break;
52530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
52630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	case XenbusStateClosed:
527a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk		xen_pcibk_disconnect(pdev);
52830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		xenbus_switch_state(xdev, XenbusStateClosed);
52930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		if (xenbus_dev_is_online(xdev))
53030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			break;
53130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		/* fall through if not online */
53230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	case XenbusStateUnknown:
53330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		dev_dbg(&xdev->dev, "frontend is gone! unregister device\n");
53430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		device_unregister(&xdev->dev);
53530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		break;
53630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
53730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	default:
53830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		break;
53930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	}
54030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk}
54130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
542a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilkstatic int xen_pcibk_setup_backend(struct xen_pcibk_device *pdev)
54330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk{
54430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	/* Get configuration from xend (if available now) */
54530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	int domain, bus, slot, func;
54630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	int err = 0;
54730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	int i, num_devs;
54830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	char dev_str[64];
54930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	char state_str[64];
55030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
55130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	/* It's possible we could get the call to setup twice, so make sure
55230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	 * we're not already connected.
55330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	 */
55430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (xenbus_read_driver_state(pdev->xdev->nodename) !=
55530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	    XenbusStateInitWait)
55630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		goto out;
55730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
55830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	dev_dbg(&pdev->xdev->dev, "getting be setup\n");
55930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
56030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, "num_devs", "%d",
56130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			   &num_devs);
56230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (err != 1) {
56330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		if (err >= 0)
56430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			err = -EINVAL;
56530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		xenbus_dev_fatal(pdev->xdev, err,
56630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				 "Error reading number of devices");
56730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		goto out;
56830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	}
56930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
57030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	for (i = 0; i < num_devs; i++) {
57130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		int l = snprintf(dev_str, sizeof(dev_str), "dev-%d", i);
57230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		if (unlikely(l >= (sizeof(dev_str) - 1))) {
57330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			err = -ENOMEM;
57430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			xenbus_dev_fatal(pdev->xdev, err,
57530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk					 "String overflow while reading "
57630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk					 "configuration");
57730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			goto out;
57830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		}
57930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
58030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, dev_str,
58130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				   "%x:%x:%x.%x", &domain, &bus, &slot, &func);
58230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		if (err < 0) {
58330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			xenbus_dev_fatal(pdev->xdev, err,
58430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk					 "Error reading device configuration");
58530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			goto out;
58630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		}
58730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		if (err != 4) {
58830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			err = -EINVAL;
58930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			xenbus_dev_fatal(pdev->xdev, err,
59030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk					 "Error parsing pci device "
59130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk					 "configuration");
59230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			goto out;
59330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		}
59430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
595a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk		err = xen_pcibk_export_device(pdev, domain, bus, slot, func, i);
59630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		if (err)
59730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			goto out;
59830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
59930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		/* Switch substate of this device. */
60030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		l = snprintf(state_str, sizeof(state_str), "state-%d", i);
60130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		if (unlikely(l >= (sizeof(state_str) - 1))) {
60230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			err = -ENOMEM;
60330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			xenbus_dev_fatal(pdev->xdev, err,
60430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk					 "String overflow while reading "
60530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk					 "configuration");
60630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			goto out;
60730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		}
60830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, state_str,
60930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				    "%d", XenbusStateInitialised);
61030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		if (err) {
61130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			xenbus_dev_fatal(pdev->xdev, err, "Error switching "
61230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk					 "substate of dev-%d\n", i);
61330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			goto out;
61430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		}
61530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	}
61630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
617a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk	err = xen_pcibk_publish_pci_roots(pdev, xen_pcibk_publish_pci_root);
61830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (err) {
61930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		xenbus_dev_fatal(pdev->xdev, err,
62030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				 "Error while publish PCI root buses "
62130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				 "for frontend");
62230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		goto out;
62330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	}
62430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
62530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	err = xenbus_switch_state(pdev->xdev, XenbusStateInitialised);
62630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (err)
62730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		xenbus_dev_fatal(pdev->xdev, err,
62830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				 "Error switching to initialised state!");
62930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
63030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilkout:
63130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (!err)
63230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		/* see if pcifront is already configured (if not, we'll wait) */
633a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk		xen_pcibk_attach(pdev);
63430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
63530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	return err;
63630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk}
63730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
638a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilkstatic void xen_pcibk_be_watch(struct xenbus_watch *watch,
63930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk			     const char **vec, unsigned int len)
64030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk{
641a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk	struct xen_pcibk_device *pdev =
642a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk	    container_of(watch, struct xen_pcibk_device, be_watch);
64330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
64430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	switch (xenbus_read_driver_state(pdev->xdev->nodename)) {
64530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	case XenbusStateInitWait:
646a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk		xen_pcibk_setup_backend(pdev);
64730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		break;
64830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
64930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	default:
65030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		break;
65130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	}
65230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk}
65330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
654a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilkstatic int xen_pcibk_xenbus_probe(struct xenbus_device *dev,
65530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk				const struct xenbus_device_id *id)
65630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk{
65730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	int err = 0;
658a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk	struct xen_pcibk_device *pdev = alloc_pdev(dev);
65930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
66030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (pdev == NULL) {
66130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		err = -ENOMEM;
66230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		xenbus_dev_fatal(dev, err,
663a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk				 "Error allocating xen_pcibk_device struct");
66430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		goto out;
66530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	}
66630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
66730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	/* wait for xend to configure us */
66830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	err = xenbus_switch_state(dev, XenbusStateInitWait);
66930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (err)
67030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		goto out;
67130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
67230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	/* watch the backend node for backend configuration information */
67330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	err = xenbus_watch_path(dev, dev->nodename, &pdev->be_watch,
674a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk				xen_pcibk_be_watch);
67530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (err)
67630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		goto out;
677494ef20db6ea2e2ab1c3a45a1461e6e717fdcf48Konrad Rzeszutek Wilk
67830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	pdev->be_watching = 1;
67930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
68030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	/* We need to force a call to our callback here in case
68130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	 * xend already configured us!
68230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	 */
683a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk	xen_pcibk_be_watch(&pdev->be_watch, NULL, 0);
68430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
68530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilkout:
68630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	return err;
68730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk}
68830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
689a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilkstatic int xen_pcibk_xenbus_remove(struct xenbus_device *dev)
69030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk{
691a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk	struct xen_pcibk_device *pdev = dev_get_drvdata(&dev->dev);
69230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
69330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	if (pdev != NULL)
69430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		free_pdev(pdev);
69530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
69630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	return 0;
69730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk}
69830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
69930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilkstatic const struct xenbus_device_id xenpci_ids[] = {
70030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	{"pci"},
70130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	{""},
70230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk};
70330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
704a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilkstatic struct xenbus_driver xenbus_xen_pcibk_driver = {
705a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk	.name			= DRV_NAME,
7068bfd4e023f5fb5793d7d7483b6e17e04933c53e9Konrad Rzeszutek Wilk	.owner			= THIS_MODULE,
7078bfd4e023f5fb5793d7d7483b6e17e04933c53e9Konrad Rzeszutek Wilk	.ids			= xenpci_ids,
708a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk	.probe			= xen_pcibk_xenbus_probe,
709a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk	.remove			= xen_pcibk_xenbus_remove,
710a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk	.otherend_changed	= xen_pcibk_frontend_changed,
71130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk};
71230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
713a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilkint __init xen_pcibk_xenbus_register(void)
71430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk{
715a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk	xen_pcibk_wq = create_workqueue("xen_pciback_workqueue");
716a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk	if (!xen_pcibk_wq) {
7178bfd4e023f5fb5793d7d7483b6e17e04933c53e9Konrad Rzeszutek Wilk		printk(KERN_ERR "%s: create"
718a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk			"xen_pciback_workqueue failed\n", __func__);
71930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk		return -EFAULT;
72030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk	}
721a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk	return xenbus_register_backend(&xenbus_xen_pcibk_driver);
72230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk}
72330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk
724a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilkvoid __exit xen_pcibk_xenbus_unregister(void)
72530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk{
726a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk	destroy_workqueue(xen_pcibk_wq);
727a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk	xenbus_unregister_driver(&xenbus_xen_pcibk_driver);
72830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk}
729