summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorpatrick <patrick@openbsd.org>2018-05-23 11:32:14 +0000
committerpatrick <patrick@openbsd.org>2018-05-23 11:32:14 +0000
commit972218f3e9850c5a45e4b92418d35040ce5cf68c (patch)
treeb89520b783485a370c3b64549446dd8d1b23c23a
parentSimplify the CVE-2017-5715 workaround code. Marvell backported SMSCCC 1.1 (diff)
downloadwireguard-openbsd-972218f3e9850c5a45e4b92418d35040ce5cf68c.tar.xz
wireguard-openbsd-972218f3e9850c5a45e4b92418d35040ce5cf68c.zip
Implement a separate initialization stage so that we can still use
and initialize bwfm(4) later in the case that the firmware was not available on bootup and was only later installed. ok stsp@
-rw-r--r--sys/dev/ic/bwfm.c112
-rw-r--r--sys/dev/ic/bwfmvar.h7
-rw-r--r--sys/dev/pci/if_bwfm_pci.c44
-rw-r--r--sys/dev/sdmmc/if_bwfm_sdio.c43
-rw-r--r--sys/dev/usb/if_bwfm_usb.c52
5 files changed, 167 insertions, 91 deletions
diff --git a/sys/dev/ic/bwfm.c b/sys/dev/ic/bwfm.c
index 718d904b4f1..63af1755fc7 100644
--- a/sys/dev/ic/bwfm.c
+++ b/sys/dev/ic/bwfm.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: bwfm.c,v 1.45 2018/05/17 06:53:45 patrick Exp $ */
+/* $OpenBSD: bwfm.c,v 1.46 2018/05/23 11:32:14 patrick Exp $ */
/*
* Copyright (c) 2010-2016 Broadcom Corporation
* Copyright (c) 2016,2017 Patrick Wildt <patrick@blueri.se>
@@ -169,24 +169,10 @@ bwfm_attach(struct bwfm_softc *sc)
{
struct ieee80211com *ic = &sc->sc_ic;
struct ifnet *ifp = &ic->ic_if;
- uint32_t bandlist[3], tmp;
- int i, j, nbands, nmode, vhtmode;
TAILQ_INIT(&sc->sc_bcdc_rxctlq);
TAILQ_INIT(&sc->sc_bcdc_txctlq);
- if (bwfm_fwvar_cmd_get_int(sc, BWFM_C_GET_VERSION, &tmp)) {
- printf("%s: could not read io type\n", DEVNAME(sc));
- return;
- } else
- sc->sc_io_type = tmp;
- if (bwfm_fwvar_var_get_data(sc, "cur_etheraddr", ic->ic_myaddr,
- sizeof(ic->ic_myaddr))) {
- printf("%s: could not read mac address\n", DEVNAME(sc));
- return;
- }
- printf("%s: address %s\n", DEVNAME(sc), ether_sprintf(ic->ic_myaddr));
-
/* Init host async commands ring. */
sc->sc_cmdq.cur = sc->sc_cmdq.next = sc->sc_cmdq.queued = 0;
sc->sc_taskq = taskq_create(DEVNAME(sc), 1, IPL_SOFTNET, 0);
@@ -204,6 +190,63 @@ bwfm_attach(struct bwfm_softc *sc)
IEEE80211_C_SCANALL | /* device scans all channels at once */
IEEE80211_C_SCANALLBAND; /* device scans all bands at once */
+ /* IBSS channel undefined for now. */
+ ic->ic_ibss_chan = &ic->ic_channels[0];
+
+ ifp->if_softc = sc;
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+ ifp->if_ioctl = bwfm_ioctl;
+ ifp->if_start = bwfm_start;
+ ifp->if_watchdog = bwfm_watchdog;
+ memcpy(ifp->if_xname, DEVNAME(sc), IFNAMSIZ);
+
+ if_attach(ifp);
+ ieee80211_ifattach(ifp);
+
+ sc->sc_newstate = ic->ic_newstate;
+ ic->ic_newstate = bwfm_newstate;
+ ic->ic_send_mgmt = bwfm_send_mgmt;
+ ic->ic_set_key = bwfm_set_key;
+ ic->ic_delete_key = bwfm_delete_key;
+
+ ieee80211_media_init(ifp, bwfm_media_change, ieee80211_media_status);
+}
+
+void
+bwfm_attachhook(struct device *self)
+{
+ struct bwfm_softc *sc = (struct bwfm_softc *)self;
+
+ if (sc->sc_bus_ops->bs_preinit != NULL &&
+ sc->sc_bus_ops->bs_preinit(sc))
+ return;
+ if (bwfm_preinit(sc))
+ return;
+ sc->sc_initialized = 1;
+}
+
+int
+bwfm_preinit(struct bwfm_softc *sc)
+{
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ifnet *ifp = &ic->ic_if;
+ int i, j, nbands, nmode, vhtmode;
+ uint32_t bandlist[3], tmp;
+
+ if (sc->sc_initialized)
+ return 0;
+
+ if (bwfm_fwvar_cmd_get_int(sc, BWFM_C_GET_VERSION, &tmp)) {
+ printf("%s: could not read io type\n", DEVNAME(sc));
+ return 1;
+ } else
+ sc->sc_io_type = tmp;
+ if (bwfm_fwvar_var_get_data(sc, "cur_etheraddr", ic->ic_myaddr,
+ sizeof(ic->ic_myaddr))) {
+ printf("%s: could not read mac address\n", DEVNAME(sc));
+ return 1;
+ }
+
if (bwfm_fwvar_var_get_int(sc, "nmode", &nmode))
nmode = 0;
if (bwfm_fwvar_var_get_int(sc, "vhtmode", &vhtmode))
@@ -211,7 +254,7 @@ bwfm_attach(struct bwfm_softc *sc)
if (bwfm_fwvar_cmd_get_data(sc, BWFM_C_GET_BANDLIST, bandlist,
sizeof(bandlist))) {
printf("%s: couldn't get supported band list\n", DEVNAME(sc));
- return;
+ return 1;
}
nbands = letoh32(bandlist[0]);
for (i = 1; i <= nbands && i < nitems(bandlist); i++) {
@@ -260,26 +303,15 @@ bwfm_attach(struct bwfm_softc *sc)
}
}
- /* IBSS channel undefined for now. */
- ic->ic_ibss_chan = &ic->ic_channels[0];
+ /* Configure channel information obtained from firmware. */
+ ieee80211_channel_init(ifp);
- ifp->if_softc = sc;
- ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
- ifp->if_ioctl = bwfm_ioctl;
- ifp->if_start = bwfm_start;
- ifp->if_watchdog = bwfm_watchdog;
- memcpy(ifp->if_xname, DEVNAME(sc), IFNAMSIZ);
-
- if_attach(ifp);
- ieee80211_ifattach(ifp);
-
- sc->sc_newstate = ic->ic_newstate;
- ic->ic_newstate = bwfm_newstate;
- ic->ic_send_mgmt = bwfm_send_mgmt;
- ic->ic_set_key = bwfm_set_key;
- ic->ic_delete_key = bwfm_delete_key;
+ /* Configure MAC address. */
+ if (if_setlladdr(ifp, ic->ic_myaddr))
+ printf("%s: could not set MAC address\n", DEVNAME(sc));
ieee80211_media_init(ifp, bwfm_media_change, ieee80211_media_status);
+ return 0;
}
int
@@ -341,8 +373,18 @@ bwfm_init(struct ifnet *ifp)
struct bwfm_join_pref_params join_pref[2];
int pm;
- if (sc->sc_bus_ops->bs_init)
- sc->sc_bus_ops->bs_init(sc);
+ if (!sc->sc_initialized) {
+ if (sc->sc_bus_ops->bs_preinit != NULL &&
+ sc->sc_bus_ops->bs_preinit(sc)) {
+ printf("%s: could not init bus\n", DEVNAME(sc));
+ return;
+ }
+ if (bwfm_preinit(sc)) {
+ printf("%s: could not init\n", DEVNAME(sc));
+ return;
+ }
+ sc->sc_initialized = 1;
+ }
if (bwfm_fwvar_var_set_int(sc, "mpc", 1)) {
printf("%s: could not set mpc\n", DEVNAME(sc));
diff --git a/sys/dev/ic/bwfmvar.h b/sys/dev/ic/bwfmvar.h
index e473c43b773..250aba20bc4 100644
--- a/sys/dev/ic/bwfmvar.h
+++ b/sys/dev/ic/bwfmvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: bwfmvar.h,v 1.13 2018/05/16 08:20:00 patrick Exp $ */
+/* $OpenBSD: bwfmvar.h,v 1.14 2018/05/23 11:32:14 patrick Exp $ */
/*
* Copyright (c) 2010-2016 Broadcom Corporation
* Copyright (c) 2016,2017 Patrick Wildt <patrick@blueri.se>
@@ -85,7 +85,7 @@ struct bwfm_chip {
};
struct bwfm_bus_ops {
- void (*bs_init)(struct bwfm_softc *);
+ int (*bs_preinit)(struct bwfm_softc *);
void (*bs_stop)(struct bwfm_softc *);
int (*bs_txcheck)(struct bwfm_softc *);
int (*bs_txdata)(struct bwfm_softc *, struct mbuf *);
@@ -159,6 +159,7 @@ struct bwfm_softc {
#define BWFM_IO_TYPE_D11N 1
#define BWFM_IO_TYPE_D11AC 2
+ int sc_initialized;
int sc_tx_timer;
int (*sc_newstate)(struct ieee80211com *,
@@ -173,6 +174,8 @@ struct bwfm_softc {
};
void bwfm_attach(struct bwfm_softc *);
+void bwfm_attachhook(struct device *);
+int bwfm_preinit(struct bwfm_softc *);
int bwfm_detach(struct bwfm_softc *, int);
int bwfm_chip_attach(struct bwfm_softc *);
int bwfm_chip_set_active(struct bwfm_softc *, uint32_t);
diff --git a/sys/dev/pci/if_bwfm_pci.c b/sys/dev/pci/if_bwfm_pci.c
index 96ef2c2e2df..2b5f918f030 100644
--- a/sys/dev/pci/if_bwfm_pci.c
+++ b/sys/dev/pci/if_bwfm_pci.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_bwfm_pci.c,v 1.20 2018/05/23 08:36:15 patrick Exp $ */
+/* $OpenBSD: if_bwfm_pci.c,v 1.21 2018/05/23 11:32:14 patrick Exp $ */
/*
* Copyright (c) 2010-2016 Broadcom Corporation
* Copyright (c) 2017 Patrick Wildt <patrick@blueri.se>
@@ -113,6 +113,8 @@ struct bwfm_pci_softc {
pcireg_t sc_id;
void *sc_ih;
+ int sc_initialized;
+
bus_space_tag_t sc_reg_iot;
bus_space_handle_t sc_reg_ioh;
bus_size_t sc_reg_ios;
@@ -185,7 +187,6 @@ struct bwfm_pci_dmamem {
#define BWFM_PCI_DMA_KVA(_bdm) ((void *)(_bdm)->bdm_kva)
int bwfm_pci_match(struct device *, void *, void *);
-void bwfm_pci_attachhook(struct device *);
void bwfm_pci_attach(struct device *, struct device *, void *);
int bwfm_pci_detach(struct device *, int);
@@ -257,6 +258,7 @@ void bwfm_pci_flowring_create(struct bwfm_pci_softc *,
void bwfm_pci_flowring_create_cb(struct bwfm_softc *, void *);
void bwfm_pci_flowring_delete(struct bwfm_pci_softc *, int);
+int bwfm_pci_preinit(struct bwfm_softc *);
void bwfm_pci_stop(struct bwfm_softc *);
int bwfm_pci_txcheck(struct bwfm_softc *);
int bwfm_pci_txdata(struct bwfm_softc *, struct mbuf *);
@@ -280,7 +282,7 @@ struct bwfm_buscore_ops bwfm_pci_buscore_ops = {
};
struct bwfm_bus_ops bwfm_pci_bus_ops = {
- .bs_init = NULL,
+ .bs_preinit = bwfm_pci_preinit,
.bs_stop = bwfm_pci_stop,
.bs_txcheck = bwfm_pci_txcheck,
.bs_txdata = bwfm_pci_txdata,
@@ -358,7 +360,10 @@ bwfm_pci_attach(struct device *parent, struct device *self, void *aux)
}
printf(": %s\n", intrstr);
- config_mountroot(self, bwfm_pci_attachhook);
+ sc->sc_sc.sc_bus_ops = &bwfm_pci_bus_ops;
+ sc->sc_sc.sc_proto_ops = &bwfm_pci_msgbuf_ops;
+ bwfm_attach(&sc->sc_sc);
+ config_mountroot(self, bwfm_attachhook);
return;
bar0:
@@ -367,11 +372,10 @@ bar1:
bus_space_unmap(sc->sc_tcm_iot, sc->sc_tcm_ioh, sc->sc_tcm_ios);
}
-void
-bwfm_pci_attachhook(struct device *self)
+int
+bwfm_pci_preinit(struct bwfm_softc *bwfm)
{
- struct bwfm_pci_softc *sc = (struct bwfm_pci_softc *)self;
- struct bwfm_softc *bwfm = (void *)sc;
+ struct bwfm_pci_softc *sc = (void *)bwfm;
struct bwfm_pci_ringinfo ringinfo;
const char *name = NULL;
u_char *ucode; size_t size;
@@ -380,10 +384,13 @@ bwfm_pci_attachhook(struct device *self)
uint32_t idx_offset, reg;
int i;
+ if (sc->sc_initialized)
+ return 0;
+
sc->sc_sc.sc_buscore_ops = &bwfm_pci_buscore_ops;
if (bwfm_chip_attach(&sc->sc_sc) != 0) {
printf("%s: cannot attach chip\n", DEVNAME(sc));
- return;
+ return 1;
}
bwfm_pci_select_core(sc, BWFM_AGENT_CORE_PCIE2);
@@ -408,13 +415,13 @@ bwfm_pci_attachhook(struct device *self)
default:
printf("%s: unknown firmware for chip %s\n",
DEVNAME(sc), bwfm->sc_chip.ch_name);
- return;
+ return 1;
}
if (loadfirmware(name, &ucode, &size) != 0) {
printf("%s: failed loadfirmware of file %s\n",
DEVNAME(sc), name);
- return;
+ return 1;
}
/* Retrieve RAM size from firmware. */
@@ -428,7 +435,7 @@ bwfm_pci_attachhook(struct device *self)
printf("%s: could not load microcode\n",
DEVNAME(sc));
free(ucode, M_DEVBUF, size);
- return;
+ return 1;
}
free(ucode, M_DEVBUF, size);
@@ -439,7 +446,7 @@ bwfm_pci_attachhook(struct device *self)
sc->sc_shared_version < BWFM_SHARED_INFO_MIN_VERSION) {
printf("%s: PCIe version %d unsupported\n",
DEVNAME(sc), sc->sc_shared_version);
- return;
+ return 1;
}
if (sc->sc_shared_flags & BWFM_SHARED_INFO_DMA_INDEX) {
@@ -510,7 +517,7 @@ bwfm_pci_attachhook(struct device *self)
/* XXX: Fallback to TCM? */
printf("%s: cannot allocate idx buf\n",
DEVNAME(sc));
- return;
+ return 1;
}
idx_offset = sc->sc_dma_idx_sz;
@@ -651,12 +658,8 @@ bwfm_pci_attachhook(struct device *self)
bwfm_pci_debug_console(sc);
#endif
- sc->sc_ioctl_poll = 1;
- sc->sc_sc.sc_bus_ops = &bwfm_pci_bus_ops;
- sc->sc_sc.sc_proto_ops = &bwfm_pci_msgbuf_ops;
- bwfm_attach(&sc->sc_sc);
- sc->sc_ioctl_poll = 0;
- return;
+ sc->sc_initialized = 1;
+ return 0;
cleanup:
if (sc->sc_ioctl_buf)
@@ -677,6 +680,7 @@ cleanup:
bwfm_pci_dmamem_free(sc, sc->sc_ctrl_submit.ring);
if (sc->sc_dma_idx_buf)
bwfm_pci_dmamem_free(sc, sc->sc_dma_idx_buf);
+ return 1;
}
int
diff --git a/sys/dev/sdmmc/if_bwfm_sdio.c b/sys/dev/sdmmc/if_bwfm_sdio.c
index 5334b087f1d..42752a9b776 100644
--- a/sys/dev/sdmmc/if_bwfm_sdio.c
+++ b/sys/dev/sdmmc/if_bwfm_sdio.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_bwfm_sdio.c,v 1.14 2018/05/23 09:08:18 patrick Exp $ */
+/* $OpenBSD: if_bwfm_sdio.c,v 1.15 2018/05/23 11:32:14 patrick Exp $ */
/*
* Copyright (c) 2010-2016 Broadcom Corporation
* Copyright (c) 2016,2017 Patrick Wildt <patrick@blueri.se>
@@ -79,6 +79,8 @@ struct bwfm_sdio_softc {
struct rwlock *sc_lock;
void *sc_ih;
+ int sc_initialized;
+
uint32_t sc_bar0;
int sc_clkstate;
int sc_alp_only;
@@ -101,7 +103,7 @@ struct bwfm_sdio_softc {
int bwfm_sdio_match(struct device *, void *, void *);
void bwfm_sdio_attach(struct device *, struct device *, void *);
-void bwfm_sdio_attachhook(struct device *);
+int bwfm_sdio_preinit(struct bwfm_softc *);
int bwfm_sdio_detach(struct device *, int);
int bwfm_sdio_intr(void *);
@@ -157,7 +159,7 @@ void bwfm_sdio_debug_console(struct bwfm_sdio_softc *);
#endif
struct bwfm_bus_ops bwfm_sdio_bus_ops = {
- .bs_init = NULL,
+ .bs_preinit = bwfm_sdio_preinit,
.bs_stop = NULL,
.bs_txcheck = bwfm_sdio_txcheck,
.bs_txdata = bwfm_sdio_txdata,
@@ -312,24 +314,29 @@ bwfm_sdio_attach(struct device *parent, struct device *self, void *aux)
bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR, 0);
sc->sc_clkstate = CLK_SDONLY;
- config_mountroot(self, bwfm_sdio_attachhook);
+ sc->sc_sc.sc_bus_ops = &bwfm_sdio_bus_ops;
+ sc->sc_sc.sc_proto_ops = &bwfm_proto_bcdc_ops;
+ bwfm_attach(&sc->sc_sc);
+ config_mountroot(self, bwfm_attachhook);
return;
err:
free(sc->sc_sf, M_DEVBUF, 0);
}
-void
-bwfm_sdio_attachhook(struct device *self)
+int
+bwfm_sdio_preinit(struct bwfm_softc *bwfm)
{
- struct bwfm_sdio_softc *sc = (struct bwfm_sdio_softc *)self;
- struct bwfm_softc *bwfm = (void *)sc;
+ struct bwfm_sdio_softc *sc = (void *)bwfm;
const char *name = NULL;
const char *nvname = NULL;
uint32_t clk, reg;
u_char *ucode, *nvram;
size_t size, nvlen;
+ if (sc->sc_initialized)
+ return 0;
+
rw_enter_write(sc->sc_lock);
switch (bwfm->sc_chip.ch_chip)
@@ -349,20 +356,20 @@ bwfm_sdio_attachhook(struct device *self)
default:
printf("%s: unknown firmware for chip %s\n",
DEVNAME(sc), bwfm->sc_chip.ch_name);
- return;
+ return 1;
}
if (loadfirmware(name, &ucode, &size) != 0) {
printf("%s: failed loadfirmware of file %s\n",
DEVNAME(sc), name);
- return;
+ return 1;
}
if (loadfirmware(nvname, &nvram, &nvlen) != 0) {
printf("%s: failed loadfirmware of file %s\n",
DEVNAME(sc), nvname);
free(ucode, M_DEVBUF, size);
- return;
+ return 1;
}
sc->sc_alp_only = 1;
@@ -372,7 +379,7 @@ bwfm_sdio_attachhook(struct device *self)
DEVNAME(sc));
free(ucode, M_DEVBUF, size);
free(nvram, M_DEVBUF, nvlen);
- return;
+ return 1;
}
sc->sc_alp_only = 0;
free(ucode, M_DEVBUF, size);
@@ -380,7 +387,7 @@ bwfm_sdio_attachhook(struct device *self)
bwfm_sdio_clkctl(sc, CLK_AVAIL, 0);
if (sc->sc_clkstate != CLK_AVAIL)
- return;
+ return 1;
clk = bwfm_sdio_read_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR);
bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR,
@@ -390,7 +397,7 @@ bwfm_sdio_attachhook(struct device *self)
SDPCM_PROT_VERSION << SDPCM_PROT_VERSION_SHIFT);
if (sdmmc_io_function_enable(sc->sc_sf[2]) != 0) {
printf("%s: cannot enable function 2\n", DEVNAME(sc));
- return;
+ return 1;
}
bwfm_sdio_dev_write(sc, SDPCMD_HOSTINTMASK,
@@ -411,20 +418,18 @@ bwfm_sdio_attachhook(struct device *self)
bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR, clk);
}
- /* if interrupt establish fails */
sc->sc_ih = sdmmc_intr_establish(bwfm->sc_dev.dv_parent,
bwfm_sdio_intr, sc, DEVNAME(sc));
if (sc->sc_ih == NULL) {
printf("%s: can't establish interrupt\n", DEVNAME(sc));
bwfm_sdio_clkctl(sc, CLK_NONE, 0);
- return;
+ return 1;
}
sdmmc_intr_enable(sc->sc_sf[1]);
rw_exit(sc->sc_lock);
- sc->sc_sc.sc_bus_ops = &bwfm_sdio_bus_ops;
- sc->sc_sc.sc_proto_ops = &bwfm_proto_bcdc_ops;
- bwfm_attach(&sc->sc_sc);
+ sc->sc_initialized = 1;
+ return 0;
}
int
diff --git a/sys/dev/usb/if_bwfm_usb.c b/sys/dev/usb/if_bwfm_usb.c
index 54c990daba0..202d34d492f 100644
--- a/sys/dev/usb/if_bwfm_usb.c
+++ b/sys/dev/usb/if_bwfm_usb.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_bwfm_usb.c,v 1.13 2018/05/16 13:14:23 patrick Exp $ */
+/* $OpenBSD: if_bwfm_usb.c,v 1.14 2018/05/23 11:32:14 patrick Exp $ */
/*
* Copyright (c) 2010-2016 Broadcom Corporation
* Copyright (c) 2016,2017 Patrick Wildt <patrick@blueri.se>
@@ -166,6 +166,8 @@ struct bwfm_usb_softc {
struct usbd_interface *sc_iface;
uint8_t sc_ifaceno;
+ int sc_initialized;
+
uint16_t sc_vendor;
uint16_t sc_product;
@@ -184,7 +186,6 @@ struct bwfm_usb_softc {
};
int bwfm_usb_match(struct device *, void *, void *);
-void bwfm_usb_attachhook(struct device *);
void bwfm_usb_attach(struct device *, struct device *, void *);
int bwfm_usb_detach(struct device *, int);
@@ -197,6 +198,7 @@ void bwfm_usb_free_rx_list(struct bwfm_usb_softc *);
int bwfm_usb_alloc_tx_list(struct bwfm_usb_softc *);
void bwfm_usb_free_tx_list(struct bwfm_usb_softc *);
+int bwfm_usb_preinit(struct bwfm_softc *);
int bwfm_usb_txcheck(struct bwfm_softc *);
int bwfm_usb_txdata(struct bwfm_softc *, struct mbuf *);
int bwfm_usb_txctl(struct bwfm_softc *);
@@ -207,7 +209,7 @@ void bwfm_usb_rxeof(struct usbd_xfer *, void *, usbd_status);
void bwfm_usb_txeof(struct usbd_xfer *, void *, usbd_status);
struct bwfm_bus_ops bwfm_usb_bus_ops = {
- .bs_init = NULL,
+ .bs_preinit = bwfm_usb_preinit,
.bs_stop = NULL,
.bs_txcheck = bwfm_usb_txcheck,
.bs_txdata = bwfm_usb_txdata,
@@ -285,13 +287,14 @@ bwfm_usb_attach(struct device *parent, struct device *self, void *aux)
return;
}
- config_mountroot(self, bwfm_usb_attachhook);
+ bwfm_attach(&sc->sc_sc);
+ config_mountroot(self, bwfm_attachhook);
}
-void
-bwfm_usb_attachhook(struct device *self)
+int
+bwfm_usb_preinit(struct bwfm_softc *bwfm)
{
- struct bwfm_usb_softc *sc = (struct bwfm_usb_softc *)self;
+ struct bwfm_usb_softc *sc = (void *)bwfm;
struct bwfm_usb_rx_data *data;
const char *name = NULL;
struct bootrom_id brom;
@@ -300,6 +303,9 @@ bwfm_usb_attachhook(struct device *self)
size_t size;
int i;
+ if (sc->sc_initialized)
+ return 0;
+
/* Read chip id and chip rev to check the firmware. */
memset(&brom, 0, sizeof(brom));
bwfm_usb_dl_cmd(sc, DL_GETVER, &brom, sizeof(brom));
@@ -312,14 +318,14 @@ bwfm_usb_attachhook(struct device *self)
if (error != 0) {
printf("%s: could not open rx pipe: %s\n",
DEVNAME(sc), usbd_errstr(error));
- return;
+ return 1;
}
error = usbd_open_pipe(sc->sc_iface, sc->sc_tx_no, USBD_EXCLUSIVE_USE,
&sc->sc_tx_pipeh);
if (error != 0) {
printf("%s: could not open tx pipe: %s\n",
DEVNAME(sc), usbd_errstr(error));
- return;
+ return 1;
}
/* Firmware not yet loaded? */
@@ -348,20 +354,20 @@ bwfm_usb_attachhook(struct device *self)
if (name == NULL) {
printf("%s: unknown firmware\n", DEVNAME(sc));
- return;
+ goto cleanup;
}
if (loadfirmware(name, &ucode, &size) != 0) {
printf("%s: failed loadfirmware of file %s\n",
DEVNAME(sc), name);
- return;
+ goto cleanup;
}
if (bwfm_usb_load_microcode(sc, ucode, size) != 0) {
printf("%s: could not load microcode\n",
DEVNAME(sc));
free(ucode, M_DEVBUF, size);
- return;
+ goto cleanup;
}
free(ucode, M_DEVBUF, size);
@@ -377,7 +383,7 @@ bwfm_usb_attachhook(struct device *self)
if (letoh32(brom.chip) != BRCMF_POSTBOOT_ID) {
printf("%s: firmware did not start up\n",
DEVNAME(sc));
- return;
+ goto cleanup;
}
sc->sc_chip = letoh32(brom.chip);
@@ -388,7 +394,7 @@ bwfm_usb_attachhook(struct device *self)
if (bwfm_usb_alloc_rx_list(sc) || bwfm_usb_alloc_tx_list(sc)) {
printf("%s: cannot allocate rx/tx lists\n", DEVNAME(sc));
- return;
+ goto cleanup;
}
for (i = 0; i < BWFM_RX_LIST_COUNT; i++) {
@@ -403,7 +409,23 @@ bwfm_usb_attachhook(struct device *self)
DEVNAME(sc), usbd_errstr(error));
}
- bwfm_attach(&sc->sc_sc);
+ sc->sc_initialized = 1;
+ return 0;
+
+cleanup:
+ if (sc->sc_rx_pipeh) {
+ usbd_abort_pipe(sc->sc_rx_pipeh);
+ usbd_close_pipe(sc->sc_rx_pipeh);
+ sc->sc_rx_pipeh = NULL;
+ }
+ if (sc->sc_tx_pipeh) {
+ usbd_abort_pipe(sc->sc_tx_pipeh);
+ usbd_close_pipe(sc->sc_tx_pipeh);
+ sc->sc_tx_pipeh = NULL;
+ }
+ bwfm_usb_free_rx_list(sc);
+ bwfm_usb_free_tx_list(sc);
+ return 1;
}
struct mbuf *