/* * Map a user I/O request into kernel virtual address space. */ int vmapbuf(struct buf *bp, vsize_t len) { vaddr_t kva; /* Kernel VA (new to) */ if ((bp->b_flags & B_PHYS) == 0) panic("vmapbuf"); vaddr_t uva = mips_trunc_page(bp->b_data); const vaddr_t off = (vaddr_t)bp->b_data - uva; len = mips_round_page(off + len); kva = uvm_km_alloc(phys_map, len, atop(uva) & uvmexp.colormask, UVM_KMF_VAONLY | UVM_KMF_WAITVA | UVM_KMF_COLORMATCH); KASSERT((atop(kva ^ uva) & uvmexp.colormask) == 0); bp->b_saveaddr = bp->b_data; bp->b_data = (void *)(kva + off); struct pmap * const upmap = vm_map_pmap(&bp->b_proc->p_vmspace->vm_map); do { paddr_t pa; /* physical address */ if (pmap_extract(upmap, uva, &pa) == false) panic("vmapbuf: null page frame"); pmap_kenter_pa(kva, pa, VM_PROT_READ | VM_PROT_WRITE, PMAP_WIRED); uva += PAGE_SIZE; kva += PAGE_SIZE; len -= PAGE_SIZE; } while (len); pmap_update(pmap_kernel()); return 0; }
void dmac3_start(struct dmac3_softc *sc, vaddr_t addr, int len, int direction) { struct dmac3reg *reg = sc->sc_reg; paddr_t pa; vaddr_t start, end, v; volatile uint32_t *p; if (reg->csr & DMAC3_CSR_ENABLE) dmac3_reset(sc); start = mips_trunc_page(addr); end = mips_round_page(addr + len); p = sc->sc_dmamap; for (v = start; v < end; v += PAGE_SIZE) { pa = kvtophys(v); mips_dcache_wbinv_range(MIPS_PHYS_TO_KSEG0(pa), PAGE_SIZE); *p++ = 0; *p++ = (pa >> PGSHIFT) | 0xc0000000; } *p++ = 0; *p++ = 0x003fffff; addr &= PGOFSET; addr += sc->sc_dmaaddr; reg->len = len; reg->addr = addr; reg->intr = DMAC3_INTR_EOPIE | DMAC3_INTR_INTEN; reg->csr = DMAC3_CSR_ENABLE | direction | BURST_MODE | APAD_MODE; }
/* * Unmap a previously-mapped user I/O request. */ void vunmapbuf(struct buf *bp, vsize_t len) { vaddr_t kva; if ((bp->b_flags & B_PHYS) == 0) panic("vunmapbuf"); kva = mips_trunc_page(bp->b_data); len = mips_round_page((vaddr_t)bp->b_data - kva + len); pmap_kremove(kva, len); pmap_update(pmap_kernel()); uvm_km_free(phys_map, kva, len, UVM_KMF_VAONLY); bp->b_data = bp->b_saveaddr; bp->b_saveaddr = NULL; }