1/*      $NetBSD: pciback.c,v 1.6 2011/12/07 15:47:43 cegger Exp $      */
2
3/*
4 * Copyright (c) 2009 Manuel Bouyer.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *
26 */
27
28#include <sys/cdefs.h>
29__KERNEL_RCSID(0, "$NetBSD: pciback.c,v 1.6 2011/12/07 15:47:43 cegger Exp $");
30
31#include "opt_xen.h"
32
33
34#include <sys/types.h>
35#include <sys/param.h>
36#include <sys/systm.h>
37#include <sys/errno.h>
38#include <sys/malloc.h>
39#include <sys/kernel.h>
40#include <sys/bus.h>
41#include <sys/queue.h>
42
43#include <uvm/uvm_extern.h>
44
45#include <machine/bus_private.h>
46
47#include <dev/isa/isareg.h>
48
49#include <xen/hypervisor.h>
50#include <xen/evtchn.h>
51#include <xen/granttables.h>
52#include <xen/xen-public/io/pciif.h>
53#include <xen/xenbus.h>
54
55#include <sys/stat.h>
56#include <sys/dirent.h>
57#include <miscfs/specfs/specdev.h>
58#include <miscfs/kernfs/kernfs.h>
59#include <xen/kernfs_machdep.h>
60
61#include "locators.h"
62
63#include <dev/pci/pcivar.h>
64#include <machine/i82093var.h>
65
66struct pciback_pci_softc;
67struct pb_xenbus_instance;
68/* list of devices we handle */
69struct pciback_pci_dev {
70	SLIST_ENTRY(pciback_pci_dev) pb_devlist_next; /* global list of pbd */
71	SLIST_ENTRY(pciback_pci_dev) pb_guest_next; /* per-guest list of pbd */
72	u_int pb_bus; /* our location */
73	u_int pb_device;
74	u_int pb_function;
75	pci_chipset_tag_t pb_pc;
76	pcitag_t pb_tag;
77	struct pciback_pci_softc *pb_pci_softc;
78	struct pb_xenbus_instance *pbx_instance;
79};
80
81/* list of devices we want to match */
82SLIST_HEAD(pciback_pci_devlist, pciback_pci_dev) pciback_pci_devlist_head  =
83    SLIST_HEAD_INITIALIZER(pciback_pci_devlist_head);
84
85/* PCI-related functions and definitions  */
86
87#define PCI_NBARS	((PCI_MAPREG_END - PCI_MAPREG_START) / 4)
88
89struct pciback_pci_softc {
90	device_t sc_dev;
91	void *sc_ih; /* our interrupt; */
92	struct pciback_pci_dev *sc_pb; /* our location */
93	struct pci_bar {
94		bus_space_tag_t b_t;
95		bus_space_handle_t b_h;
96		bus_addr_t b_addr;
97		bus_size_t b_size;
98		int b_type;
99		int b_valid;
100	} sc_bars[PCI_NBARS];
101	pci_intr_handle_t sc_intrhandle;
102	int  sc_irq;
103	pcireg_t sc_id;
104	pcireg_t sc_subid;
105	char sc_kernfsname[16];
106};
107
108int pciback_pci_match(device_t, cfdata_t, void *);
109void pciback_pci_attach(device_t, device_t, void *);
110static struct pciback_pci_dev* pciback_pci_lookup(u_int, u_int, u_int);
111static void pciback_pci_init(void);
112
113static int  pciback_parse_pci(const char *, u_int *, u_int *, u_int *);
114
115/* kernfs-related functions and definitions */
116
117static kernfs_parentdir_t *pciback_kern_pkt;
118static int  pciback_kernfs_read(void *);
119
120#define DIR_MODE	(S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
121#define FILE_MODE	(S_IRUSR)
122static const struct kernfs_fileop pciback_dev_fileops[] = {
123    { .kf_fileop = KERNFS_FILEOP_READ, .kf_vop = pciback_kernfs_read },
124};
125
126/* xenbus-related functions and definitions */
127
128static int  pciback_xenbus_create(struct xenbus_device *);
129static int  pciback_xenbus_destroy(void *);
130static void pciback_xenbus_frontend_changed(void *, XenbusState);
131static struct pb_xenbus_instance * pbxif_lookup(domid_t);
132static void pciback_xenbus_export_device(struct pb_xenbus_instance *, char *);
133static void pciback_xenbus_export_roots(struct pb_xenbus_instance *);
134
135static int  pciback_xenbus_evthandler(void *);
136
137/* emulate byte and word access to PCI config space */
138static inline u_int8_t
139pciback_read_byte(pci_chipset_tag_t pc, pcitag_t pa, int reg)
140{
141
142        return (pci_conf_read(pc, pa, (reg & ~0x03)) >>
143            ((reg & 0x03) * 8) & 0xff);
144}
145
146static inline u_int16_t
147pciback_read_word(pci_chipset_tag_t pc, pcitag_t pa, int reg)
148{
149        return (pci_conf_read(pc, pa, (reg & ~0x03)) >>
150            ((reg & 0x03) * 8) & 0xffff);
151}
152
153static inline void
154pciback_write_byte(pci_chipset_tag_t pc, pcitag_t pa, int reg, uint8_t val)
155{
156        pcireg_t pcival;
157
158        pcival = pci_conf_read(pc, pa, (reg & ~0x03));
159        pcival &= ~(0xff << ((reg & 0x03) * 8));
160        pcival |= (val << ((reg & 0x03) * 8));
161        pci_conf_write(pc, pa, (reg & ~0x03), pcival);
162}
163
164static inline void
165pciback_write_word(pci_chipset_tag_t pc, pcitag_t pa, int reg, uint16_t val)
166{
167        pcireg_t pcival;
168
169        pcival = pci_conf_read(pc, pa, (reg & ~0x03));
170        pcival &= ~(0xffff << ((reg & 0x03) * 8));
171        pcival |= (val << ((reg & 0x03) * 8));
172        pci_conf_write(pc, pa, (reg & ~0x03), pcival);
173}
174
175
176
177CFATTACH_DECL_NEW(pciback, sizeof(struct pciback_pci_softc),
178    pciback_pci_match, pciback_pci_attach, NULL, NULL);
179
180static int pciback_pci_inited = 0;
181
182/* a xenbus PCI backend instance */
183struct pb_xenbus_instance {
184	SLIST_ENTRY(pb_xenbus_instance) pbx_next; /* list of backend instances*/
185	struct xenbus_device *pbx_xbusd;
186	domid_t pbx_domid;
187	struct pciback_pci_devlist pbx_pb_pci_dev; /* list of exported PCI devices */
188	/* communication with the domU */
189        unsigned int pbx_evtchn; /* our even channel */
190        struct xen_pci_sharedinfo *pbx_sh_info;
191        grant_handle_t pbx_shinfo_handle; /* to unmap shared page */
192};
193
194SLIST_HEAD(, pb_xenbus_instance) pb_xenbus_instances;
195
196static struct xenbus_backend_driver pci_backend_driver = {
197        .xbakd_create = pciback_xenbus_create,
198        .xbakd_type = "pci"
199};
200
201int
202pciback_pci_match(device_t parent, cfdata_t match, void *aux)
203{
204	struct pci_attach_args *pa = aux;
205	if (pciback_pci_inited == 0) {
206		pciback_pci_init();
207		pciback_pci_inited = 1;
208	}
209	if (pciback_pci_lookup(pa->pa_bus, pa->pa_device, pa->pa_function))
210		return 500; /* we really want to take over anything else */
211	return 0;
212}
213
214void
215pciback_pci_attach(device_t parent, device_t self, void *aux)
216{
217	struct pci_attach_args *pa = aux;
218	struct pciback_pci_softc *sc = device_private(self);
219	char devinfo[256];
220	int i;
221	const char *intrstr;
222	kernfs_entry_t *dkt;
223	kfstype kfst;
224	pcireg_t reg;
225
226	sc->sc_dev = self;
227	sc->sc_pb = pciback_pci_lookup(pa->pa_bus, pa->pa_device, pa->pa_function);
228	if (sc->sc_pb == NULL)
229		panic("pciback_pci_attach: pciback_lookup");
230	pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo, sizeof(devinfo));
231	aprint_normal(": %s (rev. 0x%02x)\n", devinfo,
232	    PCI_REVISION(pa->pa_class));
233	sc->sc_pb->pb_pci_softc = sc;
234	sc->sc_pb->pb_pc = pa->pa_pc;
235	sc->sc_pb->pb_tag = pa->pa_tag;
236
237	sc->sc_id = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_ID_REG);
238	sc->sc_subid = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG);
239
240	for (i = 0; i < PCI_NBARS;) {
241		sc->sc_bars[i].b_type = pci_mapreg_type(pa->pa_pc, pa->pa_tag,
242		    PCI_MAPREG_START + i * 4);
243		if (pci_mapreg_map(pa, PCI_MAPREG_START + i * 4,
244		    sc->sc_bars[i].b_type, 0,
245		    &sc->sc_bars[i].b_t, &sc->sc_bars[i].b_h,
246		    &sc->sc_bars[i].b_addr, &sc->sc_bars[i].b_size) == 0)
247			sc->sc_bars[i].b_valid = 1;
248		if (sc->sc_bars[i].b_valid) {
249			aprint_verbose_dev(self, "%s: 0x%08jx - 0x%08jx\n",
250			    (sc->sc_bars[i].b_type == PCI_MAPREG_TYPE_IO) ?
251			    "I/O" : "mem",
252			    (uintmax_t)sc->sc_bars[i].b_addr,
253			    (uintmax_t)sc->sc_bars[i].b_size);
254		}
255
256		if (sc->sc_bars[i].b_type ==
257		    (PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_64BIT))
258			i += 2;
259		else
260			i += 1;
261	}
262	/* map the irq so interrupt routing is done */
263	if (pci_intr_map(pa, &sc->sc_intrhandle) != 0) {
264		aprint_error_dev(self, "couldn't map interrupt\n");
265	} else {
266		intrstr = pci_intr_string(pa->pa_pc, sc->sc_intrhandle);
267		aprint_normal_dev(self, "interrupting at %s\n",
268		    intrstr ? intrstr : "unknown interrupt");
269	}
270	unbind_pirq_from_evtch(APIC_IRQ_LEGACY_IRQ(sc->sc_intrhandle.pirq));
271	sc->sc_irq = APIC_IRQ_LEGACY_IRQ(sc->sc_intrhandle.pirq);
272	/* XXX should be done elsewhere ? */
273	reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_INTERRUPT_REG);
274	reg &= ~ (PCI_INTERRUPT_LINE_MASK << PCI_INTERRUPT_LINE_SHIFT);
275	reg |= (sc->sc_irq << PCI_INTERRUPT_LINE_SHIFT);
276	pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_INTERRUPT_REG, reg);
277	printf("irq line %d pin %d sc %p\n",
278	    PCI_INTERRUPT_LINE(pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_INTERRUPT_REG)),
279	    PCI_INTERRUPT_PIN(pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_INTERRUPT_REG)), sc);
280	/*
281	 * don't establish the interrupt, we're not interested in
282	 * getting it here.
283	 */
284	/* publish the informations about this device to /kern/xen/pci */
285	snprintf(sc->sc_kernfsname, sizeof(sc->sc_kernfsname),
286	    "0000:%02x:%02x.%x", pa->pa_bus, pa->pa_device, pa->pa_function);
287	kfst = KERNFS_ALLOCTYPE(pciback_dev_fileops);
288	KERNFS_ALLOCENTRY(dkt, M_TEMP, M_WAITOK);
289	KERNFS_INITENTRY(dkt, DT_REG, sc->sc_kernfsname, sc,
290	    kfst, VREG, FILE_MODE);
291	kernfs_addentry(pciback_kern_pkt, dkt);
292}
293
294static int
295pciback_kernfs_read(void *v)
296{
297	struct vop_read_args /* {
298		struct vnode *a_vp;
299		struct uio *a_uio;
300		int  a_ioflag;
301		struct ucred *a_cred;
302	} */ *ap = v;
303	struct kernfs_node *kfs = VTOKERN(ap->a_vp);
304	struct uio *uio = ap->a_uio;
305	struct pciback_pci_softc *sc = kfs->kfs_kt->kt_data;
306#define PCIBACK_KERNFS_SIZE 512
307	static char buf[PCIBACK_KERNFS_SIZE];
308	off_t off;
309	off_t len;
310	int error, i;
311
312	off = uio->uio_offset;
313	len = 0;
314	len += snprintf(&buf[len], PCIBACK_KERNFS_SIZE - len,
315	    "vendor: 0x%04x\nproduct: 0x%04x\n",
316	    PCI_VENDOR(sc->sc_id), PCI_PRODUCT(sc->sc_id));
317	len += snprintf(&buf[len], PCIBACK_KERNFS_SIZE - len,
318	    "subsys_vendor: 0x%04x\nsubsys_product: 0x%04x\n",
319	    PCI_VENDOR(sc->sc_subid), PCI_PRODUCT(sc->sc_subid));
320	for(i = 0; i < PCI_NBARS; i++) {
321		if (sc->sc_bars[i].b_valid) {
322			len += snprintf(&buf[len], PCIBACK_KERNFS_SIZE - len,
323			    "%s: 0x%08jx - 0x%08jx\n",
324			    (sc->sc_bars[i].b_type == PCI_MAPREG_TYPE_IO) ?
325			    "I/O" : "mem",
326			    (uintmax_t)sc->sc_bars[i].b_addr,
327			    (uintmax_t)(sc->sc_bars[i].b_addr + sc->sc_bars[i].b_size));
328		}
329	}
330	len += snprintf(&buf[len], PCIBACK_KERNFS_SIZE - len,
331	    "irq: %d\n", sc->sc_irq);
332	if (off >= len) {
333		error = uiomove(buf, 0, uio);
334	} else {
335		error = uiomove(&buf[off], len - off, uio);
336	}
337	return error;
338}
339
340static struct pciback_pci_dev*
341pciback_pci_lookup(u_int bus, u_int dev, u_int func)
342{
343	struct pciback_pci_dev *pbd;
344	SLIST_FOREACH(pbd, &pciback_pci_devlist_head, pb_devlist_next) {
345		if (pbd->pb_bus == bus &&
346		    pbd->pb_device == dev &&
347		    pbd->pb_function == func)
348			return pbd;
349	}
350	return NULL;
351}
352
353static void
354pciback_pci_init(void)
355{
356	union xen_cmdline_parseinfo xi;
357	char *pcidevs, *c;
358	u_int bus, dev, func;
359	struct pciback_pci_dev *pb;
360	kernfs_entry_t *dkt;
361
362	memset(&xi, 0, sizeof(xi));
363	xen_parse_cmdline(XEN_PARSE_PCIBACK, &xi);
364	if (strlen(xi.xcp_pcidevs) == 0)
365		return;
366	pcidevs = xi.xcp_pcidevs;
367	for(pcidevs = xi.xcp_pcidevs; *pcidevs != '\0';) {
368		if (*pcidevs != '(')
369			goto error;
370		pcidevs++;
371		/* parse location */
372		c = strchr(pcidevs, ')');
373		if (c == NULL)
374			goto error;
375		*c = '\0';
376		if (pciback_parse_pci(pcidevs, &bus, &dev, &func) == 0) {
377			pb = malloc(sizeof(struct pciback_pci_dev), M_DEVBUF,
378			    M_NOWAIT | M_ZERO);
379			if (pb == NULL) {
380				aprint_error("pciback_pci_init: out or memory\n");
381				return;
382			}
383			pb->pb_bus = bus;
384			pb->pb_device = dev;
385			pb->pb_function = func;
386			aprint_verbose("pciback_pci_init: hide claim device "
387			    "%x:%x:%x\n", bus, dev, func);
388			SLIST_INSERT_HEAD(&pciback_pci_devlist_head, pb,
389			    pb_devlist_next);
390		}
391		pcidevs = c + 1;
392	}
393	xenbus_backend_register(&pci_backend_driver);
394
395	KERNFS_ALLOCENTRY(dkt, M_TEMP, M_WAITOK);
396	KERNFS_INITENTRY(dkt, DT_DIR, "pci", NULL, KFSsubdir, VDIR, DIR_MODE);
397	kernfs_addentry(kernxen_pkt, dkt);
398	pciback_kern_pkt = KERNFS_ENTOPARENTDIR(dkt);
399	return;
400error:
401	aprint_error("pciback_pci_init: syntax error at %s\n", pcidevs);
402	return;
403}
404
405static int
406pciback_parse_pci(const char *str, u_int *busp, u_int *devp, u_int *funcp)
407{
408	char *c;
409
410	/* parse location */
411	c = strchr(str, ':');
412	if (c == NULL)
413		goto error;
414	if (strncmp("0000", str, 4) == 0) {
415		/* must be domain number, get next */
416		str = c + 1;
417	}
418	*busp = strtoul(str, &c, 16);
419	if (*c != ':')
420		goto error;
421	str = c + 1;
422	*devp = strtoul(str, &c, 16);
423	if (*c != '.')
424		goto error;
425	str = c + 1;
426	*funcp = strtoul(str, &c, 16);
427	if (*c != '\0')
428		goto error;
429	return 0;
430error:
431	aprint_error("pciback_pci_init: syntax error at char %c\n", *c);
432	return EINVAL;
433}
434
435static int
436pciback_xenbus_create(struct xenbus_device *xbusd)
437{
438	struct pb_xenbus_instance *pbxi;
439	long domid;
440	char *val;
441	char path[10];
442	int i, err;
443	u_long num_devs;
444
445	if ((err = xenbus_read_ul(NULL, xbusd->xbusd_path,
446	    "frontend-id", &domid, 10)) != 0) {
447		aprint_error("pciback: can' read %s/frontend-id: %d\n",
448		    xbusd->xbusd_path, err);
449		return err;
450	}
451
452	if (pbxif_lookup(domid) != NULL) {
453		return EEXIST;
454	}
455	pbxi = malloc(sizeof(struct pb_xenbus_instance), M_DEVBUF,
456	    M_NOWAIT | M_ZERO);
457	if (pbxi == NULL) {
458		return ENOMEM;
459	}
460	pbxi->pbx_domid = domid;
461
462	xbusd->xbusd_u.b.b_cookie = pbxi;
463	xbusd->xbusd_u.b.b_detach = pciback_xenbus_destroy;
464	pbxi->pbx_xbusd = xbusd;
465
466	SLIST_INIT(&pbxi->pbx_pb_pci_dev);
467
468	SLIST_INSERT_HEAD(&pb_xenbus_instances, pbxi, pbx_next);
469
470	xbusd->xbusd_otherend_changed = pciback_xenbus_frontend_changed;
471
472	err = xenbus_switch_state(xbusd, NULL, XenbusStateInitWait);
473	if (err) {
474		printf("failed to switch state on %s: %d\n",
475		    xbusd->xbusd_path, err);
476		goto fail;
477	}
478	if ((err = xenbus_read_ul(NULL, xbusd->xbusd_path, "num_devs",
479	    &num_devs, 10)) != 0) {
480		aprint_error("pciback: can' read %s/num_devs %d\n",
481		    xbusd->xbusd_path, err);
482		goto fail;
483	}
484	for (i = 0; i < num_devs; i++) {
485		snprintf(path, sizeof(path), "dev-%d", i);
486		if ((err = xenbus_read(NULL, xbusd->xbusd_path, path,
487		    NULL, &val)) != 0) {
488			aprint_error("pciback: can' read %s/%s: %d\n",
489			    xbusd->xbusd_path, path, err);
490			goto fail;
491		}
492		pciback_xenbus_export_device(pbxi, val);
493		free(val, M_DEVBUF);
494	}
495	pciback_xenbus_export_roots(pbxi);
496	if ((err = xenbus_switch_state(xbusd, NULL, XenbusStateInitialised))) {
497		printf("failed to switch state on %s: %d\n",
498		    xbusd->xbusd_path, err);
499		goto fail;
500	}
501
502	return 0;
503fail:
504	free(pbxi, M_DEVBUF);
505	return err;
506}
507
508static int
509pciback_xenbus_destroy(void *arg)
510{
511	struct pb_xenbus_instance *pbxi = arg;
512	struct pciback_pci_dev *pbd;
513	struct gnttab_unmap_grant_ref op;
514	int err;
515
516	hypervisor_mask_event(pbxi->pbx_evtchn);
517	event_remove_handler(pbxi->pbx_evtchn,
518	    pciback_xenbus_evthandler, pbxi);
519
520	SLIST_REMOVE(&pb_xenbus_instances,
521	    pbxi, pb_xenbus_instance, pbx_next);
522
523	if (pbxi->pbx_sh_info) {
524		op.host_addr = (vaddr_t)pbxi->pbx_sh_info;
525		op.handle = pbxi->pbx_shinfo_handle;
526		op.dev_bus_addr = 0;
527		err = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref,
528		    &op, 1);
529		if (err)
530			aprint_error("pciback: unmap_grant_ref failed: %d\n",
531			    err);
532	}
533	SLIST_FOREACH(pbd, &pbxi->pbx_pb_pci_dev, pb_guest_next) {
534		pbd->pbx_instance = NULL;
535	}
536	uvm_km_free(kernel_map, (vaddr_t)pbxi->pbx_sh_info,
537	    PAGE_SIZE, UVM_KMF_VAONLY);
538	free(pbxi, M_DEVBUF);
539	return 0;
540}
541
542static void
543pciback_xenbus_frontend_changed(void *arg, XenbusState new_state)
544{
545	struct pb_xenbus_instance *pbxi = arg;
546	struct xenbus_device *xbusd = pbxi->pbx_xbusd;
547	int err;
548	struct gnttab_map_grant_ref op;
549	evtchn_op_t evop;
550	u_long shared_ref;
551	u_long revtchn;
552
553	/* do it only once */
554	if (xenbus_read_driver_state(xbusd->xbusd_path) !=
555	    XenbusStateInitialised)
556		return;
557
558	switch(new_state) {
559	case XenbusStateInitialising:
560	case XenbusStateConnected:
561		break;
562	case XenbusStateInitialised:
563		/* read comunication informations */
564		err = xenbus_read_ul(NULL, xbusd->xbusd_otherend,
565		    "pci-op-ref", &shared_ref, 10);
566		if (err) {
567			xenbus_dev_fatal(xbusd, err, "reading %s/pci-op-ref",
568			    xbusd->xbusd_otherend);
569			break;
570		}
571		err = xenbus_read_ul(NULL, xbusd->xbusd_otherend,
572		    "event-channel", &revtchn, 10);
573		if (err) {
574			xenbus_dev_fatal(xbusd, err, "reading %s/event-channel",
575			    xbusd->xbusd_otherend);
576			break;
577		}
578		/* allocate VA space and map rings */
579		pbxi->pbx_sh_info = (void *)uvm_km_alloc(kernel_map,
580		    PAGE_SIZE, 0, UVM_KMF_VAONLY);
581		if (pbxi->pbx_sh_info == 0) {
582			xenbus_dev_fatal(xbusd, ENOMEM,
583			    "can't get VA for shared infos",
584			    xbusd->xbusd_otherend);
585			break;
586		}
587		op.host_addr = (vaddr_t)pbxi->pbx_sh_info;
588		op.flags = GNTMAP_host_map;
589		op.ref = shared_ref;
590		op.dom = pbxi->pbx_domid;
591		err = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1);
592		if (err || op.status) {
593			aprint_error("pciback: can't map shared grant ref: "
594			    "%d/%d\n", err, op.status);
595			goto err1;
596		}
597		pbxi->pbx_shinfo_handle = op.handle;
598
599		evop.cmd = EVTCHNOP_bind_interdomain;
600		evop.u.bind_interdomain.remote_dom = pbxi->pbx_domid;
601		evop.u.bind_interdomain.remote_port = revtchn;
602		err = HYPERVISOR_event_channel_op(&evop);
603		if (err) {
604			printf("pciback: can't get event channel: %d\n", err);
605			goto err1;
606		}
607		pbxi->pbx_evtchn = evop.u.bind_interdomain.local_port;
608		x86_sfence();
609		xenbus_switch_state(xbusd, NULL, XenbusStateConnected);
610		x86_sfence();
611		event_set_handler(pbxi->pbx_evtchn, pciback_xenbus_evthandler,
612		    pbxi, IPL_BIO, "pciback");
613		hypervisor_enable_event(pbxi->pbx_evtchn);
614		hypervisor_notify_via_evtchn(pbxi->pbx_evtchn);
615		break;
616
617	case XenbusStateClosing:
618		xenbus_switch_state(xbusd, NULL, XenbusStateClosing);
619		break;
620
621	case XenbusStateClosed:
622		/* otherend_changed() should handle it for us */
623		panic("pciback_xenbus_frontend_changed: closed\n");
624	case XenbusStateUnknown:
625	case XenbusStateInitWait:
626	default:
627		aprint_error("pciback: invalid frontend state %d\n",
628		    new_state);
629		break;
630	}
631	return;
632err1:
633	uvm_km_free(kernel_map, (vaddr_t)pbxi->pbx_sh_info,
634	    PAGE_SIZE, UVM_KMF_VAONLY);
635}
636
637/* lookup a pbxi based on domain id and interface handle */
638static struct pb_xenbus_instance *
639pbxif_lookup(domid_t dom)
640{
641	struct pb_xenbus_instance *pbxi;
642
643	SLIST_FOREACH(pbxi, &pb_xenbus_instances, pbx_next) {
644		if (pbxi->pbx_domid == dom)
645			return pbxi;
646	}
647	return NULL;
648}
649
650static void
651pciback_xenbus_export_device(struct pb_xenbus_instance *pbxi, char *val)
652{
653	u_int bus, dev, func;
654	struct pciback_pci_dev *pbd;
655	if (pciback_parse_pci(val, &bus, &dev, &func)) {
656		aprint_error("pciback: can't parse %s\n", val);
657		return;
658	}
659	pbd = pciback_pci_lookup(bus, dev, func);
660	if (pbd == NULL) {
661		aprint_error("pciback: can't locate 0x%02x:0x%02x.0x%02x\n",
662		    bus, dev, func);
663		return;
664	}
665	if (pbd->pb_pci_softc == NULL) {
666		aprint_error("pciback: 0x%02x:0x%02x.0x%02x not detected\n",
667		    bus, dev, func);
668		return;
669	}
670	pbd->pbx_instance = pbxi;
671	SLIST_INSERT_HEAD(&pbxi->pbx_pb_pci_dev, pbd, pb_guest_next);
672	return;
673}
674
675static void
676pciback_xenbus_export_roots(struct pb_xenbus_instance *pbxi)
677{
678	char bus[256];
679	char root[10];
680	struct pciback_pci_dev *pbd;
681	int num_roots = 0;
682	int err;
683
684	memset(bus, 0, sizeof(bus));
685
686	SLIST_FOREACH(pbd, &pbxi->pbx_pb_pci_dev, pb_guest_next) {
687		if (bus[pbd->pb_bus] == 0) {
688			/* not published yet */
689			snprintf(root, sizeof(root), "root-%d", num_roots);
690			err = xenbus_printf(NULL,
691			    pbxi->pbx_xbusd->xbusd_path,
692			    root, "0000:%02x", pbd->pb_bus);
693			if (err) {
694				aprint_error("pciback: can't write to %s/%s: "
695				    "%d\n", pbxi->pbx_xbusd->xbusd_path, root,
696				    err);
697			}
698			num_roots++;
699			bus[pbd->pb_bus]++;
700		}
701	}
702	err = xenbus_printf(NULL, pbxi->pbx_xbusd->xbusd_path, "root_num",
703	    "%d", num_roots);
704	if (err) {
705		aprint_error("pciback: can't write to %s/root_num: "
706		    "%d\n", pbxi->pbx_xbusd->xbusd_path, err);
707	}
708}
709
710static int
711pciback_xenbus_evthandler(void * arg)
712{
713	struct pb_xenbus_instance *pbxi = arg;
714	struct pciback_pci_dev *pbd;
715	struct xen_pci_op *op = &pbxi->pbx_sh_info->op;
716	u_int bus, dev, func;
717
718	hypervisor_clear_event(pbxi->pbx_evtchn);
719	if (xen_atomic_test_bit(&pbxi->pbx_sh_info->flags,
720	    _XEN_PCIF_active) == 0)
721		return 0;
722	if (op->domain != 0) {
723		aprint_error("pciback: domain %d != 0", op->domain);
724		op->err = XEN_PCI_ERR_dev_not_found;
725		goto end;
726	}
727	bus = op->bus;
728	dev = (op->devfn >> 3) & 0xff;
729	func = (op->devfn) & 0x7;
730	SLIST_FOREACH(pbd, &pbxi->pbx_pb_pci_dev, pb_guest_next) {
731		if (pbd->pb_bus == bus &&
732		    pbd->pb_device == dev &&
733		    pbd->pb_function == func)
734			break;
735	}
736	if (pbd == NULL) {
737		aprint_debug("pciback: %02x:%02x.%x not found\n",
738		    bus, dev, func);
739		op->err = XEN_PCI_ERR_dev_not_found;
740		goto end;
741	}
742	switch(op->cmd) {
743	case XEN_PCI_OP_conf_read:
744		op->err = XEN_PCI_ERR_success;
745		switch (op->size) {
746		case 1:
747			op->value = pciback_read_byte(pbd->pb_pc, pbd->pb_tag,
748			    op->offset);
749			break;
750		case 2:
751			op->value = pciback_read_word(pbd->pb_pc, pbd->pb_tag,
752			    op->offset);
753			break;
754		case 4:
755			op->value = pci_conf_read(pbd->pb_pc, pbd->pb_tag,
756			    op->offset);
757			break;
758		default:
759			aprint_error("pciback: bad size %d\n", op->size);
760			break;
761		}
762		break;
763	case XEN_PCI_OP_conf_write:
764		op->err = XEN_PCI_ERR_success;
765		switch(op->size) {
766		case 1:
767			pciback_write_byte(pbd->pb_pc, pbd->pb_tag,
768			    op->offset, op->value);
769			break;
770		case 2:
771			pciback_write_word(pbd->pb_pc, pbd->pb_tag,
772			    op->offset, op->value);
773			break;
774		case 4:
775			pci_conf_write(pbd->pb_pc, pbd->pb_tag,
776			    op->offset, op->value);
777			break;
778		default:
779			aprint_error("pciback: bad size %d\n", op->size);
780			op->err = XEN_PCI_ERR_invalid_offset;
781			break;
782		}
783		break;
784	default:
785		aprint_error("pciback: unknown cmd %d\n", op->cmd);
786		op->err = XEN_PCI_ERR_not_implemented;
787	}
788end:
789	xen_atomic_clear_bit(&pbxi->pbx_sh_info->flags, _XEN_PCIF_active);
790	hypervisor_notify_via_evtchn(pbxi->pbx_evtchn);
791	return 1;
792}
793