blob: 3a66255f14fc77a7376eedee063452c0b45c06be [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>
Johnny Kimc5c77ba2015-05-11 14:30:56 +090024#include <linux/semaphore.h>
Leo Kim11a54b32016-04-01 17:44:15 +090025#include <linux/completion.h>
Johnny Kimc5c77ba2015-05-11 14:30:56 +090026
Leo Kim885cabc2016-02-04 18:15:35 +090027static int dev_state_ev_handler(struct notifier_block *this,
28 unsigned long event, void *ptr);
Johnny Kimc5c77ba2015-05-11 14:30:56 +090029
30static struct notifier_block g_dev_notifier = {
31 .notifier_call = dev_state_ev_handler
32};
Johnny Kimc5c77ba2015-05-11 14:30:56 +090033
Glen Lee7c67c052015-10-27 18:27:50 +090034static int wlan_deinit_locks(struct net_device *dev);
Glen Lee32dd51b2015-10-27 18:27:52 +090035static void wlan_deinitialize_threads(struct net_device *dev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +090036
Johnny Kimc5c77ba2015-05-11 14:30:56 +090037static void linux_wlan_tx_complete(void *priv, int status);
Johnny Kimc5c77ba2015-05-11 14:30:56 +090038static int mac_init_fn(struct net_device *ndev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +090039static struct net_device_stats *mac_stats(struct net_device *dev);
40static int mac_ioctl(struct net_device *ndev, struct ifreq *req, int cmd);
41static void wilc_set_multicast_list(struct net_device *dev);
Arnd Bergmann750ffe92015-11-16 15:05:08 +010042
Arnd Bergmann0e1af732015-11-16 15:04:54 +010043bool wilc_enable_ps = true;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090044
Johnny Kimc5c77ba2015-05-11 14:30:56 +090045static const struct net_device_ops wilc_netdev_ops = {
46 .ndo_init = mac_init_fn,
Arnd Bergmann0e1af732015-11-16 15:04:54 +010047 .ndo_open = wilc_mac_open,
48 .ndo_stop = wilc_mac_close,
49 .ndo_start_xmit = wilc_mac_xmit,
Johnny Kimc5c77ba2015-05-11 14:30:56 +090050 .ndo_do_ioctl = mac_ioctl,
51 .ndo_get_stats = mac_stats,
52 .ndo_set_rx_mode = wilc_set_multicast_list,
53
54};
Johnny Kimc5c77ba2015-05-11 14:30:56 +090055
Leo Kim885cabc2016-02-04 18:15:35 +090056static int dev_state_ev_handler(struct notifier_block *this,
57 unsigned long event, void *ptr)
Johnny Kimc5c77ba2015-05-11 14:30:56 +090058{
Alison Schofieldd5c89442016-02-12 22:53:13 -080059 struct in_ifaddr *dev_iface = ptr;
Chaehyun Lim27268872015-09-15 14:06:13 +090060 struct wilc_priv *priv;
Leo Kimf24374a2015-11-05 14:36:12 +090061 struct host_if_drv *hif_drv;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090062 struct net_device *dev;
Leo Kimeac3e8f2015-11-05 14:36:16 +090063 u8 *ip_addr_buf;
Glen Leea4cac482015-12-21 14:18:36 +090064 struct wilc_vif *vif;
Greg Kroah-Hartman63d03e42015-06-02 14:16:04 +090065 u8 null_ip[4] = {0};
Johnny Kimc5c77ba2015-05-11 14:30:56 +090066 char wlan_dev_name[5] = "wlan0";
67
Leo Kim14086032016-02-04 18:15:36 +090068 if (!dev_iface || !dev_iface->ifa_dev || !dev_iface->ifa_dev->dev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +090069 return NOTIFY_DONE;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090070
Leo Kim582f8a22015-11-05 14:36:21 +090071 if (memcmp(dev_iface->ifa_label, "wlan0", 5) &&
Leo Kim14086032016-02-04 18:15:36 +090072 memcmp(dev_iface->ifa_label, "p2p0", 4))
Johnny Kimc5c77ba2015-05-11 14:30:56 +090073 return NOTIFY_DONE;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090074
75 dev = (struct net_device *)dev_iface->ifa_dev->dev;
Leo Kim14086032016-02-04 18:15:36 +090076 if (!dev->ieee80211_ptr || !dev->ieee80211_ptr->wiphy)
Johnny Kimc5c77ba2015-05-11 14:30:56 +090077 return NOTIFY_DONE;
Leo Kim14086032016-02-04 18:15:36 +090078
Johnny Kimc5c77ba2015-05-11 14:30:56 +090079 priv = wiphy_priv(dev->ieee80211_ptr->wiphy);
Leo Kim14086032016-02-04 18:15:36 +090080 if (!priv)
Johnny Kimc5c77ba2015-05-11 14:30:56 +090081 return NOTIFY_DONE;
Leo Kim14086032016-02-04 18:15:36 +090082
Leo Kim48b28df2016-02-04 18:15:32 +090083 hif_drv = (struct host_if_drv *)priv->hif_drv;
Glen Leea4cac482015-12-21 14:18:36 +090084 vif = netdev_priv(dev);
Leo Kim14086032016-02-04 18:15:36 +090085 if (!vif || !hif_drv)
Johnny Kimc5c77ba2015-05-11 14:30:56 +090086 return NOTIFY_DONE;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090087
88 switch (event) {
89 case NETDEV_UP:
Glen Leea4cac482015-12-21 14:18:36 +090090 if (vif->iftype == STATION_MODE || vif->iftype == CLIENT_MODE) {
Leo Kimf24374a2015-11-05 14:36:12 +090091 hif_drv->IFC_UP = 1;
Arnd Bergmann0e1af732015-11-16 15:04:54 +010092 wilc_optaining_ip = false;
93 del_timer(&wilc_during_ip_timer);
Johnny Kimc5c77ba2015-05-11 14:30:56 +090094 }
95
Arnd Bergmann0e1af732015-11-16 15:04:54 +010096 if (wilc_enable_ps)
Glen Leefbf53792015-12-21 14:18:40 +090097 wilc_set_power_mgmt(vif, 1, 0);
Johnny Kimc5c77ba2015-05-11 14:30:56 +090098
Leo Kim5ac24422016-02-04 18:15:37 +090099 netdev_dbg(dev, "[%s] Up IP\n", dev_iface->ifa_label);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900100
Leo Kimeac3e8f2015-11-05 14:36:16 +0900101 ip_addr_buf = (char *)&dev_iface->ifa_address;
Leo Kim5ac24422016-02-04 18:15:37 +0900102 netdev_dbg(dev, "IP add=%d:%d:%d:%d\n",
103 ip_addr_buf[0], ip_addr_buf[1],
104 ip_addr_buf[2], ip_addr_buf[3]);
Leo Kim67501402016-02-04 18:15:39 +0900105 wilc_setup_ipaddress(vif, ip_addr_buf, vif->idx);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900106
107 break;
108
109 case NETDEV_DOWN:
Glen Leea4cac482015-12-21 14:18:36 +0900110 if (vif->iftype == STATION_MODE || vif->iftype == CLIENT_MODE) {
Leo Kimf24374a2015-11-05 14:36:12 +0900111 hif_drv->IFC_UP = 0;
Arnd Bergmann0e1af732015-11-16 15:04:54 +0100112 wilc_optaining_ip = false;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900113 }
114
115 if (memcmp(dev_iface->ifa_label, wlan_dev_name, 5) == 0)
Glen Leefbf53792015-12-21 14:18:40 +0900116 wilc_set_power_mgmt(vif, 0, 0);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900117
Glen Leefbf53792015-12-21 14:18:40 +0900118 wilc_resolve_disconnect_aberration(vif);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900119
Leo Kim5ac24422016-02-04 18:15:37 +0900120 netdev_dbg(dev, "[%s] Down IP\n", dev_iface->ifa_label);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900121
Leo Kimeac3e8f2015-11-05 14:36:16 +0900122 ip_addr_buf = null_ip;
Leo Kim5ac24422016-02-04 18:15:37 +0900123 netdev_dbg(dev, "IP add=%d:%d:%d:%d\n",
124 ip_addr_buf[0], ip_addr_buf[1],
125 ip_addr_buf[2], ip_addr_buf[3]);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900126
Leo Kim67501402016-02-04 18:15:39 +0900127 wilc_setup_ipaddress(vif, ip_addr_buf, vif->idx);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900128
129 break;
130
131 default:
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900132 break;
133 }
134
135 return NOTIFY_DONE;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900136}
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900137
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900138static irqreturn_t isr_uh_routine(int irq, void *user_data)
139{
Glen Leea4cac482015-12-21 14:18:36 +0900140 struct wilc_vif *vif;
Glen Lee39483622015-10-27 18:27:37 +0900141 struct wilc *wilc;
Alison Schofieldd5c89442016-02-12 22:53:13 -0800142 struct net_device *dev = user_data;
Glen Lee39483622015-10-27 18:27:37 +0900143
Glen Leea4cac482015-12-21 14:18:36 +0900144 vif = netdev_priv(dev);
145 wilc = vif->wilc;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900146
Glen Lee39483622015-10-27 18:27:37 +0900147 if (wilc->close) {
Leo Kim5ac24422016-02-04 18:15:37 +0900148 netdev_err(dev, "Can't handle UH interrupt\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900149 return IRQ_HANDLED;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900150 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900151 return IRQ_WAKE_THREAD;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900152}
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900153
Arnd Bergmann1608c402015-11-16 15:04:53 +0100154static irqreturn_t isr_bh_routine(int irq, void *userdata)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900155{
Glen Leea4cac482015-12-21 14:18:36 +0900156 struct wilc_vif *vif;
Glen Lee2e7933d2015-10-27 18:27:38 +0900157 struct wilc *wilc;
Alison Schofieldd5c89442016-02-12 22:53:13 -0800158 struct net_device *dev = userdata;
Glen Lee2e7933d2015-10-27 18:27:38 +0900159
Glen Leea4cac482015-12-21 14:18:36 +0900160 vif = netdev_priv(userdata);
161 wilc = vif->wilc;
Glen Lee2e7933d2015-10-27 18:27:38 +0900162
Glen Lee2e7933d2015-10-27 18:27:38 +0900163 if (wilc->close) {
Leo Kim5ac24422016-02-04 18:15:37 +0900164 netdev_err(dev, "Can't handle BH interrupt\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900165 return IRQ_HANDLED;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900166 }
167
Glen Lee50b929e2015-10-27 18:27:40 +0900168 wilc_handle_isr(wilc);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900169
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900170 return IRQ_HANDLED;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900171}
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900172
Glen Lee2c1d05d2015-10-20 17:14:03 +0900173static int init_irq(struct net_device *dev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900174{
175 int ret = 0;
Glen Leea4cac482015-12-21 14:18:36 +0900176 struct wilc_vif *vif;
Glen Lee2c1d05d2015-10-20 17:14:03 +0900177 struct wilc *wl;
178
Glen Leea4cac482015-12-21 14:18:36 +0900179 vif = netdev_priv(dev);
180 wl = vif->wilc;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900181
Arnd Bergmannc4d139c2015-11-16 15:05:04 +0100182 if ((gpio_request(wl->gpio, "WILC_INTR") == 0) &&
183 (gpio_direction_input(wl->gpio) == 0)) {
184 wl->dev_irq_num = gpio_to_irq(wl->gpio);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900185 } else {
186 ret = -1;
Leo Kim5ac24422016-02-04 18:15:37 +0900187 netdev_err(dev, "could not obtain gpio for WILC_INTR\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900188 }
189
Leo Kim83231b72015-11-06 11:12:22 +0900190 if (ret != -1 && request_threaded_irq(wl->dev_irq_num,
191 isr_uh_routine,
192 isr_bh_routine,
193 IRQF_TRIGGER_LOW | IRQF_ONESHOT,
194 "WILC_IRQ", dev) < 0) {
Leo Kim5ac24422016-02-04 18:15:37 +0900195 netdev_err(dev, "Failed to request IRQ GPIO: %d\n", wl->gpio);
Arnd Bergmannc4d139c2015-11-16 15:05:04 +0100196 gpio_free(wl->gpio);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900197 ret = -1;
198 } else {
Leo Kim5ac24422016-02-04 18:15:37 +0900199 netdev_dbg(dev,
200 "IRQ request succeeded IRQ-NUM= %d on GPIO: %d\n",
201 wl->dev_irq_num, wl->gpio);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900202 }
203
204 return ret;
205}
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900206
Glen Leeec5cc752015-10-27 18:27:39 +0900207static void deinit_irq(struct net_device *dev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900208{
Glen Leea4cac482015-12-21 14:18:36 +0900209 struct wilc_vif *vif;
Glen Leeec5cc752015-10-27 18:27:39 +0900210 struct wilc *wilc;
211
Glen Leea4cac482015-12-21 14:18:36 +0900212 vif = netdev_priv(dev);
213 wilc = vif->wilc;
Glen Leeec5cc752015-10-27 18:27:39 +0900214
Arnd Bergmannc4d139c2015-11-16 15:05:04 +0100215 /* Deintialize IRQ */
216 if (wilc->dev_irq_num) {
Glen Leeec5cc752015-10-27 18:27:39 +0900217 free_irq(wilc->dev_irq_num, wilc);
Arnd Bergmannc4d139c2015-11-16 15:05:04 +0100218 gpio_free(wilc->gpio);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900219 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900220}
221
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100222int wilc_lock_timeout(struct wilc *nic, void *vp, u32 timeout)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900223{
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100224 /* FIXME: replace with mutex_lock or wait_for_completion */
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900225 int error = -1;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900226
Leo Kim3a147c02015-11-05 14:36:10 +0900227 if (vp)
Alison Schofieldd5c89442016-02-12 22:53:13 -0800228 error = down_timeout(vp,
Leo Kim582f8a22015-11-05 14:36:21 +0900229 msecs_to_jiffies(timeout));
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900230 return error;
231}
232
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100233void wilc_mac_indicate(struct wilc *wilc, int flag)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900234{
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900235 int status;
236
237 if (flag == WILC_MAC_INDICATE_STATUS) {
Leo Kim582f8a22015-11-05 14:36:21 +0900238 wilc_wlan_cfg_get_val(WID_STATUS,
239 (unsigned char *)&status, 4);
Glen Lee64f2b712015-10-27 18:27:43 +0900240 if (wilc->mac_status == WILC_MAC_STATUS_INIT) {
241 wilc->mac_status = status;
Binoy Jayan04247e72016-06-15 11:00:37 +0530242 complete(&wilc->sync_event);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900243 } else {
Glen Lee64f2b712015-10-27 18:27:43 +0900244 wilc->mac_status = status;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900245 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900246 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900247}
248
Arnd Bergmann1608c402015-11-16 15:04:53 +0100249static struct net_device *get_if_handler(struct wilc *wilc, u8 *mac_header)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900250{
Leo Kim660786e2015-11-05 14:36:27 +0900251 u8 *bssid, *bssid1;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900252 int i = 0;
253
Leo Kimd2392222015-11-05 14:36:26 +0900254 bssid = mac_header + 10;
Leo Kim660786e2015-11-05 14:36:27 +0900255 bssid1 = mac_header + 4;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900256
Glen Leeba615f12016-01-25 16:35:15 +0900257 for (i = 0; i < wilc->vif_num; i++) {
258 if (wilc->vif[i]->mode == STATION_MODE)
Leo Kimfa633942016-03-25 21:16:53 +0900259 if (ether_addr_equal_unaligned(bssid,
260 wilc->vif[i]->bssid))
Glen Leeba615f12016-01-25 16:35:15 +0900261 return wilc->vif[i]->ndev;
262 if (wilc->vif[i]->mode == AP_MODE)
Leo Kimfa633942016-03-25 21:16:53 +0900263 if (ether_addr_equal_unaligned(bssid1,
264 wilc->vif[i]->bssid))
Glen Leeba615f12016-01-25 16:35:15 +0900265 return wilc->vif[i]->ndev;
266 }
Tony Cho8259a532015-10-20 14:26:47 +0900267
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900268 return NULL;
269}
270
Glen Leeba615f12016-01-25 16:35:15 +0900271int wilc_wlan_set_bssid(struct net_device *wilc_netdev, u8 *bssid, u8 mode)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900272{
273 int i = 0;
274 int ret = -1;
Glen Leea4cac482015-12-21 14:18:36 +0900275 struct wilc_vif *vif;
Glen Lee472791a2015-10-27 18:27:44 +0900276 struct wilc *wilc;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900277
Glen Leea4cac482015-12-21 14:18:36 +0900278 vif = netdev_priv(wilc_netdev);
279 wilc = vif->wilc;
Glen Lee472791a2015-10-27 18:27:44 +0900280
281 for (i = 0; i < wilc->vif_num; i++)
Glen Lee1f435d22015-12-21 14:18:37 +0900282 if (wilc->vif[i]->ndev == wilc_netdev) {
283 memcpy(wilc->vif[i]->bssid, bssid, 6);
Glen Leeba615f12016-01-25 16:35:15 +0900284 wilc->vif[i]->mode = mode;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900285 ret = 0;
286 break;
287 }
Tony Cho8259a532015-10-20 14:26:47 +0900288
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900289 return ret;
290}
291
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100292int wilc_wlan_get_num_conn_ifcs(struct wilc *wilc)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900293{
Chaehyun Lim51e825f2015-09-15 14:06:14 +0900294 u8 i = 0;
295 u8 null_bssid[6] = {0};
296 u8 ret_val = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900297
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100298 for (i = 0; i < wilc->vif_num; i++)
Glen Lee1f435d22015-12-21 14:18:37 +0900299 if (memcmp(wilc->vif[i]->bssid, null_bssid, 6))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900300 ret_val++;
Tony Cho8259a532015-10-20 14:26:47 +0900301
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900302 return ret_val;
303}
304
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900305static int linux_wlan_txq_task(void *vp)
306{
307 int ret, txq_count;
Glen Leea4cac482015-12-21 14:18:36 +0900308 struct wilc_vif *vif;
Glen Lee88687582015-10-27 18:27:46 +0900309 struct wilc *wl;
310 struct net_device *dev = vp;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900311
Glen Leea4cac482015-12-21 14:18:36 +0900312 vif = netdev_priv(dev);
313 wl = vif->wilc;
Glen Lee88687582015-10-27 18:27:46 +0900314
Leo Kim11a54b32016-04-01 17:44:15 +0900315 complete(&wl->txq_thread_started);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900316 while (1) {
Binoy Jayanb27a6d52016-06-15 11:00:34 +0530317 wait_for_completion(&wl->txq_event);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900318
Glen Lee88687582015-10-27 18:27:46 +0900319 if (wl->close) {
Leo Kim11a54b32016-04-01 17:44:15 +0900320 complete(&wl->txq_thread_started);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900321
322 while (!kthread_should_stop())
323 schedule();
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900324 break;
325 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900326 do {
Glen Leea1332ca2015-10-27 18:27:47 +0900327 ret = wilc_wlan_handle_txq(dev, &txq_count);
Leo Kim98b89842015-11-05 14:36:18 +0900328 if (txq_count < FLOW_CONTROL_LOWER_THRESHOLD) {
Glen Lee1f435d22015-12-21 14:18:37 +0900329 if (netif_queue_stopped(wl->vif[0]->ndev))
330 netif_wake_queue(wl->vif[0]->ndev);
331 if (netif_queue_stopped(wl->vif[1]->ndev))
332 netif_wake_queue(wl->vif[1]->ndev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900333 }
Leo Kim98b89842015-11-05 14:36:18 +0900334 } while (ret == WILC_TX_ERR_NO_BUF && !wl->close);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900335 }
336 return 0;
337}
338
Arnd Bergmann0e1af732015-11-16 15:04:54 +0100339int wilc_wlan_get_firmware(struct net_device *dev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900340{
Glen Leea4cac482015-12-21 14:18:36 +0900341 struct wilc_vif *vif;
Glen Lee65c8adc2015-10-29 12:18:49 +0900342 struct wilc *wilc;
Glen Lee14823bf2016-01-25 16:35:13 +0900343 int chip_id, ret = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900344 const struct firmware *wilc_firmware;
345 char *firmware;
346
Glen Leea4cac482015-12-21 14:18:36 +0900347 vif = netdev_priv(dev);
348 wilc = vif->wilc;
Glen Lee65c8adc2015-10-29 12:18:49 +0900349
Chris Park65c3f002016-02-04 18:15:54 +0900350 chip_id = wilc_get_chipid(wilc, false);
Glen Lee14823bf2016-01-25 16:35:13 +0900351
352 if (chip_id < 0x1003a0)
353 firmware = FIRMWARE_1002;
354 else
355 firmware = FIRMWARE_1003;
356
357 netdev_info(dev, "loading firmware %s\n", firmware);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900358
Leo Kim14086032016-02-04 18:15:36 +0900359 if (!(&vif->ndev->dev))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900360 goto _fail_;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900361
Arnd Bergmannb03314e2015-11-16 15:05:01 +0100362 if (request_firmware(&wilc_firmware, firmware, wilc->dev) != 0) {
Julia Lawallb9811892016-05-17 16:38:43 +0200363 netdev_err(dev, "%s - firmware not available\n", firmware);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900364 ret = -1;
365 goto _fail_;
366 }
Glen Lee65c8adc2015-10-29 12:18:49 +0900367 wilc->firmware = wilc_firmware;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900368
369_fail_:
370
371 return ret;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900372}
373
Glen Lee9bf3d722015-10-29 12:18:46 +0900374static int linux_wlan_start_firmware(struct net_device *dev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900375{
Glen Leea4cac482015-12-21 14:18:36 +0900376 struct wilc_vif *vif;
Glen Lee9bf3d722015-10-29 12:18:46 +0900377 struct wilc *wilc;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900378 int ret = 0;
Glen Lee9bf3d722015-10-29 12:18:46 +0900379
Glen Leea4cac482015-12-21 14:18:36 +0900380 vif = netdev_priv(dev);
381 wilc = vif->wilc;
Glen Lee9bf3d722015-10-29 12:18:46 +0900382
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100383 ret = wilc_wlan_start(wilc);
Leo Kim14086032016-02-04 18:15:36 +0900384 if (ret < 0)
Leo Kim0aeea1a2015-11-05 14:36:30 +0900385 return ret;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900386
Binoy Jayan04247e72016-06-15 11:00:37 +0530387 if (!wait_for_completion_timeout(&wilc->sync_event,
388 msecs_to_jiffies(5000)))
389 return -ETIME;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900390
Leo Kim0aeea1a2015-11-05 14:36:30 +0900391 return 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900392}
Leo Kima40b22c2015-11-05 14:36:32 +0900393
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100394static int wilc1000_firmware_download(struct net_device *dev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900395{
Glen Leea4cac482015-12-21 14:18:36 +0900396 struct wilc_vif *vif;
Glen Leeed760b62015-10-29 12:18:42 +0900397 struct wilc *wilc;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900398 int ret = 0;
399
Glen Leea4cac482015-12-21 14:18:36 +0900400 vif = netdev_priv(dev);
401 wilc = vif->wilc;
Glen Leeed760b62015-10-29 12:18:42 +0900402
403 if (!wilc->firmware) {
Leo Kim5ac24422016-02-04 18:15:37 +0900404 netdev_err(dev, "Firmware buffer is NULL\n");
Leo Kim14b18212015-11-05 14:36:31 +0900405 return -ENOBUFS;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900406 }
Leo Kim14086032016-02-04 18:15:36 +0900407
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100408 ret = wilc_wlan_firmware_download(wilc, wilc->firmware->data,
Glen Leeed760b62015-10-29 12:18:42 +0900409 wilc->firmware->size);
Kim, Leofc4b95d2015-07-28 17:47:37 +0900410 if (ret < 0)
Leo Kim14b18212015-11-05 14:36:31 +0900411 return ret;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900412
Glen Leeed760b62015-10-29 12:18:42 +0900413 release_firmware(wilc->firmware);
Glen Lee6f72ed72015-11-25 11:59:40 +0900414 wilc->firmware = NULL;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900415
Leo Kim5ac24422016-02-04 18:15:37 +0900416 netdev_dbg(dev, "Download Succeeded\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900417
Leo Kim14b18212015-11-05 14:36:31 +0900418 return 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900419}
420
Glen Lee00215dd2015-11-18 15:11:25 +0900421static int linux_wlan_init_test_config(struct net_device *dev,
Glen Leeb8f6ca02016-01-25 16:35:12 +0900422 struct wilc_vif *vif)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900423{
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900424 unsigned char c_val[64];
Glen Leeb8f6ca02016-01-25 16:35:12 +0900425 struct wilc *wilc = vif->wilc;
Chaehyun Lim27268872015-09-15 14:06:13 +0900426 struct wilc_priv *priv;
Leo Kim0fa66c72015-11-05 14:36:13 +0900427 struct host_if_drv *hif_drv;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900428
Leo Kim5ac24422016-02-04 18:15:37 +0900429 netdev_dbg(dev, "Start configuring Firmware\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900430 priv = wiphy_priv(dev->ieee80211_ptr->wiphy);
Leo Kim48b28df2016-02-04 18:15:32 +0900431 hif_drv = (struct host_if_drv *)priv->hif_drv;
Leo Kim5ac24422016-02-04 18:15:37 +0900432 netdev_dbg(dev, "Host = %p\n", hif_drv);
Chris Park65c3f002016-02-04 18:15:54 +0900433 wilc_get_chipid(wilc, false);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900434
Johnny Kime5d57e92015-08-20 16:32:53 +0900435 *(int *)c_val = 1;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900436
Glen Lee79df6a42016-02-04 18:15:31 +0900437 if (!wilc_wlan_cfg_set(vif, 1, WID_SET_DRV_HANDLER, c_val, 4, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900438 goto _fail_;
439
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900440 c_val[0] = 0;
Glen Lee79df6a42016-02-04 18:15:31 +0900441 if (!wilc_wlan_cfg_set(vif, 0, WID_PC_TEST_MODE, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900442 goto _fail_;
443
444 c_val[0] = INFRASTRUCTURE;
Glen Lee79df6a42016-02-04 18:15:31 +0900445 if (!wilc_wlan_cfg_set(vif, 0, WID_BSS_TYPE, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900446 goto _fail_;
447
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900448 c_val[0] = RATE_AUTO;
Glen Lee79df6a42016-02-04 18:15:31 +0900449 if (!wilc_wlan_cfg_set(vif, 0, WID_CURRENT_TX_RATE, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900450 goto _fail_;
451
452 c_val[0] = G_MIXED_11B_2_MODE;
Glen Lee79df6a42016-02-04 18:15:31 +0900453 if (!wilc_wlan_cfg_set(vif, 0, WID_11G_OPERATING_MODE, c_val, 1, 0,
Glen Lee89758e12015-11-18 15:11:34 +0900454 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900455 goto _fail_;
456
457 c_val[0] = 1;
Glen Lee79df6a42016-02-04 18:15:31 +0900458 if (!wilc_wlan_cfg_set(vif, 0, WID_CURRENT_CHANNEL, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900459 goto _fail_;
460
461 c_val[0] = G_SHORT_PREAMBLE;
Glen Lee79df6a42016-02-04 18:15:31 +0900462 if (!wilc_wlan_cfg_set(vif, 0, WID_PREAMBLE, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900463 goto _fail_;
464
465 c_val[0] = AUTO_PROT;
Glen Lee79df6a42016-02-04 18:15:31 +0900466 if (!wilc_wlan_cfg_set(vif, 0, WID_11N_PROT_MECH, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900467 goto _fail_;
468
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900469 c_val[0] = ACTIVE_SCAN;
Glen Lee79df6a42016-02-04 18:15:31 +0900470 if (!wilc_wlan_cfg_set(vif, 0, WID_SCAN_TYPE, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900471 goto _fail_;
472
473 c_val[0] = SITE_SURVEY_OFF;
Glen Lee79df6a42016-02-04 18:15:31 +0900474 if (!wilc_wlan_cfg_set(vif, 0, WID_SITE_SURVEY, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900475 goto _fail_;
476
Leo Kim98b89842015-11-05 14:36:18 +0900477 *((int *)c_val) = 0xffff;
Glen Lee79df6a42016-02-04 18:15:31 +0900478 if (!wilc_wlan_cfg_set(vif, 0, WID_RTS_THRESHOLD, c_val, 2, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900479 goto _fail_;
480
481 *((int *)c_val) = 2346;
Glen Lee79df6a42016-02-04 18:15:31 +0900482 if (!wilc_wlan_cfg_set(vif, 0, WID_FRAG_THRESHOLD, c_val, 2, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900483 goto _fail_;
484
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900485 c_val[0] = 0;
Glen Lee79df6a42016-02-04 18:15:31 +0900486 if (!wilc_wlan_cfg_set(vif, 0, WID_BCAST_SSID, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900487 goto _fail_;
488
489 c_val[0] = 1;
Glen Lee79df6a42016-02-04 18:15:31 +0900490 if (!wilc_wlan_cfg_set(vif, 0, WID_QOS_ENABLE, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900491 goto _fail_;
492
493 c_val[0] = NO_POWERSAVE;
Glen Lee79df6a42016-02-04 18:15:31 +0900494 if (!wilc_wlan_cfg_set(vif, 0, WID_POWER_MANAGEMENT, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900495 goto _fail_;
496
Arnd Bergmannb4d04c12015-11-16 15:04:56 +0100497 c_val[0] = NO_SECURITY; /* NO_ENCRYPT, 0x79 */
Glen Lee79df6a42016-02-04 18:15:31 +0900498 if (!wilc_wlan_cfg_set(vif, 0, WID_11I_MODE, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900499 goto _fail_;
500
501 c_val[0] = OPEN_SYSTEM;
Glen Lee79df6a42016-02-04 18:15:31 +0900502 if (!wilc_wlan_cfg_set(vif, 0, WID_AUTH_TYPE, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900503 goto _fail_;
504
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900505 strcpy(c_val, "123456790abcdef1234567890");
Glen Lee79df6a42016-02-04 18:15:31 +0900506 if (!wilc_wlan_cfg_set(vif, 0, WID_WEP_KEY_VALUE, c_val,
Glen Lee89758e12015-11-18 15:11:34 +0900507 (strlen(c_val) + 1), 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900508 goto _fail_;
509
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900510 strcpy(c_val, "12345678");
Glen Lee79df6a42016-02-04 18:15:31 +0900511 if (!wilc_wlan_cfg_set(vif, 0, WID_11I_PSK, c_val, (strlen(c_val)), 0,
Glen Lee89758e12015-11-18 15:11:34 +0900512 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900513 goto _fail_;
514
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900515 strcpy(c_val, "password");
Glen Lee79df6a42016-02-04 18:15:31 +0900516 if (!wilc_wlan_cfg_set(vif, 0, WID_1X_KEY, c_val, (strlen(c_val) + 1),
Glen Lee89758e12015-11-18 15:11:34 +0900517 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900518 goto _fail_;
519
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900520 c_val[0] = 192;
521 c_val[1] = 168;
522 c_val[2] = 1;
523 c_val[3] = 112;
Glen Lee79df6a42016-02-04 18:15:31 +0900524 if (!wilc_wlan_cfg_set(vif, 0, WID_1X_SERV_ADDR, c_val, 4, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900525 goto _fail_;
526
527 c_val[0] = 3;
Glen Lee79df6a42016-02-04 18:15:31 +0900528 if (!wilc_wlan_cfg_set(vif, 0, WID_LISTEN_INTERVAL, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900529 goto _fail_;
530
531 c_val[0] = 3;
Glen Lee79df6a42016-02-04 18:15:31 +0900532 if (!wilc_wlan_cfg_set(vif, 0, WID_DTIM_PERIOD, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900533 goto _fail_;
534
535 c_val[0] = NORMAL_ACK;
Glen Lee79df6a42016-02-04 18:15:31 +0900536 if (!wilc_wlan_cfg_set(vif, 0, WID_ACK_POLICY, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900537 goto _fail_;
538
539 c_val[0] = 0;
Glen Lee79df6a42016-02-04 18:15:31 +0900540 if (!wilc_wlan_cfg_set(vif, 0, WID_USER_CONTROL_ON_TX_POWER, c_val, 1,
Glen Lee89758e12015-11-18 15:11:34 +0900541 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900542 goto _fail_;
543
544 c_val[0] = 48;
Glen Lee79df6a42016-02-04 18:15:31 +0900545 if (!wilc_wlan_cfg_set(vif, 0, WID_TX_POWER_LEVEL_11A, c_val, 1, 0,
Glen Lee89758e12015-11-18 15:11:34 +0900546 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900547 goto _fail_;
548
549 c_val[0] = 28;
Glen Lee79df6a42016-02-04 18:15:31 +0900550 if (!wilc_wlan_cfg_set(vif, 0, WID_TX_POWER_LEVEL_11B, c_val, 1, 0,
Glen Lee89758e12015-11-18 15:11:34 +0900551 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900552 goto _fail_;
553
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900554 *((int *)c_val) = 100;
Glen Lee79df6a42016-02-04 18:15:31 +0900555 if (!wilc_wlan_cfg_set(vif, 0, WID_BEACON_INTERVAL, c_val, 2, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900556 goto _fail_;
557
558 c_val[0] = REKEY_DISABLE;
Glen Lee79df6a42016-02-04 18:15:31 +0900559 if (!wilc_wlan_cfg_set(vif, 0, WID_REKEY_POLICY, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900560 goto _fail_;
561
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900562 *((int *)c_val) = 84600;
Glen Lee79df6a42016-02-04 18:15:31 +0900563 if (!wilc_wlan_cfg_set(vif, 0, WID_REKEY_PERIOD, c_val, 4, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900564 goto _fail_;
565
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900566 *((int *)c_val) = 500;
Glen Lee79df6a42016-02-04 18:15:31 +0900567 if (!wilc_wlan_cfg_set(vif, 0, WID_REKEY_PACKET_COUNT, c_val, 4, 0,
Glen Lee89758e12015-11-18 15:11:34 +0900568 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900569 goto _fail_;
570
571 c_val[0] = 1;
Glen Lee79df6a42016-02-04 18:15:31 +0900572 if (!wilc_wlan_cfg_set(vif, 0, WID_SHORT_SLOT_ALLOWED, c_val, 1, 0,
Glen Lee89758e12015-11-18 15:11:34 +0900573 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900574 goto _fail_;
575
576 c_val[0] = G_SELF_CTS_PROT;
Glen Lee79df6a42016-02-04 18:15:31 +0900577 if (!wilc_wlan_cfg_set(vif, 0, WID_11N_ERP_PROT_TYPE, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900578 goto _fail_;
579
Leo Kim98b89842015-11-05 14:36:18 +0900580 c_val[0] = 1;
Glen Lee79df6a42016-02-04 18:15:31 +0900581 if (!wilc_wlan_cfg_set(vif, 0, WID_11N_ENABLE, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900582 goto _fail_;
583
584 c_val[0] = HT_MIXED_MODE;
Glen Lee79df6a42016-02-04 18:15:31 +0900585 if (!wilc_wlan_cfg_set(vif, 0, WID_11N_OPERATING_MODE, c_val, 1, 0,
Glen Lee89758e12015-11-18 15:11:34 +0900586 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900587 goto _fail_;
588
Leo Kim98b89842015-11-05 14:36:18 +0900589 c_val[0] = 1;
Glen Lee79df6a42016-02-04 18:15:31 +0900590 if (!wilc_wlan_cfg_set(vif, 0, WID_11N_TXOP_PROT_DISABLE, c_val, 1, 0,
Glen Lee89758e12015-11-18 15:11:34 +0900591 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900592 goto _fail_;
593
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900594 c_val[0] = DETECT_PROTECT_REPORT;
Glen Lee79df6a42016-02-04 18:15:31 +0900595 if (!wilc_wlan_cfg_set(vif, 0, WID_11N_OBSS_NONHT_DETECTION, c_val, 1,
Glen Lee89758e12015-11-18 15:11:34 +0900596 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900597 goto _fail_;
598
599 c_val[0] = RTS_CTS_NONHT_PROT;
Glen Lee79df6a42016-02-04 18:15:31 +0900600 if (!wilc_wlan_cfg_set(vif, 0, WID_11N_HT_PROT_TYPE, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900601 goto _fail_;
602
603 c_val[0] = 0;
Glen Lee79df6a42016-02-04 18:15:31 +0900604 if (!wilc_wlan_cfg_set(vif, 0, WID_11N_RIFS_PROT_ENABLE, c_val, 1, 0,
Glen Lee89758e12015-11-18 15:11:34 +0900605 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900606 goto _fail_;
607
608 c_val[0] = MIMO_MODE;
Glen Lee79df6a42016-02-04 18:15:31 +0900609 if (!wilc_wlan_cfg_set(vif, 0, WID_11N_SMPS_MODE, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900610 goto _fail_;
611
612 c_val[0] = 7;
Glen Lee79df6a42016-02-04 18:15:31 +0900613 if (!wilc_wlan_cfg_set(vif, 0, WID_11N_CURRENT_TX_MCS, c_val, 1, 0,
Glen Lee89758e12015-11-18 15:11:34 +0900614 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900615 goto _fail_;
616
Leo Kim98b89842015-11-05 14:36:18 +0900617 c_val[0] = 1;
Glen Lee79df6a42016-02-04 18:15:31 +0900618 if (!wilc_wlan_cfg_set(vif, 0, WID_11N_IMMEDIATE_BA_ENABLED, c_val, 1,
Glen Lee89758e12015-11-18 15:11:34 +0900619 1, 1))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900620 goto _fail_;
621
622 return 0;
623
624_fail_:
625 return -1;
626}
627
Glen Lee53dc0cf2015-10-20 17:13:57 +0900628void wilc1000_wlan_deinit(struct net_device *dev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900629{
Glen Leea4cac482015-12-21 14:18:36 +0900630 struct wilc_vif *vif;
Glen Lee53dc0cf2015-10-20 17:13:57 +0900631 struct wilc *wl;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900632
Glen Leea4cac482015-12-21 14:18:36 +0900633 vif = netdev_priv(dev);
634 wl = vif->wilc;
Glen Lee53dc0cf2015-10-20 17:13:57 +0900635
636 if (!wl) {
637 netdev_err(dev, "wl is NULL\n");
638 return;
639 }
640
641 if (wl->initialized) {
642 netdev_info(dev, "Deinitializing wilc1000...\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900643
Arnd Bergmann5547c1f2015-11-16 15:05:06 +0100644 if (!wl->dev_irq_num &&
Glen Leeaf9ae092015-12-21 14:18:09 +0900645 wl->hif_func->disable_interrupt) {
Arnd Bergmannc4d139c2015-11-16 15:05:04 +0100646 mutex_lock(&wl->hif_cs);
Glen Leeaf9ae092015-12-21 14:18:09 +0900647 wl->hif_func->disable_interrupt(wl);
Arnd Bergmannc4d139c2015-11-16 15:05:04 +0100648 mutex_unlock(&wl->hif_cs);
649 }
Leo Kim3a147c02015-11-05 14:36:10 +0900650 if (&wl->txq_event)
Binoy Jayanb27a6d52016-06-15 11:00:34 +0530651 wait_for_completion(&wl->txq_event);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900652
Glen Lee32dd51b2015-10-27 18:27:52 +0900653 wlan_deinitialize_threads(dev);
Glen Leeec5cc752015-10-27 18:27:39 +0900654 deinit_irq(dev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900655
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100656 wilc_wlan_stop(wl);
Glen Lee2de7cbe2015-10-27 18:27:54 +0900657 wilc_wlan_cleanup(dev);
Glen Lee7c67c052015-10-27 18:27:50 +0900658 wlan_deinit_locks(dev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900659
Glen Lee53dc0cf2015-10-20 17:13:57 +0900660 wl->initialized = false;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900661
Leo Kim5ac24422016-02-04 18:15:37 +0900662 netdev_dbg(dev, "wilc1000 deinitialization Done\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900663 } else {
Leo Kim5ac24422016-02-04 18:15:37 +0900664 netdev_dbg(dev, "wilc1000 is not initialized\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900665 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900666}
667
Arnd Bergmann1608c402015-11-16 15:04:53 +0100668static int wlan_init_locks(struct net_device *dev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900669{
Glen Leea4cac482015-12-21 14:18:36 +0900670 struct wilc_vif *vif;
Glen Lee38afb392015-10-20 17:13:53 +0900671 struct wilc *wl;
672
Glen Leea4cac482015-12-21 14:18:36 +0900673 vif = netdev_priv(dev);
674 wl = vif->wilc;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900675
Glen Lee38afb392015-10-20 17:13:53 +0900676 mutex_init(&wl->hif_cs);
677 mutex_init(&wl->rxq_cs);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900678
Glen Lee38afb392015-10-20 17:13:53 +0900679 spin_lock_init(&wl->txq_spinlock);
Binoy Jayan334bed02016-06-15 11:00:35 +0530680 mutex_init(&wl->txq_add_to_head_cs);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900681
Binoy Jayanb27a6d52016-06-15 11:00:34 +0530682 init_completion(&wl->txq_event);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900683
Binoy Jayanfa659692016-06-15 11:00:36 +0530684 init_completion(&wl->cfg_event);
Binoy Jayan04247e72016-06-15 11:00:37 +0530685 init_completion(&wl->sync_event);
Leo Kim11a54b32016-04-01 17:44:15 +0900686 init_completion(&wl->txq_thread_started);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900687
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900688 return 0;
689}
690
Glen Lee7c67c052015-10-27 18:27:50 +0900691static int wlan_deinit_locks(struct net_device *dev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900692{
Glen Leea4cac482015-12-21 14:18:36 +0900693 struct wilc_vif *vif;
Glen Lee7c67c052015-10-27 18:27:50 +0900694 struct wilc *wilc;
695
Glen Leea4cac482015-12-21 14:18:36 +0900696 vif = netdev_priv(dev);
697 wilc = vif->wilc;
Glen Lee7c67c052015-10-27 18:27:50 +0900698
Leo Kim3a147c02015-11-05 14:36:10 +0900699 if (&wilc->hif_cs)
Glen Lee7c67c052015-10-27 18:27:50 +0900700 mutex_destroy(&wilc->hif_cs);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900701
Leo Kim3a147c02015-11-05 14:36:10 +0900702 if (&wilc->rxq_cs)
Glen Lee7c67c052015-10-27 18:27:50 +0900703 mutex_destroy(&wilc->rxq_cs);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900704
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900705 return 0;
706}
Leo Kima40b22c2015-11-05 14:36:32 +0900707
Arnd Bergmann1608c402015-11-16 15:04:53 +0100708static int wlan_initialize_threads(struct net_device *dev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900709{
Glen Leea4cac482015-12-21 14:18:36 +0900710 struct wilc_vif *vif;
Glen Lee75a94662015-10-27 18:27:45 +0900711 struct wilc *wilc;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900712
Glen Leea4cac482015-12-21 14:18:36 +0900713 vif = netdev_priv(dev);
714 wilc = vif->wilc;
Glen Lee75a94662015-10-27 18:27:45 +0900715
Glen Lee88687582015-10-27 18:27:46 +0900716 wilc->txq_thread = kthread_run(linux_wlan_txq_task, (void *)dev,
Glen Lee75a94662015-10-27 18:27:45 +0900717 "K_TXQ_TASK");
Wei Yongjunb3e69162016-06-17 17:34:17 +0000718 if (IS_ERR(wilc->txq_thread)) {
Leo Kim5ac24422016-02-04 18:15:37 +0900719 netdev_err(dev, "couldn't create TXQ thread\n");
Leo Kim6bc72c52015-11-05 14:36:33 +0900720 wilc->close = 0;
Wei Yongjunb3e69162016-06-17 17:34:17 +0000721 return PTR_ERR(wilc->txq_thread);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900722 }
Leo Kim11a54b32016-04-01 17:44:15 +0900723 wait_for_completion(&wilc->txq_thread_started);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900724
725 return 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900726}
727
Glen Lee32dd51b2015-10-27 18:27:52 +0900728static void wlan_deinitialize_threads(struct net_device *dev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900729{
Glen Leea4cac482015-12-21 14:18:36 +0900730 struct wilc_vif *vif;
Glen Lee32dd51b2015-10-27 18:27:52 +0900731 struct wilc *wl;
Leo Kimfa8b23c2016-02-04 18:15:33 +0900732
Glen Leea4cac482015-12-21 14:18:36 +0900733 vif = netdev_priv(dev);
734 wl = vif->wilc;
Glen Lee32dd51b2015-10-27 18:27:52 +0900735
736 wl->close = 1;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900737
Leo Kim3a147c02015-11-05 14:36:10 +0900738 if (&wl->txq_event)
Binoy Jayanb27a6d52016-06-15 11:00:34 +0530739 complete(&wl->txq_event);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900740
Leo Kim3a147c02015-11-05 14:36:10 +0900741 if (wl->txq_thread) {
Glen Lee32dd51b2015-10-27 18:27:52 +0900742 kthread_stop(wl->txq_thread);
743 wl->txq_thread = NULL;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900744 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900745}
746
Glen Leea4cac482015-12-21 14:18:36 +0900747int wilc1000_wlan_init(struct net_device *dev, struct wilc_vif *vif)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900748{
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900749 int ret = 0;
Glen Leea4cac482015-12-21 14:18:36 +0900750 struct wilc *wl = vif->wilc;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900751
Glen Lee0fa683b2015-10-20 17:13:52 +0900752 if (!wl->initialized) {
753 wl->mac_status = WILC_MAC_STATUS_INIT;
754 wl->close = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900755
Glen Lee38afb392015-10-20 17:13:53 +0900756 wlan_init_locks(dev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900757
Arnd Bergmann4bd7baf2015-11-16 15:04:59 +0100758 ret = wilc_wlan_init(dev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900759 if (ret < 0) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900760 ret = -EIO;
761 goto _fail_locks_;
762 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900763
Arnd Bergmannc4d139c2015-11-16 15:05:04 +0100764 if (wl->gpio >= 0 && init_irq(dev)) {
Tony Chob46d6882015-10-20 14:26:54 +0900765 ret = -EIO;
766 goto _fail_locks_;
767 }
Tony Chob46d6882015-10-20 14:26:54 +0900768
Glen Lee75a94662015-10-27 18:27:45 +0900769 ret = wlan_initialize_threads(dev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900770 if (ret < 0) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900771 ret = -EIO;
772 goto _fail_wilc_wlan_;
773 }
774
Arnd Bergmann5547c1f2015-11-16 15:05:06 +0100775 if (!wl->dev_irq_num &&
Glen Leeaf9ae092015-12-21 14:18:09 +0900776 wl->hif_func->enable_interrupt &&
777 wl->hif_func->enable_interrupt(wl)) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900778 ret = -EIO;
779 goto _fail_irq_init_;
780 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900781
Arnd Bergmann0e1af732015-11-16 15:04:54 +0100782 if (wilc_wlan_get_firmware(dev)) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900783 ret = -EIO;
784 goto _fail_irq_enable_;
785 }
786
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100787 ret = wilc1000_firmware_download(dev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900788 if (ret < 0) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900789 ret = -EIO;
790 goto _fail_irq_enable_;
791 }
792
Glen Lee9bf3d722015-10-29 12:18:46 +0900793 ret = linux_wlan_start_firmware(dev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900794 if (ret < 0) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900795 ret = -EIO;
796 goto _fail_irq_enable_;
797 }
798
Glen Lee79df6a42016-02-04 18:15:31 +0900799 if (wilc_wlan_cfg_get(vif, 1, WID_FIRMWARE_VERSION, 1, 0)) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900800 int size;
Leo Kim5ac24422016-02-04 18:15:37 +0900801 char firmware_ver[20];
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900802
Leo Kim5ac24422016-02-04 18:15:37 +0900803 size = wilc_wlan_cfg_get_val(WID_FIRMWARE_VERSION,
804 firmware_ver,
805 sizeof(firmware_ver));
806 firmware_ver[size] = '\0';
807 netdev_dbg(dev, "Firmware Ver = %s\n", firmware_ver);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900808 }
Glen Leeb8f6ca02016-01-25 16:35:12 +0900809 ret = linux_wlan_init_test_config(dev, vif);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900810
811 if (ret < 0) {
Leo Kim5ac24422016-02-04 18:15:37 +0900812 netdev_err(dev, "Failed to configure firmware\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900813 ret = -EIO;
814 goto _fail_fw_start_;
815 }
816
Glen Lee0fa683b2015-10-20 17:13:52 +0900817 wl->initialized = true;
Leo Kim98b89842015-11-05 14:36:18 +0900818 return 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900819
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900820_fail_fw_start_:
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100821 wilc_wlan_stop(wl);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900822
823_fail_irq_enable_:
Arnd Bergmann5547c1f2015-11-16 15:05:06 +0100824 if (!wl->dev_irq_num &&
Glen Leeaf9ae092015-12-21 14:18:09 +0900825 wl->hif_func->disable_interrupt)
826 wl->hif_func->disable_interrupt(wl);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900827_fail_irq_init_:
Arnd Bergmannc4d139c2015-11-16 15:05:04 +0100828 if (wl->dev_irq_num)
829 deinit_irq(dev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900830
Glen Lee32dd51b2015-10-27 18:27:52 +0900831 wlan_deinitialize_threads(dev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900832_fail_wilc_wlan_:
Glen Lee2de7cbe2015-10-27 18:27:54 +0900833 wilc_wlan_cleanup(dev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900834_fail_locks_:
Glen Lee7c67c052015-10-27 18:27:50 +0900835 wlan_deinit_locks(dev);
Leo Kim5ac24422016-02-04 18:15:37 +0900836 netdev_err(dev, "WLAN Iinitialization FAILED\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900837 } else {
Leo Kim5ac24422016-02-04 18:15:37 +0900838 netdev_dbg(dev, "wilc1000 already initialized\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900839 }
840 return ret;
841}
842
Arnd Bergmann1608c402015-11-16 15:04:53 +0100843static int mac_init_fn(struct net_device *ndev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900844{
Leo Kim98b89842015-11-05 14:36:18 +0900845 netif_start_queue(ndev);
846 netif_stop_queue(ndev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900847
848 return 0;
849}
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900850
Arnd Bergmann0e1af732015-11-16 15:04:54 +0100851int wilc_mac_open(struct net_device *ndev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900852{
Glen Leea4cac482015-12-21 14:18:36 +0900853 struct wilc_vif *vif;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900854
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900855 unsigned char mac_add[ETH_ALEN] = {0};
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900856 int ret = 0;
857 int i = 0;
Glen Leef3c13662015-10-20 17:13:54 +0900858 struct wilc *wl;
859
Glen Leea4cac482015-12-21 14:18:36 +0900860 vif = netdev_priv(ndev);
861 wl = vif->wilc;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900862
Leo Kim40095ad2016-01-27 11:50:27 +0900863 if (!wl || !wl->dev) {
Leo Kim90fd4cc2016-03-15 18:48:12 +0900864 netdev_err(ndev, "device not ready\n");
Chandra S Gorentla7d056522015-09-15 18:09:51 +0530865 return -ENODEV;
866 }
Arnd Bergmannb03314e2015-11-16 15:05:01 +0100867
Leo Kim5ac24422016-02-04 18:15:37 +0900868 netdev_dbg(ndev, "MAC OPEN[%p]\n", ndev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900869
Chaehyun Limdd4b6a82015-09-20 15:51:25 +0900870 ret = wilc_init_host_int(ndev);
Leo Kim14086032016-02-04 18:15:36 +0900871 if (ret < 0)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900872 return ret;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900873
Glen Leea4cac482015-12-21 14:18:36 +0900874 ret = wilc1000_wlan_init(ndev, vif);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900875 if (ret < 0) {
Chaehyun Lima9a16822015-09-20 15:51:24 +0900876 wilc_deinit_host_int(ndev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900877 return ret;
878 }
879
Glen Leef3c13662015-10-20 17:13:54 +0900880 for (i = 0; i < wl->vif_num; i++) {
Glen Lee1f435d22015-12-21 14:18:37 +0900881 if (ndev == wl->vif[i]->ndev) {
Glen Leeb3306862016-02-04 18:15:18 +0900882 if (vif->iftype == AP_MODE) {
883 wilc_set_wfi_drv_handler(vif,
884 wilc_get_vif_idx(vif),
885 0);
Leo Kimba750472016-03-15 18:48:11 +0900886 } else if (!wilc_wlan_get_num_conn_ifcs(wl)) {
Glen Leeb3306862016-02-04 18:15:18 +0900887 wilc_set_wfi_drv_handler(vif,
888 wilc_get_vif_idx(vif),
Leo Kimba750472016-03-15 18:48:11 +0900889 wl->open_ifcs);
Glen Leeb3306862016-02-04 18:15:18 +0900890 } else {
Leo Kimba750472016-03-15 18:48:11 +0900891 if (memcmp(wl->vif[i ^ 1]->bssid,
892 wl->vif[i ^ 1]->src_addr, 6))
Glen Leeb3306862016-02-04 18:15:18 +0900893 wilc_set_wfi_drv_handler(vif,
894 wilc_get_vif_idx(vif),
895 0);
896 else
897 wilc_set_wfi_drv_handler(vif,
898 wilc_get_vif_idx(vif),
899 1);
900 }
Glen Leee32737e2016-01-25 16:35:14 +0900901 wilc_set_operation_mode(vif, vif->iftype);
Glen Lee32cee992016-02-04 18:15:29 +0900902
903 wilc_get_mac_address(vif, mac_add);
904 netdev_dbg(ndev, "Mac address: %pM\n", mac_add);
905 memcpy(wl->vif[i]->src_addr, mac_add, ETH_ALEN);
906
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900907 break;
908 }
909 }
910
Glen Lee1f435d22015-12-21 14:18:37 +0900911 memcpy(ndev->dev_addr, wl->vif[i]->src_addr, ETH_ALEN);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900912
913 if (!is_valid_ether_addr(ndev->dev_addr)) {
Leo Kim5ac24422016-02-04 18:15:37 +0900914 netdev_err(ndev, "Wrong MAC address\n");
Leo Kim339d2442015-11-05 14:36:34 +0900915 wilc_deinit_host_int(ndev);
916 wilc1000_wlan_deinit(ndev);
917 return -EINVAL;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900918 }
919
Glen Lee1006b5c2015-12-21 14:18:38 +0900920 wilc_mgmt_frame_register(vif->ndev->ieee80211_ptr->wiphy,
921 vif->ndev->ieee80211_ptr,
Leo Kim340a84f2016-03-25 21:16:50 +0900922 vif->frame_reg[0].type,
Leo Kim89febb22016-03-25 21:16:49 +0900923 vif->frame_reg[0].reg);
Glen Lee1006b5c2015-12-21 14:18:38 +0900924 wilc_mgmt_frame_register(vif->ndev->ieee80211_ptr->wiphy,
925 vif->ndev->ieee80211_ptr,
Leo Kim340a84f2016-03-25 21:16:50 +0900926 vif->frame_reg[1].type,
Leo Kim89febb22016-03-25 21:16:49 +0900927 vif->frame_reg[1].reg);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900928 netif_wake_queue(ndev);
Glen Leef3c13662015-10-20 17:13:54 +0900929 wl->open_ifcs++;
Glen Leea4cac482015-12-21 14:18:36 +0900930 vif->mac_opened = 1;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900931 return 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900932}
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900933
Arnd Bergmann1608c402015-11-16 15:04:53 +0100934static struct net_device_stats *mac_stats(struct net_device *dev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900935{
Leo Kim40095ad2016-01-27 11:50:27 +0900936 struct wilc_vif *vif = netdev_priv(dev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900937
Glen Leea4cac482015-12-21 14:18:36 +0900938 return &vif->netstats;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900939}
940
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900941static void wilc_set_multicast_list(struct net_device *dev)
942{
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900943 struct netdev_hw_addr *ha;
Glen Leecf601062015-12-21 14:18:39 +0900944 struct wilc_vif *vif;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900945 int i = 0;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900946
Glen Leecf601062015-12-21 14:18:39 +0900947 vif = netdev_priv(dev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900948
Leo Kim14086032016-02-04 18:15:36 +0900949 if (dev->flags & IFF_PROMISC)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900950 return;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900951
Leo Kim582f8a22015-11-05 14:36:21 +0900952 if ((dev->flags & IFF_ALLMULTI) ||
953 (dev->mc.count) > WILC_MULTICAST_TABLE_SIZE) {
Glen Leefbf53792015-12-21 14:18:40 +0900954 wilc_setup_multicast_filter(vif, false, 0);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900955 return;
956 }
957
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900958 if ((dev->mc.count) == 0) {
Glen Leefbf53792015-12-21 14:18:40 +0900959 wilc_setup_multicast_filter(vif, true, 0);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900960 return;
961 }
962
Leo Kimc8537e62015-11-06 11:12:24 +0900963 netdev_for_each_mc_addr(ha, dev) {
Arnd Bergmann0e1af732015-11-16 15:04:54 +0100964 memcpy(wilc_multicast_mac_addr_list[i], ha->addr, ETH_ALEN);
Leo Kim5ac24422016-02-04 18:15:37 +0900965 netdev_dbg(dev, "Entry[%d]: %x:%x:%x:%x:%x:%x\n", i,
966 wilc_multicast_mac_addr_list[i][0],
967 wilc_multicast_mac_addr_list[i][1],
968 wilc_multicast_mac_addr_list[i][2],
969 wilc_multicast_mac_addr_list[i][3],
970 wilc_multicast_mac_addr_list[i][4],
971 wilc_multicast_mac_addr_list[i][5]);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900972 i++;
973 }
974
Glen Leefbf53792015-12-21 14:18:40 +0900975 wilc_setup_multicast_filter(vif, true, (dev->mc.count));
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900976}
977
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900978static void linux_wlan_tx_complete(void *priv, int status)
979{
Alison Schofieldd5c89442016-02-12 22:53:13 -0800980 struct tx_complete_data *pv_data = priv;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900981
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900982 dev_kfree_skb(pv_data->skb);
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -0700983 kfree(pv_data);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900984}
985
Arnd Bergmann0e1af732015-11-16 15:04:54 +0100986int wilc_mac_xmit(struct sk_buff *skb, struct net_device *ndev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900987{
Glen Leea4cac482015-12-21 14:18:36 +0900988 struct wilc_vif *vif;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900989 struct tx_complete_data *tx_data = NULL;
Leo Kim44ec3b72015-11-05 14:36:38 +0900990 int queue_count;
Leo Kimfd8f0362015-11-05 14:36:39 +0900991 char *udp_buf;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900992 struct iphdr *ih;
993 struct ethhdr *eth_h;
Glen Leeb7495be2015-10-27 18:28:01 +0900994 struct wilc *wilc;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900995
Glen Leea4cac482015-12-21 14:18:36 +0900996 vif = netdev_priv(ndev);
997 wilc = vif->wilc;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900998
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900999 if (skb->dev != ndev) {
Leo Kim5ac24422016-02-04 18:15:37 +09001000 netdev_err(ndev, "Packet not destined to this device\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001001 return 0;
1002 }
1003
Leo Kimb38e9032015-11-06 11:12:23 +09001004 tx_data = kmalloc(sizeof(*tx_data), GFP_ATOMIC);
Leo Kim3a147c02015-11-05 14:36:10 +09001005 if (!tx_data) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001006 dev_kfree_skb(skb);
1007 netif_wake_queue(ndev);
1008 return 0;
1009 }
1010
1011 tx_data->buff = skb->data;
1012 tx_data->size = skb->len;
1013 tx_data->skb = skb;
1014
1015 eth_h = (struct ethhdr *)(skb->data);
Kim, Leofc4b95d2015-07-28 17:47:37 +09001016 if (eth_h->h_proto == 0x8e88)
Leo Kim5ac24422016-02-04 18:15:37 +09001017 netdev_dbg(ndev, "EAPOL transmitted\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001018
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001019 ih = (struct iphdr *)(skb->data + sizeof(struct ethhdr));
1020
Leo Kimfd8f0362015-11-05 14:36:39 +09001021 udp_buf = (char *)ih + sizeof(struct iphdr);
1022 if ((udp_buf[1] == 68 && udp_buf[3] == 67) ||
1023 (udp_buf[1] == 67 && udp_buf[3] == 68))
Leo Kim5ac24422016-02-04 18:15:37 +09001024 netdev_dbg(ndev, "DHCP Message transmitted, type:%x %x %x\n",
1025 udp_buf[248], udp_buf[249], udp_buf[250]);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001026
Glen Leea4cac482015-12-21 14:18:36 +09001027 vif->netstats.tx_packets++;
1028 vif->netstats.tx_bytes += tx_data->size;
Leo Kim67501402016-02-04 18:15:39 +09001029 tx_data->bssid = wilc->vif[vif->idx]->bssid;
Leo Kim44ec3b72015-11-05 14:36:38 +09001030 queue_count = wilc_wlan_txq_add_net_pkt(ndev, (void *)tx_data,
1031 tx_data->buff, tx_data->size,
1032 linux_wlan_tx_complete);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001033
Leo Kim44ec3b72015-11-05 14:36:38 +09001034 if (queue_count > FLOW_CONTROL_UPPER_THRESHOLD) {
Glen Lee1f435d22015-12-21 14:18:37 +09001035 netif_stop_queue(wilc->vif[0]->ndev);
1036 netif_stop_queue(wilc->vif[1]->ndev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001037 }
1038
1039 return 0;
1040}
1041
Arnd Bergmann0e1af732015-11-16 15:04:54 +01001042int wilc_mac_close(struct net_device *ndev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001043{
Chaehyun Lim27268872015-09-15 14:06:13 +09001044 struct wilc_priv *priv;
Glen Leea4cac482015-12-21 14:18:36 +09001045 struct wilc_vif *vif;
Leo Kim2db2c8a2015-11-05 14:36:15 +09001046 struct host_if_drv *hif_drv;
Glen Leeca64ad62015-10-20 17:13:55 +09001047 struct wilc *wl;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001048
Glen Leea4cac482015-12-21 14:18:36 +09001049 vif = netdev_priv(ndev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001050
Glen Lee1006b5c2015-12-21 14:18:38 +09001051 if (!vif || !vif->ndev || !vif->ndev->ieee80211_ptr ||
Leo Kim14086032016-02-04 18:15:36 +09001052 !vif->ndev->ieee80211_ptr->wiphy)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001053 return 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001054
Glen Lee1006b5c2015-12-21 14:18:38 +09001055 priv = wiphy_priv(vif->ndev->ieee80211_ptr->wiphy);
Glen Leea4cac482015-12-21 14:18:36 +09001056 wl = vif->wilc;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001057
Leo Kim14086032016-02-04 18:15:36 +09001058 if (!priv)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001059 return 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001060
Leo Kim48b28df2016-02-04 18:15:32 +09001061 hif_drv = (struct host_if_drv *)priv->hif_drv;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001062
Leo Kim5ac24422016-02-04 18:15:37 +09001063 netdev_dbg(ndev, "Mac close\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001064
Leo Kim14086032016-02-04 18:15:36 +09001065 if (!wl)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001066 return 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001067
Leo Kim14086032016-02-04 18:15:36 +09001068 if (!hif_drv)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001069 return 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001070
Leo Kim14086032016-02-04 18:15:36 +09001071 if ((wl->open_ifcs) > 0)
Glen Leeca64ad62015-10-20 17:13:55 +09001072 wl->open_ifcs--;
Leo Kim14086032016-02-04 18:15:36 +09001073 else
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001074 return 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001075
Glen Lee1006b5c2015-12-21 14:18:38 +09001076 if (vif->ndev) {
1077 netif_stop_queue(vif->ndev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001078
Glen Lee1006b5c2015-12-21 14:18:38 +09001079 wilc_deinit_host_int(vif->ndev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001080 }
1081
Glen Leeca64ad62015-10-20 17:13:55 +09001082 if (wl->open_ifcs == 0) {
Leo Kim5ac24422016-02-04 18:15:37 +09001083 netdev_dbg(ndev, "Deinitializing wilc1000\n");
Glen Leeca64ad62015-10-20 17:13:55 +09001084 wl->close = 1;
Glen Lee53dc0cf2015-10-20 17:13:57 +09001085 wilc1000_wlan_deinit(ndev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001086 WILC_WFI_deinit_mon_interface();
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001087 }
1088
Glen Leea4cac482015-12-21 14:18:36 +09001089 vif->mac_opened = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001090
1091 return 0;
1092}
1093
Arnd Bergmann1608c402015-11-16 15:04:53 +01001094static int mac_ioctl(struct net_device *ndev, struct ifreq *req, int cmd)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001095{
Greg Kroah-Hartman63d03e42015-06-02 14:16:04 +09001096 u8 *buff = NULL;
Chaehyun Limca356ad2015-06-11 14:35:57 +09001097 s8 rssi;
Chaehyun Lim4e4467f2015-06-11 14:35:55 +09001098 u32 size = 0, length = 0;
Glen Leea4cac482015-12-21 14:18:36 +09001099 struct wilc_vif *vif;
Leo Kim9457b052015-11-05 14:36:37 +09001100 s32 ret = 0;
Glen Lee07320b62015-10-27 18:27:53 +09001101 struct wilc *wilc;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001102
Glen Leea4cac482015-12-21 14:18:36 +09001103 vif = netdev_priv(ndev);
1104 wilc = vif->wilc;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001105
Glen Lee07320b62015-10-27 18:27:53 +09001106 if (!wilc->initialized)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001107 return 0;
1108
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001109 switch (cmd) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001110 case SIOCSIWPRIV:
1111 {
Leo Kimf05ab242016-01-27 11:50:26 +09001112 struct iwreq *wrq = (struct iwreq *)req;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001113
1114 size = wrq->u.data.length;
1115
1116 if (size && wrq->u.data.pointer) {
Leo Kim582f8a22015-11-05 14:36:21 +09001117 buff = memdup_user(wrq->u.data.pointer,
1118 wrq->u.data.length);
Sudip Mukherjee360e27a2015-09-04 15:34:15 +05301119 if (IS_ERR(buff))
1120 return PTR_ERR(buff);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001121
1122 if (strncasecmp(buff, "RSSI", length) == 0) {
Glen Leefbf53792015-12-21 14:18:40 +09001123 ret = wilc_get_rssi(vif, &rssi);
Leo Kim5ac24422016-02-04 18:15:37 +09001124 netdev_info(ndev, "RSSI :%d\n", rssi);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001125
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001126 rssi += 5;
1127
1128 snprintf(buff, size, "rssi %d", rssi);
1129
1130 if (copy_to_user(wrq->u.data.pointer, buff, size)) {
Leo Kim5ac24422016-02-04 18:15:37 +09001131 netdev_err(ndev, "failed to copy\n");
Leo Kim9457b052015-11-05 14:36:37 +09001132 ret = -EFAULT;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001133 goto done;
1134 }
1135 }
1136 }
1137 }
1138 break;
1139
1140 default:
1141 {
Leo Kim5ac24422016-02-04 18:15:37 +09001142 netdev_info(ndev, "Command - %d - has been received\n", cmd);
Leo Kim9457b052015-11-05 14:36:37 +09001143 ret = -EOPNOTSUPP;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001144 goto done;
1145 }
1146 }
1147
1148done:
1149
Shraddha Barke642ac6c2015-08-10 13:30:33 +05301150 kfree(buff);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001151
Leo Kim9457b052015-11-05 14:36:37 +09001152 return ret;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001153}
1154
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001155void wilc_frmw_to_linux(struct wilc *wilc, u8 *buff, u32 size, u32 pkt_offset)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001156{
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001157 unsigned int frame_len = 0;
1158 int stats;
1159 unsigned char *buff_to_send = NULL;
1160 struct sk_buff *skb;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001161 struct net_device *wilc_netdev;
Glen Leea4cac482015-12-21 14:18:36 +09001162 struct wilc_vif *vif;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001163
Leo Kim0953a2e2016-01-27 11:50:25 +09001164 if (!wilc)
1165 return;
1166
Leo Kim7e725b42015-11-05 14:36:24 +09001167 wilc_netdev = get_if_handler(wilc, buff);
Leo Kim3a147c02015-11-05 14:36:10 +09001168 if (!wilc_netdev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001169 return;
1170
1171 buff += pkt_offset;
Glen Leea4cac482015-12-21 14:18:36 +09001172 vif = netdev_priv(wilc_netdev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001173
1174 if (size > 0) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001175 frame_len = size;
1176 buff_to_send = buff;
1177
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001178 skb = dev_alloc_skb(frame_len);
Leo Kim14086032016-02-04 18:15:36 +09001179 if (!skb)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001180 return;
Leo Kim14086032016-02-04 18:15:36 +09001181
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001182 skb->dev = wilc_netdev;
1183
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001184 memcpy(skb_put(skb, frame_len), buff_to_send, frame_len);
1185
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001186 skb->protocol = eth_type_trans(skb, wilc_netdev);
Glen Leea4cac482015-12-21 14:18:36 +09001187 vif->netstats.rx_packets++;
1188 vif->netstats.rx_bytes += frame_len;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001189 skb->ip_summed = CHECKSUM_UNNECESSARY;
1190 stats = netif_rx(skb);
Leo Kim5ac24422016-02-04 18:15:37 +09001191 netdev_dbg(wilc_netdev, "netif_rx ret value is: %d\n", stats);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001192 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001193}
1194
Glen Lee11f4b2e2015-10-27 18:27:51 +09001195void WILC_WFI_mgmt_rx(struct wilc *wilc, u8 *buff, u32 size)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001196{
1197 int i = 0;
Glen Leea4cac482015-12-21 14:18:36 +09001198 struct wilc_vif *vif;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001199
Glen Lee11f4b2e2015-10-27 18:27:51 +09001200 for (i = 0; i < wilc->vif_num; i++) {
Glen Lee1f435d22015-12-21 14:18:37 +09001201 vif = netdev_priv(wilc->vif[i]->ndev);
Glen Leea4cac482015-12-21 14:18:36 +09001202 if (vif->monitor_flag) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001203 WILC_WFI_monitor_rx(buff, size);
1204 return;
1205 }
1206 }
1207
Glen Lee1f435d22015-12-21 14:18:37 +09001208 vif = netdev_priv(wilc->vif[1]->ndev);
Leo Kim340a84f2016-03-25 21:16:50 +09001209 if ((buff[0] == vif->frame_reg[0].type && vif->frame_reg[0].reg) ||
1210 (buff[0] == vif->frame_reg[1].type && vif->frame_reg[1].reg))
Glen Lee1f435d22015-12-21 14:18:37 +09001211 WILC_WFI_p2p_rx(wilc->vif[1]->ndev, buff, size);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001212}
1213
Arnd Bergmann857c7b02015-11-16 15:05:00 +01001214void wilc_netdev_cleanup(struct wilc *wilc)
Tony Cho4875c492015-10-20 14:26:52 +09001215{
1216 int i = 0;
Glen Leea4cac482015-12-21 14:18:36 +09001217 struct wilc_vif *vif[NUM_CONCURRENT_IFC];
Tony Cho4875c492015-10-20 14:26:52 +09001218
Glen Lee1f435d22015-12-21 14:18:37 +09001219 if (wilc && (wilc->vif[0]->ndev || wilc->vif[1]->ndev)) {
Tony Cho4875c492015-10-20 14:26:52 +09001220 unregister_inetaddr_notifier(&g_dev_notifier);
1221
1222 for (i = 0; i < NUM_CONCURRENT_IFC; i++)
Glen Lee1f435d22015-12-21 14:18:37 +09001223 vif[i] = netdev_priv(wilc->vif[i]->ndev);
Tony Cho4875c492015-10-20 14:26:52 +09001224 }
1225
Leo Kim3f626cf2016-04-01 17:44:17 +09001226 if (wilc && wilc->firmware) {
Glen Lee90b984c2015-10-29 12:18:50 +09001227 release_firmware(wilc->firmware);
Leo Kim3f626cf2016-04-01 17:44:17 +09001228 wilc->firmware = NULL;
1229 }
Tony Cho4875c492015-10-20 14:26:52 +09001230
Glen Lee1f435d22015-12-21 14:18:37 +09001231 if (wilc && (wilc->vif[0]->ndev || wilc->vif[1]->ndev)) {
Tony Cho4875c492015-10-20 14:26:52 +09001232 for (i = 0; i < NUM_CONCURRENT_IFC; i++)
Glen Lee1f435d22015-12-21 14:18:37 +09001233 if (wilc->vif[i]->ndev)
Glen Leea4cac482015-12-21 14:18:36 +09001234 if (vif[i]->mac_opened)
Glen Lee1f435d22015-12-21 14:18:37 +09001235 wilc_mac_close(wilc->vif[i]->ndev);
Tony Cho4875c492015-10-20 14:26:52 +09001236
1237 for (i = 0; i < NUM_CONCURRENT_IFC; i++) {
Glen Lee1f435d22015-12-21 14:18:37 +09001238 unregister_netdev(wilc->vif[i]->ndev);
1239 wilc_free_wiphy(wilc->vif[i]->ndev);
1240 free_netdev(wilc->vif[i]->ndev);
Tony Cho4875c492015-10-20 14:26:52 +09001241 }
1242 }
1243
Glen Lee90b984c2015-10-29 12:18:50 +09001244 kfree(wilc);
Tony Cho4875c492015-10-20 14:26:52 +09001245}
Arnd Bergmann750ffe92015-11-16 15:05:08 +01001246EXPORT_SYMBOL_GPL(wilc_netdev_cleanup);
Tony Cho4875c492015-10-20 14:26:52 +09001247
Arnd Bergmann7d37a4a2015-11-16 15:05:05 +01001248int wilc_netdev_init(struct wilc **wilc, struct device *dev, int io_type,
1249 int gpio, const struct wilc_hif_func *ops)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001250{
Amitoj Kaur Chawlafe747f02016-02-17 20:41:03 +05301251 int i, ret;
Glen Leea4cac482015-12-21 14:18:36 +09001252 struct wilc_vif *vif;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001253 struct net_device *ndev;
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001254 struct wilc *wl;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001255
Glen Lee825b9662015-11-18 15:11:37 +09001256 wl = kzalloc(sizeof(*wl), GFP_KERNEL);
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001257 if (!wl)
Chaehyun Limac61ef82015-09-08 00:36:36 +09001258 return -ENOMEM;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001259
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001260 *wilc = wl;
1261 wl->io_type = io_type;
1262 wl->gpio = gpio;
Glen Leeaf9ae092015-12-21 14:18:09 +09001263 wl->hif_func = ops;
Arnd Bergmannc4d139c2015-11-16 15:05:04 +01001264
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001265 register_inetaddr_notifier(&g_dev_notifier);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001266
1267 for (i = 0; i < NUM_CONCURRENT_IFC; i++) {
Glen Leea4cac482015-12-21 14:18:36 +09001268 ndev = alloc_etherdev(sizeof(struct wilc_vif));
Leo Kim14086032016-02-04 18:15:36 +09001269 if (!ndev)
Amitoj Kaur Chawlafe747f02016-02-17 20:41:03 +05301270 return -ENOMEM;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001271
Glen Leea4cac482015-12-21 14:18:36 +09001272 vif = netdev_priv(ndev);
1273 memset(vif, 0, sizeof(struct wilc_vif));
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001274
Leo Kim84d3b872015-11-05 14:36:19 +09001275 if (i == 0)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001276 strcpy(ndev->name, "wlan%d");
Leo Kim84d3b872015-11-05 14:36:19 +09001277 else
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001278 strcpy(ndev->name, "p2p%d");
1279
Leo Kim67501402016-02-04 18:15:39 +09001280 vif->idx = wl->vif_num;
Glen Leea4cac482015-12-21 14:18:36 +09001281 vif->wilc = *wilc;
Glen Lee1f435d22015-12-21 14:18:37 +09001282 wl->vif[i] = vif;
1283 wl->vif[wl->vif_num]->ndev = ndev;
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001284 wl->vif_num++;
Arnd Bergmanne5af0562015-05-29 22:52:12 +02001285 ndev->netdev_ops = &wilc_netdev_ops;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001286
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001287 {
1288 struct wireless_dev *wdev;
Leo Kimfa8b23c2016-02-04 18:15:33 +09001289
Arnd Bergmann2e7d5372015-11-16 15:05:03 +01001290 wdev = wilc_create_wiphy(ndev, dev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001291
Arnd Bergmann67039922015-11-16 15:05:02 +01001292 if (dev)
1293 SET_NETDEV_DEV(ndev, dev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001294
Leo Kim3a147c02015-11-05 14:36:10 +09001295 if (!wdev) {
Leo Kim5ac24422016-02-04 18:15:37 +09001296 netdev_err(ndev, "Can't register WILC Wiphy\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001297 return -1;
1298 }
1299
Glen Lee1006b5c2015-12-21 14:18:38 +09001300 vif->ndev->ieee80211_ptr = wdev;
1301 vif->ndev->ml_priv = vif;
1302 wdev->netdev = vif->ndev;
Glen Leea4cac482015-12-21 14:18:36 +09001303 vif->netstats.rx_packets = 0;
1304 vif->netstats.tx_packets = 0;
1305 vif->netstats.rx_bytes = 0;
1306 vif->netstats.tx_bytes = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001307 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001308
Amitoj Kaur Chawlafe747f02016-02-17 20:41:03 +05301309 ret = register_netdev(ndev);
1310 if (ret)
1311 return ret;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001312
Glen Leea4cac482015-12-21 14:18:36 +09001313 vif->iftype = STATION_MODE;
1314 vif->mac_opened = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001315 }
1316
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001317 return 0;
1318}
Arnd Bergmann750ffe92015-11-16 15:05:08 +01001319EXPORT_SYMBOL_GPL(wilc_netdev_init);
Arnd Bergmannc94f05e2015-11-16 15:05:09 +01001320
1321MODULE_LICENSE("GPL");