diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/arch/amd64/amd64/bus_space.c | 124 |
1 files changed, 90 insertions, 34 deletions
diff --git a/sys/arch/amd64/amd64/bus_space.c b/sys/arch/amd64/amd64/bus_space.c index 6a8f17a611e..6cff8bffc57 100644 --- a/sys/arch/amd64/amd64/bus_space.c +++ b/sys/arch/amd64/amd64/bus_space.c @@ -1,4 +1,4 @@ -/* $OpenBSD: bus_space.c,v 1.12 2009/03/10 15:03:16 oga Exp $ */ +/* $OpenBSD: bus_space.c,v 1.13 2009/03/26 19:04:56 oga Exp $ */ /* $NetBSD: bus_space.c,v 1.2 2003/03/14 18:47:53 christos Exp $ */ /*- @@ -138,7 +138,7 @@ bus_space_map(bus_space_tag_t t, bus_addr_t bpa, bus_size_t size, int flags, * For memory space, map the bus physical address to * a kernel virtual address. */ - error = x86_mem_add_mapping(bpa, size, 0, bshp); + error = x86_mem_add_mapping(bpa, size, flags, bshp); if (error) { if (extent_free(ex, bpa, size, EX_NOWAIT | (ioport_malloc_safe ? EX_MALLOCOK : 0))) { @@ -168,7 +168,7 @@ _bus_space_map(bus_space_tag_t t, bus_addr_t bpa, bus_size_t size, int flags, * For memory space, map the bus physical address to * a kernel virtual address. */ - return (x86_mem_add_mapping(bpa, size, 0, bshp)); + return (x86_mem_add_mapping(bpa, size, flags, bshp)); } int @@ -219,7 +219,7 @@ bus_space_alloc(bus_space_tag_t t, bus_addr_t rstart, bus_addr_t rend, * For memory space, map the bus physical address to * a kernel virtual address. */ - error = x86_mem_add_mapping(bpa, size, 0, bshp); + error = x86_mem_add_mapping(bpa, size, flags, bshp); if (error) { if (extent_free(iomem_ex, bpa, size, EX_NOWAIT | (ioport_malloc_safe ? EX_MALLOCOK : 0))) { @@ -235,13 +235,45 @@ bus_space_alloc(bus_space_tag_t t, bus_addr_t rstart, bus_addr_t rend, } int -x86_mem_add_mapping(bus_addr_t bpa, bus_size_t size, int cacheable, +x86_mem_add_mapping(bus_addr_t bpa, bus_size_t size, int flags, bus_space_handle_t *bshp) { - if (cacheable) - *bshp = PMAP_DIRECT_MAP(bpa); - else - *bshp = PMAP_DIRECT_NC_MAP(bpa); + u_long pa, endpa; + vaddr_t va, sva; + pt_entry_t *pte; + bus_size_t map_size; + + pa = trunc_page(bpa); + endpa = round_page(bpa + size); + +#ifdef DIAGNOSTIC + if (endpa <= pa && endpa != 0) + panic("bus_mem_add_mapping: overflow"); +#endif + + map_size = endpa - pa; + + va = uvm_km_valloc(kernel_map, map_size); + if (va == 0) + return (ENOMEM); + + *bshp = (bus_space_handle_t)(va + (bpa & PGOFSET)); + + sva = va; + for (; map_size > 0; + pa += PAGE_SIZE, va += PAGE_SIZE, map_size -= PAGE_SIZE) { + pmap_kenter_pa(va, pa, VM_PROT_READ | VM_PROT_WRITE); + + pte = kvtopte(va); + if (flags & BUS_SPACE_MAP_CACHEABLE) + *pte &= ~PG_N; + else + *pte |= PG_N; + } + pmap_tlb_shootrange(pmap_kernel(), sva, va); + pmap_tlb_shootwait(); + pmap_update(pmap_kernel()); + return 0; } @@ -259,36 +291,50 @@ void _bus_space_unmap(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t size, bus_addr_t *adrp) { + u_long va, endva; bus_addr_t bpa; /* - * Find the correct extent and bus physical address. + * Find the correct bus physical address. */ if (t == X86_BUS_SPACE_IO) { bpa = bsh; } else if (t == X86_BUS_SPACE_MEM) { - if (bsh >= atdevbase && (bsh + size) <= (atdevbase + IOM_SIZE)) { - bpa = (bus_addr_t)ISA_PHYSADDR(bsh); - } else { - if (bsh >= PMAP_DIRECT_BASE_NC && - bsh < PMAP_DIRECT_END_NC) - bpa = PMAP_DIRECT_NC_UNMAP(bsh); - else - bpa = PMAP_DIRECT_UNMAP(bsh); - } - } else { - panic("_bus_space_unmap: bad bus space tag"); - } + bpa = (bus_addr_t)ISA_PHYSADDR(bsh); + if (IOM_BEGIN <= bpa && bpa <= IOM_END) + goto ok; - if (adrp != NULL) { + va = trunc_page(bsh); + endva = round_page(bsh + size); + +#ifdef DIAGNOSTIC + if (endva <= va) + panic("_bus_space_unmap: overflow"); +#endif + + (void) pmap_extract(pmap_kernel(), va, &bpa); + bpa += (bsh & PGOFSET); + + pmap_kremove(va, endva - va); + pmap_update(pmap_kernel()); + + /* + * Free the kernel virtual mapping. + */ + uvm_km_free(kernel_map, va, endva - va); + } else + panic("bus_space_unmap: bad bus space tag"); + +ok: + if (adrp != NULL) *adrp = bpa; - } } void bus_space_unmap(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t size) { struct extent *ex; + u_long va, endva; bus_addr_t bpa; /* @@ -299,18 +345,28 @@ bus_space_unmap(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t size) bpa = bsh; } else if (t == X86_BUS_SPACE_MEM) { ex = iomem_ex; - - if (bsh >= atdevbase && - (bsh + size) <= (atdevbase + IOM_SIZE)) { - bpa = (bus_addr_t)ISA_PHYSADDR(bsh); + bpa = (bus_addr_t)ISA_PHYSADDR(bsh); + if (IOM_BEGIN <= bpa && bpa <= IOM_END) goto ok; - } - if (bsh >= PMAP_DIRECT_BASE_NC && - bsh < PMAP_DIRECT_END_NC) - bpa = PMAP_DIRECT_NC_UNMAP(bsh); - else - bpa = PMAP_DIRECT_UNMAP(bsh); + va = trunc_page(bsh); + endva = round_page(bsh + size); + +#ifdef DIAGNOSTIC + if (endva <= va) + panic("bus_space_unmap: overflow"); +#endif + + (void)pmap_extract(pmap_kernel(), va, &bpa); + bpa += (bsh & PGOFSET); + + pmap_kremove(va, endva - va); + pmap_update(pmap_kernel()); + + /* + * Free the kernel virtual mapping. + */ + uvm_km_free(kernel_map, va, endva - va); } else panic("bus_space_unmap: bad bus space tag"); |