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