aboutsummaryrefslogtreecommitdiff
path: root/sys/mips/broadcom
diff options
context:
space:
mode:
authorLandon J. Fuller <landonf@FreeBSD.org>2017-03-23 19:29:12 +0000
committerLandon J. Fuller <landonf@FreeBSD.org>2017-03-23 19:29:12 +0000
commit591e79bc762a4a95e1e3a537e06d37a3def91950 (patch)
tree02ce264bcedcd6537d6c450856fe7b5335f01e8c /sys/mips/broadcom
parent8f7eee5a63f1d5a1844fb1b08cf295b309cd0ccf (diff)
downloadsrc-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.c51
-rw-r--r--sys/mips/broadcom/bcm_machdep.h9
-rw-r--r--sys/mips/broadcom/bcm_nvram_cfe.c158
-rw-r--r--sys/mips/broadcom/bcm_nvram_cfevar.h20
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;