Commit bdf5ff51 authored by Arend van Spriel's avatar Arend van Spriel Committed by John W. Linville

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: default avatarPieter-Paul Giesberts <pieterpg@broadcom.com>
Reviewed-by: default avatarHante Meuleman <meuleman@broadcom.com>
Signed-off-by: default avatarArend van Spriel <arend@broadcom.com>
Signed-off-by: default avatarFranky Lin <frankyl@broadcom.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 699b5e5b
...@@ -513,8 +513,6 @@ struct brcmf_pub { ...@@ -513,8 +513,6 @@ struct brcmf_pub {
struct mutex proto_block; struct mutex proto_block;
unsigned char proto_buf[BRCMF_DCMD_MAXLEN]; unsigned char proto_buf[BRCMF_DCMD_MAXLEN];
struct work_struct setmacaddr_work;
struct work_struct multicast_work;
u8 macvalue[ETH_ALEN]; u8 macvalue[ETH_ALEN];
atomic_t pend_8021x_cnt; atomic_t pend_8021x_cnt;
wait_queue_head_t pend_8021x_wait; wait_queue_head_t pend_8021x_wait;
...@@ -556,6 +554,8 @@ struct brcmf_if { ...@@ -556,6 +554,8 @@ struct brcmf_if {
struct brcmf_cfg80211_vif *vif; struct brcmf_cfg80211_vif *vif;
struct net_device *ndev; struct net_device *ndev;
struct net_device_stats stats; struct net_device_stats stats;
struct work_struct setmacaddr_work;
struct work_struct multicast_work;
int idx; int idx;
s32 bssidx; s32 bssidx;
u8 mac_addr[ETH_ALEN]; u8 mac_addr[ETH_ALEN];
......
...@@ -105,12 +105,10 @@ static void _brcmf_set_multicast_list(struct work_struct *work) ...@@ -105,12 +105,10 @@ static void _brcmf_set_multicast_list(struct work_struct *work)
char *buf, *bufp; char *buf, *bufp;
u32 buflen; u32 buflen;
s32 err; s32 err;
struct brcmf_pub *drvr = container_of(work, struct brcmf_pub,
multicast_work);
brcmf_dbg(TRACE, "enter\n"); brcmf_dbg(TRACE, "enter\n");
ifp = drvr->iflist[0]; ifp = container_of(work, struct brcmf_if, multicast_work);
ndev = ifp->ndev; ndev = ifp->ndev;
/* Determine initial value of allmulti flag */ /* Determine initial value of allmulti flag */
...@@ -165,45 +163,37 @@ static void ...@@ -165,45 +163,37 @@ static void
_brcmf_set_mac_address(struct work_struct *work) _brcmf_set_mac_address(struct work_struct *work)
{ {
struct brcmf_if *ifp; struct brcmf_if *ifp;
struct net_device *ndev;
s32 err; s32 err;
struct brcmf_pub *drvr = container_of(work, struct brcmf_pub,
setmacaddr_work);
brcmf_dbg(TRACE, "enter\n"); brcmf_dbg(TRACE, "enter\n");
ifp = drvr->iflist[0]; ifp = container_of(work, struct brcmf_if, setmacaddr_work);
ndev = ifp->ndev; err = brcmf_fil_iovar_data_set(ifp, "cur_etheraddr", ifp->mac_addr,
err = brcmf_fil_iovar_data_set(ifp, "cur_etheraddr", drvr->macvalue,
ETH_ALEN); ETH_ALEN);
if (err < 0) { if (err < 0) {
brcmf_dbg(ERROR, "Setting cur_etheraddr failed, %d\n", err); brcmf_dbg(ERROR, "Setting cur_etheraddr failed, %d\n", err);
} else { } else {
brcmf_dbg(TRACE, "MAC address updated to %pM\n", brcmf_dbg(TRACE, "MAC address updated to %pM\n",
drvr->macvalue); ifp->mac_addr);
memcpy(ndev->dev_addr, drvr->macvalue, ETH_ALEN); memcpy(ifp->ndev->dev_addr, ifp->mac_addr, ETH_ALEN);
} }
} }
static int brcmf_netdev_set_mac_address(struct net_device *ndev, void *addr) static int brcmf_netdev_set_mac_address(struct net_device *ndev, void *addr)
{ {
struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_if *ifp = netdev_priv(ndev);
struct brcmf_pub *drvr = ifp->drvr;
struct sockaddr *sa = (struct sockaddr *)addr; struct sockaddr *sa = (struct sockaddr *)addr;
memcpy(&drvr->macvalue, sa->sa_data, ETH_ALEN); memcpy(&ifp->mac_addr, sa->sa_data, ETH_ALEN);
schedule_work(&drvr->setmacaddr_work); schedule_work(&ifp->setmacaddr_work);
return 0; return 0;
} }
static void brcmf_netdev_set_multicast_list(struct net_device *ndev) static void brcmf_netdev_set_multicast_list(struct net_device *ndev)
{ {
struct brcmf_if *ifp = netdev_priv(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) 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,7 +572,7 @@ static int brcmf_netdev_stop(struct net_device *ndev)
if (drvr->bus_if->drvr_up == 0) if (drvr->bus_if->drvr_up == 0)
return 0; return 0;
brcmf_cfg80211_down(drvr->config); brcmf_cfg80211_down(ndev);
/* Set state and stop OS transmissions */ /* Set state and stop OS transmissions */
drvr->bus_if->drvr_up = false; drvr->bus_if->drvr_up = false;
...@@ -601,7 +591,6 @@ static int brcmf_netdev_open(struct net_device *ndev) ...@@ -601,7 +591,6 @@ static int brcmf_netdev_open(struct net_device *ndev)
brcmf_dbg(TRACE, "ifidx %d\n", ifp->idx); 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 is not ready, can't continue */
if (bus_if->state != BRCMF_BUS_DATA) { if (bus_if->state != BRCMF_BUS_DATA) {
brcmf_dbg(ERROR, "failed bus is not ready\n"); brcmf_dbg(ERROR, "failed bus is not ready\n");
...@@ -620,7 +609,6 @@ static int brcmf_netdev_open(struct net_device *ndev) ...@@ -620,7 +609,6 @@ static int brcmf_netdev_open(struct net_device *ndev)
else else
drvr->iflist[ifp->idx]->ndev->features &= drvr->iflist[ifp->idx]->ndev->features &=
~NETIF_F_IP_CSUM; ~NETIF_F_IP_CSUM;
}
/* make sure RF is ready for work */ /* make sure RF is ready for work */
brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0); brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
...@@ -628,7 +616,7 @@ static int brcmf_netdev_open(struct net_device *ndev) ...@@ -628,7 +616,7 @@ static int brcmf_netdev_open(struct net_device *ndev)
/* Allow transmit calls */ /* Allow transmit calls */
netif_start_queue(ndev); netif_start_queue(ndev);
drvr->bus_if->drvr_up = true; 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"); brcmf_dbg(ERROR, "failed to bring up cfg80211\n");
return -1; return -1;
} }
...@@ -646,16 +634,30 @@ static const struct net_device_ops brcmf_netdev_ops_pri = { ...@@ -646,16 +634,30 @@ static const struct net_device_ops brcmf_netdev_ops_pri = {
.ndo_set_rx_mode = brcmf_netdev_set_multicast_list .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) int brcmf_net_attach(struct brcmf_if *ifp)
{ {
struct brcmf_pub *drvr = ifp->drvr; struct brcmf_pub *drvr = ifp->drvr;
struct net_device *ndev; struct net_device *ndev;
u8 temp_addr[ETH_ALEN]; 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; /* set appropriate operations */
if (!ifp->idx)
ndev->netdev_ops = &brcmf_netdev_ops_pri; ndev->netdev_ops = &brcmf_netdev_ops_pri;
else
ndev->netdev_ops = &brcmf_netdev_ops_virt;
/* /*
* determine mac address to use * determine mac address to use
...@@ -665,13 +667,6 @@ int brcmf_net_attach(struct brcmf_if *ifp) ...@@ -665,13 +667,6 @@ int brcmf_net_attach(struct brcmf_if *ifp)
else else
memcpy(temp_addr, drvr->mac, ETH_ALEN); 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->hard_header_len = ETH_HLEN + drvr->hdrlen;
ndev->ethtool_ops = &brcmf_ethtool_ops; ndev->ethtool_ops = &brcmf_ethtool_ops;
...@@ -729,6 +724,10 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, int ifidx, s32 bssidx, ...@@ -729,6 +724,10 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, int ifidx, s32 bssidx,
drvr->iflist[ifidx] = ifp; drvr->iflist[ifidx] = ifp;
ifp->idx = ifidx; ifp->idx = ifidx;
ifp->bssidx = bssidx; 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) if (mac_addr != NULL)
memcpy(&ifp->mac_addr, mac_addr, ETH_ALEN); memcpy(&ifp->mac_addr, mac_addr, ETH_ALEN);
...@@ -760,6 +759,9 @@ void brcmf_del_if(struct brcmf_pub *drvr, int ifidx) ...@@ -760,6 +759,9 @@ void brcmf_del_if(struct brcmf_pub *drvr, int ifidx)
netif_stop_queue(ifp->ndev); netif_stop_queue(ifp->ndev);
} }
cancel_work_sync(&ifp->setmacaddr_work);
cancel_work_sync(&ifp->multicast_work);
unregister_netdev(ifp->ndev); unregister_netdev(ifp->ndev);
drvr->iflist[ifidx] = NULL; drvr->iflist[ifidx] = NULL;
if (ifidx == 0) if (ifidx == 0)
...@@ -801,9 +803,6 @@ int brcmf_attach(uint bus_hdrlen, struct device *dev) ...@@ -801,9 +803,6 @@ int brcmf_attach(uint bus_hdrlen, struct device *dev)
/* attach firmware event handler */ /* attach firmware event handler */
brcmf_fweh_attach(drvr); 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_LIST_HEAD(&drvr->bus_if->dcmd_list);
init_waitqueue_head(&drvr->pend_8021x_wait); init_waitqueue_head(&drvr->pend_8021x_wait);
...@@ -904,8 +903,6 @@ void brcmf_detach(struct device *dev) ...@@ -904,8 +903,6 @@ void brcmf_detach(struct device *dev)
brcmf_bus_detach(drvr); brcmf_bus_detach(drvr);
if (drvr->prot) { if (drvr->prot) {
cancel_work_sync(&drvr->setmacaddr_work);
cancel_work_sync(&drvr->multicast_work);
brcmf_proto_detach(drvr); brcmf_proto_detach(drvr);
} }
......
...@@ -4526,19 +4526,18 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg) ...@@ -4526,19 +4526,18 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
} }
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); 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_cfg80211_info *cfg = ifp->drvr->config;
struct brcmf_if *ifp = netdev_priv(ndev);
/* /*
* While going down, if associated with AP disassociate * While going down, if associated with AP disassociate
...@@ -4563,23 +4562,27 @@ static s32 __brcmf_cfg80211_down(struct brcmf_cfg80211_info *cfg) ...@@ -4563,23 +4562,27 @@ static s32 __brcmf_cfg80211_down(struct brcmf_cfg80211_info *cfg)
return 0; 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; s32 err = 0;
mutex_lock(&cfg->usr_sync); mutex_lock(&cfg->usr_sync);
err = __brcmf_cfg80211_up(cfg); err = __brcmf_cfg80211_up(ifp);
mutex_unlock(&cfg->usr_sync); mutex_unlock(&cfg->usr_sync);
return err; 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; s32 err = 0;
mutex_lock(&cfg->usr_sync); mutex_lock(&cfg->usr_sync);
err = __brcmf_cfg80211_down(cfg); err = __brcmf_cfg80211_down(ifp);
mutex_unlock(&cfg->usr_sync); mutex_unlock(&cfg->usr_sync);
return err; return err;
......
...@@ -455,7 +455,7 @@ brcmf_cfg80211_connect_info *cfg_to_conn(struct brcmf_cfg80211_info *cfg) ...@@ -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); struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr);
void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg); void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg);
s32 brcmf_cfg80211_up(struct brcmf_cfg80211_info *cfg); s32 brcmf_cfg80211_up(struct net_device *ndev);
s32 brcmf_cfg80211_down(struct brcmf_cfg80211_info *cfg); s32 brcmf_cfg80211_down(struct net_device *ndev);
#endif /* _wl_cfg80211_h_ */ #endif /* _wl_cfg80211_h_ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment