diff options
author | Hante Meuleman <meuleman@broadcom.com> | 2012-09-11 15:18:48 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2012-09-12 14:19:15 -0400 |
commit | c6ab42948d7727e9efb2e29d9a0e68b88150f319 (patch) | |
tree | 806e63a6ffa2d8d2a04dba2431a193d0462865ef /drivers/net/wireless/brcm80211/brcmfmac/usb.c | |
parent | c4fdb05696f315f43eb44c2a44fec1677ba47b31 (diff) |
brcmfmac: Add tx flow control on net if queue for USB.
Enable tx flow control for USB host interface.
Reviewed-by: Arend Van Spriel <arend@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/usb.c')
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmfmac/usb.c | 61 |
1 files changed, 36 insertions, 25 deletions
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/brcm80211/brcmfmac/usb.c index 7fe68aa69dfd..8aab2a22d6a1 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/usb.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.c | |||
@@ -119,9 +119,8 @@ struct brcmf_usbdev_info { | |||
119 | int rx_low_watermark; | 119 | int rx_low_watermark; |
120 | int tx_low_watermark; | 120 | int tx_low_watermark; |
121 | int tx_high_watermark; | 121 | int tx_high_watermark; |
122 | bool txoff; | 122 | int tx_freecount; |
123 | bool rxoff; | 123 | bool tx_flowblock; |
124 | bool txoverride; | ||
125 | 124 | ||
126 | struct brcmf_usbreq *tx_reqs; | 125 | struct brcmf_usbreq *tx_reqs; |
127 | struct brcmf_usbreq *rx_reqs; | 126 | struct brcmf_usbreq *rx_reqs; |
@@ -179,14 +178,6 @@ static struct brcmf_usbdev_info *brcmf_usb_get_businfo(struct device *dev) | |||
179 | return brcmf_usb_get_buspub(dev)->devinfo; | 178 | return brcmf_usb_get_buspub(dev)->devinfo; |
180 | } | 179 | } |
181 | 180 | ||
182 | #if 0 | ||
183 | static void | ||
184 | brcmf_usb_txflowcontrol(struct brcmf_usbdev_info *devinfo, bool onoff) | ||
185 | { | ||
186 | dhd_txflowcontrol(devinfo->bus_pub.netdev, 0, onoff); | ||
187 | } | ||
188 | #endif | ||
189 | |||
190 | static int brcmf_usb_ioctl_resp_wait(struct brcmf_usbdev_info *devinfo, | 181 | static int brcmf_usb_ioctl_resp_wait(struct brcmf_usbdev_info *devinfo, |
191 | uint *condition, bool *pending) | 182 | uint *condition, bool *pending) |
192 | { | 183 | { |
@@ -420,7 +411,7 @@ static int brcmf_usb_rx_ctlpkt(struct device *dev, u8 *buf, u32 len) | |||
420 | } | 411 | } |
421 | 412 | ||
422 | static struct brcmf_usbreq *brcmf_usb_deq(struct brcmf_usbdev_info *devinfo, | 413 | static struct brcmf_usbreq *brcmf_usb_deq(struct brcmf_usbdev_info *devinfo, |
423 | struct list_head *q) | 414 | struct list_head *q, int *counter) |
424 | { | 415 | { |
425 | unsigned long flags; | 416 | unsigned long flags; |
426 | struct brcmf_usbreq *req; | 417 | struct brcmf_usbreq *req; |
@@ -431,17 +422,22 @@ static struct brcmf_usbreq *brcmf_usb_deq(struct brcmf_usbdev_info *devinfo, | |||
431 | } | 422 | } |
432 | req = list_entry(q->next, struct brcmf_usbreq, list); | 423 | req = list_entry(q->next, struct brcmf_usbreq, list); |
433 | list_del_init(q->next); | 424 | list_del_init(q->next); |
425 | if (counter) | ||
426 | (*counter)--; | ||
434 | spin_unlock_irqrestore(&devinfo->qlock, flags); | 427 | spin_unlock_irqrestore(&devinfo->qlock, flags); |
435 | return req; | 428 | return req; |
436 | 429 | ||
437 | } | 430 | } |
438 | 431 | ||
439 | static void brcmf_usb_enq(struct brcmf_usbdev_info *devinfo, | 432 | static void brcmf_usb_enq(struct brcmf_usbdev_info *devinfo, |
440 | struct list_head *q, struct brcmf_usbreq *req) | 433 | struct list_head *q, struct brcmf_usbreq *req, |
434 | int *counter) | ||
441 | { | 435 | { |
442 | unsigned long flags; | 436 | unsigned long flags; |
443 | spin_lock_irqsave(&devinfo->qlock, flags); | 437 | spin_lock_irqsave(&devinfo->qlock, flags); |
444 | list_add_tail(&req->list, q); | 438 | list_add_tail(&req->list, q); |
439 | if (counter) | ||
440 | (*counter)++; | ||
445 | spin_unlock_irqrestore(&devinfo->qlock, flags); | 441 | spin_unlock_irqrestore(&devinfo->qlock, flags); |
446 | } | 442 | } |
447 | 443 | ||
@@ -523,8 +519,12 @@ static void brcmf_usb_tx_complete(struct urb *urb) | |||
523 | 519 | ||
524 | brcmu_pkt_buf_free_skb(req->skb); | 520 | brcmu_pkt_buf_free_skb(req->skb); |
525 | req->skb = NULL; | 521 | req->skb = NULL; |
526 | brcmf_usb_enq(devinfo, &devinfo->tx_freeq, req); | 522 | brcmf_usb_enq(devinfo, &devinfo->tx_freeq, req, &devinfo->tx_freecount); |
527 | 523 | if (devinfo->tx_freecount > devinfo->tx_high_watermark && | |
524 | devinfo->tx_flowblock) { | ||
525 | brcmf_txflowblock(devinfo->dev, false); | ||
526 | devinfo->tx_flowblock = false; | ||
527 | } | ||
528 | } | 528 | } |
529 | 529 | ||
530 | static void brcmf_usb_rx_complete(struct urb *urb) | 530 | static void brcmf_usb_rx_complete(struct urb *urb) |
@@ -543,7 +543,7 @@ static void brcmf_usb_rx_complete(struct urb *urb) | |||
543 | } else { | 543 | } else { |
544 | devinfo->bus_pub.bus->dstats.rx_errors++; | 544 | devinfo->bus_pub.bus->dstats.rx_errors++; |
545 | brcmu_pkt_buf_free_skb(skb); | 545 | brcmu_pkt_buf_free_skb(skb); |
546 | brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req); | 546 | brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req, NULL); |
547 | return; | 547 | return; |
548 | } | 548 | } |
549 | 549 | ||
@@ -552,7 +552,7 @@ static void brcmf_usb_rx_complete(struct urb *urb) | |||
552 | if (brcmf_proto_hdrpull(devinfo->dev, &ifidx, skb) != 0) { | 552 | if (brcmf_proto_hdrpull(devinfo->dev, &ifidx, skb) != 0) { |
553 | brcmf_dbg(ERROR, "rx protocol error\n"); | 553 | brcmf_dbg(ERROR, "rx protocol error\n"); |
554 | brcmu_pkt_buf_free_skb(skb); | 554 | brcmu_pkt_buf_free_skb(skb); |
555 | brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req); | 555 | brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req, NULL); |
556 | devinfo->bus_pub.bus->dstats.rx_errors++; | 556 | devinfo->bus_pub.bus->dstats.rx_errors++; |
557 | } else { | 557 | } else { |
558 | brcmf_rx_packet(devinfo->dev, ifidx, skb); | 558 | brcmf_rx_packet(devinfo->dev, ifidx, skb); |
@@ -560,7 +560,7 @@ static void brcmf_usb_rx_complete(struct urb *urb) | |||
560 | } | 560 | } |
561 | } else { | 561 | } else { |
562 | brcmu_pkt_buf_free_skb(skb); | 562 | brcmu_pkt_buf_free_skb(skb); |
563 | brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req); | 563 | brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req, NULL); |
564 | } | 564 | } |
565 | return; | 565 | return; |
566 | 566 | ||
@@ -577,7 +577,7 @@ static void brcmf_usb_rx_refill(struct brcmf_usbdev_info *devinfo, | |||
577 | 577 | ||
578 | skb = dev_alloc_skb(devinfo->bus_pub.bus_mtu); | 578 | skb = dev_alloc_skb(devinfo->bus_pub.bus_mtu); |
579 | if (!skb) { | 579 | if (!skb) { |
580 | brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req); | 580 | brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req, NULL); |
581 | return; | 581 | return; |
582 | } | 582 | } |
583 | req->skb = skb; | 583 | req->skb = skb; |
@@ -586,14 +586,14 @@ static void brcmf_usb_rx_refill(struct brcmf_usbdev_info *devinfo, | |||
586 | skb->data, skb_tailroom(skb), brcmf_usb_rx_complete, | 586 | skb->data, skb_tailroom(skb), brcmf_usb_rx_complete, |
587 | req); | 587 | req); |
588 | req->devinfo = devinfo; | 588 | req->devinfo = devinfo; |
589 | brcmf_usb_enq(devinfo, &devinfo->rx_postq, req); | 589 | brcmf_usb_enq(devinfo, &devinfo->rx_postq, req, NULL); |
590 | 590 | ||
591 | ret = usb_submit_urb(req->urb, GFP_ATOMIC); | 591 | ret = usb_submit_urb(req->urb, GFP_ATOMIC); |
592 | if (ret) { | 592 | if (ret) { |
593 | brcmf_usb_del_fromq(devinfo, req); | 593 | brcmf_usb_del_fromq(devinfo, req); |
594 | brcmu_pkt_buf_free_skb(req->skb); | 594 | brcmu_pkt_buf_free_skb(req->skb); |
595 | req->skb = NULL; | 595 | req->skb = NULL; |
596 | brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req); | 596 | brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req, NULL); |
597 | } | 597 | } |
598 | return; | 598 | return; |
599 | } | 599 | } |
@@ -606,7 +606,7 @@ static void brcmf_usb_rx_fill_all(struct brcmf_usbdev_info *devinfo) | |||
606 | brcmf_dbg(ERROR, "bus is not up\n"); | 606 | brcmf_dbg(ERROR, "bus is not up\n"); |
607 | return; | 607 | return; |
608 | } | 608 | } |
609 | while ((req = brcmf_usb_deq(devinfo, &devinfo->rx_freeq)) != NULL) | 609 | while ((req = brcmf_usb_deq(devinfo, &devinfo->rx_freeq, NULL)) != NULL) |
610 | brcmf_usb_rx_refill(devinfo, req); | 610 | brcmf_usb_rx_refill(devinfo, req); |
611 | } | 611 | } |
612 | 612 | ||
@@ -684,7 +684,8 @@ static int brcmf_usb_tx(struct device *dev, struct sk_buff *skb) | |||
684 | return -EIO; | 684 | return -EIO; |
685 | } | 685 | } |
686 | 686 | ||
687 | req = brcmf_usb_deq(devinfo, &devinfo->tx_freeq); | 687 | req = brcmf_usb_deq(devinfo, &devinfo->tx_freeq, |
688 | &devinfo->tx_freecount); | ||
688 | if (!req) { | 689 | if (!req) { |
689 | brcmu_pkt_buf_free_skb(skb); | 690 | brcmu_pkt_buf_free_skb(skb); |
690 | brcmf_dbg(ERROR, "no req to send\n"); | 691 | brcmf_dbg(ERROR, "no req to send\n"); |
@@ -696,14 +697,21 @@ static int brcmf_usb_tx(struct device *dev, struct sk_buff *skb) | |||
696 | usb_fill_bulk_urb(req->urb, devinfo->usbdev, devinfo->tx_pipe, | 697 | usb_fill_bulk_urb(req->urb, devinfo->usbdev, devinfo->tx_pipe, |
697 | skb->data, skb->len, brcmf_usb_tx_complete, req); | 698 | skb->data, skb->len, brcmf_usb_tx_complete, req); |
698 | req->urb->transfer_flags |= URB_ZERO_PACKET; | 699 | req->urb->transfer_flags |= URB_ZERO_PACKET; |
699 | brcmf_usb_enq(devinfo, &devinfo->tx_postq, req); | 700 | brcmf_usb_enq(devinfo, &devinfo->tx_postq, req, NULL); |
700 | ret = usb_submit_urb(req->urb, GFP_ATOMIC); | 701 | ret = usb_submit_urb(req->urb, GFP_ATOMIC); |
701 | if (ret) { | 702 | if (ret) { |
702 | brcmf_dbg(ERROR, "brcmf_usb_tx usb_submit_urb FAILED\n"); | 703 | brcmf_dbg(ERROR, "brcmf_usb_tx usb_submit_urb FAILED\n"); |
703 | brcmf_usb_del_fromq(devinfo, req); | 704 | brcmf_usb_del_fromq(devinfo, req); |
704 | brcmu_pkt_buf_free_skb(req->skb); | 705 | brcmu_pkt_buf_free_skb(req->skb); |
705 | req->skb = NULL; | 706 | req->skb = NULL; |
706 | brcmf_usb_enq(devinfo, &devinfo->tx_freeq, req); | 707 | brcmf_usb_enq(devinfo, &devinfo->tx_freeq, req, |
708 | &devinfo->tx_freecount); | ||
709 | } else { | ||
710 | if (devinfo->tx_freecount < devinfo->tx_low_watermark && | ||
711 | !devinfo->tx_flowblock) { | ||
712 | brcmf_txflowblock(dev, true); | ||
713 | devinfo->tx_flowblock = true; | ||
714 | } | ||
707 | } | 715 | } |
708 | 716 | ||
709 | return ret; | 717 | return ret; |
@@ -1316,6 +1324,8 @@ struct brcmf_usbdev *brcmf_usb_attach(int nrxq, int ntxq, struct device *dev) | |||
1316 | INIT_LIST_HEAD(&devinfo->tx_freeq); | 1324 | INIT_LIST_HEAD(&devinfo->tx_freeq); |
1317 | INIT_LIST_HEAD(&devinfo->tx_postq); | 1325 | INIT_LIST_HEAD(&devinfo->tx_postq); |
1318 | 1326 | ||
1327 | devinfo->tx_flowblock = false; | ||
1328 | |||
1319 | devinfo->rx_reqs = brcmf_usbdev_qinit(&devinfo->rx_freeq, nrxq); | 1329 | devinfo->rx_reqs = brcmf_usbdev_qinit(&devinfo->rx_freeq, nrxq); |
1320 | if (!devinfo->rx_reqs) | 1330 | if (!devinfo->rx_reqs) |
1321 | goto error; | 1331 | goto error; |
@@ -1323,6 +1333,7 @@ struct brcmf_usbdev *brcmf_usb_attach(int nrxq, int ntxq, struct device *dev) | |||
1323 | devinfo->tx_reqs = brcmf_usbdev_qinit(&devinfo->tx_freeq, ntxq); | 1333 | devinfo->tx_reqs = brcmf_usbdev_qinit(&devinfo->tx_freeq, ntxq); |
1324 | if (!devinfo->tx_reqs) | 1334 | if (!devinfo->tx_reqs) |
1325 | goto error; | 1335 | goto error; |
1336 | devinfo->tx_freecount = ntxq; | ||
1326 | 1337 | ||
1327 | devinfo->intr_urb = usb_alloc_urb(0, GFP_ATOMIC); | 1338 | devinfo->intr_urb = usb_alloc_urb(0, GFP_ATOMIC); |
1328 | if (!devinfo->intr_urb) { | 1339 | if (!devinfo->intr_urb) { |