forked from Minki/linux
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>
This commit is contained in:
parent
474ab7cea4
commit
2e875acd39
@ -550,6 +550,7 @@ static void brcmf_usb_rx_complete(struct urb *urb)
|
||||
if (brcmf_proto_hdrpull(devinfo->dev, &ifidx, skb) != 0) {
|
||||
brcmf_dbg(ERROR, "rx protocol error\n");
|
||||
brcmu_pkt_buf_free_skb(skb);
|
||||
brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req);
|
||||
devinfo->bus_pub.bus->dstats.rx_errors++;
|
||||
} else {
|
||||
brcmf_rx_packet(devinfo->dev, ifidx, skb);
|
||||
@ -557,6 +558,7 @@ static void brcmf_usb_rx_complete(struct urb *urb)
|
||||
}
|
||||
} else {
|
||||
brcmu_pkt_buf_free_skb(skb);
|
||||
brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req);
|
||||
}
|
||||
return;
|
||||
|
||||
@ -582,11 +584,11 @@ static void brcmf_usb_rx_refill(struct brcmf_usbdev_info *devinfo,
|
||||
skb->data, skb_tailroom(skb), brcmf_usb_rx_complete,
|
||||
req);
|
||||
req->devinfo = devinfo;
|
||||
brcmf_usb_enq(devinfo, &devinfo->rx_postq, req);
|
||||
|
||||
ret = usb_submit_urb(req->urb, GFP_ATOMIC);
|
||||
if (ret == 0) {
|
||||
brcmf_usb_enq(devinfo, &devinfo->rx_postq, req);
|
||||
} else {
|
||||
if (ret) {
|
||||
brcmf_usb_del_fromq(devinfo, req);
|
||||
brcmu_pkt_buf_free_skb(req->skb);
|
||||
req->skb = NULL;
|
||||
brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req);
|
||||
@ -682,23 +684,22 @@ static int brcmf_usb_tx(struct device *dev, struct sk_buff *skb)
|
||||
|
||||
req = brcmf_usb_deq(devinfo, &devinfo->tx_freeq);
|
||||
if (!req) {
|
||||
brcmu_pkt_buf_free_skb(skb);
|
||||
brcmf_dbg(ERROR, "no req to send\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (!req->urb) {
|
||||
brcmf_dbg(ERROR, "no urb for req %p\n", req);
|
||||
return -ENOBUFS;
|
||||
}
|
||||
|
||||
req->skb = skb;
|
||||
req->devinfo = devinfo;
|
||||
usb_fill_bulk_urb(req->urb, devinfo->usbdev, devinfo->tx_pipe,
|
||||
skb->data, skb->len, brcmf_usb_tx_complete, req);
|
||||
req->urb->transfer_flags |= URB_ZERO_PACKET;
|
||||
brcmf_usb_enq(devinfo, &devinfo->tx_postq, req);
|
||||
ret = usb_submit_urb(req->urb, GFP_ATOMIC);
|
||||
if (!ret) {
|
||||
brcmf_usb_enq(devinfo, &devinfo->tx_postq, req);
|
||||
} else {
|
||||
if (ret) {
|
||||
brcmf_dbg(ERROR, "brcmf_usb_tx usb_submit_urb FAILED\n");
|
||||
brcmf_usb_del_fromq(devinfo, req);
|
||||
brcmu_pkt_buf_free_skb(req->skb);
|
||||
req->skb = NULL;
|
||||
brcmf_usb_enq(devinfo, &devinfo->tx_freeq, req);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user