Example #1
0
static __inline void
_bus_dmamap_sync_linear(bus_dma_tag_t t, bus_dmamap_t map, bus_addr_t offset,
    bus_size_t len, int ops)
{
	vaddr_t addr = (vaddr_t) map->_dm_origbuf;

	addr += offset;

	switch (ops) {
	case BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE:
		cpu_dcache_wbinv_range(addr, len);
		break;

	case BUS_DMASYNC_PREREAD:
		if (((addr | len) & arm_dcache_align_mask) == 0)
			cpu_dcache_inv_range(addr, len);
		else
			cpu_dcache_wbinv_range(addr, len);
		break;

	case BUS_DMASYNC_PREWRITE:
		cpu_dcache_wb_range(addr, len);
		break;

	case BUS_DMASYNC_POSTREAD:
		cpu_dcache_inv_range(addr, len);
		break;
	}
}
Example #2
0
int
elf_cpu_load_file(linker_file_t lf)
{

	/*
	 * The pmap code does not do an icache sync upon establishing executable
	 * mappings in the kernel pmap.  It's an optimization based on the fact
	 * that kernel memory allocations always have EXECUTABLE protection even
	 * when the memory isn't going to hold executable code.  The only time
	 * kernel memory holding instructions does need a sync is after loading
	 * a kernel module, and that's when this function gets called.
	 *
	 * This syncs data and instruction caches after loading a module.  We
	 * don't worry about the kernel itself (lf->id is 1) as locore.S did
	 * that on entry.  Even if data cache maintenance was done by IO code,
	 * the relocation fixup process creates dirty cache entries that we must
	 * write back before doing icache sync. The instruction cache sync also
	 * invalidates the branch predictor cache on platforms that have one.
	 */
	if (lf->id == 1)
		return (0);
#if __ARM_ARCH >= 6
	dcache_wb_pou((vm_offset_t)lf->address, (vm_size_t)lf->size);
	icache_inv_all();
#else
	cpu_dcache_wb_range((vm_offset_t)lf->address, (vm_size_t)lf->size);
	cpu_l2cache_wb_range((vm_offset_t)lf->address, (vm_size_t)lf->size);
	cpu_icache_sync_range((vm_offset_t)lf->address, (vm_size_t)lf->size);
#endif
	return (0);
}
Example #3
0
static void
_bus_dmamap_sync_segment(vaddr_t va, paddr_t pa, vsize_t len, int ops)
{
	KASSERT((va & PAGE_MASK) == (pa & PAGE_MASK));

#ifdef DEBUG_DMA
	printf("sync_segment: va=%#lx pa=%#lx len=%#lx ops=%#x\n",
	    va, pa, len, ops);
#endif

	switch (ops) {
	case BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE:
		cpu_dcache_wbinv_range(va, len);
		cpu_sdcache_wbinv_range(va, pa, len);
		break;
		/* FALLTHROUGH */

	case BUS_DMASYNC_PREREAD: {
		const size_t line_size = arm_dcache_align;
		const size_t line_mask = arm_dcache_align_mask;
		vsize_t misalignment = va & line_mask;
		if (misalignment) {
			va -= misalignment;
			pa -= misalignment;
			len += misalignment;
			cpu_dcache_wbinv_range(va, line_size);
			cpu_sdcache_wbinv_range(va, pa, line_size);
			if (len <= line_size)
				break;
			va += line_size;
			pa += line_size;
			len -= line_size;
		}
		misalignment = len & line_mask;
		len -= misalignment;
		if (len > 0) {
			cpu_dcache_inv_range(va, len);
			cpu_sdcache_inv_range(va, pa, len);
		}
		if (misalignment) {
			va += len;
			pa += len;
			cpu_dcache_wbinv_range(va, line_size);
			cpu_sdcache_wbinv_range(va, pa, line_size);
		}
		break;
	}

	case BUS_DMASYNC_PREWRITE:
		cpu_dcache_wb_range(va, len);
		cpu_sdcache_wb_range(va, pa, len);
		break;
	}
}
Example #4
0
static __inline void
_bus_dmamap_sync_uio(bus_dma_tag_t t, bus_dmamap_t map, bus_addr_t offset,
    bus_size_t len, int ops)
{
	struct uio *uio = map->_dm_origbuf;
	struct iovec *iov;
	bus_size_t minlen, ioff;
	vaddr_t addr;

	for (iov = uio->uio_iov, ioff = offset; len != 0; iov++) {
		/* Find the beginning iovec. */
		if (ioff >= iov->iov_len) {
			ioff -= iov->iov_len;
			continue;
		}

		/*
		 * Now at the first iovec to sync; nail each one until
		 * we have exhausted the length.
		 */
		minlen = iov->iov_len - ioff;
		if (len < minlen)
			minlen = len;

		addr = (vaddr_t) iov->iov_base;
		addr += ioff;

		switch (ops) {
		case BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE:
			cpu_dcache_wbinv_range(addr, minlen);
			break;

		case BUS_DMASYNC_PREREAD:
			if (((addr | minlen) & arm_dcache_align_mask) == 0)
				cpu_dcache_inv_range(addr, minlen);
			else
				cpu_dcache_wbinv_range(addr, minlen);
			break;

		case BUS_DMASYNC_PREWRITE:
			cpu_dcache_wb_range(addr, minlen);
			break;
		}
		ioff = 0;
		len -= minlen;
	}
}
Example #5
0
/*
 * Write bytes to kernel address space for debugger.
 */
int
db_write_bytes(vm_offset_t addr, size_t size, char *data)
{
	char *dst;

	dst = (char *)addr;
	while (size-- > 0) {
		if (db_validate_address((vm_offset_t)dst)) {
			db_printf("address %p is invalid\n", dst);
			return (-1);
		}
		*dst++ = *data++;
	}
	dsb(ish);

	/* Clean D-cache and invalidate I-cache */
	cpu_dcache_wb_range(addr, (vm_size_t)size);
	cpu_icache_sync_range(addr, (vm_size_t)size);

	return (0);
}
Example #6
0
static int
aau_bzero(void *dst, int len, int flags)
{
	struct i80321_aau_softc *sc = aau_softc;
	i80321_aaudesc_t *desc;
	int ret;
	int csr;
	int descnb = 0;
	int tmplen = len;
	int to_nextpagedst;
	int min_hop;
	vm_paddr_t pa, tmppa;

	if (!sc)
		return (-1);
	mtx_lock_spin(&sc->mtx);
	if (sc->flags & BUSY) {
		mtx_unlock_spin(&sc->mtx);
		return (-1);
	}
	sc->flags |= BUSY;
	mtx_unlock_spin(&sc->mtx);
	desc = sc->aauring[0].desc;
	if (flags & IS_PHYSICAL) {
		desc->local_addr = (vm_paddr_t)dst;
		desc->next_desc = 0;
		desc->count = len;
		desc->descr_ctrl = 2 << 1 | 1 << 31; /* Fill, enable dest write */
		bus_dmamap_sync(sc->dmatag, sc->aauring[0].map,
		    BUS_DMASYNC_PREWRITE);
	} else {
		test_virt_addr(dst, len);
		if ((vm_offset_t)dst & (31))
			cpu_dcache_wb_range((vm_offset_t)dst & ~31, 32);
		if (((vm_offset_t)dst + len) & 31)
			cpu_dcache_wb_range(((vm_offset_t)dst + len) & ~31,
			    32);
		cpu_dcache_inv_range((vm_offset_t)dst, len);
		while (tmplen > 0) {
			pa = vtophys(dst);
			to_nextpagedst = ((vm_offset_t)dst & ~PAGE_MASK) +
			    PAGE_SIZE - (vm_offset_t)dst;
			while (to_nextpagedst < tmplen) {
				tmppa = vtophys((vm_offset_t)dst +
				    to_nextpagedst);
				if (tmppa != pa + to_nextpagedst)
					break;
				to_nextpagedst += PAGE_SIZE;
			}
			min_hop = to_nextpagedst;
			if (min_hop < 64) {
				tmplen -= min_hop;
				bzero(dst, min_hop);
				cpu_dcache_wbinv_range((vm_offset_t)dst,
				    min_hop);

				dst = (void *)((vm_offset_t)dst + min_hop);
				if (tmplen <= 0 && descnb > 0) {
					sc->aauring[descnb - 1].desc->next_desc
					    = 0;
					bus_dmamap_sync(sc->dmatag,
					    sc->aauring[descnb - 1].map,
					    BUS_DMASYNC_PREWRITE);
				}
				continue;
			}
			desc->local_addr = pa;
			desc->count = tmplen > min_hop ? min_hop : tmplen;
			desc->descr_ctrl = 2 << 1 | 1 << 31; /* Fill, enable dest write */;
			if (min_hop < tmplen) {
				tmplen -= min_hop;
				dst = (void *)((vm_offset_t)dst + min_hop);
			} else
				tmplen = 0;
			if (descnb + 1 >= AAU_RING_SIZE) {
				mtx_lock_spin(&sc->mtx);
				sc->flags &= ~BUSY;
				mtx_unlock_spin(&sc->mtx);
				return (-1);
			}
			if (tmplen > 0) {
				desc->next_desc = sc->aauring[descnb + 1].
				    phys_addr;
				bus_dmamap_sync(sc->dmatag,
				    sc->aauring[descnb].map,
				    BUS_DMASYNC_PREWRITE);
				desc = sc->aauring[descnb + 1].desc;
				descnb++;
			} else {
				desc->next_desc = 0;
				bus_dmamap_sync(sc->dmatag,
				    sc->aauring[descnb].map,
				    BUS_DMASYNC_PREWRITE);
			}
									
		}

	}
	AAU_REG_WRITE(sc, 0x0c /* Descriptor addr */,
	    sc->aauring[0].phys_addr);
	AAU_REG_WRITE(sc, 0 /* Control register */, 1 << 0/* Start transfer */);
	while ((csr = AAU_REG_READ(sc, 0x4)) & (1 << 10));
	/* Wait until it's done. */
	if (csr & (1 << 5)) /* error */
		ret = -1;
	else
		ret = 0;
	/* Clear the interrupt. */
	AAU_REG_WRITE(sc, 0x4, csr);
	/* Stop the AAU. */
	AAU_REG_WRITE(sc, 0, 0);
	mtx_lock_spin(&sc->mtx);
	sc->flags &= ~BUSY;
	mtx_unlock_spin(&sc->mtx);
	return (ret);
}
Example #7
0
static int
dma_memcpy(void *dst, void *src, int len, int flags)
{
	struct i80321_dma_softc *sc;
	i80321_dmadesc_t *desc;
	int ret;
	int csr;
	int descnb = 0;
	int tmplen = len;
	int to_nextpagesrc, to_nextpagedst;
	int min_hop;
	vm_paddr_t pa, pa2, tmppa;
	pmap_t pmap = vmspace_pmap(curthread->td_proc->p_vmspace);

	if (!softcs[0] || !softcs[1])
		return (-1);
	mtx_lock_spin(&softcs[0]->mtx);
	if (softcs[0]->flags & BUSY) {
		mtx_unlock_spin(&softcs[0]->mtx);
		mtx_lock_spin(&softcs[1]->mtx);
		if (softcs[1]->flags & BUSY) {
			mtx_unlock(&softcs[1]->mtx);
			return (-1);
		}
		sc = softcs[1];
	} else
		sc = softcs[0];
	sc->flags |= BUSY;
	mtx_unlock_spin(&sc->mtx);
	desc = sc->dmaring[0].desc;
	if (flags & IS_PHYSICAL) {
		desc->next_desc = 0;
		desc->low_pciaddr = (vm_paddr_t)src;
		desc->high_pciaddr = 0;
		desc->local_addr = (vm_paddr_t)dst;
		desc->count = len;
		desc->descr_ctrl = 1 << 6; /* Local memory to local memory. */
		bus_dmamap_sync(sc->dmatag, 
		    sc->dmaring[0].map, 
		    BUS_DMASYNC_PREWRITE);
	} else {
		if (!virt_addr_is_valid(dst, len, 1, !(flags & DST_IS_USER)) || 
		    !virt_addr_is_valid(src, len, 0, !(flags & SRC_IS_USER))) {
			mtx_lock_spin(&sc->mtx);
			sc->flags &= ~BUSY;
			mtx_unlock_spin(&sc->mtx);
			return (-1);
		}
		cpu_dcache_wb_range((vm_offset_t)src, len);
		if ((vm_offset_t)dst & (31))
			cpu_dcache_wb_range((vm_offset_t)dst & ~31, 32);
		if (((vm_offset_t)dst + len) & 31)
			cpu_dcache_wb_range(((vm_offset_t)dst + len) & ~31,
			    32);
		cpu_dcache_inv_range((vm_offset_t)dst, len);
		while (tmplen > 0) {
			pa = (flags & SRC_IS_USER) ?
			    pmap_extract(pmap, (vm_offset_t)src) :
				    vtophys(src);
			pa2 = (flags & DST_IS_USER) ?
			    pmap_extract(pmap, (vm_offset_t)dst) :
				    vtophys(dst);
			to_nextpagesrc = ((vm_offset_t)src & ~PAGE_MASK) +
			    PAGE_SIZE - (vm_offset_t)src;
			to_nextpagedst = ((vm_offset_t)dst & ~PAGE_MASK) +
			    PAGE_SIZE - (vm_offset_t)dst;
			while (to_nextpagesrc < tmplen) {
				tmppa = (flags & SRC_IS_USER) ?
				    pmap_extract(pmap, (vm_offset_t)src +
				    to_nextpagesrc) :
					    vtophys((vm_offset_t)src +
						to_nextpagesrc);
				if (tmppa != pa + to_nextpagesrc)
					break;
				to_nextpagesrc += PAGE_SIZE;
			}
			while (to_nextpagedst < tmplen) {
				tmppa = (flags & DST_IS_USER) ?
				    pmap_extract(pmap, (vm_offset_t)dst +
				    to_nextpagedst) :
					    vtophys((vm_offset_t)dst +
						to_nextpagedst);
				if (tmppa != pa2 + to_nextpagedst)
					break;
				to_nextpagedst += PAGE_SIZE;
			}
			min_hop = to_nextpagedst > to_nextpagesrc ?
			    to_nextpagesrc : to_nextpagedst;
			if (min_hop < 64) {
				tmplen -= min_hop;
				memcpy(dst, src, min_hop);
				cpu_dcache_wbinv_range((vm_offset_t)dst,
				    min_hop);

				src = (void *)((vm_offset_t)src + min_hop);
				dst = (void *)((vm_offset_t)dst + min_hop);
				if (tmplen <= 0 && descnb > 0) {
					sc->dmaring[descnb - 1].desc->next_desc
					    = 0;
					bus_dmamap_sync(sc->dmatag, 
					    sc->dmaring[descnb - 1].map, 
					    BUS_DMASYNC_PREWRITE);
				}
				continue;
			}
			desc->low_pciaddr = pa;
			desc->high_pciaddr = 0;
			desc->local_addr = pa2;
			desc->count = tmplen > min_hop ? min_hop : tmplen;
			desc->descr_ctrl = 1 << 6;
			if (min_hop < tmplen) {
				tmplen -= min_hop;
				src = (void *)((vm_offset_t)src + min_hop);
				dst = (void *)((vm_offset_t)dst + min_hop);
			} else
				tmplen = 0;
			if (descnb + 1 >= DMA_RING_SIZE) {
				mtx_lock_spin(&sc->mtx);
				sc->flags &= ~BUSY;
				mtx_unlock_spin(&sc->mtx);
				return (-1);
			}
			if (tmplen > 0) {
				desc->next_desc = sc->dmaring[descnb + 1].
				    phys_addr;
				bus_dmamap_sync(sc->dmatag, 
				    sc->dmaring[descnb].map, 
				    BUS_DMASYNC_PREWRITE);
				desc = sc->dmaring[descnb + 1].desc;
				descnb++;
			} else {
				desc->next_desc = 0;
				bus_dmamap_sync(sc->dmatag,
				    sc->dmaring[descnb].map,
				    BUS_DMASYNC_PREWRITE);
			}
									
		}

	}
	DMA_REG_WRITE(sc, 4 /* Status register */,
	    DMA_REG_READ(sc, 4) | DMA_CLEAN_MASK);
	DMA_REG_WRITE(sc, 0x10 /* Descriptor addr */,
	    sc->dmaring[0].phys_addr);
	DMA_REG_WRITE(sc, 0 /* Control register */, 1 | 2/* Start transfer */);
	while ((csr = DMA_REG_READ(sc, 0x4)) & (1 << 10));
	/* Wait until it's done. */
	if (csr & 0x2e) /* error */
		ret = -1;
	else
		ret = 0;
	DMA_REG_WRITE(sc, 0, 0);
	mtx_lock_spin(&sc->mtx);
	sc->flags &= ~BUSY;
	mtx_unlock_spin(&sc->mtx);
	return (ret);
}
Example #8
0
static __inline void
_bus_dmamap_sync_mbuf(bus_dma_tag_t t, bus_dmamap_t map, bus_addr_t offset,
    bus_size_t len, int ops)
{
	struct mbuf *m, *m0 = map->_dm_origbuf;
	bus_size_t minlen, moff;
	vaddr_t maddr;

	for (moff = offset, m = m0; m != NULL && len != 0;
	     m = m->m_next) {
		/* Find the beginning mbuf. */
		if (moff >= m->m_len) {
			moff -= m->m_len;
			continue;
		}

		/*
		 * Now at the first mbuf to sync; nail each one until
		 * we have exhausted the length.
		 */
		minlen = m->m_len - moff;
		if (len < minlen)
			minlen = len;

		maddr = mtod(m, vaddr_t);
		maddr += moff;

		/*
		 * We can save a lot of work here if we know the mapping
		 * is read-only at the MMU:
		 *
		 * If a mapping is read-only, no dirty cache blocks will
		 * exist for it.  If a writable mapping was made read-only,
		 * we know any dirty cache lines for the range will have
		 * been cleaned for us already.  Therefore, if the upper
		 * layer can tell us we have a read-only mapping, we can
		 * skip all cache cleaning.
		 *
		 * NOTE: This only works if we know the pmap cleans pages
		 * before making a read-write -> read-only transition.  If
		 * this ever becomes non-true (e.g. Physically Indexed
		 * cache), this will have to be revisited.
		 */
		switch (ops) {
		case BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE:
			/* if (! M_ROMAP(m)) */{
				cpu_dcache_wbinv_range(maddr, minlen);
				break;
			}
			/* else FALLTHROUGH */

		case BUS_DMASYNC_PREREAD:
			if (((maddr | minlen) & arm_dcache_align_mask) == 0)
				cpu_dcache_inv_range(maddr, minlen);
			else
				cpu_dcache_wbinv_range(maddr, minlen);
			break;

		case BUS_DMASYNC_PREWRITE:
			/* if (! M_ROMAP(m)) */
				cpu_dcache_wb_range(maddr, minlen);
			break;
		}
		moff = 0;
		len -= minlen;
	}
}
static int
flush_dc_changes_to_screen(struct fb_devconfig *dc)
{
	int v, cleared = 0;

	v = dc->_internal_dc_changed;

	if (v == 0) {
		disable_irq(IRQ_FLYBACK);
		return 1;
	}

	if (v & WSDISPLAY_WB_COUNTER) {
	    	dc->dc_writeback_delay--;
		if (dc->dc_writeback_delay == 0) {
		    	cpu_dcache_wb_range(dc->dc_vaddr, dc->dc_size);
			cleared |= WSDISPLAY_WB_COUNTER;
		}
	}

	if (v & WSDISPLAY_CMAP_DOLUT) {
		struct hwcmap256 *cm = &dc->dc_cmap;
		int index;

		if (dc->dc_depth == 4) {
			/* palette for 4 bpp is different from 8bpp */
			vidcvideo_write(VIDC_PALREG, 0x00000000);
			for (index=0; index < (1 << dc->dc_depth); index++)
				vidcvideo_write(VIDC_PALETTE,
					VIDC_COL(cm->r[index],
						 cm->g[index],
						 cm->b[index]));
		}

		if (dc->dc_depth == 8) {
			/*
			 * dunno what to do in more than 8bpp 
			 * palettes only make sense in 8bpp and less modes
			 * on VIDC
			 */
			vidcvideo_write(VIDC_PALREG, 0x00000000);
			for (index = 0; index < CMAP_SIZE; index++) {
				vidcvideo_write(VIDC_PALETTE,
					VIDC_COL(cm->r[index], cm->g[index],
					    cm->b[index]));
			}
		}
		cleared |= WSDISPLAY_CMAP_DOLUT;
	}

	if (v & WSDISPLAY_VIDEO_ONOFF) {
		vidcvideo_blank(dc->dc_blanked);
		cleared |= WSDISPLAY_VIDEO_ONOFF;
	}

	if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) {
		int x, y;
		x = dc->dc_cursor.cc_pos.x - dc->dc_cursor.cc_hot.x;
		y = dc->dc_cursor.cc_pos.y - dc->dc_cursor.cc_hot.y;

		vidcvideo_updatecursor(x, y);
		cleared |= WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT;
	}

	if (v & WSDISPLAY_CURSOR_DOCUR) {
		vidcvideo_enablecursor(dc->dc_curenb);
		cleared |= WSDISPLAY_CURSOR_DOCUR;
	}

	dc->_internal_dc_changed ^= cleared;

	if (dc->_internal_dc_changed == 0) {
		disable_irq(IRQ_FLYBACK);
	}

	return 1;
}