|
@@ -82,6 +82,7 @@ struct brcmf_usbdev_info {
|
|
|
int tx_high_watermark;
|
|
|
int tx_freecount;
|
|
|
bool tx_flowblock;
|
|
|
+ spinlock_t tx_flowblock_lock;
|
|
|
|
|
|
struct brcmf_usbreq *tx_reqs;
|
|
|
struct brcmf_usbreq *rx_reqs;
|
|
@@ -411,6 +412,7 @@ static void brcmf_usb_tx_complete(struct urb *urb)
|
|
|
{
|
|
|
struct brcmf_usbreq *req = (struct brcmf_usbreq *)urb->context;
|
|
|
struct brcmf_usbdev_info *devinfo = req->devinfo;
|
|
|
+ unsigned long flags;
|
|
|
|
|
|
brcmf_dbg(USB, "Enter, urb->status=%d, skb=%p\n", urb->status,
|
|
|
req->skb);
|
|
@@ -419,11 +421,13 @@ static void brcmf_usb_tx_complete(struct urb *urb)
|
|
|
brcmf_txcomplete(devinfo->dev, req->skb, urb->status == 0);
|
|
|
req->skb = NULL;
|
|
|
brcmf_usb_enq(devinfo, &devinfo->tx_freeq, req, &devinfo->tx_freecount);
|
|
|
+ spin_lock_irqsave(&devinfo->tx_flowblock_lock, flags);
|
|
|
if (devinfo->tx_freecount > devinfo->tx_high_watermark &&
|
|
|
devinfo->tx_flowblock) {
|
|
|
brcmf_txflowblock(devinfo->dev, false);
|
|
|
devinfo->tx_flowblock = false;
|
|
|
}
|
|
|
+ spin_unlock_irqrestore(&devinfo->tx_flowblock_lock, flags);
|
|
|
}
|
|
|
|
|
|
static void brcmf_usb_rx_complete(struct urb *urb)
|
|
@@ -568,6 +572,7 @@ static int brcmf_usb_tx(struct device *dev, struct sk_buff *skb)
|
|
|
struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);
|
|
|
struct brcmf_usbreq *req;
|
|
|
int ret;
|
|
|
+ unsigned long flags;
|
|
|
|
|
|
brcmf_dbg(USB, "Enter, skb=%p\n", skb);
|
|
|
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)
|
|
|
goto fail;
|
|
|
}
|
|
|
|
|
|
+ spin_lock_irqsave(&devinfo->tx_flowblock_lock, flags);
|
|
|
if (devinfo->tx_freecount < devinfo->tx_low_watermark &&
|
|
|
!devinfo->tx_flowblock) {
|
|
|
brcmf_txflowblock(dev, true);
|
|
|
devinfo->tx_flowblock = true;
|
|
|
}
|
|
|
+ spin_unlock_irqrestore(&devinfo->tx_flowblock_lock, flags);
|
|
|
return 0;
|
|
|
|
|
|
fail:
|
|
@@ -1164,6 +1171,7 @@ struct brcmf_usbdev *brcmf_usb_attach(struct brcmf_usbdev_info *devinfo,
|
|
|
|
|
|
/* Initialize the spinlocks */
|
|
|
spin_lock_init(&devinfo->qlock);
|
|
|
+ spin_lock_init(&devinfo->tx_flowblock_lock);
|
|
|
|
|
|
INIT_LIST_HEAD(&devinfo->rx_freeq);
|
|
|
INIT_LIST_HEAD(&devinfo->rx_postq);
|