aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHante Meuleman <meuleman@broadcom.com>2012-11-14 21:46:07 -0500
committerJohn W. Linville <linville@tuxdriver.com>2012-11-16 14:28:47 -0500
commit7c38e6982582541aa591f227917862f06b8abf23 (patch)
treea93ab595857d1cf614d8407ed3d214d3a5d43761
parent83bc9c313d2d8af7900ec6f78a7a1f1b1f232af6 (diff)
brcmfmac: usb suspend/resume.
Add support for usb suspend/resume. 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: Franky Lin <frankyl@broadcom.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/usb.c136
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/usb.h18
2 files changed, 58 insertions, 96 deletions
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/brcm80211/brcmfmac/usb.c
index 395c49d6e80e..589afe6b3fb3 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/usb.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.c
@@ -67,16 +67,6 @@
67#define BRCMF_USB_43236_FW_NAME "brcm/brcmfmac43236b.bin" 67#define BRCMF_USB_43236_FW_NAME "brcm/brcmfmac43236b.bin"
68#define BRCMF_USB_43242_FW_NAME "brcm/brcmfmac43242a.bin" 68#define BRCMF_USB_43242_FW_NAME "brcm/brcmfmac43242a.bin"
69 69
70enum usbdev_suspend_state {
71 USBOS_SUSPEND_STATE_DEVICE_ACTIVE = 0, /* Device is busy, won't allow
72 suspend */
73 USBOS_SUSPEND_STATE_SUSPEND_PENDING, /* Device is idle, can be
74 * suspended. Wating PM to
75 * suspend the device
76 */
77 USBOS_SUSPEND_STATE_SUSPENDED /* Device suspended */
78};
79
80struct brcmf_usb_image { 70struct brcmf_usb_image {
81 struct list_head list; 71 struct list_head list;
82 s8 *fwname; 72 s8 *fwname;
@@ -97,10 +87,8 @@ struct brcmf_usbdev_info {
97 struct list_head rx_postq; 87 struct list_head rx_postq;
98 struct list_head tx_freeq; 88 struct list_head tx_freeq;
99 struct list_head tx_postq; 89 struct list_head tx_postq;
100 enum usbdev_suspend_state suspend_state;
101 uint rx_pipe, tx_pipe, intr_pipe, rx_pipe2; 90 uint rx_pipe, tx_pipe, intr_pipe, rx_pipe2;
102 91
103 bool activity;
104 int rx_low_watermark; 92 int rx_low_watermark;
105 int tx_low_watermark; 93 int tx_low_watermark;
106 int tx_high_watermark; 94 int tx_high_watermark;
@@ -213,11 +201,6 @@ brcmf_usb_ctlwrite_complete(struct urb *urb)
213 urb->status); 201 urb->status);
214} 202}
215 203
216static int brcmf_usb_pnp(struct brcmf_usbdev_info *devinfo, uint state)
217{
218 return 0;
219}
220
221static int 204static int
222brcmf_usb_send_ctl(struct brcmf_usbdev_info *devinfo, u8 *buf, int len) 205brcmf_usb_send_ctl(struct brcmf_usbdev_info *devinfo, u8 *buf, int len)
223{ 206{
@@ -229,14 +212,6 @@ brcmf_usb_send_ctl(struct brcmf_usbdev_info *devinfo, u8 *buf, int len)
229 len == 0 || devinfo->ctl_urb == NULL) 212 len == 0 || devinfo->ctl_urb == NULL)
230 return -EINVAL; 213 return -EINVAL;
231 214
232 /* If the USB/HSIC bus in sleep state, wake it up */
233 if (devinfo->suspend_state == USBOS_SUSPEND_STATE_SUSPENDED)
234 if (brcmf_usb_pnp(devinfo, BCMFMAC_USB_PNP_RESUME) != 0) {
235 brcmf_dbg(ERROR, "Could not Resume the bus!\n");
236 return -EIO;
237 }
238
239 devinfo->activity = true;
240 size = len; 215 size = len;
241 devinfo->ctl_write.wLength = cpu_to_le16p(&size); 216 devinfo->ctl_write.wLength = cpu_to_le16p(&size);
242 devinfo->ctl_urb->transfer_buffer_length = size; 217 devinfo->ctl_urb->transfer_buffer_length = size;
@@ -299,10 +274,8 @@ static int brcmf_usb_tx_ctlpkt(struct device *dev, u8 *buf, u32 len)
299 struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev); 274 struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);
300 275
301 brcmf_dbg(USB, "Enter\n"); 276 brcmf_dbg(USB, "Enter\n");
302 if (devinfo->bus_pub.state != BCMFMAC_USB_STATE_UP) { 277 if (devinfo->bus_pub.state != BRCMFMAC_USB_STATE_UP)
303 /* TODO: handle suspend/resume */
304 return -EIO; 278 return -EIO;
305 }
306 279
307 if (test_and_set_bit(0, &devinfo->ctl_op)) 280 if (test_and_set_bit(0, &devinfo->ctl_op))
308 return -EIO; 281 return -EIO;
@@ -330,10 +303,9 @@ static int brcmf_usb_rx_ctlpkt(struct device *dev, u8 *buf, u32 len)
330 struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev); 303 struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);
331 304
332 brcmf_dbg(USB, "Enter\n"); 305 brcmf_dbg(USB, "Enter\n");
333 if (devinfo->bus_pub.state != BCMFMAC_USB_STATE_UP) { 306 if (devinfo->bus_pub.state != BRCMFMAC_USB_STATE_UP)
334 /* TODO: handle suspend/resume */
335 return -EIO; 307 return -EIO;
336 } 308
337 if (test_and_set_bit(0, &devinfo->ctl_op)) 309 if (test_and_set_bit(0, &devinfo->ctl_op))
338 return -EIO; 310 return -EIO;
339 311
@@ -499,7 +471,7 @@ static void brcmf_usb_rx_complete(struct urb *urb)
499 return; 471 return;
500 } 472 }
501 473
502 if (devinfo->bus_pub.state == BCMFMAC_USB_STATE_UP) { 474 if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_UP) {
503 skb_put(skb, urb->actual_length); 475 skb_put(skb, urb->actual_length);
504 if (brcmf_proto_hdrpull(devinfo->dev, &ifidx, skb) != 0) { 476 if (brcmf_proto_hdrpull(devinfo->dev, &ifidx, skb) != 0) {
505 brcmf_dbg(ERROR, "rx protocol error\n"); 477 brcmf_dbg(ERROR, "rx protocol error\n");
@@ -552,8 +524,8 @@ static void brcmf_usb_rx_fill_all(struct brcmf_usbdev_info *devinfo)
552{ 524{
553 struct brcmf_usbreq *req; 525 struct brcmf_usbreq *req;
554 526
555 if (devinfo->bus_pub.state != BCMFMAC_USB_STATE_UP) { 527 if (devinfo->bus_pub.state != BRCMFMAC_USB_STATE_UP) {
556 brcmf_dbg(ERROR, "bus is not up\n"); 528 brcmf_dbg(ERROR, "bus is not up=%d\n", devinfo->bus_pub.state);
557 return; 529 return;
558 } 530 }
559 while ((req = brcmf_usb_deq(devinfo, &devinfo->rx_freeq, NULL)) != NULL) 531 while ((req = brcmf_usb_deq(devinfo, &devinfo->rx_freeq, NULL)) != NULL)
@@ -573,20 +545,15 @@ brcmf_usb_state_change(struct brcmf_usbdev_info *devinfo, int state)
573 return; 545 return;
574 546
575 old_state = devinfo->bus_pub.state; 547 old_state = devinfo->bus_pub.state;
576 548 devinfo->bus_pub.state = state;
577 /* Don't update state if it's PnP firmware re-download */
578 if (state != BCMFMAC_USB_STATE_PNP_FWDL) /* TODO */
579 devinfo->bus_pub.state = state;
580
581 if ((old_state == BCMFMAC_USB_STATE_SLEEP)
582 && (state == BCMFMAC_USB_STATE_UP)) {
583 brcmf_usb_rx_fill_all(devinfo);
584 }
585 549
586 /* update state of upper layer */ 550 /* update state of upper layer */
587 if (state == BCMFMAC_USB_STATE_DOWN) { 551 if (state == BRCMFMAC_USB_STATE_DOWN) {
588 brcmf_dbg(USB, "DBUS is down\n"); 552 brcmf_dbg(USB, "DBUS is down\n");
589 bcmf_bus->state = BRCMF_BUS_DOWN; 553 bcmf_bus->state = BRCMF_BUS_DOWN;
554 } else if (state == BRCMFMAC_USB_STATE_UP) {
555 brcmf_dbg(USB, "DBUS is up\n");
556 bcmf_bus->state = BRCMF_BUS_DATA;
590 } else { 557 } else {
591 brcmf_dbg(USB, "DBUS current state=%d\n", state); 558 brcmf_dbg(USB, "DBUS current state=%d\n", state);
592 } 559 }
@@ -597,7 +564,7 @@ brcmf_usb_intr_complete(struct urb *urb)
597{ 564{
598 struct brcmf_usbdev_info *devinfo = 565 struct brcmf_usbdev_info *devinfo =
599 (struct brcmf_usbdev_info *)urb->context; 566 (struct brcmf_usbdev_info *)urb->context;
600 bool killed; 567 int err;
601 568
602 brcmf_dbg(USB, "Enter, urb->status=%d\n", urb->status); 569 brcmf_dbg(USB, "Enter, urb->status=%d\n", urb->status);
603 570
@@ -605,24 +572,24 @@ brcmf_usb_intr_complete(struct urb *urb)
605 return; 572 return;
606 573
607 if (unlikely(urb->status)) { 574 if (unlikely(urb->status)) {
608 if (devinfo->suspend_state == 575 if (urb->status == -ENOENT ||
609 USBOS_SUSPEND_STATE_SUSPEND_PENDING) 576 urb->status == -ESHUTDOWN ||
610 killed = true; 577 urb->status == -ENODEV) {
611 578 brcmf_usb_state_change(devinfo,
612 if ((urb->status == -ENOENT && (!killed)) 579 BRCMFMAC_USB_STATE_DOWN);
613 || urb->status == -ESHUTDOWN ||
614 urb->status == -ENODEV) {
615 brcmf_usb_state_change(devinfo, BCMFMAC_USB_STATE_DOWN);
616 } 580 }
617 } 581 }
618 582
619 if (devinfo->bus_pub.state == BCMFMAC_USB_STATE_DOWN) { 583 if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_DOWN) {
620 brcmf_dbg(ERROR, "intr cb when DBUS down, ignoring\n"); 584 brcmf_dbg(ERROR, "intr cb when DBUS down, ignoring\n");
621 return; 585 return;
622 } 586 }
623 587
624 if (devinfo->bus_pub.state == BCMFMAC_USB_STATE_UP) 588 if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_UP) {
625 usb_submit_urb(devinfo->intr_urb, GFP_ATOMIC); 589 err = usb_submit_urb(devinfo->intr_urb, GFP_ATOMIC);
590 if (err)
591 brcmf_dbg(ERROR, "usb_submit_urb, err=%d\n", err);
592 }
626} 593}
627 594
628static int brcmf_usb_tx(struct device *dev, struct sk_buff *skb) 595static int brcmf_usb_tx(struct device *dev, struct sk_buff *skb)
@@ -632,10 +599,8 @@ static int brcmf_usb_tx(struct device *dev, struct sk_buff *skb)
632 int ret; 599 int ret;
633 600
634 brcmf_dbg(USB, "Enter, skb=%p\n", skb); 601 brcmf_dbg(USB, "Enter, skb=%p\n", skb);
635 if (devinfo->bus_pub.state != BCMFMAC_USB_STATE_UP) { 602 if (devinfo->bus_pub.state != BRCMFMAC_USB_STATE_UP)
636 /* TODO: handle suspend/resume */
637 return -EIO; 603 return -EIO;
638 }
639 604
640 req = brcmf_usb_deq(devinfo, &devinfo->tx_freeq, 605 req = brcmf_usb_deq(devinfo, &devinfo->tx_freeq,
641 &devinfo->tx_freecount); 606 &devinfo->tx_freecount);
@@ -675,26 +640,16 @@ static int brcmf_usb_up(struct device *dev)
675{ 640{
676 struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev); 641 struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);
677 u16 ifnum; 642 u16 ifnum;
643 int ret;
678 644
679 brcmf_dbg(USB, "Enter\n"); 645 brcmf_dbg(USB, "Enter\n");
680 if (devinfo->bus_pub.state == BCMFMAC_USB_STATE_UP) 646 if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_UP)
681 return 0; 647 return 0;
682 648
683 /* If the USB/HSIC bus in sleep state, wake it up */
684 if (devinfo->suspend_state == USBOS_SUSPEND_STATE_SUSPENDED) {
685 if (brcmf_usb_pnp(devinfo, BCMFMAC_USB_PNP_RESUME) != 0) {
686 brcmf_dbg(ERROR, "Could not Resume the bus!\n");
687 return -EIO;
688 }
689 }
690 devinfo->activity = true;
691
692 /* Success, indicate devinfo is fully up */ 649 /* Success, indicate devinfo is fully up */
693 brcmf_usb_state_change(devinfo, BCMFMAC_USB_STATE_UP); 650 brcmf_usb_state_change(devinfo, BRCMFMAC_USB_STATE_UP);
694 651
695 if (devinfo->intr_urb) { 652 if (devinfo->intr_urb) {
696 int ret;
697
698 usb_fill_int_urb(devinfo->intr_urb, devinfo->usbdev, 653 usb_fill_int_urb(devinfo->intr_urb, devinfo->usbdev,
699 devinfo->intr_pipe, 654 devinfo->intr_pipe,
700 &devinfo->intr, 655 &devinfo->intr,
@@ -743,10 +698,10 @@ static void brcmf_usb_down(struct device *dev)
743 if (devinfo == NULL) 698 if (devinfo == NULL)
744 return; 699 return;
745 700
746 if (devinfo->bus_pub.state == BCMFMAC_USB_STATE_DOWN) 701 if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_DOWN)
747 return; 702 return;
748 703
749 brcmf_usb_state_change(devinfo, BCMFMAC_USB_STATE_DOWN); 704 brcmf_usb_state_change(devinfo, BRCMFMAC_USB_STATE_DOWN);
750 if (devinfo->intr_urb) 705 if (devinfo->intr_urb)
751 usb_kill_urb(devinfo->intr_urb); 706 usb_kill_urb(devinfo->intr_urb);
752 707
@@ -1006,9 +961,9 @@ static int brcmf_usb_dlstart(struct brcmf_usbdev_info *devinfo, u8 *fw, int len)
1006 961
1007 err = brcmf_usb_dl_writeimage(devinfo, fw, len); 962 err = brcmf_usb_dl_writeimage(devinfo, fw, len);
1008 if (err == 0) 963 if (err == 0)
1009 devinfo->bus_pub.state = BCMFMAC_USB_STATE_DL_DONE; 964 devinfo->bus_pub.state = BRCMFMAC_USB_STATE_DL_DONE;
1010 else 965 else
1011 devinfo->bus_pub.state = BCMFMAC_USB_STATE_DL_PENDING; 966 devinfo->bus_pub.state = BRCMFMAC_USB_STATE_DL_FAIL;
1012 brcmf_dbg(USB, "Exit, err=%d\n", err); 967 brcmf_dbg(USB, "Exit, err=%d\n", err);
1013 968
1014 return err; 969 return err;
@@ -1221,6 +1176,7 @@ struct brcmf_usbdev *brcmf_usb_attach(struct brcmf_usbdev_info *devinfo,
1221 devinfo->rx_low_watermark = nrxq / 2; 1176 devinfo->rx_low_watermark = nrxq / 2;
1222 devinfo->bus_pub.devinfo = devinfo; 1177 devinfo->bus_pub.devinfo = devinfo;
1223 devinfo->bus_pub.ntxq = ntxq; 1178 devinfo->bus_pub.ntxq = ntxq;
1179 devinfo->bus_pub.state = BRCMFMAC_USB_STATE_DOWN;
1224 1180
1225 /* flow control when too many tx urbs posted */ 1181 /* flow control when too many tx urbs posted */
1226 devinfo->tx_low_watermark = ntxq / 4; 1182 devinfo->tx_low_watermark = ntxq / 4;
@@ -1491,7 +1447,7 @@ brcmf_usb_disconnect(struct usb_interface *intf)
1491} 1447}
1492 1448
1493/* 1449/*
1494 * only need to signal the bus being down and update the suspend state. 1450 * only need to signal the bus being down and update the state.
1495 */ 1451 */
1496static int brcmf_usb_suspend(struct usb_interface *intf, pm_message_t state) 1452static int brcmf_usb_suspend(struct usb_interface *intf, pm_message_t state)
1497{ 1453{
@@ -1499,13 +1455,13 @@ static int brcmf_usb_suspend(struct usb_interface *intf, pm_message_t state)
1499 struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(&usb->dev); 1455 struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(&usb->dev);
1500 1456
1501 brcmf_dbg(USB, "Enter\n"); 1457 brcmf_dbg(USB, "Enter\n");
1502 devinfo->bus_pub.state = BCMFMAC_USB_STATE_DOWN; 1458 devinfo->bus_pub.state = BRCMFMAC_USB_STATE_SLEEP;
1503 devinfo->suspend_state = USBOS_SUSPEND_STATE_SUSPENDED; 1459 brcmf_detach(&usb->dev);
1504 return 0; 1460 return 0;
1505} 1461}
1506 1462
1507/* 1463/*
1508 * mark suspend state active and crank up the bus. 1464 * (re-) start the bus.
1509 */ 1465 */
1510static int brcmf_usb_resume(struct usb_interface *intf) 1466static int brcmf_usb_resume(struct usb_interface *intf)
1511{ 1467{
@@ -1513,11 +1469,25 @@ static int brcmf_usb_resume(struct usb_interface *intf)
1513 struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(&usb->dev); 1469 struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(&usb->dev);
1514 1470
1515 brcmf_dbg(USB, "Enter\n"); 1471 brcmf_dbg(USB, "Enter\n");
1516 devinfo->suspend_state = USBOS_SUSPEND_STATE_DEVICE_ACTIVE; 1472 if (!brcmf_attach(0, devinfo->dev))
1517 brcmf_bus_start(&usb->dev); 1473 return brcmf_bus_start(&usb->dev);
1474
1518 return 0; 1475 return 0;
1519} 1476}
1520 1477
1478static int brcmf_usb_reset_resume(struct usb_interface *intf)
1479{
1480 struct usb_device *usb = interface_to_usbdev(intf);
1481 struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(&usb->dev);
1482
1483 brcmf_dbg(USB, "Enter\n");
1484
1485 if (!brcmf_usb_fw_download(devinfo))
1486 return brcmf_usb_resume(intf);
1487
1488 return -EIO;
1489}
1490
1521#define BRCMF_USB_VENDOR_ID_BROADCOM 0x0a5c 1491#define BRCMF_USB_VENDOR_ID_BROADCOM 0x0a5c
1522#define BRCMF_USB_DEVICE_ID_43143 0xbd1e 1492#define BRCMF_USB_DEVICE_ID_43143 0xbd1e
1523#define BRCMF_USB_DEVICE_ID_43236 0xbd17 1493#define BRCMF_USB_DEVICE_ID_43236 0xbd17
@@ -1537,7 +1507,6 @@ MODULE_FIRMWARE(BRCMF_USB_43143_FW_NAME);
1537MODULE_FIRMWARE(BRCMF_USB_43236_FW_NAME); 1507MODULE_FIRMWARE(BRCMF_USB_43236_FW_NAME);
1538MODULE_FIRMWARE(BRCMF_USB_43242_FW_NAME); 1508MODULE_FIRMWARE(BRCMF_USB_43242_FW_NAME);
1539 1509
1540/* TODO: suspend and resume entries */
1541static struct usb_driver brcmf_usbdrvr = { 1510static struct usb_driver brcmf_usbdrvr = {
1542 .name = KBUILD_MODNAME, 1511 .name = KBUILD_MODNAME,
1543 .probe = brcmf_usb_probe, 1512 .probe = brcmf_usb_probe,
@@ -1545,6 +1514,7 @@ static struct usb_driver brcmf_usbdrvr = {
1545 .id_table = brcmf_usb_devid_table, 1514 .id_table = brcmf_usb_devid_table,
1546 .suspend = brcmf_usb_suspend, 1515 .suspend = brcmf_usb_suspend,
1547 .resume = brcmf_usb_resume, 1516 .resume = brcmf_usb_resume,
1517 .reset_resume = brcmf_usb_reset_resume,
1548 .supports_autosuspend = 1, 1518 .supports_autosuspend = 1,
1549 .disable_hub_initiated_lpm = 1, 1519 .disable_hub_initiated_lpm = 1,
1550}; 1520};
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.h b/drivers/net/wireless/brcm80211/brcmfmac/usb.h
index acfa5e89872f..f483a8c9945b 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/usb.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.h
@@ -17,19 +17,11 @@
17#define BRCMFMAC_USB_H 17#define BRCMFMAC_USB_H
18 18
19enum brcmf_usb_state { 19enum brcmf_usb_state {
20 BCMFMAC_USB_STATE_DL_PENDING, 20 BRCMFMAC_USB_STATE_DOWN,
21 BCMFMAC_USB_STATE_DL_DONE, 21 BRCMFMAC_USB_STATE_DL_FAIL,
22 BCMFMAC_USB_STATE_UP, 22 BRCMFMAC_USB_STATE_DL_DONE,
23 BCMFMAC_USB_STATE_DOWN, 23 BRCMFMAC_USB_STATE_UP,
24 BCMFMAC_USB_STATE_PNP_FWDL, 24 BRCMFMAC_USB_STATE_SLEEP
25 BCMFMAC_USB_STATE_DISCONNECT,
26 BCMFMAC_USB_STATE_SLEEP
27};
28
29enum brcmf_usb_pnp_state {
30 BCMFMAC_USB_PNP_DISCONNECT,
31 BCMFMAC_USB_PNP_SLEEP,
32 BCMFMAC_USB_PNP_RESUME,
33}; 25};
34 26
35struct brcmf_stats { 27struct brcmf_stats {