aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorArend van Spriel <arend@broadcom.com>2013-04-23 06:53:15 -0400
committerJohn W. Linville <linville@tuxdriver.com>2013-04-23 14:17:05 -0400
commit1aac1e91171586e4d0981e40484a7c93d9b1f289 (patch)
tree81f174cf957bc2ae54f36cbc550f1316b17a24be /drivers
parenta786b38d542f62e19ffa8adbcbfc82065cd13a11 (diff)
brcmfmac: add credit borrowing mechanism
The firmware provides credits to the driver per WMM-AC. When only AC_BE are to be transmitted to the firmware the driver may use credits from other priorities to send AC_BE packets towards the firmware. Reviewed-by: Hante Meuleman <meuleman@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>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c95
1 files changed, 87 insertions, 8 deletions
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
index f9153b115dcf..5352dc1fdf3c 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
@@ -21,6 +21,7 @@
21#include <linux/netdevice.h> 21#include <linux/netdevice.h>
22#include <linux/etherdevice.h> 22#include <linux/etherdevice.h>
23#include <linux/err.h> 23#include <linux/err.h>
24#include <linux/jiffies.h>
24#include <uapi/linux/nl80211.h> 25#include <uapi/linux/nl80211.h>
25#include <net/cfg80211.h> 26#include <net/cfg80211.h>
26 27
@@ -271,6 +272,9 @@ struct brcmf_skbuff_cb {
271 brcmu_maskget32(txs, BRCMF_FWS_TXSTAT_ ## field ## _MASK, \ 272 brcmu_maskget32(txs, BRCMF_FWS_TXSTAT_ ## field ## _MASK, \
272 BRCMF_FWS_TXSTAT_ ## field ## _SHIFT) 273 BRCMF_FWS_TXSTAT_ ## field ## _SHIFT)
273 274
275/* How long to defer borrowing in jiffies */
276#define BRCMF_FWS_BORROW_DEFER_PERIOD (HZ / 10)
277
274/** 278/**
275 * enum brcmf_fws_fifo - fifo indices used by dongle firmware. 279 * enum brcmf_fws_fifo - fifo indices used by dongle firmware.
276 * 280 *
@@ -425,9 +429,11 @@ struct brcmf_fws_info {
425 struct work_struct fws_dequeue_work; 429 struct work_struct fws_dequeue_work;
426 u32 fifo_enqpkt[BRCMF_FWS_FIFO_COUNT]; 430 u32 fifo_enqpkt[BRCMF_FWS_FIFO_COUNT];
427 int fifo_credit[BRCMF_FWS_FIFO_COUNT]; 431 int fifo_credit[BRCMF_FWS_FIFO_COUNT];
432 int credits_borrowed[BRCMF_FWS_FIFO_AC_VO + 1];
428 int deq_node_pos[BRCMF_FWS_FIFO_COUNT]; 433 int deq_node_pos[BRCMF_FWS_FIFO_COUNT];
429 u32 fifo_credit_map; 434 u32 fifo_credit_map;
430 u32 fifo_delay_map; 435 u32 fifo_delay_map;
436 unsigned long borrow_defer_timestamp;
431}; 437};
432 438
433/* 439/*
@@ -997,9 +1003,34 @@ static int brcmf_fws_request_indicate(struct brcmf_fws_info *fws, u8 type,
997static void brcmf_fws_return_credits(struct brcmf_fws_info *fws, 1003static void brcmf_fws_return_credits(struct brcmf_fws_info *fws,
998 u8 fifo, u8 credits) 1004 u8 fifo, u8 credits)
999{ 1005{
1006 int lender_ac;
1007 int *borrowed;
1008 int *fifo_credit;
1009
1000 if (!credits) 1010 if (!credits)
1001 return; 1011 return;
1002 1012
1013 if ((fifo == BRCMF_FWS_FIFO_AC_BE) &&
1014 (fws->credits_borrowed[0])) {
1015 for (lender_ac = BRCMF_FWS_FIFO_AC_VO; lender_ac >= 0;
1016 lender_ac--) {
1017 borrowed = &fws->credits_borrowed[lender_ac];
1018 if (*borrowed) {
1019 fws->fifo_credit_map |= (1 << lender_ac);
1020 fifo_credit = &fws->fifo_credit[lender_ac];
1021 if (*borrowed >= credits) {
1022 *borrowed -= credits;
1023 *fifo_credit += credits;
1024 return;
1025 } else {
1026 credits -= *borrowed;
1027 *fifo_credit += *borrowed;
1028 *borrowed = 0;
1029 }
1030 }
1031 }
1032 }
1033
1003 fws->fifo_credit_map |= 1 << fifo; 1034 fws->fifo_credit_map |= 1 << fifo;
1004 fws->fifo_credit[fifo] += credits; 1035 fws->fifo_credit[fifo] += credits;
1005} 1036}
@@ -1658,6 +1689,26 @@ fail:
1658 fws->stats.rollback_success++; 1689 fws->stats.rollback_success++;
1659} 1690}
1660 1691
1692static int brcmf_fws_borrow_credit(struct brcmf_fws_info *fws)
1693{
1694 int lender_ac;
1695
1696 if (time_after(fws->borrow_defer_timestamp, jiffies))
1697 return -ENAVAIL;
1698
1699 for (lender_ac = 0; lender_ac <= BRCMF_FWS_FIFO_AC_VO; lender_ac++) {
1700 if (fws->fifo_credit[lender_ac]) {
1701 fws->credits_borrowed[lender_ac]++;
1702 fws->fifo_credit[lender_ac]--;
1703 if (fws->fifo_credit[lender_ac] == 0)
1704 fws->fifo_credit_map &= ~(1 << lender_ac);
1705 brcmf_dbg(TRACE, "borrow credit from: %d\n", lender_ac);
1706 return 0;
1707 }
1708 }
1709 return -ENAVAIL;
1710}
1711
1661static int brcmf_fws_consume_credit(struct brcmf_fws_info *fws, int fifo, 1712static int brcmf_fws_consume_credit(struct brcmf_fws_info *fws, int fifo,
1662 struct sk_buff *skb) 1713 struct sk_buff *skb)
1663{ 1714{
@@ -1691,8 +1742,17 @@ static int brcmf_fws_consume_credit(struct brcmf_fws_info *fws, int fifo,
1691 return 0; 1742 return 0;
1692 } 1743 }
1693 1744
1745 if (fifo != BRCMF_FWS_FIFO_AC_BE)
1746 fws->borrow_defer_timestamp = jiffies +
1747 BRCMF_FWS_BORROW_DEFER_PERIOD;
1748
1694 if (!(*credit)) { 1749 if (!(*credit)) {
1695 brcmf_dbg(TRACE, "exit: credits depleted\n"); 1750 /* Try to borrow a credit from other queue */
1751 if (fifo == BRCMF_FWS_FIFO_AC_BE &&
1752 brcmf_fws_borrow_credit(fws) == 0)
1753 return 0;
1754
1755 brcmf_dbg(TRACE, "exit: ac=%d, credits depleted\n", fifo);
1696 return -ENAVAIL; 1756 return -ENAVAIL;
1697 } 1757 }
1698 (*credit)--; 1758 (*credit)--;
@@ -1741,6 +1801,7 @@ rollback:
1741int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb) 1801int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb)
1742{ 1802{
1743 struct brcmf_pub *drvr = ifp->drvr; 1803 struct brcmf_pub *drvr = ifp->drvr;
1804 struct brcmf_fws_info *fws = drvr->fws;
1744 struct brcmf_skbuff_cb *skcb = brcmf_skbcb(skb); 1805 struct brcmf_skbuff_cb *skcb = brcmf_skbcb(skb);
1745 struct ethhdr *eh = (struct ethhdr *)(skb->data); 1806 struct ethhdr *eh = (struct ethhdr *)(skb->data);
1746 ulong flags; 1807 ulong flags;
@@ -1755,7 +1816,7 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb)
1755 if (ntohs(eh->h_proto) == ETH_P_PAE) 1816 if (ntohs(eh->h_proto) == ETH_P_PAE)
1756 atomic_inc(&ifp->pend_8021x_cnt); 1817 atomic_inc(&ifp->pend_8021x_cnt);
1757 1818
1758 if (!brcmf_fws_fc_active(drvr->fws)) { 1819 if (!brcmf_fws_fc_active(fws)) {
1759 /* If the protocol uses a data header, apply it */ 1820 /* If the protocol uses a data header, apply it */
1760 brcmf_proto_hdrpush(drvr, ifp->ifidx, 0, skb); 1821 brcmf_proto_hdrpush(drvr, ifp->ifidx, 0, skb);
1761 1822
@@ -1765,7 +1826,7 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb)
1765 1826
1766 /* set control buffer information */ 1827 /* set control buffer information */
1767 skcb->if_flags = 0; 1828 skcb->if_flags = 0;
1768 skcb->mac = brcmf_fws_find_mac_desc(drvr->fws, ifp, eh->h_dest); 1829 skcb->mac = brcmf_fws_find_mac_desc(fws, ifp, eh->h_dest);
1769 skcb->state = BRCMF_FWS_SKBSTATE_NEW; 1830 skcb->state = BRCMF_FWS_SKBSTATE_NEW;
1770 brcmf_skb_if_flags_set_field(skb, INDEX, ifp->ifidx); 1831 brcmf_skb_if_flags_set_field(skb, INDEX, ifp->ifidx);
1771 if (!multicast) 1832 if (!multicast)
@@ -1777,15 +1838,17 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb)
1777 1838
1778 brcmf_fws_lock(drvr, flags); 1839 brcmf_fws_lock(drvr, flags);
1779 if (skcb->mac->suppressed || 1840 if (skcb->mac->suppressed ||
1780 brcmf_fws_mac_desc_closed(drvr->fws, skcb->mac, fifo) || 1841 brcmf_fws_mac_desc_closed(fws, skcb->mac, fifo) ||
1781 brcmu_pktq_mlen(&skcb->mac->psq, 3 << (fifo * 2)) || 1842 brcmu_pktq_mlen(&skcb->mac->psq, 3 << (fifo * 2)) ||
1782 (!multicast && 1843 (!multicast &&
1783 brcmf_fws_consume_credit(drvr->fws, fifo, skb) < 0)) { 1844 brcmf_fws_consume_credit(fws, fifo, skb) < 0)) {
1784 /* enqueue the packet in delayQ */ 1845 /* enqueue the packet in delayQ */
1785 drvr->fws->fifo_delay_map |= 1 << fifo; 1846 drvr->fws->fifo_delay_map |= 1 << fifo;
1786 brcmf_fws_enq(drvr->fws, BRCMF_FWS_SKBSTATE_DELAYED, fifo, skb); 1847 brcmf_fws_enq(fws, BRCMF_FWS_SKBSTATE_DELAYED, fifo, skb);
1787 } else { 1848 } else {
1788 brcmf_fws_commit_skb(drvr->fws, fifo, skb); 1849 if (brcmf_fws_commit_skb(fws, fifo, skb))
1850 if (!multicast)
1851 brcmf_skb_pick_up_credit(fws, fifo, skb);
1789 } 1852 }
1790 brcmf_fws_unlock(drvr, flags); 1853 brcmf_fws_unlock(drvr, flags);
1791 return 0; 1854 return 0;
@@ -1858,7 +1921,23 @@ static void brcmf_fws_dequeue_worker(struct work_struct *worker)
1858 BRCMF_SKB_IF_FLAGS_CREDITCHECK_MASK) 1921 BRCMF_SKB_IF_FLAGS_CREDITCHECK_MASK)
1859 credit++; 1922 credit++;
1860 } 1923 }
1861 fws->fifo_credit[fifo] -= credit; 1924 if ((fifo == BRCMF_FWS_FIFO_AC_BE) &&
1925 (credit == fws->fifo_credit[fifo])) {
1926 fws->fifo_credit[fifo] -= credit;
1927 while (brcmf_fws_borrow_credit(fws) == 0) {
1928 skb = brcmf_fws_deq(fws, fifo);
1929 if (!skb) {
1930 brcmf_fws_return_credits(fws, fifo, 1);
1931 break;
1932 }
1933 if (brcmf_fws_commit_skb(fws, fifo, skb)) {
1934 brcmf_fws_return_credits(fws, fifo, 1);
1935 break;
1936 }
1937 }
1938 } else {
1939 fws->fifo_credit[fifo] -= credit;
1940 }
1862 } 1941 }
1863 brcmf_fws_unlock(fws->drvr, flags); 1942 brcmf_fws_unlock(fws->drvr, flags);
1864} 1943}