Add some helper functions to make it easier to write a driver for a bus

which needs to manage resources for its children.
This commit is contained in:
Doug Rabson 1999-05-22 14:57:15 +00:00
parent 32ea10b4fc
commit 7e082b48a2
2 changed files with 218 additions and 3 deletions

View File

@ -23,7 +23,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: subr_bus.c,v 1.24 1999/05/21 08:23:58 dfr Exp $
* $Id: subr_bus.c,v 1.25 1999/05/22 09:52:21 peter Exp $
*/
#include <sys/param.h>
@ -34,6 +34,8 @@
#include <sys/sysctl.h>
#include <sys/bus_private.h>
#include <sys/systm.h>
#include <machine/bus.h>
#include <sys/rman.h>
#include <machine/stdarg.h> /* for device_printf() */
#include "opt_bus.h"
@ -1607,6 +1609,152 @@ SYSINIT(cfgload, SI_SUB_KMEM, SI_ORDER_ANY + 50, resource_cfgload, 0)
* Some useful method implementations to make life easier for bus drivers.
*/
void
resource_list_init(struct resource_list *rl)
{
SLIST_INIT(rl);
}
void
resource_list_free(struct resource_list *rl)
{
struct resource_list_entry *rle;
while ((rle = SLIST_FIRST(rl)) != NULL) {
if (rle->res)
panic("resource_list_free: resource entry is busy");
SLIST_REMOVE_HEAD(rl, link);
free(rle, M_DEVBUF);
}
}
void
resource_list_add(struct resource_list *rl,
int type, int rid,
u_long start, u_long end, u_long count)
{
struct resource_list_entry *rle;
rle = resource_list_find(rl, type, rid);
if (!rle) {
rle = malloc(sizeof(struct resource_list_entry), M_DEVBUF, M_NOWAIT);
if (!rle)
panic("resource_list_add: can't record entry");
SLIST_INSERT_HEAD(rl, rle, link);
rle->type = type;
rle->rid = rid;
rle->res = NULL;
}
if (rle->res)
panic("resource_list_add: resource entry is busy");
rle->start = start;
rle->end = end;
rle->count = count;
}
struct resource_list_entry*
resource_list_find(struct resource_list *rl,
int type, int rid)
{
struct resource_list_entry *rle;
SLIST_FOREACH(rle, rl, link)
if (rle->type == type && rle->rid == rid)
return rle;
return NULL;
}
void
resource_list_remove(struct resource_list *rl,
int type, int rid)
{
struct resource_list_entry *rle = resource_list_find(rl, type, rid);
if (rle) {
SLIST_REMOVE(rl, rle, resource_list_entry, link);
free(rle, M_DEVBUF);
}
}
struct resource *
resource_list_alloc(device_t bus, device_t child,
int type, int *rid,
u_long start, u_long end,
u_long count, u_int flags)
{
struct resource_list *rl;
struct resource_list_entry *rle = 0;
int passthrough = (device_get_parent(child) != bus);
int isdefault = (start == 0UL && end == ~0UL);
if (passthrough) {
return BUS_ALLOC_RESOURCE(device_get_parent(bus), child,
type, rid,
start, end, count, flags);
}
rl = device_get_ivars(child);
rle = resource_list_find(rl, type, *rid);
if (!rle)
return 0; /* no resource of that type/rid */
if (rle->res)
panic("resource_list_alloc: resource entry is busy");
if (isdefault) {
start = rle->start;
count = max(count, rle->count);
end = max(rle->end, start + count - 1);
}
rle->res = BUS_ALLOC_RESOURCE(device_get_parent(bus), child,
type, rid, start, end, count, flags);
/*
* Record the new range.
*/
if (rle->res) {
rle->start = rman_get_start(rle->res);
rle->end = rman_get_end(rle->res);
rle->count = count;
}
return rle->res;
}
int
resource_list_release(device_t bus, device_t child,
int type, int rid, struct resource *res)
{
struct resource_list *rl;
struct resource_list_entry *rle = 0;
int passthrough = (device_get_parent(child) != bus);
int error;
if (passthrough) {
return BUS_RELEASE_RESOURCE(device_get_parent(bus), child,
type, rid, res);
}
rl = device_get_ivars(child);
rle = resource_list_find(rl, type, rid);
if (!rle)
panic("resource_list_release: can't find resource");
if (!rle->res)
panic("resource_list_release: resource entry is not busy");
error = BUS_RELEASE_RESOURCE(device_get_parent(bus), child,
type, rid, res);
if (error)
return error;
rle->res = NULL;
return 0;
}
/*
* Call DEVICE_IDENTIFY for each driver.
*/

View File

@ -23,7 +23,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: bus.h,v 1.15 1999/05/09 13:00:49 phk Exp $
* $Id: bus.h,v 1.16 1999/05/14 11:22:47 dfr Exp $
*/
#ifndef _SYS_BUS_H_
@ -84,6 +84,74 @@ typedef enum device_state {
DS_BUSY /* device is open */
} device_state_t;
/*
* Definitions for drivers which need to keep simple lists of resources
* for their child devices.
*/
struct resource;
struct resource_list_entry {
SLIST_ENTRY(resource_list_entry) link;
int type; /* type argument to alloc_resource */
int rid; /* resource identifier */
struct resource *res; /* the real resource when allocated */
u_long start; /* start of resource range */
u_long end; /* end of resource range */
u_long count; /* count within range */
};
SLIST_HEAD(resource_list, resource_list_entry);
/*
* Initialise a resource list.
*/
void resource_list_init(struct resource_list *rl);
/*
* Reclaim memory used by a resource list.
*/
void resource_list_free(struct resource_list *rl);
/*
* Add a resource entry or modify an existing entry if one exists with
* the same type and rid.
*/
void resource_list_add(struct resource_list *rl,
int type, int rid,
u_long start, u_long end, u_long count);
/*
* Find a resource entry by type and rid.
*/
struct resource_list_entry*
resource_list_find(struct resource_list *rl,
int type, int rid);
/*
* Remove a resource entry.
*/
void resource_list_remove(struct resource_list *rl,
int type, int rid);
/*
* Implement BUS_ALLOC_RESOURCE by looking up a resource from the list
* and passing the allocation up to the parent of bus. This assumes
* that the first entry of device_get_ivars(child) is a struct
* resource_list. This also handles 'passthrough' allocations where a
* child is a remote descendant of bus by passing the allocation up to
* the parent of bus.
*/
struct resource *
resource_list_alloc(device_t bus, device_t child,
int type, int *rid,
u_long start, u_long end,
u_long count, u_int flags);
/*
* Implement BUS_RELEASE_RESOURCE.
*/
int resource_list_release(device_t bus, device_t child,
int type, int rid, struct resource *res);
/*
* The root bus, to which all top-level busses are attached.
*/
@ -94,7 +162,6 @@ void root_bus_configure(void);
/*
* Useful functions for implementing busses.
*/
struct resource;
int bus_generic_activate_resource(device_t dev, device_t child, int type,
int rid, struct resource *r);