summaryrefslogtreecommitdiff
path: root/sys/dev/ic
diff options
context:
space:
mode:
authorPatrick Wildt <patrick@cvs.openbsd.org>2021-02-26 00:07:42 +0000
committerPatrick Wildt <patrick@cvs.openbsd.org>2021-02-26 00:07:42 +0000
commit2ba53c3bbcff9c9a493fb35cbe267fe0f6d27ac3 (patch)
treec3b976d71efdf460385d147d7e9fbc96c46d916b /sys/dev/ic
parentec57b1d75264f428bf6a9494c1f08df330116e2f (diff)
Refactor bwfm(4) firmware loading. The PCIe backend will need to be able
to load the CLM blob like the SDIO backend already does. Additionally it is also helpful for the PCIe backend to try a file named after the device tree compatible. Thus refactor the SDIO code and make it available for both SDIO and PCIe.
Diffstat (limited to 'sys/dev/ic')
-rw-r--r--sys/dev/ic/bwfm.c119
-rw-r--r--sys/dev/ic/bwfmvar.h4
2 files changed, 121 insertions, 2 deletions
diff --git a/sys/dev/ic/bwfm.c b/sys/dev/ic/bwfm.c
index ff734bc92d3..f720281b09e 100644
--- a/sys/dev/ic/bwfm.c
+++ b/sys/dev/ic/bwfm.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: bwfm.c,v 1.82 2021/02/25 23:55:41 patrick Exp $ */
+/* $OpenBSD: bwfm.c,v 1.83 2021/02/26 00:07:41 patrick Exp $ */
/*
* Copyright (c) 2010-2016 Broadcom Corporation
* Copyright (c) 2016,2017 Patrick Wildt <patrick@blueri.se>
@@ -28,6 +28,11 @@
#include <sys/socket.h>
#include <sys/sockio.h>
+#if defined(__HAVE_FDT)
+#include <machine/fdt.h>
+#include <dev/ofw/openfirm.h>
+#endif
+
#if NBPFILTER > 0
#include <net/bpf.h>
#endif
@@ -2901,3 +2906,115 @@ out:
sc->sc_clm = NULL;
sc->sc_clmsize = 0;
}
+
+#if defined(__HAVE_FDT)
+const char *
+bwfm_sysname(void)
+{
+ static char sysfw[128];
+ int len;
+ char *p;
+
+ len = OF_getprop(OF_peer(0), "compatible", sysfw, sizeof(sysfw));
+ if (len > 0 && len < sizeof(sysfw)) {
+ sysfw[len] = '\0';
+ if ((p = strchr(sysfw, '/')) != NULL)
+ *p = '\0';
+ return sysfw;
+ }
+ return NULL;
+}
+#else
+const char *
+bwfm_sysname(void)
+{
+ return NULL;
+}
+#endif
+
+int
+bwfm_loadfirmware(struct bwfm_softc *sc, const char *chip, const char *bus,
+ u_char **ucode, size_t *size, u_char **nvram, size_t *nvsize, size_t *nvlen)
+{
+ const char *sysname = NULL;
+ char name[128];
+ int r;
+
+ *ucode = *nvram = NULL;
+ *size = *nvsize = *nvlen = 0;
+
+ sysname = bwfm_sysname();
+
+ if (sysname != NULL) {
+ r = snprintf(name, sizeof(name), "brcmfmac%s%s.%s.bin", chip,
+ bus, sysname);
+ if ((r > 0 && r < sizeof(name)) &&
+ loadfirmware(name, ucode, size) != 0)
+ *size = 0;
+ }
+ if (*size == 0) {
+ snprintf(name, sizeof(name), "brcmfmac%s%s.bin", chip, bus);
+ if (loadfirmware(name, ucode, size) != 0) {
+ printf("%s: failed loadfirmware of file %s\n",
+ DEVNAME(sc), name);
+ return 1;
+ }
+ }
+
+ /* .txt needs to be processed first */
+ if (sysname != NULL) {
+ r = snprintf(name, sizeof(name), "brcmfmac%s%s.%s.txt", chip,
+ bus, sysname);
+ if ((r > 0 && r < sizeof(name)) &&
+ loadfirmware(name, nvram, nvsize) == 0) {
+ if (bwfm_nvram_convert(*nvram, *nvsize, nvlen) != 0) {
+ printf("%s: failed to process file %s\n",
+ DEVNAME(sc), name);
+ free(*ucode, M_DEVBUF, *size);
+ free(*nvram, M_DEVBUF, *nvsize);
+ return 1;
+ }
+ }
+ }
+
+ if (*nvlen == 0) {
+ snprintf(name, sizeof(name), "brcmfmac%s%s.txt", chip, bus);
+ if (loadfirmware(name, nvram, nvsize) == 0) {
+ if (bwfm_nvram_convert(*nvram, *nvsize, nvlen) != 0) {
+ printf("%s: failed to process file %s\n",
+ DEVNAME(sc), name);
+ free(*ucode, M_DEVBUF, *size);
+ free(*nvram, M_DEVBUF, *nvsize);
+ return 1;
+ }
+ }
+ }
+
+ /* .nvram is the pre-processed version */
+ if (*nvlen == 0) {
+ snprintf(name, sizeof(name), "brcmfmac%s%s.nvram", chip, bus);
+ if (loadfirmware(name, nvram, nvsize) == 0)
+ *nvlen = *nvsize;
+ }
+
+ if (*nvlen == 0 && strcmp(bus, "-sdio") == 0) {
+ snprintf(name, sizeof(name), "brcmfmac%s%s.txt", chip, bus);
+ printf("%s: failed loadfirmware of file %s\n",
+ DEVNAME(sc), name);
+ free(*ucode, M_DEVBUF, *size);
+ return 1;
+ }
+
+ if (sysname != NULL) {
+ r = snprintf(name, sizeof(name), "brcmfmac%s%s.%s.clm_blob",
+ chip, bus, sysname);
+ if (r > 0 && r < sizeof(name))
+ loadfirmware(name, &sc->sc_clm, &sc->sc_clmsize);
+ }
+ if (sc->sc_clmsize == 0) {
+ snprintf(name, sizeof(name), "brcmfmac%s%s.clm_blob", chip, bus);
+ loadfirmware(name, &sc->sc_clm, &sc->sc_clmsize);
+ }
+
+ return 0;
+}
diff --git a/sys/dev/ic/bwfmvar.h b/sys/dev/ic/bwfmvar.h
index 3262f326483..2d143ae7a31 100644
--- a/sys/dev/ic/bwfmvar.h
+++ b/sys/dev/ic/bwfmvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: bwfmvar.h,v 1.22 2021/01/31 11:07:51 patrick Exp $ */
+/* $OpenBSD: bwfmvar.h,v 1.23 2021/02/26 00:07:41 patrick Exp $ */
/*
* Copyright (c) 2010-2016 Broadcom Corporation
* Copyright (c) 2016,2017 Patrick Wildt <patrick@blueri.se>
@@ -190,3 +190,5 @@ void bwfm_rx(struct bwfm_softc *, struct mbuf *, struct mbuf_list *);
void bwfm_do_async(struct bwfm_softc *, void (*)(struct bwfm_softc *, void *),
void *, int);
int bwfm_nvram_convert(u_char *, size_t, size_t *);
+int bwfm_loadfirmware(struct bwfm_softc *, const char *, const char *,
+ u_char **, size_t *, u_char **, size_t *, size_t *);