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 /** 148 * Dynamic register window allocation reference. 149 */ 150 struct bhndb_dw_rentry { 151 struct resource *dw_res; /**< child resource */ 152 LIST_ENTRY(bhndb_dw_rentry) dw_link; 153 }; 154 155 /** 156 * A dynamic register window allocation record. 157 */ 158 struct bhndb_dw_alloc { 159 const struct bhndb_regwin *win; /**< window definition */ 160 struct resource *parent_res; /**< enclosing resource */ 161 u_int rnid; /**< region identifier */ 162 rman_res_t target; /**< the current window address, or 0x0 if unknown */ 163 164 LIST_HEAD(, bhndb_dw_rentry) refs; /**< references */ 165 }; 166 167 /** 168 * A bus address region description. 169 */ 170 struct bhndb_region { 171 bhnd_addr_t addr; /**< start of mapped range */ 172 bhnd_size_t size; /**< size of mapped range */ 173 bhndb_priority_t priority; /**< direct resource allocation priority */ 174 uint32_t alloc_flags; /**< resource allocation flags (@see bhndb_alloc_flags) */ 175 const struct bhndb_regwin *static_regwin; /**< fixed mapping regwin, if any */ 176 177 STAILQ_ENTRY(bhndb_region) link; 178 }; 179 180 /** 181 * Attached interrupt handler state 182 */ 183 struct bhndb_intr_handler { 184 device_t ih_owner; /**< child device */ 185 struct resource *ih_res; /**< child resource */ 186 void *ih_cookiep; /**< hostb-assigned cookiep, or NULL if bus_setup_intr() incomplete. */ 187 struct bhndb_intr_isrc *ih_isrc; /**< host interrupt source routing the child's interrupt */ 188 bool ih_active; /**< handler has been registered via bhndb_register_intr_handler */ 189 190 STAILQ_ENTRY(bhndb_intr_handler) ih_link; 191 }; 192 193 /** 194 * BHNDB resource allocation state. 195 */ 196 struct bhndb_resources { 197 device_t dev; /**< bridge device */ 198 const struct bhndb_hwcfg *cfg; /**< hardware configuration */ 199 200 struct bhndb_host_resources *res; /**< host resources, or NULL if not allocated */ 201 202 struct rman ht_mem_rman; /**< host memory manager */ 203 struct rman br_mem_rman; /**< bridged memory manager */ 204 struct rman br_irq_rman; /**< bridged irq manager */ 205 206 STAILQ_HEAD(, bhndb_region) bus_regions; /**< bus region descriptors */ 207 208 struct mtx dw_steal_mtx; /**< spinlock must be held when stealing a dynamic window allocation */ 209 struct bhndb_dw_alloc *dw_alloc; /**< dynamic window allocation records */ 210 size_t dwa_count; /**< number of dynamic windows available. */ 211 bitstr_t *dwa_freelist; /**< dynamic window free list */ 212 bhndb_priority_t min_prio; /**< minimum resource priority required to 213 allocate a dynamic window */ 214 215 STAILQ_HEAD(,bhndb_intr_handler) bus_intrs; /**< attached child interrupt handlers */ 216 }; 217 218 /** 219 * Returns true if the all dynamic windows are marked free, false 220 * otherwise. 221 * 222 * @param br The resource state to check. 223 */ 224 static inline bool 225 bhndb_dw_all_free(struct bhndb_resources *br) 226 { 227 int bit; 228 bit_ffs(br->dwa_freelist, br->dwa_count, &bit); 229 return (bit == -1); 230 } 231 232 /** 233 * Find the next free dynamic window region in @p br. 234 * 235 * @param br The resource state to search. 236 */ 237 static inline struct bhndb_dw_alloc * 238 bhndb_dw_next_free(struct bhndb_resources *br) 239 { 240 struct bhndb_dw_alloc *dw_free; 241 int bit; 242 243 bit_ffc(br->dwa_freelist, br->dwa_count, &bit); 244 if (bit == -1) 245 return (NULL); 246 247 dw_free = &br->dw_alloc[bit]; 248 249 KASSERT(LIST_EMPTY(&dw_free->refs), 250 ("free list out of sync with refs")); 251 252 return (dw_free); 253 } 254 255 /** 256 * Returns true if a dynamic window allocation is marked as free. 257 * 258 * @param br The resource state owning @p dwa. 259 * @param dwa The dynamic window allocation record to be checked. 260 */ 261 static inline bool 262 bhndb_dw_is_free(struct bhndb_resources *br, struct bhndb_dw_alloc *dwa) 263 { 264 bool is_free = LIST_EMPTY(&dwa->refs); 265 266 KASSERT(is_free == !bit_test(br->dwa_freelist, dwa->rnid), 267 ("refs out of sync with free list")); 268 269 return (is_free); 270 } 271 272 273 #define BHNDB_LOCK_INIT(sc) \ 274 mtx_init(&(sc)->sc_mtx, device_get_nameunit((sc)->dev), \ 275 "bhndb resource allocator lock", MTX_DEF) 276 #define BHNDB_LOCK(sc) mtx_lock(&(sc)->sc_mtx) 277 #define BHNDB_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx) 278 #define BHNDB_LOCK_ASSERT(sc, what) mtx_assert(&(sc)->sc_mtx, what) 279 #define BHNDB_LOCK_DESTROY(sc) mtx_destroy(&(sc)->sc_mtx) 280 281 #endif /* _BHND_BHNDB_PRIVATE_H_ */ 282