Deleted Added
full compact
siba_subr.c (300548) siba_subr.c (301410)
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>
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: head/sys/dev/bhnd/siba/siba_subr.c 300548 2016-05-24 01:12:19Z adrian $");
31__FBSDID("$FreeBSD: head/sys/dev/bhnd/siba/siba_subr.c 301410 2016-06-04 19:53:47Z landonf $");
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 "sibareg.h"
45#include "sibavar.h"
46
47/**
48 * Map a siba(4) OCP vendor code to its corresponding JEDEC JEP-106 vendor
49 * code.
50 *
51 * @param ocp_vendor An OCP vendor code.
52 * @return The BHND_MFGID constant corresponding to @p ocp_vendor, or
53 * BHND_MFGID_INVALID if the OCP vendor is unknown.
54 */
55uint16_t
56siba_get_bhnd_mfgid(uint16_t ocp_vendor)
57{
58 switch (ocp_vendor) {
59 case OCP_VENDOR_BCM:
60 return (BHND_MFGID_BCM);
61 default:
62 return (BHND_MFGID_INVALID);
63 }
64}
65
66/**
67 * Parse the SIBA_IDH_* fields from the per-core identification
68 * registers, returning a siba_core_id representation.
69 *
70 * @param idhigh The SIBA_R0_IDHIGH register.
71 * @param idlow The SIBA_R0_IDLOW register.
72 * @param core_id The core id (index) to include in the result.
73 * @param unit The unit number to include in the result.
74 */
75struct siba_core_id
76siba_parse_core_id(uint32_t idhigh, uint32_t idlow, u_int core_idx, int unit)
77{
78
79 uint16_t ocp_vendor;
80 uint8_t sonics_rev;
81 uint8_t num_addrspace;
82 uint8_t num_cfg;
83
84 ocp_vendor = SIBA_REG_GET(idhigh, IDH_VENDOR);
85 sonics_rev = SIBA_REG_GET(idlow, IDL_SBREV);
86 num_addrspace = SIBA_REG_GET(idlow, IDL_NRADDR) + 1 /* + enum block */;
87
88 /* Determine the number of sonics config register blocks */
89 num_cfg = SIBA_CFG_NUM_2_2;
90 if (sonics_rev >= SIBA_IDL_SBREV_2_3)
91 num_cfg = SIBA_CFG_NUM_2_3;
92
93 return (struct siba_core_id) {
94 .core_info = {
95 .vendor = siba_get_bhnd_mfgid(ocp_vendor),
96 .device = SIBA_REG_GET(idhigh, IDH_DEVICE),
97 .hwrev = SIBA_IDH_CORE_REV(idhigh),
98 .core_idx = core_idx,
99 .unit = unit
100 },
101 .sonics_vendor = ocp_vendor,
102 .sonics_rev = sonics_rev,
103 .num_addrspace = num_addrspace,
104 .num_cfg_blocks = num_cfg
105 };
106}
107
108/**
109 * Initialize new port descriptor.
110 *
111 * @param port_num Port number.
112 * @param port_type Port type.
113 */
114static void
115siba_init_port(struct siba_port *port, bhnd_port_type port_type, u_int port_num)
116{
117 port->sp_num = port_num;
118 port->sp_type = port_type;
119 port->sp_num_addrs = 0;
120 STAILQ_INIT(&port->sp_addrs);
121}
122
123/**
124 * Deallocate all resources associated with the given port descriptor.
125 *
126 * @param port Port descriptor to be deallocated.
127 */
128static void
129siba_release_port(struct siba_port *port) {
130 struct siba_addrspace *as, *as_next;
131
132 STAILQ_FOREACH_SAFE(as, &port->sp_addrs, sa_link, as_next) {
133 free(as, M_BHND);
134 }
135}
136
137/**
138 * Allocate and initialize new device info structure, copying the
139 * provided core id.
140 *
141 * @param dev The requesting bus device.
142 * @param core Device core info.
143 */
144struct siba_devinfo *
145siba_alloc_dinfo(device_t bus, const struct siba_core_id *core_id)
146{
147 struct siba_devinfo *dinfo;
148
149 dinfo = malloc(sizeof(struct siba_devinfo), M_BHND, M_NOWAIT);
150 if (dinfo == NULL)
151 return NULL;
152
153 dinfo->core_id = *core_id;
154
155 for (u_int i = 0; i < nitems(dinfo->cfg); i++) {
156 dinfo->cfg[i] = NULL;
157 dinfo->cfg_rid[i] = -1;
158 }
159
160 siba_init_port(&dinfo->device_port, BHND_PORT_DEVICE, 0);
161 resource_list_init(&dinfo->resources);
162
163 return dinfo;
164}
165
166/**
167 * Return the @p dinfo port instance for @p type, or NULL.
168 *
169 * @param dinfo The siba device info.
170 * @param type The requested port type.
171 *
172 * @retval siba_port If @p port_type and @p port_num are defined on @p dinfo.
173 * @retval NULL If the requested port is not defined on @p dinfo.
174 */
175struct siba_port *
176siba_dinfo_get_port(struct siba_devinfo *dinfo, bhnd_port_type port_type,
177 u_int port_num)
178{
179 /* We only define a single port for any given type. */
180 if (port_num != 0)
181 return (NULL);
182
183 switch (port_type) {
184 case BHND_PORT_DEVICE:
185 return (&dinfo->device_port);
186 case BHND_PORT_BRIDGE:
187 return (NULL);
188 case BHND_PORT_AGENT:
189 return (NULL);
190 default:
191 printf("%s: unknown port_type (%d)\n",
192 __func__,
193 port_type);
194 return (NULL);
195 }
196}
197
198
199/**
200 * Find an address space with @p sid on @p port.
201 *
202 * @param port The port to search for a matching address space.
203 * @param sid The siba-assigned address space ID to search for.
204 */
205struct siba_addrspace *
206siba_find_port_addrspace(struct siba_port *port, uint8_t sid)
207{
208 struct siba_addrspace *addrspace;
209
210 STAILQ_FOREACH(addrspace, &port->sp_addrs, sa_link) {
211 if (addrspace->sa_sid == sid)
212 return (addrspace);
213 }
214
215 /* not found */
216 return (NULL);
217}
218
219/**
220 * Append a new address space entry to @p port_num of type @p port_type
221 * in @p dinfo.
222 *
223 * The range will also be registered in @p dinfo resource list.
224 *
225 * @param dinfo The device info entry to update.
226 * @param port_type The port type.
227 * @param port_num The port number.
228 * @param region_num The region index number.
229 * @param sid The siba-assigned core-unique address space identifier.
230 * @param base The mapping's base address.
231 * @param size The mapping size.
232 * @param bus_reserved Number of bytes to reserve in @p size for bus use
233 * when registering the resource list entry. This is used to reserve bus
234 * access to the core's SIBA_CFG* register blocks.
235 *
236 * @retval 0 success
237 * @retval non-zero An error occurred appending the entry.
238 */
239int
240siba_append_dinfo_region(struct siba_devinfo *dinfo, bhnd_port_type port_type,
241 u_int port_num, u_int region_num, uint8_t sid, uint32_t base, uint32_t size,
242 uint32_t bus_reserved)
243{
244 struct siba_addrspace *sa;
245 struct siba_port *port;
246 rman_res_t r_size;
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 "sibareg.h"
45#include "sibavar.h"
46
47/**
48 * Map a siba(4) OCP vendor code to its corresponding JEDEC JEP-106 vendor
49 * code.
50 *
51 * @param ocp_vendor An OCP vendor code.
52 * @return The BHND_MFGID constant corresponding to @p ocp_vendor, or
53 * BHND_MFGID_INVALID if the OCP vendor is unknown.
54 */
55uint16_t
56siba_get_bhnd_mfgid(uint16_t ocp_vendor)
57{
58 switch (ocp_vendor) {
59 case OCP_VENDOR_BCM:
60 return (BHND_MFGID_BCM);
61 default:
62 return (BHND_MFGID_INVALID);
63 }
64}
65
66/**
67 * Parse the SIBA_IDH_* fields from the per-core identification
68 * registers, returning a siba_core_id representation.
69 *
70 * @param idhigh The SIBA_R0_IDHIGH register.
71 * @param idlow The SIBA_R0_IDLOW register.
72 * @param core_id The core id (index) to include in the result.
73 * @param unit The unit number to include in the result.
74 */
75struct siba_core_id
76siba_parse_core_id(uint32_t idhigh, uint32_t idlow, u_int core_idx, int unit)
77{
78
79 uint16_t ocp_vendor;
80 uint8_t sonics_rev;
81 uint8_t num_addrspace;
82 uint8_t num_cfg;
83
84 ocp_vendor = SIBA_REG_GET(idhigh, IDH_VENDOR);
85 sonics_rev = SIBA_REG_GET(idlow, IDL_SBREV);
86 num_addrspace = SIBA_REG_GET(idlow, IDL_NRADDR) + 1 /* + enum block */;
87
88 /* Determine the number of sonics config register blocks */
89 num_cfg = SIBA_CFG_NUM_2_2;
90 if (sonics_rev >= SIBA_IDL_SBREV_2_3)
91 num_cfg = SIBA_CFG_NUM_2_3;
92
93 return (struct siba_core_id) {
94 .core_info = {
95 .vendor = siba_get_bhnd_mfgid(ocp_vendor),
96 .device = SIBA_REG_GET(idhigh, IDH_DEVICE),
97 .hwrev = SIBA_IDH_CORE_REV(idhigh),
98 .core_idx = core_idx,
99 .unit = unit
100 },
101 .sonics_vendor = ocp_vendor,
102 .sonics_rev = sonics_rev,
103 .num_addrspace = num_addrspace,
104 .num_cfg_blocks = num_cfg
105 };
106}
107
108/**
109 * Initialize new port descriptor.
110 *
111 * @param port_num Port number.
112 * @param port_type Port type.
113 */
114static void
115siba_init_port(struct siba_port *port, bhnd_port_type port_type, u_int port_num)
116{
117 port->sp_num = port_num;
118 port->sp_type = port_type;
119 port->sp_num_addrs = 0;
120 STAILQ_INIT(&port->sp_addrs);
121}
122
123/**
124 * Deallocate all resources associated with the given port descriptor.
125 *
126 * @param port Port descriptor to be deallocated.
127 */
128static void
129siba_release_port(struct siba_port *port) {
130 struct siba_addrspace *as, *as_next;
131
132 STAILQ_FOREACH_SAFE(as, &port->sp_addrs, sa_link, as_next) {
133 free(as, M_BHND);
134 }
135}
136
137/**
138 * Allocate and initialize new device info structure, copying the
139 * provided core id.
140 *
141 * @param dev The requesting bus device.
142 * @param core Device core info.
143 */
144struct siba_devinfo *
145siba_alloc_dinfo(device_t bus, const struct siba_core_id *core_id)
146{
147 struct siba_devinfo *dinfo;
148
149 dinfo = malloc(sizeof(struct siba_devinfo), M_BHND, M_NOWAIT);
150 if (dinfo == NULL)
151 return NULL;
152
153 dinfo->core_id = *core_id;
154
155 for (u_int i = 0; i < nitems(dinfo->cfg); i++) {
156 dinfo->cfg[i] = NULL;
157 dinfo->cfg_rid[i] = -1;
158 }
159
160 siba_init_port(&dinfo->device_port, BHND_PORT_DEVICE, 0);
161 resource_list_init(&dinfo->resources);
162
163 return dinfo;
164}
165
166/**
167 * Return the @p dinfo port instance for @p type, or NULL.
168 *
169 * @param dinfo The siba device info.
170 * @param type The requested port type.
171 *
172 * @retval siba_port If @p port_type and @p port_num are defined on @p dinfo.
173 * @retval NULL If the requested port is not defined on @p dinfo.
174 */
175struct siba_port *
176siba_dinfo_get_port(struct siba_devinfo *dinfo, bhnd_port_type port_type,
177 u_int port_num)
178{
179 /* We only define a single port for any given type. */
180 if (port_num != 0)
181 return (NULL);
182
183 switch (port_type) {
184 case BHND_PORT_DEVICE:
185 return (&dinfo->device_port);
186 case BHND_PORT_BRIDGE:
187 return (NULL);
188 case BHND_PORT_AGENT:
189 return (NULL);
190 default:
191 printf("%s: unknown port_type (%d)\n",
192 __func__,
193 port_type);
194 return (NULL);
195 }
196}
197
198
199/**
200 * Find an address space with @p sid on @p port.
201 *
202 * @param port The port to search for a matching address space.
203 * @param sid The siba-assigned address space ID to search for.
204 */
205struct siba_addrspace *
206siba_find_port_addrspace(struct siba_port *port, uint8_t sid)
207{
208 struct siba_addrspace *addrspace;
209
210 STAILQ_FOREACH(addrspace, &port->sp_addrs, sa_link) {
211 if (addrspace->sa_sid == sid)
212 return (addrspace);
213 }
214
215 /* not found */
216 return (NULL);
217}
218
219/**
220 * Append a new address space entry to @p port_num of type @p port_type
221 * in @p dinfo.
222 *
223 * The range will also be registered in @p dinfo resource list.
224 *
225 * @param dinfo The device info entry to update.
226 * @param port_type The port type.
227 * @param port_num The port number.
228 * @param region_num The region index number.
229 * @param sid The siba-assigned core-unique address space identifier.
230 * @param base The mapping's base address.
231 * @param size The mapping size.
232 * @param bus_reserved Number of bytes to reserve in @p size for bus use
233 * when registering the resource list entry. This is used to reserve bus
234 * access to the core's SIBA_CFG* register blocks.
235 *
236 * @retval 0 success
237 * @retval non-zero An error occurred appending the entry.
238 */
239int
240siba_append_dinfo_region(struct siba_devinfo *dinfo, bhnd_port_type port_type,
241 u_int port_num, u_int region_num, uint8_t sid, uint32_t base, uint32_t size,
242 uint32_t bus_reserved)
243{
244 struct siba_addrspace *sa;
245 struct siba_port *port;
246 rman_res_t r_size;
247
247
248 /* Verify that base + size will not overflow */
248 /* Verify that base + size will not overflow */
249 if (UINT32_MAX - size < base)
249 if (size > 0 && UINT32_MAX - (size - 1) < base)
250 return (ERANGE);
251
252 /* Verify that size - bus_reserved will not underflow */
253 if (size < bus_reserved)
254 return (ERANGE);
255
256 /* Must not be 0-length */
257 if (size == 0)
258 return (EINVAL);
259
260 /* Determine target port */
261 port = siba_dinfo_get_port(dinfo, port_type, port_num);
262 if (port == NULL)
263 return (EINVAL);
264
265 /* Allocate new addrspace entry */
266 sa = malloc(sizeof(*sa), M_BHND, M_NOWAIT|M_ZERO);
267 if (sa == NULL)
268 return (ENOMEM);
269
270 sa->sa_base = base;
271 sa->sa_size = size;
272 sa->sa_sid = sid;
273 sa->sa_region_num = region_num;
274 sa->sa_bus_reserved = bus_reserved;
275
276 /* Populate the resource list */
277 r_size = size - bus_reserved;
278 sa->sa_rid = resource_list_add_next(&dinfo->resources, SYS_RES_MEMORY,
250 return (ERANGE);
251
252 /* Verify that size - bus_reserved will not underflow */
253 if (size < bus_reserved)
254 return (ERANGE);
255
256 /* Must not be 0-length */
257 if (size == 0)
258 return (EINVAL);
259
260 /* Determine target port */
261 port = siba_dinfo_get_port(dinfo, port_type, port_num);
262 if (port == NULL)
263 return (EINVAL);
264
265 /* Allocate new addrspace entry */
266 sa = malloc(sizeof(*sa), M_BHND, M_NOWAIT|M_ZERO);
267 if (sa == NULL)
268 return (ENOMEM);
269
270 sa->sa_base = base;
271 sa->sa_size = size;
272 sa->sa_sid = sid;
273 sa->sa_region_num = region_num;
274 sa->sa_bus_reserved = bus_reserved;
275
276 /* Populate the resource list */
277 r_size = size - bus_reserved;
278 sa->sa_rid = resource_list_add_next(&dinfo->resources, SYS_RES_MEMORY,
279 base, base + r_size - 1, r_size);
279 base, base + (r_size - 1), r_size);
280
281 /* Append to target port */
282 STAILQ_INSERT_TAIL(&port->sp_addrs, sa, sa_link);
283 port->sp_num_addrs++;
284
285 return (0);
286}
287
288/**
289 * Deallocate the given device info structure and any associated resources.
290 *
291 * @param dev The requesting bus device.
292 * @param dinfo Device info to be deallocated.
293 */
294void
295siba_free_dinfo(device_t dev, struct siba_devinfo *dinfo)
296{
297 siba_release_port(&dinfo->device_port);
298
299 resource_list_free(&dinfo->resources);
300
301 /* Free all mapped configuration blocks */
302 for (u_int i = 0; i < nitems(dinfo->cfg); i++) {
303 if (dinfo->cfg[i] == NULL)
304 continue;
305
306 bhnd_release_resource(dev, SYS_RES_MEMORY, dinfo->cfg_rid[i],
307 dinfo->cfg[i]);
308
309 dinfo->cfg[i] = NULL;
310 dinfo->cfg_rid[i] = -1;
311 }
312
313 free(dinfo, M_BHND);
314}
315
316/**
317 * Return the core-enumeration-relative offset for the @p addrspace
318 * SIBA_R0_ADMATCH* register.
319 *
320 * @param addrspace The address space index.
321 *
322 * @retval non-zero success
323 * @retval 0 the given @p addrspace index is not supported.
324 */
325u_int
326siba_admatch_offset(uint8_t addrspace)
327{
328 switch (addrspace) {
329 case 0:
330 return SB0_REG_ABS(SIBA_CFG0_ADMATCH0);
331 case 1:
332 return SB0_REG_ABS(SIBA_CFG0_ADMATCH1);
333 case 2:
334 return SB0_REG_ABS(SIBA_CFG0_ADMATCH2);
335 case 3:
336 return SB0_REG_ABS(SIBA_CFG0_ADMATCH3);
337 default:
338 return (0);
339 }
340}
341
342/**
343 * Parse a SIBA_R0_ADMATCH* register.
344 *
345 * @param addrspace The address space index.
346 * @param am The address match register value to be parsed.
347 * @param[out] addr The parsed address.
348 * @param[out] size The parsed size.
349 *
350 * @retval 0 success
351 * @retval non-zero a parse error occurred.
352 */
353int
354siba_parse_admatch(uint32_t am, uint32_t *addr, uint32_t *size)
355{
356 u_int am_type;
357
358 /* Negative encoding is not supported. This is not used on any
359 * currently known devices*/
360 if (am & SIBA_AM_ADNEG)
361 return (EINVAL);
362
363 /* Extract the base address and size */
364 am_type = SIBA_REG_GET(am, AM_TYPE);
365 switch (am_type) {
366 case 0:
367 *addr = am & SIBA_AM_BASE0_MASK;
368 *size = 1 << (SIBA_REG_GET(am, AM_ADINT0) + 1);
369 break;
370 case 1:
371 *addr = am & SIBA_AM_BASE1_MASK;
372 *size = 1 << (SIBA_REG_GET(am, AM_ADINT1) + 1);
373 break;
374 case 2:
375 *addr = am & SIBA_AM_BASE2_MASK;
376 *size = 1 << (SIBA_REG_GET(am, AM_ADINT2) + 1);
377 break;
378 default:
379 return (EINVAL);
380 }
381
382 return (0);
383}
280
281 /* Append to target port */
282 STAILQ_INSERT_TAIL(&port->sp_addrs, sa, sa_link);
283 port->sp_num_addrs++;
284
285 return (0);
286}
287
288/**
289 * Deallocate the given device info structure and any associated resources.
290 *
291 * @param dev The requesting bus device.
292 * @param dinfo Device info to be deallocated.
293 */
294void
295siba_free_dinfo(device_t dev, struct siba_devinfo *dinfo)
296{
297 siba_release_port(&dinfo->device_port);
298
299 resource_list_free(&dinfo->resources);
300
301 /* Free all mapped configuration blocks */
302 for (u_int i = 0; i < nitems(dinfo->cfg); i++) {
303 if (dinfo->cfg[i] == NULL)
304 continue;
305
306 bhnd_release_resource(dev, SYS_RES_MEMORY, dinfo->cfg_rid[i],
307 dinfo->cfg[i]);
308
309 dinfo->cfg[i] = NULL;
310 dinfo->cfg_rid[i] = -1;
311 }
312
313 free(dinfo, M_BHND);
314}
315
316/**
317 * Return the core-enumeration-relative offset for the @p addrspace
318 * SIBA_R0_ADMATCH* register.
319 *
320 * @param addrspace The address space index.
321 *
322 * @retval non-zero success
323 * @retval 0 the given @p addrspace index is not supported.
324 */
325u_int
326siba_admatch_offset(uint8_t addrspace)
327{
328 switch (addrspace) {
329 case 0:
330 return SB0_REG_ABS(SIBA_CFG0_ADMATCH0);
331 case 1:
332 return SB0_REG_ABS(SIBA_CFG0_ADMATCH1);
333 case 2:
334 return SB0_REG_ABS(SIBA_CFG0_ADMATCH2);
335 case 3:
336 return SB0_REG_ABS(SIBA_CFG0_ADMATCH3);
337 default:
338 return (0);
339 }
340}
341
342/**
343 * Parse a SIBA_R0_ADMATCH* register.
344 *
345 * @param addrspace The address space index.
346 * @param am The address match register value to be parsed.
347 * @param[out] addr The parsed address.
348 * @param[out] size The parsed size.
349 *
350 * @retval 0 success
351 * @retval non-zero a parse error occurred.
352 */
353int
354siba_parse_admatch(uint32_t am, uint32_t *addr, uint32_t *size)
355{
356 u_int am_type;
357
358 /* Negative encoding is not supported. This is not used on any
359 * currently known devices*/
360 if (am & SIBA_AM_ADNEG)
361 return (EINVAL);
362
363 /* Extract the base address and size */
364 am_type = SIBA_REG_GET(am, AM_TYPE);
365 switch (am_type) {
366 case 0:
367 *addr = am & SIBA_AM_BASE0_MASK;
368 *size = 1 << (SIBA_REG_GET(am, AM_ADINT0) + 1);
369 break;
370 case 1:
371 *addr = am & SIBA_AM_BASE1_MASK;
372 *size = 1 << (SIBA_REG_GET(am, AM_ADINT1) + 1);
373 break;
374 case 2:
375 *addr = am & SIBA_AM_BASE2_MASK;
376 *size = 1 << (SIBA_REG_GET(am, AM_ADINT2) + 1);
377 break;
378 default:
379 return (EINVAL);
380 }
381
382 return (0);
383}