tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

bus_space(9) overrides & resource reservations



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
dyoung%ojctech.com@localhost      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);


Home | Main Index | Thread Index | Old Index