Module Name:    src
Committed By:   mlelstv
Date:           Mon Oct 28 06:37:52 UTC 2019

Modified Files:
        src/sys/dev/ic: bwfm.c bwfmreg.h bwfmvar.h
        src/sys/dev/sdmmc: if_bwfm_sdio.c

Log Message:
More code from OpenBSD
no need to splnet() when enqueing packets
explicit structure padding
make internal functions static

also prepare for GPIO interrupts.


To generate a diff of this commit:
cvs rdiff -u -r1.17 -r1.18 src/sys/dev/ic/bwfm.c
cvs rdiff -u -r1.5 -r1.6 src/sys/dev/ic/bwfmreg.h
cvs rdiff -u -r1.4 -r1.5 src/sys/dev/ic/bwfmvar.h
cvs rdiff -u -r1.8 -r1.9 src/sys/dev/sdmmc/if_bwfm_sdio.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/ic/bwfm.c
diff -u src/sys/dev/ic/bwfm.c:1.17 src/sys/dev/ic/bwfm.c:1.18
--- src/sys/dev/ic/bwfm.c:1.17	Thu Oct  3 14:42:20 2019
+++ src/sys/dev/ic/bwfm.c	Mon Oct 28 06:37:51 2019
@@ -1,4 +1,4 @@
-/* $NetBSD: bwfm.c,v 1.17 2019/10/03 14:42:20 jmcneill Exp $ */
+/* $NetBSD: bwfm.c,v 1.18 2019/10/28 06:37:51 mlelstv Exp $ */
 /* $OpenBSD: bwfm.c,v 1.5 2017/10/16 22:27:16 patrick Exp $ */
 /*
  * Copyright (c) 2010-2016 Broadcom Corporation
@@ -345,6 +345,7 @@ bwfm_init(struct ifnet *ifp)
 	struct ieee80211com *ic = &sc->sc_ic;
 	uint8_t evmask[BWFM_EVENT_MASK_LEN];
 	struct bwfm_join_pref_params join_pref[2];
+	int pm;
 
 	if (bwfm_fwvar_var_set_int(sc, "mpc", 1)) {
 		printf("%s: could not set mpc\n", DEVNAME(sc));
@@ -370,10 +371,31 @@ bwfm_init(struct ifnet *ifp)
 
 #define	ENABLE_EVENT(e)		evmask[(e) / 8] |= 1 << ((e) % 8)
 	/* Events used to drive the state machine */
-	ENABLE_EVENT(BWFM_E_ASSOC);
-	ENABLE_EVENT(BWFM_E_ESCAN_RESULT);
-	ENABLE_EVENT(BWFM_E_SET_SSID);
-	ENABLE_EVENT(BWFM_E_LINK);
+	switch (ic->ic_opmode) {
+	case IEEE80211_M_STA:
+		ENABLE_EVENT(BWFM_E_IF);
+		ENABLE_EVENT(BWFM_E_LINK);
+		ENABLE_EVENT(BWFM_E_AUTH);
+		ENABLE_EVENT(BWFM_E_ASSOC);
+		ENABLE_EVENT(BWFM_E_DEAUTH);
+		ENABLE_EVENT(BWFM_E_DISASSOC);
+		ENABLE_EVENT(BWFM_E_SET_SSID);
+		ENABLE_EVENT(BWFM_E_ESCAN_RESULT);
+		break;
+#ifndef IEEE80211_STA_ONLY
+	case IEEE80211_M_HOSTAP:
+		ENABLE_EVENT(BWFM_E_AUTH_IND);
+		ENABLE_EVENT(BWFM_E_ASSOC_IND);
+		ENABLE_EVENT(BWFM_E_REASSOC_IND);
+		ENABLE_EVENT(BWFM_E_DEAUTH_IND);
+		ENABLE_EVENT(BWFM_E_DISASSOC_IND);
+		ENABLE_EVENT(BWFM_E_ESCAN_RESULT);
+		ENABLE_EVENT(BWFM_E_ESCAN_RESULT);
+		break;
+#endif
+	default:
+		break;
+	}
 #undef	ENABLE_EVENT
 
 #ifdef BWFM_DEBUG
@@ -401,7 +423,16 @@ bwfm_init(struct ifnet *ifp)
 		return EIO;
 	}
 
-	if (bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_PM, 2)) {
+        /*
+         * Use CAM (constantly awake) when we are running as AP
+         * otherwise use fast power saving.
+         */
+	pm = BWFM_PM_FAST_PS;
+#ifndef IEEE80211_STA_ONLY
+	if (ic->ic_opmode == IEEE80211_M_HOSTAP)
+		pm = BWFM_PM_CAM;
+#endif
+	if (bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_PM, pm)) {
 		printf("%s: could not set power\n", DEVNAME(sc));
 		return EIO;
 	}
@@ -448,15 +479,25 @@ bwfm_stop(struct ifnet *ifp, int disable
 {
 	struct bwfm_softc *sc = ifp->if_softc;
 	struct ieee80211com *ic = &sc->sc_ic;
+	struct bwfm_join_params join;
 
 	sc->sc_tx_timer = 0;
 	ifp->if_timer = 0;
 	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
 
+	memset(&join, 0, sizeof(join));
+	bwfm_fwvar_cmd_set_data(sc, BWFM_C_SET_SSID, &join, sizeof(join));
 	bwfm_fwvar_cmd_set_int(sc, BWFM_C_DOWN, 1);
 	bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_PM, 0);
+	bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_AP, 0);
+	bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_INFRA, 0);
+	bwfm_fwvar_cmd_set_int(sc, BWFM_C_UP, 1);
+	bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_PM, BWFM_PM_FAST_PS);
 
 	ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
+
+	if (sc->sc_bus_ops->bs_stop)
+		sc->sc_bus_ops->bs_stop(sc);
 }
 
 void
@@ -606,7 +647,7 @@ bwfm_key_set_cb(struct bwfm_softc *sc, s
 	wsec_key.len = htole32(wk->wk_keylen);
 	memcpy(wsec_key.data, wk->wk_key, sizeof(wsec_key.data));
 	if (!ext_key)
-		wsec_key.flags = htole32(BWFM_PRIMARY_KEY);
+		wsec_key.flags = htole32(BWFM_WSEC_PRIMARY_KEY);
 
 	switch (wk->wk_cipher->ic_cipher) {
 	case IEEE80211_CIPHER_WEP:
@@ -670,7 +711,7 @@ bwfm_key_delete_cb(struct bwfm_softc *sc
 
 	memset(&wsec_key, 0, sizeof(wsec_key));
 	wsec_key.index = htole32(wk->wk_keyix);
-	wsec_key.flags = htole32(BWFM_PRIMARY_KEY);
+	wsec_key.flags = htole32(BWFM_WSEC_PRIMARY_KEY);
 
 	if (bwfm_fwvar_var_set_data(sc, "wsec_key", &wsec_key, sizeof(wsec_key)))
 		return;
@@ -1452,10 +1493,10 @@ bwfm_proto_bcdc_query_dcmd(struct bwfm_s
 {
 	struct bwfm_proto_bcdc_dcmd *dcmd;
 	size_t size = sizeof(dcmd->hdr) + *len;
-	static int reqid = 0;
+	int reqid;
 	int ret = 1;
 
-	reqid++;
+	reqid = sc->sc_bcdc_reqid++;
 
 	dcmd = kmem_zalloc(sizeof(*dcmd), KM_SLEEP);
 	if (*len > sizeof(dcmd->buf))
@@ -1512,10 +1553,9 @@ bwfm_proto_bcdc_set_dcmd(struct bwfm_sof
 {
 	struct bwfm_proto_bcdc_dcmd *dcmd;
 	size_t size = sizeof(dcmd->hdr) + len;
-	int reqid = 0;
-	int ret = 1;
+	int ret = 1, reqid;
 
-	reqid++;
+	reqid = sc->sc_bcdc_reqid++;
 
 	dcmd = kmem_zalloc(sizeof(*dcmd), KM_SLEEP);
 	if (len > sizeof(dcmd->buf))
@@ -1845,7 +1885,6 @@ bwfm_rx(struct bwfm_softc *sc, struct mb
 	struct ieee80211com *ic = &sc->sc_ic;
 	struct ifnet *ifp = ic->ic_ifp;
 	struct bwfm_event *e = mtod(m, struct bwfm_event *);
-	int s;
 
 	if (m->m_len >= sizeof(e->ehdr) &&
 	    ntohs(e->ehdr.ether_type) == BWFM_ETHERTYPE_LINK_CTL &&
@@ -1856,14 +1895,8 @@ bwfm_rx(struct bwfm_softc *sc, struct mb
 		return;
 	}
 
-	s = splnet();
-
-	//if ((ifp->if_flags & IFF_RUNNING) != 0) {
-		m_set_rcvif(m, ifp);
-		if_percpuq_enqueue(ifp->if_percpuq, m);
-	//}
-
-	splx(s);
+	m_set_rcvif(m, ifp);
+	if_percpuq_enqueue(ifp->if_percpuq, m);
 }
 
 void

Index: src/sys/dev/ic/bwfmreg.h
diff -u src/sys/dev/ic/bwfmreg.h:1.5 src/sys/dev/ic/bwfmreg.h:1.6
--- src/sys/dev/ic/bwfmreg.h:1.5	Thu Oct  3 14:42:20 2019
+++ src/sys/dev/ic/bwfmreg.h	Mon Oct 28 06:37:51 2019
@@ -1,4 +1,4 @@
-/* $NetBSD: bwfmreg.h,v 1.5 2019/10/03 14:42:20 jmcneill Exp $ */
+/* $NetBSD: bwfmreg.h,v 1.6 2019/10/28 06:37:51 mlelstv Exp $ */
 /* $OpenBSD: bwfmreg.h,v 1.16 2018/02/07 21:44:09 patrick Exp $ */
 /*
  * Copyright (c) 2010-2016 Broadcom Corporation
@@ -372,21 +372,26 @@ struct bwfm_bss_info {
 	uint16_t capability;
 	uint8_t ssid_len;
 	uint8_t ssid[BWFM_MAX_SSID_LEN];
+	uint8_t pad0;
 	uint32_t nrates;
 	uint8_t rates[16];
 	uint16_t chanspec;
 	uint16_t atim_window;
 	uint8_t dtim_period;
+	uint8_t pad1;
 	uint16_t rssi;
 	uint8_t phy_noise;
 	uint8_t n_cap;
+	uint16_t pad2;
 	uint32_t nbss_cap;
 	uint8_t ctl_ch;
+	uint8_t pad3[3];
 	uint32_t reserved32[1];
 	uint8_t flags;
 	uint8_t reserved[3];
 	uint8_t basic_mcs[BWFM_MCSSET_LEN];
 	uint16_t ie_offset;
+	uint16_t pad4;
 	uint32_t ie_length;
 	uint16_t snr;
 };
@@ -572,6 +577,7 @@ struct bwfm_escan_results {
 
 struct bwfm_assoc_params {
 	uint8_t bssid[ETHER_ADDR_LEN];
+	uint16_t pad;
 	uint32_t chanspec_num;
 	uint16_t chanspec_list[];
 };
@@ -599,6 +605,7 @@ struct bwfm_join_params {
 
 struct bwfm_join_scan_params {
 	uint8_t scan_type;
+	uint8_t pad[3];
 	uint32_t nprobes;
 	uint32_t active_time;
 	uint32_t passive_time;
@@ -633,15 +640,18 @@ struct bwfm_wsec_key {
 #define	BWFM_CRYPTO_ALGO_AES_RESERVED1	5
 #define	BWFM_CRYPTO_ALGO_AES_RESERVED2	6
 	uint32_t flags;
-#define	BWFM_PRIMARY_KEY		(1 << 1)
+#define	BWFM_WSEC_PRIMARY_KEY		(1 << 1)
+#define	BWFM_PRIMARY_KEY		BWFM_WSEC_PRIMARY_KEY
 	uint32_t pad_2[3];
 	uint32_t iv_initialized;
 	uint32_t pad_3;
+	/* Rx IV */
 	struct {
 		uint32_t hi;
 		uint16_t lo;
+		uint16_t pad_4;
 	} rxiv;
-	uint32_t pad_4[2];
+	uint32_t pad_5[2];
 	uint8_t ea[IEEE80211_ADDR_LEN];
 };
 
@@ -753,7 +763,7 @@ struct bwfm_ethhdr {
 #define	BWFM_BRCM_OUI			"\x00\x10\x18"
 	uint16_t usr_subtype;
 #define	BWFM_BRCM_SUBTYPE_EVENT		1
-};
+} __packed;
 
 struct bwfm_event_msg {
 	uint16_t version;
@@ -767,7 +777,7 @@ struct bwfm_event_msg {
 	char ifname[IFNAMSIZ];
 	uint8_t ifidx;
 	uint8_t bsscfgidx;
-};
+} __packed;
 
 struct bwfm_event {
 	struct ether_header ehdr;
@@ -775,4 +785,3 @@ struct bwfm_event {
 	struct bwfm_ethhdr hdr;
 	struct bwfm_event_msg msg;
 } __packed;
-

Index: src/sys/dev/ic/bwfmvar.h
diff -u src/sys/dev/ic/bwfmvar.h:1.4 src/sys/dev/ic/bwfmvar.h:1.5
--- src/sys/dev/ic/bwfmvar.h:1.4	Sun Sep  1 05:40:39 2019
+++ src/sys/dev/ic/bwfmvar.h	Mon Oct 28 06:37:51 2019
@@ -1,4 +1,4 @@
-/* $NetBSD: bwfmvar.h,v 1.4 2019/09/01 05:40:39 mlelstv Exp $ */
+/* $NetBSD: bwfmvar.h,v 1.5 2019/10/28 06:37:51 mlelstv Exp $ */
 /* $OpenBSD: bwfmvar.h,v 1.1 2017/10/11 17:19:50 patrick Exp $ */
 /*
  * Copyright (c) 2010-2016 Broadcom Corporation
@@ -169,6 +169,8 @@ struct bwfm_softc {
 
 	int			(*sc_newstate)(struct ieee80211com *,
 				    enum ieee80211_state, int);
+
+	int			 sc_bcdc_reqid;
 };
 
 void bwfm_attach(struct bwfm_softc *);

Index: src/sys/dev/sdmmc/if_bwfm_sdio.c
diff -u src/sys/dev/sdmmc/if_bwfm_sdio.c:1.8 src/sys/dev/sdmmc/if_bwfm_sdio.c:1.9
--- src/sys/dev/sdmmc/if_bwfm_sdio.c:1.8	Mon Oct 28 06:20:01 2019
+++ src/sys/dev/sdmmc/if_bwfm_sdio.c	Mon Oct 28 06:37:52 2019
@@ -1,4 +1,4 @@
-/* $NetBSD: if_bwfm_sdio.c,v 1.8 2019/10/28 06:20:01 mlelstv Exp $ */
+/* $NetBSD: if_bwfm_sdio.c,v 1.9 2019/10/28 06:37:52 mlelstv Exp $ */
 /* $OpenBSD: if_bwfm_sdio.c,v 1.1 2017/10/11 17:19:50 patrick Exp $ */
 /*
  * Copyright (c) 2010-2016 Broadcom Corporation
@@ -36,6 +36,9 @@
 
 #include <netinet/in.h>
 
+#include <dev/ofw/openfirm.h>
+#include <dev/fdt/fdtvar.h>
+
 #include <dev/firmload.h>
 
 #include <net80211/ieee80211_var.h>
@@ -80,6 +83,7 @@ struct bwfm_sdio_softc {
 	bool			sc_sr_enabled;
 	bool			sc_alp_only;
 	bool			sc_sleeping;
+	bool			sc_rxskip;
 
 	struct sdmmc_task	sc_task;
 	bool			sc_task_queued;
@@ -102,78 +106,86 @@ struct bwfm_sdio_softc {
 	char			*sc_console_buf;
 	size_t			sc_console_buf_size;
 	uint32_t		sc_console_readidx;
+
+	int			sc_phandle;
+	void			*sc_fdtih;
 };
 
-int		bwfm_sdio_match(device_t, cfdata_t, void *);
-void		bwfm_sdio_attach(device_t, struct device *, void *);
-int		bwfm_sdio_detach(device_t, int);
-void		bwfm_sdio_attachhook(device_t);
-
-void		bwfm_sdio_backplane(struct bwfm_sdio_softc *, uint32_t);
-uint8_t		bwfm_sdio_read_1(struct bwfm_sdio_softc *, uint32_t);
-uint32_t	bwfm_sdio_read_4(struct bwfm_sdio_softc *, uint32_t);
-void		bwfm_sdio_write_1(struct bwfm_sdio_softc *, uint32_t,
+static int	bwfm_sdio_match(device_t, cfdata_t, void *);
+static void	bwfm_sdio_attach(device_t, device_t, void *);
+static int	bwfm_sdio_detach(device_t, int);
+static void	bwfm_sdio_attachhook(device_t);
+static int	bwfm_fdt_find_phandle(device_t, device_t);
+
+static void	bwfm_sdio_backplane(struct bwfm_sdio_softc *, uint32_t);
+static uint8_t	bwfm_sdio_read_1(struct bwfm_sdio_softc *, uint32_t);
+static uint32_t	bwfm_sdio_read_4(struct bwfm_sdio_softc *, uint32_t);
+static void	bwfm_sdio_write_1(struct bwfm_sdio_softc *, uint32_t,
 		     uint8_t);
-void		bwfm_sdio_write_4(struct bwfm_sdio_softc *, uint32_t,
+static void	bwfm_sdio_write_4(struct bwfm_sdio_softc *, uint32_t,
 		     uint32_t);
 
-uint32_t	bwfm_sdio_dev_read(struct bwfm_sdio_softc *, uint32_t);
-void		bwfm_sdio_dev_write(struct bwfm_sdio_softc *, uint32_t,
+static uint32_t	bwfm_sdio_dev_read(struct bwfm_sdio_softc *, uint32_t);
+static void	bwfm_sdio_dev_write(struct bwfm_sdio_softc *, uint32_t,
 		     uint32_t);
 
-uint32_t	bwfm_sdio_buscore_read(struct bwfm_softc *, uint32_t);
-void		bwfm_sdio_buscore_write(struct bwfm_softc *, uint32_t,
+static uint32_t	bwfm_sdio_buscore_read(struct bwfm_softc *, uint32_t);
+static void	bwfm_sdio_buscore_write(struct bwfm_softc *, uint32_t,
 		     uint32_t);
-int		bwfm_sdio_buscore_prepare(struct bwfm_softc *);
-void		bwfm_sdio_buscore_activate(struct bwfm_softc *, uint32_t);
+static int	bwfm_sdio_buscore_prepare(struct bwfm_softc *);
+static void	bwfm_sdio_buscore_activate(struct bwfm_softc *, uint32_t);
 
-int		bwfm_sdio_buf_read(struct bwfm_sdio_softc *,
+static int	bwfm_sdio_buf_read(struct bwfm_sdio_softc *,
 		    struct sdmmc_function *, uint32_t, char *, size_t);
-int		bwfm_sdio_buf_write(struct bwfm_sdio_softc *,
+static int	bwfm_sdio_buf_write(struct bwfm_sdio_softc *,
 		    struct sdmmc_function *, uint32_t, char *, size_t);
 
-struct mbuf	*bwfm_sdio_newbuf(void);
-void		bwfm_qput(struct mbuf **, struct mbuf *);
-struct mbuf	*bwfm_qget(struct mbuf **);
+static struct mbuf	*bwfm_sdio_newbuf(void);
+static void		bwfm_qput(struct mbuf **, struct mbuf *);
+static struct mbuf	*bwfm_qget(struct mbuf **);
 
-uint32_t	bwfm_sdio_ram_read_write(struct bwfm_sdio_softc *,
+static uint32_t	bwfm_sdio_ram_read_write(struct bwfm_sdio_softc *,
 		    uint32_t, char *, size_t, int);
-uint32_t	bwfm_sdio_frame_read_write(struct bwfm_sdio_softc *,
+static uint32_t	bwfm_sdio_frame_read_write(struct bwfm_sdio_softc *,
 		    char *, size_t, int);
 
-int		bwfm_sdio_intr(void *);
-void		bwfm_sdio_task(void *);
-void		bwfm_sdio_task1(struct bwfm_sdio_softc *);
+static int	bwfm_sdio_intr1(void *, const char *);
+static int	bwfm_sdio_intr(void *);
+static void	bwfm_sdio_task(void *);
+static void	bwfm_sdio_task1(struct bwfm_sdio_softc *);
 
-int		bwfm_nvram_convert(u_char *, size_t, size_t *);
-int		bwfm_sdio_load_microcode(struct bwfm_sdio_softc *,
+static int	bwfm_nvram_convert(u_char *, size_t, size_t *);
+static int	bwfm_sdio_load_microcode(struct bwfm_sdio_softc *,
 		    u_char *, size_t, u_char *, size_t);
-void		bwfm_sdio_clkctl(struct bwfm_sdio_softc *,
+static void	bwfm_sdio_clkctl(struct bwfm_sdio_softc *,
 		    enum bwfm_sdio_clkstate, bool);
-void		bwfm_sdio_htclk(struct bwfm_sdio_softc *, bool, bool);
+static void	bwfm_sdio_htclk(struct bwfm_sdio_softc *, bool, bool);
 
-int		bwfm_sdio_bus_sleep(struct bwfm_sdio_softc *, bool, bool);
-void		bwfm_sdio_readshared(struct bwfm_sdio_softc *);
+#ifdef notyet
+static int	bwfm_sdio_bus_sleep(struct bwfm_sdio_softc *, bool, bool);
+#endif
+static void	bwfm_sdio_drivestrength(struct bwfm_sdio_softc *, unsigned);
+static void	bwfm_sdio_readshared(struct bwfm_sdio_softc *);
 
-int		bwfm_sdio_txcheck(struct bwfm_softc *);
-int		bwfm_sdio_txdata(struct bwfm_softc *, struct mbuf **);
-int		bwfm_sdio_txctl(struct bwfm_softc *, char *, size_t);
-int		bwfm_sdio_rxctl(struct bwfm_softc *, char *, size_t *);
-
-int		bwfm_sdio_tx_ok(struct bwfm_sdio_softc *);
-void		bwfm_sdio_tx_frames(struct bwfm_sdio_softc *);
-void		bwfm_sdio_tx_ctrlframe(struct bwfm_sdio_softc *,
+static int	bwfm_sdio_txcheck(struct bwfm_softc *);
+static int	bwfm_sdio_txdata(struct bwfm_softc *, struct mbuf **);
+static int	bwfm_sdio_txctl(struct bwfm_softc *, char *, size_t);
+static int	bwfm_sdio_rxctl(struct bwfm_softc *, char *, size_t *);
+
+static int		bwfm_sdio_tx_ok(struct bwfm_sdio_softc *);
+static void	bwfm_sdio_tx_frames(struct bwfm_sdio_softc *);
+static void	bwfm_sdio_tx_ctrlframe(struct bwfm_sdio_softc *,
 		    struct mbuf *);
-void		bwfm_sdio_tx_dataframe(struct bwfm_sdio_softc *,
+static void	bwfm_sdio_tx_dataframe(struct bwfm_sdio_softc *,
 		    struct mbuf *);
 
-void            bwfm_sdio_rx_frames(struct bwfm_sdio_softc *);
-void            bwfm_sdio_rx_glom(struct bwfm_sdio_softc *,
+static void	bwfm_sdio_rx_frames(struct bwfm_sdio_softc *);
+static void	bwfm_sdio_rx_glom(struct bwfm_sdio_softc *,
 		    uint16_t *, int, uint16_t *);
 
-#ifdef BWFM_DEBUG
-void		bwfm_sdio_debug_console(struct bwfm_sdio_softc *);
-#endif
+#ifdef BWFM_DEBUG 
+static void	bwfm_sdio_debug_console(struct bwfm_sdio_softc *);
+#endif 
 
 struct bwfm_bus_ops bwfm_sdio_bus_ops = {
 	.bs_init = NULL,
@@ -203,27 +215,32 @@ static const struct bwfm_sdio_product {
 } bwfm_sdio_products[] = {
 	{
 		SDMMC_VENDOR_BROADCOM,
-		SDMMC_PRODUCT_BROADCOM_BCM4330,
+		SDMMC_PRODUCT_BROADCOM_BCM4330, 
 		SDMMC_CIS_BROADCOM_BCM4330
 	},
 	{
 		SDMMC_VENDOR_BROADCOM,
-		SDMMC_PRODUCT_BROADCOM_BCM4334,
+		SDMMC_PRODUCT_BROADCOM_BCM4334, 
 		SDMMC_CIS_BROADCOM_BCM4334
 	},
 	{
 		SDMMC_VENDOR_BROADCOM,
-		SDMMC_PRODUCT_BROADCOM_BCM43143,
+		SDMMC_PRODUCT_BROADCOM_BCM43143, 
 		SDMMC_CIS_BROADCOM_BCM43143
 	},
 	{
 		SDMMC_VENDOR_BROADCOM,
-		SDMMC_PRODUCT_BROADCOM_BCM43430,
+		SDMMC_PRODUCT_BROADCOM_BCM43430, 
 		SDMMC_CIS_BROADCOM_BCM43430
 	},
 };
 
-int
+static const char *compatible[] = {
+	"brcm,bcm4329-fmac",
+	NULL
+};
+
+static int
 bwfm_sdio_match(device_t parent, cfdata_t match, void *aux)
 {
 	struct sdmmc_attach_args *saa = aux;
@@ -257,7 +274,7 @@ bwfm_sdio_match(device_t parent, cfdata_
 	return 1;
 }
 
-void
+static void
 bwfm_sdio_attach(device_t parent, device_t self, void *aux)
 {
 	struct bwfm_sdio_softc *sc = device_private(self);
@@ -271,6 +288,8 @@ bwfm_sdio_attach(device_t parent, device
 	aprint_naive("\n");
 	aprint_normal("\n");
 
+	sc->sc_phandle = bwfm_fdt_find_phandle(self, parent);
+
 	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
 	cv_init(&sc->sc_rxctl_cv, "bwfmctl");
 	mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_NONE);
@@ -293,7 +312,7 @@ bwfm_sdio_attach(device_t parent, device
 		sc->sc_sf[sf->number] = sf;
 	}
 
-	sdmmc_io_set_blocklen(sc->sc_sf[1], 64);
+	sdmmc_io_set_blocklen(sc->sc_sf[1], 64); 
 	sdmmc_io_set_blocklen(sc->sc_sf[2], 512);
 
 	/* Enable Function 1. */
@@ -331,7 +350,8 @@ bwfm_sdio_attach(device_t parent, device
 		}
 	}
 
-	/* TODO: drive strength */
+	/* Default, override from "brcm,drive-strength" */
+	bwfm_sdio_drivestrength(sc, 6);
 
 	bwfm_sdio_write_1(sc, BWFM_SDIO_CCCR_CARDCTRL,
 	    bwfm_sdio_read_1(sc, BWFM_SDIO_CCCR_CARDCTRL) |
@@ -351,7 +371,7 @@ bwfm_sdio_attach(device_t parent, device
 	config_mountroot(self, bwfm_sdio_attachhook);
 }
 
-void
+static void
 bwfm_sdio_attachhook(device_t self)
 {
 	struct bwfm_sdio_softc *sc = device_private(self);
@@ -389,6 +409,7 @@ bwfm_sdio_attachhook(device_t self)
 		} else {
 			name = "brcmfmac4339-sdio.bin";
 			nvname = "brcmfmac4339-sdio.txt";
+			bwfm->sc_chip.ch_chip = BRCM_CC_4339_CHIP_ID;
 		}
 		break;
 	case BRCM_CC_4339_CHIP_ID:
@@ -472,6 +493,8 @@ bwfm_sdio_attachhook(device_t self)
 	firmware_free(nvram, nvlen);
 	firmware_free(ucode, size);
 
+	sdmmc_pause(hztoms(1)*1000, NULL);
+
 	bwfm_sdio_clkctl(sc, CLK_AVAIL, false);
 	if (sc->sc_clkstate != CLK_AVAIL) {
 		printf("%s: could not access clock\n",
@@ -490,8 +513,9 @@ bwfm_sdio_attachhook(device_t self)
 		goto err;
 	}
 
-	bwfm_sdio_dev_write(sc, SDPCMD_HOSTINTMASK,
-	    SDPCMD_INTSTATUS_HMB_SW_MASK | SDPCMD_INTSTATUS_CHIPACTIVE);
+//	bwfm_sdio_dev_write(sc, SDPCMD_HOSTINTMASK,
+//	    SDPCMD_INTSTATUS_HMB_SW_MASK | SDPCMD_INTSTATUS_CHIPACTIVE);
+	bwfm_sdio_dev_write(sc, SDPCMD_HOSTINTMASK, 0xffffffff);
 	bwfm_sdio_write_1(sc, BWFM_SDIO_WATERMARK, 8);
 
 	if (bwfm_chip_sr_capable(bwfm)) {
@@ -508,15 +532,28 @@ bwfm_sdio_attachhook(device_t self)
 		bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR, clk);
 	}
 
-	sc->sc_ih = sdmmc_intr_establish(sc->sc_sc.sc_dev->dv_parent,
-		bwfm_sdio_intr, sc, DEVNAME(sc));
-	if (sc->sc_ih == NULL) {
+#ifdef notyet
+	if (sc->sc_phandle >= 0) {
+		sc->sc_fdtih = fdtbus_intr_establish(sc->sc_phandle,
+		    0, IPL_SDMMC, IST_LEVEL, bwfm_sdio_intr, sc);
+	}
+#endif
+	if (sc->sc_fdtih != NULL) {
+		aprint_normal_dev(self, "enabling GPIO interrupt\n");
+	} else {
+		sc->sc_ih = sdmmc_intr_establish(device_parent(self),
+		    bwfm_sdio_intr, sc, DEVNAME(sc));
+	}
+
+	if (sc->sc_ih == NULL && sc->sc_fdtih == NULL) {
 		aprint_error_dev(self, "could not establish interrupt\n");
 		bwfm_sdio_clkctl(sc, CLK_NONE, false);
 		return;
 	}
 	sdmmc_intr_enable(sc->sc_sf[1]);
 
+	sdmmc_pause(100000, NULL);
+
 	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);
@@ -532,8 +569,42 @@ err:
 	return;
 }
 
-int
-bwfm_sdio_detach(struct device *self, int flags)
+static int
+bwfm_fdt_find_phandle(device_t self, device_t parent)
+{
+	prop_dictionary_t dict;
+	device_t dev;
+	const char *str;
+	int phandle;
+
+	/* locate in FDT */
+	dict = device_properties(self);
+	if (prop_dictionary_get_cstring_nocopy(dict, "fdt-path", &str)) {
+		/* search in FDT */
+		phandle = OF_finddevice(str);
+	} else {
+
+		/* parent parent is sdhc controller */
+		dev = device_parent(parent);
+		if (dev == NULL)
+			return -1;
+		/* locate in FDT */
+		dict = device_properties(dev);
+		if (!prop_dictionary_get_cstring_nocopy(dict, "fdt-path", &str))
+			return -1;
+
+		/* are we the only FDT child ? */
+		phandle = OF_child(OF_finddevice(str));
+	}
+
+	if (!of_match_compatible(phandle, compatible))
+		return -1;
+
+	return phandle;
+}
+
+static int
+bwfm_sdio_detach(device_t self, int flags)
 {
 	struct bwfm_sdio_softc *sc = (struct bwfm_sdio_softc *)self;
 
@@ -541,9 +612,12 @@ bwfm_sdio_detach(struct device *self, in
 	bwfm_sdio_debug_console(sc);
 #endif
 
-	if (sc->sc_ih) {
+	if (sc->sc_ih || sc->sc_fdtih) {
 		sdmmc_intr_disable(sc->sc_sf[1]);
-		sdmmc_intr_disestablish(sc->sc_ih);
+		if (sc->sc_ih)
+			sdmmc_intr_disestablish(sc->sc_ih);
+		if (sc->sc_fdtih)
+			fdtbus_intr_disestablish(sc->sc_phandle, sc->sc_fdtih);
 	}
 	if (sc->sc_bwfm_attached)
 		bwfm_detach(&sc->sc_sc, flags);
@@ -558,7 +632,7 @@ bwfm_sdio_detach(struct device *self, in
 	return 0;
 }
 
-void
+static void
 bwfm_sdio_backplane(struct bwfm_sdio_softc *sc, uint32_t addr)
 {
 	uint32_t bar0 = addr & ~BWFM_SDIO_SB_OFT_ADDR_MASK;
@@ -575,7 +649,7 @@ bwfm_sdio_backplane(struct bwfm_sdio_sof
 	sc->sc_bar0 = bar0;
 }
 
-uint8_t
+static uint8_t
 bwfm_sdio_read_1(struct bwfm_sdio_softc *sc, uint32_t addr)
 {
 	struct sdmmc_function *sf;
@@ -596,7 +670,7 @@ bwfm_sdio_read_1(struct bwfm_sdio_softc 
 	return rv;
 }
 
-uint32_t
+static uint32_t
 bwfm_sdio_read_4(struct bwfm_sdio_softc *sc, uint32_t addr)
 {
 	struct sdmmc_function *sf;
@@ -622,7 +696,7 @@ bwfm_sdio_read_4(struct bwfm_sdio_softc 
 	return rv;
 }
 
-void
+static void
 bwfm_sdio_write_1(struct bwfm_sdio_softc *sc, uint32_t addr, uint8_t data)
 {
 	struct sdmmc_function *sf;
@@ -641,7 +715,7 @@ bwfm_sdio_write_1(struct bwfm_sdio_softc
 	sdmmc_io_write_1(sf, addr, data);
 }
 
-void
+static void
 bwfm_sdio_write_4(struct bwfm_sdio_softc *sc, uint32_t addr, uint32_t data)
 {
 	struct sdmmc_function *sf;
@@ -665,7 +739,7 @@ bwfm_sdio_write_4(struct bwfm_sdio_softc
 	sdmmc_io_write_4(sf, addr, data);
 }
 
-int
+static int
 bwfm_sdio_buf_read(struct bwfm_sdio_softc *sc, struct sdmmc_function *sf,
     uint32_t reg, char *data, size_t size)
 {
@@ -685,7 +759,7 @@ bwfm_sdio_buf_read(struct bwfm_sdio_soft
 	return err;
 }
 
-int
+static int
 bwfm_sdio_buf_write(struct bwfm_sdio_softc *sc, struct sdmmc_function *sf,
     uint32_t reg, char *data, size_t size)
 {
@@ -702,7 +776,7 @@ bwfm_sdio_buf_write(struct bwfm_sdio_sof
 	return err;
 }
 
-uint32_t
+static uint32_t
 bwfm_sdio_ram_read_write(struct bwfm_sdio_softc *sc, uint32_t reg,
     char *data, size_t left, int write)
 {
@@ -738,10 +812,13 @@ bwfm_sdio_ram_read_write(struct bwfm_sdi
 		left -= size;
 	}
 
+	if (err)
+		printf("%s: error %d\n", __func__, err);
+
 	return err;
 }
 
-uint32_t
+static uint32_t
 bwfm_sdio_frame_read_write(struct bwfm_sdio_softc *sc,
     char *data, size_t size, int write)
 {
@@ -759,10 +836,13 @@ bwfm_sdio_frame_read_write(struct bwfm_s
 	else
 		err = bwfm_sdio_buf_read(sc, sc->sc_sf[2], addr, data, size);
 
+	if (err)
+		printf("%s: error %d\n", __func__, err);
+
 	return err;
 }
 
-uint32_t
+static uint32_t
 bwfm_sdio_dev_read(struct bwfm_sdio_softc *sc, uint32_t reg)
 {
 	struct bwfm_core *core;
@@ -775,7 +855,7 @@ bwfm_sdio_dev_read(struct bwfm_sdio_soft
 	return val;
 }
 
-void
+static void
 bwfm_sdio_dev_write(struct bwfm_sdio_softc *sc, uint32_t reg, uint32_t val)
 {
 	struct bwfm_core *core;
@@ -784,7 +864,7 @@ bwfm_sdio_dev_write(struct bwfm_sdio_sof
 	bwfm_sdio_write_4(sc, core->co_base + reg, val);
 }
 
-uint32_t
+static uint32_t
 bwfm_sdio_buscore_read(struct bwfm_softc *bwfm, uint32_t reg)
 {
 	struct bwfm_sdio_softc *sc = (void *)bwfm;
@@ -798,7 +878,7 @@ bwfm_sdio_buscore_read(struct bwfm_softc
 	return val;
 }
 
-void
+static void
 bwfm_sdio_buscore_write(struct bwfm_softc *bwfm, uint32_t reg, uint32_t val)
 {
 	struct bwfm_sdio_softc *sc = (void *)bwfm;
@@ -808,7 +888,7 @@ bwfm_sdio_buscore_write(struct bwfm_soft
 	mutex_exit(&sc->sc_lock);
 }
 
-int
+static int
 bwfm_sdio_buscore_prepare(struct bwfm_softc *bwfm)
 {
 	struct bwfm_sdio_softc *sc = (void *)bwfm;
@@ -858,7 +938,7 @@ done:
 	return error;
 }
 
-void
+static void
 bwfm_sdio_buscore_activate(struct bwfm_softc *bwfm, uint32_t rstvec)
 {
 	struct bwfm_sdio_softc *sc = (void *)bwfm;
@@ -875,7 +955,7 @@ bwfm_sdio_buscore_activate(struct bwfm_s
 	mutex_exit(&sc->sc_lock);
 }
 
-struct mbuf *
+static struct mbuf *
 bwfm_sdio_newbuf(void)
 {
 	struct mbuf *m;
@@ -894,7 +974,7 @@ bwfm_sdio_newbuf(void)
 	return m;
 }
 
-struct mbuf *
+static struct mbuf *
 bwfm_qget(struct mbuf **q)
 {
 	struct mbuf *m = NULL;
@@ -908,7 +988,7 @@ bwfm_qget(struct mbuf **q)
 	return m;
 }
 
-void
+static void
 bwfm_qput(struct mbuf **q, struct mbuf *m)
 {
 
@@ -918,7 +998,7 @@ bwfm_qput(struct mbuf **q, struct mbuf *
 		m_cat(*q, m);
 }
 
-int
+static int
 bwfm_sdio_txcheck(struct bwfm_softc *bwfm)
 {
 	struct bwfm_sdio_softc *sc = (void *)bwfm;
@@ -933,7 +1013,7 @@ bwfm_sdio_txcheck(struct bwfm_softc *bwf
 }
 
 
-int
+static int
 bwfm_sdio_txdata(struct bwfm_softc *bwfm, struct mbuf **mp)
 {
 	struct bwfm_sdio_softc *sc = (void *)bwfm;
@@ -948,12 +1028,12 @@ bwfm_sdio_txdata(struct bwfm_softc *bwfm
 	MBUFQ_ENQUEUE(&sc->sc_tx_queue, *mp);
 	mutex_exit(&sc->sc_lock);
 
-	bwfm_sdio_intr(sc);
+	bwfm_sdio_intr1(sc, "sdio_txdata");
 
 	return 0;
 }
 
-int
+static int
 bwfm_sdio_txctl(struct bwfm_softc *bwfm, char *buf, size_t len)
 {
 	struct bwfm_sdio_softc *sc = (void *)bwfm;
@@ -978,7 +1058,7 @@ bwfm_sdio_txctl(struct bwfm_softc *bwfm,
 	MBUFQ_ENQUEUE(&sc->sc_tx_queue, m);
 	mutex_exit(&sc->sc_lock);
 
-	bwfm_sdio_intr(sc);
+	bwfm_sdio_intr1(sc, "sdio_txctl");
 
 	return 0;
 
@@ -986,7 +1066,7 @@ fail:
 	return ENOBUFS;
 }
 
-int
+static int
 bwfm_nvram_convert(u_char *buf, size_t len, size_t *newlenp)
 {
 	u_char *src, *dst, *end = buf + len;
@@ -1036,7 +1116,7 @@ bwfm_nvram_convert(u_char *buf, size_t l
 	return 0;
 }
 
-int
+static int
 bwfm_sdio_load_microcode(struct bwfm_sdio_softc *sc, u_char *ucode, size_t size,
     u_char *nvram, size_t nvlen)
 {
@@ -1096,7 +1176,7 @@ out:
 	return err;
 }
 
-void
+static void
 bwfm_sdio_clkctl(struct bwfm_sdio_softc *sc, enum bwfm_sdio_clkstate newstate,
     bool pendok)
 {
@@ -1134,7 +1214,7 @@ bwfm_sdio_clkctl(struct bwfm_sdio_softc 
 	    sc->sc_clkstate));
 }
 
-void
+static void
 bwfm_sdio_htclk(struct bwfm_sdio_softc *sc, bool on, bool pendok)
 {
 	uint32_t clkctl, devctl, req;
@@ -1169,16 +1249,15 @@ bwfm_sdio_htclk(struct bwfm_sdio_softc *
 			bwfm_sdio_write_1(sc, BWFM_SDIO_DEVICE_CTL, devctl);
 		}
 
-		for (i = 0; i < 5000; i++) {
+		for (i = 0; i < 50; i++) {
 			if (BWFM_SDIO_FUNC1_CHIPCLKCSR_CLKAV(clkctl,
 			    sc->sc_alp_only))
 				break;
 			clkctl = bwfm_sdio_read_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR
 );
-			delay(1000);
+			sdmmc_pause(100000, NULL);
 		}
-		if (!BWFM_SDIO_FUNC1_CHIPCLKCSR_CLKAV(clkctl, sc->sc_alp_only))
-{
+		if (i >= 50) {
 			printf("%s: HT avail timeout\n", DEVNAME(sc));
 			return;
 		}
@@ -1195,8 +1274,91 @@ bwfm_sdio_htclk(struct bwfm_sdio_softc *
 	}
 }
 
+struct bwfm_sdio_dstab {
+	uint8_t milli;
+	uint8_t val;
+};
+
+static struct bwfm_sdio_dstab pmu11_1v8[] = {
+	{32, 0x6},
+	{26, 0x7},
+	{22, 0x4},
+	{16, 0x5},
+	{12, 0x2},
+	{8, 0x3},
+	{4, 0x0},
+	{0, 0x1}
+}, pmu13_1v8[] = {
+	{6, 0x7},
+	{5, 0x6},
+	{4, 0x5},
+	{3, 0x4},
+	{2, 0x2},
+	{1, 0x1},
+	{0, 0x0}
+}, pmu17_1v8[] = {
+	{3, 0x3},       
+	{2, 0x2},       
+	{1, 0x1},       
+	{0, 0x0}
+}, pmu17_3v3[] = {
+	{16, 0x7},
+	{12, 0x5},
+	{8,  0x3},
+	{4,  0x1},
+	{0,  0x0}
+};
+
+static void
+bwfm_sdio_drivestrength(struct bwfm_sdio_softc *sc, unsigned milli)
+{
+	struct bwfm_softc *bwfm = &sc->sc_sc;
+	struct bwfm_core *core;
+	struct bwfm_sdio_dstab *tab;
+	uint32_t tmp, mask;
+	unsigned i;
+
+	if ((bwfm->sc_chip.ch_cc_caps & BWFM_CHIP_REG_CAPABILITIES_PMU) == 0)
+		return;
+
+	switch (bwfm->sc_chip.ch_chip) {
+	case BRCM_CC_4330_CHIP_ID:
+		tab = pmu11_1v8;
+		mask = __BITS(11,13);
+		break;
+	case BRCM_CC_4334_CHIP_ID:
+		tab = pmu17_1v8;
+		mask = __BITS(11,12);
+		break;
+	case BRCM_CC_43143_CHIP_ID:
+		tab = pmu17_3v3;
+		mask = __BITS(0,3);
+		break;
+	case BRCM_CC_43362_CHIP_ID:
+		tab = pmu13_1v8;
+		mask = __BITS(11,13);
+		break;
+	default:
+		return;
+	}
+
+	for (i=0; tab[i].milli != 0; ++i) {
+		if (milli >= tab[i].milli)
+			break;
+	}
+	if (tab[i].milli == 0)
+		return;
+
+	core = bwfm_chip_get_pmu(&sc->sc_sc);
+	tmp = bwfm_sdio_read_4(sc, core->co_base + BWFM_CHIP_REG_CHIPCONTROL_ADDR);
+	tmp &= mask;
+	tmp |= __SHIFTIN(tab[i].val, mask);
+	bwfm_sdio_write_4(sc, core->co_base + BWFM_CHIP_REG_CHIPCONTROL_ADDR, tmp);
+}
+
+
 #if notyet
-int
+static int
 bwfm_sdio_bus_sleep(struct bwfm_sdio_softc *sc, bool sleep, bool pendok)
 {
 	uint32_t clkctl;
@@ -1226,7 +1388,7 @@ bwfm_sdio_bus_sleep(struct bwfm_sdio_sof
 }
 #endif
 
-void
+static void
 bwfm_sdio_readshared(struct bwfm_sdio_softc *sc)
 {
 	struct bwfm_softc *bwfm = &sc->sc_sc;
@@ -1259,12 +1421,12 @@ bwfm_sdio_readshared(struct bwfm_sdio_so
 	sc->sc_console_addr = le32toh(sdpcm.console_addr);
 }
 
-int
-bwfm_sdio_intr(void *v)
+static int
+bwfm_sdio_intr1(void *v, const char *name)
 {
 	struct bwfm_sdio_softc *sc = (void *)v;
 
-	DPRINTF(("%s: sdio_intr\n", DEVNAME(sc)));
+	DPRINTF(("%s: %s\n", DEVNAME(sc), name));
 
 	mutex_enter(&sc->sc_intr_lock);
 	if (!sdmmc_task_pending(&sc->sc_task))
@@ -1274,13 +1436,25 @@ bwfm_sdio_intr(void *v)
 	return 1;
 }
 
-void
+static int
+bwfm_sdio_intr(void *v)
+{
+	return bwfm_sdio_intr1(v, "sdio_intr");
+}
+
+static void
 bwfm_sdio_task(void *v)
 {
 	struct bwfm_sdio_softc *sc = (void *)v;
+#ifdef BWFM_DEBUG
+	unsigned count = 0;
+#endif
 
 	mutex_enter(&sc->sc_intr_lock);
 	while (sc->sc_task_queued) {
+#ifdef BWFM_DEBUG
+		++count;
+#endif
 		sc->sc_task_queued = false;
 		mutex_exit(&sc->sc_intr_lock);
 
@@ -1294,12 +1468,18 @@ bwfm_sdio_task(void *v)
 		mutex_enter(&sc->sc_intr_lock);
 	}
 	mutex_exit(&sc->sc_intr_lock);
+
+#ifdef BWFM_DEBUG
+	if (count > 1)
+		DPRINTF(("%s: finished %u tasks\n", DEVNAME(sc), count));
+#endif
 }
 
-void
+static void
 bwfm_sdio_task1(struct bwfm_sdio_softc *sc)
 {
 	uint32_t clkctl, devctl, intstat, hostint;
+	bool dorecv, dosend;
 
 	if (!sc->sc_sr_enabled && sc->sc_clkstate == CLK_PENDING) {
 		clkctl = bwfm_sdio_read_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR);
@@ -1311,41 +1491,64 @@ bwfm_sdio_task1(struct bwfm_sdio_softc *
 		}
 	}
 
+	dorecv = dosend = sc->sc_clkstate == CLK_AVAIL;
+
 	intstat = bwfm_sdio_dev_read(sc, BWFM_SDPCMD_INTSTATUS);
 	DPRINTF(("%s: intstat 0x%" PRIx32 "\n", DEVNAME(sc), intstat));
 	intstat &= (SDPCMD_INTSTATUS_HMB_SW_MASK|SDPCMD_INTSTATUS_CHIPACTIVE);
-	/* XXX fc state */
 	if (intstat)
 		bwfm_sdio_dev_write(sc, BWFM_SDPCMD_INTSTATUS, intstat);
 
+	if (intstat & SDPCMD_INTSTATUS_CHIPACTIVE)
+		printf("%s: CHIPACTIVE\n", DEVNAME(sc));
+
 	if (intstat & SDPCMD_INTSTATUS_HMB_HOST_INT) {
 		hostint = bwfm_sdio_dev_read(sc, SDPCMD_TOHOSTMAILBOXDATA);
 		DPRINTF(("%s: hostint 0x%" PRIx32 "\n", DEVNAME(sc), hostint));
 		bwfm_sdio_dev_write(sc, SDPCMD_TOSBMAILBOX,
 		    SDPCMD_TOSBMAILBOX_INT_ACK);
 		if (hostint & SDPCMD_TOHOSTMAILBOXDATA_NAKHANDLED)
-			intstat |= SDPCMD_INTSTATUS_HMB_FRAME_IND;
+			sc->sc_rxskip = false;
 		if (hostint & SDPCMD_TOHOSTMAILBOXDATA_DEVREADY ||
 		    hostint & SDPCMD_TOHOSTMAILBOXDATA_FWREADY)
 			bwfm_sdio_readshared(sc);
 	}
 
-	/* FIXME: Might stall if we don't when not set. */
-	if (intstat & SDPCMD_INTSTATUS_HMB_FRAME_IND)
-		bwfm_sdio_rx_frames(sc);
+	if (intstat & SDPCMD_INTSTATUS_HMB_FRAME_IND) {
+		/* ignore receive indications while recovering */
+		if (dorecv && !sc->sc_rxskip) {
+			DPRINTF(("%s: recv\n", DEVNAME(sc)));
+			bwfm_sdio_rx_frames(sc);
+		}
+	}
 
-	if (MBUFQ_FIRST(&sc->sc_tx_queue))
+	if (intstat & SDPCMD_INTSTATUS_HMB_FC_STATE)
+		dosend = false;
+
+	if (intstat & SDPCMD_INTSTATUS_HMB_FC_CHANGE) {
+		if (dosend) {
+			intstat = bwfm_sdio_dev_read(sc, BWFM_SDPCMD_INTSTATUS);
+			DPRINTF(("%s: intstat2 0x%" PRIx32 "\n", DEVNAME(sc), intstat));
+			if (intstat & (SDPCMD_INTSTATUS_HMB_FC_STATE | SDPCMD_INTSTATUS_HMB_FC_CHANGE))
+				dosend = false;
+		}
+	}
+
+if (!dosend && MBUFQ_FIRST(&sc->sc_tx_queue)) printf("%s: flowctl\n", DEVNAME(sc));
+	if (dosend && MBUFQ_FIRST(&sc->sc_tx_queue)) {
+		DPRINTF(("%s: xmit\n", DEVNAME(sc)));
 		bwfm_sdio_tx_frames(sc);
+	}
 }
 
-int
+static int
 bwfm_sdio_tx_ok(struct bwfm_sdio_softc *sc)
 {
 	return (uint8_t)(sc->sc_tx_max_seq - sc->sc_tx_seq) != 0 &&
 	    ((uint8_t)(sc->sc_tx_max_seq - sc->sc_tx_seq) & 0x80) == 0;
 }
 
-void
+static void    
 bwfm_sdio_tx_frames(struct bwfm_sdio_softc *sc)
 {
 	struct mbuf *m;
@@ -1365,7 +1568,7 @@ bwfm_sdio_tx_frames(struct bwfm_sdio_sof
 		if (m->m_type == MT_CONTROL)
 			bwfm_sdio_tx_ctrlframe(sc, m);
 		else {
-			bwfm_sdio_tx_dataframe(sc, m);
+			bwfm_sdio_tx_dataframe(sc, m);  
 			ifp->if_opackets++;
 			ifstart = true;
 		}
@@ -1379,13 +1582,13 @@ bwfm_sdio_tx_frames(struct bwfm_sdio_sof
 	}
 }
 
-void
+static void
 bwfm_sdio_tx_ctrlframe(struct bwfm_sdio_softc *sc, struct mbuf *m)
 {
 	struct bwfm_sdio_hwhdr *hwhdr;
 	struct bwfm_sdio_swhdr *swhdr;
 	size_t len, roundto;
-
+	
 	len = sizeof(*hwhdr) + sizeof(*swhdr) + m->m_len;
 
 	/* Zero-pad to either block-size or 4-byte alignment. */
@@ -1395,29 +1598,29 @@ bwfm_sdio_tx_ctrlframe(struct bwfm_sdio_
 		roundto = 4;
 
 	KASSERT(roundup(len, roundto) <= sc->sc_bounce_size);
-
+ 
 	hwhdr = (void *)sc->sc_bounce_buf;
 	hwhdr->frmlen = htole16(len);
 	hwhdr->cksum = htole16(~len);
-
+	
 	swhdr = (void *)&hwhdr[1];
 	swhdr->seqnr = sc->sc_tx_seq++;
 	swhdr->chanflag = BWFM_SDIO_SWHDR_CHANNEL_CONTROL;
 	swhdr->nextlen = 0;
 	swhdr->dataoff = sizeof(*hwhdr) + sizeof(*swhdr);
 	swhdr->maxseqnr = 0;
-
+	
 	m_copydata(m, 0, m->m_len, &swhdr[1]);
-
+	
 	if (roundup(len, roundto) != len)
 		memset(sc->sc_bounce_buf + len, 0,
 		    roundup(len, roundto) - len);
-
+	
 	bwfm_sdio_frame_read_write(sc, sc->sc_bounce_buf,
 	    roundup(len, roundto), 1);
 }
 
-void
+static void
 bwfm_sdio_tx_dataframe(struct bwfm_sdio_softc *sc, struct mbuf *m)
 {
 	struct bwfm_sdio_hwhdr *hwhdr;
@@ -1465,7 +1668,7 @@ bwfm_sdio_tx_dataframe(struct bwfm_sdio_
 	sc->sc_tx_count--;
 }
 
-int
+static int
 bwfm_sdio_rxctl(struct bwfm_softc *bwfm, char *buf, size_t *lenp)
 {
 	struct bwfm_sdio_softc *sc = (void *)bwfm;
@@ -1475,7 +1678,7 @@ bwfm_sdio_rxctl(struct bwfm_softc *bwfm,
 	mutex_enter(&sc->sc_lock);
 	while ((m = bwfm_qget(&sc->sc_rxctl_queue)) == NULL) {
 		err = cv_timedwait(&sc->sc_rxctl_cv, &sc->sc_lock,
-				   mstohz(5000));
+		    mstohz(5000));
 		if (err == EWOULDBLOCK)
 			break;
 	}
@@ -1495,49 +1698,52 @@ bwfm_sdio_rxctl(struct bwfm_softc *bwfm,
 	return 0;
 }
 
-void
+static void
 bwfm_sdio_rx_frames(struct bwfm_sdio_softc *sc)
-{
+{       
 	struct bwfm_sdio_hwhdr *hwhdr;
 	struct bwfm_sdio_swhdr *swhdr;
 	struct bwfm_proto_bcdc_hdr *bcdc;
-	uint16_t *sublen, nextlen = 0;
+	uint16_t *sublen, nextlen = 0;  
 	struct mbuf *m;
 	size_t flen, off, hoff;
 	char *data;
 	int nsub;
+	size_t subsize;
 
 	hwhdr = (struct bwfm_sdio_hwhdr *)sc->sc_bounce_buf;
 	swhdr = (struct bwfm_sdio_swhdr *)&hwhdr[1];
 	data = (char *)&swhdr[1];
-
+	
 	for (;;) {
 		/* If we know the next size, just read ahead. */
 		if (nextlen) {
 			if (bwfm_sdio_frame_read_write(sc, sc->sc_bounce_buf,
 			    nextlen, 0))
 				break;
+			nextlen = 0;
 		} else {
 			if (bwfm_sdio_frame_read_write(sc, sc->sc_bounce_buf,
 			    sizeof(*hwhdr) + sizeof(*swhdr), 0))
-				break;
+				break; 
 		}
-
+	
 		hwhdr->frmlen = le16toh(hwhdr->frmlen);
 		hwhdr->cksum = le16toh(hwhdr->cksum);
-
-		if (hwhdr->frmlen == 0 && hwhdr->cksum == 0)
+	
+		if (hwhdr->frmlen == 0 && hwhdr->cksum == 0) {
 			break;
+		}
 
 		if ((hwhdr->frmlen ^ hwhdr->cksum) != 0xffff) {
 			printf("%s: checksum error\n", DEVNAME(sc));
-			break;
+			break;  
 		}
 
 		if (hwhdr->frmlen < sizeof(*hwhdr) + sizeof(*swhdr)) {
 			printf("%s: length error\n", DEVNAME(sc));
 			break;
-		}
+		} 
 
 		if (nextlen && hwhdr->frmlen > nextlen) {
 			printf("%s: read ahead length error (%u > %u)\n",
@@ -1557,8 +1763,11 @@ bwfm_sdio_rx_frames(struct bwfm_sdio_sof
 			KASSERT(roundup(flen, 4) <= sc->sc_bounce_size -
 			    (sizeof(*hwhdr) + sizeof(*swhdr)));
 			if (bwfm_sdio_frame_read_write(sc, data,
-			    roundup(flen, 4), 0))
+			    roundup(flen, 4), 0)) {
+				printf("%s: I/O error roundup(%zu, 4) bytes\n",
+				    DEVNAME(sc), flen);
 				break;
+			}
 		}
 
 		if (swhdr->dataoff < (sizeof(*hwhdr) + sizeof(*swhdr))) {
@@ -1628,10 +1837,16 @@ bwfm_sdio_rx_frames(struct bwfm_sdio_sof
 				break;
 			}
 			nsub = flen / sizeof(uint16_t);
-			sublen = kmem_zalloc(nsub * sizeof(uint16_t), KM_SLEEP);
-			memcpy(sublen, data, nsub * sizeof(uint16_t));
-			bwfm_sdio_rx_glom(sc, sublen, nsub, &nextlen);
-			kmem_free(sublen, nsub * sizeof(uint16_t));
+			subsize = nsub * sizeof(uint16_t);
+			sublen = NULL;
+			nextlen = 0;
+			if (subsize > 0)
+				sublen = kmem_zalloc(subsize, KM_NOSLEEP);
+			if (sublen != NULL) {
+				memcpy(sublen, data, subsize);
+				bwfm_sdio_rx_glom(sc, sublen, nsub, &nextlen);
+				kmem_free(sublen, subsize);
+			}
 			break;
 		default:
 			printf("%s: unknown channel\n", DEVNAME(sc));
@@ -1640,7 +1855,7 @@ bwfm_sdio_rx_frames(struct bwfm_sdio_sof
 	}
 }
 
-void
+static void
 bwfm_sdio_rx_glom(struct bwfm_sdio_softc *sc, uint16_t *sublen, int nsub,
     uint16_t *nextlen)
 {
@@ -1664,11 +1879,13 @@ bwfm_sdio_rx_glom(struct bwfm_sdio_softc
 		bwfm_qput(&m0, m);
 		if (le16toh(sublen[i]) > m->m_len) {
 			m_freem(m0);
+			printf("%s: header larger than mbuf\n", DEVNAME(sc));
 			return;
 		}
 		if (bwfm_sdio_frame_read_write(sc, mtod(m, char *),
 		    le16toh(sublen[i]), 0)) {
 			m_freem(m0);
+			printf("%s: frame I/O error\n", DEVNAME(sc));
 			return;
 		}
 		m->m_len = m->m_pkthdr.len = le16toh(sublen[i]);
@@ -1776,11 +1993,12 @@ bwfm_sdio_rx_glom(struct bwfm_sdio_softc
 drop:
 		printf("rx dropped %p len %d\n",mtod(m, char *),m->m_pkthdr.len);
 		m_free(m);
+		break;
 	}
 }
 
 #ifdef BWFM_DEBUG
-void
+static void
 bwfm_sdio_debug_console(struct bwfm_sdio_softc *sc)
 {
 	struct bwfm_sdio_console c;
@@ -1793,8 +2011,8 @@ bwfm_sdio_debug_console(struct bwfm_sdio
 	err = bwfm_sdio_ram_read_write(sc, sc->sc_console_addr,
 	    (char *)&c, sizeof(c), 0);
 	if (err)
-		return;
-
+		return; 
+ 
 	c.log_buf = le32toh(c.log_buf);
 	c.log_bufsz = le32toh(c.log_bufsz);
 	c.log_idx = le32toh(c.log_idx);

Reply via email to