Module Name: src Committed By: dyoung Date: Wed Jul 6 18:46:04 UTC 2011
Modified Files: src/sys/arch/amd64/include: types.h src/sys/arch/i386/include: types.h src/sys/arch/x86/x86: bus_space.c Log Message: Implement bus_space_tag_create() and _destroy(). Factor bus_space_reserve(), bus_space_release(), et cetera out of bus_space_alloc(), bus_space_map(), bus_space_free(), bus_space_unmap(), et cetera. For i386 and amd64, activate the use of <machine/bus_defs.h> and <machine/bus_funcs.h> by #defining __HAVE_NEW_STYLE_BUS_H in their respective types.h. While I'm here, remove unnecessary __HAVE_DEVICE_REGISTER #defines. To generate a diff of this commit: cvs rdiff -u -r1.38 -r1.39 src/sys/arch/amd64/include/types.h cvs rdiff -u -r1.73 -r1.74 src/sys/arch/i386/include/types.h cvs rdiff -u -r1.33 -r1.34 src/sys/arch/x86/x86/bus_space.c 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/amd64/include/types.h diff -u src/sys/arch/amd64/include/types.h:1.38 src/sys/arch/amd64/include/types.h:1.39 --- src/sys/arch/amd64/include/types.h:1.38 Sun Jun 12 03:35:38 2011 +++ src/sys/arch/amd64/include/types.h Wed Jul 6 18:46:04 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: types.h,v 1.38 2011/06/12 03:35:38 rmind Exp $ */ +/* $NetBSD: types.h,v 1.39 2011/07/06 18:46:04 dyoung Exp $ */ /*- * Copyright (c) 1990 The Regents of the University of California. @@ -76,7 +76,7 @@ /* The amd64 does not have strict alignment requirements. */ #define __NO_STRICT_ALIGNMENT -#define __HAVE_DEVICE_REGISTER +#define __HAVE_NEW_STYLE_BUS_H #define __HAVE_CPU_COUNTER #define __HAVE_CPU_DATA_FIRST #define __HAVE_MD_CPU_OFFLINE Index: src/sys/arch/i386/include/types.h diff -u src/sys/arch/i386/include/types.h:1.73 src/sys/arch/i386/include/types.h:1.74 --- src/sys/arch/i386/include/types.h:1.73 Sun Jun 12 03:35:42 2011 +++ src/sys/arch/i386/include/types.h Wed Jul 6 18:46:04 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: types.h,v 1.73 2011/06/12 03:35:42 rmind Exp $ */ +/* $NetBSD: types.h,v 1.74 2011/07/06 18:46:04 dyoung Exp $ */ /*- * Copyright (c) 1990 The Regents of the University of California. @@ -101,7 +101,7 @@ /* The x86 does not have strict alignment requirements. */ #define __NO_STRICT_ALIGNMENT -#define __HAVE_DEVICE_REGISTER +#define __HAVE_NEW_STYLE_BUS_H #define __HAVE_CPU_DATA_FIRST #define __HAVE_CPU_COUNTER #define __HAVE_MD_CPU_OFFLINE Index: src/sys/arch/x86/x86/bus_space.c diff -u src/sys/arch/x86/x86/bus_space.c:1.33 src/sys/arch/x86/x86/bus_space.c:1.34 --- src/sys/arch/x86/x86/bus_space.c:1.33 Fri Feb 11 23:08:38 2011 +++ src/sys/arch/x86/x86/bus_space.c Wed Jul 6 18:46:04 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: bus_space.c,v 1.33 2011/02/11 23:08:38 jmcneill Exp $ */ +/* $NetBSD: bus_space.c,v 1.34 2011/07/06 18:46:04 dyoung Exp $ */ /*- * Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc. @@ -31,12 +31,13 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: bus_space.c,v 1.33 2011/02/11 23:08:38 jmcneill Exp $"); +__KERNEL_RCSID(0, "$NetBSD: bus_space.c,v 1.34 2011/07/06 18:46:04 dyoung Exp $"); #include <sys/param.h> #include <sys/systm.h> #include <sys/malloc.h> #include <sys/extent.h> +#include <sys/kmem.h> #include <uvm/uvm_extern.h> @@ -156,42 +157,58 @@ bus_space_map(bus_space_tag_t t, bus_addr_t bpa, bus_size_t size, int flags, bus_space_handle_t *bshp) { + bus_space_reservation_t bsr; int error; - struct extent *ex; - /* - * Pick the appropriate extent map. - */ - if (x86_bus_space_is_io(t)) { - if (flags & BUS_SPACE_MAP_LINEAR) - return (EOPNOTSUPP); - ex = ioport_ex; - } else if (x86_bus_space_is_mem(t)) - ex = iomem_ex; - else - panic("x86_memio_map: bad bus space tag"); + if ((t->bst_present & BUS_SPACE_OVERRIDE_MAP) != 0) { + return (*t->bst_ov->ov_space_map)(t->bst_ctx, t, bpa, size, + flags, bshp); + } + if (t->bst_super != NULL) + return bus_space_map(t->bst_super, bpa, size, flags, bshp); + + error = bus_space_reserve(t, bpa, size, flags, &bsr); + if (error != 0) + return error; + + error = bus_space_reservation_map(t, &bsr, flags, bshp); + if (error != 0) + bus_space_release(t, &bsr); - /* - * Before we go any further, let's make sure that this - * region is available. - */ - error = extent_alloc_region(ex, bpa, size, - EX_NOWAIT | (ioport_malloc_safe ? EX_MALLOCOK : 0)); - if (error) - return (error); + return error; +} + +int +bus_space_reservation_map(bus_space_tag_t t, bus_space_reservation_t *bsr, + int flags, bus_space_handle_t *bshp) +{ + bus_addr_t bpa; + bus_size_t size; + + if ((t->bst_present & BUS_SPACE_OVERRIDE_RESERVATION_MAP) != 0) { + return (*t->bst_ov->ov_space_reservation_map)(t->bst_ctx, t, + bsr, flags, bshp); + } + if (t->bst_super != NULL) { + return bus_space_reservation_map(t->bst_super, + bsr, flags, bshp); + } + + bpa = bus_space_reservation_addr(bsr); + size = bus_space_reservation_size(bsr); /* * For I/O space, that's all she wrote. */ if (x86_bus_space_is_io(t)) { *bshp = bpa; - return (0); + return 0; } #ifndef XEN if (bpa >= IOM_BEGIN && (bpa + size) != 0 && (bpa + size) <= IOM_END) { *bshp = (bus_space_handle_t)ISA_HOLE_VADDR(bpa); - return(0); + return 0; } #endif /* !XEN */ @@ -199,17 +216,7 @@ * For memory space, map the bus physical address to * a kernel virtual address. */ - 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))) { - printf("x86_memio_map: pa 0x%jx, size 0x%jx\n", - (uintmax_t)bpa, (uintmax_t)size); - printf("x86_memio_map: can't free region\n"); - } - } - - return (error); + return x86_mem_add_mapping(bpa, size, flags, bshp); } int @@ -235,14 +242,66 @@ } int -bus_space_alloc(bus_space_tag_t t, bus_addr_t rstart, bus_addr_t rend, - bus_size_t size, bus_size_t alignment, bus_size_t boundary, - int flags, bus_addr_t *bpap, bus_space_handle_t *bshp) +bus_space_reserve(bus_space_tag_t t, + bus_addr_t bpa, + bus_size_t size, + int flags, bus_space_reservation_t *bsrp) { struct extent *ex; + int error; + + if ((t->bst_present & BUS_SPACE_OVERRIDE_RESERVE) != 0) { + return (*t->bst_ov->ov_space_reserve)(t->bst_ctx, t, + bpa, size, flags, bsrp); + } + if (t->bst_super != NULL) + return bus_space_reserve(t->bst_super, bpa, size, flags, bsrp); + + /* + * Pick the appropriate extent map. + */ + if (x86_bus_space_is_io(t)) { + if (flags & BUS_SPACE_MAP_LINEAR) + return (EOPNOTSUPP); + ex = ioport_ex; + } else if (x86_bus_space_is_mem(t)) + ex = iomem_ex; + else + panic("x86_memio_alloc: bad bus space tag"); + + /* + * Before we go any further, let's make sure that this + * region is available. + */ + error = extent_alloc_region(ex, bpa, size, + EX_NOWAIT | (ioport_malloc_safe ? EX_MALLOCOK : 0)); + + if (error != 0) + return error; + + bus_space_reservation_init(bsrp, bpa, size); + + return 0; +} + +int +bus_space_reserve_subregion(bus_space_tag_t t, + bus_addr_t rstart, bus_addr_t rend, + bus_size_t size, bus_size_t alignment, bus_size_t boundary, + int flags, bus_space_reservation_t *bsrp) +{ + bus_space_reservation_t bsr; + struct extent *ex; u_long bpa; int error; + if ((t->bst_present & BUS_SPACE_OVERRIDE_RESERVE_SUBREGION) != 0) { + return (*t->bst_ov->ov_space_reserve_subregion)(t->bst_ctx, t, + rstart, rend, size, alignment, boundary, flags, bsrp); + } + if (t->bst_super != NULL) + return bus_space_reserve(t->bst_super, bpa, size, flags, bsrp); + /* * Pick the appropriate extent map. */ @@ -258,7 +317,9 @@ /* * Sanity check the allocation against the extent's boundaries. */ - if (rstart < ex->ex_start || rend > ex->ex_end) + rstart = MAX(rstart, ex->ex_start); + rend = MIN(rend, ex->ex_end); + if (rstart >= rend) panic("x86_memio_alloc: bad region start/end"); /* @@ -272,31 +333,79 @@ if (error) return (error); + bus_space_reservation_init(&bsr, bpa, size); + + *bsrp = bsr; + + return 0; +} + +void +bus_space_release(bus_space_tag_t t, bus_space_reservation_t *bsr) +{ + struct extent *ex; + + if ((t->bst_present & BUS_SPACE_OVERRIDE_RELEASE) != 0) { + (*t->bst_ov->ov_space_release)(t->bst_ctx, t, bsr); + return; + } + if (t->bst_super != NULL) { + bus_space_release(t->bst_super, bsr); + return; + } /* - * For I/O space, that's all she wrote. + * Pick the appropriate extent map. */ if (x86_bus_space_is_io(t)) { - *bshp = *bpap = bpa; - return (0); + ex = ioport_ex; + } else if (x86_bus_space_is_mem(t)) + ex = iomem_ex; + else + panic("x86_memio_alloc: bad bus space tag"); + + if (extent_free(ex, bus_space_reservation_addr(bsr), + bus_space_reservation_size(bsr), EX_NOWAIT | + (ioport_malloc_safe ? EX_MALLOCOK : 0))) { + printf("%s: pa 0x%jx, size 0x%jx\n", __func__, + (uintmax_t)bus_space_reservation_addr(bsr), + (uintmax_t)bus_space_reservation_size(bsr)); + printf("%s: can't free region\n", __func__); + } +} + +int +bus_space_alloc(bus_space_tag_t t, bus_addr_t rstart, bus_addr_t rend, + bus_size_t size, bus_size_t alignment, bus_size_t boundary, + int flags, bus_addr_t *bpap, bus_space_handle_t *bshp) +{ + bus_space_reservation_t bsr; + int error; + + if ((t->bst_present & BUS_SPACE_OVERRIDE_ALLOC) != 0) { + return (*t->bst_ov->ov_space_alloc)(t->bst_ctx, t, rstart, rend, + size, alignment, boundary, flags, bpap, bshp); + } + if (t->bst_super != NULL) { + return bus_space_alloc(t->bst_super, rstart, rend, size, + alignment, boundary, flags, bpap, bshp); } /* - * For memory space, map the bus physical address to - * a kernel virtual address. + * Do the requested allocation. */ - 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))) { - printf("x86_memio_alloc: pa 0x%jx, size 0x%jx\n", - (uintmax_t)bpa, (uintmax_t)size); - printf("x86_memio_alloc: can't free region\n"); - } - } + error = bus_space_reserve_subregion(t, rstart, rend, size, alignment, + boundary, flags, &bsr); + + if (error != 0) + return error; + + error = bus_space_reservation_map(t, &bsr, flags, bshp); + if (error != 0) + bus_space_release(t, &bsr); - *bpap = bpa; + *bpap = bus_space_reservation_addr(&bsr); - return (error); + return error; } int @@ -410,10 +519,10 @@ } } -void -bus_space_unmap(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t size) +static void +bus_space_reservation_unmap1(bus_space_tag_t t, const bus_space_handle_t bsh, + const bus_size_t size, bus_addr_t *bpap) { - struct extent *ex; u_long va, endva; bus_addr_t bpa; @@ -421,11 +530,8 @@ * Find the correct extent and bus physical address. */ if (x86_bus_space_is_io(t)) { - ex = ioport_ex; bpa = bsh; } else if (x86_bus_space_is_mem(t)) { - ex = iomem_ex; - if (bsh >= atdevbase && (bsh + size) != 0 && (bsh + size) <= (atdevbase + IOM_SIZE)) { bpa = (bus_addr_t)ISA_PHYSADDR(bsh); @@ -452,21 +558,62 @@ uvm_km_free(kernel_map, va, endva - va, UVM_KMF_VAONLY); } else panic("x86_memio_unmap: bad bus space tag"); - ok: - if (extent_free(ex, bpa, size, - EX_NOWAIT | (ioport_malloc_safe ? EX_MALLOCOK : 0))) { - printf("x86_memio_unmap: %s 0x%jx, size 0x%jx\n", - x86_bus_space_is_io(t) ? "port" : "pa", - (uintmax_t)bpa, (uintmax_t)size); - printf("x86_memio_unmap: can't free region\n"); + if (bpap != NULL) + *bpap = bpa; +} + +void +bus_space_reservation_unmap(bus_space_tag_t t, const bus_space_handle_t bsh, + const bus_size_t size) +{ + if ((t->bst_present & BUS_SPACE_OVERRIDE_RESERVATION_UNMAP) != 0) { + (*t->bst_ov->ov_space_reservation_unmap)(t->bst_ctx, + t, bsh, size); + return; + } + if (t->bst_super != NULL) { + bus_space_reservation_unmap(t->bst_super, bsh, size); + return; + } + + bus_space_reservation_unmap1(t, bsh, size, NULL); +} + +void +bus_space_unmap(bus_space_tag_t t, const bus_space_handle_t bsh, + const bus_size_t size) +{ + bus_addr_t addr; + bus_space_reservation_t bsr; + + if ((t->bst_present & BUS_SPACE_OVERRIDE_UNMAP) != 0) { + (*t->bst_ov->ov_space_unmap)(t->bst_ctx, t, bsh, size); + return; } + if (t->bst_super != NULL) { + bus_space_unmap(t->bst_super, bsh, size); + return; + } + + bus_space_reservation_unmap1(t, bsh, size, &addr); + + bus_space_reservation_init(&bsr, addr, size); + bus_space_release(t, &bsr); } void bus_space_free(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t size) { + if ((t->bst_present & BUS_SPACE_OVERRIDE_FREE) != 0) { + (*t->bst_ov->ov_space_free)(t->bst_ctx, t, bsh, size); + return; + } + if (t->bst_super != NULL) { + bus_space_free(t->bst_super, bsh, size); + return; + } /* bus_space_unmap() does all that we need to do. */ bus_space_unmap(t, bsh, size); } @@ -720,3 +867,76 @@ return x86_bus_space_is_mem(tag) ? (void *)bsh : NULL; } + +static const void * +bit_to_function_pointer(const struct bus_space_overrides *ov, uint64_t bit) +{ + switch (bit) { + case BUS_SPACE_OVERRIDE_MAP: + return ov->ov_space_map; + case BUS_SPACE_OVERRIDE_UNMAP: + return ov->ov_space_unmap; + case BUS_SPACE_OVERRIDE_ALLOC: + return ov->ov_space_alloc; + case BUS_SPACE_OVERRIDE_FREE: + return ov->ov_space_free; + case BUS_SPACE_OVERRIDE_RESERVE: + return ov->ov_space_reserve; + case BUS_SPACE_OVERRIDE_RELEASE: + return ov->ov_space_release; + case BUS_SPACE_OVERRIDE_RESERVATION_MAP: + return ov->ov_space_reservation_map; + case BUS_SPACE_OVERRIDE_RESERVATION_UNMAP: + return ov->ov_space_reservation_unmap; + case BUS_SPACE_OVERRIDE_RESERVE_SUBREGION: + return ov->ov_space_reserve_subregion; + default: + return NULL; + } +} + +void +bus_space_tag_destroy(bus_space_tag_t bst) +{ + kmem_free(bst, sizeof(struct bus_space_tag)); +} + +int +bus_space_tag_create(bus_space_tag_t obst, uint64_t present, + const struct bus_space_overrides *ov, void *ctx, bus_space_tag_t *bstp) +{ + uint64_t bit, bits, nbits; + bus_space_tag_t bst; + const void *fp; + + if (ov == NULL || present != 0) + return EINVAL; + + bst = kmem_alloc(sizeof(struct bus_space_tag), KM_SLEEP); + + if (bst == NULL) + return ENOMEM; + + bst->bst_super = obst; + bst->bst_type = obst->bst_type; + + for (bits = present; bits != 0; bits = nbits) { + nbits = bits & (bits - 1); + bit = nbits ^ bits; + if ((fp = bit_to_function_pointer(ov, bit)) == NULL) { + printf("%s: missing bit %" PRIx64 "\n", __func__, bit); + goto einval; + } + } + + bst->bst_ov = ov; + bst->bst_present = present; + bst->bst_ctx = ctx; + + *bstp = bst; + + return 0; +einval: + kmem_free(bst, sizeof(struct bus_space_tag)); + return EINVAL; +}