Commit | Line | Data |
---|---|---|
903ac63f | 1 | // SPDX-License-Identifier: GPL-2.0 |
c5c77ba1 | 2 | #include <linux/irq.h> |
f1a99830 | 3 | #include <linux/gpio.h> |
c5c77ba1 JK |
4 | #include <linux/kthread.h> |
5 | #include <linux/firmware.h> | |
c5c77ba1 | 6 | #include <linux/netdevice.h> |
c5c77ba1 | 7 | #include <linux/inetdevice.h> |
880e404e AS |
8 | |
9 | #include "wilc_wfi_cfgoperations.h" | |
c5c77ba1 | 10 | |
0e1af73d | 11 | bool wilc_enable_ps = true; |
c5c77ba1 | 12 | |
885cabcc LK |
13 | static int dev_state_ev_handler(struct notifier_block *this, |
14 | unsigned long event, void *ptr) | |
c5c77ba1 | 15 | { |
d5c89442 | 16 | struct in_ifaddr *dev_iface = ptr; |
2726887c | 17 | struct wilc_priv *priv; |
f24374aa | 18 | struct host_if_drv *hif_drv; |
c5c77ba1 | 19 | struct net_device *dev; |
eac3e8f6 | 20 | u8 *ip_addr_buf; |
a4cac481 | 21 | struct wilc_vif *vif; |
63d03e47 | 22 | u8 null_ip[4] = {0}; |
c5c77ba1 JK |
23 | char wlan_dev_name[5] = "wlan0"; |
24 | ||
1408603c | 25 | if (!dev_iface || !dev_iface->ifa_dev || !dev_iface->ifa_dev->dev) |
c5c77ba1 | 26 | return NOTIFY_DONE; |
c5c77ba1 | 27 | |
582f8a27 | 28 | if (memcmp(dev_iface->ifa_label, "wlan0", 5) && |
1408603c | 29 | memcmp(dev_iface->ifa_label, "p2p0", 4)) |
c5c77ba1 | 30 | return NOTIFY_DONE; |
c5c77ba1 JK |
31 | |
32 | dev = (struct net_device *)dev_iface->ifa_dev->dev; | |
1408603c | 33 | if (!dev->ieee80211_ptr || !dev->ieee80211_ptr->wiphy) |
c5c77ba1 | 34 | return NOTIFY_DONE; |
1408603c | 35 | |
c5c77ba1 | 36 | priv = wiphy_priv(dev->ieee80211_ptr->wiphy); |
1408603c | 37 | if (!priv) |
c5c77ba1 | 38 | return NOTIFY_DONE; |
1408603c | 39 | |
48b28df9 | 40 | hif_drv = (struct host_if_drv *)priv->hif_drv; |
a4cac481 | 41 | vif = netdev_priv(dev); |
1408603c | 42 | if (!vif || !hif_drv) |
c5c77ba1 | 43 | return NOTIFY_DONE; |
c5c77ba1 JK |
44 | |
45 | switch (event) { | |
46 | case NETDEV_UP: | |
a4cac481 | 47 | if (vif->iftype == STATION_MODE || vif->iftype == CLIENT_MODE) { |
f24374aa | 48 | hif_drv->IFC_UP = 1; |
0e1af73d AB |
49 | wilc_optaining_ip = false; |
50 | del_timer(&wilc_during_ip_timer); | |
c5c77ba1 JK |
51 | } |
52 | ||
0e1af73d | 53 | if (wilc_enable_ps) |
fbf5379b | 54 | wilc_set_power_mgmt(vif, 1, 0); |
c5c77ba1 | 55 | |
5ac24427 | 56 | netdev_dbg(dev, "[%s] Up IP\n", dev_iface->ifa_label); |
c5c77ba1 | 57 | |
eac3e8f6 | 58 | ip_addr_buf = (char *)&dev_iface->ifa_address; |
5ac24427 LK |
59 | netdev_dbg(dev, "IP add=%d:%d:%d:%d\n", |
60 | ip_addr_buf[0], ip_addr_buf[1], | |
61 | ip_addr_buf[2], ip_addr_buf[3]); | |
6750140d | 62 | wilc_setup_ipaddress(vif, ip_addr_buf, vif->idx); |
c5c77ba1 JK |
63 | |
64 | break; | |
65 | ||
66 | case NETDEV_DOWN: | |
a4cac481 | 67 | if (vif->iftype == STATION_MODE || vif->iftype == CLIENT_MODE) { |
f24374aa | 68 | hif_drv->IFC_UP = 0; |
0e1af73d | 69 | wilc_optaining_ip = false; |
c5c77ba1 JK |
70 | } |
71 | ||
72 | if (memcmp(dev_iface->ifa_label, wlan_dev_name, 5) == 0) | |
fbf5379b | 73 | wilc_set_power_mgmt(vif, 0, 0); |
c5c77ba1 | 74 | |
fbf5379b | 75 | wilc_resolve_disconnect_aberration(vif); |
c5c77ba1 | 76 | |
5ac24427 | 77 | netdev_dbg(dev, "[%s] Down IP\n", dev_iface->ifa_label); |
c5c77ba1 | 78 | |
eac3e8f6 | 79 | ip_addr_buf = null_ip; |
5ac24427 LK |
80 | netdev_dbg(dev, "IP add=%d:%d:%d:%d\n", |
81 | ip_addr_buf[0], ip_addr_buf[1], | |
82 | ip_addr_buf[2], ip_addr_buf[3]); | |
c5c77ba1 | 83 | |
6750140d | 84 | wilc_setup_ipaddress(vif, ip_addr_buf, vif->idx); |
c5c77ba1 JK |
85 | |
86 | break; | |
87 | ||
88 | default: | |
c5c77ba1 JK |
89 | break; |
90 | } | |
91 | ||
92 | return NOTIFY_DONE; | |
c5c77ba1 | 93 | } |
c5c77ba1 | 94 | |
c5c77ba1 JK |
95 | static irqreturn_t isr_uh_routine(int irq, void *user_data) |
96 | { | |
a4cac481 | 97 | struct wilc_vif *vif; |
3948362d | 98 | struct wilc *wilc; |
d5c89442 | 99 | struct net_device *dev = user_data; |
3948362d | 100 | |
a4cac481 GL |
101 | vif = netdev_priv(dev); |
102 | wilc = vif->wilc; | |
c5c77ba1 | 103 | |
3948362d | 104 | if (wilc->close) { |
5ac24427 | 105 | netdev_err(dev, "Can't handle UH interrupt\n"); |
c5c77ba1 | 106 | return IRQ_HANDLED; |
c5c77ba1 | 107 | } |
c5c77ba1 | 108 | return IRQ_WAKE_THREAD; |
c5c77ba1 | 109 | } |
c5c77ba1 | 110 | |
1608c403 | 111 | static irqreturn_t isr_bh_routine(int irq, void *userdata) |
c5c77ba1 | 112 | { |
a4cac481 | 113 | struct wilc_vif *vif; |
2e7933d0 | 114 | struct wilc *wilc; |
d5c89442 | 115 | struct net_device *dev = userdata; |
2e7933d0 | 116 | |
a4cac481 GL |
117 | vif = netdev_priv(userdata); |
118 | wilc = vif->wilc; | |
2e7933d0 | 119 | |
2e7933d0 | 120 | if (wilc->close) { |
5ac24427 | 121 | netdev_err(dev, "Can't handle BH interrupt\n"); |
c5c77ba1 | 122 | return IRQ_HANDLED; |
c5c77ba1 JK |
123 | } |
124 | ||
50b929e0 | 125 | wilc_handle_isr(wilc); |
c5c77ba1 | 126 | |
c5c77ba1 | 127 | return IRQ_HANDLED; |
c5c77ba1 | 128 | } |
c5c77ba1 | 129 | |
2c1d05d1 | 130 | static int init_irq(struct net_device *dev) |
c5c77ba1 JK |
131 | { |
132 | int ret = 0; | |
a4cac481 | 133 | struct wilc_vif *vif; |
2c1d05d1 GL |
134 | struct wilc *wl; |
135 | ||
a4cac481 GL |
136 | vif = netdev_priv(dev); |
137 | wl = vif->wilc; | |
c5c77ba1 | 138 | |
c4d139cb AB |
139 | if ((gpio_request(wl->gpio, "WILC_INTR") == 0) && |
140 | (gpio_direction_input(wl->gpio) == 0)) { | |
141 | wl->dev_irq_num = gpio_to_irq(wl->gpio); | |
c5c77ba1 JK |
142 | } else { |
143 | ret = -1; | |
5ac24427 | 144 | netdev_err(dev, "could not obtain gpio for WILC_INTR\n"); |
c5c77ba1 JK |
145 | } |
146 | ||
83231b72 LK |
147 | if (ret != -1 && request_threaded_irq(wl->dev_irq_num, |
148 | isr_uh_routine, | |
149 | isr_bh_routine, | |
150 | IRQF_TRIGGER_LOW | IRQF_ONESHOT, | |
151 | "WILC_IRQ", dev) < 0) { | |
5ac24427 | 152 | netdev_err(dev, "Failed to request IRQ GPIO: %d\n", wl->gpio); |
c4d139cb | 153 | gpio_free(wl->gpio); |
c5c77ba1 JK |
154 | ret = -1; |
155 | } else { | |
5ac24427 LK |
156 | netdev_dbg(dev, |
157 | "IRQ request succeeded IRQ-NUM= %d on GPIO: %d\n", | |
158 | wl->dev_irq_num, wl->gpio); | |
c5c77ba1 JK |
159 | } |
160 | ||
161 | return ret; | |
162 | } | |
c5c77ba1 | 163 | |
ec5cc750 | 164 | static void deinit_irq(struct net_device *dev) |
c5c77ba1 | 165 | { |
a4cac481 | 166 | struct wilc_vif *vif; |
ec5cc750 GL |
167 | struct wilc *wilc; |
168 | ||
a4cac481 GL |
169 | vif = netdev_priv(dev); |
170 | wilc = vif->wilc; | |
ec5cc750 | 171 | |
1cce2000 | 172 | /* Deinitialize IRQ */ |
c4d139cb | 173 | if (wilc->dev_irq_num) { |
ec5cc750 | 174 | free_irq(wilc->dev_irq_num, wilc); |
c4d139cb | 175 | gpio_free(wilc->gpio); |
c5c77ba1 | 176 | } |
c5c77ba1 JK |
177 | } |
178 | ||
562ed3f1 | 179 | void wilc_mac_indicate(struct wilc *wilc, int flag) |
c5c77ba1 | 180 | { |
c5c77ba1 JK |
181 | int status; |
182 | ||
183 | if (flag == WILC_MAC_INDICATE_STATUS) { | |
582f8a27 LK |
184 | wilc_wlan_cfg_get_val(WID_STATUS, |
185 | (unsigned char *)&status, 4); | |
52b1d208 | 186 | if (wilc->mac_status == MAC_STATUS_INIT) { |
64f2b71b | 187 | wilc->mac_status = status; |
04247e7d | 188 | complete(&wilc->sync_event); |
c5c77ba1 | 189 | } else { |
64f2b71b | 190 | wilc->mac_status = status; |
c5c77ba1 | 191 | } |
c5c77ba1 | 192 | } |
c5c77ba1 JK |
193 | } |
194 | ||
1608c403 | 195 | static struct net_device *get_if_handler(struct wilc *wilc, u8 *mac_header) |
c5c77ba1 | 196 | { |
660786ea | 197 | u8 *bssid, *bssid1; |
c5c77ba1 JK |
198 | int i = 0; |
199 | ||
d239222e | 200 | bssid = mac_header + 10; |
660786ea | 201 | bssid1 = mac_header + 4; |
c5c77ba1 | 202 | |
ba615f1e GL |
203 | for (i = 0; i < wilc->vif_num; i++) { |
204 | if (wilc->vif[i]->mode == STATION_MODE) | |
fa633941 LK |
205 | if (ether_addr_equal_unaligned(bssid, |
206 | wilc->vif[i]->bssid)) | |
ba615f1e GL |
207 | return wilc->vif[i]->ndev; |
208 | if (wilc->vif[i]->mode == AP_MODE) | |
fa633941 LK |
209 | if (ether_addr_equal_unaligned(bssid1, |
210 | wilc->vif[i]->bssid)) | |
ba615f1e GL |
211 | return wilc->vif[i]->ndev; |
212 | } | |
8259a53e | 213 | |
c5c77ba1 JK |
214 | return NULL; |
215 | } | |
216 | ||
ba615f1e | 217 | int wilc_wlan_set_bssid(struct net_device *wilc_netdev, u8 *bssid, u8 mode) |
c5c77ba1 | 218 | { |
735bb39c | 219 | struct wilc_vif *vif = netdev_priv(wilc_netdev); |
472791a9 | 220 | |
735bb39c AB |
221 | memcpy(vif->bssid, bssid, 6); |
222 | vif->mode = mode; | |
8259a53e | 223 | |
735bb39c | 224 | return 0; |
c5c77ba1 JK |
225 | } |
226 | ||
562ed3f1 | 227 | int wilc_wlan_get_num_conn_ifcs(struct wilc *wilc) |
c5c77ba1 | 228 | { |
51e825f7 CL |
229 | u8 i = 0; |
230 | u8 null_bssid[6] = {0}; | |
231 | u8 ret_val = 0; | |
c5c77ba1 | 232 | |
562ed3f1 | 233 | for (i = 0; i < wilc->vif_num; i++) |
1f435d2e | 234 | if (memcmp(wilc->vif[i]->bssid, null_bssid, 6)) |
c5c77ba1 | 235 | ret_val++; |
8259a53e | 236 | |
c5c77ba1 JK |
237 | return ret_val; |
238 | } | |
239 | ||
c5c77ba1 JK |
240 | static int linux_wlan_txq_task(void *vp) |
241 | { | |
8a88dd46 IS |
242 | int ret; |
243 | u32 txq_count; | |
a4cac481 | 244 | struct wilc_vif *vif; |
88687584 GL |
245 | struct wilc *wl; |
246 | struct net_device *dev = vp; | |
c5c77ba1 | 247 | |
a4cac481 GL |
248 | vif = netdev_priv(dev); |
249 | wl = vif->wilc; | |
88687584 | 250 | |
11a54b3f | 251 | complete(&wl->txq_thread_started); |
c5c77ba1 | 252 | while (1) { |
b27a6d5e | 253 | wait_for_completion(&wl->txq_event); |
c5c77ba1 | 254 | |
88687584 | 255 | if (wl->close) { |
11a54b3f | 256 | complete(&wl->txq_thread_started); |
c5c77ba1 JK |
257 | |
258 | while (!kthread_should_stop()) | |
259 | schedule(); | |
c5c77ba1 JK |
260 | break; |
261 | } | |
c5c77ba1 | 262 | do { |
a1332cad | 263 | ret = wilc_wlan_handle_txq(dev, &txq_count); |
98b89847 | 264 | if (txq_count < FLOW_CONTROL_LOWER_THRESHOLD) { |
1f435d2e GL |
265 | if (netif_queue_stopped(wl->vif[0]->ndev)) |
266 | netif_wake_queue(wl->vif[0]->ndev); | |
267 | if (netif_queue_stopped(wl->vif[1]->ndev)) | |
268 | netif_wake_queue(wl->vif[1]->ndev); | |
c5c77ba1 | 269 | } |
98b89847 | 270 | } while (ret == WILC_TX_ERR_NO_BUF && !wl->close); |
c5c77ba1 JK |
271 | } |
272 | return 0; | |
273 | } | |
274 | ||
ead6cb05 | 275 | static int wilc_wlan_get_firmware(struct net_device *dev) |
c5c77ba1 | 276 | { |
a4cac481 | 277 | struct wilc_vif *vif; |
65c8adcf | 278 | struct wilc *wilc; |
14823bf2 | 279 | int chip_id, ret = 0; |
c5c77ba1 JK |
280 | const struct firmware *wilc_firmware; |
281 | char *firmware; | |
282 | ||
a4cac481 GL |
283 | vif = netdev_priv(dev); |
284 | wilc = vif->wilc; | |
65c8adcf | 285 | |
65c3f000 | 286 | chip_id = wilc_get_chipid(wilc, false); |
14823bf2 GL |
287 | |
288 | if (chip_id < 0x1003a0) | |
289 | firmware = FIRMWARE_1002; | |
290 | else | |
291 | firmware = FIRMWARE_1003; | |
292 | ||
293 | netdev_info(dev, "loading firmware %s\n", firmware); | |
c5c77ba1 | 294 | |
1408603c | 295 | if (!(&vif->ndev->dev)) |
5fe678b1 | 296 | goto fail; |
c5c77ba1 | 297 | |
b03314e2 | 298 | if (request_firmware(&wilc_firmware, firmware, wilc->dev) != 0) { |
b9811891 | 299 | netdev_err(dev, "%s - firmware not available\n", firmware); |
c5c77ba1 | 300 | ret = -1; |
5fe678b1 | 301 | goto fail; |
c5c77ba1 | 302 | } |
65c8adcf | 303 | wilc->firmware = wilc_firmware; |
c5c77ba1 | 304 | |
5fe678b1 | 305 | fail: |
c5c77ba1 JK |
306 | |
307 | return ret; | |
c5c77ba1 JK |
308 | } |
309 | ||
9bf3d727 | 310 | static int linux_wlan_start_firmware(struct net_device *dev) |
c5c77ba1 | 311 | { |
a4cac481 | 312 | struct wilc_vif *vif; |
9bf3d727 | 313 | struct wilc *wilc; |
c5c77ba1 | 314 | int ret = 0; |
9bf3d727 | 315 | |
a4cac481 GL |
316 | vif = netdev_priv(dev); |
317 | wilc = vif->wilc; | |
9bf3d727 | 318 | |
562ed3f1 | 319 | ret = wilc_wlan_start(wilc); |
1408603c | 320 | if (ret < 0) |
0aeea1ad | 321 | return ret; |
c5c77ba1 | 322 | |
04247e7d | 323 | if (!wait_for_completion_timeout(&wilc->sync_event, |
36190caa | 324 | msecs_to_jiffies(5000))) |
04247e7d | 325 | return -ETIME; |
c5c77ba1 | 326 | |
0aeea1ad | 327 | return 0; |
c5c77ba1 | 328 | } |
a40b22c5 | 329 | |
562ed3f1 | 330 | static int wilc1000_firmware_download(struct net_device *dev) |
c5c77ba1 | 331 | { |
a4cac481 | 332 | struct wilc_vif *vif; |
ed760b67 | 333 | struct wilc *wilc; |
c5c77ba1 JK |
334 | int ret = 0; |
335 | ||
a4cac481 GL |
336 | vif = netdev_priv(dev); |
337 | wilc = vif->wilc; | |
ed760b67 GL |
338 | |
339 | if (!wilc->firmware) { | |
5ac24427 | 340 | netdev_err(dev, "Firmware buffer is NULL\n"); |
14b1821d | 341 | return -ENOBUFS; |
c5c77ba1 | 342 | } |
1408603c | 343 | |
562ed3f1 | 344 | ret = wilc_wlan_firmware_download(wilc, wilc->firmware->data, |
ed760b67 | 345 | wilc->firmware->size); |
fc4b95d6 | 346 | if (ret < 0) |
14b1821d | 347 | return ret; |
c5c77ba1 | 348 | |
ed760b67 | 349 | release_firmware(wilc->firmware); |
6f72ed75 | 350 | wilc->firmware = NULL; |
c5c77ba1 | 351 | |
5ac24427 | 352 | netdev_dbg(dev, "Download Succeeded\n"); |
c5c77ba1 | 353 | |
14b1821d | 354 | return 0; |
c5c77ba1 JK |
355 | } |
356 | ||
00215dde | 357 | static int linux_wlan_init_test_config(struct net_device *dev, |
b8f6ca0b | 358 | struct wilc_vif *vif) |
c5c77ba1 | 359 | { |
c5c77ba1 | 360 | unsigned char c_val[64]; |
b8f6ca0b | 361 | struct wilc *wilc = vif->wilc; |
2726887c | 362 | struct wilc_priv *priv; |
0fa66c71 | 363 | struct host_if_drv *hif_drv; |
c5c77ba1 | 364 | |
5ac24427 | 365 | netdev_dbg(dev, "Start configuring Firmware\n"); |
c5c77ba1 | 366 | priv = wiphy_priv(dev->ieee80211_ptr->wiphy); |
48b28df9 | 367 | hif_drv = (struct host_if_drv *)priv->hif_drv; |
5ac24427 | 368 | netdev_dbg(dev, "Host = %p\n", hif_drv); |
65c3f000 | 369 | wilc_get_chipid(wilc, false); |
c5c77ba1 | 370 | |
e5d57e91 | 371 | *(int *)c_val = 1; |
c5c77ba1 | 372 | |
79df6a49 | 373 | if (!wilc_wlan_cfg_set(vif, 1, WID_SET_DRV_HANDLER, c_val, 4, 0, 0)) |
5fe678b1 | 374 | goto fail; |
c5c77ba1 | 375 | |
c5c77ba1 | 376 | c_val[0] = 0; |
79df6a49 | 377 | if (!wilc_wlan_cfg_set(vif, 0, WID_PC_TEST_MODE, c_val, 1, 0, 0)) |
5fe678b1 | 378 | goto fail; |
c5c77ba1 JK |
379 | |
380 | c_val[0] = INFRASTRUCTURE; | |
79df6a49 | 381 | if (!wilc_wlan_cfg_set(vif, 0, WID_BSS_TYPE, c_val, 1, 0, 0)) |
5fe678b1 | 382 | goto fail; |
c5c77ba1 | 383 | |
c5c77ba1 | 384 | c_val[0] = RATE_AUTO; |
79df6a49 | 385 | if (!wilc_wlan_cfg_set(vif, 0, WID_CURRENT_TX_RATE, c_val, 1, 0, 0)) |
5fe678b1 | 386 | goto fail; |
c5c77ba1 JK |
387 | |
388 | c_val[0] = G_MIXED_11B_2_MODE; | |
79df6a49 | 389 | if (!wilc_wlan_cfg_set(vif, 0, WID_11G_OPERATING_MODE, c_val, 1, 0, |
89758e13 | 390 | 0)) |
5fe678b1 | 391 | goto fail; |
c5c77ba1 JK |
392 | |
393 | c_val[0] = 1; | |
79df6a49 | 394 | if (!wilc_wlan_cfg_set(vif, 0, WID_CURRENT_CHANNEL, c_val, 1, 0, 0)) |
5fe678b1 | 395 | goto fail; |
c5c77ba1 JK |
396 | |
397 | c_val[0] = G_SHORT_PREAMBLE; | |
79df6a49 | 398 | if (!wilc_wlan_cfg_set(vif, 0, WID_PREAMBLE, c_val, 1, 0, 0)) |
5fe678b1 | 399 | goto fail; |
c5c77ba1 JK |
400 | |
401 | c_val[0] = AUTO_PROT; | |
79df6a49 | 402 | if (!wilc_wlan_cfg_set(vif, 0, WID_11N_PROT_MECH, c_val, 1, 0, 0)) |
5fe678b1 | 403 | goto fail; |
c5c77ba1 | 404 | |
c5c77ba1 | 405 | c_val[0] = ACTIVE_SCAN; |
79df6a49 | 406 | if (!wilc_wlan_cfg_set(vif, 0, WID_SCAN_TYPE, c_val, 1, 0, 0)) |
5fe678b1 | 407 | goto fail; |
c5c77ba1 JK |
408 | |
409 | c_val[0] = SITE_SURVEY_OFF; | |
79df6a49 | 410 | if (!wilc_wlan_cfg_set(vif, 0, WID_SITE_SURVEY, c_val, 1, 0, 0)) |
5fe678b1 | 411 | goto fail; |
c5c77ba1 | 412 | |
98b89847 | 413 | *((int *)c_val) = 0xffff; |
79df6a49 | 414 | if (!wilc_wlan_cfg_set(vif, 0, WID_RTS_THRESHOLD, c_val, 2, 0, 0)) |
5fe678b1 | 415 | goto fail; |
c5c77ba1 JK |
416 | |
417 | *((int *)c_val) = 2346; | |
79df6a49 | 418 | if (!wilc_wlan_cfg_set(vif, 0, WID_FRAG_THRESHOLD, c_val, 2, 0, 0)) |
5fe678b1 | 419 | goto fail; |
c5c77ba1 | 420 | |
c5c77ba1 | 421 | c_val[0] = 0; |
79df6a49 | 422 | if (!wilc_wlan_cfg_set(vif, 0, WID_BCAST_SSID, c_val, 1, 0, 0)) |
5fe678b1 | 423 | goto fail; |
c5c77ba1 JK |
424 | |
425 | c_val[0] = 1; | |
79df6a49 | 426 | if (!wilc_wlan_cfg_set(vif, 0, WID_QOS_ENABLE, c_val, 1, 0, 0)) |
5fe678b1 | 427 | goto fail; |
c5c77ba1 JK |
428 | |
429 | c_val[0] = NO_POWERSAVE; | |
79df6a49 | 430 | if (!wilc_wlan_cfg_set(vif, 0, WID_POWER_MANAGEMENT, c_val, 1, 0, 0)) |
5fe678b1 | 431 | goto fail; |
c5c77ba1 | 432 | |
b4d04c15 | 433 | c_val[0] = NO_SECURITY; /* NO_ENCRYPT, 0x79 */ |
79df6a49 | 434 | if (!wilc_wlan_cfg_set(vif, 0, WID_11I_MODE, c_val, 1, 0, 0)) |
5fe678b1 | 435 | goto fail; |
c5c77ba1 JK |
436 | |
437 | c_val[0] = OPEN_SYSTEM; | |
79df6a49 | 438 | if (!wilc_wlan_cfg_set(vif, 0, WID_AUTH_TYPE, c_val, 1, 0, 0)) |
5fe678b1 | 439 | goto fail; |
c5c77ba1 | 440 | |
c5c77ba1 | 441 | strcpy(c_val, "123456790abcdef1234567890"); |
79df6a49 | 442 | if (!wilc_wlan_cfg_set(vif, 0, WID_WEP_KEY_VALUE, c_val, |
89758e13 | 443 | (strlen(c_val) + 1), 0, 0)) |
5fe678b1 | 444 | goto fail; |
c5c77ba1 | 445 | |
c5c77ba1 | 446 | strcpy(c_val, "12345678"); |
79df6a49 | 447 | if (!wilc_wlan_cfg_set(vif, 0, WID_11I_PSK, c_val, (strlen(c_val)), 0, |
89758e13 | 448 | 0)) |
5fe678b1 | 449 | goto fail; |
c5c77ba1 | 450 | |
c5c77ba1 | 451 | strcpy(c_val, "password"); |
79df6a49 | 452 | if (!wilc_wlan_cfg_set(vif, 0, WID_1X_KEY, c_val, (strlen(c_val) + 1), |
89758e13 | 453 | 0, 0)) |
5fe678b1 | 454 | goto fail; |
c5c77ba1 | 455 | |
c5c77ba1 JK |
456 | c_val[0] = 192; |
457 | c_val[1] = 168; | |
458 | c_val[2] = 1; | |
459 | c_val[3] = 112; | |
79df6a49 | 460 | if (!wilc_wlan_cfg_set(vif, 0, WID_1X_SERV_ADDR, c_val, 4, 0, 0)) |
5fe678b1 | 461 | goto fail; |
c5c77ba1 JK |
462 | |
463 | c_val[0] = 3; | |
79df6a49 | 464 | if (!wilc_wlan_cfg_set(vif, 0, WID_LISTEN_INTERVAL, c_val, 1, 0, 0)) |
5fe678b1 | 465 | goto fail; |
c5c77ba1 JK |
466 | |
467 | c_val[0] = 3; | |
79df6a49 | 468 | if (!wilc_wlan_cfg_set(vif, 0, WID_DTIM_PERIOD, c_val, 1, 0, 0)) |
5fe678b1 | 469 | goto fail; |
c5c77ba1 JK |
470 | |
471 | c_val[0] = NORMAL_ACK; | |
79df6a49 | 472 | if (!wilc_wlan_cfg_set(vif, 0, WID_ACK_POLICY, c_val, 1, 0, 0)) |
5fe678b1 | 473 | goto fail; |
c5c77ba1 JK |
474 | |
475 | c_val[0] = 0; | |
79df6a49 | 476 | if (!wilc_wlan_cfg_set(vif, 0, WID_USER_CONTROL_ON_TX_POWER, c_val, 1, |
89758e13 | 477 | 0, 0)) |
5fe678b1 | 478 | goto fail; |
c5c77ba1 JK |
479 | |
480 | c_val[0] = 48; | |
79df6a49 | 481 | if (!wilc_wlan_cfg_set(vif, 0, WID_TX_POWER_LEVEL_11A, c_val, 1, 0, |
89758e13 | 482 | 0)) |
5fe678b1 | 483 | goto fail; |
c5c77ba1 JK |
484 | |
485 | c_val[0] = 28; | |
79df6a49 | 486 | if (!wilc_wlan_cfg_set(vif, 0, WID_TX_POWER_LEVEL_11B, c_val, 1, 0, |
89758e13 | 487 | 0)) |
5fe678b1 | 488 | goto fail; |
c5c77ba1 | 489 | |
c5c77ba1 | 490 | *((int *)c_val) = 100; |
79df6a49 | 491 | if (!wilc_wlan_cfg_set(vif, 0, WID_BEACON_INTERVAL, c_val, 2, 0, 0)) |
5fe678b1 | 492 | goto fail; |
c5c77ba1 JK |
493 | |
494 | c_val[0] = REKEY_DISABLE; | |
79df6a49 | 495 | if (!wilc_wlan_cfg_set(vif, 0, WID_REKEY_POLICY, c_val, 1, 0, 0)) |
5fe678b1 | 496 | goto fail; |
c5c77ba1 | 497 | |
c5c77ba1 | 498 | *((int *)c_val) = 84600; |
79df6a49 | 499 | if (!wilc_wlan_cfg_set(vif, 0, WID_REKEY_PERIOD, c_val, 4, 0, 0)) |
5fe678b1 | 500 | goto fail; |
c5c77ba1 | 501 | |
c5c77ba1 | 502 | *((int *)c_val) = 500; |
79df6a49 | 503 | if (!wilc_wlan_cfg_set(vif, 0, WID_REKEY_PACKET_COUNT, c_val, 4, 0, |
89758e13 | 504 | 0)) |
5fe678b1 | 505 | goto fail; |
c5c77ba1 JK |
506 | |
507 | c_val[0] = 1; | |
79df6a49 | 508 | if (!wilc_wlan_cfg_set(vif, 0, WID_SHORT_SLOT_ALLOWED, c_val, 1, 0, |
89758e13 | 509 | 0)) |
5fe678b1 | 510 | goto fail; |
c5c77ba1 JK |
511 | |
512 | c_val[0] = G_SELF_CTS_PROT; | |
79df6a49 | 513 | if (!wilc_wlan_cfg_set(vif, 0, WID_11N_ERP_PROT_TYPE, c_val, 1, 0, 0)) |
5fe678b1 | 514 | goto fail; |
c5c77ba1 | 515 | |
98b89847 | 516 | c_val[0] = 1; |
79df6a49 | 517 | if (!wilc_wlan_cfg_set(vif, 0, WID_11N_ENABLE, c_val, 1, 0, 0)) |
5fe678b1 | 518 | goto fail; |
c5c77ba1 JK |
519 | |
520 | c_val[0] = HT_MIXED_MODE; | |
79df6a49 | 521 | if (!wilc_wlan_cfg_set(vif, 0, WID_11N_OPERATING_MODE, c_val, 1, 0, |
89758e13 | 522 | 0)) |
5fe678b1 | 523 | goto fail; |
c5c77ba1 | 524 | |
98b89847 | 525 | c_val[0] = 1; |
79df6a49 | 526 | if (!wilc_wlan_cfg_set(vif, 0, WID_11N_TXOP_PROT_DISABLE, c_val, 1, 0, |
89758e13 | 527 | 0)) |
5fe678b1 | 528 | goto fail; |
c5c77ba1 | 529 | |
c5c77ba1 | 530 | c_val[0] = DETECT_PROTECT_REPORT; |
79df6a49 | 531 | if (!wilc_wlan_cfg_set(vif, 0, WID_11N_OBSS_NONHT_DETECTION, c_val, 1, |
89758e13 | 532 | 0, 0)) |
5fe678b1 | 533 | goto fail; |
c5c77ba1 JK |
534 | |
535 | c_val[0] = RTS_CTS_NONHT_PROT; | |
79df6a49 | 536 | if (!wilc_wlan_cfg_set(vif, 0, WID_11N_HT_PROT_TYPE, c_val, 1, 0, 0)) |
5fe678b1 | 537 | goto fail; |
c5c77ba1 JK |
538 | |
539 | c_val[0] = 0; | |
79df6a49 | 540 | if (!wilc_wlan_cfg_set(vif, 0, WID_11N_RIFS_PROT_ENABLE, c_val, 1, 0, |
89758e13 | 541 | 0)) |
5fe678b1 | 542 | goto fail; |
c5c77ba1 JK |
543 | |
544 | c_val[0] = MIMO_MODE; | |
79df6a49 | 545 | if (!wilc_wlan_cfg_set(vif, 0, WID_11N_SMPS_MODE, c_val, 1, 0, 0)) |
5fe678b1 | 546 | goto fail; |
c5c77ba1 JK |
547 | |
548 | c_val[0] = 7; | |
79df6a49 | 549 | if (!wilc_wlan_cfg_set(vif, 0, WID_11N_CURRENT_TX_MCS, c_val, 1, 0, |
89758e13 | 550 | 0)) |
5fe678b1 | 551 | goto fail; |
c5c77ba1 | 552 | |
98b89847 | 553 | c_val[0] = 1; |
79df6a49 | 554 | if (!wilc_wlan_cfg_set(vif, 0, WID_11N_IMMEDIATE_BA_ENABLED, c_val, 1, |
89758e13 | 555 | 1, 1)) |
5fe678b1 | 556 | goto fail; |
c5c77ba1 JK |
557 | |
558 | return 0; | |
559 | ||
5fe678b1 | 560 | fail: |
c5c77ba1 JK |
561 | return -1; |
562 | } | |
563 | ||
fec2dbfe AS |
564 | static int wlan_deinit_locks(struct net_device *dev) |
565 | { | |
566 | struct wilc_vif *vif; | |
567 | struct wilc *wilc; | |
568 | ||
569 | vif = netdev_priv(dev); | |
570 | wilc = vif->wilc; | |
571 | ||
572 | mutex_destroy(&wilc->hif_cs); | |
573 | mutex_destroy(&wilc->rxq_cs); | |
574 | mutex_destroy(&wilc->txq_add_to_head_cs); | |
575 | ||
576 | return 0; | |
577 | } | |
578 | ||
579 | static void wlan_deinitialize_threads(struct net_device *dev) | |
580 | { | |
581 | struct wilc_vif *vif; | |
582 | struct wilc *wl; | |
583 | ||
584 | vif = netdev_priv(dev); | |
585 | wl = vif->wilc; | |
586 | ||
587 | wl->close = 1; | |
588 | ||
589 | complete(&wl->txq_event); | |
590 | ||
591 | if (wl->txq_thread) { | |
592 | kthread_stop(wl->txq_thread); | |
593 | wl->txq_thread = NULL; | |
594 | } | |
595 | } | |
596 | ||
ead6cb05 | 597 | static void wilc_wlan_deinitialize(struct net_device *dev) |
c5c77ba1 | 598 | { |
a4cac481 | 599 | struct wilc_vif *vif; |
53dc0cfe | 600 | struct wilc *wl; |
c5c77ba1 | 601 | |
a4cac481 GL |
602 | vif = netdev_priv(dev); |
603 | wl = vif->wilc; | |
53dc0cfe GL |
604 | |
605 | if (!wl) { | |
606 | netdev_err(dev, "wl is NULL\n"); | |
607 | return; | |
608 | } | |
609 | ||
610 | if (wl->initialized) { | |
611 | netdev_info(dev, "Deinitializing wilc1000...\n"); | |
c5c77ba1 | 612 | |
5547c1f0 | 613 | if (!wl->dev_irq_num && |
af9ae09a | 614 | wl->hif_func->disable_interrupt) { |
c4d139cb | 615 | mutex_lock(&wl->hif_cs); |
af9ae09a | 616 | wl->hif_func->disable_interrupt(wl); |
c4d139cb AB |
617 | mutex_unlock(&wl->hif_cs); |
618 | } | |
1646ff6c | 619 | complete(&wl->txq_event); |
c5c77ba1 | 620 | |
32dd51bc | 621 | wlan_deinitialize_threads(dev); |
ec5cc750 | 622 | deinit_irq(dev); |
c5c77ba1 | 623 | |
562ed3f1 | 624 | wilc_wlan_stop(wl); |
2de7cbec | 625 | wilc_wlan_cleanup(dev); |
7c67c053 | 626 | wlan_deinit_locks(dev); |
c5c77ba1 | 627 | |
53dc0cfe | 628 | wl->initialized = false; |
c5c77ba1 | 629 | |
5ac24427 | 630 | netdev_dbg(dev, "wilc1000 deinitialization Done\n"); |
c5c77ba1 | 631 | } else { |
5ac24427 | 632 | netdev_dbg(dev, "wilc1000 is not initialized\n"); |
c5c77ba1 | 633 | } |
c5c77ba1 JK |
634 | } |
635 | ||
1608c403 | 636 | static int wlan_init_locks(struct net_device *dev) |
c5c77ba1 | 637 | { |
a4cac481 | 638 | struct wilc_vif *vif; |
38afb390 GL |
639 | struct wilc *wl; |
640 | ||
a4cac481 GL |
641 | vif = netdev_priv(dev); |
642 | wl = vif->wilc; | |
c5c77ba1 | 643 | |
38afb390 GL |
644 | mutex_init(&wl->hif_cs); |
645 | mutex_init(&wl->rxq_cs); | |
c5c77ba1 | 646 | |
38afb390 | 647 | spin_lock_init(&wl->txq_spinlock); |
334bed08 | 648 | mutex_init(&wl->txq_add_to_head_cs); |
c5c77ba1 | 649 | |
b27a6d5e | 650 | init_completion(&wl->txq_event); |
c5c77ba1 | 651 | |
fa659698 | 652 | init_completion(&wl->cfg_event); |
04247e7d | 653 | init_completion(&wl->sync_event); |
11a54b3f | 654 | init_completion(&wl->txq_thread_started); |
c5c77ba1 | 655 | |
c5c77ba1 JK |
656 | return 0; |
657 | } | |
658 | ||
1608c403 | 659 | static int wlan_initialize_threads(struct net_device *dev) |
c5c77ba1 | 660 | { |
a4cac481 | 661 | struct wilc_vif *vif; |
75a94665 | 662 | struct wilc *wilc; |
8dfaafd6 | 663 | |
a4cac481 GL |
664 | vif = netdev_priv(dev); |
665 | wilc = vif->wilc; | |
75a94665 | 666 | |
88687584 | 667 | wilc->txq_thread = kthread_run(linux_wlan_txq_task, (void *)dev, |
387fbf00 | 668 | "K_TXQ_TASK"); |
b3e6916d | 669 | if (IS_ERR(wilc->txq_thread)) { |
5ac24427 | 670 | netdev_err(dev, "couldn't create TXQ thread\n"); |
6bc72c5a | 671 | wilc->close = 0; |
b3e6916d | 672 | return PTR_ERR(wilc->txq_thread); |
c5c77ba1 | 673 | } |
11a54b3f | 674 | wait_for_completion(&wilc->txq_thread_started); |
c5c77ba1 JK |
675 | |
676 | return 0; | |
c5c77ba1 JK |
677 | } |
678 | ||
ead6cb05 | 679 | static int wilc_wlan_initialize(struct net_device *dev, struct wilc_vif *vif) |
c5c77ba1 | 680 | { |
c5c77ba1 | 681 | int ret = 0; |
a4cac481 | 682 | struct wilc *wl = vif->wilc; |
c5c77ba1 | 683 | |
0fa683b6 | 684 | if (!wl->initialized) { |
52b1d208 | 685 | wl->mac_status = MAC_STATUS_INIT; |
0fa683b6 | 686 | wl->close = 0; |
c5c77ba1 | 687 | |
38afb390 | 688 | wlan_init_locks(dev); |
c5c77ba1 | 689 | |
4bd7baf0 | 690 | ret = wilc_wlan_init(dev); |
c5c77ba1 | 691 | if (ret < 0) { |
c5c77ba1 | 692 | ret = -EIO; |
8eb658f1 | 693 | goto fail_locks; |
c5c77ba1 | 694 | } |
c5c77ba1 | 695 | |
c4d139cb | 696 | if (wl->gpio >= 0 && init_irq(dev)) { |
c5c77ba1 | 697 | ret = -EIO; |
8eb658f1 | 698 | goto fail_locks; |
c5c77ba1 | 699 | } |
c5c77ba1 | 700 | |
75a94665 | 701 | ret = wlan_initialize_threads(dev); |
b46d6882 | 702 | if (ret < 0) { |
b46d6882 | 703 | ret = -EIO; |
8eb658f1 | 704 | goto fail_wilc_wlan; |
b46d6882 TC |
705 | } |
706 | ||
5547c1f0 | 707 | if (!wl->dev_irq_num && |
af9ae09a GL |
708 | wl->hif_func->enable_interrupt && |
709 | wl->hif_func->enable_interrupt(wl)) { | |
c5c77ba1 | 710 | ret = -EIO; |
8eb658f1 | 711 | goto fail_irq_init; |
c5c77ba1 | 712 | } |
c5c77ba1 | 713 | |
0e1af73d | 714 | if (wilc_wlan_get_firmware(dev)) { |
c5c77ba1 | 715 | ret = -EIO; |
8eb658f1 | 716 | goto fail_irq_enable; |
c5c77ba1 JK |
717 | } |
718 | ||
562ed3f1 | 719 | ret = wilc1000_firmware_download(dev); |
c5c77ba1 | 720 | if (ret < 0) { |
c5c77ba1 | 721 | ret = -EIO; |
8eb658f1 | 722 | goto fail_irq_enable; |
c5c77ba1 JK |
723 | } |
724 | ||
9bf3d727 | 725 | ret = linux_wlan_start_firmware(dev); |
c5c77ba1 | 726 | if (ret < 0) { |
c5c77ba1 | 727 | ret = -EIO; |
8eb658f1 | 728 | goto fail_irq_enable; |
c5c77ba1 JK |
729 | } |
730 | ||
79df6a49 | 731 | if (wilc_wlan_cfg_get(vif, 1, WID_FIRMWARE_VERSION, 1, 0)) { |
c5c77ba1 | 732 | int size; |
5ac24427 | 733 | char firmware_ver[20]; |
8dfaafd6 | 734 | |
5ac24427 LK |
735 | size = wilc_wlan_cfg_get_val(WID_FIRMWARE_VERSION, |
736 | firmware_ver, | |
737 | sizeof(firmware_ver)); | |
738 | firmware_ver[size] = '\0'; | |
739 | netdev_dbg(dev, "Firmware Ver = %s\n", firmware_ver); | |
c5c77ba1 | 740 | } |
b8f6ca0b | 741 | ret = linux_wlan_init_test_config(dev, vif); |
c5c77ba1 JK |
742 | |
743 | if (ret < 0) { | |
5ac24427 | 744 | netdev_err(dev, "Failed to configure firmware\n"); |
c5c77ba1 | 745 | ret = -EIO; |
8eb658f1 | 746 | goto fail_fw_start; |
c5c77ba1 JK |
747 | } |
748 | ||
0fa683b6 | 749 | wl->initialized = true; |
98b89847 | 750 | return 0; |
c5c77ba1 | 751 | |
8eb658f1 | 752 | fail_fw_start: |
562ed3f1 | 753 | wilc_wlan_stop(wl); |
c5c77ba1 | 754 | |
8eb658f1 | 755 | fail_irq_enable: |
5547c1f0 | 756 | if (!wl->dev_irq_num && |
af9ae09a GL |
757 | wl->hif_func->disable_interrupt) |
758 | wl->hif_func->disable_interrupt(wl); | |
8eb658f1 | 759 | fail_irq_init: |
c4d139cb AB |
760 | if (wl->dev_irq_num) |
761 | deinit_irq(dev); | |
c5c77ba1 | 762 | |
32dd51bc | 763 | wlan_deinitialize_threads(dev); |
8eb658f1 | 764 | fail_wilc_wlan: |
2de7cbec | 765 | wilc_wlan_cleanup(dev); |
8eb658f1 | 766 | fail_locks: |
7c67c053 | 767 | wlan_deinit_locks(dev); |
073cbb6c | 768 | netdev_err(dev, "WLAN initialization FAILED\n"); |
c5c77ba1 | 769 | } else { |
5ac24427 | 770 | netdev_dbg(dev, "wilc1000 already initialized\n"); |
c5c77ba1 JK |
771 | } |
772 | return ret; | |
773 | } | |
774 | ||
1608c403 | 775 | static int mac_init_fn(struct net_device *ndev) |
c5c77ba1 | 776 | { |
98b89847 LK |
777 | netif_start_queue(ndev); |
778 | netif_stop_queue(ndev); | |
c5c77ba1 JK |
779 | |
780 | return 0; | |
781 | } | |
c5c77ba1 | 782 | |
68a30a63 | 783 | static int wilc_mac_open(struct net_device *ndev) |
c5c77ba1 | 784 | { |
a4cac481 | 785 | struct wilc_vif *vif; |
c5c77ba1 | 786 | |
c5c77ba1 | 787 | unsigned char mac_add[ETH_ALEN] = {0}; |
c5c77ba1 JK |
788 | int ret = 0; |
789 | int i = 0; | |
f3c1366e GL |
790 | struct wilc *wl; |
791 | ||
a4cac481 GL |
792 | vif = netdev_priv(ndev); |
793 | wl = vif->wilc; | |
c5c77ba1 | 794 | |
40095ad9 | 795 | if (!wl || !wl->dev) { |
90fd4cc5 | 796 | netdev_err(ndev, "device not ready\n"); |
7d05652c CG |
797 | return -ENODEV; |
798 | } | |
b03314e2 | 799 | |
5ac24427 | 800 | netdev_dbg(ndev, "MAC OPEN[%p]\n", ndev); |
c5c77ba1 | 801 | |
dd4b6a83 | 802 | ret = wilc_init_host_int(ndev); |
1408603c | 803 | if (ret < 0) |
c5c77ba1 | 804 | return ret; |
c5c77ba1 | 805 | |
81a7dc3d | 806 | ret = wilc_wlan_initialize(ndev, vif); |
c5c77ba1 | 807 | if (ret < 0) { |
a9a16823 | 808 | wilc_deinit_host_int(ndev); |
c5c77ba1 JK |
809 | return ret; |
810 | } | |
811 | ||
f3c1366e | 812 | for (i = 0; i < wl->vif_num; i++) { |
1f435d2e | 813 | if (ndev == wl->vif[i]->ndev) { |
46949b48 AS |
814 | wilc_set_wfi_drv_handler(vif, wilc_get_vif_idx(vif), |
815 | vif->iftype, vif->ifc_id); | |
e32737e9 | 816 | wilc_set_operation_mode(vif, vif->iftype); |
c5c77ba1 JK |
817 | break; |
818 | } | |
819 | } | |
820 | ||
76c01fdd HE |
821 | wilc_get_mac_address(vif, mac_add); |
822 | netdev_dbg(ndev, "Mac address: %pM\n", mac_add); | |
823 | memcpy(wl->vif[i]->src_addr, mac_add, ETH_ALEN); | |
1f435d2e | 824 | memcpy(ndev->dev_addr, wl->vif[i]->src_addr, ETH_ALEN); |
c5c77ba1 JK |
825 | |
826 | if (!is_valid_ether_addr(ndev->dev_addr)) { | |
5ac24427 | 827 | netdev_err(ndev, "Wrong MAC address\n"); |
339d244a | 828 | wilc_deinit_host_int(ndev); |
81a7dc3d | 829 | wilc_wlan_deinitialize(ndev); |
339d244a | 830 | return -EINVAL; |
c5c77ba1 JK |
831 | } |
832 | ||
1006b5c7 GL |
833 | wilc_mgmt_frame_register(vif->ndev->ieee80211_ptr->wiphy, |
834 | vif->ndev->ieee80211_ptr, | |
340a84ff | 835 | vif->frame_reg[0].type, |
89febb21 | 836 | vif->frame_reg[0].reg); |
1006b5c7 GL |
837 | wilc_mgmt_frame_register(vif->ndev->ieee80211_ptr->wiphy, |
838 | vif->ndev->ieee80211_ptr, | |
340a84ff | 839 | vif->frame_reg[1].type, |
89febb21 | 840 | vif->frame_reg[1].reg); |
c5c77ba1 | 841 | netif_wake_queue(ndev); |
f3c1366e | 842 | wl->open_ifcs++; |
a4cac481 | 843 | vif->mac_opened = 1; |
c5c77ba1 | 844 | return 0; |
c5c77ba1 | 845 | } |
c5c77ba1 | 846 | |
1608c403 | 847 | static struct net_device_stats *mac_stats(struct net_device *dev) |
c5c77ba1 | 848 | { |
40095ad9 | 849 | struct wilc_vif *vif = netdev_priv(dev); |
c5c77ba1 | 850 | |
a4cac481 | 851 | return &vif->netstats; |
c5c77ba1 JK |
852 | } |
853 | ||
c5c77ba1 JK |
854 | static void wilc_set_multicast_list(struct net_device *dev) |
855 | { | |
c5c77ba1 | 856 | struct netdev_hw_addr *ha; |
cf60106b | 857 | struct wilc_vif *vif; |
c5c77ba1 | 858 | int i = 0; |
8dfaafd6 | 859 | |
cf60106b | 860 | vif = netdev_priv(dev); |
c5c77ba1 | 861 | |
1408603c | 862 | if (dev->flags & IFF_PROMISC) |
c5c77ba1 | 863 | return; |
c5c77ba1 | 864 | |
7bf0242a AS |
865 | if (dev->flags & IFF_ALLMULTI || |
866 | dev->mc.count > WILC_MULTICAST_TABLE_SIZE) { | |
fbf5379b | 867 | wilc_setup_multicast_filter(vif, false, 0); |
c5c77ba1 JK |
868 | return; |
869 | } | |
870 | ||
7bf0242a | 871 | if (dev->mc.count == 0) { |
fbf5379b | 872 | wilc_setup_multicast_filter(vif, true, 0); |
c5c77ba1 JK |
873 | return; |
874 | } | |
875 | ||
c8537e6d | 876 | netdev_for_each_mc_addr(ha, dev) { |
0e1af73d | 877 | memcpy(wilc_multicast_mac_addr_list[i], ha->addr, ETH_ALEN); |
5ac24427 LK |
878 | netdev_dbg(dev, "Entry[%d]: %x:%x:%x:%x:%x:%x\n", i, |
879 | wilc_multicast_mac_addr_list[i][0], | |
880 | wilc_multicast_mac_addr_list[i][1], | |
881 | wilc_multicast_mac_addr_list[i][2], | |
882 | wilc_multicast_mac_addr_list[i][3], | |
883 | wilc_multicast_mac_addr_list[i][4], | |
884 | wilc_multicast_mac_addr_list[i][5]); | |
c5c77ba1 JK |
885 | i++; |
886 | } | |
887 | ||
fbf5379b | 888 | wilc_setup_multicast_filter(vif, true, (dev->mc.count)); |
c5c77ba1 JK |
889 | } |
890 | ||
c5c77ba1 JK |
891 | static void linux_wlan_tx_complete(void *priv, int status) |
892 | { | |
d5c89442 | 893 | struct tx_complete_data *pv_data = priv; |
8dfaafd6 | 894 | |
c5c77ba1 | 895 | dev_kfree_skb(pv_data->skb); |
a18dd630 | 896 | kfree(pv_data); |
c5c77ba1 JK |
897 | } |
898 | ||
ad891807 | 899 | netdev_tx_t wilc_mac_xmit(struct sk_buff *skb, struct net_device *ndev) |
c5c77ba1 | 900 | { |
a4cac481 | 901 | struct wilc_vif *vif; |
c5c77ba1 | 902 | struct tx_complete_data *tx_data = NULL; |
44ec3b75 | 903 | int queue_count; |
fd8f0367 | 904 | char *udp_buf; |
c5c77ba1 JK |
905 | struct iphdr *ih; |
906 | struct ethhdr *eth_h; | |
b7495be5 | 907 | struct wilc *wilc; |
8dfaafd6 | 908 | |
a4cac481 GL |
909 | vif = netdev_priv(ndev); |
910 | wilc = vif->wilc; | |
c5c77ba1 | 911 | |
c5c77ba1 | 912 | if (skb->dev != ndev) { |
5ac24427 | 913 | netdev_err(ndev, "Packet not destined to this device\n"); |
c5c77ba1 JK |
914 | return 0; |
915 | } | |
916 | ||
b38e9030 | 917 | tx_data = kmalloc(sizeof(*tx_data), GFP_ATOMIC); |
3a147c07 | 918 | if (!tx_data) { |
c5c77ba1 JK |
919 | dev_kfree_skb(skb); |
920 | netif_wake_queue(ndev); | |
921 | return 0; | |
922 | } | |
923 | ||
924 | tx_data->buff = skb->data; | |
925 | tx_data->size = skb->len; | |
926 | tx_data->skb = skb; | |
927 | ||
928 | eth_h = (struct ethhdr *)(skb->data); | |
94500d56 | 929 | if (eth_h->h_proto == cpu_to_be16(0x8e88)) |
5ac24427 | 930 | netdev_dbg(ndev, "EAPOL transmitted\n"); |
c5c77ba1 | 931 | |
c5c77ba1 JK |
932 | ih = (struct iphdr *)(skb->data + sizeof(struct ethhdr)); |
933 | ||
fd8f0367 LK |
934 | udp_buf = (char *)ih + sizeof(struct iphdr); |
935 | if ((udp_buf[1] == 68 && udp_buf[3] == 67) || | |
936 | (udp_buf[1] == 67 && udp_buf[3] == 68)) | |
5ac24427 LK |
937 | netdev_dbg(ndev, "DHCP Message transmitted, type:%x %x %x\n", |
938 | udp_buf[248], udp_buf[249], udp_buf[250]); | |
c5c77ba1 | 939 | |
a4cac481 GL |
940 | vif->netstats.tx_packets++; |
941 | vif->netstats.tx_bytes += tx_data->size; | |
6750140d | 942 | tx_data->bssid = wilc->vif[vif->idx]->bssid; |
44ec3b75 LK |
943 | queue_count = wilc_wlan_txq_add_net_pkt(ndev, (void *)tx_data, |
944 | tx_data->buff, tx_data->size, | |
945 | linux_wlan_tx_complete); | |
c5c77ba1 | 946 | |
44ec3b75 | 947 | if (queue_count > FLOW_CONTROL_UPPER_THRESHOLD) { |
1f435d2e GL |
948 | netif_stop_queue(wilc->vif[0]->ndev); |
949 | netif_stop_queue(wilc->vif[1]->ndev); | |
c5c77ba1 JK |
950 | } |
951 | ||
952 | return 0; | |
953 | } | |
954 | ||
68a30a63 | 955 | static int wilc_mac_close(struct net_device *ndev) |
c5c77ba1 | 956 | { |
2726887c | 957 | struct wilc_priv *priv; |
a4cac481 | 958 | struct wilc_vif *vif; |
2db2c8a7 | 959 | struct host_if_drv *hif_drv; |
ca64ad6e | 960 | struct wilc *wl; |
c5c77ba1 | 961 | |
a4cac481 | 962 | vif = netdev_priv(ndev); |
c5c77ba1 | 963 | |
1006b5c7 | 964 | if (!vif || !vif->ndev || !vif->ndev->ieee80211_ptr || |
1408603c | 965 | !vif->ndev->ieee80211_ptr->wiphy) |
c5c77ba1 | 966 | return 0; |
c5c77ba1 | 967 | |
1006b5c7 | 968 | priv = wiphy_priv(vif->ndev->ieee80211_ptr->wiphy); |
a4cac481 | 969 | wl = vif->wilc; |
c5c77ba1 | 970 | |
1408603c | 971 | if (!priv) |
c5c77ba1 | 972 | return 0; |
c5c77ba1 | 973 | |
48b28df9 | 974 | hif_drv = (struct host_if_drv *)priv->hif_drv; |
c5c77ba1 | 975 | |
5ac24427 | 976 | netdev_dbg(ndev, "Mac close\n"); |
c5c77ba1 | 977 | |
1408603c | 978 | if (!wl) |
c5c77ba1 | 979 | return 0; |
c5c77ba1 | 980 | |
1408603c | 981 | if (!hif_drv) |
c5c77ba1 | 982 | return 0; |
c5c77ba1 | 983 | |
7bf0242a | 984 | if (wl->open_ifcs > 0) |
ca64ad6e | 985 | wl->open_ifcs--; |
1408603c | 986 | else |
c5c77ba1 | 987 | return 0; |
c5c77ba1 | 988 | |
1006b5c7 GL |
989 | if (vif->ndev) { |
990 | netif_stop_queue(vif->ndev); | |
c5c77ba1 | 991 | |
1006b5c7 | 992 | wilc_deinit_host_int(vif->ndev); |
c5c77ba1 JK |
993 | } |
994 | ||
ca64ad6e | 995 | if (wl->open_ifcs == 0) { |
5ac24427 | 996 | netdev_dbg(ndev, "Deinitializing wilc1000\n"); |
ca64ad6e | 997 | wl->close = 1; |
81a7dc3d | 998 | wilc_wlan_deinitialize(ndev); |
30324405 | 999 | wilc_wfi_deinit_mon_interface(); |
c5c77ba1 JK |
1000 | } |
1001 | ||
a4cac481 | 1002 | vif->mac_opened = 0; |
c5c77ba1 JK |
1003 | |
1004 | return 0; | |
1005 | } | |
1006 | ||
562ed3f1 | 1007 | void wilc_frmw_to_linux(struct wilc *wilc, u8 *buff, u32 size, u32 pkt_offset) |
c5c77ba1 | 1008 | { |
c5c77ba1 JK |
1009 | unsigned int frame_len = 0; |
1010 | int stats; | |
1011 | unsigned char *buff_to_send = NULL; | |
1012 | struct sk_buff *skb; | |
c5c77ba1 | 1013 | struct net_device *wilc_netdev; |
a4cac481 | 1014 | struct wilc_vif *vif; |
c5c77ba1 | 1015 | |
0953a2e3 LK |
1016 | if (!wilc) |
1017 | return; | |
1018 | ||
7e725b47 | 1019 | wilc_netdev = get_if_handler(wilc, buff); |
3a147c07 | 1020 | if (!wilc_netdev) |
c5c77ba1 JK |
1021 | return; |
1022 | ||
1023 | buff += pkt_offset; | |
a4cac481 | 1024 | vif = netdev_priv(wilc_netdev); |
c5c77ba1 JK |
1025 | |
1026 | if (size > 0) { | |
c5c77ba1 JK |
1027 | frame_len = size; |
1028 | buff_to_send = buff; | |
1029 | ||
c5c77ba1 | 1030 | skb = dev_alloc_skb(frame_len); |
1408603c | 1031 | if (!skb) |
c5c77ba1 | 1032 | return; |
1408603c | 1033 | |
c5c77ba1 JK |
1034 | skb->dev = wilc_netdev; |
1035 | ||
59ae1d12 | 1036 | skb_put_data(skb, buff_to_send, frame_len); |
c5c77ba1 | 1037 | |
c5c77ba1 | 1038 | skb->protocol = eth_type_trans(skb, wilc_netdev); |
a4cac481 GL |
1039 | vif->netstats.rx_packets++; |
1040 | vif->netstats.rx_bytes += frame_len; | |
c5c77ba1 JK |
1041 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
1042 | stats = netif_rx(skb); | |
5ac24427 | 1043 | netdev_dbg(wilc_netdev, "netif_rx ret value is: %d\n", stats); |
c5c77ba1 | 1044 | } |
c5c77ba1 JK |
1045 | } |
1046 | ||
44b4709c | 1047 | void wilc_wfi_mgmt_rx(struct wilc *wilc, u8 *buff, u32 size) |
c5c77ba1 JK |
1048 | { |
1049 | int i = 0; | |
a4cac481 | 1050 | struct wilc_vif *vif; |
c5c77ba1 | 1051 | |
11f4b2ee | 1052 | for (i = 0; i < wilc->vif_num; i++) { |
1f435d2e | 1053 | vif = netdev_priv(wilc->vif[i]->ndev); |
a4cac481 | 1054 | if (vif->monitor_flag) { |
436d918a | 1055 | wilc_wfi_monitor_rx(buff, size); |
c5c77ba1 JK |
1056 | return; |
1057 | } | |
1058 | } | |
1059 | ||
1f435d2e | 1060 | vif = netdev_priv(wilc->vif[1]->ndev); |
340a84ff LK |
1061 | if ((buff[0] == vif->frame_reg[0].type && vif->frame_reg[0].reg) || |
1062 | (buff[0] == vif->frame_reg[1].type && vif->frame_reg[1].reg)) | |
34db1aac | 1063 | wilc_wfi_p2p_rx(wilc->vif[1]->ndev, buff, size); |
c5c77ba1 JK |
1064 | } |
1065 | ||
fec2dbfe AS |
1066 | static struct notifier_block g_dev_notifier = { |
1067 | .notifier_call = dev_state_ev_handler | |
1068 | }; | |
1069 | ||
857c7b00 | 1070 | void wilc_netdev_cleanup(struct wilc *wilc) |
4875c499 | 1071 | { |
735bb39c | 1072 | int i; |
4875c499 | 1073 | |
735bb39c | 1074 | if (wilc && (wilc->vif[0]->ndev || wilc->vif[1]->ndev)) |
4875c499 TC |
1075 | unregister_inetaddr_notifier(&g_dev_notifier); |
1076 | ||
3f626cf4 | 1077 | if (wilc && wilc->firmware) { |
90b984c8 | 1078 | release_firmware(wilc->firmware); |
3f626cf4 LK |
1079 | wilc->firmware = NULL; |
1080 | } | |
4875c499 | 1081 | |
1f435d2e | 1082 | if (wilc && (wilc->vif[0]->ndev || wilc->vif[1]->ndev)) { |
4875c499 | 1083 | for (i = 0; i < NUM_CONCURRENT_IFC; i++) |
1f435d2e | 1084 | if (wilc->vif[i]->ndev) |
735bb39c | 1085 | if (wilc->vif[i]->mac_opened) |
1f435d2e | 1086 | wilc_mac_close(wilc->vif[i]->ndev); |
4875c499 TC |
1087 | |
1088 | for (i = 0; i < NUM_CONCURRENT_IFC; i++) { | |
1f435d2e GL |
1089 | unregister_netdev(wilc->vif[i]->ndev); |
1090 | wilc_free_wiphy(wilc->vif[i]->ndev); | |
1091 | free_netdev(wilc->vif[i]->ndev); | |
4875c499 TC |
1092 | } |
1093 | } | |
1094 | ||
90b984c8 | 1095 | kfree(wilc); |
4875c499 | 1096 | } |
750ffe9b | 1097 | EXPORT_SYMBOL_GPL(wilc_netdev_cleanup); |
4875c499 | 1098 | |
fec2dbfe AS |
1099 | static const struct net_device_ops wilc_netdev_ops = { |
1100 | .ndo_init = mac_init_fn, | |
1101 | .ndo_open = wilc_mac_open, | |
1102 | .ndo_stop = wilc_mac_close, | |
1103 | .ndo_start_xmit = wilc_mac_xmit, | |
1104 | .ndo_get_stats = mac_stats, | |
1105 | .ndo_set_rx_mode = wilc_set_multicast_list, | |
1106 | }; | |
1107 | ||
7d37a4a1 AB |
1108 | int wilc_netdev_init(struct wilc **wilc, struct device *dev, int io_type, |
1109 | int gpio, const struct wilc_hif_func *ops) | |
c5c77ba1 | 1110 | { |
fe747f0f | 1111 | int i, ret; |
a4cac481 | 1112 | struct wilc_vif *vif; |
c5c77ba1 | 1113 | struct net_device *ndev; |
562ed3f1 | 1114 | struct wilc *wl; |
c5c77ba1 | 1115 | |
825b966f | 1116 | wl = kzalloc(sizeof(*wl), GFP_KERNEL); |
562ed3f1 | 1117 | if (!wl) |
ac61ef86 | 1118 | return -ENOMEM; |
c5c77ba1 | 1119 | |
562ed3f1 AB |
1120 | *wilc = wl; |
1121 | wl->io_type = io_type; | |
1122 | wl->gpio = gpio; | |
af9ae09a | 1123 | wl->hif_func = ops; |
c4d139cb | 1124 | |
c5c77ba1 | 1125 | register_inetaddr_notifier(&g_dev_notifier); |
c5c77ba1 JK |
1126 | |
1127 | for (i = 0; i < NUM_CONCURRENT_IFC; i++) { | |
026e14ae AS |
1128 | struct wireless_dev *wdev; |
1129 | ||
a4cac481 | 1130 | ndev = alloc_etherdev(sizeof(struct wilc_vif)); |
1408603c | 1131 | if (!ndev) |
fe747f0f | 1132 | return -ENOMEM; |
c5c77ba1 | 1133 | |
a4cac481 GL |
1134 | vif = netdev_priv(ndev); |
1135 | memset(vif, 0, sizeof(struct wilc_vif)); | |
c5c77ba1 | 1136 | |
46949b48 | 1137 | if (i == 0) { |
c5c77ba1 | 1138 | strcpy(ndev->name, "wlan%d"); |
46949b48 AS |
1139 | vif->ifc_id = 1; |
1140 | } else { | |
c5c77ba1 | 1141 | strcpy(ndev->name, "p2p%d"); |
46949b48 AS |
1142 | vif->ifc_id = 0; |
1143 | } | |
a4cac481 | 1144 | vif->wilc = *wilc; |
735bb39c | 1145 | vif->ndev = ndev; |
1f435d2e | 1146 | wl->vif[i] = vif; |
735bb39c | 1147 | wl->vif_num = i; |
0e490657 AS |
1148 | vif->idx = wl->vif_num; |
1149 | ||
e5af0561 | 1150 | ndev->netdev_ops = &wilc_netdev_ops; |
c5c77ba1 | 1151 | |
026e14ae | 1152 | wdev = wilc_create_wiphy(ndev, dev); |
c5c77ba1 | 1153 | |
026e14ae AS |
1154 | if (dev) |
1155 | SET_NETDEV_DEV(ndev, dev); | |
c5c77ba1 | 1156 | |
026e14ae AS |
1157 | if (!wdev) { |
1158 | netdev_err(ndev, "Can't register WILC Wiphy\n"); | |
1159 | return -1; | |
c5c77ba1 | 1160 | } |
c5c77ba1 | 1161 | |
026e14ae AS |
1162 | vif->ndev->ieee80211_ptr = wdev; |
1163 | vif->ndev->ml_priv = vif; | |
1164 | wdev->netdev = vif->ndev; | |
1165 | vif->netstats.rx_packets = 0; | |
1166 | vif->netstats.tx_packets = 0; | |
1167 | vif->netstats.rx_bytes = 0; | |
1168 | vif->netstats.tx_bytes = 0; | |
1169 | ||
fe747f0f AKC |
1170 | ret = register_netdev(ndev); |
1171 | if (ret) | |
1172 | return ret; | |
c5c77ba1 | 1173 | |
a4cac481 GL |
1174 | vif->iftype = STATION_MODE; |
1175 | vif->mac_opened = 0; | |
c5c77ba1 JK |
1176 | } |
1177 | ||
c5c77ba1 JK |
1178 | return 0; |
1179 | } | |
750ffe9b | 1180 | EXPORT_SYMBOL_GPL(wilc_netdev_init); |
c94f05ee AB |
1181 | |
1182 | MODULE_LICENSE("GPL"); |