blob: ddb03a82b0f9a966d9c1aa24c25a50db839d9b9c [file] [log] [blame]
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001/* ////////////////////////////////////////////////////////////////////////// */
2/* */
3/* Copyright (c) Atmel Corporation. All rights reserved. */
4/* */
5/* Module Name: wilc_wlan.c */
6/* */
7/* */
8/* //////////////////////////////////////////////////////////////////////////// */
9
10#include "wilc_wlan_if.h"
11#include "wilc_wlan.h"
Johnny Kimc5c77ba2015-05-11 14:30:56 +090012
13/********************************************
14 *
15 * Global
16 *
17 ********************************************/
Johnny Kimc5c77ba2015-05-11 14:30:56 +090018extern wilc_hif_func_t hif_sdio;
19extern wilc_hif_func_t hif_spi;
20extern wilc_cfg_func_t mac_cfg;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +090021extern void WILC_WFI_mgmt_rx(u8 *buff, u32 size);
22u32 wilc_get_chipid(u8 update);
Dean Lee72ed4dc2015-06-12 14:11:44 +090023u16 Set_machw_change_vir_if(bool bValue);
Johnny Kimc5c77ba2015-05-11 14:30:56 +090024
Johnny Kimc5c77ba2015-05-11 14:30:56 +090025
26
27typedef struct {
28 int quit;
29
30 /**
31 * input interface functions
32 **/
33 wilc_wlan_os_func_t os_func;
34 wilc_wlan_io_func_t io_func;
35 wilc_wlan_net_func_t net_func;
36 wilc_wlan_indicate_func_t indicate_func;
37
38 /**
39 * host interface functions
40 **/
41 wilc_hif_func_t hif_func;
Greg Kroah-Hartman5e150b52015-09-03 19:32:11 -070042 struct mutex *hif_lock;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090043
44 /**
45 * configuration interface functions
46 **/
47 wilc_cfg_func_t cif_func;
48 int cfg_frame_in_use;
49 wilc_cfg_frame_t cfg_frame;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +090050 u32 cfg_frame_offset;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090051 int cfg_seq_no;
52 void *cfg_wait;
53
54 /**
55 * RX buffer
56 **/
57 #ifdef MEMORY_STATIC
Chaehyun Limfbc2fe12015-09-15 14:06:16 +090058 u32 rx_buffer_size;
Chaehyun Lim51e825f2015-09-15 14:06:14 +090059 u8 *rx_buffer;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +090060 u32 rx_buffer_offset;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090061 #endif
62 /**
63 * TX buffer
64 **/
Chaehyun Limfbc2fe12015-09-15 14:06:16 +090065 u32 tx_buffer_size;
Chaehyun Lim51e825f2015-09-15 14:06:14 +090066 u8 *tx_buffer;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +090067 u32 tx_buffer_offset;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090068
69 /**
70 * TX queue
71 **/
72 void *txq_lock;
73
Greg Kroah-Hartman8990d852015-09-03 20:07:58 -070074 struct semaphore *txq_add_to_head_lock;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090075 void *txq_spinlock;
76 unsigned long txq_spinlock_flags;
77
78 struct txq_entry_t *txq_head;
79 struct txq_entry_t *txq_tail;
80 int txq_entries;
81 void *txq_wait;
82 int txq_exit;
83
84 /**
85 * RX queue
86 **/
Greg Kroah-Hartman5e150b52015-09-03 19:32:11 -070087 struct mutex *rxq_lock;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090088 struct rxq_entry_t *rxq_head;
89 struct rxq_entry_t *rxq_tail;
90 int rxq_entries;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090091 int rxq_exit;
92
93
94} wilc_wlan_dev_t;
95
96static wilc_wlan_dev_t g_wlan;
97
Chaehyun Lim9af382b2015-09-16 20:11:27 +090098static inline void chip_allow_sleep(void);
99static inline void chip_wakeup(void);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900100/********************************************
101 *
102 * Debug
103 *
104 ********************************************/
105
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900106static u32 dbgflag = N_INIT | N_ERR | N_INTR | N_TXQ | N_RXQ;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900107
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900108static void wilc_debug(u32 flag, char *fmt, ...)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900109{
110 char buf[256];
111 va_list args;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900112
113 if (flag & dbgflag) {
114 va_start(args, fmt);
Hari Prasath Gujulan Elango81053222015-06-22 13:13:58 +0000115 vsprintf(buf, fmt, args);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900116 va_end(args);
117
118 if (g_wlan.os_func.os_debug)
119 g_wlan.os_func.os_debug(buf);
120 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900121}
122
123static CHIP_PS_STATE_T genuChipPSstate = CHIP_WAKEDUP;
124
Chaehyun Lim9af382b2015-09-16 20:11:27 +0900125/*acquire_bus() and release_bus() are made static inline functions*/
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900126/*as a temporary workaround to fix a problem of receiving*/
127/*unknown interrupt from FW*/
Chaehyun Lim9af382b2015-09-16 20:11:27 +0900128static inline void acquire_bus(BUS_ACQUIRE_T acquire)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900129{
130
Greg Kroah-Hartman5e150b52015-09-03 19:32:11 -0700131 mutex_lock(g_wlan.hif_lock);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900132 #ifndef WILC_OPTIMIZE_SLEEP_INT
133 if (genuChipPSstate != CHIP_WAKEDUP)
134 #endif
135 {
136 if (acquire == ACQUIRE_AND_WAKEUP)
137 chip_wakeup();
138 }
139
140}
Chaehyun Lim9af382b2015-09-16 20:11:27 +0900141static inline void release_bus(BUS_RELEASE_T release)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900142{
143 #ifdef WILC_OPTIMIZE_SLEEP_INT
144 if (release == RELEASE_ALLOW_SLEEP)
145 chip_allow_sleep();
146 #endif
Greg Kroah-Hartman5e150b52015-09-03 19:32:11 -0700147 mutex_unlock(g_wlan.hif_lock);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900148}
149/********************************************
150 *
151 * Queue
152 *
153 ********************************************/
154
155static void wilc_wlan_txq_remove(struct txq_entry_t *tqe)
156{
157
158 wilc_wlan_dev_t *p = (wilc_wlan_dev_t *)&g_wlan;
159 /* unsigned long flags; */
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900160 if (tqe == p->txq_head) {
161
162 p->txq_head = tqe->next;
163 if (p->txq_head)
164 p->txq_head->prev = NULL;
165
166
167 } else if (tqe == p->txq_tail) {
168 p->txq_tail = (tqe->prev);
169 if (p->txq_tail)
170 p->txq_tail->next = NULL;
171 } else {
172 tqe->prev->next = tqe->next;
173 tqe->next->prev = tqe->prev;
174 }
175 p->txq_entries -= 1;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900176
177}
178
179static struct txq_entry_t *wilc_wlan_txq_remove_from_head(void)
180{
181 struct txq_entry_t *tqe;
182 wilc_wlan_dev_t *p = (wilc_wlan_dev_t *)&g_wlan;
183 unsigned long flags;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900184
Greg Kroah-Hartman17c4d5d2015-09-03 20:17:31 -0700185 spin_lock_irqsave(p->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900186 if (p->txq_head) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900187 tqe = p->txq_head;
188 p->txq_head = tqe->next;
189 if (p->txq_head) {
190 p->txq_head->prev = NULL;
191 }
192 p->txq_entries -= 1;
193
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900194
195
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900196
197 } else {
198 tqe = NULL;
199 }
Greg Kroah-Hartman17c4d5d2015-09-03 20:17:31 -0700200 spin_unlock_irqrestore(p->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900201 return tqe;
202}
203
204static void wilc_wlan_txq_add_to_tail(struct txq_entry_t *tqe)
205{
206 wilc_wlan_dev_t *p = (wilc_wlan_dev_t *)&g_wlan;
207 unsigned long flags;
Greg Kroah-Hartman17c4d5d2015-09-03 20:17:31 -0700208 spin_lock_irqsave(p->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900209
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900210 if (p->txq_head == NULL) {
211 tqe->next = NULL;
212 tqe->prev = NULL;
213 p->txq_head = tqe;
214 p->txq_tail = tqe;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900215 } else {
216 tqe->next = NULL;
217 tqe->prev = p->txq_tail;
218 p->txq_tail->next = tqe;
219 p->txq_tail = tqe;
220 }
221 p->txq_entries += 1;
222 PRINT_D(TX_DBG, "Number of entries in TxQ = %d\n", p->txq_entries);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900223
Greg Kroah-Hartman17c4d5d2015-09-03 20:17:31 -0700224 spin_unlock_irqrestore(p->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900225
226 /**
227 * wake up TX queue
228 **/
229 PRINT_D(TX_DBG, "Wake the txq_handling\n");
230
Greg Kroah-Hartman8990d852015-09-03 20:07:58 -0700231 up(p->txq_wait);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900232}
233
234static int wilc_wlan_txq_add_to_head(struct txq_entry_t *tqe)
235{
236 wilc_wlan_dev_t *p = (wilc_wlan_dev_t *)&g_wlan;
237 unsigned long flags;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900238 if (p->os_func.os_wait(p->txq_add_to_head_lock, CFG_PKTS_TIMEOUT))
239 return -1;
240
Greg Kroah-Hartman17c4d5d2015-09-03 20:17:31 -0700241 spin_lock_irqsave(p->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900242
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900243 if (p->txq_head == NULL) {
244 tqe->next = NULL;
245 tqe->prev = NULL;
246 p->txq_head = tqe;
247 p->txq_tail = tqe;
248 } else {
249 tqe->next = p->txq_head;
250 tqe->prev = NULL;
251 p->txq_head->prev = tqe;
252 p->txq_head = tqe;
253 }
254 p->txq_entries += 1;
255 PRINT_D(TX_DBG, "Number of entries in TxQ = %d\n", p->txq_entries);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900256
Greg Kroah-Hartman17c4d5d2015-09-03 20:17:31 -0700257 spin_unlock_irqrestore(p->txq_spinlock, flags);
Greg Kroah-Hartman8990d852015-09-03 20:07:58 -0700258 up(p->txq_add_to_head_lock);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900259
260
261 /**
262 * wake up TX queue
263 **/
Greg Kroah-Hartman8990d852015-09-03 20:07:58 -0700264 up(p->txq_wait);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900265 PRINT_D(TX_DBG, "Wake up the txq_handler\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900266
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900267 return 0;
268
269}
270
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900271u32 Statisitcs_totalAcks = 0, Statisitcs_DroppedAcks = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900272
273#ifdef TCP_ACK_FILTER
274struct Ack_session_info;
Shraddha Barkeeeb1c062015-08-05 01:29:22 +0530275struct Ack_session_info {
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900276 u32 Ack_seq_num;
277 u32 Bigger_Ack_num;
Chaehyun Limec53adf2015-09-15 14:06:15 +0900278 u16 src_port;
279 u16 dst_port;
280 u16 status;
Shraddha Barkeeeb1c062015-08-05 01:29:22 +0530281};
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900282
283typedef struct {
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900284 u32 ack_num;
285 u32 Session_index;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900286 struct txq_entry_t *txqe;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900287} Pending_Acks_info_t /*Ack_info_t*/;
288
289
290
291
292struct Ack_session_info *Free_head;
293struct Ack_session_info *Alloc_head;
294
295#define TCP_FIN_MASK (1 << 0)
296#define TCP_SYN_MASK (1 << 1)
297#define TCP_Ack_MASK (1 << 4)
298#define NOT_TCP_ACK (-1)
299
300#define MAX_TCP_SESSION 25
301#define MAX_PENDING_ACKS 256
Shraddha Barkeeeb1c062015-08-05 01:29:22 +0530302struct Ack_session_info Acks_keep_track_info[2 * MAX_TCP_SESSION];
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900303Pending_Acks_info_t Pending_Acks_info[MAX_PENDING_ACKS];
304
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900305u32 PendingAcks_arrBase;
306u32 Opened_TCP_session;
307u32 Pending_Acks;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900308
309
310
Chaehyun Limfed16f22015-09-17 16:48:43 +0900311static inline int Init_TCP_tracking(void)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900312{
313
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900314 return 0;
315
316}
Chaehyun Limfed16f22015-09-17 16:48:43 +0900317static inline int add_TCP_track_session(u32 src_prt, u32 dst_prt, u32 seq)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900318{
319 Acks_keep_track_info[Opened_TCP_session].Ack_seq_num = seq;
320 Acks_keep_track_info[Opened_TCP_session].Bigger_Ack_num = 0;
321 Acks_keep_track_info[Opened_TCP_session].src_port = src_prt;
322 Acks_keep_track_info[Opened_TCP_session].dst_port = dst_prt;
323 Opened_TCP_session++;
324
325 PRINT_D(TCP_ENH, "TCP Session %d to Ack %d\n", Opened_TCP_session, seq);
326 return 0;
327}
328
Chaehyun Limfed16f22015-09-17 16:48:43 +0900329static inline int Update_TCP_track_session(u32 index, u32 Ack)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900330{
331
332 if (Ack > Acks_keep_track_info[index].Bigger_Ack_num) {
333 Acks_keep_track_info[index].Bigger_Ack_num = Ack;
334 }
335 return 0;
336
337}
Chaehyun Limfed16f22015-09-17 16:48:43 +0900338static inline int add_TCP_Pending_Ack(u32 Ack, u32 Session_index, struct txq_entry_t *txqe)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900339{
340 Statisitcs_totalAcks++;
341 if (Pending_Acks < MAX_PENDING_ACKS) {
342 Pending_Acks_info[PendingAcks_arrBase + Pending_Acks].ack_num = Ack;
343 Pending_Acks_info[PendingAcks_arrBase + Pending_Acks].txqe = txqe;
344 Pending_Acks_info[PendingAcks_arrBase + Pending_Acks].Session_index = Session_index;
345 txqe->tcp_PendingAck_index = PendingAcks_arrBase + Pending_Acks;
346 Pending_Acks++;
347
348 } else {
349
350 }
351 return 0;
352}
Chaehyun Limfed16f22015-09-17 16:48:43 +0900353static inline int remove_TCP_related(void)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900354{
355 wilc_wlan_dev_t *p = (wilc_wlan_dev_t *)&g_wlan;
356 unsigned long flags;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900357
Greg Kroah-Hartman17c4d5d2015-09-03 20:17:31 -0700358 spin_lock_irqsave(p->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900359
Greg Kroah-Hartman17c4d5d2015-09-03 20:17:31 -0700360 spin_unlock_irqrestore(p->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900361 return 0;
362}
363
Chaehyun Limfed16f22015-09-17 16:48:43 +0900364static inline int tcp_process(struct txq_entry_t *tqe)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900365{
366 int ret;
Chaehyun Lim51e825f2015-09-15 14:06:14 +0900367 u8 *eth_hdr_ptr;
368 u8 *buffer = tqe->buffer;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900369 unsigned short h_proto;
370 int i;
371 wilc_wlan_dev_t *p = (wilc_wlan_dev_t *)&g_wlan;
372 unsigned long flags;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900373
Greg Kroah-Hartman17c4d5d2015-09-03 20:17:31 -0700374 spin_lock_irqsave(p->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900375
376 eth_hdr_ptr = &buffer[0];
377 h_proto = ntohs(*((unsigned short *)&eth_hdr_ptr[12]));
378 if (h_proto == 0x0800) { /* IP */
Chaehyun Lim51e825f2015-09-15 14:06:14 +0900379 u8 *ip_hdr_ptr;
380 u8 protocol;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900381
382 ip_hdr_ptr = &buffer[ETHERNET_HDR_LEN];
383 protocol = ip_hdr_ptr[9];
384
385
386 if (protocol == 0x06) {
Chaehyun Lim51e825f2015-09-15 14:06:14 +0900387 u8 *tcp_hdr_ptr;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900388 u32 IHL, Total_Length, Data_offset;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900389
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900390 tcp_hdr_ptr = &ip_hdr_ptr[IP_HDR_LEN];
391 IHL = (ip_hdr_ptr[0] & 0xf) << 2;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900392 Total_Length = (((u32)ip_hdr_ptr[2]) << 8) + ((u32)ip_hdr_ptr[3]);
393 Data_offset = (((u32)tcp_hdr_ptr[12] & 0xf0) >> 2);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900394 if (Total_Length == (IHL + Data_offset)) { /*we want to recognize the clear Acks(packet only carry Ack infos not with data) so data size must be equal zero*/
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900395 u32 seq_no, Ack_no;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900396
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900397 seq_no = (((u32)tcp_hdr_ptr[4]) << 24) + (((u32)tcp_hdr_ptr[5]) << 16) + (((u32)tcp_hdr_ptr[6]) << 8) + ((u32)tcp_hdr_ptr[7]);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900398
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900399 Ack_no = (((u32)tcp_hdr_ptr[8]) << 24) + (((u32)tcp_hdr_ptr[9]) << 16) + (((u32)tcp_hdr_ptr[10]) << 8) + ((u32)tcp_hdr_ptr[11]);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900400
401
402 for (i = 0; i < Opened_TCP_session; i++) {
403 if (Acks_keep_track_info[i].Ack_seq_num == seq_no) {
404 Update_TCP_track_session(i, Ack_no);
405 break;
406 }
407 }
408 if (i == Opened_TCP_session) {
409 add_TCP_track_session(0, 0, seq_no);
410 }
411 add_TCP_Pending_Ack(Ack_no, i, tqe);
412
413
414 }
415
416 } else {
417 ret = 0;
418 }
419 } else {
420 ret = 0;
421 }
Greg Kroah-Hartman17c4d5d2015-09-03 20:17:31 -0700422 spin_unlock_irqrestore(p->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900423 return ret;
424}
425
426
427static int wilc_wlan_txq_filter_dup_tcp_ack(void)
428{
429
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900430 u32 i = 0;
431 u32 Dropped = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900432 wilc_wlan_dev_t *p = (wilc_wlan_dev_t *)&g_wlan;
433
Greg Kroah-Hartman17c4d5d2015-09-03 20:17:31 -0700434 spin_lock_irqsave(p->txq_spinlock, p->txq_spinlock_flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900435 for (i = PendingAcks_arrBase; i < (PendingAcks_arrBase + Pending_Acks); i++) {
436 if (Pending_Acks_info[i].ack_num < Acks_keep_track_info[Pending_Acks_info[i].Session_index].Bigger_Ack_num) {
437 struct txq_entry_t *tqe;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900438
Chandra S Gorentla17aacd42015-08-08 17:41:35 +0530439 PRINT_D(TCP_ENH, "DROP ACK: %u\n", Pending_Acks_info[i].ack_num);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900440 tqe = Pending_Acks_info[i].txqe;
441 if (tqe) {
442 wilc_wlan_txq_remove(tqe);
443 Statisitcs_DroppedAcks++;
444 tqe->status = 1; /* mark the packet send */
445 if (tqe->tx_complete_func)
446 tqe->tx_complete_func(tqe->priv, tqe->status);
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -0700447 kfree(tqe);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900448 Dropped++;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900449 }
450 }
451 }
452 Pending_Acks = 0;
453 Opened_TCP_session = 0;
454
Chandra S Gorentla78174ad2015-08-08 17:41:36 +0530455 if (PendingAcks_arrBase == 0)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900456 PendingAcks_arrBase = MAX_TCP_SESSION;
Chandra S Gorentla78174ad2015-08-08 17:41:36 +0530457 else
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900458 PendingAcks_arrBase = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900459
460
Greg Kroah-Hartman17c4d5d2015-09-03 20:17:31 -0700461 spin_unlock_irqrestore(p->txq_spinlock, p->txq_spinlock_flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900462
463 while (Dropped > 0) {
464 /*consume the semaphore count of the removed packet*/
465 p->os_func.os_wait(p->txq_wait, 1);
466 Dropped--;
467 }
468
469 return 1;
470}
471#endif
472
Dean Lee72ed4dc2015-06-12 14:11:44 +0900473bool EnableTCPAckFilter = false;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900474
Dean Lee72ed4dc2015-06-12 14:11:44 +0900475void Enable_TCP_ACK_Filter(bool value)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900476{
477 EnableTCPAckFilter = value;
478}
479
Dean Lee72ed4dc2015-06-12 14:11:44 +0900480bool is_TCP_ACK_Filter_Enabled(void)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900481{
482 return EnableTCPAckFilter;
483}
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900484
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900485static int wilc_wlan_txq_add_cfg_pkt(u8 *buffer, u32 buffer_size)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900486{
487 wilc_wlan_dev_t *p = (wilc_wlan_dev_t *)&g_wlan;
488 struct txq_entry_t *tqe;
489
490 PRINT_D(TX_DBG, "Adding config packet ...\n");
491 if (p->quit) {
492 PRINT_D(TX_DBG, "Return due to clear function\n");
Greg Kroah-Hartman8990d852015-09-03 20:07:58 -0700493 up(p->cfg_wait);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900494 return 0;
495 }
496
Greg Kroah-Hartman47c632d2015-09-03 18:55:43 -0700497 tqe = kmalloc(sizeof(struct txq_entry_t), GFP_ATOMIC);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900498 if (tqe == NULL) {
499 PRINT_ER("Failed to allocate memory\n");
500 return 0;
501 }
502
503 tqe->type = WILC_CFG_PKT;
504 tqe->buffer = buffer;
505 tqe->buffer_size = buffer_size;
506 tqe->tx_complete_func = NULL;
507 tqe->priv = NULL;
508#ifdef TCP_ACK_FILTER
509 tqe->tcp_PendingAck_index = NOT_TCP_ACK;
510#endif
511 /**
512 * Configuration packet always at the front
513 **/
514 PRINT_D(TX_DBG, "Adding the config packet at the Queue tail\n");
515
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900516 if (wilc_wlan_txq_add_to_head(tqe))
517 return 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900518 return 1;
519}
520
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900521static int wilc_wlan_txq_add_net_pkt(void *priv, u8 *buffer, u32 buffer_size, wilc_tx_complete_func_t func)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900522{
523 wilc_wlan_dev_t *p = (wilc_wlan_dev_t *)&g_wlan;
524 struct txq_entry_t *tqe;
525
526 if (p->quit)
527 return 0;
528
Greg Kroah-Hartman47c632d2015-09-03 18:55:43 -0700529 tqe = kmalloc(sizeof(struct txq_entry_t), GFP_ATOMIC);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900530
531 if (tqe == NULL)
532 return 0;
533 tqe->type = WILC_NET_PKT;
534 tqe->buffer = buffer;
535 tqe->buffer_size = buffer_size;
536 tqe->tx_complete_func = func;
537 tqe->priv = priv;
538
539 PRINT_D(TX_DBG, "Adding mgmt packet at the Queue tail\n");
540#ifdef TCP_ACK_FILTER
541 tqe->tcp_PendingAck_index = NOT_TCP_ACK;
Abdul Hussain5a66bf22015-06-16 09:44:06 +0000542 if (is_TCP_ACK_Filter_Enabled())
Glen Lee25a84832015-09-16 18:53:22 +0900543 tcp_process(tqe);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900544#endif
545 wilc_wlan_txq_add_to_tail(tqe);
546 /*return number of itemes in the queue*/
547 return p->txq_entries;
548}
Glen Leefcc6ef92015-09-16 18:53:21 +0900549
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900550int wilc_wlan_txq_add_mgmt_pkt(void *priv, u8 *buffer, u32 buffer_size, wilc_tx_complete_func_t func)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900551{
552
553 wilc_wlan_dev_t *p = (wilc_wlan_dev_t *)&g_wlan;
554 struct txq_entry_t *tqe;
555
556 if (p->quit)
557 return 0;
558
Greg Kroah-Hartman47c632d2015-09-03 18:55:43 -0700559 tqe = kmalloc(sizeof(struct txq_entry_t), GFP_KERNEL);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900560
561 if (tqe == NULL)
562 return 0;
563 tqe->type = WILC_MGMT_PKT;
564 tqe->buffer = buffer;
565 tqe->buffer_size = buffer_size;
566 tqe->tx_complete_func = func;
567 tqe->priv = priv;
568#ifdef TCP_ACK_FILTER
569 tqe->tcp_PendingAck_index = NOT_TCP_ACK;
570#endif
571 PRINT_D(TX_DBG, "Adding Network packet at the Queue tail\n");
572 wilc_wlan_txq_add_to_tail(tqe);
573 return 1;
574}
Glen Leefcc6ef92015-09-16 18:53:21 +0900575
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900576static struct txq_entry_t *wilc_wlan_txq_get_first(void)
577{
578 wilc_wlan_dev_t *p = (wilc_wlan_dev_t *)&g_wlan;
579 struct txq_entry_t *tqe;
580 unsigned long flags;
581
Greg Kroah-Hartman17c4d5d2015-09-03 20:17:31 -0700582 spin_lock_irqsave(p->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900583
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900584 tqe = p->txq_head;
585
Greg Kroah-Hartman17c4d5d2015-09-03 20:17:31 -0700586 spin_unlock_irqrestore(p->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900587
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900588
589 return tqe;
590}
591
592static struct txq_entry_t *wilc_wlan_txq_get_next(struct txq_entry_t *tqe)
593{
594 wilc_wlan_dev_t *p = (wilc_wlan_dev_t *)&g_wlan;
595 unsigned long flags;
Greg Kroah-Hartman17c4d5d2015-09-03 20:17:31 -0700596 spin_lock_irqsave(p->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900597
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900598 tqe = tqe->next;
Greg Kroah-Hartman17c4d5d2015-09-03 20:17:31 -0700599 spin_unlock_irqrestore(p->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900600
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900601
602 return tqe;
603}
604
605static int wilc_wlan_rxq_add(struct rxq_entry_t *rqe)
606{
607 wilc_wlan_dev_t *p = (wilc_wlan_dev_t *)&g_wlan;
608
609 if (p->quit)
610 return 0;
611
Greg Kroah-Hartman5e150b52015-09-03 19:32:11 -0700612 mutex_lock(p->rxq_lock);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900613 if (p->rxq_head == NULL) {
614 PRINT_D(RX_DBG, "Add to Queue head\n");
615 rqe->next = NULL;
616 p->rxq_head = rqe;
617 p->rxq_tail = rqe;
618 } else {
619 PRINT_D(RX_DBG, "Add to Queue tail\n");
620 p->rxq_tail->next = rqe;
621 rqe->next = NULL;
622 p->rxq_tail = rqe;
623 }
624 p->rxq_entries += 1;
625 PRINT_D(RX_DBG, "Number of queue entries: %d\n", p->rxq_entries);
Greg Kroah-Hartman5e150b52015-09-03 19:32:11 -0700626 mutex_unlock(p->rxq_lock);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900627 return p->rxq_entries;
628}
629
630static struct rxq_entry_t *wilc_wlan_rxq_remove(void)
631{
632 wilc_wlan_dev_t *p = (wilc_wlan_dev_t *)&g_wlan;
633
634 PRINT_D(RX_DBG, "Getting rxQ element\n");
635 if (p->rxq_head) {
636 struct rxq_entry_t *rqe;
637
Greg Kroah-Hartman5e150b52015-09-03 19:32:11 -0700638 mutex_lock(p->rxq_lock);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900639 rqe = p->rxq_head;
640 p->rxq_head = p->rxq_head->next;
641 p->rxq_entries -= 1;
642 PRINT_D(RX_DBG, "RXQ entries decreased\n");
Greg Kroah-Hartman5e150b52015-09-03 19:32:11 -0700643 mutex_unlock(p->rxq_lock);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900644 return rqe;
645 }
646 PRINT_D(RX_DBG, "Nothing to get from Q\n");
647 return NULL;
648}
649
650
651/********************************************
652 *
653 * Power Save handle functions
654 *
655 ********************************************/
656
657
658
659#ifdef WILC_OPTIMIZE_SLEEP_INT
660
Chaehyun Lim9af382b2015-09-16 20:11:27 +0900661static inline void chip_allow_sleep(void)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900662{
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900663 u32 reg = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900664
665 /* Clear bit 1 */
666 g_wlan.hif_func.hif_read_reg(0xf0, &reg);
667
668 g_wlan.hif_func.hif_write_reg(0xf0, reg & ~(1 << 0));
669}
670
Chaehyun Lim9af382b2015-09-16 20:11:27 +0900671static inline void chip_wakeup(void)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900672{
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900673 u32 reg, clk_status_reg, trials = 0;
674 u32 sleep_time;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900675
676 if ((g_wlan.io_func.io_type & 0x1) == HIF_SPI) {
677 do {
678 g_wlan.hif_func.hif_read_reg(1, &reg);
679 /* Set bit 1 */
680 g_wlan.hif_func.hif_write_reg(1, reg | (1 << 1));
681
682 /* Clear bit 1*/
683 g_wlan.hif_func.hif_write_reg(1, reg & ~(1 << 1));
684
685 do {
686 /* Wait for the chip to stabilize*/
Greg Kroah-Hartman80e29c72015-08-14 19:42:23 -0700687 usleep_range(2 * 1000, 2 * 1000);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900688 /* Make sure chip is awake. This is an extra step that can be removed */
689 /* later to avoid the bus access overhead */
Dean Lee72ed4dc2015-06-12 14:11:44 +0900690 if ((wilc_get_chipid(true) == 0)) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900691 wilc_debug(N_ERR, "Couldn't read chip id. Wake up failed\n");
692 }
Dean Lee72ed4dc2015-06-12 14:11:44 +0900693 } while ((wilc_get_chipid(true) == 0) && ((++trials % 3) == 0));
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900694
Dean Lee72ed4dc2015-06-12 14:11:44 +0900695 } while (wilc_get_chipid(true) == 0);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900696 } else if ((g_wlan.io_func.io_type & 0x1) == HIF_SDIO) {
697 g_wlan.hif_func.hif_read_reg(0xf0, &reg);
698 do {
699 /* Set bit 1 */
700 g_wlan.hif_func.hif_write_reg(0xf0, reg | (1 << 0));
701
702 /* Check the clock status */
703 g_wlan.hif_func.hif_read_reg(0xf1, &clk_status_reg);
704
705 /* in case of clocks off, wait 2ms, and check it again. */
706 /* if still off, wait for another 2ms, for a total wait of 6ms. */
707 /* If still off, redo the wake up sequence */
708 while (((clk_status_reg & 0x1) == 0) && (((++trials) % 3) == 0)) {
709 /* Wait for the chip to stabilize*/
Greg Kroah-Hartman80e29c72015-08-14 19:42:23 -0700710 usleep_range(2 * 1000, 2 * 1000);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900711
712 /* Make sure chip is awake. This is an extra step that can be removed */
713 /* later to avoid the bus access overhead */
714 g_wlan.hif_func.hif_read_reg(0xf1, &clk_status_reg);
715
716 if ((clk_status_reg & 0x1) == 0) {
717 wilc_debug(N_ERR, "clocks still OFF. Wake up failed\n");
718 }
719 }
720 /* in case of failure, Reset the wakeup bit to introduce a new edge on the next loop */
721 if ((clk_status_reg & 0x1) == 0) {
722 /* Reset bit 0 */
723 g_wlan.hif_func.hif_write_reg(0xf0, reg & (~(1 << 0)));
724 }
725 } while ((clk_status_reg & 0x1) == 0);
726 }
727
728
729 if (genuChipPSstate == CHIP_SLEEPING_MANUAL) {
730 g_wlan.hif_func.hif_read_reg(0x1C0C, &reg);
731 reg &= ~(1 << 0);
732 g_wlan.hif_func.hif_write_reg(0x1C0C, reg);
733
Dean Lee72ed4dc2015-06-12 14:11:44 +0900734 if (wilc_get_chipid(false) >= 0x1002b0) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900735 /* Enable PALDO back right after wakeup */
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900736 u32 val32;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900737
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900738 g_wlan.hif_func.hif_read_reg(0x1e1c, &val32);
739 val32 |= (1 << 6);
740 g_wlan.hif_func.hif_write_reg(0x1e1c, val32);
741
742 g_wlan.hif_func.hif_read_reg(0x1e9c, &val32);
743 val32 |= (1 << 6);
744 g_wlan.hif_func.hif_write_reg(0x1e9c, val32);
745 }
746 }
747 genuChipPSstate = CHIP_WAKEDUP;
748}
749#else
Chaehyun Lim9af382b2015-09-16 20:11:27 +0900750static inline void chip_wakeup(void)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900751{
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900752 u32 reg, trials = 0;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900753
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900754 do {
755 if ((g_wlan.io_func.io_type & 0x1) == HIF_SPI) {
756 g_wlan.hif_func.hif_read_reg(1, &reg);
757 /* Make sure bit 1 is 0 before we start. */
758 g_wlan.hif_func.hif_write_reg(1, reg & ~(1 << 1));
759 /* Set bit 1 */
760 g_wlan.hif_func.hif_write_reg(1, reg | (1 << 1));
761 /* Clear bit 1*/
762 g_wlan.hif_func.hif_write_reg(1, reg & ~(1 << 1));
763 } else if ((g_wlan.io_func.io_type & 0x1) == HIF_SDIO) {
764 /* Make sure bit 0 is 0 before we start. */
765 g_wlan.hif_func.hif_read_reg(0xf0, &reg);
766 g_wlan.hif_func.hif_write_reg(0xf0, reg & ~(1 << 0));
767 /* Set bit 1 */
768 g_wlan.hif_func.hif_write_reg(0xf0, reg | (1 << 0));
769 /* Clear bit 1 */
770 g_wlan.hif_func.hif_write_reg(0xf0, reg & ~(1 << 0));
771 }
772
773 do {
774 /* Wait for the chip to stabilize*/
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900775 mdelay(3);
776
777 /* Make sure chip is awake. This is an extra step that can be removed */
778 /* later to avoid the bus access overhead */
Dean Lee72ed4dc2015-06-12 14:11:44 +0900779 if ((wilc_get_chipid(true) == 0)) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900780 wilc_debug(N_ERR, "Couldn't read chip id. Wake up failed\n");
781 }
Dean Lee72ed4dc2015-06-12 14:11:44 +0900782 } while ((wilc_get_chipid(true) == 0) && ((++trials % 3) == 0));
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900783
Dean Lee72ed4dc2015-06-12 14:11:44 +0900784 } while (wilc_get_chipid(true) == 0);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900785
786 if (genuChipPSstate == CHIP_SLEEPING_MANUAL) {
787 g_wlan.hif_func.hif_read_reg(0x1C0C, &reg);
788 reg &= ~(1 << 0);
789 g_wlan.hif_func.hif_write_reg(0x1C0C, reg);
790
Dean Lee72ed4dc2015-06-12 14:11:44 +0900791 if (wilc_get_chipid(false) >= 0x1002b0) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900792 /* Enable PALDO back right after wakeup */
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900793 u32 val32;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900794
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900795 g_wlan.hif_func.hif_read_reg(0x1e1c, &val32);
796 val32 |= (1 << 6);
797 g_wlan.hif_func.hif_write_reg(0x1e1c, val32);
798
799 g_wlan.hif_func.hif_read_reg(0x1e9c, &val32);
800 val32 |= (1 << 6);
801 g_wlan.hif_func.hif_write_reg(0x1e9c, val32);
802 }
803 }
804 genuChipPSstate = CHIP_WAKEDUP;
805}
806#endif
Chaehyun Lim4e4467f2015-06-11 14:35:55 +0900807void chip_sleep_manually(u32 u32SleepTime)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900808{
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900809 if (genuChipPSstate != CHIP_WAKEDUP) {
810 /* chip is already sleeping. Do nothing */
811 return;
812 }
813 acquire_bus(ACQUIRE_ONLY);
814
815#ifdef WILC_OPTIMIZE_SLEEP_INT
816 chip_allow_sleep();
817#endif
818
819 /* Trigger the manual sleep interrupt */
820 g_wlan.hif_func.hif_write_reg(0x10a8, 1);
821
822 genuChipPSstate = CHIP_SLEEPING_MANUAL;
823 release_bus(RELEASE_ONLY);
824
825}
826
827
828/********************************************
829 *
830 * Tx, Rx queue handle functions
831 *
832 ********************************************/
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900833static int wilc_wlan_handle_txq(u32 *pu32TxqCount)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900834{
835 wilc_wlan_dev_t *p = (wilc_wlan_dev_t *)&g_wlan;
836 int i, entries = 0;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900837 u32 sum;
838 u32 reg;
Chaehyun Lim51e825f2015-09-15 14:06:14 +0900839 u8 *txb = p->tx_buffer;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900840 u32 offset = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900841 int vmm_sz = 0;
842 struct txq_entry_t *tqe;
843 int ret = 0;
844 int counter;
845 int timeout;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900846 u32 vmm_table[WILC_VMM_TBL_SIZE];
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900847
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900848 p->txq_exit = 0;
849 do {
850 if (p->quit)
851 break;
852
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900853 p->os_func.os_wait(p->txq_add_to_head_lock, CFG_PKTS_TIMEOUT);
854#ifdef TCP_ACK_FILTER
855 wilc_wlan_txq_filter_dup_tcp_ack();
856#endif
857 /**
858 * build the vmm list
859 **/
860 PRINT_D(TX_DBG, "Getting the head of the TxQ\n");
861 tqe = wilc_wlan_txq_get_first();
862 i = 0;
863 sum = 0;
864 do {
865 /* if ((tqe != NULL) && (i < (8)) && */
866 /* if ((tqe != NULL) && (i < (WILC_VMM_TBL_SIZE-1)) && */
867 if ((tqe != NULL) && (i < (WILC_VMM_TBL_SIZE - 1)) /* reserve last entry to 0 */) {
868
869 if (tqe->type == WILC_CFG_PKT) {
870 vmm_sz = ETH_CONFIG_PKT_HDR_OFFSET;
871 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900872 else if (tqe->type == WILC_NET_PKT) {
873 vmm_sz = ETH_ETHERNET_HDR_OFFSET;
874 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900875 else {
876 vmm_sz = HOST_HDR_OFFSET;
877 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900878 vmm_sz += tqe->buffer_size;
879 PRINT_D(TX_DBG, "VMM Size before alignment = %d\n", vmm_sz);
880 if (vmm_sz & 0x3) { /* has to be word aligned */
881 vmm_sz = (vmm_sz + 4) & ~0x3;
882 }
883 if ((sum + vmm_sz) > p->tx_buffer_size) {
884 break;
885 }
886 PRINT_D(TX_DBG, "VMM Size AFTER alignment = %d\n", vmm_sz);
887 vmm_table[i] = vmm_sz / 4; /* table take the word size */
888 PRINT_D(TX_DBG, "VMMTable entry size = %d\n", vmm_table[i]);
889
890 if (tqe->type == WILC_CFG_PKT) {
891 vmm_table[i] |= (1 << 10);
892 PRINT_D(TX_DBG, "VMMTable entry changed for CFG packet = %d\n", vmm_table[i]);
893 }
894#ifdef BIG_ENDIAN
895 vmm_table[i] = BYTE_SWAP(vmm_table[i]);
896#endif
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900897
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900898 i++;
899 sum += vmm_sz;
900 PRINT_D(TX_DBG, "sum = %d\n", sum);
901 tqe = wilc_wlan_txq_get_next(tqe);
902 } else {
903 break;
904 }
905 } while (1);
906
907 if (i == 0) { /* nothing in the queue */
908 PRINT_D(TX_DBG, "Nothing in TX-Q\n");
909 break;
910 } else {
911 PRINT_D(TX_DBG, "Mark the last entry in VMM table - number of previous entries = %d\n", i);
912 vmm_table[i] = 0x0; /* mark the last element to 0 */
913 }
914 acquire_bus(ACQUIRE_AND_WAKEUP);
915 counter = 0;
916 do {
917
918 ret = p->hif_func.hif_read_reg(WILC_HOST_TX_CTRL, &reg);
919 if (!ret) {
920 wilc_debug(N_ERR, "[wilc txq]: fail can't read reg vmm_tbl_entry..\n");
921 break;
922 }
923
924 if ((reg & 0x1) == 0) {
925 /**
926 * write to vmm table
927 **/
928 PRINT_D(TX_DBG, "Writing VMM table ... with Size = %d\n", ((i + 1) * 4));
929 break;
930 } else {
931 counter++;
932 if (counter > 200) {
933 counter = 0;
934 PRINT_D(TX_DBG, "Looping in tx ctrl , forcce quit\n");
935 ret = p->hif_func.hif_write_reg(WILC_HOST_TX_CTRL, 0);
936 break;
937 }
938 /**
939 * wait for vmm table is ready
940 **/
Chandra S Gorentla17aacd42015-08-08 17:41:35 +0530941 PRINT_WRN(GENERIC_DBG, "[wilc txq]: warn, vmm table not clear yet, wait...\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900942 release_bus(RELEASE_ALLOW_SLEEP);
Greg Kroah-Hartman2b922cb2015-09-04 09:30:51 -0700943 usleep_range(3000, 3000);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900944 acquire_bus(ACQUIRE_AND_WAKEUP);
945 }
946 } while (!p->quit);
947
948 if (!ret) {
949 goto _end_;
950 }
951
952 timeout = 200;
953 do {
954
955 /**
956 * write to vmm table
957 **/
Chaehyun Limc3ca6372015-09-20 15:51:19 +0900958 ret = p->hif_func.hif_block_tx(WILC_VMM_TBL_RX_SHADOW_BASE, (u8 *)vmm_table, ((i + 1) * 4));
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900959 if (!ret) {
960 wilc_debug(N_ERR, "ERR block TX of VMM table.\n");
961 break;
962 }
963
964
965 /**
966 * interrupt firmware
967 **/
968 ret = p->hif_func.hif_write_reg(WILC_HOST_VMM_CTL, 0x2);
969 if (!ret) {
970 wilc_debug(N_ERR, "[wilc txq]: fail can't write reg host_vmm_ctl..\n");
971 break;
972 }
973
974 /**
975 * wait for confirm...
976 **/
977
978 do {
979 ret = p->hif_func.hif_read_reg(WILC_HOST_VMM_CTL, &reg);
980 if (!ret) {
981 wilc_debug(N_ERR, "[wilc txq]: fail can't read reg host_vmm_ctl..\n");
982 break;
983 }
984 if ((reg >> 2) & 0x1) {
985 /**
986 * Get the entries
987 **/
988 entries = ((reg >> 3) & 0x3f);
989 /* entries = ((reg>>3)&0x2f); */
990 break;
991 } else {
992 release_bus(RELEASE_ALLOW_SLEEP);
Greg Kroah-Hartman2b922cb2015-09-04 09:30:51 -0700993 usleep_range(3000, 3000);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900994 acquire_bus(ACQUIRE_AND_WAKEUP);
995 PRINT_WRN(GENERIC_DBG, "Can't get VMM entery - reg = %2x\n", reg);
996 }
997 } while (--timeout);
998 if (timeout <= 0) {
999 ret = p->hif_func.hif_write_reg(WILC_HOST_VMM_CTL, 0x0);
1000 break;
1001 }
1002
1003 if (!ret) {
1004 break;
1005 }
1006
1007 if (entries == 0) {
Chandra S Gorentla17aacd42015-08-08 17:41:35 +05301008 PRINT_WRN(GENERIC_DBG, "[wilc txq]: no more buffer in the chip (reg: %08x), retry later [[ %d, %x ]]\n", reg, i, vmm_table[i - 1]);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001009
1010 /* undo the transaction. */
1011 ret = p->hif_func.hif_read_reg(WILC_HOST_TX_CTRL, &reg);
1012 if (!ret) {
1013 wilc_debug(N_ERR, "[wilc txq]: fail can't read reg WILC_HOST_TX_CTRL..\n");
1014 break;
1015 }
1016 reg &= ~(1ul << 0);
1017 ret = p->hif_func.hif_write_reg(WILC_HOST_TX_CTRL, reg);
1018 if (!ret) {
1019 wilc_debug(N_ERR, "[wilc txq]: fail can't write reg WILC_HOST_TX_CTRL..\n");
1020 break;
1021 }
1022 break;
1023 } else {
1024 break;
1025 }
1026 } while (1);
1027
1028 if (!ret) {
1029 goto _end_;
1030 }
1031 if (entries == 0) {
1032 ret = WILC_TX_ERR_NO_BUF;
1033 goto _end_;
1034 }
1035
1036 /* since copying data into txb takes some time, then
1037 * allow the bus lock to be released let the RX task go. */
1038 release_bus(RELEASE_ALLOW_SLEEP);
1039
1040 /**
1041 * Copy data to the TX buffer
1042 **/
1043 offset = 0;
1044 i = 0;
1045 do {
1046 tqe = wilc_wlan_txq_remove_from_head();
1047 if (tqe != NULL && (vmm_table[i] != 0)) {
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001048 u32 header, buffer_offset;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001049
1050#ifdef BIG_ENDIAN
1051 vmm_table[i] = BYTE_SWAP(vmm_table[i]);
1052#endif
1053 vmm_sz = (vmm_table[i] & 0x3ff); /* in word unit */
1054 vmm_sz *= 4;
1055 header = (tqe->type << 31) | (tqe->buffer_size << 15) | vmm_sz;
Chandra S Gorentla78174ad2015-08-08 17:41:36 +05301056 if (tqe->type == WILC_MGMT_PKT)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001057 header |= (1 << 30);
Chandra S Gorentla78174ad2015-08-08 17:41:36 +05301058 else
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001059 header &= ~(1 << 30);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001060
1061#ifdef BIG_ENDIAN
1062 header = BYTE_SWAP(header);
1063#endif
1064 memcpy(&txb[offset], &header, 4);
1065 if (tqe->type == WILC_CFG_PKT) {
1066 buffer_offset = ETH_CONFIG_PKT_HDR_OFFSET;
1067 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001068 else if (tqe->type == WILC_NET_PKT) {
1069 char *pBSSID = ((struct tx_complete_data *)(tqe->priv))->pBssid;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +09001070
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001071 buffer_offset = ETH_ETHERNET_HDR_OFFSET;
1072 /* copy the bssid at the sart of the buffer */
1073 memcpy(&txb[offset + 4], pBSSID, 6);
1074 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001075 else {
1076 buffer_offset = HOST_HDR_OFFSET;
1077 }
1078
1079 memcpy(&txb[offset + buffer_offset], tqe->buffer, tqe->buffer_size);
1080 offset += vmm_sz;
1081 i++;
1082 tqe->status = 1; /* mark the packet send */
1083 if (tqe->tx_complete_func)
1084 tqe->tx_complete_func(tqe->priv, tqe->status);
1085 #ifdef TCP_ACK_FILTER
1086 if (tqe->tcp_PendingAck_index != NOT_TCP_ACK) {
1087 Pending_Acks_info[tqe->tcp_PendingAck_index].txqe = NULL;
1088 }
1089 #endif
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -07001090 kfree(tqe);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001091 } else {
1092 break;
1093 }
1094 } while (--entries);
1095
1096 /**
1097 * lock the bus
1098 **/
1099 acquire_bus(ACQUIRE_AND_WAKEUP);
1100
1101 ret = p->hif_func.hif_clear_int_ext(ENABLE_TX_VMM);
1102 if (!ret) {
1103 wilc_debug(N_ERR, "[wilc txq]: fail can't start tx VMM ...\n");
1104 goto _end_;
1105 }
1106
1107 /**
1108 * transfer
1109 **/
1110 ret = p->hif_func.hif_block_tx_ext(0, txb, offset);
1111 if (!ret) {
1112 wilc_debug(N_ERR, "[wilc txq]: fail can't block tx ext...\n");
1113 goto _end_;
1114 }
1115
1116_end_:
1117
1118 release_bus(RELEASE_ALLOW_SLEEP);
1119 if (ret != 1)
1120 break;
1121 } while (0);
Greg Kroah-Hartman8990d852015-09-03 20:07:58 -07001122 up(p->txq_add_to_head_lock);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001123
1124 p->txq_exit = 1;
1125 PRINT_D(TX_DBG, "THREAD: Exiting txq\n");
1126 /* return tx[]q count */
1127 *pu32TxqCount = p->txq_entries;
1128 return ret;
1129}
1130
1131static void wilc_wlan_handle_rxq(void)
1132{
1133 wilc_wlan_dev_t *p = (wilc_wlan_dev_t *)&g_wlan;
1134 int offset = 0, size, has_packet = 0;
Chaehyun Lim51e825f2015-09-15 14:06:14 +09001135 u8 *buffer;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001136 struct rxq_entry_t *rqe;
1137
1138 p->rxq_exit = 0;
1139
1140
1141
1142
1143 do {
1144 if (p->quit) {
Chandra S Gorentla17aacd42015-08-08 17:41:35 +05301145 PRINT_D(RX_DBG, "exit 1st do-while due to Clean_UP function\n");
Greg Kroah-Hartman8990d852015-09-03 20:07:58 -07001146 up(p->cfg_wait);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001147 break;
1148 }
1149 rqe = wilc_wlan_rxq_remove();
1150 if (rqe == NULL) {
1151 PRINT_D(RX_DBG, "nothing in the queue - exit 1st do-while\n");
1152 break;
1153 }
1154 buffer = rqe->buffer;
1155 size = rqe->buffer_size;
1156 PRINT_D(RX_DBG, "rxQ entery Size = %d - Address = %p\n", size, buffer);
1157 offset = 0;
1158
1159
1160
1161 do {
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001162 u32 header;
1163 u32 pkt_len, pkt_offset, tp_len;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001164 int is_cfg_packet;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +09001165
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001166 PRINT_D(RX_DBG, "In the 2nd do-while\n");
1167 memcpy(&header, &buffer[offset], 4);
1168#ifdef BIG_ENDIAN
1169 header = BYTE_SWAP(header);
1170#endif
1171 PRINT_D(RX_DBG, "Header = %04x - Offset = %d\n", header, offset);
1172
1173
1174
1175 is_cfg_packet = (header >> 31) & 0x1;
1176 pkt_offset = (header >> 22) & 0x1ff;
1177 tp_len = (header >> 11) & 0x7ff;
1178 pkt_len = header & 0x7ff;
1179
1180 if (pkt_len == 0 || tp_len == 0) {
1181 wilc_debug(N_RXQ, "[wilc rxq]: data corrupt, packet len or tp_len is 0 [%d][%d]\n", pkt_len, tp_len);
1182 break;
1183 }
1184
1185/*bug 3887: [AP] Allow Management frames to be passed to the host*/
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001186 #define IS_MANAGMEMENT 0x100
1187 #define IS_MANAGMEMENT_CALLBACK 0x080
1188 #define IS_MGMT_STATUS_SUCCES 0x040
1189
1190
1191 if (pkt_offset & IS_MANAGMEMENT) {
1192 /* reset mgmt indicator bit, to use pkt_offeset in furthur calculations */
1193 pkt_offset &= ~(IS_MANAGMEMENT | IS_MANAGMEMENT_CALLBACK | IS_MGMT_STATUS_SUCCES);
1194
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001195 WILC_WFI_mgmt_rx(&buffer[offset + HOST_HDR_OFFSET], pkt_len);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001196 }
1197 /* BUG4530 fix */
1198 else
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001199 {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001200
1201 if (!is_cfg_packet) {
1202
1203 if (p->net_func.rx_indicate) {
1204 if (pkt_len > 0) {
1205 p->net_func.rx_indicate(&buffer[offset], pkt_len, pkt_offset);
1206 has_packet = 1;
1207 }
1208 }
1209 } else {
1210 wilc_cfg_rsp_t rsp;
1211
1212
1213
1214 p->cif_func.rx_indicate(&buffer[pkt_offset + offset], pkt_len, &rsp);
1215 if (rsp.type == WILC_CFG_RSP) {
1216 /**
1217 * wake up the waiting task...
1218 **/
1219 PRINT_D(RX_DBG, "p->cfg_seq_no = %d - rsp.seq_no = %d\n", p->cfg_seq_no, rsp.seq_no);
1220 if (p->cfg_seq_no == rsp.seq_no) {
Greg Kroah-Hartman8990d852015-09-03 20:07:58 -07001221 up(p->cfg_wait);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001222 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001223 } else if (rsp.type == WILC_CFG_RSP_STATUS) {
1224 /**
1225 * Call back to indicate status...
1226 **/
1227 if (p->indicate_func.mac_indicate) {
1228 p->indicate_func.mac_indicate(WILC_MAC_INDICATE_STATUS);
1229 }
1230
1231 } else if (rsp.type == WILC_CFG_RSP_SCAN) {
1232 if (p->indicate_func.mac_indicate)
1233 p->indicate_func.mac_indicate(WILC_MAC_INDICATE_SCAN);
1234 }
1235 }
1236 }
1237 offset += tp_len;
1238 if (offset >= size)
1239 break;
1240 } while (1);
1241
1242
1243#ifndef MEMORY_STATIC
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -07001244 kfree(buffer);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001245#endif
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -07001246 kfree(rqe);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001247
1248 if (has_packet) {
1249 if (p->net_func.rx_complete)
1250 p->net_func.rx_complete();
1251 }
1252 } while (1);
1253
1254 p->rxq_exit = 1;
Chandra S Gorentla17aacd42015-08-08 17:41:35 +05301255 PRINT_D(RX_DBG, "THREAD: Exiting RX thread\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001256}
1257
1258/********************************************
1259 *
1260 * Fast DMA Isr
1261 *
1262 ********************************************/
1263static void wilc_unknown_isr_ext(void)
1264{
1265 g_wlan.hif_func.hif_clear_int_ext(0);
1266}
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001267static void wilc_pllupdate_isr_ext(u32 int_stats)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001268{
1269
1270 int trials = 10;
1271
1272 g_wlan.hif_func.hif_clear_int_ext(PLL_INT_CLR);
1273
1274 /* Waiting for PLL */
Greg Kroah-Hartmanc2e4c0f2015-09-03 19:09:50 -07001275 mdelay(WILC_PLL_TO);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001276
1277 /* poll till read a valid data */
Dean Lee72ed4dc2015-06-12 14:11:44 +09001278 while (!(ISWILC1000(wilc_get_chipid(true)) && --trials)) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001279 PRINT_D(TX_DBG, "PLL update retrying\n");
Greg Kroah-Hartmanc2e4c0f2015-09-03 19:09:50 -07001280 mdelay(1);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001281 }
1282}
1283
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001284static void wilc_sleeptimer_isr_ext(u32 int_stats1)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001285{
1286 g_wlan.hif_func.hif_clear_int_ext(SLEEP_INT_CLR);
1287#ifndef WILC_OPTIMIZE_SLEEP_INT
1288 genuChipPSstate = CHIP_SLEEPING_AUTO;
1289#endif
1290}
1291
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001292static void wilc_wlan_handle_isr_ext(u32 int_status)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001293{
1294 wilc_wlan_dev_t *p = (wilc_wlan_dev_t *)&g_wlan;
1295#ifdef MEMORY_STATIC
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001296 u32 offset = p->rx_buffer_offset;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001297#endif
Chaehyun Lim51e825f2015-09-15 14:06:14 +09001298 u8 *buffer = NULL;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001299 u32 size;
1300 u32 retries = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001301 int ret = 0;
1302 struct rxq_entry_t *rqe;
1303
1304
1305 /**
1306 * Get the rx size
1307 **/
1308
1309 size = ((int_status & 0x7fff) << 2);
1310
1311 while (!size && retries < 10) {
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001312 u32 time = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001313 /*looping more secure*/
1314 /*zero size make a crashe because the dma will not happen and that will block the firmware*/
1315 wilc_debug(N_ERR, "RX Size equal zero ... Trying to read it again for %d time\n", time++);
1316 p->hif_func.hif_read_size(&size);
1317 size = ((size & 0x7fff) << 2);
1318 retries++;
1319
1320 }
1321
1322 if (size > 0) {
1323#ifdef MEMORY_STATIC
1324 if (p->rx_buffer_size - offset < size)
1325 offset = 0;
1326
1327 if (p->rx_buffer)
1328 buffer = &p->rx_buffer[offset];
1329 else {
1330 wilc_debug(N_ERR, "[wilc isr]: fail Rx Buffer is NULL...drop the packets (%d)\n", size);
1331 goto _end_;
1332 }
1333
1334#else
Greg Kroah-Hartmanf019b9d2015-09-03 18:50:27 -07001335 buffer = kmalloc(size, GFP_KERNEL);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001336 if (buffer == NULL) {
1337 wilc_debug(N_ERR, "[wilc isr]: fail alloc host memory...drop the packets (%d)\n", size);
Greg Kroah-Hartman80e29c72015-08-14 19:42:23 -07001338 usleep_range(100 * 1000, 100 * 1000);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001339 goto _end_;
1340 }
1341#endif
1342
1343 /**
1344 * clear the chip's interrupt after getting size some register getting corrupted after clear the interrupt
1345 **/
1346 p->hif_func.hif_clear_int_ext(DATA_INT_CLR | ENABLE_RX_VMM);
1347
1348
1349 /**
1350 * start transfer
1351 **/
1352 ret = p->hif_func.hif_block_rx_ext(0, buffer, size);
1353
1354 if (!ret) {
1355 wilc_debug(N_ERR, "[wilc isr]: fail block rx...\n");
1356 goto _end_;
1357 }
1358_end_:
1359
1360
1361 if (ret) {
1362#ifdef MEMORY_STATIC
1363 offset += size;
1364 p->rx_buffer_offset = offset;
1365#endif
1366 /**
1367 * add to rx queue
1368 **/
Greg Kroah-Hartmanf019b9d2015-09-03 18:50:27 -07001369 rqe = kmalloc(sizeof(struct rxq_entry_t), GFP_KERNEL);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001370 if (rqe != NULL) {
1371 rqe->buffer = buffer;
1372 rqe->buffer_size = size;
1373 PRINT_D(RX_DBG, "rxq entery Size= %d - Address = %p\n", rqe->buffer_size, rqe->buffer);
1374 wilc_wlan_rxq_add(rqe);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001375 }
1376 } else {
1377#ifndef MEMORY_STATIC
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -07001378 kfree(buffer);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001379#endif
1380 }
1381 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001382 wilc_wlan_handle_rxq();
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001383}
1384
1385void wilc_handle_isr(void)
1386{
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001387 u32 int_status;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001388
1389 acquire_bus(ACQUIRE_AND_WAKEUP);
1390 g_wlan.hif_func.hif_read_int(&int_status);
1391
1392 if (int_status & PLL_INT_EXT) {
1393 wilc_pllupdate_isr_ext(int_status);
1394 }
1395 if (int_status & DATA_INT_EXT) {
1396 wilc_wlan_handle_isr_ext(int_status);
1397 #ifndef WILC_OPTIMIZE_SLEEP_INT
1398 /* Chip is up and talking*/
1399 genuChipPSstate = CHIP_WAKEDUP;
1400 #endif
1401 }
1402 if (int_status & SLEEP_INT_EXT) {
1403 wilc_sleeptimer_isr_ext(int_status);
1404 }
1405
1406 if (!(int_status & (ALL_INT_EXT))) {
1407#ifdef WILC_SDIO
1408 PRINT_D(TX_DBG, ">> UNKNOWN_INTERRUPT - 0x%08x\n", int_status);
1409#endif
1410 wilc_unknown_isr_ext();
1411 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001412 release_bus(RELEASE_ALLOW_SLEEP);
1413}
1414
1415/********************************************
1416 *
1417 * Firmware download
1418 *
1419 ********************************************/
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001420static int wilc_wlan_firmware_download(const u8 *buffer, u32 buffer_size)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001421{
1422 wilc_wlan_dev_t *p = (wilc_wlan_dev_t *)&g_wlan;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001423 u32 offset;
1424 u32 addr, size, size2, blksz;
Chaehyun Lim51e825f2015-09-15 14:06:14 +09001425 u8 *dma_buffer;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001426 int ret = 0;
1427
Chaehyun Limc3ca6372015-09-20 15:51:19 +09001428 blksz = (1ul << 12);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001429 /* Allocate a DMA coherent buffer. */
1430
Greg Kroah-Hartmanf019b9d2015-09-03 18:50:27 -07001431 dma_buffer = kmalloc(blksz, GFP_KERNEL);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001432 if (dma_buffer == NULL) {
1433 /*EIO 5*/
1434 ret = -5;
1435 PRINT_ER("Can't allocate buffer for firmware download IO error\n ");
1436 goto _fail_1;
1437 }
1438
1439 PRINT_D(INIT_DBG, "Downloading firmware size = %d ...\n", buffer_size);
1440 /**
1441 * load the firmware
1442 **/
1443 offset = 0;
1444 do {
1445 memcpy(&addr, &buffer[offset], 4);
1446 memcpy(&size, &buffer[offset + 4], 4);
1447#ifdef BIG_ENDIAN
1448 addr = BYTE_SWAP(addr);
1449 size = BYTE_SWAP(size);
1450#endif
1451 acquire_bus(ACQUIRE_ONLY);
1452 offset += 8;
1453 while (((int)size) && (offset < buffer_size)) {
Chandra S Gorentla78174ad2015-08-08 17:41:36 +05301454 if (size <= blksz)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001455 size2 = size;
Chandra S Gorentla78174ad2015-08-08 17:41:36 +05301456 else
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001457 size2 = blksz;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001458 /* Copy firmware into a DMA coherent buffer */
1459 memcpy(dma_buffer, &buffer[offset], size2);
1460 ret = p->hif_func.hif_block_tx(addr, dma_buffer, size2);
1461 if (!ret)
1462 break;
1463
1464 addr += size2;
1465 offset += size2;
1466 size -= size2;
1467 }
1468 release_bus(RELEASE_ONLY);
1469
1470 if (!ret) {
1471 /*EIO 5*/
1472 ret = -5;
1473 PRINT_ER("Can't download firmware IO error\n ");
1474 goto _fail_;
1475 }
1476 PRINT_D(INIT_DBG, "Offset = %d\n", offset);
1477 } while (offset < buffer_size);
1478
1479_fail_:
1480
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -07001481 kfree(dma_buffer);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001482
1483_fail_1:
1484
1485 return (ret < 0) ? ret : 0;
1486}
1487
1488/********************************************
1489 *
1490 * Common
1491 *
1492 ********************************************/
1493static int wilc_wlan_start(void)
1494{
1495 wilc_wlan_dev_t *p = (wilc_wlan_dev_t *)&g_wlan;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001496 u32 reg = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001497 int ret;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001498 u32 chipid;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001499
1500 /**
1501 * Set the host interface
1502 **/
1503#ifdef OLD_FPGA_BITFILE
1504 acquire_bus(ACQUIRE_ONLY);
1505 ret = p->hif_func.hif_read_reg(WILC_VMM_CORE_CTL, &reg);
1506 if (!ret) {
1507 wilc_debug(N_ERR, "[wilc start]: fail read reg vmm_core_ctl...\n");
1508 release_bus(RELEASE_ALLOW_SLEEP);
1509 return ret;
1510 }
1511 reg |= (p->io_func.io_type << 2);
1512 ret = p->hif_func.hif_write_reg(WILC_VMM_CORE_CTL, reg);
1513 if (!ret) {
1514 wilc_debug(N_ERR, "[wilc start]: fail write reg vmm_core_ctl...\n");
1515 release_bus(RELEASE_ONLY);
1516 return ret;
1517 }
1518#else
1519 if (p->io_func.io_type == HIF_SDIO) {
1520 reg = 0;
1521 reg |= (1 << 3); /* bug 4456 and 4557 */
1522 } else if (p->io_func.io_type == HIF_SPI) {
1523 reg = 1;
1524 }
1525 acquire_bus(ACQUIRE_ONLY);
1526 ret = p->hif_func.hif_write_reg(WILC_VMM_CORE_CFG, reg);
1527 if (!ret) {
1528 wilc_debug(N_ERR, "[wilc start]: fail write reg vmm_core_cfg...\n");
1529 release_bus(RELEASE_ONLY);
1530 /* EIO 5*/
1531 ret = -5;
1532 return ret;
1533 }
1534 reg = 0;
1535#ifdef WILC_SDIO_IRQ_GPIO
1536 reg |= WILC_HAVE_SDIO_IRQ_GPIO;
1537#endif
1538
1539#ifdef WILC_DISABLE_PMU
1540#else
1541 reg |= WILC_HAVE_USE_PMU;
1542#endif
1543
1544#ifdef WILC_SLEEP_CLK_SRC_XO
1545 reg |= WILC_HAVE_SLEEP_CLK_SRC_XO;
1546#elif defined WILC_SLEEP_CLK_SRC_RTC
1547 reg |= WILC_HAVE_SLEEP_CLK_SRC_RTC;
1548#endif
1549
1550#ifdef WILC_EXT_PA_INV_TX_RX
1551 reg |= WILC_HAVE_EXT_PA_INV_TX_RX;
1552#endif
1553
1554 reg |= WILC_HAVE_LEGACY_RF_SETTINGS;
1555
1556
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001557/*Set oscillator frequency*/
1558#ifdef XTAL_24
1559 reg |= WILC_HAVE_XTAL_24;
1560#endif
1561
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001562/*Enable/Disable GPIO configuration for FW logs*/
1563#ifdef DISABLE_WILC_UART
1564 reg |= WILC_HAVE_DISABLE_WILC_UART;
1565#endif
1566
1567 ret = p->hif_func.hif_write_reg(WILC_GP_REG_1, reg);
1568 if (!ret) {
1569 wilc_debug(N_ERR, "[wilc start]: fail write WILC_GP_REG_1 ...\n");
1570 release_bus(RELEASE_ONLY);
1571 /* EIO 5*/
1572 ret = -5;
1573 return ret;
1574 }
1575#endif
1576
1577
1578 /**
1579 * Bus related
1580 **/
1581 p->hif_func.hif_sync_ext(NUM_INT_EXT);
1582
1583 ret = p->hif_func.hif_read_reg(0x1000, &chipid);
1584 if (!ret) {
1585 wilc_debug(N_ERR, "[wilc start]: fail read reg 0x1000 ...\n");
1586 release_bus(RELEASE_ONLY);
1587 /* EIO 5*/
1588 ret = -5;
1589 return ret;
1590 }
1591
1592 /**
1593 * Go...
1594 **/
1595
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001596
1597 p->hif_func.hif_read_reg(WILC_GLB_RESET_0, &reg);
1598 if ((reg & (1ul << 10)) == (1ul << 10)) {
1599 reg &= ~(1ul << 10);
1600 p->hif_func.hif_write_reg(WILC_GLB_RESET_0, reg);
1601 p->hif_func.hif_read_reg(WILC_GLB_RESET_0, &reg);
1602 }
1603
1604 reg |= (1ul << 10);
1605 ret = p->hif_func.hif_write_reg(WILC_GLB_RESET_0, reg);
1606 p->hif_func.hif_read_reg(WILC_GLB_RESET_0, &reg);
1607 release_bus(RELEASE_ONLY);
1608
1609 return (ret < 0) ? ret : 0;
1610}
1611
1612void wilc_wlan_global_reset(void)
1613{
1614
1615 wilc_wlan_dev_t *p = (wilc_wlan_dev_t *)&g_wlan;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +09001616
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001617 acquire_bus(ACQUIRE_AND_WAKEUP);
1618 p->hif_func.hif_write_reg(WILC_GLB_RESET_0, 0x0);
1619 release_bus(RELEASE_ONLY);
1620}
1621static int wilc_wlan_stop(void)
1622{
1623 wilc_wlan_dev_t *p = (wilc_wlan_dev_t *)&g_wlan;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001624 u32 reg = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001625 int ret;
Chaehyun Lim51e825f2015-09-15 14:06:14 +09001626 u8 timeout = 10;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001627 /**
1628 * TODO: stop the firmware, need a re-download
1629 **/
1630 acquire_bus(ACQUIRE_AND_WAKEUP);
1631
1632 ret = p->hif_func.hif_read_reg(WILC_GLB_RESET_0, &reg);
1633 if (!ret) {
1634 PRINT_ER("Error while reading reg\n");
1635 release_bus(RELEASE_ALLOW_SLEEP);
1636 return ret;
1637 }
1638
1639 reg &= ~(1 << 10);
1640
1641
1642 ret = p->hif_func.hif_write_reg(WILC_GLB_RESET_0, reg);
1643 if (!ret) {
1644 PRINT_ER("Error while writing reg\n");
1645 release_bus(RELEASE_ALLOW_SLEEP);
1646 return ret;
1647 }
1648
1649
1650
1651 do {
1652 ret = p->hif_func.hif_read_reg(WILC_GLB_RESET_0, &reg);
1653 if (!ret) {
1654 PRINT_ER("Error while reading reg\n");
1655 release_bus(RELEASE_ALLOW_SLEEP);
1656 return ret;
1657 }
1658 PRINT_D(GENERIC_DBG, "Read RESET Reg %x : Retry%d\n", reg, timeout);
1659 /*Workaround to ensure that the chip is actually reset*/
1660 if ((reg & (1 << 10))) {
1661 PRINT_D(GENERIC_DBG, "Bit 10 not reset : Retry %d\n", timeout);
1662 reg &= ~(1 << 10);
1663 ret = p->hif_func.hif_write_reg(WILC_GLB_RESET_0, reg);
1664 timeout--;
1665 } else {
1666 PRINT_D(GENERIC_DBG, "Bit 10 reset after : Retry %d\n", timeout);
1667 ret = p->hif_func.hif_read_reg(WILC_GLB_RESET_0, &reg);
1668 if (!ret) {
1669 PRINT_ER("Error while reading reg\n");
1670 release_bus(RELEASE_ALLOW_SLEEP);
1671 return ret;
1672 }
1673 PRINT_D(GENERIC_DBG, "Read RESET Reg %x : Retry%d\n", reg, timeout);
1674 break;
1675 }
1676
1677 } while (timeout);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001678 reg = ((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 8) | (1 << 9) | (1 << 26) | (1 << 29) | (1 << 30) | (1 << 31)); /**/
1679 /**/
Hari Prasath Gujulan Elango369f1902015-06-22 07:04:39 +00001680 p->hif_func.hif_write_reg(WILC_GLB_RESET_0, reg); /**/
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001681 reg = ~(1 << 10); /**/
1682 /**/
1683 ret = p->hif_func.hif_write_reg(WILC_GLB_RESET_0, reg); /**/
1684/******************************************************************************/
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001685
1686 release_bus(RELEASE_ALLOW_SLEEP);
1687
1688 return ret;
1689}
1690
1691static void wilc_wlan_cleanup(void)
1692{
1693 wilc_wlan_dev_t *p = (wilc_wlan_dev_t *)&g_wlan;
1694 struct txq_entry_t *tqe;
1695 struct rxq_entry_t *rqe;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001696 u32 reg = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001697 int ret;
1698
1699 p->quit = 1;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001700 do {
1701 tqe = wilc_wlan_txq_remove_from_head();
1702 if (tqe == NULL)
1703 break;
1704 if (tqe->tx_complete_func)
1705 tqe->tx_complete_func(tqe->priv, 0);
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -07001706 kfree(tqe);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001707 } while (1);
1708
1709 do {
1710 rqe = wilc_wlan_rxq_remove();
1711 if (rqe == NULL)
1712 break;
Javier Martinez Canillas6a272242015-09-22 15:24:50 +02001713#ifndef MEMORY_STATIC
1714 kfree(rqe->buffer);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001715#endif
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -07001716 kfree(rqe);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001717 } while (1);
1718
1719 /**
1720 * clean up buffer
1721 **/
1722
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001723 #ifdef MEMORY_STATIC
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -07001724 kfree(p->rx_buffer);
1725 p->rx_buffer = NULL;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001726 #endif
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -07001727 kfree(p->tx_buffer);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001728
1729 acquire_bus(ACQUIRE_AND_WAKEUP);
1730
1731
1732 ret = p->hif_func.hif_read_reg(WILC_GP_REG_0, &reg);
1733 if (!ret) {
1734 PRINT_ER("Error while reading reg\n");
1735 release_bus(RELEASE_ALLOW_SLEEP);
1736 }
1737 PRINT_ER("Writing ABORT reg\n");
1738 ret = p->hif_func.hif_write_reg(WILC_GP_REG_0, (reg | ABORT_INT));
1739 if (!ret) {
1740 PRINT_ER("Error while writing reg\n");
1741 release_bus(RELEASE_ALLOW_SLEEP);
1742 }
1743 release_bus(RELEASE_ALLOW_SLEEP);
1744 /**
1745 * io clean up
1746 **/
1747 p->hif_func.hif_deinit(NULL);
1748
1749}
1750
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001751static int wilc_wlan_cfg_commit(int type, u32 drvHandler)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001752{
1753 wilc_wlan_dev_t *p = (wilc_wlan_dev_t *)&g_wlan;
1754 wilc_cfg_frame_t *cfg = &p->cfg_frame;
1755 int total_len = p->cfg_frame_offset + 4 + DRIVER_HANDLER_SIZE;
1756 int seq_no = p->cfg_seq_no % 256;
Chaehyun Lim4e4467f2015-06-11 14:35:55 +09001757 int driver_handler = (u32)drvHandler;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001758
1759
1760 /**
1761 * Set up header
1762 **/
1763 if (type == WILC_CFG_SET) { /* Set */
1764 cfg->wid_header[0] = 'W';
1765 } else { /* Query */
1766 cfg->wid_header[0] = 'Q';
1767 }
1768 cfg->wid_header[1] = seq_no; /* sequence number */
Chaehyun Lim51e825f2015-09-15 14:06:14 +09001769 cfg->wid_header[2] = (u8)total_len;
1770 cfg->wid_header[3] = (u8)(total_len >> 8);
1771 cfg->wid_header[4] = (u8)driver_handler;
1772 cfg->wid_header[5] = (u8)(driver_handler >> 8);
1773 cfg->wid_header[6] = (u8)(driver_handler >> 16);
1774 cfg->wid_header[7] = (u8)(driver_handler >> 24);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001775 p->cfg_seq_no = seq_no;
1776
1777 /**
1778 * Add to TX queue
1779 **/
1780
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001781 if (!wilc_wlan_txq_add_cfg_pkt(&cfg->wid_header[0], total_len))
1782 return -1;
1783
1784 return 0;
1785}
1786
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001787static int wilc_wlan_cfg_set(int start, u32 wid, u8 *buffer, u32 buffer_size, int commit, u32 drvHandler)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001788{
1789 wilc_wlan_dev_t *p = (wilc_wlan_dev_t *)&g_wlan;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001790 u32 offset;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001791 int ret_size;
1792
1793
1794 if (p->cfg_frame_in_use)
1795 return 0;
1796
1797 if (start)
1798 p->cfg_frame_offset = 0;
1799
1800 offset = p->cfg_frame_offset;
Chaehyun Limec53adf2015-09-15 14:06:15 +09001801 ret_size = p->cif_func.cfg_wid_set(p->cfg_frame.frame, offset, (u16)wid, buffer, buffer_size);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001802 offset += ret_size;
1803 p->cfg_frame_offset = offset;
1804
1805 if (commit) {
1806 PRINT_D(TX_DBG, "[WILC]PACKET Commit with sequence number %d\n", p->cfg_seq_no);
1807 PRINT_D(RX_DBG, "Processing cfg_set()\n");
1808 p->cfg_frame_in_use = 1;
1809
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001810 if (wilc_wlan_cfg_commit(WILC_CFG_SET, drvHandler))
Chaehyun Lim5af6b852015-09-17 16:48:48 +09001811 ret_size = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001812
1813 if (p->os_func.os_wait(p->cfg_wait, CFG_PKTS_TIMEOUT)) {
1814 PRINT_D(TX_DBG, "Set Timed Out\n");
1815 ret_size = 0;
1816 }
1817 p->cfg_frame_in_use = 0;
1818 p->cfg_frame_offset = 0;
1819 p->cfg_seq_no += 1;
1820
1821 }
1822
1823 return ret_size;
1824}
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001825static int wilc_wlan_cfg_get(int start, u32 wid, int commit, u32 drvHandler)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001826{
1827 wilc_wlan_dev_t *p = (wilc_wlan_dev_t *)&g_wlan;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001828 u32 offset;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001829 int ret_size;
1830
1831
1832 if (p->cfg_frame_in_use)
1833 return 0;
1834
1835 if (start)
1836 p->cfg_frame_offset = 0;
1837
1838 offset = p->cfg_frame_offset;
Chaehyun Limec53adf2015-09-15 14:06:15 +09001839 ret_size = p->cif_func.cfg_wid_get(p->cfg_frame.frame, offset, (u16)wid);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001840 offset += ret_size;
1841 p->cfg_frame_offset = offset;
1842
1843 if (commit) {
1844 p->cfg_frame_in_use = 1;
1845
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001846 if (wilc_wlan_cfg_commit(WILC_CFG_QUERY, drvHandler))
Chaehyun Lim5af6b852015-09-17 16:48:48 +09001847 ret_size = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001848
1849
1850 if (p->os_func.os_wait(p->cfg_wait, CFG_PKTS_TIMEOUT)) {
1851 PRINT_D(TX_DBG, "Get Timed Out\n");
1852 ret_size = 0;
1853 }
1854 PRINT_D(GENERIC_DBG, "[WILC]Get Response received\n");
1855 p->cfg_frame_in_use = 0;
1856 p->cfg_frame_offset = 0;
1857 p->cfg_seq_no += 1;
1858 }
1859
1860 return ret_size;
1861}
1862
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001863static int wilc_wlan_cfg_get_val(u32 wid, u8 *buffer, u32 buffer_size)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001864{
1865 wilc_wlan_dev_t *p = (wilc_wlan_dev_t *)&g_wlan;
1866 int ret;
1867
Chaehyun Limec53adf2015-09-15 14:06:15 +09001868 ret = p->cif_func.cfg_wid_get_val((u16)wid, buffer, buffer_size);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001869
1870 return ret;
1871}
1872
1873void wilc_bus_set_max_speed(void)
1874{
1875
1876 /* Increase bus speed to max possible. */
1877 g_wlan.hif_func.hif_set_max_bus_speed();
1878}
1879
1880void wilc_bus_set_default_speed(void)
1881{
1882
1883 /* Restore bus speed to default. */
1884 g_wlan.hif_func.hif_set_default_bus_speed();
1885}
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001886u32 init_chip(void)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001887{
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001888 u32 chipid;
1889 u32 reg, ret = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001890
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001891 acquire_bus(ACQUIRE_ONLY);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001892
Dean Lee72ed4dc2015-06-12 14:11:44 +09001893 chipid = wilc_get_chipid(true);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001894
1895
1896
1897 if ((chipid & 0xfff) != 0xa0) {
1898 /**
1899 * Avoid booting from boot ROM. Make sure that Drive IRQN [SDIO platform]
1900 * or SD_DAT3 [SPI platform] to ?1?
1901 **/
1902 /* Set cortus reset register to register control. */
1903 ret = g_wlan.hif_func.hif_read_reg(0x1118, &reg);
1904 if (!ret) {
1905 wilc_debug(N_ERR, "[wilc start]: fail read reg 0x1118 ...\n");
1906 return ret;
1907 }
1908 reg |= (1 << 0);
1909 ret = g_wlan.hif_func.hif_write_reg(0x1118, reg);
1910 if (!ret) {
1911 wilc_debug(N_ERR, "[wilc start]: fail write reg 0x1118 ...\n");
1912 return ret;
1913 }
1914 /**
1915 * Write branch intruction to IRAM (0x71 trap) at location 0xFFFF0000
1916 * (Cortus map) or C0000 (AHB map).
1917 **/
1918 ret = g_wlan.hif_func.hif_write_reg(0xc0000, 0x71);
1919 if (!ret) {
1920 wilc_debug(N_ERR, "[wilc start]: fail write reg 0xc0000 ...\n");
1921 return ret;
1922 }
1923 }
1924
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001925 release_bus(RELEASE_ONLY);
1926
1927 return ret;
1928
1929}
1930
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001931u32 wilc_get_chipid(u8 update)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001932{
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001933 static u32 chipid;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001934 /* SDIO can't read into global variables */
1935 /* Use this variable as a temp, then copy to the global */
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001936 u32 tempchipid = 0;
1937 u32 rfrevid;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001938
1939 if (chipid == 0 || update != 0) {
1940 g_wlan.hif_func.hif_read_reg(0x1000, &tempchipid);
1941 g_wlan.hif_func.hif_read_reg(0x13f4, &rfrevid);
1942 if (!ISWILC1000(tempchipid)) {
1943 chipid = 0;
1944 goto _fail_;
1945 }
1946 if (tempchipid == 0x1002a0) {
1947 if (rfrevid == 0x1) { /* 1002A0 */
1948 } else { /* if (rfrevid == 0x2) */ /* 1002A1 */
1949 tempchipid = 0x1002a1;
1950 }
1951 } else if (tempchipid == 0x1002b0) {
1952 if (rfrevid == 3) { /* 1002B0 */
1953 } else if (rfrevid == 4) { /* 1002B1 */
1954 tempchipid = 0x1002b1;
1955 } else { /* if(rfrevid == 5) */ /* 1002B2 */
1956 tempchipid = 0x1002b2;
1957 }
1958 } else {
1959 }
1960
1961 chipid = tempchipid;
1962 }
1963_fail_:
1964 return chipid;
1965}
1966
1967#ifdef COMPLEMENT_BOOT
Chaehyun Lim51e825f2015-09-15 14:06:14 +09001968u8 core_11b_ready(void)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001969{
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001970 u32 reg_val;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001971
1972 acquire_bus(ACQUIRE_ONLY);
1973 g_wlan.hif_func.hif_write_reg(0x16082c, 1);
1974 g_wlan.hif_func.hif_write_reg(0x161600, 0x90);
1975 g_wlan.hif_func.hif_read_reg(0x161600, &reg_val);
1976 release_bus(RELEASE_ONLY);
1977
1978 if (reg_val == 0x90)
1979 return 0;
1980 else
1981 return 1;
1982}
1983#endif
1984
1985int wilc_wlan_init(wilc_wlan_inp_t *inp, wilc_wlan_oup_t *oup)
1986{
1987
1988 int ret = 0;
1989
1990 PRINT_D(INIT_DBG, "Initializing WILC_Wlan ...\n");
1991
1992 memset((void *)&g_wlan, 0, sizeof(wilc_wlan_dev_t));
1993
1994 /**
1995 * store the input
1996 **/
1997 memcpy((void *)&g_wlan.os_func, (void *)&inp->os_func, sizeof(wilc_wlan_os_func_t));
1998 memcpy((void *)&g_wlan.io_func, (void *)&inp->io_func, sizeof(wilc_wlan_io_func_t));
1999 memcpy((void *)&g_wlan.net_func, (void *)&inp->net_func, sizeof(wilc_wlan_net_func_t));
2000 memcpy((void *)&g_wlan.indicate_func, (void *)&inp->indicate_func, sizeof(wilc_wlan_net_func_t));
2001 g_wlan.hif_lock = inp->os_context.hif_critical_section;
2002 g_wlan.txq_lock = inp->os_context.txq_critical_section;
2003
Johnny Kimc5c77ba2015-05-11 14:30:56 +09002004 g_wlan.txq_add_to_head_lock = inp->os_context.txq_add_to_head_critical_section;
2005
Johnny Kimc5c77ba2015-05-11 14:30:56 +09002006 g_wlan.txq_spinlock = inp->os_context.txq_spin_lock;
2007
2008 g_wlan.rxq_lock = inp->os_context.rxq_critical_section;
2009 g_wlan.txq_wait = inp->os_context.txq_wait_event;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09002010 g_wlan.cfg_wait = inp->os_context.cfg_wait_event;
2011 g_wlan.tx_buffer_size = inp->os_context.tx_buffer_size;
2012#if defined (MEMORY_STATIC)
2013 g_wlan.rx_buffer_size = inp->os_context.rx_buffer_size;
2014#endif
Johnny Kimc5c77ba2015-05-11 14:30:56 +09002015 /***
2016 * host interface init
2017 **/
Johnny Kimc5c77ba2015-05-11 14:30:56 +09002018 if ((inp->io_func.io_type & 0x1) == HIF_SDIO) {
2019 if (!hif_sdio.hif_init(inp, wilc_debug)) {
2020 /* EIO 5 */
2021 ret = -5;
2022 goto _fail_;
2023 }
2024 memcpy((void *)&g_wlan.hif_func, &hif_sdio, sizeof(wilc_hif_func_t));
2025 } else {
2026 if ((inp->io_func.io_type & 0x1) == HIF_SPI) {
2027 /**
2028 * TODO:
2029 **/
2030 if (!hif_spi.hif_init(inp, wilc_debug)) {
2031 /* EIO 5 */
2032 ret = -5;
2033 goto _fail_;
2034 }
2035 memcpy((void *)&g_wlan.hif_func, &hif_spi, sizeof(wilc_hif_func_t));
2036 } else {
2037 /* EIO 5 */
2038 ret = -5;
2039 goto _fail_;
2040 }
2041 }
2042
2043 /***
2044 * mac interface init
2045 **/
2046 if (!mac_cfg.cfg_init(wilc_debug)) {
2047 /* ENOBUFS 105 */
2048 ret = -105;
2049 goto _fail_;
2050 }
2051 memcpy((void *)&g_wlan.cif_func, &mac_cfg, sizeof(wilc_cfg_func_t));
2052
2053
2054 /**
2055 * alloc tx, rx buffer
2056 **/
Greg Kroah-Hartmanb1413b62015-06-02 14:11:12 +09002057 if (g_wlan.tx_buffer == NULL)
Greg Kroah-Hartmanf019b9d2015-09-03 18:50:27 -07002058 g_wlan.tx_buffer = kmalloc(g_wlan.tx_buffer_size, GFP_KERNEL);
Arnd Bergmann7a8fd842015-06-01 21:06:45 +02002059 PRINT_D(TX_DBG, "g_wlan.tx_buffer = %p\n", g_wlan.tx_buffer);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09002060
Greg Kroah-Hartmanb1413b62015-06-02 14:11:12 +09002061 if (g_wlan.tx_buffer == NULL) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09002062 /* ENOBUFS 105 */
2063 ret = -105;
2064 PRINT_ER("Can't allocate Tx Buffer");
2065 goto _fail_;
2066 }
2067
2068/* rx_buffer is not used unless we activate USE_MEM STATIC which is not applicable, allocating such memory is useless*/
2069#if defined (MEMORY_STATIC)
Greg Kroah-Hartmanb1413b62015-06-02 14:11:12 +09002070 if (g_wlan.rx_buffer == NULL)
Greg Kroah-Hartmanf019b9d2015-09-03 18:50:27 -07002071 g_wlan.rx_buffer = kmalloc(g_wlan.rx_buffer_size, GFP_KERNEL);
Arnd Bergmann7a8fd842015-06-01 21:06:45 +02002072 PRINT_D(TX_DBG, "g_wlan.rx_buffer =%p\n", g_wlan.rx_buffer);
Greg Kroah-Hartmanb1413b62015-06-02 14:11:12 +09002073 if (g_wlan.rx_buffer == NULL) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09002074 /* ENOBUFS 105 */
2075 ret = -105;
2076 PRINT_ER("Can't allocate Rx Buffer");
2077 goto _fail_;
2078 }
2079#endif
2080
2081 /**
2082 * export functions
2083 **/
2084 oup->wlan_firmware_download = wilc_wlan_firmware_download;
2085 oup->wlan_start = wilc_wlan_start;
2086 oup->wlan_stop = wilc_wlan_stop;
2087 oup->wlan_add_to_tx_que = wilc_wlan_txq_add_net_pkt;
2088 oup->wlan_handle_tx_que = wilc_wlan_handle_txq;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09002089 oup->wlan_handle_rx_isr = wilc_handle_isr;
2090 oup->wlan_cleanup = wilc_wlan_cleanup;
2091 oup->wlan_cfg_set = wilc_wlan_cfg_set;
2092 oup->wlan_cfg_get = wilc_wlan_cfg_get;
2093 oup->wlan_cfg_get_value = wilc_wlan_cfg_get_val;
2094
Johnny Kimc5c77ba2015-05-11 14:30:56 +09002095 oup->wlan_add_mgmt_to_tx_que = wilc_wlan_txq_add_mgmt_pkt;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09002096
2097 if (!init_chip()) {
2098 /* EIO 5 */
2099 ret = -5;
2100 goto _fail_;
2101 }
2102#ifdef TCP_ACK_FILTER
2103 Init_TCP_tracking();
2104#endif
2105
Johnny Kimc5c77ba2015-05-11 14:30:56 +09002106 return 1;
2107
2108_fail_:
2109
Johnny Kimc5c77ba2015-05-11 14:30:56 +09002110 #ifdef MEMORY_STATIC
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -07002111 kfree(g_wlan.rx_buffer);
2112 g_wlan.rx_buffer = NULL;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09002113 #endif
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -07002114 kfree(g_wlan.tx_buffer);
2115 g_wlan.tx_buffer = NULL;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09002116
Johnny Kimc5c77ba2015-05-11 14:30:56 +09002117 return ret;
2118
2119}
2120
Dean Lee72ed4dc2015-06-12 14:11:44 +09002121u16 Set_machw_change_vir_if(bool bValue)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09002122{
Chaehyun Limd85f5322015-06-11 14:35:54 +09002123 u16 ret;
Chaehyun Lim4e4467f2015-06-11 14:35:55 +09002124 u32 reg;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09002125
2126 /*Reset WILC_CHANGING_VIR_IF register to allow adding futrue keys to CE H/W*/
Greg Kroah-Hartman5e150b52015-09-03 19:32:11 -07002127 mutex_lock((&g_wlan)->hif_lock);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09002128 ret = (&g_wlan)->hif_func.hif_read_reg(WILC_CHANGING_VIR_IF, &reg);
2129 if (!ret) {
2130 PRINT_ER("Error while Reading reg WILC_CHANGING_VIR_IF\n");
2131 }
2132
Chandra S Gorentla78174ad2015-08-08 17:41:36 +05302133 if (bValue)
Chaehyun Lim50b51da2015-09-16 20:11:26 +09002134 reg |= BIT(31);
Chandra S Gorentla78174ad2015-08-08 17:41:36 +05302135 else
Chaehyun Lim50b51da2015-09-16 20:11:26 +09002136 reg &= ~BIT(31);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09002137
2138 ret = (&g_wlan)->hif_func.hif_write_reg(WILC_CHANGING_VIR_IF, reg);
2139
2140 if (!ret) {
2141 PRINT_ER("Error while writing reg WILC_CHANGING_VIR_IF\n");
2142 }
Greg Kroah-Hartman5e150b52015-09-03 19:32:11 -07002143 mutex_unlock((&g_wlan)->hif_lock);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09002144
2145 return ret;
2146}