LCOV - code coverage report
Current view: top level - dev/pv - xen.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 708 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 49 0.0 %
Legend: Lines: hit not hit

          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 : }

Generated by: LCOV version 1.13