Index: sys/arch/sparc64/dev/iommu.c =================================================================== RCS file: /cvsroot/src/sys/arch/sparc64/dev/iommu.c,v retrieving revision 1.108 diff -u -r1.108 iommu.c --- sys/arch/sparc64/dev/iommu.c 24 Aug 2014 19:09:43 -0000 1.108 +++ sys/arch/sparc64/dev/iommu.c 31 Aug 2015 04:21:57 -0000 @@ -101,6 +101,10 @@ static int iommu_strbuf_flush_done(struct strbuf_ctl *); static void _iommu_dvmamap_sync(bus_dma_tag_t, bus_dmamap_t, bus_addr_t, bus_size_t, int); +static void iommu_enter_sun4u(struct strbuf_ctl *sb, vaddr_t va, int64_t pa, int flags); +static void iommu_enter_sun4v(struct strbuf_ctl *sb, vaddr_t va, int64_t pa, int flags); +static void iommu_remove_sun4u(struct iommu_state *is, vaddr_t va, size_t len); +static void iommu_remove_sun4v(struct iommu_state *is, vaddr_t va, size_t len); /* * initialise the UltraSPARC IOMMU (SBUS or PCI): @@ -118,6 +122,8 @@ struct vm_page *pg; struct pglist pglist; + DPRINTF(IDB_INFO, ("iommu_init: tsbsize %x iovabase %x\n", tsbsize, iovabase)); + /* * Setup the iommu. * @@ -181,17 +187,18 @@ if (iommudebug & IDB_INFO) { /* Probe the iommu */ - - printf("iommu cr=%llx tsb=%llx\n", - (unsigned long long)bus_space_read_8(is->is_bustag, + if (!CPU_ISSUN4V) { + printf("iommu cr=%llx tsb=%llx\n", + (unsigned long long)bus_space_read_8(is->is_bustag, is->is_iommu, offsetof(struct iommureg, iommu_cr)), - (unsigned long long)bus_space_read_8(is->is_bustag, + (unsigned long long)bus_space_read_8(is->is_bustag, is->is_iommu, offsetof(struct iommureg, iommu_tsb))); - printf("TSB base %p phys %llx\n", (void *)is->is_tsb, - (unsigned long long)is->is_ptsb); - delay(1000000); /* 1 s */ + printf("TSB base %p phys %llx\n", (void *)is->is_tsb, + (unsigned long long)is->is_ptsb); + delay(1000000); /* 1 s */ + } } #endif @@ -207,8 +214,9 @@ is->is_dvmamap = extent_create(name, is->is_dvmabase, is->is_dvmaend, 0, 0, EX_NOWAIT); - /* XXXMRG Check is_dvmamap is valid. */ - + if (!is->is_dvmamap) + panic("iommu_init: extent_create() failed"); + mutex_init(&is->is_lock, MUTEX_DEFAULT, IPL_HIGH); /* @@ -223,7 +231,8 @@ /* * now actually start up the IOMMU */ - iommu_reset(is); + if (!CPU_ISSUN4V) + iommu_reset(is); } /* @@ -276,9 +285,22 @@ /* * Here are the iommu control routines. */ + void iommu_enter(struct strbuf_ctl *sb, vaddr_t va, int64_t pa, int flags) { + DPRINTF(IDB_IOMMU, ("iommu_enter: va %lx pa %lx flags %x\n", + va, (long)pa, flags)); + if (!CPU_ISSUN4V) + iommu_enter_sun4u(sb, va, pa, flags); + else + iommu_enter_sun4v(sb, va, pa, flags); +} + + +void +iommu_enter_sun4u(struct strbuf_ctl *sb, vaddr_t va, int64_t pa, int flags) +{ struct iommu_state *is = sb->sb_is; int strbuf = (flags & BUS_DMA_STREAMING); int64_t tte; @@ -311,6 +333,35 @@ (u_long)tte)); } +void +iommu_enter_sun4v(struct strbuf_ctl *sb, vaddr_t va, int64_t pa, int flags) +{ + struct iommu_state *is = sb->sb_is; + u_int64_t tsbid = IOTSBSLOT(va, is->is_tsbsize); + paddr_t page_list[1], addr; + u_int64_t attr, nmapped; + int err; + +#ifdef DIAGNOSTIC + if (va < is->is_dvmabase || (va + PAGE_MASK) > is->is_dvmaend) + panic("viommu_enter: va %#lx not in DVMA space", va); +#endif + + attr = PCI_MAP_ATTR_READ | PCI_MAP_ATTR_WRITE; + if (flags & BUS_DMA_READ) + attr &= ~PCI_MAP_ATTR_READ; + if (flags & BUS_DMA_WRITE) + attr &= ~PCI_MAP_ATTR_WRITE; + + page_list[0] = trunc_page(pa); + if (!pmap_extract(pmap_kernel(), (vaddr_t)page_list, &addr)) + panic("viommu_enter: pmap_extract failed"); + err = hv_pci_iommu_map(is->is_devhandle, tsbid, 1, attr, + addr, &nmapped); + if (err != H_EOK || nmapped != 1) + panic("hv_pci_iommu_map: err=%d, nmapped=%lu", err, nmapped); +} + /* * Find the value of a DVMA address (debug routine). */ @@ -334,9 +385,22 @@ * * XXX: this function needs better internal error checking. */ + + void iommu_remove(struct iommu_state *is, vaddr_t va, size_t len) { + DPRINTF(IDB_IOMMU, ("iommu_remove: va %lx len %zu\n", va, len)); + if (!CPU_ISSUN4V) + iommu_remove_sun4u(is, va, len); + else + iommu_remove_sun4v(is, va, len); +} + +void +iommu_remove_sun4u(struct iommu_state *is, vaddr_t va, size_t len) +{ + int slot; #ifdef DIAGNOSTIC @@ -389,6 +453,27 @@ } } +void +iommu_remove_sun4v(struct iommu_state *is, vaddr_t va, size_t len) +{ + u_int64_t tsbid = IOTSBSLOT(va, is->is_tsbsize); + u_int64_t ndemapped; + int err; + +#ifdef DIAGNOSTIC + if (va < is->is_dvmabase || (va + PAGE_MASK) > is->is_dvmaend) + panic("iommu_remove: va 0x%lx not in DVMA space", (u_long)va); + if (va != trunc_page(va)) { + printf("iommu_remove: unaligned va: %lx\n", va); + va = trunc_page(va); + } +#endif + + err = hv_pci_iommu_demap(is->is_devhandle, tsbid, 1, &ndemapped); + if (err != H_EOK || ndemapped != 1) + panic("hv_pci_iommu_unmap: err=%d", err); +} + static int iommu_strbuf_flush_done(struct strbuf_ctl *sb) { Index: sys/arch/sparc64/dev/iommuvar.h =================================================================== RCS file: /cvsroot/src/sys/arch/sparc64/dev/iommuvar.h,v retrieving revision 1.21 diff -u -r1.21 iommuvar.h --- sys/arch/sparc64/dev/iommuvar.h 25 Mar 2012 03:51:33 -0000 1.21 +++ sys/arch/sparc64/dev/iommuvar.h 31 Aug 2015 04:21:57 -0000 @@ -65,6 +65,7 @@ /* copies of our parents state, to allow us to be self contained */ bus_space_tag_t is_bustag; /* our bus tag */ bus_space_handle_t is_iommu; /* IOMMU registers */ + uint64_t is_devhandle; /* for sun4v hypervisor calls */ }; /* interfaces for PCI/SBUS code */ Index: sys/arch/sparc64/dev/vpci.c =================================================================== RCS file: /cvsroot/src/sys/arch/sparc64/dev/vpci.c,v retrieving revision 1.1 diff -u -r1.1 vpci.c --- sys/arch/sparc64/dev/vpci.c 12 Feb 2015 04:48:37 -0000 1.1 +++ sys/arch/sparc64/dev/vpci.c 31 Aug 2015 04:21:57 -0000 @@ -56,11 +56,13 @@ #include #ifdef DEBUG -#define VDB_PROM 0x01 -#define VDB_BUSMAP 0x02 -#define VDB_INTR 0x04 -#define VDB_CONF 0x08 -int vpci_debug = 0xff; +#define VDB_PROM 0x01 +#define VDB_BUSMAP 0x02 +#define VDB_INTR 0x04 +#define VDB_CONF_READ 0x08 +#define VDB_CONF_WRITE 0x10 +#define VDB_CONF VDB_CONF_READ|VDB_CONF_WRITE +int vpci_debug = 0x00; #define DPRINTF(l, s) do { if (vpci_debug & l) printf s; } while (0) #else #define DPRINTF(l, s) @@ -94,10 +96,7 @@ vpci_match, vpci_attach, NULL, NULL); void vpci_init(struct vpci_softc */*FIXME, int*/, struct mainbus_attach_args *); -#if 0 -FIXME void vpci_init_iommu(struct vpci_softc *, struct vpci_pbm *); -#endif pci_chipset_tag_t vpci_alloc_chipset(struct vpci_pbm *, int, pci_chipset_tag_t); bus_space_tag_t vpci_alloc_mem_tag(struct vpci_pbm *); @@ -233,20 +232,9 @@ panic("vpci: can't get bus-range"); for (int range = 0; range < nranges; range++) DPRINTF(VDB_PROM, ("\nvpci_attach: bus-range %d %08x", range, busranges[range])); -#if 0 -FIXME - printf(": \"%s\", rev %d, ign %x, bus %c %d to %d\n", - sc->sc_oberon ? "Oberon" : "Fire", - prom_getpropint(sc->sc_node, "module-revision#", 0), sc->sc_ign, - busa ? 'A' : 'B', busranges[0], busranges[1]); -#else - printf(": ign %x, bus %d to %d\n", sc->sc_ign, busranges[0], busranges[1]); -#endif - printf("%s: ", device_xname(sc->sc_dev)); -#if 0 -FIXME + vpci_init_iommu(sc, pbm); -#endif + pbm->vp_memt = vpci_alloc_mem_tag(pbm); pbm->vp_iot = vpci_alloc_io_tag(pbm); pbm->vp_cfgt = vpci_alloc_config_tag(pbm); @@ -284,14 +272,15 @@ config_found(sc->sc_dev, &pba, vpci_print); } -#if 0 -FIXME void vpci_init_iommu(struct vpci_softc *sc, struct vpci_pbm *pbm) { struct iommu_state *is = &pbm->vp_is; - int tsbsize = 7; + int *vdma = NULL; + int nitem; + int tsbsize = 0; u_int32_t iobase = -1; + u_int32_t iolen = 0; char *name; pbm->vp_sb.sb_is = is; @@ -302,6 +291,20 @@ panic("vpci: unable to create iommu handle"); } + /* Construct tsbsize */ + if (!prom_getprop(sc->sc_node, "virtual-dma", sizeof(vdma), &nitem, + (void **)&vdma)) { + DPRINTF(VDB_BUSMAP, ("vpci_init_iommu: vdma[0]=0x%x vdma[1]=0x%x\n", + vdma[0], vdma[1])); + iobase = vdma[0]; + iolen = vdma[1]; + for (tsbsize = 8; (1 << (tsbsize+23)) > iolen; tsbsize--) ; + DPRINTF(VDB_BUSMAP, ("vpci_init_iommu: iobase=0x%x iolen = 0x%x tsbsize=0x%x\n", + iobase, iolen, tsbsize)); + free(vdma, M_DEVBUF); + } else + panic("vpci_init_iommu: getprop failed"); + /* We have no STC. */ is->is_sb[0] = NULL; @@ -313,13 +316,10 @@ /* Tell iommu how to set the TSB size. */ is->is_flags = IOMMU_TSBSIZE_IN_PTSB; - /* On Oberon, we need to flush the cache. */ - if (sc->sc_oberon) - is->is_flags |= IOMMU_FLUSH_CACHE; - + is->is_devhandle = pbm->vp_devhandle; iommu_init(name, is, tsbsize, iobase); } -#endif + int vpci_print(void *aux, const char *p) @@ -336,7 +336,7 @@ uint64_t error_flag, data; int64_t hv_rc; - DPRINTF(VDB_CONF, ("%s: tag %lx reg %x ", __func__, (long)tag, reg)); + DPRINTF(VDB_CONF_READ, ("%s: tag %lx reg %x ", __func__, (long)tag, reg)); hv_rc = hv_pci_config_get(pbm->vp_devhandle, PCITAG_OFFSET(tag), reg, 4, &error_flag, &data); if (hv_rc != H_EOK) @@ -344,7 +344,7 @@ hv_rc); pcireg_t val = error_flag ? (pcireg_t)~0 : data; - DPRINTF(VDB_CONF, (" returning %08x\n", (u_int)val)); + DPRINTF(VDB_CONF_READ, (" returning %08x\n", (u_int)val)); return val; } @@ -355,14 +355,14 @@ struct vpci_pbm *pbm = pc->cookie; uint64_t error_flag; int64_t hv_rc; - DPRINTF(VDB_CONF, ("%s: tag %lx; reg %x; data %x", __func__, + DPRINTF(VDB_CONF_WRITE, ("%s: tag %lx; reg %x; data %x", __func__, (long)tag, reg, (int)data)); hv_rc = hv_pci_config_put(pbm->vp_devhandle, PCITAG_OFFSET(tag), reg, 4, data, &error_flag); if (hv_rc != H_EOK) panic("hv_pci_config_put() failed - rc = %" PRId64 "\n", hv_rc); - DPRINTF(VDB_CONF, (" .. done\n")); + DPRINTF(VDB_CONF_WRITE, (" .. done\n")); } /* @@ -371,8 +371,6 @@ int vpci_intr_map(const struct pci_attach_args *pa, pci_intr_handle_t *ihp) { - DPRINTF(VDB_INTR, ("vpci_intr_map()\n")); - struct vpci_pbm *pbm = pa->pa_pc->cookie; uint64_t devhandle = pbm->vp_devhandle; uint64_t devino = INTINO(*ihp); @@ -459,8 +457,8 @@ dt->_dmamap_sync = iommu_dvmamap_sync; dt->_dmamem_alloc = iommu_dvmamem_alloc; dt->_dmamem_free = iommu_dvmamem_free; - dt->_dmamem_map = iommu_dvmamem_map; - dt->_dmamem_unmap = iommu_dvmamem_unmap; + dt->_dmamem_map = iommu_dvmamem_map; + dt->_dmamem_unmap = iommu_dvmamem_unmap; PCOPY(_dmamem_mmap); #undef PCOPY return (dt); @@ -508,14 +506,14 @@ struct vpci_softc *sc = pbm->vp_sc; int i, ss; - DPRINTF(VDB_BUSMAP, ("vpci_bus_map: type %d off %qx sz %qx flags %d\n", + DPRINTF(VDB_BUSMAP, ("vpci_bus_map: type %d off %qx sz %qx flags %d", t->type, (unsigned long long)offset, (unsigned long long)size, flags)); ss = sparc_pci_childspace(t->type); - DPRINTF(VDB_BUSMAP, (" cspace %d", ss)); + DPRINTF(VDB_BUSMAP, (" cspace %d\n", ss)); if (t->parent == 0 || t->parent->sparc_bus_map == 0) { printf("\n_vpci_bus_map: invalid parent");