Here is a bus_space(9) patch for review. It adds the ability for MI code to override some of the bus_space(9) routines. It also adds new bus_space(9) routines that decouple bus-space reservations from bus-space mapping.
Five new bus_space(9) routines decouple bus-space reservations from bus-space mapping: now a bus can "borrow" space from a parent just as soon as it knows its requirements, but postpone mapping the space until the last possible moment. This helps me both to do rbus-like management of bus space in bus hierarchies while tossing out rbus, and to get rid of CardBus as a bus type distinct from PCI. The new routines are bus_space_reserve(), bus_space_reserve_subregion(), and bus_space_release() for reserving bus space and for releasing reservations, bus_space_reservation_map() and bus_space_reservation_unmap() for mapping/unmapping reservations. bus_space_reserve() is only implemented on x86. On all other architectures, it returns EOPNOTSUPP. I have refactored bus_space(9) on x86 to make _alloc()/_map() either re-use or share code with bus_space_reserve() and family. Two new routines create and destroy bus_space_tag_t's. One routine, bus_space_tag_create(), derives from an existing bus_space_tag_t a new one whose behavior is the same as the old except where you override it. bus_space_tag_destroy() destroys tags created by bus_space_tag_create(). Currently you can override bus_space_alloc(), _map(), and some other routines. bus_space_tag_create() is only implemented on x86. On all other architectures, it returns EOPNOTSUPP. Dave -- David Young OJC Technologies dyo...@ojctech.com Urbana, IL * (217) 278-3933
Index: sys/arch/x86/include/bus.h =================================================================== RCS file: /cvsroot/src/sys/arch/x86/include/bus.h,v retrieving revision 1.20 diff -u -p -r1.20 bus.h --- sys/arch/x86/include/bus.h 28 Apr 2010 19:17:04 -0000 1.20 +++ sys/arch/x86/include/bus.h 26 May 2010 23:38:04 -0000 @@ -80,11 +80,24 @@ typedef paddr_t bus_addr_t; typedef size_t bus_size_t; -struct bus_space_tag { - int bst_type; +struct bus_space_reservation { + bus_addr_t bsr_start; + bus_size_t bsr_size; }; +typedef struct bus_space_reservation bus_space_reservation_t; + +struct bus_space_tag; typedef struct bus_space_tag *bus_space_tag_t; + +struct bus_space_tag { + int bst_type; + bus_space_tag_t bst_super; + uint64_t bst_present; + const struct bus_space_overrides *bst_ov; + void *bst_ctx; +}; + typedef vaddr_t bus_space_handle_t; extern bus_space_tag_t x86_bus_space_mem; Index: sys/arch/x86/x86/bus_space.c =================================================================== RCS file: /cvsroot/src/sys/arch/x86/x86/bus_space.c,v retrieving revision 1.29 diff -u -p -r1.29 bus_space.c --- sys/arch/x86/x86/bus_space.c 10 May 2010 18:46:58 -0000 1.29 +++ sys/arch/x86/x86/bus_space.c 26 May 2010 23:38:04 -0000 @@ -156,42 +156,49 @@ int 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_SPACE_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; + + bpa = bsr->bsr_start; + size = bsr->bsr_size; /* * 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,18 +206,8 @@ bus_space_map(bus_space_tag_t t, bus_add * For memory space, map the bus physical address to * a kernel virtual address. */ - error = x86_mem_add_mapping(bpa, size, - (flags & BUS_SPACE_MAP_CACHEABLE) != 0, 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 & BUS_SPACE_MAP_CACHEABLE) != 0, bshp); } int @@ -237,10 +234,56 @@ _x86_memio_map(bus_space_tag_t t, bus_ad } 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_SPACE_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; + + bsrp->bsr_start = bpa; + bsrp->bsr_size = 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; @@ -274,32 +317,78 @@ bus_space_alloc(bus_space_tag_t t, bus_a if (error) return (error); + bsr.bsr_start = bpa; + bsr.bsr_size = 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_SPACE_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, bsr->bsr_start, bsr->bsr_size, EX_NOWAIT | + (ioport_malloc_safe ? EX_MALLOCOK : 0))) { + printf("%s: pa 0x%jx, size 0x%jx\n", __func__, + (uintmax_t)bsr->bsr_start, (uintmax_t)bsr->bsr_size); + 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_SPACE_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 & BUS_SPACE_MAP_CACHEABLE) != 0, 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; - *bpap = bpa; + error = bus_space_reservation_map(t, &bsr, flags, bshp); + if (error != 0) + bus_space_release(t, &bsr); - return (error); + *bpap = bsr.bsr_start; + + return error; } int @@ -410,10 +499,10 @@ _x86_memio_unmap(bus_space_tag_t t, bus_ } } -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 +510,8 @@ bus_space_unmap(bus_space_tag_t t, bus_s * 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 +538,51 @@ bus_space_unmap(bus_space_tag_t t, bus_s 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) +{ + 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_space_reservation_t bsr; + + if ((t->bst_present & BUS_SPACE_OVERRIDE_SPACE_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, &bsr.bsr_start); + + bsr.bsr_size = 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_SPACE_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); } Index: sys/sys/bus.h =================================================================== RCS file: /cvsroot/src/sys/sys/bus.h,v retrieving revision 1.3 diff -u -p -r1.3 bus.h --- sys/sys/bus.h 19 Apr 2010 18:24:27 -0000 1.3 +++ sys/sys/bus.h 26 May 2010 23:38:08 -0000 @@ -31,48 +31,47 @@ #include <machine/bus.h> -struct bus_space_reservation; - -typedef struct bus_space_reservation /* { - bus_addr_t sr_addr; - bus_size_t sr_size; -} */ bus_space_reservation_t; - enum bus_space_override_idx { BUS_SPACE_OVERRIDE_SPACE_MAP = __BIT(0) , BUS_SPACE_OVERRIDE_SPACE_UNMAP = __BIT(1) , BUS_SPACE_OVERRIDE_SPACE_ALLOC = __BIT(2) , BUS_SPACE_OVERRIDE_SPACE_FREE = __BIT(3) - , BUS_SPACE_OVERRIDE_SPACE_EXTEND = __BIT(4) - , BUS_SPACE_OVERRIDE_SPACE_TRIM = __BIT(5) + , BUS_SPACE_OVERRIDE_SPACE_RESERVE = __BIT(4) + , BUS_SPACE_OVERRIDE_SPACE_RELEASE = __BIT(5) +#if 0 + , BUS_SPACE_OVERRIDE_SPACE_EXTEND = __BIT(6) + , BUS_SPACE_OVERRIDE_SPACE_TRIM = __BIT(7) +#endif }; /* Only add new members at the end of this struct! */ struct bus_space_overrides { - int (*bs_space_map)(void *, bus_space_tag_t, bus_addr_t, bus_size_t, + int (*ov_space_map)(void *, bus_space_tag_t, bus_addr_t, bus_size_t, int, bus_space_handle_t *); - void (*bs_space_unmap)(void *, bus_space_tag_t, bus_space_handle_t, + void (*ov_space_unmap)(void *, bus_space_tag_t, bus_space_handle_t, bus_size_t); - int (*bs_space_alloc)(void *, bus_space_tag_t, bus_addr_t, bus_addr_t, + int (*ov_space_alloc)(void *, bus_space_tag_t, bus_addr_t, bus_addr_t, bus_size_t, bus_size_t, bus_size_t, int, bus_addr_t *, bus_space_handle_t *); - void (*bs_space_free)(void *, bus_space_tag_t, bus_space_handle_t, + void (*ov_space_free)(void *, bus_space_tag_t, bus_space_handle_t, bus_size_t); - int (*bs_space_reserve)(void *, bus_space_tag_t, bus_addr_t, bus_size_t, - bus_space_reservation_t *); - - void (*bus_space_release)(void *, bus_space_tag_t, - bus_space_reservation_t); + int (*ov_space_reserve)(void *, bus_space_tag_t, bus_addr_t, bus_size_t, + int, bus_space_reservation_t *); - int (*bs_space_extend)(void *, bus_space_tag_t, bus_space_reservation_t, - bus_size_t, bus_size_t); + void (*ov_space_release)(void *, bus_space_tag_t, + bus_space_reservation_t *); - void (*bs_space_trim)(void *, bus_space_tag_t, bus_space_reservation_t, - bus_size_t, bus_size_t); +#if 0 + int (*ov_space_extend)(void *, bus_space_tag_t, + bus_space_reservation_t *, bus_size_t, bus_size_t); + + void (*ov_space_trim)(void *, bus_space_tag_t, + bus_space_reservation_t *, bus_size_t, bus_size_t); +#endif }; bool bus_space_is_equal(bus_space_tag_t, bus_space_tag_t); @@ -84,20 +83,33 @@ void bus_space_tag_destroy(bus_space_tag /* Reserve a region of bus space. Reserved bus space cannot be allocated * with bus_space_alloc(). Reserved space has not been bus_space_map()'d. */ -int bus_space_reserve(bus_space_tag_t, bus_addr_t, bus_size_t, +int bus_space_reserve(bus_space_tag_t, bus_addr_t, bus_size_t, int, bus_space_reservation_t *); +int +bus_space_reserve_subregion(bus_space_tag_t, + bus_addr_t, bus_addr_t, bus_size_t, bus_size_t, bus_size_t, + int, bus_space_reservation_t *); + /* Cancel a reservation. */ -void bus_space_release(bus_space_tag_t, bus_space_reservation_t); +void bus_space_release(bus_space_tag_t, bus_space_reservation_t *); + +int bus_space_reservation_map(bus_space_tag_t, bus_space_reservation_t *, + int, bus_space_handle_t *); + +void bus_space_reservation_unmap(bus_space_tag_t, bus_space_handle_t, + bus_size_t); +#if 0 /* Extend a reservation to the left and/or to the right. The extension * has not been bus_space_map()'d. */ -int bus_space_extend(bus_space_tag_t, bus_space_reservation_t, bus_size_t, +int bus_space_extend(bus_space_tag_t, bus_space_reservation_t *, bus_size_t, bus_size_t); /* Trim bus space from a reservation on the left and/or on the right. */ -void bus_space_trim(bus_space_tag_t, bus_space_reservation_t, bus_size_t, +void bus_space_trim(bus_space_tag_t, bus_space_reservation_t *, bus_size_t, bus_size_t); +#endif #endif /* _SYS_BUS_H_ */ Index: sys/kern/kern_stub.c =================================================================== RCS file: /cvsroot/src/sys/kern/kern_stub.c,v retrieving revision 1.28 diff -u -p -r1.28 kern_stub.c --- sys/kern/kern_stub.c 28 Apr 2010 20:33:52 -0000 1.28 +++ sys/kern/kern_stub.c 27 May 2010 00:01:06 -0000 @@ -127,6 +127,8 @@ __weak_alias(spldebug_stop, voidop); __weak_alias(machdep_init,nullop); __weak_alias(pci_chipset_tag_create, eopnotsupp); __weak_alias(pci_chipset_tag_destroy, voidop); +__weak_alias(bus_space_reserve, eopnotsupp); +__weak_alias(bus_space_release, voidop); __weak_alias(bus_space_tag_create, eopnotsupp); __weak_alias(bus_space_tag_destroy, voidop); __weak_alias(bus_space_is_equal, default_bus_space_is_equal);