brcmfmac: add flow-control mode to firmware signalling
authorArend van Spriel <arend@broadcom.com>
Wed, 3 Apr 2013 10:40:39 +0000 (12:40 +0200)
committerJohn W. Linville <linville@tuxdriver.com>
Wed, 3 Apr 2013 19:07:06 +0000 (15:07 -0400)
Upcoming patches will add firmware signalled flow control. Prepare
by adding the mode, which defaults to disable it. The mode can be
queried by brcmf_fws_fc_active() and set by a module parameter.

Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
Reviewed-by: Piotr Haber <phaber@broadcom.com>
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
Signed-off-by: Arend van Spriel <arend@broadcom.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/brcm80211/brcmfmac/dhd.h
drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
drivers/net/wireless/brcm80211/brcmfmac/fwsignal.h

index af307c101c941667ce522a3a62e93befeb142b43..ef5e3a92deb1e9daa6da82a8fbc0f9f190295338 100644 (file)
@@ -623,5 +623,7 @@ extern void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx);
 void brcmf_txflowblock_if(struct brcmf_if *ifp,
                          enum brcmf_netif_stop_reason reason, bool state);
 extern u32 brcmf_get_chip_info(struct brcmf_if *ifp);
+extern void brcmf_txfinalize(struct brcmf_pub *drvr, struct sk_buff *txp,
+                            bool success);
 
 #endif                         /* _BRCMF_H_ */
index 3ba9e1049f3bbfd40081a4a7d8e418b03d4cd8a5..05c8840392e5ebf6b5cfb7196d0868f7d4126c67 100644 (file)
@@ -363,21 +363,20 @@ void brcmf_rx_frames(struct device *dev, struct sk_buff_head *skb_list)
        }
 }
 
-void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success)
+void brcmf_txfinalize(struct brcmf_pub *drvr, struct sk_buff *txp,
+                     bool success)
 {
-       u8 ifidx;
+       struct brcmf_if *ifp;
        struct ethhdr *eh;
+       u8 ifidx;
        u16 type;
-       struct brcmf_bus *bus_if = dev_get_drvdata(dev);
-       struct brcmf_pub *drvr = bus_if->drvr;
-       struct brcmf_if *ifp;
        int res;
 
        res = brcmf_proto_hdrpull(drvr, false, &ifidx, txp);
 
        ifp = drvr->iflist[ifidx];
        if (!ifp)
-               goto done;
+               return;
 
        if (res == 0) {
                eh = (struct ethhdr *)(txp->data);
@@ -391,8 +390,18 @@ void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success)
        }
        if (!success)
                ifp->stats.tx_errors++;
+}
 
-done:
+void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success)
+{
+       struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+       struct brcmf_pub *drvr = bus_if->drvr;
+
+       /* await txstatus signal for firmware is active */
+       if (success && brcmf_fws_fc_active(drvr->fws))
+               return;
+
+       brcmf_txfinalize(drvr, txp, success);
        brcmu_pkt_buf_free_skb(txp);
 }
 
index 2afd850f22c60bd7c89e5509e634c27c54883a24..cb1414d93a672e57ffc5897abcaa8eb98138ebe9 100644 (file)
@@ -14,6 +14,7 @@
  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 #include <linux/types.h>
+#include <linux/module.h>
 #include <linux/if_ether.h>
 #include <linux/spinlock.h>
 #include <linux/skbuff.h>
@@ -124,10 +125,6 @@ static const char *brcmf_fws_get_tlv_name(enum brcmf_fws_tlv_type id)
 #define BRCMF_FWS_STATE_OPEN                           1
 #define BRCMF_FWS_STATE_CLOSE                          2
 
-#define BRCMF_FWS_FCMODE_NONE                          0
-#define BRCMF_FWS_FCMODE_IMPLIED_CREDIT                        1
-#define BRCMF_FWS_FCMODE_EXPLICIT_CREDIT               2
-
 #define BRCMF_FWS_MAC_DESC_TABLE_SIZE                  32
 #define BRCMF_FWS_MAX_IFNUM                            16
 #define BRCMF_FWS_MAC_DESC_ID_INVALID                  0xff
@@ -245,6 +242,12 @@ struct brcmf_skbuff_cb {
                        BRCMF_SKB_HTOD_TAG_ ## field ## _MASK, \
                        BRCMF_SKB_HTOD_TAG_ ## field ## _SHIFT)
 
+enum brcmf_fws_fcmode {
+       BRCMF_FWS_FCMODE_NONE,
+       BRCMF_FWS_FCMODE_IMPLIED_CREDIT,
+       BRCMF_FWS_FCMODE_EXPLICIT_CREDIT
+};
+
 /**
  * struct brcmf_fws_mac_descriptor - firmware signalling data per node/interface
  *
@@ -328,9 +331,14 @@ struct brcmf_fws_info {
        struct brcmf_fws_hanger hanger;
        struct brcmf_fws_mac_descriptor nodes[BRCMF_FWS_MAC_DESC_TABLE_SIZE];
        struct brcmf_fws_mac_descriptor other;
+       enum brcmf_fws_fcmode fcmode;
        int fifo_credit[NL80211_NUM_ACS+1+1];
 };
 
+static int fcmode;
+module_param(fcmode, int, S_IRUSR);
+MODULE_PARM_DESC(fcmode, "mode of firmware signalled flow control");
+
 /**
  * brcmf_fws_get_tlv_len() - returns defined length for given tlv id.
  */
@@ -745,6 +753,7 @@ int brcmf_fws_init(struct brcmf_pub *drvr)
 
        /* set linkage back */
        drvr->fws->drvr = drvr;
+       drvr->fws->fcmode = fcmode;
 
        /* TODO: remove upon feature delivery */
        brcmf_err("%s bdcv2 tlv signaling [%x]\n",
@@ -920,3 +929,12 @@ void brcmf_fws_del_interface(struct brcmf_if *ifp)
        brcmf_fws_cleanup(ifp->drvr->fws, ifp->ifidx);
        kfree(entry);
 }
+
+bool brcmf_fws_fc_active(struct brcmf_fws_info *fws)
+{
+       if (!fws)
+               return false;
+
+       brcmf_dbg(TRACE, "enter: mode=%d\n", fws->fcmode);
+       return fws->fcmode != BRCMF_FWS_FCMODE_NONE;
+}
index 38a75e494d7d35676948bd885f3979e5015ad0a0..1566f4de0edad85a5b8849d117f783e81f116dcb 100644 (file)
@@ -20,6 +20,7 @@
 
 int brcmf_fws_init(struct brcmf_pub *drvr);
 void brcmf_fws_deinit(struct brcmf_pub *drvr);
+bool brcmf_fws_fc_active(struct brcmf_fws_info *fws);
 int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len,
                      struct sk_buff *skb);