staging: brcm80211: removed log after kzalloc()/kmalloc() failure
[pandora-kernel.git] / drivers / staging / brcm80211 / brcmfmac / dhd_linux.c
index f462a5f..659a9c2 100644 (file)
@@ -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,25 +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;
-module_param(brcmf_arp_mode, uint, 0);
-
-/* ARP offload enable */
-uint brcmf_arp_enable = true;
-module_param(brcmf_arp_enable, uint, 0);
-
-/* Control radio state */
-uint brcmf_radio_up = 1;
-
-/* Network inteface name */
-char iface_name[IFNAMSIZ] = "wlan";
-module_param_string(iface_name, iface_name, IFNAMSIZ, 0);
 
 static int brcmf_net2idx(struct brcmf_info *drvr_priv, struct net_device *net)
 {
@@ -155,18 +133,23 @@ 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;
        u32 allmulti, cnt;
+       __le32 cnt_le;
+       __le32 allmulti_le;
 
        struct brcmf_ioctl ioc;
        char *buf, *bufp;
        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 */
@@ -176,18 +159,15 @@ static void _brcmf_set_multicast_list(struct brcmf_info *drvr_priv, int ifidx)
 
        buflen = sizeof("mcast_list") + sizeof(cnt) + (cnt * ETH_ALEN);
        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);
+       if (!bufp)
                return;
-       }
 
        strcpy(bufp, "mcast_list");
        bufp += strlen("mcast_list") + 1;
 
-       cnt = cpu_to_le32(cnt);
-       memcpy(bufp, &cnt, sizeof(cnt));
-       bufp += sizeof(cnt);
+       cnt_le = cpu_to_le32(cnt);
+       memcpy(bufp, &cnt_le, sizeof(cnt));
+       bufp += sizeof(cnt_le);
 
        netdev_for_each_mc_addr(ha, dev) {
                if (!cnt)
@@ -203,10 +183,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.buf, 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;
        }
 
@@ -219,17 +199,16 @@ static void _brcmf_set_multicast_list(struct brcmf_info *drvr_priv, int ifidx)
 
        buflen = sizeof("allmulti") + sizeof(allmulti);
        buf = kmalloc(buflen, GFP_ATOMIC);
-       if (!buf) {
-               brcmf_dbg(ERROR, "%s: out of memory for allmulti\n",
-                         brcmf_ifname(&drvr_priv->pub, ifidx));
+       if (!buf)
                return;
-       }
-       allmulti = cpu_to_le32(allmulti);
+
+       allmulti_le = cpu_to_le32(allmulti);
 
        if (!brcmu_mkiovar
-           ("allmulti", (void *)&allmulti, sizeof(allmulti), buf, buflen)) {
+           ("allmulti", (void *)&allmulti_le,
+           sizeof(allmulti_le), 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;
@@ -241,11 +220,11 @@ 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.buf, 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),
-                         le32_to_cpu(allmulti));
+                         brcmf_ifname(&drvr_priv->pub, 0),
+                         le32_to_cpu(allmulti_le));
        }
 
        kfree(buf);
@@ -254,34 +233,38 @@ static void _brcmf_set_multicast_list(struct brcmf_info *drvr_priv, int ifidx)
                 driver does */
 
        allmulti = (dev->flags & IFF_PROMISC) ? true : false;
-       allmulti = cpu_to_le32(allmulti);
+       allmulti_le = cpu_to_le32(allmulti);
 
        memset(&ioc, 0, sizeof(ioc));
        ioc.cmd = BRCMF_C_SET_PROMISC;
-       ioc.buf = &allmulti;
-       ioc.len = sizeof(allmulti);
+       ioc.buf = &allmulti_le;
+       ioc.len = sizeof(allmulti_le);
        ioc.set = true;
 
-       ret = brcmf_proto_ioctl(&drvr_priv->pub, ifidx, &ioc, ioc.buf, 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),
-                         le32_to_cpu(allmulti));
+                         brcmf_ifname(&drvr_priv->pub, 0),
+                         le32_to_cpu(allmulti_le));
        }
 }
 
-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;
@@ -289,14 +272,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.buf, 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) */
@@ -322,10 +306,11 @@ static void brcmf_op_if(struct brcmf_if *ifp)
                        unregister_netdev(ifp->net);
                        free_netdev(ifp->net);
                }
-               /* Allocate etherdev, including space for private structure */
-               ifp->net = alloc_etherdev(sizeof(drvr_priv));
+               /* Allocate netdev, including space for private structure */
+               ifp->net = alloc_netdev(sizeof(drvr_priv), "wlan%d",
+                                       ether_setup);
                if (!ifp->net) {
-                       brcmf_dbg(ERROR, "OOM - alloc_etherdev\n");
+                       brcmf_dbg(ERROR, "OOM - alloc_netdev\n");
                        ret = -ENOMEM;
                }
                if (ret == 0) {
@@ -367,76 +352,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;
@@ -446,9 +363,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)
@@ -460,8 +376,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)
@@ -721,7 +636,7 @@ static int brcmf_toe_get(struct brcmf_info *drvr_priv, int ifidx, u32 *toe_ol)
        ioc.set = false;
 
        strcpy(buf, "toe_ol");
-       ret = brcmf_proto_ioctl(&drvr_priv->pub, ifidx, &ioc, ioc.buf, ioc.len);
+       ret = brcmf_proto_ioctl(&drvr_priv->pub, ifidx, &ioc, ioc.len);
        if (ret < 0) {
                /* Check for older dongle image that doesn't support toe_ol */
                if (ret == -EIO) {
@@ -759,7 +674,7 @@ static int brcmf_toe_set(struct brcmf_info *drvr_priv, int ifidx, u32 toe_ol)
        strcpy(buf, "toe_ol");
        memcpy(&buf[sizeof("toe_ol")], &toe_ol, sizeof(u32));
 
-       ret = brcmf_proto_ioctl(&drvr_priv->pub, ifidx, &ioc, ioc.buf, ioc.len);
+       ret = brcmf_proto_ioctl(&drvr_priv->pub, ifidx, &ioc, ioc.len);
        if (ret < 0) {
                brcmf_dbg(ERROR, "%s: could not set toe_ol: ret=%d\n",
                          brcmf_ifname(&drvr_priv->pub, ifidx), ret);
@@ -773,7 +688,7 @@ static int brcmf_toe_set(struct brcmf_info *drvr_priv, int ifidx, u32 toe_ol)
        strcpy(buf, "toe");
        memcpy(&buf[sizeof("toe")], &toe, sizeof(u32));
 
-       ret = brcmf_proto_ioctl(&drvr_priv->pub, ifidx, &ioc, ioc.buf, ioc.len);
+       ret = brcmf_proto_ioctl(&drvr_priv->pub, ifidx, &ioc, ioc.len);
        if (ret < 0) {
                brcmf_dbg(ERROR, "%s: could not set toe: ret=%d\n",
                          brcmf_ifname(&drvr_priv->pub, ifidx), ret);
@@ -966,8 +881,7 @@ int brcmf_netdev_ioctl_priv(struct net_device *net, struct brcmf_ioctl *ioc)
        if (is_set_key_cmd)
                brcmf_netdev_wait_pend8021x(net);
 
-       bcmerror = brcmf_proto_ioctl(&drvr_priv->pub, ifidx,
-                                    ioc, ioc->buf, buflen);
+       bcmerror = brcmf_proto_ioctl(&drvr_priv->pub, ifidx, ioc, buflen);
 
 done:
        if (bcmerror > 0)
@@ -1025,7 +939,7 @@ static int brcmf_netdev_open(struct net_device *net)
        /* Allow transmit calls */
        netif_start_queue(net);
        drvr_priv->pub.up = 1;
-       if (unlikely(brcmf_cfg80211_up(drvr_priv->pub.config))) {
+       if (brcmf_cfg80211_up(drvr_priv->pub.config)) {
                brcmf_dbg(ERROR, "failed to bring up cfg80211\n");
                return -1;
        }
@@ -1044,10 +958,8 @@ brcmf_add_if(struct brcmf_info *drvr_priv, int ifidx, struct net_device *net,
        ifp = drvr_priv->iflist[ifidx];
        if (!ifp) {
                ifp = kmalloc(sizeof(struct brcmf_if), GFP_ATOMIC);
-               if (!ifp) {
-                       brcmf_dbg(ERROR, "OOM - struct brcmf_if\n");
+               if (!ifp)
                        return -ENOMEM;
-               }
        }
 
        memset(ifp, 0, sizeof(struct brcmf_if));
@@ -1060,7 +972,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;
 
@@ -1081,7 +993,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)
@@ -1091,37 +1003,23 @@ struct brcmf_pub *brcmf_attach(struct brcmf_bus *bus, uint bus_hdrlen)
 
        brcmf_dbg(TRACE, "Enter\n");
 
-       /* Allocate etherdev, including space for private structure */
-       net = alloc_etherdev(sizeof(drvr_priv));
+       /* Allocate netdev, including space for private structure */
+       net = alloc_netdev(sizeof(drvr_priv), "wlan%d", ether_setup);
        if (!net) {
-               brcmf_dbg(ERROR, "OOM - alloc_etherdev\n");
+               brcmf_dbg(ERROR, "OOM - alloc_netdev\n");
                goto fail;
        }
 
        /* Allocate primary brcmf_info */
        drvr_priv = kzalloc(sizeof(struct brcmf_info), GFP_ATOMIC);
-       if (!drvr_priv) {
-               brcmf_dbg(ERROR, "OOM - alloc brcmf_info\n");
+       if (!drvr_priv)
                goto fail;
-       }
 
        /*
         * Save the brcmf_info into the priv
         */
        memcpy(netdev_priv(net), &drvr_priv, sizeof(drvr_priv));
 
-       /* Set network interface name if it was provided as module parameter */
-       if (iface_name[0]) {
-               int len;
-               char ch;
-               strncpy(net->name, iface_name, IFNAMSIZ);
-               net->name[IFNAMSIZ - 1] = 0;
-               len = strlen(net->name);
-               ch = net->name[len - 1];
-               if ((ch > '9' || ch < '0') && (len < IFNAMSIZ - 2))
-                       strcat(net->name, "%d");
-       }
-
        if (brcmf_add_if(drvr_priv, 0, net, net->name, NULL, 0, 0) ==
            BRCMF_BAD_IF)
                goto fail;
@@ -1147,22 +1045,13 @@ struct brcmf_pub *brcmf_attach(struct brcmf_bus *bus, uint bus_hdrlen)
                        brcmf_cfg80211_attach(net,
                                              brcmf_bus_get_device(bus),
                                              &drvr_priv->pub);
-       if (unlikely(drvr_priv->pub.config == NULL)) {
+       if (drvr_priv->pub.config == NULL) {
                brcmf_dbg(ERROR, "wl_cfg80211_attach failed\n");
                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
@@ -1341,11 +1230,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);