diff options
author | Landon J. Fuller <landonf@FreeBSD.org> | 2017-03-23 19:29:12 +0000 |
---|---|---|
committer | Landon J. Fuller <landonf@FreeBSD.org> | 2017-03-23 19:29:12 +0000 |
commit | 591e79bc762a4a95e1e3a537e06d37a3def91950 (patch) | |
tree | 02ce264bcedcd6537d6c450856fe7b5335f01e8c /sys/mips/broadcom | |
parent | 8f7eee5a63f1d5a1844fb1b08cf295b309cd0ccf (diff) | |
download | src-591e79bc762a4a95e1e3a537e06d37a3def91950.tar.gz src-591e79bc762a4a95e1e3a537e06d37a3def91950.zip |
[mips/broadcom]: Early boot NVRAM support
Add support for early boot access to NVRAM variables, using a new
bhnd_nvram_data_getvar_direct() API to support zero-allocation direct
reading of NVRAM variables from a bhnd_nvram_io instance backed by the
CFE NVRAM device.
Approved by: adrian (mentor)
Differential Revision: https://reviews.freebsd.org/D9913
Notes
Notes:
svn path=/head/; revision=315866
Diffstat (limited to 'sys/mips/broadcom')
-rw-r--r-- | sys/mips/broadcom/bcm_machdep.c | 51 | ||||
-rw-r--r-- | sys/mips/broadcom/bcm_machdep.h | 9 | ||||
-rw-r--r-- | sys/mips/broadcom/bcm_nvram_cfe.c | 158 | ||||
-rw-r--r-- | sys/mips/broadcom/bcm_nvram_cfevar.h | 20 |
4 files changed, 137 insertions, 101 deletions
diff --git a/sys/mips/broadcom/bcm_machdep.c b/sys/mips/broadcom/bcm_machdep.c index 0d7177774847..51596db9d0b2 100644 --- a/sys/mips/broadcom/bcm_machdep.c +++ b/sys/mips/broadcom/bcm_machdep.c @@ -88,6 +88,7 @@ __FBSDID("$FreeBSD$"); #ifdef CFE #include <dev/cfe/cfe_api.h> +#include <dev/cfe/cfe_error.h> #endif #if 0 @@ -112,6 +113,10 @@ extern int *end; static struct bcm_platform bcm_platform_data; static bool bcm_platform_data_avail = false; +#ifdef CFE +static struct bcm_nvram_iocfe bcm_cfe_nvram; +#endif + static const struct bhnd_core_match bcm_chipc_cores[] = { { BHND_MATCH_CORE(BHND_MFGID_BCM, BHND_COREID_CC) }, { BHND_MATCH_CORE(BHND_MFGID_BCM, BHND_COREID_4706_CC) }, @@ -190,6 +195,40 @@ bcm_find_core(struct bcm_platform *bp, const struct bhnd_core_match *descs, } /** + * Read a variable directly from NVRAM, decoding as @p type. + * + * @param bp Platform state. + * @param name The raw name of the variable to be fetched, + * including any device path (/pci/1/1/varname) or + * alias prefix (0:varname). + * @param[out] buf 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 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 ENOMEM If @p buf is non-NULL and a buffer of @p len is too + * small to hold the requested value. + * @retval ENOENT If @p name is not found. + * @retval EFTYPE If the variable data cannot be coerced to @p type. + * @retval ERANGE If value coercion would overflow @p type. + * @retval non-zero If parsing NVRAM otherwise fails, a regular unix error + * code will be returned. + */ +int +bcm_get_nvram(struct bcm_platform *bp, const char *name, void *buf, size_t *len, + bhnd_nvram_type type) +{ + if (bp->nvram_io == NULL || bp->nvram_cls == NULL) + return (ENOENT); + + return (bhnd_nvram_data_getvar_direct(bp->nvram_cls, bp->nvram_io, name, + buf, len, type)); +} + +/** * Probe and attach a bhnd_erom parser instance for the bhnd bus. * * @param[out] erom_cls The probed EROM class. @@ -280,12 +319,20 @@ bcm_init_platform_data(struct bcm_platform *bp) bool aob, pmu; int error; +#ifdef CFE /* Fetch CFE console handle (if any). Must be initialized before * any calls to printf/early_putc. */ -#ifdef CFE if ((bp->cfe_console = cfe_getstdhandle(CFE_STDHANDLE_CONSOLE)) < 0) bp->cfe_console = -1; -#endif + + /* Probe CFE NVRAM sources */ + bp->nvram_io = &bcm_cfe_nvram.io; + error = bcm_nvram_find_cfedev(&bcm_cfe_nvram, &bp->nvram_cls); + if (error) { + bp->nvram_io = NULL; + bp->nvram_cls = NULL; + } +#endif /* CFE */ /* Probe and attach device table provider, populating our * chip identification */ diff --git a/sys/mips/broadcom/bcm_machdep.h b/sys/mips/broadcom/bcm_machdep.h index 84aed350874f..a20f40754c69 100644 --- a/sys/mips/broadcom/bcm_machdep.h +++ b/sys/mips/broadcom/bcm_machdep.h @@ -40,6 +40,8 @@ #include <dev/bhnd/cores/pmu/bhnd_pmuvar.h> +#include "bcm_nvram_cfevar.h" + extern const struct bhnd_pmu_io bcm_pmu_soc_io; struct bcm_platform { @@ -65,6 +67,9 @@ struct bcm_platform { bhnd_erom_t obj; } erom; + struct bhnd_nvram_io *nvram_io; /**< NVRAM I/O context, or NULL if unavailable */ + bhnd_nvram_data_class *nvram_cls; /**< NVRAM data class, or NULL if unavailable */ + #ifdef CFE int cfe_console; /**< Console handle, or -1 */ #endif @@ -79,6 +84,10 @@ uint64_t bcm_get_ilpfreq(struct bcm_platform *bp); u_int bcm_get_uart_rclk(struct bcm_platform *bp); +int bcm_get_nvram(struct bcm_platform *bp, + const char *name, void *outp, size_t *olen, + bhnd_nvram_type type); + #define BCM_ERR(fmt, ...) \ printf("%s: " fmt, __FUNCTION__, ##__VA_ARGS__) diff --git a/sys/mips/broadcom/bcm_nvram_cfe.c b/sys/mips/broadcom/bcm_nvram_cfe.c index 916b641d6486..7132a45ae38c 100644 --- a/sys/mips/broadcom/bcm_nvram_cfe.c +++ b/sys/mips/broadcom/bcm_nvram_cfe.c @@ -54,36 +54,18 @@ __FBSDID("$FreeBSD$"); #include <dev/cfe/cfe_error.h> #include <dev/cfe/cfe_ioctl.h> -#include <dev/bhnd/nvram/bhnd_nvram_iovar.h> - #include "bhnd_nvram_if.h" +#include "bcm_machdep.h" #include "bcm_nvram_cfevar.h" -/** - * CFE-backed bhnd_nvram_io implementation. - */ -struct bhnd_nvram_iocfe { - struct bhnd_nvram_io io; /**< common I/O instance state */ - - char *dname; /**< CFE device name (borrowed) */ - int fd; /**< CFE file descriptor */ - size_t offset; /**< base offset */ - size_t size; /**< device size */ - bool req_blk_erase; /**< flash blocks must be erased - before writing */ -}; - BHND_NVRAM_IOPS_DEFN(iocfe) #define IOCFE_LOG(_io, _fmt, ...) \ printf("%s/%s: " _fmt, __FUNCTION__, (_io)->dname, ##__VA_ARGS__) -static int bhnd_nvram_iocfe_new(struct bhnd_nvram_io **io, - char *dname); - -static struct bhnd_nvram_io *bhnd_nvram_find_cfedev(device_t dev, - char **dname, bhnd_nvram_data_class **cls); +static int bcm_nvram_iocfe_init(struct bcm_nvram_iocfe *iocfe, + char *dname); /** Known CFE NVRAM device names, in probe order. */ static char *nvram_cfe_devs[] = { @@ -99,31 +81,20 @@ static bhnd_nvram_data_class * const nvram_cfe_fmts[] = { &bhnd_nvram_tlv_class }; - static int bhnd_nvram_cfe_probe(device_t dev) { - struct bhnd_nvram_io *io; - bhnd_nvram_data_class *cls; - const char *cls_desc; - char *dname; - char *desc; - - /* Locate a usable CFE device */ - io = bhnd_nvram_find_cfedev(dev, &dname, &cls); - if (io == NULL) + struct bcm_platform *bp; + + /* Fetch platform NVRAM I/O context */ + bp = bcm_get_platform(); + if (bp->nvram_io == NULL) return (ENXIO); - bhnd_nvram_io_free(io); - - /* Format the device description */ - cls_desc = bhnd_nvram_data_class_desc(cls); - asprintf(&desc, M_DEVBUF, "%s CFE %s", cls_desc, dname); - if (desc != NULL) { - device_set_desc_copy(dev, desc); - free(desc, M_DEVBUF); - } else { - device_set_desc(dev, cls_desc); - } + + KASSERT(bp->nvram_cls != NULL, ("missing NVRAM class")); + + /* Set the device description */ + device_set_desc(dev, bhnd_nvram_data_class_desc(bp->nvram_cls)); /* Refuse wildcard attachments */ return (BUS_PROBE_NOWILDCARD); @@ -133,25 +104,19 @@ bhnd_nvram_cfe_probe(device_t dev) static int bhnd_nvram_cfe_attach(device_t dev) { + struct bcm_platform *bp; struct bhnd_nvram_cfe_softc *sc; - bhnd_nvram_data_class *cls; - struct bhnd_nvram_io *io; - char *dname; int error; + bp = bcm_get_platform(); + KASSERT(bp->nvram_io != NULL, ("missing NVRAM I/O context")); + KASSERT(bp->nvram_cls != NULL, ("missing NVRAM class")); + sc = device_get_softc(dev); sc->dev = dev; - /* Locate NVRAM device via CFE */ - io = bhnd_nvram_find_cfedev(dev, &dname, &cls); - if (io == NULL) { - device_printf(dev, "CFE NVRAM device not found\n"); - return (ENXIO); - } - - /* Initialize NVRAM store and free the I/O context */ - error = bhnd_nvram_store_parse_new(&sc->store, io, cls); - bhnd_nvram_io_free(io); + error = bhnd_nvram_store_parse_new(&sc->store, bp->nvram_io, + bp->nvram_cls); if (error) return (error); @@ -201,79 +166,79 @@ bhnd_nvram_cfe_setvar(device_t dev, const char *name, const void *buf, } /** - * Find, open, identify, and return an I/O context mapping our - * CFE NVRAM device. + * Find, open, identify, and initialize an I/O context mapping the CFE NVRAM + * device. * - * @param dev bhnd_nvram_cfe device. - * @param[out] dname On success, the CFE device name. + * @param[out] iocfe On success, an I/O context mapping the CFE NVRAM + * device. * @param[out] cls On success, the identified NVRAM data format * class. * - * @retval non-NULL success. the caller inherits ownership of the returned - * NVRAM I/O context. - * @retval NULL if no usable CFE NVRAM device could be found. + * @retval 0 success. the caller inherits ownership of @p iocfe. + * @retval non-zero if no usable CFE NVRAM device can be found, a standard + * unix error will be returned. */ -static struct bhnd_nvram_io * -bhnd_nvram_find_cfedev(device_t dev, char **dname, bhnd_nvram_data_class **cls) +int +bcm_nvram_find_cfedev(struct bcm_nvram_iocfe *iocfe, + bhnd_nvram_data_class **cls) { - struct bhnd_nvram_io *io; - int devinfo; - int error, result; + char *dname; + int devinfo; + int error, result; for (u_int i = 0; i < nitems(nvram_cfe_fmts); i++) { *cls = nvram_cfe_fmts[i]; for (u_int j = 0; j < nitems(nvram_cfe_devs); j++) { - *dname = nvram_cfe_devs[j]; + dname = nvram_cfe_devs[j]; /* Does the device exist? */ - if ((devinfo = cfe_getdevinfo(*dname)) < 0) { + if ((devinfo = cfe_getdevinfo(dname)) < 0) { if (devinfo != CFE_ERR_DEVNOTFOUND) { - device_printf(dev, "cfe_getdevinfo(%s) " - "failed: %d\n", *dname, devinfo); + BCM_ERR("cfe_getdevinfo(%s) failed: " + "%d\n", dname, devinfo); } continue; } /* Open for reading */ - if ((error = bhnd_nvram_iocfe_new(&io, *dname))) + if ((error = bcm_nvram_iocfe_init(iocfe, dname))) continue; /* Probe */ - result = bhnd_nvram_data_probe(*cls, io); + result = bhnd_nvram_data_probe(*cls, &iocfe->io); if (result <= 0) { /* Found a supporting NVRAM data class */ - return (io); + return (0); } /* Keep searching */ - bhnd_nvram_io_free(io); - io = NULL; + bhnd_nvram_io_free(&iocfe->io); } } - return (NULL); + return (ENODEV); } /** - * Allocate and return a new I/O context backed by a CFE device. + * Initialize a new CFE device-backed I/O context. * - * The caller is responsible for deallocating the returned I/O context via - * bhnd_nvram_io_free(). + * The caller is responsible for releasing all resources held by the returned + * I/O context via bhnd_nvram_io_free(). * - * @param[out] io On success, a valid I/O context for @p dname. - * @param dname The name of the CFE device to be opened for reading. + * @param[out] io On success, will be initialized as an I/O context for + * CFE device @p dname. + * @param dname The name of the CFE device to be opened for reading. * - * @retval 0 success. - * @retval non-zero if opening @p dname otherwise fails, a standard unix error - * will be returned. + * @retval 0 success. + * @retval non-zero if opening @p dname otherwise fails, a standard unix + * error will be returned. */ static int -bhnd_nvram_iocfe_new(struct bhnd_nvram_io **io, char *dname) +bcm_nvram_iocfe_init(struct bcm_nvram_iocfe *iocfe, char *dname) { - struct bhnd_nvram_iocfe *iocfe; nvram_info_t nvram_info; int cerr, devinfo, dtype, rlen; int64_t nv_offset; @@ -281,7 +246,6 @@ bhnd_nvram_iocfe_new(struct bhnd_nvram_io **io, char *dname) bool req_blk_erase; int error; - iocfe = malloc(sizeof(*iocfe), M_DEVBUF, M_WAITOK); iocfe->io.iops = &bhnd_nvram_iocfe_ops; iocfe->dname = dname; @@ -290,8 +254,7 @@ bhnd_nvram_iocfe_new(struct bhnd_nvram_io **io, char *dname) if (iocfe->fd <= 0) { IOCFE_LOG(iocfe, "cfe_open() failed: %d\n", iocfe->fd); - error = ENXIO; - goto failed; + return (ENXIO); } /* Try to fetch device info */ @@ -374,32 +337,29 @@ bhnd_nvram_iocfe_new(struct bhnd_nvram_io **io, char *dname) iocfe->size = nv_size; iocfe->req_blk_erase = req_blk_erase; - *io = &iocfe->io; return (CFE_OK); failed: if (iocfe->fd >= 0) cfe_close(iocfe->fd); - free(iocfe, M_DEVBUF); - - *io = NULL; return (error); } static void bhnd_nvram_iocfe_free(struct bhnd_nvram_io *io) { - struct bhnd_nvram_iocfe *iocfe = (struct bhnd_nvram_iocfe *)io; + struct bcm_nvram_iocfe *iocfe = (struct bcm_nvram_iocfe *)io; + /* CFE I/O instances are statically allocated; we do not need to free + * the instance itself */ cfe_close(iocfe->fd); - free(io, M_DEVBUF); } static size_t bhnd_nvram_iocfe_getsize(struct bhnd_nvram_io *io) { - struct bhnd_nvram_iocfe *iocfe = (struct bhnd_nvram_iocfe *)io; + struct bcm_nvram_iocfe *iocfe = (struct bcm_nvram_iocfe *)io; return (iocfe->size); } @@ -438,12 +398,12 @@ static int bhnd_nvram_iocfe_read(struct bhnd_nvram_io *io, size_t offset, void *buffer, size_t nbytes) { - struct bhnd_nvram_iocfe *iocfe; + struct bcm_nvram_iocfe *iocfe; size_t remain; int64_t cfe_offset; int nr, nreq; - iocfe = (struct bhnd_nvram_iocfe *)io; + iocfe = (struct bcm_nvram_iocfe *)io; /* Determine (and validate) the base CFE offset */ #if (SIZE_MAX > INT64_MAX) diff --git a/sys/mips/broadcom/bcm_nvram_cfevar.h b/sys/mips/broadcom/bcm_nvram_cfevar.h index 6044111d5ae2..dc082d586cec 100644 --- a/sys/mips/broadcom/bcm_nvram_cfevar.h +++ b/sys/mips/broadcom/bcm_nvram_cfevar.h @@ -36,8 +36,28 @@ #include <sys/bus.h> #include <dev/bhnd/nvram/bhnd_nvram.h> +#include <dev/bhnd/nvram/bhnd_nvram_iovar.h> #include <dev/bhnd/nvram/bhnd_nvram_store.h> +struct bcm_nvram_iocfe; + +int bcm_nvram_find_cfedev(struct bcm_nvram_iocfe *iocfe, + bhnd_nvram_data_class **cls); + +/** + * CFE-backed bhnd_nvram_io implementation. + */ +struct bcm_nvram_iocfe { + struct bhnd_nvram_io io; /**< common I/O instance state */ + + char *dname; /**< CFE device name (borrowed) */ + int fd; /**< CFE file descriptor */ + size_t offset; /**< base offset */ + size_t size; /**< device size */ + bool req_blk_erase; /**< flash blocks must be erased + before writing */ +}; + /** bhnd_nvram_cfe driver instance state. */ struct bhnd_nvram_cfe_softc { device_t dev; |