> Date: Tue, 11 Jun 2019 11:51:51 +1000 > From: David Gwynne <da...@gwynne.id.au> > > this is a reposting of the diff i sent out a while back. it lets sparc64 > enable iommu bypass, and then uses that bypass support for BUS_DMA_64BIT > dmamaps. > > the main benefit is around performance. without this diff on an M4000, > tcpbench can do about 70Mbps before the system is CPU bound. all that > cpu time is in the iommu tte management. with this diff and an > appropriate network driver, tcpbench does 940 Mbps and the box is mostly > idle. that is a 1300 percent improvement in network transfer speed. if > you factor the cpu time benefits it would be another order of magnitude > improvement. > > kernel build times are slightly improved with this diff on mpii. system > time is about 5 percent less, but there's also a lot less I/O when > you're mostly running a compiler. > > i hit an edge case with my previous diff that i believe is fixed with > this one. this one properly checks boundaries, segment sizes, and number > of segments for things like mbufs. i got lucky previously with the > drivers i was using.
Looks mostly ok, one request below. With that fixed, ok kettenis@ > Index: dev/iommu.c > =================================================================== > RCS file: /cvs/src/sys/arch/sparc64/dev/iommu.c,v > retrieving revision 1.75 > diff -u -p -r1.75 iommu.c > --- dev/iommu.c 25 May 2017 03:19:39 -0000 1.75 > +++ dev/iommu.c 11 Jun 2019 01:37:25 -0000 > @@ -87,6 +87,8 @@ void iommu_dvmamap_print_map(bus_dma_tag > bus_dmamap_t); > int iommu_dvmamap_append_range(bus_dma_tag_t, bus_dmamap_t, paddr_t, > bus_size_t, int, bus_size_t); > +int iommu_dvmamap_insert(bus_dma_tag_t, bus_dmamap_t, bus_addr_t, > + bus_size_t, int, bus_size_t); > int64_t iommu_tsb_entry(struct iommu_state *, bus_addr_t); > void strbuf_reset(struct strbuf_ctl *); > int iommu_iomap_insert_page(struct iommu_map_state *, paddr_t); > @@ -100,6 +102,25 @@ void iommu_iomap_clear_pages(struct iomm > void _iommu_dvmamap_sync(bus_dma_tag_t, bus_dma_tag_t, bus_dmamap_t, > bus_addr_t, bus_size_t, int); > > +void iommu_hw_enable(struct iommu_state *); > + > +const struct iommu_hw iommu_hw_default = { > + .ihw_enable = iommu_hw_enable, > + > + .ihw_dvma_pa = IOTTE_PAMASK, > + > + .ihw_bypass = 0x3fffUL << 50, > + .ihw_bypass_nc = 0, > + .ihw_bypass_ro = 0, > +}; > + > +void > +iommu_hw_enable(struct iommu_state *is) > +{ > + IOMMUREG_WRITE(is, iommu_tsb, is->is_ptsb); > + IOMMUREG_WRITE(is, iommu_cr, IOMMUCR_EN | (is->is_tsbsize << 16)); > +} > + > /* > * Initiate an STC entry flush. > */ > @@ -125,7 +146,8 @@ iommu_strbuf_flush(struct strbuf_ctl *sb > * - create a private DVMA map. > */ > void > -iommu_init(char *name, struct iommu_state *is, int tsbsize, u_int32_t > iovabase) > +iommu_init(char *name, const struct iommu_hw *ihw, struct iommu_state *is, > + int tsbsize, u_int32_t iovabase) > { > psize_t size; > vaddr_t va; > @@ -149,13 +171,9 @@ iommu_init(char *name, struct iommu_stat > * be hard-wired, so we read the start and size from the PROM and > * just use those values. > */ > - if (strncmp(name, "pyro", 4) == 0) { > - is->is_cr = IOMMUREG_READ(is, iommu_cr); > - is->is_cr &= ~IOMMUCR_FIRE_BE; > - is->is_cr |= (IOMMUCR_FIRE_SE | IOMMUCR_FIRE_CM_EN | > - IOMMUCR_FIRE_TE); > - } else > - is->is_cr = IOMMUCR_EN; > + > + is->is_hw = ihw; > + > is->is_tsbsize = tsbsize; > if (iovabase == (u_int32_t)-1) { > is->is_dvmabase = IOTSB_VSTART(is->is_tsbsize); > @@ -237,15 +255,6 @@ iommu_init(char *name, struct iommu_stat > mtx_init(&is->is_mtx, IPL_HIGH); > > /* > - * Set the TSB size. The relevant bits were moved to the TSB > - * base register in the PCIe host bridges. > - */ > - if (strncmp(name, "pyro", 4) == 0) > - is->is_ptsb |= is->is_tsbsize; > - else > - is->is_cr |= (is->is_tsbsize << 16); > - > - /* > * Now actually start up the IOMMU. > */ > iommu_reset(is); > @@ -262,10 +271,7 @@ iommu_reset(struct iommu_state *is) > { > int i; > > - IOMMUREG_WRITE(is, iommu_tsb, is->is_ptsb); > - > - /* Enable IOMMU */ > - IOMMUREG_WRITE(is, iommu_cr, is->is_cr); > + (*is->is_hw->ihw_enable)(is); > > for (i = 0; i < 2; ++i) { > struct strbuf_ctl *sb = is->is_sb[i]; > @@ -280,7 +286,7 @@ iommu_reset(struct iommu_state *is) > printf(", STC%d enabled", i); > } > > - if (is->is_flags & IOMMU_FLUSH_CACHE) > + if (ISSET(is->is_hw->ihw_flags, IOMMU_HW_FLUSH_CACHE)) > IOMMUREG_WRITE(is, iommu_cache_invalidate, -1ULL); > } > > @@ -433,7 +439,7 @@ iommu_extract(struct iommu_state *is, bu > if (dva >= is->is_dvmabase && dva <= is->is_dvmaend) > tte = is->is_tsb[IOTSBSLOT(dva, is->is_tsbsize)]; > > - return (tte & IOTTE_PAMASK); > + return (tte & is->is_hw->ihw_dvma_pa); > } > > /* > @@ -601,6 +607,7 @@ iommu_dvmamap_create(bus_dma_tag_t t, bu > { > int ret; > bus_dmamap_t map; > + struct iommu_state *is = sb->sb_iommu; > struct iommu_map_state *ims; > > BUS_DMA_FIND_PARENT(t, _dmamap_create); > @@ -610,6 +617,12 @@ iommu_dvmamap_create(bus_dma_tag_t t, bu > if (ret) > return (ret); > > + if (flags & BUS_DMA_64BIT) { > + map->_dm_cookie = is; > + *dmamap = map; > + return (0); > + } > + > ims = iommu_iomap_create(atop(round_page(size))); > > if (ims == NULL) { > @@ -641,8 +654,10 @@ iommu_dvmamap_destroy(bus_dma_tag_t t, b > if (map->dm_nsegs) > bus_dmamap_unload(t0, map); > > - if (map->_dm_cookie) > - iommu_iomap_destroy(map->_dm_cookie); > + if (!ISSET(map->_dm_flags, BUS_DMA_64BIT)) { > + if (map->_dm_cookie) > + iommu_iomap_destroy(map->_dm_cookie); > + } > map->_dm_cookie = NULL; > > BUS_DMA_FIND_PARENT(t, _dmamap_destroy); > @@ -667,36 +682,36 @@ iommu_dvmamap_load(bus_dma_tag_t t, bus_ > u_long dvmaddr, sgstart, sgend; > bus_size_t align, boundary; > struct iommu_state *is; > - struct iommu_map_state *ims = map->_dm_cookie; > + struct iommu_map_state *ims; > pmap_t pmap; > > -#ifdef DIAGNOSTIC > - if (ims == NULL) > - panic("iommu_dvmamap_load: null map state"); > -#endif > -#ifdef DEBUG > - if (ims->ims_sb == NULL) > - panic("iommu_dvmamap_load: null sb"); > - if (ims->ims_sb->sb_iommu == NULL) > - panic("iommu_dvmamap_load: null iommu"); > -#endif /* DEBUG */ > - is = ims->ims_sb->sb_iommu; > - > - if (map->dm_nsegs) { > - /* > - * Is it still in use? _bus_dmamap_load should have taken care > - * of this. > - */ > -#ifdef DIAGNOSTIC > - panic("iommu_dvmamap_load: map still in use"); > -#endif > - bus_dmamap_unload(t0, map); > - } > - > /* > * Make sure that on error condition we return "no valid mappings". > */ > - map->dm_nsegs = 0; > + KASSERTMSG(map->dm_nsegs == 0, "map still in use"); > + > + if (ISSET(map->_dm_flags, BUS_DMA_64BIT)) { > + unsigned long bypass; > + int i; > + > + is = map->_dm_cookie; > + bypass = is->is_hw->ihw_bypass; > + > + /* Bypass translation by the IOMMU. */ > + > + BUS_DMA_FIND_PARENT(t, _dmamap_load); > + err = (*t->_dmamap_load)(t, t0, map, buf, buflen, p, flags); > + if (err != 0) > + return (err); > + > + for (i = 0; i < map->dm_nsegs; i++) > + map->dm_segs[i].ds_addr |= bypass; > + > + return (0); > + } > + > + ims = map->_dm_cookie; > + is = ims->ims_sb->sb_iommu; > > if (buflen < 1 || buflen > map->_dm_size) { > DPRINTF(IDB_BUSDMA, > @@ -876,27 +891,9 @@ iommu_dvmamap_load_raw(bus_dma_tag_t t, > bus_size_t boundary, align; > u_long dvmaddr, sgstart, sgend; > struct iommu_state *is; > - struct iommu_map_state *ims = map->_dm_cookie; > - > -#ifdef DIAGNOSTIC > - if (ims == NULL) > - panic("iommu_dvmamap_load_raw: null map state"); > -#endif > -#ifdef DEBUG > - if (ims->ims_sb == NULL) > - panic("iommu_dvmamap_load_raw: null sb"); > - if (ims->ims_sb->sb_iommu == NULL) > - panic("iommu_dvmamap_load_raw: null iommu"); > -#endif /* DEBUG */ > - is = ims->ims_sb->sb_iommu; > + struct iommu_map_state *ims; > > - if (map->dm_nsegs) { > - /* Already in use?? */ > -#ifdef DIAGNOSTIC > - panic("iommu_dvmamap_load_raw: map still in use"); > -#endif > - bus_dmamap_unload(t0, map); > - } > + KASSERTMSG(map->dm_nsegs == 0, "map stil in use"); > > /* > * A boundary presented to bus_dmamem_alloc() takes precedence > @@ -905,6 +902,31 @@ iommu_dvmamap_load_raw(bus_dma_tag_t t, > if ((boundary = segs[0]._ds_boundary) == 0) > boundary = map->_dm_boundary; > > + if (ISSET(map->_dm_flags, BUS_DMA_64BIT)) { > + unsigned long bypass; > + > + is = map->_dm_cookie; > + bypass = is->is_hw->ihw_bypass; > + > + /* Bypass translation by the IOMMU. */ > + for (i = 0; i < nsegs; i++) { > + err = iommu_dvmamap_insert(t, map, > + bypass | segs[i].ds_addr, segs[i].ds_len, > + 0, boundary); > + if (err != 0) { > + map->dm_nsegs = 0; > + return (err); > + } > + } > + > + map->dm_mapsize = size; > + > + return (0); > + } > + > + ims = map->_dm_cookie; > + is = ims->ims_sb->sb_iommu; > + > align = MAX(segs[0]._ds_align, PAGE_SIZE); > > /* > @@ -1084,22 +1106,24 @@ iommu_dvmamap_append_range(bus_dma_tag_t > bus_size_t length, int flags, bus_size_t boundary) > { > struct iommu_map_state *ims = map->_dm_cookie; > - bus_addr_t sgstart, sgend, bd_mask; > - bus_dma_segment_t *seg = NULL; > - int i = map->dm_nsegs; > + bus_addr_t sgstart = iommu_iomap_translate(ims, pa); > > -#ifdef DEBUG > - if (ims == NULL) > - panic("iommu_dvmamap_append_range: null map state"); > -#endif > + return (iommu_dvmamap_insert(t, map, sgstart, length, flags, boundary)); > +} > > - sgstart = iommu_iomap_translate(ims, pa); > - sgend = sgstart + length - 1; > +int > +iommu_dvmamap_insert(bus_dma_tag_t t, bus_dmamap_t map, > + bus_addr_t sgstart, bus_size_t length, int flags, bus_size_t boundary) > +{ > + bus_addr_t sgend = sgstart + length - 1; > + bus_addr_t bd_mask; > + bus_dma_segment_t *seg = NULL; > + int i = map->dm_nsegs; > > #ifdef DIAGNOSTIC > if (sgstart == 0 || sgstart > sgend) { > - printf("append range invalid mapping for %lx " > - "(0x%lx - 0x%lx)\n", pa, sgstart, sgend); > + printf("append range invalid mapping for " > + "0x%lx - 0x%lx\n", sgstart, sgend); > map->dm_nsegs = 0; > return (EINVAL); > } > @@ -1298,20 +1322,17 @@ void > iommu_dvmamap_unload(bus_dma_tag_t t, bus_dma_tag_t t0, bus_dmamap_t map) > { > struct iommu_state *is; > - struct iommu_map_state *ims = map->_dm_cookie; > + struct iommu_map_state *ims; > bus_addr_t dvmaddr = map->_dm_dvmastart; > bus_size_t sgsize = map->_dm_dvmasize; > int error; > > -#ifdef DEBUG > - if (ims == NULL) > - panic("iommu_dvmamap_unload: null map state"); > - if (ims->ims_sb == NULL) > - panic("iommu_dvmamap_unload: null sb"); > - if (ims->ims_sb->sb_iommu == NULL) > - panic("iommu_dvmamap_unload: null iommu"); > -#endif /* DEBUG */ > + if (ISSET(map->_dm_flags, BUS_DMA_64BIT)) { > + bus_dmamap_unload(t->_parent, map); > + return; > + } > > + ims = map->_dm_cookie; > is = ims->ims_sb->sb_iommu; > > /* Flush the iommu */ > @@ -1488,7 +1509,7 @@ iommu_dvmamap_print_map(bus_dma_tag_t t, > break; > } > > - if (map->_dm_cookie) { > + if (!ISSET(map->_dm_flags, BUS_DMA_64BIT) && map->_dm_cookie != NULL) { > struct iommu_map_state *ims = map->_dm_cookie; > struct iommu_page_map *ipm = &ims->ims_map; > > @@ -1546,19 +1567,19 @@ void > iommu_dvmamap_sync(bus_dma_tag_t t, bus_dma_tag_t t0, bus_dmamap_t map, > bus_addr_t offset, bus_size_t len, int ops) > { > - struct iommu_map_state *ims = map->_dm_cookie; > + struct iommu_map_state *ims; > > -#ifdef DIAGNOSTIC > - if (ims == NULL) > - panic("iommu_dvmamap_sync: null map state"); > - if (ims->ims_sb == NULL) > - panic("iommu_dvmamap_sync: null sb"); > - if (ims->ims_sb->sb_iommu == NULL) > - panic("iommu_dvmamap_sync: null iommu"); > -#endif > if (len == 0) > return; > > + if (map->_dm_flags & BUS_DMA_64BIT) { > + if (ops & (BUS_DMASYNC_PREWRITE | BUS_DMASYNC_POSTREAD)) > + __membar("#MemIssue"); > + return; > + } > + > + ims = map->_dm_cookie; > + > if (ops & BUS_DMASYNC_PREWRITE) > __membar("#MemIssue"); > > @@ -1622,9 +1643,13 @@ iommu_dvmamem_alloc(bus_dma_tag_t t, bus > "bound %llx segp %p flags %d\n", (unsigned long long)size, > (unsigned long long)alignment, (unsigned long long)boundary, > segs, flags)); > + > + if ((flags & BUS_DMA_64BIT) == 0) > + flags |= BUS_DMA_DVMA; > + > BUS_DMA_FIND_PARENT(t, _dmamem_alloc); > return ((*t->_dmamem_alloc)(t, t0, size, alignment, boundary, > - segs, nsegs, rsegs, flags | BUS_DMA_DVMA)); > + segs, nsegs, rsegs, flags)); > } > > void > @@ -1763,7 +1788,7 @@ iommu_iomap_load_map(struct iommu_state > > /* Flush cache if necessary. */ > slot = IOTSBSLOT(e->ipe_va, is->is_tsbsize); > - if (is->is_flags & IOMMU_FLUSH_CACHE && > + if (ISSET(is->is_hw->ihw_flags, IOMMU_HW_FLUSH_CACHE) && > (i == (ipm->ipm_pagecnt - 1) || (slot % 8) == 7)) > IOMMUREG_WRITE(is, iommu_cache_flush, > is->is_ptsb + slot * 8); > @@ -1788,7 +1813,7 @@ iommu_iomap_unload_map(struct iommu_stat > > /* Flush cache if necessary. */ > slot = IOTSBSLOT(e->ipe_va, is->is_tsbsize); > - if (is->is_flags & IOMMU_FLUSH_CACHE && > + if (ISSET(is->is_hw->ihw_flags, IOMMU_HW_FLUSH_CACHE) && > (i == (ipm->ipm_pagecnt - 1) || (slot % 8) == 7)) > IOMMUREG_WRITE(is, iommu_cache_flush, > is->is_ptsb + slot * 8); > Index: dev/iommureg.h > =================================================================== > RCS file: /cvs/src/sys/arch/sparc64/dev/iommureg.h,v > retrieving revision 1.17 > diff -u -p -r1.17 iommureg.h > --- dev/iommureg.h 17 Aug 2012 20:46:50 -0000 1.17 > +++ dev/iommureg.h 11 Jun 2019 01:37:25 -0000 > @@ -90,10 +90,11 @@ struct iommu_strbuf { > #define IOMMUCR_DE 0x000000000000000002LL /* Diag enable */ > #define IOMMUCR_EN 0x000000000000000001LL /* Enable IOMMU */ > > -#define IOMMUCR_FIRE_SE 0x000000000000000400LL /* Snoop enable > */ > -#define IOMMUCR_FIRE_CM_EN 0x000000000000000300LL /* Cache mode enable */ > -#define IOMMUCR_FIRE_BE 0x000000000000000002LL /* Bypass > enable */ > -#define IOMMUCR_FIRE_TE 0x000000000000000001LL /* Translation > enabled */ > +#define IOMMUCR_FIRE_PD 0x000000000000001000UL /* Process > disable */ > +#define IOMMUCR_FIRE_SE 0x000000000000000400UL /* Snoop enable > */ > +#define IOMMUCR_FIRE_CM_EN 0x000000000000000300UL /* Cache mode enable */ > +#define IOMMUCR_FIRE_BE 0x000000000000000002UL /* Bypass > enable */ > +#define IOMMUCR_FIRE_TE 0x000000000000000001UL /* Translation > enabled */ > > /* > * IOMMU stuff > Index: dev/iommuvar.h > =================================================================== > RCS file: /cvs/src/sys/arch/sparc64/dev/iommuvar.h,v > retrieving revision 1.17 > diff -u -p -r1.17 iommuvar.h > --- dev/iommuvar.h 4 May 2016 18:26:12 -0000 1.17 > +++ dev/iommuvar.h 11 Jun 2019 01:37:25 -0000 > @@ -100,6 +100,21 @@ struct iommu_map_state { > }; > #define IOMMU_MAP_STREAM 1 > > +struct iommu_hw { > + void (*ihw_enable)(struct iommu_state *); > + > + unsigned long ihw_dvma_pa; > + > + unsigned long ihw_bypass; > + unsigned long ihw_bypass_nc; /* non-cached */ > + unsigned long ihw_bypass_ro; /* relaxed ordering */ > + > + unsigned int ihw_flags; > +#define IOMMU_HW_FLUSH_CACHE (1 << 0) > +}; > + > +extern const struct iommu_hw iommu_hw_default; > + > /* > * per-IOMMU state > */ > @@ -112,8 +127,7 @@ struct iommu_state { > int64_t is_cr; /* Control register value */ > struct mutex is_mtx; > struct extent *is_dvmamap; /* DVMA map for this instance */ > - int is_flags; > -#define IOMMU_FLUSH_CACHE 0x00000001 > + const struct iommu_hw *is_hw; > > struct strbuf_ctl *is_sb[2]; /* Streaming buffers if any */ > > @@ -126,7 +140,8 @@ struct iommu_state { > }; > > /* interfaces for PCI/SBus code */ > -void iommu_init(char *, struct iommu_state *, int, u_int32_t); > +void iommu_init(char *, const struct iommu_hw *, struct iommu_state *, > + int, u_int32_t); > void iommu_reset(struct iommu_state *); > paddr_t iommu_extract(struct iommu_state *, bus_addr_t); > int64_t iommu_lookup_tte(struct iommu_state *, bus_addr_t); > @@ -146,6 +161,7 @@ int iommu_dvmamem_alloc(bus_dma_tag_t, b > bus_size_t, bus_size_t, bus_dma_segment_t *, int, int *, int); > void iommu_dvmamem_free(bus_dma_tag_t, bus_dma_tag_t, bus_dma_segment_t *, > int); > + > > #define IOMMUREG_READ(is, reg) \ > bus_space_read_8((is)->is_bustag, \ > Index: dev/pci_machdep.c > =================================================================== > RCS file: /cvs/src/sys/arch/sparc64/dev/pci_machdep.c,v > retrieving revision 1.47 > diff -u -p -r1.47 pci_machdep.c > --- dev/pci_machdep.c 11 Jun 2019 00:45:31 -0000 1.47 > +++ dev/pci_machdep.c 11 Jun 2019 01:37:25 -0000 > @@ -57,6 +57,7 @@ int sparc_pci_debug = 0x0; > #include <machine/openfirm.h> > #include <dev/pci/pcivar.h> > #include <dev/pci/pcireg.h> > +#include <dev/pci/pcidevs.h> > > #include <dev/ofw/ofw_pci.h> > > @@ -84,6 +85,46 @@ pci_attach_hook(parent, self, pba) > struct pcibus_attach_args *pba; > { > /* Don't do anything */ > +} > + > +int > +pci_bcm_dmamap_create(bus_dma_tag_t dt, bus_dma_tag_t t0, bus_size_t size, > + int nsegments, bus_size_t maxsegsz, bus_size_t boundary, int flags, > + bus_dmamap_t *dmamp) > +{ > + bus_dma_tag_t pdt = dt->_parent; > + > + CLR(flags, BUS_DMA_64BIT); > + > + return ((*pdt->_dmamap_create)(pdt, t0, size, nsegments, maxsegsz, > + boundary, flags, dmamp)); > +} Maybe rename this function to pci_32bit_dmamap_create(). > + > +int > +pci_probe_device_hook(pci_chipset_tag_t pc, struct pci_attach_args *pa) > +{ > + bus_dma_tag_t dt, pdt; > + > + if (pa->pa_id == > + PCI_ID_CODE(PCI_VENDOR_RCC, PCI_PRODUCT_RCC_PCIE_PCIX)) { I'd really prefer to write this as if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_RCC && PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_RCC_PCIE_PCIX) { since that is how most other drivers handle this. > + /* > + * These PCI bridges only support 40bit DVA, so intercept > + * bus_dmamap_create so we can clear BUS_DMA_64BIT. > + */ > + > + dt = malloc(sizeof(*dt), M_DEVBUF, M_NOWAIT | M_ZERO); > + if (dt == NULL) > + panic("%s: could not alloc dma tag", __func__); > + > + pdt = pa->pa_dmat; > + > + dt->_parent = pdt; > + dt->_dmamap_create = pci_bcm_dmamap_create; > + > + pa->pa_dmat = dt; > + } > + > + return (0); > } > > int > Index: dev/psycho.c > =================================================================== > RCS file: /cvs/src/sys/arch/sparc64/dev/psycho.c,v > retrieving revision 1.75 > diff -u -p -r1.75 psycho.c > --- dev/psycho.c 25 May 2017 03:19:39 -0000 1.75 > +++ dev/psycho.c 11 Jun 2019 01:37:25 -0000 > @@ -902,7 +902,7 @@ psycho_iommu_init(struct psycho_softc *s > panic("couldn't malloc iommu name"); > snprintf(name, 32, "%s dvma", sc->sc_dev.dv_xname); > > - iommu_init(name, is, tsbsize, iobase); > + iommu_init(name, &iommu_hw_default, is, tsbsize, iobase); > } > > /* > Index: dev/pyro.c > =================================================================== > RCS file: /cvs/src/sys/arch/sparc64/dev/pyro.c,v > retrieving revision 1.32 > diff -u -p -r1.32 pyro.c > --- dev/pyro.c 11 Jun 2019 00:45:31 -0000 1.32 > +++ dev/pyro.c 11 Jun 2019 01:37:25 -0000 > @@ -131,6 +131,30 @@ int pyro_msi_eq_intr(void *); > int pyro_dmamap_create(bus_dma_tag_t, bus_dma_tag_t, bus_size_t, int, > bus_size_t, bus_size_t, int, bus_dmamap_t *); > > +void pyro_iommu_enable(struct iommu_state *); > + > +const struct iommu_hw iommu_hw_fire = { > + .ihw_enable = pyro_iommu_enable, > + > + .ihw_dvma_pa = 0x000007ffffffffffUL, > + > + .ihw_bypass = 0xfffc000000000000UL, > + .ihw_bypass_nc = 0x0000080000000000UL, > + .ihw_bypass_ro = 0, > +}; > + > +const struct iommu_hw iommu_hw_oberon = { > + .ihw_enable = pyro_iommu_enable, > + > + .ihw_dvma_pa = 0x00007fffffffffffUL, > + > + .ihw_bypass = 0x7ffc000000000000UL, > + .ihw_bypass_nc = 0x0000800000000000UL, > + .ihw_bypass_ro = 0x8000000000000000UL, > + > + .ihw_flags = IOMMU_HW_FLUSH_CACHE, > +}; > + > #ifdef DDB > void pyro_xir(void *, int); > #endif > @@ -266,6 +290,7 @@ pyro_init_iommu(struct pyro_softc *sc, s > int tsbsize = 7; > u_int32_t iobase = -1; > char *name; > + const struct iommu_hw *ihw = &iommu_hw_fire; > > is->is_bustag = sc->sc_bust; > > @@ -282,11 +307,23 @@ pyro_init_iommu(struct pyro_softc *sc, s > panic("couldn't malloc iommu name"); > snprintf(name, 32, "%s dvma", sc->sc_dv.dv_xname); > > - /* On Oberon, we need to flush the cache. */ > if (sc->sc_oberon) > - is->is_flags |= IOMMU_FLUSH_CACHE; > + ihw = &iommu_hw_oberon; > + > + iommu_init(name, ihw, is, tsbsize, iobase); > +} > + > +void > +pyro_iommu_enable(struct iommu_state *is) > +{ > + unsigned long cr; > + > + cr = IOMMUREG_READ(is, iommu_cr); > + cr |= IOMMUCR_FIRE_BE | IOMMUCR_FIRE_SE | IOMMUCR_FIRE_CM_EN | > + IOMMUCR_FIRE_TE; > > - iommu_init(name, is, tsbsize, iobase); > + IOMMUREG_WRITE(is, iommu_tsb, is->is_ptsb | is->is_tsbsize); > + IOMMUREG_WRITE(is, iommu_cr, cr); > } > > void > Index: dev/sbus.c > =================================================================== > RCS file: /cvs/src/sys/arch/sparc64/dev/sbus.c,v > retrieving revision 1.44 > diff -u -p -r1.44 sbus.c > --- dev/sbus.c 19 Sep 2015 21:07:04 -0000 1.44 > +++ dev/sbus.c 11 Jun 2019 01:37:25 -0000 > @@ -349,7 +349,7 @@ sbus_mb_attach(struct device *parent, st > snprintf(name, 32, "%s dvma", sc->sc_dev.dv_xname); > > printf("%s: ", sc->sc_dev.dv_xname); > - iommu_init(name, &sc->sc_is, 0, -1); > + iommu_init(name, &iommu_hw_default, &sc->sc_is, 0, -1); > > /* Initialize Starfire PC interrupt translation. */ > if (OF_getprop(findroot(), "name", buf, sizeof(buf)) > 0 && > Index: dev/schizo.c > =================================================================== > RCS file: /cvs/src/sys/arch/sparc64/dev/schizo.c,v > retrieving revision 1.68 > diff -u -p -r1.68 schizo.c > --- dev/schizo.c 25 May 2017 03:19:39 -0000 1.68 > +++ dev/schizo.c 11 Jun 2019 01:37:25 -0000 > @@ -451,7 +451,7 @@ schizo_init_iommu(struct schizo_softc *s > "using iobase=0x%x, tsbsize=%d\n", iobase, tsbsize)); > } > > - iommu_init(name, is, tsbsize, iobase); > + iommu_init(name, &iommu_hw_default, is, tsbsize, iobase); > } > > int > Index: include/pci_machdep.h > =================================================================== > RCS file: /cvs/src/sys/arch/sparc64/include/pci_machdep.h,v > retrieving revision 1.34 > diff -u -p -r1.34 pci_machdep.h > --- include/pci_machdep.h 11 Jun 2019 00:45:31 -0000 1.34 > +++ include/pci_machdep.h 11 Jun 2019 01:37:25 -0000 > @@ -84,10 +84,13 @@ struct sparc_pci_chipset { > pcireg_t (*conf_read)(pci_chipset_tag_t, pcitag_t, int); > void (*conf_write)(pci_chipset_tag_t, pcitag_t, int, pcireg_t); > int (*intr_map)(struct pci_attach_args *, pci_intr_handle_t *); > + int (*probe_device_hook)(void *, struct pci_attach_args *); > }; > > void pci_attach_hook(struct device *, struct device *, > struct pcibus_attach_args *); > +int pci_probe_device_hook(pci_chipset_tag_t, > + struct pci_attach_args *); > int pci_bus_maxdevs(pci_chipset_tag_t, int); > pcitag_t pci_make_tag(pci_chipset_tag_t, int, int, int); > void pci_decompose_tag(pci_chipset_tag_t, pcitag_t, int *, int *, > @@ -115,8 +118,6 @@ int sparc64_pci_enumerate_bus(struct pc > struct pci_attach_args *); > > #define PCI_MACHDEP_ENUMERATE_BUS sparc64_pci_enumerate_bus > - > -#define pci_probe_device_hook(c, a) (0) > > #define pci_min_powerstate(c, t) (PCI_PMCSR_STATE_D3) > #define pci_set_powerstate_md(c, t, s, p) > >