diff options
author | Hante Meuleman <meuleman@broadcom.com> | 2012-08-30 04:05:36 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2012-09-05 14:53:34 -0400 |
commit | 2e875acd399fcc6e301063e5ead371ad089d5920 (patch) | |
tree | b8b8d887ae56d7caf8b9e2bd6186d2c972caaa82 | |
parent | 474ab7cea4001f07ec8599a680fd19d8761fa7d8 (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.c | 21 |
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 | } |