blob: b8eea21f265572b926d4008c59e96b4c8b4d9d87 [file] [log] [blame]
Sage Ahn247e9cf2012-05-15 13:20:36 +09001/*
2 * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
3 *
4 * This software is licensed under the terms of the GNU General Public
5 * License version 2, as published by the Free Software Foundation, and
6 * may be copied, distributed, and modified under those terms.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
YAMANE Toshiakif57cee12012-10-29 20:03:47 +090014#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
15
Sage Ahn247e9cf2012-05-15 13:20:36 +090016#include <linux/etherdevice.h>
17#include <asm/byteorder.h>
18#include <linux/ip.h>
19#include <linux/ipv6.h>
20#include <linux/udp.h>
21#include <linux/in.h>
22
23#include "gdm_wimax.h"
24#include "hci.h"
25#include "wm_ioctl.h"
26#include "netlink_k.h"
27
28#define gdm_wimax_send(n, d, l) \
29 (n->phy_dev->send_func)(n->phy_dev->priv_dev, d, l, NULL, NULL)
30#define gdm_wimax_send_with_cb(n, d, l, c, b) \
31 (n->phy_dev->send_func)(n->phy_dev->priv_dev, d, l, c, b)
32#define gdm_wimax_rcv_with_cb(n, c, b) \
33 (n->phy_dev->rcv_func)(n->phy_dev->priv_dev, c, b)
34
35#define EVT_MAX_SIZE 2048
36
37struct evt_entry {
Michalis Pappasac1a3bf2014-05-09 18:08:28 +080038 struct list_head list;
39 struct net_device *dev;
40 char evt_data[EVT_MAX_SIZE];
41 int size;
Sage Ahn247e9cf2012-05-15 13:20:36 +090042};
43
Sage Ahn247e9cf2012-05-15 13:20:36 +090044static struct {
45 int ref_cnt;
46 struct sock *sock;
47 struct list_head evtq;
48 spinlock_t evt_lock;
Sage Ahn247e9cf2012-05-15 13:20:36 +090049 struct list_head freeq;
50 struct work_struct ws;
51} wm_event;
52
53static u8 gdm_wimax_macaddr[6] = {0x00, 0x0a, 0x3b, 0xf0, 0x01, 0x30};
54
Sage Ahn247e9cf2012-05-15 13:20:36 +090055static inline int gdm_wimax_header(struct sk_buff **pskb)
56{
57 u16 buf[HCI_HEADER_SIZE / sizeof(u16)];
Ben Chana8a175d2014-06-30 23:32:27 -070058 struct hci_s *hci = (struct hci_s *)buf;
Sage Ahn247e9cf2012-05-15 13:20:36 +090059 struct sk_buff *skb = *pskb;
Sage Ahn247e9cf2012-05-15 13:20:36 +090060
61 if (unlikely(skb_headroom(skb) < HCI_HEADER_SIZE)) {
62 struct sk_buff *skb2;
63
64 skb2 = skb_realloc_headroom(skb, HCI_HEADER_SIZE);
Sudip Mukherjeec32bb252015-09-07 18:08:22 +053065 if (!skb2)
Sage Ahn247e9cf2012-05-15 13:20:36 +090066 return -ENOMEM;
67 if (skb->sk)
68 skb_set_owner_w(skb2, skb->sk);
69 kfree_skb(skb);
70 skb = skb2;
71 }
72
73 skb_push(skb, HCI_HEADER_SIZE);
Ben Chana8a175d2014-06-30 23:32:27 -070074 hci->cmd_evt = cpu_to_be16(WIMAX_TX_SDU);
75 hci->length = cpu_to_be16(skb->len - HCI_HEADER_SIZE);
Sage Ahn247e9cf2012-05-15 13:20:36 +090076 memcpy(skb->data, buf, HCI_HEADER_SIZE);
77
78 *pskb = skb;
Gengis Dave8a5e7b02014-05-23 01:07:13 +020079 return 0;
Sage Ahn247e9cf2012-05-15 13:20:36 +090080}
81
Michalis Pappas1aa8ae72014-07-09 20:44:18 +010082static inline struct evt_entry *alloc_event_entry(void)
83{
84 return kmalloc(sizeof(struct evt_entry), GFP_ATOMIC);
85}
86
Michalis Pappas1aa8ae72014-07-09 20:44:18 +010087static struct evt_entry *get_event_entry(void)
88{
89 struct evt_entry *e;
90
91 if (list_empty(&wm_event.freeq)) {
92 e = alloc_event_entry();
93 } else {
94 e = list_entry(wm_event.freeq.next, struct evt_entry, list);
95 list_del(&e->list);
96 }
97
98 return e;
99}
100
101static void put_event_entry(struct evt_entry *e)
102{
103 BUG_ON(!e);
104
105 list_add_tail(&e->list, &wm_event.freeq);
106}
107
Sage Ahn247e9cf2012-05-15 13:20:36 +0900108static void gdm_wimax_event_rcv(struct net_device *dev, u16 type, void *msg,
109 int len)
110{
111 struct nic *nic = netdev_priv(dev);
112
Tapasweni Pathakedb3cc12014-10-30 17:02:15 +0530113 u8 *buf = msg;
Sage Ahn247e9cf2012-05-15 13:20:36 +0900114 u16 hci_cmd = (buf[0]<<8) | buf[1];
115 u16 hci_len = (buf[2]<<8) | buf[3];
Michalis Pappas39c511f2014-05-09 18:08:27 +0800116
Kristina Martšenko8943a922014-03-15 01:10:05 +0200117 netdev_dbg(dev, "H=>D: 0x%04x(%d)\n", hci_cmd, hci_len);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900118
119 gdm_wimax_send(nic, msg, len);
120}
121
Michalis Pappas1aa8ae72014-07-09 20:44:18 +0100122static void __gdm_wimax_event_send(struct work_struct *work)
123{
124 int idx;
125 unsigned long flags;
126 struct evt_entry *e;
Somya Anand7e6eaa92015-03-14 01:03:09 +0530127 struct evt_entry *tmp;
Michalis Pappas1aa8ae72014-07-09 20:44:18 +0100128
129 spin_lock_irqsave(&wm_event.evt_lock, flags);
130
Somya Anand7e6eaa92015-03-14 01:03:09 +0530131 list_for_each_entry_safe(e, tmp, &wm_event.evtq, list) {
Michalis Pappas1aa8ae72014-07-09 20:44:18 +0100132 spin_unlock_irqrestore(&wm_event.evt_lock, flags);
133
134 if (sscanf(e->dev->name, "wm%d", &idx) == 1)
135 netlink_send(wm_event.sock, idx, 0, e->evt_data,
136 e->size);
137
138 spin_lock_irqsave(&wm_event.evt_lock, flags);
139 list_del(&e->list);
140 put_event_entry(e);
141 }
142
143 spin_unlock_irqrestore(&wm_event.evt_lock, flags);
144}
145
Sage Ahn247e9cf2012-05-15 13:20:36 +0900146static int gdm_wimax_event_init(void)
147{
Devendra Naga8df858e2012-07-12 11:57:25 +0545148 if (!wm_event.ref_cnt) {
Sage Ahn247e9cf2012-05-15 13:20:36 +0900149 wm_event.sock = netlink_init(NETLINK_WIMAX,
150 gdm_wimax_event_rcv);
Ben Chan472aba52012-07-24 07:49:42 -0700151 if (wm_event.sock) {
152 INIT_LIST_HEAD(&wm_event.evtq);
153 INIT_LIST_HEAD(&wm_event.freeq);
154 INIT_WORK(&wm_event.ws, __gdm_wimax_event_send);
155 spin_lock_init(&wm_event.evt_lock);
156 }
157 }
158
159 if (wm_event.sock) {
160 wm_event.ref_cnt++;
Sage Ahn247e9cf2012-05-15 13:20:36 +0900161 return 0;
162 }
163
YAMANE Toshiakif57cee12012-10-29 20:03:47 +0900164 pr_err("Creating WiMax Event netlink is failed\n");
Sage Ahn247e9cf2012-05-15 13:20:36 +0900165 return -1;
166}
167
168static void gdm_wimax_event_exit(void)
169{
170 if (wm_event.sock && --wm_event.ref_cnt == 0) {
171 struct evt_entry *e, *temp;
172 unsigned long flags;
173
174 spin_lock_irqsave(&wm_event.evt_lock, flags);
175
176 list_for_each_entry_safe(e, temp, &wm_event.evtq, list) {
177 list_del(&e->list);
Amitoj Kaur Chawlae1fec532015-10-30 02:12:16 +0530178 kfree(e);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900179 }
180 list_for_each_entry_safe(e, temp, &wm_event.freeq, list) {
181 list_del(&e->list);
Amitoj Kaur Chawlae1fec532015-10-30 02:12:16 +0530182 kfree(e);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900183 }
184
185 spin_unlock_irqrestore(&wm_event.evt_lock, flags);
186 netlink_exit(wm_event.sock);
187 wm_event.sock = NULL;
188 }
189}
190
Sage Ahn247e9cf2012-05-15 13:20:36 +0900191static int gdm_wimax_event_send(struct net_device *dev, char *buf, int size)
192{
193 struct evt_entry *e;
194 unsigned long flags;
195
Sage Ahn247e9cf2012-05-15 13:20:36 +0900196 u16 hci_cmd = ((u8)buf[0]<<8) | (u8)buf[1];
197 u16 hci_len = ((u8)buf[2]<<8) | (u8)buf[3];
Michalis Pappas39c511f2014-05-09 18:08:27 +0800198
Kristina Martšenko8943a922014-03-15 01:10:05 +0200199 netdev_dbg(dev, "D=>H: 0x%04x(%d)\n", hci_cmd, hci_len);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900200
201 spin_lock_irqsave(&wm_event.evt_lock, flags);
202
203 e = get_event_entry();
204 if (!e) {
YAMANE Toshiakif57cee12012-10-29 20:03:47 +0900205 netdev_err(dev, "%s: No memory for event\n", __func__);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900206 spin_unlock_irqrestore(&wm_event.evt_lock, flags);
207 return -ENOMEM;
208 }
209
210 e->dev = dev;
211 e->size = size;
212 memcpy(e->evt_data, buf, size);
213
214 list_add_tail(&e->list, &wm_event.evtq);
215 spin_unlock_irqrestore(&wm_event.evt_lock, flags);
216
217 schedule_work(&wm_event.ws);
218
219 return 0;
220}
221
222static void tx_complete(void *arg)
223{
224 struct nic *nic = arg;
225
226 if (netif_queue_stopped(nic->netdev))
227 netif_wake_queue(nic->netdev);
228}
229
230int gdm_wimax_send_tx(struct sk_buff *skb, struct net_device *dev)
231{
232 int ret = 0;
233 struct nic *nic = netdev_priv(dev);
234
Davide Gianfortea3709f72014-05-23 22:06:44 +0200235 ret = gdm_wimax_send_with_cb(nic, skb->data, skb->len, tx_complete,
236 nic);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900237 if (ret == -ENOSPC) {
238 netif_stop_queue(dev);
239 ret = 0;
240 }
241
242 if (ret) {
243 skb_pull(skb, HCI_HEADER_SIZE);
244 return ret;
245 }
246
Tobias Klauserb92274e2014-07-08 08:47:47 +0200247 dev->stats.tx_packets++;
248 dev->stats.tx_bytes += skb->len - HCI_HEADER_SIZE;
Sage Ahn247e9cf2012-05-15 13:20:36 +0900249 kfree_skb(skb);
250 return ret;
251}
252
253static int gdm_wimax_tx(struct sk_buff *skb, struct net_device *dev)
254{
255 int ret = 0;
Sage Ahn247e9cf2012-05-15 13:20:36 +0900256
Sage Ahn247e9cf2012-05-15 13:20:36 +0900257 ret = gdm_wimax_header(&skb);
258 if (ret < 0) {
259 skb_pull(skb, HCI_HEADER_SIZE);
260 return ret;
261 }
262
Sage Ahn247e9cf2012-05-15 13:20:36 +0900263#if defined(CONFIG_WIMAX_GDM72XX_QOS)
264 ret = gdm_qos_send_hci_pkt(skb, dev);
265#else
266 ret = gdm_wimax_send_tx(skb, dev);
267#endif
268 return ret;
269}
270
271static int gdm_wimax_set_config(struct net_device *dev, struct ifmap *map)
272{
273 if (dev->flags & IFF_UP)
274 return -EBUSY;
275
276 return 0;
277}
278
279static void __gdm_wimax_set_mac_addr(struct net_device *dev, char *mac_addr)
280{
281 u16 hci_pkt_buf[32 / sizeof(u16)];
Ben Chana8a175d2014-06-30 23:32:27 -0700282 struct hci_s *hci = (struct hci_s *)hci_pkt_buf;
Sage Ahn247e9cf2012-05-15 13:20:36 +0900283 struct nic *nic = netdev_priv(dev);
284
285 /* Since dev is registered as a ethernet device,
286 * ether_setup has made dev->addr_len to be ETH_ALEN
287 */
288 memcpy(dev->dev_addr, mac_addr, dev->addr_len);
289
290 /* Let lower layer know of this change by sending
291 * SetInformation(MAC Address)
292 */
Ben Chana8a175d2014-06-30 23:32:27 -0700293 hci->cmd_evt = cpu_to_be16(WIMAX_SET_INFO);
294 hci->length = cpu_to_be16(8);
295 hci->data[0] = 0; /* T */
296 hci->data[1] = 6; /* L */
297 memcpy(&hci->data[2], mac_addr, dev->addr_len); /* V */
Sage Ahn247e9cf2012-05-15 13:20:36 +0900298
Ben Chana8a175d2014-06-30 23:32:27 -0700299 gdm_wimax_send(nic, hci, HCI_HEADER_SIZE + 8);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900300}
301
302/* A driver function */
303static int gdm_wimax_set_mac_addr(struct net_device *dev, void *p)
304{
305 struct sockaddr *addr = p;
306
307 if (netif_running(dev))
308 return -EBUSY;
309
310 if (!is_valid_ether_addr(addr->sa_data))
311 return -EADDRNOTAVAIL;
312
313 __gdm_wimax_set_mac_addr(dev, addr->sa_data);
314
315 return 0;
316}
317
Michalis Pappas1aa8ae72014-07-09 20:44:18 +0100318static void gdm_wimax_ind_if_updown(struct net_device *dev, int if_up)
319{
320 u16 buf[32 / sizeof(u16)];
321 struct hci_s *hci = (struct hci_s *)buf;
322 unsigned char up_down;
323
324 up_down = if_up ? WIMAX_IF_UP : WIMAX_IF_DOWN;
325
326 /* Indicate updating fsm */
327 hci->cmd_evt = cpu_to_be16(WIMAX_IF_UPDOWN);
328 hci->length = cpu_to_be16(sizeof(up_down));
329 hci->data[0] = up_down;
330
331 gdm_wimax_event_send(dev, (char *)hci, HCI_HEADER_SIZE+sizeof(up_down));
332}
333
Sage Ahn247e9cf2012-05-15 13:20:36 +0900334static int gdm_wimax_open(struct net_device *dev)
335{
336 struct nic *nic = netdev_priv(dev);
Shraddha Barke759f19d2015-10-15 00:58:25 +0530337 struct fsm_s *fsm = nic->sdk_data[SIOC_DATA_FSM].buf;
Sage Ahn247e9cf2012-05-15 13:20:36 +0900338
339 netif_start_queue(dev);
340
341 if (fsm && fsm->m_status != M_INIT)
342 gdm_wimax_ind_if_updown(dev, 1);
343 return 0;
344}
345
346static int gdm_wimax_close(struct net_device *dev)
347{
348 struct nic *nic = netdev_priv(dev);
Shraddha Barke759f19d2015-10-15 00:58:25 +0530349 struct fsm_s *fsm = nic->sdk_data[SIOC_DATA_FSM].buf;
Sage Ahn247e9cf2012-05-15 13:20:36 +0900350
351 netif_stop_queue(dev);
352
353 if (fsm && fsm->m_status != M_INIT)
354 gdm_wimax_ind_if_updown(dev, 0);
355 return 0;
356}
357
358static void kdelete(void **buf)
359{
360 if (buf && *buf) {
361 kfree(*buf);
362 *buf = NULL;
363 }
364}
365
366static int gdm_wimax_ioctl_get_data(struct data_s *dst, struct data_s *src)
367{
368 int size;
369
370 size = dst->size < src->size ? dst->size : src->size;
371
372 dst->size = size;
373 if (src->size) {
374 if (!dst->buf)
375 return -EINVAL;
Shraddha Barke759f19d2015-10-15 00:58:25 +0530376 if (copy_to_user(dst->buf, src->buf, size))
Sage Ahn247e9cf2012-05-15 13:20:36 +0900377 return -EFAULT;
378 }
379 return 0;
380}
381
382static int gdm_wimax_ioctl_set_data(struct data_s *dst, struct data_s *src)
383{
384 if (!src->size) {
385 dst->size = 0;
386 return 0;
387 }
388
389 if (!src->buf)
390 return -EINVAL;
391
392 if (!(dst->buf && dst->size == src->size)) {
393 kdelete(&dst->buf);
394 dst->buf = kmalloc(src->size, GFP_KERNEL);
Sudip Mukherjeec32bb252015-09-07 18:08:22 +0530395 if (!dst->buf)
Sage Ahn247e9cf2012-05-15 13:20:36 +0900396 return -ENOMEM;
397 }
398
Shraddha Barke759f19d2015-10-15 00:58:25 +0530399 if (copy_from_user(dst->buf, src->buf, src->size)) {
Sage Ahn247e9cf2012-05-15 13:20:36 +0900400 kdelete(&dst->buf);
401 return -EFAULT;
402 }
403 dst->size = src->size;
404 return 0;
405}
406
407static void gdm_wimax_cleanup_ioctl(struct net_device *dev)
408{
409 struct nic *nic = netdev_priv(dev);
410 int i;
411
412 for (i = 0; i < SIOC_DATA_MAX; i++)
413 kdelete(&nic->sdk_data[i].buf);
414}
415
Michalis Pappas1aa8ae72014-07-09 20:44:18 +0100416static void gdm_wimax_ind_fsm_update(struct net_device *dev, struct fsm_s *fsm)
417{
418 u16 buf[32 / sizeof(u16)];
419 struct hci_s *hci = (struct hci_s *)buf;
420
421 /* Indicate updating fsm */
422 hci->cmd_evt = cpu_to_be16(WIMAX_FSM_UPDATE);
423 hci->length = cpu_to_be16(sizeof(struct fsm_s));
424 memcpy(&hci->data[0], fsm, sizeof(struct fsm_s));
425
426 gdm_wimax_event_send(dev, (char *)hci,
427 HCI_HEADER_SIZE + sizeof(struct fsm_s));
428}
429
Sage Ahn247e9cf2012-05-15 13:20:36 +0900430static void gdm_update_fsm(struct net_device *dev, struct fsm_s *new_fsm)
431{
432 struct nic *nic = netdev_priv(dev);
Shraddha Barke759f19d2015-10-15 00:58:25 +0530433 struct fsm_s *cur_fsm =
Davide Gianfortea3709f72014-05-23 22:06:44 +0200434 nic->sdk_data[SIOC_DATA_FSM].buf;
Sage Ahn247e9cf2012-05-15 13:20:36 +0900435
436 if (!cur_fsm)
437 return;
438
439 if (cur_fsm->m_status != new_fsm->m_status ||
Michalis Pappas39c511f2014-05-09 18:08:27 +0800440 cur_fsm->c_status != new_fsm->c_status) {
Michalis Pappas71fd11e2014-05-09 18:08:25 +0800441 if (new_fsm->m_status == M_CONNECTED) {
Sage Ahn247e9cf2012-05-15 13:20:36 +0900442 netif_carrier_on(dev);
Michalis Pappas71fd11e2014-05-09 18:08:25 +0800443 } else if (cur_fsm->m_status == M_CONNECTED) {
Sage Ahn247e9cf2012-05-15 13:20:36 +0900444 netif_carrier_off(dev);
445 #if defined(CONFIG_WIMAX_GDM72XX_QOS)
446 gdm_qos_release_list(nic);
447 #endif
448 }
449 gdm_wimax_ind_fsm_update(dev, new_fsm);
450 }
451}
452
453static int gdm_wimax_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
454{
Michalis Pappas39c511f2014-05-09 18:08:27 +0800455 struct wm_req_s *req = (struct wm_req_s *)ifr;
Sage Ahn247e9cf2012-05-15 13:20:36 +0900456 struct nic *nic = netdev_priv(dev);
457 int ret;
458
459 if (cmd != SIOCWMIOCTL)
460 return -EOPNOTSUPP;
461
462 switch (req->cmd) {
463 case SIOCG_DATA:
464 case SIOCS_DATA:
465 if (req->data_id >= SIOC_DATA_MAX) {
YAMANE Toshiakif57cee12012-10-29 20:03:47 +0900466 netdev_err(dev, "%s error: data-index(%d) is invalid!!\n",
467 __func__, req->data_id);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900468 return -EOPNOTSUPP;
469 }
470 if (req->cmd == SIOCG_DATA) {
Davide Gianfortea3709f72014-05-23 22:06:44 +0200471 ret = gdm_wimax_ioctl_get_data(
472 &req->data, &nic->sdk_data[req->data_id]);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900473 if (ret < 0)
474 return ret;
475 } else if (req->cmd == SIOCS_DATA) {
476 if (req->data_id == SIOC_DATA_FSM) {
Ben Chane7d374e2014-06-24 00:55:58 -0700477 /* NOTE: gdm_update_fsm should be called
478 * before gdm_wimax_ioctl_set_data is called.
479 */
Davide Gianfortea3709f72014-05-23 22:06:44 +0200480 gdm_update_fsm(dev,
Shraddha Barke759f19d2015-10-15 00:58:25 +0530481 req->data.buf);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900482 }
483 ret = gdm_wimax_ioctl_set_data(
484 &nic->sdk_data[req->data_id], &req->data);
485 if (ret < 0)
486 return ret;
487 }
488 break;
489 default:
YAMANE Toshiakif57cee12012-10-29 20:03:47 +0900490 netdev_err(dev, "%s: %x unknown ioctl\n", __func__, cmd);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900491 return -EOPNOTSUPP;
492 }
493
494 return 0;
495}
496
497static void gdm_wimax_prepare_device(struct net_device *dev)
498{
499 struct nic *nic = netdev_priv(dev);
500 u16 buf[32 / sizeof(u16)];
Michalis Pappas39c511f2014-05-09 18:08:27 +0800501 struct hci_s *hci = (struct hci_s *)buf;
Sage Ahn247e9cf2012-05-15 13:20:36 +0900502 u16 len = 0;
503 u32 val = 0;
Ben Chana8a175d2014-06-30 23:32:27 -0700504 __be32 val_be32;
Sage Ahn247e9cf2012-05-15 13:20:36 +0900505
Sage Ahn247e9cf2012-05-15 13:20:36 +0900506 /* GetInformation mac address */
507 len = 0;
Ben Chana8a175d2014-06-30 23:32:27 -0700508 hci->cmd_evt = cpu_to_be16(WIMAX_GET_INFO);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900509 hci->data[len++] = TLV_T(T_MAC_ADDRESS);
Ben Chana8a175d2014-06-30 23:32:27 -0700510 hci->length = cpu_to_be16(len);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900511 gdm_wimax_send(nic, hci, HCI_HEADER_SIZE+len);
512
Michalis Pappas7ba58222014-07-09 20:21:21 +0100513 val = T_CAPABILITY_WIMAX | T_CAPABILITY_MULTI_CS;
Sage Ahn247e9cf2012-05-15 13:20:36 +0900514 #if defined(CONFIG_WIMAX_GDM72XX_QOS)
Michalis Pappas7ba58222014-07-09 20:21:21 +0100515 val |= T_CAPABILITY_QOS;
Sage Ahn247e9cf2012-05-15 13:20:36 +0900516 #endif
517 #if defined(CONFIG_WIMAX_GDM72XX_WIMAX2)
Michalis Pappas7ba58222014-07-09 20:21:21 +0100518 val |= T_CAPABILITY_AGGREGATION;
Sage Ahn247e9cf2012-05-15 13:20:36 +0900519 #endif
520
521 /* Set capability */
522 len = 0;
Ben Chana8a175d2014-06-30 23:32:27 -0700523 hci->cmd_evt = cpu_to_be16(WIMAX_SET_INFO);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900524 hci->data[len++] = TLV_T(T_CAPABILITY);
525 hci->data[len++] = TLV_L(T_CAPABILITY);
Ben Chana8a175d2014-06-30 23:32:27 -0700526 val_be32 = cpu_to_be32(val);
527 memcpy(&hci->data[len], &val_be32, TLV_L(T_CAPABILITY));
Sage Ahn247e9cf2012-05-15 13:20:36 +0900528 len += TLV_L(T_CAPABILITY);
Ben Chana8a175d2014-06-30 23:32:27 -0700529 hci->length = cpu_to_be16(len);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900530 gdm_wimax_send(nic, hci, HCI_HEADER_SIZE+len);
531
Ben Chana8a175d2014-06-30 23:32:27 -0700532 netdev_info(dev, "GDM WiMax Set CAPABILITY: 0x%08X\n", val);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900533}
534
535static int gdm_wimax_hci_get_tlv(u8 *buf, u8 *T, u16 *L, u8 **V)
536{
537 #define __U82U16(b) ((u16)((u8 *)(b))[0] | ((u16)((u8 *)(b))[1] << 8))
538 int next_pos;
539
540 *T = buf[0];
541 if (buf[1] == 0x82) {
Ben Chana8a175d2014-06-30 23:32:27 -0700542 *L = be16_to_cpu(__U82U16(&buf[2]));
Sage Ahn247e9cf2012-05-15 13:20:36 +0900543 next_pos = 1/*type*/+3/*len*/;
544 } else {
545 *L = buf[1];
546 next_pos = 1/*type*/+1/*len*/;
547 }
548 *V = &buf[next_pos];
549
550 next_pos += *L/*length of val*/;
551 return next_pos;
552}
553
Davide Gianfortea3709f72014-05-23 22:06:44 +0200554static int gdm_wimax_get_prepared_info(struct net_device *dev, char *buf,
555 int len)
Sage Ahn247e9cf2012-05-15 13:20:36 +0900556{
557 u8 T, *V;
558 u16 L;
559 u16 cmd_evt, cmd_len;
560 int pos = HCI_HEADER_SIZE;
561
Ben Chana8a175d2014-06-30 23:32:27 -0700562 cmd_evt = be16_to_cpup((const __be16 *)&buf[0]);
563 cmd_len = be16_to_cpup((const __be16 *)&buf[2]);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900564
565 if (len < cmd_len + HCI_HEADER_SIZE) {
YAMANE Toshiakif57cee12012-10-29 20:03:47 +0900566 netdev_err(dev, "%s: invalid length [%d/%d]\n", __func__,
567 cmd_len + HCI_HEADER_SIZE, len);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900568 return -1;
569 }
570
571 if (cmd_evt == WIMAX_GET_INFO_RESULT) {
572 if (cmd_len < 2) {
YAMANE Toshiakif57cee12012-10-29 20:03:47 +0900573 netdev_err(dev, "%s: len is too short [%x/%d]\n",
574 __func__, cmd_evt, len);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900575 return -1;
576 }
577
578 pos += gdm_wimax_hci_get_tlv(&buf[pos], &T, &L, &V);
Alison Schofield0a589f42015-10-12 13:53:22 -0700579 if (TLV_T(T_MAC_ADDRESS) == T) {
580 if (dev->addr_len != L) {
YAMANE Toshiakif57cee12012-10-29 20:03:47 +0900581 netdev_err(dev,
Masanari Iida24768162015-05-27 23:51:51 +0900582 "%s Invalid information result T/L [%x/%d]\n",
YAMANE Toshiakif57cee12012-10-29 20:03:47 +0900583 __func__, T, L);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900584 return -1;
585 }
YAMANE Toshiakif57cee12012-10-29 20:03:47 +0900586 netdev_info(dev, "MAC change [%pM]->[%pM]\n",
587 dev->dev_addr, V);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900588 memcpy(dev->dev_addr, V, dev->addr_len);
589 return 1;
590 }
591 }
592
593 gdm_wimax_event_send(dev, buf, len);
594 return 0;
595}
596
597static void gdm_wimax_netif_rx(struct net_device *dev, char *buf, int len)
598{
Sage Ahn247e9cf2012-05-15 13:20:36 +0900599 struct sk_buff *skb;
600 int ret;
601
Sage Ahn247e9cf2012-05-15 13:20:36 +0900602 skb = dev_alloc_skb(len + 2);
Sarah Khan35b042a2014-10-06 00:25:51 +0530603 if (!skb)
Sage Ahn247e9cf2012-05-15 13:20:36 +0900604 return;
Sage Ahn247e9cf2012-05-15 13:20:36 +0900605 skb_reserve(skb, 2);
606
Tobias Klauserb92274e2014-07-08 08:47:47 +0200607 dev->stats.rx_packets++;
608 dev->stats.rx_bytes += len;
Sage Ahn247e9cf2012-05-15 13:20:36 +0900609
610 memcpy(skb_put(skb, len), buf, len);
611
612 skb->dev = dev;
613 skb->protocol = eth_type_trans(skb, dev); /* what will happen? */
614
615 ret = in_interrupt() ? netif_rx(skb) : netif_rx_ni(skb);
616 if (ret == NET_RX_DROP)
YAMANE Toshiakif57cee12012-10-29 20:03:47 +0900617 netdev_err(dev, "%s skb dropped\n", __func__);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900618}
619
620static void gdm_wimax_transmit_aggr_pkt(struct net_device *dev, char *buf,
621 int len)
622{
623 #define HCI_PADDING_BYTE 4
624 #define HCI_RESERVED_BYTE 4
625 struct hci_s *hci;
626 int length;
627
628 while (len > 0) {
Michalis Pappas39c511f2014-05-09 18:08:27 +0800629 hci = (struct hci_s *)buf;
Sage Ahn247e9cf2012-05-15 13:20:36 +0900630
Ben Chana8a175d2014-06-30 23:32:27 -0700631 if (hci->cmd_evt != cpu_to_be16(WIMAX_RX_SDU)) {
YAMANE Toshiakif57cee12012-10-29 20:03:47 +0900632 netdev_err(dev, "Wrong cmd_evt(0x%04X)\n",
Ben Chana8a175d2014-06-30 23:32:27 -0700633 be16_to_cpu(hci->cmd_evt));
Sage Ahn247e9cf2012-05-15 13:20:36 +0900634 break;
635 }
636
Ben Chana8a175d2014-06-30 23:32:27 -0700637 length = be16_to_cpu(hci->length);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900638 gdm_wimax_netif_rx(dev, hci->data, length);
639
640 if (length & 0x3) {
641 /* Add padding size */
642 length += HCI_PADDING_BYTE - (length & 0x3);
643 }
644
645 length += HCI_HEADER_SIZE + HCI_RESERVED_BYTE;
646 len -= length;
647 buf += length;
648 }
649}
650
651static void gdm_wimax_transmit_pkt(struct net_device *dev, char *buf, int len)
652{
653 #if defined(CONFIG_WIMAX_GDM72XX_QOS)
654 struct nic *nic = netdev_priv(dev);
655 #endif
656 u16 cmd_evt, cmd_len;
657
658 /* This code is added for certain rx packet to be ignored. */
659 if (len == 0)
660 return;
661
Ben Chana8a175d2014-06-30 23:32:27 -0700662 cmd_evt = be16_to_cpup((const __be16 *)&buf[0]);
663 cmd_len = be16_to_cpup((const __be16 *)&buf[2]);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900664
665 if (len < cmd_len + HCI_HEADER_SIZE) {
666 if (len)
YAMANE Toshiakif57cee12012-10-29 20:03:47 +0900667 netdev_err(dev, "%s: invalid length [%d/%d]\n",
668 __func__, cmd_len + HCI_HEADER_SIZE, len);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900669 return;
670 }
671
672 switch (cmd_evt) {
673 case WIMAX_RX_SDU_AGGR:
Davide Gianfortea3709f72014-05-23 22:06:44 +0200674 gdm_wimax_transmit_aggr_pkt(dev, &buf[HCI_HEADER_SIZE],
675 cmd_len);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900676 break;
677 case WIMAX_RX_SDU:
678 gdm_wimax_netif_rx(dev, &buf[HCI_HEADER_SIZE], cmd_len);
679 break;
680 #if defined(CONFIG_WIMAX_GDM72XX_QOS)
681 case WIMAX_EVT_MODEM_REPORT:
682 gdm_recv_qos_hci_packet(nic, buf, len);
683 break;
684 #endif
685 case WIMAX_SDU_TX_FLOW:
686 if (buf[4] == 0) {
687 if (!netif_queue_stopped(dev))
688 netif_stop_queue(dev);
689 } else if (buf[4] == 1) {
690 if (netif_queue_stopped(dev))
691 netif_wake_queue(dev);
692 }
693 break;
694 default:
695 gdm_wimax_event_send(dev, buf, len);
696 break;
697 }
698}
699
Sage Ahn247e9cf2012-05-15 13:20:36 +0900700static void rx_complete(void *arg, void *data, int len)
701{
702 struct nic *nic = arg;
703
704 gdm_wimax_transmit_pkt(nic->netdev, data, len);
705 gdm_wimax_rcv_with_cb(nic, rx_complete, nic);
706}
707
708static void prepare_rx_complete(void *arg, void *data, int len)
709{
710 struct nic *nic = arg;
711 int ret;
712
713 ret = gdm_wimax_get_prepared_info(nic->netdev, data, len);
Michalis Pappas71fd11e2014-05-09 18:08:25 +0800714 if (ret == 1) {
Sage Ahn247e9cf2012-05-15 13:20:36 +0900715 gdm_wimax_rcv_with_cb(nic, rx_complete, nic);
Michalis Pappas71fd11e2014-05-09 18:08:25 +0800716 } else {
Sage Ahn247e9cf2012-05-15 13:20:36 +0900717 if (ret < 0)
YAMANE Toshiakif57cee12012-10-29 20:03:47 +0900718 netdev_err(nic->netdev,
719 "get_prepared_info failed(%d)\n", ret);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900720 gdm_wimax_rcv_with_cb(nic, prepare_rx_complete, nic);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900721 }
722}
723
724static void start_rx_proc(struct nic *nic)
725{
726 gdm_wimax_rcv_with_cb(nic, prepare_rx_complete, nic);
727}
728
729static struct net_device_ops gdm_netdev_ops = {
Michalis Pappasac1a3bf2014-05-09 18:08:28 +0800730 .ndo_open = gdm_wimax_open,
731 .ndo_stop = gdm_wimax_close,
732 .ndo_set_config = gdm_wimax_set_config,
733 .ndo_start_xmit = gdm_wimax_tx,
Sage Ahn247e9cf2012-05-15 13:20:36 +0900734 .ndo_set_mac_address = gdm_wimax_set_mac_addr,
Michalis Pappasac1a3bf2014-05-09 18:08:28 +0800735 .ndo_do_ioctl = gdm_wimax_ioctl,
Sage Ahn247e9cf2012-05-15 13:20:36 +0900736};
737
Paul Stewart54bc1ff2012-05-17 11:15:10 -0700738int register_wimax_device(struct phy_dev *phy_dev, struct device *pdev)
Sage Ahn247e9cf2012-05-15 13:20:36 +0900739{
740 struct nic *nic = NULL;
741 struct net_device *dev;
742 int ret;
743
Tom Gundersenc835a672014-07-14 16:37:24 +0200744 dev = alloc_netdev(sizeof(*nic), "wm%d", NET_NAME_UNKNOWN,
745 ether_setup);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900746
Somya Anand87e3dbc2015-03-16 19:34:08 +0530747 if (!dev) {
YAMANE Toshiakif57cee12012-10-29 20:03:47 +0900748 pr_err("alloc_etherdev failed\n");
Sage Ahn247e9cf2012-05-15 13:20:36 +0900749 return -ENOMEM;
750 }
751
Paul Stewart54bc1ff2012-05-17 11:15:10 -0700752 SET_NETDEV_DEV(dev, pdev);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900753 dev->mtu = 1400;
754 dev->netdev_ops = &gdm_netdev_ops;
755 dev->flags &= ~IFF_MULTICAST;
756 memcpy(dev->dev_addr, gdm_wimax_macaddr, sizeof(gdm_wimax_macaddr));
757
758 nic = netdev_priv(dev);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900759 nic->netdev = dev;
760 nic->phy_dev = phy_dev;
761 phy_dev->netdev = dev;
762
763 /* event socket init */
764 ret = gdm_wimax_event_init();
765 if (ret < 0) {
YAMANE Toshiakif57cee12012-10-29 20:03:47 +0900766 pr_err("Cannot create event.\n");
Sage Ahn247e9cf2012-05-15 13:20:36 +0900767 goto cleanup;
768 }
769
770 ret = register_netdev(dev);
771 if (ret)
772 goto cleanup;
773
Sage Ahn247e9cf2012-05-15 13:20:36 +0900774 netif_carrier_off(dev);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900775
776#ifdef CONFIG_WIMAX_GDM72XX_QOS
777 gdm_qos_init(nic);
778#endif
779
780 start_rx_proc(nic);
781
782 /* Prepare WiMax device */
783 gdm_wimax_prepare_device(dev);
784
785 return 0;
786
787cleanup:
YAMANE Toshiakif57cee12012-10-29 20:03:47 +0900788 pr_err("register_netdev failed\n");
Sage Ahn247e9cf2012-05-15 13:20:36 +0900789 free_netdev(dev);
790 return ret;
791}
792
793void unregister_wimax_device(struct phy_dev *phy_dev)
794{
795 struct nic *nic = netdev_priv(phy_dev->netdev);
Shraddha Barke759f19d2015-10-15 00:58:25 +0530796 struct fsm_s *fsm = nic->sdk_data[SIOC_DATA_FSM].buf;
Sage Ahn247e9cf2012-05-15 13:20:36 +0900797
798 if (fsm)
799 fsm->m_status = M_INIT;
800 unregister_netdev(nic->netdev);
801
802 gdm_wimax_event_exit();
803
804#if defined(CONFIG_WIMAX_GDM72XX_QOS)
805 gdm_qos_release_list(nic);
806#endif
807
808 gdm_wimax_cleanup_ioctl(phy_dev->netdev);
809
810 free_netdev(nic->netdev);
811}