1296077Sadrian/*-
2296077Sadrian * Copyright (c) 2015 Landon Fuller <landon@landonf.org>
3296077Sadrian * All rights reserved.
4296077Sadrian *
5296077Sadrian * Redistribution and use in source and binary forms, with or without
6296077Sadrian * modification, are permitted provided that the following conditions
7296077Sadrian * are met:
8296077Sadrian * 1. Redistributions of source code must retain the above copyright
9296077Sadrian *    notice, this list of conditions and the following disclaimer,
10296077Sadrian *    without modification.
11296077Sadrian * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12296077Sadrian *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13296077Sadrian *    redistribution must be conditioned upon including a substantially
14296077Sadrian *    similar Disclaimer requirement for further binary redistribution.
15296077Sadrian *
16296077Sadrian * NO WARRANTY
17296077Sadrian * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18296077Sadrian * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19296077Sadrian * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
20296077Sadrian * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21296077Sadrian * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
22296077Sadrian * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23296077Sadrian * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24296077Sadrian * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25296077Sadrian * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26296077Sadrian * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27296077Sadrian * THE POSSIBILITY OF SUCH DAMAGES.
28296077Sadrian */
29296077Sadrian
30296077Sadrian#include <sys/cdefs.h>
31296077Sadrian__FBSDID("$FreeBSD: releng/11.0/sys/dev/bhnd/bhndb/bhndb_subr.c 300628 2016-05-24 21:20:17Z adrian $");
32296077Sadrian
33296077Sadrian#include <sys/param.h>
34296077Sadrian#include <sys/kernel.h>
35296077Sadrian
36296077Sadrian#include "bhndb_private.h"
37296077Sadrian#include "bhndbvar.h"
38296077Sadrian
39296077Sadrian/**
40296077Sadrian * Attach a BHND bridge device to @p parent.
41296077Sadrian *
42296077Sadrian * @param parent A parent PCI device.
43296077Sadrian * @param[out] bhndb On success, the probed and attached bhndb bridge device.
44296077Sadrian * @param unit The device unit number, or -1 to select the next available unit
45296077Sadrian * number.
46296077Sadrian *
47296077Sadrian * @retval 0 success
48296077Sadrian * @retval non-zero Failed to attach the bhndb device.
49296077Sadrian */
50296077Sadrianint
51296077Sadrianbhndb_attach_bridge(device_t parent, device_t *bhndb, int unit)
52296077Sadrian{
53296077Sadrian	int error;
54296077Sadrian
55299097Sadrian	*bhndb = device_add_child(parent, "bhndb", unit);
56296077Sadrian	if (*bhndb == NULL)
57296077Sadrian		return (ENXIO);
58296077Sadrian
59296077Sadrian	if (!(error = device_probe_and_attach(*bhndb)))
60296077Sadrian		return (0);
61296077Sadrian
62296077Sadrian	if ((device_delete_child(parent, *bhndb)))
63296077Sadrian		device_printf(parent, "failed to detach bhndb child\n");
64296077Sadrian
65296077Sadrian	return (error);
66296077Sadrian}
67296077Sadrian
68296077Sadrian/*
69296077Sadrian * Call BHNDB_SUSPEND_RESOURCE() for all resources in @p rl.
70296077Sadrian */
71296077Sadrianstatic void
72296077Sadrianbhndb_do_suspend_resources(device_t dev, struct resource_list *rl)
73296077Sadrian{
74296077Sadrian	struct resource_list_entry *rle;
75296077Sadrian
76296077Sadrian	/* Suspend all child resources. */
77296077Sadrian	STAILQ_FOREACH(rle, rl, link) {
78296077Sadrian		/* Skip non-allocated resources */
79296077Sadrian		if (rle->res == NULL)
80296077Sadrian			continue;
81296077Sadrian
82296077Sadrian		BHNDB_SUSPEND_RESOURCE(device_get_parent(dev), dev, rle->type,
83296077Sadrian		    rle->res);
84296077Sadrian	}
85296077Sadrian}
86296077Sadrian
87296077Sadrian/**
88296077Sadrian * Helper function for implementing BUS_RESUME_CHILD() on bridged
89296077Sadrian * bhnd(4) buses.
90296077Sadrian *
91296077Sadrian * This implementation of BUS_RESUME_CHILD() uses BUS_GET_RESOURCE_LIST()
92296077Sadrian * to find the child's resources and call BHNDB_SUSPEND_RESOURCE() for all
93296077Sadrian * child resources, ensuring that the device's allocated bridge resources
94296077Sadrian * will be available to other devices during bus resumption.
95296077Sadrian *
96296077Sadrian * Before suspending any resources, @p child is suspended by
97296077Sadrian * calling bhnd_generic_suspend_child().
98296077Sadrian *
99296077Sadrian * If @p child is not a direct child of @p dev, suspension is delegated to
100296077Sadrian * the @p dev parent.
101296077Sadrian */
102296077Sadrianint
103296077Sadrianbhnd_generic_br_suspend_child(device_t dev, device_t child)
104296077Sadrian{
105296077Sadrian	struct resource_list		*rl;
106296077Sadrian	int				 error;
107296077Sadrian
108296077Sadrian	if (device_get_parent(child) != dev)
109296077Sadrian		BUS_SUSPEND_CHILD(device_get_parent(dev), child);
110296077Sadrian
111296077Sadrian	if (device_is_suspended(child))
112296077Sadrian		return (EBUSY);
113296077Sadrian
114296077Sadrian	/* Suspend the child device */
115296077Sadrian	if ((error = bhnd_generic_suspend_child(dev, child)))
116296077Sadrian		return (error);
117296077Sadrian
118296077Sadrian	/* Fetch the resource list. If none, there's nothing else to do */
119296077Sadrian	rl = BUS_GET_RESOURCE_LIST(device_get_parent(child), child);
120296077Sadrian	if (rl == NULL)
121296077Sadrian		return (0);
122296077Sadrian
123296077Sadrian	/* Suspend all child resources. */
124296077Sadrian	bhndb_do_suspend_resources(dev, rl);
125296077Sadrian
126296077Sadrian	return (0);
127296077Sadrian}
128296077Sadrian
129296077Sadrian/**
130296077Sadrian * Helper function for implementing BUS_RESUME_CHILD() on bridged
131296077Sadrian * bhnd(4) bus devices.
132296077Sadrian *
133296077Sadrian * This implementation of BUS_RESUME_CHILD() uses BUS_GET_RESOURCE_LIST()
134296077Sadrian * to find the child's resources and call BHNDB_RESUME_RESOURCE() for all
135296077Sadrian * child resources, before delegating to bhnd_generic_resume_child().
136296077Sadrian *
137296077Sadrian * If resource resumption fails, @p child will not be resumed.
138296077Sadrian *
139296077Sadrian * If @p child is not a direct child of @p dev, suspension is delegated to
140296077Sadrian * the @p dev parent.
141296077Sadrian */
142296077Sadrianint
143296077Sadrianbhnd_generic_br_resume_child(device_t dev, device_t child)
144296077Sadrian{
145296077Sadrian	struct resource_list		*rl;
146296077Sadrian	struct resource_list_entry	*rle;
147296077Sadrian	int				 error;
148296077Sadrian
149296077Sadrian	if (device_get_parent(child) != dev)
150296077Sadrian		BUS_RESUME_CHILD(device_get_parent(dev), child);
151296077Sadrian
152296077Sadrian	if (!device_is_suspended(child))
153296077Sadrian		return (EBUSY);
154296077Sadrian
155296077Sadrian	/* Fetch the resource list. If none, there's nothing else to do */
156296077Sadrian	rl = BUS_GET_RESOURCE_LIST(device_get_parent(child), child);
157296077Sadrian	if (rl == NULL)
158296077Sadrian		return (bhnd_generic_resume_child(dev, child));
159296077Sadrian
160296077Sadrian	/* Resume all resources */
161296077Sadrian	STAILQ_FOREACH(rle, rl, link) {
162296077Sadrian		/* Skip non-allocated resources */
163296077Sadrian		if (rle->res == NULL)
164296077Sadrian			continue;
165296077Sadrian
166296077Sadrian		error = BHNDB_RESUME_RESOURCE(device_get_parent(dev), dev,
167296077Sadrian		    rle->type, rle->res);
168296077Sadrian		if (error) {
169296077Sadrian			/* Put all resources back into a suspend state */
170296077Sadrian			bhndb_do_suspend_resources(dev, rl);
171296077Sadrian			return (error);
172296077Sadrian		}
173296077Sadrian	}
174296077Sadrian
175296077Sadrian	/* Now that all resources are resumed, resume child */
176296077Sadrian	if ((error = bhnd_generic_resume_child(dev, child))) {
177296077Sadrian		/* Put all resources back into a suspend state */
178296077Sadrian		bhndb_do_suspend_resources(dev, rl);
179296077Sadrian	}
180296077Sadrian
181296077Sadrian	return (error);
182296077Sadrian}
183296077Sadrian
184296077Sadrian/**
185298276Sadrian * Find a SYS_RES_MEMORY resource containing the given address range.
186298276Sadrian *
187298276Sadrian * @param br The bhndb resource state to search.
188298276Sadrian * @param start The start address of the range to search for.
189298276Sadrian * @param count The size of the range to search for.
190298276Sadrian *
191298276Sadrian * @retval resource the host resource containing the requested range.
192298276Sadrian * @retval NULL if no resource containing the requested range can be found.
193298276Sadrian */
194298276Sadrianstruct resource *
195298276Sadrianbhndb_find_resource_range(struct bhndb_resources *br, rman_res_t start,
196298276Sadrian     rman_res_t count)
197298276Sadrian{
198298276Sadrian	for (u_int i = 0; br->res_spec[i].type != -1; i++) {
199298276Sadrian		struct resource *r = br->res[i];
200298276Sadrian
201298276Sadrian		if (br->res_spec->type != SYS_RES_MEMORY)
202298276Sadrian			continue;
203298276Sadrian
204298276Sadrian		/* Verify range */
205298276Sadrian		if (rman_get_start(r) > start)
206298276Sadrian			continue;
207298276Sadrian
208298276Sadrian		if (rman_get_end(r) < (start + count - 1))
209298276Sadrian			continue;
210298276Sadrian
211298276Sadrian		return (r);
212298276Sadrian	}
213298276Sadrian
214298276Sadrian	return (NULL);
215298276Sadrian}
216298276Sadrian
217298276Sadrian/**
218296077Sadrian * Find the resource containing @p win.
219296077Sadrian *
220296077Sadrian * @param br The bhndb resource state to search.
221296077Sadrian * @param win A register window.
222296077Sadrian *
223296077Sadrian * @retval resource the resource containing @p win.
224296077Sadrian * @retval NULL if no resource containing @p win can be found.
225296077Sadrian */
226296077Sadrianstruct resource *
227296077Sadrianbhndb_find_regwin_resource(struct bhndb_resources *br,
228296077Sadrian    const struct bhndb_regwin *win)
229296077Sadrian{
230296077Sadrian	const struct resource_spec *rspecs;
231296077Sadrian
232296077Sadrian	rspecs = br->cfg->resource_specs;
233296077Sadrian	for (u_int i = 0; rspecs[i].type != -1; i++) {
234296077Sadrian		if (win->res.type != rspecs[i].type)
235296077Sadrian			continue;
236296077Sadrian
237296077Sadrian		if (win->res.rid != rspecs[i].rid)
238296077Sadrian			continue;
239296077Sadrian
240296077Sadrian		/* Found declared resource */
241296077Sadrian		return (br->res[i]);
242296077Sadrian	}
243296077Sadrian
244296077Sadrian	device_printf(br->dev,
245296077Sadrian	    "missing regwin resource spec (type=%d, rid=%d)\n",
246296077Sadrian	    win->res.type, win->res.rid);
247296077Sadrian
248296077Sadrian	return (NULL);
249296077Sadrian}
250296077Sadrian
251296077Sadrian/**
252296077Sadrian * Allocate and initialize a new resource state structure, allocating
253296077Sadrian * bus resources from @p parent_dev according to @p cfg.
254296077Sadrian *
255296077Sadrian * @param dev The bridge device.
256296077Sadrian * @param parent_dev The parent device from which resources will be allocated.
257296077Sadrian * @param cfg The hardware configuration to be used.
258296077Sadrian */
259296077Sadrianstruct bhndb_resources *
260296077Sadrianbhndb_alloc_resources(device_t dev, device_t parent_dev,
261296077Sadrian    const struct bhndb_hwcfg *cfg)
262296077Sadrian{
263296077Sadrian	struct bhndb_resources		*r;
264296077Sadrian	const struct bhndb_regwin	*win;
265296077Sadrian	bus_size_t			 last_window_size;
266296077Sadrian	size_t				 res_num;
267296077Sadrian	u_int				 rnid;
268296077Sadrian	int				 error;
269296077Sadrian	bool				 free_parent_res;
270298276Sadrian	bool				 free_ht_mem, free_br_mem;
271296077Sadrian
272296077Sadrian	free_parent_res = false;
273298276Sadrian	free_ht_mem = false;
274298276Sadrian	free_br_mem = false;
275296077Sadrian
276296077Sadrian	r = malloc(sizeof(*r), M_BHND, M_NOWAIT|M_ZERO);
277296077Sadrian	if (r == NULL)
278296077Sadrian		return (NULL);
279296077Sadrian
280296077Sadrian	/* Basic initialization */
281296077Sadrian	r->dev = dev;
282296077Sadrian	r->parent_dev = parent_dev;
283296077Sadrian	r->cfg = cfg;
284296077Sadrian	r->min_prio = BHNDB_PRIORITY_NONE;
285296077Sadrian	STAILQ_INIT(&r->bus_regions);
286296077Sadrian
287298276Sadrian	/* Initialize host address space resource manager. */
288298276Sadrian	r->ht_mem_rman.rm_start = 0;
289298276Sadrian	r->ht_mem_rman.rm_end = ~0;
290298276Sadrian	r->ht_mem_rman.rm_type = RMAN_ARRAY;
291298276Sadrian	r->ht_mem_rman.rm_descr = "BHNDB host memory";
292298276Sadrian	if ((error = rman_init(&r->ht_mem_rman))) {
293298276Sadrian		device_printf(r->dev, "could not initialize ht_mem_rman\n");
294298276Sadrian		goto failed;
295298276Sadrian	}
296298276Sadrian	free_ht_mem = true;
297298276Sadrian
298298276Sadrian
299298276Sadrian	/* Initialize resource manager for the bridged address space. */
300298276Sadrian	r->br_mem_rman.rm_start = 0;
301298276Sadrian	r->br_mem_rman.rm_end = BUS_SPACE_MAXADDR_32BIT;
302298276Sadrian	r->br_mem_rman.rm_type = RMAN_ARRAY;
303298276Sadrian	r->br_mem_rman.rm_descr = "BHNDB bridged memory";
304298276Sadrian
305298276Sadrian	if ((error = rman_init(&r->br_mem_rman))) {
306298276Sadrian		device_printf(r->dev, "could not initialize br_mem_rman\n");
307298276Sadrian		goto failed;
308298276Sadrian	}
309298276Sadrian	free_br_mem = true;
310298276Sadrian
311298276Sadrian	error = rman_manage_region(&r->br_mem_rman, 0, BUS_SPACE_MAXADDR_32BIT);
312298276Sadrian	if (error) {
313298276Sadrian		device_printf(r->dev, "could not configure br_mem_rman\n");
314298276Sadrian		goto failed;
315298276Sadrian	}
316298276Sadrian
317298276Sadrian
318296077Sadrian	/* Determine our bridge resource count from the hardware config. */
319296077Sadrian	res_num = 0;
320296077Sadrian	for (size_t i = 0; cfg->resource_specs[i].type != -1; i++)
321296077Sadrian		res_num++;
322296077Sadrian
323296077Sadrian	/* Allocate space for a non-const copy of our resource_spec
324296077Sadrian	 * table; this will be updated with the RIDs assigned by
325296077Sadrian	 * bus_alloc_resources. */
326296077Sadrian	r->res_spec = malloc(sizeof(r->res_spec[0]) * (res_num + 1), M_BHND,
327296077Sadrian	    M_NOWAIT);
328296077Sadrian	if (r->res_spec == NULL)
329296077Sadrian		goto failed;
330296077Sadrian
331296077Sadrian	/* Initialize and terminate the table */
332296077Sadrian	for (size_t i = 0; i < res_num; i++)
333296077Sadrian		r->res_spec[i] = cfg->resource_specs[i];
334296077Sadrian
335296077Sadrian	r->res_spec[res_num].type = -1;
336296077Sadrian
337296077Sadrian	/* Allocate space for our resource references */
338296077Sadrian	r->res = malloc(sizeof(r->res[0]) * res_num, M_BHND, M_NOWAIT);
339296077Sadrian	if (r->res == NULL)
340296077Sadrian		goto failed;
341296077Sadrian
342296077Sadrian	/* Allocate resources */
343296077Sadrian	error = bus_alloc_resources(r->parent_dev, r->res_spec, r->res);
344296077Sadrian	if (error) {
345296077Sadrian		device_printf(r->dev,
346296077Sadrian		    "could not allocate bridge resources on %s: %d\n",
347296077Sadrian		    device_get_nameunit(r->parent_dev), error);
348296077Sadrian		goto failed;
349296077Sadrian	} else {
350296077Sadrian		free_parent_res = true;
351296077Sadrian	}
352296077Sadrian
353298276Sadrian	/* Add allocated memory resources to our host memory resource manager */
354298276Sadrian	for (u_int i = 0; r->res_spec[i].type != -1; i++) {
355298276Sadrian		struct resource *res;
356298276Sadrian
357298276Sadrian		/* skip non-memory resources */
358298276Sadrian		if (r->res_spec[i].type != SYS_RES_MEMORY)
359298276Sadrian			continue;
360298276Sadrian
361298276Sadrian		/* add host resource to set of managed regions */
362298276Sadrian		res = r->res[i];
363298276Sadrian		error = rman_manage_region(&r->ht_mem_rman, rman_get_start(res),
364298276Sadrian		    rman_get_end(res));
365298276Sadrian		if (error) {
366298276Sadrian			device_printf(r->dev,
367298276Sadrian			    "could not register host memory region with "
368298276Sadrian			    "ht_mem_rman: %d\n", error);
369298276Sadrian			goto failed;
370298276Sadrian		}
371298276Sadrian	}
372298276Sadrian
373296077Sadrian	/* Fetch the dynamic regwin count and verify that it does not exceed
374296077Sadrian	 * what is representable via our freelist bitmask. */
375296077Sadrian	r->dwa_count = bhndb_regwin_count(cfg->register_windows,
376296077Sadrian	    BHNDB_REGWIN_T_DYN);
377296077Sadrian	if (r->dwa_count >= (8 * sizeof(r->dwa_freelist))) {
378296077Sadrian		device_printf(r->dev, "max dynamic regwin count exceeded\n");
379296077Sadrian		goto failed;
380296077Sadrian	}
381296077Sadrian
382296077Sadrian	/* Allocate the dynamic window allocation table. */
383296077Sadrian	r->dw_alloc = malloc(sizeof(r->dw_alloc[0]) * r->dwa_count, M_BHND,
384296077Sadrian	    M_NOWAIT);
385296077Sadrian	if (r->dw_alloc == NULL)
386296077Sadrian		goto failed;
387296077Sadrian
388296077Sadrian	/* Initialize the dynamic window table and freelist. */
389296077Sadrian	r->dwa_freelist = 0;
390296077Sadrian	rnid = 0;
391296077Sadrian	last_window_size = 0;
392296077Sadrian	for (win = cfg->register_windows;
393296077Sadrian	    win->win_type != BHNDB_REGWIN_T_INVALID; win++)
394296077Sadrian	{
395296077Sadrian		struct bhndb_dw_alloc *dwa;
396296077Sadrian
397296077Sadrian		/* Skip non-DYN windows */
398296077Sadrian		if (win->win_type != BHNDB_REGWIN_T_DYN)
399296077Sadrian			continue;
400296077Sadrian
401296077Sadrian		/* Validate the window size */
402296077Sadrian		if (win->win_size == 0) {
403296077Sadrian			device_printf(r->dev, "ignoring zero-length dynamic "
404296077Sadrian			    "register window\n");
405296077Sadrian			continue;
406296077Sadrian		} else if (last_window_size == 0) {
407296077Sadrian			last_window_size = win->win_size;
408296077Sadrian		} else if (last_window_size != win->win_size) {
409296077Sadrian			/*
410296077Sadrian			 * No existing hardware should trigger this.
411296077Sadrian			 *
412296077Sadrian			 * If you run into this in the future, the dynamic
413296077Sadrian			 * window allocator and the resource priority system
414296077Sadrian			 * will need to be extended to support multiple register
415296077Sadrian			 * window allocation pools.
416296077Sadrian			 */
417296077Sadrian			device_printf(r->dev, "devices that vend multiple "
418296077Sadrian			    "dynamic register window sizes are not currently "
419296077Sadrian			    "supported\n");
420296077Sadrian			goto failed;
421296077Sadrian		}
422296077Sadrian
423296077Sadrian		dwa = &r->dw_alloc[rnid];
424296077Sadrian		dwa->win = win;
425296077Sadrian		dwa->parent_res = NULL;
426296077Sadrian		dwa->rnid = rnid;
427296077Sadrian		dwa->target = 0x0;
428296077Sadrian
429296077Sadrian		LIST_INIT(&dwa->refs);
430296077Sadrian
431296077Sadrian		/* Find and validate corresponding resource. */
432296077Sadrian		dwa->parent_res = bhndb_find_regwin_resource(r, win);
433296077Sadrian		if (dwa->parent_res == NULL)
434296077Sadrian			goto failed;
435296077Sadrian
436296077Sadrian		if (rman_get_size(dwa->parent_res) < win->win_offset +
437296077Sadrian		    win->win_size)
438296077Sadrian		{
439296077Sadrian			device_printf(r->dev, "resource %d too small for "
440296077Sadrian			    "register window with offset %llx and size %llx\n",
441296077Sadrian			    rman_get_rid(dwa->parent_res),
442296077Sadrian			    (unsigned long long) win->win_offset,
443296077Sadrian			    (unsigned long long) win->win_size);
444296077Sadrian
445296077Sadrian			error = EINVAL;
446296077Sadrian			goto failed;
447296077Sadrian		}
448296077Sadrian
449296077Sadrian		/* Add to freelist */
450296077Sadrian		r->dwa_freelist |= (1 << rnid);
451296077Sadrian
452296077Sadrian		rnid++;
453296077Sadrian	}
454296077Sadrian
455296077Sadrian	return (r);
456296077Sadrian
457296077Sadrianfailed:
458296077Sadrian	if (free_parent_res)
459296077Sadrian		bus_release_resources(r->parent_dev, r->res_spec, r->res);
460298276Sadrian
461298276Sadrian	if (free_ht_mem)
462298276Sadrian		rman_fini(&r->ht_mem_rman);
463296077Sadrian
464298276Sadrian	if (free_br_mem)
465298276Sadrian		rman_fini(&r->br_mem_rman);
466298276Sadrian
467296077Sadrian	if (r->res != NULL)
468296077Sadrian		free(r->res, M_BHND);
469296077Sadrian
470296077Sadrian	if (r->res_spec != NULL)
471296077Sadrian		free(r->res_spec, M_BHND);
472296077Sadrian
473296077Sadrian	if (r->dw_alloc != NULL)
474296077Sadrian		free(r->dw_alloc, M_BHND);
475296077Sadrian
476296077Sadrian	free (r, M_BHND);
477296077Sadrian
478296077Sadrian	return (NULL);
479296077Sadrian}
480296077Sadrian
481296077Sadrian/**
482296077Sadrian * Deallocate the given bridge resource structure and any associated resources.
483296077Sadrian *
484296077Sadrian * @param br Resource state to be deallocated.
485296077Sadrian */
486296077Sadrianvoid
487296077Sadrianbhndb_free_resources(struct bhndb_resources *br)
488296077Sadrian{
489296077Sadrian	struct bhndb_region	*region, *r_next;
490296077Sadrian	struct bhndb_dw_alloc	*dwa;
491296077Sadrian	struct bhndb_dw_rentry	*dwr, *dwr_next;
492296077Sadrian
493296077Sadrian	/* No window regions may still be held */
494296077Sadrian	if (__builtin_popcount(br->dwa_freelist) != br->dwa_count) {
495296077Sadrian		device_printf(br->dev, "leaked %llu dynamic register regions\n",
496296077Sadrian		    (unsigned long long) br->dwa_count - br->dwa_freelist);
497296077Sadrian	}
498296077Sadrian
499296077Sadrian	/* Release resources allocated through our parent. */
500296077Sadrian	bus_release_resources(br->parent_dev, br->res_spec, br->res);
501296077Sadrian
502296077Sadrian	/* Clean up resource reservations */
503296077Sadrian	for (size_t i = 0; i < br->dwa_count; i++) {
504296077Sadrian		dwa = &br->dw_alloc[i];
505296077Sadrian
506296077Sadrian		LIST_FOREACH_SAFE(dwr, &dwa->refs, dw_link, dwr_next) {
507296077Sadrian			LIST_REMOVE(dwr, dw_link);
508296077Sadrian			free(dwr, M_BHND);
509296077Sadrian		}
510296077Sadrian	}
511296077Sadrian
512296077Sadrian	/* Release bus regions */
513296077Sadrian	STAILQ_FOREACH_SAFE(region, &br->bus_regions, link, r_next) {
514296077Sadrian		STAILQ_REMOVE(&br->bus_regions, region, bhndb_region, link);
515296077Sadrian		free(region, M_BHND);
516296077Sadrian	}
517296077Sadrian
518298276Sadrian	/* Release our resource managers */
519298276Sadrian	rman_fini(&br->ht_mem_rman);
520298276Sadrian	rman_fini(&br->br_mem_rman);
521298276Sadrian
522296077Sadrian	/* Free backing resource state structures */
523296077Sadrian	free(br->res, M_BHND);
524296077Sadrian	free(br->res_spec, M_BHND);
525296077Sadrian	free(br->dw_alloc, M_BHND);
526296077Sadrian}
527296077Sadrian
528296077Sadrian/**
529296077Sadrian * Add a bus region entry to @p r for the given base @p addr and @p size.
530296077Sadrian *
531296077Sadrian * @param br The resource state to which the bus region entry will be added.
532296077Sadrian * @param addr The base address of this region.
533296077Sadrian * @param size The size of this region.
534296077Sadrian * @param priority The resource priority to be assigned to allocations
535296077Sadrian * made within this bus region.
536296077Sadrian * @param static_regwin If available, a static register window mapping this
537296077Sadrian * bus region entry. If not available, NULL.
538296077Sadrian *
539296077Sadrian * @retval 0 success
540296077Sadrian * @retval non-zero if adding the bus region fails.
541296077Sadrian */
542296077Sadrianint
543296077Sadrianbhndb_add_resource_region(struct bhndb_resources *br, bhnd_addr_t addr,
544296077Sadrian    bhnd_size_t size, bhndb_priority_t priority,
545296077Sadrian    const struct bhndb_regwin *static_regwin)
546296077Sadrian{
547296077Sadrian	struct bhndb_region	*reg;
548296077Sadrian
549296077Sadrian	/* Insert in the bus resource list */
550296077Sadrian	reg = malloc(sizeof(*reg), M_BHND, M_NOWAIT);
551296077Sadrian	if (reg == NULL)
552296077Sadrian		return (ENOMEM);
553296077Sadrian
554296077Sadrian	*reg = (struct bhndb_region) {
555296077Sadrian		.addr = addr,
556296077Sadrian		.size = size,
557296077Sadrian		.priority = priority,
558296077Sadrian		.static_regwin = static_regwin
559296077Sadrian	};
560296077Sadrian
561296077Sadrian	STAILQ_INSERT_HEAD(&br->bus_regions, reg, link);
562296077Sadrian
563296077Sadrian	return (0);
564296077Sadrian}
565296077Sadrian
566300251Sadrian
567296077Sadrian/**
568300251Sadrian * Find the maximum start and end limits of the register window mapping
569300251Sadrian * resource @p r.
570296077Sadrian *
571300251Sadrian * If the memory range is not mapped by an existing dynamic or static register
572300251Sadrian * window, ENOENT will be returned.
573300251Sadrian *
574296077Sadrian * @param br The resource state to search.
575300251Sadrian * @param r The resource to search for in @p br.
576296077Sadrian * @param addr The requested starting address.
577296077Sadrian * @param size The requested size.
578296077Sadrian *
579296077Sadrian * @retval bhndb_region A region that fully contains the requested range.
580296077Sadrian * @retval NULL If no mapping region can be found.
581296077Sadrian */
582300251Sadrianint
583300251Sadrianbhndb_find_resource_limits(struct bhndb_resources *br, struct resource *r,
584300251Sadrian    rman_res_t *start, rman_res_t *end)
585300251Sadrian{
586300251Sadrian	struct bhndb_dw_alloc	*dynamic;
587300251Sadrian	struct bhndb_region	*sregion;
588300251Sadrian
589300251Sadrian	/* Check for an enclosing dynamic register window */
590300251Sadrian	if ((dynamic = bhndb_dw_find_resource(br, r))) {
591300251Sadrian		*start = dynamic->target;
592300251Sadrian		*end = dynamic->target + dynamic->win->win_size - 1;
593300251Sadrian		return (0);
594300251Sadrian	}
595300251Sadrian
596300251Sadrian	/* Check for a static region */
597300251Sadrian	sregion = bhndb_find_resource_region(br, rman_get_start(r),
598300251Sadrian	    rman_get_size(r));
599300251Sadrian	if (sregion != NULL && sregion->static_regwin != NULL) {
600300251Sadrian		*start = sregion->addr;
601300251Sadrian		*end = sregion->addr + sregion->size - 1;
602300251Sadrian
603300251Sadrian		return (0);
604300251Sadrian	}
605300251Sadrian
606300251Sadrian	/* Not found */
607300251Sadrian	return (ENOENT);
608300251Sadrian}
609300251Sadrian
610300251Sadrian/**
611300251Sadrian * Find the bus region that maps @p size bytes at @p addr.
612300251Sadrian *
613300251Sadrian * @param br The resource state to search.
614300251Sadrian * @param addr The requested starting address.
615300251Sadrian * @param size The requested size.
616300251Sadrian *
617300251Sadrian * @retval bhndb_region A region that fully contains the requested range.
618300251Sadrian * @retval NULL If no mapping region can be found.
619300251Sadrian */
620296077Sadrianstruct bhndb_region *
621296077Sadrianbhndb_find_resource_region(struct bhndb_resources *br, bhnd_addr_t addr,
622296077Sadrian    bhnd_size_t size)
623296077Sadrian{
624296077Sadrian	struct bhndb_region *region;
625296077Sadrian
626296077Sadrian	STAILQ_FOREACH(region, &br->bus_regions, link) {
627296077Sadrian		/* Request must fit within the region's mapping  */
628296077Sadrian		if (addr < region->addr)
629296077Sadrian			continue;
630296077Sadrian
631296077Sadrian		if (addr + size > region->addr + region->size)
632296077Sadrian			continue;
633296077Sadrian
634296077Sadrian		return (region);
635296077Sadrian	}
636296077Sadrian
637296077Sadrian	/* Not found */
638296077Sadrian	return (NULL);
639296077Sadrian}
640296077Sadrian
641296077Sadrian/**
642296077Sadrian * Find the entry matching @p r in @p dwa's references, if any.
643296077Sadrian *
644296077Sadrian * @param dwa The dynamic window allocation to search
645296077Sadrian * @param r The resource to search for in @p dwa.
646296077Sadrian */
647296077Sadrianstatic struct bhndb_dw_rentry *
648296077Sadrianbhndb_dw_find_resource_entry(struct bhndb_dw_alloc *dwa, struct resource *r)
649296077Sadrian{
650296077Sadrian	struct bhndb_dw_rentry	*rentry;
651296077Sadrian
652296077Sadrian	LIST_FOREACH(rentry, &dwa->refs, dw_link) {
653296077Sadrian		struct resource *dw_res = rentry->dw_res;
654296077Sadrian
655296077Sadrian		/* Match dev/rid/addr/size */
656296077Sadrian		if (rman_get_device(dw_res)	!= rman_get_device(r) ||
657296077Sadrian			rman_get_rid(dw_res)	!= rman_get_rid(r) ||
658296077Sadrian			rman_get_start(dw_res)	!= rman_get_start(r) ||
659296077Sadrian			rman_get_size(dw_res)	!= rman_get_size(r))
660296077Sadrian		{
661296077Sadrian			continue;
662296077Sadrian		}
663296077Sadrian
664296077Sadrian		/* Matching allocation found */
665296077Sadrian		return (rentry);
666296077Sadrian	}
667296077Sadrian
668296077Sadrian	return (NULL);
669296077Sadrian}
670296077Sadrian
671296077Sadrian/**
672296077Sadrian * Find the dynamic region allocated for @p r, if any.
673296077Sadrian *
674296077Sadrian * @param br The resource state to search.
675296077Sadrian * @param r The resource to search for.
676296077Sadrian *
677296077Sadrian * @retval bhndb_dw_alloc The allocation record for @p r.
678296077Sadrian * @retval NULL if no dynamic window is allocated for @p r.
679296077Sadrian */
680296077Sadrianstruct bhndb_dw_alloc *
681296077Sadrianbhndb_dw_find_resource(struct bhndb_resources *br, struct resource *r)
682296077Sadrian{
683296077Sadrian	struct bhndb_dw_alloc	*dwa;
684296077Sadrian
685296077Sadrian	for (size_t i = 0; i < br->dwa_count; i++) {
686296077Sadrian		dwa = &br->dw_alloc[i];
687296077Sadrian
688296077Sadrian		/* Skip free dynamic windows */
689296077Sadrian		if (bhndb_dw_is_free(br, dwa))
690296077Sadrian			continue;
691296077Sadrian
692296077Sadrian		/* Matching allocation found? */
693296077Sadrian		if (bhndb_dw_find_resource_entry(dwa, r) != NULL)
694296077Sadrian			return (dwa);
695296077Sadrian	}
696296077Sadrian
697296077Sadrian	return (NULL);
698296077Sadrian}
699296077Sadrian
700296077Sadrian/**
701296077Sadrian * Find an existing dynamic window mapping @p size bytes
702296077Sadrian * at @p addr. The window may or may not be free.
703296077Sadrian *
704296077Sadrian * @param br The resource state to search.
705296077Sadrian * @param addr The requested starting address.
706296077Sadrian * @param size The requested size.
707296077Sadrian *
708296077Sadrian * @retval bhndb_dw_alloc A window allocation that fully contains the requested
709296077Sadrian * range.
710296077Sadrian * @retval NULL If no mapping region can be found.
711296077Sadrian */
712296077Sadrianstruct bhndb_dw_alloc *
713296077Sadrianbhndb_dw_find_mapping(struct bhndb_resources *br, bhnd_addr_t addr,
714296077Sadrian    bhnd_size_t size)
715296077Sadrian{
716296077Sadrian	struct bhndb_dw_alloc		*dwr;
717296077Sadrian	const struct bhndb_regwin	*win;
718296077Sadrian
719296077Sadrian	/* Search for an existing dynamic mapping of this address range. */
720296077Sadrian	for (size_t i = 0; i < br->dwa_count; i++) {
721296077Sadrian		dwr = &br->dw_alloc[i];
722296077Sadrian		win = dwr->win;
723296077Sadrian
724296077Sadrian		/* Verify the range */
725296077Sadrian		if (addr < dwr->target)
726296077Sadrian			continue;
727296077Sadrian
728296077Sadrian		if (addr + size > dwr->target + win->win_size)
729296077Sadrian			continue;
730296077Sadrian
731296077Sadrian		/* Found a usable mapping */
732296077Sadrian		return (dwr);
733296077Sadrian	}
734296077Sadrian
735296077Sadrian	/* not found */
736296077Sadrian	return (NULL);
737296077Sadrian}
738296077Sadrian
739296077Sadrian/**
740296077Sadrian * Retain a reference to @p dwa for use by @p res.
741296077Sadrian *
742296077Sadrian * @param br The resource state owning @p dwa.
743296077Sadrian * @param dwa The allocation record to be retained.
744296077Sadrian * @param res The resource that will own a reference to @p dwa.
745296077Sadrian *
746296077Sadrian * @retval 0 success
747296077Sadrian * @retval ENOMEM Failed to allocate a new reference structure.
748296077Sadrian */
749296077Sadrianint
750296077Sadrianbhndb_dw_retain(struct bhndb_resources *br, struct bhndb_dw_alloc *dwa,
751296077Sadrian    struct resource *res)
752296077Sadrian{
753296077Sadrian	struct bhndb_dw_rentry *rentry;
754296077Sadrian
755296077Sadrian	KASSERT(bhndb_dw_find_resource_entry(dwa, res) == NULL,
756296077Sadrian	    ("double-retain of dynamic window for same resource"));
757296077Sadrian
758296077Sadrian	/* Insert a reference entry; we use M_NOWAIT to allow use from
759296077Sadrian	 * within a non-sleepable lock */
760296077Sadrian	rentry = malloc(sizeof(*rentry), M_BHND, M_NOWAIT);
761296077Sadrian	if (rentry == NULL)
762296077Sadrian		return (ENOMEM);
763296077Sadrian
764296077Sadrian	rentry->dw_res = res;
765296077Sadrian	LIST_INSERT_HEAD(&dwa->refs, rentry, dw_link);
766296077Sadrian
767296077Sadrian	/* Update the free list */
768296077Sadrian	br->dwa_freelist &= ~(1 << (dwa->rnid));
769296077Sadrian
770296077Sadrian	return (0);
771296077Sadrian}
772296077Sadrian
773296077Sadrian/**
774296077Sadrian * Release a reference to @p dwa previously retained by @p res. If the
775296077Sadrian * reference count of @p dwa reaches zero, it will be added to the
776296077Sadrian * free list.
777296077Sadrian *
778296077Sadrian * @param br The resource state owning @p dwa.
779296077Sadrian * @param dwa The allocation record to be released.
780296077Sadrian * @param res The resource that currently owns a reference to @p dwa.
781296077Sadrian */
782296077Sadrianvoid
783296077Sadrianbhndb_dw_release(struct bhndb_resources *br, struct bhndb_dw_alloc *dwa,
784296077Sadrian    struct resource *r)
785296077Sadrian{
786296077Sadrian	struct bhndb_dw_rentry	*rentry;
787296077Sadrian
788296077Sadrian	/* Find the rentry */
789296077Sadrian	rentry = bhndb_dw_find_resource_entry(dwa, r);
790296077Sadrian	KASSERT(rentry != NULL, ("over release of resource entry"));
791296077Sadrian
792296077Sadrian	LIST_REMOVE(rentry, dw_link);
793296077Sadrian	free(rentry, M_BHND);
794296077Sadrian
795296077Sadrian	/* If this was the last reference, update the free list */
796296077Sadrian	if (LIST_EMPTY(&dwa->refs))
797296077Sadrian		br->dwa_freelist |= (1 << (dwa->rnid));
798296077Sadrian}
799296077Sadrian
800296077Sadrian/**
801296077Sadrian * Attempt to set (or reset) the target address of @p dwa to map @p size bytes
802296077Sadrian * at @p addr.
803296077Sadrian *
804296077Sadrian * This will apply any necessary window alignment and verify that
805296077Sadrian * the window is capable of mapping the requested range prior to modifying
806296077Sadrian * therecord.
807296077Sadrian *
808296077Sadrian * @param dev The device on which to issue the BHNDB_SET_WINDOW_ADDR() request.
809296077Sadrian * @param br The resource state owning @p dwa.
810296077Sadrian * @param dwa The allocation record to be configured.
811296077Sadrian * @param addr The address to be mapped via @p dwa.
812296077Sadrian * @param size The number of bytes to be mapped at @p addr.
813296077Sadrian *
814296077Sadrian * @retval 0 success
815296077Sadrian * @retval non-zero no usable register window available.
816296077Sadrian */
817296077Sadrianint
818296077Sadrianbhndb_dw_set_addr(device_t dev, struct bhndb_resources *br,
819296077Sadrian    struct bhndb_dw_alloc *dwa, bus_addr_t addr, bus_size_t size)
820296077Sadrian{
821296077Sadrian	const struct bhndb_regwin	*rw;
822296077Sadrian	bus_addr_t			 offset;
823296077Sadrian	int				 error;
824296077Sadrian
825296077Sadrian	rw = dwa->win;
826296077Sadrian
827296077Sadrian	KASSERT(bhndb_dw_is_free(br, dwa),
828296077Sadrian	    ("attempting to set the target address on an in-use window"));
829296077Sadrian
830296077Sadrian	/* Page-align the target address */
831296077Sadrian	offset = addr % rw->win_size;
832296077Sadrian	dwa->target = addr - offset;
833296077Sadrian
834296077Sadrian	/* Verify that the window is large enough for the full target */
835296077Sadrian	if (rw->win_size - offset < size)
836296077Sadrian		return (ENOMEM);
837296077Sadrian
838296077Sadrian	/* Update the window target */
839296077Sadrian	error = BHNDB_SET_WINDOW_ADDR(dev, dwa->win, dwa->target);
840296077Sadrian	if (error) {
841296077Sadrian		dwa->target = 0x0;
842296077Sadrian		return (error);
843296077Sadrian	}
844296077Sadrian
845296077Sadrian	return (0);
846296077Sadrian}
847296077Sadrian
848296077Sadrian/**
849296077Sadrian * Return the count of @p type register windows in @p table.
850296077Sadrian *
851296077Sadrian * @param table The table to search.
852296077Sadrian * @param type The required window type, or BHNDB_REGWIN_T_INVALID to
853296077Sadrian * count all register window types.
854296077Sadrian */
855296077Sadriansize_t
856296077Sadrianbhndb_regwin_count(const struct bhndb_regwin *table,
857296077Sadrian    bhndb_regwin_type_t type)
858296077Sadrian{
859296077Sadrian	const struct bhndb_regwin	*rw;
860296077Sadrian	size_t				 count;
861296077Sadrian
862296077Sadrian	count = 0;
863296077Sadrian	for (rw = table; rw->win_type != BHNDB_REGWIN_T_INVALID; rw++) {
864296077Sadrian		if (type == BHNDB_REGWIN_T_INVALID || rw->win_type == type)
865296077Sadrian			count++;
866296077Sadrian	}
867296077Sadrian
868296077Sadrian	return (count);
869296077Sadrian}
870296077Sadrian
871296077Sadrian/**
872296077Sadrian * Search @p table for the first window with the given @p type.
873296077Sadrian *
874296077Sadrian * @param table The table to search.
875296077Sadrian * @param type The required window type.
876296077Sadrian * @param min_size The minimum window size.
877296077Sadrian *
878296077Sadrian * @retval bhndb_regwin The first matching window.
879296077Sadrian * @retval NULL If no window of the requested type could be found.
880296077Sadrian */
881296077Sadrianconst struct bhndb_regwin *
882296077Sadrianbhndb_regwin_find_type(const struct bhndb_regwin *table,
883296077Sadrian    bhndb_regwin_type_t type, bus_size_t min_size)
884296077Sadrian{
885296077Sadrian	const struct bhndb_regwin *rw;
886296077Sadrian
887296077Sadrian	for (rw = table; rw->win_type != BHNDB_REGWIN_T_INVALID; rw++)
888296077Sadrian	{
889296077Sadrian		if (rw->win_type == type && rw->win_size >= min_size)
890296077Sadrian			return (rw);
891296077Sadrian	}
892296077Sadrian
893296077Sadrian	return (NULL);
894296077Sadrian}
895296077Sadrian
896296077Sadrian/**
897296077Sadrian * Search @p windows for the first matching core window.
898296077Sadrian *
899296077Sadrian * @param table The table to search.
900296077Sadrian * @param class The required core class.
901296077Sadrian * @param unit The required core unit, or -1.
902296077Sadrian * @param port_type The required port type.
903296077Sadrian * @param port The required port.
904296077Sadrian * @param region The required region.
905296077Sadrian *
906296077Sadrian * @retval bhndb_regwin The first matching window.
907296077Sadrian * @retval NULL If no matching window was found.
908296077Sadrian */
909296077Sadrianconst struct bhndb_regwin *
910296077Sadrianbhndb_regwin_find_core(const struct bhndb_regwin *table, bhnd_devclass_t class,
911296077Sadrian    int unit, bhnd_port_type port_type, u_int port, u_int region)
912296077Sadrian{
913296077Sadrian	const struct bhndb_regwin *rw;
914296077Sadrian
915296077Sadrian	for (rw = table; rw->win_type != BHNDB_REGWIN_T_INVALID; rw++)
916296077Sadrian	{
917296077Sadrian		if (rw->win_type != BHNDB_REGWIN_T_CORE)
918296077Sadrian			continue;
919296077Sadrian
920299135Sadrian		if (rw->d.core.class != class)
921296077Sadrian			continue;
922296077Sadrian
923299135Sadrian		if (unit != -1 && rw->d.core.unit != unit)
924296077Sadrian			continue;
925296077Sadrian
926299135Sadrian		if (rw->d.core.port_type != port_type)
927296077Sadrian			continue;
928296077Sadrian
929299135Sadrian		if (rw->d.core.port != port)
930296077Sadrian			continue;
931296077Sadrian
932299135Sadrian		if (rw->d.core.region != region)
933296077Sadrian			continue;
934296077Sadrian
935296077Sadrian		return (rw);
936296077Sadrian	}
937296077Sadrian
938296077Sadrian	return (NULL);
939296077Sadrian}
940296077Sadrian
941296077Sadrian/**
942296077Sadrian * Search @p windows for the best available window of at least @p min_size.
943296077Sadrian *
944296077Sadrian * Search order:
945296077Sadrian * - BHND_REGWIN_T_CORE
946296077Sadrian * - BHND_REGWIN_T_DYN
947296077Sadrian *
948296077Sadrian * @param table The table to search.
949296077Sadrian * @param class The required core class.
950296077Sadrian * @param unit The required core unit, or -1.
951296077Sadrian * @param port_type The required port type.
952296077Sadrian * @param port The required port.
953296077Sadrian * @param region The required region.
954296077Sadrian * @param min_size The minimum window size.
955296077Sadrian *
956296077Sadrian * @retval bhndb_regwin The first matching window.
957296077Sadrian * @retval NULL If no matching window was found.
958296077Sadrian */
959296077Sadrianconst struct bhndb_regwin *
960296077Sadrianbhndb_regwin_find_best(const struct bhndb_regwin *table,
961296077Sadrian    bhnd_devclass_t class, int unit, bhnd_port_type port_type, u_int port,
962296077Sadrian    u_int region, bus_size_t min_size)
963296077Sadrian{
964296077Sadrian	const struct bhndb_regwin *rw;
965296077Sadrian
966296077Sadrian	/* Prefer a fixed core mapping */
967296077Sadrian	rw = bhndb_regwin_find_core(table, class, unit, port_type,
968296077Sadrian	    port, region);
969296077Sadrian	if (rw != NULL)
970296077Sadrian		return (rw);
971296077Sadrian
972296077Sadrian	/* Fall back on a generic dynamic window */
973296077Sadrian	return (bhndb_regwin_find_type(table, BHNDB_REGWIN_T_DYN, min_size));
974296077Sadrian}
975296077Sadrian
976296077Sadrian/**
977296077Sadrian * Return true if @p regw defines a static port register window, and
978296077Sadrian * the mapped port is actually defined on @p dev.
979296077Sadrian *
980296077Sadrian * @param regw A register window to match against.
981296077Sadrian * @param dev A bhnd(4) bus device.
982296077Sadrian */
983296077Sadrianbool
984296077Sadrianbhndb_regwin_matches_device(const struct bhndb_regwin *regw, device_t dev)
985296077Sadrian{
986296077Sadrian	/* Only core windows are supported */
987296077Sadrian	if (regw->win_type != BHNDB_REGWIN_T_CORE)
988296077Sadrian		return (false);
989296077Sadrian
990296077Sadrian	/* Device class must match */
991299135Sadrian	if (bhnd_get_class(dev) != regw->d.core.class)
992296077Sadrian		return (false);
993296077Sadrian
994296077Sadrian	/* Device unit must match */
995299135Sadrian	if (bhnd_get_core_unit(dev) != regw->d.core.unit)
996296077Sadrian		return (false);
997296077Sadrian
998296077Sadrian	/* The regwin port/region must be defined. */
999299135Sadrian	if (!bhnd_is_region_valid(dev, regw->d.core.port_type, regw->d.core.port,
1000299135Sadrian	    regw->d.core.region))
1001296077Sadrian	{
1002296077Sadrian		return (false);
1003296077Sadrian	}
1004296077Sadrian
1005296077Sadrian	/* Matches */
1006296077Sadrian	return (true);
1007296077Sadrian}
1008296077Sadrian
1009296077Sadrian/**
1010296077Sadrian * Search for a core resource priority descriptor in @p table that matches
1011296077Sadrian * @p device.
1012296077Sadrian *
1013296077Sadrian * @param table The table to search.
1014296077Sadrian * @param device A bhnd(4) bus device.
1015296077Sadrian */
1016296077Sadrianconst struct bhndb_hw_priority *
1017296077Sadrianbhndb_hw_priority_find_device(const struct bhndb_hw_priority *table,
1018296077Sadrian    device_t device)
1019296077Sadrian{
1020300628Sadrian	const struct bhndb_hw_priority	*hp;
1021300628Sadrian	struct bhnd_core_info		 ci;
1022296077Sadrian
1023300628Sadrian	ci = bhnd_get_core_info(device);
1024300628Sadrian
1025296077Sadrian	for (hp = table; hp->ports != NULL; hp++) {
1026300628Sadrian		if (bhnd_core_matches(&ci, &hp->match))
1027296077Sadrian			return (hp);
1028296077Sadrian	}
1029296077Sadrian
1030296077Sadrian	/* not found */
1031296077Sadrian	return (NULL);
1032296077Sadrian}
1033