diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c index 4acbac5a74c6ee41a44981cd886c89172408eb2c..6739ece56587ce94490ba393821485b2d6696e55 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c @@ -893,6 +893,16 @@ static int brcmf_netdev_open(struct net_device *ndev) return ret; } +static const struct net_device_ops brcmf_netdev_ops_pri = { + .ndo_open = brcmf_netdev_open, + .ndo_stop = brcmf_netdev_stop, + .ndo_get_stats = brcmf_netdev_get_stats, + .ndo_do_ioctl = brcmf_netdev_ioctl_entry, + .ndo_start_xmit = brcmf_netdev_start_xmit, + .ndo_set_mac_address = brcmf_netdev_set_mac_address, + .ndo_set_rx_mode = brcmf_netdev_set_multicast_list +}; + int brcmf_add_if(struct brcmf_info *drvr_priv, int ifidx, struct net_device *ndev, char *name, u8 *mac_addr, u32 flags, u8 bssidx) @@ -977,14 +987,23 @@ void brcmf_del_if(struct brcmf_info *drvr_priv, int ifidx) brcmf_dbg(ERROR, "Null interface\n"); return; } - ifp->state = BRCMF_E_IF_DEL; - ifp->idx = ifidx; - if (ifp->ndev != NULL) { - netif_stop_queue(ifp->ndev); + if (ifp->ndev) { + if (ifidx == 0) { + if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) { + rtnl_lock(); + brcmf_netdev_stop(ifp->ndev); + rtnl_unlock(); + } + } else { + netif_stop_queue(ifp->ndev); + } + unregister_netdev(ifp->ndev); - free_netdev(ifp->ndev); drvr_priv->iflist[ifidx] = NULL; + if (ifidx == 0) + brcmf_cfg80211_detach(drvr_priv->pub.config); + free_netdev(ifp->ndev); kfree(ifp); } } @@ -1123,16 +1142,6 @@ int brcmf_bus_start(struct brcmf_pub *drvr) return 0; } -static struct net_device_ops brcmf_netdev_ops_pri = { - .ndo_open = brcmf_netdev_open, - .ndo_stop = brcmf_netdev_stop, - .ndo_get_stats = brcmf_netdev_get_stats, - .ndo_do_ioctl = brcmf_netdev_ioctl_entry, - .ndo_start_xmit = brcmf_netdev_start_xmit, - .ndo_set_mac_address = brcmf_netdev_set_mac_address, - .ndo_set_rx_mode = brcmf_netdev_set_multicast_list -}; - int brcmf_net_attach(struct brcmf_pub *drvr, int ifidx) { struct brcmf_info *drvr_priv = drvr->info; @@ -1210,21 +1219,13 @@ void brcmf_detach(struct brcmf_pub *drvr) if (drvr) { drvr_priv = drvr->info; if (drvr_priv) { - struct brcmf_if *ifp; int i; - for (i = 1; i < BRCMF_MAX_IFS; i++) + /* make sure primary interface removed last */ + for (i = BRCMF_MAX_IFS-1; i > -1; i--) if (drvr_priv->iflist[i]) brcmf_del_if(drvr_priv, i); - ifp = drvr_priv->iflist[0]; - if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) { - rtnl_lock(); - brcmf_netdev_stop(ifp->ndev); - rtnl_unlock(); - unregister_netdev(ifp->ndev); - } - cancel_work_sync(&drvr_priv->setmacaddr_work); cancel_work_sync(&drvr_priv->multicast_work); @@ -1233,10 +1234,6 @@ void brcmf_detach(struct brcmf_pub *drvr) if (drvr->prot) brcmf_proto_detach(drvr); - brcmf_cfg80211_detach(drvr->config); - - free_netdev(ifp->ndev); - kfree(ifp); kfree(drvr_priv); } }