brcmfmac: fix for multiple netdevice interface support
authorArend van Spriel <arend@broadcom.com>
Thu, 15 Nov 2012 02:46:09 +0000 (18:46 -0800)
committerJohn W. Linville <linville@tuxdriver.com>
Fri, 16 Nov 2012 19:28:49 +0000 (14:28 -0500)
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>
drivers/net/wireless/brcm80211/brcmfmac/dhd.h
drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h

index a41e1c69f8c57ef50bb669c8c0a2858bbd1a0499..499c5c240e045528142c682f80fa41e03f85d4e7 100644 (file)
@@ -513,8 +513,6 @@ struct brcmf_pub {
        struct mutex proto_block;
        unsigned char proto_buf[BRCMF_DCMD_MAXLEN];
 
-       struct work_struct setmacaddr_work;
-       struct work_struct multicast_work;
        u8 macvalue[ETH_ALEN];
        atomic_t pend_8021x_cnt;
        wait_queue_head_t pend_8021x_wait;
@@ -556,6 +554,8 @@ struct brcmf_if {
        struct brcmf_cfg80211_vif *vif;
        struct net_device *ndev;
        struct net_device_stats stats;
+       struct work_struct setmacaddr_work;
+       struct work_struct multicast_work;
        int idx;
        s32 bssidx;
        u8 mac_addr[ETH_ALEN];
index f10203410b39cfc09e1a8350b1b36f2f2aa19707..32b73550e5ad2ce1f75d1cd31f516354ccfbc509 100644 (file)
@@ -105,12 +105,10 @@ static void _brcmf_set_multicast_list(struct work_struct *work)
        char *buf, *bufp;
        u32 buflen;
        s32 err;
-       struct brcmf_pub *drvr = container_of(work, struct brcmf_pub,
-                                                   multicast_work);
 
        brcmf_dbg(TRACE, "enter\n");
 
-       ifp = drvr->iflist[0];
+       ifp = container_of(work, struct brcmf_if, multicast_work);
        ndev = ifp->ndev;
 
        /* Determine initial value of allmulti flag */
@@ -165,45 +163,37 @@ static void
 _brcmf_set_mac_address(struct work_struct *work)
 {
        struct brcmf_if *ifp;
-       struct net_device *ndev;
        s32 err;
 
-       struct brcmf_pub *drvr = container_of(work, struct brcmf_pub,
-                                                   setmacaddr_work);
-
        brcmf_dbg(TRACE, "enter\n");
 
-       ifp = drvr->iflist[0];
-       ndev = ifp->ndev;
-
-       err = brcmf_fil_iovar_data_set(ifp, "cur_etheraddr", drvr->macvalue,
+       ifp = container_of(work, struct brcmf_if, setmacaddr_work);
+       err = brcmf_fil_iovar_data_set(ifp, "cur_etheraddr", ifp->mac_addr,
                                       ETH_ALEN);
        if (err < 0) {
                brcmf_dbg(ERROR, "Setting cur_etheraddr failed, %d\n", err);
        } else {
                brcmf_dbg(TRACE, "MAC address updated to %pM\n",
-                         drvr->macvalue);
-               memcpy(ndev->dev_addr, drvr->macvalue, ETH_ALEN);
+                         ifp->mac_addr);
+               memcpy(ifp->ndev->dev_addr, ifp->mac_addr, ETH_ALEN);
        }
 }
 
 static int brcmf_netdev_set_mac_address(struct net_device *ndev, void *addr)
 {
        struct brcmf_if *ifp = netdev_priv(ndev);
-       struct brcmf_pub *drvr = ifp->drvr;
        struct sockaddr *sa = (struct sockaddr *)addr;
 
-       memcpy(&drvr->macvalue, sa->sa_data, ETH_ALEN);
-       schedule_work(&drvr->setmacaddr_work);
+       memcpy(&ifp->mac_addr, sa->sa_data, ETH_ALEN);
+       schedule_work(&ifp->setmacaddr_work);
        return 0;
 }
 
 static void brcmf_netdev_set_multicast_list(struct net_device *ndev)
 {
        struct brcmf_if *ifp = netdev_priv(ndev);
-       struct brcmf_pub *drvr = ifp->drvr;
 
-       schedule_work(&drvr->multicast_work);
+       schedule_work(&ifp->multicast_work);
 }
 
 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)
        if (drvr->bus_if->drvr_up == 0)
                return 0;
 
-       brcmf_cfg80211_down(drvr->config);
+       brcmf_cfg80211_down(ndev);
 
        /* Set state and stop OS transmissions */
        drvr->bus_if->drvr_up = false;
@@ -601,26 +591,24 @@ static int brcmf_netdev_open(struct net_device *ndev)
 
        brcmf_dbg(TRACE, "ifidx %d\n", ifp->idx);
 
-       if (ifp->idx == 0) {    /* do it only for primary eth0 */
-               /* If bus is not ready, can't continue */
-               if (bus_if->state != BRCMF_BUS_DATA) {
-                       brcmf_dbg(ERROR, "failed bus is not ready\n");
-                       return -EAGAIN;
-               }
+       /* If bus is not ready, can't continue */
+       if (bus_if->state != BRCMF_BUS_DATA) {
+               brcmf_dbg(ERROR, "failed bus is not ready\n");
+               return -EAGAIN;
+       }
 
-               atomic_set(&drvr->pend_8021x_cnt, 0);
+       atomic_set(&drvr->pend_8021x_cnt, 0);
 
-               memcpy(ndev->dev_addr, drvr->mac, ETH_ALEN);
+       memcpy(ndev->dev_addr, drvr->mac, ETH_ALEN);
 
-               /* Get current TOE mode from dongle */
-               if (brcmf_fil_iovar_int_get(ifp, "toe_ol", &toe_ol) >= 0
-                   && (toe_ol & TOE_TX_CSUM_OL) != 0)
-                       drvr->iflist[ifp->idx]->ndev->features |=
-                               NETIF_F_IP_CSUM;
-               else
-                       drvr->iflist[ifp->idx]->ndev->features &=
-                               ~NETIF_F_IP_CSUM;
-       }
+       /* Get current TOE mode from dongle */
+       if (brcmf_fil_iovar_int_get(ifp, "toe_ol", &toe_ol) >= 0
+           && (toe_ol & TOE_TX_CSUM_OL) != 0)
+               drvr->iflist[ifp->idx]->ndev->features |=
+                       NETIF_F_IP_CSUM;
+       else
+               drvr->iflist[ifp->idx]->ndev->features &=
+                       ~NETIF_F_IP_CSUM;
 
        /* make sure RF is ready for work */
        brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
@@ -628,7 +616,7 @@ static int brcmf_netdev_open(struct net_device *ndev)
        /* Allow transmit calls */
        netif_start_queue(ndev);
        drvr->bus_if->drvr_up = true;
-       if (brcmf_cfg80211_up(drvr->config)) {
+       if (brcmf_cfg80211_up(ndev)) {
                brcmf_dbg(ERROR, "failed to bring up cfg80211\n");
                return -1;
        }
@@ -646,16 +634,30 @@ static const struct net_device_ops brcmf_netdev_ops_pri = {
        .ndo_set_rx_mode = brcmf_netdev_set_multicast_list
 };
 
+static const struct net_device_ops brcmf_netdev_ops_virt = {
+       .ndo_open = brcmf_cfg80211_up,
+       .ndo_stop = brcmf_cfg80211_down,
+       .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_if *ifp)
 {
        struct brcmf_pub *drvr = ifp->drvr;
        struct net_device *ndev;
        u8 temp_addr[ETH_ALEN];
 
-       brcmf_dbg(TRACE, "ifidx %d\n", ifp->idx);
+       brcmf_dbg(TRACE, "ifidx %d mac %pM\n", ifp->idx, ifp->mac_addr);
+       ndev = ifp->ndev;
 
-       ndev = drvr->iflist[ifp->idx]->ndev;
-       ndev->netdev_ops = &brcmf_netdev_ops_pri;
+       /* set appropriate operations */
+       if (!ifp->idx)
+               ndev->netdev_ops = &brcmf_netdev_ops_pri;
+       else
+               ndev->netdev_ops = &brcmf_netdev_ops_virt;
 
        /*
         * determine mac address to use
@@ -665,13 +667,6 @@ int brcmf_net_attach(struct brcmf_if *ifp)
        else
                memcpy(temp_addr, drvr->mac, ETH_ALEN);
 
-       if (ifp->idx == 1) {
-               brcmf_dbg(TRACE, "ACCESS POINT MAC:\n");
-               /*  ACCESSPOINT INTERFACE CASE */
-               temp_addr[0] |= 0X02;   /* set bit 2 ,
-                        - Locally Administered address  */
-
-       }
        ndev->hard_header_len = ETH_HLEN + drvr->hdrlen;
        ndev->ethtool_ops = &brcmf_ethtool_ops;
 
@@ -729,6 +724,10 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, int ifidx, s32 bssidx,
        drvr->iflist[ifidx] = ifp;
        ifp->idx = ifidx;
        ifp->bssidx = bssidx;
+
+       INIT_WORK(&ifp->setmacaddr_work, _brcmf_set_mac_address);
+       INIT_WORK(&ifp->multicast_work, _brcmf_set_multicast_list);
+
        if (mac_addr != NULL)
                memcpy(&ifp->mac_addr, mac_addr, ETH_ALEN);
 
@@ -760,6 +759,9 @@ void brcmf_del_if(struct brcmf_pub *drvr, int ifidx)
                        netif_stop_queue(ifp->ndev);
                }
 
+               cancel_work_sync(&ifp->setmacaddr_work);
+               cancel_work_sync(&ifp->multicast_work);
+
                unregister_netdev(ifp->ndev);
                drvr->iflist[ifidx] = NULL;
                if (ifidx == 0)
@@ -801,9 +803,6 @@ int brcmf_attach(uint bus_hdrlen, struct device *dev)
        /* attach firmware event handler */
        brcmf_fweh_attach(drvr);
 
-       INIT_WORK(&drvr->setmacaddr_work, _brcmf_set_mac_address);
-       INIT_WORK(&drvr->multicast_work, _brcmf_set_multicast_list);
-
        INIT_LIST_HEAD(&drvr->bus_if->dcmd_list);
 
        init_waitqueue_head(&drvr->pend_8021x_wait);
@@ -904,8 +903,6 @@ void brcmf_detach(struct device *dev)
        brcmf_bus_detach(drvr);
 
        if (drvr->prot) {
-               cancel_work_sync(&drvr->setmacaddr_work);
-               cancel_work_sync(&drvr->multicast_work);
                brcmf_proto_detach(drvr);
        }
 
index e6d2d40ad8d586eb876044e6b8ba7cf3766bc2d5..14cf71b4251ccb7788adcac471eb52ef0eabe400 100644 (file)
@@ -4526,19 +4526,18 @@ default_conf_out:
 
 }
 
-static s32 __brcmf_cfg80211_up(struct brcmf_cfg80211_info *cfg)
+static s32 __brcmf_cfg80211_up(struct brcmf_if *ifp)
 {
-       struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
-
        set_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
+       if (ifp->idx)
+               return 0;
 
-       return brcmf_config_dongle(cfg);
+       return brcmf_config_dongle(ifp->drvr->config);
 }
 
-static s32 __brcmf_cfg80211_down(struct brcmf_cfg80211_info *cfg)
+static s32 __brcmf_cfg80211_down(struct brcmf_if *ifp)
 {
-       struct net_device *ndev = cfg_to_ndev(cfg);
-       struct brcmf_if *ifp = netdev_priv(ndev);
+       struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
 
        /*
         * While going down, if associated with AP disassociate
@@ -4563,23 +4562,27 @@ static s32 __brcmf_cfg80211_down(struct brcmf_cfg80211_info *cfg)
        return 0;
 }
 
-s32 brcmf_cfg80211_up(struct brcmf_cfg80211_info *cfg)
+s32 brcmf_cfg80211_up(struct net_device *ndev)
 {
+       struct brcmf_if *ifp = netdev_priv(ndev);
+       struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
        s32 err = 0;
 
        mutex_lock(&cfg->usr_sync);
-       err = __brcmf_cfg80211_up(cfg);
+       err = __brcmf_cfg80211_up(ifp);
        mutex_unlock(&cfg->usr_sync);
 
        return err;
 }
 
-s32 brcmf_cfg80211_down(struct brcmf_cfg80211_info *cfg)
+s32 brcmf_cfg80211_down(struct net_device *ndev)
 {
+       struct brcmf_if *ifp = netdev_priv(ndev);
+       struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
        s32 err = 0;
 
        mutex_lock(&cfg->usr_sync);
-       err = __brcmf_cfg80211_down(cfg);
+       err = __brcmf_cfg80211_down(ifp);
        mutex_unlock(&cfg->usr_sync);
 
        return err;
index 80ba2ea378e4aa4de1739fecc629500a1fa284d6..e2ef8519ea8499076546f1cb85edf8923aa6d449 100644 (file)
@@ -455,7 +455,7 @@ brcmf_cfg80211_connect_info *cfg_to_conn(struct brcmf_cfg80211_info *cfg)
 
 struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr);
 void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg);
-s32 brcmf_cfg80211_up(struct brcmf_cfg80211_info *cfg);
-s32 brcmf_cfg80211_down(struct brcmf_cfg80211_info *cfg);
+s32 brcmf_cfg80211_up(struct net_device *ndev);
+s32 brcmf_cfg80211_down(struct net_device *ndev);
 
 #endif                         /* _wl_cfg80211_h_ */