diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2013-11-06 16:20:21 +0100 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2013-11-11 10:08:08 +0100 |
commit | 66659ff1ad6831b0ea7425fa6ecd8a8687523658 (patch) | |
tree | 48e22b475fa8854128e0861a33fed6f78c8094b5 /freebsd/sys/kern/subr_bus.c | |
parent | Define __GLOBL1() and __GLOBL() (diff) | |
download | rtems-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.c | 304 |
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); } |