summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/kern/subr_bus.c
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2013-11-06 16:20:21 +0100
committerSebastian Huber <sebastian.huber@embedded-brains.de>2013-11-11 10:08:08 +0100
commit66659ff1ad6831b0ea7425fa6ecd8a8687523658 (patch)
tree48e22b475fa8854128e0861a33fed6f78c8094b5 /freebsd/sys/kern/subr_bus.c
parentDefine __GLOBL1() and __GLOBL() (diff)
downloadrtems-libbsd-66659ff1ad6831b0ea7425fa6ecd8a8687523658.tar.bz2
Update to FreeBSD 9.2
Diffstat (limited to 'freebsd/sys/kern/subr_bus.c')
-rw-r--r--freebsd/sys/kern/subr_bus.c304
1 files changed, 240 insertions, 64 deletions
diff --git a/freebsd/sys/kern/subr_bus.c b/freebsd/sys/kern/subr_bus.c
index 3d1bd2bc..951a63c6 100644
--- a/freebsd/sys/kern/subr_bus.c
+++ b/freebsd/sys/kern/subr_bus.c
@@ -55,6 +55,8 @@ __FBSDID("$FreeBSD$");
#include <sys/bus.h>
#include <sys/interrupt.h>
+#include <net/vnet.h>
+
#include <machine/stdarg.h>
#include <vm/uma.h>
@@ -124,7 +126,7 @@ struct device {
char* desc; /**< driver specific description */
int busy; /**< count of calls to device_busy() */
device_state_t state; /**< current device state */
- u_int32_t devflags; /**< api level flags for device_get_flags() */
+ uint32_t devflags; /**< api level flags for device_get_flags() */
u_int flags; /**< internal device flags */
#define DF_ENABLED 0x01 /* device should be probed/attached */
#define DF_FIXEDCLASS 0x02 /* devclass specified at create time */
@@ -235,7 +237,7 @@ devclass_sysctl_init(devclass_t dc)
SYSCTL_STATIC_CHILDREN(_dev), OID_AUTO, dc->name,
CTLFLAG_RD, NULL, "");
SYSCTL_ADD_PROC(&dc->sysctl_ctx, SYSCTL_CHILDREN(dc->sysctl_tree),
- OID_AUTO, "%parent", CTLFLAG_RD,
+ OID_AUTO, "%parent", CTLTYPE_STRING | CTLFLAG_RD,
dc, DEVCLASS_SYSCTL_PARENT, devclass_sysctl_handler, "A",
"parent class");
}
@@ -300,23 +302,23 @@ device_sysctl_init(device_t dev)
dev->nameunit + strlen(dc->name),
CTLFLAG_RD, NULL, "");
SYSCTL_ADD_PROC(&dev->sysctl_ctx, SYSCTL_CHILDREN(dev->sysctl_tree),
- OID_AUTO, "%desc", CTLFLAG_RD,
+ OID_AUTO, "%desc", CTLTYPE_STRING | CTLFLAG_RD,
dev, DEVICE_SYSCTL_DESC, device_sysctl_handler, "A",
"device description");
SYSCTL_ADD_PROC(&dev->sysctl_ctx, SYSCTL_CHILDREN(dev->sysctl_tree),
- OID_AUTO, "%driver", CTLFLAG_RD,
+ OID_AUTO, "%driver", CTLTYPE_STRING | CTLFLAG_RD,
dev, DEVICE_SYSCTL_DRIVER, device_sysctl_handler, "A",
"device driver name");
SYSCTL_ADD_PROC(&dev->sysctl_ctx, SYSCTL_CHILDREN(dev->sysctl_tree),
- OID_AUTO, "%location", CTLFLAG_RD,
+ OID_AUTO, "%location", CTLTYPE_STRING | CTLFLAG_RD,
dev, DEVICE_SYSCTL_LOCATION, device_sysctl_handler, "A",
"device location relative to parent");
SYSCTL_ADD_PROC(&dev->sysctl_ctx, SYSCTL_CHILDREN(dev->sysctl_tree),
- OID_AUTO, "%pnpinfo", CTLFLAG_RD,
+ OID_AUTO, "%pnpinfo", CTLTYPE_STRING | CTLFLAG_RD,
dev, DEVICE_SYSCTL_PNPINFO, device_sysctl_handler, "A",
"device identification");
SYSCTL_ADD_PROC(&dev->sysctl_ctx, SYSCTL_CHILDREN(dev->sysctl_tree),
- OID_AUTO, "%parent", CTLFLAG_RD,
+ OID_AUTO, "%parent", CTLTYPE_STRING | CTLFLAG_RD,
dev, DEVICE_SYSCTL_PARENT, device_sysctl_handler, "A",
"parent device");
#endif /* __rtems__ */
@@ -605,7 +607,7 @@ devctl_queue_data_f(char *data, int flags)
p = devsoftc.async_proc;
if (p != NULL) {
PROC_LOCK(p);
- psignal(p, SIGIO);
+ kern_psignal(p, SIGIO);
PROC_UNLOCK(p);
}
return;
@@ -742,25 +744,7 @@ bad:
static void
devadded(device_t dev)
{
- char *pnp = NULL;
- char *tmp = NULL;
-
- pnp = malloc(1024, M_BUS, M_NOWAIT);
- if (pnp == NULL)
- goto fail;
- tmp = malloc(1024, M_BUS, M_NOWAIT);
- if (tmp == NULL)
- goto fail;
- *pnp = '\0';
- bus_child_pnpinfo_str(dev, pnp, 1024);
- snprintf(tmp, 1024, "%s %s", device_get_nameunit(dev), pnp);
- devaddq("+", tmp, dev);
-fail:
- if (pnp != NULL)
- free(pnp, M_BUS);
- if (tmp != NULL)
- free(tmp, M_BUS);
- return;
+ devaddq("+", device_get_nameunit(dev), dev);
}
/*
@@ -770,25 +754,7 @@ fail:
static void
devremoved(device_t dev)
{
- char *pnp = NULL;
- char *tmp = NULL;
-
- pnp = malloc(1024, M_BUS, M_NOWAIT);
- if (pnp == NULL)
- goto fail;
- tmp = malloc(1024, M_BUS, M_NOWAIT);
- if (tmp == NULL)
- goto fail;
- *pnp = '\0';
- bus_child_pnpinfo_str(dev, pnp, 1024);
- snprintf(tmp, 1024, "%s %s", device_get_nameunit(dev), pnp);
- devaddq("-", tmp, dev);
-fail:
- if (pnp != NULL)
- free(pnp, M_BUS);
- if (tmp != NULL)
- free(tmp, M_BUS);
- return;
+ devaddq("-", device_get_nameunit(dev), dev);
}
/*
@@ -796,7 +762,7 @@ fail:
* the first time that no match happens, so we don't keep getting this
* message. Should that prove to be undesirable, we can change it.
* This is called when all drivers that can attach to a given bus
- * decline to accept this device. Other errrors may not be detected.
+ * decline to accept this device. Other errors may not be detected.
*/
static void
devnomatch(device_t dev)
@@ -1110,7 +1076,7 @@ devclass_driver_added(devclass_t dc, driver_t *driver)
* @param dc the devclass to edit
* @param driver the driver to register
*/
-static int
+int
devclass_add_driver(devclass_t dc, driver_t *driver, int pass, devclass_t *dcp)
{
driverlink_t dl;
@@ -1243,7 +1209,7 @@ devclass_driver_deleted(devclass_t busclass, devclass_t dc, driver_t *driver)
* @param dc the devclass to edit
* @param driver the driver to unregister
*/
-static int
+int
devclass_delete_driver(devclass_t busclass, driver_t *driver)
{
devclass_t dc = devclass_find(driver->name);
@@ -1953,6 +1919,8 @@ device_delete_child(device_t dev, device_t child)
return (error);
if (child->devclass)
devclass_delete_device(child->devclass, child);
+ if (child->parent)
+ BUS_CHILD_DELETED(dev, child);
TAILQ_REMOVE(&dev->children, child, link);
TAILQ_REMOVE(&bus_data_devices, child, devlink);
kobj_delete((kobj_t) child, M_BUS);
@@ -2350,7 +2318,7 @@ device_get_desc(device_t dev)
/**
* @brief Return the device's flags
*/
-u_int32_t
+uint32_t
device_get_flags(device_t dev)
{
return (dev->devflags);
@@ -2466,7 +2434,7 @@ device_set_desc_copy(device_t dev, const char* desc)
* @brief Set the device's flags
*/
void
-device_set_flags(device_t dev, u_int32_t flags)
+device_set_flags(device_t dev, uint32_t flags)
{
dev->devflags = flags;
}
@@ -2502,6 +2470,35 @@ device_set_softc(device_t dev, void *softc)
}
/**
+ * @brief Free claimed softc
+ *
+ * Most drivers do not need to use this since the softc is freed
+ * automatically when the driver is detached.
+ */
+void
+device_free_softc(void *softc)
+{
+ free(softc, M_BUS_SC);
+}
+
+/**
+ * @brief Claim softc
+ *
+ * This function can be used to let the driver free the automatically
+ * allocated softc using "device_free_softc()". This function is
+ * useful when the driver is refcounting the softc and the softc
+ * cannot be freed when the "device_detach" method is called.
+ */
+void
+device_claim_softc(device_t dev)
+{
+ if (dev->softc)
+ dev->flags |= DF_EXTERNALSOFTC;
+ else
+ dev->flags &= ~DF_EXTERNALSOFTC;
+}
+
+/**
* @brief Get the device's ivars field
*
* The ivars field is used by the parent device to store per-device
@@ -2790,7 +2787,11 @@ device_probe_and_attach(device_t dev)
return (0);
else if (error != 0)
return (error);
- return (device_attach(dev));
+
+ CURVNET_SET_QUIET(vnet0);
+ error = device_attach(dev);
+ CURVNET_RESTORE();
+ return error;
}
/**
@@ -3061,6 +3062,7 @@ resource_list_add(struct resource_list *rl, int type, int rid,
rle->type = type;
rle->rid = rid;
rle->res = NULL;
+ rle->flags = 0;
}
if (rle->res)
@@ -3073,6 +3075,58 @@ resource_list_add(struct resource_list *rl, int type, int rid,
}
/**
+ * @brief Determine if a resource entry is busy.
+ *
+ * Returns true if a resource entry is busy meaning that it has an
+ * associated resource that is not an unallocated "reserved" resource.
+ *
+ * @param rl the resource list to search
+ * @param type the resource entry type (e.g. SYS_RES_MEMORY)
+ * @param rid the resource identifier
+ *
+ * @returns Non-zero if the entry is busy, zero otherwise.
+ */
+int
+resource_list_busy(struct resource_list *rl, int type, int rid)
+{
+ struct resource_list_entry *rle;
+
+ rle = resource_list_find(rl, type, rid);
+ if (rle == NULL || rle->res == NULL)
+ return (0);
+ if ((rle->flags & (RLE_RESERVED | RLE_ALLOCATED)) == RLE_RESERVED) {
+ KASSERT(!(rman_get_flags(rle->res) & RF_ACTIVE),
+ ("reserved resource is active"));
+ return (0);
+ }
+ return (1);
+}
+
+/**
+ * @brief Determine if a resource entry is reserved.
+ *
+ * Returns true if a resource entry is reserved meaning that it has an
+ * associated "reserved" resource. The resource can either be
+ * allocated or unallocated.
+ *
+ * @param rl the resource list to search
+ * @param type the resource entry type (e.g. SYS_RES_MEMORY)
+ * @param rid the resource identifier
+ *
+ * @returns Non-zero if the entry is reserved, zero otherwise.
+ */
+int
+resource_list_reserved(struct resource_list *rl, int type, int rid)
+{
+ struct resource_list_entry *rle;
+
+ rle = resource_list_find(rl, type, rid);
+ if (rle != NULL && rle->flags & RLE_RESERVED)
+ return (1);
+ return (0);
+}
+
+/**
* @brief Find a resource entry by type and rid.
*
* @param rl the resource list to search
@@ -3115,6 +3169,66 @@ resource_list_delete(struct resource_list *rl, int type, int rid)
}
/**
+ * @brief Allocate a reserved resource
+ *
+ * This can be used by busses to force the allocation of resources
+ * that are always active in the system even if they are not allocated
+ * by a driver (e.g. PCI BARs). This function is usually called when
+ * adding a new child to the bus. The resource is allocated from the
+ * parent bus when it is reserved. The resource list entry is marked
+ * with RLE_RESERVED to note that it is a reserved resource.
+ *
+ * Subsequent attempts to allocate the resource with
+ * resource_list_alloc() will succeed the first time and will set
+ * RLE_ALLOCATED to note that it has been allocated. When a reserved
+ * resource that has been allocated is released with
+ * resource_list_release() the resource RLE_ALLOCATED is cleared, but
+ * the actual resource remains allocated. The resource can be released to
+ * the parent bus by calling resource_list_unreserve().
+ *
+ * @param rl the resource list to allocate from
+ * @param bus the parent device of @p child
+ * @param child the device for which the resource is being reserved
+ * @param type the type of resource to allocate
+ * @param rid a pointer to the resource identifier
+ * @param start hint at the start of the resource range - pass
+ * @c 0UL for any start address
+ * @param end hint at the end of the resource range - pass
+ * @c ~0UL for any end address
+ * @param count hint at the size of range required - pass @c 1
+ * for any size
+ * @param flags any extra flags to control the resource
+ * allocation - see @c RF_XXX flags in
+ * <sys/rman.h> for details
+ *
+ * @returns the resource which was allocated or @c NULL if no
+ * resource could be allocated
+ */
+struct resource *
+resource_list_reserve(struct resource_list *rl, 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_entry *rle = NULL;
+ int passthrough = (device_get_parent(child) != bus);
+ struct resource *r;
+
+ if (passthrough)
+ panic(
+ "resource_list_reserve() should only be called for direct children");
+ if (flags & RF_ACTIVE)
+ panic(
+ "resource_list_reserve() should only reserve inactive resources");
+
+ r = resource_list_alloc(rl, bus, child, type, rid, start, end, count,
+ flags);
+ if (r != NULL) {
+ rle = resource_list_find(rl, type, *rid);
+ rle->flags |= RLE_RESERVED;
+ }
+ return (r);
+}
+
+/**
* @brief Helper function for implementing BUS_ALLOC_RESOURCE()
*
* Implement BUS_ALLOC_RESOURCE() by looking up a resource from the list
@@ -3165,8 +3279,19 @@ resource_list_alloc(struct resource_list *rl, device_t bus, device_t child,
if (!rle)
return (NULL); /* no resource of that type/rid */
- if (rle->res)
+ if (rle->res) {
+ if (rle->flags & RLE_RESERVED) {
+ if (rle->flags & RLE_ALLOCATED)
+ return (NULL);
+ if ((flags & RF_ACTIVE) &&
+ bus_activate_resource(child, type, *rid,
+ rle->res) != 0)
+ return (NULL);
+ rle->flags |= RLE_ALLOCATED;
+ return (rle->res);
+ }
panic("resource_list_alloc: resource entry is busy");
+ }
if (isdefault) {
start = rle->start;
@@ -3198,7 +3323,7 @@ resource_list_alloc(struct resource_list *rl, device_t bus, device_t child,
* @param rl the resource list which was allocated from
* @param bus the parent device of @p child
* @param child the device which is requesting a release
- * @param type the type of resource to allocate
+ * @param type the type of resource to release
* @param rid the resource identifier
* @param res the resource to release
*
@@ -3225,6 +3350,19 @@ resource_list_release(struct resource_list *rl, device_t bus, device_t child,
panic("resource_list_release: can't find resource");
if (!rle->res)
panic("resource_list_release: resource entry is not busy");
+ if (rle->flags & RLE_RESERVED) {
+ if (rle->flags & RLE_ALLOCATED) {
+ if (rman_get_flags(res) & RF_ACTIVE) {
+ error = bus_deactivate_resource(child, type,
+ rid, res);
+ if (error)
+ return (error);
+ }
+ rle->flags &= ~RLE_ALLOCATED;
+ return (0);
+ }
+ return (EINVAL);
+ }
error = BUS_RELEASE_RESOURCE(device_get_parent(bus), child,
type, rid, res);
@@ -3236,6 +3374,45 @@ resource_list_release(struct resource_list *rl, device_t bus, device_t child,
}
/**
+ * @brief Fully release a reserved resource
+ *
+ * Fully releases a resouce reserved via resource_list_reserve().
+ *
+ * @param rl the resource list which was allocated from
+ * @param bus the parent device of @p child
+ * @param child the device whose reserved resource is being released
+ * @param type the type of resource to release
+ * @param rid the resource identifier
+ * @param res the resource to release
+ *
+ * @retval 0 success
+ * @retval non-zero a standard unix error code indicating what
+ * error condition prevented the operation
+ */
+int
+resource_list_unreserve(struct resource_list *rl, device_t bus, device_t child,
+ int type, int rid)
+{
+ struct resource_list_entry *rle = NULL;
+ int passthrough = (device_get_parent(child) != bus);
+
+ if (passthrough)
+ panic(
+ "resource_list_unreserve() should only be called for direct children");
+
+ rle = resource_list_find(rl, type, rid);
+
+ if (!rle)
+ panic("resource_list_unreserve: can't find resource");
+ if (!(rle->flags & RLE_RESERVED))
+ return (EINVAL);
+ if (rle->flags & RLE_ALLOCATED)
+ return (EBUSY);
+ rle->flags &= ~RLE_RESERVED;
+ return (resource_list_release(rl, bus, child, type, rid, rle->res));
+}
+
+/**
* @brief Print a description of resources in a resource list
*
* Print all resources of a specified type, for use in BUS_PRINT_CHILD().
@@ -3331,7 +3508,7 @@ bus_generic_probe(device_t dev)
* on early-pass busses during BUS_NEW_PASS().
*/
if (dl->pass > bus_current_pass)
- continue;
+ continue;
DEVICE_IDENTIFY(dl->driver, dev);
}
@@ -3864,6 +4041,10 @@ bus_generic_rl_release_resource(device_t dev, device_t child, int type,
{
struct resource_list * rl = NULL;
+ if (device_get_parent(child) != dev)
+ return (BUS_RELEASE_RESOURCE(device_get_parent(dev), child,
+ type, rid, r));
+
rl = BUS_GET_RESOURCE_LIST(dev, child);
if (!rl)
return (EINVAL);
@@ -3884,6 +4065,10 @@ bus_generic_rl_alloc_resource(device_t dev, device_t child, int type,
{
struct resource_list * rl = NULL;
+ if (device_get_parent(child) != dev)
+ return (BUS_ALLOC_RESOURCE(device_get_parent(dev), child,
+ type, rid, start, end, count, flags));
+
rl = BUS_GET_RESOURCE_LIST(dev, child);
if (!rl)
return (NULL);
@@ -4038,15 +4223,6 @@ bus_setup_intr(device_t dev, struct resource *r, int flags,
return (error);
if (handler != NULL && !(flags & INTR_MPSAFE))
device_printf(dev, "[GIANT-LOCKED]\n");
- if (bootverbose && (flags & INTR_MPSAFE))
- device_printf(dev, "[MPSAFE]\n");
- if (filter != NULL) {
- if (handler == NULL)
- device_printf(dev, "[FILTER]\n");
- else
- device_printf(dev, "[FILTER+ITHREAD]\n");
- } else
- device_printf(dev, "[ITHREAD]\n");
return (0);
}