From owner-svn-src-all@freebsd.org Tue Aug 16 21:32:07 2016 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 4DD6FBBC18A; Tue, 16 Aug 2016 21:32:07 +0000 (UTC) (envelope-from landonf@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id E6FB71E65; Tue, 16 Aug 2016 21:32:06 +0000 (UTC) (envelope-from landonf@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id u7GLW6kB083497; Tue, 16 Aug 2016 21:32:06 GMT (envelope-from landonf@FreeBSD.org) Received: (from landonf@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id u7GLW5Q2083485; Tue, 16 Aug 2016 21:32:05 GMT (envelope-from landonf@FreeBSD.org) Message-Id: <201608162132.u7GLW5Q2083485@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: landonf set sender to landonf@FreeBSD.org using -f From: "Landon J. Fuller" Date: Tue, 16 Aug 2016 21:32:05 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r304243 - in head/sys: conf dev/bhnd dev/bhnd/cores/chipc dev/bhnd/nvram dev/bhnd/tools dev/bwn mips/conf modules/bhnd X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.22 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 16 Aug 2016 21:32:07 -0000 Author: landonf Date: Tue Aug 16 21:32:05 2016 New Revision: 304243 URL: https://svnweb.freebsd.org/changeset/base/304243 Log: bhnd(4): Implement NVRAM support required for PMU bring-up. - Added a generic bhnd_nvram_parser API, with support for the TLV format used on WGT634U devices, the standard BCM NVRAM format used on most modern devices, and the "board text file" format used on some hardware to supply external NVRAM data at runtime (e.g. via an EFI variable). - Extended the bhnd_bus_if and bhnd_nvram_if interfaces to support both string-based and primitive data type variable access, required for common behavior across both SPROM and NVRAM data sources. - Extended the existing SPROM implementation to support the new string-based NVRAM APIs. - Added an abstract bhnd_nvram driver, implementing the bhnd_nvram_if atop the bhnd_nvram_parser API. - Added a CFE-based bhnd_nvram driver to provide read-only access to NVRAM data on MIPS SoCs, pending implementation of a flash-aware bhnd_nvram driver. Approved by: adrian (mentor) Differential Revision: https://reviews.freebsd.org/D7489 Added: head/sys/dev/bhnd/nvram/bhnd_nvram.c (contents, props changed) head/sys/dev/bhnd/nvram/bhnd_nvram_cfe.c (contents, props changed) head/sys/dev/bhnd/nvram/bhnd_nvram_common.c (contents, props changed) head/sys/dev/bhnd/nvram/bhnd_nvram_common.h - copied, changed from r304242, head/sys/dev/bhnd/nvram/nvramvar.h head/sys/dev/bhnd/nvram/bhnd_nvram_parser.c (contents, props changed) head/sys/dev/bhnd/nvram/bhnd_nvram_parser.h (contents, props changed) head/sys/dev/bhnd/nvram/bhnd_nvram_parserreg.h (contents, props changed) head/sys/dev/bhnd/nvram/bhnd_nvram_parservar.h (contents, props changed) head/sys/dev/bhnd/nvram/bhnd_nvramvar.h - copied, changed from r304242, head/sys/dev/bhnd/nvram/bhnd_spromreg.h head/sys/dev/bhnd/nvram/bhnd_sprom_parser.c - copied, changed from r304242, head/sys/dev/bhnd/nvram/bhnd_sprom_subr.c head/sys/dev/bhnd/nvram/bhnd_sprom_parser.h - copied, changed from r304242, head/sys/dev/bhnd/nvram/bhnd_spromvar.h head/sys/dev/bhnd/nvram/bhnd_sprom_parservar.h - copied, changed from r304242, head/sys/dev/bhnd/nvram/bhnd_spromreg.h Deleted: head/sys/dev/bhnd/nvram/bhnd_sprom_subr.c head/sys/dev/bhnd/nvram/bhnd_spromreg.h head/sys/dev/bhnd/nvram/nvram_subr.c head/sys/dev/bhnd/nvram/nvramvar.h Modified: head/sys/conf/files head/sys/dev/bhnd/bhnd.c head/sys/dev/bhnd/bhnd.h head/sys/dev/bhnd/bhnd_bus_if.m head/sys/dev/bhnd/bhnd_subr.c head/sys/dev/bhnd/bhnd_types.h head/sys/dev/bhnd/bhndvar.h head/sys/dev/bhnd/cores/chipc/chipc.c head/sys/dev/bhnd/nvram/bhnd_nvram.h head/sys/dev/bhnd/nvram/bhnd_nvram_if.m head/sys/dev/bhnd/nvram/bhnd_sprom.c head/sys/dev/bhnd/nvram/bhnd_spromvar.h head/sys/dev/bhnd/tools/nvram_map_gen.awk head/sys/dev/bwn/bwn_mac.c head/sys/mips/conf/BCM head/sys/mips/conf/BCM.hints head/sys/mips/conf/SENTRY5 head/sys/mips/conf/SENTRY5.hints head/sys/modules/bhnd/Makefile Modified: head/sys/conf/files ============================================================================== --- head/sys/conf/files Tue Aug 16 21:20:05 2016 (r304242) +++ head/sys/conf/files Tue Aug 16 21:32:05 2016 (r304243) @@ -1163,10 +1163,14 @@ dev/bhnd/cores/pci/bhnd_pcib.c optional dev/bhnd/cores/pcie2/bhnd_pcie2.c optional bhnd pci dev/bhnd/cores/pcie2/bhnd_pcie2_hostb.c optional bhndb bhnd pci dev/bhnd/cores/pcie2/bhnd_pcie2b.c optional bhnd_pcie2b bhnd pci +dev/bhnd/nvram/bhnd_nvram.c optional bhnd +dev/bhnd/nvram/bhnd_nvram_common.c optional bhnd +dev/bhnd/nvram/bhnd_nvram_cfe.c optional bhnd siba_nexus cfe | \ + bhnd bcma_nexus cfe dev/bhnd/nvram/bhnd_nvram_if.m optional bhnd +dev/bhnd/nvram/bhnd_nvram_parser.c optional bhnd dev/bhnd/nvram/bhnd_sprom.c optional bhnd -dev/bhnd/nvram/bhnd_sprom_subr.c optional bhnd -dev/bhnd/nvram/nvram_subr.c optional bhnd +dev/bhnd/nvram/bhnd_sprom_parser.c optional bhnd dev/bhnd/siba/siba.c optional siba bhnd dev/bhnd/siba/siba_bhndb.c optional siba bhnd bhndb dev/bhnd/siba/siba_nexus.c optional siba_nexus siba bhnd Modified: head/sys/dev/bhnd/bhnd.c ============================================================================== --- head/sys/dev/bhnd/bhnd.c Tue Aug 16 21:20:05 2016 (r304242) +++ head/sys/dev/bhnd/bhnd.c Tue Aug 16 21:32:05 2016 (r304243) @@ -361,7 +361,7 @@ bhnd_finish_attach(struct bhnd_softc *sc 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", + "warning: NVRAM %s device not found\n", bhnd_nvram_src_name(ccaps->nvram_src)); } } @@ -459,6 +459,11 @@ bhnd_find_platform_dev(struct bhnd_softc } child = device_find_child(chipc, classname, -1); + if (child != NULL) + goto found; + + /* Look for a parent-attached device (e.g. nexus0 -> bhnd_nvram) */ + child = device_find_child(device_get_parent(sc->dev), classname, -1); if (child == NULL) return (NULL); @@ -651,7 +656,7 @@ bhnd_generic_is_region_valid(device_t de */ int bhnd_generic_get_nvram_var(device_t dev, device_t child, const char *name, - void *buf, size_t *size) + void *buf, size_t *size, bhnd_nvram_type type) { struct bhnd_softc *sc; device_t nvram, parent; @@ -660,14 +665,14 @@ bhnd_generic_get_nvram_var(device_t 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); + return BHND_NVRAM_GETVAR(nvram, name, buf, size, type); /* 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)); + name, buf, size, type)); } /** Modified: head/sys/dev/bhnd/bhnd.h ============================================================================== --- head/sys/dev/bhnd/bhnd.h Tue Aug 16 21:20:05 2016 (r304242) +++ head/sys/dev/bhnd/bhnd.h Tue Aug 16 21:32:05 2016 (r304243) @@ -321,6 +321,31 @@ void bhnd_set_custom_core_desc(devic const char *name); void bhnd_set_default_core_desc(device_t dev); +int bhnd_nvram_getvar_str(device_t dev, + const char *name, char *buf, size_t len, + size_t *rlen); + +int bhnd_nvram_getvar_uint(device_t dev, + const char *name, void *value, int width); +int bhnd_nvram_getvar_uint8(device_t dev, + const char *name, uint8_t *value); +int bhnd_nvram_getvar_uint16(device_t dev, + const char *name, uint16_t *value); +int bhnd_nvram_getvar_uint32(device_t dev, + const char *name, uint32_t *value); + +int bhnd_nvram_getvar_int(device_t dev, + const char *name, void *value, int width); +int bhnd_nvram_getvar_int8(device_t dev, + const char *name, int8_t *value); +int bhnd_nvram_getvar_int16(device_t dev, + const char *name, int16_t *value); +int bhnd_nvram_getvar_int32(device_t dev, + const char *name, int32_t *value); + +int bhnd_nvram_getvar_array(device_t dev, + const char *name, void *buf, size_t count, + bhnd_nvram_type type); bool bhnd_bus_generic_is_hw_disabled(device_t dev, device_t child); @@ -329,7 +354,8 @@ bool bhnd_bus_generic_is_region_vali u_int port, u_int region); int bhnd_bus_generic_get_nvram_var(device_t dev, device_t child, const char *name, - void *buf, size_t *size); + void *buf, size_t *size, + bhnd_nvram_type type); const struct bhnd_chipid *bhnd_bus_generic_get_chipid(device_t dev, device_t child); int bhnd_bus_generic_read_board_info(device_t dev, @@ -428,55 +454,36 @@ bhnd_read_board_info(device_t dev, struc } /** - * Determine an NVRAM variable's expected size. - * - * @param dev A bhnd bus child device. - * @param name The variable name. - * @param[out] len On success, the variable's size, in bytes. - * - * @retval 0 success - * @retval ENOENT The requested variable was not found. - * @retval ENODEV No valid NVRAM source could be found. - * @retval non-zero If reading @p name otherwise fails, a regular unix - * error code will be returned. - */ -static inline int -bhnd_nvram_getvarlen(device_t dev, const char *name, size_t *len) -{ - return (BHND_BUS_GET_NVRAM_VAR(device_get_parent(dev), dev, name, NULL, - len)); -} - -/** - * Read an NVRAM variable. - * - * @param dev A bhnd bus child device. - * @param name The NVRAM variable name. - * @param buf A buffer large enough to hold @p len bytes. On success, - * the requested value will be written to this buffer. - * @param len The required variable length. + * Read an NVRAM variable, coerced to the requested @p type. * + * @param dev A bhnd bus child device. + * @param name The NVRAM variable name. + * @param[out] buf A buffer large enough to hold @p len bytes. On + * success, the requested value will be written to + * this buffer. This argment may be NULL if + * the value is not desired. + * @param[in,out] len The maximum capacity of @p buf. On success, + * will be set to the actual size of the requested + * value. + * @param type The desired data representation to be written + * to @p buf. + * * @retval 0 success * @retval ENOENT The requested variable was not found. - * @retval EINVAL If @p len does not match the actual variable size. * @retval ENODEV No valid NVRAM source could be found. + * @retval ENOMEM If a buffer of @p size is too small to hold the + * requested value. + * @retval EOPNOTSUPP If the value cannot be coerced to @p type. + * @retval ERANGE If value coercion would overflow @p type. * @retval non-zero If reading @p name otherwise fails, a regular unix * error code will be returned. */ static inline int -bhnd_nvram_getvar(device_t dev, const char *name, void *buf, size_t len) +bhnd_nvram_getvar(device_t dev, const char *name, void *buf, size_t *len, + bhnd_nvram_type type) { - size_t var_len; - int error; - - if ((error = bhnd_nvram_getvarlen(dev, name, &var_len))) - return (error); - - if (len != var_len) - return (EINVAL); - return (BHND_BUS_GET_NVRAM_VAR(device_get_parent(dev), dev, name, buf, - &len)); + len, type)); } /** Modified: head/sys/dev/bhnd/bhnd_bus_if.m ============================================================================== --- head/sys/dev/bhnd/bhnd_bus_if.m Tue Aug 16 21:20:05 2016 (r304242) +++ head/sys/dev/bhnd/bhnd_bus_if.m Tue Aug 16 21:32:05 2016 (r304243) @@ -116,7 +116,7 @@ CODE { static int bhnd_bus_null_get_nvram_var(device_t dev, device_t child, - const char *name, void *buf, size_t *size) + const char *name, void *buf, size_t *size, bhnd_nvram_type type) { return (ENODEV); } @@ -492,12 +492,15 @@ METHOD int get_region_addr { * the value is not desired. * @param[in,out] size The capacity of @p buf. On success, will be set * to the actual size of the requested value. + * @param type The data type to be written to @p buf. * * @retval 0 success * @retval ENOENT The requested variable was not found. * @retval ENOMEM If @p buf is non-NULL and a buffer of @p size is too * small to hold the requested value. * @retval ENODEV No valid NVRAM source could be found. + * @retval EFTYPE If the @p name's data type cannot be coerced to @p type. + * @retval ERANGE If value coercion would overflow @p type. * @retval non-zero If reading @p name otherwise fails, a regular unix * error code will be returned. */ @@ -507,6 +510,7 @@ METHOD int get_nvram_var { const char *name; void *buf; size_t *size; + bhnd_nvram_type type; } DEFAULT bhnd_bus_null_get_nvram_var; Modified: head/sys/dev/bhnd/bhnd_subr.c ============================================================================== --- head/sys/dev/bhnd/bhnd_subr.c Tue Aug 16 21:20:05 2016 (r304242) +++ head/sys/dev/bhnd/bhnd_subr.c Tue Aug 16 21:32:05 2016 (r304243) @@ -30,7 +30,6 @@ #include __FBSDID("$FreeBSD$"); -#include #include #include #include @@ -881,6 +880,325 @@ cleanup: } /** + * Read an NVRAM variable's NUL-terminated string value. + * + * @param dev A bhnd bus child device. + * @param name The NVRAM variable name. + * @param[out] buf A buffer large enough to hold @p len bytes. On + * success, the NUL-terminated string value will be + * written to this buffer. This argment may be NULL if + * the value is not desired. + * @param len The maximum capacity of @p buf. + * @param[out] rlen On success, will be set to the actual size of + * the requested value (including NUL termination). This + * argment may be NULL if the size is not desired. + * + * @retval 0 success + * @retval ENOENT The requested variable was not found. + * @retval ENODEV No valid NVRAM source could be found. + * @retval ENOMEM If @p buf is non-NULL and a buffer of @p len is too + * small to hold the requested value. + * @retval EFTYPE If the variable data cannot be coerced to a valid + * string representation. + * @retval ERANGE If value coercion would overflow @p type. + * @retval non-zero If reading @p name otherwise fails, a regular unix + * error code will be returned. + */ +int +bhnd_nvram_getvar_str(device_t dev, const char *name, char *buf, size_t len, + size_t *rlen) +{ + size_t larg; + int error; + + larg = len; + error = bhnd_nvram_getvar(dev, name, buf, &larg, BHND_NVRAM_TYPE_CSTR); + if (rlen != NULL) + *rlen = larg; + + return (error); +} + +/** + * Read an NVRAM variable's unsigned integer value. + * + * @param dev A bhnd bus child device. + * @param name The NVRAM variable name. + * @param[out] value On success, the requested value will be written + * to this pointer. + * @param width The output integer type width (1, 2, or + * 4 bytes). + * + * @retval 0 success + * @retval ENOENT The requested variable was not found. + * @retval ENODEV No valid NVRAM source could be found. + * @retval EFTYPE If the variable data cannot be coerced to a + * a valid unsigned integer representation. + * @retval ERANGE If value coercion would overflow (or underflow) an + * unsigned representation of the given @p width. + * @retval non-zero If reading @p name otherwise fails, a regular unix + * error code will be returned. + */ +int +bhnd_nvram_getvar_uint(device_t dev, const char *name, void *value, int width) +{ + bhnd_nvram_type type; + size_t len; + + switch (width) { + case 1: + type = BHND_NVRAM_TYPE_UINT8; + break; + case 2: + type = BHND_NVRAM_TYPE_UINT16; + break; + case 4: + type = BHND_NVRAM_TYPE_UINT32; + break; + default: + device_printf(dev, "unsupported NVRAM integer width: %d\n", + width); + return (EINVAL); + } + + len = width; + return (bhnd_nvram_getvar(dev, name, value, &len, type)); +} + +/** + * Read an NVRAM variable's unsigned 8-bit integer value. + * + * @param dev A bhnd bus child device. + * @param name The NVRAM variable name. + * @param[out] value On success, the requested value will be written + * to this pointer. + * + * @retval 0 success + * @retval ENOENT The requested variable was not found. + * @retval ENODEV No valid NVRAM source could be found. + * @retval EFTYPE If the variable data cannot be coerced to a + * a valid unsigned integer representation. + * @retval ERANGE If value coercion would overflow (or underflow) uint8_t. + * @retval non-zero If reading @p name otherwise fails, a regular unix + * error code will be returned. + */ +int +bhnd_nvram_getvar_uint8(device_t dev, const char *name, uint8_t *value) +{ + return (bhnd_nvram_getvar_uint(dev, name, value, sizeof(*value))); +} + +/** + * Read an NVRAM variable's unsigned 16-bit integer value. + * + * @param dev A bhnd bus child device. + * @param name The NVRAM variable name. + * @param[out] value On success, the requested value will be written + * to this pointer. + * + * @retval 0 success + * @retval ENOENT The requested variable was not found. + * @retval ENODEV No valid NVRAM source could be found. + * @retval EFTYPE If the variable data cannot be coerced to a + * a valid unsigned integer representation. + * @retval ERANGE If value coercion would overflow (or underflow) + * uint16_t. + * @retval non-zero If reading @p name otherwise fails, a regular unix + * error code will be returned. + */ +int +bhnd_nvram_getvar_uint16(device_t dev, const char *name, uint16_t *value) +{ + return (bhnd_nvram_getvar_uint(dev, name, value, sizeof(*value))); +} + +/** + * Read an NVRAM variable's unsigned 32-bit integer value. + * + * @param dev A bhnd bus child device. + * @param name The NVRAM variable name. + * @param[out] value On success, the requested value will be written + * to this pointer. + * + * @retval 0 success + * @retval ENOENT The requested variable was not found. + * @retval ENODEV No valid NVRAM source could be found. + * @retval EFTYPE If the variable data cannot be coerced to a + * a valid unsigned integer representation. + * @retval ERANGE If value coercion would overflow (or underflow) + * uint32_t. + * @retval non-zero If reading @p name otherwise fails, a regular unix + * error code will be returned. + */ +int +bhnd_nvram_getvar_uint32(device_t dev, const char *name, uint32_t *value) +{ + return (bhnd_nvram_getvar_uint(dev, name, value, sizeof(*value))); +} + +/** + * Read an NVRAM variable's signed integer value. + * + * @param dev A bhnd bus child device. + * @param name The NVRAM variable name. + * @param[out] value On success, the requested value will be written + * to this pointer. + * @param width The output integer type width (1, 2, or + * 4 bytes). + * + * @retval 0 success + * @retval ENOENT The requested variable was not found. + * @retval ENODEV No valid NVRAM source could be found. + * @retval EFTYPE If the variable data cannot be coerced to a + * a valid integer representation. + * @retval ERANGE If value coercion would overflow (or underflow) an + * signed representation of the given @p width. + * @retval non-zero If reading @p name otherwise fails, a regular unix + * error code will be returned. + */ +int +bhnd_nvram_getvar_int(device_t dev, const char *name, void *value, int width) +{ + bhnd_nvram_type type; + size_t len; + + switch (width) { + case 1: + type = BHND_NVRAM_TYPE_INT8; + break; + case 2: + type = BHND_NVRAM_TYPE_INT16; + break; + case 4: + type = BHND_NVRAM_TYPE_INT32; + break; + default: + device_printf(dev, "unsupported NVRAM integer width: %d\n", + width); + return (EINVAL); + } + + len = width; + return (bhnd_nvram_getvar(dev, name, value, &len, type)); +} + +/** + * Read an NVRAM variable's signed 8-bit integer value. + * + * @param dev A bhnd bus child device. + * @param name The NVRAM variable name. + * @param[out] value On success, the requested value will be written + * to this pointer. + * + * @retval 0 success + * @retval ENOENT The requested variable was not found. + * @retval ENODEV No valid NVRAM source could be found. + * @retval EFTYPE If the variable data cannot be coerced to a + * a valid integer representation. + * @retval ERANGE If value coercion would overflow (or underflow) int8_t. + * @retval non-zero If reading @p name otherwise fails, a regular unix + * error code will be returned. + */ +int +bhnd_nvram_getvar_int8(device_t dev, const char *name, int8_t *value) +{ + return (bhnd_nvram_getvar_int(dev, name, value, sizeof(*value))); +} + +/** + * Read an NVRAM variable's signed 16-bit integer value. + * + * @param dev A bhnd bus child device. + * @param name The NVRAM variable name. + * @param[out] value On success, the requested value will be written + * to this pointer. + * + * @retval 0 success + * @retval ENOENT The requested variable was not found. + * @retval ENODEV No valid NVRAM source could be found. + * @retval EFTYPE If the variable data cannot be coerced to a + * a valid integer representation. + * @retval ERANGE If value coercion would overflow (or underflow) + * int16_t. + * @retval non-zero If reading @p name otherwise fails, a regular unix + * error code will be returned. + */ +int +bhnd_nvram_getvar_int16(device_t dev, const char *name, int16_t *value) +{ + return (bhnd_nvram_getvar_int(dev, name, value, sizeof(*value))); +} + +/** + * Read an NVRAM variable's signed 32-bit integer value. + * + * @param dev A bhnd bus child device. + * @param name The NVRAM variable name. + * @param[out] value On success, the requested value will be written + * to this pointer. + * + * @retval 0 success + * @retval ENOENT The requested variable was not found. + * @retval ENODEV No valid NVRAM source could be found. + * @retval EFTYPE If the variable data cannot be coerced to a + * a valid integer representation. + * @retval ERANGE If value coercion would overflow (or underflow) + * int32_t. + * @retval non-zero If reading @p name otherwise fails, a regular unix + * error code will be returned. + */ +int +bhnd_nvram_getvar_int32(device_t dev, const char *name, int32_t *value) +{ + return (bhnd_nvram_getvar_int(dev, name, value, sizeof(*value))); +} + + +/** + * Read an NVRAM variable's array value. + * + * @param dev A bhnd bus child device. + * @param name The NVRAM variable name. + * @param[out] buf A buffer large enough to hold @p size bytes. + * On success, the requested value will be written + * to this buffer. + * @param[in,out] size The required number of bytes to write to + * @p buf. + * @param type The desired array element data representation. + * + * @retval 0 success + * @retval ENOENT The requested variable was not found. + * @retval ENODEV No valid NVRAM source could be found. + * @retval ENXIO If less than @p size bytes are available. + * @retval ENOMEM If a buffer of @p size is too small to hold the + * requested value. + * @retval EFTYPE If the variable data cannot be coerced to a + * a valid instance of @p type. + * @retval ERANGE If value coercion would overflow (or underflow) a + * representation of @p type. + * @retval non-zero If reading @p name otherwise fails, a regular unix + * error code will be returned. + */ +int +bhnd_nvram_getvar_array(device_t dev, const char *name, void *buf, size_t size, + bhnd_nvram_type type) +{ + size_t nbytes; + int error; + + /* Attempt read */ + nbytes = size; + if ((error = bhnd_nvram_getvar(dev, name, buf, &nbytes, type))) + return (error); + + /* Verify that the expected number of bytes were fetched */ + if (nbytes < size) + return (ENXIO); + + return (0); +} + +/** * Using the bhnd(4) bus-level core information and a custom core name, * populate @p dev's device description. * @@ -953,7 +1271,8 @@ bhnd_bus_generic_get_chipid(device_t dev /* nvram board_info population macros for bhnd_bus_generic_read_board_info() */ #define BHND_GV(_dest, _name) \ - bhnd_nvram_getvar(child, BHND_NVAR_ ## _name, &_dest, sizeof(_dest)) + bhnd_nvram_getvar_uint(child, BHND_NVAR_ ## _name, &_dest, \ + sizeof(_dest)) #define REQ_BHND_GV(_dest, _name) do { \ if ((error = BHND_GV(_dest, _name))) { \ @@ -1017,7 +1336,7 @@ bhnd_bus_generic_read_board_info(device_ */ int bhnd_bus_generic_get_nvram_var(device_t dev, device_t child, const char *name, - void *buf, size_t *size) + void *buf, size_t *size, bhnd_nvram_type type) { device_t nvram; device_t parent; @@ -1027,14 +1346,14 @@ bhnd_bus_generic_get_nvram_var(device_t /* 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); + return BHND_NVRAM_GETVAR(nvram, name, buf, size, type); /* 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)); + name, buf, size, type)); } /** Modified: head/sys/dev/bhnd/bhnd_types.h ============================================================================== --- head/sys/dev/bhnd/bhnd_types.h Tue Aug 16 21:20:05 2016 (r304242) +++ head/sys/dev/bhnd/bhnd_types.h Tue Aug 16 21:32:05 2016 (r304243) @@ -34,6 +34,8 @@ #include +#include "nvram/bhnd_nvram.h" + /** bhnd(4) device classes. */ typedef enum { BHND_DEVCLASS_CC, /**< chipcommon i/o controller */ Modified: head/sys/dev/bhnd/bhndvar.h ============================================================================== --- head/sys/dev/bhnd/bhndvar.h Tue Aug 16 21:20:05 2016 (r304242) +++ head/sys/dev/bhnd/bhndvar.h Tue Aug 16 21:32:05 2016 (r304243) @@ -92,6 +92,6 @@ int bhnd_generic_resume_child(device_ int bhnd_generic_get_nvram_var(device_t dev, device_t child, const char *name, void *buf, - size_t *size); + size_t *size, bhnd_nvram_type type); #endif /* _BHND_BHNDVAR_H_ */ Modified: head/sys/dev/bhnd/cores/chipc/chipc.c ============================================================================== --- head/sys/dev/bhnd/cores/chipc/chipc.c Tue Aug 16 21:20:05 2016 (r304242) +++ head/sys/dev/bhnd/cores/chipc/chipc.c Tue Aug 16 21:32:05 2016 (r304243) @@ -369,19 +369,11 @@ chipc_find_nvram_src(struct chipc_softc { uint32_t otp_st, srom_ctrl; - /* Very early devices vend SPROM/OTP/CIS (if at all) via the - * host bridge interface instead of ChipCommon. */ - if (!CHIPC_QUIRK(sc, SUPPORTS_SPROM)) - return (BHND_NVRAM_SRC_UNKNOWN); - /* - * Later chipset revisions standardized the SPROM capability flags and - * register interfaces. - * * We check for hardware presence in order of precedence. For example, * SPROM is is always used in preference to internal OTP if found. */ - if (caps->sprom) { + if (CHIPC_QUIRK(sc, SUPPORTS_SPROM) && caps->sprom) { srom_ctrl = bhnd_bus_read_4(sc->core, CHIPC_SPROM_CTRL); if (srom_ctrl & CHIPC_SRC_PRESENT) return (BHND_NVRAM_SRC_SPROM); Added: head/sys/dev/bhnd/nvram/bhnd_nvram.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/dev/bhnd/nvram/bhnd_nvram.c Tue Aug 16 21:32:05 2016 (r304243) @@ -0,0 +1,189 @@ +/*- + * Copyright (c) 2016 Landon Fuller + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + */ + +#include +__FBSDID("$FreeBSD$"); + +/* + * BHND CFE NVRAM driver. + * + * Provides access to device NVRAM via CFE. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include + +#include "bhnd_nvram_if.h" + +#include "bhnd_nvramvar.h" + +/** + * Default bhnd_nvram driver implementation of DEVICE_PROBE(). + */ +int +bhnd_nvram_probe(device_t dev) +{ + device_set_desc(dev, "Broadcom NVRAM"); + + /* Refuse wildcard attachments */ + return (BUS_PROBE_NOWILDCARD); +} + +/** + * Call from subclass DEVICE_ATTACH() implementations to handle + * device attachment. + * + * @param dev BHND NVRAM device. + * @param data NVRAM data to be copied and parsed. No reference to data + * will be held after return. + * @param size Size of @p data, in bytes. + * @param fmt NVRAM format. + */ +int +bhnd_nvram_attach(device_t dev, void *data, size_t size, bhnd_nvram_format fmt) +{ + struct bhnd_nvram_softc *sc; + int error; + + sc = device_get_softc(dev); + sc->dev = dev; + + /* Initialize NVRAM parser */ + error = bhnd_nvram_parser_init(&sc->nvram, dev, data, size, fmt); + if (error) + return (error); + + /* Initialize mutex */ + BHND_NVRAM_LOCK_INIT(sc); + + return (0); +} + +/** + * Default bhnd_nvram driver implementation of DEVICE_RESUME(). + */ +int +bhnd_nvram_resume(device_t dev) +{ + return (0); +} + +/** + * Default bhnd_nvram driver implementation of DEVICE_SUSPEND(). + */ +int +bhnd_nvram_suspend(device_t dev) +{ + return (0); +} + +/** + * Default bhnd_nvram driver implementation of DEVICE_DETACH(). + */ +int +bhnd_nvram_detach(device_t dev) +{ + struct bhnd_nvram_softc *sc; + + sc = device_get_softc(dev); + + bhnd_nvram_parser_fini(&sc->nvram); + BHND_NVRAM_LOCK_DESTROY(sc); + + return (0); +} + +/** + * Default bhnd_nvram driver implementation of BHND_NVRAM_GETVAR(). + */ +static int +bhnd_nvram_getvar_method(device_t dev, const char *name, void *buf, size_t *len, + bhnd_nvram_type type) +{ + struct bhnd_nvram_softc *sc; + int error; + + sc = device_get_softc(dev); + + BHND_NVRAM_LOCK(sc); + error = bhnd_nvram_parser_getvar(&sc->nvram, name, buf, len, type); + BHND_NVRAM_UNLOCK(sc); + + return (error); +} + +/** + * Default bhnd_nvram driver implementation of BHND_NVRAM_SETVAR(). + */ +static int +bhnd_nvram_setvar_method(device_t dev, const char *name, const void *buf, + size_t len, bhnd_nvram_type type) +{ + struct bhnd_nvram_softc *sc; + int error; + + sc = device_get_softc(dev); + + BHND_NVRAM_LOCK(sc); + error = bhnd_nvram_parser_setvar(&sc->nvram, name, buf, len, type); + BHND_NVRAM_UNLOCK(sc); + + return (error); +} + +static device_method_t bhnd_nvram_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, bhnd_nvram_probe), + DEVMETHOD(device_resume, bhnd_nvram_resume), + DEVMETHOD(device_suspend, bhnd_nvram_suspend), + DEVMETHOD(device_detach, bhnd_nvram_detach), + + /* NVRAM interface */ + DEVMETHOD(bhnd_nvram_getvar, bhnd_nvram_getvar_method), + DEVMETHOD(bhnd_nvram_setvar, bhnd_nvram_setvar_method), + + DEVMETHOD_END +}; + +DEFINE_CLASS_0(bhnd_nvram, bhnd_nvram_driver, bhnd_nvram_methods, sizeof(struct bhnd_nvram_softc)); Modified: head/sys/dev/bhnd/nvram/bhnd_nvram.h ============================================================================== --- head/sys/dev/bhnd/nvram/bhnd_nvram.h Tue Aug 16 21:20:05 2016 (r304242) +++ head/sys/dev/bhnd/nvram/bhnd_nvram.h Tue Aug 16 21:32:05 2016 (r304243) @@ -67,4 +67,50 @@ typedef enum { */ } bhnd_nvram_src; +/** Supported NVRAM formats. */ +typedef enum { + BHND_NVRAM_FMT_BCM = 0, /**< Broadcom NUL-delimited key=value pairs */ + BHND_NVRAM_FMT_TLV = 1, /**< CFE TLV encoding, as used on WGT634U */ + BHND_NVRAM_FMT_BTXT = 2, /**< Broadcom board text file. This is used + to provide external NVRAM data for some + fullmac WiFi devices. */ + BHND_NVRAM_FMT_SPROM = 3, /**< SPROM/OTP-specific encoding used by + Broadcom network adapters */ + BHND_NVRAM_FMT_CIS = 4, /**< A mostly CIS-compatible encoding used + on some Broadcom network adapters */ + BHND_NVRAM_FMT_UNKNOWN = 5 /**< Unknown or unrecognized format */ +} bhnd_nvram_format; + + +/** bhnd_nvram_type bit flags */ +enum { + BHND_NVRAM_TF_SIGNED = (1<<7), +}; + +#define BHND_NVRAM_TYPE_ID_MASK 0xF +#define BHND_NVRAM_TYPE_FLAGS_MASK 0x70 + +#define BHND_NVRAM_TYPE_ID(_id, _flags) \ + (((_id) & BHND_NVRAM_TYPE_ID_MASK) | \ + ((_flags) & BHND_NVRAM_TYPE_FLAGS_MASK)) + +/** Supported NVRAM data types */ +typedef enum { + BHND_NVRAM_TYPE_UINT8 = BHND_NVRAM_TYPE_ID(0, 0), /**< unsigned 8-bit integer */ + BHND_NVRAM_TYPE_UINT16 = BHND_NVRAM_TYPE_ID(1, 0), /**< unsigned 16-bit integer */ + BHND_NVRAM_TYPE_UINT32 = BHND_NVRAM_TYPE_ID(2, 0), /**< unsigned 32-bit integer */ + BHND_NVRAM_TYPE_INT8 = BHND_NVRAM_TYPE_ID(4, BHND_NVRAM_TF_SIGNED), /**< signed 8-bit integer */ + BHND_NVRAM_TYPE_INT16 = BHND_NVRAM_TYPE_ID(5, BHND_NVRAM_TF_SIGNED), /**< signed 16-bit integer */ + BHND_NVRAM_TYPE_INT32 = BHND_NVRAM_TYPE_ID(6, BHND_NVRAM_TF_SIGNED), /**< signed 32-bit integer */ + BHND_NVRAM_TYPE_CHAR = BHND_NVRAM_TYPE_ID(7, BHND_NVRAM_TF_SIGNED), /**< ASCII character */ + BHND_NVRAM_TYPE_CSTR = BHND_NVRAM_TYPE_ID(8, 0), /**< NUL-terminated C string */ +} bhnd_nvram_type; + +#undef BHND_NVRAM_TYPE_ID_MASK +#undef BHND_NVRAM_TYPE_FLAGS_MASK +#undef BHND_NVRAM_TYPE_ID + +#define BHND_NVRAM_SIGNED_TYPE(_type) \ + (((_type) & BHND_NVRAM_TF_SIGNED) == BHND_NVRAM_TF_SIGNED) + #endif /* _BHND_NVRAM_BHND_NVRAM_H_ */ Added: head/sys/dev/bhnd/nvram/bhnd_nvram_cfe.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/dev/bhnd/nvram/bhnd_nvram_cfe.c Tue Aug 16 21:32:05 2016 (r304243) @@ -0,0 +1,373 @@ +/*- + * Copyright (c) 2016 Landon Fuller + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + */ + +#include +__FBSDID("$FreeBSD$"); + +/* + * BHND CFE NVRAM driver. + * + * Provides access to device NVRAM via CFE. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include + +#include "bhnd_nvram_if.h" + +#include "bhnd_nvramvar.h" + +static int nvram_open_cfedev(device_t dev, char *devname, int fd, + int64_t *offset, uint32_t *size, bhnd_nvram_format fmt); +static char *nvram_find_cfedev(device_t dev, int *fd, int64_t *offset, + uint32_t *size, bhnd_nvram_format *fmt); + +/** Known CFE NVRAM device names, in probe order. */ +static char *nvram_cfe_devs[] = { + "nflash0.nvram", /* NAND */ + "nflash1.nvram", + "flash0.nvram", + "flash1.nvram", +}; + +/** Supported CFE NVRAM formats, in probe order. */ +bhnd_nvram_format nvram_cfe_fmts[] = { + BHND_NVRAM_FMT_BCM, + BHND_NVRAM_FMT_TLV +}; + + +static int +bhnd_nvram_cfe_probe(device_t dev) +{ + char *devname; + bhnd_nvram_format fmt; + int64_t offset; + uint32_t size; + int error; + int fd; + + /* Defer to default driver implementation */ + if ((error = bhnd_nvram_probe(dev)) > 0) + return (error); + + /* Locate a usable CFE device */ + devname = nvram_find_cfedev(dev, &fd, &offset, &size, &fmt); + if (devname == NULL) + return (ENXIO); + cfe_close(fd); + + switch (fmt) { + case BHND_NVRAM_FMT_BCM: + device_set_desc(dev, "Broadcom NVRAM"); + break; + case BHND_NVRAM_FMT_TLV: + device_set_desc(dev, "Broadcom WGT634U NVRAM"); + break; + default: + device_printf(dev, "unknown NVRAM format: %d\n", fmt); + return (ENXIO); + } + + /* Refuse wildcard attachments */ *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***