blob: 6370a5efe343abd657226735be6d044e28c91d99 [file] [log] [blame]
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001#include "wilc_wfi_cfgoperations.h"
Johnny Kimc5c77ba2015-05-11 14:30:56 +09002#include "wilc_wlan_if.h"
3#include "wilc_wlan.h"
Johnny Kimc5c77ba2015-05-11 14:30:56 +09004
5#include <linux/slab.h>
6#include <linux/sched.h>
7#include <linux/delay.h>
8#include <linux/workqueue.h>
9#include <linux/interrupt.h>
10#include <linux/irq.h>
Guenter Roeckf1a99832015-05-27 13:02:16 -070011#include <linux/gpio.h>
Johnny Kimc5c77ba2015-05-11 14:30:56 +090012
13#include <linux/kthread.h>
14#include <linux/firmware.h>
Johnny Kimc5c77ba2015-05-11 14:30:56 +090015
16#include <linux/init.h>
17#include <linux/netdevice.h>
Johnny Kimc5c77ba2015-05-11 14:30:56 +090018#include <linux/inetdevice.h>
Johnny Kimc5c77ba2015-05-11 14:30:56 +090019#include <linux/etherdevice.h>
20#include <linux/module.h>
21#include <linux/kernel.h>
22#include <linux/skbuff.h>
Binoy Jayan334bed02016-06-15 11:00:35 +053023#include <linux/mutex.h>
Leo Kim11a54b32016-04-01 17:44:15 +090024#include <linux/completion.h>
Johnny Kimc5c77ba2015-05-11 14:30:56 +090025
Leo Kim885cabc2016-02-04 18:15:35 +090026static int dev_state_ev_handler(struct notifier_block *this,
27 unsigned long event, void *ptr);
Johnny Kimc5c77ba2015-05-11 14:30:56 +090028
29static struct notifier_block g_dev_notifier = {
30 .notifier_call = dev_state_ev_handler
31};
Johnny Kimc5c77ba2015-05-11 14:30:56 +090032
Glen Lee7c67c052015-10-27 18:27:50 +090033static int wlan_deinit_locks(struct net_device *dev);
Glen Lee32dd51b2015-10-27 18:27:52 +090034static void wlan_deinitialize_threads(struct net_device *dev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +090035
Johnny Kimc5c77ba2015-05-11 14:30:56 +090036static void linux_wlan_tx_complete(void *priv, int status);
Johnny Kimc5c77ba2015-05-11 14:30:56 +090037static int mac_init_fn(struct net_device *ndev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +090038static struct net_device_stats *mac_stats(struct net_device *dev);
39static int mac_ioctl(struct net_device *ndev, struct ifreq *req, int cmd);
40static void wilc_set_multicast_list(struct net_device *dev);
Arnd Bergmann750ffe92015-11-16 15:05:08 +010041
Arnd Bergmann0e1af732015-11-16 15:04:54 +010042bool wilc_enable_ps = true;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090043
Johnny Kimc5c77ba2015-05-11 14:30:56 +090044static const struct net_device_ops wilc_netdev_ops = {
45 .ndo_init = mac_init_fn,
Arnd Bergmann0e1af732015-11-16 15:04:54 +010046 .ndo_open = wilc_mac_open,
47 .ndo_stop = wilc_mac_close,
48 .ndo_start_xmit = wilc_mac_xmit,
Johnny Kimc5c77ba2015-05-11 14:30:56 +090049 .ndo_do_ioctl = mac_ioctl,
50 .ndo_get_stats = mac_stats,
51 .ndo_set_rx_mode = wilc_set_multicast_list,
52
53};
Johnny Kimc5c77ba2015-05-11 14:30:56 +090054
Leo Kim885cabc2016-02-04 18:15:35 +090055static int dev_state_ev_handler(struct notifier_block *this,
56 unsigned long event, void *ptr)
Johnny Kimc5c77ba2015-05-11 14:30:56 +090057{
Alison Schofieldd5c89442016-02-12 22:53:13 -080058 struct in_ifaddr *dev_iface = ptr;
Chaehyun Lim27268872015-09-15 14:06:13 +090059 struct wilc_priv *priv;
Leo Kimf24374a2015-11-05 14:36:12 +090060 struct host_if_drv *hif_drv;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090061 struct net_device *dev;
Leo Kimeac3e8f2015-11-05 14:36:16 +090062 u8 *ip_addr_buf;
Glen Leea4cac482015-12-21 14:18:36 +090063 struct wilc_vif *vif;
Greg Kroah-Hartman63d03e42015-06-02 14:16:04 +090064 u8 null_ip[4] = {0};
Johnny Kimc5c77ba2015-05-11 14:30:56 +090065 char wlan_dev_name[5] = "wlan0";
66
Leo Kim14086032016-02-04 18:15:36 +090067 if (!dev_iface || !dev_iface->ifa_dev || !dev_iface->ifa_dev->dev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +090068 return NOTIFY_DONE;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090069
Leo Kim582f8a22015-11-05 14:36:21 +090070 if (memcmp(dev_iface->ifa_label, "wlan0", 5) &&
Leo Kim14086032016-02-04 18:15:36 +090071 memcmp(dev_iface->ifa_label, "p2p0", 4))
Johnny Kimc5c77ba2015-05-11 14:30:56 +090072 return NOTIFY_DONE;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090073
74 dev = (struct net_device *)dev_iface->ifa_dev->dev;
Leo Kim14086032016-02-04 18:15:36 +090075 if (!dev->ieee80211_ptr || !dev->ieee80211_ptr->wiphy)
Johnny Kimc5c77ba2015-05-11 14:30:56 +090076 return NOTIFY_DONE;
Leo Kim14086032016-02-04 18:15:36 +090077
Johnny Kimc5c77ba2015-05-11 14:30:56 +090078 priv = wiphy_priv(dev->ieee80211_ptr->wiphy);
Leo Kim14086032016-02-04 18:15:36 +090079 if (!priv)
Johnny Kimc5c77ba2015-05-11 14:30:56 +090080 return NOTIFY_DONE;
Leo Kim14086032016-02-04 18:15:36 +090081
Leo Kim48b28df2016-02-04 18:15:32 +090082 hif_drv = (struct host_if_drv *)priv->hif_drv;
Glen Leea4cac482015-12-21 14:18:36 +090083 vif = netdev_priv(dev);
Leo Kim14086032016-02-04 18:15:36 +090084 if (!vif || !hif_drv)
Johnny Kimc5c77ba2015-05-11 14:30:56 +090085 return NOTIFY_DONE;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090086
87 switch (event) {
88 case NETDEV_UP:
Glen Leea4cac482015-12-21 14:18:36 +090089 if (vif->iftype == STATION_MODE || vif->iftype == CLIENT_MODE) {
Leo Kimf24374a2015-11-05 14:36:12 +090090 hif_drv->IFC_UP = 1;
Arnd Bergmann0e1af732015-11-16 15:04:54 +010091 wilc_optaining_ip = false;
92 del_timer(&wilc_during_ip_timer);
Johnny Kimc5c77ba2015-05-11 14:30:56 +090093 }
94
Arnd Bergmann0e1af732015-11-16 15:04:54 +010095 if (wilc_enable_ps)
Glen Leefbf53792015-12-21 14:18:40 +090096 wilc_set_power_mgmt(vif, 1, 0);
Johnny Kimc5c77ba2015-05-11 14:30:56 +090097
Leo Kim5ac24422016-02-04 18:15:37 +090098 netdev_dbg(dev, "[%s] Up IP\n", dev_iface->ifa_label);
Johnny Kimc5c77ba2015-05-11 14:30:56 +090099
Leo Kimeac3e8f2015-11-05 14:36:16 +0900100 ip_addr_buf = (char *)&dev_iface->ifa_address;
Leo Kim5ac24422016-02-04 18:15:37 +0900101 netdev_dbg(dev, "IP add=%d:%d:%d:%d\n",
102 ip_addr_buf[0], ip_addr_buf[1],
103 ip_addr_buf[2], ip_addr_buf[3]);
Leo Kim67501402016-02-04 18:15:39 +0900104 wilc_setup_ipaddress(vif, ip_addr_buf, vif->idx);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900105
106 break;
107
108 case NETDEV_DOWN:
Glen Leea4cac482015-12-21 14:18:36 +0900109 if (vif->iftype == STATION_MODE || vif->iftype == CLIENT_MODE) {
Leo Kimf24374a2015-11-05 14:36:12 +0900110 hif_drv->IFC_UP = 0;
Arnd Bergmann0e1af732015-11-16 15:04:54 +0100111 wilc_optaining_ip = false;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900112 }
113
114 if (memcmp(dev_iface->ifa_label, wlan_dev_name, 5) == 0)
Glen Leefbf53792015-12-21 14:18:40 +0900115 wilc_set_power_mgmt(vif, 0, 0);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900116
Glen Leefbf53792015-12-21 14:18:40 +0900117 wilc_resolve_disconnect_aberration(vif);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900118
Leo Kim5ac24422016-02-04 18:15:37 +0900119 netdev_dbg(dev, "[%s] Down IP\n", dev_iface->ifa_label);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900120
Leo Kimeac3e8f2015-11-05 14:36:16 +0900121 ip_addr_buf = null_ip;
Leo Kim5ac24422016-02-04 18:15:37 +0900122 netdev_dbg(dev, "IP add=%d:%d:%d:%d\n",
123 ip_addr_buf[0], ip_addr_buf[1],
124 ip_addr_buf[2], ip_addr_buf[3]);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900125
Leo Kim67501402016-02-04 18:15:39 +0900126 wilc_setup_ipaddress(vif, ip_addr_buf, vif->idx);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900127
128 break;
129
130 default:
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900131 break;
132 }
133
134 return NOTIFY_DONE;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900135}
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900136
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900137static irqreturn_t isr_uh_routine(int irq, void *user_data)
138{
Glen Leea4cac482015-12-21 14:18:36 +0900139 struct wilc_vif *vif;
Glen Lee39483622015-10-27 18:27:37 +0900140 struct wilc *wilc;
Alison Schofieldd5c89442016-02-12 22:53:13 -0800141 struct net_device *dev = user_data;
Glen Lee39483622015-10-27 18:27:37 +0900142
Glen Leea4cac482015-12-21 14:18:36 +0900143 vif = netdev_priv(dev);
144 wilc = vif->wilc;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900145
Glen Lee39483622015-10-27 18:27:37 +0900146 if (wilc->close) {
Leo Kim5ac24422016-02-04 18:15:37 +0900147 netdev_err(dev, "Can't handle UH interrupt\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900148 return IRQ_HANDLED;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900149 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900150 return IRQ_WAKE_THREAD;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900151}
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900152
Arnd Bergmann1608c402015-11-16 15:04:53 +0100153static irqreturn_t isr_bh_routine(int irq, void *userdata)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900154{
Glen Leea4cac482015-12-21 14:18:36 +0900155 struct wilc_vif *vif;
Glen Lee2e7933d2015-10-27 18:27:38 +0900156 struct wilc *wilc;
Alison Schofieldd5c89442016-02-12 22:53:13 -0800157 struct net_device *dev = userdata;
Glen Lee2e7933d2015-10-27 18:27:38 +0900158
Glen Leea4cac482015-12-21 14:18:36 +0900159 vif = netdev_priv(userdata);
160 wilc = vif->wilc;
Glen Lee2e7933d2015-10-27 18:27:38 +0900161
Glen Lee2e7933d2015-10-27 18:27:38 +0900162 if (wilc->close) {
Leo Kim5ac24422016-02-04 18:15:37 +0900163 netdev_err(dev, "Can't handle BH interrupt\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900164 return IRQ_HANDLED;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900165 }
166
Glen Lee50b929e2015-10-27 18:27:40 +0900167 wilc_handle_isr(wilc);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900168
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900169 return IRQ_HANDLED;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900170}
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900171
Glen Lee2c1d05d2015-10-20 17:14:03 +0900172static int init_irq(struct net_device *dev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900173{
174 int ret = 0;
Glen Leea4cac482015-12-21 14:18:36 +0900175 struct wilc_vif *vif;
Glen Lee2c1d05d2015-10-20 17:14:03 +0900176 struct wilc *wl;
177
Glen Leea4cac482015-12-21 14:18:36 +0900178 vif = netdev_priv(dev);
179 wl = vif->wilc;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900180
Arnd Bergmannc4d139c2015-11-16 15:05:04 +0100181 if ((gpio_request(wl->gpio, "WILC_INTR") == 0) &&
182 (gpio_direction_input(wl->gpio) == 0)) {
183 wl->dev_irq_num = gpio_to_irq(wl->gpio);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900184 } else {
185 ret = -1;
Leo Kim5ac24422016-02-04 18:15:37 +0900186 netdev_err(dev, "could not obtain gpio for WILC_INTR\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900187 }
188
Leo Kim83231b72015-11-06 11:12:22 +0900189 if (ret != -1 && request_threaded_irq(wl->dev_irq_num,
190 isr_uh_routine,
191 isr_bh_routine,
192 IRQF_TRIGGER_LOW | IRQF_ONESHOT,
193 "WILC_IRQ", dev) < 0) {
Leo Kim5ac24422016-02-04 18:15:37 +0900194 netdev_err(dev, "Failed to request IRQ GPIO: %d\n", wl->gpio);
Arnd Bergmannc4d139c2015-11-16 15:05:04 +0100195 gpio_free(wl->gpio);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900196 ret = -1;
197 } else {
Leo Kim5ac24422016-02-04 18:15:37 +0900198 netdev_dbg(dev,
199 "IRQ request succeeded IRQ-NUM= %d on GPIO: %d\n",
200 wl->dev_irq_num, wl->gpio);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900201 }
202
203 return ret;
204}
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900205
Glen Leeec5cc752015-10-27 18:27:39 +0900206static void deinit_irq(struct net_device *dev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900207{
Glen Leea4cac482015-12-21 14:18:36 +0900208 struct wilc_vif *vif;
Glen Leeec5cc752015-10-27 18:27:39 +0900209 struct wilc *wilc;
210
Glen Leea4cac482015-12-21 14:18:36 +0900211 vif = netdev_priv(dev);
212 wilc = vif->wilc;
Glen Leeec5cc752015-10-27 18:27:39 +0900213
Arnd Bergmannc4d139c2015-11-16 15:05:04 +0100214 /* Deintialize IRQ */
215 if (wilc->dev_irq_num) {
Glen Leeec5cc752015-10-27 18:27:39 +0900216 free_irq(wilc->dev_irq_num, wilc);
Arnd Bergmannc4d139c2015-11-16 15:05:04 +0100217 gpio_free(wilc->gpio);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900218 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900219}
220
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100221int wilc_lock_timeout(struct wilc *nic, void *vp, u32 timeout)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900222{
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100223 /* FIXME: replace with mutex_lock or wait_for_completion */
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900224 int error = -1;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900225
Leo Kim3a147c02015-11-05 14:36:10 +0900226 if (vp)
Alison Schofieldd5c89442016-02-12 22:53:13 -0800227 error = down_timeout(vp,
Leo Kim582f8a22015-11-05 14:36:21 +0900228 msecs_to_jiffies(timeout));
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900229 return error;
230}
231
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100232void wilc_mac_indicate(struct wilc *wilc, int flag)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900233{
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900234 int status;
235
236 if (flag == WILC_MAC_INDICATE_STATUS) {
Leo Kim582f8a22015-11-05 14:36:21 +0900237 wilc_wlan_cfg_get_val(WID_STATUS,
238 (unsigned char *)&status, 4);
Glen Lee64f2b712015-10-27 18:27:43 +0900239 if (wilc->mac_status == WILC_MAC_STATUS_INIT) {
240 wilc->mac_status = status;
Binoy Jayan04247e72016-06-15 11:00:37 +0530241 complete(&wilc->sync_event);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900242 } else {
Glen Lee64f2b712015-10-27 18:27:43 +0900243 wilc->mac_status = status;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900244 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900245 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900246}
247
Arnd Bergmann1608c402015-11-16 15:04:53 +0100248static struct net_device *get_if_handler(struct wilc *wilc, u8 *mac_header)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900249{
Leo Kim660786e2015-11-05 14:36:27 +0900250 u8 *bssid, *bssid1;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900251 int i = 0;
252
Leo Kimd2392222015-11-05 14:36:26 +0900253 bssid = mac_header + 10;
Leo Kim660786e2015-11-05 14:36:27 +0900254 bssid1 = mac_header + 4;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900255
Glen Leeba615f12016-01-25 16:35:15 +0900256 for (i = 0; i < wilc->vif_num; i++) {
257 if (wilc->vif[i]->mode == STATION_MODE)
Leo Kimfa633942016-03-25 21:16:53 +0900258 if (ether_addr_equal_unaligned(bssid,
259 wilc->vif[i]->bssid))
Glen Leeba615f12016-01-25 16:35:15 +0900260 return wilc->vif[i]->ndev;
261 if (wilc->vif[i]->mode == AP_MODE)
Leo Kimfa633942016-03-25 21:16:53 +0900262 if (ether_addr_equal_unaligned(bssid1,
263 wilc->vif[i]->bssid))
Glen Leeba615f12016-01-25 16:35:15 +0900264 return wilc->vif[i]->ndev;
265 }
Tony Cho8259a532015-10-20 14:26:47 +0900266
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900267 return NULL;
268}
269
Glen Leeba615f12016-01-25 16:35:15 +0900270int wilc_wlan_set_bssid(struct net_device *wilc_netdev, u8 *bssid, u8 mode)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900271{
272 int i = 0;
273 int ret = -1;
Glen Leea4cac482015-12-21 14:18:36 +0900274 struct wilc_vif *vif;
Glen Lee472791a2015-10-27 18:27:44 +0900275 struct wilc *wilc;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900276
Glen Leea4cac482015-12-21 14:18:36 +0900277 vif = netdev_priv(wilc_netdev);
278 wilc = vif->wilc;
Glen Lee472791a2015-10-27 18:27:44 +0900279
280 for (i = 0; i < wilc->vif_num; i++)
Glen Lee1f435d22015-12-21 14:18:37 +0900281 if (wilc->vif[i]->ndev == wilc_netdev) {
282 memcpy(wilc->vif[i]->bssid, bssid, 6);
Glen Leeba615f12016-01-25 16:35:15 +0900283 wilc->vif[i]->mode = mode;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900284 ret = 0;
285 break;
286 }
Tony Cho8259a532015-10-20 14:26:47 +0900287
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900288 return ret;
289}
290
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100291int wilc_wlan_get_num_conn_ifcs(struct wilc *wilc)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900292{
Chaehyun Lim51e825f2015-09-15 14:06:14 +0900293 u8 i = 0;
294 u8 null_bssid[6] = {0};
295 u8 ret_val = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900296
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100297 for (i = 0; i < wilc->vif_num; i++)
Glen Lee1f435d22015-12-21 14:18:37 +0900298 if (memcmp(wilc->vif[i]->bssid, null_bssid, 6))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900299 ret_val++;
Tony Cho8259a532015-10-20 14:26:47 +0900300
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900301 return ret_val;
302}
303
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900304static int linux_wlan_txq_task(void *vp)
305{
306 int ret, txq_count;
Glen Leea4cac482015-12-21 14:18:36 +0900307 struct wilc_vif *vif;
Glen Lee88687582015-10-27 18:27:46 +0900308 struct wilc *wl;
309 struct net_device *dev = vp;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900310
Glen Leea4cac482015-12-21 14:18:36 +0900311 vif = netdev_priv(dev);
312 wl = vif->wilc;
Glen Lee88687582015-10-27 18:27:46 +0900313
Leo Kim11a54b32016-04-01 17:44:15 +0900314 complete(&wl->txq_thread_started);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900315 while (1) {
Binoy Jayanb27a6d52016-06-15 11:00:34 +0530316 wait_for_completion(&wl->txq_event);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900317
Glen Lee88687582015-10-27 18:27:46 +0900318 if (wl->close) {
Leo Kim11a54b32016-04-01 17:44:15 +0900319 complete(&wl->txq_thread_started);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900320
321 while (!kthread_should_stop())
322 schedule();
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900323 break;
324 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900325 do {
Glen Leea1332ca2015-10-27 18:27:47 +0900326 ret = wilc_wlan_handle_txq(dev, &txq_count);
Leo Kim98b89842015-11-05 14:36:18 +0900327 if (txq_count < FLOW_CONTROL_LOWER_THRESHOLD) {
Glen Lee1f435d22015-12-21 14:18:37 +0900328 if (netif_queue_stopped(wl->vif[0]->ndev))
329 netif_wake_queue(wl->vif[0]->ndev);
330 if (netif_queue_stopped(wl->vif[1]->ndev))
331 netif_wake_queue(wl->vif[1]->ndev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900332 }
Leo Kim98b89842015-11-05 14:36:18 +0900333 } while (ret == WILC_TX_ERR_NO_BUF && !wl->close);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900334 }
335 return 0;
336}
337
Arnd Bergmann0e1af732015-11-16 15:04:54 +0100338int wilc_wlan_get_firmware(struct net_device *dev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900339{
Glen Leea4cac482015-12-21 14:18:36 +0900340 struct wilc_vif *vif;
Glen Lee65c8adc2015-10-29 12:18:49 +0900341 struct wilc *wilc;
Glen Lee14823bf2016-01-25 16:35:13 +0900342 int chip_id, ret = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900343 const struct firmware *wilc_firmware;
344 char *firmware;
345
Glen Leea4cac482015-12-21 14:18:36 +0900346 vif = netdev_priv(dev);
347 wilc = vif->wilc;
Glen Lee65c8adc2015-10-29 12:18:49 +0900348
Chris Park65c3f002016-02-04 18:15:54 +0900349 chip_id = wilc_get_chipid(wilc, false);
Glen Lee14823bf2016-01-25 16:35:13 +0900350
351 if (chip_id < 0x1003a0)
352 firmware = FIRMWARE_1002;
353 else
354 firmware = FIRMWARE_1003;
355
356 netdev_info(dev, "loading firmware %s\n", firmware);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900357
Leo Kim14086032016-02-04 18:15:36 +0900358 if (!(&vif->ndev->dev))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900359 goto _fail_;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900360
Arnd Bergmannb03314e2015-11-16 15:05:01 +0100361 if (request_firmware(&wilc_firmware, firmware, wilc->dev) != 0) {
Julia Lawallb9811892016-05-17 16:38:43 +0200362 netdev_err(dev, "%s - firmware not available\n", firmware);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900363 ret = -1;
364 goto _fail_;
365 }
Glen Lee65c8adc2015-10-29 12:18:49 +0900366 wilc->firmware = wilc_firmware;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900367
368_fail_:
369
370 return ret;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900371}
372
Glen Lee9bf3d722015-10-29 12:18:46 +0900373static int linux_wlan_start_firmware(struct net_device *dev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900374{
Glen Leea4cac482015-12-21 14:18:36 +0900375 struct wilc_vif *vif;
Glen Lee9bf3d722015-10-29 12:18:46 +0900376 struct wilc *wilc;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900377 int ret = 0;
Glen Lee9bf3d722015-10-29 12:18:46 +0900378
Glen Leea4cac482015-12-21 14:18:36 +0900379 vif = netdev_priv(dev);
380 wilc = vif->wilc;
Glen Lee9bf3d722015-10-29 12:18:46 +0900381
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100382 ret = wilc_wlan_start(wilc);
Leo Kim14086032016-02-04 18:15:36 +0900383 if (ret < 0)
Leo Kim0aeea1a2015-11-05 14:36:30 +0900384 return ret;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900385
Binoy Jayan04247e72016-06-15 11:00:37 +0530386 if (!wait_for_completion_timeout(&wilc->sync_event,
387 msecs_to_jiffies(5000)))
388 return -ETIME;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900389
Leo Kim0aeea1a2015-11-05 14:36:30 +0900390 return 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900391}
Leo Kima40b22c2015-11-05 14:36:32 +0900392
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100393static int wilc1000_firmware_download(struct net_device *dev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900394{
Glen Leea4cac482015-12-21 14:18:36 +0900395 struct wilc_vif *vif;
Glen Leeed760b62015-10-29 12:18:42 +0900396 struct wilc *wilc;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900397 int ret = 0;
398
Glen Leea4cac482015-12-21 14:18:36 +0900399 vif = netdev_priv(dev);
400 wilc = vif->wilc;
Glen Leeed760b62015-10-29 12:18:42 +0900401
402 if (!wilc->firmware) {
Leo Kim5ac24422016-02-04 18:15:37 +0900403 netdev_err(dev, "Firmware buffer is NULL\n");
Leo Kim14b18212015-11-05 14:36:31 +0900404 return -ENOBUFS;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900405 }
Leo Kim14086032016-02-04 18:15:36 +0900406
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100407 ret = wilc_wlan_firmware_download(wilc, wilc->firmware->data,
Glen Leeed760b62015-10-29 12:18:42 +0900408 wilc->firmware->size);
Kim, Leofc4b95d2015-07-28 17:47:37 +0900409 if (ret < 0)
Leo Kim14b18212015-11-05 14:36:31 +0900410 return ret;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900411
Glen Leeed760b62015-10-29 12:18:42 +0900412 release_firmware(wilc->firmware);
Glen Lee6f72ed72015-11-25 11:59:40 +0900413 wilc->firmware = NULL;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900414
Leo Kim5ac24422016-02-04 18:15:37 +0900415 netdev_dbg(dev, "Download Succeeded\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900416
Leo Kim14b18212015-11-05 14:36:31 +0900417 return 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900418}
419
Glen Lee00215dd2015-11-18 15:11:25 +0900420static int linux_wlan_init_test_config(struct net_device *dev,
Glen Leeb8f6ca02016-01-25 16:35:12 +0900421 struct wilc_vif *vif)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900422{
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900423 unsigned char c_val[64];
Glen Leeb8f6ca02016-01-25 16:35:12 +0900424 struct wilc *wilc = vif->wilc;
Chaehyun Lim27268872015-09-15 14:06:13 +0900425 struct wilc_priv *priv;
Leo Kim0fa66c72015-11-05 14:36:13 +0900426 struct host_if_drv *hif_drv;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900427
Leo Kim5ac24422016-02-04 18:15:37 +0900428 netdev_dbg(dev, "Start configuring Firmware\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900429 priv = wiphy_priv(dev->ieee80211_ptr->wiphy);
Leo Kim48b28df2016-02-04 18:15:32 +0900430 hif_drv = (struct host_if_drv *)priv->hif_drv;
Leo Kim5ac24422016-02-04 18:15:37 +0900431 netdev_dbg(dev, "Host = %p\n", hif_drv);
Chris Park65c3f002016-02-04 18:15:54 +0900432 wilc_get_chipid(wilc, false);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900433
Johnny Kime5d57e92015-08-20 16:32:53 +0900434 *(int *)c_val = 1;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900435
Glen Lee79df6a42016-02-04 18:15:31 +0900436 if (!wilc_wlan_cfg_set(vif, 1, WID_SET_DRV_HANDLER, c_val, 4, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900437 goto _fail_;
438
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900439 c_val[0] = 0;
Glen Lee79df6a42016-02-04 18:15:31 +0900440 if (!wilc_wlan_cfg_set(vif, 0, WID_PC_TEST_MODE, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900441 goto _fail_;
442
443 c_val[0] = INFRASTRUCTURE;
Glen Lee79df6a42016-02-04 18:15:31 +0900444 if (!wilc_wlan_cfg_set(vif, 0, WID_BSS_TYPE, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900445 goto _fail_;
446
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900447 c_val[0] = RATE_AUTO;
Glen Lee79df6a42016-02-04 18:15:31 +0900448 if (!wilc_wlan_cfg_set(vif, 0, WID_CURRENT_TX_RATE, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900449 goto _fail_;
450
451 c_val[0] = G_MIXED_11B_2_MODE;
Glen Lee79df6a42016-02-04 18:15:31 +0900452 if (!wilc_wlan_cfg_set(vif, 0, WID_11G_OPERATING_MODE, c_val, 1, 0,
Glen Lee89758e12015-11-18 15:11:34 +0900453 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900454 goto _fail_;
455
456 c_val[0] = 1;
Glen Lee79df6a42016-02-04 18:15:31 +0900457 if (!wilc_wlan_cfg_set(vif, 0, WID_CURRENT_CHANNEL, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900458 goto _fail_;
459
460 c_val[0] = G_SHORT_PREAMBLE;
Glen Lee79df6a42016-02-04 18:15:31 +0900461 if (!wilc_wlan_cfg_set(vif, 0, WID_PREAMBLE, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900462 goto _fail_;
463
464 c_val[0] = AUTO_PROT;
Glen Lee79df6a42016-02-04 18:15:31 +0900465 if (!wilc_wlan_cfg_set(vif, 0, WID_11N_PROT_MECH, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900466 goto _fail_;
467
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900468 c_val[0] = ACTIVE_SCAN;
Glen Lee79df6a42016-02-04 18:15:31 +0900469 if (!wilc_wlan_cfg_set(vif, 0, WID_SCAN_TYPE, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900470 goto _fail_;
471
472 c_val[0] = SITE_SURVEY_OFF;
Glen Lee79df6a42016-02-04 18:15:31 +0900473 if (!wilc_wlan_cfg_set(vif, 0, WID_SITE_SURVEY, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900474 goto _fail_;
475
Leo Kim98b89842015-11-05 14:36:18 +0900476 *((int *)c_val) = 0xffff;
Glen Lee79df6a42016-02-04 18:15:31 +0900477 if (!wilc_wlan_cfg_set(vif, 0, WID_RTS_THRESHOLD, c_val, 2, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900478 goto _fail_;
479
480 *((int *)c_val) = 2346;
Glen Lee79df6a42016-02-04 18:15:31 +0900481 if (!wilc_wlan_cfg_set(vif, 0, WID_FRAG_THRESHOLD, c_val, 2, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900482 goto _fail_;
483
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900484 c_val[0] = 0;
Glen Lee79df6a42016-02-04 18:15:31 +0900485 if (!wilc_wlan_cfg_set(vif, 0, WID_BCAST_SSID, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900486 goto _fail_;
487
488 c_val[0] = 1;
Glen Lee79df6a42016-02-04 18:15:31 +0900489 if (!wilc_wlan_cfg_set(vif, 0, WID_QOS_ENABLE, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900490 goto _fail_;
491
492 c_val[0] = NO_POWERSAVE;
Glen Lee79df6a42016-02-04 18:15:31 +0900493 if (!wilc_wlan_cfg_set(vif, 0, WID_POWER_MANAGEMENT, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900494 goto _fail_;
495
Arnd Bergmannb4d04c12015-11-16 15:04:56 +0100496 c_val[0] = NO_SECURITY; /* NO_ENCRYPT, 0x79 */
Glen Lee79df6a42016-02-04 18:15:31 +0900497 if (!wilc_wlan_cfg_set(vif, 0, WID_11I_MODE, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900498 goto _fail_;
499
500 c_val[0] = OPEN_SYSTEM;
Glen Lee79df6a42016-02-04 18:15:31 +0900501 if (!wilc_wlan_cfg_set(vif, 0, WID_AUTH_TYPE, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900502 goto _fail_;
503
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900504 strcpy(c_val, "123456790abcdef1234567890");
Glen Lee79df6a42016-02-04 18:15:31 +0900505 if (!wilc_wlan_cfg_set(vif, 0, WID_WEP_KEY_VALUE, c_val,
Glen Lee89758e12015-11-18 15:11:34 +0900506 (strlen(c_val) + 1), 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900507 goto _fail_;
508
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900509 strcpy(c_val, "12345678");
Glen Lee79df6a42016-02-04 18:15:31 +0900510 if (!wilc_wlan_cfg_set(vif, 0, WID_11I_PSK, c_val, (strlen(c_val)), 0,
Glen Lee89758e12015-11-18 15:11:34 +0900511 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900512 goto _fail_;
513
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900514 strcpy(c_val, "password");
Glen Lee79df6a42016-02-04 18:15:31 +0900515 if (!wilc_wlan_cfg_set(vif, 0, WID_1X_KEY, c_val, (strlen(c_val) + 1),
Glen Lee89758e12015-11-18 15:11:34 +0900516 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900517 goto _fail_;
518
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900519 c_val[0] = 192;
520 c_val[1] = 168;
521 c_val[2] = 1;
522 c_val[3] = 112;
Glen Lee79df6a42016-02-04 18:15:31 +0900523 if (!wilc_wlan_cfg_set(vif, 0, WID_1X_SERV_ADDR, c_val, 4, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900524 goto _fail_;
525
526 c_val[0] = 3;
Glen Lee79df6a42016-02-04 18:15:31 +0900527 if (!wilc_wlan_cfg_set(vif, 0, WID_LISTEN_INTERVAL, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900528 goto _fail_;
529
530 c_val[0] = 3;
Glen Lee79df6a42016-02-04 18:15:31 +0900531 if (!wilc_wlan_cfg_set(vif, 0, WID_DTIM_PERIOD, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900532 goto _fail_;
533
534 c_val[0] = NORMAL_ACK;
Glen Lee79df6a42016-02-04 18:15:31 +0900535 if (!wilc_wlan_cfg_set(vif, 0, WID_ACK_POLICY, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900536 goto _fail_;
537
538 c_val[0] = 0;
Glen Lee79df6a42016-02-04 18:15:31 +0900539 if (!wilc_wlan_cfg_set(vif, 0, WID_USER_CONTROL_ON_TX_POWER, c_val, 1,
Glen Lee89758e12015-11-18 15:11:34 +0900540 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900541 goto _fail_;
542
543 c_val[0] = 48;
Glen Lee79df6a42016-02-04 18:15:31 +0900544 if (!wilc_wlan_cfg_set(vif, 0, WID_TX_POWER_LEVEL_11A, c_val, 1, 0,
Glen Lee89758e12015-11-18 15:11:34 +0900545 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900546 goto _fail_;
547
548 c_val[0] = 28;
Glen Lee79df6a42016-02-04 18:15:31 +0900549 if (!wilc_wlan_cfg_set(vif, 0, WID_TX_POWER_LEVEL_11B, c_val, 1, 0,
Glen Lee89758e12015-11-18 15:11:34 +0900550 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900551 goto _fail_;
552
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900553 *((int *)c_val) = 100;
Glen Lee79df6a42016-02-04 18:15:31 +0900554 if (!wilc_wlan_cfg_set(vif, 0, WID_BEACON_INTERVAL, c_val, 2, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900555 goto _fail_;
556
557 c_val[0] = REKEY_DISABLE;
Glen Lee79df6a42016-02-04 18:15:31 +0900558 if (!wilc_wlan_cfg_set(vif, 0, WID_REKEY_POLICY, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900559 goto _fail_;
560
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900561 *((int *)c_val) = 84600;
Glen Lee79df6a42016-02-04 18:15:31 +0900562 if (!wilc_wlan_cfg_set(vif, 0, WID_REKEY_PERIOD, c_val, 4, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900563 goto _fail_;
564
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900565 *((int *)c_val) = 500;
Glen Lee79df6a42016-02-04 18:15:31 +0900566 if (!wilc_wlan_cfg_set(vif, 0, WID_REKEY_PACKET_COUNT, c_val, 4, 0,
Glen Lee89758e12015-11-18 15:11:34 +0900567 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900568 goto _fail_;
569
570 c_val[0] = 1;
Glen Lee79df6a42016-02-04 18:15:31 +0900571 if (!wilc_wlan_cfg_set(vif, 0, WID_SHORT_SLOT_ALLOWED, c_val, 1, 0,
Glen Lee89758e12015-11-18 15:11:34 +0900572 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900573 goto _fail_;
574
575 c_val[0] = G_SELF_CTS_PROT;
Glen Lee79df6a42016-02-04 18:15:31 +0900576 if (!wilc_wlan_cfg_set(vif, 0, WID_11N_ERP_PROT_TYPE, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900577 goto _fail_;
578
Leo Kim98b89842015-11-05 14:36:18 +0900579 c_val[0] = 1;
Glen Lee79df6a42016-02-04 18:15:31 +0900580 if (!wilc_wlan_cfg_set(vif, 0, WID_11N_ENABLE, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900581 goto _fail_;
582
583 c_val[0] = HT_MIXED_MODE;
Glen Lee79df6a42016-02-04 18:15:31 +0900584 if (!wilc_wlan_cfg_set(vif, 0, WID_11N_OPERATING_MODE, c_val, 1, 0,
Glen Lee89758e12015-11-18 15:11:34 +0900585 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900586 goto _fail_;
587
Leo Kim98b89842015-11-05 14:36:18 +0900588 c_val[0] = 1;
Glen Lee79df6a42016-02-04 18:15:31 +0900589 if (!wilc_wlan_cfg_set(vif, 0, WID_11N_TXOP_PROT_DISABLE, c_val, 1, 0,
Glen Lee89758e12015-11-18 15:11:34 +0900590 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900591 goto _fail_;
592
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900593 c_val[0] = DETECT_PROTECT_REPORT;
Glen Lee79df6a42016-02-04 18:15:31 +0900594 if (!wilc_wlan_cfg_set(vif, 0, WID_11N_OBSS_NONHT_DETECTION, c_val, 1,
Glen Lee89758e12015-11-18 15:11:34 +0900595 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900596 goto _fail_;
597
598 c_val[0] = RTS_CTS_NONHT_PROT;
Glen Lee79df6a42016-02-04 18:15:31 +0900599 if (!wilc_wlan_cfg_set(vif, 0, WID_11N_HT_PROT_TYPE, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900600 goto _fail_;
601
602 c_val[0] = 0;
Glen Lee79df6a42016-02-04 18:15:31 +0900603 if (!wilc_wlan_cfg_set(vif, 0, WID_11N_RIFS_PROT_ENABLE, c_val, 1, 0,
Glen Lee89758e12015-11-18 15:11:34 +0900604 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900605 goto _fail_;
606
607 c_val[0] = MIMO_MODE;
Glen Lee79df6a42016-02-04 18:15:31 +0900608 if (!wilc_wlan_cfg_set(vif, 0, WID_11N_SMPS_MODE, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900609 goto _fail_;
610
611 c_val[0] = 7;
Glen Lee79df6a42016-02-04 18:15:31 +0900612 if (!wilc_wlan_cfg_set(vif, 0, WID_11N_CURRENT_TX_MCS, c_val, 1, 0,
Glen Lee89758e12015-11-18 15:11:34 +0900613 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900614 goto _fail_;
615
Leo Kim98b89842015-11-05 14:36:18 +0900616 c_val[0] = 1;
Glen Lee79df6a42016-02-04 18:15:31 +0900617 if (!wilc_wlan_cfg_set(vif, 0, WID_11N_IMMEDIATE_BA_ENABLED, c_val, 1,
Glen Lee89758e12015-11-18 15:11:34 +0900618 1, 1))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900619 goto _fail_;
620
621 return 0;
622
623_fail_:
624 return -1;
625}
626
Glen Lee53dc0cf2015-10-20 17:13:57 +0900627void wilc1000_wlan_deinit(struct net_device *dev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900628{
Glen Leea4cac482015-12-21 14:18:36 +0900629 struct wilc_vif *vif;
Glen Lee53dc0cf2015-10-20 17:13:57 +0900630 struct wilc *wl;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900631
Glen Leea4cac482015-12-21 14:18:36 +0900632 vif = netdev_priv(dev);
633 wl = vif->wilc;
Glen Lee53dc0cf2015-10-20 17:13:57 +0900634
635 if (!wl) {
636 netdev_err(dev, "wl is NULL\n");
637 return;
638 }
639
640 if (wl->initialized) {
641 netdev_info(dev, "Deinitializing wilc1000...\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900642
Arnd Bergmann5547c1f2015-11-16 15:05:06 +0100643 if (!wl->dev_irq_num &&
Glen Leeaf9ae092015-12-21 14:18:09 +0900644 wl->hif_func->disable_interrupt) {
Arnd Bergmannc4d139c2015-11-16 15:05:04 +0100645 mutex_lock(&wl->hif_cs);
Glen Leeaf9ae092015-12-21 14:18:09 +0900646 wl->hif_func->disable_interrupt(wl);
Arnd Bergmannc4d139c2015-11-16 15:05:04 +0100647 mutex_unlock(&wl->hif_cs);
648 }
Leo Kim3a147c02015-11-05 14:36:10 +0900649 if (&wl->txq_event)
Binoy Jayan23535c12016-07-21 13:26:56 +0530650 complete(&wl->txq_event);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900651
Glen Lee32dd51b2015-10-27 18:27:52 +0900652 wlan_deinitialize_threads(dev);
Glen Leeec5cc752015-10-27 18:27:39 +0900653 deinit_irq(dev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900654
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100655 wilc_wlan_stop(wl);
Glen Lee2de7cbe2015-10-27 18:27:54 +0900656 wilc_wlan_cleanup(dev);
Glen Lee7c67c052015-10-27 18:27:50 +0900657 wlan_deinit_locks(dev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900658
Glen Lee53dc0cf2015-10-20 17:13:57 +0900659 wl->initialized = false;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900660
Leo Kim5ac24422016-02-04 18:15:37 +0900661 netdev_dbg(dev, "wilc1000 deinitialization Done\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900662 } else {
Leo Kim5ac24422016-02-04 18:15:37 +0900663 netdev_dbg(dev, "wilc1000 is not initialized\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900664 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900665}
666
Arnd Bergmann1608c402015-11-16 15:04:53 +0100667static int wlan_init_locks(struct net_device *dev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900668{
Glen Leea4cac482015-12-21 14:18:36 +0900669 struct wilc_vif *vif;
Glen Lee38afb392015-10-20 17:13:53 +0900670 struct wilc *wl;
671
Glen Leea4cac482015-12-21 14:18:36 +0900672 vif = netdev_priv(dev);
673 wl = vif->wilc;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900674
Glen Lee38afb392015-10-20 17:13:53 +0900675 mutex_init(&wl->hif_cs);
676 mutex_init(&wl->rxq_cs);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900677
Glen Lee38afb392015-10-20 17:13:53 +0900678 spin_lock_init(&wl->txq_spinlock);
Binoy Jayan334bed02016-06-15 11:00:35 +0530679 mutex_init(&wl->txq_add_to_head_cs);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900680
Binoy Jayanb27a6d52016-06-15 11:00:34 +0530681 init_completion(&wl->txq_event);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900682
Binoy Jayanfa659692016-06-15 11:00:36 +0530683 init_completion(&wl->cfg_event);
Binoy Jayan04247e72016-06-15 11:00:37 +0530684 init_completion(&wl->sync_event);
Leo Kim11a54b32016-04-01 17:44:15 +0900685 init_completion(&wl->txq_thread_started);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900686
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900687 return 0;
688}
689
Glen Lee7c67c052015-10-27 18:27:50 +0900690static int wlan_deinit_locks(struct net_device *dev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900691{
Glen Leea4cac482015-12-21 14:18:36 +0900692 struct wilc_vif *vif;
Glen Lee7c67c052015-10-27 18:27:50 +0900693 struct wilc *wilc;
694
Glen Leea4cac482015-12-21 14:18:36 +0900695 vif = netdev_priv(dev);
696 wilc = vif->wilc;
Glen Lee7c67c052015-10-27 18:27:50 +0900697
Leo Kim3a147c02015-11-05 14:36:10 +0900698 if (&wilc->hif_cs)
Glen Lee7c67c052015-10-27 18:27:50 +0900699 mutex_destroy(&wilc->hif_cs);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900700
Leo Kim3a147c02015-11-05 14:36:10 +0900701 if (&wilc->rxq_cs)
Glen Lee7c67c052015-10-27 18:27:50 +0900702 mutex_destroy(&wilc->rxq_cs);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900703
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900704 return 0;
705}
Leo Kima40b22c2015-11-05 14:36:32 +0900706
Arnd Bergmann1608c402015-11-16 15:04:53 +0100707static int wlan_initialize_threads(struct net_device *dev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900708{
Glen Leea4cac482015-12-21 14:18:36 +0900709 struct wilc_vif *vif;
Glen Lee75a94662015-10-27 18:27:45 +0900710 struct wilc *wilc;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900711
Glen Leea4cac482015-12-21 14:18:36 +0900712 vif = netdev_priv(dev);
713 wilc = vif->wilc;
Glen Lee75a94662015-10-27 18:27:45 +0900714
Glen Lee88687582015-10-27 18:27:46 +0900715 wilc->txq_thread = kthread_run(linux_wlan_txq_task, (void *)dev,
Glen Lee75a94662015-10-27 18:27:45 +0900716 "K_TXQ_TASK");
Wei Yongjunb3e69162016-06-17 17:34:17 +0000717 if (IS_ERR(wilc->txq_thread)) {
Leo Kim5ac24422016-02-04 18:15:37 +0900718 netdev_err(dev, "couldn't create TXQ thread\n");
Leo Kim6bc72c52015-11-05 14:36:33 +0900719 wilc->close = 0;
Wei Yongjunb3e69162016-06-17 17:34:17 +0000720 return PTR_ERR(wilc->txq_thread);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900721 }
Leo Kim11a54b32016-04-01 17:44:15 +0900722 wait_for_completion(&wilc->txq_thread_started);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900723
724 return 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900725}
726
Glen Lee32dd51b2015-10-27 18:27:52 +0900727static void wlan_deinitialize_threads(struct net_device *dev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900728{
Glen Leea4cac482015-12-21 14:18:36 +0900729 struct wilc_vif *vif;
Glen Lee32dd51b2015-10-27 18:27:52 +0900730 struct wilc *wl;
Leo Kimfa8b23c2016-02-04 18:15:33 +0900731
Glen Leea4cac482015-12-21 14:18:36 +0900732 vif = netdev_priv(dev);
733 wl = vif->wilc;
Glen Lee32dd51b2015-10-27 18:27:52 +0900734
735 wl->close = 1;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900736
Leo Kim3a147c02015-11-05 14:36:10 +0900737 if (&wl->txq_event)
Binoy Jayanb27a6d52016-06-15 11:00:34 +0530738 complete(&wl->txq_event);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900739
Leo Kim3a147c02015-11-05 14:36:10 +0900740 if (wl->txq_thread) {
Glen Lee32dd51b2015-10-27 18:27:52 +0900741 kthread_stop(wl->txq_thread);
742 wl->txq_thread = NULL;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900743 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900744}
745
Glen Leea4cac482015-12-21 14:18:36 +0900746int wilc1000_wlan_init(struct net_device *dev, struct wilc_vif *vif)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900747{
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900748 int ret = 0;
Glen Leea4cac482015-12-21 14:18:36 +0900749 struct wilc *wl = vif->wilc;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900750
Glen Lee0fa683b2015-10-20 17:13:52 +0900751 if (!wl->initialized) {
752 wl->mac_status = WILC_MAC_STATUS_INIT;
753 wl->close = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900754
Glen Lee38afb392015-10-20 17:13:53 +0900755 wlan_init_locks(dev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900756
Arnd Bergmann4bd7baf2015-11-16 15:04:59 +0100757 ret = wilc_wlan_init(dev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900758 if (ret < 0) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900759 ret = -EIO;
760 goto _fail_locks_;
761 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900762
Arnd Bergmannc4d139c2015-11-16 15:05:04 +0100763 if (wl->gpio >= 0 && init_irq(dev)) {
Tony Chob46d6882015-10-20 14:26:54 +0900764 ret = -EIO;
765 goto _fail_locks_;
766 }
Tony Chob46d6882015-10-20 14:26:54 +0900767
Glen Lee75a94662015-10-27 18:27:45 +0900768 ret = wlan_initialize_threads(dev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900769 if (ret < 0) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900770 ret = -EIO;
771 goto _fail_wilc_wlan_;
772 }
773
Arnd Bergmann5547c1f2015-11-16 15:05:06 +0100774 if (!wl->dev_irq_num &&
Glen Leeaf9ae092015-12-21 14:18:09 +0900775 wl->hif_func->enable_interrupt &&
776 wl->hif_func->enable_interrupt(wl)) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900777 ret = -EIO;
778 goto _fail_irq_init_;
779 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900780
Arnd Bergmann0e1af732015-11-16 15:04:54 +0100781 if (wilc_wlan_get_firmware(dev)) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900782 ret = -EIO;
783 goto _fail_irq_enable_;
784 }
785
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100786 ret = wilc1000_firmware_download(dev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900787 if (ret < 0) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900788 ret = -EIO;
789 goto _fail_irq_enable_;
790 }
791
Glen Lee9bf3d722015-10-29 12:18:46 +0900792 ret = linux_wlan_start_firmware(dev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900793 if (ret < 0) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900794 ret = -EIO;
795 goto _fail_irq_enable_;
796 }
797
Glen Lee79df6a42016-02-04 18:15:31 +0900798 if (wilc_wlan_cfg_get(vif, 1, WID_FIRMWARE_VERSION, 1, 0)) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900799 int size;
Leo Kim5ac24422016-02-04 18:15:37 +0900800 char firmware_ver[20];
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900801
Leo Kim5ac24422016-02-04 18:15:37 +0900802 size = wilc_wlan_cfg_get_val(WID_FIRMWARE_VERSION,
803 firmware_ver,
804 sizeof(firmware_ver));
805 firmware_ver[size] = '\0';
806 netdev_dbg(dev, "Firmware Ver = %s\n", firmware_ver);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900807 }
Glen Leeb8f6ca02016-01-25 16:35:12 +0900808 ret = linux_wlan_init_test_config(dev, vif);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900809
810 if (ret < 0) {
Leo Kim5ac24422016-02-04 18:15:37 +0900811 netdev_err(dev, "Failed to configure firmware\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900812 ret = -EIO;
813 goto _fail_fw_start_;
814 }
815
Glen Lee0fa683b2015-10-20 17:13:52 +0900816 wl->initialized = true;
Leo Kim98b89842015-11-05 14:36:18 +0900817 return 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900818
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900819_fail_fw_start_:
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100820 wilc_wlan_stop(wl);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900821
822_fail_irq_enable_:
Arnd Bergmann5547c1f2015-11-16 15:05:06 +0100823 if (!wl->dev_irq_num &&
Glen Leeaf9ae092015-12-21 14:18:09 +0900824 wl->hif_func->disable_interrupt)
825 wl->hif_func->disable_interrupt(wl);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900826_fail_irq_init_:
Arnd Bergmannc4d139c2015-11-16 15:05:04 +0100827 if (wl->dev_irq_num)
828 deinit_irq(dev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900829
Glen Lee32dd51b2015-10-27 18:27:52 +0900830 wlan_deinitialize_threads(dev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900831_fail_wilc_wlan_:
Glen Lee2de7cbe2015-10-27 18:27:54 +0900832 wilc_wlan_cleanup(dev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900833_fail_locks_:
Glen Lee7c67c052015-10-27 18:27:50 +0900834 wlan_deinit_locks(dev);
Leo Kim5ac24422016-02-04 18:15:37 +0900835 netdev_err(dev, "WLAN Iinitialization FAILED\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900836 } else {
Leo Kim5ac24422016-02-04 18:15:37 +0900837 netdev_dbg(dev, "wilc1000 already initialized\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900838 }
839 return ret;
840}
841
Arnd Bergmann1608c402015-11-16 15:04:53 +0100842static int mac_init_fn(struct net_device *ndev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900843{
Leo Kim98b89842015-11-05 14:36:18 +0900844 netif_start_queue(ndev);
845 netif_stop_queue(ndev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900846
847 return 0;
848}
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900849
Arnd Bergmann0e1af732015-11-16 15:04:54 +0100850int wilc_mac_open(struct net_device *ndev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900851{
Glen Leea4cac482015-12-21 14:18:36 +0900852 struct wilc_vif *vif;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900853
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900854 unsigned char mac_add[ETH_ALEN] = {0};
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900855 int ret = 0;
856 int i = 0;
Glen Leef3c13662015-10-20 17:13:54 +0900857 struct wilc *wl;
858
Glen Leea4cac482015-12-21 14:18:36 +0900859 vif = netdev_priv(ndev);
860 wl = vif->wilc;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900861
Leo Kim40095ad2016-01-27 11:50:27 +0900862 if (!wl || !wl->dev) {
Leo Kim90fd4cc2016-03-15 18:48:12 +0900863 netdev_err(ndev, "device not ready\n");
Chandra S Gorentla7d056522015-09-15 18:09:51 +0530864 return -ENODEV;
865 }
Arnd Bergmannb03314e2015-11-16 15:05:01 +0100866
Leo Kim5ac24422016-02-04 18:15:37 +0900867 netdev_dbg(ndev, "MAC OPEN[%p]\n", ndev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900868
Chaehyun Limdd4b6a82015-09-20 15:51:25 +0900869 ret = wilc_init_host_int(ndev);
Leo Kim14086032016-02-04 18:15:36 +0900870 if (ret < 0)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900871 return ret;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900872
Glen Leea4cac482015-12-21 14:18:36 +0900873 ret = wilc1000_wlan_init(ndev, vif);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900874 if (ret < 0) {
Chaehyun Lima9a16822015-09-20 15:51:24 +0900875 wilc_deinit_host_int(ndev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900876 return ret;
877 }
878
Glen Leef3c13662015-10-20 17:13:54 +0900879 for (i = 0; i < wl->vif_num; i++) {
Glen Lee1f435d22015-12-21 14:18:37 +0900880 if (ndev == wl->vif[i]->ndev) {
Glen Leeb3306862016-02-04 18:15:18 +0900881 if (vif->iftype == AP_MODE) {
882 wilc_set_wfi_drv_handler(vif,
883 wilc_get_vif_idx(vif),
884 0);
Leo Kimba750472016-03-15 18:48:11 +0900885 } else if (!wilc_wlan_get_num_conn_ifcs(wl)) {
Glen Leeb3306862016-02-04 18:15:18 +0900886 wilc_set_wfi_drv_handler(vif,
887 wilc_get_vif_idx(vif),
Leo Kimba750472016-03-15 18:48:11 +0900888 wl->open_ifcs);
Glen Leeb3306862016-02-04 18:15:18 +0900889 } else {
Leo Kimba750472016-03-15 18:48:11 +0900890 if (memcmp(wl->vif[i ^ 1]->bssid,
891 wl->vif[i ^ 1]->src_addr, 6))
Glen Leeb3306862016-02-04 18:15:18 +0900892 wilc_set_wfi_drv_handler(vif,
893 wilc_get_vif_idx(vif),
894 0);
895 else
896 wilc_set_wfi_drv_handler(vif,
897 wilc_get_vif_idx(vif),
898 1);
899 }
Glen Leee32737e2016-01-25 16:35:14 +0900900 wilc_set_operation_mode(vif, vif->iftype);
Glen Lee32cee992016-02-04 18:15:29 +0900901
902 wilc_get_mac_address(vif, mac_add);
903 netdev_dbg(ndev, "Mac address: %pM\n", mac_add);
904 memcpy(wl->vif[i]->src_addr, mac_add, ETH_ALEN);
905
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900906 break;
907 }
908 }
909
Glen Lee1f435d22015-12-21 14:18:37 +0900910 memcpy(ndev->dev_addr, wl->vif[i]->src_addr, ETH_ALEN);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900911
912 if (!is_valid_ether_addr(ndev->dev_addr)) {
Leo Kim5ac24422016-02-04 18:15:37 +0900913 netdev_err(ndev, "Wrong MAC address\n");
Leo Kim339d2442015-11-05 14:36:34 +0900914 wilc_deinit_host_int(ndev);
915 wilc1000_wlan_deinit(ndev);
916 return -EINVAL;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900917 }
918
Glen Lee1006b5c2015-12-21 14:18:38 +0900919 wilc_mgmt_frame_register(vif->ndev->ieee80211_ptr->wiphy,
920 vif->ndev->ieee80211_ptr,
Leo Kim340a84f2016-03-25 21:16:50 +0900921 vif->frame_reg[0].type,
Leo Kim89febb22016-03-25 21:16:49 +0900922 vif->frame_reg[0].reg);
Glen Lee1006b5c2015-12-21 14:18:38 +0900923 wilc_mgmt_frame_register(vif->ndev->ieee80211_ptr->wiphy,
924 vif->ndev->ieee80211_ptr,
Leo Kim340a84f2016-03-25 21:16:50 +0900925 vif->frame_reg[1].type,
Leo Kim89febb22016-03-25 21:16:49 +0900926 vif->frame_reg[1].reg);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900927 netif_wake_queue(ndev);
Glen Leef3c13662015-10-20 17:13:54 +0900928 wl->open_ifcs++;
Glen Leea4cac482015-12-21 14:18:36 +0900929 vif->mac_opened = 1;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900930 return 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900931}
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900932
Arnd Bergmann1608c402015-11-16 15:04:53 +0100933static struct net_device_stats *mac_stats(struct net_device *dev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900934{
Leo Kim40095ad2016-01-27 11:50:27 +0900935 struct wilc_vif *vif = netdev_priv(dev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900936
Glen Leea4cac482015-12-21 14:18:36 +0900937 return &vif->netstats;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900938}
939
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900940static void wilc_set_multicast_list(struct net_device *dev)
941{
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900942 struct netdev_hw_addr *ha;
Glen Leecf601062015-12-21 14:18:39 +0900943 struct wilc_vif *vif;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900944 int i = 0;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900945
Glen Leecf601062015-12-21 14:18:39 +0900946 vif = netdev_priv(dev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900947
Leo Kim14086032016-02-04 18:15:36 +0900948 if (dev->flags & IFF_PROMISC)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900949 return;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900950
Leo Kim582f8a22015-11-05 14:36:21 +0900951 if ((dev->flags & IFF_ALLMULTI) ||
952 (dev->mc.count) > WILC_MULTICAST_TABLE_SIZE) {
Glen Leefbf53792015-12-21 14:18:40 +0900953 wilc_setup_multicast_filter(vif, false, 0);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900954 return;
955 }
956
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900957 if ((dev->mc.count) == 0) {
Glen Leefbf53792015-12-21 14:18:40 +0900958 wilc_setup_multicast_filter(vif, true, 0);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900959 return;
960 }
961
Leo Kimc8537e62015-11-06 11:12:24 +0900962 netdev_for_each_mc_addr(ha, dev) {
Arnd Bergmann0e1af732015-11-16 15:04:54 +0100963 memcpy(wilc_multicast_mac_addr_list[i], ha->addr, ETH_ALEN);
Leo Kim5ac24422016-02-04 18:15:37 +0900964 netdev_dbg(dev, "Entry[%d]: %x:%x:%x:%x:%x:%x\n", i,
965 wilc_multicast_mac_addr_list[i][0],
966 wilc_multicast_mac_addr_list[i][1],
967 wilc_multicast_mac_addr_list[i][2],
968 wilc_multicast_mac_addr_list[i][3],
969 wilc_multicast_mac_addr_list[i][4],
970 wilc_multicast_mac_addr_list[i][5]);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900971 i++;
972 }
973
Glen Leefbf53792015-12-21 14:18:40 +0900974 wilc_setup_multicast_filter(vif, true, (dev->mc.count));
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900975}
976
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900977static void linux_wlan_tx_complete(void *priv, int status)
978{
Alison Schofieldd5c89442016-02-12 22:53:13 -0800979 struct tx_complete_data *pv_data = priv;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900980
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900981 dev_kfree_skb(pv_data->skb);
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -0700982 kfree(pv_data);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900983}
984
Arnd Bergmann0e1af732015-11-16 15:04:54 +0100985int wilc_mac_xmit(struct sk_buff *skb, struct net_device *ndev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900986{
Glen Leea4cac482015-12-21 14:18:36 +0900987 struct wilc_vif *vif;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900988 struct tx_complete_data *tx_data = NULL;
Leo Kim44ec3b72015-11-05 14:36:38 +0900989 int queue_count;
Leo Kimfd8f0362015-11-05 14:36:39 +0900990 char *udp_buf;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900991 struct iphdr *ih;
992 struct ethhdr *eth_h;
Glen Leeb7495be2015-10-27 18:28:01 +0900993 struct wilc *wilc;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900994
Glen Leea4cac482015-12-21 14:18:36 +0900995 vif = netdev_priv(ndev);
996 wilc = vif->wilc;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900997
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900998 if (skb->dev != ndev) {
Leo Kim5ac24422016-02-04 18:15:37 +0900999 netdev_err(ndev, "Packet not destined to this device\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001000 return 0;
1001 }
1002
Leo Kimb38e9032015-11-06 11:12:23 +09001003 tx_data = kmalloc(sizeof(*tx_data), GFP_ATOMIC);
Leo Kim3a147c02015-11-05 14:36:10 +09001004 if (!tx_data) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001005 dev_kfree_skb(skb);
1006 netif_wake_queue(ndev);
1007 return 0;
1008 }
1009
1010 tx_data->buff = skb->data;
1011 tx_data->size = skb->len;
1012 tx_data->skb = skb;
1013
1014 eth_h = (struct ethhdr *)(skb->data);
Kim, Leofc4b95d2015-07-28 17:47:37 +09001015 if (eth_h->h_proto == 0x8e88)
Leo Kim5ac24422016-02-04 18:15:37 +09001016 netdev_dbg(ndev, "EAPOL transmitted\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001017
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001018 ih = (struct iphdr *)(skb->data + sizeof(struct ethhdr));
1019
Leo Kimfd8f0362015-11-05 14:36:39 +09001020 udp_buf = (char *)ih + sizeof(struct iphdr);
1021 if ((udp_buf[1] == 68 && udp_buf[3] == 67) ||
1022 (udp_buf[1] == 67 && udp_buf[3] == 68))
Leo Kim5ac24422016-02-04 18:15:37 +09001023 netdev_dbg(ndev, "DHCP Message transmitted, type:%x %x %x\n",
1024 udp_buf[248], udp_buf[249], udp_buf[250]);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001025
Glen Leea4cac482015-12-21 14:18:36 +09001026 vif->netstats.tx_packets++;
1027 vif->netstats.tx_bytes += tx_data->size;
Leo Kim67501402016-02-04 18:15:39 +09001028 tx_data->bssid = wilc->vif[vif->idx]->bssid;
Leo Kim44ec3b72015-11-05 14:36:38 +09001029 queue_count = wilc_wlan_txq_add_net_pkt(ndev, (void *)tx_data,
1030 tx_data->buff, tx_data->size,
1031 linux_wlan_tx_complete);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001032
Leo Kim44ec3b72015-11-05 14:36:38 +09001033 if (queue_count > FLOW_CONTROL_UPPER_THRESHOLD) {
Glen Lee1f435d22015-12-21 14:18:37 +09001034 netif_stop_queue(wilc->vif[0]->ndev);
1035 netif_stop_queue(wilc->vif[1]->ndev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001036 }
1037
1038 return 0;
1039}
1040
Arnd Bergmann0e1af732015-11-16 15:04:54 +01001041int wilc_mac_close(struct net_device *ndev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001042{
Chaehyun Lim27268872015-09-15 14:06:13 +09001043 struct wilc_priv *priv;
Glen Leea4cac482015-12-21 14:18:36 +09001044 struct wilc_vif *vif;
Leo Kim2db2c8a2015-11-05 14:36:15 +09001045 struct host_if_drv *hif_drv;
Glen Leeca64ad62015-10-20 17:13:55 +09001046 struct wilc *wl;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001047
Glen Leea4cac482015-12-21 14:18:36 +09001048 vif = netdev_priv(ndev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001049
Glen Lee1006b5c2015-12-21 14:18:38 +09001050 if (!vif || !vif->ndev || !vif->ndev->ieee80211_ptr ||
Leo Kim14086032016-02-04 18:15:36 +09001051 !vif->ndev->ieee80211_ptr->wiphy)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001052 return 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001053
Glen Lee1006b5c2015-12-21 14:18:38 +09001054 priv = wiphy_priv(vif->ndev->ieee80211_ptr->wiphy);
Glen Leea4cac482015-12-21 14:18:36 +09001055 wl = vif->wilc;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001056
Leo Kim14086032016-02-04 18:15:36 +09001057 if (!priv)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001058 return 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001059
Leo Kim48b28df2016-02-04 18:15:32 +09001060 hif_drv = (struct host_if_drv *)priv->hif_drv;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001061
Leo Kim5ac24422016-02-04 18:15:37 +09001062 netdev_dbg(ndev, "Mac close\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001063
Leo Kim14086032016-02-04 18:15:36 +09001064 if (!wl)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001065 return 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001066
Leo Kim14086032016-02-04 18:15:36 +09001067 if (!hif_drv)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001068 return 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001069
Leo Kim14086032016-02-04 18:15:36 +09001070 if ((wl->open_ifcs) > 0)
Glen Leeca64ad62015-10-20 17:13:55 +09001071 wl->open_ifcs--;
Leo Kim14086032016-02-04 18:15:36 +09001072 else
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001073 return 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001074
Glen Lee1006b5c2015-12-21 14:18:38 +09001075 if (vif->ndev) {
1076 netif_stop_queue(vif->ndev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001077
Glen Lee1006b5c2015-12-21 14:18:38 +09001078 wilc_deinit_host_int(vif->ndev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001079 }
1080
Glen Leeca64ad62015-10-20 17:13:55 +09001081 if (wl->open_ifcs == 0) {
Leo Kim5ac24422016-02-04 18:15:37 +09001082 netdev_dbg(ndev, "Deinitializing wilc1000\n");
Glen Leeca64ad62015-10-20 17:13:55 +09001083 wl->close = 1;
Glen Lee53dc0cf2015-10-20 17:13:57 +09001084 wilc1000_wlan_deinit(ndev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001085 WILC_WFI_deinit_mon_interface();
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001086 }
1087
Glen Leea4cac482015-12-21 14:18:36 +09001088 vif->mac_opened = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001089
1090 return 0;
1091}
1092
Arnd Bergmann1608c402015-11-16 15:04:53 +01001093static int mac_ioctl(struct net_device *ndev, struct ifreq *req, int cmd)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001094{
Greg Kroah-Hartman63d03e42015-06-02 14:16:04 +09001095 u8 *buff = NULL;
Chaehyun Limca356ad2015-06-11 14:35:57 +09001096 s8 rssi;
Chaehyun Lim4e4467f2015-06-11 14:35:55 +09001097 u32 size = 0, length = 0;
Glen Leea4cac482015-12-21 14:18:36 +09001098 struct wilc_vif *vif;
Leo Kim9457b052015-11-05 14:36:37 +09001099 s32 ret = 0;
Glen Lee07320b62015-10-27 18:27:53 +09001100 struct wilc *wilc;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001101
Glen Leea4cac482015-12-21 14:18:36 +09001102 vif = netdev_priv(ndev);
1103 wilc = vif->wilc;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001104
Glen Lee07320b62015-10-27 18:27:53 +09001105 if (!wilc->initialized)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001106 return 0;
1107
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001108 switch (cmd) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001109 case SIOCSIWPRIV:
1110 {
Leo Kimf05ab242016-01-27 11:50:26 +09001111 struct iwreq *wrq = (struct iwreq *)req;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001112
1113 size = wrq->u.data.length;
1114
1115 if (size && wrq->u.data.pointer) {
Leo Kim582f8a22015-11-05 14:36:21 +09001116 buff = memdup_user(wrq->u.data.pointer,
1117 wrq->u.data.length);
Sudip Mukherjee360e27a2015-09-04 15:34:15 +05301118 if (IS_ERR(buff))
1119 return PTR_ERR(buff);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001120
1121 if (strncasecmp(buff, "RSSI", length) == 0) {
Glen Leefbf53792015-12-21 14:18:40 +09001122 ret = wilc_get_rssi(vif, &rssi);
Leo Kim5ac24422016-02-04 18:15:37 +09001123 netdev_info(ndev, "RSSI :%d\n", rssi);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001124
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001125 rssi += 5;
1126
1127 snprintf(buff, size, "rssi %d", rssi);
1128
1129 if (copy_to_user(wrq->u.data.pointer, buff, size)) {
Leo Kim5ac24422016-02-04 18:15:37 +09001130 netdev_err(ndev, "failed to copy\n");
Leo Kim9457b052015-11-05 14:36:37 +09001131 ret = -EFAULT;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001132 goto done;
1133 }
1134 }
1135 }
1136 }
1137 break;
1138
1139 default:
1140 {
Leo Kim5ac24422016-02-04 18:15:37 +09001141 netdev_info(ndev, "Command - %d - has been received\n", cmd);
Leo Kim9457b052015-11-05 14:36:37 +09001142 ret = -EOPNOTSUPP;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001143 goto done;
1144 }
1145 }
1146
1147done:
1148
Shraddha Barke642ac6c2015-08-10 13:30:33 +05301149 kfree(buff);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001150
Leo Kim9457b052015-11-05 14:36:37 +09001151 return ret;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001152}
1153
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001154void wilc_frmw_to_linux(struct wilc *wilc, u8 *buff, u32 size, u32 pkt_offset)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001155{
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001156 unsigned int frame_len = 0;
1157 int stats;
1158 unsigned char *buff_to_send = NULL;
1159 struct sk_buff *skb;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001160 struct net_device *wilc_netdev;
Glen Leea4cac482015-12-21 14:18:36 +09001161 struct wilc_vif *vif;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001162
Leo Kim0953a2e2016-01-27 11:50:25 +09001163 if (!wilc)
1164 return;
1165
Leo Kim7e725b42015-11-05 14:36:24 +09001166 wilc_netdev = get_if_handler(wilc, buff);
Leo Kim3a147c02015-11-05 14:36:10 +09001167 if (!wilc_netdev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001168 return;
1169
1170 buff += pkt_offset;
Glen Leea4cac482015-12-21 14:18:36 +09001171 vif = netdev_priv(wilc_netdev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001172
1173 if (size > 0) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001174 frame_len = size;
1175 buff_to_send = buff;
1176
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001177 skb = dev_alloc_skb(frame_len);
Leo Kim14086032016-02-04 18:15:36 +09001178 if (!skb)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001179 return;
Leo Kim14086032016-02-04 18:15:36 +09001180
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001181 skb->dev = wilc_netdev;
1182
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001183 memcpy(skb_put(skb, frame_len), buff_to_send, frame_len);
1184
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001185 skb->protocol = eth_type_trans(skb, wilc_netdev);
Glen Leea4cac482015-12-21 14:18:36 +09001186 vif->netstats.rx_packets++;
1187 vif->netstats.rx_bytes += frame_len;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001188 skb->ip_summed = CHECKSUM_UNNECESSARY;
1189 stats = netif_rx(skb);
Leo Kim5ac24422016-02-04 18:15:37 +09001190 netdev_dbg(wilc_netdev, "netif_rx ret value is: %d\n", stats);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001191 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001192}
1193
Glen Lee11f4b2e2015-10-27 18:27:51 +09001194void WILC_WFI_mgmt_rx(struct wilc *wilc, u8 *buff, u32 size)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001195{
1196 int i = 0;
Glen Leea4cac482015-12-21 14:18:36 +09001197 struct wilc_vif *vif;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001198
Glen Lee11f4b2e2015-10-27 18:27:51 +09001199 for (i = 0; i < wilc->vif_num; i++) {
Glen Lee1f435d22015-12-21 14:18:37 +09001200 vif = netdev_priv(wilc->vif[i]->ndev);
Glen Leea4cac482015-12-21 14:18:36 +09001201 if (vif->monitor_flag) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001202 WILC_WFI_monitor_rx(buff, size);
1203 return;
1204 }
1205 }
1206
Glen Lee1f435d22015-12-21 14:18:37 +09001207 vif = netdev_priv(wilc->vif[1]->ndev);
Leo Kim340a84f2016-03-25 21:16:50 +09001208 if ((buff[0] == vif->frame_reg[0].type && vif->frame_reg[0].reg) ||
1209 (buff[0] == vif->frame_reg[1].type && vif->frame_reg[1].reg))
Glen Lee1f435d22015-12-21 14:18:37 +09001210 WILC_WFI_p2p_rx(wilc->vif[1]->ndev, buff, size);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001211}
1212
Arnd Bergmann857c7b02015-11-16 15:05:00 +01001213void wilc_netdev_cleanup(struct wilc *wilc)
Tony Cho4875c492015-10-20 14:26:52 +09001214{
1215 int i = 0;
Glen Leea4cac482015-12-21 14:18:36 +09001216 struct wilc_vif *vif[NUM_CONCURRENT_IFC];
Tony Cho4875c492015-10-20 14:26:52 +09001217
Glen Lee1f435d22015-12-21 14:18:37 +09001218 if (wilc && (wilc->vif[0]->ndev || wilc->vif[1]->ndev)) {
Tony Cho4875c492015-10-20 14:26:52 +09001219 unregister_inetaddr_notifier(&g_dev_notifier);
1220
1221 for (i = 0; i < NUM_CONCURRENT_IFC; i++)
Glen Lee1f435d22015-12-21 14:18:37 +09001222 vif[i] = netdev_priv(wilc->vif[i]->ndev);
Tony Cho4875c492015-10-20 14:26:52 +09001223 }
1224
Leo Kim3f626cf2016-04-01 17:44:17 +09001225 if (wilc && wilc->firmware) {
Glen Lee90b984c2015-10-29 12:18:50 +09001226 release_firmware(wilc->firmware);
Leo Kim3f626cf2016-04-01 17:44:17 +09001227 wilc->firmware = NULL;
1228 }
Tony Cho4875c492015-10-20 14:26:52 +09001229
Glen Lee1f435d22015-12-21 14:18:37 +09001230 if (wilc && (wilc->vif[0]->ndev || wilc->vif[1]->ndev)) {
Tony Cho4875c492015-10-20 14:26:52 +09001231 for (i = 0; i < NUM_CONCURRENT_IFC; i++)
Glen Lee1f435d22015-12-21 14:18:37 +09001232 if (wilc->vif[i]->ndev)
Glen Leea4cac482015-12-21 14:18:36 +09001233 if (vif[i]->mac_opened)
Glen Lee1f435d22015-12-21 14:18:37 +09001234 wilc_mac_close(wilc->vif[i]->ndev);
Tony Cho4875c492015-10-20 14:26:52 +09001235
1236 for (i = 0; i < NUM_CONCURRENT_IFC; i++) {
Glen Lee1f435d22015-12-21 14:18:37 +09001237 unregister_netdev(wilc->vif[i]->ndev);
1238 wilc_free_wiphy(wilc->vif[i]->ndev);
1239 free_netdev(wilc->vif[i]->ndev);
Tony Cho4875c492015-10-20 14:26:52 +09001240 }
1241 }
1242
Glen Lee90b984c2015-10-29 12:18:50 +09001243 kfree(wilc);
Tony Cho4875c492015-10-20 14:26:52 +09001244}
Arnd Bergmann750ffe92015-11-16 15:05:08 +01001245EXPORT_SYMBOL_GPL(wilc_netdev_cleanup);
Tony Cho4875c492015-10-20 14:26:52 +09001246
Arnd Bergmann7d37a4a2015-11-16 15:05:05 +01001247int wilc_netdev_init(struct wilc **wilc, struct device *dev, int io_type,
1248 int gpio, const struct wilc_hif_func *ops)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001249{
Amitoj Kaur Chawlafe747f02016-02-17 20:41:03 +05301250 int i, ret;
Glen Leea4cac482015-12-21 14:18:36 +09001251 struct wilc_vif *vif;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001252 struct net_device *ndev;
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001253 struct wilc *wl;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001254
Glen Lee825b9662015-11-18 15:11:37 +09001255 wl = kzalloc(sizeof(*wl), GFP_KERNEL);
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001256 if (!wl)
Chaehyun Limac61ef82015-09-08 00:36:36 +09001257 return -ENOMEM;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001258
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001259 *wilc = wl;
1260 wl->io_type = io_type;
1261 wl->gpio = gpio;
Glen Leeaf9ae092015-12-21 14:18:09 +09001262 wl->hif_func = ops;
Arnd Bergmannc4d139c2015-11-16 15:05:04 +01001263
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001264 register_inetaddr_notifier(&g_dev_notifier);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001265
1266 for (i = 0; i < NUM_CONCURRENT_IFC; i++) {
Glen Leea4cac482015-12-21 14:18:36 +09001267 ndev = alloc_etherdev(sizeof(struct wilc_vif));
Leo Kim14086032016-02-04 18:15:36 +09001268 if (!ndev)
Amitoj Kaur Chawlafe747f02016-02-17 20:41:03 +05301269 return -ENOMEM;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001270
Glen Leea4cac482015-12-21 14:18:36 +09001271 vif = netdev_priv(ndev);
1272 memset(vif, 0, sizeof(struct wilc_vif));
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001273
Leo Kim84d3b872015-11-05 14:36:19 +09001274 if (i == 0)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001275 strcpy(ndev->name, "wlan%d");
Leo Kim84d3b872015-11-05 14:36:19 +09001276 else
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001277 strcpy(ndev->name, "p2p%d");
1278
Leo Kim67501402016-02-04 18:15:39 +09001279 vif->idx = wl->vif_num;
Glen Leea4cac482015-12-21 14:18:36 +09001280 vif->wilc = *wilc;
Glen Lee1f435d22015-12-21 14:18:37 +09001281 wl->vif[i] = vif;
1282 wl->vif[wl->vif_num]->ndev = ndev;
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001283 wl->vif_num++;
Arnd Bergmanne5af0562015-05-29 22:52:12 +02001284 ndev->netdev_ops = &wilc_netdev_ops;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001285
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001286 {
1287 struct wireless_dev *wdev;
Leo Kimfa8b23c2016-02-04 18:15:33 +09001288
Arnd Bergmann2e7d5372015-11-16 15:05:03 +01001289 wdev = wilc_create_wiphy(ndev, dev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001290
Arnd Bergmann67039922015-11-16 15:05:02 +01001291 if (dev)
1292 SET_NETDEV_DEV(ndev, dev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001293
Leo Kim3a147c02015-11-05 14:36:10 +09001294 if (!wdev) {
Leo Kim5ac24422016-02-04 18:15:37 +09001295 netdev_err(ndev, "Can't register WILC Wiphy\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001296 return -1;
1297 }
1298
Glen Lee1006b5c2015-12-21 14:18:38 +09001299 vif->ndev->ieee80211_ptr = wdev;
1300 vif->ndev->ml_priv = vif;
1301 wdev->netdev = vif->ndev;
Glen Leea4cac482015-12-21 14:18:36 +09001302 vif->netstats.rx_packets = 0;
1303 vif->netstats.tx_packets = 0;
1304 vif->netstats.rx_bytes = 0;
1305 vif->netstats.tx_bytes = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001306 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001307
Amitoj Kaur Chawlafe747f02016-02-17 20:41:03 +05301308 ret = register_netdev(ndev);
1309 if (ret)
1310 return ret;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001311
Glen Leea4cac482015-12-21 14:18:36 +09001312 vif->iftype = STATION_MODE;
1313 vif->mac_opened = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001314 }
1315
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001316 return 0;
1317}
Arnd Bergmann750ffe92015-11-16 15:05:08 +01001318EXPORT_SYMBOL_GPL(wilc_netdev_init);
Arnd Bergmannc94f05e2015-11-16 15:05:09 +01001319
1320MODULE_LICENSE("GPL");