1 /*- 2 * Copyright (c) 2015 Landon Fuller <landon@landonf.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer, 10 * without modification. 11 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12 * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 13 * redistribution must be conditioned upon including a substantially 14 * similar Disclaimer requirement for further binary redistribution. 15 * 16 * NO WARRANTY 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 20 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 21 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 22 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 * THE POSSIBILITY OF SUCH DAMAGES. 28 */ 29 30 #include <sys/cdefs.h> 31 __FBSDID("$FreeBSD$"); 32 33 #include <sys/param.h> 34 #include <sys/bus.h> 35 #include <sys/kernel.h> 36 #include <sys/limits.h> 37 #include <sys/systm.h> 38 39 #include <machine/bus.h> 40 #include <machine/resource.h> 41 42 #include <dev/bhnd/bhndvar.h> 43 44 #include "bcmavar.h" 45 46 /** 47 * Allocate and initialize new core config structure. 48 * 49 * @param core_index Core index on the bus. 50 * @param core_unit Core unit number. 51 * @param vendor Core designer. 52 * @param device Core identifier (e.g. part number). 53 * @param hwrev Core revision. 54 */ 55 struct bcma_corecfg * 56 bcma_alloc_corecfg(u_int core_index, int core_unit, uint16_t vendor, 57 uint16_t device, uint8_t hwrev) 58 { 59 struct bcma_corecfg *cfg; 60 61 cfg = malloc(sizeof(*cfg), M_BHND, M_NOWAIT); 62 if (cfg == NULL) 63 return NULL; 64 65 cfg->core_info = (struct bhnd_core_info) { 66 .vendor = vendor, 67 .device = device, 68 .hwrev = hwrev, 69 .core_idx = core_index, 70 .unit = core_unit 71 }; 72 73 STAILQ_INIT(&cfg->master_ports); 74 cfg->num_master_ports = 0; 75 76 STAILQ_INIT(&cfg->dev_ports); 77 cfg->num_dev_ports = 0; 78 79 STAILQ_INIT(&cfg->bridge_ports); 80 cfg->num_bridge_ports = 0; 81 82 STAILQ_INIT(&cfg->wrapper_ports); 83 cfg->num_wrapper_ports = 0; 84 85 return (cfg); 86 } 87 88 /** 89 * Deallocate the given core config and any associated resources. 90 * 91 * @param corecfg Core info to be deallocated. 92 */ 93 void 94 bcma_free_corecfg(struct bcma_corecfg *corecfg) 95 { 96 struct bcma_mport *mport, *mnext; 97 struct bcma_sport *sport, *snext; 98 99 STAILQ_FOREACH_SAFE(mport, &corecfg->master_ports, mp_link, mnext) { 100 free(mport, M_BHND); 101 } 102 103 STAILQ_FOREACH_SAFE(sport, &corecfg->dev_ports, sp_link, snext) { 104 bcma_free_sport(sport); 105 } 106 107 STAILQ_FOREACH_SAFE(sport, &corecfg->bridge_ports, sp_link, snext) { 108 bcma_free_sport(sport); 109 } 110 111 STAILQ_FOREACH_SAFE(sport, &corecfg->wrapper_ports, sp_link, snext) { 112 bcma_free_sport(sport); 113 } 114 115 free(corecfg, M_BHND); 116 } 117 118 /** 119 * Return the @p cfg port list for @p type. 120 * 121 * @param cfg The core configuration. 122 * @param type The requested port type. 123 */ 124 struct bcma_sport_list * 125 bcma_corecfg_get_port_list(struct bcma_corecfg *cfg, bhnd_port_type type) 126 { 127 switch (type) { 128 case BHND_PORT_DEVICE: 129 return (&cfg->dev_ports); 130 break; 131 case BHND_PORT_BRIDGE: 132 return (&cfg->bridge_ports); 133 break; 134 case BHND_PORT_AGENT: 135 return (&cfg->wrapper_ports); 136 break; 137 default: 138 return (NULL); 139 } 140 } 141 142 /** 143 * Populate the resource list and bcma_map RIDs using the maps defined on 144 * @p ports. 145 * 146 * @param bus The requesting bus device. 147 * @param dinfo The device info instance to be initialized. 148 * @param ports The set of ports to be enumerated 149 */ 150 static void 151 bcma_dinfo_init_resource_info(device_t bus, struct bcma_devinfo *dinfo, 152 struct bcma_sport_list *ports) 153 { 154 struct bcma_map *map; 155 struct bcma_sport *port; 156 bhnd_addr_t end; 157 158 STAILQ_FOREACH(port, ports, sp_link) { 159 STAILQ_FOREACH(map, &port->sp_maps, m_link) { 160 /* 161 * Create the corresponding device resource list entry. 162 * 163 * We necessarily skip registration if the region's 164 * device memory range is not representable via 165 * rman_res_t. 166 * 167 * When rman_res_t is migrated to uintmax_t, any 168 * range should be representable. 169 */ 170 end = map->m_base + map->m_size; 171 if (map->m_base <= RM_MAX_END && end <= RM_MAX_END) { 172 map->m_rid = resource_list_add_next( 173 &dinfo->resources, SYS_RES_MEMORY, 174 map->m_base, end, map->m_size); 175 } else if (bootverbose) { 176 device_printf(bus, 177 "core%u %s%u.%u: region %llx-%llx extends " 178 "beyond supported addressable range\n", 179 dinfo->corecfg->core_info.core_idx, 180 bhnd_port_type_name(port->sp_type), 181 port->sp_num, map->m_region_num, 182 (unsigned long long) map->m_base, 183 (unsigned long long) end); 184 } 185 } 186 } 187 } 188 189 190 /** 191 * Allocate and return a new empty device info structure. 192 * 193 * @param bus The requesting bus device. 194 * 195 * @retval NULL if allocation failed. 196 */ 197 struct bcma_devinfo * 198 bcma_alloc_dinfo(device_t bus) 199 { 200 struct bcma_devinfo *dinfo; 201 202 dinfo = malloc(sizeof(struct bcma_devinfo), M_BHND, M_NOWAIT|M_ZERO); 203 if (dinfo == NULL) 204 return (NULL); 205 206 dinfo->corecfg = NULL; 207 dinfo->res_agent = NULL; 208 dinfo->rid_agent = -1; 209 210 resource_list_init(&dinfo->resources); 211 212 return (dinfo); 213 } 214 215 /** 216 * Initialize a device info structure previously allocated via 217 * bcma_alloc_dinfo, assuming ownership of the provided core 218 * configuration. 219 * 220 * @param bus The requesting bus device. 221 * @param dinfo The device info instance. 222 * @param corecfg Device core configuration; ownership of this value 223 * will be assumed by @p dinfo. 224 * 225 * @retval 0 success 226 * @retval non-zero initialization failed. 227 */ 228 int 229 bcma_init_dinfo(device_t bus, struct bcma_devinfo *dinfo, 230 struct bcma_corecfg *corecfg) 231 { 232 KASSERT(dinfo->corecfg == NULL, ("dinfo previously initialized")); 233 234 /* Save core configuration value */ 235 dinfo->corecfg = corecfg; 236 237 /* The device ports must always be initialized first to ensure that 238 * rid 0 maps to the first device port */ 239 bcma_dinfo_init_resource_info(bus, dinfo, &corecfg->dev_ports); 240 241 bcma_dinfo_init_resource_info(bus, dinfo, &corecfg->bridge_ports); 242 bcma_dinfo_init_resource_info(bus, dinfo, &corecfg->wrapper_ports); 243 244 return (0); 245 } 246 247 /** 248 * Deallocate the given device info structure and any associated resources. 249 * 250 * @param bus The requesting bus device. 251 * @param dinfo Device info to be deallocated. 252 */ 253 void 254 bcma_free_dinfo(device_t bus, struct bcma_devinfo *dinfo) 255 { 256 resource_list_free(&dinfo->resources); 257 258 if (dinfo->corecfg != NULL) 259 bcma_free_corecfg(dinfo->corecfg); 260 261 /* Release agent resource, if any */ 262 if (dinfo->res_agent != NULL) { 263 bhnd_release_resource(bus, SYS_RES_MEMORY, dinfo->rid_agent, 264 dinfo->res_agent); 265 } 266 267 free(dinfo, M_BHND); 268 } 269 270 271 /** 272 * Allocate and initialize new slave port descriptor. 273 * 274 * @param port_num Per-core port number. 275 * @param port_type Port type. 276 */ 277 struct bcma_sport * 278 bcma_alloc_sport(bcma_pid_t port_num, bhnd_port_type port_type) 279 { 280 struct bcma_sport *sport; 281 282 sport = malloc(sizeof(struct bcma_sport), M_BHND, M_NOWAIT); 283 if (sport == NULL) 284 return NULL; 285 286 sport->sp_num = port_num; 287 sport->sp_type = port_type; 288 sport->sp_num_maps = 0; 289 STAILQ_INIT(&sport->sp_maps); 290 291 return sport; 292 } 293 294 /** 295 * Deallocate all resources associated with the given port descriptor. 296 * 297 * @param sport Port descriptor to be deallocated. 298 */ 299 void 300 bcma_free_sport(struct bcma_sport *sport) { 301 struct bcma_map *map, *mapnext; 302 303 STAILQ_FOREACH_SAFE(map, &sport->sp_maps, m_link, mapnext) { 304 free(map, M_BHND); 305 } 306 307 free(sport, M_BHND); 308 } 309 310