brcmfmac: Only use credits for bcmc when firmware indicates it.
authorHante Meuleman <meuleman@broadcom.com>
Tue, 18 Jun 2013 11:29:22 +0000 (13:29 +0200)
committerJohn W. Linville <linville@tuxdriver.com>
Tue, 18 Jun 2013 18:46:48 +0000 (14:46 -0400)
The firmware will sent an event message when bc/mc traffic should
be sent to the device using credit mechanism.

Reviewed-by: Arend Van Spriel <arend@broadcom.com>
Signed-off-by: Hante Meuleman <meuleman@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/fweh.h
drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c

index 6ec5db9..e679214 100644 (file)
@@ -101,7 +101,8 @@ struct brcmf_event;
        BRCMF_ENUM_DEF(P2P_PROBEREQ_MSG, 72) \
        BRCMF_ENUM_DEF(DCS_REQUEST, 73) \
        BRCMF_ENUM_DEF(FIFO_CREDIT_MAP, 74) \
-       BRCMF_ENUM_DEF(ACTION_FRAME_RX, 75)
+       BRCMF_ENUM_DEF(ACTION_FRAME_RX, 75) \
+       BRCMF_ENUM_DEF(BCMC_CREDIT_SUPPORT, 127)
 
 #define BRCMF_ENUM_DEF(id, val) \
        BRCMF_E_##id = (val),
index 70f70ce..1d8fa7d 100644 (file)
@@ -426,6 +426,7 @@ struct brcmf_fws_info {
        struct brcmf_fws_stats stats;
        struct brcmf_fws_hanger hanger;
        enum brcmf_fws_fcmode fcmode;
+       bool bcmc_credit_check;
        struct brcmf_fws_macdesc_table desc;
        struct workqueue_struct *fws_wq;
        struct work_struct fws_dequeue_work;
@@ -1438,6 +1439,20 @@ static int brcmf_fws_notify_credit_map(struct brcmf_if *ifp,
        return 0;
 }
 
+static int brcmf_fws_notify_bcmc_credit_support(struct brcmf_if *ifp,
+                                               const struct brcmf_event_msg *e,
+                                               void *data)
+{
+       struct brcmf_fws_info *fws = ifp->drvr->fws;
+       ulong flags;
+
+       brcmf_fws_lock(ifp->drvr, flags);
+       if (fws)
+               fws->bcmc_credit_check = true;
+       brcmf_fws_unlock(ifp->drvr, flags);
+       return 0;
+}
+
 int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len,
                      struct sk_buff *skb)
 {
@@ -1806,6 +1821,12 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb)
                  eh->h_dest, multicast, fifo);
 
        brcmf_fws_lock(drvr, flags);
+       /* multicast credit support is conditional, setting
+        * flag to false to assure credit is consumed below.
+        */
+       if (fws->bcmc_credit_check)
+               multicast = false;
+
        if (skcb->mac->suppressed ||
            fws->bus_flow_blocked ||
            brcmf_fws_mac_desc_closed(fws, skcb->mac, fifo) ||
@@ -1878,7 +1899,8 @@ static void brcmf_fws_dequeue_worker(struct work_struct *worker)
        brcmf_fws_lock(fws->drvr, flags);
        for (fifo = NL80211_NUM_ACS; fifo >= 0 && !fws->bus_flow_blocked;
             fifo--) {
-               while (fws->fifo_credit[fifo]) {
+               while ((fws->fifo_credit[fifo]) || ((!fws->bcmc_credit_check) &&
+                      (fifo == BRCMF_FWS_FIFO_BCMC))) {
                        skb = brcmf_fws_deq(fws, fifo);
                        if (!skb)
                                break;
@@ -1947,6 +1969,13 @@ int brcmf_fws_init(struct brcmf_pub *drvr)
                brcmf_err("register credit map handler failed\n");
                goto fail;
        }
+       rc = brcmf_fweh_register(drvr, BRCMF_E_BCMC_CREDIT_SUPPORT,
+                                brcmf_fws_notify_bcmc_credit_support);
+       if (rc < 0) {
+               brcmf_err("register bcmc credit handler failed\n");
+               brcmf_fweh_unregister(drvr, BRCMF_E_FIFO_CREDIT_MAP);
+               goto fail;
+       }
 
        /* setting the iovar may fail if feature is unsupported
         * so leave the rc as is so driver initialization can
@@ -1971,6 +2000,7 @@ int brcmf_fws_init(struct brcmf_pub *drvr)
        return 0;
 
 fail_event:
+       brcmf_fweh_unregister(drvr, BRCMF_E_BCMC_CREDIT_SUPPORT);
        brcmf_fweh_unregister(drvr, BRCMF_E_FIFO_CREDIT_MAP);
 fail:
        brcmf_fws_deinit(drvr);