diff options
Diffstat (limited to 'drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c')
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c | 301 |
1 files changed, 104 insertions, 197 deletions
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c index 4acbac5a74c..719fd9397eb 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c | |||
@@ -58,7 +58,6 @@ struct brcmf_if { | |||
58 | struct net_device *ndev; | 58 | struct net_device *ndev; |
59 | struct net_device_stats stats; | 59 | struct net_device_stats stats; |
60 | int idx; /* iface idx in dongle */ | 60 | int idx; /* iface idx in dongle */ |
61 | int state; /* interface state */ | ||
62 | u8 mac_addr[ETH_ALEN]; /* assigned MAC address */ | 61 | u8 mac_addr[ETH_ALEN]; /* assigned MAC address */ |
63 | }; | 62 | }; |
64 | 63 | ||
@@ -80,20 +79,6 @@ struct brcmf_info { | |||
80 | /* Error bits */ | 79 | /* Error bits */ |
81 | module_param(brcmf_msg_level, int, 0); | 80 | module_param(brcmf_msg_level, int, 0); |
82 | 81 | ||
83 | |||
84 | static int brcmf_net2idx(struct brcmf_info *drvr_priv, struct net_device *ndev) | ||
85 | { | ||
86 | int i = 0; | ||
87 | |||
88 | while (i < BRCMF_MAX_IFS) { | ||
89 | if (drvr_priv->iflist[i] && drvr_priv->iflist[i]->ndev == ndev) | ||
90 | return i; | ||
91 | i++; | ||
92 | } | ||
93 | |||
94 | return BRCMF_BAD_IF; | ||
95 | } | ||
96 | |||
97 | int brcmf_ifname2idx(struct brcmf_info *drvr_priv, char *name) | 82 | int brcmf_ifname2idx(struct brcmf_info *drvr_priv, char *name) |
98 | { | 83 | { |
99 | int i = BRCMF_MAX_IFS; | 84 | int i = BRCMF_MAX_IFS; |
@@ -285,14 +270,9 @@ _brcmf_set_mac_address(struct work_struct *work) | |||
285 | 270 | ||
286 | static int brcmf_netdev_set_mac_address(struct net_device *ndev, void *addr) | 271 | static int brcmf_netdev_set_mac_address(struct net_device *ndev, void *addr) |
287 | { | 272 | { |
288 | struct brcmf_info *drvr_priv = *(struct brcmf_info **) | 273 | struct brcmf_if *ifp = netdev_priv(ndev); |
289 | netdev_priv(ndev); | 274 | struct brcmf_info *drvr_priv = ifp->info; |
290 | struct sockaddr *sa = (struct sockaddr *)addr; | 275 | struct sockaddr *sa = (struct sockaddr *)addr; |
291 | int ifidx; | ||
292 | |||
293 | ifidx = brcmf_net2idx(drvr_priv, ndev); | ||
294 | if (ifidx == BRCMF_BAD_IF) | ||
295 | return -1; | ||
296 | 276 | ||
297 | memcpy(&drvr_priv->macvalue, sa->sa_data, ETH_ALEN); | 277 | memcpy(&drvr_priv->macvalue, sa->sa_data, ETH_ALEN); |
298 | schedule_work(&drvr_priv->setmacaddr_work); | 278 | schedule_work(&drvr_priv->setmacaddr_work); |
@@ -301,13 +281,8 @@ static int brcmf_netdev_set_mac_address(struct net_device *ndev, void *addr) | |||
301 | 281 | ||
302 | static void brcmf_netdev_set_multicast_list(struct net_device *ndev) | 282 | static void brcmf_netdev_set_multicast_list(struct net_device *ndev) |
303 | { | 283 | { |
304 | struct brcmf_info *drvr_priv = *(struct brcmf_info **) | 284 | struct brcmf_if *ifp = netdev_priv(ndev); |
305 | netdev_priv(ndev); | 285 | struct brcmf_info *drvr_priv = ifp->info; |
306 | int ifidx; | ||
307 | |||
308 | ifidx = brcmf_net2idx(drvr_priv, ndev); | ||
309 | if (ifidx == BRCMF_BAD_IF) | ||
310 | return; | ||
311 | 286 | ||
312 | schedule_work(&drvr_priv->multicast_work); | 287 | schedule_work(&drvr_priv->multicast_work); |
313 | } | 288 | } |
@@ -341,9 +316,8 @@ int brcmf_sendpkt(struct brcmf_pub *drvr, int ifidx, struct sk_buff *pktbuf) | |||
341 | static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev) | 316 | static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev) |
342 | { | 317 | { |
343 | int ret; | 318 | int ret; |
344 | struct brcmf_info *drvr_priv = *(struct brcmf_info **) | 319 | struct brcmf_if *ifp = netdev_priv(ndev); |
345 | netdev_priv(ndev); | 320 | struct brcmf_info *drvr_priv = ifp->info; |
346 | int ifidx; | ||
347 | 321 | ||
348 | brcmf_dbg(TRACE, "Enter\n"); | 322 | brcmf_dbg(TRACE, "Enter\n"); |
349 | 323 | ||
@@ -355,9 +329,8 @@ static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev) | |||
355 | return -ENODEV; | 329 | return -ENODEV; |
356 | } | 330 | } |
357 | 331 | ||
358 | ifidx = brcmf_net2idx(drvr_priv, ndev); | 332 | if (!drvr_priv->iflist[ifp->idx]) { |
359 | if (ifidx == BRCMF_BAD_IF) { | 333 | brcmf_dbg(ERROR, "bad ifidx %d\n", ifp->idx); |
360 | brcmf_dbg(ERROR, "bad ifidx %d\n", ifidx); | ||
361 | netif_stop_queue(ndev); | 334 | netif_stop_queue(ndev); |
362 | return -ENODEV; | 335 | return -ENODEV; |
363 | } | 336 | } |
@@ -367,20 +340,20 @@ static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev) | |||
367 | struct sk_buff *skb2; | 340 | struct sk_buff *skb2; |
368 | 341 | ||
369 | brcmf_dbg(INFO, "%s: insufficient headroom\n", | 342 | brcmf_dbg(INFO, "%s: insufficient headroom\n", |
370 | brcmf_ifname(&drvr_priv->pub, ifidx)); | 343 | brcmf_ifname(&drvr_priv->pub, ifp->idx)); |
371 | drvr_priv->pub.tx_realloc++; | 344 | drvr_priv->pub.tx_realloc++; |
372 | skb2 = skb_realloc_headroom(skb, drvr_priv->pub.hdrlen); | 345 | skb2 = skb_realloc_headroom(skb, drvr_priv->pub.hdrlen); |
373 | dev_kfree_skb(skb); | 346 | dev_kfree_skb(skb); |
374 | skb = skb2; | 347 | skb = skb2; |
375 | if (skb == NULL) { | 348 | if (skb == NULL) { |
376 | brcmf_dbg(ERROR, "%s: skb_realloc_headroom failed\n", | 349 | brcmf_dbg(ERROR, "%s: skb_realloc_headroom failed\n", |
377 | brcmf_ifname(&drvr_priv->pub, ifidx)); | 350 | brcmf_ifname(&drvr_priv->pub, ifp->idx)); |
378 | ret = -ENOMEM; | 351 | ret = -ENOMEM; |
379 | goto done; | 352 | goto done; |
380 | } | 353 | } |
381 | } | 354 | } |
382 | 355 | ||
383 | ret = brcmf_sendpkt(&drvr_priv->pub, ifidx, skb); | 356 | ret = brcmf_sendpkt(&drvr_priv->pub, ifp->idx, skb); |
384 | 357 | ||
385 | done: | 358 | done: |
386 | if (ret) | 359 | if (ret) |
@@ -482,12 +455,10 @@ void brcmf_rx_frame(struct brcmf_pub *drvr, int ifidx, struct sk_buff *skb, | |||
482 | skb_mac_header(skb), | 455 | skb_mac_header(skb), |
483 | &event, &data); | 456 | &event, &data); |
484 | 457 | ||
485 | if (drvr_priv->iflist[ifidx] && | 458 | if (drvr_priv->iflist[ifidx]) { |
486 | !drvr_priv->iflist[ifidx]->state) | ||
487 | ifp = drvr_priv->iflist[ifidx]; | 459 | ifp = drvr_priv->iflist[ifidx]; |
488 | |||
489 | if (ifp->ndev) | ||
490 | ifp->ndev->last_rx = jiffies; | 460 | ifp->ndev->last_rx = jiffies; |
461 | } | ||
491 | 462 | ||
492 | drvr->dstats.rx_bytes += skb->len; | 463 | drvr->dstats.rx_bytes += skb->len; |
493 | drvr->rx_packets++; /* Local count */ | 464 | drvr->rx_packets++; /* Local count */ |
@@ -524,19 +495,11 @@ void brcmf_txcomplete(struct brcmf_pub *drvr, struct sk_buff *txp, bool success) | |||
524 | 495 | ||
525 | static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *ndev) | 496 | static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *ndev) |
526 | { | 497 | { |
527 | struct brcmf_info *drvr_priv = *(struct brcmf_info **) | 498 | struct brcmf_if *ifp = netdev_priv(ndev); |
528 | netdev_priv(ndev); | 499 | struct brcmf_info *drvr_priv = ifp->info; |
529 | struct brcmf_if *ifp; | ||
530 | int ifidx; | ||
531 | 500 | ||
532 | brcmf_dbg(TRACE, "Enter\n"); | 501 | brcmf_dbg(TRACE, "Enter\n"); |
533 | 502 | ||
534 | ifidx = brcmf_net2idx(drvr_priv, ndev); | ||
535 | if (ifidx == BRCMF_BAD_IF) | ||
536 | return NULL; | ||
537 | |||
538 | ifp = drvr_priv->iflist[ifidx]; | ||
539 | |||
540 | if (drvr_priv->pub.up) | 503 | if (drvr_priv->pub.up) |
541 | /* Use the protocol to get dongle stats */ | 504 | /* Use the protocol to get dongle stats */ |
542 | brcmf_proto_dstats(&drvr_priv->pub); | 505 | brcmf_proto_dstats(&drvr_priv->pub); |
@@ -637,8 +600,8 @@ static int brcmf_toe_set(struct brcmf_info *drvr_priv, int ifidx, u32 toe_ol) | |||
637 | static void brcmf_ethtool_get_drvinfo(struct net_device *ndev, | 600 | static void brcmf_ethtool_get_drvinfo(struct net_device *ndev, |
638 | struct ethtool_drvinfo *info) | 601 | struct ethtool_drvinfo *info) |
639 | { | 602 | { |
640 | struct brcmf_info *drvr_priv = *(struct brcmf_info **) | 603 | struct brcmf_if *ifp = netdev_priv(ndev); |
641 | netdev_priv(ndev); | 604 | struct brcmf_info *drvr_priv = ifp->info; |
642 | 605 | ||
643 | sprintf(info->driver, KBUILD_MODNAME); | 606 | sprintf(info->driver, KBUILD_MODNAME); |
644 | sprintf(info->version, "%lu", drvr_priv->pub.drv_version); | 607 | sprintf(info->version, "%lu", drvr_priv->pub.drv_version); |
@@ -765,14 +728,12 @@ static int brcmf_ethtool(struct brcmf_info *drvr_priv, void __user *uaddr) | |||
765 | static int brcmf_netdev_ioctl_entry(struct net_device *ndev, struct ifreq *ifr, | 728 | static int brcmf_netdev_ioctl_entry(struct net_device *ndev, struct ifreq *ifr, |
766 | int cmd) | 729 | int cmd) |
767 | { | 730 | { |
768 | struct brcmf_info *drvr_priv = *(struct brcmf_info **) | 731 | struct brcmf_if *ifp = netdev_priv(ndev); |
769 | netdev_priv(ndev); | 732 | struct brcmf_info *drvr_priv = ifp->info; |
770 | int ifidx; | ||
771 | 733 | ||
772 | ifidx = brcmf_net2idx(drvr_priv, ndev); | 734 | brcmf_dbg(TRACE, "ifidx %d, cmd 0x%04x\n", ifp->idx, cmd); |
773 | brcmf_dbg(TRACE, "ifidx %d, cmd 0x%04x\n", ifidx, cmd); | ||
774 | 735 | ||
775 | if (ifidx == BRCMF_BAD_IF) | 736 | if (!drvr_priv->iflist[ifp->idx]) |
776 | return -1; | 737 | return -1; |
777 | 738 | ||
778 | if (cmd == SIOCETHTOOL) | 739 | if (cmd == SIOCETHTOOL) |
@@ -788,17 +749,14 @@ s32 brcmf_exec_dcmd(struct net_device *ndev, u32 cmd, void *arg, u32 len) | |||
788 | s32 err = 0; | 749 | s32 err = 0; |
789 | int buflen = 0; | 750 | int buflen = 0; |
790 | bool is_set_key_cmd; | 751 | bool is_set_key_cmd; |
791 | struct brcmf_info *drvr_priv = *(struct brcmf_info **) | 752 | struct brcmf_if *ifp = netdev_priv(ndev); |
792 | netdev_priv(ndev); | 753 | struct brcmf_info *drvr_priv = ifp->info; |
793 | int ifidx; | ||
794 | 754 | ||
795 | memset(&dcmd, 0, sizeof(dcmd)); | 755 | memset(&dcmd, 0, sizeof(dcmd)); |
796 | dcmd.cmd = cmd; | 756 | dcmd.cmd = cmd; |
797 | dcmd.buf = arg; | 757 | dcmd.buf = arg; |
798 | dcmd.len = len; | 758 | dcmd.len = len; |
799 | 759 | ||
800 | ifidx = brcmf_net2idx(drvr_priv, ndev); | ||
801 | |||
802 | if (dcmd.buf != NULL) | 760 | if (dcmd.buf != NULL) |
803 | buflen = min_t(uint, dcmd.len, BRCMF_DCMD_MAXLEN); | 761 | buflen = min_t(uint, dcmd.len, BRCMF_DCMD_MAXLEN); |
804 | 762 | ||
@@ -826,7 +784,7 @@ s32 brcmf_exec_dcmd(struct net_device *ndev, u32 cmd, void *arg, u32 len) | |||
826 | if (is_set_key_cmd) | 784 | if (is_set_key_cmd) |
827 | brcmf_netdev_wait_pend8021x(ndev); | 785 | brcmf_netdev_wait_pend8021x(ndev); |
828 | 786 | ||
829 | err = brcmf_proto_dcmd(&drvr_priv->pub, ifidx, &dcmd, buflen); | 787 | err = brcmf_proto_dcmd(&drvr_priv->pub, ifp->idx, &dcmd, buflen); |
830 | 788 | ||
831 | done: | 789 | done: |
832 | if (err > 0) | 790 | if (err > 0) |
@@ -837,7 +795,8 @@ done: | |||
837 | 795 | ||
838 | static int brcmf_netdev_stop(struct net_device *ndev) | 796 | static int brcmf_netdev_stop(struct net_device *ndev) |
839 | { | 797 | { |
840 | struct brcmf_pub *drvr = *(struct brcmf_pub **) netdev_priv(ndev); | 798 | struct brcmf_if *ifp = netdev_priv(ndev); |
799 | struct brcmf_pub *drvr = &ifp->info->pub; | ||
841 | 800 | ||
842 | brcmf_dbg(TRACE, "Enter\n"); | 801 | brcmf_dbg(TRACE, "Enter\n"); |
843 | brcmf_cfg80211_down(drvr->config); | 802 | brcmf_cfg80211_down(drvr->config); |
@@ -853,16 +812,14 @@ static int brcmf_netdev_stop(struct net_device *ndev) | |||
853 | 812 | ||
854 | static int brcmf_netdev_open(struct net_device *ndev) | 813 | static int brcmf_netdev_open(struct net_device *ndev) |
855 | { | 814 | { |
856 | struct brcmf_info *drvr_priv = *(struct brcmf_info **) | 815 | struct brcmf_if *ifp = netdev_priv(ndev); |
857 | netdev_priv(ndev); | 816 | struct brcmf_info *drvr_priv = ifp->info; |
858 | u32 toe_ol; | 817 | u32 toe_ol; |
859 | int ifidx = brcmf_net2idx(drvr_priv, ndev); | ||
860 | s32 ret = 0; | 818 | s32 ret = 0; |
861 | 819 | ||
862 | brcmf_dbg(TRACE, "ifidx %d\n", ifidx); | 820 | brcmf_dbg(TRACE, "ifidx %d\n", ifp->idx); |
863 | |||
864 | if (ifidx == 0) { /* do it only for primary eth0 */ | ||
865 | 821 | ||
822 | if (ifp->idx == 0) { /* do it only for primary eth0 */ | ||
866 | /* try to bring up bus */ | 823 | /* try to bring up bus */ |
867 | ret = brcmf_bus_start(&drvr_priv->pub); | 824 | ret = brcmf_bus_start(&drvr_priv->pub); |
868 | if (ret != 0) { | 825 | if (ret != 0) { |
@@ -874,12 +831,12 @@ static int brcmf_netdev_open(struct net_device *ndev) | |||
874 | memcpy(ndev->dev_addr, drvr_priv->pub.mac, ETH_ALEN); | 831 | memcpy(ndev->dev_addr, drvr_priv->pub.mac, ETH_ALEN); |
875 | 832 | ||
876 | /* Get current TOE mode from dongle */ | 833 | /* Get current TOE mode from dongle */ |
877 | if (brcmf_toe_get(drvr_priv, ifidx, &toe_ol) >= 0 | 834 | if (brcmf_toe_get(drvr_priv, ifp->idx, &toe_ol) >= 0 |
878 | && (toe_ol & TOE_TX_CSUM_OL) != 0) | 835 | && (toe_ol & TOE_TX_CSUM_OL) != 0) |
879 | drvr_priv->iflist[ifidx]->ndev->features |= | 836 | drvr_priv->iflist[ifp->idx]->ndev->features |= |
880 | NETIF_F_IP_CSUM; | 837 | NETIF_F_IP_CSUM; |
881 | else | 838 | else |
882 | drvr_priv->iflist[ifidx]->ndev->features &= | 839 | drvr_priv->iflist[ifp->idx]->ndev->features &= |
883 | ~NETIF_F_IP_CSUM; | 840 | ~NETIF_F_IP_CSUM; |
884 | } | 841 | } |
885 | /* Allow transmit calls */ | 842 | /* Allow transmit calls */ |
@@ -893,75 +850,62 @@ static int brcmf_netdev_open(struct net_device *ndev) | |||
893 | return ret; | 850 | return ret; |
894 | } | 851 | } |
895 | 852 | ||
853 | static const struct net_device_ops brcmf_netdev_ops_pri = { | ||
854 | .ndo_open = brcmf_netdev_open, | ||
855 | .ndo_stop = brcmf_netdev_stop, | ||
856 | .ndo_get_stats = brcmf_netdev_get_stats, | ||
857 | .ndo_do_ioctl = brcmf_netdev_ioctl_entry, | ||
858 | .ndo_start_xmit = brcmf_netdev_start_xmit, | ||
859 | .ndo_set_mac_address = brcmf_netdev_set_mac_address, | ||
860 | .ndo_set_rx_mode = brcmf_netdev_set_multicast_list | ||
861 | }; | ||
862 | |||
896 | int | 863 | int |
897 | brcmf_add_if(struct brcmf_info *drvr_priv, int ifidx, struct net_device *ndev, | 864 | brcmf_add_if(struct brcmf_info *drvr_priv, int ifidx, char *name, u8 *mac_addr) |
898 | char *name, u8 *mac_addr, u32 flags, u8 bssidx) | ||
899 | { | 865 | { |
900 | struct brcmf_if *ifp; | 866 | struct brcmf_if *ifp; |
901 | int ret = 0, err = 0; | 867 | struct net_device *ndev; |
902 | 868 | ||
903 | brcmf_dbg(TRACE, "idx %d, handle->%p\n", ifidx, ndev); | 869 | brcmf_dbg(TRACE, "idx %d\n", ifidx); |
904 | 870 | ||
905 | ifp = drvr_priv->iflist[ifidx]; | 871 | ifp = drvr_priv->iflist[ifidx]; |
906 | if (!ifp) { | 872 | /* |
907 | ifp = kmalloc(sizeof(struct brcmf_if), GFP_ATOMIC); | 873 | * Delete the existing interface before overwriting it |
908 | if (!ifp) | 874 | * in case we missed the BRCMF_E_IF_DEL event. |
909 | return -ENOMEM; | 875 | */ |
876 | if (ifp) { | ||
877 | brcmf_dbg(ERROR, "ERROR: netdev:%s already exists, try free & unregister\n", | ||
878 | ifp->ndev->name); | ||
879 | netif_stop_queue(ifp->ndev); | ||
880 | unregister_netdev(ifp->ndev); | ||
881 | free_netdev(ifp->ndev); | ||
882 | drvr_priv->iflist[ifidx] = NULL; | ||
883 | } | ||
884 | |||
885 | /* Allocate netdev, including space for private structure */ | ||
886 | ndev = alloc_netdev(sizeof(struct brcmf_if), name, ether_setup); | ||
887 | if (!ndev) { | ||
888 | brcmf_dbg(ERROR, "OOM - alloc_netdev\n"); | ||
889 | return -ENOMEM; | ||
910 | } | 890 | } |
911 | 891 | ||
912 | memset(ifp, 0, sizeof(struct brcmf_if)); | 892 | ifp = netdev_priv(ndev); |
893 | ifp->ndev = ndev; | ||
913 | ifp->info = drvr_priv; | 894 | ifp->info = drvr_priv; |
914 | drvr_priv->iflist[ifidx] = ifp; | 895 | drvr_priv->iflist[ifidx] = ifp; |
896 | ifp->idx = ifidx; | ||
915 | if (mac_addr != NULL) | 897 | if (mac_addr != NULL) |
916 | memcpy(&ifp->mac_addr, mac_addr, ETH_ALEN); | 898 | memcpy(&ifp->mac_addr, mac_addr, ETH_ALEN); |
917 | 899 | ||
918 | if (ndev == NULL) { | 900 | if (brcmf_net_attach(&drvr_priv->pub, ifp->idx)) { |
919 | ifp->state = BRCMF_E_IF_ADD; | 901 | brcmf_dbg(ERROR, "brcmf_net_attach failed"); |
920 | ifp->idx = ifidx; | 902 | free_netdev(ifp->ndev); |
921 | /* | 903 | drvr_priv->iflist[ifidx] = NULL; |
922 | * Delete the existing interface before overwriting it | 904 | return -EOPNOTSUPP; |
923 | * in case we missed the BRCMF_E_IF_DEL event. | 905 | } |
924 | */ | ||
925 | if (ifp->ndev != NULL) { | ||
926 | brcmf_dbg(ERROR, "ERROR: netdev:%s already exists, try free & unregister\n", | ||
927 | ifp->ndev->name); | ||
928 | netif_stop_queue(ifp->ndev); | ||
929 | unregister_netdev(ifp->ndev); | ||
930 | free_netdev(ifp->ndev); | ||
931 | } | ||
932 | |||
933 | /* Allocate netdev, including space for private structure */ | ||
934 | ifp->ndev = alloc_netdev(sizeof(drvr_priv), "wlan%d", | ||
935 | ether_setup); | ||
936 | if (!ifp->ndev) { | ||
937 | brcmf_dbg(ERROR, "OOM - alloc_netdev\n"); | ||
938 | ret = -ENOMEM; | ||
939 | } | ||
940 | |||
941 | if (ret == 0) { | ||
942 | memcpy(netdev_priv(ifp->ndev), &drvr_priv, | ||
943 | sizeof(drvr_priv)); | ||
944 | err = brcmf_net_attach(&drvr_priv->pub, ifp->idx); | ||
945 | if (err != 0) { | ||
946 | brcmf_dbg(ERROR, "brcmf_net_attach failed, err %d\n", | ||
947 | err); | ||
948 | ret = -EOPNOTSUPP; | ||
949 | } else { | ||
950 | brcmf_dbg(TRACE, " ==== pid:%x, net_device for if:%s created ===\n", | ||
951 | current->pid, ifp->ndev->name); | ||
952 | ifp->state = 0; | ||
953 | } | ||
954 | } | ||
955 | |||
956 | if (ret < 0) { | ||
957 | if (ifp->ndev) | ||
958 | free_netdev(ifp->ndev); | ||
959 | 906 | ||
960 | drvr_priv->iflist[ifp->idx] = NULL; | 907 | brcmf_dbg(TRACE, " ==== pid:%x, net_device for if:%s created ===\n", |
961 | kfree(ifp); | 908 | current->pid, ifp->ndev->name); |
962 | } | ||
963 | } else | ||
964 | ifp->ndev = ndev; | ||
965 | 909 | ||
966 | return 0; | 910 | return 0; |
967 | } | 911 | } |
@@ -977,47 +921,36 @@ void brcmf_del_if(struct brcmf_info *drvr_priv, int ifidx) | |||
977 | brcmf_dbg(ERROR, "Null interface\n"); | 921 | brcmf_dbg(ERROR, "Null interface\n"); |
978 | return; | 922 | return; |
979 | } | 923 | } |
924 | if (ifp->ndev) { | ||
925 | if (ifidx == 0) { | ||
926 | if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) { | ||
927 | rtnl_lock(); | ||
928 | brcmf_netdev_stop(ifp->ndev); | ||
929 | rtnl_unlock(); | ||
930 | } | ||
931 | } else { | ||
932 | netif_stop_queue(ifp->ndev); | ||
933 | } | ||
980 | 934 | ||
981 | ifp->state = BRCMF_E_IF_DEL; | ||
982 | ifp->idx = ifidx; | ||
983 | if (ifp->ndev != NULL) { | ||
984 | netif_stop_queue(ifp->ndev); | ||
985 | unregister_netdev(ifp->ndev); | 935 | unregister_netdev(ifp->ndev); |
986 | free_netdev(ifp->ndev); | ||
987 | drvr_priv->iflist[ifidx] = NULL; | 936 | drvr_priv->iflist[ifidx] = NULL; |
988 | kfree(ifp); | 937 | if (ifidx == 0) |
938 | brcmf_cfg80211_detach(drvr_priv->pub.config); | ||
939 | free_netdev(ifp->ndev); | ||
989 | } | 940 | } |
990 | } | 941 | } |
991 | 942 | ||
992 | struct brcmf_pub *brcmf_attach(struct brcmf_bus *bus, uint bus_hdrlen) | 943 | struct brcmf_pub *brcmf_attach(struct brcmf_bus *bus, uint bus_hdrlen) |
993 | { | 944 | { |
994 | struct brcmf_info *drvr_priv = NULL; | 945 | struct brcmf_info *drvr_priv = NULL; |
995 | struct net_device *ndev; | ||
996 | 946 | ||
997 | brcmf_dbg(TRACE, "Enter\n"); | 947 | brcmf_dbg(TRACE, "Enter\n"); |
998 | 948 | ||
999 | /* Allocate netdev, including space for private structure */ | ||
1000 | ndev = alloc_netdev(sizeof(drvr_priv), "wlan%d", ether_setup); | ||
1001 | if (!ndev) { | ||
1002 | brcmf_dbg(ERROR, "OOM - alloc_netdev\n"); | ||
1003 | goto fail; | ||
1004 | } | ||
1005 | |||
1006 | /* Allocate primary brcmf_info */ | 949 | /* Allocate primary brcmf_info */ |
1007 | drvr_priv = kzalloc(sizeof(struct brcmf_info), GFP_ATOMIC); | 950 | drvr_priv = kzalloc(sizeof(struct brcmf_info), GFP_ATOMIC); |
1008 | if (!drvr_priv) | 951 | if (!drvr_priv) |
1009 | goto fail; | 952 | goto fail; |
1010 | 953 | ||
1011 | /* | ||
1012 | * Save the brcmf_info into the priv | ||
1013 | */ | ||
1014 | memcpy(netdev_priv(ndev), &drvr_priv, sizeof(drvr_priv)); | ||
1015 | |||
1016 | if (brcmf_add_if(drvr_priv, 0, ndev, ndev->name, NULL, 0, 0) == | ||
1017 | BRCMF_BAD_IF) | ||
1018 | goto fail; | ||
1019 | |||
1020 | ndev->netdev_ops = NULL; | ||
1021 | mutex_init(&drvr_priv->proto_block); | 954 | mutex_init(&drvr_priv->proto_block); |
1022 | 955 | ||
1023 | /* Link to info module */ | 956 | /* Link to info module */ |
@@ -1033,29 +966,12 @@ struct brcmf_pub *brcmf_attach(struct brcmf_bus *bus, uint bus_hdrlen) | |||
1033 | goto fail; | 966 | goto fail; |
1034 | } | 967 | } |
1035 | 968 | ||
1036 | /* Attach and link in the cfg80211 */ | ||
1037 | drvr_priv->pub.config = | ||
1038 | brcmf_cfg80211_attach(ndev, | ||
1039 | brcmf_bus_get_device(bus), | ||
1040 | &drvr_priv->pub); | ||
1041 | if (drvr_priv->pub.config == NULL) { | ||
1042 | brcmf_dbg(ERROR, "wl_cfg80211_attach failed\n"); | ||
1043 | goto fail; | ||
1044 | } | ||
1045 | |||
1046 | INIT_WORK(&drvr_priv->setmacaddr_work, _brcmf_set_mac_address); | 969 | INIT_WORK(&drvr_priv->setmacaddr_work, _brcmf_set_mac_address); |
1047 | INIT_WORK(&drvr_priv->multicast_work, _brcmf_set_multicast_list); | 970 | INIT_WORK(&drvr_priv->multicast_work, _brcmf_set_multicast_list); |
1048 | 971 | ||
1049 | /* | ||
1050 | * Save the brcmf_info into the priv | ||
1051 | */ | ||
1052 | memcpy(netdev_priv(ndev), &drvr_priv, sizeof(drvr_priv)); | ||
1053 | |||
1054 | return &drvr_priv->pub; | 972 | return &drvr_priv->pub; |
1055 | 973 | ||
1056 | fail: | 974 | fail: |
1057 | if (ndev) | ||
1058 | free_netdev(ndev); | ||
1059 | if (drvr_priv) | 975 | if (drvr_priv) |
1060 | brcmf_detach(&drvr_priv->pub); | 976 | brcmf_detach(&drvr_priv->pub); |
1061 | 977 | ||
@@ -1123,16 +1039,6 @@ int brcmf_bus_start(struct brcmf_pub *drvr) | |||
1123 | return 0; | 1039 | return 0; |
1124 | } | 1040 | } |
1125 | 1041 | ||
1126 | static struct net_device_ops brcmf_netdev_ops_pri = { | ||
1127 | .ndo_open = brcmf_netdev_open, | ||
1128 | .ndo_stop = brcmf_netdev_stop, | ||
1129 | .ndo_get_stats = brcmf_netdev_get_stats, | ||
1130 | .ndo_do_ioctl = brcmf_netdev_ioctl_entry, | ||
1131 | .ndo_start_xmit = brcmf_netdev_start_xmit, | ||
1132 | .ndo_set_mac_address = brcmf_netdev_set_mac_address, | ||
1133 | .ndo_set_rx_mode = brcmf_netdev_set_multicast_list | ||
1134 | }; | ||
1135 | |||
1136 | int brcmf_net_attach(struct brcmf_pub *drvr, int ifidx) | 1042 | int brcmf_net_attach(struct brcmf_pub *drvr, int ifidx) |
1137 | { | 1043 | { |
1138 | struct brcmf_info *drvr_priv = drvr->info; | 1044 | struct brcmf_info *drvr_priv = drvr->info; |
@@ -1169,6 +1075,18 @@ int brcmf_net_attach(struct brcmf_pub *drvr, int ifidx) | |||
1169 | 1075 | ||
1170 | memcpy(ndev->dev_addr, temp_addr, ETH_ALEN); | 1076 | memcpy(ndev->dev_addr, temp_addr, ETH_ALEN); |
1171 | 1077 | ||
1078 | /* attach to cfg80211 for primary interface */ | ||
1079 | if (!ifidx) { | ||
1080 | drvr->config = | ||
1081 | brcmf_cfg80211_attach(ndev, | ||
1082 | brcmf_bus_get_device(drvr->bus), | ||
1083 | drvr); | ||
1084 | if (drvr->config == NULL) { | ||
1085 | brcmf_dbg(ERROR, "wl_cfg80211_attach failed\n"); | ||
1086 | goto fail; | ||
1087 | } | ||
1088 | } | ||
1089 | |||
1172 | if (register_netdev(ndev) != 0) { | 1090 | if (register_netdev(ndev) != 0) { |
1173 | brcmf_dbg(ERROR, "couldn't register the net device\n"); | 1091 | brcmf_dbg(ERROR, "couldn't register the net device\n"); |
1174 | goto fail; | 1092 | goto fail; |
@@ -1210,21 +1128,13 @@ void brcmf_detach(struct brcmf_pub *drvr) | |||
1210 | if (drvr) { | 1128 | if (drvr) { |
1211 | drvr_priv = drvr->info; | 1129 | drvr_priv = drvr->info; |
1212 | if (drvr_priv) { | 1130 | if (drvr_priv) { |
1213 | struct brcmf_if *ifp; | ||
1214 | int i; | 1131 | int i; |
1215 | 1132 | ||
1216 | for (i = 1; i < BRCMF_MAX_IFS; i++) | 1133 | /* make sure primary interface removed last */ |
1134 | for (i = BRCMF_MAX_IFS-1; i > -1; i--) | ||
1217 | if (drvr_priv->iflist[i]) | 1135 | if (drvr_priv->iflist[i]) |
1218 | brcmf_del_if(drvr_priv, i); | 1136 | brcmf_del_if(drvr_priv, i); |
1219 | 1137 | ||
1220 | ifp = drvr_priv->iflist[0]; | ||
1221 | if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) { | ||
1222 | rtnl_lock(); | ||
1223 | brcmf_netdev_stop(ifp->ndev); | ||
1224 | rtnl_unlock(); | ||
1225 | unregister_netdev(ifp->ndev); | ||
1226 | } | ||
1227 | |||
1228 | cancel_work_sync(&drvr_priv->setmacaddr_work); | 1138 | cancel_work_sync(&drvr_priv->setmacaddr_work); |
1229 | cancel_work_sync(&drvr_priv->multicast_work); | 1139 | cancel_work_sync(&drvr_priv->multicast_work); |
1230 | 1140 | ||
@@ -1233,10 +1143,6 @@ void brcmf_detach(struct brcmf_pub *drvr) | |||
1233 | if (drvr->prot) | 1143 | if (drvr->prot) |
1234 | brcmf_proto_detach(drvr); | 1144 | brcmf_proto_detach(drvr); |
1235 | 1145 | ||
1236 | brcmf_cfg80211_detach(drvr->config); | ||
1237 | |||
1238 | free_netdev(ifp->ndev); | ||
1239 | kfree(ifp); | ||
1240 | kfree(drvr_priv); | 1146 | kfree(drvr_priv); |
1241 | } | 1147 | } |
1242 | } | 1148 | } |
@@ -1302,7 +1208,8 @@ static int brcmf_get_pend_8021x_cnt(struct brcmf_info *drvr_priv) | |||
1302 | 1208 | ||
1303 | int brcmf_netdev_wait_pend8021x(struct net_device *ndev) | 1209 | int brcmf_netdev_wait_pend8021x(struct net_device *ndev) |
1304 | { | 1210 | { |
1305 | struct brcmf_info *drvr_priv = *(struct brcmf_info **)netdev_priv(ndev); | 1211 | struct brcmf_if *ifp = netdev_priv(ndev); |
1212 | struct brcmf_info *drvr_priv = ifp->info; | ||
1306 | int timeout = 10 * HZ / 1000; | 1213 | int timeout = 10 * HZ / 1000; |
1307 | int ntimes = MAX_WAIT_FOR_8021X_TX; | 1214 | int ntimes = MAX_WAIT_FOR_8021X_TX; |
1308 | int pend = brcmf_get_pend_8021x_cnt(drvr_priv); | 1215 | int pend = brcmf_get_pend_8021x_cnt(drvr_priv); |