aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHante Meuleman <meuleman@broadcom.com>2012-08-30 04:05:36 -0400
committerJohn W. Linville <linville@tuxdriver.com>2012-09-05 14:53:34 -0400
commit2e875acd399fcc6e301063e5ead371ad089d5920 (patch)
treeb8b8d887ae56d7caf8b9e2bd6186d2c972caaa82
parent474ab7cea4001f07ec8599a680fd19d8761fa7d8 (diff)
brcmfmac: fix race condition for rx and tx data.
On both rx and tx there is was a race condition on the queueing of usb requests. When for example frame gets submitted it is possible that complete function gets called even before usb_submit_urb() returns. As a result it is possible that usb requests get losts, which was noticed on OMAP4 pandaboard platform. This patch fixes the race condition. 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>
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/usb.c21
1 files changed, 11 insertions, 10 deletions
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/brcm80211/brcmfmac/usb.c
index 8ea2db7326b..58f89fa9c9f 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/usb.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.c
@@ -550,6 +550,7 @@ static void brcmf_usb_rx_complete(struct urb *urb)
550 if (brcmf_proto_hdrpull(devinfo->dev, &ifidx, skb) != 0) { 550 if (brcmf_proto_hdrpull(devinfo->dev, &ifidx, skb) != 0) {
551 brcmf_dbg(ERROR, "rx protocol error\n"); 551 brcmf_dbg(ERROR, "rx protocol error\n");
552 brcmu_pkt_buf_free_skb(skb); 552 brcmu_pkt_buf_free_skb(skb);
553 brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req);
553 devinfo->bus_pub.bus->dstats.rx_errors++; 554 devinfo->bus_pub.bus->dstats.rx_errors++;
554 } else { 555 } else {
555 brcmf_rx_packet(devinfo->dev, ifidx, skb); 556 brcmf_rx_packet(devinfo->dev, ifidx, skb);
@@ -557,6 +558,7 @@ static void brcmf_usb_rx_complete(struct urb *urb)
557 } 558 }
558 } else { 559 } else {
559 brcmu_pkt_buf_free_skb(skb); 560 brcmu_pkt_buf_free_skb(skb);
561 brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req);
560 } 562 }
561 return; 563 return;
562 564
@@ -582,11 +584,11 @@ static void brcmf_usb_rx_refill(struct brcmf_usbdev_info *devinfo,
582 skb->data, skb_tailroom(skb), brcmf_usb_rx_complete, 584 skb->data, skb_tailroom(skb), brcmf_usb_rx_complete,
583 req); 585 req);
584 req->devinfo = devinfo; 586 req->devinfo = devinfo;
587 brcmf_usb_enq(devinfo, &devinfo->rx_postq, req);
585 588
586 ret = usb_submit_urb(req->urb, GFP_ATOMIC); 589 ret = usb_submit_urb(req->urb, GFP_ATOMIC);
587 if (ret == 0) { 590 if (ret) {
588 brcmf_usb_enq(devinfo, &devinfo->rx_postq, req); 591 brcmf_usb_del_fromq(devinfo, req);
589 } else {
590 brcmu_pkt_buf_free_skb(req->skb); 592 brcmu_pkt_buf_free_skb(req->skb);
591 req->skb = NULL; 593 req->skb = NULL;
592 brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req); 594 brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req);
@@ -682,23 +684,22 @@ static int brcmf_usb_tx(struct device *dev, struct sk_buff *skb)
682 684
683 req = brcmf_usb_deq(devinfo, &devinfo->tx_freeq); 685 req = brcmf_usb_deq(devinfo, &devinfo->tx_freeq);
684 if (!req) { 686 if (!req) {
687 brcmu_pkt_buf_free_skb(skb);
685 brcmf_dbg(ERROR, "no req to send\n"); 688 brcmf_dbg(ERROR, "no req to send\n");
686 return -ENOMEM; 689 return -ENOMEM;
687 } 690 }
688 if (!req->urb) {
689 brcmf_dbg(ERROR, "no urb for req %p\n", req);
690 return -ENOBUFS;
691 }
692 691
693 req->skb = skb; 692 req->skb = skb;
694 req->devinfo = devinfo; 693 req->devinfo = devinfo;
695 usb_fill_bulk_urb(req->urb, devinfo->usbdev, devinfo->tx_pipe, 694 usb_fill_bulk_urb(req->urb, devinfo->usbdev, devinfo->tx_pipe,
696 skb->data, skb->len, brcmf_usb_tx_complete, req); 695 skb->data, skb->len, brcmf_usb_tx_complete, req);
697 req->urb->transfer_flags |= URB_ZERO_PACKET; 696 req->urb->transfer_flags |= URB_ZERO_PACKET;
697 brcmf_usb_enq(devinfo, &devinfo->tx_postq, req);
698 ret = usb_submit_urb(req->urb, GFP_ATOMIC); 698 ret = usb_submit_urb(req->urb, GFP_ATOMIC);
699 if (!ret) { 699 if (ret) {
700 brcmf_usb_enq(devinfo, &devinfo->tx_postq, req); 700 brcmf_dbg(ERROR, "brcmf_usb_tx usb_submit_urb FAILED\n");
701 } else { 701 brcmf_usb_del_fromq(devinfo, req);
702 brcmu_pkt_buf_free_skb(req->skb);
702 req->skb = NULL; 703 req->skb = NULL;
703 brcmf_usb_enq(devinfo, &devinfo->tx_freeq, req); 704 brcmf_usb_enq(devinfo, &devinfo->tx_freeq, req);
704 } 705 }