blob: 54fe9d74b78082b57988d24fbf68e325fab67095 [file] [log] [blame]
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001#include "wilc_wfi_cfgoperations.h"
2#include "linux_wlan_common.h"
3#include "wilc_wlan_if.h"
4#include "wilc_wlan.h"
Johnny Kimc5c77ba2015-05-11 14:30:56 +09005
6#include <linux/slab.h>
7#include <linux/sched.h>
8#include <linux/delay.h>
9#include <linux/workqueue.h>
10#include <linux/interrupt.h>
11#include <linux/irq.h>
Guenter Roeckf1a99832015-05-27 13:02:16 -070012#include <linux/gpio.h>
Johnny Kimc5c77ba2015-05-11 14:30:56 +090013
14#include <linux/kthread.h>
15#include <linux/firmware.h>
16#include <linux/delay.h>
17
18#include <linux/init.h>
19#include <linux/netdevice.h>
Johnny Kimc5c77ba2015-05-11 14:30:56 +090020#include <linux/inetdevice.h>
Johnny Kimc5c77ba2015-05-11 14:30:56 +090021#include <linux/etherdevice.h>
22#include <linux/module.h>
23#include <linux/kernel.h>
24#include <linux/skbuff.h>
25
Johnny Kimc5c77ba2015-05-11 14:30:56 +090026#include <linux/semaphore.h>
27
Johnny Kimc5c77ba2015-05-11 14:30:56 +090028static int dev_state_ev_handler(struct notifier_block *this, unsigned long event, void *ptr);
29
30static struct notifier_block g_dev_notifier = {
31 .notifier_call = dev_state_ev_handler
32};
Johnny Kimc5c77ba2015-05-11 14:30:56 +090033
Johnny Kimc5c77ba2015-05-11 14:30:56 +090034#define IRQ_WAIT 1
35#define IRQ_NO_WAIT 0
Johnny Kimc5c77ba2015-05-11 14:30:56 +090036static struct semaphore close_exit_sync;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090037
Glen Lee7c67c052015-10-27 18:27:50 +090038static int wlan_deinit_locks(struct net_device *dev);
Glen Lee32dd51b2015-10-27 18:27:52 +090039static void wlan_deinitialize_threads(struct net_device *dev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +090040
Johnny Kimc5c77ba2015-05-11 14:30:56 +090041static void linux_wlan_tx_complete(void *priv, int status);
Johnny Kimc5c77ba2015-05-11 14:30:56 +090042static int mac_init_fn(struct net_device *ndev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +090043static struct net_device_stats *mac_stats(struct net_device *dev);
44static int mac_ioctl(struct net_device *ndev, struct ifreq *req, int cmd);
45static void wilc_set_multicast_list(struct net_device *dev);
Arnd Bergmann750ffe92015-11-16 15:05:08 +010046
Arnd Bergmann0e1af732015-11-16 15:04:54 +010047bool wilc_enable_ps = true;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090048
Johnny Kimc5c77ba2015-05-11 14:30:56 +090049static const struct net_device_ops wilc_netdev_ops = {
50 .ndo_init = mac_init_fn,
Arnd Bergmann0e1af732015-11-16 15:04:54 +010051 .ndo_open = wilc_mac_open,
52 .ndo_stop = wilc_mac_close,
53 .ndo_start_xmit = wilc_mac_xmit,
Johnny Kimc5c77ba2015-05-11 14:30:56 +090054 .ndo_do_ioctl = mac_ioctl,
55 .ndo_get_stats = mac_stats,
56 .ndo_set_rx_mode = wilc_set_multicast_list,
57
58};
Johnny Kimc5c77ba2015-05-11 14:30:56 +090059
Johnny Kimc5c77ba2015-05-11 14:30:56 +090060static int dev_state_ev_handler(struct notifier_block *this, unsigned long event, void *ptr)
61{
62 struct in_ifaddr *dev_iface = (struct in_ifaddr *)ptr;
Chaehyun Lim27268872015-09-15 14:06:13 +090063 struct wilc_priv *priv;
Leo Kimf24374a2015-11-05 14:36:12 +090064 struct host_if_drv *hif_drv;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090065 struct net_device *dev;
Leo Kimeac3e8f2015-11-05 14:36:16 +090066 u8 *ip_addr_buf;
Glen Leea4cac482015-12-21 14:18:36 +090067 struct wilc_vif *vif;
Greg Kroah-Hartman63d03e42015-06-02 14:16:04 +090068 u8 null_ip[4] = {0};
Johnny Kimc5c77ba2015-05-11 14:30:56 +090069 char wlan_dev_name[5] = "wlan0";
70
Leo Kim3a147c02015-11-05 14:36:10 +090071 if (!dev_iface || !dev_iface->ifa_dev || !dev_iface->ifa_dev->dev) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +090072 PRINT_D(GENERIC_DBG, "dev_iface = NULL\n");
73 return NOTIFY_DONE;
74 }
75
Leo Kim582f8a22015-11-05 14:36:21 +090076 if (memcmp(dev_iface->ifa_label, "wlan0", 5) &&
77 memcmp(dev_iface->ifa_label, "p2p0", 4)) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +090078 PRINT_D(GENERIC_DBG, "Interface is neither WLAN0 nor P2P0\n");
79 return NOTIFY_DONE;
80 }
81
82 dev = (struct net_device *)dev_iface->ifa_dev->dev;
Leo Kim3a147c02015-11-05 14:36:10 +090083 if (!dev->ieee80211_ptr || !dev->ieee80211_ptr->wiphy) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +090084 PRINT_D(GENERIC_DBG, "No Wireless registerd\n");
85 return NOTIFY_DONE;
86 }
87 priv = wiphy_priv(dev->ieee80211_ptr->wiphy);
Leo Kim3a147c02015-11-05 14:36:10 +090088 if (!priv) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +090089 PRINT_D(GENERIC_DBG, "No Wireless Priv\n");
90 return NOTIFY_DONE;
91 }
Leo Kimf24374a2015-11-05 14:36:12 +090092 hif_drv = (struct host_if_drv *)priv->hWILCWFIDrv;
Glen Leea4cac482015-12-21 14:18:36 +090093 vif = netdev_priv(dev);
94 if (!vif || !hif_drv) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +090095 PRINT_D(GENERIC_DBG, "No Wireless Priv\n");
96 return NOTIFY_DONE;
97 }
98
Leo Kim98b89842015-11-05 14:36:18 +090099 PRINT_INFO(GENERIC_DBG, "dev_state_ev_handler +++\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900100
101 switch (event) {
102 case NETDEV_UP:
Leo Kim98b89842015-11-05 14:36:18 +0900103 PRINT_D(GENERIC_DBG, "dev_state_ev_handler event=NETDEV_UP %p\n", dev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900104
105 PRINT_INFO(GENERIC_DBG, "\n ============== IP Address Obtained ===============\n\n");
106
Glen Leea4cac482015-12-21 14:18:36 +0900107 if (vif->iftype == STATION_MODE || vif->iftype == CLIENT_MODE) {
Leo Kimf24374a2015-11-05 14:36:12 +0900108 hif_drv->IFC_UP = 1;
Arnd Bergmann0e1af732015-11-16 15:04:54 +0100109 wilc_optaining_ip = false;
110 del_timer(&wilc_during_ip_timer);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900111 PRINT_D(GENERIC_DBG, "IP obtained , enable scan\n");
112 }
113
Arnd Bergmann0e1af732015-11-16 15:04:54 +0100114 if (wilc_enable_ps)
Glen Leefbf53792015-12-21 14:18:40 +0900115 wilc_set_power_mgmt(vif, 1, 0);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900116
117 PRINT_D(GENERIC_DBG, "[%s] Up IP\n", dev_iface->ifa_label);
118
Leo Kimeac3e8f2015-11-05 14:36:16 +0900119 ip_addr_buf = (char *)&dev_iface->ifa_address;
120 PRINT_D(GENERIC_DBG, "IP add=%d:%d:%d:%d\n",
121 ip_addr_buf[0], ip_addr_buf[1],
122 ip_addr_buf[2], ip_addr_buf[3]);
Glen Leefbf53792015-12-21 14:18:40 +0900123 wilc_setup_ipaddress(vif, ip_addr_buf, vif->u8IfIdx);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900124
125 break;
126
127 case NETDEV_DOWN:
Leo Kim98b89842015-11-05 14:36:18 +0900128 PRINT_D(GENERIC_DBG, "dev_state_ev_handler event=NETDEV_DOWN %p\n", dev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900129
130 PRINT_INFO(GENERIC_DBG, "\n ============== IP Address Released ===============\n\n");
Glen Leea4cac482015-12-21 14:18:36 +0900131 if (vif->iftype == STATION_MODE || vif->iftype == CLIENT_MODE) {
Leo Kimf24374a2015-11-05 14:36:12 +0900132 hif_drv->IFC_UP = 0;
Arnd Bergmann0e1af732015-11-16 15:04:54 +0100133 wilc_optaining_ip = false;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900134 }
135
136 if (memcmp(dev_iface->ifa_label, wlan_dev_name, 5) == 0)
Glen Leefbf53792015-12-21 14:18:40 +0900137 wilc_set_power_mgmt(vif, 0, 0);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900138
Glen Leefbf53792015-12-21 14:18:40 +0900139 wilc_resolve_disconnect_aberration(vif);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900140
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900141 PRINT_D(GENERIC_DBG, "[%s] Down IP\n", dev_iface->ifa_label);
142
Leo Kimeac3e8f2015-11-05 14:36:16 +0900143 ip_addr_buf = null_ip;
144 PRINT_D(GENERIC_DBG, "IP add=%d:%d:%d:%d\n",
145 ip_addr_buf[0], ip_addr_buf[1],
146 ip_addr_buf[2], ip_addr_buf[3]);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900147
Glen Leefbf53792015-12-21 14:18:40 +0900148 wilc_setup_ipaddress(vif, ip_addr_buf, vif->u8IfIdx);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900149
150 break;
151
152 default:
Leo Kim98b89842015-11-05 14:36:18 +0900153 PRINT_INFO(GENERIC_DBG, "dev_state_ev_handler event=default\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900154 PRINT_INFO(GENERIC_DBG, "[%s] unknown dev event: %lu\n", dev_iface->ifa_label, event);
155
156 break;
157 }
158
159 return NOTIFY_DONE;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900160}
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900161
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900162static irqreturn_t isr_uh_routine(int irq, void *user_data)
163{
Glen Leea4cac482015-12-21 14:18:36 +0900164 struct wilc_vif *vif;
Glen Lee39483622015-10-27 18:27:37 +0900165 struct wilc *wilc;
166 struct net_device *dev = (struct net_device *)user_data;
167
Glen Leea4cac482015-12-21 14:18:36 +0900168 vif = netdev_priv(dev);
169 wilc = vif->wilc;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900170 PRINT_D(INT_DBG, "Interrupt received UH\n");
171
Glen Lee39483622015-10-27 18:27:37 +0900172 if (wilc->close) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900173 PRINT_ER("Driver is CLOSING: Can't handle UH interrupt\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900174 return IRQ_HANDLED;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900175 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900176 return IRQ_WAKE_THREAD;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900177}
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900178
Arnd Bergmann1608c402015-11-16 15:04:53 +0100179static irqreturn_t isr_bh_routine(int irq, void *userdata)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900180{
Glen Leea4cac482015-12-21 14:18:36 +0900181 struct wilc_vif *vif;
Glen Lee2e7933d2015-10-27 18:27:38 +0900182 struct wilc *wilc;
183
Glen Leea4cac482015-12-21 14:18:36 +0900184 vif = netdev_priv(userdata);
185 wilc = vif->wilc;
Glen Lee2e7933d2015-10-27 18:27:38 +0900186
Glen Lee2e7933d2015-10-27 18:27:38 +0900187 if (wilc->close) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900188 PRINT_ER("Driver is CLOSING: Can't handle BH interrupt\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900189 return IRQ_HANDLED;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900190 }
191
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900192 PRINT_D(INT_DBG, "Interrupt received BH\n");
Glen Lee50b929e2015-10-27 18:27:40 +0900193 wilc_handle_isr(wilc);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900194
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900195 return IRQ_HANDLED;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900196}
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900197
Glen Lee2c1d05d2015-10-20 17:14:03 +0900198static int init_irq(struct net_device *dev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900199{
200 int ret = 0;
Glen Leea4cac482015-12-21 14:18:36 +0900201 struct wilc_vif *vif;
Glen Lee2c1d05d2015-10-20 17:14:03 +0900202 struct wilc *wl;
203
Glen Leea4cac482015-12-21 14:18:36 +0900204 vif = netdev_priv(dev);
205 wl = vif->wilc;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900206
Arnd Bergmannc4d139c2015-11-16 15:05:04 +0100207 if ((gpio_request(wl->gpio, "WILC_INTR") == 0) &&
208 (gpio_direction_input(wl->gpio) == 0)) {
209 wl->dev_irq_num = gpio_to_irq(wl->gpio);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900210 } else {
211 ret = -1;
212 PRINT_ER("could not obtain gpio for WILC_INTR\n");
213 }
214
Leo Kim83231b72015-11-06 11:12:22 +0900215 if (ret != -1 && request_threaded_irq(wl->dev_irq_num,
216 isr_uh_routine,
217 isr_bh_routine,
218 IRQF_TRIGGER_LOW | IRQF_ONESHOT,
219 "WILC_IRQ", dev) < 0) {
Arnd Bergmannc4d139c2015-11-16 15:05:04 +0100220 PRINT_ER("Failed to request IRQ for GPIO: %d\n", wl->gpio);
221 gpio_free(wl->gpio);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900222 ret = -1;
223 } else {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900224 PRINT_D(INIT_DBG, "IRQ request succeeded IRQ-NUM= %d on GPIO: %d\n",
Arnd Bergmannc4d139c2015-11-16 15:05:04 +0100225 wl->dev_irq_num, wl->gpio);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900226 }
227
228 return ret;
229}
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900230
Glen Leeec5cc752015-10-27 18:27:39 +0900231static void deinit_irq(struct net_device *dev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900232{
Glen Leea4cac482015-12-21 14:18:36 +0900233 struct wilc_vif *vif;
Glen Leeec5cc752015-10-27 18:27:39 +0900234 struct wilc *wilc;
235
Glen Leea4cac482015-12-21 14:18:36 +0900236 vif = netdev_priv(dev);
237 wilc = vif->wilc;
Glen Leeec5cc752015-10-27 18:27:39 +0900238
Arnd Bergmannc4d139c2015-11-16 15:05:04 +0100239 /* Deintialize IRQ */
240 if (wilc->dev_irq_num) {
Glen Leeec5cc752015-10-27 18:27:39 +0900241 free_irq(wilc->dev_irq_num, wilc);
Arnd Bergmannc4d139c2015-11-16 15:05:04 +0100242 gpio_free(wilc->gpio);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900243 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900244}
245
Glen Leed36ec222015-11-18 15:11:36 +0900246void wilc_dbg(u8 *buff)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900247{
248 PRINT_D(INIT_DBG, "%d\n", *buff);
249}
250
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100251int wilc_lock_timeout(struct wilc *nic, void *vp, u32 timeout)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900252{
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100253 /* FIXME: replace with mutex_lock or wait_for_completion */
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900254 int error = -1;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900255
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900256 PRINT_D(LOCK_DBG, "Locking %p\n", vp);
Leo Kim3a147c02015-11-05 14:36:10 +0900257 if (vp)
Leo Kim582f8a22015-11-05 14:36:21 +0900258 error = down_timeout((struct semaphore *)vp,
259 msecs_to_jiffies(timeout));
Chandra S Gorentla78174ad2015-08-08 17:41:36 +0530260 else
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900261 PRINT_ER("Failed, mutex is NULL\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900262 return error;
263}
264
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100265void wilc_mac_indicate(struct wilc *wilc, int flag)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900266{
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900267 int status;
268
269 if (flag == WILC_MAC_INDICATE_STATUS) {
Leo Kim582f8a22015-11-05 14:36:21 +0900270 wilc_wlan_cfg_get_val(WID_STATUS,
271 (unsigned char *)&status, 4);
Glen Lee64f2b712015-10-27 18:27:43 +0900272 if (wilc->mac_status == WILC_MAC_STATUS_INIT) {
273 wilc->mac_status = status;
274 up(&wilc->sync_event);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900275 } else {
Glen Lee64f2b712015-10-27 18:27:43 +0900276 wilc->mac_status = status;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900277 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900278 } else if (flag == WILC_MAC_INDICATE_SCAN) {
279 PRINT_D(GENERIC_DBG, "Scanning ...\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900280 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900281}
282
Arnd Bergmann1608c402015-11-16 15:04:53 +0100283static struct net_device *get_if_handler(struct wilc *wilc, u8 *mac_header)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900284{
Leo Kim660786e2015-11-05 14:36:27 +0900285 u8 *bssid, *bssid1;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900286 int i = 0;
287
Leo Kimd2392222015-11-05 14:36:26 +0900288 bssid = mac_header + 10;
Leo Kim660786e2015-11-05 14:36:27 +0900289 bssid1 = mac_header + 4;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900290
Glen Lee4ad81fd2015-10-27 18:27:57 +0900291 for (i = 0; i < wilc->vif_num; i++)
Glen Lee1f435d22015-12-21 14:18:37 +0900292 if (!memcmp(bssid1, wilc->vif[i]->bssid, ETH_ALEN) ||
293 !memcmp(bssid, wilc->vif[i]->bssid, ETH_ALEN))
294 return wilc->vif[i]->ndev;
Tony Cho8259a532015-10-20 14:26:47 +0900295
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900296 PRINT_INFO(INIT_DBG, "Invalide handle\n");
Kim, Leofc4b95d2015-07-28 17:47:37 +0900297 for (i = 0; i < 25; i++)
Leo Kim51456c22015-11-05 14:36:25 +0900298 PRINT_D(INIT_DBG, "%02x ", mac_header[i]);
Leo Kimd2392222015-11-05 14:36:26 +0900299 bssid = mac_header + 18;
Leo Kim660786e2015-11-05 14:36:27 +0900300 bssid1 = mac_header + 12;
Glen Lee4ad81fd2015-10-27 18:27:57 +0900301 for (i = 0; i < wilc->vif_num; i++)
Glen Lee1f435d22015-12-21 14:18:37 +0900302 if (!memcmp(bssid1, wilc->vif[i]->bssid, ETH_ALEN) ||
303 !memcmp(bssid, wilc->vif[i]->bssid, ETH_ALEN))
304 return wilc->vif[i]->ndev;
Tony Cho8259a532015-10-20 14:26:47 +0900305
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900306 PRINT_INFO(INIT_DBG, "\n");
307 return NULL;
308}
309
Arnd Bergmann0e1af732015-11-16 15:04:54 +0100310int wilc_wlan_set_bssid(struct net_device *wilc_netdev, u8 *bssid)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900311{
312 int i = 0;
313 int ret = -1;
Glen Leea4cac482015-12-21 14:18:36 +0900314 struct wilc_vif *vif;
Glen Lee472791a2015-10-27 18:27:44 +0900315 struct wilc *wilc;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900316
Glen Leea4cac482015-12-21 14:18:36 +0900317 vif = netdev_priv(wilc_netdev);
318 wilc = vif->wilc;
Glen Lee472791a2015-10-27 18:27:44 +0900319
320 for (i = 0; i < wilc->vif_num; i++)
Glen Lee1f435d22015-12-21 14:18:37 +0900321 if (wilc->vif[i]->ndev == wilc_netdev) {
322 memcpy(wilc->vif[i]->bssid, bssid, 6);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900323 ret = 0;
324 break;
325 }
Tony Cho8259a532015-10-20 14:26:47 +0900326
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900327 return ret;
328}
329
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100330int wilc_wlan_get_num_conn_ifcs(struct wilc *wilc)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900331{
Chaehyun Lim51e825f2015-09-15 14:06:14 +0900332 u8 i = 0;
333 u8 null_bssid[6] = {0};
334 u8 ret_val = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900335
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100336 for (i = 0; i < wilc->vif_num; i++)
Glen Lee1f435d22015-12-21 14:18:37 +0900337 if (memcmp(wilc->vif[i]->bssid, null_bssid, 6))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900338 ret_val++;
Tony Cho8259a532015-10-20 14:26:47 +0900339
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900340 return ret_val;
341}
342
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900343#define USE_TX_BACKOFF_DELAY_IF_NO_BUFFERS
344
345static int linux_wlan_txq_task(void *vp)
346{
347 int ret, txq_count;
Glen Leea4cac482015-12-21 14:18:36 +0900348 struct wilc_vif *vif;
Glen Lee88687582015-10-27 18:27:46 +0900349 struct wilc *wl;
350 struct net_device *dev = vp;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900351#if defined USE_TX_BACKOFF_DELAY_IF_NO_BUFFERS
352#define TX_BACKOFF_WEIGHT_INCR_STEP (1)
353#define TX_BACKOFF_WEIGHT_DECR_STEP (1)
354#define TX_BACKOFF_WEIGHT_MAX (7)
355#define TX_BACKOFF_WEIGHT_MIN (0)
356#define TX_BACKOFF_WEIGHT_UNIT_MS (10)
357 int backoff_weight = TX_BACKOFF_WEIGHT_MIN;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900358#endif
359
Glen Leea4cac482015-12-21 14:18:36 +0900360 vif = netdev_priv(dev);
361 wl = vif->wilc;
Glen Lee88687582015-10-27 18:27:46 +0900362
Glen Lee88687582015-10-27 18:27:46 +0900363 up(&wl->txq_thread_started);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900364 while (1) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900365 PRINT_D(TX_DBG, "txq_task Taking a nap :)\n");
Glen Lee88687582015-10-27 18:27:46 +0900366 down(&wl->txq_event);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900367 PRINT_D(TX_DBG, "txq_task Who waked me up :$\n");
368
Glen Lee88687582015-10-27 18:27:46 +0900369 if (wl->close) {
Glen Lee88687582015-10-27 18:27:46 +0900370 up(&wl->txq_thread_started);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900371
372 while (!kthread_should_stop())
373 schedule();
374
375 PRINT_D(TX_DBG, "TX thread stopped\n");
376 break;
377 }
378 PRINT_D(TX_DBG, "txq_task handle the sending packet and let me go to sleep.\n");
379#if !defined USE_TX_BACKOFF_DELAY_IF_NO_BUFFERS
Glen Leea1332ca2015-10-27 18:27:47 +0900380 ret = wilc_wlan_handle_txq(dev, &txq_count);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900381#else
382 do {
Glen Leea1332ca2015-10-27 18:27:47 +0900383 ret = wilc_wlan_handle_txq(dev, &txq_count);
Leo Kim98b89842015-11-05 14:36:18 +0900384 if (txq_count < FLOW_CONTROL_LOWER_THRESHOLD) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900385 PRINT_D(TX_DBG, "Waking up queue\n");
Leo Kim98b89842015-11-05 14:36:18 +0900386
Glen Lee1f435d22015-12-21 14:18:37 +0900387 if (netif_queue_stopped(wl->vif[0]->ndev))
388 netif_wake_queue(wl->vif[0]->ndev);
389 if (netif_queue_stopped(wl->vif[1]->ndev))
390 netif_wake_queue(wl->vif[1]->ndev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900391 }
392
Leo Kim98b89842015-11-05 14:36:18 +0900393 if (ret == WILC_TX_ERR_NO_BUF) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900394 do {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900395 msleep(TX_BACKOFF_WEIGHT_UNIT_MS << backoff_weight);
Leo Kim98b89842015-11-05 14:36:18 +0900396 } while (0);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900397 backoff_weight += TX_BACKOFF_WEIGHT_INCR_STEP;
Kim, Leofc4b95d2015-07-28 17:47:37 +0900398 if (backoff_weight > TX_BACKOFF_WEIGHT_MAX)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900399 backoff_weight = TX_BACKOFF_WEIGHT_MAX;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900400 } else {
401 if (backoff_weight > TX_BACKOFF_WEIGHT_MIN) {
402 backoff_weight -= TX_BACKOFF_WEIGHT_DECR_STEP;
Kim, Leofc4b95d2015-07-28 17:47:37 +0900403 if (backoff_weight < TX_BACKOFF_WEIGHT_MIN)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900404 backoff_weight = TX_BACKOFF_WEIGHT_MIN;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900405 }
406 }
Leo Kim98b89842015-11-05 14:36:18 +0900407 } while (ret == WILC_TX_ERR_NO_BUF && !wl->close);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900408#endif
409 }
410 return 0;
411}
412
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100413void wilc_rx_complete(struct wilc *nic)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900414{
415 PRINT_D(RX_DBG, "RX completed\n");
416}
417
Arnd Bergmann0e1af732015-11-16 15:04:54 +0100418int wilc_wlan_get_firmware(struct net_device *dev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900419{
Glen Leea4cac482015-12-21 14:18:36 +0900420 struct wilc_vif *vif;
Glen Lee65c8adc2015-10-29 12:18:49 +0900421 struct wilc *wilc;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900422 int ret = 0;
423 const struct firmware *wilc_firmware;
424 char *firmware;
425
Glen Leea4cac482015-12-21 14:18:36 +0900426 vif = netdev_priv(dev);
427 wilc = vif->wilc;
Glen Lee65c8adc2015-10-29 12:18:49 +0900428
Glen Leea4cac482015-12-21 14:18:36 +0900429 if (vif->iftype == AP_MODE) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900430 firmware = AP_FIRMWARE;
Glen Leea4cac482015-12-21 14:18:36 +0900431 } else if (vif->iftype == STATION_MODE) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900432 firmware = STA_FIRMWARE;
Leo Kim1b7a93a2015-11-05 14:36:29 +0900433 } else {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900434 PRINT_D(INIT_DBG, "Get P2P_CONCURRENCY_FIRMWARE\n");
435 firmware = P2P_CONCURRENCY_FIRMWARE;
436 }
437
Glen Leea4cac482015-12-21 14:18:36 +0900438 if (!vif) {
439 PRINT_ER("vif is NULL\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900440 goto _fail_;
441 }
442
Glen Lee1006b5c2015-12-21 14:18:38 +0900443 if (!(&vif->ndev->dev)) {
444 PRINT_ER("&vif->ndev->dev is NULL\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900445 goto _fail_;
446 }
447
Arnd Bergmannb03314e2015-11-16 15:05:01 +0100448 if (request_firmware(&wilc_firmware, firmware, wilc->dev) != 0) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900449 PRINT_ER("%s - firmare not available\n", firmware);
450 ret = -1;
451 goto _fail_;
452 }
Glen Lee65c8adc2015-10-29 12:18:49 +0900453 wilc->firmware = wilc_firmware;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900454
455_fail_:
456
457 return ret;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900458}
459
Glen Lee9bf3d722015-10-29 12:18:46 +0900460static int linux_wlan_start_firmware(struct net_device *dev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900461{
Glen Leea4cac482015-12-21 14:18:36 +0900462 struct wilc_vif *vif;
Glen Lee9bf3d722015-10-29 12:18:46 +0900463 struct wilc *wilc;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900464 int ret = 0;
Glen Lee9bf3d722015-10-29 12:18:46 +0900465
Glen Leea4cac482015-12-21 14:18:36 +0900466 vif = netdev_priv(dev);
467 wilc = vif->wilc;
Glen Lee9bf3d722015-10-29 12:18:46 +0900468
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900469 PRINT_D(INIT_DBG, "Starting Firmware ...\n");
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100470 ret = wilc_wlan_start(wilc);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900471 if (ret < 0) {
472 PRINT_ER("Failed to start Firmware\n");
Leo Kim0aeea1a2015-11-05 14:36:30 +0900473 return ret;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900474 }
475
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900476 PRINT_D(INIT_DBG, "Waiting for Firmware to get ready ...\n");
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100477 ret = wilc_lock_timeout(wilc, &wilc->sync_event, 5000);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900478 if (ret) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900479 PRINT_D(INIT_DBG, "Firmware start timed out");
Leo Kim0aeea1a2015-11-05 14:36:30 +0900480 return ret;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900481 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900482 PRINT_D(INIT_DBG, "Firmware successfully started\n");
483
Leo Kim0aeea1a2015-11-05 14:36:30 +0900484 return 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900485}
Leo Kima40b22c2015-11-05 14:36:32 +0900486
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100487static int wilc1000_firmware_download(struct net_device *dev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900488{
Glen Leea4cac482015-12-21 14:18:36 +0900489 struct wilc_vif *vif;
Glen Leeed760b62015-10-29 12:18:42 +0900490 struct wilc *wilc;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900491 int ret = 0;
492
Glen Leea4cac482015-12-21 14:18:36 +0900493 vif = netdev_priv(dev);
494 wilc = vif->wilc;
Glen Leeed760b62015-10-29 12:18:42 +0900495
496 if (!wilc->firmware) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900497 PRINT_ER("Firmware buffer is NULL\n");
Leo Kim14b18212015-11-05 14:36:31 +0900498 return -ENOBUFS;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900499 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900500 PRINT_D(INIT_DBG, "Downloading Firmware ...\n");
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100501 ret = wilc_wlan_firmware_download(wilc, wilc->firmware->data,
Glen Leeed760b62015-10-29 12:18:42 +0900502 wilc->firmware->size);
Kim, Leofc4b95d2015-07-28 17:47:37 +0900503 if (ret < 0)
Leo Kim14b18212015-11-05 14:36:31 +0900504 return ret;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900505
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900506 PRINT_D(INIT_DBG, "Freeing FW buffer ...\n");
507 PRINT_D(INIT_DBG, "Releasing firmware\n");
Glen Leeed760b62015-10-29 12:18:42 +0900508 release_firmware(wilc->firmware);
Glen Lee6f72ed72015-11-25 11:59:40 +0900509 wilc->firmware = NULL;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900510
Chandra S Gorentla17aacd42015-08-08 17:41:35 +0530511 PRINT_D(INIT_DBG, "Download Succeeded\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900512
Leo Kim14b18212015-11-05 14:36:31 +0900513 return 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900514}
515
Glen Lee00215dd2015-11-18 15:11:25 +0900516static int linux_wlan_init_test_config(struct net_device *dev,
517 struct wilc *wilc)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900518{
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900519 unsigned char c_val[64];
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900520 unsigned char mac_add[] = {0x00, 0x80, 0xC2, 0x5E, 0xa2, 0xff};
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900521
Chaehyun Lim27268872015-09-15 14:06:13 +0900522 struct wilc_priv *priv;
Leo Kim0fa66c72015-11-05 14:36:13 +0900523 struct host_if_drv *hif_drv;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900524
525 PRINT_D(TX_DBG, "Start configuring Firmware\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900526 get_random_bytes(&mac_add[5], 1);
527 get_random_bytes(&mac_add[4], 1);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900528 priv = wiphy_priv(dev->ieee80211_ptr->wiphy);
Leo Kim0fa66c72015-11-05 14:36:13 +0900529 hif_drv = (struct host_if_drv *)priv->hWILCWFIDrv;
530 PRINT_D(INIT_DBG, "Host = %p\n", hif_drv);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900531
Leo Kim582f8a22015-11-05 14:36:21 +0900532 PRINT_D(INIT_DBG, "MAC address is : %02x-%02x-%02x-%02x-%02x-%02x\n",
533 mac_add[0], mac_add[1], mac_add[2],
534 mac_add[3], mac_add[4], mac_add[5]);
Glen Lee00215dd2015-11-18 15:11:25 +0900535 wilc_get_chipid(wilc, 0);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900536
Johnny Kime5d57e92015-08-20 16:32:53 +0900537 *(int *)c_val = 1;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900538
Glen Lee89758e12015-11-18 15:11:34 +0900539 if (!wilc_wlan_cfg_set(wilc, 1, WID_SET_DRV_HANDLER, c_val, 4, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900540 goto _fail_;
541
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900542 c_val[0] = 0;
Glen Lee89758e12015-11-18 15:11:34 +0900543 if (!wilc_wlan_cfg_set(wilc, 0, WID_PC_TEST_MODE, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900544 goto _fail_;
545
546 c_val[0] = INFRASTRUCTURE;
Glen Lee89758e12015-11-18 15:11:34 +0900547 if (!wilc_wlan_cfg_set(wilc, 0, WID_BSS_TYPE, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900548 goto _fail_;
549
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900550 c_val[0] = RATE_AUTO;
Glen Lee89758e12015-11-18 15:11:34 +0900551 if (!wilc_wlan_cfg_set(wilc, 0, WID_CURRENT_TX_RATE, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900552 goto _fail_;
553
554 c_val[0] = G_MIXED_11B_2_MODE;
Glen Lee89758e12015-11-18 15:11:34 +0900555 if (!wilc_wlan_cfg_set(wilc, 0, WID_11G_OPERATING_MODE, c_val, 1, 0,
556 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900557 goto _fail_;
558
559 c_val[0] = 1;
Glen Lee89758e12015-11-18 15:11:34 +0900560 if (!wilc_wlan_cfg_set(wilc, 0, WID_CURRENT_CHANNEL, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900561 goto _fail_;
562
563 c_val[0] = G_SHORT_PREAMBLE;
Glen Lee89758e12015-11-18 15:11:34 +0900564 if (!wilc_wlan_cfg_set(wilc, 0, WID_PREAMBLE, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900565 goto _fail_;
566
567 c_val[0] = AUTO_PROT;
Glen Lee89758e12015-11-18 15:11:34 +0900568 if (!wilc_wlan_cfg_set(wilc, 0, WID_11N_PROT_MECH, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900569 goto _fail_;
570
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900571 c_val[0] = ACTIVE_SCAN;
Glen Lee89758e12015-11-18 15:11:34 +0900572 if (!wilc_wlan_cfg_set(wilc, 0, WID_SCAN_TYPE, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900573 goto _fail_;
574
575 c_val[0] = SITE_SURVEY_OFF;
Glen Lee89758e12015-11-18 15:11:34 +0900576 if (!wilc_wlan_cfg_set(wilc, 0, WID_SITE_SURVEY, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900577 goto _fail_;
578
Leo Kim98b89842015-11-05 14:36:18 +0900579 *((int *)c_val) = 0xffff;
Glen Lee89758e12015-11-18 15:11:34 +0900580 if (!wilc_wlan_cfg_set(wilc, 0, WID_RTS_THRESHOLD, c_val, 2, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900581 goto _fail_;
582
583 *((int *)c_val) = 2346;
Glen Lee89758e12015-11-18 15:11:34 +0900584 if (!wilc_wlan_cfg_set(wilc, 0, WID_FRAG_THRESHOLD, c_val, 2, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900585 goto _fail_;
586
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900587 c_val[0] = 0;
Glen Lee89758e12015-11-18 15:11:34 +0900588 if (!wilc_wlan_cfg_set(wilc, 0, WID_BCAST_SSID, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900589 goto _fail_;
590
591 c_val[0] = 1;
Glen Lee89758e12015-11-18 15:11:34 +0900592 if (!wilc_wlan_cfg_set(wilc, 0, WID_QOS_ENABLE, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900593 goto _fail_;
594
595 c_val[0] = NO_POWERSAVE;
Glen Lee89758e12015-11-18 15:11:34 +0900596 if (!wilc_wlan_cfg_set(wilc, 0, WID_POWER_MANAGEMENT, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900597 goto _fail_;
598
Arnd Bergmannb4d04c12015-11-16 15:04:56 +0100599 c_val[0] = NO_SECURITY; /* NO_ENCRYPT, 0x79 */
Glen Lee89758e12015-11-18 15:11:34 +0900600 if (!wilc_wlan_cfg_set(wilc, 0, WID_11I_MODE, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900601 goto _fail_;
602
603 c_val[0] = OPEN_SYSTEM;
Glen Lee89758e12015-11-18 15:11:34 +0900604 if (!wilc_wlan_cfg_set(wilc, 0, WID_AUTH_TYPE, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900605 goto _fail_;
606
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900607 strcpy(c_val, "123456790abcdef1234567890");
Glen Lee89758e12015-11-18 15:11:34 +0900608 if (!wilc_wlan_cfg_set(wilc, 0, WID_WEP_KEY_VALUE, c_val,
609 (strlen(c_val) + 1), 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900610 goto _fail_;
611
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900612 strcpy(c_val, "12345678");
Glen Lee89758e12015-11-18 15:11:34 +0900613 if (!wilc_wlan_cfg_set(wilc, 0, WID_11I_PSK, c_val, (strlen(c_val)), 0,
614 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900615 goto _fail_;
616
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900617 strcpy(c_val, "password");
Glen Lee89758e12015-11-18 15:11:34 +0900618 if (!wilc_wlan_cfg_set(wilc, 0, WID_1X_KEY, c_val, (strlen(c_val) + 1),
619 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900620 goto _fail_;
621
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900622 c_val[0] = 192;
623 c_val[1] = 168;
624 c_val[2] = 1;
625 c_val[3] = 112;
Glen Lee89758e12015-11-18 15:11:34 +0900626 if (!wilc_wlan_cfg_set(wilc, 0, WID_1X_SERV_ADDR, c_val, 4, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900627 goto _fail_;
628
629 c_val[0] = 3;
Glen Lee89758e12015-11-18 15:11:34 +0900630 if (!wilc_wlan_cfg_set(wilc, 0, WID_LISTEN_INTERVAL, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900631 goto _fail_;
632
633 c_val[0] = 3;
Glen Lee89758e12015-11-18 15:11:34 +0900634 if (!wilc_wlan_cfg_set(wilc, 0, WID_DTIM_PERIOD, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900635 goto _fail_;
636
637 c_val[0] = NORMAL_ACK;
Glen Lee89758e12015-11-18 15:11:34 +0900638 if (!wilc_wlan_cfg_set(wilc, 0, WID_ACK_POLICY, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900639 goto _fail_;
640
641 c_val[0] = 0;
Glen Lee89758e12015-11-18 15:11:34 +0900642 if (!wilc_wlan_cfg_set(wilc, 0, WID_USER_CONTROL_ON_TX_POWER, c_val, 1,
643 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900644 goto _fail_;
645
646 c_val[0] = 48;
Glen Lee89758e12015-11-18 15:11:34 +0900647 if (!wilc_wlan_cfg_set(wilc, 0, WID_TX_POWER_LEVEL_11A, c_val, 1, 0,
648 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900649 goto _fail_;
650
651 c_val[0] = 28;
Glen Lee89758e12015-11-18 15:11:34 +0900652 if (!wilc_wlan_cfg_set(wilc, 0, WID_TX_POWER_LEVEL_11B, c_val, 1, 0,
653 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900654 goto _fail_;
655
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900656 *((int *)c_val) = 100;
Glen Lee89758e12015-11-18 15:11:34 +0900657 if (!wilc_wlan_cfg_set(wilc, 0, WID_BEACON_INTERVAL, c_val, 2, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900658 goto _fail_;
659
660 c_val[0] = REKEY_DISABLE;
Glen Lee89758e12015-11-18 15:11:34 +0900661 if (!wilc_wlan_cfg_set(wilc, 0, WID_REKEY_POLICY, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900662 goto _fail_;
663
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900664 *((int *)c_val) = 84600;
Glen Lee89758e12015-11-18 15:11:34 +0900665 if (!wilc_wlan_cfg_set(wilc, 0, WID_REKEY_PERIOD, c_val, 4, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900666 goto _fail_;
667
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900668 *((int *)c_val) = 500;
Glen Lee89758e12015-11-18 15:11:34 +0900669 if (!wilc_wlan_cfg_set(wilc, 0, WID_REKEY_PACKET_COUNT, c_val, 4, 0,
670 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900671 goto _fail_;
672
673 c_val[0] = 1;
Glen Lee89758e12015-11-18 15:11:34 +0900674 if (!wilc_wlan_cfg_set(wilc, 0, WID_SHORT_SLOT_ALLOWED, c_val, 1, 0,
675 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900676 goto _fail_;
677
678 c_val[0] = G_SELF_CTS_PROT;
Glen Lee89758e12015-11-18 15:11:34 +0900679 if (!wilc_wlan_cfg_set(wilc, 0, WID_11N_ERP_PROT_TYPE, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900680 goto _fail_;
681
Leo Kim98b89842015-11-05 14:36:18 +0900682 c_val[0] = 1;
Glen Lee89758e12015-11-18 15:11:34 +0900683 if (!wilc_wlan_cfg_set(wilc, 0, WID_11N_ENABLE, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900684 goto _fail_;
685
686 c_val[0] = HT_MIXED_MODE;
Glen Lee89758e12015-11-18 15:11:34 +0900687 if (!wilc_wlan_cfg_set(wilc, 0, WID_11N_OPERATING_MODE, c_val, 1, 0,
688 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900689 goto _fail_;
690
Leo Kim98b89842015-11-05 14:36:18 +0900691 c_val[0] = 1;
Glen Lee89758e12015-11-18 15:11:34 +0900692 if (!wilc_wlan_cfg_set(wilc, 0, WID_11N_TXOP_PROT_DISABLE, c_val, 1, 0,
693 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900694 goto _fail_;
695
696 memcpy(c_val, mac_add, 6);
697
Glen Lee89758e12015-11-18 15:11:34 +0900698 if (!wilc_wlan_cfg_set(wilc, 0, WID_MAC_ADDR, c_val, 6, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900699 goto _fail_;
700
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900701 c_val[0] = DETECT_PROTECT_REPORT;
Glen Lee89758e12015-11-18 15:11:34 +0900702 if (!wilc_wlan_cfg_set(wilc, 0, WID_11N_OBSS_NONHT_DETECTION, c_val, 1,
703 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900704 goto _fail_;
705
706 c_val[0] = RTS_CTS_NONHT_PROT;
Glen Lee89758e12015-11-18 15:11:34 +0900707 if (!wilc_wlan_cfg_set(wilc, 0, WID_11N_HT_PROT_TYPE, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900708 goto _fail_;
709
710 c_val[0] = 0;
Glen Lee89758e12015-11-18 15:11:34 +0900711 if (!wilc_wlan_cfg_set(wilc, 0, WID_11N_RIFS_PROT_ENABLE, c_val, 1, 0,
712 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900713 goto _fail_;
714
715 c_val[0] = MIMO_MODE;
Glen Lee89758e12015-11-18 15:11:34 +0900716 if (!wilc_wlan_cfg_set(wilc, 0, WID_11N_SMPS_MODE, c_val, 1, 0, 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900717 goto _fail_;
718
719 c_val[0] = 7;
Glen Lee89758e12015-11-18 15:11:34 +0900720 if (!wilc_wlan_cfg_set(wilc, 0, WID_11N_CURRENT_TX_MCS, c_val, 1, 0,
721 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900722 goto _fail_;
723
Leo Kim98b89842015-11-05 14:36:18 +0900724 c_val[0] = 1;
Glen Lee89758e12015-11-18 15:11:34 +0900725 if (!wilc_wlan_cfg_set(wilc, 0, WID_11N_IMMEDIATE_BA_ENABLED, c_val, 1,
726 1, 1))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900727 goto _fail_;
728
729 return 0;
730
731_fail_:
732 return -1;
733}
734
Glen Lee53dc0cf2015-10-20 17:13:57 +0900735void wilc1000_wlan_deinit(struct net_device *dev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900736{
Glen Leea4cac482015-12-21 14:18:36 +0900737 struct wilc_vif *vif;
Glen Lee53dc0cf2015-10-20 17:13:57 +0900738 struct wilc *wl;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900739
Glen Leea4cac482015-12-21 14:18:36 +0900740 vif = netdev_priv(dev);
741 wl = vif->wilc;
Glen Lee53dc0cf2015-10-20 17:13:57 +0900742
743 if (!wl) {
744 netdev_err(dev, "wl is NULL\n");
745 return;
746 }
747
748 if (wl->initialized) {
749 netdev_info(dev, "Deinitializing wilc1000...\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900750
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900751 PRINT_D(INIT_DBG, "Disabling IRQ\n");
Arnd Bergmann5547c1f2015-11-16 15:05:06 +0100752 if (!wl->dev_irq_num &&
Glen Leeaf9ae092015-12-21 14:18:09 +0900753 wl->hif_func->disable_interrupt) {
Arnd Bergmannc4d139c2015-11-16 15:05:04 +0100754 mutex_lock(&wl->hif_cs);
Glen Leeaf9ae092015-12-21 14:18:09 +0900755 wl->hif_func->disable_interrupt(wl);
Arnd Bergmannc4d139c2015-11-16 15:05:04 +0100756 mutex_unlock(&wl->hif_cs);
757 }
Leo Kim3a147c02015-11-05 14:36:10 +0900758 if (&wl->txq_event)
Glen Lee53dc0cf2015-10-20 17:13:57 +0900759 up(&wl->txq_event);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900760
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900761 PRINT_D(INIT_DBG, "Deinitializing Threads\n");
Glen Lee32dd51b2015-10-27 18:27:52 +0900762 wlan_deinitialize_threads(dev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900763
764 PRINT_D(INIT_DBG, "Deinitializing IRQ\n");
Glen Leeec5cc752015-10-27 18:27:39 +0900765 deinit_irq(dev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900766
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100767 wilc_wlan_stop(wl);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900768
769 PRINT_D(INIT_DBG, "Deinitializing WILC Wlan\n");
Glen Lee2de7cbe2015-10-27 18:27:54 +0900770 wilc_wlan_cleanup(dev);
Arnd Bergmannc4d139c2015-11-16 15:05:04 +0100771#if defined(PLAT_ALLWINNER_A20) || defined(PLAT_ALLWINNER_A23) || defined(PLAT_ALLWINNER_A31)
Arnd Bergmann5547c1f2015-11-16 15:05:06 +0100772 if (!wl->dev_irq_num &&
Glen Leeaf9ae092015-12-21 14:18:09 +0900773 wl->hif_func->disable_interrupt) {
Arnd Bergmann5547c1f2015-11-16 15:05:06 +0100774
Arnd Bergmannc4d139c2015-11-16 15:05:04 +0100775 PRINT_D(INIT_DBG, "Disabling IRQ 2\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900776
Arnd Bergmannc4d139c2015-11-16 15:05:04 +0100777 mutex_lock(&wl->hif_cs);
Glen Leeaf9ae092015-12-21 14:18:09 +0900778 wl->hif_func->disable_interrupt(wl);
Arnd Bergmannc4d139c2015-11-16 15:05:04 +0100779 mutex_unlock(&wl->hif_cs);
780 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900781#endif
782
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900783 PRINT_D(INIT_DBG, "Deinitializing Locks\n");
Glen Lee7c67c052015-10-27 18:27:50 +0900784 wlan_deinit_locks(dev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900785
Glen Lee53dc0cf2015-10-20 17:13:57 +0900786 wl->initialized = false;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900787
788 PRINT_D(INIT_DBG, "wilc1000 deinitialization Done\n");
789
790 } else {
791 PRINT_D(INIT_DBG, "wilc1000 is not initialized\n");
792 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900793}
794
Arnd Bergmann1608c402015-11-16 15:04:53 +0100795static int wlan_init_locks(struct net_device *dev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900796{
Glen Leea4cac482015-12-21 14:18:36 +0900797 struct wilc_vif *vif;
Glen Lee38afb392015-10-20 17:13:53 +0900798 struct wilc *wl;
799
Glen Leea4cac482015-12-21 14:18:36 +0900800 vif = netdev_priv(dev);
801 wl = vif->wilc;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900802
803 PRINT_D(INIT_DBG, "Initializing Locks ...\n");
804
Glen Lee38afb392015-10-20 17:13:53 +0900805 mutex_init(&wl->hif_cs);
806 mutex_init(&wl->rxq_cs);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900807
Glen Lee38afb392015-10-20 17:13:53 +0900808 spin_lock_init(&wl->txq_spinlock);
809 sema_init(&wl->txq_add_to_head_cs, 1);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900810
Glen Lee38afb392015-10-20 17:13:53 +0900811 sema_init(&wl->txq_event, 0);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900812
Glen Lee38afb392015-10-20 17:13:53 +0900813 sema_init(&wl->cfg_event, 0);
814 sema_init(&wl->sync_event, 0);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900815
Glen Lee38afb392015-10-20 17:13:53 +0900816 sema_init(&wl->txq_thread_started, 0);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900817
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900818 return 0;
819}
820
Glen Lee7c67c052015-10-27 18:27:50 +0900821static int wlan_deinit_locks(struct net_device *dev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900822{
Glen Leea4cac482015-12-21 14:18:36 +0900823 struct wilc_vif *vif;
Glen Lee7c67c052015-10-27 18:27:50 +0900824 struct wilc *wilc;
825
Glen Leea4cac482015-12-21 14:18:36 +0900826 vif = netdev_priv(dev);
827 wilc = vif->wilc;
Glen Lee7c67c052015-10-27 18:27:50 +0900828
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900829 PRINT_D(INIT_DBG, "De-Initializing Locks\n");
830
Leo Kim3a147c02015-11-05 14:36:10 +0900831 if (&wilc->hif_cs)
Glen Lee7c67c052015-10-27 18:27:50 +0900832 mutex_destroy(&wilc->hif_cs);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900833
Leo Kim3a147c02015-11-05 14:36:10 +0900834 if (&wilc->rxq_cs)
Glen Lee7c67c052015-10-27 18:27:50 +0900835 mutex_destroy(&wilc->rxq_cs);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900836
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900837 return 0;
838}
Leo Kima40b22c2015-11-05 14:36:32 +0900839
Arnd Bergmann1608c402015-11-16 15:04:53 +0100840static int wlan_initialize_threads(struct net_device *dev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900841{
Glen Leea4cac482015-12-21 14:18:36 +0900842 struct wilc_vif *vif;
Glen Lee75a94662015-10-27 18:27:45 +0900843 struct wilc *wilc;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900844
Glen Leea4cac482015-12-21 14:18:36 +0900845 vif = netdev_priv(dev);
846 wilc = vif->wilc;
Glen Lee75a94662015-10-27 18:27:45 +0900847
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900848 PRINT_D(INIT_DBG, "Initializing Threads ...\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900849 PRINT_D(INIT_DBG, "Creating kthread for transmission\n");
Glen Lee88687582015-10-27 18:27:46 +0900850 wilc->txq_thread = kthread_run(linux_wlan_txq_task, (void *)dev,
Glen Lee75a94662015-10-27 18:27:45 +0900851 "K_TXQ_TASK");
852 if (!wilc->txq_thread) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900853 PRINT_ER("couldn't create TXQ thread\n");
Leo Kim6bc72c52015-11-05 14:36:33 +0900854 wilc->close = 0;
855 return -ENOBUFS;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900856 }
Glen Lee75a94662015-10-27 18:27:45 +0900857 down(&wilc->txq_thread_started);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900858
859 return 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900860}
861
Glen Lee32dd51b2015-10-27 18:27:52 +0900862static void wlan_deinitialize_threads(struct net_device *dev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900863{
Glen Leea4cac482015-12-21 14:18:36 +0900864 struct wilc_vif *vif;
Glen Lee32dd51b2015-10-27 18:27:52 +0900865 struct wilc *wl;
Glen Leea4cac482015-12-21 14:18:36 +0900866 vif = netdev_priv(dev);
867 wl = vif->wilc;
Glen Lee32dd51b2015-10-27 18:27:52 +0900868
869 wl->close = 1;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900870 PRINT_D(INIT_DBG, "Deinitializing Threads\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900871
Leo Kim3a147c02015-11-05 14:36:10 +0900872 if (&wl->txq_event)
Glen Lee32dd51b2015-10-27 18:27:52 +0900873 up(&wl->txq_event);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900874
Leo Kim3a147c02015-11-05 14:36:10 +0900875 if (wl->txq_thread) {
Glen Lee32dd51b2015-10-27 18:27:52 +0900876 kthread_stop(wl->txq_thread);
877 wl->txq_thread = NULL;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900878 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900879}
880
Glen Leea4cac482015-12-21 14:18:36 +0900881int wilc1000_wlan_init(struct net_device *dev, struct wilc_vif *vif)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900882{
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900883 int ret = 0;
Glen Leea4cac482015-12-21 14:18:36 +0900884 struct wilc *wl = vif->wilc;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900885
Glen Lee0fa683b2015-10-20 17:13:52 +0900886 if (!wl->initialized) {
887 wl->mac_status = WILC_MAC_STATUS_INIT;
888 wl->close = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900889
Glen Lee38afb392015-10-20 17:13:53 +0900890 wlan_init_locks(dev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900891
Arnd Bergmann4bd7baf2015-11-16 15:04:59 +0100892 ret = wilc_wlan_init(dev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900893 if (ret < 0) {
894 PRINT_ER("Initializing WILC_Wlan FAILED\n");
895 ret = -EIO;
896 goto _fail_locks_;
897 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900898
Arnd Bergmannc4d139c2015-11-16 15:05:04 +0100899 if (wl->gpio >= 0 && init_irq(dev)) {
Tony Chob46d6882015-10-20 14:26:54 +0900900 PRINT_ER("couldn't initialize IRQ\n");
901 ret = -EIO;
902 goto _fail_locks_;
903 }
Tony Chob46d6882015-10-20 14:26:54 +0900904
Glen Lee75a94662015-10-27 18:27:45 +0900905 ret = wlan_initialize_threads(dev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900906 if (ret < 0) {
907 PRINT_ER("Initializing Threads FAILED\n");
908 ret = -EIO;
909 goto _fail_wilc_wlan_;
910 }
911
Arnd Bergmann5547c1f2015-11-16 15:05:06 +0100912 if (!wl->dev_irq_num &&
Glen Leeaf9ae092015-12-21 14:18:09 +0900913 wl->hif_func->enable_interrupt &&
914 wl->hif_func->enable_interrupt(wl)) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900915 PRINT_ER("couldn't initialize IRQ\n");
916 ret = -EIO;
917 goto _fail_irq_init_;
918 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900919
Arnd Bergmann0e1af732015-11-16 15:04:54 +0100920 if (wilc_wlan_get_firmware(dev)) {
Chandra S Gorentla17aacd42015-08-08 17:41:35 +0530921 PRINT_ER("Can't get firmware\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900922 ret = -EIO;
923 goto _fail_irq_enable_;
924 }
925
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100926 ret = wilc1000_firmware_download(dev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900927 if (ret < 0) {
928 PRINT_ER("Failed to download firmware\n");
929 ret = -EIO;
930 goto _fail_irq_enable_;
931 }
932
Glen Lee9bf3d722015-10-29 12:18:46 +0900933 ret = linux_wlan_start_firmware(dev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900934 if (ret < 0) {
935 PRINT_ER("Failed to start firmware\n");
936 ret = -EIO;
937 goto _fail_irq_enable_;
938 }
939
Glen Leed40c99c2015-11-18 15:11:35 +0900940 if (wilc_wlan_cfg_get(wl, 1, WID_FIRMWARE_VERSION, 1, 0)) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900941 int size;
942 char Firmware_ver[20];
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900943
Glen Lee894de36b2015-10-01 16:03:42 +0900944 size = wilc_wlan_cfg_get_val(
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900945 WID_FIRMWARE_VERSION,
946 Firmware_ver, sizeof(Firmware_ver));
947 Firmware_ver[size] = '\0';
948 PRINT_D(INIT_DBG, "***** Firmware Ver = %s *******\n", Firmware_ver);
949 }
Glen Lee0fa683b2015-10-20 17:13:52 +0900950 ret = linux_wlan_init_test_config(dev, wl);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900951
952 if (ret < 0) {
953 PRINT_ER("Failed to configure firmware\n");
954 ret = -EIO;
955 goto _fail_fw_start_;
956 }
957
Glen Lee0fa683b2015-10-20 17:13:52 +0900958 wl->initialized = true;
Leo Kim98b89842015-11-05 14:36:18 +0900959 return 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900960
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900961_fail_fw_start_:
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100962 wilc_wlan_stop(wl);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900963
964_fail_irq_enable_:
Arnd Bergmann5547c1f2015-11-16 15:05:06 +0100965 if (!wl->dev_irq_num &&
Glen Leeaf9ae092015-12-21 14:18:09 +0900966 wl->hif_func->disable_interrupt)
967 wl->hif_func->disable_interrupt(wl);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900968_fail_irq_init_:
Arnd Bergmannc4d139c2015-11-16 15:05:04 +0100969 if (wl->dev_irq_num)
970 deinit_irq(dev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900971
Glen Lee32dd51b2015-10-27 18:27:52 +0900972 wlan_deinitialize_threads(dev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900973_fail_wilc_wlan_:
Glen Lee2de7cbe2015-10-27 18:27:54 +0900974 wilc_wlan_cleanup(dev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900975_fail_locks_:
Glen Lee7c67c052015-10-27 18:27:50 +0900976 wlan_deinit_locks(dev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900977 PRINT_ER("WLAN Iinitialization FAILED\n");
978 } else {
979 PRINT_D(INIT_DBG, "wilc1000 already initialized\n");
980 }
981 return ret;
982}
983
Arnd Bergmann1608c402015-11-16 15:04:53 +0100984static int mac_init_fn(struct net_device *ndev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900985{
Leo Kim98b89842015-11-05 14:36:18 +0900986 netif_start_queue(ndev);
987 netif_stop_queue(ndev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900988
989 return 0;
990}
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900991
Arnd Bergmann0e1af732015-11-16 15:04:54 +0100992int wilc_mac_open(struct net_device *ndev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900993{
Glen Leea4cac482015-12-21 14:18:36 +0900994 struct wilc_vif *vif;
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100995 struct wilc *wilc;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900996
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900997 unsigned char mac_add[ETH_ALEN] = {0};
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900998 int ret = 0;
999 int i = 0;
Chaehyun Lim27268872015-09-15 14:06:13 +09001000 struct wilc_priv *priv;
Glen Leef3c13662015-10-20 17:13:54 +09001001 struct wilc *wl;
1002
Glen Leea4cac482015-12-21 14:18:36 +09001003 vif = netdev_priv(ndev);
1004 wl = vif->wilc;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001005
Arnd Bergmannb03314e2015-11-16 15:05:01 +01001006 if (!wl|| !wl->dev) {
Chandra S Gorentla7d056522015-09-15 18:09:51 +05301007 netdev_err(ndev, "wilc1000: SPI device not ready\n");
1008 return -ENODEV;
1009 }
Arnd Bergmannb03314e2015-11-16 15:05:01 +01001010
Glen Leea4cac482015-12-21 14:18:36 +09001011 vif = netdev_priv(ndev);
1012 wilc = vif->wilc;
Glen Lee1006b5c2015-12-21 14:18:38 +09001013 priv = wiphy_priv(vif->ndev->ieee80211_ptr->wiphy);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001014 PRINT_D(INIT_DBG, "MAC OPEN[%p]\n", ndev);
1015
Chaehyun Limdd4b6a82015-09-20 15:51:25 +09001016 ret = wilc_init_host_int(ndev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001017 if (ret < 0) {
1018 PRINT_ER("Failed to initialize host interface\n");
1019
1020 return ret;
1021 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001022
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001023 PRINT_D(INIT_DBG, "*** re-init ***\n");
Glen Leea4cac482015-12-21 14:18:36 +09001024 ret = wilc1000_wlan_init(ndev, vif);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001025 if (ret < 0) {
1026 PRINT_ER("Failed to initialize wilc1000\n");
Chaehyun Lima9a16822015-09-20 15:51:24 +09001027 wilc_deinit_host_int(ndev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001028 return ret;
1029 }
1030
Arnd Bergmann0e1af732015-11-16 15:04:54 +01001031 wilc_set_machw_change_vir_if(ndev, false);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001032
Glen Leefbf53792015-12-21 14:18:40 +09001033 wilc_get_mac_address(vif, mac_add);
Alexander Kuleshov310a28f2015-09-04 00:48:14 +06001034 PRINT_D(INIT_DBG, "Mac address: %pM\n", mac_add);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001035
Glen Leef3c13662015-10-20 17:13:54 +09001036 for (i = 0; i < wl->vif_num; i++) {
Glen Lee1f435d22015-12-21 14:18:37 +09001037 if (ndev == wl->vif[i]->ndev) {
1038 memcpy(wl->vif[i]->src_addr, mac_add, ETH_ALEN);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001039 break;
1040 }
1041 }
1042
Glen Lee1f435d22015-12-21 14:18:37 +09001043 memcpy(ndev->dev_addr, wl->vif[i]->src_addr, ETH_ALEN);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001044
1045 if (!is_valid_ether_addr(ndev->dev_addr)) {
1046 PRINT_ER("Error: Wrong MAC address\n");
Leo Kim339d2442015-11-05 14:36:34 +09001047 wilc_deinit_host_int(ndev);
1048 wilc1000_wlan_deinit(ndev);
1049 return -EINVAL;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001050 }
1051
Glen Lee1006b5c2015-12-21 14:18:38 +09001052 wilc_mgmt_frame_register(vif->ndev->ieee80211_ptr->wiphy,
1053 vif->ndev->ieee80211_ptr,
Glen Leea4cac482015-12-21 14:18:36 +09001054 vif->g_struct_frame_reg[0].frame_type,
1055 vif->g_struct_frame_reg[0].reg);
Glen Lee1006b5c2015-12-21 14:18:38 +09001056 wilc_mgmt_frame_register(vif->ndev->ieee80211_ptr->wiphy,
1057 vif->ndev->ieee80211_ptr,
Glen Leea4cac482015-12-21 14:18:36 +09001058 vif->g_struct_frame_reg[1].frame_type,
1059 vif->g_struct_frame_reg[1].reg);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001060 netif_wake_queue(ndev);
Glen Leef3c13662015-10-20 17:13:54 +09001061 wl->open_ifcs++;
Glen Leea4cac482015-12-21 14:18:36 +09001062 vif->mac_opened = 1;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001063 return 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001064}
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001065
Arnd Bergmann1608c402015-11-16 15:04:53 +01001066static struct net_device_stats *mac_stats(struct net_device *dev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001067{
Glen Leea4cac482015-12-21 14:18:36 +09001068 struct wilc_vif *vif= netdev_priv(dev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001069
Glen Leea4cac482015-12-21 14:18:36 +09001070 return &vif->netstats;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001071}
1072
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001073static void wilc_set_multicast_list(struct net_device *dev)
1074{
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001075 struct netdev_hw_addr *ha;
Chaehyun Lim27268872015-09-15 14:06:13 +09001076 struct wilc_priv *priv;
Leo Kimef7606c2015-11-05 14:36:14 +09001077 struct host_if_drv *hif_drv;
Glen Leecf601062015-12-21 14:18:39 +09001078 struct wilc_vif *vif;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001079 int i = 0;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +09001080
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001081 priv = wiphy_priv(dev->ieee80211_ptr->wiphy);
Glen Leecf601062015-12-21 14:18:39 +09001082 vif = netdev_priv(dev);
Leo Kimef7606c2015-11-05 14:36:14 +09001083 hif_drv = (struct host_if_drv *)priv->hWILCWFIDrv;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001084
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001085 if (!dev)
1086 return;
1087
Leo Kim582f8a22015-11-05 14:36:21 +09001088 PRINT_D(INIT_DBG, "Setting Multicast List with count = %d.\n",
1089 dev->mc.count);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001090
1091 if (dev->flags & IFF_PROMISC) {
Chandra S Gorentla17aacd42015-08-08 17:41:35 +05301092 PRINT_D(INIT_DBG, "Set promiscuous mode ON, retrive all packets\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001093 return;
1094 }
1095
Leo Kim582f8a22015-11-05 14:36:21 +09001096 if ((dev->flags & IFF_ALLMULTI) ||
1097 (dev->mc.count) > WILC_MULTICAST_TABLE_SIZE) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001098 PRINT_D(INIT_DBG, "Disable multicast filter, retrive all multicast packets\n");
Glen Leefbf53792015-12-21 14:18:40 +09001099 wilc_setup_multicast_filter(vif, false, 0);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001100 return;
1101 }
1102
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001103 if ((dev->mc.count) == 0) {
1104 PRINT_D(INIT_DBG, "Enable multicast filter, retrive directed packets only.\n");
Glen Leefbf53792015-12-21 14:18:40 +09001105 wilc_setup_multicast_filter(vif, true, 0);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001106 return;
1107 }
1108
Leo Kimc8537e62015-11-06 11:12:24 +09001109 netdev_for_each_mc_addr(ha, dev) {
Arnd Bergmann0e1af732015-11-16 15:04:54 +01001110 memcpy(wilc_multicast_mac_addr_list[i], ha->addr, ETH_ALEN);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001111 PRINT_D(INIT_DBG, "Entry[%d]: %x:%x:%x:%x:%x:%x\n", i,
Arnd Bergmann0e1af732015-11-16 15:04:54 +01001112 wilc_multicast_mac_addr_list[i][0],
1113 wilc_multicast_mac_addr_list[i][1],
1114 wilc_multicast_mac_addr_list[i][2],
1115 wilc_multicast_mac_addr_list[i][3],
1116 wilc_multicast_mac_addr_list[i][4],
1117 wilc_multicast_mac_addr_list[i][5]);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001118 i++;
1119 }
1120
Glen Leefbf53792015-12-21 14:18:40 +09001121 wilc_setup_multicast_filter(vif, true, (dev->mc.count));
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001122
1123 return;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001124}
1125
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001126static void linux_wlan_tx_complete(void *priv, int status)
1127{
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001128 struct tx_complete_data *pv_data = (struct tx_complete_data *)priv;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +09001129
Chandra S Gorentla78174ad2015-08-08 17:41:36 +05301130 if (status == 1)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001131 PRINT_D(TX_DBG, "Packet sent successfully - Size = %d - Address = %p - SKB = %p\n", pv_data->size, pv_data->buff, pv_data->skb);
Chandra S Gorentla78174ad2015-08-08 17:41:36 +05301132 else
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001133 PRINT_D(TX_DBG, "Couldn't send packet - Size = %d - Address = %p - SKB = %p\n", pv_data->size, pv_data->buff, pv_data->skb);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001134 dev_kfree_skb(pv_data->skb);
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -07001135 kfree(pv_data);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001136}
1137
Arnd Bergmann0e1af732015-11-16 15:04:54 +01001138int wilc_mac_xmit(struct sk_buff *skb, struct net_device *ndev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001139{
Glen Leea4cac482015-12-21 14:18:36 +09001140 struct wilc_vif *vif;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001141 struct tx_complete_data *tx_data = NULL;
Leo Kim44ec3b72015-11-05 14:36:38 +09001142 int queue_count;
Leo Kimfd8f0362015-11-05 14:36:39 +09001143 char *udp_buf;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001144 struct iphdr *ih;
1145 struct ethhdr *eth_h;
Glen Leeb7495be2015-10-27 18:28:01 +09001146 struct wilc *wilc;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +09001147
Glen Leea4cac482015-12-21 14:18:36 +09001148 vif = netdev_priv(ndev);
1149 wilc = vif->wilc;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001150
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001151 PRINT_D(TX_DBG, "Sending packet just received from TCP/IP\n");
1152
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001153 if (skb->dev != ndev) {
1154 PRINT_ER("Packet not destined to this device\n");
1155 return 0;
1156 }
1157
Leo Kimb38e9032015-11-06 11:12:23 +09001158 tx_data = kmalloc(sizeof(*tx_data), GFP_ATOMIC);
Leo Kim3a147c02015-11-05 14:36:10 +09001159 if (!tx_data) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001160 PRINT_ER("Failed to allocate memory for tx_data structure\n");
1161 dev_kfree_skb(skb);
1162 netif_wake_queue(ndev);
1163 return 0;
1164 }
1165
1166 tx_data->buff = skb->data;
1167 tx_data->size = skb->len;
1168 tx_data->skb = skb;
1169
1170 eth_h = (struct ethhdr *)(skb->data);
Kim, Leofc4b95d2015-07-28 17:47:37 +09001171 if (eth_h->h_proto == 0x8e88)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001172 PRINT_D(INIT_DBG, "EAPOL transmitted\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001173
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001174 ih = (struct iphdr *)(skb->data + sizeof(struct ethhdr));
1175
Leo Kimfd8f0362015-11-05 14:36:39 +09001176 udp_buf = (char *)ih + sizeof(struct iphdr);
1177 if ((udp_buf[1] == 68 && udp_buf[3] == 67) ||
1178 (udp_buf[1] == 67 && udp_buf[3] == 68))
1179 PRINT_D(GENERIC_DBG, "DHCP Message transmitted, type:%x %x %x\n",
1180 udp_buf[248], udp_buf[249], udp_buf[250]);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001181
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001182 PRINT_D(TX_DBG, "Sending packet - Size = %d - Address = %p - SKB = %p\n", tx_data->size, tx_data->buff, tx_data->skb);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001183 PRINT_D(TX_DBG, "Adding tx packet to TX Queue\n");
Glen Leea4cac482015-12-21 14:18:36 +09001184 vif->netstats.tx_packets++;
1185 vif->netstats.tx_bytes += tx_data->size;
Glen Lee1f435d22015-12-21 14:18:37 +09001186 tx_data->pBssid = wilc->vif[vif->u8IfIdx]->bssid;
Leo Kim44ec3b72015-11-05 14:36:38 +09001187 queue_count = wilc_wlan_txq_add_net_pkt(ndev, (void *)tx_data,
1188 tx_data->buff, tx_data->size,
1189 linux_wlan_tx_complete);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001190
Leo Kim44ec3b72015-11-05 14:36:38 +09001191 if (queue_count > FLOW_CONTROL_UPPER_THRESHOLD) {
Glen Lee1f435d22015-12-21 14:18:37 +09001192 netif_stop_queue(wilc->vif[0]->ndev);
1193 netif_stop_queue(wilc->vif[1]->ndev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001194 }
1195
1196 return 0;
1197}
1198
Arnd Bergmann0e1af732015-11-16 15:04:54 +01001199int wilc_mac_close(struct net_device *ndev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001200{
Chaehyun Lim27268872015-09-15 14:06:13 +09001201 struct wilc_priv *priv;
Glen Leea4cac482015-12-21 14:18:36 +09001202 struct wilc_vif *vif;
Leo Kim2db2c8a2015-11-05 14:36:15 +09001203 struct host_if_drv *hif_drv;
Glen Leeca64ad62015-10-20 17:13:55 +09001204 struct wilc *wl;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001205
Glen Leea4cac482015-12-21 14:18:36 +09001206 vif = netdev_priv(ndev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001207
Glen Lee1006b5c2015-12-21 14:18:38 +09001208 if (!vif || !vif->ndev || !vif->ndev->ieee80211_ptr ||
1209 !vif->ndev->ieee80211_ptr->wiphy) {
Glen Leea4cac482015-12-21 14:18:36 +09001210 PRINT_ER("vif = NULL\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001211 return 0;
1212 }
1213
Glen Lee1006b5c2015-12-21 14:18:38 +09001214 priv = wiphy_priv(vif->ndev->ieee80211_ptr->wiphy);
Glen Leea4cac482015-12-21 14:18:36 +09001215 wl = vif->wilc;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001216
Leo Kim3a147c02015-11-05 14:36:10 +09001217 if (!priv) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001218 PRINT_ER("priv = NULL\n");
1219 return 0;
1220 }
1221
Leo Kim2db2c8a2015-11-05 14:36:15 +09001222 hif_drv = (struct host_if_drv *)priv->hWILCWFIDrv;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001223
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001224 PRINT_D(GENERIC_DBG, "Mac close\n");
1225
Glen Leeca64ad62015-10-20 17:13:55 +09001226 if (!wl) {
1227 PRINT_ER("wl = NULL\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001228 return 0;
1229 }
1230
Leo Kim2db2c8a2015-11-05 14:36:15 +09001231 if (!hif_drv) {
1232 PRINT_ER("hif_drv = NULL\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001233 return 0;
1234 }
1235
Glen Leeca64ad62015-10-20 17:13:55 +09001236 if ((wl->open_ifcs) > 0) {
1237 wl->open_ifcs--;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001238 } else {
1239 PRINT_ER("ERROR: MAC close called while number of opened interfaces is zero\n");
1240 return 0;
1241 }
1242
Glen Lee1006b5c2015-12-21 14:18:38 +09001243 if (vif->ndev) {
1244 netif_stop_queue(vif->ndev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001245
Glen Lee1006b5c2015-12-21 14:18:38 +09001246 wilc_deinit_host_int(vif->ndev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001247 }
1248
Glen Leeca64ad62015-10-20 17:13:55 +09001249 if (wl->open_ifcs == 0) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001250 PRINT_D(GENERIC_DBG, "Deinitializing wilc1000\n");
Glen Leeca64ad62015-10-20 17:13:55 +09001251 wl->close = 1;
Glen Lee53dc0cf2015-10-20 17:13:57 +09001252 wilc1000_wlan_deinit(ndev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001253 WILC_WFI_deinit_mon_interface();
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001254 }
1255
Greg Kroah-Hartman8990d852015-09-03 20:07:58 -07001256 up(&close_exit_sync);
Glen Leea4cac482015-12-21 14:18:36 +09001257 vif->mac_opened = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001258
1259 return 0;
1260}
1261
Arnd Bergmann1608c402015-11-16 15:04:53 +01001262static int mac_ioctl(struct net_device *ndev, struct ifreq *req, int cmd)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001263{
Greg Kroah-Hartman63d03e42015-06-02 14:16:04 +09001264 u8 *buff = NULL;
Chaehyun Limca356ad2015-06-11 14:35:57 +09001265 s8 rssi;
Chaehyun Lim4e4467f2015-06-11 14:35:55 +09001266 u32 size = 0, length = 0;
Glen Leea4cac482015-12-21 14:18:36 +09001267 struct wilc_vif *vif;
Chaehyun Lim27268872015-09-15 14:06:13 +09001268 struct wilc_priv *priv;
Leo Kim9457b052015-11-05 14:36:37 +09001269 s32 ret = 0;
Glen Lee07320b62015-10-27 18:27:53 +09001270 struct wilc *wilc;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001271
Glen Leea4cac482015-12-21 14:18:36 +09001272 vif = netdev_priv(ndev);
1273 wilc = vif->wilc;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001274
Glen Lee07320b62015-10-27 18:27:53 +09001275 if (!wilc->initialized)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001276 return 0;
1277
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001278 switch (cmd) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001279 case SIOCSIWPRIV:
1280 {
Leo Kim98b89842015-11-05 14:36:18 +09001281 struct iwreq *wrq = (struct iwreq *) req;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001282
1283 size = wrq->u.data.length;
1284
1285 if (size && wrq->u.data.pointer) {
Leo Kim582f8a22015-11-05 14:36:21 +09001286 buff = memdup_user(wrq->u.data.pointer,
1287 wrq->u.data.length);
Sudip Mukherjee360e27a2015-09-04 15:34:15 +05301288 if (IS_ERR(buff))
1289 return PTR_ERR(buff);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001290
1291 if (strncasecmp(buff, "RSSI", length) == 0) {
Glen Lee1006b5c2015-12-21 14:18:38 +09001292 priv = wiphy_priv(vif->ndev->ieee80211_ptr->wiphy);
Glen Leefbf53792015-12-21 14:18:40 +09001293 ret = wilc_get_rssi(vif, &rssi);
Leo Kim9457b052015-11-05 14:36:37 +09001294 if (ret)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001295 PRINT_ER("Failed to send get rssi param's message queue ");
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001296 PRINT_INFO(GENERIC_DBG, "RSSI :%d\n", rssi);
1297
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001298 rssi += 5;
1299
1300 snprintf(buff, size, "rssi %d", rssi);
1301
1302 if (copy_to_user(wrq->u.data.pointer, buff, size)) {
Chaehyun Lim60cb1e22015-06-19 09:06:28 +09001303 PRINT_ER("%s: failed to copy data to user buffer\n", __func__);
Leo Kim9457b052015-11-05 14:36:37 +09001304 ret = -EFAULT;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001305 goto done;
1306 }
1307 }
1308 }
1309 }
1310 break;
1311
1312 default:
1313 {
1314 PRINT_INFO(GENERIC_DBG, "Command - %d - has been received\n", cmd);
Leo Kim9457b052015-11-05 14:36:37 +09001315 ret = -EOPNOTSUPP;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001316 goto done;
1317 }
1318 }
1319
1320done:
1321
Shraddha Barke642ac6c2015-08-10 13:30:33 +05301322 kfree(buff);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001323
Leo Kim9457b052015-11-05 14:36:37 +09001324 return ret;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001325}
1326
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001327void wilc_frmw_to_linux(struct wilc *wilc, u8 *buff, u32 size, u32 pkt_offset)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001328{
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001329 unsigned int frame_len = 0;
1330 int stats;
1331 unsigned char *buff_to_send = NULL;
1332 struct sk_buff *skb;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001333 struct net_device *wilc_netdev;
Glen Leea4cac482015-12-21 14:18:36 +09001334 struct wilc_vif *vif;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001335
Leo Kim7e725b42015-11-05 14:36:24 +09001336 wilc_netdev = get_if_handler(wilc, buff);
Leo Kim3a147c02015-11-05 14:36:10 +09001337 if (!wilc_netdev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001338 return;
1339
1340 buff += pkt_offset;
Glen Leea4cac482015-12-21 14:18:36 +09001341 vif = netdev_priv(wilc_netdev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001342
1343 if (size > 0) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001344 frame_len = size;
1345 buff_to_send = buff;
1346
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001347 skb = dev_alloc_skb(frame_len);
Leo Kim3a147c02015-11-05 14:36:10 +09001348 if (!skb) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001349 PRINT_ER("Low memory - packet droped\n");
1350 return;
1351 }
1352
Leo Kim3a147c02015-11-05 14:36:10 +09001353 if (!wilc || !wilc_netdev)
Glen Leecb1991a2015-10-27 18:27:56 +09001354 PRINT_ER("wilc_netdev in wilc is NULL");
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001355 skb->dev = wilc_netdev;
1356
Leo Kim3a147c02015-11-05 14:36:10 +09001357 if (!skb->dev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001358 PRINT_ER("skb->dev is NULL\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001359
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001360 memcpy(skb_put(skb, frame_len), buff_to_send, frame_len);
1361
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001362 skb->protocol = eth_type_trans(skb, wilc_netdev);
Glen Leea4cac482015-12-21 14:18:36 +09001363 vif->netstats.rx_packets++;
1364 vif->netstats.rx_bytes += frame_len;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001365 skb->ip_summed = CHECKSUM_UNNECESSARY;
1366 stats = netif_rx(skb);
1367 PRINT_D(RX_DBG, "netif_rx ret value is: %d\n", stats);
1368 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001369}
1370
Glen Lee11f4b2e2015-10-27 18:27:51 +09001371void WILC_WFI_mgmt_rx(struct wilc *wilc, u8 *buff, u32 size)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001372{
1373 int i = 0;
Glen Leea4cac482015-12-21 14:18:36 +09001374 struct wilc_vif *vif;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001375
Glen Lee11f4b2e2015-10-27 18:27:51 +09001376 for (i = 0; i < wilc->vif_num; i++) {
Glen Lee1f435d22015-12-21 14:18:37 +09001377 vif = netdev_priv(wilc->vif[i]->ndev);
Glen Leea4cac482015-12-21 14:18:36 +09001378 if (vif->monitor_flag) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001379 WILC_WFI_monitor_rx(buff, size);
1380 return;
1381 }
1382 }
1383
Glen Lee1f435d22015-12-21 14:18:37 +09001384 vif = netdev_priv(wilc->vif[1]->ndev);
Glen Leea4cac482015-12-21 14:18:36 +09001385 if ((buff[0] == vif->g_struct_frame_reg[0].frame_type && vif->g_struct_frame_reg[0].reg) ||
1386 (buff[0] == vif->g_struct_frame_reg[1].frame_type && vif->g_struct_frame_reg[1].reg))
Glen Lee1f435d22015-12-21 14:18:37 +09001387 WILC_WFI_p2p_rx(wilc->vif[1]->ndev, buff, size);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001388}
1389
Arnd Bergmann857c7b02015-11-16 15:05:00 +01001390void wilc_netdev_cleanup(struct wilc *wilc)
Tony Cho4875c492015-10-20 14:26:52 +09001391{
1392 int i = 0;
Glen Leea4cac482015-12-21 14:18:36 +09001393 struct wilc_vif *vif[NUM_CONCURRENT_IFC];
Tony Cho4875c492015-10-20 14:26:52 +09001394
Glen Lee1f435d22015-12-21 14:18:37 +09001395 if (wilc && (wilc->vif[0]->ndev || wilc->vif[1]->ndev)) {
Tony Cho4875c492015-10-20 14:26:52 +09001396 unregister_inetaddr_notifier(&g_dev_notifier);
1397
1398 for (i = 0; i < NUM_CONCURRENT_IFC; i++)
Glen Lee1f435d22015-12-21 14:18:37 +09001399 vif[i] = netdev_priv(wilc->vif[i]->ndev);
Tony Cho4875c492015-10-20 14:26:52 +09001400 }
1401
Glen Lee90b984c2015-10-29 12:18:50 +09001402 if (wilc && wilc->firmware)
1403 release_firmware(wilc->firmware);
Tony Cho4875c492015-10-20 14:26:52 +09001404
Glen Lee1f435d22015-12-21 14:18:37 +09001405 if (wilc && (wilc->vif[0]->ndev || wilc->vif[1]->ndev)) {
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001406 wilc_lock_timeout(wilc, &close_exit_sync, 12 * 1000);
Tony Cho4875c492015-10-20 14:26:52 +09001407
1408 for (i = 0; i < NUM_CONCURRENT_IFC; i++)
Glen Lee1f435d22015-12-21 14:18:37 +09001409 if (wilc->vif[i]->ndev)
Glen Leea4cac482015-12-21 14:18:36 +09001410 if (vif[i]->mac_opened)
Glen Lee1f435d22015-12-21 14:18:37 +09001411 wilc_mac_close(wilc->vif[i]->ndev);
Tony Cho4875c492015-10-20 14:26:52 +09001412
1413 for (i = 0; i < NUM_CONCURRENT_IFC; i++) {
Glen Lee1f435d22015-12-21 14:18:37 +09001414 unregister_netdev(wilc->vif[i]->ndev);
1415 wilc_free_wiphy(wilc->vif[i]->ndev);
1416 free_netdev(wilc->vif[i]->ndev);
Tony Cho4875c492015-10-20 14:26:52 +09001417 }
1418 }
1419
Glen Lee90b984c2015-10-29 12:18:50 +09001420 kfree(wilc);
Tony Cho4875c492015-10-20 14:26:52 +09001421}
Arnd Bergmann750ffe92015-11-16 15:05:08 +01001422EXPORT_SYMBOL_GPL(wilc_netdev_cleanup);
Tony Cho4875c492015-10-20 14:26:52 +09001423
Arnd Bergmann7d37a4a2015-11-16 15:05:05 +01001424int wilc_netdev_init(struct wilc **wilc, struct device *dev, int io_type,
1425 int gpio, const struct wilc_hif_func *ops)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001426{
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001427 int i;
Glen Leea4cac482015-12-21 14:18:36 +09001428 struct wilc_vif *vif;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001429 struct net_device *ndev;
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001430 struct wilc *wl;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001431
Greg Kroah-Hartman642768e2015-09-03 19:56:21 -07001432 sema_init(&close_exit_sync, 0);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001433
Glen Lee825b9662015-11-18 15:11:37 +09001434 wl = kzalloc(sizeof(*wl), GFP_KERNEL);
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001435 if (!wl)
Chaehyun Limac61ef82015-09-08 00:36:36 +09001436 return -ENOMEM;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001437
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001438 *wilc = wl;
1439 wl->io_type = io_type;
1440 wl->gpio = gpio;
Glen Leeaf9ae092015-12-21 14:18:09 +09001441 wl->hif_func = ops;
Arnd Bergmannc4d139c2015-11-16 15:05:04 +01001442
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001443 register_inetaddr_notifier(&g_dev_notifier);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001444
1445 for (i = 0; i < NUM_CONCURRENT_IFC; i++) {
Glen Leea4cac482015-12-21 14:18:36 +09001446 ndev = alloc_etherdev(sizeof(struct wilc_vif));
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001447 if (!ndev) {
1448 PRINT_ER("Failed to allocate ethernet dev\n");
1449 return -1;
1450 }
1451
Glen Leea4cac482015-12-21 14:18:36 +09001452 vif = netdev_priv(ndev);
1453 memset(vif, 0, sizeof(struct wilc_vif));
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001454
Leo Kim84d3b872015-11-05 14:36:19 +09001455 if (i == 0)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001456 strcpy(ndev->name, "wlan%d");
Leo Kim84d3b872015-11-05 14:36:19 +09001457 else
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001458 strcpy(ndev->name, "p2p%d");
1459
Glen Leea4cac482015-12-21 14:18:36 +09001460 vif->u8IfIdx = wl->vif_num;
Glen Leea4cac482015-12-21 14:18:36 +09001461 vif->wilc = *wilc;
Glen Lee1f435d22015-12-21 14:18:37 +09001462 wl->vif[i] = vif;
1463 wl->vif[wl->vif_num]->ndev = ndev;
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001464 wl->vif_num++;
Arnd Bergmanne5af0562015-05-29 22:52:12 +02001465 ndev->netdev_ops = &wilc_netdev_ops;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001466
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001467 {
1468 struct wireless_dev *wdev;
Arnd Bergmann2e7d5372015-11-16 15:05:03 +01001469 wdev = wilc_create_wiphy(ndev, dev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001470
Arnd Bergmann67039922015-11-16 15:05:02 +01001471 if (dev)
1472 SET_NETDEV_DEV(ndev, dev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001473
Leo Kim3a147c02015-11-05 14:36:10 +09001474 if (!wdev) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001475 PRINT_ER("Can't register WILC Wiphy\n");
1476 return -1;
1477 }
1478
Glen Lee1006b5c2015-12-21 14:18:38 +09001479 vif->ndev->ieee80211_ptr = wdev;
1480 vif->ndev->ml_priv = vif;
1481 wdev->netdev = vif->ndev;
Glen Leea4cac482015-12-21 14:18:36 +09001482 vif->netstats.rx_packets = 0;
1483 vif->netstats.tx_packets = 0;
1484 vif->netstats.rx_bytes = 0;
1485 vif->netstats.tx_bytes = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001486 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001487
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001488 if (register_netdev(ndev)) {
Leo Kim582f8a22015-11-05 14:36:21 +09001489 PRINT_ER("Device couldn't be registered - %s\n",
1490 ndev->name);
Leo Kim98b89842015-11-05 14:36:18 +09001491 return -1;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001492 }
1493
Glen Leea4cac482015-12-21 14:18:36 +09001494 vif->iftype = STATION_MODE;
1495 vif->mac_opened = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001496 }
1497
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001498 return 0;
1499}
Arnd Bergmann750ffe92015-11-16 15:05:08 +01001500EXPORT_SYMBOL_GPL(wilc_netdev_init);
Arnd Bergmannc94f05e2015-11-16 15:05:09 +01001501
1502MODULE_LICENSE("GPL");