aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/brcm80211/brcmfmac
diff options
context:
space:
mode:
authorHante Meuleman <meuleman@broadcom.com>2013-06-06 07:17:48 -0400
committerJohn W. Linville <linville@tuxdriver.com>2013-06-12 15:02:16 -0400
commitdf50f756966cc07addaae5449a6fd45a17bdb06c (patch)
treee0a8ac79d0241bd1293e61d2bf061753bbf8deaf /drivers/net/wireless/brcm80211/brcmfmac
parent51f6dd9da27359d9218046ed0003f71e05a673c1 (diff)
brcmfmac: Take bus flowcontrol at credit mgmt into account.
On bus flow control (no more host bus resources to send packets to device) the netif flow control was toggled, however credit management should also take this status into account. Since there are multiple sources handling this flow control necessary spinlocks were added to protect flow control related data/states. Reviewed-by: Arend Van Spriel <arend@broadcom.com> Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com> Reviewed-by: Pieter-Paul Giesberts <pieterpg@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>
Diffstat (limited to 'drivers/net/wireless/brcm80211/brcmfmac')
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd.h2
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c8
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c2
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c21
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/fwsignal.h1
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/usb.c8
6 files changed, 39 insertions, 3 deletions
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h
index 28db9cf39672..86cbfe2c7c6c 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h
@@ -583,6 +583,7 @@ enum brcmf_netif_stop_reason {
583 * @bssidx: index of bss associated with this interface. 583 * @bssidx: index of bss associated with this interface.
584 * @mac_addr: assigned mac address. 584 * @mac_addr: assigned mac address.
585 * @netif_stop: bitmap indicates reason why netif queues are stopped. 585 * @netif_stop: bitmap indicates reason why netif queues are stopped.
586 * @netif_stop_lock: spinlock for update netif_stop from multiple sources.
586 * @pend_8021x_cnt: tracks outstanding number of 802.1x frames. 587 * @pend_8021x_cnt: tracks outstanding number of 802.1x frames.
587 * @pend_8021x_wait: used for signalling change in count. 588 * @pend_8021x_wait: used for signalling change in count.
588 */ 589 */
@@ -598,6 +599,7 @@ struct brcmf_if {
598 s32 bssidx; 599 s32 bssidx;
599 u8 mac_addr[ETH_ALEN]; 600 u8 mac_addr[ETH_ALEN];
600 u8 netif_stop; 601 u8 netif_stop;
602 spinlock_t netif_stop_lock;
601 atomic_t pend_8021x_cnt; 603 atomic_t pend_8021x_cnt;
602 wait_queue_head_t pend_8021x_wait; 604 wait_queue_head_t pend_8021x_wait;
603}; 605};
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
index b98f2235978e..df37645f493e 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
@@ -240,11 +240,15 @@ done:
240void brcmf_txflowblock_if(struct brcmf_if *ifp, 240void brcmf_txflowblock_if(struct brcmf_if *ifp,
241 enum brcmf_netif_stop_reason reason, bool state) 241 enum brcmf_netif_stop_reason reason, bool state)
242{ 242{
243 unsigned long flags;
244
243 if (!ifp) 245 if (!ifp)
244 return; 246 return;
245 247
246 brcmf_dbg(TRACE, "enter: idx=%d stop=0x%X reason=%d state=%d\n", 248 brcmf_dbg(TRACE, "enter: idx=%d stop=0x%X reason=%d state=%d\n",
247 ifp->bssidx, ifp->netif_stop, reason, state); 249 ifp->bssidx, ifp->netif_stop, reason, state);
250
251 spin_lock_irqsave(&ifp->netif_stop_lock, flags);
248 if (state) { 252 if (state) {
249 if (!ifp->netif_stop) 253 if (!ifp->netif_stop)
250 netif_stop_queue(ifp->ndev); 254 netif_stop_queue(ifp->ndev);
@@ -254,6 +258,7 @@ void brcmf_txflowblock_if(struct brcmf_if *ifp,
254 if (!ifp->netif_stop) 258 if (!ifp->netif_stop)
255 netif_wake_queue(ifp->ndev); 259 netif_wake_queue(ifp->ndev);
256 } 260 }
261 spin_unlock_irqrestore(&ifp->netif_stop_lock, flags);
257} 262}
258 263
259void brcmf_txflowblock(struct device *dev, bool state) 264void brcmf_txflowblock(struct device *dev, bool state)
@@ -264,6 +269,8 @@ void brcmf_txflowblock(struct device *dev, bool state)
264 269
265 brcmf_dbg(TRACE, "Enter\n"); 270 brcmf_dbg(TRACE, "Enter\n");
266 271
272 brcmf_fws_bus_blocked(drvr, state);
273
267 for (i = 0; i < BRCMF_MAX_IFS; i++) 274 for (i = 0; i < BRCMF_MAX_IFS; i++)
268 brcmf_txflowblock_if(drvr->iflist[i], 275 brcmf_txflowblock_if(drvr->iflist[i],
269 BRCMF_NETIF_STOP_REASON_BLOCK_BUS, state); 276 BRCMF_NETIF_STOP_REASON_BLOCK_BUS, state);
@@ -779,6 +786,7 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx,
779 ifp->bssidx = bssidx; 786 ifp->bssidx = bssidx;
780 787
781 init_waitqueue_head(&ifp->pend_8021x_wait); 788 init_waitqueue_head(&ifp->pend_8021x_wait);
789 spin_lock_init(&ifp->netif_stop_lock);
782 790
783 if (mac_addr != NULL) 791 if (mac_addr != NULL)
784 memcpy(ifp->mac_addr, mac_addr, ETH_ALEN); 792 memcpy(ifp->mac_addr, mac_addr, ETH_ALEN);
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
index d2487518bd2a..6f3d181659ef 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
@@ -2369,12 +2369,12 @@ static int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt)
2369 } else { 2369 } else {
2370 ret = 0; 2370 ret = 0;
2371 } 2371 }
2372 spin_unlock_bh(&bus->txqlock);
2373 2372
2374 if (pktq_len(&bus->txq) >= TXHI) { 2373 if (pktq_len(&bus->txq) >= TXHI) {
2375 bus->txoff = true; 2374 bus->txoff = true;
2376 brcmf_txflowblock(bus->sdiodev->dev, true); 2375 brcmf_txflowblock(bus->sdiodev->dev, true);
2377 } 2376 }
2377 spin_unlock_bh(&bus->txqlock);
2378 2378
2379#ifdef DEBUG 2379#ifdef DEBUG
2380 if (pktq_plen(&bus->txq, prec) > qcount[prec]) 2380 if (pktq_plen(&bus->txq, prec) > qcount[prec])
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
index bc2edc04e525..c1930ef5c55f 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
@@ -431,6 +431,7 @@ struct brcmf_fws_info {
431 u32 fifo_credit_map; 431 u32 fifo_credit_map;
432 u32 fifo_delay_map; 432 u32 fifo_delay_map;
433 unsigned long borrow_defer_timestamp; 433 unsigned long borrow_defer_timestamp;
434 bool bus_flow_blocked;
434}; 435};
435 436
436/* 437/*
@@ -1833,6 +1834,7 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb)
1833 1834
1834 brcmf_fws_lock(drvr, flags); 1835 brcmf_fws_lock(drvr, flags);
1835 if (skcb->mac->suppressed || 1836 if (skcb->mac->suppressed ||
1837 fws->bus_flow_blocked ||
1836 brcmf_fws_mac_desc_closed(fws, skcb->mac, fifo) || 1838 brcmf_fws_mac_desc_closed(fws, skcb->mac, fifo) ||
1837 brcmu_pktq_mlen(&skcb->mac->psq, 3 << (fifo * 2)) || 1839 brcmu_pktq_mlen(&skcb->mac->psq, 3 << (fifo * 2)) ||
1838 (!multicast && 1840 (!multicast &&
@@ -1905,7 +1907,8 @@ static void brcmf_fws_dequeue_worker(struct work_struct *worker)
1905 1907
1906 brcmf_dbg(TRACE, "enter: fws=%p\n", fws); 1908 brcmf_dbg(TRACE, "enter: fws=%p\n", fws);
1907 brcmf_fws_lock(fws->drvr, flags); 1909 brcmf_fws_lock(fws->drvr, flags);
1908 for (fifo = NL80211_NUM_ACS; fifo >= 0; fifo--) { 1910 for (fifo = NL80211_NUM_ACS; fifo >= 0 && !fws->bus_flow_blocked;
1911 fifo--) {
1909 brcmf_dbg(TRACE, "fifo %d credit %d\n", fifo, 1912 brcmf_dbg(TRACE, "fifo %d credit %d\n", fifo,
1910 fws->fifo_credit[fifo]); 1913 fws->fifo_credit[fifo]);
1911 for (credit = 0; credit < fws->fifo_credit[fifo]; /* nop */) { 1914 for (credit = 0; credit < fws->fifo_credit[fifo]; /* nop */) {
@@ -1915,9 +1918,12 @@ static void brcmf_fws_dequeue_worker(struct work_struct *worker)
1915 if (brcmf_skbcb(skb)->if_flags & 1918 if (brcmf_skbcb(skb)->if_flags &
1916 BRCMF_SKB_IF_FLAGS_CREDITCHECK_MASK) 1919 BRCMF_SKB_IF_FLAGS_CREDITCHECK_MASK)
1917 credit++; 1920 credit++;
1921 if (fws->bus_flow_blocked)
1922 break;
1918 } 1923 }
1919 if ((fifo == BRCMF_FWS_FIFO_AC_BE) && 1924 if ((fifo == BRCMF_FWS_FIFO_AC_BE) &&
1920 (credit == fws->fifo_credit[fifo])) { 1925 (credit == fws->fifo_credit[fifo]) &&
1926 (!fws->bus_flow_blocked)) {
1921 fws->fifo_credit[fifo] -= credit; 1927 fws->fifo_credit[fifo] -= credit;
1922 while (brcmf_fws_borrow_credit(fws) == 0) { 1928 while (brcmf_fws_borrow_credit(fws) == 0) {
1923 skb = brcmf_fws_deq(fws, fifo); 1929 skb = brcmf_fws_deq(fws, fifo);
@@ -1929,6 +1935,8 @@ static void brcmf_fws_dequeue_worker(struct work_struct *worker)
1929 brcmf_fws_return_credits(fws, fifo, 1); 1935 brcmf_fws_return_credits(fws, fifo, 1);
1930 break; 1936 break;
1931 } 1937 }
1938 if (fws->bus_flow_blocked)
1939 break;
1932 } 1940 }
1933 } else { 1941 } else {
1934 fws->fifo_credit[fifo] -= credit; 1942 fws->fifo_credit[fifo] -= credit;
@@ -2060,3 +2068,12 @@ void brcmf_fws_bustxfail(struct brcmf_fws_info *fws, struct sk_buff *skb)
2060 } 2068 }
2061 brcmf_fws_unlock(fws->drvr, flags); 2069 brcmf_fws_unlock(fws->drvr, flags);
2062} 2070}
2071
2072void brcmf_fws_bus_blocked(struct brcmf_pub *drvr, bool flow_blocked)
2073{
2074 struct brcmf_fws_info *fws = drvr->fws;
2075
2076 fws->bus_flow_blocked = flow_blocked;
2077 if (!flow_blocked)
2078 brcmf_fws_schedule_deq(fws);
2079}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.h b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.h
index fbe483d23752..9fc860910bd8 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.h
@@ -29,5 +29,6 @@ void brcmf_fws_reset_interface(struct brcmf_if *ifp);
29void brcmf_fws_add_interface(struct brcmf_if *ifp); 29void brcmf_fws_add_interface(struct brcmf_if *ifp);
30void brcmf_fws_del_interface(struct brcmf_if *ifp); 30void brcmf_fws_del_interface(struct brcmf_if *ifp);
31void brcmf_fws_bustxfail(struct brcmf_fws_info *fws, struct sk_buff *skb); 31void brcmf_fws_bustxfail(struct brcmf_fws_info *fws, struct sk_buff *skb);
32void brcmf_fws_bus_blocked(struct brcmf_pub *drvr, bool flow_blocked);
32 33
33#endif /* FWSIGNAL_H_ */ 34#endif /* FWSIGNAL_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/brcm80211/brcmfmac/usb.c
index 01aed7ad6bec..322cadc51ded 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/usb.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.c
@@ -82,6 +82,7 @@ struct brcmf_usbdev_info {
82 int tx_high_watermark; 82 int tx_high_watermark;
83 int tx_freecount; 83 int tx_freecount;
84 bool tx_flowblock; 84 bool tx_flowblock;
85 spinlock_t tx_flowblock_lock;
85 86
86 struct brcmf_usbreq *tx_reqs; 87 struct brcmf_usbreq *tx_reqs;
87 struct brcmf_usbreq *rx_reqs; 88 struct brcmf_usbreq *rx_reqs;
@@ -411,6 +412,7 @@ static void brcmf_usb_tx_complete(struct urb *urb)
411{ 412{
412 struct brcmf_usbreq *req = (struct brcmf_usbreq *)urb->context; 413 struct brcmf_usbreq *req = (struct brcmf_usbreq *)urb->context;
413 struct brcmf_usbdev_info *devinfo = req->devinfo; 414 struct brcmf_usbdev_info *devinfo = req->devinfo;
415 unsigned long flags;
414 416
415 brcmf_dbg(USB, "Enter, urb->status=%d, skb=%p\n", urb->status, 417 brcmf_dbg(USB, "Enter, urb->status=%d, skb=%p\n", urb->status,
416 req->skb); 418 req->skb);
@@ -419,11 +421,13 @@ static void brcmf_usb_tx_complete(struct urb *urb)
419 brcmf_txcomplete(devinfo->dev, req->skb, urb->status == 0); 421 brcmf_txcomplete(devinfo->dev, req->skb, urb->status == 0);
420 req->skb = NULL; 422 req->skb = NULL;
421 brcmf_usb_enq(devinfo, &devinfo->tx_freeq, req, &devinfo->tx_freecount); 423 brcmf_usb_enq(devinfo, &devinfo->tx_freeq, req, &devinfo->tx_freecount);
424 spin_lock_irqsave(&devinfo->tx_flowblock_lock, flags);
422 if (devinfo->tx_freecount > devinfo->tx_high_watermark && 425 if (devinfo->tx_freecount > devinfo->tx_high_watermark &&
423 devinfo->tx_flowblock) { 426 devinfo->tx_flowblock) {
424 brcmf_txflowblock(devinfo->dev, false); 427 brcmf_txflowblock(devinfo->dev, false);
425 devinfo->tx_flowblock = false; 428 devinfo->tx_flowblock = false;
426 } 429 }
430 spin_unlock_irqrestore(&devinfo->tx_flowblock_lock, flags);
427} 431}
428 432
429static void brcmf_usb_rx_complete(struct urb *urb) 433static void brcmf_usb_rx_complete(struct urb *urb)
@@ -568,6 +572,7 @@ static int brcmf_usb_tx(struct device *dev, struct sk_buff *skb)
568 struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev); 572 struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);
569 struct brcmf_usbreq *req; 573 struct brcmf_usbreq *req;
570 int ret; 574 int ret;
575 unsigned long flags;
571 576
572 brcmf_dbg(USB, "Enter, skb=%p\n", skb); 577 brcmf_dbg(USB, "Enter, skb=%p\n", skb);
573 if (devinfo->bus_pub.state != BRCMFMAC_USB_STATE_UP) { 578 if (devinfo->bus_pub.state != BRCMFMAC_USB_STATE_UP) {
@@ -599,11 +604,13 @@ static int brcmf_usb_tx(struct device *dev, struct sk_buff *skb)
599 goto fail; 604 goto fail;
600 } 605 }
601 606
607 spin_lock_irqsave(&devinfo->tx_flowblock_lock, flags);
602 if (devinfo->tx_freecount < devinfo->tx_low_watermark && 608 if (devinfo->tx_freecount < devinfo->tx_low_watermark &&
603 !devinfo->tx_flowblock) { 609 !devinfo->tx_flowblock) {
604 brcmf_txflowblock(dev, true); 610 brcmf_txflowblock(dev, true);
605 devinfo->tx_flowblock = true; 611 devinfo->tx_flowblock = true;
606 } 612 }
613 spin_unlock_irqrestore(&devinfo->tx_flowblock_lock, flags);
607 return 0; 614 return 0;
608 615
609fail: 616fail:
@@ -1164,6 +1171,7 @@ struct brcmf_usbdev *brcmf_usb_attach(struct brcmf_usbdev_info *devinfo,
1164 1171
1165 /* Initialize the spinlocks */ 1172 /* Initialize the spinlocks */
1166 spin_lock_init(&devinfo->qlock); 1173 spin_lock_init(&devinfo->qlock);
1174 spin_lock_init(&devinfo->tx_flowblock_lock);
1167 1175
1168 INIT_LIST_HEAD(&devinfo->rx_freeq); 1176 INIT_LIST_HEAD(&devinfo->rx_freeq);
1169 INIT_LIST_HEAD(&devinfo->rx_postq); 1177 INIT_LIST_HEAD(&devinfo->rx_postq);