net:wireless:Support eswin usb wifi ECR6600U
[platform/kernel/linux-starfive.git] / drivers / net / wireless / eswin / sdio / core.c
1 /**\r
2  ******************************************************************************\r
3  *\r
4  * @file core.c\r
5  *\r
6  * @brief sdio core function definitions\r
7  *\r
8  * Copyright (C) ESWIN 2015-2020\r
9  *\r
10  ******************************************************************************\r
11  */\r
12 #include <linux/firmware.h>\r
13 #include <linux/kthread.h>\r
14 #include "core.h"\r
15 #include "fw.h"\r
16 #include <uapi/linux/sched/types.h>\r
17 //#include "debug.h"\r
18 #include "ecrnx_platform.h"\r
19 #include "sdio.h"\r
20 #include "ecrnx_rx.h"\r
21 #include "sdio_host_interface.h"\r
22 #include "eswin_utils.h"\r
23 \r
24 bool loopback;\r
25 module_param(loopback, bool, S_IRUSR | S_IWUSR);\r
26 MODULE_PARM_DESC(loopback, "HIF loopback");\r
27 \r
28 int power_save;\r
29 module_param(power_save, int, S_IRUSR | S_IWUSR);\r
30 MODULE_PARM_DESC(power_save, "Power Save(0: disable, 1:enable)");\r
31 \r
32 int disable_cqm = 0;\r
33 module_param(disable_cqm, int, S_IRUSR | S_IWUSR);\r
34 MODULE_PARM_DESC(disable_cqm, "Disable CQM (0: disable, 1:enable)");\r
35 \r
36 \r
37 int listen_interval = 0;\r
38 module_param(listen_interval, int, S_IRUSR | S_IWUSR);\r
39 MODULE_PARM_DESC(listen_interval, "Listen Interval");\r
40 \r
41 int bss_max_idle = 0;\r
42 module_param(bss_max_idle, int, S_IRUSR | S_IWUSR);\r
43 MODULE_PARM_DESC(bss_max_idle, "BSS Max Idle");\r
44 \r
45 \r
46 bool dl_fw;\r
47 module_param(dl_fw, bool, S_IRUSR | S_IWUSR);\r
48 MODULE_PARM_DESC(dl_fw, "download firmware");\r
49 \r
50 \r
51 #ifdef CONFIG_ECRNX_WIFO_CAIL\r
52 bool amt_mode;\r
53 module_param(amt_mode, bool, S_IRUSR | S_IWUSR);\r
54 MODULE_PARM_DESC(amt_mode, "calibrate mode");\r
55 #endif\r
56 \r
57 bool set_gain;\r
58 module_param(set_gain, bool, S_IRUSR | S_IWUSR);\r
59 MODULE_PARM_DESC(set_gain, "set gain delta");\r
60 \r
61 char *fw_name;\r
62 struct eswin *pEswin;\r
63 \r
64 module_param(fw_name, charp, S_IRUGO);\r
65 MODULE_PARM_DESC(fw_name, "Firmware file name");\r
66 \r
67 #if 0\r
68 static void eswin_fw_ready(struct sk_buff *skb, struct eswin * tr)\r
69 {\r
70         struct ieee80211_hw *hw = tr->hw;\r
71         struct wim_ready *ready;\r
72         struct wim *wim = (struct wim *)skb->data;\r
73 \r
74         ECRNX_PRINT(" %s entry!!", __func__);\r
75         ready = (struct wim_ready *) (wim + 1);\r
76 \r
77         ECRNX_PRINT(" %s  -- version: 0x%x", __func__, ready->v.version);\r
78         ECRNX_PRINT(" %s  -- rx_head_size: %d", __func__, ready->v.rx_head_size);\r
79         ECRNX_PRINT(" %s  -- tx_head_size: %d", __func__, ready->v.tx_head_size);\r
80         ECRNX_PRINT(" %s  -- buffer_size: %d", __func__, ready->v.buffer_size);\r
81 \r
82         tr->fwinfo.ready = 2;\r
83         tr->fwinfo.version = ready->v.version;\r
84         tr->fwinfo.rx_head_size = ready->v.rx_head_size;\r
85         tr->fwinfo.tx_head_size = ready->v.tx_head_size;\r
86         tr->fwinfo.payload_align = ready->v.payload_align;\r
87         tr->fwinfo.buffer_size = ready->v.buffer_size;\r
88 \r
89         ECRNX_PRINT(" %s  -- cap_mask: 0x%llx", __func__, ready->v.cap.cap);\r
90         ECRNX_PRINT(" %s  -- cap_li: %d, %d", __func__, ready->v.cap.listen_interval, listen_interval);\r
91         ECRNX_PRINT(" %s  -- cap_idle: %d, %d", __func__, ready->v.cap.bss_max_idle, bss_max_idle);\r
92 \r
93         tr->cap.cap_mask = ready->v.cap.cap;\r
94         tr->cap.listen_interval = ready->v.cap.listen_interval;\r
95         tr->cap.bss_max_idle = ready->v.cap.bss_max_idle;\r
96 \r
97         if (listen_interval) {\r
98                 hw->max_listen_interval = listen_interval;\r
99                 tr->cap.listen_interval = listen_interval;\r
100         } \r
101 \r
102         if (bss_max_idle) {\r
103                 tr->cap.bss_max_idle = bss_max_idle;\r
104         } \r
105 \r
106         dev_kfree_skb(skb);\r
107         ECRNX_PRINT(" %s exit!!", __func__);\r
108 }\r
109 #endif\r
110 static unsigned int sdio_tx_packets = 0;
111 static struct timer_list sdio_tx_timer = {0};
112 \r
113 #define SDIO_TX_TIMER_TIMEOUT_US          (200)
114 \r
115 void sdio_tx_queue_init(struct tx_buff_queue * queue)\r
116 {\r
117         queue->head = NULL;\r
118         queue->tail = NULL;\r
119         queue->count = 0;\r
120         spin_lock_init(&queue->lock);\r
121 }\r
122 \r
123 void sdio_tx_queue_push(struct tx_buff_queue * queue, struct tx_buff_node *node)\r
124 {\r
125         unsigned long flags;\r
126 \r
127         spin_lock_irqsave(&queue->lock, flags);\r
128         if (queue->head) {\r
129                 queue->tail->next = node;\r
130         } else {\r
131                 queue->head = node;\r
132         }\r
133 \r
134         queue->tail = node;;\r
135         queue->tail->next = NULL;\r
136         queue->count++;\r
137 \r
138         spin_unlock_irqrestore(&queue->lock, flags);\r
139 \r
140         //ECRNX_PRINT(" queue push count: %d\n", queue->count);\r
141         //ECRNX_PRINT(" queue push head: %#x\n", queue->head);\r
142 }\r
143 \r
144 struct tx_buff_node *sdio_tx_queue_pop(struct tx_buff_queue *queue)\r
145 {\r
146         unsigned long flags;\r
147         struct tx_buff_node *res = NULL;\r
148 \r
149         //ECRNX_PRINT(" queue pop count: %d\n", queue->count);\r
150         //ECRNX_PRINT(" queue pop head: %#x\n", queue->head);\r
151 \r
152         spin_lock_irqsave(&queue->lock, flags);\r
153 \r
154         if (queue->count) {\r
155                 res = queue->head;\r
156                 queue->head = res->next;\r
157                 res->next = NULL;\r
158                 queue->count--;\r
159         }\r
160 \r
161         spin_unlock_irqrestore(&queue->lock, flags);\r
162         return res;\r
163 }\r
164 \r
165 struct tx_buff_node *sdio_tx_queue_peek(struct tx_buff_queue *queue)\r
166 {\r
167         unsigned long flags;\r
168         struct tx_buff_node *res = NULL;\r
169 \r
170         spin_lock_irqsave(&queue->lock, flags);\r
171 \r
172         if (queue->count) {\r
173                 res = queue->head;\r
174         }\r
175 \r
176         spin_unlock_irqrestore(&queue->lock, flags);\r
177         return res;\r
178 }\r
179 \r
180 struct tx_buff_node * sdio_tx_node_alloc(struct eswin *tr)\r
181 {\r
182         struct tx_buff_node * res;\r
183         unsigned long flags;\r
184 \r
185         spin_lock_irqsave(&tr->tx_lock,flags);\r
186         res = tr->tx_node_head;\r
187         if(res == NULL)\r
188         {\r
189                 spin_unlock_irqrestore(&tr->tx_lock, flags);\r
190                 return NULL;\r
191         }\r
192         tr->tx_node_head = tr->tx_node_head->next;\r
193         res->next = NULL;\r
194         tr->tx_node_num--;\r
195         spin_unlock_irqrestore(&tr->tx_lock, flags);\r
196 \r
197         return res;\r
198 }\r
199 \r
200 void sdio_tx_node_free(struct eswin *tr, struct tx_buff_node * node)\r
201 {\r
202         unsigned long flags;\r
203         spin_lock_irqsave(&tr->tx_lock,flags);\r
204         kfree(node->buff);\r
205     node->buff = NULL;\r
206         node->next = tr->tx_node_head;\r
207         tr->tx_node_head = node;\r
208         tr->tx_node_num++;\r
209         spin_unlock_irqrestore(&tr->tx_lock, flags);\r
210 }\r
211 \r
212 void sdio_tx_pkg_queue_init(struct tx_buff_pkg_queue * queue)\r
213 {\r
214         queue->head = NULL;\r
215         queue->tail = NULL;\r
216         queue->count = 0;\r
217         spin_lock_init(&queue->lock);\r
218 }\r
219 \r
220 void sdio_tx_pkg_queue_push(struct tx_buff_pkg_queue * queue, struct tx_buff_pkg_node *node)\r
221 {\r
222         unsigned long flags;\r
223 \r
224         spin_lock_irqsave(&queue->lock, flags);\r
225         if (queue->head) {\r
226                 queue->tail->next = node;\r
227         } else {\r
228                 queue->head = node;\r
229         }\r
230 \r
231         queue->tail = node;;\r
232         queue->tail->next = NULL;\r
233         queue->count++;\r
234 \r
235         spin_unlock_irqrestore(&queue->lock, flags);\r
236 }\r
237 \r
238 struct tx_buff_pkg_node *sdio_tx_pkg_queue_pop(struct tx_buff_pkg_queue *queue)\r
239 {\r
240         unsigned long flags;\r
241         struct tx_buff_pkg_node *res = NULL;\r
242 \r
243         spin_lock_irqsave(&queue->lock, flags);\r
244 \r
245         if (queue->count) {\r
246                 res = queue->head;\r
247                 queue->head = res->next;\r
248                 res->next = NULL;\r
249                 queue->count--;\r
250         }\r
251 \r
252         spin_unlock_irqrestore(&queue->lock, flags);\r
253         return res;\r
254 }\r
255 \r
256 struct tx_buff_pkg_node * sdio_tx_pkg_node_alloc(struct eswin *tr)\r
257 {\r
258         struct tx_buff_pkg_node * res;\r
259         unsigned long flags;\r
260 \r
261         spin_lock_irqsave(&tr->tx_pkg_lock,flags);\r
262         res = tr->tx_pkg_node_head;\r
263         if(res == NULL)\r
264         {\r
265                 spin_unlock_irqrestore(&tr->tx_pkg_lock, flags);\r
266                 return NULL;\r
267         }\r
268         tr->tx_pkg_node_head = tr->tx_pkg_node_head->next;\r
269         res->next = NULL;\r
270         tr->tx_pkg_node_num--;\r
271         spin_unlock_irqrestore(&tr->tx_pkg_lock, flags);\r
272 \r
273         return res;\r
274 }\r
275 \r
276 void sdio_tx_pkg_node_free(struct eswin *tr, struct tx_buff_pkg_node * node)\r
277 {\r
278         unsigned long flags;\r
279         int i;\r
280         spin_lock_irqsave(&tr->tx_pkg_lock,flags);\r
281         if((node->flag & FLAG_MSG_TYPE_MASK) == TX_FLAG_TX_DESC)\r
282         {\r
283                 kfree(node->buff);\r
284         }\r
285         node->buff = NULL;\r
286         node->next = tr->tx_pkg_node_head;\r
287         tr->tx_pkg_node_head = node;\r
288         tr->tx_pkg_node_num++;\r
289         /*\r
290         if (node->node_cnt > 1)\r
291         {\r
292                 printk("%s,count :%d\n",__func__,node->node_cnt);\r
293         }\r
294         */\r
295 \r
296         for (i = 0; i < node->node_cnt; ++i)\r
297         {\r
298                 sdio_tx_node_free(tr, node->tx_node[i]);\r
299         }\r
300         spin_unlock_irqrestore(&tr->tx_pkg_lock, flags);\r
301 }\r
302 \r
303 \r
304 void eswin_sdio_register_rx_cb(struct eswin *tr, sdio_rx_cb_t cb)\r
305 {\r
306     tr->rx_callback = cb;\r
307 }\r
308 \r
309 extern int ecrnx_data_cfm_callback(void *priv, void *host_id);\r
310 extern int ecrnx_msg_cfm_callback(void *priv, void *host_id);\r
311 static void eswin_core_register_work(struct work_struct *work)\r
312 {\r
313         //struct sk_buff *skb_resp;\r
314         int ret;\r
315         struct eswin *tr = container_of(work, struct eswin, register_work.work);\r
316 \r
317         ECRNX_PRINT(" %s entry, dl_fw = %d!!", __func__, dl_fw);\r
318 \r
319         if (dl_fw  && eswin_fw_file_chech(tr)) {\r
320                 eswin_fw_file_download(tr);\r
321         release_firmware(tr->fw);\r
322                 dl_fw = false;\r
323                 schedule_delayed_work(&tr->register_work, msecs_to_jiffies(1000));\r
324                 return;\r
325         }\r
326 \r
327 #ifdef CONFIG_ECRNX_WIFO_CAIL\r
328         ECRNX_PRINT(" %s entry, amt_mode = %d!!", __func__, amt_mode);\r
329 #endif\r
330 \r
331         tr->rx_callback = ecrnx_rx_callback;\r
332         tr->data_cfm_callback = ecrnx_data_cfm_callback;\r
333         tr->msg_cfm_callback = ecrnx_msg_cfm_callback;\r
334 \r
335         ret = ecrnx_platform_init(tr, &tr->umac_priv);\r
336         set_bit(ESWIN_FLAG_CORE_REGISTERED, &tr->dev_flags);\r
337     ECRNX_DBG("%s exit!!", __func__);\r
338 \r
339     return;\r
340 }\r
341 \r
342 int eswin_core_register(struct eswin *tr)\r
343 {\r
344         ECRNX_PRINT("%s entry!!", __func__);\r
345         tr->ops->start(tr);\r
346 \r
347         //schedule_delayed_work(&tr->register_work, msecs_to_jiffies(10));\r
348         schedule_delayed_work(&tr->register_work, msecs_to_jiffies(1));\r
349         ECRNX_PRINT("%s exit!!", __func__);\r
350         return 0;\r
351 }\r
352 \r
353 void eswin_core_unregister(struct eswin *tr)\r
354 {\r
355         struct eswin_sdio *tr_sdio   = (struct eswin_sdio *)tr->drv_priv;\r
356         ECRNX_PRINT("%s entry!!", __func__);\r
357 \r
358         cancel_delayed_work(&tr->register_work);\r
359 \r
360         if (!test_bit(ESWIN_FLAG_CORE_REGISTERED, &tr->dev_flags))\r
361                 return;\r
362 \r
363     ecrnx_platform_deinit(tr->umac_priv);\r
364 }\r
365 \r
366 static int eswin_sdio_tx_thread(void *data)
367 {
368         struct eswin *tr = (struct eswin *)data;
369         struct tx_buff_pkg_node *node;\r
370         int i, ret = 0, cb_per = 0;\r
371
372 #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 9, 0)
373                 struct sched_param param = { .sched_priority = 1 };
374                 param.sched_priority = 56;
375                 sched_setscheduler(get_current(), SCHED_FIFO, &param);
376 #else
377                 sched_set_fifo(get_current());
378 #endif
379                 ECRNX_PRINT("sdio pkg thread entry\n");\r
380
381         while (!kthread_should_stop())
382         {
383                 ret = wait_event_interruptible(tr->wait_tx, tr->tx_pkg_queue.count != 0 || kthread_should_stop());
384                 if (ret < 0)
385                 {
386                         ECRNX_ERR("sdio pkg thread error!\n");\r
387                         return 0;\r
388                 }
389                 if(kthread_should_stop())\r
390                 {\r
391                         continue;\r
392                 }\r
393                 while (tr->tx_pkg_queue.count != 0)
394                 {
395                         node = sdio_tx_pkg_queue_pop(&tr->tx_pkg_queue);\r
396                         if (!node) {\r
397                                 cb_per = 0;\r
398                                 wake_up_interruptible(&tr->wait_cb);\r
399                             break;\r
400                         }\r
401                         \r
402                         if (tr->ops->xmit) {\r
403                                 ret = tr->ops->xmit(tr, node);\r
404                                 WARN_ON(ret < 0);\r
405                                 if((node->flag & FLAG_MSG_TYPE_MASK) == TX_FLAG_TX_DESC || (node->flag & FLAG_MSG_TYPE_MASK) == TX_FLAG_MSG_E)\r
406                                 {\r
407                                         sdio_tx_pkg_queue_push(&tr->tx_c_queue,node);\r
408                                 }\r
409                                 else\r
410                                 {\r
411                                         sdio_tx_pkg_node_free(tr, node);\r
412                                 }\r
413                                 cb_per++;\r
414                                 //if (cb_per % 4 == 0)\r
415                                 {\r
416                                         cb_per = 0;\r
417                                         wake_up_interruptible(&tr->wait_cb);\r
418                                 }\r
419                         } else {\r
420                                 ECRNX_ERR(" eswin_sdio_work, ops->xmit is null\n");\r
421                         }\r
422                 }
423         }
424         ECRNX_PRINT("sdio tx thread exit\n");\r
425         return 0;
426 }
427 \r
428 static int eswin_sdio_callback_thread(void *data)
429 {
430         struct eswin *tr = (struct eswin *)data;
431         struct tx_buff_pkg_node *node;\r
432         int i, ret = 0;\r
433         struct txdesc_api *tx_desc;\r
434         ptr_addr host_id;\r
435
436 #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 9, 0)
437                 struct sched_param param = { .sched_priority = 1 };
438                 param.sched_priority = 56;
439                 sched_setscheduler(get_current(), SCHED_FIFO, &param);
440 #else
441                 sched_set_fifo(get_current());
442 #endif
443                 ECRNX_PRINT("sdio callback thread entry\n");\r
444
445         while (!kthread_should_stop())
446         {
447                 ret = wait_event_interruptible(tr->wait_cb, tr->tx_c_queue.count != 0 || kthread_should_stop());
448                 if (ret < 0)
449                 {
450                         ECRNX_ERR("sdio callback thread error!\n");\r
451                         return 0;\r
452                 }
453                 if(kthread_should_stop())\r
454                 {\r
455                         continue;\r
456                 }\r
457                 while (tr->tx_c_queue.count != 0)
458                 {
459                         node = sdio_tx_pkg_queue_pop(&tr->tx_c_queue);\r
460                         if((node->flag & FLAG_MSG_TYPE_MASK) == TX_FLAG_TX_DESC && (tr->data_cfm_callback))\r
461                         {\r
462                                 for (i = 0; i < node->node_cnt; ++i)\r
463                                 {\r
464                                         tx_desc = (struct txdesc_api *)node->tx_node[i]->buff;\r
465                                         if (tx_desc->host.flags & TXU_CNTRL_MGMT)\r
466                                         {\r
467                                                 continue;\r
468                                         }\r
469                                         memcpy(&host_id, tx_desc->host.packet_addr, sizeof(ptr_addr));\r
470                                         tr->data_cfm_callback(tr->umac_priv, (void*)host_id);\r
471                                 }\r
472                         }\r
473                         //else if((node->flag & FLAG_MSG_TYPE_MASK) == TX_FLAG_MSG_E && (tr->msg_cfm_callback))\r
474                         //{\r
475                         //      for (i = 0; i < node->node_cnt; ++i)\r
476                         //      {\r
477                         //              struct ecrnx_cmd_a2emsg *msg = (struct ecrnx_cmd_a2emsg *)node->tx_node[i]->buff;\r
478                         //              tr->msg_cfm_callback(tr->umac_priv, msg->hostid);\r
479                         //      }\r
480                         //}\r
481                         sdio_tx_pkg_node_free(tr, node);\r
482                 }
483         }
484         ECRNX_PRINT("rx callback thread exit\n");\r
485         return 0;
486 }
487 \r
488 static int eswin_sdio_tx_pkg_thread(void *data)
489 {
490         struct eswin *tr = (struct eswin *)data;
491         struct tx_buff_node *node;\r
492         struct txdesc_api *tx_desc;\r
493         struct tx_buff_pkg_node * pkg_node = NULL;\r
494         struct tx_buff_pkg_head tx_pkg_head;\r
495         unsigned int offset = 0;\r
496         int i, ret, pkg_cnt = 0;\r
497
498 #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 9, 0)
499                 struct sched_param param = { .sched_priority = 1 };
500                 param.sched_priority = 56;
501                 sched_setscheduler(get_current(), SCHED_FIFO, &param);
502 #else
503                 sched_set_fifo(get_current());
504 #endif
505                 ECRNX_PRINT("sdio tx pkg thread entry\n");\r
506
507         while (!kthread_should_stop())
508         {
509                 ret = wait_event_interruptible(tr->wait_pkg, tr->tx_queue.count != 0 || kthread_should_stop());
510                 if (ret < 0)
511                 {
512                         ECRNX_ERR("sdio tx pkg thread error!\n");\r
513                         return 0;\r
514                 }
515                 if(kthread_should_stop())\r
516                 {\r
517                         continue;\r
518                 }\r
519                 while (tr->tx_queue.count != 0)
520                 {
521                         pkg_cnt = 0;\r
522                         offset = 0;\r
523                         memset(&tx_pkg_head,0,sizeof(tx_pkg_head));\r
524                         pkg_node = sdio_tx_pkg_node_alloc(tr);\r
525                         memset(pkg_node,0,sizeof(struct tx_buff_pkg_node));\r
526                         if (!pkg_node) {\r
527                             ECRNX_PRINT(" sdio pkg failed, no node!!\n");\r
528                             break;\r
529                         }\r
530                         node = sdio_tx_queue_peek(&tr->tx_queue);\r
531                         pkg_node->flag = node->flag;\r
532 \r
533                         if((node->flag & FLAG_MSG_TYPE_MASK) != TX_FLAG_TX_DESC)\r
534                         {\r
535                                 node = sdio_tx_queue_pop(&tr->tx_queue);\r
536                                 pkg_node->buff = node->buff;\r
537                                 pkg_node->len = node->len;\r
538                                 pkg_node->tx_node[pkg_cnt] = node;\r
539                                 pkg_cnt++;\r
540                         }\r
541                         else\r
542                         {\r
543                                 pkg_node->buff = (void *)kzalloc(ALIGN(SDIO_PKG_MAX_DATA*SDIO_PKG_MAX_CNT + sizeof(tx_pkg_head), 512), GFP_ATOMIC);\r
544                                 if(!pkg_node->buff){\r
545                                 ECRNX_PRINT("pkg_node buff malloc error! \n");\r
546                                 }\r
547                                 pkg_node->len = sizeof(tx_pkg_head);\r
548 \r
549                                 while (tr->tx_queue.count)\r
550                                 {\r
551                                         offset = pkg_node->len;\r
552                                         node = sdio_tx_queue_peek(&tr->tx_queue);\r
553 \r
554                                         if (((node->flag & FLAG_MSG_TYPE_MASK) != TX_FLAG_TX_DESC) || (pkg_cnt > (SDIO_PKG_MAX_CNT-1)))\r
555                                         {\r
556                                                 break;\r
557                                         }\r
558                                         //ECRNX_DBG("tx count 2 %d,node %x",tr->tx_queue.count,node);\r
559                                         node = sdio_tx_queue_pop(&tr->tx_queue);\r
560                                         if(ALIGN(node->len, SDIO_PKG_PAD_GRN) < (SDIO_PKG_DIV_MSZ+1))\r
561                                         {\r
562                                                 pkg_node->len += ALIGN(node->len, SDIO_PKG_PAD_GRN);\r
563                                                 pkg_node->flag |= (ALIGN(node->len, SDIO_PKG_PAD_GRN)/SDIO_PKG_PAD_GRN) << (8+SDIO_PKG_BIT_SHIFT*pkg_cnt);\r
564                                         }\r
565                                         else\r
566                                         {\r
567                                                 pkg_node->len += SDIO_PKG_MAX_DATA;\r
568                                                 pkg_node->flag |= ((1 << SDIO_PKG_BIT_SHIFT) - 1) << (8+SDIO_PKG_BIT_SHIFT*pkg_cnt);\r
569                                         }\r
570                                         memcpy(pkg_node->buff + offset, node->buff, node->len);\r
571                                         pkg_node->tx_node[pkg_cnt] = node;\r
572                                         tx_pkg_head.len[pkg_cnt] = node->len;\r
573                                         pkg_cnt++;\r
574                                 }\r
575                                 pkg_node->len = ALIGN(pkg_node->len, 512);\r
576                                 memcpy(pkg_node->buff, &tx_pkg_head, sizeof(tx_pkg_head));\r
577                         }\r
578                         pkg_node->node_cnt = pkg_cnt;\r
579                         sdio_tx_pkg_queue_push(&tr->tx_pkg_queue, pkg_node);\r
580                         wake_up_interruptible(&tr->wait_tx);\r
581                 }
582         }
583         ECRNX_PRINT("tx pkg thread exit\n");\r
584         return 0;
585 }\r
586 \r
587 void eswin_sdio_ops_init(struct eswin * tr, const struct sdio_ops * ops)\r
588 {\r
589         int i;\r
590 \r
591         tr->ops = ops;\r
592         \r
593         sdio_tx_queue_init(&tr->tx_queue);\r
594         sdio_tx_pkg_queue_init(&tr->tx_c_queue);\r
595         sdio_tx_pkg_queue_init(&tr->tx_pkg_queue);\r
596 \r
597         for (i=1; i<ESWIN_TX_NODE_CNT; i++) {\r
598                 tr->tx_node[i-1].next = &tr->tx_node[i];\r
599         }\r
600 \r
601         tr->tx_node[i-1].next = NULL;\r
602         tr->tx_node_head = &tr->tx_node[0];\r
603         tr->tx_node_num = ESWIN_TX_NODE_CNT;\r
604         spin_lock_init(&tr->tx_lock);\r
605 \r
606         for (i=1; i<ESWIN_TX_NODE_CNT; i++) {\r
607                 tr->tx_pkg_node[i-1].next = &tr->tx_pkg_node[i];\r
608         }\r
609 \r
610         tr->tx_pkg_node[i-1].next = NULL;\r
611         tr->tx_pkg_node_head = &tr->tx_pkg_node[0];\r
612         tr->tx_pkg_node_num = ESWIN_TX_NODE_CNT;\r
613         spin_lock_init(&tr->tx_pkg_lock);\r
614 }\r
615 \r
616 int tx_desc_count = 0;\r
617 int sdio_host_send(void *buff, int len, int flag)\r
618 {\r
619     struct eswin * tr= pEswin;\r
620     struct tx_buff_node * node = sdio_tx_node_alloc(tr);\r
621 \r
622     ECRNX_DBG("%s enter, data len :%d ", __func__, len);\r
623 \r
624     if (!node) {\r
625         ECRNX_PRINT(" sdio send failed, no node!!\n");\r
626         return -1;\r
627     }\r
628 \r
629     node->buff = (struct lmac_msg *)kzalloc(len, GFP_ATOMIC);\r
630     if(!node->buff){\r
631         ECRNX_PRINT("buff malloc error! \n");\r
632     }\r
633 \r
634     memcpy(node->buff, buff, len);\r
635     node->len  = len;\r
636     node->flag = flag & 0xFF;\r
637 \r
638     if ((len > 512) && (len%512) && ((node->flag & FLAG_MSG_TYPE_MASK) != TX_FLAG_TX_DESC)) {\r
639         node->flag |= (len%512)<<8;\r
640     }\r
641         else\r
642         {\r
643         }\r
644 \r
645     sdio_tx_queue_push(&tr->tx_queue, node);\r
646 \r
647         if((node->flag & FLAG_MSG_TYPE_MASK) != TX_FLAG_TX_DESC)\r
648         {\r
649                 tx_desc_count = 0;\r
650                 //queue_work(tr->workqueue_pkg,&tr->work_pkg);\r
651                 wake_up_interruptible(&tr->wait_pkg);\r
652         }\r
653         else\r
654         {\r
655                 tx_desc_count++;\r
656                 if(tx_desc_count%SDIO_PKG_MAX_CNT == 0)\r
657                 {\r
658                         //queue_work(tr->workqueue_pkg,&tr->work_pkg);\r
659                         wake_up_interruptible(&tr->wait_pkg);\r
660                 }\r
661                 else\r
662                 {\r
663                         mod_timer(&sdio_tx_timer, jiffies + usecs_to_jiffies(SDIO_TX_TIMER_TIMEOUT_US));\r
664                 }\r
665         }\r
666     return 0;\r
667 }\r
668 \r
669 void sdio_tx_timer_handle(struct timer_list *time)
670 {
671         struct eswin * tr = pEswin;\r
672         if (tx_desc_count)\r
673         {\r
674                 tx_desc_count = 0;\r
675                 wake_up_interruptible(&tr->wait_pkg);\r
676         }\r
677 }
678 \r
679 extern void ecrnx_send_handle_register(void * fn);\r
680 \r
681 struct eswin * eswin_core_create(size_t priv_size, struct device *dev,\r
682                                 const struct sdio_ops * ops)\r
683 {\r
684         struct eswin * tr;\r
685 \r
686         tr = (struct eswin *)kzalloc(sizeof(struct eswin) + priv_size, GFP_KERNEL);\r
687         if(!tr) {\r
688                 return NULL;\r
689         }\r
690 \r
691         pEswin = tr;\r
692 \r
693         tr->dev = dev;\r
694         tr->loopback = loopback;\r
695         //tr->loopback = 1;\r
696         eswin_sdio_ops_init(tr, ops);\r
697         ecrnx_send_handle_register(sdio_host_send);\r
698 \r
699         //init_completion(&tr->wim_responded);\r
700         init_waitqueue_head(&tr->wait_pkg);\r
701         init_waitqueue_head(&tr->wait_tx);
702         init_waitqueue_head(&tr->wait_cb);\r
703         \r
704         tr->kthread_pkg = kthread_run(eswin_sdio_tx_pkg_thread, tr, "sdio-tx-pkg");
705         tr->kthread_tx = kthread_run(eswin_sdio_tx_thread, tr, "sdio-tx");\r
706         tr->kthread_cb = kthread_run(eswin_sdio_callback_thread, tr, "sdio-tx-callback");\r
707 \r
708         INIT_DELAYED_WORK(&tr->register_work, eswin_core_register_work);\r
709         timer_setup(&sdio_tx_timer, sdio_tx_timer_handle, 0);\r
710 \r
711         tr->state = ESWIN_STATE_INIT;\r
712 \r
713         //eswin_init_debugfs(tr);\r
714 \r
715         ECRNX_PRINT(" %s exit!!", __func__);\r
716         return tr;\r
717 \r
718 err_free_mac:\r
719         eswin_core_destroy(tr);\r
720         return NULL;\r
721 }\r
722 \r
723 void eswin_core_destroy(struct eswin *tr)\r
724 {\r
725     unsigned long flags;\r
726     int i;\r
727 \r
728     ECRNX_PRINT("%s entry!!", __func__);\r
729     tr->state = ESWIN_STATE_CLOSEED;\r
730 \r
731 \r
732     //flush_workqueue(tr->workqueue);\r
733     //destroy_workqueue(tr->workqueue);\r
734     //tr->workqueue = NULL;\r
735 \r
736     ECRNX_PRINT("%s node_num %d\n", __func__, tr->tx_node_num);\r
737     spin_lock_irqsave(&tr->tx_lock,flags);\r
738     for (i=0; i<64; i++) \r
739     {\r
740         if (tr->tx_node[i].buff)\r
741         {\r
742             kfree(tr->tx_node[i].buff);\r
743         }\r
744     }\r
745     spin_unlock_irqrestore(&tr->tx_lock, flags);\r
746 \r
747     spin_lock_irqsave(&tr->tx_pkg_lock,flags);\r
748     for (i=0; i<64; i++)\r
749     {\r
750         if (tr->tx_pkg_node[i].buff)\r
751         {\r
752             kfree(tr->tx_pkg_node[i].buff);\r
753         }\r
754     }\r
755     spin_unlock_irqrestore(&tr->tx_pkg_lock, flags);\r
756 \r
757         kthread_stop(tr->kthread_pkg);\r
758         wake_up_interruptible(&tr->wait_pkg);\r
759         kthread_stop(tr->kthread_cb);\r
760         wake_up_interruptible(&tr->wait_cb);\r
761         kthread_stop(tr->kthread_tx);\r
762         wake_up_interruptible(&tr->wait_tx);\r
763 \r
764     kfree(tr);\r
765     tr = NULL;\r
766     //TODO:\r
767     //eswin_mac_destroy(tr);\r
768     ECRNX_PRINT("%s exit!!", __func__);\r
769 }\r
770 \r
771 \r
772 //MODULE_AUTHOR("Transa-Semi");\r
773 //MODULE_LICENSE("Dual BSD/GPL");\r
774 //MODULE_DESCRIPTION("Core module for Transa-Semi 802.11 WLAN SDIO driver");\r