summaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
diff options
context:
space:
mode:
authorArend van Spriel2013-04-05 10:57:40 +0200
committerJohn W. Linville2013-04-08 21:28:41 +0200
commit33753d47d390624f09ee57dbb2bc611b15a10e8f (patch)
tree3b9c025274b278d2a4827304dcddb654a3fb43cb /drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
parentbrcmfmac: fix unaligned access in TXSTATUS signal handling (diff)
downloadkernel-qcow2-linux-33753d47d390624f09ee57dbb2bc611b15a10e8f.tar.gz
kernel-qcow2-linux-33753d47d390624f09ee57dbb2bc611b15a10e8f.tar.xz
kernel-qcow2-linux-33753d47d390624f09ee57dbb2bc611b15a10e8f.zip
brcmfmac: handle firmware signalling destination entry state
Firmware can signal whether the host driver may sent packets for a specific destination or interface. This can happen when a destination is sleeping or when going off-channel. Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com> Reviewed-by: Hante Meuleman <meuleman@broadcom.com> Signed-off-by: Arend van Spriel <arend@broadcom.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c')
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c80
1 files changed, 73 insertions, 7 deletions
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
index 451cfc1b2c47..57cbfb661d58 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
@@ -896,6 +896,69 @@ int brcmf_fws_macdesc_indicate(struct brcmf_fws_info *fws, u8 type, u8 *data)
return 0;
}
+static int brcmf_fws_macdesc_state_indicate(struct brcmf_fws_info *fws,
+ u8 type, u8 *data)
+{
+ struct brcmf_fws_mac_descriptor *entry;
+ u8 mac_handle;
+ int i;
+
+ mac_handle = data[0];
+ entry = &fws->desc.nodes[mac_handle & 0x1F];
+ if (!entry->occupied) {
+ fws->stats.mac_ps_update_failed++;
+ return -ESRCH;
+ }
+
+ /* a state update should wipe old credits? */
+ entry->requested_credit = 0;
+ if (type == BRCMF_FWS_TYPE_MAC_OPEN) {
+ entry->state = BRCMF_FWS_STATE_OPEN;
+ } else {
+ entry->state = BRCMF_FWS_STATE_CLOSE;
+ for (i = BRCMF_FWS_FIFO_AC_BE; i < NL80211_NUM_ACS; i++)
+ brcmf_fws_tim_update(fws, entry, i);
+ }
+ return 0;
+}
+
+static int brcmf_fws_interface_state_indicate(struct brcmf_fws_info *fws,
+ u8 type, u8 *data)
+{
+ struct brcmf_fws_mac_descriptor *entry;
+ u8 ifidx;
+ int ret;
+
+ ifidx = data[0];
+
+ brcmf_dbg(TRACE, "enter: ifidx=%d\n", ifidx);
+ if (ifidx >= BRCMF_MAX_IFS) {
+ ret = -ERANGE;
+ goto fail;
+ }
+
+ entry = &fws->desc.iface[ifidx];
+ if (!entry->occupied) {
+ ret = -ESRCH;
+ goto fail;
+ }
+
+ switch (type) {
+ case BRCMF_FWS_TYPE_INTERFACE_OPEN:
+ entry->state = BRCMF_FWS_STATE_OPEN;
+ return 0;
+ case BRCMF_FWS_TYPE_INTERFACE_CLOSE:
+ entry->state = BRCMF_FWS_STATE_CLOSE;
+ return 0;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+fail:
+ fws->stats.if_update_failed++;
+ return ret;
+}
+
static void brcmf_fws_return_credits(struct brcmf_fws_info *fws,
u8 fifo, u8 credits)
{
@@ -1111,8 +1174,6 @@ brcmf_fws_txstatus_process(struct brcmf_fws_info *fws, u8 flags, u32 hslot,
struct sk_buff *skb;
struct brcmf_fws_mac_descriptor *entry = NULL;
- fws->stats.txs_indicate++;
-
brcmf_dbg(TRACE, "status: flags=0x%X, hslot=%d\n",
flags, hslot);
@@ -1305,11 +1366,7 @@ int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len,
break;
switch (type) {
- case BRCMF_FWS_TYPE_MAC_OPEN:
- case BRCMF_FWS_TYPE_MAC_CLOSE:
case BRCMF_FWS_TYPE_MAC_REQUEST_CREDIT:
- case BRCMF_FWS_TYPE_INTERFACE_OPEN:
- case BRCMF_FWS_TYPE_INTERFACE_CLOSE:
case BRCMF_FWS_TYPE_MAC_REQUEST_PACKET:
case BRCMF_FWS_TYPE_HOST_REORDER_RXPKTS:
case BRCMF_FWS_TYPE_COMP_TXSTATUS:
@@ -1318,6 +1375,14 @@ int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len,
case BRCMF_FWS_TYPE_MACDESC_DEL:
brcmf_fws_macdesc_indicate(fws, type, data);
break;
+ case BRCMF_FWS_TYPE_MAC_OPEN:
+ case BRCMF_FWS_TYPE_MAC_CLOSE:
+ brcmf_fws_macdesc_state_indicate(fws, type, data);
+ break;
+ case BRCMF_FWS_TYPE_INTERFACE_OPEN:
+ case BRCMF_FWS_TYPE_INTERFACE_CLOSE:
+ brcmf_fws_interface_state_indicate(fws, type, data);
+ break;
case BRCMF_FWS_TYPE_TXSTATUS:
brcmf_fws_txstatus_indicate(fws, data);
break;
@@ -1779,7 +1844,8 @@ int brcmf_fws_init(struct brcmf_pub *drvr)
/* enable firmware signalling if fcmode active */
if (drvr->fws->fcmode != BRCMF_FWS_FCMODE_NONE)
tlv |= BRCMF_FWS_FLAGS_XONXOFF_SIGNALS |
- BRCMF_FWS_FLAGS_CREDIT_STATUS_SIGNALS;
+ BRCMF_FWS_FLAGS_CREDIT_STATUS_SIGNALS |
+ BRCMF_FWS_FLAGS_HOST_PROPTXSTATUS_ACTIVE;
rc = brcmf_fil_iovar_int_set(drvr->iflist[0], "tlv", tlv);
if (rc < 0) {