blob: 5dcc4d21fa313bdd3895f241e8631f371e78f823 [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"
Tony Cho60bd1002015-10-12 16:56:04 +090011#include "wilc_wfi_netdevice.h"
Glen Lee17e8f162015-10-02 14:22:07 +090012#include "wilc_wlan_cfg.h"
Johnny Kimc5c77ba2015-05-11 14:30:56 +090013
14/********************************************
15 *
16 * Global
17 *
18 ********************************************/
Johnny Kimc5c77ba2015-05-11 14:30:56 +090019extern wilc_hif_func_t hif_sdio;
20extern wilc_hif_func_t hif_spi;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +090021u32 wilc_get_chipid(u8 update);
Johnny Kimc5c77ba2015-05-11 14:30:56 +090022
Johnny Kimc5c77ba2015-05-11 14:30:56 +090023
24
25typedef struct {
26 int quit;
27
28 /**
29 * input interface functions
30 **/
Johnny Kimc5c77ba2015-05-11 14:30:56 +090031 wilc_wlan_io_func_t io_func;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090032
33 /**
34 * host interface functions
35 **/
36 wilc_hif_func_t hif_func;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090037
38 /**
39 * configuration interface functions
40 **/
Johnny Kimc5c77ba2015-05-11 14:30:56 +090041 int cfg_frame_in_use;
42 wilc_cfg_frame_t cfg_frame;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +090043 u32 cfg_frame_offset;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090044 int cfg_seq_no;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090045
46 /**
47 * RX buffer
48 **/
49 #ifdef MEMORY_STATIC
Chaehyun Lim51e825f2015-09-15 14:06:14 +090050 u8 *rx_buffer;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +090051 u32 rx_buffer_offset;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090052 #endif
53 /**
54 * TX buffer
55 **/
Chaehyun Lim51e825f2015-09-15 14:06:14 +090056 u8 *tx_buffer;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +090057 u32 tx_buffer_offset;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090058
59 /**
60 * TX queue
61 **/
Johnny Kimc5c77ba2015-05-11 14:30:56 +090062
Johnny Kimc5c77ba2015-05-11 14:30:56 +090063 unsigned long txq_spinlock_flags;
64
65 struct txq_entry_t *txq_head;
66 struct txq_entry_t *txq_tail;
67 int txq_entries;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090068 int txq_exit;
69
70 /**
71 * RX queue
72 **/
Johnny Kimc5c77ba2015-05-11 14:30:56 +090073 struct rxq_entry_t *rxq_head;
74 struct rxq_entry_t *rxq_tail;
75 int rxq_entries;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090076 int rxq_exit;
77
78
79} wilc_wlan_dev_t;
80
81static wilc_wlan_dev_t g_wlan;
82
Chaehyun Lim9af382b2015-09-16 20:11:27 +090083static inline void chip_allow_sleep(void);
84static inline void chip_wakeup(void);
Johnny Kimc5c77ba2015-05-11 14:30:56 +090085/********************************************
86 *
87 * Debug
88 *
89 ********************************************/
90
Chaehyun Limfbc2fe12015-09-15 14:06:16 +090091static u32 dbgflag = N_INIT | N_ERR | N_INTR | N_TXQ | N_RXQ;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090092
Chaehyun Limfbc2fe12015-09-15 14:06:16 +090093static void wilc_debug(u32 flag, char *fmt, ...)
Johnny Kimc5c77ba2015-05-11 14:30:56 +090094{
95 char buf[256];
96 va_list args;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090097
98 if (flag & dbgflag) {
99 va_start(args, fmt);
Hari Prasath Gujulan Elango81053222015-06-22 13:13:58 +0000100 vsprintf(buf, fmt, args);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900101 va_end(args);
102
Glen Leeef2b7842015-09-24 18:14:55 +0900103 linux_wlan_dbg(buf);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900104 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900105}
106
107static CHIP_PS_STATE_T genuChipPSstate = CHIP_WAKEDUP;
108
Chaehyun Lim9af382b2015-09-16 20:11:27 +0900109/*acquire_bus() and release_bus() are made static inline functions*/
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900110/*as a temporary workaround to fix a problem of receiving*/
111/*unknown interrupt from FW*/
Chaehyun Lim9af382b2015-09-16 20:11:27 +0900112static inline void acquire_bus(BUS_ACQUIRE_T acquire)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900113{
114
Glen Lee187f1ef2015-09-24 18:15:01 +0900115 mutex_lock(&g_linux_wlan->hif_cs);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900116 #ifndef WILC_OPTIMIZE_SLEEP_INT
117 if (genuChipPSstate != CHIP_WAKEDUP)
118 #endif
119 {
120 if (acquire == ACQUIRE_AND_WAKEUP)
121 chip_wakeup();
122 }
123
124}
Chaehyun Lim9af382b2015-09-16 20:11:27 +0900125static inline void release_bus(BUS_RELEASE_T release)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900126{
127 #ifdef WILC_OPTIMIZE_SLEEP_INT
128 if (release == RELEASE_ALLOW_SLEEP)
129 chip_allow_sleep();
130 #endif
Glen Lee187f1ef2015-09-24 18:15:01 +0900131 mutex_unlock(&g_linux_wlan->hif_cs);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900132}
133/********************************************
134 *
135 * Queue
136 *
137 ********************************************/
138
139static void wilc_wlan_txq_remove(struct txq_entry_t *tqe)
140{
141
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +0530142 wilc_wlan_dev_t *p = &g_wlan;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900143 if (tqe == p->txq_head) {
144
145 p->txq_head = tqe->next;
146 if (p->txq_head)
147 p->txq_head->prev = NULL;
148
149
150 } else if (tqe == p->txq_tail) {
151 p->txq_tail = (tqe->prev);
152 if (p->txq_tail)
153 p->txq_tail->next = NULL;
154 } else {
155 tqe->prev->next = tqe->next;
156 tqe->next->prev = tqe->prev;
157 }
158 p->txq_entries -= 1;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900159
160}
161
Glen Lee718fc2c2015-10-29 12:18:43 +0900162static struct txq_entry_t *
163wilc_wlan_txq_remove_from_head(struct net_device *dev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900164{
165 struct txq_entry_t *tqe;
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +0530166 wilc_wlan_dev_t *p = &g_wlan;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900167 unsigned long flags;
Glen Lee718fc2c2015-10-29 12:18:43 +0900168 perInterface_wlan_t *nic;
169 struct wilc *wilc;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900170
Glen Lee718fc2c2015-10-29 12:18:43 +0900171 nic = netdev_priv(dev);
172 wilc = nic->wilc;
173
174 spin_lock_irqsave(&wilc->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900175 if (p->txq_head) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900176 tqe = p->txq_head;
177 p->txq_head = tqe->next;
Alison Schofield39823a52015-10-08 21:18:03 -0700178 if (p->txq_head)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900179 p->txq_head->prev = NULL;
Alison Schofield39823a52015-10-08 21:18:03 -0700180
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900181 p->txq_entries -= 1;
182
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900183
184
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900185
186 } else {
187 tqe = NULL;
188 }
Glen Lee718fc2c2015-10-29 12:18:43 +0900189 spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900190 return tqe;
191}
192
193static void wilc_wlan_txq_add_to_tail(struct txq_entry_t *tqe)
194{
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +0530195 wilc_wlan_dev_t *p = &g_wlan;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900196 unsigned long flags;
Glen Lee85e57562015-09-24 18:14:56 +0900197 spin_lock_irqsave(&g_linux_wlan->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900198
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900199 if (p->txq_head == NULL) {
200 tqe->next = NULL;
201 tqe->prev = NULL;
202 p->txq_head = tqe;
203 p->txq_tail = tqe;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900204 } else {
205 tqe->next = NULL;
206 tqe->prev = p->txq_tail;
207 p->txq_tail->next = tqe;
208 p->txq_tail = tqe;
209 }
210 p->txq_entries += 1;
211 PRINT_D(TX_DBG, "Number of entries in TxQ = %d\n", p->txq_entries);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900212
Glen Lee85e57562015-09-24 18:14:56 +0900213 spin_unlock_irqrestore(&g_linux_wlan->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900214
215 /**
216 * wake up TX queue
217 **/
218 PRINT_D(TX_DBG, "Wake the txq_handling\n");
219
Glen Lee5cd63632015-09-24 18:14:58 +0900220 up(&g_linux_wlan->txq_event);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900221}
222
223static int wilc_wlan_txq_add_to_head(struct txq_entry_t *tqe)
224{
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +0530225 wilc_wlan_dev_t *p = &g_wlan;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900226 unsigned long flags;
Glen Leeb002e202015-09-24 18:15:05 +0900227 if (linux_wlan_lock_timeout(&g_linux_wlan->txq_add_to_head_cs,
228 CFG_PKTS_TIMEOUT))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900229 return -1;
230
Glen Lee85e57562015-09-24 18:14:56 +0900231 spin_lock_irqsave(&g_linux_wlan->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900232
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900233 if (p->txq_head == NULL) {
234 tqe->next = NULL;
235 tqe->prev = NULL;
236 p->txq_head = tqe;
237 p->txq_tail = tqe;
238 } else {
239 tqe->next = p->txq_head;
240 tqe->prev = NULL;
241 p->txq_head->prev = tqe;
242 p->txq_head = tqe;
243 }
244 p->txq_entries += 1;
245 PRINT_D(TX_DBG, "Number of entries in TxQ = %d\n", p->txq_entries);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900246
Glen Lee85e57562015-09-24 18:14:56 +0900247 spin_unlock_irqrestore(&g_linux_wlan->txq_spinlock, flags);
Glen Leed5a63a82015-09-24 18:15:00 +0900248 up(&g_linux_wlan->txq_add_to_head_cs);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900249
250
251 /**
252 * wake up TX queue
253 **/
Glen Lee5cd63632015-09-24 18:14:58 +0900254 up(&g_linux_wlan->txq_event);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900255 PRINT_D(TX_DBG, "Wake up the txq_handler\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900256
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900257 return 0;
258
259}
260
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900261u32 Statisitcs_totalAcks = 0, Statisitcs_DroppedAcks = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900262
263#ifdef TCP_ACK_FILTER
264struct Ack_session_info;
Shraddha Barkeeeb1c062015-08-05 01:29:22 +0530265struct Ack_session_info {
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900266 u32 Ack_seq_num;
267 u32 Bigger_Ack_num;
Chaehyun Limec53adf2015-09-15 14:06:15 +0900268 u16 src_port;
269 u16 dst_port;
270 u16 status;
Shraddha Barkeeeb1c062015-08-05 01:29:22 +0530271};
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900272
273typedef struct {
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900274 u32 ack_num;
275 u32 Session_index;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900276 struct txq_entry_t *txqe;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900277} Pending_Acks_info_t /*Ack_info_t*/;
278
279
280
281
282struct Ack_session_info *Free_head;
283struct Ack_session_info *Alloc_head;
284
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900285#define NOT_TCP_ACK (-1)
286
287#define MAX_TCP_SESSION 25
288#define MAX_PENDING_ACKS 256
Shraddha Barkeeeb1c062015-08-05 01:29:22 +0530289struct Ack_session_info Acks_keep_track_info[2 * MAX_TCP_SESSION];
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900290Pending_Acks_info_t Pending_Acks_info[MAX_PENDING_ACKS];
291
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900292u32 PendingAcks_arrBase;
293u32 Opened_TCP_session;
294u32 Pending_Acks;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900295
296
297
Chaehyun Limfed16f22015-09-17 16:48:43 +0900298static inline int Init_TCP_tracking(void)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900299{
300
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900301 return 0;
302
303}
Chaehyun Limfed16f22015-09-17 16:48:43 +0900304static inline int add_TCP_track_session(u32 src_prt, u32 dst_prt, u32 seq)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900305{
306 Acks_keep_track_info[Opened_TCP_session].Ack_seq_num = seq;
307 Acks_keep_track_info[Opened_TCP_session].Bigger_Ack_num = 0;
308 Acks_keep_track_info[Opened_TCP_session].src_port = src_prt;
309 Acks_keep_track_info[Opened_TCP_session].dst_port = dst_prt;
310 Opened_TCP_session++;
311
312 PRINT_D(TCP_ENH, "TCP Session %d to Ack %d\n", Opened_TCP_session, seq);
313 return 0;
314}
315
Chaehyun Limfed16f22015-09-17 16:48:43 +0900316static inline int Update_TCP_track_session(u32 index, u32 Ack)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900317{
318
Alison Schofield39823a52015-10-08 21:18:03 -0700319 if (Ack > Acks_keep_track_info[index].Bigger_Ack_num)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900320 Acks_keep_track_info[index].Bigger_Ack_num = Ack;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900321 return 0;
322
323}
Chaehyun Limfed16f22015-09-17 16:48:43 +0900324static inline int add_TCP_Pending_Ack(u32 Ack, u32 Session_index, struct txq_entry_t *txqe)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900325{
326 Statisitcs_totalAcks++;
327 if (Pending_Acks < MAX_PENDING_ACKS) {
328 Pending_Acks_info[PendingAcks_arrBase + Pending_Acks].ack_num = Ack;
329 Pending_Acks_info[PendingAcks_arrBase + Pending_Acks].txqe = txqe;
330 Pending_Acks_info[PendingAcks_arrBase + Pending_Acks].Session_index = Session_index;
331 txqe->tcp_PendingAck_index = PendingAcks_arrBase + Pending_Acks;
332 Pending_Acks++;
333
334 } else {
335
336 }
337 return 0;
338}
Chaehyun Limfed16f22015-09-17 16:48:43 +0900339static inline int remove_TCP_related(void)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900340{
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +0530341 wilc_wlan_dev_t *p = &g_wlan;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900342 unsigned long flags;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900343
Glen Lee85e57562015-09-24 18:14:56 +0900344 spin_lock_irqsave(&g_linux_wlan->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900345
Glen Lee85e57562015-09-24 18:14:56 +0900346 spin_unlock_irqrestore(&g_linux_wlan->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900347 return 0;
348}
349
Glen Lee82bb18e2015-10-27 18:28:03 +0900350static inline int tcp_process(struct net_device *dev, struct txq_entry_t *tqe)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900351{
352 int ret;
Chaehyun Lim51e825f2015-09-15 14:06:14 +0900353 u8 *eth_hdr_ptr;
354 u8 *buffer = tqe->buffer;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900355 unsigned short h_proto;
356 int i;
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +0530357 wilc_wlan_dev_t *p = &g_wlan;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900358 unsigned long flags;
Glen Lee82bb18e2015-10-27 18:28:03 +0900359 perInterface_wlan_t *nic;
360 struct wilc *wilc;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900361
Glen Lee82bb18e2015-10-27 18:28:03 +0900362 nic = netdev_priv(dev);
363 wilc = nic->wilc;
364
365 spin_lock_irqsave(&wilc->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900366
367 eth_hdr_ptr = &buffer[0];
368 h_proto = ntohs(*((unsigned short *)&eth_hdr_ptr[12]));
369 if (h_proto == 0x0800) { /* IP */
Chaehyun Lim51e825f2015-09-15 14:06:14 +0900370 u8 *ip_hdr_ptr;
371 u8 protocol;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900372
373 ip_hdr_ptr = &buffer[ETHERNET_HDR_LEN];
374 protocol = ip_hdr_ptr[9];
375
376
377 if (protocol == 0x06) {
Chaehyun Lim51e825f2015-09-15 14:06:14 +0900378 u8 *tcp_hdr_ptr;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900379 u32 IHL, Total_Length, Data_offset;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900380
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900381 tcp_hdr_ptr = &ip_hdr_ptr[IP_HDR_LEN];
382 IHL = (ip_hdr_ptr[0] & 0xf) << 2;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900383 Total_Length = (((u32)ip_hdr_ptr[2]) << 8) + ((u32)ip_hdr_ptr[3]);
384 Data_offset = (((u32)tcp_hdr_ptr[12] & 0xf0) >> 2);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900385 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 +0900386 u32 seq_no, Ack_no;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900387
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900388 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 +0900389
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900390 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 +0900391
392
393 for (i = 0; i < Opened_TCP_session; i++) {
394 if (Acks_keep_track_info[i].Ack_seq_num == seq_no) {
395 Update_TCP_track_session(i, Ack_no);
396 break;
397 }
398 }
Alison Schofield39823a52015-10-08 21:18:03 -0700399 if (i == Opened_TCP_session)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900400 add_TCP_track_session(0, 0, seq_no);
Alison Schofield39823a52015-10-08 21:18:03 -0700401
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900402 add_TCP_Pending_Ack(Ack_no, i, tqe);
403
404
405 }
406
407 } else {
408 ret = 0;
409 }
410 } else {
411 ret = 0;
412 }
Glen Lee82bb18e2015-10-27 18:28:03 +0900413 spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900414 return ret;
415}
416
417
Glen Leec029e992015-10-27 18:27:48 +0900418static int wilc_wlan_txq_filter_dup_tcp_ack(struct net_device *dev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900419{
Glen Leec029e992015-10-27 18:27:48 +0900420 perInterface_wlan_t *nic;
421 struct wilc *wilc;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900422 u32 i = 0;
423 u32 Dropped = 0;
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +0530424 wilc_wlan_dev_t *p = &g_wlan;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900425
Glen Leec029e992015-10-27 18:27:48 +0900426 nic = netdev_priv(dev);
427 wilc = nic->wilc;
428
429 spin_lock_irqsave(&wilc->txq_spinlock, p->txq_spinlock_flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900430 for (i = PendingAcks_arrBase; i < (PendingAcks_arrBase + Pending_Acks); i++) {
431 if (Pending_Acks_info[i].ack_num < Acks_keep_track_info[Pending_Acks_info[i].Session_index].Bigger_Ack_num) {
432 struct txq_entry_t *tqe;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900433
Chandra S Gorentla17aacd42015-08-08 17:41:35 +0530434 PRINT_D(TCP_ENH, "DROP ACK: %u\n", Pending_Acks_info[i].ack_num);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900435 tqe = Pending_Acks_info[i].txqe;
436 if (tqe) {
437 wilc_wlan_txq_remove(tqe);
438 Statisitcs_DroppedAcks++;
439 tqe->status = 1; /* mark the packet send */
440 if (tqe->tx_complete_func)
441 tqe->tx_complete_func(tqe->priv, tqe->status);
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -0700442 kfree(tqe);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900443 Dropped++;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900444 }
445 }
446 }
447 Pending_Acks = 0;
448 Opened_TCP_session = 0;
449
Chandra S Gorentla78174ad2015-08-08 17:41:36 +0530450 if (PendingAcks_arrBase == 0)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900451 PendingAcks_arrBase = MAX_TCP_SESSION;
Chandra S Gorentla78174ad2015-08-08 17:41:36 +0530452 else
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900453 PendingAcks_arrBase = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900454
455
Glen Leec029e992015-10-27 18:27:48 +0900456 spin_unlock_irqrestore(&wilc->txq_spinlock, p->txq_spinlock_flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900457
458 while (Dropped > 0) {
459 /*consume the semaphore count of the removed packet*/
Glen Leec029e992015-10-27 18:27:48 +0900460 linux_wlan_lock_timeout(&wilc->txq_event, 1);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900461 Dropped--;
462 }
463
464 return 1;
465}
466#endif
467
Dean Lee72ed4dc2015-06-12 14:11:44 +0900468bool EnableTCPAckFilter = false;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900469
Dean Lee72ed4dc2015-06-12 14:11:44 +0900470void Enable_TCP_ACK_Filter(bool value)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900471{
472 EnableTCPAckFilter = value;
473}
474
Dean Lee72ed4dc2015-06-12 14:11:44 +0900475bool is_TCP_ACK_Filter_Enabled(void)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900476{
477 return EnableTCPAckFilter;
478}
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900479
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900480static int wilc_wlan_txq_add_cfg_pkt(u8 *buffer, u32 buffer_size)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900481{
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +0530482 wilc_wlan_dev_t *p = &g_wlan;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900483 struct txq_entry_t *tqe;
484
485 PRINT_D(TX_DBG, "Adding config packet ...\n");
486 if (p->quit) {
487 PRINT_D(TX_DBG, "Return due to clear function\n");
Glen Lee6a3b94f2015-09-24 18:14:59 +0900488 up(&g_linux_wlan->cfg_event);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900489 return 0;
490 }
491
Greg Kroah-Hartman47c632d2015-09-03 18:55:43 -0700492 tqe = kmalloc(sizeof(struct txq_entry_t), GFP_ATOMIC);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900493 if (tqe == NULL) {
494 PRINT_ER("Failed to allocate memory\n");
495 return 0;
496 }
497
498 tqe->type = WILC_CFG_PKT;
499 tqe->buffer = buffer;
500 tqe->buffer_size = buffer_size;
501 tqe->tx_complete_func = NULL;
502 tqe->priv = NULL;
503#ifdef TCP_ACK_FILTER
504 tqe->tcp_PendingAck_index = NOT_TCP_ACK;
505#endif
506 /**
507 * Configuration packet always at the front
508 **/
509 PRINT_D(TX_DBG, "Adding the config packet at the Queue tail\n");
510
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900511 if (wilc_wlan_txq_add_to_head(tqe))
512 return 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900513 return 1;
514}
515
Glen Lee691bbd42015-10-27 18:28:02 +0900516int wilc_wlan_txq_add_net_pkt(struct net_device *dev, void *priv, u8 *buffer,
517 u32 buffer_size, wilc_tx_complete_func_t func)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900518{
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +0530519 wilc_wlan_dev_t *p = &g_wlan;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900520 struct txq_entry_t *tqe;
521
522 if (p->quit)
523 return 0;
524
Greg Kroah-Hartman47c632d2015-09-03 18:55:43 -0700525 tqe = kmalloc(sizeof(struct txq_entry_t), GFP_ATOMIC);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900526
527 if (tqe == NULL)
528 return 0;
529 tqe->type = WILC_NET_PKT;
530 tqe->buffer = buffer;
531 tqe->buffer_size = buffer_size;
532 tqe->tx_complete_func = func;
533 tqe->priv = priv;
534
535 PRINT_D(TX_DBG, "Adding mgmt packet at the Queue tail\n");
536#ifdef TCP_ACK_FILTER
537 tqe->tcp_PendingAck_index = NOT_TCP_ACK;
Abdul Hussain5a66bf22015-06-16 09:44:06 +0000538 if (is_TCP_ACK_Filter_Enabled())
Glen Lee82bb18e2015-10-27 18:28:03 +0900539 tcp_process(dev, tqe);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900540#endif
541 wilc_wlan_txq_add_to_tail(tqe);
542 /*return number of itemes in the queue*/
543 return p->txq_entries;
544}
Glen Leefcc6ef92015-09-16 18:53:21 +0900545
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900546int 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 +0900547{
548
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +0530549 wilc_wlan_dev_t *p = &g_wlan;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900550 struct txq_entry_t *tqe;
551
552 if (p->quit)
553 return 0;
554
Greg Kroah-Hartman47c632d2015-09-03 18:55:43 -0700555 tqe = kmalloc(sizeof(struct txq_entry_t), GFP_KERNEL);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900556
557 if (tqe == NULL)
558 return 0;
559 tqe->type = WILC_MGMT_PKT;
560 tqe->buffer = buffer;
561 tqe->buffer_size = buffer_size;
562 tqe->tx_complete_func = func;
563 tqe->priv = priv;
564#ifdef TCP_ACK_FILTER
565 tqe->tcp_PendingAck_index = NOT_TCP_ACK;
566#endif
567 PRINT_D(TX_DBG, "Adding Network packet at the Queue tail\n");
568 wilc_wlan_txq_add_to_tail(tqe);
569 return 1;
570}
Glen Leefcc6ef92015-09-16 18:53:21 +0900571
Glen Lee7af05222015-10-29 12:18:41 +0900572static struct txq_entry_t *wilc_wlan_txq_get_first(struct wilc *wilc)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900573{
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +0530574 wilc_wlan_dev_t *p = &g_wlan;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900575 struct txq_entry_t *tqe;
576 unsigned long flags;
577
Glen Lee7af05222015-10-29 12:18:41 +0900578 spin_lock_irqsave(&wilc->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900579
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900580 tqe = p->txq_head;
581
Glen Lee7af05222015-10-29 12:18:41 +0900582 spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900583
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900584
585 return tqe;
586}
587
Glen Lee50a0b3b2015-10-27 18:28:00 +0900588static struct txq_entry_t *wilc_wlan_txq_get_next(struct wilc *wilc,
589 struct txq_entry_t *tqe)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900590{
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900591 unsigned long flags;
Glen Lee50a0b3b2015-10-27 18:28:00 +0900592 spin_lock_irqsave(&wilc->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900593
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900594 tqe = tqe->next;
Glen Lee50a0b3b2015-10-27 18:28:00 +0900595 spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900596
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900597
598 return tqe;
599}
600
Glen Leed06f3622015-10-27 18:27:59 +0900601static int wilc_wlan_rxq_add(struct wilc *wilc, struct rxq_entry_t *rqe)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900602{
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +0530603 wilc_wlan_dev_t *p = &g_wlan;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900604
605 if (p->quit)
606 return 0;
607
Glen Leed06f3622015-10-27 18:27:59 +0900608 mutex_lock(&wilc->rxq_cs);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900609 if (p->rxq_head == NULL) {
610 PRINT_D(RX_DBG, "Add to Queue head\n");
611 rqe->next = NULL;
612 p->rxq_head = rqe;
613 p->rxq_tail = rqe;
614 } else {
615 PRINT_D(RX_DBG, "Add to Queue tail\n");
616 p->rxq_tail->next = rqe;
617 rqe->next = NULL;
618 p->rxq_tail = rqe;
619 }
620 p->rxq_entries += 1;
621 PRINT_D(RX_DBG, "Number of queue entries: %d\n", p->rxq_entries);
Glen Leed06f3622015-10-27 18:27:59 +0900622 mutex_unlock(&wilc->rxq_cs);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900623 return p->rxq_entries;
624}
625
Glen Leedb387632015-10-27 18:27:55 +0900626static struct rxq_entry_t *wilc_wlan_rxq_remove(struct wilc *wilc)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900627{
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +0530628 wilc_wlan_dev_t *p = &g_wlan;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900629
630 PRINT_D(RX_DBG, "Getting rxQ element\n");
631 if (p->rxq_head) {
632 struct rxq_entry_t *rqe;
633
Glen Leedb387632015-10-27 18:27:55 +0900634 mutex_lock(&wilc->rxq_cs);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900635 rqe = p->rxq_head;
636 p->rxq_head = p->rxq_head->next;
637 p->rxq_entries -= 1;
638 PRINT_D(RX_DBG, "RXQ entries decreased\n");
Glen Leedb387632015-10-27 18:27:55 +0900639 mutex_unlock(&wilc->rxq_cs);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900640 return rqe;
641 }
642 PRINT_D(RX_DBG, "Nothing to get from Q\n");
643 return NULL;
644}
645
646
647/********************************************
648 *
649 * Power Save handle functions
650 *
651 ********************************************/
652
653
654
655#ifdef WILC_OPTIMIZE_SLEEP_INT
656
Chaehyun Lim9af382b2015-09-16 20:11:27 +0900657static inline void chip_allow_sleep(void)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900658{
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900659 u32 reg = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900660
661 /* Clear bit 1 */
662 g_wlan.hif_func.hif_read_reg(0xf0, &reg);
663
Anish Bhattffda2032015-09-29 12:15:49 -0700664 g_wlan.hif_func.hif_write_reg(0xf0, reg & ~BIT(0));
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900665}
666
Chaehyun Lim9af382b2015-09-16 20:11:27 +0900667static inline void chip_wakeup(void)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900668{
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900669 u32 reg, clk_status_reg, trials = 0;
670 u32 sleep_time;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900671
672 if ((g_wlan.io_func.io_type & 0x1) == HIF_SPI) {
673 do {
674 g_wlan.hif_func.hif_read_reg(1, &reg);
675 /* Set bit 1 */
Anish Bhattffda2032015-09-29 12:15:49 -0700676 g_wlan.hif_func.hif_write_reg(1, reg | BIT(1));
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900677
678 /* Clear bit 1*/
Anish Bhattffda2032015-09-29 12:15:49 -0700679 g_wlan.hif_func.hif_write_reg(1, reg & ~BIT(1));
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900680
681 do {
682 /* Wait for the chip to stabilize*/
Greg Kroah-Hartman80e29c72015-08-14 19:42:23 -0700683 usleep_range(2 * 1000, 2 * 1000);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900684 /* Make sure chip is awake. This is an extra step that can be removed */
685 /* later to avoid the bus access overhead */
Alison Schofield39823a52015-10-08 21:18:03 -0700686 if ((wilc_get_chipid(true) == 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900687 wilc_debug(N_ERR, "Couldn't read chip id. Wake up failed\n");
Alison Schofield39823a52015-10-08 21:18:03 -0700688
Dean Lee72ed4dc2015-06-12 14:11:44 +0900689 } while ((wilc_get_chipid(true) == 0) && ((++trials % 3) == 0));
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900690
Dean Lee72ed4dc2015-06-12 14:11:44 +0900691 } while (wilc_get_chipid(true) == 0);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900692 } else if ((g_wlan.io_func.io_type & 0x1) == HIF_SDIO) {
693 g_wlan.hif_func.hif_read_reg(0xf0, &reg);
694 do {
695 /* Set bit 1 */
Anish Bhattffda2032015-09-29 12:15:49 -0700696 g_wlan.hif_func.hif_write_reg(0xf0, reg | BIT(0));
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900697
698 /* Check the clock status */
699 g_wlan.hif_func.hif_read_reg(0xf1, &clk_status_reg);
700
701 /* in case of clocks off, wait 2ms, and check it again. */
702 /* if still off, wait for another 2ms, for a total wait of 6ms. */
703 /* If still off, redo the wake up sequence */
704 while (((clk_status_reg & 0x1) == 0) && (((++trials) % 3) == 0)) {
705 /* Wait for the chip to stabilize*/
Greg Kroah-Hartman80e29c72015-08-14 19:42:23 -0700706 usleep_range(2 * 1000, 2 * 1000);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900707
708 /* Make sure chip is awake. This is an extra step that can be removed */
709 /* later to avoid the bus access overhead */
710 g_wlan.hif_func.hif_read_reg(0xf1, &clk_status_reg);
711
Alison Schofield39823a52015-10-08 21:18:03 -0700712 if ((clk_status_reg & 0x1) == 0)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900713 wilc_debug(N_ERR, "clocks still OFF. Wake up failed\n");
Alison Schofield39823a52015-10-08 21:18:03 -0700714
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900715 }
716 /* in case of failure, Reset the wakeup bit to introduce a new edge on the next loop */
717 if ((clk_status_reg & 0x1) == 0) {
718 /* Reset bit 0 */
Anish Bhattffda2032015-09-29 12:15:49 -0700719 g_wlan.hif_func.hif_write_reg(0xf0, reg &
720 (~BIT(0)));
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900721 }
722 } while ((clk_status_reg & 0x1) == 0);
723 }
724
725
726 if (genuChipPSstate == CHIP_SLEEPING_MANUAL) {
727 g_wlan.hif_func.hif_read_reg(0x1C0C, &reg);
Anish Bhattffda2032015-09-29 12:15:49 -0700728 reg &= ~BIT(0);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900729 g_wlan.hif_func.hif_write_reg(0x1C0C, reg);
730
Dean Lee72ed4dc2015-06-12 14:11:44 +0900731 if (wilc_get_chipid(false) >= 0x1002b0) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900732 /* Enable PALDO back right after wakeup */
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900733 u32 val32;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900734
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900735 g_wlan.hif_func.hif_read_reg(0x1e1c, &val32);
Anish Bhattffda2032015-09-29 12:15:49 -0700736 val32 |= BIT(6);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900737 g_wlan.hif_func.hif_write_reg(0x1e1c, val32);
738
739 g_wlan.hif_func.hif_read_reg(0x1e9c, &val32);
Anish Bhattffda2032015-09-29 12:15:49 -0700740 val32 |= BIT(6);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900741 g_wlan.hif_func.hif_write_reg(0x1e9c, val32);
742 }
743 }
744 genuChipPSstate = CHIP_WAKEDUP;
745}
746#else
Chaehyun Lim9af382b2015-09-16 20:11:27 +0900747static inline void chip_wakeup(void)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900748{
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900749 u32 reg, trials = 0;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900750
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900751 do {
752 if ((g_wlan.io_func.io_type & 0x1) == HIF_SPI) {
753 g_wlan.hif_func.hif_read_reg(1, &reg);
754 /* Make sure bit 1 is 0 before we start. */
Anish Bhattffda2032015-09-29 12:15:49 -0700755 g_wlan.hif_func.hif_write_reg(1, reg & ~BIT(1));
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900756 /* Set bit 1 */
Anish Bhattffda2032015-09-29 12:15:49 -0700757 g_wlan.hif_func.hif_write_reg(1, reg | BIT(1));
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900758 /* Clear bit 1*/
Anish Bhattffda2032015-09-29 12:15:49 -0700759 g_wlan.hif_func.hif_write_reg(1, reg & ~BIT(1));
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900760 } else if ((g_wlan.io_func.io_type & 0x1) == HIF_SDIO) {
761 /* Make sure bit 0 is 0 before we start. */
762 g_wlan.hif_func.hif_read_reg(0xf0, &reg);
Anish Bhattffda2032015-09-29 12:15:49 -0700763 g_wlan.hif_func.hif_write_reg(0xf0, reg & ~BIT(0));
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900764 /* Set bit 1 */
Anish Bhattffda2032015-09-29 12:15:49 -0700765 g_wlan.hif_func.hif_write_reg(0xf0, reg | BIT(0));
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900766 /* Clear bit 1 */
Anish Bhattffda2032015-09-29 12:15:49 -0700767 g_wlan.hif_func.hif_write_reg(0xf0, reg & ~BIT(0));
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900768 }
769
770 do {
771 /* Wait for the chip to stabilize*/
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900772 mdelay(3);
773
774 /* Make sure chip is awake. This is an extra step that can be removed */
775 /* later to avoid the bus access overhead */
Alison Schofield39823a52015-10-08 21:18:03 -0700776 if ((wilc_get_chipid(true) == 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900777 wilc_debug(N_ERR, "Couldn't read chip id. Wake up failed\n");
Alison Schofield39823a52015-10-08 21:18:03 -0700778
Dean Lee72ed4dc2015-06-12 14:11:44 +0900779 } while ((wilc_get_chipid(true) == 0) && ((++trials % 3) == 0));
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900780
Dean Lee72ed4dc2015-06-12 14:11:44 +0900781 } while (wilc_get_chipid(true) == 0);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900782
783 if (genuChipPSstate == CHIP_SLEEPING_MANUAL) {
784 g_wlan.hif_func.hif_read_reg(0x1C0C, &reg);
Anish Bhattffda2032015-09-29 12:15:49 -0700785 reg &= ~BIT(0);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900786 g_wlan.hif_func.hif_write_reg(0x1C0C, reg);
787
Dean Lee72ed4dc2015-06-12 14:11:44 +0900788 if (wilc_get_chipid(false) >= 0x1002b0) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900789 /* Enable PALDO back right after wakeup */
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900790 u32 val32;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900791
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900792 g_wlan.hif_func.hif_read_reg(0x1e1c, &val32);
Anish Bhattffda2032015-09-29 12:15:49 -0700793 val32 |= BIT(6);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900794 g_wlan.hif_func.hif_write_reg(0x1e1c, val32);
795
796 g_wlan.hif_func.hif_read_reg(0x1e9c, &val32);
Anish Bhattffda2032015-09-29 12:15:49 -0700797 val32 |= BIT(6);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900798 g_wlan.hif_func.hif_write_reg(0x1e9c, val32);
799 }
800 }
801 genuChipPSstate = CHIP_WAKEDUP;
802}
803#endif
Chaehyun Lim4e4467f2015-06-11 14:35:55 +0900804void chip_sleep_manually(u32 u32SleepTime)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900805{
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900806 if (genuChipPSstate != CHIP_WAKEDUP) {
807 /* chip is already sleeping. Do nothing */
808 return;
809 }
810 acquire_bus(ACQUIRE_ONLY);
811
812#ifdef WILC_OPTIMIZE_SLEEP_INT
813 chip_allow_sleep();
814#endif
815
816 /* Trigger the manual sleep interrupt */
817 g_wlan.hif_func.hif_write_reg(0x10a8, 1);
818
819 genuChipPSstate = CHIP_SLEEPING_MANUAL;
820 release_bus(RELEASE_ONLY);
821
822}
823
824
825/********************************************
826 *
827 * Tx, Rx queue handle functions
828 *
829 ********************************************/
Glen Leea1332ca2015-10-27 18:27:47 +0900830int wilc_wlan_handle_txq(struct net_device *dev, u32 *pu32TxqCount)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900831{
832 wilc_wlan_dev_t *p = (wilc_wlan_dev_t *)&g_wlan;
833 int i, entries = 0;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900834 u32 sum;
835 u32 reg;
Chaehyun Lim51e825f2015-09-15 14:06:14 +0900836 u8 *txb = p->tx_buffer;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900837 u32 offset = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900838 int vmm_sz = 0;
839 struct txq_entry_t *tqe;
840 int ret = 0;
841 int counter;
842 int timeout;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900843 u32 vmm_table[WILC_VMM_TBL_SIZE];
Glen Leea1332ca2015-10-27 18:27:47 +0900844 perInterface_wlan_t *nic;
845 struct wilc *wilc;
846
847 nic = netdev_priv(dev);
848 wilc = nic->wilc;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900849
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900850 p->txq_exit = 0;
851 do {
852 if (p->quit)
853 break;
854
Glen Leea1332ca2015-10-27 18:27:47 +0900855 linux_wlan_lock_timeout(&wilc->txq_add_to_head_cs,
Glen Leeb002e202015-09-24 18:15:05 +0900856 CFG_PKTS_TIMEOUT);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900857#ifdef TCP_ACK_FILTER
Glen Leec029e992015-10-27 18:27:48 +0900858 wilc_wlan_txq_filter_dup_tcp_ack(dev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900859#endif
860 /**
861 * build the vmm list
862 **/
863 PRINT_D(TX_DBG, "Getting the head of the TxQ\n");
Glen Lee7af05222015-10-29 12:18:41 +0900864 tqe = wilc_wlan_txq_get_first(wilc);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900865 i = 0;
866 sum = 0;
867 do {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900868 if ((tqe != NULL) && (i < (WILC_VMM_TBL_SIZE - 1)) /* reserve last entry to 0 */) {
869
Alison Schofield39823a52015-10-08 21:18:03 -0700870 if (tqe->type == WILC_CFG_PKT)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900871 vmm_sz = ETH_CONFIG_PKT_HDR_OFFSET;
Alison Schofield39823a52015-10-08 21:18:03 -0700872
873 else if (tqe->type == WILC_NET_PKT)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900874 vmm_sz = ETH_ETHERNET_HDR_OFFSET;
Alison Schofield39823a52015-10-08 21:18:03 -0700875
876 else
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900877 vmm_sz = HOST_HDR_OFFSET;
Alison Schofield39823a52015-10-08 21:18:03 -0700878
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900879 vmm_sz += tqe->buffer_size;
880 PRINT_D(TX_DBG, "VMM Size before alignment = %d\n", vmm_sz);
881 if (vmm_sz & 0x3) { /* has to be word aligned */
882 vmm_sz = (vmm_sz + 4) & ~0x3;
883 }
Alison Schofield39823a52015-10-08 21:18:03 -0700884 if ((sum + vmm_sz) > LINUX_TX_SIZE)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900885 break;
Alison Schofield39823a52015-10-08 21:18:03 -0700886
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900887 PRINT_D(TX_DBG, "VMM Size AFTER alignment = %d\n", vmm_sz);
888 vmm_table[i] = vmm_sz / 4; /* table take the word size */
889 PRINT_D(TX_DBG, "VMMTable entry size = %d\n", vmm_table[i]);
890
891 if (tqe->type == WILC_CFG_PKT) {
Anish Bhattffda2032015-09-29 12:15:49 -0700892 vmm_table[i] |= BIT(10);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900893 PRINT_D(TX_DBG, "VMMTable entry changed for CFG packet = %d\n", vmm_table[i]);
894 }
895#ifdef BIG_ENDIAN
896 vmm_table[i] = BYTE_SWAP(vmm_table[i]);
897#endif
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900898
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900899 i++;
900 sum += vmm_sz;
901 PRINT_D(TX_DBG, "sum = %d\n", sum);
Glen Lee50a0b3b2015-10-27 18:28:00 +0900902 tqe = wilc_wlan_txq_get_next(wilc, tqe);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900903 } else {
904 break;
905 }
906 } while (1);
907
908 if (i == 0) { /* nothing in the queue */
909 PRINT_D(TX_DBG, "Nothing in TX-Q\n");
910 break;
911 } else {
912 PRINT_D(TX_DBG, "Mark the last entry in VMM table - number of previous entries = %d\n", i);
913 vmm_table[i] = 0x0; /* mark the last element to 0 */
914 }
915 acquire_bus(ACQUIRE_AND_WAKEUP);
916 counter = 0;
917 do {
918
919 ret = p->hif_func.hif_read_reg(WILC_HOST_TX_CTRL, &reg);
920 if (!ret) {
921 wilc_debug(N_ERR, "[wilc txq]: fail can't read reg vmm_tbl_entry..\n");
922 break;
923 }
924
925 if ((reg & 0x1) == 0) {
926 /**
927 * write to vmm table
928 **/
929 PRINT_D(TX_DBG, "Writing VMM table ... with Size = %d\n", ((i + 1) * 4));
930 break;
931 } else {
932 counter++;
933 if (counter > 200) {
934 counter = 0;
935 PRINT_D(TX_DBG, "Looping in tx ctrl , forcce quit\n");
936 ret = p->hif_func.hif_write_reg(WILC_HOST_TX_CTRL, 0);
937 break;
938 }
939 /**
940 * wait for vmm table is ready
941 **/
Chandra S Gorentla17aacd42015-08-08 17:41:35 +0530942 PRINT_WRN(GENERIC_DBG, "[wilc txq]: warn, vmm table not clear yet, wait...\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900943 release_bus(RELEASE_ALLOW_SLEEP);
Greg Kroah-Hartman2b922cb2015-09-04 09:30:51 -0700944 usleep_range(3000, 3000);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900945 acquire_bus(ACQUIRE_AND_WAKEUP);
946 }
947 } while (!p->quit);
948
Alison Schofield39823a52015-10-08 21:18:03 -0700949 if (!ret)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900950 goto _end_;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900951
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);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900989 break;
990 } else {
991 release_bus(RELEASE_ALLOW_SLEEP);
Greg Kroah-Hartman2b922cb2015-09-04 09:30:51 -0700992 usleep_range(3000, 3000);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900993 acquire_bus(ACQUIRE_AND_WAKEUP);
994 PRINT_WRN(GENERIC_DBG, "Can't get VMM entery - reg = %2x\n", reg);
995 }
996 } while (--timeout);
997 if (timeout <= 0) {
998 ret = p->hif_func.hif_write_reg(WILC_HOST_VMM_CTL, 0x0);
999 break;
1000 }
1001
Alison Schofield39823a52015-10-08 21:18:03 -07001002 if (!ret)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001003 break;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001004
1005 if (entries == 0) {
Chandra S Gorentla17aacd42015-08-08 17:41:35 +05301006 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 +09001007
1008 /* undo the transaction. */
1009 ret = p->hif_func.hif_read_reg(WILC_HOST_TX_CTRL, &reg);
1010 if (!ret) {
1011 wilc_debug(N_ERR, "[wilc txq]: fail can't read reg WILC_HOST_TX_CTRL..\n");
1012 break;
1013 }
Anish Bhattffda2032015-09-29 12:15:49 -07001014 reg &= ~BIT(0);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001015 ret = p->hif_func.hif_write_reg(WILC_HOST_TX_CTRL, reg);
1016 if (!ret) {
1017 wilc_debug(N_ERR, "[wilc txq]: fail can't write reg WILC_HOST_TX_CTRL..\n");
1018 break;
1019 }
1020 break;
1021 } else {
1022 break;
1023 }
1024 } while (1);
1025
Alison Schofield39823a52015-10-08 21:18:03 -07001026 if (!ret)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001027 goto _end_;
Alison Schofield39823a52015-10-08 21:18:03 -07001028
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001029 if (entries == 0) {
1030 ret = WILC_TX_ERR_NO_BUF;
1031 goto _end_;
1032 }
1033
1034 /* since copying data into txb takes some time, then
1035 * allow the bus lock to be released let the RX task go. */
1036 release_bus(RELEASE_ALLOW_SLEEP);
1037
1038 /**
1039 * Copy data to the TX buffer
1040 **/
1041 offset = 0;
1042 i = 0;
1043 do {
Glen Lee718fc2c2015-10-29 12:18:43 +09001044 tqe = wilc_wlan_txq_remove_from_head(dev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001045 if (tqe != NULL && (vmm_table[i] != 0)) {
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001046 u32 header, buffer_offset;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001047
1048#ifdef BIG_ENDIAN
1049 vmm_table[i] = BYTE_SWAP(vmm_table[i]);
1050#endif
1051 vmm_sz = (vmm_table[i] & 0x3ff); /* in word unit */
1052 vmm_sz *= 4;
1053 header = (tqe->type << 31) | (tqe->buffer_size << 15) | vmm_sz;
Chandra S Gorentla78174ad2015-08-08 17:41:36 +05301054 if (tqe->type == WILC_MGMT_PKT)
Anish Bhattffda2032015-09-29 12:15:49 -07001055 header |= BIT(30);
Chandra S Gorentla78174ad2015-08-08 17:41:36 +05301056 else
Anish Bhattffda2032015-09-29 12:15:49 -07001057 header &= ~BIT(30);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001058
1059#ifdef BIG_ENDIAN
1060 header = BYTE_SWAP(header);
1061#endif
1062 memcpy(&txb[offset], &header, 4);
1063 if (tqe->type == WILC_CFG_PKT) {
1064 buffer_offset = ETH_CONFIG_PKT_HDR_OFFSET;
1065 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001066 else if (tqe->type == WILC_NET_PKT) {
1067 char *pBSSID = ((struct tx_complete_data *)(tqe->priv))->pBssid;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +09001068
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001069 buffer_offset = ETH_ETHERNET_HDR_OFFSET;
1070 /* copy the bssid at the sart of the buffer */
1071 memcpy(&txb[offset + 4], pBSSID, 6);
1072 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001073 else {
1074 buffer_offset = HOST_HDR_OFFSET;
1075 }
1076
1077 memcpy(&txb[offset + buffer_offset], tqe->buffer, tqe->buffer_size);
1078 offset += vmm_sz;
1079 i++;
1080 tqe->status = 1; /* mark the packet send */
1081 if (tqe->tx_complete_func)
1082 tqe->tx_complete_func(tqe->priv, tqe->status);
1083 #ifdef TCP_ACK_FILTER
Alison Schofield39823a52015-10-08 21:18:03 -07001084 if (tqe->tcp_PendingAck_index != NOT_TCP_ACK)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001085 Pending_Acks_info[tqe->tcp_PendingAck_index].txqe = NULL;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001086 #endif
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -07001087 kfree(tqe);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001088 } else {
1089 break;
1090 }
1091 } while (--entries);
1092
1093 /**
1094 * lock the bus
1095 **/
1096 acquire_bus(ACQUIRE_AND_WAKEUP);
1097
1098 ret = p->hif_func.hif_clear_int_ext(ENABLE_TX_VMM);
1099 if (!ret) {
1100 wilc_debug(N_ERR, "[wilc txq]: fail can't start tx VMM ...\n");
1101 goto _end_;
1102 }
1103
1104 /**
1105 * transfer
1106 **/
1107 ret = p->hif_func.hif_block_tx_ext(0, txb, offset);
1108 if (!ret) {
1109 wilc_debug(N_ERR, "[wilc txq]: fail can't block tx ext...\n");
1110 goto _end_;
1111 }
1112
1113_end_:
1114
1115 release_bus(RELEASE_ALLOW_SLEEP);
1116 if (ret != 1)
1117 break;
1118 } while (0);
Glen Leea1332ca2015-10-27 18:27:47 +09001119 up(&wilc->txq_add_to_head_cs);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001120
1121 p->txq_exit = 1;
1122 PRINT_D(TX_DBG, "THREAD: Exiting txq\n");
1123 /* return tx[]q count */
1124 *pu32TxqCount = p->txq_entries;
1125 return ret;
1126}
1127
Glen Lee39ce4d32015-10-27 18:27:42 +09001128static void wilc_wlan_handle_rxq(struct wilc *wilc)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001129{
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +05301130 wilc_wlan_dev_t *p = &g_wlan;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001131 int offset = 0, size, has_packet = 0;
Chaehyun Lim51e825f2015-09-15 14:06:14 +09001132 u8 *buffer;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001133 struct rxq_entry_t *rqe;
1134
1135 p->rxq_exit = 0;
1136
1137
1138
1139
1140 do {
1141 if (p->quit) {
Chandra S Gorentla17aacd42015-08-08 17:41:35 +05301142 PRINT_D(RX_DBG, "exit 1st do-while due to Clean_UP function\n");
Glen Lee39ce4d32015-10-27 18:27:42 +09001143 up(&wilc->cfg_event);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001144 break;
1145 }
Glen Leedb387632015-10-27 18:27:55 +09001146 rqe = wilc_wlan_rxq_remove(wilc);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001147 if (rqe == NULL) {
1148 PRINT_D(RX_DBG, "nothing in the queue - exit 1st do-while\n");
1149 break;
1150 }
1151 buffer = rqe->buffer;
1152 size = rqe->buffer_size;
1153 PRINT_D(RX_DBG, "rxQ entery Size = %d - Address = %p\n", size, buffer);
1154 offset = 0;
1155
1156
1157
1158 do {
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001159 u32 header;
1160 u32 pkt_len, pkt_offset, tp_len;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001161 int is_cfg_packet;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +09001162
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001163 PRINT_D(RX_DBG, "In the 2nd do-while\n");
1164 memcpy(&header, &buffer[offset], 4);
1165#ifdef BIG_ENDIAN
1166 header = BYTE_SWAP(header);
1167#endif
1168 PRINT_D(RX_DBG, "Header = %04x - Offset = %d\n", header, offset);
1169
1170
1171
1172 is_cfg_packet = (header >> 31) & 0x1;
1173 pkt_offset = (header >> 22) & 0x1ff;
1174 tp_len = (header >> 11) & 0x7ff;
1175 pkt_len = header & 0x7ff;
1176
1177 if (pkt_len == 0 || tp_len == 0) {
1178 wilc_debug(N_RXQ, "[wilc rxq]: data corrupt, packet len or tp_len is 0 [%d][%d]\n", pkt_len, tp_len);
1179 break;
1180 }
1181
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001182 #define IS_MANAGMEMENT 0x100
1183 #define IS_MANAGMEMENT_CALLBACK 0x080
1184 #define IS_MGMT_STATUS_SUCCES 0x040
1185
1186
1187 if (pkt_offset & IS_MANAGMEMENT) {
1188 /* reset mgmt indicator bit, to use pkt_offeset in furthur calculations */
1189 pkt_offset &= ~(IS_MANAGMEMENT | IS_MANAGMEMENT_CALLBACK | IS_MGMT_STATUS_SUCCES);
1190
Glen Lee11f4b2e2015-10-27 18:27:51 +09001191 WILC_WFI_mgmt_rx(wilc, &buffer[offset + HOST_HDR_OFFSET], pkt_len);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001192 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001193 else
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001194 {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001195
1196 if (!is_cfg_packet) {
Glen Lee63611672015-09-24 18:14:52 +09001197 if (pkt_len > 0) {
Glen Leecb1991a2015-10-27 18:27:56 +09001198 frmw_to_linux(wilc,
1199 &buffer[offset],
Glen Lee63611672015-09-24 18:14:52 +09001200 pkt_len,
1201 pkt_offset);
1202 has_packet = 1;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001203 }
1204 } else {
1205 wilc_cfg_rsp_t rsp;
1206
1207
1208
Glen Lee30f535a2015-10-02 14:22:10 +09001209 wilc_wlan_cfg_indicate_rx(&buffer[pkt_offset + offset], pkt_len, &rsp);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001210 if (rsp.type == WILC_CFG_RSP) {
1211 /**
1212 * wake up the waiting task...
1213 **/
1214 PRINT_D(RX_DBG, "p->cfg_seq_no = %d - rsp.seq_no = %d\n", p->cfg_seq_no, rsp.seq_no);
Alison Schofield39823a52015-10-08 21:18:03 -07001215 if (p->cfg_seq_no == rsp.seq_no)
Glen Lee39ce4d32015-10-27 18:27:42 +09001216 up(&wilc->cfg_event);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001217 } else if (rsp.type == WILC_CFG_RSP_STATUS) {
1218 /**
1219 * Call back to indicate status...
1220 **/
Glen Lee64f2b712015-10-27 18:27:43 +09001221 linux_wlan_mac_indicate(wilc, WILC_MAC_INDICATE_STATUS);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001222
1223 } else if (rsp.type == WILC_CFG_RSP_SCAN) {
Glen Lee64f2b712015-10-27 18:27:43 +09001224 linux_wlan_mac_indicate(wilc, WILC_MAC_INDICATE_SCAN);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001225 }
1226 }
1227 }
1228 offset += tp_len;
1229 if (offset >= size)
1230 break;
1231 } while (1);
1232
1233
1234#ifndef MEMORY_STATIC
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -07001235 kfree(buffer);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001236#endif
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -07001237 kfree(rqe);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001238
Alison Schofield39823a52015-10-08 21:18:03 -07001239 if (has_packet)
Glen Leec0cadaa2015-09-24 18:14:54 +09001240 linux_wlan_rx_complete();
Alison Schofield39823a52015-10-08 21:18:03 -07001241
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001242 } while (1);
1243
1244 p->rxq_exit = 1;
Chandra S Gorentla17aacd42015-08-08 17:41:35 +05301245 PRINT_D(RX_DBG, "THREAD: Exiting RX thread\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001246}
1247
1248/********************************************
1249 *
1250 * Fast DMA Isr
1251 *
1252 ********************************************/
1253static void wilc_unknown_isr_ext(void)
1254{
1255 g_wlan.hif_func.hif_clear_int_ext(0);
1256}
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001257static void wilc_pllupdate_isr_ext(u32 int_stats)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001258{
1259
1260 int trials = 10;
1261
1262 g_wlan.hif_func.hif_clear_int_ext(PLL_INT_CLR);
1263
1264 /* Waiting for PLL */
Greg Kroah-Hartmanc2e4c0f2015-09-03 19:09:50 -07001265 mdelay(WILC_PLL_TO);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001266
1267 /* poll till read a valid data */
Dean Lee72ed4dc2015-06-12 14:11:44 +09001268 while (!(ISWILC1000(wilc_get_chipid(true)) && --trials)) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001269 PRINT_D(TX_DBG, "PLL update retrying\n");
Greg Kroah-Hartmanc2e4c0f2015-09-03 19:09:50 -07001270 mdelay(1);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001271 }
1272}
1273
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001274static void wilc_sleeptimer_isr_ext(u32 int_stats1)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001275{
1276 g_wlan.hif_func.hif_clear_int_ext(SLEEP_INT_CLR);
1277#ifndef WILC_OPTIMIZE_SLEEP_INT
1278 genuChipPSstate = CHIP_SLEEPING_AUTO;
1279#endif
1280}
1281
Glen Lee3bcd45b2015-10-27 18:27:41 +09001282static void wilc_wlan_handle_isr_ext(struct wilc *wilc, u32 int_status)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001283{
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +05301284 wilc_wlan_dev_t *p = &g_wlan;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001285#ifdef MEMORY_STATIC
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001286 u32 offset = p->rx_buffer_offset;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001287#endif
Chaehyun Lim51e825f2015-09-15 14:06:14 +09001288 u8 *buffer = NULL;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001289 u32 size;
1290 u32 retries = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001291 int ret = 0;
1292 struct rxq_entry_t *rqe;
1293
1294
1295 /**
1296 * Get the rx size
1297 **/
1298
1299 size = ((int_status & 0x7fff) << 2);
1300
1301 while (!size && retries < 10) {
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001302 u32 time = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001303 /*looping more secure*/
1304 /*zero size make a crashe because the dma will not happen and that will block the firmware*/
1305 wilc_debug(N_ERR, "RX Size equal zero ... Trying to read it again for %d time\n", time++);
1306 p->hif_func.hif_read_size(&size);
1307 size = ((size & 0x7fff) << 2);
1308 retries++;
1309
1310 }
1311
1312 if (size > 0) {
1313#ifdef MEMORY_STATIC
Glen Lee03eb7262015-09-24 18:15:03 +09001314 if (LINUX_RX_SIZE - offset < size)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001315 offset = 0;
1316
1317 if (p->rx_buffer)
1318 buffer = &p->rx_buffer[offset];
1319 else {
1320 wilc_debug(N_ERR, "[wilc isr]: fail Rx Buffer is NULL...drop the packets (%d)\n", size);
1321 goto _end_;
1322 }
1323
1324#else
Greg Kroah-Hartmanf019b9d2015-09-03 18:50:27 -07001325 buffer = kmalloc(size, GFP_KERNEL);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001326 if (buffer == NULL) {
1327 wilc_debug(N_ERR, "[wilc isr]: fail alloc host memory...drop the packets (%d)\n", size);
Greg Kroah-Hartman80e29c72015-08-14 19:42:23 -07001328 usleep_range(100 * 1000, 100 * 1000);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001329 goto _end_;
1330 }
1331#endif
1332
1333 /**
1334 * clear the chip's interrupt after getting size some register getting corrupted after clear the interrupt
1335 **/
1336 p->hif_func.hif_clear_int_ext(DATA_INT_CLR | ENABLE_RX_VMM);
1337
1338
1339 /**
1340 * start transfer
1341 **/
1342 ret = p->hif_func.hif_block_rx_ext(0, buffer, size);
1343
1344 if (!ret) {
1345 wilc_debug(N_ERR, "[wilc isr]: fail block rx...\n");
1346 goto _end_;
1347 }
1348_end_:
1349
1350
1351 if (ret) {
1352#ifdef MEMORY_STATIC
1353 offset += size;
1354 p->rx_buffer_offset = offset;
1355#endif
1356 /**
1357 * add to rx queue
1358 **/
Greg Kroah-Hartmanf019b9d2015-09-03 18:50:27 -07001359 rqe = kmalloc(sizeof(struct rxq_entry_t), GFP_KERNEL);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001360 if (rqe != NULL) {
1361 rqe->buffer = buffer;
1362 rqe->buffer_size = size;
1363 PRINT_D(RX_DBG, "rxq entery Size= %d - Address = %p\n", rqe->buffer_size, rqe->buffer);
Glen Leed06f3622015-10-27 18:27:59 +09001364 wilc_wlan_rxq_add(wilc, rqe);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001365 }
1366 } else {
1367#ifndef MEMORY_STATIC
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -07001368 kfree(buffer);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001369#endif
1370 }
1371 }
Glen Lee39ce4d32015-10-27 18:27:42 +09001372 wilc_wlan_handle_rxq(wilc);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001373}
1374
Glen Lee50b929e2015-10-27 18:27:40 +09001375void wilc_handle_isr(void *wilc)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001376{
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001377 u32 int_status;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001378
1379 acquire_bus(ACQUIRE_AND_WAKEUP);
1380 g_wlan.hif_func.hif_read_int(&int_status);
1381
Alison Schofield39823a52015-10-08 21:18:03 -07001382 if (int_status & PLL_INT_EXT)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001383 wilc_pllupdate_isr_ext(int_status);
Alison Schofield39823a52015-10-08 21:18:03 -07001384
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001385 if (int_status & DATA_INT_EXT) {
Glen Lee3bcd45b2015-10-27 18:27:41 +09001386 wilc_wlan_handle_isr_ext(wilc, int_status);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001387 #ifndef WILC_OPTIMIZE_SLEEP_INT
1388 /* Chip is up and talking*/
1389 genuChipPSstate = CHIP_WAKEDUP;
1390 #endif
1391 }
Alison Schofield39823a52015-10-08 21:18:03 -07001392 if (int_status & SLEEP_INT_EXT)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001393 wilc_sleeptimer_isr_ext(int_status);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001394
1395 if (!(int_status & (ALL_INT_EXT))) {
1396#ifdef WILC_SDIO
1397 PRINT_D(TX_DBG, ">> UNKNOWN_INTERRUPT - 0x%08x\n", int_status);
1398#endif
1399 wilc_unknown_isr_ext();
1400 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001401 release_bus(RELEASE_ALLOW_SLEEP);
1402}
1403
1404/********************************************
1405 *
1406 * Firmware download
1407 *
1408 ********************************************/
Glen Lee63d7ab82015-10-01 16:03:32 +09001409int wilc_wlan_firmware_download(const u8 *buffer, u32 buffer_size)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001410{
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +05301411 wilc_wlan_dev_t *p = &g_wlan;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001412 u32 offset;
1413 u32 addr, size, size2, blksz;
Chaehyun Lim51e825f2015-09-15 14:06:14 +09001414 u8 *dma_buffer;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001415 int ret = 0;
1416
Anish Bhattffda2032015-09-29 12:15:49 -07001417 blksz = BIT(12);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001418 /* Allocate a DMA coherent buffer. */
1419
Greg Kroah-Hartmanf019b9d2015-09-03 18:50:27 -07001420 dma_buffer = kmalloc(blksz, GFP_KERNEL);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001421 if (dma_buffer == NULL) {
1422 /*EIO 5*/
1423 ret = -5;
1424 PRINT_ER("Can't allocate buffer for firmware download IO error\n ");
1425 goto _fail_1;
1426 }
1427
1428 PRINT_D(INIT_DBG, "Downloading firmware size = %d ...\n", buffer_size);
1429 /**
1430 * load the firmware
1431 **/
1432 offset = 0;
1433 do {
1434 memcpy(&addr, &buffer[offset], 4);
1435 memcpy(&size, &buffer[offset + 4], 4);
1436#ifdef BIG_ENDIAN
1437 addr = BYTE_SWAP(addr);
1438 size = BYTE_SWAP(size);
1439#endif
1440 acquire_bus(ACQUIRE_ONLY);
1441 offset += 8;
1442 while (((int)size) && (offset < buffer_size)) {
Chandra S Gorentla78174ad2015-08-08 17:41:36 +05301443 if (size <= blksz)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001444 size2 = size;
Chandra S Gorentla78174ad2015-08-08 17:41:36 +05301445 else
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001446 size2 = blksz;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001447 /* Copy firmware into a DMA coherent buffer */
1448 memcpy(dma_buffer, &buffer[offset], size2);
1449 ret = p->hif_func.hif_block_tx(addr, dma_buffer, size2);
1450 if (!ret)
1451 break;
1452
1453 addr += size2;
1454 offset += size2;
1455 size -= size2;
1456 }
1457 release_bus(RELEASE_ONLY);
1458
1459 if (!ret) {
1460 /*EIO 5*/
1461 ret = -5;
1462 PRINT_ER("Can't download firmware IO error\n ");
1463 goto _fail_;
1464 }
1465 PRINT_D(INIT_DBG, "Offset = %d\n", offset);
1466 } while (offset < buffer_size);
1467
1468_fail_:
1469
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -07001470 kfree(dma_buffer);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001471
1472_fail_1:
1473
1474 return (ret < 0) ? ret : 0;
1475}
1476
1477/********************************************
1478 *
1479 * Common
1480 *
1481 ********************************************/
Glen Leee42563b2015-10-01 16:03:33 +09001482int wilc_wlan_start(void)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001483{
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +05301484 wilc_wlan_dev_t *p = &g_wlan;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001485 u32 reg = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001486 int ret;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001487 u32 chipid;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001488
1489 /**
1490 * Set the host interface
1491 **/
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001492 if (p->io_func.io_type == HIF_SDIO) {
1493 reg = 0;
Anish Bhattffda2032015-09-29 12:15:49 -07001494 reg |= BIT(3); /* bug 4456 and 4557 */
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001495 } else if (p->io_func.io_type == HIF_SPI) {
1496 reg = 1;
1497 }
1498 acquire_bus(ACQUIRE_ONLY);
1499 ret = p->hif_func.hif_write_reg(WILC_VMM_CORE_CFG, reg);
1500 if (!ret) {
1501 wilc_debug(N_ERR, "[wilc start]: fail write reg vmm_core_cfg...\n");
1502 release_bus(RELEASE_ONLY);
1503 /* EIO 5*/
1504 ret = -5;
1505 return ret;
1506 }
1507 reg = 0;
1508#ifdef WILC_SDIO_IRQ_GPIO
1509 reg |= WILC_HAVE_SDIO_IRQ_GPIO;
1510#endif
1511
1512#ifdef WILC_DISABLE_PMU
1513#else
1514 reg |= WILC_HAVE_USE_PMU;
1515#endif
1516
1517#ifdef WILC_SLEEP_CLK_SRC_XO
1518 reg |= WILC_HAVE_SLEEP_CLK_SRC_XO;
1519#elif defined WILC_SLEEP_CLK_SRC_RTC
1520 reg |= WILC_HAVE_SLEEP_CLK_SRC_RTC;
1521#endif
1522
1523#ifdef WILC_EXT_PA_INV_TX_RX
1524 reg |= WILC_HAVE_EXT_PA_INV_TX_RX;
1525#endif
1526
1527 reg |= WILC_HAVE_LEGACY_RF_SETTINGS;
1528
1529
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001530/*Set oscillator frequency*/
1531#ifdef XTAL_24
1532 reg |= WILC_HAVE_XTAL_24;
1533#endif
1534
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001535/*Enable/Disable GPIO configuration for FW logs*/
1536#ifdef DISABLE_WILC_UART
1537 reg |= WILC_HAVE_DISABLE_WILC_UART;
1538#endif
1539
1540 ret = p->hif_func.hif_write_reg(WILC_GP_REG_1, reg);
1541 if (!ret) {
1542 wilc_debug(N_ERR, "[wilc start]: fail write WILC_GP_REG_1 ...\n");
1543 release_bus(RELEASE_ONLY);
1544 /* EIO 5*/
1545 ret = -5;
1546 return ret;
1547 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001548
1549 /**
1550 * Bus related
1551 **/
1552 p->hif_func.hif_sync_ext(NUM_INT_EXT);
1553
1554 ret = p->hif_func.hif_read_reg(0x1000, &chipid);
1555 if (!ret) {
1556 wilc_debug(N_ERR, "[wilc start]: fail read reg 0x1000 ...\n");
1557 release_bus(RELEASE_ONLY);
1558 /* EIO 5*/
1559 ret = -5;
1560 return ret;
1561 }
1562
1563 /**
1564 * Go...
1565 **/
1566
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001567
1568 p->hif_func.hif_read_reg(WILC_GLB_RESET_0, &reg);
Anish Bhattffda2032015-09-29 12:15:49 -07001569 if ((reg & BIT(10)) == BIT(10)) {
1570 reg &= ~BIT(10);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001571 p->hif_func.hif_write_reg(WILC_GLB_RESET_0, reg);
1572 p->hif_func.hif_read_reg(WILC_GLB_RESET_0, &reg);
1573 }
1574
Anish Bhattffda2032015-09-29 12:15:49 -07001575 reg |= BIT(10);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001576 ret = p->hif_func.hif_write_reg(WILC_GLB_RESET_0, reg);
1577 p->hif_func.hif_read_reg(WILC_GLB_RESET_0, &reg);
1578 release_bus(RELEASE_ONLY);
1579
1580 return (ret < 0) ? ret : 0;
1581}
1582
1583void wilc_wlan_global_reset(void)
1584{
1585
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +05301586 wilc_wlan_dev_t *p = &g_wlan;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +09001587
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001588 acquire_bus(ACQUIRE_AND_WAKEUP);
1589 p->hif_func.hif_write_reg(WILC_GLB_RESET_0, 0x0);
1590 release_bus(RELEASE_ONLY);
1591}
Glen Lee8cec7412015-10-01 16:03:34 +09001592int wilc_wlan_stop(void)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001593{
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +05301594 wilc_wlan_dev_t *p = &g_wlan;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001595 u32 reg = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001596 int ret;
Chaehyun Lim51e825f2015-09-15 14:06:14 +09001597 u8 timeout = 10;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001598 /**
1599 * TODO: stop the firmware, need a re-download
1600 **/
1601 acquire_bus(ACQUIRE_AND_WAKEUP);
1602
1603 ret = p->hif_func.hif_read_reg(WILC_GLB_RESET_0, &reg);
1604 if (!ret) {
1605 PRINT_ER("Error while reading reg\n");
1606 release_bus(RELEASE_ALLOW_SLEEP);
1607 return ret;
1608 }
1609
Anish Bhattffda2032015-09-29 12:15:49 -07001610 reg &= ~BIT(10);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001611
1612
1613 ret = p->hif_func.hif_write_reg(WILC_GLB_RESET_0, reg);
1614 if (!ret) {
1615 PRINT_ER("Error while writing reg\n");
1616 release_bus(RELEASE_ALLOW_SLEEP);
1617 return ret;
1618 }
1619
1620
1621
1622 do {
1623 ret = p->hif_func.hif_read_reg(WILC_GLB_RESET_0, &reg);
1624 if (!ret) {
1625 PRINT_ER("Error while reading reg\n");
1626 release_bus(RELEASE_ALLOW_SLEEP);
1627 return ret;
1628 }
1629 PRINT_D(GENERIC_DBG, "Read RESET Reg %x : Retry%d\n", reg, timeout);
1630 /*Workaround to ensure that the chip is actually reset*/
Anish Bhattffda2032015-09-29 12:15:49 -07001631 if ((reg & BIT(10))) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001632 PRINT_D(GENERIC_DBG, "Bit 10 not reset : Retry %d\n", timeout);
Anish Bhattffda2032015-09-29 12:15:49 -07001633 reg &= ~BIT(10);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001634 ret = p->hif_func.hif_write_reg(WILC_GLB_RESET_0, reg);
1635 timeout--;
1636 } else {
1637 PRINT_D(GENERIC_DBG, "Bit 10 reset after : Retry %d\n", timeout);
1638 ret = p->hif_func.hif_read_reg(WILC_GLB_RESET_0, &reg);
1639 if (!ret) {
1640 PRINT_ER("Error while reading reg\n");
1641 release_bus(RELEASE_ALLOW_SLEEP);
1642 return ret;
1643 }
1644 PRINT_D(GENERIC_DBG, "Read RESET Reg %x : Retry%d\n", reg, timeout);
1645 break;
1646 }
1647
1648 } while (timeout);
Anish Bhattffda2032015-09-29 12:15:49 -07001649 reg = (BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(8) | BIT(9) | BIT(26) |
1650 BIT(29) | BIT(30) | BIT(31));
Anish Bhatt65ead4e2015-09-29 12:15:48 -07001651
1652 p->hif_func.hif_write_reg(WILC_GLB_RESET_0, reg);
Anish Bhattffda2032015-09-29 12:15:49 -07001653 reg = (u32)~BIT(10);
Anish Bhatt65ead4e2015-09-29 12:15:48 -07001654
1655 ret = p->hif_func.hif_write_reg(WILC_GLB_RESET_0, reg);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001656
1657 release_bus(RELEASE_ALLOW_SLEEP);
1658
1659 return ret;
1660}
1661
Glen Lee2de7cbe2015-10-27 18:27:54 +09001662void wilc_wlan_cleanup(struct net_device *dev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001663{
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +05301664 wilc_wlan_dev_t *p = &g_wlan;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001665 struct txq_entry_t *tqe;
1666 struct rxq_entry_t *rqe;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001667 u32 reg = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001668 int ret;
Glen Leedb387632015-10-27 18:27:55 +09001669 perInterface_wlan_t *nic;
1670 struct wilc *wilc;
1671
1672 nic = netdev_priv(dev);
1673 wilc = nic->wilc;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001674
1675 p->quit = 1;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001676 do {
Glen Lee718fc2c2015-10-29 12:18:43 +09001677 tqe = wilc_wlan_txq_remove_from_head(dev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001678 if (tqe == NULL)
1679 break;
1680 if (tqe->tx_complete_func)
1681 tqe->tx_complete_func(tqe->priv, 0);
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -07001682 kfree(tqe);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001683 } while (1);
1684
1685 do {
Glen Leedb387632015-10-27 18:27:55 +09001686 rqe = wilc_wlan_rxq_remove(wilc);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001687 if (rqe == NULL)
1688 break;
Javier Martinez Canillas6a272242015-09-22 15:24:50 +02001689#ifndef MEMORY_STATIC
1690 kfree(rqe->buffer);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001691#endif
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -07001692 kfree(rqe);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001693 } while (1);
1694
1695 /**
1696 * clean up buffer
1697 **/
1698
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001699 #ifdef MEMORY_STATIC
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -07001700 kfree(p->rx_buffer);
1701 p->rx_buffer = NULL;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001702 #endif
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -07001703 kfree(p->tx_buffer);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001704
1705 acquire_bus(ACQUIRE_AND_WAKEUP);
1706
1707
1708 ret = p->hif_func.hif_read_reg(WILC_GP_REG_0, &reg);
1709 if (!ret) {
1710 PRINT_ER("Error while reading reg\n");
1711 release_bus(RELEASE_ALLOW_SLEEP);
1712 }
1713 PRINT_ER("Writing ABORT reg\n");
1714 ret = p->hif_func.hif_write_reg(WILC_GP_REG_0, (reg | ABORT_INT));
1715 if (!ret) {
1716 PRINT_ER("Error while writing reg\n");
1717 release_bus(RELEASE_ALLOW_SLEEP);
1718 }
1719 release_bus(RELEASE_ALLOW_SLEEP);
1720 /**
1721 * io clean up
1722 **/
1723 p->hif_func.hif_deinit(NULL);
1724
1725}
1726
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001727static int wilc_wlan_cfg_commit(int type, u32 drvHandler)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001728{
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +05301729 wilc_wlan_dev_t *p = &g_wlan;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001730 wilc_cfg_frame_t *cfg = &p->cfg_frame;
1731 int total_len = p->cfg_frame_offset + 4 + DRIVER_HANDLER_SIZE;
1732 int seq_no = p->cfg_seq_no % 256;
Chaehyun Lim4e4467f2015-06-11 14:35:55 +09001733 int driver_handler = (u32)drvHandler;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001734
1735
1736 /**
1737 * Set up header
1738 **/
1739 if (type == WILC_CFG_SET) { /* Set */
1740 cfg->wid_header[0] = 'W';
1741 } else { /* Query */
1742 cfg->wid_header[0] = 'Q';
1743 }
1744 cfg->wid_header[1] = seq_no; /* sequence number */
Chaehyun Lim51e825f2015-09-15 14:06:14 +09001745 cfg->wid_header[2] = (u8)total_len;
1746 cfg->wid_header[3] = (u8)(total_len >> 8);
1747 cfg->wid_header[4] = (u8)driver_handler;
1748 cfg->wid_header[5] = (u8)(driver_handler >> 8);
1749 cfg->wid_header[6] = (u8)(driver_handler >> 16);
1750 cfg->wid_header[7] = (u8)(driver_handler >> 24);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001751 p->cfg_seq_no = seq_no;
1752
1753 /**
1754 * Add to TX queue
1755 **/
1756
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001757 if (!wilc_wlan_txq_add_cfg_pkt(&cfg->wid_header[0], total_len))
1758 return -1;
1759
1760 return 0;
1761}
1762
Glen Lee1028e5a2015-10-01 16:03:40 +09001763int wilc_wlan_cfg_set(int start, u32 wid, u8 *buffer, u32 buffer_size,
1764 int commit, u32 drvHandler)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001765{
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +05301766 wilc_wlan_dev_t *p = &g_wlan;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001767 u32 offset;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001768 int ret_size;
1769
1770
1771 if (p->cfg_frame_in_use)
1772 return 0;
1773
1774 if (start)
1775 p->cfg_frame_offset = 0;
1776
1777 offset = p->cfg_frame_offset;
Glen Lee17e8f162015-10-02 14:22:07 +09001778 ret_size = wilc_wlan_cfg_set_wid(p->cfg_frame.frame, offset, (u16)wid,
1779 buffer, buffer_size);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001780 offset += ret_size;
1781 p->cfg_frame_offset = offset;
1782
1783 if (commit) {
1784 PRINT_D(TX_DBG, "[WILC]PACKET Commit with sequence number %d\n", p->cfg_seq_no);
1785 PRINT_D(RX_DBG, "Processing cfg_set()\n");
1786 p->cfg_frame_in_use = 1;
1787
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001788 if (wilc_wlan_cfg_commit(WILC_CFG_SET, drvHandler))
Chaehyun Lim5af6b852015-09-17 16:48:48 +09001789 ret_size = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001790
Glen Leeb002e202015-09-24 18:15:05 +09001791 if (linux_wlan_lock_timeout(&g_linux_wlan->cfg_event,
1792 CFG_PKTS_TIMEOUT)) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001793 PRINT_D(TX_DBG, "Set Timed Out\n");
1794 ret_size = 0;
1795 }
1796 p->cfg_frame_in_use = 0;
1797 p->cfg_frame_offset = 0;
1798 p->cfg_seq_no += 1;
1799
1800 }
1801
1802 return ret_size;
1803}
Glen Lee07056a82015-10-01 16:03:41 +09001804int wilc_wlan_cfg_get(int start, u32 wid, int commit, u32 drvHandler)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001805{
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +05301806 wilc_wlan_dev_t *p = &g_wlan;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001807 u32 offset;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001808 int ret_size;
1809
1810
1811 if (p->cfg_frame_in_use)
1812 return 0;
1813
1814 if (start)
1815 p->cfg_frame_offset = 0;
1816
1817 offset = p->cfg_frame_offset;
Glen Leeec1b86b2015-10-02 14:22:08 +09001818 ret_size = wilc_wlan_cfg_get_wid(p->cfg_frame.frame, offset, (u16)wid);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001819 offset += ret_size;
1820 p->cfg_frame_offset = offset;
1821
1822 if (commit) {
1823 p->cfg_frame_in_use = 1;
1824
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001825 if (wilc_wlan_cfg_commit(WILC_CFG_QUERY, drvHandler))
Chaehyun Lim5af6b852015-09-17 16:48:48 +09001826 ret_size = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001827
1828
Glen Leeb002e202015-09-24 18:15:05 +09001829 if (linux_wlan_lock_timeout(&g_linux_wlan->cfg_event,
1830 CFG_PKTS_TIMEOUT)) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001831 PRINT_D(TX_DBG, "Get Timed Out\n");
1832 ret_size = 0;
1833 }
1834 PRINT_D(GENERIC_DBG, "[WILC]Get Response received\n");
1835 p->cfg_frame_in_use = 0;
1836 p->cfg_frame_offset = 0;
1837 p->cfg_seq_no += 1;
1838 }
1839
1840 return ret_size;
1841}
1842
Glen Lee894de36b2015-10-01 16:03:42 +09001843int wilc_wlan_cfg_get_val(u32 wid, u8 *buffer, u32 buffer_size)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001844{
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001845 int ret;
1846
Glen Lee355cca22015-10-02 14:22:09 +09001847 ret = wilc_wlan_cfg_get_wid_value((u16)wid, buffer, buffer_size);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001848
1849 return ret;
1850}
1851
1852void wilc_bus_set_max_speed(void)
1853{
1854
1855 /* Increase bus speed to max possible. */
1856 g_wlan.hif_func.hif_set_max_bus_speed();
1857}
1858
1859void wilc_bus_set_default_speed(void)
1860{
1861
1862 /* Restore bus speed to default. */
1863 g_wlan.hif_func.hif_set_default_bus_speed();
1864}
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001865u32 init_chip(void)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001866{
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001867 u32 chipid;
1868 u32 reg, ret = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001869
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001870 acquire_bus(ACQUIRE_ONLY);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001871
Dean Lee72ed4dc2015-06-12 14:11:44 +09001872 chipid = wilc_get_chipid(true);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001873
1874
1875
1876 if ((chipid & 0xfff) != 0xa0) {
1877 /**
1878 * Avoid booting from boot ROM. Make sure that Drive IRQN [SDIO platform]
1879 * or SD_DAT3 [SPI platform] to ?1?
1880 **/
1881 /* Set cortus reset register to register control. */
1882 ret = g_wlan.hif_func.hif_read_reg(0x1118, &reg);
1883 if (!ret) {
1884 wilc_debug(N_ERR, "[wilc start]: fail read reg 0x1118 ...\n");
1885 return ret;
1886 }
Anish Bhattffda2032015-09-29 12:15:49 -07001887 reg |= BIT(0);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001888 ret = g_wlan.hif_func.hif_write_reg(0x1118, reg);
1889 if (!ret) {
1890 wilc_debug(N_ERR, "[wilc start]: fail write reg 0x1118 ...\n");
1891 return ret;
1892 }
1893 /**
1894 * Write branch intruction to IRAM (0x71 trap) at location 0xFFFF0000
1895 * (Cortus map) or C0000 (AHB map).
1896 **/
1897 ret = g_wlan.hif_func.hif_write_reg(0xc0000, 0x71);
1898 if (!ret) {
1899 wilc_debug(N_ERR, "[wilc start]: fail write reg 0xc0000 ...\n");
1900 return ret;
1901 }
1902 }
1903
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001904 release_bus(RELEASE_ONLY);
1905
1906 return ret;
1907
1908}
1909
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001910u32 wilc_get_chipid(u8 update)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001911{
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001912 static u32 chipid;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001913 /* SDIO can't read into global variables */
1914 /* Use this variable as a temp, then copy to the global */
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001915 u32 tempchipid = 0;
1916 u32 rfrevid;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001917
1918 if (chipid == 0 || update != 0) {
1919 g_wlan.hif_func.hif_read_reg(0x1000, &tempchipid);
1920 g_wlan.hif_func.hif_read_reg(0x13f4, &rfrevid);
1921 if (!ISWILC1000(tempchipid)) {
1922 chipid = 0;
1923 goto _fail_;
1924 }
1925 if (tempchipid == 0x1002a0) {
1926 if (rfrevid == 0x1) { /* 1002A0 */
1927 } else { /* if (rfrevid == 0x2) */ /* 1002A1 */
1928 tempchipid = 0x1002a1;
1929 }
1930 } else if (tempchipid == 0x1002b0) {
1931 if (rfrevid == 3) { /* 1002B0 */
1932 } else if (rfrevid == 4) { /* 1002B1 */
1933 tempchipid = 0x1002b1;
1934 } else { /* if(rfrevid == 5) */ /* 1002B2 */
1935 tempchipid = 0x1002b2;
1936 }
1937 } else {
1938 }
1939
1940 chipid = tempchipid;
1941 }
1942_fail_:
1943 return chipid;
1944}
1945
Glen Leec9d48342015-10-01 16:03:43 +09001946int wilc_wlan_init(wilc_wlan_inp_t *inp)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001947{
1948
1949 int ret = 0;
1950
1951 PRINT_D(INIT_DBG, "Initializing WILC_Wlan ...\n");
1952
1953 memset((void *)&g_wlan, 0, sizeof(wilc_wlan_dev_t));
1954
1955 /**
1956 * store the input
1957 **/
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001958 memcpy((void *)&g_wlan.io_func, (void *)&inp->io_func, sizeof(wilc_wlan_io_func_t));
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001959 /***
1960 * host interface init
1961 **/
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001962 if ((inp->io_func.io_type & 0x1) == HIF_SDIO) {
1963 if (!hif_sdio.hif_init(inp, wilc_debug)) {
1964 /* EIO 5 */
1965 ret = -5;
1966 goto _fail_;
1967 }
1968 memcpy((void *)&g_wlan.hif_func, &hif_sdio, sizeof(wilc_hif_func_t));
1969 } else {
1970 if ((inp->io_func.io_type & 0x1) == HIF_SPI) {
1971 /**
1972 * TODO:
1973 **/
1974 if (!hif_spi.hif_init(inp, wilc_debug)) {
1975 /* EIO 5 */
1976 ret = -5;
1977 goto _fail_;
1978 }
1979 memcpy((void *)&g_wlan.hif_func, &hif_spi, sizeof(wilc_hif_func_t));
1980 } else {
1981 /* EIO 5 */
1982 ret = -5;
1983 goto _fail_;
1984 }
1985 }
1986
1987 /***
1988 * mac interface init
1989 **/
Glen Lee814bc362015-10-02 14:22:11 +09001990 if (!wilc_wlan_cfg_init(wilc_debug)) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001991 /* ENOBUFS 105 */
1992 ret = -105;
1993 goto _fail_;
1994 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001995
1996 /**
1997 * alloc tx, rx buffer
1998 **/
Greg Kroah-Hartmanb1413b62015-06-02 14:11:12 +09001999 if (g_wlan.tx_buffer == NULL)
Glen Lee7015b5d2015-09-24 18:15:02 +09002000 g_wlan.tx_buffer = kmalloc(LINUX_TX_SIZE, GFP_KERNEL);
Arnd Bergmann7a8fd842015-06-01 21:06:45 +02002001 PRINT_D(TX_DBG, "g_wlan.tx_buffer = %p\n", g_wlan.tx_buffer);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09002002
Greg Kroah-Hartmanb1413b62015-06-02 14:11:12 +09002003 if (g_wlan.tx_buffer == NULL) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09002004 /* ENOBUFS 105 */
2005 ret = -105;
2006 PRINT_ER("Can't allocate Tx Buffer");
2007 goto _fail_;
2008 }
2009
2010/* rx_buffer is not used unless we activate USE_MEM STATIC which is not applicable, allocating such memory is useless*/
2011#if defined (MEMORY_STATIC)
Greg Kroah-Hartmanb1413b62015-06-02 14:11:12 +09002012 if (g_wlan.rx_buffer == NULL)
Glen Lee03eb7262015-09-24 18:15:03 +09002013 g_wlan.rx_buffer = kmalloc(LINUX_RX_SIZE, GFP_KERNEL);
Arnd Bergmann7a8fd842015-06-01 21:06:45 +02002014 PRINT_D(TX_DBG, "g_wlan.rx_buffer =%p\n", g_wlan.rx_buffer);
Greg Kroah-Hartmanb1413b62015-06-02 14:11:12 +09002015 if (g_wlan.rx_buffer == NULL) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09002016 /* ENOBUFS 105 */
2017 ret = -105;
2018 PRINT_ER("Can't allocate Rx Buffer");
2019 goto _fail_;
2020 }
2021#endif
2022
Johnny Kimc5c77ba2015-05-11 14:30:56 +09002023 if (!init_chip()) {
2024 /* EIO 5 */
2025 ret = -5;
2026 goto _fail_;
2027 }
2028#ifdef TCP_ACK_FILTER
2029 Init_TCP_tracking();
2030#endif
2031
Johnny Kimc5c77ba2015-05-11 14:30:56 +09002032 return 1;
2033
2034_fail_:
2035
Johnny Kimc5c77ba2015-05-11 14:30:56 +09002036 #ifdef MEMORY_STATIC
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -07002037 kfree(g_wlan.rx_buffer);
2038 g_wlan.rx_buffer = NULL;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09002039 #endif
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -07002040 kfree(g_wlan.tx_buffer);
2041 g_wlan.tx_buffer = NULL;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09002042
Johnny Kimc5c77ba2015-05-11 14:30:56 +09002043 return ret;
2044
2045}
2046
Glen Lee178c3832015-10-27 18:27:58 +09002047u16 Set_machw_change_vir_if(struct net_device *dev, bool bValue)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09002048{
Chaehyun Limd85f5322015-06-11 14:35:54 +09002049 u16 ret;
Chaehyun Lim4e4467f2015-06-11 14:35:55 +09002050 u32 reg;
Glen Lee178c3832015-10-27 18:27:58 +09002051 perInterface_wlan_t *nic;
2052 struct wilc *wilc;
2053
2054 nic = netdev_priv(dev);
2055 wilc = nic->wilc;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09002056
2057 /*Reset WILC_CHANGING_VIR_IF register to allow adding futrue keys to CE H/W*/
Glen Lee178c3832015-10-27 18:27:58 +09002058 mutex_lock(&wilc->hif_cs);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09002059 ret = (&g_wlan)->hif_func.hif_read_reg(WILC_CHANGING_VIR_IF, &reg);
Alison Schofield39823a52015-10-08 21:18:03 -07002060 if (!ret)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09002061 PRINT_ER("Error while Reading reg WILC_CHANGING_VIR_IF\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +09002062
Chandra S Gorentla78174ad2015-08-08 17:41:36 +05302063 if (bValue)
Chaehyun Lim50b51da2015-09-16 20:11:26 +09002064 reg |= BIT(31);
Chandra S Gorentla78174ad2015-08-08 17:41:36 +05302065 else
Chaehyun Lim50b51da2015-09-16 20:11:26 +09002066 reg &= ~BIT(31);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09002067
2068 ret = (&g_wlan)->hif_func.hif_write_reg(WILC_CHANGING_VIR_IF, reg);
2069
Alison Schofield39823a52015-10-08 21:18:03 -07002070 if (!ret)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09002071 PRINT_ER("Error while writing reg WILC_CHANGING_VIR_IF\n");
Alison Schofield39823a52015-10-08 21:18:03 -07002072
Glen Lee178c3832015-10-27 18:27:58 +09002073 mutex_unlock(&wilc->hif_cs);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09002074
2075 return ret;
2076}