diff options
author | Arend van Spriel <arend@broadcom.com> | 2012-11-14 21:46:09 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2012-11-16 14:28:49 -0500 |
commit | bdf5ff516b453137cecb71e60ff860ec0a704509 (patch) | |
tree | 2e0dca2869b5546623305d9ef1e0c63145d1aba4 | |
parent | 699b5e5b0ba19b41ddd31ea5dc87d3c5e512342c (diff) |
brcmfmac: fix for multiple netdevice interface support
virtual netdevice interface like P2P client and GO need
different callbacks for .open and .down. This patch adds
those.
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
Signed-off-by: Arend van Spriel <arend@broadcom.com>
Signed-off-by: Franky Lin <frankyl@broadcom.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
4 files changed, 67 insertions, 67 deletions
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h index a41e1c69f8c5..499c5c240e04 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h | |||
@@ -513,8 +513,6 @@ struct brcmf_pub { | |||
513 | struct mutex proto_block; | 513 | struct mutex proto_block; |
514 | unsigned char proto_buf[BRCMF_DCMD_MAXLEN]; | 514 | unsigned char proto_buf[BRCMF_DCMD_MAXLEN]; |
515 | 515 | ||
516 | struct work_struct setmacaddr_work; | ||
517 | struct work_struct multicast_work; | ||
518 | u8 macvalue[ETH_ALEN]; | 516 | u8 macvalue[ETH_ALEN]; |
519 | atomic_t pend_8021x_cnt; | 517 | atomic_t pend_8021x_cnt; |
520 | wait_queue_head_t pend_8021x_wait; | 518 | wait_queue_head_t pend_8021x_wait; |
@@ -556,6 +554,8 @@ struct brcmf_if { | |||
556 | struct brcmf_cfg80211_vif *vif; | 554 | struct brcmf_cfg80211_vif *vif; |
557 | struct net_device *ndev; | 555 | struct net_device *ndev; |
558 | struct net_device_stats stats; | 556 | struct net_device_stats stats; |
557 | struct work_struct setmacaddr_work; | ||
558 | struct work_struct multicast_work; | ||
559 | int idx; | 559 | int idx; |
560 | s32 bssidx; | 560 | s32 bssidx; |
561 | u8 mac_addr[ETH_ALEN]; | 561 | u8 mac_addr[ETH_ALEN]; |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c index f10203410b39..32b73550e5ad 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c | |||
@@ -105,12 +105,10 @@ static void _brcmf_set_multicast_list(struct work_struct *work) | |||
105 | char *buf, *bufp; | 105 | char *buf, *bufp; |
106 | u32 buflen; | 106 | u32 buflen; |
107 | s32 err; | 107 | s32 err; |
108 | struct brcmf_pub *drvr = container_of(work, struct brcmf_pub, | ||
109 | multicast_work); | ||
110 | 108 | ||
111 | brcmf_dbg(TRACE, "enter\n"); | 109 | brcmf_dbg(TRACE, "enter\n"); |
112 | 110 | ||
113 | ifp = drvr->iflist[0]; | 111 | ifp = container_of(work, struct brcmf_if, multicast_work); |
114 | ndev = ifp->ndev; | 112 | ndev = ifp->ndev; |
115 | 113 | ||
116 | /* Determine initial value of allmulti flag */ | 114 | /* Determine initial value of allmulti flag */ |
@@ -165,45 +163,37 @@ static void | |||
165 | _brcmf_set_mac_address(struct work_struct *work) | 163 | _brcmf_set_mac_address(struct work_struct *work) |
166 | { | 164 | { |
167 | struct brcmf_if *ifp; | 165 | struct brcmf_if *ifp; |
168 | struct net_device *ndev; | ||
169 | s32 err; | 166 | s32 err; |
170 | 167 | ||
171 | struct brcmf_pub *drvr = container_of(work, struct brcmf_pub, | ||
172 | setmacaddr_work); | ||
173 | |||
174 | brcmf_dbg(TRACE, "enter\n"); | 168 | brcmf_dbg(TRACE, "enter\n"); |
175 | 169 | ||
176 | ifp = drvr->iflist[0]; | 170 | ifp = container_of(work, struct brcmf_if, setmacaddr_work); |
177 | ndev = ifp->ndev; | 171 | err = brcmf_fil_iovar_data_set(ifp, "cur_etheraddr", ifp->mac_addr, |
178 | |||
179 | err = brcmf_fil_iovar_data_set(ifp, "cur_etheraddr", drvr->macvalue, | ||
180 | ETH_ALEN); | 172 | ETH_ALEN); |
181 | if (err < 0) { | 173 | if (err < 0) { |
182 | brcmf_dbg(ERROR, "Setting cur_etheraddr failed, %d\n", err); | 174 | brcmf_dbg(ERROR, "Setting cur_etheraddr failed, %d\n", err); |
183 | } else { | 175 | } else { |
184 | brcmf_dbg(TRACE, "MAC address updated to %pM\n", | 176 | brcmf_dbg(TRACE, "MAC address updated to %pM\n", |
185 | drvr->macvalue); | 177 | ifp->mac_addr); |
186 | memcpy(ndev->dev_addr, drvr->macvalue, ETH_ALEN); | 178 | memcpy(ifp->ndev->dev_addr, ifp->mac_addr, ETH_ALEN); |
187 | } | 179 | } |
188 | } | 180 | } |
189 | 181 | ||
190 | static int brcmf_netdev_set_mac_address(struct net_device *ndev, void *addr) | 182 | static int brcmf_netdev_set_mac_address(struct net_device *ndev, void *addr) |
191 | { | 183 | { |
192 | struct brcmf_if *ifp = netdev_priv(ndev); | 184 | struct brcmf_if *ifp = netdev_priv(ndev); |
193 | struct brcmf_pub *drvr = ifp->drvr; | ||
194 | struct sockaddr *sa = (struct sockaddr *)addr; | 185 | struct sockaddr *sa = (struct sockaddr *)addr; |
195 | 186 | ||
196 | memcpy(&drvr->macvalue, sa->sa_data, ETH_ALEN); | 187 | memcpy(&ifp->mac_addr, sa->sa_data, ETH_ALEN); |
197 | schedule_work(&drvr->setmacaddr_work); | 188 | schedule_work(&ifp->setmacaddr_work); |
198 | return 0; | 189 | return 0; |
199 | } | 190 | } |
200 | 191 | ||
201 | static void brcmf_netdev_set_multicast_list(struct net_device *ndev) | 192 | static void brcmf_netdev_set_multicast_list(struct net_device *ndev) |
202 | { | 193 | { |
203 | struct brcmf_if *ifp = netdev_priv(ndev); | 194 | struct brcmf_if *ifp = netdev_priv(ndev); |
204 | struct brcmf_pub *drvr = ifp->drvr; | ||
205 | 195 | ||
206 | schedule_work(&drvr->multicast_work); | 196 | schedule_work(&ifp->multicast_work); |
207 | } | 197 | } |
208 | 198 | ||
209 | static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev) | 199 | static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev) |
@@ -582,7 +572,7 @@ static int brcmf_netdev_stop(struct net_device *ndev) | |||
582 | if (drvr->bus_if->drvr_up == 0) | 572 | if (drvr->bus_if->drvr_up == 0) |
583 | return 0; | 573 | return 0; |
584 | 574 | ||
585 | brcmf_cfg80211_down(drvr->config); | 575 | brcmf_cfg80211_down(ndev); |
586 | 576 | ||
587 | /* Set state and stop OS transmissions */ | 577 | /* Set state and stop OS transmissions */ |
588 | drvr->bus_if->drvr_up = false; | 578 | drvr->bus_if->drvr_up = false; |
@@ -601,26 +591,24 @@ static int brcmf_netdev_open(struct net_device *ndev) | |||
601 | 591 | ||
602 | brcmf_dbg(TRACE, "ifidx %d\n", ifp->idx); | 592 | brcmf_dbg(TRACE, "ifidx %d\n", ifp->idx); |
603 | 593 | ||
604 | if (ifp->idx == 0) { /* do it only for primary eth0 */ | 594 | /* If bus is not ready, can't continue */ |
605 | /* If bus is not ready, can't continue */ | 595 | if (bus_if->state != BRCMF_BUS_DATA) { |
606 | if (bus_if->state != BRCMF_BUS_DATA) { | 596 | brcmf_dbg(ERROR, "failed bus is not ready\n"); |
607 | brcmf_dbg(ERROR, "failed bus is not ready\n"); | 597 | return -EAGAIN; |
608 | return -EAGAIN; | 598 | } |
609 | } | ||
610 | 599 | ||
611 | atomic_set(&drvr->pend_8021x_cnt, 0); | 600 | atomic_set(&drvr->pend_8021x_cnt, 0); |
612 | 601 | ||
613 | memcpy(ndev->dev_addr, drvr->mac, ETH_ALEN); | 602 | memcpy(ndev->dev_addr, drvr->mac, ETH_ALEN); |
614 | 603 | ||
615 | /* Get current TOE mode from dongle */ | 604 | /* Get current TOE mode from dongle */ |
616 | if (brcmf_fil_iovar_int_get(ifp, "toe_ol", &toe_ol) >= 0 | 605 | if (brcmf_fil_iovar_int_get(ifp, "toe_ol", &toe_ol) >= 0 |
617 | && (toe_ol & TOE_TX_CSUM_OL) != 0) | 606 | && (toe_ol & TOE_TX_CSUM_OL) != 0) |
618 | drvr->iflist[ifp->idx]->ndev->features |= | 607 | drvr->iflist[ifp->idx]->ndev->features |= |
619 | NETIF_F_IP_CSUM; | 608 | NETIF_F_IP_CSUM; |
620 | else | 609 | else |
621 | drvr->iflist[ifp->idx]->ndev->features &= | 610 | drvr->iflist[ifp->idx]->ndev->features &= |
622 | ~NETIF_F_IP_CSUM; | 611 | ~NETIF_F_IP_CSUM; |
623 | } | ||
624 | 612 | ||
625 | /* make sure RF is ready for work */ | 613 | /* make sure RF is ready for work */ |
626 | brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0); | 614 | brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0); |
@@ -628,7 +616,7 @@ static int brcmf_netdev_open(struct net_device *ndev) | |||
628 | /* Allow transmit calls */ | 616 | /* Allow transmit calls */ |
629 | netif_start_queue(ndev); | 617 | netif_start_queue(ndev); |
630 | drvr->bus_if->drvr_up = true; | 618 | drvr->bus_if->drvr_up = true; |
631 | if (brcmf_cfg80211_up(drvr->config)) { | 619 | if (brcmf_cfg80211_up(ndev)) { |
632 | brcmf_dbg(ERROR, "failed to bring up cfg80211\n"); | 620 | brcmf_dbg(ERROR, "failed to bring up cfg80211\n"); |
633 | return -1; | 621 | return -1; |
634 | } | 622 | } |
@@ -646,16 +634,30 @@ static const struct net_device_ops brcmf_netdev_ops_pri = { | |||
646 | .ndo_set_rx_mode = brcmf_netdev_set_multicast_list | 634 | .ndo_set_rx_mode = brcmf_netdev_set_multicast_list |
647 | }; | 635 | }; |
648 | 636 | ||
637 | static const struct net_device_ops brcmf_netdev_ops_virt = { | ||
638 | .ndo_open = brcmf_cfg80211_up, | ||
639 | .ndo_stop = brcmf_cfg80211_down, | ||
640 | .ndo_get_stats = brcmf_netdev_get_stats, | ||
641 | .ndo_do_ioctl = brcmf_netdev_ioctl_entry, | ||
642 | .ndo_start_xmit = brcmf_netdev_start_xmit, | ||
643 | .ndo_set_mac_address = brcmf_netdev_set_mac_address, | ||
644 | .ndo_set_rx_mode = brcmf_netdev_set_multicast_list | ||
645 | }; | ||
646 | |||
649 | int brcmf_net_attach(struct brcmf_if *ifp) | 647 | int brcmf_net_attach(struct brcmf_if *ifp) |
650 | { | 648 | { |
651 | struct brcmf_pub *drvr = ifp->drvr; | 649 | struct brcmf_pub *drvr = ifp->drvr; |
652 | struct net_device *ndev; | 650 | struct net_device *ndev; |
653 | u8 temp_addr[ETH_ALEN]; | 651 | u8 temp_addr[ETH_ALEN]; |
654 | 652 | ||
655 | brcmf_dbg(TRACE, "ifidx %d\n", ifp->idx); | 653 | brcmf_dbg(TRACE, "ifidx %d mac %pM\n", ifp->idx, ifp->mac_addr); |
654 | ndev = ifp->ndev; | ||
656 | 655 | ||
657 | ndev = drvr->iflist[ifp->idx]->ndev; | 656 | /* set appropriate operations */ |
658 | ndev->netdev_ops = &brcmf_netdev_ops_pri; | 657 | if (!ifp->idx) |
658 | ndev->netdev_ops = &brcmf_netdev_ops_pri; | ||
659 | else | ||
660 | ndev->netdev_ops = &brcmf_netdev_ops_virt; | ||
659 | 661 | ||
660 | /* | 662 | /* |
661 | * determine mac address to use | 663 | * determine mac address to use |
@@ -665,13 +667,6 @@ int brcmf_net_attach(struct brcmf_if *ifp) | |||
665 | else | 667 | else |
666 | memcpy(temp_addr, drvr->mac, ETH_ALEN); | 668 | memcpy(temp_addr, drvr->mac, ETH_ALEN); |
667 | 669 | ||
668 | if (ifp->idx == 1) { | ||
669 | brcmf_dbg(TRACE, "ACCESS POINT MAC:\n"); | ||
670 | /* ACCESSPOINT INTERFACE CASE */ | ||
671 | temp_addr[0] |= 0X02; /* set bit 2 , | ||
672 | - Locally Administered address */ | ||
673 | |||
674 | } | ||
675 | ndev->hard_header_len = ETH_HLEN + drvr->hdrlen; | 670 | ndev->hard_header_len = ETH_HLEN + drvr->hdrlen; |
676 | ndev->ethtool_ops = &brcmf_ethtool_ops; | 671 | ndev->ethtool_ops = &brcmf_ethtool_ops; |
677 | 672 | ||
@@ -729,6 +724,10 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, int ifidx, s32 bssidx, | |||
729 | drvr->iflist[ifidx] = ifp; | 724 | drvr->iflist[ifidx] = ifp; |
730 | ifp->idx = ifidx; | 725 | ifp->idx = ifidx; |
731 | ifp->bssidx = bssidx; | 726 | ifp->bssidx = bssidx; |
727 | |||
728 | INIT_WORK(&ifp->setmacaddr_work, _brcmf_set_mac_address); | ||
729 | INIT_WORK(&ifp->multicast_work, _brcmf_set_multicast_list); | ||
730 | |||
732 | if (mac_addr != NULL) | 731 | if (mac_addr != NULL) |
733 | memcpy(&ifp->mac_addr, mac_addr, ETH_ALEN); | 732 | memcpy(&ifp->mac_addr, mac_addr, ETH_ALEN); |
734 | 733 | ||
@@ -760,6 +759,9 @@ void brcmf_del_if(struct brcmf_pub *drvr, int ifidx) | |||
760 | netif_stop_queue(ifp->ndev); | 759 | netif_stop_queue(ifp->ndev); |
761 | } | 760 | } |
762 | 761 | ||
762 | cancel_work_sync(&ifp->setmacaddr_work); | ||
763 | cancel_work_sync(&ifp->multicast_work); | ||
764 | |||
763 | unregister_netdev(ifp->ndev); | 765 | unregister_netdev(ifp->ndev); |
764 | drvr->iflist[ifidx] = NULL; | 766 | drvr->iflist[ifidx] = NULL; |
765 | if (ifidx == 0) | 767 | if (ifidx == 0) |
@@ -801,9 +803,6 @@ int brcmf_attach(uint bus_hdrlen, struct device *dev) | |||
801 | /* attach firmware event handler */ | 803 | /* attach firmware event handler */ |
802 | brcmf_fweh_attach(drvr); | 804 | brcmf_fweh_attach(drvr); |
803 | 805 | ||
804 | INIT_WORK(&drvr->setmacaddr_work, _brcmf_set_mac_address); | ||
805 | INIT_WORK(&drvr->multicast_work, _brcmf_set_multicast_list); | ||
806 | |||
807 | INIT_LIST_HEAD(&drvr->bus_if->dcmd_list); | 806 | INIT_LIST_HEAD(&drvr->bus_if->dcmd_list); |
808 | 807 | ||
809 | init_waitqueue_head(&drvr->pend_8021x_wait); | 808 | init_waitqueue_head(&drvr->pend_8021x_wait); |
@@ -904,8 +903,6 @@ void brcmf_detach(struct device *dev) | |||
904 | brcmf_bus_detach(drvr); | 903 | brcmf_bus_detach(drvr); |
905 | 904 | ||
906 | if (drvr->prot) { | 905 | if (drvr->prot) { |
907 | cancel_work_sync(&drvr->setmacaddr_work); | ||
908 | cancel_work_sync(&drvr->multicast_work); | ||
909 | brcmf_proto_detach(drvr); | 906 | brcmf_proto_detach(drvr); |
910 | } | 907 | } |
911 | 908 | ||
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index e6d2d40ad8d5..14cf71b4251c 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | |||
@@ -4526,19 +4526,18 @@ default_conf_out: | |||
4526 | 4526 | ||
4527 | } | 4527 | } |
4528 | 4528 | ||
4529 | static s32 __brcmf_cfg80211_up(struct brcmf_cfg80211_info *cfg) | 4529 | static s32 __brcmf_cfg80211_up(struct brcmf_if *ifp) |
4530 | { | 4530 | { |
4531 | struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg)); | ||
4532 | |||
4533 | set_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state); | 4531 | set_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state); |
4532 | if (ifp->idx) | ||
4533 | return 0; | ||
4534 | 4534 | ||
4535 | return brcmf_config_dongle(cfg); | 4535 | return brcmf_config_dongle(ifp->drvr->config); |
4536 | } | 4536 | } |
4537 | 4537 | ||
4538 | static s32 __brcmf_cfg80211_down(struct brcmf_cfg80211_info *cfg) | 4538 | static s32 __brcmf_cfg80211_down(struct brcmf_if *ifp) |
4539 | { | 4539 | { |
4540 | struct net_device *ndev = cfg_to_ndev(cfg); | 4540 | struct brcmf_cfg80211_info *cfg = ifp->drvr->config; |
4541 | struct brcmf_if *ifp = netdev_priv(ndev); | ||
4542 | 4541 | ||
4543 | /* | 4542 | /* |
4544 | * While going down, if associated with AP disassociate | 4543 | * While going down, if associated with AP disassociate |
@@ -4563,23 +4562,27 @@ static s32 __brcmf_cfg80211_down(struct brcmf_cfg80211_info *cfg) | |||
4563 | return 0; | 4562 | return 0; |
4564 | } | 4563 | } |
4565 | 4564 | ||
4566 | s32 brcmf_cfg80211_up(struct brcmf_cfg80211_info *cfg) | 4565 | s32 brcmf_cfg80211_up(struct net_device *ndev) |
4567 | { | 4566 | { |
4567 | struct brcmf_if *ifp = netdev_priv(ndev); | ||
4568 | struct brcmf_cfg80211_info *cfg = ifp->drvr->config; | ||
4568 | s32 err = 0; | 4569 | s32 err = 0; |
4569 | 4570 | ||
4570 | mutex_lock(&cfg->usr_sync); | 4571 | mutex_lock(&cfg->usr_sync); |
4571 | err = __brcmf_cfg80211_up(cfg); | 4572 | err = __brcmf_cfg80211_up(ifp); |
4572 | mutex_unlock(&cfg->usr_sync); | 4573 | mutex_unlock(&cfg->usr_sync); |
4573 | 4574 | ||
4574 | return err; | 4575 | return err; |
4575 | } | 4576 | } |
4576 | 4577 | ||
4577 | s32 brcmf_cfg80211_down(struct brcmf_cfg80211_info *cfg) | 4578 | s32 brcmf_cfg80211_down(struct net_device *ndev) |
4578 | { | 4579 | { |
4580 | struct brcmf_if *ifp = netdev_priv(ndev); | ||
4581 | struct brcmf_cfg80211_info *cfg = ifp->drvr->config; | ||
4579 | s32 err = 0; | 4582 | s32 err = 0; |
4580 | 4583 | ||
4581 | mutex_lock(&cfg->usr_sync); | 4584 | mutex_lock(&cfg->usr_sync); |
4582 | err = __brcmf_cfg80211_down(cfg); | 4585 | err = __brcmf_cfg80211_down(ifp); |
4583 | mutex_unlock(&cfg->usr_sync); | 4586 | mutex_unlock(&cfg->usr_sync); |
4584 | 4587 | ||
4585 | return err; | 4588 | return err; |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h index 80ba2ea378e4..e2ef8519ea84 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h | |||
@@ -455,7 +455,7 @@ brcmf_cfg80211_connect_info *cfg_to_conn(struct brcmf_cfg80211_info *cfg) | |||
455 | 455 | ||
456 | struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr); | 456 | struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr); |
457 | void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg); | 457 | void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg); |
458 | s32 brcmf_cfg80211_up(struct brcmf_cfg80211_info *cfg); | 458 | s32 brcmf_cfg80211_up(struct net_device *ndev); |
459 | s32 brcmf_cfg80211_down(struct brcmf_cfg80211_info *cfg); | 459 | s32 brcmf_cfg80211_down(struct net_device *ndev); |
460 | 460 | ||
461 | #endif /* _wl_cfg80211_h_ */ | 461 | #endif /* _wl_cfg80211_h_ */ |