Module Name: src Committed By: mrg Date: Wed Mar 16 02:41:19 UTC 2011
Modified Files: src/sys/arch/sparc64/dev: iommu.c iommureg.h iommuvar.h Log Message: various changes to adapt for Fire controller support, based upon the openbsd code to do the same: - add the tsb size into the ptsb bits - avoid setting tsbsize in the CR - disable IDB_INFO for now; it crashes - add new macros for reading/writing IOMMU registers (need to use these more regularly across the whole file) - add a missing membar #lookaside - add support for flushing the pyro(4) caches - extend struct iommureg to include everything pyro To generate a diff of this commit: cvs rdiff -u -r1.100 -r1.101 src/sys/arch/sparc64/dev/iommu.c cvs rdiff -u -r1.15 -r1.16 src/sys/arch/sparc64/dev/iommureg.h cvs rdiff -u -r1.17 -r1.18 src/sys/arch/sparc64/dev/iommuvar.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/sparc64/dev/iommu.c diff -u src/sys/arch/sparc64/dev/iommu.c:1.100 src/sys/arch/sparc64/dev/iommu.c:1.101 --- src/sys/arch/sparc64/dev/iommu.c:1.100 Sat Nov 6 11:46:02 2010 +++ src/sys/arch/sparc64/dev/iommu.c Wed Mar 16 02:41:19 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: iommu.c,v 1.100 2010/11/06 11:46:02 uebayasi Exp $ */ +/* $NetBSD: iommu.c,v 1.101 2011/03/16 02:41:19 mrg Exp $ */ /* * Copyright (c) 1999, 2000 Matthew R. Green @@ -59,7 +59,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: iommu.c,v 1.100 2010/11/06 11:46:02 uebayasi Exp $"); +__KERNEL_RCSID(0, "$NetBSD: iommu.c,v 1.101 2011/03/16 02:41:19 mrg Exp $"); #include "opt_ddb.h" @@ -134,7 +134,7 @@ * be hard-wired, so we read the start and size from the PROM and * just use those values. */ - is->is_cr = (tsbsize << 16) | IOMMUCR_EN; + is->is_cr = IOMMUCR_EN; is->is_tsbsize = tsbsize; if (iovabase == -1) { is->is_dvmabase = IOTSB_VSTART(is->is_tsbsize); @@ -172,7 +172,7 @@ memset(is->is_tsb, 0, size); #ifdef DEBUG - if (iommudebug & IDB_INFO) + if ((iommudebug & IDB_INFO) && 0) { /* Probe the iommu */ @@ -197,11 +197,6 @@ #endif /* - * now actually start up the IOMMU - */ - iommu_reset(is); - - /* * Now all the hardware's working we need to allocate a dvma map. */ aprint_debug("DVMA map: %x to %x\n", @@ -214,6 +209,20 @@ is->is_dvmabase, is->is_dvmaend, M_DEVBUF, 0, 0, EX_NOWAIT); /* XXXMRG Check is_dvmamap is valid. */ + + /* + * 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); } /* @@ -227,13 +236,10 @@ int i; struct strbuf_ctl *sb; - /* Need to do 64-bit stores */ - bus_space_write_8(is->is_bustag, is->is_iommu, IOMMUREG(iommu_tsb), - is->is_ptsb); + IOMMUREG_WRITE(is, iommu_tsb, is->is_ptsb); /* Enable IOMMU in diagnostic mode */ - bus_space_write_8(is->is_bustag, is->is_iommu, IOMMUREG(iommu_cr), - is->is_cr|IOMMUCR_DE); + IOMMUREG_WRITE(is, iommu_cr, is->is_cr|IOMMUCR_DE); for (i = 0; i < 2; i++) { if ((sb = is->is_sb[i])) { @@ -242,6 +248,8 @@ bus_space_write_8(is->is_bustag, is->is_sb[i]->sb_sb, STRBUFREG(strbuf_ctl), STRBUF_EN); + membar_lookaside(); + /* No streaming buffers? Disable them */ if (bus_space_read_8(is->is_bustag, is->is_sb[i]->sb_sb, @@ -252,12 +260,16 @@ /* * locate the pa of the flush buffer. */ - (void)pmap_extract(pmap_kernel(), - (vaddr_t)is->is_sb[i]->sb_flush, - &is->is_sb[i]->sb_flushpa); + if (pmap_extract(pmap_kernel(), + (vaddr_t)is->is_sb[i]->sb_flush, + &is->is_sb[i]->sb_flushpa) == FALSE) + is->is_sb[i]->sb_flush = NULL; } } } + + if (is->is_flags & IOMMU_FLUSH_CACHE) + IOMMUREG_WRITE(is, iommu_cache_invalidate, -1ULL); } /* @@ -325,6 +337,7 @@ void iommu_remove(struct iommu_state *is, vaddr_t va, size_t len) { + int slot; #ifdef DIAGNOSTIC if (va < is->is_dvmabase || va > is->is_dvmaend) @@ -363,8 +376,15 @@ is->is_tsb[IOTSBSLOT(va,is->is_tsbsize)] &= ~IOTTE_V; membar_storestore(); #endif - bus_space_write_8(is->is_bustag, is->is_iommu, - IOMMUREG(iommu_flush), va); + IOMMUREG_WRITE(is, iommu_flush, va); + + /* Flush cache if necessary. */ + slot = IOTSBSLOT(trunc_page(va), is->is_tsbsize); + if ((is->is_flags & IOMMU_FLUSH_CACHE) && + (len == 0 || (slot % 8) == 7)) + IOMMUREG_WRITE(is, iommu_cache_flush, + is->is_ptsb + slot * 8); + va += PAGE_SIZE; } } @@ -453,6 +473,7 @@ vaddr_t vaddr = (vaddr_t)buf; int seg; struct pmap *pmap; + int slot; if (map->dm_nsegs) { /* Already in use?? */ @@ -489,6 +510,7 @@ * If our segment size is larger than the boundary we need to * split the transfer up int little pieces ourselves. */ + KASSERT(is->is_dvmamap); s = splhigh(); err = extent_alloc(is->is_dvmamap, sgsize, align, (sgsize > boundary) ? 0 : boundary, @@ -597,9 +619,17 @@ flags | IOTTE_DEBUG(0x4000)); needsflush = 1; - dvmaddr += PAGE_SIZE; vaddr += sgsize; buflen -= sgsize; + + /* Flush cache if necessary. */ + slot = IOTSBSLOT(trunc_page(dvmaddr), is->is_tsbsize); + if ((is->is_flags & IOMMU_FLUSH_CACHE) && + (buflen <= 0 || (slot % 8) == 7)) + IOMMUREG_WRITE(is, iommu_cache_flush, + is->is_ptsb + slot * 8); + + dvmaddr += PAGE_SIZE; } if (needsflush) iommu_strbuf_flush_done(sb); @@ -672,6 +702,7 @@ u_long dvmaddr, sgstart, sgend, bmask; struct pglist *pglist; const int pagesz = PAGE_SIZE; + int slot; #ifdef DEBUG int npg = 0; #endif @@ -841,7 +872,15 @@ prev_pa = pa, flags | IOTTE_DEBUG(++npg << 12)); needsflush = 1; + + /* Flush cache if necessary. */ + slot = IOTSBSLOT(trunc_page(dvmaddr), is->is_tsbsize); + if ((is->is_flags & IOMMU_FLUSH_CACHE) && + ((dvmaddr + pagesz) > sgend || (slot % 8) == 7)) + IOMMUREG_WRITE(is, iommu_cache_flush, + is->is_ptsb + slot * 8); } + dvmaddr += pagesz; pa += pagesz; last_va = dvmaddr; @@ -912,8 +951,16 @@ iommu_enter(sb, dvmaddr, pa, flags | IOTTE_DEBUG(0x8000)); needsflush = 1; - dvmaddr += pagesz; sgsize -= pagesz; + + /* Flush cache if necessary. */ + slot = IOTSBSLOT(trunc_page(dvmaddr), is->is_tsbsize); + if ((is->is_flags & IOMMU_FLUSH_CACHE) && + (sgsize == 0 || (slot % 8) == 7)) + IOMMUREG_WRITE(is, iommu_cache_flush, + is->is_ptsb + slot * 8); + + dvmaddr += pagesz; } if (needsflush) iommu_strbuf_flush_done(sb); Index: src/sys/arch/sparc64/dev/iommureg.h diff -u src/sys/arch/sparc64/dev/iommureg.h:1.15 src/sys/arch/sparc64/dev/iommureg.h:1.16 --- src/sys/arch/sparc64/dev/iommureg.h:1.15 Sun Dec 7 08:56:10 2008 +++ src/sys/arch/sparc64/dev/iommureg.h Wed Mar 16 02:41:19 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: iommureg.h,v 1.15 2008/12/07 08:56:10 mrg Exp $ */ +/* $NetBSD: iommureg.h,v 1.16 2011/03/16 02:41:19 mrg Exp $ */ /* * Copyright (c) 1992, 1993 @@ -50,9 +50,14 @@ /* iommmu registers */ struct iommureg { - uint64_t iommu_cr; /* IOMMU control register */ - uint64_t iommu_tsb; /* IOMMU TSB base register */ - uint64_t iommu_flush; /* IOMMU flush register */ + volatile uint64_t iommu_cr; /* IOMMU control register */ + volatile uint64_t iommu_tsb; /* IOMMU TSB base register */ + volatile uint64_t iommu_flush; /* IOMMU flush register */ + volatile u_int64_t iommu_ctxflush; + volatile u_int64_t iommu_reserved[28]; + volatile u_int64_t iommu_cache_flush; + volatile u_int64_t iommu_cache_invalidate; + volatile u_int64_t iommu_reserved2[30]; }; /* streaming buffer registers */ @@ -64,6 +69,7 @@ #define IOMMUREG(x) (offsetof(struct iommureg, x)) #define STRBUFREG(x) (offsetof(struct iommu_strbuf, x)) + /* streaming buffer control register */ #define STRBUF_EN 0x000000000000000001LL #define STRBUF_D 0x000000000000000002LL Index: src/sys/arch/sparc64/dev/iommuvar.h diff -u src/sys/arch/sparc64/dev/iommuvar.h:1.17 src/sys/arch/sparc64/dev/iommuvar.h:1.18 --- src/sys/arch/sparc64/dev/iommuvar.h:1.17 Sat Oct 18 03:31:10 2008 +++ src/sys/arch/sparc64/dev/iommuvar.h Wed Mar 16 02:41:19 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: iommuvar.h,v 1.17 2008/10/18 03:31:10 nakayama Exp $ */ +/* $NetBSD: iommuvar.h,v 1.18 2011/03/16 02:41:19 mrg Exp $ */ /* * Copyright (c) 1999 Matthew R. Green @@ -55,6 +55,8 @@ u_int is_dvmaend; int64_t is_cr; /* IOMMU control regiter value */ struct extent *is_dvmamap; /* DVMA map for this instance */ + int is_flags; +#define IOMMU_FLUSH_CACHE 0x00000001 struct strbuf_ctl *is_sb[2]; /* Streaming buffers if any */ @@ -84,4 +86,15 @@ void **, int); void iommu_dvmamem_unmap(bus_dma_tag_t, void *, size_t); +#define IOMMUREG_READ(is, reg) \ + bus_space_read_8((is)->is_bustag, \ + (is)->is_iommu, \ + IOMMUREG(reg)) + +#define IOMMUREG_WRITE(is, reg, v) \ + bus_space_write_8((is)->is_bustag, \ + (is)->is_iommu, \ + IOMMUREG(reg), \ + (v)) + #endif /* _SPARC64_DEV_IOMMUVAR_H_ */