1 /*- 2 * Copyright (c) 2015-2016 Landon Fuller <landon@landonf.org> 3 * Copyright (c) 2017 The FreeBSD Foundation 4 * All rights reserved. 5 * 6 * Portions of this software were developed by Landon Fuller 7 * under sponsorship from the FreeBSD Foundation. 8 * 9 * Portions of this software were developed by Landon Fuller 10 * under sponsorship from the FreeBSD Foundation. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer, 17 * without modification. 18 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 19 * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 20 * redistribution must be conditioned upon including a substantially 21 * similar Disclaimer requirement for further binary redistribution. 22 * 23 * NO WARRANTY 24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 25 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 26 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 28 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 29 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 32 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 34 * THE POSSIBILITY OF SUCH DAMAGES. 35 * 36 * $FreeBSD$ 37 */ 38 39 #ifndef _BHND_BHNDB_PRIVATE_H_ 40 #define _BHND_BHNDB_PRIVATE_H_ 41 42 #include <sys/param.h> 43 #include <sys/bitstring.h> 44 #include <sys/bus.h> 45 #include <sys/systm.h> 46 47 #include <machine/bus.h> 48 #include <sys/rman.h> 49 #include <machine/resource.h> 50 51 #include "bhndbvar.h" 52 53 /* 54 * Private bhndb(4) driver definitions. 55 */ 56 57 struct bhndb_dw_alloc; 58 struct bhndb_intr_handler; 59 struct bhndb_region; 60 struct bhndb_resources; 61 62 struct bhndb_resources *bhndb_alloc_resources(device_t dev, 63 device_t parent_dev, 64 const struct bhndb_hwcfg *cfg); 65 66 void bhndb_free_resources( 67 struct bhndb_resources *br); 68 69 int bhndb_add_resource_region( 70 struct bhndb_resources *br, 71 bhnd_addr_t addr, bhnd_size_t size, 72 bhndb_priority_t priority, 73 uint32_t alloc_flags, 74 const struct bhndb_regwin *static_regwin); 75 76 int bhndb_find_resource_limits( 77 struct bhndb_resources *br, int type, 78 struct resource *r, rman_res_t *start, 79 rman_res_t *end); 80 81 struct bhndb_intr_handler *bhndb_alloc_intr_handler(device_t owner, 82 struct resource *r, 83 struct bhndb_intr_isrc *isrc); 84 void bhndb_free_intr_handler( 85 struct bhndb_intr_handler *ih); 86 87 void bhndb_register_intr_handler( 88 struct bhndb_resources *br, 89 struct bhndb_intr_handler *ih); 90 void bhndb_deregister_intr_handler( 91 struct bhndb_resources *br, 92 struct bhndb_intr_handler *ih); 93 struct bhndb_intr_handler *bhndb_find_intr_handler( 94 struct bhndb_resources *br, 95 void *cookiep); 96 97 bool bhndb_has_static_region_mapping( 98 struct bhndb_resources *br, 99 bhnd_addr_t addr, bhnd_size_t size); 100 101 struct bhndb_region *bhndb_find_resource_region( 102 struct bhndb_resources *br, 103 bhnd_addr_t addr, bhnd_size_t size); 104 105 struct bhndb_dw_alloc *bhndb_dw_find_resource( 106 struct bhndb_resources *dr, 107 struct resource *r); 108 109 struct bhndb_dw_alloc *bhndb_dw_find_mapping( 110 struct bhndb_resources *br, 111 bhnd_addr_t addr, bhnd_size_t size); 112 113 int bhndb_dw_retain( 114 struct bhndb_resources *br, 115 struct bhndb_dw_alloc *dwa, 116 struct resource *res); 117 118 void bhndb_dw_release( 119 struct bhndb_resources *br, 120 struct bhndb_dw_alloc *dwa, 121 struct resource *res); 122 123 int bhndb_dw_set_addr(device_t dev, 124 struct bhndb_resources *br, 125 struct bhndb_dw_alloc *dwa, 126 bus_addr_t addr, bus_size_t size); 127 128 struct bhndb_dw_alloc *bhndb_dw_steal(struct bhndb_resources *br, 129 bus_addr_t *saved); 130 131 void bhndb_dw_return_stolen(device_t dev, 132 struct bhndb_resources *br, 133 struct bhndb_dw_alloc *dwa, 134 bus_addr_t saved); 135 136 const struct bhndb_hw_priority *bhndb_hw_priority_find_core( 137 const struct bhndb_hw_priority *table, 138 struct bhnd_core_info *core); 139 140 const struct bhndb_port_priority *bhndb_hw_priorty_find_port( 141 const struct bhndb_hw_priority *table, 142 struct bhnd_core_info *core, 143 bhnd_port_type port_type, u_int port, 144 u_int region); 145 146 /** 147 * Dynamic register window allocation reference. 148 */ 149 struct bhndb_dw_rentry { 150 struct resource *dw_res; /**< child resource */ 151 LIST_ENTRY(bhndb_dw_rentry) dw_link; 152 }; 153 154 /** 155 * A dynamic register window allocation record. 156 */ 157 struct bhndb_dw_alloc { 158 const struct bhndb_regwin *win; /**< window definition */ 159 struct resource *parent_res; /**< enclosing resource */ 160 u_int rnid; /**< region identifier */ 161 rman_res_t target; /**< the current window address, or 0x0 if unknown */ 162 163 LIST_HEAD(, bhndb_dw_rentry) refs; /**< references */ 164 }; 165 166 /** 167 * A bus address region description. 168 */ 169 struct bhndb_region { 170 bhnd_addr_t addr; /**< start of mapped range */ 171 bhnd_size_t size; /**< size of mapped range */ 172 bhndb_priority_t priority; /**< direct resource allocation priority */ 173 uint32_t alloc_flags; /**< resource allocation flags (@see bhndb_alloc_flags) */ 174 const struct bhndb_regwin *static_regwin; /**< fixed mapping regwin, if any */ 175 176 STAILQ_ENTRY(bhndb_region) link; 177 }; 178 179 /** 180 * Attached interrupt handler state 181 */ 182 struct bhndb_intr_handler { 183 device_t ih_owner; /**< child device */ 184 struct resource *ih_res; /**< child resource */ 185 void *ih_cookiep; /**< hostb-assigned cookiep, or NULL if bus_setup_intr() incomplete. */ 186 struct bhndb_intr_isrc *ih_isrc; /**< host interrupt source routing the child's interrupt */ 187 bool ih_active; /**< handler has been registered via bhndb_register_intr_handler */ 188 189 STAILQ_ENTRY(bhndb_intr_handler) ih_link; 190 }; 191 192 /** 193 * BHNDB resource allocation state. 194 */ 195 struct bhndb_resources { 196 device_t dev; /**< bridge device */ 197 const struct bhndb_hwcfg *cfg; /**< hardware configuration */ 198 199 struct bhndb_host_resources *res; /**< host resources, or NULL if not allocated */ 200 201 struct rman ht_mem_rman; /**< host memory manager */ 202 struct rman br_mem_rman; /**< bridged memory manager */ 203 struct rman br_irq_rman; /**< bridged irq manager */ 204 205 STAILQ_HEAD(, bhndb_region) bus_regions; /**< bus region descriptors */ 206 207 struct mtx dw_steal_mtx; /**< spinlock must be held when stealing a dynamic window allocation */ 208 struct bhndb_dw_alloc *dw_alloc; /**< dynamic window allocation records */ 209 size_t dwa_count; /**< number of dynamic windows available. */ 210 bitstr_t *dwa_freelist; /**< dynamic window free list */ 211 bhndb_priority_t min_prio; /**< minimum resource priority required to 212 allocate a dynamic window */ 213 214 STAILQ_HEAD(,bhndb_intr_handler) bus_intrs; /**< attached child interrupt handlers */ 215 }; 216 217 /** 218 * Returns true if the all dynamic windows are marked free, false 219 * otherwise. 220 * 221 * @param br The resource state to check. 222 */ 223 static inline bool 224 bhndb_dw_all_free(struct bhndb_resources *br) 225 { 226 int bit; 227 bit_ffs(br->dwa_freelist, br->dwa_count, &bit); 228 return (bit == -1); 229 } 230 231 /** 232 * Find the next free dynamic window region in @p br. 233 * 234 * @param br The resource state to search. 235 */ 236 static inline struct bhndb_dw_alloc * 237 bhndb_dw_next_free(struct bhndb_resources *br) 238 { 239 struct bhndb_dw_alloc *dw_free; 240 int bit; 241 242 bit_ffc(br->dwa_freelist, br->dwa_count, &bit); 243 if (bit == -1) 244 return (NULL); 245 246 dw_free = &br->dw_alloc[bit]; 247 248 KASSERT(LIST_EMPTY(&dw_free->refs), 249 ("free list out of sync with refs")); 250 251 return (dw_free); 252 } 253 254 /** 255 * Returns true if a dynamic window allocation is marked as free. 256 * 257 * @param br The resource state owning @p dwa. 258 * @param dwa The dynamic window allocation record to be checked. 259 */ 260 static inline bool 261 bhndb_dw_is_free(struct bhndb_resources *br, struct bhndb_dw_alloc *dwa) 262 { 263 bool is_free = LIST_EMPTY(&dwa->refs); 264 265 KASSERT(is_free == !bit_test(br->dwa_freelist, dwa->rnid), 266 ("refs out of sync with free list")); 267 268 return (is_free); 269 } 270 271 #define BHNDB_LOCK_INIT(sc) \ 272 mtx_init(&(sc)->sc_mtx, device_get_nameunit((sc)->dev), \ 273 "bhndb resource allocator lock", MTX_DEF) 274 #define BHNDB_LOCK(sc) mtx_lock(&(sc)->sc_mtx) 275 #define BHNDB_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx) 276 #define BHNDB_LOCK_ASSERT(sc, what) mtx_assert(&(sc)->sc_mtx, what) 277 #define BHNDB_LOCK_DESTROY(sc) mtx_destroy(&(sc)->sc_mtx) 278 279 #endif /* _BHND_BHNDB_PRIVATE_H_ */ 280