FreeBSD/sys/sparc64/sparc64/iommu.c
/*
 * initialise the UltraSPARC IOMMU (PCI or SBus):
 *	- allocate and setup the iotsb.
 *	- enable the IOMMU
 *	- initialise the streaming buffers (if they exist)
 *	- create a private DVMA map.
 */
initialise the UltraSPARC IOMMU (PCI or SBus):
- allocate and setup the iotsb.
- enable the IOMMU
- initialise the streaming buffers (if they exist)
- create a private DVMA map.
initialise the UltraSPARC IOMMU ( PCI or SBus ) : - allocate and setup the iotsb . - enable the IOMMU - initialise the streaming buffers ( if they exist ) - create a private DVMA map .
void
iommu_init(const char *name, struct iommu_state *is, u_int tsbsize,
    uint32_t iovabase, u_int resvpg)
{
	vm_size_t size;
	vm_offset_t offs;
	uint64_t end, obpmap, obpptsb, tte;
	u_int maxtsbsize, obptsbentries, obptsbsize, slot, tsbentries;
	int i;
	if ((is->is_flags & IOMMU_FIRE) != 0) {
		maxtsbsize = IOMMU_TSB512K;
		is->is_cr = IOMMUCR_SE | IOMMUCR_CM_C_TLB_TBW | IOMMUCR_BE;
	} else {
		maxtsbsize = IOMMU_TSB128K;
		is->is_cr = (tsbsize << IOMMUCR_TSBSZ_SHIFT) | IOMMUCR_DE;
	}
	if (tsbsize > maxtsbsize)
		panic("%s: unsupported TSB size	", __func__);
	tsbentries = IOMMU_TSBENTRIES(tsbsize);
	is->is_cr |= IOMMUCR_EN;
	is->is_tsbsize = tsbsize;
	is->is_dvmabase = iovabase;
	if (iovabase == -1)
		is->is_dvmabase = IOTSB_VSTART(is->is_tsbsize);
	size = IOTSB_BASESZ << is->is_tsbsize;
	printf("%s: DVMA map: %#lx to %#lx %d entries%s\n", name,
	    is->is_dvmabase, is->is_dvmabase +
	    (size << (IO_PAGE_SHIFT - IOTTE_SHIFT)) - 1, tsbentries,
	    IOMMU_HAS_SB(is) ? ", streaming buffer" : "");
	mtx_init(&is->is_mtx, "iommu", NULL, MTX_DEF);
	end = is->is_dvmabase + (size << (IO_PAGE_SHIFT - IOTTE_SHIFT));
	is->is_dvma_rman.rm_type = RMAN_ARRAY;
	is->is_dvma_rman.rm_descr = "DVMA Memory";
	if (rman_init(&is->is_dvma_rman) != 0 ||
	    rman_manage_region(&is->is_dvma_rman,
	    (is->is_dvmabase >> IO_PAGE_SHIFT) + resvpg,
	    (end >> IO_PAGE_SHIFT) - 1) != 0)
		panic("%s: could not initialize DVMA rman", __func__);
	TAILQ_INIT(&is->is_maplruq);
	is->is_tsb = contigmalloc(size, M_DEVBUF, M_NOWAIT, 0, ~0UL,
	    PAGE_SIZE, 0);
	if (is->is_tsb == NULL)
		panic("%s: contigmalloc failed", __func__);
	is->is_ptsb = pmap_kextract((vm_offset_t)is->is_tsb);
	bzero(is->is_tsb, size);
	if ((is->is_flags & IOMMU_FIRE) != 0)
		obptsbsize = (IOMMU_READ8(is, is_iommu, IMR_TSB) &
		    IOMMUTB_TSBSZ_MASK) >> IOMMUTB_TSBSZ_SHIFT;
	else
		obptsbsize = (IOMMU_READ8(is, is_iommu, IMR_CTL) &
		    IOMMUCR_TSBSZ_MASK) >> IOMMUCR_TSBSZ_SHIFT;
	obptsbentries = IOMMU_TSBENTRIES(obptsbsize);
	if (bootverbose)
		printf("%s: PROM IOTSB size: %d (%d entries)\n", name,
		    obptsbsize, obptsbentries);
	if ((is->is_flags & IOMMU_PRESERVE_PROM) != 0 &&
	    !(PCPU_GET(impl) == CPU_IMPL_ULTRASPARCIIi && obptsbsize == 7)) {
		if (obptsbentries > tsbentries)
			panic("%s: PROM IOTSB entries exceed kernel",
			    __func__);
		obpptsb = IOMMU_READ8(is, is_iommu, IMR_TSB) &
		    IOMMUTB_TB_MASK;
		for (i = 0; i < obptsbentries; i++) {
			tte = ldxa(obpptsb + i * 8, ASI_PHYS_USE_EC);
			if ((tte & IOTTE_V) == 0)
				continue;
			slot = tsbentries - obptsbentries + i;
			if (bootverbose)
				printf("%s: adding PROM IOTSB slot %d "
				    "(kernel slot %d) TTE: %#lx\n", name,
				    i, slot, tte);
			obpmap = (is->is_dvmabase + slot * IO_PAGE_SIZE) >>
			    IO_PAGE_SHIFT;
			if (rman_reserve_resource(&is->is_dvma_rman, obpmap,
			    obpmap, IO_PAGE_SIZE >> IO_PAGE_SHIFT, RF_ACTIVE,
			    NULL) == NULL)
				panic("%s: could not reserve PROM IOTSB slot "
				    "%d (kernel slot %d)", __func__, i, slot);
			is->is_tsb[slot] = tte;
		}
	}
	if (IOMMU_HAS_SB(is)) {
		offs = roundup2((vm_offset_t)is->is_flush,
		    STRBUF_FLUSHSYNC_NBYTES);
		for (i = 0; i < 2; i++, offs += STRBUF_FLUSHSYNC_NBYTES) {
			is->is_flushva[i] = (uint64_t *)offs;
			is->is_flushpa[i] = pmap_kextract(offs);
		}
	}
	iommu_reset(is);
}
void iommu_init ( const char * name , struct iommu_state * is , u_int tsbsize , uint32_t iovabase , u_int resvpg ) { vm_size_t size ; vm_offset_t offs ; uint64_t end , obpmap , obpptsb , tte ; u_int maxtsbsize , obptsbentries , obptsbsize , slot , tsbentries ; int i ; if ( ( is -> is_flags & IOMMU_FIRE ) != 0 ) { maxtsbsize = IOMMU_TSB512K ; is -> is_cr = IOMMUCR_SE | IOMMUCR_CM_C_TLB_TBW | IOMMUCR_BE ; } else { maxtsbsize = IOMMU_TSB128K ; is -> is_cr = ( tsbsize << IOMMUCR_TSBSZ_SHIFT ) | IOMMUCR_DE ; } if ( tsbsize > maxtsbsize ) panic ( " " , __func__ ) ; tsbentries = IOMMU_TSBENTRIES ( tsbsize ) ; is -> is_cr |= IOMMUCR_EN ; is -> is_tsbsize = tsbsize ; is -> is_dvmabase = iovabase ; if ( iovabase == -1 ) is -> is_dvmabase = IOTSB_VSTART ( is -> is_tsbsize ) ; size = IOTSB_BASESZ << is -> is_tsbsize ; printf ( " \n " , name , is -> is_dvmabase , is -> is_dvmabase + ( size << ( IO_PAGE_SHIFT - IOTTE_SHIFT ) ) - 1 , tsbentries , IOMMU_HAS_SB ( is ) ? " " : " " ) ; mtx_init ( & is -> is_mtx , " " , NULL , MTX_DEF ) ; end = is -> is_dvmabase + ( size << ( IO_PAGE_SHIFT - IOTTE_SHIFT ) ) ; is -> is_dvma_rman . rm_type = RMAN_ARRAY ; is -> is_dvma_rman . rm_descr = " " ; if ( rman_init ( & is -> is_dvma_rman ) != 0 || rman_manage_region ( & is -> is_dvma_rman , ( is -> is_dvmabase >> IO_PAGE_SHIFT ) + resvpg , ( end >> IO_PAGE_SHIFT ) - 1 ) != 0 ) panic ( " " , __func__ ) ; TAILQ_INIT ( & is -> is_maplruq ) ; is -> is_tsb = contigmalloc ( size , M_DEVBUF , M_NOWAIT , 0 , ~ 0UL , PAGE_SIZE , 0 ) ; if ( is -> is_tsb == NULL ) panic ( " " , __func__ ) ; is -> is_ptsb = pmap_kextract ( ( vm_offset_t ) is -> is_tsb ) ; bzero ( is -> is_tsb , size ) ; if ( ( is -> is_flags & IOMMU_FIRE ) != 0 ) obptsbsize = ( IOMMU_READ8 ( is , is_iommu , IMR_TSB ) & IOMMUTB_TSBSZ_MASK ) >> IOMMUTB_TSBSZ_SHIFT ; else obptsbsize = ( IOMMU_READ8 ( is , is_iommu , IMR_CTL ) & IOMMUCR_TSBSZ_MASK ) >> IOMMUCR_TSBSZ_SHIFT ; obptsbentries = IOMMU_TSBENTRIES ( obptsbsize ) ; if ( bootverbose ) printf ( " \n " , name , obptsbsize , obptsbentries ) ; if ( ( is -> is_flags & IOMMU_PRESERVE_PROM ) != 0 && ! ( PCPU_GET ( impl ) == CPU_IMPL_ULTRASPARCIIi && obptsbsize == 7 ) ) { if ( obptsbentries > tsbentries ) panic ( " " , __func__ ) ; obpptsb = IOMMU_READ8 ( is , is_iommu , IMR_TSB ) & IOMMUTB_TB_MASK ; for ( i = 0 ; i < obptsbentries ; i ++ ) { tte = ldxa ( obpptsb + i * 8 , ASI_PHYS_USE_EC ) ; if ( ( tte & IOTTE_V ) == 0 ) continue ; slot = tsbentries - obptsbentries + i ; if ( bootverbose ) printf ( " " " \n " , name , i , slot , tte ) ; obpmap = ( is -> is_dvmabase + slot * IO_PAGE_SIZE ) >> IO_PAGE_SHIFT ; if ( rman_reserve_resource ( & is -> is_dvma_rman , obpmap , obpmap , IO_PAGE_SIZE >> IO_PAGE_SHIFT , RF_ACTIVE , NULL ) == NULL ) panic ( " " " " , __func__ , i , slot ) ; is -> is_tsb [ slot ] = tte ; } } if ( IOMMU_HAS_SB ( is ) ) { offs = roundup2 ( ( vm_offset_t ) is -> is_flush , STRBUF_FLUSHSYNC_NBYTES ) ; for ( i = 0 ; i < 2 ; i ++ , offs += STRBUF_FLUSHSYNC_NBYTES ) { is -> is_flushva [ i ] = ( uint64_t * ) offs ; is -> is_flushpa [ i ] = pmap_kextract ( offs ) ; } } iommu_reset ( is ) ; }
initialise the UltraSPARC IOMMU (PCI or SBus):
      - allocate and setup the iotsb.
initialise the UltraSPARC IOMMU ( PCI or SBus ) : - allocate and setup the iotsb .
/*
	 * Setup the IOMMU.
	 *
	 * The sun4u IOMMU is part of the PCI or SBus controller so we
	 * will deal with it here..
	 *
	 * The IOMMU address space always ends at 0xffffe000, but the starting
	 * address depends on the size of the map.  The map size is 1024 * 2 ^
	 * is->is_tsbsize entries, where each entry is 8 bytes.  The start of
	 * the map can be calculated by (0xffffe000 << (8 + is->is_tsbsize)).
	 */ /*
		 * We enable bypass in order to be able to use a physical
		 * address for the event queue base.
		 */ /*
	 * Set up resource mamangement.
	 */ /*
	 * Allocate memory for I/O page tables.  They need to be
	 * physically contiguous.
	 */ /*
	 * Add the PROM mappings to the kernel IOTSB if desired.
	 * Note that the firmware of certain Darwin boards doesn't set
	 * the TSB size correctly.
	 */ /*
	 * Initialize streaming buffer, if it is there.
	 */ /*
		 * Find two 64-byte blocks in is_flush that are aligned on
		 * a 64-byte boundary for flushing.
		 */ /*
	 * Now actually start up the IOMMU.
	 */