Date: Tue, 12 Jul 2016 02:16:49 +0000 (UTC) From: "Landon J. Fuller" <landonf@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r302604 - in head/sys/dev/bhnd: . bhndb Message-ID: <201607120216.u6C2GnIb091106@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: landonf Date: Tue Jul 12 02:16:48 2016 New Revision: 302604 URL: https://svnweb.freebsd.org/changeset/base/302604 Log: bhnd(4): Add bus pass-aware discovery of platform devices (PMU, NVRAM, ChipCommon, etc). This extends the existing handling of NVRAM core discovery to support locating additional devices that may be attached either directly as real cores, or indirectly via ChipCommon (e.g. bhnd_pmu). When attached as a SoC root bus (as opposed to a bridged WiFi device), the platform devices may not be attached until later bus passes, necessitating delayed discovery/initialization. Approved by: adrian (mentor) Differential Revision: https://reviews.freebsd.org/D6962 Modified: head/sys/dev/bhnd/bhnd.c head/sys/dev/bhnd/bhnd.h head/sys/dev/bhnd/bhnd_subr.c head/sys/dev/bhnd/bhndb/bhndb.c head/sys/dev/bhnd/bhndvar.h Modified: head/sys/dev/bhnd/bhnd.c ============================================================================== --- head/sys/dev/bhnd/bhnd.c Tue Jul 12 02:12:31 2016 (r302603) +++ head/sys/dev/bhnd/bhnd.c Tue Jul 12 02:16:48 2016 (r302604) @@ -58,11 +58,20 @@ __FBSDID("$FreeBSD$"); #include <sys/rman.h> #include <machine/resource.h> +#include <dev/bhnd/cores/chipc/chipcvar.h> + +#include "bhnd_chipc_if.h" +#include "bhnd_nvram_if.h" + #include "bhnd.h" #include "bhndvar.h" MALLOC_DEFINE(M_BHND, "bhnd", "bhnd bus data structures"); +/* Bus pass at which all bus-required children must be available, and + * attachment may be finalized. */ +#define BHND_FINISH_ATTACH_PASS BUS_PASS_DEFAULT + /** * bhnd_generic_probe_nomatch() reporting configuration. */ @@ -80,10 +89,22 @@ static const struct bhnd_nomatch { { BHND_MFGID_INVALID, BHND_COREID_INVALID, false } }; -static int compare_ascending_probe_order(const void *lhs, - const void *rhs); -static int compare_descending_probe_order(const void *lhs, - const void *rhs); + +static int bhnd_delete_children(struct bhnd_softc *sc); + +static int bhnd_finish_attach(struct bhnd_softc *sc); + +static device_t bhnd_find_chipc(struct bhnd_softc *sc); +static struct chipc_caps *bhnd_find_chipc_caps(struct bhnd_softc *sc); +static device_t bhnd_find_platform_dev(struct bhnd_softc *sc, + const char *classname); +static device_t bhnd_find_pmu(struct bhnd_softc *sc); +static device_t bhnd_find_nvram(struct bhnd_softc *sc); + +static int compare_ascending_probe_order(const void *lhs, + const void *rhs); +static int compare_descending_probe_order(const void *lhs, + const void *rhs); /** * Default bhnd(4) bus driver implementation of DEVICE_ATTACH(). @@ -94,44 +115,53 @@ static int compare_descending_probe_orde int bhnd_generic_attach(device_t dev) { - device_t *devs; - int ndevs; - int error; + struct bhnd_softc *sc; + device_t *devs; + int ndevs; + int error; if (device_is_attached(dev)) return (EBUSY); + sc = device_get_softc(dev); + sc->dev = dev; + if ((error = device_get_children(dev, &devs, &ndevs))) return (error); + /* Probe and attach all children */ qsort(devs, ndevs, sizeof(*devs), compare_ascending_probe_order); for (int i = 0; i < ndevs; i++) { device_t child = devs[i]; device_probe_and_attach(child); } + /* Try to finalize attachment */ + if (bus_current_pass >= BHND_FINISH_ATTACH_PASS) { + if ((error = bhnd_finish_attach(sc))) + goto cleanup; + } + +cleanup: free(devs, M_TEMP); - return (0); + + if (error) + bhnd_delete_children(sc); + + return (error); } /** - * Default bhnd(4) bus driver implementation of DEVICE_DETACH(). - * - * This implementation calls device_detach() for each of the device's - * children, in reverse bhnd probe order, terminating if any call to - * device_detach() fails. + * Detach and delete all children, in reverse of their attach order. */ -int -bhnd_generic_detach(device_t dev) +static int +bhnd_delete_children(struct bhnd_softc *sc) { - device_t *devs; - int ndevs; - int error; + device_t *devs; + int ndevs; + int error; - if (!device_is_attached(dev)) - return (EBUSY); - - if ((error = device_get_children(dev, &devs, &ndevs))) + if ((error = device_get_children(sc->dev, &devs, &ndevs))) return (error); /* Detach in the reverse of attach order */ @@ -140,7 +170,7 @@ bhnd_generic_detach(device_t dev) device_t child = devs[i]; /* Terminate on first error */ - if ((error = device_detach(child))) + if ((error = device_delete_child(sc->dev, child))) goto cleanup; } @@ -150,6 +180,25 @@ cleanup: } /** + * Default bhnd(4) bus driver implementation of DEVICE_DETACH(). + * + * This implementation calls device_detach() for each of the device's + * children, in reverse bhnd probe order, terminating if any call to + * device_detach() fails. + */ +int +bhnd_generic_detach(device_t dev) +{ + struct bhnd_softc *sc; + + if (!device_is_attached(dev)) + return (EBUSY); + + sc = device_get_softc(dev); + return (bhnd_delete_children(sc)); +} + +/** * Default bhnd(4) bus driver implementation of DEVICE_SHUTDOWN(). * * This implementation calls device_shutdown() for each of the device's @@ -262,6 +311,223 @@ cleanup: return (error); } +static void +bhnd_new_pass(device_t dev) +{ + struct bhnd_softc *sc; + int error; + + sc = device_get_softc(dev); + + /* Attach any permissible children */ + bus_generic_new_pass(dev); + + /* Finalize attachment */ + if (!sc->attach_done && bus_current_pass >= BHND_FINISH_ATTACH_PASS) { + if ((error = bhnd_finish_attach(sc))) { + panic("bhnd_finish_attach() failed: %d", error); + } + } +} + +/* + * Finish any pending bus attachment operations. + * + * When attached as a SoC bus (as opposed to a bridged WiFi device), our + * platform devices may not be attached until later bus passes, necessitating + * delayed initialization on our part. + */ +static int +bhnd_finish_attach(struct bhnd_softc *sc) +{ + struct chipc_caps *ccaps; + + GIANT_REQUIRED; /* newbus */ + + KASSERT(bus_current_pass >= BHND_FINISH_ATTACH_PASS, + ("bhnd_finish_attach() called in pass %d", bus_current_pass)); + + KASSERT(!sc->attach_done, ("duplicate call to bhnd_finish_attach()")); + + /* Locate chipc device */ + if ((sc->chipc_dev = bhnd_find_chipc(sc)) == NULL) { + device_printf(sc->dev, "error: ChipCommon device not found\n"); + return (ENXIO); + } + + ccaps = BHND_CHIPC_GET_CAPS(sc->chipc_dev); + + /* Look for NVRAM device */ + if (ccaps->nvram_src != BHND_NVRAM_SRC_UNKNOWN) { + if ((sc->nvram_dev = bhnd_find_nvram(sc)) == NULL) { + device_printf(sc->dev, + "warning: %s NVRAM device not found\n", + bhnd_nvram_src_name(ccaps->nvram_src)); + } + } + + /* Look for a PMU */ + if (ccaps->pmu) { + if ((sc->pmu_dev = bhnd_find_pmu(sc)) == NULL) { + device_printf(sc->dev, + "warning: PMU device not found\n"); + } + } + + /* Mark attach as completed */ + sc->attach_done = true; + + return (0); +} + +/* Locate the ChipCommon core. */ +static device_t +bhnd_find_chipc(struct bhnd_softc *sc) +{ + device_t chipc; + + /* Make sure we're holding Giant for newbus */ + GIANT_REQUIRED; + + /* chipc_dev is initialized during attachment */ + if (sc->attach_done) { + if ((chipc = sc->chipc_dev) == NULL) + return (NULL); + + goto found; + } + + /* Locate chipc core with a core unit of 0 */ + chipc = bhnd_find_child(sc->dev, BHND_DEVCLASS_CC, 0); + if (chipc == NULL) + return (NULL); + +found: + if (device_get_state(chipc) < DS_ATTACHING) { + device_printf(sc->dev, "chipc found, but did not attach\n"); + return (NULL); + } + + return (chipc); +} + +/* Locate the ChipCommon core and return the device capabilities */ +static struct chipc_caps * +bhnd_find_chipc_caps(struct bhnd_softc *sc) +{ + device_t chipc; + + if ((chipc = bhnd_find_chipc(sc)) == NULL) { + device_printf(sc->dev, + "chipc unavailable; cannot fetch capabilities\n"); + return (NULL); + } + + return (BHND_CHIPC_GET_CAPS(chipc)); +} + +/** + * Find an attached platform device on @p dev, searching first for cores + * matching @p classname, and if not found, searching the children of the first + * bhnd_chipc device on the bus. + * + * @param sc Driver state. + * @param chipc Attached ChipCommon device. + * @param classname Device class to search for. + * + * @retval device_t A matching device. + * @retval NULL If no matching device is found. + */ +static device_t +bhnd_find_platform_dev(struct bhnd_softc *sc, const char *classname) +{ + device_t chipc, child; + + /* Make sure we're holding Giant for newbus */ + GIANT_REQUIRED; + + /* Look for a directly-attached child */ + child = device_find_child(sc->dev, classname, -1); + if (child != NULL) + goto found; + + /* Look for the first matching ChipCommon child */ + if ((chipc = bhnd_find_chipc(sc)) == NULL) { + device_printf(sc->dev, + "chipc unavailable; cannot locate %s\n", classname); + return (NULL); + } + + child = device_find_child(chipc, classname, -1); + if (child == NULL) + return (NULL); + +found: + if (device_get_state(child) < DS_ATTACHING) + return (NULL); + + return (child); +} + +/* Locate the PMU device, if any */ +static device_t +bhnd_find_pmu(struct bhnd_softc *sc) +{ + struct chipc_caps *ccaps; + + /* Make sure we're holding Giant for newbus */ + GIANT_REQUIRED; + + /* pmu_dev is initialized during attachment */ + if (sc->attach_done) { + if (sc->pmu_dev == NULL) + return (NULL); + + if (device_get_state(sc->pmu_dev) < DS_ATTACHING) + return (NULL); + + return (sc->pmu_dev); + } + + if ((ccaps = bhnd_find_chipc_caps(sc)) == NULL) + return (NULL); + + if (!ccaps->pmu) + return (NULL); + + return (bhnd_find_platform_dev(sc, "bhnd_pmu")); +} + +/* Locate the NVRAM device, if any */ +static device_t +bhnd_find_nvram(struct bhnd_softc *sc) +{ + struct chipc_caps *ccaps; + + /* Make sure we're holding Giant for newbus */ + GIANT_REQUIRED; + + + /* nvram_dev is initialized during attachment */ + if (sc->attach_done) { + if (sc->nvram_dev == NULL) + return (NULL); + + if (device_get_state(sc->nvram_dev) < DS_ATTACHING) + return (NULL); + + return (sc->nvram_dev); + } + + if ((ccaps = bhnd_find_chipc_caps(sc)) == NULL) + return (NULL); + + if (ccaps->nvram_src == BHND_NVRAM_SRC_UNKNOWN) + return (NULL); + + return (bhnd_find_platform_dev(sc, "bhnd_nvram")); +} + /* * Ascending comparison of bhnd device's probe order. */ @@ -376,6 +642,35 @@ bhnd_generic_is_region_valid(device_t de } /** + * Default bhnd(4) bus driver implementation of BHND_BUS_GET_NVRAM_VAR(). + * + * This implementation searches @p dev for a usable NVRAM child device. + * + * If no usable child device is found on @p dev, the request is delegated to + * the BHND_BUS_GET_NVRAM_VAR() method on the parent of @p dev. + */ +int +bhnd_generic_get_nvram_var(device_t dev, device_t child, const char *name, + void *buf, size_t *size) +{ + struct bhnd_softc *sc; + device_t nvram, parent; + + sc = device_get_softc(dev); + + /* If a NVRAM device is available, consult it first */ + if ((nvram = bhnd_find_nvram(sc)) != NULL) + return BHND_NVRAM_GETVAR(nvram, name, buf, size); + + /* Otherwise, try to delegate to parent */ + if ((parent = device_get_parent(dev)) == NULL) + return (ENODEV); + + return (BHND_BUS_GET_NVRAM_VAR(device_get_parent(dev), child, + name, buf, size)); +} + +/** * Default bhnd(4) bus driver implementation of BUS_PRINT_CHILD(). * * This implementation requests the device's struct resource_list via @@ -538,6 +833,15 @@ bhnd_generic_child_deleted(device_t dev, /* Free device info */ if ((dinfo = device_get_ivars(child)) != NULL) BHND_BUS_FREE_DEVINFO(dev, dinfo); + + /* Clean up platform device references */ + if (sc->chipc_dev == child) { + sc->chipc_dev = NULL; + } else if (sc->nvram_dev == child) { + sc->nvram_dev = NULL; + } else if (sc->pmu_dev == child) { + sc->pmu_dev = NULL; + } } /** @@ -659,6 +963,7 @@ static device_method_t bhnd_methods[] = DEVMETHOD(device_resume, bhnd_generic_resume), /* Bus interface */ + DEVMETHOD(bus_new_pass, bhnd_new_pass), DEVMETHOD(bus_add_child, bhnd_generic_add_child), DEVMETHOD(bus_child_deleted, bhnd_generic_child_deleted), DEVMETHOD(bus_probe_nomatch, bhnd_generic_probe_nomatch), @@ -691,7 +996,7 @@ static device_method_t bhnd_methods[] = DEVMETHOD(bhnd_bus_get_probe_order, bhnd_generic_get_probe_order), DEVMETHOD(bhnd_bus_is_region_valid, bhnd_generic_is_region_valid), DEVMETHOD(bhnd_bus_is_hw_disabled, bhnd_bus_generic_is_hw_disabled), - DEVMETHOD(bhnd_bus_get_nvram_var, bhnd_bus_generic_get_nvram_var), + DEVMETHOD(bhnd_bus_get_nvram_var, bhnd_generic_get_nvram_var), /* BHND interface (bus I/O) */ DEVMETHOD(bhnd_bus_read_1, bhnd_read_1), Modified: head/sys/dev/bhnd/bhnd.h ============================================================================== --- head/sys/dev/bhnd/bhnd.h Tue Jul 12 02:12:31 2016 (r302603) +++ head/sys/dev/bhnd/bhnd.h Tue Jul 12 02:16:48 2016 (r302604) @@ -43,6 +43,8 @@ #include "bhnd_bus_if.h" #include "bhnd_match.h" +#include "nvram/bhnd_nvram.h" + extern devclass_t bhnd_devclass; extern devclass_t bhnd_hostb_devclass; extern devclass_t bhnd_nvram_devclass; @@ -242,6 +244,7 @@ struct bhnd_device { const char *bhnd_vendor_name(uint16_t vendor); const char *bhnd_port_type_name(bhnd_port_type port_type); +const char *bhnd_nvram_src_name(bhnd_nvram_src nvram_src); const char *bhnd_find_core_name(uint16_t vendor, uint16_t device); @@ -324,7 +327,7 @@ bool bhnd_bus_generic_is_hw_disabled bool bhnd_bus_generic_is_region_valid(device_t dev, device_t child, bhnd_port_type type, u_int port, u_int region); -int bhnd_bus_generic_read_nvram_var(device_t dev, +int bhnd_bus_generic_get_nvram_var(device_t dev, device_t child, const char *name, void *buf, size_t *size); const struct bhnd_chipid *bhnd_bus_generic_get_chipid(device_t dev, @@ -332,9 +335,6 @@ const struct bhnd_chipid *bhnd_bus_gener int bhnd_bus_generic_read_board_info(device_t dev, device_t child, struct bhnd_board_info *info); -int bhnd_bus_generic_get_nvram_var(device_t dev, - device_t child, const char *name, - void *buf, size_t *size); struct bhnd_resource *bhnd_bus_generic_alloc_resource (device_t dev, device_t child, int type, int *rid, rman_res_t start, rman_res_t end, Modified: head/sys/dev/bhnd/bhnd_subr.c ============================================================================== --- head/sys/dev/bhnd/bhnd_subr.c Tue Jul 12 02:12:31 2016 (r302603) +++ head/sys/dev/bhnd/bhnd_subr.c Tue Jul 12 02:16:48 2016 (r302604) @@ -51,8 +51,6 @@ __FBSDID("$FreeBSD$"); #include "bhndreg.h" #include "bhndvar.h" -static device_t find_nvram_child(device_t dev); - /* BHND core device description table. */ static const struct bhnd_core_desc { uint16_t vendor; @@ -198,6 +196,25 @@ bhnd_port_type_name(bhnd_port_type port_ } } +/** + * Return the name of an NVRAM source. + */ +const char * +bhnd_nvram_src_name(bhnd_nvram_src nvram_src) +{ + switch (nvram_src) { + case BHND_NVRAM_SRC_FLASH: + return ("flash"); + case BHND_NVRAM_SRC_OTP: + return ("OTP"); + case BHND_NVRAM_SRC_SPROM: + return ("SPROM"); + case BHND_NVRAM_SRC_UNKNOWN: + return ("none"); + default: + return ("unknown"); + } +} static const struct bhnd_core_desc * bhnd_find_core_desc(uint16_t vendor, uint16_t device) @@ -293,7 +310,7 @@ bhnd_get_core_info(device_t dev) { * * @param parent The bhnd-compatible bus to be searched. * @param class The device class to match on. - * @param unit The device unit number; specify -1 to return the first match + * @param unit The core unit number; specify -1 to return the first match * regardless of unit number. * * @retval device_t if a matching child device is found. @@ -990,47 +1007,10 @@ bhnd_bus_generic_read_board_info(device_ #undef BHND_GV_REQ #undef BHND_GV_OPT - -/** - * Find an NVRAM child device on @p dev, if any. - * - * @retval device_t An NVRAM device. - * @retval NULL If no NVRAM device is found. - */ -static device_t -find_nvram_child(device_t dev) -{ - device_t chipc, nvram; - - /* Look for a directly-attached NVRAM child */ - nvram = device_find_child(dev, "bhnd_nvram", 0); - if (nvram != NULL) - return (nvram); - - /* Remaining checks are only applicable when searching a bhnd(4) - * bus. */ - if (device_get_devclass(dev) != bhnd_devclass) - return (NULL); - - /* Look for a ChipCommon-attached NVRAM device */ - if ((chipc = bhnd_find_child(dev, BHND_DEVCLASS_CC, -1)) != NULL) { - nvram = device_find_child(chipc, "bhnd_nvram", 0); - if (nvram != NULL) - return (nvram); - } - - /* Not found */ - return (NULL); -} - /** * Helper function for implementing BHND_BUS_GET_NVRAM_VAR(). * - * This implementation searches @p dev for a usable NVRAM child device: - * - The first child device implementing the bhnd_nvram devclass is - * returned, otherwise - * - If @p dev is a bhnd(4) bus, a ChipCommon core that advertises an - * attached NVRAM source. + * This implementation searches @p dev for a usable NVRAM child device. * * If no usable child device is found on @p dev, the request is delegated to * the BHND_BUS_GET_NVRAM_VAR() method on the parent of @p dev. @@ -1042,8 +1022,11 @@ bhnd_bus_generic_get_nvram_var(device_t device_t nvram; device_t parent; - /* Try to find an NVRAM device applicable to @p child */ - if ((nvram = find_nvram_child(dev)) != NULL) + /* Make sure we're holding Giant for newbus */ + GIANT_REQUIRED; + + /* Look for a directly-attached NVRAM child */ + if ((nvram = device_find_child(dev, "bhnd_nvram", -1)) != NULL) return BHND_NVRAM_GETVAR(nvram, name, buf, size); /* Try to delegate to parent */ Modified: head/sys/dev/bhnd/bhndb/bhndb.c ============================================================================== --- head/sys/dev/bhnd/bhndb/bhndb.c Tue Jul 12 02:12:31 2016 (r302603) +++ head/sys/dev/bhnd/bhndb/bhndb.c Tue Jul 12 02:16:48 2016 (r302604) @@ -1121,7 +1121,11 @@ static int bhndb_release_resource(device_t dev, device_t child, int type, int rid, struct resource *r) { - int error; + struct resource_list_entry *rle; + bool passthrough; + int error; + + passthrough = (device_get_parent(child) != dev); /* Deactivate resources */ if (rman_get_flags(r) & RF_ACTIVE) { @@ -1133,6 +1137,14 @@ bhndb_release_resource(device_t dev, dev if ((error = rman_release_resource(r))) return (error); + if (!passthrough) { + /* Clean resource list entry */ + rle = resource_list_find(BUS_GET_RESOURCE_LIST(dev, child), + type, rid); + if (rle != NULL) + rle->res = NULL; + } + return (0); } Modified: head/sys/dev/bhnd/bhndvar.h ============================================================================== --- head/sys/dev/bhnd/bhndvar.h Tue Jul 12 02:12:31 2016 (r302603) +++ head/sys/dev/bhnd/bhndvar.h Tue Jul 12 02:16:48 2016 (r302604) @@ -56,8 +56,16 @@ struct bhnd_devinfo { * bhnd driver instance state. Must be first member of all subclass * softc structures. */ -struct bhnd_softc {}; +struct bhnd_softc { + device_t dev; /**< bus device */ + bool attach_done; /**< true if initialization of all + * platform devices has been + * completed */ + device_t chipc_dev; /**< bhnd_chipc device */ + device_t nvram_dev; /**< bhnd_nvram device, if any */ + device_t pmu_dev; /**< bhnd_pmu device, if any */ +}; int bhnd_generic_attach(device_t dev); int bhnd_generic_detach(device_t dev); @@ -82,4 +90,8 @@ int bhnd_generic_suspend_child(device int bhnd_generic_resume_child(device_t dev, device_t child); +int bhnd_generic_get_nvram_var(device_t dev, + device_t child, const char *name, void *buf, + size_t *size); + #endif /* _BHND_BHNDVAR_H_ */
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201607120216.u6C2GnIb091106>