xref: /openbsd/sys/dev/pv/xen.c (revision 264ca280)
1 /*	$OpenBSD: xen.c,v 1.57 2016/07/29 21:27:43 mikeb Exp $	*/
2 
3 /*
4  * Copyright (c) 2015 Mike Belopuhov
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/param.h>
20 
21 /* Xen requires locked atomic operations */
22 #ifndef MULTIPROCESSOR
23 #define _XENMPATOMICS
24 #define MULTIPROCESSOR
25 #endif
26 #include <sys/atomic.h>
27 #ifdef _XENMPATOMICS
28 #undef MULTIPROCESSOR
29 #undef _XENMPATOMICS
30 #endif
31 
32 #include <sys/systm.h>
33 #include <sys/proc.h>
34 #include <sys/signal.h>
35 #include <sys/signalvar.h>
36 #include <sys/malloc.h>
37 #include <sys/kernel.h>
38 #include <sys/device.h>
39 #include <sys/task.h>
40 #include <sys/syslog.h>
41 
42 #include <machine/bus.h>
43 #include <machine/cpu.h>
44 #include <machine/cpufunc.h>
45 
46 #include <uvm/uvm_extern.h>
47 
48 #include <machine/i82489var.h>
49 
50 #include <dev/rndvar.h>
51 
52 #include <dev/pv/pvvar.h>
53 #include <dev/pv/pvreg.h>
54 #include <dev/pv/xenreg.h>
55 #include <dev/pv/xenvar.h>
56 
57 struct xen_softc *xen_sc;
58 
59 int	xen_init_hypercall(struct xen_softc *);
60 int	xen_getfeatures(struct xen_softc *);
61 int	xen_init_info_page(struct xen_softc *);
62 int	xen_init_cbvec(struct xen_softc *);
63 int	xen_init_interrupts(struct xen_softc *);
64 int	xen_init_grant_tables(struct xen_softc *);
65 struct xen_gntent *
66 	xen_grant_table_grow(struct xen_softc *);
67 int	xen_grant_table_alloc(struct xen_softc *, grant_ref_t *);
68 void	xen_grant_table_free(struct xen_softc *, grant_ref_t);
69 void	xen_grant_table_enter(struct xen_softc *, grant_ref_t, paddr_t,
70 	    int, int);
71 void	xen_grant_table_remove(struct xen_softc *, grant_ref_t);
72 void	xen_disable_emulated_devices(struct xen_softc *);
73 
74 int 	xen_match(struct device *, void *, void *);
75 void	xen_attach(struct device *, struct device *, void *);
76 void	xen_deferred(struct device *);
77 void	xen_control(void *);
78 void	xen_resume(struct device *);
79 int	xen_activate(struct device *, int);
80 int	xen_probe_devices(struct xen_softc *);
81 
82 int	xen_bus_dmamap_create(bus_dma_tag_t, bus_size_t, int, bus_size_t,
83 	    bus_size_t, int, bus_dmamap_t *);
84 void	xen_bus_dmamap_destroy(bus_dma_tag_t, bus_dmamap_t);
85 int	xen_bus_dmamap_load(bus_dma_tag_t, bus_dmamap_t, void *, bus_size_t,
86 	    struct proc *, int);
87 int	xen_bus_dmamap_load_mbuf(bus_dma_tag_t, bus_dmamap_t, struct mbuf *,
88 	    int);
89 void	xen_bus_dmamap_unload(bus_dma_tag_t, bus_dmamap_t);
90 void	xen_bus_dmamap_sync(bus_dma_tag_t, bus_dmamap_t, bus_addr_t,
91 	    bus_size_t, int);
92 
93 int	xs_attach(struct xen_softc *);
94 
95 struct cfdriver xen_cd = {
96 	NULL, "xen", DV_DULL
97 };
98 
99 const struct cfattach xen_ca = {
100 	sizeof(struct xen_softc), xen_match, xen_attach, NULL, xen_activate
101 };
102 
103 struct bus_dma_tag xen_bus_dma_tag = {
104 	NULL,
105 	xen_bus_dmamap_create,
106 	xen_bus_dmamap_destroy,
107 	xen_bus_dmamap_load,
108 	xen_bus_dmamap_load_mbuf,
109 	NULL,
110 	NULL,
111 	xen_bus_dmamap_unload,
112 	xen_bus_dmamap_sync,
113 	_bus_dmamem_alloc,
114 	NULL,
115 	_bus_dmamem_free,
116 	_bus_dmamem_map,
117 	_bus_dmamem_unmap,
118 	NULL,
119 };
120 
121 int
122 xen_match(struct device *parent, void *match, void *aux)
123 {
124 	struct pv_attach_args *pva = aux;
125 	struct pvbus_hv *hv = &pva->pva_hv[PVBUS_XEN];
126 
127 	if (hv->hv_base == 0)
128 		return (0);
129 
130 	return (1);
131 }
132 
133 void
134 xen_attach(struct device *parent, struct device *self, void *aux)
135 {
136 	struct pv_attach_args *pva = (struct pv_attach_args *)aux;
137 	struct pvbus_hv *hv = &pva->pva_hv[PVBUS_XEN];
138 	struct xen_softc *sc = (struct xen_softc *)self;
139 
140 	sc->sc_base = hv->hv_base;
141 
142 	if (xen_init_hypercall(sc))
143 		return;
144 
145 	/* Wire it up to the global */
146 	xen_sc = sc;
147 
148 	if (xen_getfeatures(sc))
149 		return;
150 
151 	if (xen_init_info_page(sc))
152 		return;
153 
154 	xen_init_cbvec(sc);
155 
156 	if (xen_init_interrupts(sc))
157 		return;
158 
159 	if (xen_init_grant_tables(sc))
160 		return;
161 
162 	if (xs_attach(sc))
163 		return;
164 
165 	xen_probe_devices(sc);
166 
167 	/* pvbus(4) key/value interface */
168 	hv->hv_kvop = xs_kvop;
169 	hv->hv_arg = sc;
170 
171 	xen_disable_emulated_devices(sc);
172 
173 	config_mountroot(self, xen_deferred);
174 }
175 
176 void
177 xen_deferred(struct device *self)
178 {
179 	struct xen_softc *sc = (struct xen_softc *)self;
180 
181 	if (!(sc->sc_flags & XSF_CBVEC)) {
182 		DPRINTF("%s: callback vector hasn't been established\n",
183 		    sc->sc_dev.dv_xname);
184 		return;
185 	}
186 
187 	xen_intr_enable();
188 
189 	if (xs_watch(sc, "control", "shutdown", &sc->sc_ctltsk,
190 	    xen_control, sc))
191 		printf("%s: failed to setup shutdown control watch\n",
192 		    sc->sc_dev.dv_xname);
193 }
194 
195 void
196 xen_control(void *arg)
197 {
198 	struct xen_softc *sc = arg;
199 	struct xs_transaction xst;
200 	char action[128];
201 	int error;
202 
203 	memset(&xst, 0, sizeof(xst));
204 	xst.xst_id = 0;
205 	xst.xst_sc = sc->sc_xs;
206 
207 	error = xs_getprop(sc, "control", "shutdown", action, sizeof(action));
208 	if (error) {
209 		if (error != ENOENT)
210 			printf("%s: failed to process control event\n",
211 			    sc->sc_dev.dv_xname);
212 		return;
213 	}
214 
215 	if (strlen(action) == 0)
216 		return;
217 
218 	/* Acknowledge the event */
219 	xs_setprop(sc, "control", "shutdown", "", 0);
220 
221 	if (strcmp(action, "halt") == 0 || strcmp(action, "poweroff") == 0) {
222 		extern int allowpowerdown;
223 
224 		if (allowpowerdown == 0)
225 			return;
226 
227 		suspend_randomness();
228 
229 		log(LOG_KERN | LOG_NOTICE, "Shutting down in response to "
230 		    "request from Xen host\n");
231 		prsignal(initprocess, SIGUSR2);
232 	} else if (strcmp(action, "reboot") == 0) {
233 		extern int allowpowerdown;
234 
235 		if (allowpowerdown == 0)
236 			return;
237 
238 		suspend_randomness();
239 
240 		log(LOG_KERN | LOG_NOTICE, "Rebooting in response to request "
241 		    "from Xen host\n");
242 		prsignal(initprocess, SIGINT);
243 	} else if (strcmp(action, "crash") == 0) {
244 		panic("xen told us to do this");
245 	} else if (strcmp(action, "suspend") == 0) {
246 		/* Not implemented yet */
247 	} else {
248 		printf("%s: unknown shutdown event \"%s\"\n",
249 		    sc->sc_dev.dv_xname, action);
250 	}
251 }
252 
253 void
254 xen_resume(struct device *self)
255 {
256 }
257 
258 int
259 xen_activate(struct device *self, int act)
260 {
261 	int rv = 0;
262 
263 	switch (act) {
264 	case DVACT_RESUME:
265 		xen_resume(self);
266 		break;
267 	}
268 	return (rv);
269 }
270 
271 int
272 xen_init_hypercall(struct xen_softc *sc)
273 {
274 	extern void *xen_hypercall_page;
275 	uint32_t regs[4];
276 	paddr_t pa;
277 
278 	/* Get hypercall page configuration MSR */
279 	CPUID(sc->sc_base + CPUID_OFFSET_XEN_HYPERCALL,
280 	    regs[0], regs[1], regs[2], regs[3]);
281 
282 	/* We don't support more than one hypercall page */
283 	if (regs[0] != 1) {
284 		printf(": requested %d hypercall pages\n", regs[0]);
285 		return (-1);
286 	}
287 
288 	sc->sc_hc = &xen_hypercall_page;
289 
290 	if (!pmap_extract(pmap_kernel(), (vaddr_t)sc->sc_hc, &pa)) {
291 		printf(": hypercall page PA extraction failed\n");
292 		return (-1);
293 	}
294 	wrmsr(regs[1], pa);
295 
296 	return (0);
297 }
298 
299 int
300 xen_hypercall(struct xen_softc *sc, int op, int argc, ...)
301 {
302 	va_list ap;
303 	ulong argv[5];
304 	int i;
305 
306 	if (argc < 0 || argc > 5)
307 		return (-1);
308 	va_start(ap, argc);
309 	for (i = 0; i < argc; i++)
310 		argv[i] = (ulong)va_arg(ap, ulong);
311 	return (xen_hypercallv(sc, op, argc, argv));
312 }
313 
314 int
315 xen_hypercallv(struct xen_softc *sc, int op, int argc, ulong *argv)
316 {
317 	ulong hcall;
318 	int rv = 0;
319 
320 	hcall = (ulong)sc->sc_hc + op * 32;
321 
322 #if defined(XEN_DEBUG) && disabled
323 	{
324 		int i;
325 
326 		printf("hypercall %d", op);
327 		if (argc > 0) {
328 			printf(", args {");
329 			for (i = 0; i < argc; i++)
330 				printf(" %#lx", argv[i]);
331 			printf(" }\n");
332 		} else
333 			printf("\n");
334 	}
335 #endif
336 
337 	switch (argc) {
338 	case 0: {
339 		HYPERCALL_RES1;
340 		__asm__ volatile (			\
341 			  HYPERCALL_LABEL		\
342 			: HYPERCALL_OUT1		\
343 			: HYPERCALL_PTR(hcall)		\
344 			: HYPERCALL_CLOBBER		\
345 		);
346 		HYPERCALL_RET(rv);
347 		break;
348 	}
349 	case 1: {
350 		HYPERCALL_RES1; HYPERCALL_RES2;
351 		HYPERCALL_ARG1(argv[0]);
352 		__asm__ volatile (			\
353 			  HYPERCALL_LABEL		\
354 			: HYPERCALL_OUT1 HYPERCALL_OUT2	\
355 			: HYPERCALL_IN1			\
356 			, HYPERCALL_PTR(hcall)		\
357 			: HYPERCALL_CLOBBER		\
358 		);
359 		HYPERCALL_RET(rv);
360 		break;
361 	}
362 	case 2: {
363 		HYPERCALL_RES1; HYPERCALL_RES2; HYPERCALL_RES3;
364 		HYPERCALL_ARG1(argv[0]); HYPERCALL_ARG2(argv[1]);
365 		__asm__ volatile (			\
366 			  HYPERCALL_LABEL		\
367 			: HYPERCALL_OUT1 HYPERCALL_OUT2	\
368 			  HYPERCALL_OUT3		\
369 			: HYPERCALL_IN1	HYPERCALL_IN2	\
370 			, HYPERCALL_PTR(hcall)		\
371 			: HYPERCALL_CLOBBER		\
372 		);
373 		HYPERCALL_RET(rv);
374 		break;
375 	}
376 	case 3: {
377 		HYPERCALL_RES1; HYPERCALL_RES2; HYPERCALL_RES3;
378 		HYPERCALL_RES4;
379 		HYPERCALL_ARG1(argv[0]); HYPERCALL_ARG2(argv[1]);
380 		HYPERCALL_ARG3(argv[2]);
381 		__asm__ volatile (			\
382 			  HYPERCALL_LABEL		\
383 			: HYPERCALL_OUT1 HYPERCALL_OUT2	\
384 			  HYPERCALL_OUT3 HYPERCALL_OUT4	\
385 			: HYPERCALL_IN1	HYPERCALL_IN2	\
386 			  HYPERCALL_IN3			\
387 			, HYPERCALL_PTR(hcall)		\
388 			: HYPERCALL_CLOBBER		\
389 		);
390 		HYPERCALL_RET(rv);
391 		break;
392 	}
393 	case 4: {
394 		HYPERCALL_RES1; HYPERCALL_RES2; HYPERCALL_RES3;
395 		HYPERCALL_RES4; HYPERCALL_RES5;
396 		HYPERCALL_ARG1(argv[0]); HYPERCALL_ARG2(argv[1]);
397 		HYPERCALL_ARG3(argv[2]); HYPERCALL_ARG4(argv[3]);
398 		__asm__ volatile (			\
399 			  HYPERCALL_LABEL		\
400 			: HYPERCALL_OUT1 HYPERCALL_OUT2	\
401 			  HYPERCALL_OUT3 HYPERCALL_OUT4	\
402 			  HYPERCALL_OUT5		\
403 			: HYPERCALL_IN1	HYPERCALL_IN2	\
404 			  HYPERCALL_IN3	HYPERCALL_IN4	\
405 			, HYPERCALL_PTR(hcall)		\
406 			: HYPERCALL_CLOBBER		\
407 		);
408 		HYPERCALL_RET(rv);
409 		break;
410 	}
411 	case 5: {
412 		HYPERCALL_RES1; HYPERCALL_RES2; HYPERCALL_RES3;
413 		HYPERCALL_RES4; HYPERCALL_RES5; HYPERCALL_RES6;
414 		HYPERCALL_ARG1(argv[0]); HYPERCALL_ARG2(argv[1]);
415 		HYPERCALL_ARG3(argv[2]); HYPERCALL_ARG4(argv[3]);
416 		HYPERCALL_ARG5(argv[4]);
417 		__asm__ volatile (			\
418 			  HYPERCALL_LABEL		\
419 			: HYPERCALL_OUT1 HYPERCALL_OUT2	\
420 			  HYPERCALL_OUT3 HYPERCALL_OUT4	\
421 			  HYPERCALL_OUT5 HYPERCALL_OUT6	\
422 			: HYPERCALL_IN1	HYPERCALL_IN2	\
423 			  HYPERCALL_IN3	HYPERCALL_IN4	\
424 			  HYPERCALL_IN5			\
425 			, HYPERCALL_PTR(hcall)		\
426 			: HYPERCALL_CLOBBER		\
427 		);
428 		HYPERCALL_RET(rv);
429 		break;
430 	}
431 	default:
432 		DPRINTF("%s: wrong number of arguments: %d\n", __func__, argc);
433 		rv = -1;
434 		break;
435 	}
436 	return (rv);
437 }
438 
439 int
440 xen_getfeatures(struct xen_softc *sc)
441 {
442 	struct xen_feature_info xfi;
443 
444 	memset(&xfi, 0, sizeof(xfi));
445 	if (xen_hypercall(sc, XC_VERSION, 2, XENVER_get_features, &xfi) < 0) {
446 		printf(": failed to fetch features\n");
447 		return (-1);
448 	}
449 	sc->sc_features = xfi.submap;
450 #ifdef XEN_DEBUG
451 	printf(": features %b", sc->sc_features,
452 	    "\20\014DOM0\013PIRQ\012PVCLOCK\011CBVEC\010GNTFLAGS\007HMA"
453 	    "\006PTUPD\005PAE4G\004SUPERVISOR\003AUTOPMAP\002WDT\001WPT");
454 #else
455 	printf(": features %#x", sc->sc_features);
456 #endif
457 	return (0);
458 }
459 
460 #ifdef XEN_DEBUG
461 void
462 xen_print_info_page(void)
463 {
464 	struct xen_softc *sc = xen_sc;
465 	struct shared_info *s = sc->sc_ipg;
466 	struct vcpu_info *v;
467 	int i;
468 
469 	virtio_membar_sync();
470 	for (i = 0; i < XEN_LEGACY_MAX_VCPUS; i++) {
471 		v = &s->vcpu_info[i];
472 		if (!v->evtchn_upcall_pending && !v->evtchn_upcall_mask &&
473 		    !v->evtchn_pending_sel && !v->time.version &&
474 		    !v->time.tsc_timestamp && !v->time.system_time &&
475 		    !v->time.tsc_to_system_mul && !v->time.tsc_shift)
476 			continue;
477 		printf("vcpu%d:\n"
478 		    "   upcall_pending=%02x upcall_mask=%02x pending_sel=%#lx\n"
479 		    "   time version=%u tsc=%llu system=%llu\n"
480 		    "   time mul=%u shift=%d\n",
481 		    i, v->evtchn_upcall_pending, v->evtchn_upcall_mask,
482 		    v->evtchn_pending_sel, v->time.version,
483 		    v->time.tsc_timestamp, v->time.system_time,
484 		    v->time.tsc_to_system_mul, v->time.tsc_shift);
485 	}
486 	printf("pending events: ");
487 	for (i = 0; i < nitems(s->evtchn_pending); i++) {
488 		if (s->evtchn_pending[i] == 0)
489 			continue;
490 		printf(" %d:%#lx", i, s->evtchn_pending[i]);
491 	}
492 	printf("\nmasked events: ");
493 	for (i = 0; i < nitems(s->evtchn_mask); i++) {
494 		if (s->evtchn_mask[i] == 0xffffffffffffffffULL)
495 			continue;
496 		printf(" %d:%#lx", i, s->evtchn_mask[i]);
497 	}
498 	printf("\nwc ver=%u sec=%u nsec=%u\n", s->wc_version, s->wc_sec,
499 	    s->wc_nsec);
500 	printf("arch maxpfn=%lu framelist=%lu nmi=%lu\n", s->arch.max_pfn,
501 	    s->arch.pfn_to_mfn_frame_list, s->arch.nmi_reason);
502 }
503 #endif	/* XEN_DEBUG */
504 
505 int
506 xen_init_info_page(struct xen_softc *sc)
507 {
508 	struct xen_add_to_physmap xatp;
509 	paddr_t pa;
510 
511 	sc->sc_ipg = malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT | M_ZERO);
512 	if (sc->sc_ipg == NULL) {
513 		printf(": failed to allocate shared info page\n");
514 		return (-1);
515 	}
516 	if (!pmap_extract(pmap_kernel(), (vaddr_t)sc->sc_ipg, &pa)) {
517 		printf(": shared info page PA extraction failed\n");
518 		free(sc->sc_ipg, M_DEVBUF, PAGE_SIZE);
519 		return (-1);
520 	}
521 	xatp.domid = DOMID_SELF;
522 	xatp.idx = 0;
523 	xatp.space = XENMAPSPACE_shared_info;
524 	xatp.gpfn = atop(pa);
525 	if (xen_hypercall(sc, XC_MEMORY, 2, XENMEM_add_to_physmap, &xatp)) {
526 		printf(": failed to register shared info page\n");
527 		free(sc->sc_ipg, M_DEVBUF, PAGE_SIZE);
528 		return (-1);
529 	}
530 	return (0);
531 }
532 
533 int
534 xen_init_cbvec(struct xen_softc *sc)
535 {
536 	struct xen_hvm_param xhp;
537 
538 	if ((sc->sc_features & XENFEAT_CBVEC) == 0)
539 		return (ENOENT);
540 
541 	xhp.domid = DOMID_SELF;
542 	xhp.index = HVM_PARAM_CALLBACK_IRQ;
543 	xhp.value = HVM_CALLBACK_VECTOR(LAPIC_XEN_VECTOR);
544 	if (xen_hypercall(sc, XC_HVM, 2, HVMOP_set_param, &xhp)) {
545 		/* Will retry with the xspd(4) PCI interrupt */
546 		return (ENOENT);
547 	}
548 	DPRINTF(", idtvec %d", LAPIC_XEN_VECTOR);
549 
550 	sc->sc_flags |= XSF_CBVEC;
551 
552 	return (0);
553 }
554 
555 int
556 xen_init_interrupts(struct xen_softc *sc)
557 {
558 	int i;
559 
560 	sc->sc_irq = LAPIC_XEN_VECTOR;
561 
562 	/*
563 	 * Clear all pending events and mask all interrupts
564 	 */
565 	for (i = 0; i < nitems(sc->sc_ipg->evtchn_pending); i++) {
566 		sc->sc_ipg->evtchn_pending[i] = 0;
567 		sc->sc_ipg->evtchn_mask[i] = ~0UL;
568 	}
569 
570 	SLIST_INIT(&sc->sc_intrs);
571 
572 	return (0);
573 }
574 
575 static int
576 xen_evtchn_hypercall(struct xen_softc *sc, int cmd, void *arg, size_t len)
577 {
578 	struct evtchn_op compat;
579 	int error;
580 
581 	error = xen_hypercall(sc, XC_EVTCHN, 2, cmd, arg);
582 	if (error == -ENOXENSYS) {
583 		memset(&compat, 0, sizeof(compat));
584 		compat.cmd = cmd;
585 		memcpy(&compat.u, arg, len);
586 		error = xen_hypercall(sc, XC_OEVTCHN, 1, &compat);
587 	}
588 	return (error);
589 }
590 
591 static inline struct xen_intsrc *
592 xen_lookup_intsrc(struct xen_softc *sc, evtchn_port_t port)
593 {
594 	struct xen_intsrc *xi;
595 
596 	SLIST_FOREACH(xi, &sc->sc_intrs, xi_entry)
597 		if (xi->xi_port == port)
598 			break;
599 	return (xi);
600 }
601 
602 void
603 xen_intr_ack(void)
604 {
605 	struct xen_softc *sc = xen_sc;
606 	struct shared_info *s = sc->sc_ipg;
607 	struct cpu_info *ci = curcpu();
608 	struct vcpu_info *v = &s->vcpu_info[CPU_INFO_UNIT(ci)];
609 
610 	v->evtchn_upcall_pending = 0;
611 	virtio_membar_sync();
612 }
613 
614 void
615 xen_intr(void)
616 {
617 	struct xen_softc *sc = xen_sc;
618 	struct xen_intsrc *xi;
619 	struct shared_info *s = sc->sc_ipg;
620 	struct cpu_info *ci = curcpu();
621 	struct vcpu_info *v = &s->vcpu_info[CPU_INFO_UNIT(ci)];
622 	ulong pending, selector;
623 	int port, bit, row;
624 
625 	v->evtchn_upcall_pending = 0;
626 	selector = atomic_swap_ulong(&v->evtchn_pending_sel, 0);
627 
628 	for (row = 0; selector > 0; selector >>= 1, row++) {
629 		if ((selector & 1) == 0)
630 			continue;
631 		pending = sc->sc_ipg->evtchn_pending[row] &
632 		    ~(sc->sc_ipg->evtchn_mask[row]);
633 		for (bit = 0; pending > 0; pending >>= 1, bit++) {
634 			if ((pending & 1) == 0)
635 				continue;
636 			sc->sc_ipg->evtchn_pending[row] &= ~(1 << bit);
637 			virtio_membar_producer();
638 			port = (row * LONG_BIT) + bit;
639 			if ((xi = xen_lookup_intsrc(sc, port)) == NULL) {
640 				printf("%s: unhandled interrupt on port %u\n",
641 				    sc->sc_dev.dv_xname, port);
642 				continue;
643 			}
644 			xi->xi_evcnt.ec_count++;
645 			task_add(xi->xi_taskq, &xi->xi_task);
646 		}
647 	}
648 }
649 
650 void
651 xen_intr_schedule(xen_intr_handle_t xih)
652 {
653 	struct xen_softc *sc = xen_sc;
654 	struct xen_intsrc *xi;
655 
656 	if ((xi = xen_lookup_intsrc(sc, (evtchn_port_t)xih)) != NULL)
657 		task_add(xi->xi_taskq, &xi->xi_task);
658 }
659 
660 void
661 xen_intr_signal(xen_intr_handle_t xih)
662 {
663 	struct xen_softc *sc = xen_sc;
664 	struct xen_intsrc *xi;
665 	struct evtchn_send es;
666 
667 	if ((xi = xen_lookup_intsrc(sc, (evtchn_port_t)xih)) != NULL) {
668 		es.port = xi->xi_port;
669 		xen_evtchn_hypercall(sc, EVTCHNOP_send, &es, sizeof(es));
670 	}
671 }
672 
673 int
674 xen_intr_establish(evtchn_port_t port, xen_intr_handle_t *xih, int domain,
675     void (*handler)(void *), void *arg, char *name)
676 {
677 	struct xen_softc *sc = xen_sc;
678 	struct xen_intsrc *xi;
679 	struct evtchn_alloc_unbound eau;
680 #ifdef notyet
681 	struct evtchn_bind_vcpu ebv;
682 #endif
683 #if defined(XEN_DEBUG) && disabled
684 	struct evtchn_status es;
685 #endif
686 
687 	if (port && xen_lookup_intsrc(sc, port)) {
688 		DPRINTF("%s: interrupt handler has already been established "
689 		    "for port %u\n", sc->sc_dev.dv_xname, port);
690 		return (-1);
691 	}
692 
693 	xi = malloc(sizeof(*xi), M_DEVBUF, M_NOWAIT | M_ZERO);
694 	if (xi == NULL)
695 		return (-1);
696 
697 	xi->xi_port = (evtchn_port_t)*xih;
698 
699 	xi->xi_taskq = taskq_create(name, 1, IPL_NET, TASKQ_MPSAFE);
700 	if (!xi->xi_taskq) {
701 		printf("%s: failed to create interrupt task for %s\n",
702 		    sc->sc_dev.dv_xname, name);
703 		free(xi, M_DEVBUF, sizeof(*xi));
704 		return (-1);
705 	}
706 	task_set(&xi->xi_task, handler, arg);
707 
708 	if (port == 0) {
709 		/* We're being asked to allocate a new event port */
710 		memset(&eau, 0, sizeof(eau));
711 		eau.dom = DOMID_SELF;
712 		eau.remote_dom = domain;
713 		if (xen_evtchn_hypercall(sc, EVTCHNOP_alloc_unbound, &eau,
714 		    sizeof(eau)) != 0) {
715 			DPRINTF("%s: failed to allocate new event port\n",
716 			    sc->sc_dev.dv_xname);
717 			free(xi, M_DEVBUF, sizeof(*xi));
718 			return (-1);
719 		}
720 		*xih = xi->xi_port = eau.port;
721 	} else {
722 		*xih = xi->xi_port = port;
723 		/*
724 		 * The Event Channel API didn't open this port, so it is not
725 		 * responsible for closing it automatically on unbind.
726 		 */
727 		xi->xi_noclose = 1;
728 	}
729 
730 #ifdef notyet
731 	/* Bind interrupt to VCPU#0 */
732 	memset(&ebv, 0, sizeof(ebv));
733 	ebv.port = xi->xi_port;
734 	ebv.vcpu = 0;
735 	if (xen_evtchn_hypercall(sc, EVTCHNOP_bind_vcpu, &ebv, sizeof(ebv))) {
736 		printf("%s: failed to bind interrupt on port %u to vcpu%d\n",
737 		    sc->sc_dev.dv_xname, ebv.port, ebv.vcpu);
738 	}
739 #endif
740 
741 	evcount_attach(&xi->xi_evcnt, name, &sc->sc_irq);
742 
743 	SLIST_INSERT_HEAD(&sc->sc_intrs, xi, xi_entry);
744 
745 	/* Mask the event port */
746 	setbit((char *)&sc->sc_ipg->evtchn_mask[0], xi->xi_port);
747 
748 #if defined(XEN_DEBUG) && disabled
749 	memset(&es, 0, sizeof(es));
750 	es.dom = DOMID_SELF;
751 	es.port = xi->xi_port;
752 	if (xen_evtchn_hypercall(sc, EVTCHNOP_status, &es, sizeof(es))) {
753 		printf("%s: failed to obtain status for port %d\n",
754 		    sc->sc_dev.dv_xname, es.port);
755 	}
756 	printf("%s: port %u bound to vcpu%u", sc->sc_dev.dv_xname,
757 	    es.port, es.vcpu);
758 	if (es.status == EVTCHNSTAT_interdomain)
759 		printf(": domain %d port %u\n", es.u.interdomain.dom,
760 		    es.u.interdomain.port);
761 	else if (es.status == EVTCHNSTAT_unbound)
762 		printf(": domain %d\n", es.u.unbound.dom);
763 	else if (es.status == EVTCHNSTAT_pirq)
764 		printf(": pirq %u\n", es.u.pirq);
765 	else if (es.status == EVTCHNSTAT_virq)
766 		printf(": virq %u\n", es.u.virq);
767 	else
768 		printf("\n");
769 #endif
770 
771 	return (0);
772 }
773 
774 int
775 xen_intr_disestablish(xen_intr_handle_t xih)
776 {
777 	struct xen_softc *sc = xen_sc;
778 	evtchn_port_t port = (evtchn_port_t)xih;
779 	struct evtchn_close ec;
780 	struct xen_intsrc *xi;
781 
782 	if ((xi = xen_lookup_intsrc(sc, port)) == NULL)
783 		return (-1);
784 
785 	evcount_detach(&xi->xi_evcnt);
786 
787 	SLIST_REMOVE(&sc->sc_intrs, xi, xen_intsrc, xi_entry);
788 
789 	setbit((char *)&sc->sc_ipg->evtchn_mask[0], xi->xi_port);
790 	clrbit((char *)&sc->sc_ipg->evtchn_pending[0], xi->xi_port);
791 	virtio_membar_sync();
792 
793 	if (!xi->xi_noclose) {
794 		ec.port = xi->xi_port;
795 		if (xen_evtchn_hypercall(sc, EVTCHNOP_close, &ec, sizeof(ec))) {
796 			DPRINTF("%s: failed to close event port %u\n",
797 			    sc->sc_dev.dv_xname, xi->xi_port);
798 		}
799 	}
800 
801 	free(xi, M_DEVBUF, sizeof(*xi));
802 	return (0);
803 }
804 
805 void
806 xen_intr_enable(void)
807 {
808 	struct xen_softc *sc = xen_sc;
809 	struct xen_intsrc *xi;
810 	struct evtchn_unmask eu;
811 
812 	SLIST_FOREACH(xi, &sc->sc_intrs, xi_entry) {
813 		if (!xi->xi_masked) {
814 			eu.port = xi->xi_port;
815 			if (xen_evtchn_hypercall(sc, EVTCHNOP_unmask, &eu,
816 			    sizeof(eu)))
817 				printf("%s: unmasking port %u failed\n",
818 				    sc->sc_dev.dv_xname, xi->xi_port);
819 			virtio_membar_sync();
820 			if (isset((char *)&sc->sc_ipg->evtchn_mask[0],
821 			    xi->xi_port))
822 				printf("%s: port %u is still masked\n",
823 				    sc->sc_dev.dv_xname, xi->xi_port);
824 		}
825 	}
826 }
827 
828 void
829 xen_intr_mask(xen_intr_handle_t xih)
830 {
831 	struct xen_softc *sc = xen_sc;
832 	evtchn_port_t port = (evtchn_port_t)xih;
833 	struct xen_intsrc *xi;
834 
835 	if ((xi = xen_lookup_intsrc(sc, port)) != NULL) {
836 		xi->xi_masked = 1;
837 		setbit((char *)&sc->sc_ipg->evtchn_mask[0], xi->xi_port);
838 		virtio_membar_sync();
839 	}
840 }
841 
842 int
843 xen_intr_unmask(xen_intr_handle_t xih)
844 {
845 	struct xen_softc *sc = xen_sc;
846 	evtchn_port_t port = (evtchn_port_t)xih;
847 	struct xen_intsrc *xi;
848 	struct evtchn_unmask eu;
849 
850 	if ((xi = xen_lookup_intsrc(sc, port)) != NULL) {
851 		xi->xi_masked = 0;
852 		if (!isset((char *)&sc->sc_ipg->evtchn_mask[0], xi->xi_port))
853 			return (0);
854 		eu.port = xi->xi_port;
855 		return (xen_evtchn_hypercall(sc, EVTCHNOP_unmask, &eu,
856 		    sizeof(eu)));
857 	}
858 	return (0);
859 }
860 
861 int
862 xen_init_grant_tables(struct xen_softc *sc)
863 {
864 	struct gnttab_query_size gqs;
865 
866 	gqs.dom = DOMID_SELF;
867 	if (xen_hypercall(sc, XC_GNTTAB, 3, GNTTABOP_query_size, &gqs, 1)) {
868 		printf(": failed the query for grant table pages\n");
869 		return (-1);
870 	}
871 	if (gqs.nr_frames == 0 || gqs.nr_frames > gqs.max_nr_frames) {
872 		printf(": invalid number of grant table pages: %u/%u\n",
873 		    gqs.nr_frames, gqs.max_nr_frames);
874 		return (-1);
875 	}
876 
877 	sc->sc_gntmax = gqs.max_nr_frames;
878 
879 	sc->sc_gnt = mallocarray(sc->sc_gntmax + 1, sizeof(struct xen_gntent),
880 	    M_DEVBUF, M_ZERO | M_NOWAIT);
881 	if (sc->sc_gnt == NULL) {
882 		printf(": failed to allocate grant table lookup table\n");
883 		return (-1);
884 	}
885 
886 	mtx_init(&sc->sc_gntmtx, IPL_NET);
887 
888 	if (xen_grant_table_grow(sc) == NULL) {
889 		free(sc->sc_gnt, M_DEVBUF, sc->sc_gntmax *
890 		    sizeof(struct xen_gntent));
891 		return (-1);
892 	}
893 
894 	printf(", %u grant table frames", sc->sc_gntmax);
895 
896 	xen_bus_dma_tag._cookie = sc;
897 
898 	return (0);
899 }
900 
901 struct xen_gntent *
902 xen_grant_table_grow(struct xen_softc *sc)
903 {
904 	struct xen_add_to_physmap xatp;
905 	struct xen_gntent *ge;
906 	paddr_t pa;
907 
908 	if (sc->sc_gntcnt == sc->sc_gntmax) {
909 		printf("%s: grant table frame allotment limit reached\n",
910 		    sc->sc_dev.dv_xname);
911 		return (NULL);
912 	}
913 
914 	mtx_enter(&sc->sc_gntmtx);
915 
916 	ge = &sc->sc_gnt[sc->sc_gntcnt];
917 	ge->ge_table = km_alloc(PAGE_SIZE, &kv_any, &kp_zero, &kd_nowait);
918 	if (ge->ge_table == NULL) {
919 		free(ge, M_DEVBUF, sizeof(*ge));
920 		mtx_leave(&sc->sc_gntmtx);
921 		return (NULL);
922 	}
923 	if (!pmap_extract(pmap_kernel(), (vaddr_t)ge->ge_table, &pa)) {
924 		printf("%s: grant table page PA extraction failed\n",
925 		    sc->sc_dev.dv_xname);
926 		km_free(ge->ge_table, PAGE_SIZE, &kv_any, &kp_zero);
927 		free(ge, M_DEVBUF, sizeof(*ge));
928 		mtx_leave(&sc->sc_gntmtx);
929 		return (NULL);
930 	}
931 	xatp.domid = DOMID_SELF;
932 	xatp.idx = sc->sc_gntcnt;
933 	xatp.space = XENMAPSPACE_grant_table;
934 	xatp.gpfn = atop(pa);
935 	if (xen_hypercall(sc, XC_MEMORY, 2, XENMEM_add_to_physmap, &xatp)) {
936 		printf("%s: failed to add a grant table page\n",
937 		    sc->sc_dev.dv_xname);
938 		km_free(ge->ge_table, PAGE_SIZE, &kv_any, &kp_zero);
939 		free(ge, M_DEVBUF, sizeof(*ge));
940 		mtx_leave(&sc->sc_gntmtx);
941 		return (NULL);
942 	}
943 	ge->ge_start = sc->sc_gntcnt * GNTTAB_NEPG;
944 	/* First page has 8 reserved entries */
945 	ge->ge_reserved = ge->ge_start == 0 ? GNTTAB_NR_RESERVED_ENTRIES : 0;
946 	ge->ge_free = GNTTAB_NEPG - ge->ge_reserved;
947 	ge->ge_next = ge->ge_reserved;
948 	mtx_init(&ge->ge_mtx, IPL_NET);
949 
950 	sc->sc_gntcnt++;
951 	mtx_leave(&sc->sc_gntmtx);
952 
953 	return (ge);
954 }
955 
956 int
957 xen_grant_table_alloc(struct xen_softc *sc, grant_ref_t *ref)
958 {
959 	struct xen_gntent *ge;
960 	int i;
961 
962 	/* Start with a previously allocated table page */
963 	ge = &sc->sc_gnt[sc->sc_gntcnt - 1];
964 	if (ge->ge_free > 0) {
965 		mtx_enter(&ge->ge_mtx);
966 		if (ge->ge_free > 0)
967 			goto search;
968 		mtx_leave(&ge->ge_mtx);
969 	}
970 
971 	/* Try other existing table pages */
972 	for (i = 0; i < sc->sc_gntcnt; i++) {
973 		ge = &sc->sc_gnt[i];
974 		if (ge->ge_free == 0)
975 			continue;
976 		mtx_enter(&ge->ge_mtx);
977 		if (ge->ge_free > 0)
978 			goto search;
979 		mtx_leave(&ge->ge_mtx);
980 	}
981 
982  alloc:
983 	/* Allocate a new table page */
984 	if ((ge = xen_grant_table_grow(sc)) == NULL)
985 		return (-1);
986 
987 	mtx_enter(&ge->ge_mtx);
988 	if (ge->ge_free == 0) {
989 		/* We were not fast enough... */
990 		mtx_leave(&ge->ge_mtx);
991 		goto alloc;
992 	}
993 
994  search:
995 	for (i = ge->ge_next;
996 	     /* Math works here because GNTTAB_NEPG is a power of 2 */
997 	     i != ((ge->ge_next + GNTTAB_NEPG - 1) & (GNTTAB_NEPG - 1));
998 	     i++) {
999 		if (i == GNTTAB_NEPG)
1000 			i = 0;
1001 		if (ge->ge_reserved && i < ge->ge_reserved)
1002 			continue;
1003 		if (ge->ge_table[i].flags != GTF_invalid &&
1004 		    ge->ge_table[i].frame != 0)
1005 			continue;
1006 		*ref = ge->ge_start + i;
1007 		/* XXX Mark as taken */
1008 		ge->ge_table[i].frame = 0xffffffff;
1009 		if ((ge->ge_next = i + 1) == GNTTAB_NEPG)
1010 			ge->ge_next = ge->ge_reserved;
1011 		ge->ge_free--;
1012 		mtx_leave(&ge->ge_mtx);
1013 		return (0);
1014 	}
1015 	mtx_leave(&ge->ge_mtx);
1016 
1017 	panic("page full, sc %p gnt %p (%d) ge %p", sc, sc->sc_gnt,
1018 	    sc->sc_gntcnt, ge);
1019 	return (-1);
1020 }
1021 
1022 void
1023 xen_grant_table_free(struct xen_softc *sc, grant_ref_t ref)
1024 {
1025 	struct xen_gntent *ge;
1026 
1027 #ifdef XEN_DEBUG
1028 	if (ref > sc->sc_gntcnt * GNTTAB_NEPG)
1029 		panic("unmanaged ref %u sc %p gnt %p (%d)", ref, sc,
1030 		    sc->sc_gnt, sc->sc_gntcnt);
1031 #endif
1032 	ge = &sc->sc_gnt[ref / GNTTAB_NEPG];
1033 	mtx_enter(&ge->ge_mtx);
1034 #ifdef XEN_DEBUG
1035 	if (ref < ge->ge_start || ref > ge->ge_start + GNTTAB_NEPG) {
1036 		mtx_leave(&ge->ge_mtx);
1037 		panic("out of bounds ref %u ge %p start %u sc %p gnt %p",
1038 		    ref, ge, ge->ge_start, sc, sc->sc_gnt);
1039 	}
1040 #endif
1041 	ref -= ge->ge_start;
1042 	if (ge->ge_table[ref].flags != GTF_invalid) {
1043 		mtx_leave(&ge->ge_mtx);
1044 #ifdef XEN_DEBUG
1045 		panic("ref %u is still in use, sc %p gnt %p", ref +
1046 		    ge->ge_start, sc, sc->sc_gnt);
1047 #else
1048 		printf("%s: reference %u is still in use\n",
1049 		    sc->sc_dev.dv_xname, ref + ge->ge_start);
1050 #endif
1051 	}
1052 	ge->ge_table[ref].frame = 0;
1053 	ge->ge_next = ref;
1054 	ge->ge_free++;
1055 	mtx_leave(&ge->ge_mtx);
1056 }
1057 
1058 void
1059 xen_grant_table_enter(struct xen_softc *sc, grant_ref_t ref, paddr_t pa,
1060     int domain, int flags)
1061 {
1062 	struct xen_gntent *ge;
1063 
1064 #ifdef XEN_DEBUG
1065 	if (ref > sc->sc_gntcnt * GNTTAB_NEPG)
1066 		panic("unmanaged ref %u sc %p gnt %p (%d)", ref, sc,
1067 		    sc->sc_gnt, sc->sc_gntcnt);
1068 #endif
1069 	ge = &sc->sc_gnt[ref / GNTTAB_NEPG];
1070 #ifdef XEN_DEBUG
1071 	if (ref < ge->ge_start || ref > ge->ge_start + GNTTAB_NEPG) {
1072 		panic("out of bounds ref %u ge %p start %u sc %p gnt %p",
1073 		    ref, ge, ge->ge_start, sc, sc->sc_gnt);
1074 	}
1075 #endif
1076 	ref -= ge->ge_start;
1077 	ge->ge_table[ref].frame = atop(pa);
1078 	ge->ge_table[ref].domid = domain;
1079 	virtio_membar_sync();
1080 	ge->ge_table[ref].flags = GTF_permit_access | flags;
1081 	virtio_membar_sync();
1082 }
1083 
1084 void
1085 xen_grant_table_remove(struct xen_softc *sc, grant_ref_t ref)
1086 {
1087 	struct xen_gntent *ge;
1088 	uint32_t flags, *ptr;
1089 	int loop;
1090 
1091 #ifdef XEN_DEBUG
1092 	if (ref > sc->sc_gntcnt * GNTTAB_NEPG)
1093 		panic("unmanaged ref %u sc %p gnt %p (%d)", ref, sc,
1094 		    sc->sc_gnt, sc->sc_gntcnt);
1095 #endif
1096 	ge = &sc->sc_gnt[ref / GNTTAB_NEPG];
1097 #ifdef XEN_DEBUG
1098 	if (ref < ge->ge_start || ref > ge->ge_start + GNTTAB_NEPG) {
1099 		panic("out of bounds ref %u ge %p start %u sc %p gnt %p",
1100 		    ref, ge, ge->ge_start, sc, sc->sc_gnt);
1101 	}
1102 #endif
1103 	ref -= ge->ge_start;
1104 	/* Invalidate the grant reference */
1105 	virtio_membar_sync();
1106 	ptr = (uint32_t *)&ge->ge_table[ref];
1107 	flags = (ge->ge_table[ref].flags & ~(GTF_reading|GTF_writing)) |
1108 	    (ge->ge_table[ref].domid << 16);
1109 	loop = 0;
1110 	while (atomic_cas_uint(ptr, flags, GTF_invalid) != flags) {
1111 		if (loop++ > 10000000) {
1112 			printf("%s: grant table reference %u is held "
1113 			    "by domain %d\n", sc->sc_dev.dv_xname, ref +
1114 			    ge->ge_start, ge->ge_table[ref].domid);
1115 			return;
1116 		}
1117 		CPU_BUSY_CYCLE();
1118 	}
1119 	ge->ge_table[ref].frame = 0xffffffff;
1120 }
1121 
1122 int
1123 xen_bus_dmamap_create(bus_dma_tag_t t, bus_size_t size, int nsegments,
1124     bus_size_t maxsegsz, bus_size_t boundary, int flags, bus_dmamap_t *dmamp)
1125 {
1126 	struct xen_softc *sc = t->_cookie;
1127 	struct xen_gntmap *gm;
1128 	int i, error;
1129 
1130 	if (maxsegsz < PAGE_SIZE)
1131 		return (EINVAL);
1132 
1133 	/* Allocate a dma map structure */
1134 	error = _bus_dmamap_create(t, size, nsegments, maxsegsz, boundary,
1135 	    flags, dmamp);
1136 	if (error)
1137 		return (error);
1138 	/* Allocate an array of grant table pa<->ref maps */
1139 	gm = mallocarray(nsegments, sizeof(struct xen_gntmap), M_DEVBUF,
1140 	    M_ZERO | ((flags & BUS_DMA_NOWAIT) ? M_NOWAIT : M_WAITOK));
1141 	if (gm == NULL) {
1142 		_bus_dmamap_destroy(t, *dmamp);
1143 		*dmamp = NULL;
1144 		return (ENOMEM);
1145 	}
1146 	/* Wire it to the dma map */
1147 	(*dmamp)->_dm_cookie = gm;
1148 	/* Claim references from the grant table */
1149 	for (i = 0; i < (*dmamp)->_dm_segcnt; i++) {
1150 		if (xen_grant_table_alloc(sc, &gm[i].gm_ref)) {
1151 			xen_bus_dmamap_destroy(t, *dmamp);
1152 			*dmamp = NULL;
1153 			return (ENOBUFS);
1154 		}
1155 	}
1156 	return (0);
1157 }
1158 
1159 void
1160 xen_bus_dmamap_destroy(bus_dma_tag_t t, bus_dmamap_t map)
1161 {
1162 	struct xen_softc *sc = t->_cookie;
1163 	struct xen_gntmap *gm;
1164 	int i;
1165 
1166 	gm = map->_dm_cookie;
1167 	for (i = 0; i < map->_dm_segcnt; i++) {
1168 		if (gm[i].gm_ref == 0)
1169 			continue;
1170 		xen_grant_table_free(sc, gm[i].gm_ref);
1171 	}
1172 	free(gm, M_DEVBUF, map->_dm_segcnt * sizeof(struct xen_gntmap));
1173 	_bus_dmamap_destroy(t, map);
1174 }
1175 
1176 int
1177 xen_bus_dmamap_load(bus_dma_tag_t t, bus_dmamap_t map, void *buf,
1178     bus_size_t buflen, struct proc *p, int flags)
1179 {
1180 	struct xen_softc *sc = t->_cookie;
1181 	struct xen_gntmap *gm = map->_dm_cookie;
1182 	int i, domain, error;
1183 
1184 	domain = flags >> 16;
1185 	flags &= 0xffff;
1186 	error = _bus_dmamap_load(t, map, buf, buflen, p, flags);
1187 	if (error)
1188 		return (error);
1189 	for (i = 0; i < map->dm_nsegs; i++) {
1190 		xen_grant_table_enter(sc, gm[i].gm_ref, map->dm_segs[i].ds_addr,
1191 		    domain, flags & BUS_DMA_WRITE ? GTF_readonly : 0);
1192 		gm[i].gm_paddr = map->dm_segs[i].ds_addr;
1193 		map->dm_segs[i].ds_addr = gm[i].gm_ref;
1194 	}
1195 	return (0);
1196 }
1197 
1198 int
1199 xen_bus_dmamap_load_mbuf(bus_dma_tag_t t, bus_dmamap_t map, struct mbuf *m0,
1200     int flags)
1201 {
1202 	struct xen_softc *sc = t->_cookie;
1203 	struct xen_gntmap *gm = map->_dm_cookie;
1204 	int i, domain, error;
1205 
1206 	domain = flags >> 16;
1207 	flags &= 0xffff;
1208 	error = _bus_dmamap_load_mbuf(t, map, m0, flags);
1209 	if (error)
1210 		return (error);
1211 	for (i = 0; i < map->dm_nsegs; i++) {
1212 		xen_grant_table_enter(sc, gm[i].gm_ref, map->dm_segs[i].ds_addr,
1213 		    domain, flags & BUS_DMA_WRITE ? GTF_readonly : 0);
1214 		gm[i].gm_paddr = map->dm_segs[i].ds_addr;
1215 		map->dm_segs[i].ds_addr = gm[i].gm_ref;
1216 	}
1217 	return (0);
1218 }
1219 
1220 void
1221 xen_bus_dmamap_unload(bus_dma_tag_t t, bus_dmamap_t map)
1222 {
1223 	struct xen_softc *sc = t->_cookie;
1224 	struct xen_gntmap *gm = map->_dm_cookie;
1225 	int i;
1226 
1227 	for (i = 0; i < map->dm_nsegs; i++) {
1228 		if (gm[i].gm_paddr == 0)
1229 			continue;
1230 		xen_grant_table_remove(sc, gm[i].gm_ref);
1231 		map->dm_segs[i].ds_addr = gm[i].gm_paddr;
1232 		gm[i].gm_paddr = 0;
1233 	}
1234 	_bus_dmamap_unload(t, map);
1235 }
1236 
1237 void
1238 xen_bus_dmamap_sync(bus_dma_tag_t t, bus_dmamap_t map, bus_addr_t addr,
1239     bus_size_t size, int op)
1240 {
1241 	if ((op == (BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE)) ||
1242 	    (op == (BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE)))
1243 		virtio_membar_sync();
1244 }
1245 
1246 static int
1247 atoi(char *cp, int *res)
1248 {
1249 	*res = 0;
1250 	do {
1251 		if (*cp < '0' || *cp > '9')
1252 			return (-1);
1253 		*res *= 10;
1254 		*res += *cp - '0';
1255 	} while (*(++cp) != '\0');
1256 	return (0);
1257 }
1258 
1259 static int
1260 xen_attach_print(void *aux, const char *name)
1261 {
1262 	struct xen_attach_args *xa = aux;
1263 
1264 	if (name)
1265 		printf("\"%s\" at %s: %s", xa->xa_name, name, xa->xa_node);
1266 
1267 	return (UNCONF);
1268 }
1269 
1270 int
1271 xen_probe_devices(struct xen_softc *sc)
1272 {
1273 	struct xen_attach_args xa;
1274 	struct xs_transaction xst;
1275 	struct iovec *iovp1 = NULL, *iovp2 = NULL;
1276 	int i, j, error = 0, iov1_cnt = 0, iov2_cnt = 0;
1277 	char domid[16];
1278 	char path[256];
1279 
1280 	memset(&xst, 0, sizeof(xst));
1281 	xst.xst_id = 0;
1282 	xst.xst_sc = sc->sc_xs;
1283 	xst.xst_flags |= XST_POLL;
1284 
1285 	if ((error = xs_cmd(&xst, XS_LIST, "device", &iovp1, &iov1_cnt)) != 0)
1286 		return (error);
1287 
1288 	for (i = 0; i < iov1_cnt; i++) {
1289 		if (strcmp("suspend", (char *)iovp1[i].iov_base) == 0)
1290 			continue;
1291 		snprintf(path, sizeof(path), "device/%s",
1292 		    (char *)iovp1[i].iov_base);
1293 		if ((error = xs_cmd(&xst, XS_LIST, path, &iovp2,
1294 		    &iov2_cnt)) != 0) {
1295 			xs_resfree(&xst, iovp1, iov1_cnt);
1296 			return (error);
1297 		}
1298 		for (j = 0; j < iov2_cnt; j++) {
1299 			xa.xa_parent = sc;
1300 			xa.xa_dmat = &xen_bus_dma_tag;
1301 			strlcpy(xa.xa_name, (char *)iovp1[i].iov_base,
1302 			    sizeof(xa.xa_name));
1303 			snprintf(xa.xa_node, sizeof(xa.xa_node), "device/%s/%s",
1304 			    (char *)iovp1[i].iov_base,
1305 			    (char *)iovp2[j].iov_base);
1306 			if (xs_getprop(sc, xa.xa_node, "backend-id", domid,
1307 			    sizeof(domid)) ||
1308 			    xs_getprop(sc, xa.xa_node, "backend", xa.xa_backend,
1309 			    sizeof(xa.xa_backend))) {
1310 				printf("%s: failed to identify \"backend\" "
1311 				    "for \"%s\"\n", sc->sc_dev.dv_xname,
1312 				    xa.xa_node);
1313 			} else if (atoi(domid, &xa.xa_domid)) {
1314 				printf("%s: non-numeric backend domain id "
1315 				    "\"%s\" for \"%s\"\n", sc->sc_dev.dv_xname,
1316 				    domid, xa.xa_node);
1317 			}
1318 			config_found((struct device *)sc, &xa,
1319 			    xen_attach_print);
1320 		}
1321 		xs_resfree(&xst, iovp2, iov2_cnt);
1322 	}
1323 
1324 	return (error);
1325 }
1326 
1327 #include <machine/pio.h>
1328 
1329 #define	XMI_PORT		0x10
1330 #define XMI_MAGIC		0x49d2
1331 #define XMI_UNPLUG_IDE		0x01
1332 #define XMI_UNPLUG_NIC		0x02
1333 #define XMI_UNPLUG_IDESEC	0x04
1334 
1335 void
1336 xen_disable_emulated_devices(struct xen_softc *sc)
1337 {
1338 #if defined(__i386__) || defined(__amd64__)
1339 	ushort unplug = 0;
1340 
1341 	if (inw(XMI_PORT) != XMI_MAGIC) {
1342 		printf("%s: failed to disable emulated devices\n",
1343 		    sc->sc_dev.dv_xname);
1344 		return;
1345 	}
1346 	if (sc->sc_flags & XSF_UNPLUG_IDE)
1347 		unplug |= XMI_UNPLUG_IDE;
1348 	if (sc->sc_flags & XSF_UNPLUG_IDESEC)
1349 		unplug |= XMI_UNPLUG_IDESEC;
1350 	if (sc->sc_flags & XSF_UNPLUG_NIC)
1351 		unplug |= XMI_UNPLUG_NIC;
1352 	if (unplug)
1353 		outw(XMI_PORT, unplug);
1354 #endif	/* __i386__ || __amd64__ */
1355 }
1356