|
@@ -73,11 +73,8 @@ struct brcmf_info {
|
|
|
|
|
|
struct mutex proto_block;
|
|
|
|
|
|
- /* Thread to issue ioctl for multicast */
|
|
|
- struct task_struct *sysioc_tsk;
|
|
|
- wait_queue_head_t sysioc_waitq;
|
|
|
- bool set_multicast;
|
|
|
- bool set_macaddress;
|
|
|
+ struct work_struct setmacaddr_work;
|
|
|
+ struct work_struct multicast_work;
|
|
|
u8 macvalue[ETH_ALEN];
|
|
|
atomic_t pend_8021x_cnt;
|
|
|
};
|
|
@@ -85,10 +82,6 @@ struct brcmf_info {
|
|
|
/* Error bits */
|
|
|
module_param(brcmf_msg_level, int, 0);
|
|
|
|
|
|
-/* Spawn a thread for system ioctls (set mac, set mcast) */
|
|
|
-uint brcmf_sysioc = true;
|
|
|
-module_param(brcmf_sysioc, uint, 0);
|
|
|
-
|
|
|
/* ARP offload agent mode : Enable ARP Host Auto-Reply
|
|
|
and ARP Peer Auto-Reply */
|
|
|
uint brcmf_arp_mode = 0xb;
|
|
@@ -152,7 +145,7 @@ char *brcmf_ifname(struct brcmf_pub *drvr, int ifidx)
|
|
|
return "<if_none>";
|
|
|
}
|
|
|
|
|
|
-static void _brcmf_set_multicast_list(struct brcmf_info *drvr_priv, int ifidx)
|
|
|
+static void _brcmf_set_multicast_list(struct work_struct *work)
|
|
|
{
|
|
|
struct net_device *dev;
|
|
|
struct netdev_hw_addr *ha;
|
|
@@ -163,7 +156,10 @@ static void _brcmf_set_multicast_list(struct brcmf_info *drvr_priv, int ifidx)
|
|
|
uint buflen;
|
|
|
int ret;
|
|
|
|
|
|
- dev = drvr_priv->iflist[ifidx]->net;
|
|
|
+ struct brcmf_info *drvr_priv = container_of(work, struct brcmf_info,
|
|
|
+ multicast_work);
|
|
|
+
|
|
|
+ dev = drvr_priv->iflist[0]->net;
|
|
|
cnt = netdev_mc_count(dev);
|
|
|
|
|
|
/* Determine initial value of allmulti flag */
|
|
@@ -175,7 +171,7 @@ static void _brcmf_set_multicast_list(struct brcmf_info *drvr_priv, int ifidx)
|
|
|
bufp = buf = kmalloc(buflen, GFP_ATOMIC);
|
|
|
if (!bufp) {
|
|
|
brcmf_dbg(ERROR, "%s: out of memory for mcast_list, cnt %d\n",
|
|
|
- brcmf_ifname(&drvr_priv->pub, ifidx), cnt);
|
|
|
+ brcmf_ifname(&drvr_priv->pub, 0), cnt);
|
|
|
return;
|
|
|
}
|
|
|
|
|
@@ -200,10 +196,10 @@ static void _brcmf_set_multicast_list(struct brcmf_info *drvr_priv, int ifidx)
|
|
|
ioc.len = buflen;
|
|
|
ioc.set = true;
|
|
|
|
|
|
- ret = brcmf_proto_ioctl(&drvr_priv->pub, ifidx, &ioc, ioc.len);
|
|
|
+ ret = brcmf_proto_ioctl(&drvr_priv->pub, 0, &ioc, ioc.len);
|
|
|
if (ret < 0) {
|
|
|
brcmf_dbg(ERROR, "%s: set mcast_list failed, cnt %d\n",
|
|
|
- brcmf_ifname(&drvr_priv->pub, ifidx), cnt);
|
|
|
+ brcmf_ifname(&drvr_priv->pub, 0), cnt);
|
|
|
allmulti = cnt ? true : allmulti;
|
|
|
}
|
|
|
|
|
@@ -218,7 +214,7 @@ static void _brcmf_set_multicast_list(struct brcmf_info *drvr_priv, int ifidx)
|
|
|
buf = kmalloc(buflen, GFP_ATOMIC);
|
|
|
if (!buf) {
|
|
|
brcmf_dbg(ERROR, "%s: out of memory for allmulti\n",
|
|
|
- brcmf_ifname(&drvr_priv->pub, ifidx));
|
|
|
+ brcmf_ifname(&drvr_priv->pub, 0));
|
|
|
return;
|
|
|
}
|
|
|
allmulti = cpu_to_le32(allmulti);
|
|
@@ -226,7 +222,7 @@ static void _brcmf_set_multicast_list(struct brcmf_info *drvr_priv, int ifidx)
|
|
|
if (!brcmu_mkiovar
|
|
|
("allmulti", (void *)&allmulti, sizeof(allmulti), buf, buflen)) {
|
|
|
brcmf_dbg(ERROR, "%s: mkiovar failed for allmulti, datalen %d buflen %u\n",
|
|
|
- brcmf_ifname(&drvr_priv->pub, ifidx),
|
|
|
+ brcmf_ifname(&drvr_priv->pub, 0),
|
|
|
(int)sizeof(allmulti), buflen);
|
|
|
kfree(buf);
|
|
|
return;
|
|
@@ -238,10 +234,10 @@ static void _brcmf_set_multicast_list(struct brcmf_info *drvr_priv, int ifidx)
|
|
|
ioc.len = buflen;
|
|
|
ioc.set = true;
|
|
|
|
|
|
- ret = brcmf_proto_ioctl(&drvr_priv->pub, ifidx, &ioc, ioc.len);
|
|
|
+ ret = brcmf_proto_ioctl(&drvr_priv->pub, 0, &ioc, ioc.len);
|
|
|
if (ret < 0) {
|
|
|
brcmf_dbg(ERROR, "%s: set allmulti %d failed\n",
|
|
|
- brcmf_ifname(&drvr_priv->pub, ifidx),
|
|
|
+ brcmf_ifname(&drvr_priv->pub, 0),
|
|
|
le32_to_cpu(allmulti));
|
|
|
}
|
|
|
|
|
@@ -259,26 +255,30 @@ static void _brcmf_set_multicast_list(struct brcmf_info *drvr_priv, int ifidx)
|
|
|
ioc.len = sizeof(allmulti);
|
|
|
ioc.set = true;
|
|
|
|
|
|
- ret = brcmf_proto_ioctl(&drvr_priv->pub, ifidx, &ioc, ioc.len);
|
|
|
+ ret = brcmf_proto_ioctl(&drvr_priv->pub, 0, &ioc, ioc.len);
|
|
|
if (ret < 0) {
|
|
|
brcmf_dbg(ERROR, "%s: set promisc %d failed\n",
|
|
|
- brcmf_ifname(&drvr_priv->pub, ifidx),
|
|
|
+ brcmf_ifname(&drvr_priv->pub, 0),
|
|
|
le32_to_cpu(allmulti));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static int
|
|
|
-_brcmf_set_mac_address(struct brcmf_info *drvr_priv, int ifidx, u8 *addr)
|
|
|
+static void
|
|
|
+_brcmf_set_mac_address(struct work_struct *work)
|
|
|
{
|
|
|
char buf[32];
|
|
|
struct brcmf_ioctl ioc;
|
|
|
int ret;
|
|
|
|
|
|
+ struct brcmf_info *drvr_priv = container_of(work, struct brcmf_info,
|
|
|
+ setmacaddr_work);
|
|
|
+
|
|
|
brcmf_dbg(TRACE, "enter\n");
|
|
|
- if (!brcmu_mkiovar("cur_etheraddr", (char *)addr, ETH_ALEN, buf, 32)) {
|
|
|
+ if (!brcmu_mkiovar("cur_etheraddr", (char *)drvr_priv->macvalue,
|
|
|
+ ETH_ALEN, buf, 32)) {
|
|
|
brcmf_dbg(ERROR, "%s: mkiovar failed for cur_etheraddr\n",
|
|
|
- brcmf_ifname(&drvr_priv->pub, ifidx));
|
|
|
- return -1;
|
|
|
+ brcmf_ifname(&drvr_priv->pub, 0));
|
|
|
+ return;
|
|
|
}
|
|
|
memset(&ioc, 0, sizeof(ioc));
|
|
|
ioc.cmd = BRCMF_C_SET_VAR;
|
|
@@ -286,14 +286,15 @@ _brcmf_set_mac_address(struct brcmf_info *drvr_priv, int ifidx, u8 *addr)
|
|
|
ioc.len = 32;
|
|
|
ioc.set = true;
|
|
|
|
|
|
- ret = brcmf_proto_ioctl(&drvr_priv->pub, ifidx, &ioc, ioc.len);
|
|
|
+ ret = brcmf_proto_ioctl(&drvr_priv->pub, 0, &ioc, ioc.len);
|
|
|
if (ret < 0)
|
|
|
brcmf_dbg(ERROR, "%s: set cur_etheraddr failed\n",
|
|
|
- brcmf_ifname(&drvr_priv->pub, ifidx));
|
|
|
+ brcmf_ifname(&drvr_priv->pub, 0));
|
|
|
else
|
|
|
- memcpy(drvr_priv->iflist[ifidx]->net->dev_addr, addr, ETH_ALEN);
|
|
|
+ memcpy(drvr_priv->iflist[0]->net->dev_addr,
|
|
|
+ drvr_priv->macvalue, ETH_ALEN);
|
|
|
|
|
|
- return ret;
|
|
|
+ return;
|
|
|
}
|
|
|
|
|
|
/* Virtual interfaces only ((ifp && ifp->info && ifp->idx == true) */
|
|
@@ -364,76 +365,8 @@ static void brcmf_op_if(struct brcmf_if *ifp)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static int _brcmf_sysioc_thread(void *data)
|
|
|
-{
|
|
|
- struct brcmf_info *drvr_priv = (struct brcmf_info *) data;
|
|
|
- int i;
|
|
|
-#ifdef SOFTAP
|
|
|
- bool in_ap = false;
|
|
|
-#endif
|
|
|
- DECLARE_WAITQUEUE(wait, current);
|
|
|
- allow_signal(SIGTERM);
|
|
|
-
|
|
|
- add_wait_queue(&drvr_priv->sysioc_waitq, &wait);
|
|
|
- while (1) {
|
|
|
- prepare_to_wait(&drvr_priv->sysioc_waitq, &wait,
|
|
|
- TASK_INTERRUPTIBLE);
|
|
|
-
|
|
|
- /* wait for event */
|
|
|
- schedule();
|
|
|
-
|
|
|
- if (kthread_should_stop())
|
|
|
- break;
|
|
|
-
|
|
|
- for (i = 0; i < BRCMF_MAX_IFS; i++) {
|
|
|
- struct brcmf_if *ifentry = drvr_priv->iflist[i];
|
|
|
- if (ifentry) {
|
|
|
-#ifdef SOFTAP
|
|
|
- in_ap = (ap_net_dev != NULL);
|
|
|
-#endif /* SOFTAP */
|
|
|
- if (ifentry->state)
|
|
|
- brcmf_op_if(ifentry);
|
|
|
-#ifdef SOFTAP
|
|
|
- if (drvr_priv->iflist[i] == NULL) {
|
|
|
- brcmf_dbg(TRACE, "interface %d removed!\n",
|
|
|
- i);
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- if (in_ap && drvr_priv->set_macaddress) {
|
|
|
- brcmf_dbg(TRACE, "attempt to set MAC for %s in AP Mode, blocked.\n",
|
|
|
- ifentry->net->name);
|
|
|
- drvr_priv->set_macaddress = false;
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- if (in_ap && drvr_priv->set_multicast) {
|
|
|
- brcmf_dbg(TRACE, "attempt to set MULTICAST list for %s in AP Mode, blocked.\n",
|
|
|
- ifentry->net->name);
|
|
|
- drvr_priv->set_multicast = false;
|
|
|
- continue;
|
|
|
- }
|
|
|
-#endif /* SOFTAP */
|
|
|
- if (drvr_priv->set_multicast) {
|
|
|
- drvr_priv->set_multicast = false;
|
|
|
- _brcmf_set_multicast_list(drvr_priv, i);
|
|
|
- }
|
|
|
- if (drvr_priv->set_macaddress) {
|
|
|
- drvr_priv->set_macaddress = false;
|
|
|
- _brcmf_set_mac_address(drvr_priv, i,
|
|
|
- drvr_priv->macvalue);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- finish_wait(&drvr_priv->sysioc_waitq, &wait);
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
static int brcmf_netdev_set_mac_address(struct net_device *dev, void *addr)
|
|
|
{
|
|
|
- int ret = 0;
|
|
|
-
|
|
|
struct brcmf_info *drvr_priv = *(struct brcmf_info **) netdev_priv(dev);
|
|
|
struct sockaddr *sa = (struct sockaddr *)addr;
|
|
|
int ifidx;
|
|
@@ -443,9 +376,8 @@ static int brcmf_netdev_set_mac_address(struct net_device *dev, void *addr)
|
|
|
return -1;
|
|
|
|
|
|
memcpy(&drvr_priv->macvalue, sa->sa_data, ETH_ALEN);
|
|
|
- drvr_priv->set_macaddress = true;
|
|
|
- wake_up(&drvr_priv->sysioc_waitq);
|
|
|
- return ret;
|
|
|
+ schedule_work(&drvr_priv->setmacaddr_work);
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
static void brcmf_netdev_set_multicast_list(struct net_device *dev)
|
|
@@ -457,8 +389,7 @@ static void brcmf_netdev_set_multicast_list(struct net_device *dev)
|
|
|
if (ifidx == BRCMF_BAD_IF)
|
|
|
return;
|
|
|
|
|
|
- drvr_priv->set_multicast = true;
|
|
|
- wake_up(&drvr_priv->sysioc_waitq);
|
|
|
+ schedule_work(&drvr_priv->multicast_work);
|
|
|
}
|
|
|
|
|
|
int brcmf_sendpkt(struct brcmf_pub *drvr, int ifidx, struct sk_buff *pktbuf)
|
|
@@ -1056,7 +987,7 @@ brcmf_add_if(struct brcmf_info *drvr_priv, int ifidx, struct net_device *net,
|
|
|
if (net == NULL) {
|
|
|
ifp->state = BRCMF_E_IF_ADD;
|
|
|
ifp->idx = ifidx;
|
|
|
- wake_up(&drvr_priv->sysioc_waitq);
|
|
|
+ brcmf_op_if(ifp);
|
|
|
} else
|
|
|
ifp->net = net;
|
|
|
|
|
@@ -1077,7 +1008,7 @@ void brcmf_del_if(struct brcmf_info *drvr_priv, int ifidx)
|
|
|
|
|
|
ifp->state = BRCMF_E_IF_DEL;
|
|
|
ifp->idx = ifidx;
|
|
|
- wake_up(&drvr_priv->sysioc_waitq);
|
|
|
+ brcmf_op_if(ifp);
|
|
|
}
|
|
|
|
|
|
struct brcmf_pub *brcmf_attach(struct brcmf_bus *bus, uint bus_hdrlen)
|
|
@@ -1148,17 +1079,8 @@ struct brcmf_pub *brcmf_attach(struct brcmf_bus *bus, uint bus_hdrlen)
|
|
|
goto fail;
|
|
|
}
|
|
|
|
|
|
- if (brcmf_sysioc) {
|
|
|
- init_waitqueue_head(&drvr_priv->sysioc_waitq);
|
|
|
- drvr_priv->sysioc_tsk = kthread_run(_brcmf_sysioc_thread,
|
|
|
- drvr_priv, "_brcmf_sysioc");
|
|
|
- if (IS_ERR(drvr_priv->sysioc_tsk)) {
|
|
|
- printk(KERN_WARNING
|
|
|
- "_brcmf_sysioc thread failed to start\n");
|
|
|
- drvr_priv->sysioc_tsk = NULL;
|
|
|
- }
|
|
|
- } else
|
|
|
- drvr_priv->sysioc_tsk = NULL;
|
|
|
+ INIT_WORK(&drvr_priv->setmacaddr_work, _brcmf_set_mac_address);
|
|
|
+ INIT_WORK(&drvr_priv->multicast_work, _brcmf_set_multicast_list);
|
|
|
|
|
|
/*
|
|
|
* Save the brcmf_info into the priv
|
|
@@ -1337,11 +1259,8 @@ void brcmf_detach(struct brcmf_pub *drvr)
|
|
|
unregister_netdev(ifp->net);
|
|
|
}
|
|
|
|
|
|
- if (drvr_priv->sysioc_tsk) {
|
|
|
- send_sig(SIGTERM, drvr_priv->sysioc_tsk, 1);
|
|
|
- kthread_stop(drvr_priv->sysioc_tsk);
|
|
|
- drvr_priv->sysioc_tsk = NULL;
|
|
|
- }
|
|
|
+ cancel_work_sync(&drvr_priv->setmacaddr_work);
|
|
|
+ cancel_work_sync(&drvr_priv->multicast_work);
|
|
|
|
|
|
brcmf_bus_detach(drvr);
|
|
|
|