blob: 52351c6186572a175cf87fd05cf793ec55525fb6 [file] [log] [blame]
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001#include "wilc_wlan_if.h"
Tony Cho60bd1002015-10-12 16:56:04 +09002#include "wilc_wfi_netdevice.h"
Glen Lee17e8f162015-10-02 14:22:07 +09003#include "wilc_wlan_cfg.h"
Johnny Kimc5c77ba2015-05-11 14:30:56 +09004
Johnny Kimc5c77ba2015-05-11 14:30:56 +09005extern wilc_hif_func_t hif_sdio;
6extern wilc_hif_func_t hif_spi;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09007u32 wilc_get_chipid(u8 update);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09008
Johnny Kimc5c77ba2015-05-11 14:30:56 +09009typedef struct {
10 int quit;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090011 wilc_wlan_io_func_t io_func;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090012 wilc_hif_func_t hif_func;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090013 int cfg_frame_in_use;
14 wilc_cfg_frame_t cfg_frame;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +090015 u32 cfg_frame_offset;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090016 int cfg_seq_no;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090017
Johnny Kimc5c77ba2015-05-11 14:30:56 +090018 #ifdef MEMORY_STATIC
Chaehyun Lim51e825f2015-09-15 14:06:14 +090019 u8 *rx_buffer;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +090020 u32 rx_buffer_offset;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090021 #endif
Chaehyun Lim51e825f2015-09-15 14:06:14 +090022 u8 *tx_buffer;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +090023 u32 tx_buffer_offset;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090024
Johnny Kimc5c77ba2015-05-11 14:30:56 +090025 unsigned long txq_spinlock_flags;
26
27 struct txq_entry_t *txq_head;
28 struct txq_entry_t *txq_tail;
29 int txq_entries;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090030 int txq_exit;
31
Johnny Kimc5c77ba2015-05-11 14:30:56 +090032 struct rxq_entry_t *rxq_head;
33 struct rxq_entry_t *rxq_tail;
34 int rxq_entries;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090035 int rxq_exit;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090036} wilc_wlan_dev_t;
37
38static wilc_wlan_dev_t g_wlan;
39
Chaehyun Lim9af382b2015-09-16 20:11:27 +090040static inline void chip_allow_sleep(void);
41static inline void chip_wakeup(void);
Chaehyun Limfbc2fe12015-09-15 14:06:16 +090042static u32 dbgflag = N_INIT | N_ERR | N_INTR | N_TXQ | N_RXQ;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090043
Chaehyun Limfbc2fe12015-09-15 14:06:16 +090044static void wilc_debug(u32 flag, char *fmt, ...)
Johnny Kimc5c77ba2015-05-11 14:30:56 +090045{
46 char buf[256];
47 va_list args;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090048
49 if (flag & dbgflag) {
50 va_start(args, fmt);
Hari Prasath Gujulan Elango81053222015-06-22 13:13:58 +000051 vsprintf(buf, fmt, args);
Johnny Kimc5c77ba2015-05-11 14:30:56 +090052 va_end(args);
53
Glen Leeef2b7842015-09-24 18:14:55 +090054 linux_wlan_dbg(buf);
Johnny Kimc5c77ba2015-05-11 14:30:56 +090055 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +090056}
57
Leo Kimb7d1e182015-11-06 11:12:30 +090058static CHIP_PS_STATE_T chip_ps_state = CHIP_WAKEDUP;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090059
Chaehyun Lim9af382b2015-09-16 20:11:27 +090060static inline void acquire_bus(BUS_ACQUIRE_T acquire)
Johnny Kimc5c77ba2015-05-11 14:30:56 +090061{
Glen Lee187f1ef2015-09-24 18:15:01 +090062 mutex_lock(&g_linux_wlan->hif_cs);
Johnny Kimc5c77ba2015-05-11 14:30:56 +090063 #ifndef WILC_OPTIMIZE_SLEEP_INT
Leo Kimb7d1e182015-11-06 11:12:30 +090064 if (chip_ps_state != CHIP_WAKEDUP)
Johnny Kimc5c77ba2015-05-11 14:30:56 +090065 #endif
66 {
67 if (acquire == ACQUIRE_AND_WAKEUP)
68 chip_wakeup();
69 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +090070}
Leo Kim2d6973e2015-11-06 11:12:28 +090071
Chaehyun Lim9af382b2015-09-16 20:11:27 +090072static inline void release_bus(BUS_RELEASE_T release)
Johnny Kimc5c77ba2015-05-11 14:30:56 +090073{
74 #ifdef WILC_OPTIMIZE_SLEEP_INT
75 if (release == RELEASE_ALLOW_SLEEP)
76 chip_allow_sleep();
77 #endif
Glen Lee187f1ef2015-09-24 18:15:01 +090078 mutex_unlock(&g_linux_wlan->hif_cs);
Johnny Kimc5c77ba2015-05-11 14:30:56 +090079}
Johnny Kimc5c77ba2015-05-11 14:30:56 +090080
81static void wilc_wlan_txq_remove(struct txq_entry_t *tqe)
82{
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +053083 wilc_wlan_dev_t *p = &g_wlan;
Leo Kim8739eeb2015-11-06 11:12:29 +090084
Johnny Kimc5c77ba2015-05-11 14:30:56 +090085 if (tqe == p->txq_head) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +090086 p->txq_head = tqe->next;
87 if (p->txq_head)
88 p->txq_head->prev = NULL;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090089 } else if (tqe == p->txq_tail) {
90 p->txq_tail = (tqe->prev);
91 if (p->txq_tail)
92 p->txq_tail->next = NULL;
93 } else {
94 tqe->prev->next = tqe->next;
95 tqe->next->prev = tqe->prev;
96 }
97 p->txq_entries -= 1;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090098}
99
Glen Lee718fc2c2015-10-29 12:18:43 +0900100static struct txq_entry_t *
101wilc_wlan_txq_remove_from_head(struct net_device *dev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900102{
103 struct txq_entry_t *tqe;
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +0530104 wilc_wlan_dev_t *p = &g_wlan;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900105 unsigned long flags;
Glen Lee718fc2c2015-10-29 12:18:43 +0900106 perInterface_wlan_t *nic;
107 struct wilc *wilc;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900108
Glen Lee718fc2c2015-10-29 12:18:43 +0900109 nic = netdev_priv(dev);
110 wilc = nic->wilc;
111
112 spin_lock_irqsave(&wilc->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900113 if (p->txq_head) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900114 tqe = p->txq_head;
115 p->txq_head = tqe->next;
Alison Schofield39823a52015-10-08 21:18:03 -0700116 if (p->txq_head)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900117 p->txq_head->prev = NULL;
Alison Schofield39823a52015-10-08 21:18:03 -0700118
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900119 p->txq_entries -= 1;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900120 } else {
121 tqe = NULL;
122 }
Glen Lee718fc2c2015-10-29 12:18:43 +0900123 spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900124 return tqe;
125}
126
Glen Lee32f03322015-10-29 12:18:45 +0900127static void wilc_wlan_txq_add_to_tail(struct net_device *dev,
128 struct txq_entry_t *tqe)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900129{
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +0530130 wilc_wlan_dev_t *p = &g_wlan;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900131 unsigned long flags;
Glen Lee32f03322015-10-29 12:18:45 +0900132 perInterface_wlan_t *nic;
133 struct wilc *wilc;
134
135 nic = netdev_priv(dev);
136 wilc = nic->wilc;
137
138 spin_lock_irqsave(&wilc->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900139
Leo Kima4b17192015-11-06 11:12:31 +0900140 if (!p->txq_head) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900141 tqe->next = NULL;
142 tqe->prev = NULL;
143 p->txq_head = tqe;
144 p->txq_tail = tqe;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900145 } else {
146 tqe->next = NULL;
147 tqe->prev = p->txq_tail;
148 p->txq_tail->next = tqe;
149 p->txq_tail = tqe;
150 }
151 p->txq_entries += 1;
152 PRINT_D(TX_DBG, "Number of entries in TxQ = %d\n", p->txq_entries);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900153
Glen Lee32f03322015-10-29 12:18:45 +0900154 spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900155
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900156 PRINT_D(TX_DBG, "Wake the txq_handling\n");
157
Glen Lee32f03322015-10-29 12:18:45 +0900158 up(&wilc->txq_event);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900159}
160
161static int wilc_wlan_txq_add_to_head(struct txq_entry_t *tqe)
162{
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +0530163 wilc_wlan_dev_t *p = &g_wlan;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900164 unsigned long flags;
Glen Leeb002e202015-09-24 18:15:05 +0900165 if (linux_wlan_lock_timeout(&g_linux_wlan->txq_add_to_head_cs,
166 CFG_PKTS_TIMEOUT))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900167 return -1;
168
Glen Lee85e57562015-09-24 18:14:56 +0900169 spin_lock_irqsave(&g_linux_wlan->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900170
Leo Kima4b17192015-11-06 11:12:31 +0900171 if (!p->txq_head) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900172 tqe->next = NULL;
173 tqe->prev = NULL;
174 p->txq_head = tqe;
175 p->txq_tail = tqe;
176 } else {
177 tqe->next = p->txq_head;
178 tqe->prev = NULL;
179 p->txq_head->prev = tqe;
180 p->txq_head = tqe;
181 }
182 p->txq_entries += 1;
183 PRINT_D(TX_DBG, "Number of entries in TxQ = %d\n", p->txq_entries);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900184
Glen Lee85e57562015-09-24 18:14:56 +0900185 spin_unlock_irqrestore(&g_linux_wlan->txq_spinlock, flags);
Glen Leed5a63a82015-09-24 18:15:00 +0900186 up(&g_linux_wlan->txq_add_to_head_cs);
Glen Lee5cd63632015-09-24 18:14:58 +0900187 up(&g_linux_wlan->txq_event);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900188 PRINT_D(TX_DBG, "Wake up the txq_handler\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900189
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900190 return 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900191}
192
Leo Kimeb59da32015-11-06 11:12:33 +0900193u32 total_acks = 0, dropped_acks = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900194
195#ifdef TCP_ACK_FILTER
Leo Kim130a41f2015-11-06 11:12:34 +0900196struct ack_session_info;
197struct ack_session_info {
Leo Kimd06b6cb2015-11-06 11:12:35 +0900198 u32 seq_num;
Leo Kim9d54d3d2015-11-06 11:12:36 +0900199 u32 bigger_ack_num;
Chaehyun Limec53adf2015-09-15 14:06:15 +0900200 u16 src_port;
201 u16 dst_port;
202 u16 status;
Shraddha Barkeeeb1c062015-08-05 01:29:22 +0530203};
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900204
Leo Kim08b90b12015-11-06 11:12:37 +0900205struct pending_acks_info {
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900206 u32 ack_num;
Leo Kim84136972015-11-06 11:12:38 +0900207 u32 session_index;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900208 struct txq_entry_t *txqe;
Leo Kim08b90b12015-11-06 11:12:37 +0900209};
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900210
Leo Kim130a41f2015-11-06 11:12:34 +0900211struct ack_session_info *Free_head;
212struct ack_session_info *Alloc_head;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900213
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900214#define NOT_TCP_ACK (-1)
215
216#define MAX_TCP_SESSION 25
217#define MAX_PENDING_ACKS 256
Leo Kim32065052015-11-06 11:12:39 +0900218struct ack_session_info ack_session_info[2 * MAX_TCP_SESSION];
Leo Kim2bb17082015-11-06 11:12:40 +0900219struct pending_acks_info pending_acks_info[MAX_PENDING_ACKS];
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900220
Leo Kim2ae91ed2015-11-06 11:12:41 +0900221u32 pending_base;
Leo Kim3056ec32015-11-06 11:12:42 +0900222u32 tcp_session;
Leo Kimd12ac7e2015-11-06 11:12:43 +0900223u32 pending_acks;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900224
Leo Kimef06b5f2015-11-06 11:12:44 +0900225static inline int init_tcp_tracking(void)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900226{
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900227 return 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900228}
Leo Kim2d6973e2015-11-06 11:12:28 +0900229
Leo Kim67620782015-11-06 11:12:45 +0900230static inline int add_tcp_session(u32 src_prt, u32 dst_prt, u32 seq)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900231{
Leo Kim3056ec32015-11-06 11:12:42 +0900232 ack_session_info[tcp_session].seq_num = seq;
233 ack_session_info[tcp_session].bigger_ack_num = 0;
234 ack_session_info[tcp_session].src_port = src_prt;
235 ack_session_info[tcp_session].dst_port = dst_prt;
236 tcp_session++;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900237
Leo Kim3056ec32015-11-06 11:12:42 +0900238 PRINT_D(TCP_ENH, "TCP Session %d to Ack %d\n", tcp_session, seq);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900239 return 0;
240}
241
Leo Kimb801a962015-11-06 11:12:48 +0900242static inline int update_tcp_session(u32 index, u32 ack)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900243{
Leo Kimb801a962015-11-06 11:12:48 +0900244 if (ack > ack_session_info[index].bigger_ack_num)
245 ack_session_info[index].bigger_ack_num = ack;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900246 return 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900247}
Leo Kim2d6973e2015-11-06 11:12:28 +0900248
Leo Kimea03f572015-11-06 11:12:49 +0900249static inline int add_tcp_pending_ack(u32 ack, u32 session_index,
Leo Kimbdc13ad2015-11-06 11:12:47 +0900250 struct txq_entry_t *txqe)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900251{
Leo Kim821466d2015-11-06 11:12:32 +0900252 total_acks++;
Leo Kimd12ac7e2015-11-06 11:12:43 +0900253 if (pending_acks < MAX_PENDING_ACKS) {
Leo Kimb801a962015-11-06 11:12:48 +0900254 pending_acks_info[pending_base + pending_acks].ack_num = ack;
Leo Kimd12ac7e2015-11-06 11:12:43 +0900255 pending_acks_info[pending_base + pending_acks].txqe = txqe;
Leo Kimea03f572015-11-06 11:12:49 +0900256 pending_acks_info[pending_base + pending_acks].session_index = session_index;
Leo Kimd12ac7e2015-11-06 11:12:43 +0900257 txqe->tcp_PendingAck_index = pending_base + pending_acks;
258 pending_acks++;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900259 }
260 return 0;
261}
Chaehyun Limfed16f22015-09-17 16:48:43 +0900262static inline int remove_TCP_related(void)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900263{
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +0530264 wilc_wlan_dev_t *p = &g_wlan;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900265 unsigned long flags;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900266
Glen Lee85e57562015-09-24 18:14:56 +0900267 spin_lock_irqsave(&g_linux_wlan->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900268
Glen Lee85e57562015-09-24 18:14:56 +0900269 spin_unlock_irqrestore(&g_linux_wlan->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900270 return 0;
271}
272
Glen Lee82bb18e2015-10-27 18:28:03 +0900273static inline int tcp_process(struct net_device *dev, struct txq_entry_t *tqe)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900274{
275 int ret;
Chaehyun Lim51e825f2015-09-15 14:06:14 +0900276 u8 *eth_hdr_ptr;
277 u8 *buffer = tqe->buffer;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900278 unsigned short h_proto;
279 int i;
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +0530280 wilc_wlan_dev_t *p = &g_wlan;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900281 unsigned long flags;
Glen Lee82bb18e2015-10-27 18:28:03 +0900282 perInterface_wlan_t *nic;
283 struct wilc *wilc;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900284
Glen Lee82bb18e2015-10-27 18:28:03 +0900285 nic = netdev_priv(dev);
286 wilc = nic->wilc;
287
288 spin_lock_irqsave(&wilc->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900289
290 eth_hdr_ptr = &buffer[0];
291 h_proto = ntohs(*((unsigned short *)&eth_hdr_ptr[12]));
Leo Kimac087c82015-11-06 11:12:25 +0900292 if (h_proto == 0x0800) {
Chaehyun Lim51e825f2015-09-15 14:06:14 +0900293 u8 *ip_hdr_ptr;
294 u8 protocol;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900295
296 ip_hdr_ptr = &buffer[ETHERNET_HDR_LEN];
297 protocol = ip_hdr_ptr[9];
298
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900299 if (protocol == 0x06) {
Chaehyun Lim51e825f2015-09-15 14:06:14 +0900300 u8 *tcp_hdr_ptr;
Leo Kim51bffa92015-11-06 11:12:52 +0900301 u32 IHL, total_length, data_offset;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900302
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900303 tcp_hdr_ptr = &ip_hdr_ptr[IP_HDR_LEN];
304 IHL = (ip_hdr_ptr[0] & 0xf) << 2;
Leo Kim24e2dac2015-11-06 11:12:51 +0900305 total_length = ((u32)ip_hdr_ptr[2] << 8) +
306 (u32)ip_hdr_ptr[3];
Leo Kim51bffa92015-11-06 11:12:52 +0900307 data_offset = ((u32)tcp_hdr_ptr[12] & 0xf0) >> 2;
308 if (total_length == (IHL + data_offset)) {
Leo Kimf91c5d72015-11-06 11:12:53 +0900309 u32 seq_no, ack_no;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900310
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900311 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 +0900312
Leo Kimf91c5d72015-11-06 11:12:53 +0900313 ack_no = ((u32)tcp_hdr_ptr[8] << 24) +
314 ((u32)tcp_hdr_ptr[9] << 16) +
315 ((u32)tcp_hdr_ptr[10] << 8) +
316 (u32)tcp_hdr_ptr[11];
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900317
Leo Kim3056ec32015-11-06 11:12:42 +0900318 for (i = 0; i < tcp_session; i++) {
Leo Kim32065052015-11-06 11:12:39 +0900319 if (ack_session_info[i].seq_num == seq_no) {
Leo Kimf91c5d72015-11-06 11:12:53 +0900320 update_tcp_session(i, ack_no);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900321 break;
322 }
323 }
Leo Kim3056ec32015-11-06 11:12:42 +0900324 if (i == tcp_session)
Leo Kim67620782015-11-06 11:12:45 +0900325 add_tcp_session(0, 0, seq_no);
Alison Schofield39823a52015-10-08 21:18:03 -0700326
Leo Kimf91c5d72015-11-06 11:12:53 +0900327 add_tcp_pending_ack(ack_no, i, tqe);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900328 }
329
330 } else {
331 ret = 0;
332 }
333 } else {
334 ret = 0;
335 }
Glen Lee82bb18e2015-10-27 18:28:03 +0900336 spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900337 return ret;
338}
339
Glen Leec029e992015-10-27 18:27:48 +0900340static int wilc_wlan_txq_filter_dup_tcp_ack(struct net_device *dev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900341{
Glen Leec029e992015-10-27 18:27:48 +0900342 perInterface_wlan_t *nic;
343 struct wilc *wilc;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900344 u32 i = 0;
345 u32 Dropped = 0;
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +0530346 wilc_wlan_dev_t *p = &g_wlan;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900347
Glen Leec029e992015-10-27 18:27:48 +0900348 nic = netdev_priv(dev);
349 wilc = nic->wilc;
350
351 spin_lock_irqsave(&wilc->txq_spinlock, p->txq_spinlock_flags);
Leo Kimd12ac7e2015-11-06 11:12:43 +0900352 for (i = pending_base; i < (pending_base + pending_acks); i++) {
Leo Kim2bb17082015-11-06 11:12:40 +0900353 if (pending_acks_info[i].ack_num < ack_session_info[pending_acks_info[i].session_index].bigger_ack_num) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900354 struct txq_entry_t *tqe;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900355
Leo Kim2bb17082015-11-06 11:12:40 +0900356 PRINT_D(TCP_ENH, "DROP ACK: %u\n",
357 pending_acks_info[i].ack_num);
358 tqe = pending_acks_info[i].txqe;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900359 if (tqe) {
360 wilc_wlan_txq_remove(tqe);
Leo Kimeb59da32015-11-06 11:12:33 +0900361 dropped_acks++;
Leo Kimac087c82015-11-06 11:12:25 +0900362 tqe->status = 1;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900363 if (tqe->tx_complete_func)
364 tqe->tx_complete_func(tqe->priv, tqe->status);
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -0700365 kfree(tqe);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900366 Dropped++;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900367 }
368 }
369 }
Leo Kimd12ac7e2015-11-06 11:12:43 +0900370 pending_acks = 0;
Leo Kim3056ec32015-11-06 11:12:42 +0900371 tcp_session = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900372
Leo Kim2ae91ed2015-11-06 11:12:41 +0900373 if (pending_base == 0)
374 pending_base = MAX_TCP_SESSION;
Chandra S Gorentla78174ad2015-08-08 17:41:36 +0530375 else
Leo Kim2ae91ed2015-11-06 11:12:41 +0900376 pending_base = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900377
Glen Leec029e992015-10-27 18:27:48 +0900378 spin_unlock_irqrestore(&wilc->txq_spinlock, p->txq_spinlock_flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900379
380 while (Dropped > 0) {
Glen Leec029e992015-10-27 18:27:48 +0900381 linux_wlan_lock_timeout(&wilc->txq_event, 1);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900382 Dropped--;
383 }
384
385 return 1;
386}
387#endif
388
Dean Lee72ed4dc2015-06-12 14:11:44 +0900389bool EnableTCPAckFilter = false;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900390
Dean Lee72ed4dc2015-06-12 14:11:44 +0900391void Enable_TCP_ACK_Filter(bool value)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900392{
393 EnableTCPAckFilter = value;
394}
395
Dean Lee72ed4dc2015-06-12 14:11:44 +0900396bool is_TCP_ACK_Filter_Enabled(void)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900397{
398 return EnableTCPAckFilter;
399}
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900400
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900401static int wilc_wlan_txq_add_cfg_pkt(u8 *buffer, u32 buffer_size)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900402{
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +0530403 wilc_wlan_dev_t *p = &g_wlan;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900404 struct txq_entry_t *tqe;
405
406 PRINT_D(TX_DBG, "Adding config packet ...\n");
407 if (p->quit) {
408 PRINT_D(TX_DBG, "Return due to clear function\n");
Glen Lee6a3b94f2015-09-24 18:14:59 +0900409 up(&g_linux_wlan->cfg_event);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900410 return 0;
411 }
412
Greg Kroah-Hartman47c632d2015-09-03 18:55:43 -0700413 tqe = kmalloc(sizeof(struct txq_entry_t), GFP_ATOMIC);
Leo Kima4b17192015-11-06 11:12:31 +0900414 if (!tqe) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900415 PRINT_ER("Failed to allocate memory\n");
416 return 0;
417 }
418
419 tqe->type = WILC_CFG_PKT;
420 tqe->buffer = buffer;
421 tqe->buffer_size = buffer_size;
422 tqe->tx_complete_func = NULL;
423 tqe->priv = NULL;
424#ifdef TCP_ACK_FILTER
425 tqe->tcp_PendingAck_index = NOT_TCP_ACK;
426#endif
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900427 PRINT_D(TX_DBG, "Adding the config packet at the Queue tail\n");
428
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900429 if (wilc_wlan_txq_add_to_head(tqe))
430 return 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900431 return 1;
432}
433
Glen Lee691bbd42015-10-27 18:28:02 +0900434int wilc_wlan_txq_add_net_pkt(struct net_device *dev, void *priv, u8 *buffer,
435 u32 buffer_size, wilc_tx_complete_func_t func)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900436{
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +0530437 wilc_wlan_dev_t *p = &g_wlan;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900438 struct txq_entry_t *tqe;
439
440 if (p->quit)
441 return 0;
442
Greg Kroah-Hartman47c632d2015-09-03 18:55:43 -0700443 tqe = kmalloc(sizeof(struct txq_entry_t), GFP_ATOMIC);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900444
Leo Kima4b17192015-11-06 11:12:31 +0900445 if (!tqe)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900446 return 0;
447 tqe->type = WILC_NET_PKT;
448 tqe->buffer = buffer;
449 tqe->buffer_size = buffer_size;
450 tqe->tx_complete_func = func;
451 tqe->priv = priv;
452
453 PRINT_D(TX_DBG, "Adding mgmt packet at the Queue tail\n");
454#ifdef TCP_ACK_FILTER
455 tqe->tcp_PendingAck_index = NOT_TCP_ACK;
Abdul Hussain5a66bf22015-06-16 09:44:06 +0000456 if (is_TCP_ACK_Filter_Enabled())
Glen Lee82bb18e2015-10-27 18:28:03 +0900457 tcp_process(dev, tqe);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900458#endif
Glen Lee32f03322015-10-29 12:18:45 +0900459 wilc_wlan_txq_add_to_tail(dev, tqe);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900460 return p->txq_entries;
461}
Glen Leefcc6ef92015-09-16 18:53:21 +0900462
Glen Lee829c4772015-10-29 12:18:44 +0900463int wilc_wlan_txq_add_mgmt_pkt(struct net_device *dev, void *priv, u8 *buffer,
464 u32 buffer_size, wilc_tx_complete_func_t func)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900465{
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +0530466 wilc_wlan_dev_t *p = &g_wlan;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900467 struct txq_entry_t *tqe;
468
469 if (p->quit)
470 return 0;
471
Greg Kroah-Hartman47c632d2015-09-03 18:55:43 -0700472 tqe = kmalloc(sizeof(struct txq_entry_t), GFP_KERNEL);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900473
Leo Kima4b17192015-11-06 11:12:31 +0900474 if (!tqe)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900475 return 0;
476 tqe->type = WILC_MGMT_PKT;
477 tqe->buffer = buffer;
478 tqe->buffer_size = buffer_size;
479 tqe->tx_complete_func = func;
480 tqe->priv = priv;
481#ifdef TCP_ACK_FILTER
482 tqe->tcp_PendingAck_index = NOT_TCP_ACK;
483#endif
484 PRINT_D(TX_DBG, "Adding Network packet at the Queue tail\n");
Glen Lee32f03322015-10-29 12:18:45 +0900485 wilc_wlan_txq_add_to_tail(dev, tqe);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900486 return 1;
487}
Glen Leefcc6ef92015-09-16 18:53:21 +0900488
Glen Lee7af05222015-10-29 12:18:41 +0900489static struct txq_entry_t *wilc_wlan_txq_get_first(struct wilc *wilc)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900490{
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +0530491 wilc_wlan_dev_t *p = &g_wlan;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900492 struct txq_entry_t *tqe;
493 unsigned long flags;
494
Glen Lee7af05222015-10-29 12:18:41 +0900495 spin_lock_irqsave(&wilc->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900496
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900497 tqe = p->txq_head;
498
Glen Lee7af05222015-10-29 12:18:41 +0900499 spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900500
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900501 return tqe;
502}
503
Glen Lee50a0b3b2015-10-27 18:28:00 +0900504static struct txq_entry_t *wilc_wlan_txq_get_next(struct wilc *wilc,
505 struct txq_entry_t *tqe)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900506{
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900507 unsigned long flags;
Leo Kim8739eeb2015-11-06 11:12:29 +0900508
Glen Lee50a0b3b2015-10-27 18:28:00 +0900509 spin_lock_irqsave(&wilc->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900510
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900511 tqe = tqe->next;
Glen Lee50a0b3b2015-10-27 18:28:00 +0900512 spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900513
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900514 return tqe;
515}
516
Glen Leed06f3622015-10-27 18:27:59 +0900517static int wilc_wlan_rxq_add(struct wilc *wilc, struct rxq_entry_t *rqe)
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
521 if (p->quit)
522 return 0;
523
Glen Leed06f3622015-10-27 18:27:59 +0900524 mutex_lock(&wilc->rxq_cs);
Leo Kima4b17192015-11-06 11:12:31 +0900525 if (!p->rxq_head) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900526 PRINT_D(RX_DBG, "Add to Queue head\n");
527 rqe->next = NULL;
528 p->rxq_head = rqe;
529 p->rxq_tail = rqe;
530 } else {
531 PRINT_D(RX_DBG, "Add to Queue tail\n");
532 p->rxq_tail->next = rqe;
533 rqe->next = NULL;
534 p->rxq_tail = rqe;
535 }
536 p->rxq_entries += 1;
537 PRINT_D(RX_DBG, "Number of queue entries: %d\n", p->rxq_entries);
Glen Leed06f3622015-10-27 18:27:59 +0900538 mutex_unlock(&wilc->rxq_cs);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900539 return p->rxq_entries;
540}
541
Glen Leedb387632015-10-27 18:27:55 +0900542static struct rxq_entry_t *wilc_wlan_rxq_remove(struct wilc *wilc)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900543{
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +0530544 wilc_wlan_dev_t *p = &g_wlan;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900545
546 PRINT_D(RX_DBG, "Getting rxQ element\n");
547 if (p->rxq_head) {
548 struct rxq_entry_t *rqe;
549
Glen Leedb387632015-10-27 18:27:55 +0900550 mutex_lock(&wilc->rxq_cs);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900551 rqe = p->rxq_head;
552 p->rxq_head = p->rxq_head->next;
553 p->rxq_entries -= 1;
554 PRINT_D(RX_DBG, "RXQ entries decreased\n");
Glen Leedb387632015-10-27 18:27:55 +0900555 mutex_unlock(&wilc->rxq_cs);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900556 return rqe;
557 }
558 PRINT_D(RX_DBG, "Nothing to get from Q\n");
559 return NULL;
560}
561
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900562#ifdef WILC_OPTIMIZE_SLEEP_INT
563
Chaehyun Lim9af382b2015-09-16 20:11:27 +0900564static inline void chip_allow_sleep(void)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900565{
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900566 u32 reg = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900567
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900568 g_wlan.hif_func.hif_read_reg(0xf0, &reg);
569
Anish Bhattffda2032015-09-29 12:15:49 -0700570 g_wlan.hif_func.hif_write_reg(0xf0, reg & ~BIT(0));
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900571}
572
Chaehyun Lim9af382b2015-09-16 20:11:27 +0900573static inline void chip_wakeup(void)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900574{
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900575 u32 reg, clk_status_reg, trials = 0;
576 u32 sleep_time;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900577
578 if ((g_wlan.io_func.io_type & 0x1) == HIF_SPI) {
579 do {
580 g_wlan.hif_func.hif_read_reg(1, &reg);
Anish Bhattffda2032015-09-29 12:15:49 -0700581 g_wlan.hif_func.hif_write_reg(1, reg | BIT(1));
Anish Bhattffda2032015-09-29 12:15:49 -0700582 g_wlan.hif_func.hif_write_reg(1, reg & ~BIT(1));
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900583
584 do {
Greg Kroah-Hartman80e29c72015-08-14 19:42:23 -0700585 usleep_range(2 * 1000, 2 * 1000);
Alison Schofield39823a52015-10-08 21:18:03 -0700586 if ((wilc_get_chipid(true) == 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900587 wilc_debug(N_ERR, "Couldn't read chip id. Wake up failed\n");
Alison Schofield39823a52015-10-08 21:18:03 -0700588
Dean Lee72ed4dc2015-06-12 14:11:44 +0900589 } while ((wilc_get_chipid(true) == 0) && ((++trials % 3) == 0));
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900590
Dean Lee72ed4dc2015-06-12 14:11:44 +0900591 } while (wilc_get_chipid(true) == 0);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900592 } else if ((g_wlan.io_func.io_type & 0x1) == HIF_SDIO) {
593 g_wlan.hif_func.hif_read_reg(0xf0, &reg);
594 do {
Anish Bhattffda2032015-09-29 12:15:49 -0700595 g_wlan.hif_func.hif_write_reg(0xf0, reg | BIT(0));
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900596 g_wlan.hif_func.hif_read_reg(0xf1, &clk_status_reg);
597
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900598 while (((clk_status_reg & 0x1) == 0) && (((++trials) % 3) == 0)) {
Greg Kroah-Hartman80e29c72015-08-14 19:42:23 -0700599 usleep_range(2 * 1000, 2 * 1000);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900600
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900601 g_wlan.hif_func.hif_read_reg(0xf1, &clk_status_reg);
602
Alison Schofield39823a52015-10-08 21:18:03 -0700603 if ((clk_status_reg & 0x1) == 0)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900604 wilc_debug(N_ERR, "clocks still OFF. Wake up failed\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900605 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900606 if ((clk_status_reg & 0x1) == 0) {
Anish Bhattffda2032015-09-29 12:15:49 -0700607 g_wlan.hif_func.hif_write_reg(0xf0, reg &
608 (~BIT(0)));
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900609 }
610 } while ((clk_status_reg & 0x1) == 0);
611 }
612
Leo Kimb7d1e182015-11-06 11:12:30 +0900613 if (chip_ps_state == CHIP_SLEEPING_MANUAL) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900614 g_wlan.hif_func.hif_read_reg(0x1C0C, &reg);
Anish Bhattffda2032015-09-29 12:15:49 -0700615 reg &= ~BIT(0);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900616 g_wlan.hif_func.hif_write_reg(0x1C0C, reg);
617
Dean Lee72ed4dc2015-06-12 14:11:44 +0900618 if (wilc_get_chipid(false) >= 0x1002b0) {
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900619 u32 val32;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900620
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900621 g_wlan.hif_func.hif_read_reg(0x1e1c, &val32);
Anish Bhattffda2032015-09-29 12:15:49 -0700622 val32 |= BIT(6);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900623 g_wlan.hif_func.hif_write_reg(0x1e1c, val32);
624
625 g_wlan.hif_func.hif_read_reg(0x1e9c, &val32);
Anish Bhattffda2032015-09-29 12:15:49 -0700626 val32 |= BIT(6);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900627 g_wlan.hif_func.hif_write_reg(0x1e9c, val32);
628 }
629 }
Leo Kimb7d1e182015-11-06 11:12:30 +0900630 chip_ps_state = CHIP_WAKEDUP;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900631}
632#else
Chaehyun Lim9af382b2015-09-16 20:11:27 +0900633static inline void chip_wakeup(void)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900634{
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900635 u32 reg, trials = 0;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900636
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900637 do {
638 if ((g_wlan.io_func.io_type & 0x1) == HIF_SPI) {
639 g_wlan.hif_func.hif_read_reg(1, &reg);
Anish Bhattffda2032015-09-29 12:15:49 -0700640 g_wlan.hif_func.hif_write_reg(1, reg & ~BIT(1));
Anish Bhattffda2032015-09-29 12:15:49 -0700641 g_wlan.hif_func.hif_write_reg(1, reg | BIT(1));
Anish Bhattffda2032015-09-29 12:15:49 -0700642 g_wlan.hif_func.hif_write_reg(1, reg & ~BIT(1));
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900643 } else if ((g_wlan.io_func.io_type & 0x1) == HIF_SDIO) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900644 g_wlan.hif_func.hif_read_reg(0xf0, &reg);
Anish Bhattffda2032015-09-29 12:15:49 -0700645 g_wlan.hif_func.hif_write_reg(0xf0, reg & ~BIT(0));
Anish Bhattffda2032015-09-29 12:15:49 -0700646 g_wlan.hif_func.hif_write_reg(0xf0, reg | BIT(0));
Anish Bhattffda2032015-09-29 12:15:49 -0700647 g_wlan.hif_func.hif_write_reg(0xf0, reg & ~BIT(0));
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900648 }
649
650 do {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900651 mdelay(3);
652
Alison Schofield39823a52015-10-08 21:18:03 -0700653 if ((wilc_get_chipid(true) == 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900654 wilc_debug(N_ERR, "Couldn't read chip id. Wake up failed\n");
Alison Schofield39823a52015-10-08 21:18:03 -0700655
Dean Lee72ed4dc2015-06-12 14:11:44 +0900656 } while ((wilc_get_chipid(true) == 0) && ((++trials % 3) == 0));
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900657
Dean Lee72ed4dc2015-06-12 14:11:44 +0900658 } while (wilc_get_chipid(true) == 0);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900659
Leo Kimb7d1e182015-11-06 11:12:30 +0900660 if (chip_ps_state == CHIP_SLEEPING_MANUAL) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900661 g_wlan.hif_func.hif_read_reg(0x1C0C, &reg);
Anish Bhattffda2032015-09-29 12:15:49 -0700662 reg &= ~BIT(0);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900663 g_wlan.hif_func.hif_write_reg(0x1C0C, reg);
664
Dean Lee72ed4dc2015-06-12 14:11:44 +0900665 if (wilc_get_chipid(false) >= 0x1002b0) {
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900666 u32 val32;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900667
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900668 g_wlan.hif_func.hif_read_reg(0x1e1c, &val32);
Anish Bhattffda2032015-09-29 12:15:49 -0700669 val32 |= BIT(6);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900670 g_wlan.hif_func.hif_write_reg(0x1e1c, val32);
671
672 g_wlan.hif_func.hif_read_reg(0x1e9c, &val32);
Anish Bhattffda2032015-09-29 12:15:49 -0700673 val32 |= BIT(6);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900674 g_wlan.hif_func.hif_write_reg(0x1e9c, val32);
675 }
676 }
Leo Kimb7d1e182015-11-06 11:12:30 +0900677 chip_ps_state = CHIP_WAKEDUP;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900678}
679#endif
Chaehyun Lim4e4467f2015-06-11 14:35:55 +0900680void chip_sleep_manually(u32 u32SleepTime)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900681{
Leo Kimb7d1e182015-11-06 11:12:30 +0900682 if (chip_ps_state != CHIP_WAKEDUP)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900683 return;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900684 acquire_bus(ACQUIRE_ONLY);
685
686#ifdef WILC_OPTIMIZE_SLEEP_INT
687 chip_allow_sleep();
688#endif
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900689 g_wlan.hif_func.hif_write_reg(0x10a8, 1);
690
Leo Kimb7d1e182015-11-06 11:12:30 +0900691 chip_ps_state = CHIP_SLEEPING_MANUAL;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900692 release_bus(RELEASE_ONLY);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900693}
694
Glen Leea1332ca2015-10-27 18:27:47 +0900695int wilc_wlan_handle_txq(struct net_device *dev, u32 *pu32TxqCount)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900696{
697 wilc_wlan_dev_t *p = (wilc_wlan_dev_t *)&g_wlan;
698 int i, entries = 0;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900699 u32 sum;
700 u32 reg;
Chaehyun Lim51e825f2015-09-15 14:06:14 +0900701 u8 *txb = p->tx_buffer;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900702 u32 offset = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900703 int vmm_sz = 0;
704 struct txq_entry_t *tqe;
705 int ret = 0;
706 int counter;
707 int timeout;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900708 u32 vmm_table[WILC_VMM_TBL_SIZE];
Glen Leea1332ca2015-10-27 18:27:47 +0900709 perInterface_wlan_t *nic;
710 struct wilc *wilc;
711
712 nic = netdev_priv(dev);
713 wilc = nic->wilc;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900714
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900715 p->txq_exit = 0;
716 do {
717 if (p->quit)
718 break;
719
Glen Leea1332ca2015-10-27 18:27:47 +0900720 linux_wlan_lock_timeout(&wilc->txq_add_to_head_cs,
Glen Leeb002e202015-09-24 18:15:05 +0900721 CFG_PKTS_TIMEOUT);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900722#ifdef TCP_ACK_FILTER
Glen Leec029e992015-10-27 18:27:48 +0900723 wilc_wlan_txq_filter_dup_tcp_ack(dev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900724#endif
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900725 PRINT_D(TX_DBG, "Getting the head of the TxQ\n");
Glen Lee7af05222015-10-29 12:18:41 +0900726 tqe = wilc_wlan_txq_get_first(wilc);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900727 i = 0;
728 sum = 0;
729 do {
Leo Kima4b17192015-11-06 11:12:31 +0900730 if (tqe && (i < (WILC_VMM_TBL_SIZE - 1))) {
Alison Schofield39823a52015-10-08 21:18:03 -0700731 if (tqe->type == WILC_CFG_PKT)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900732 vmm_sz = ETH_CONFIG_PKT_HDR_OFFSET;
Alison Schofield39823a52015-10-08 21:18:03 -0700733
734 else if (tqe->type == WILC_NET_PKT)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900735 vmm_sz = ETH_ETHERNET_HDR_OFFSET;
Alison Schofield39823a52015-10-08 21:18:03 -0700736
737 else
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900738 vmm_sz = HOST_HDR_OFFSET;
Alison Schofield39823a52015-10-08 21:18:03 -0700739
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900740 vmm_sz += tqe->buffer_size;
741 PRINT_D(TX_DBG, "VMM Size before alignment = %d\n", vmm_sz);
Leo Kimac087c82015-11-06 11:12:25 +0900742 if (vmm_sz & 0x3)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900743 vmm_sz = (vmm_sz + 4) & ~0x3;
Leo Kimac087c82015-11-06 11:12:25 +0900744
Alison Schofield39823a52015-10-08 21:18:03 -0700745 if ((sum + vmm_sz) > LINUX_TX_SIZE)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900746 break;
Alison Schofield39823a52015-10-08 21:18:03 -0700747
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900748 PRINT_D(TX_DBG, "VMM Size AFTER alignment = %d\n", vmm_sz);
Leo Kimac087c82015-11-06 11:12:25 +0900749 vmm_table[i] = vmm_sz / 4;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900750 PRINT_D(TX_DBG, "VMMTable entry size = %d\n", vmm_table[i]);
751
752 if (tqe->type == WILC_CFG_PKT) {
Anish Bhattffda2032015-09-29 12:15:49 -0700753 vmm_table[i] |= BIT(10);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900754 PRINT_D(TX_DBG, "VMMTable entry changed for CFG packet = %d\n", vmm_table[i]);
755 }
756#ifdef BIG_ENDIAN
757 vmm_table[i] = BYTE_SWAP(vmm_table[i]);
758#endif
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900759
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900760 i++;
761 sum += vmm_sz;
762 PRINT_D(TX_DBG, "sum = %d\n", sum);
Glen Lee50a0b3b2015-10-27 18:28:00 +0900763 tqe = wilc_wlan_txq_get_next(wilc, tqe);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900764 } else {
765 break;
766 }
767 } while (1);
768
Leo Kimac087c82015-11-06 11:12:25 +0900769 if (i == 0) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900770 PRINT_D(TX_DBG, "Nothing in TX-Q\n");
771 break;
772 } else {
773 PRINT_D(TX_DBG, "Mark the last entry in VMM table - number of previous entries = %d\n", i);
Leo Kimac087c82015-11-06 11:12:25 +0900774 vmm_table[i] = 0x0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900775 }
776 acquire_bus(ACQUIRE_AND_WAKEUP);
777 counter = 0;
778 do {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900779 ret = p->hif_func.hif_read_reg(WILC_HOST_TX_CTRL, &reg);
780 if (!ret) {
781 wilc_debug(N_ERR, "[wilc txq]: fail can't read reg vmm_tbl_entry..\n");
782 break;
783 }
784
785 if ((reg & 0x1) == 0) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900786 PRINT_D(TX_DBG, "Writing VMM table ... with Size = %d\n", ((i + 1) * 4));
787 break;
788 } else {
789 counter++;
790 if (counter > 200) {
791 counter = 0;
792 PRINT_D(TX_DBG, "Looping in tx ctrl , forcce quit\n");
793 ret = p->hif_func.hif_write_reg(WILC_HOST_TX_CTRL, 0);
794 break;
795 }
Chandra S Gorentla17aacd42015-08-08 17:41:35 +0530796 PRINT_WRN(GENERIC_DBG, "[wilc txq]: warn, vmm table not clear yet, wait...\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900797 release_bus(RELEASE_ALLOW_SLEEP);
Greg Kroah-Hartman2b922cb2015-09-04 09:30:51 -0700798 usleep_range(3000, 3000);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900799 acquire_bus(ACQUIRE_AND_WAKEUP);
800 }
801 } while (!p->quit);
802
Alison Schofield39823a52015-10-08 21:18:03 -0700803 if (!ret)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900804 goto _end_;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900805
806 timeout = 200;
807 do {
Chaehyun Limc3ca6372015-09-20 15:51:19 +0900808 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 +0900809 if (!ret) {
810 wilc_debug(N_ERR, "ERR block TX of VMM table.\n");
811 break;
812 }
813
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900814 ret = p->hif_func.hif_write_reg(WILC_HOST_VMM_CTL, 0x2);
815 if (!ret) {
816 wilc_debug(N_ERR, "[wilc txq]: fail can't write reg host_vmm_ctl..\n");
817 break;
818 }
819
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900820 do {
821 ret = p->hif_func.hif_read_reg(WILC_HOST_VMM_CTL, &reg);
822 if (!ret) {
823 wilc_debug(N_ERR, "[wilc txq]: fail can't read reg host_vmm_ctl..\n");
824 break;
825 }
826 if ((reg >> 2) & 0x1) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900827 entries = ((reg >> 3) & 0x3f);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900828 break;
829 } else {
830 release_bus(RELEASE_ALLOW_SLEEP);
Greg Kroah-Hartman2b922cb2015-09-04 09:30:51 -0700831 usleep_range(3000, 3000);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900832 acquire_bus(ACQUIRE_AND_WAKEUP);
833 PRINT_WRN(GENERIC_DBG, "Can't get VMM entery - reg = %2x\n", reg);
834 }
835 } while (--timeout);
836 if (timeout <= 0) {
837 ret = p->hif_func.hif_write_reg(WILC_HOST_VMM_CTL, 0x0);
838 break;
839 }
840
Alison Schofield39823a52015-10-08 21:18:03 -0700841 if (!ret)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900842 break;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900843
844 if (entries == 0) {
Chandra S Gorentla17aacd42015-08-08 17:41:35 +0530845 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 +0900846
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900847 ret = p->hif_func.hif_read_reg(WILC_HOST_TX_CTRL, &reg);
848 if (!ret) {
849 wilc_debug(N_ERR, "[wilc txq]: fail can't read reg WILC_HOST_TX_CTRL..\n");
850 break;
851 }
Anish Bhattffda2032015-09-29 12:15:49 -0700852 reg &= ~BIT(0);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900853 ret = p->hif_func.hif_write_reg(WILC_HOST_TX_CTRL, reg);
854 if (!ret) {
855 wilc_debug(N_ERR, "[wilc txq]: fail can't write reg WILC_HOST_TX_CTRL..\n");
856 break;
857 }
858 break;
859 } else {
860 break;
861 }
862 } while (1);
863
Alison Schofield39823a52015-10-08 21:18:03 -0700864 if (!ret)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900865 goto _end_;
Alison Schofield39823a52015-10-08 21:18:03 -0700866
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900867 if (entries == 0) {
868 ret = WILC_TX_ERR_NO_BUF;
869 goto _end_;
870 }
871
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900872 release_bus(RELEASE_ALLOW_SLEEP);
873
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900874 offset = 0;
875 i = 0;
876 do {
Glen Lee718fc2c2015-10-29 12:18:43 +0900877 tqe = wilc_wlan_txq_remove_from_head(dev);
Leo Kima4b17192015-11-06 11:12:31 +0900878 if (tqe && (vmm_table[i] != 0)) {
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900879 u32 header, buffer_offset;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900880
881#ifdef BIG_ENDIAN
882 vmm_table[i] = BYTE_SWAP(vmm_table[i]);
883#endif
Leo Kimac087c82015-11-06 11:12:25 +0900884 vmm_sz = (vmm_table[i] & 0x3ff);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900885 vmm_sz *= 4;
886 header = (tqe->type << 31) | (tqe->buffer_size << 15) | vmm_sz;
Chandra S Gorentla78174ad2015-08-08 17:41:36 +0530887 if (tqe->type == WILC_MGMT_PKT)
Anish Bhattffda2032015-09-29 12:15:49 -0700888 header |= BIT(30);
Chandra S Gorentla78174ad2015-08-08 17:41:36 +0530889 else
Anish Bhattffda2032015-09-29 12:15:49 -0700890 header &= ~BIT(30);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900891
892#ifdef BIG_ENDIAN
893 header = BYTE_SWAP(header);
894#endif
895 memcpy(&txb[offset], &header, 4);
896 if (tqe->type == WILC_CFG_PKT) {
897 buffer_offset = ETH_CONFIG_PKT_HDR_OFFSET;
898 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900899 else if (tqe->type == WILC_NET_PKT) {
900 char *pBSSID = ((struct tx_complete_data *)(tqe->priv))->pBssid;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900901
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900902 buffer_offset = ETH_ETHERNET_HDR_OFFSET;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900903 memcpy(&txb[offset + 4], pBSSID, 6);
904 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900905 else {
906 buffer_offset = HOST_HDR_OFFSET;
907 }
908
909 memcpy(&txb[offset + buffer_offset], tqe->buffer, tqe->buffer_size);
910 offset += vmm_sz;
911 i++;
Leo Kimac087c82015-11-06 11:12:25 +0900912 tqe->status = 1;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900913 if (tqe->tx_complete_func)
914 tqe->tx_complete_func(tqe->priv, tqe->status);
915 #ifdef TCP_ACK_FILTER
Alison Schofield39823a52015-10-08 21:18:03 -0700916 if (tqe->tcp_PendingAck_index != NOT_TCP_ACK)
Leo Kim2bb17082015-11-06 11:12:40 +0900917 pending_acks_info[tqe->tcp_PendingAck_index].txqe = NULL;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900918 #endif
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -0700919 kfree(tqe);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900920 } else {
921 break;
922 }
923 } while (--entries);
924
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900925 acquire_bus(ACQUIRE_AND_WAKEUP);
926
927 ret = p->hif_func.hif_clear_int_ext(ENABLE_TX_VMM);
928 if (!ret) {
929 wilc_debug(N_ERR, "[wilc txq]: fail can't start tx VMM ...\n");
930 goto _end_;
931 }
932
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900933 ret = p->hif_func.hif_block_tx_ext(0, txb, offset);
934 if (!ret) {
935 wilc_debug(N_ERR, "[wilc txq]: fail can't block tx ext...\n");
936 goto _end_;
937 }
938
939_end_:
940
941 release_bus(RELEASE_ALLOW_SLEEP);
942 if (ret != 1)
943 break;
944 } while (0);
Glen Leea1332ca2015-10-27 18:27:47 +0900945 up(&wilc->txq_add_to_head_cs);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900946
947 p->txq_exit = 1;
948 PRINT_D(TX_DBG, "THREAD: Exiting txq\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900949 *pu32TxqCount = p->txq_entries;
950 return ret;
951}
952
Glen Lee39ce4d32015-10-27 18:27:42 +0900953static void wilc_wlan_handle_rxq(struct wilc *wilc)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900954{
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +0530955 wilc_wlan_dev_t *p = &g_wlan;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900956 int offset = 0, size, has_packet = 0;
Chaehyun Lim51e825f2015-09-15 14:06:14 +0900957 u8 *buffer;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900958 struct rxq_entry_t *rqe;
959
960 p->rxq_exit = 0;
961
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900962 do {
963 if (p->quit) {
Chandra S Gorentla17aacd42015-08-08 17:41:35 +0530964 PRINT_D(RX_DBG, "exit 1st do-while due to Clean_UP function\n");
Glen Lee39ce4d32015-10-27 18:27:42 +0900965 up(&wilc->cfg_event);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900966 break;
967 }
Glen Leedb387632015-10-27 18:27:55 +0900968 rqe = wilc_wlan_rxq_remove(wilc);
Leo Kima4b17192015-11-06 11:12:31 +0900969 if (!rqe) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900970 PRINT_D(RX_DBG, "nothing in the queue - exit 1st do-while\n");
971 break;
972 }
973 buffer = rqe->buffer;
974 size = rqe->buffer_size;
975 PRINT_D(RX_DBG, "rxQ entery Size = %d - Address = %p\n", size, buffer);
976 offset = 0;
977
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900978 do {
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900979 u32 header;
980 u32 pkt_len, pkt_offset, tp_len;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900981 int is_cfg_packet;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900982
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900983 PRINT_D(RX_DBG, "In the 2nd do-while\n");
984 memcpy(&header, &buffer[offset], 4);
985#ifdef BIG_ENDIAN
986 header = BYTE_SWAP(header);
987#endif
988 PRINT_D(RX_DBG, "Header = %04x - Offset = %d\n", header, offset);
989
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900990 is_cfg_packet = (header >> 31) & 0x1;
991 pkt_offset = (header >> 22) & 0x1ff;
992 tp_len = (header >> 11) & 0x7ff;
993 pkt_len = header & 0x7ff;
994
995 if (pkt_len == 0 || tp_len == 0) {
996 wilc_debug(N_RXQ, "[wilc rxq]: data corrupt, packet len or tp_len is 0 [%d][%d]\n", pkt_len, tp_len);
997 break;
998 }
999
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001000 #define IS_MANAGMEMENT 0x100
1001 #define IS_MANAGMEMENT_CALLBACK 0x080
1002 #define IS_MGMT_STATUS_SUCCES 0x040
1003
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001004 if (pkt_offset & IS_MANAGMEMENT) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001005 pkt_offset &= ~(IS_MANAGMEMENT | IS_MANAGMEMENT_CALLBACK | IS_MGMT_STATUS_SUCCES);
1006
Glen Lee11f4b2e2015-10-27 18:27:51 +09001007 WILC_WFI_mgmt_rx(wilc, &buffer[offset + HOST_HDR_OFFSET], pkt_len);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001008 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001009 else
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001010 {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001011 if (!is_cfg_packet) {
Glen Lee63611672015-09-24 18:14:52 +09001012 if (pkt_len > 0) {
Glen Leecb1991a2015-10-27 18:27:56 +09001013 frmw_to_linux(wilc,
1014 &buffer[offset],
Glen Lee63611672015-09-24 18:14:52 +09001015 pkt_len,
1016 pkt_offset);
1017 has_packet = 1;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001018 }
1019 } else {
1020 wilc_cfg_rsp_t rsp;
1021
Glen Lee30f535a2015-10-02 14:22:10 +09001022 wilc_wlan_cfg_indicate_rx(&buffer[pkt_offset + offset], pkt_len, &rsp);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001023 if (rsp.type == WILC_CFG_RSP) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001024 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 -07001025 if (p->cfg_seq_no == rsp.seq_no)
Glen Lee39ce4d32015-10-27 18:27:42 +09001026 up(&wilc->cfg_event);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001027 } else if (rsp.type == WILC_CFG_RSP_STATUS) {
Glen Lee64f2b712015-10-27 18:27:43 +09001028 linux_wlan_mac_indicate(wilc, WILC_MAC_INDICATE_STATUS);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001029
1030 } else if (rsp.type == WILC_CFG_RSP_SCAN) {
Glen Lee64f2b712015-10-27 18:27:43 +09001031 linux_wlan_mac_indicate(wilc, WILC_MAC_INDICATE_SCAN);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001032 }
1033 }
1034 }
1035 offset += tp_len;
1036 if (offset >= size)
1037 break;
1038 } while (1);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001039#ifndef MEMORY_STATIC
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -07001040 kfree(buffer);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001041#endif
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -07001042 kfree(rqe);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001043
Alison Schofield39823a52015-10-08 21:18:03 -07001044 if (has_packet)
Glen Leec0cadaa2015-09-24 18:14:54 +09001045 linux_wlan_rx_complete();
Alison Schofield39823a52015-10-08 21:18:03 -07001046
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001047 } while (1);
1048
1049 p->rxq_exit = 1;
Chandra S Gorentla17aacd42015-08-08 17:41:35 +05301050 PRINT_D(RX_DBG, "THREAD: Exiting RX thread\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001051}
1052
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001053static void wilc_unknown_isr_ext(void)
1054{
1055 g_wlan.hif_func.hif_clear_int_ext(0);
1056}
Leo Kim2d6973e2015-11-06 11:12:28 +09001057
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001058static void wilc_pllupdate_isr_ext(u32 int_stats)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001059{
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001060 int trials = 10;
1061
1062 g_wlan.hif_func.hif_clear_int_ext(PLL_INT_CLR);
1063
Greg Kroah-Hartmanc2e4c0f2015-09-03 19:09:50 -07001064 mdelay(WILC_PLL_TO);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001065
Dean Lee72ed4dc2015-06-12 14:11:44 +09001066 while (!(ISWILC1000(wilc_get_chipid(true)) && --trials)) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001067 PRINT_D(TX_DBG, "PLL update retrying\n");
Greg Kroah-Hartmanc2e4c0f2015-09-03 19:09:50 -07001068 mdelay(1);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001069 }
1070}
1071
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001072static void wilc_sleeptimer_isr_ext(u32 int_stats1)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001073{
1074 g_wlan.hif_func.hif_clear_int_ext(SLEEP_INT_CLR);
1075#ifndef WILC_OPTIMIZE_SLEEP_INT
Leo Kimb7d1e182015-11-06 11:12:30 +09001076 chip_ps_state = CHIP_SLEEPING_AUTO;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001077#endif
1078}
1079
Glen Lee3bcd45b2015-10-27 18:27:41 +09001080static void wilc_wlan_handle_isr_ext(struct wilc *wilc, u32 int_status)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001081{
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +05301082 wilc_wlan_dev_t *p = &g_wlan;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001083#ifdef MEMORY_STATIC
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001084 u32 offset = p->rx_buffer_offset;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001085#endif
Chaehyun Lim51e825f2015-09-15 14:06:14 +09001086 u8 *buffer = NULL;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001087 u32 size;
1088 u32 retries = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001089 int ret = 0;
1090 struct rxq_entry_t *rqe;
1091
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001092 size = ((int_status & 0x7fff) << 2);
1093
1094 while (!size && retries < 10) {
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001095 u32 time = 0;
Leo Kimac087c82015-11-06 11:12:25 +09001096
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001097 wilc_debug(N_ERR, "RX Size equal zero ... Trying to read it again for %d time\n", time++);
1098 p->hif_func.hif_read_size(&size);
1099 size = ((size & 0x7fff) << 2);
1100 retries++;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001101 }
1102
1103 if (size > 0) {
1104#ifdef MEMORY_STATIC
Glen Lee03eb7262015-09-24 18:15:03 +09001105 if (LINUX_RX_SIZE - offset < size)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001106 offset = 0;
1107
1108 if (p->rx_buffer)
1109 buffer = &p->rx_buffer[offset];
1110 else {
1111 wilc_debug(N_ERR, "[wilc isr]: fail Rx Buffer is NULL...drop the packets (%d)\n", size);
1112 goto _end_;
1113 }
1114
1115#else
Greg Kroah-Hartmanf019b9d2015-09-03 18:50:27 -07001116 buffer = kmalloc(size, GFP_KERNEL);
Leo Kima4b17192015-11-06 11:12:31 +09001117 if (!buffer) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001118 wilc_debug(N_ERR, "[wilc isr]: fail alloc host memory...drop the packets (%d)\n", size);
Greg Kroah-Hartman80e29c72015-08-14 19:42:23 -07001119 usleep_range(100 * 1000, 100 * 1000);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001120 goto _end_;
1121 }
1122#endif
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001123 p->hif_func.hif_clear_int_ext(DATA_INT_CLR | ENABLE_RX_VMM);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001124 ret = p->hif_func.hif_block_rx_ext(0, buffer, size);
1125
1126 if (!ret) {
1127 wilc_debug(N_ERR, "[wilc isr]: fail block rx...\n");
1128 goto _end_;
1129 }
1130_end_:
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001131 if (ret) {
1132#ifdef MEMORY_STATIC
1133 offset += size;
1134 p->rx_buffer_offset = offset;
1135#endif
Greg Kroah-Hartmanf019b9d2015-09-03 18:50:27 -07001136 rqe = kmalloc(sizeof(struct rxq_entry_t), GFP_KERNEL);
Leo Kima4b17192015-11-06 11:12:31 +09001137 if (rqe) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001138 rqe->buffer = buffer;
1139 rqe->buffer_size = size;
1140 PRINT_D(RX_DBG, "rxq entery Size= %d - Address = %p\n", rqe->buffer_size, rqe->buffer);
Glen Leed06f3622015-10-27 18:27:59 +09001141 wilc_wlan_rxq_add(wilc, rqe);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001142 }
1143 } else {
1144#ifndef MEMORY_STATIC
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -07001145 kfree(buffer);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001146#endif
1147 }
1148 }
Glen Lee39ce4d32015-10-27 18:27:42 +09001149 wilc_wlan_handle_rxq(wilc);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001150}
1151
Glen Lee50b929e2015-10-27 18:27:40 +09001152void wilc_handle_isr(void *wilc)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001153{
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001154 u32 int_status;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001155
1156 acquire_bus(ACQUIRE_AND_WAKEUP);
1157 g_wlan.hif_func.hif_read_int(&int_status);
1158
Alison Schofield39823a52015-10-08 21:18:03 -07001159 if (int_status & PLL_INT_EXT)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001160 wilc_pllupdate_isr_ext(int_status);
Alison Schofield39823a52015-10-08 21:18:03 -07001161
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001162 if (int_status & DATA_INT_EXT) {
Glen Lee3bcd45b2015-10-27 18:27:41 +09001163 wilc_wlan_handle_isr_ext(wilc, int_status);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001164 #ifndef WILC_OPTIMIZE_SLEEP_INT
Leo Kimb7d1e182015-11-06 11:12:30 +09001165 chip_ps_state = CHIP_WAKEDUP;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001166 #endif
1167 }
Alison Schofield39823a52015-10-08 21:18:03 -07001168 if (int_status & SLEEP_INT_EXT)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001169 wilc_sleeptimer_isr_ext(int_status);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001170
1171 if (!(int_status & (ALL_INT_EXT))) {
1172#ifdef WILC_SDIO
1173 PRINT_D(TX_DBG, ">> UNKNOWN_INTERRUPT - 0x%08x\n", int_status);
1174#endif
1175 wilc_unknown_isr_ext();
1176 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001177 release_bus(RELEASE_ALLOW_SLEEP);
1178}
1179
Glen Lee63d7ab82015-10-01 16:03:32 +09001180int wilc_wlan_firmware_download(const u8 *buffer, u32 buffer_size)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001181{
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +05301182 wilc_wlan_dev_t *p = &g_wlan;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001183 u32 offset;
1184 u32 addr, size, size2, blksz;
Chaehyun Lim51e825f2015-09-15 14:06:14 +09001185 u8 *dma_buffer;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001186 int ret = 0;
1187
Anish Bhattffda2032015-09-29 12:15:49 -07001188 blksz = BIT(12);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001189
Greg Kroah-Hartmanf019b9d2015-09-03 18:50:27 -07001190 dma_buffer = kmalloc(blksz, GFP_KERNEL);
Leo Kima4b17192015-11-06 11:12:31 +09001191 if (!dma_buffer) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001192 ret = -5;
1193 PRINT_ER("Can't allocate buffer for firmware download IO error\n ");
1194 goto _fail_1;
1195 }
1196
1197 PRINT_D(INIT_DBG, "Downloading firmware size = %d ...\n", buffer_size);
Leo Kimac087c82015-11-06 11:12:25 +09001198
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001199 offset = 0;
1200 do {
1201 memcpy(&addr, &buffer[offset], 4);
1202 memcpy(&size, &buffer[offset + 4], 4);
1203#ifdef BIG_ENDIAN
1204 addr = BYTE_SWAP(addr);
1205 size = BYTE_SWAP(size);
1206#endif
1207 acquire_bus(ACQUIRE_ONLY);
1208 offset += 8;
1209 while (((int)size) && (offset < buffer_size)) {
Chandra S Gorentla78174ad2015-08-08 17:41:36 +05301210 if (size <= blksz)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001211 size2 = size;
Chandra S Gorentla78174ad2015-08-08 17:41:36 +05301212 else
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001213 size2 = blksz;
Leo Kimac087c82015-11-06 11:12:25 +09001214
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001215 memcpy(dma_buffer, &buffer[offset], size2);
1216 ret = p->hif_func.hif_block_tx(addr, dma_buffer, size2);
1217 if (!ret)
1218 break;
1219
1220 addr += size2;
1221 offset += size2;
1222 size -= size2;
1223 }
1224 release_bus(RELEASE_ONLY);
1225
1226 if (!ret) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001227 ret = -5;
1228 PRINT_ER("Can't download firmware IO error\n ");
1229 goto _fail_;
1230 }
1231 PRINT_D(INIT_DBG, "Offset = %d\n", offset);
1232 } while (offset < buffer_size);
1233
1234_fail_:
1235
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -07001236 kfree(dma_buffer);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001237
1238_fail_1:
1239
1240 return (ret < 0) ? ret : 0;
1241}
1242
Glen Leee42563b2015-10-01 16:03:33 +09001243int wilc_wlan_start(void)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001244{
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +05301245 wilc_wlan_dev_t *p = &g_wlan;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001246 u32 reg = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001247 int ret;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001248 u32 chipid;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001249
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001250 if (p->io_func.io_type == HIF_SDIO) {
1251 reg = 0;
Leo Kimac087c82015-11-06 11:12:25 +09001252 reg |= BIT(3);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001253 } else if (p->io_func.io_type == HIF_SPI) {
1254 reg = 1;
1255 }
1256 acquire_bus(ACQUIRE_ONLY);
1257 ret = p->hif_func.hif_write_reg(WILC_VMM_CORE_CFG, reg);
1258 if (!ret) {
1259 wilc_debug(N_ERR, "[wilc start]: fail write reg vmm_core_cfg...\n");
1260 release_bus(RELEASE_ONLY);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001261 ret = -5;
1262 return ret;
1263 }
1264 reg = 0;
1265#ifdef WILC_SDIO_IRQ_GPIO
1266 reg |= WILC_HAVE_SDIO_IRQ_GPIO;
1267#endif
1268
1269#ifdef WILC_DISABLE_PMU
1270#else
1271 reg |= WILC_HAVE_USE_PMU;
1272#endif
1273
1274#ifdef WILC_SLEEP_CLK_SRC_XO
1275 reg |= WILC_HAVE_SLEEP_CLK_SRC_XO;
1276#elif defined WILC_SLEEP_CLK_SRC_RTC
1277 reg |= WILC_HAVE_SLEEP_CLK_SRC_RTC;
1278#endif
1279
1280#ifdef WILC_EXT_PA_INV_TX_RX
1281 reg |= WILC_HAVE_EXT_PA_INV_TX_RX;
1282#endif
1283
1284 reg |= WILC_HAVE_LEGACY_RF_SETTINGS;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001285#ifdef XTAL_24
1286 reg |= WILC_HAVE_XTAL_24;
1287#endif
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001288#ifdef DISABLE_WILC_UART
1289 reg |= WILC_HAVE_DISABLE_WILC_UART;
1290#endif
1291
1292 ret = p->hif_func.hif_write_reg(WILC_GP_REG_1, reg);
1293 if (!ret) {
1294 wilc_debug(N_ERR, "[wilc start]: fail write WILC_GP_REG_1 ...\n");
1295 release_bus(RELEASE_ONLY);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001296 ret = -5;
1297 return ret;
1298 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001299
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001300 p->hif_func.hif_sync_ext(NUM_INT_EXT);
1301
1302 ret = p->hif_func.hif_read_reg(0x1000, &chipid);
1303 if (!ret) {
1304 wilc_debug(N_ERR, "[wilc start]: fail read reg 0x1000 ...\n");
1305 release_bus(RELEASE_ONLY);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001306 ret = -5;
1307 return ret;
1308 }
1309
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001310 p->hif_func.hif_read_reg(WILC_GLB_RESET_0, &reg);
Anish Bhattffda2032015-09-29 12:15:49 -07001311 if ((reg & BIT(10)) == BIT(10)) {
1312 reg &= ~BIT(10);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001313 p->hif_func.hif_write_reg(WILC_GLB_RESET_0, reg);
1314 p->hif_func.hif_read_reg(WILC_GLB_RESET_0, &reg);
1315 }
1316
Anish Bhattffda2032015-09-29 12:15:49 -07001317 reg |= BIT(10);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001318 ret = p->hif_func.hif_write_reg(WILC_GLB_RESET_0, reg);
1319 p->hif_func.hif_read_reg(WILC_GLB_RESET_0, &reg);
1320 release_bus(RELEASE_ONLY);
1321
1322 return (ret < 0) ? ret : 0;
1323}
1324
1325void wilc_wlan_global_reset(void)
1326{
1327
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +05301328 wilc_wlan_dev_t *p = &g_wlan;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +09001329
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001330 acquire_bus(ACQUIRE_AND_WAKEUP);
1331 p->hif_func.hif_write_reg(WILC_GLB_RESET_0, 0x0);
1332 release_bus(RELEASE_ONLY);
1333}
Glen Lee8cec7412015-10-01 16:03:34 +09001334int wilc_wlan_stop(void)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001335{
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +05301336 wilc_wlan_dev_t *p = &g_wlan;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001337 u32 reg = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001338 int ret;
Chaehyun Lim51e825f2015-09-15 14:06:14 +09001339 u8 timeout = 10;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001340 acquire_bus(ACQUIRE_AND_WAKEUP);
1341
1342 ret = p->hif_func.hif_read_reg(WILC_GLB_RESET_0, &reg);
1343 if (!ret) {
1344 PRINT_ER("Error while reading reg\n");
1345 release_bus(RELEASE_ALLOW_SLEEP);
1346 return ret;
1347 }
1348
Anish Bhattffda2032015-09-29 12:15:49 -07001349 reg &= ~BIT(10);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001350 ret = p->hif_func.hif_write_reg(WILC_GLB_RESET_0, reg);
1351 if (!ret) {
1352 PRINT_ER("Error while writing reg\n");
1353 release_bus(RELEASE_ALLOW_SLEEP);
1354 return ret;
1355 }
1356
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001357 do {
1358 ret = p->hif_func.hif_read_reg(WILC_GLB_RESET_0, &reg);
1359 if (!ret) {
1360 PRINT_ER("Error while reading reg\n");
1361 release_bus(RELEASE_ALLOW_SLEEP);
1362 return ret;
1363 }
1364 PRINT_D(GENERIC_DBG, "Read RESET Reg %x : Retry%d\n", reg, timeout);
Leo Kimac087c82015-11-06 11:12:25 +09001365
Anish Bhattffda2032015-09-29 12:15:49 -07001366 if ((reg & BIT(10))) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001367 PRINT_D(GENERIC_DBG, "Bit 10 not reset : Retry %d\n", timeout);
Anish Bhattffda2032015-09-29 12:15:49 -07001368 reg &= ~BIT(10);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001369 ret = p->hif_func.hif_write_reg(WILC_GLB_RESET_0, reg);
1370 timeout--;
1371 } else {
1372 PRINT_D(GENERIC_DBG, "Bit 10 reset after : Retry %d\n", timeout);
1373 ret = p->hif_func.hif_read_reg(WILC_GLB_RESET_0, &reg);
1374 if (!ret) {
1375 PRINT_ER("Error while reading reg\n");
1376 release_bus(RELEASE_ALLOW_SLEEP);
1377 return ret;
1378 }
1379 PRINT_D(GENERIC_DBG, "Read RESET Reg %x : Retry%d\n", reg, timeout);
1380 break;
1381 }
1382
1383 } while (timeout);
Anish Bhattffda2032015-09-29 12:15:49 -07001384 reg = (BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(8) | BIT(9) | BIT(26) |
1385 BIT(29) | BIT(30) | BIT(31));
Anish Bhatt65ead4e2015-09-29 12:15:48 -07001386
1387 p->hif_func.hif_write_reg(WILC_GLB_RESET_0, reg);
Anish Bhattffda2032015-09-29 12:15:49 -07001388 reg = (u32)~BIT(10);
Anish Bhatt65ead4e2015-09-29 12:15:48 -07001389
1390 ret = p->hif_func.hif_write_reg(WILC_GLB_RESET_0, reg);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001391
1392 release_bus(RELEASE_ALLOW_SLEEP);
1393
1394 return ret;
1395}
1396
Glen Lee2de7cbe2015-10-27 18:27:54 +09001397void wilc_wlan_cleanup(struct net_device *dev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001398{
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +05301399 wilc_wlan_dev_t *p = &g_wlan;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001400 struct txq_entry_t *tqe;
1401 struct rxq_entry_t *rqe;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001402 u32 reg = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001403 int ret;
Glen Leedb387632015-10-27 18:27:55 +09001404 perInterface_wlan_t *nic;
1405 struct wilc *wilc;
1406
1407 nic = netdev_priv(dev);
1408 wilc = nic->wilc;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001409
1410 p->quit = 1;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001411 do {
Glen Lee718fc2c2015-10-29 12:18:43 +09001412 tqe = wilc_wlan_txq_remove_from_head(dev);
Leo Kima4b17192015-11-06 11:12:31 +09001413 if (!tqe)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001414 break;
1415 if (tqe->tx_complete_func)
1416 tqe->tx_complete_func(tqe->priv, 0);
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -07001417 kfree(tqe);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001418 } while (1);
1419
1420 do {
Glen Leedb387632015-10-27 18:27:55 +09001421 rqe = wilc_wlan_rxq_remove(wilc);
Leo Kima4b17192015-11-06 11:12:31 +09001422 if (!rqe)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001423 break;
Javier Martinez Canillas6a272242015-09-22 15:24:50 +02001424#ifndef MEMORY_STATIC
1425 kfree(rqe->buffer);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001426#endif
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -07001427 kfree(rqe);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001428 } while (1);
1429
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001430 #ifdef MEMORY_STATIC
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -07001431 kfree(p->rx_buffer);
1432 p->rx_buffer = NULL;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001433 #endif
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -07001434 kfree(p->tx_buffer);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001435
1436 acquire_bus(ACQUIRE_AND_WAKEUP);
1437
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001438 ret = p->hif_func.hif_read_reg(WILC_GP_REG_0, &reg);
1439 if (!ret) {
1440 PRINT_ER("Error while reading reg\n");
1441 release_bus(RELEASE_ALLOW_SLEEP);
1442 }
1443 PRINT_ER("Writing ABORT reg\n");
1444 ret = p->hif_func.hif_write_reg(WILC_GP_REG_0, (reg | ABORT_INT));
1445 if (!ret) {
1446 PRINT_ER("Error while writing reg\n");
1447 release_bus(RELEASE_ALLOW_SLEEP);
1448 }
1449 release_bus(RELEASE_ALLOW_SLEEP);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001450 p->hif_func.hif_deinit(NULL);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001451}
1452
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001453static int wilc_wlan_cfg_commit(int type, u32 drvHandler)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001454{
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +05301455 wilc_wlan_dev_t *p = &g_wlan;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001456 wilc_cfg_frame_t *cfg = &p->cfg_frame;
1457 int total_len = p->cfg_frame_offset + 4 + DRIVER_HANDLER_SIZE;
1458 int seq_no = p->cfg_seq_no % 256;
Chaehyun Lim4e4467f2015-06-11 14:35:55 +09001459 int driver_handler = (u32)drvHandler;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001460
Leo Kimac087c82015-11-06 11:12:25 +09001461 if (type == WILC_CFG_SET) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001462 cfg->wid_header[0] = 'W';
Leo Kimac087c82015-11-06 11:12:25 +09001463 } else {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001464 cfg->wid_header[0] = 'Q';
1465 }
Leo Kimac087c82015-11-06 11:12:25 +09001466 cfg->wid_header[1] = seq_no;
Chaehyun Lim51e825f2015-09-15 14:06:14 +09001467 cfg->wid_header[2] = (u8)total_len;
1468 cfg->wid_header[3] = (u8)(total_len >> 8);
1469 cfg->wid_header[4] = (u8)driver_handler;
1470 cfg->wid_header[5] = (u8)(driver_handler >> 8);
1471 cfg->wid_header[6] = (u8)(driver_handler >> 16);
1472 cfg->wid_header[7] = (u8)(driver_handler >> 24);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001473 p->cfg_seq_no = seq_no;
1474
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001475 if (!wilc_wlan_txq_add_cfg_pkt(&cfg->wid_header[0], total_len))
1476 return -1;
1477
1478 return 0;
1479}
1480
Glen Lee1028e5a2015-10-01 16:03:40 +09001481int wilc_wlan_cfg_set(int start, u32 wid, u8 *buffer, u32 buffer_size,
1482 int commit, u32 drvHandler)
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 offset;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001486 int ret_size;
1487
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001488 if (p->cfg_frame_in_use)
1489 return 0;
1490
1491 if (start)
1492 p->cfg_frame_offset = 0;
1493
1494 offset = p->cfg_frame_offset;
Glen Lee17e8f162015-10-02 14:22:07 +09001495 ret_size = wilc_wlan_cfg_set_wid(p->cfg_frame.frame, offset, (u16)wid,
1496 buffer, buffer_size);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001497 offset += ret_size;
1498 p->cfg_frame_offset = offset;
1499
1500 if (commit) {
1501 PRINT_D(TX_DBG, "[WILC]PACKET Commit with sequence number %d\n", p->cfg_seq_no);
1502 PRINT_D(RX_DBG, "Processing cfg_set()\n");
1503 p->cfg_frame_in_use = 1;
1504
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001505 if (wilc_wlan_cfg_commit(WILC_CFG_SET, drvHandler))
Chaehyun Lim5af6b852015-09-17 16:48:48 +09001506 ret_size = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001507
Glen Leeb002e202015-09-24 18:15:05 +09001508 if (linux_wlan_lock_timeout(&g_linux_wlan->cfg_event,
1509 CFG_PKTS_TIMEOUT)) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001510 PRINT_D(TX_DBG, "Set Timed Out\n");
1511 ret_size = 0;
1512 }
1513 p->cfg_frame_in_use = 0;
1514 p->cfg_frame_offset = 0;
1515 p->cfg_seq_no += 1;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001516 }
1517
1518 return ret_size;
1519}
Leo Kim2d6973e2015-11-06 11:12:28 +09001520
Glen Lee07056a82015-10-01 16:03:41 +09001521int wilc_wlan_cfg_get(int start, u32 wid, int commit, u32 drvHandler)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001522{
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +05301523 wilc_wlan_dev_t *p = &g_wlan;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001524 u32 offset;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001525 int ret_size;
1526
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001527 if (p->cfg_frame_in_use)
1528 return 0;
1529
1530 if (start)
1531 p->cfg_frame_offset = 0;
1532
1533 offset = p->cfg_frame_offset;
Glen Leeec1b86b2015-10-02 14:22:08 +09001534 ret_size = wilc_wlan_cfg_get_wid(p->cfg_frame.frame, offset, (u16)wid);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001535 offset += ret_size;
1536 p->cfg_frame_offset = offset;
1537
1538 if (commit) {
1539 p->cfg_frame_in_use = 1;
1540
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001541 if (wilc_wlan_cfg_commit(WILC_CFG_QUERY, drvHandler))
Chaehyun Lim5af6b852015-09-17 16:48:48 +09001542 ret_size = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001543
Glen Leeb002e202015-09-24 18:15:05 +09001544 if (linux_wlan_lock_timeout(&g_linux_wlan->cfg_event,
1545 CFG_PKTS_TIMEOUT)) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001546 PRINT_D(TX_DBG, "Get Timed Out\n");
1547 ret_size = 0;
1548 }
1549 PRINT_D(GENERIC_DBG, "[WILC]Get Response received\n");
1550 p->cfg_frame_in_use = 0;
1551 p->cfg_frame_offset = 0;
1552 p->cfg_seq_no += 1;
1553 }
1554
1555 return ret_size;
1556}
1557
Glen Lee894de36b2015-10-01 16:03:42 +09001558int wilc_wlan_cfg_get_val(u32 wid, u8 *buffer, u32 buffer_size)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001559{
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001560 int ret;
1561
Glen Lee355cca22015-10-02 14:22:09 +09001562 ret = wilc_wlan_cfg_get_wid_value((u16)wid, buffer, buffer_size);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001563
1564 return ret;
1565}
1566
1567void wilc_bus_set_max_speed(void)
1568{
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001569 g_wlan.hif_func.hif_set_max_bus_speed();
1570}
1571
1572void wilc_bus_set_default_speed(void)
1573{
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001574 g_wlan.hif_func.hif_set_default_bus_speed();
1575}
Leo Kim2d6973e2015-11-06 11:12:28 +09001576
Glen Leeae6f7722015-10-29 12:18:48 +09001577u32 init_chip(struct net_device *dev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001578{
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001579 u32 chipid;
1580 u32 reg, ret = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001581
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001582 acquire_bus(ACQUIRE_ONLY);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001583
Dean Lee72ed4dc2015-06-12 14:11:44 +09001584 chipid = wilc_get_chipid(true);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001585
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001586 if ((chipid & 0xfff) != 0xa0) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001587 ret = g_wlan.hif_func.hif_read_reg(0x1118, &reg);
1588 if (!ret) {
1589 wilc_debug(N_ERR, "[wilc start]: fail read reg 0x1118 ...\n");
1590 return ret;
1591 }
Anish Bhattffda2032015-09-29 12:15:49 -07001592 reg |= BIT(0);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001593 ret = g_wlan.hif_func.hif_write_reg(0x1118, reg);
1594 if (!ret) {
1595 wilc_debug(N_ERR, "[wilc start]: fail write reg 0x1118 ...\n");
1596 return ret;
1597 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001598 ret = g_wlan.hif_func.hif_write_reg(0xc0000, 0x71);
1599 if (!ret) {
1600 wilc_debug(N_ERR, "[wilc start]: fail write reg 0xc0000 ...\n");
1601 return ret;
1602 }
1603 }
1604
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001605 release_bus(RELEASE_ONLY);
1606
1607 return ret;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001608}
1609
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001610u32 wilc_get_chipid(u8 update)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001611{
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001612 static u32 chipid;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001613 u32 tempchipid = 0;
1614 u32 rfrevid;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001615
1616 if (chipid == 0 || update != 0) {
1617 g_wlan.hif_func.hif_read_reg(0x1000, &tempchipid);
1618 g_wlan.hif_func.hif_read_reg(0x13f4, &rfrevid);
1619 if (!ISWILC1000(tempchipid)) {
1620 chipid = 0;
1621 goto _fail_;
1622 }
1623 if (tempchipid == 0x1002a0) {
Leo Kimac087c82015-11-06 11:12:25 +09001624 if (rfrevid == 0x1) {
1625 } else {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001626 tempchipid = 0x1002a1;
1627 }
1628 } else if (tempchipid == 0x1002b0) {
Leo Kimac087c82015-11-06 11:12:25 +09001629 if (rfrevid == 3) {
1630 } else if (rfrevid == 4) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001631 tempchipid = 0x1002b1;
Leo Kimac087c82015-11-06 11:12:25 +09001632 } else {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001633 tempchipid = 0x1002b2;
1634 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001635 }
1636
1637 chipid = tempchipid;
1638 }
1639_fail_:
1640 return chipid;
1641}
1642
Glen Lee47a466f2015-10-29 12:18:47 +09001643int wilc_wlan_init(struct net_device *dev, wilc_wlan_inp_t *inp)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001644{
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001645 int ret = 0;
1646
1647 PRINT_D(INIT_DBG, "Initializing WILC_Wlan ...\n");
1648
1649 memset((void *)&g_wlan, 0, sizeof(wilc_wlan_dev_t));
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001650 memcpy((void *)&g_wlan.io_func, (void *)&inp->io_func, sizeof(wilc_wlan_io_func_t));
Leo Kimac087c82015-11-06 11:12:25 +09001651
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001652 if ((inp->io_func.io_type & 0x1) == HIF_SDIO) {
1653 if (!hif_sdio.hif_init(inp, wilc_debug)) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001654 ret = -5;
1655 goto _fail_;
1656 }
1657 memcpy((void *)&g_wlan.hif_func, &hif_sdio, sizeof(wilc_hif_func_t));
1658 } else {
1659 if ((inp->io_func.io_type & 0x1) == HIF_SPI) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001660 if (!hif_spi.hif_init(inp, wilc_debug)) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001661 ret = -5;
1662 goto _fail_;
1663 }
1664 memcpy((void *)&g_wlan.hif_func, &hif_spi, sizeof(wilc_hif_func_t));
1665 } else {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001666 ret = -5;
1667 goto _fail_;
1668 }
1669 }
1670
Glen Lee814bc362015-10-02 14:22:11 +09001671 if (!wilc_wlan_cfg_init(wilc_debug)) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001672 ret = -105;
1673 goto _fail_;
1674 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001675
Leo Kima4b17192015-11-06 11:12:31 +09001676 if (!g_wlan.tx_buffer)
Glen Lee7015b5d2015-09-24 18:15:02 +09001677 g_wlan.tx_buffer = kmalloc(LINUX_TX_SIZE, GFP_KERNEL);
Arnd Bergmann7a8fd842015-06-01 21:06:45 +02001678 PRINT_D(TX_DBG, "g_wlan.tx_buffer = %p\n", g_wlan.tx_buffer);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001679
Leo Kima4b17192015-11-06 11:12:31 +09001680 if (!g_wlan.tx_buffer) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001681 ret = -105;
1682 PRINT_ER("Can't allocate Tx Buffer");
1683 goto _fail_;
1684 }
1685
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001686#if defined (MEMORY_STATIC)
Leo Kima4b17192015-11-06 11:12:31 +09001687 if (!g_wlan.rx_buffer)
Glen Lee03eb7262015-09-24 18:15:03 +09001688 g_wlan.rx_buffer = kmalloc(LINUX_RX_SIZE, GFP_KERNEL);
Arnd Bergmann7a8fd842015-06-01 21:06:45 +02001689 PRINT_D(TX_DBG, "g_wlan.rx_buffer =%p\n", g_wlan.rx_buffer);
Leo Kima4b17192015-11-06 11:12:31 +09001690 if (!g_wlan.rx_buffer) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001691 ret = -105;
1692 PRINT_ER("Can't allocate Rx Buffer");
1693 goto _fail_;
1694 }
1695#endif
1696
Glen Leeae6f7722015-10-29 12:18:48 +09001697 if (!init_chip(dev)) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001698 ret = -5;
1699 goto _fail_;
1700 }
1701#ifdef TCP_ACK_FILTER
Leo Kimef06b5f2015-11-06 11:12:44 +09001702 init_tcp_tracking();
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001703#endif
1704
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001705 return 1;
1706
1707_fail_:
1708
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001709 #ifdef MEMORY_STATIC
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -07001710 kfree(g_wlan.rx_buffer);
1711 g_wlan.rx_buffer = NULL;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001712 #endif
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -07001713 kfree(g_wlan.tx_buffer);
1714 g_wlan.tx_buffer = NULL;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001715
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001716 return ret;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001717}
1718
Leo Kim2ad8c472015-11-05 14:36:35 +09001719u16 set_machw_change_vir_if(struct net_device *dev, bool bValue)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001720{
Chaehyun Limd85f5322015-06-11 14:35:54 +09001721 u16 ret;
Chaehyun Lim4e4467f2015-06-11 14:35:55 +09001722 u32 reg;
Glen Lee178c3832015-10-27 18:27:58 +09001723 perInterface_wlan_t *nic;
1724 struct wilc *wilc;
1725
1726 nic = netdev_priv(dev);
1727 wilc = nic->wilc;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001728
Glen Lee178c3832015-10-27 18:27:58 +09001729 mutex_lock(&wilc->hif_cs);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001730 ret = (&g_wlan)->hif_func.hif_read_reg(WILC_CHANGING_VIR_IF, &reg);
Alison Schofield39823a52015-10-08 21:18:03 -07001731 if (!ret)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001732 PRINT_ER("Error while Reading reg WILC_CHANGING_VIR_IF\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001733
Chandra S Gorentla78174ad2015-08-08 17:41:36 +05301734 if (bValue)
Chaehyun Lim50b51da2015-09-16 20:11:26 +09001735 reg |= BIT(31);
Chandra S Gorentla78174ad2015-08-08 17:41:36 +05301736 else
Chaehyun Lim50b51da2015-09-16 20:11:26 +09001737 reg &= ~BIT(31);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001738
1739 ret = (&g_wlan)->hif_func.hif_write_reg(WILC_CHANGING_VIR_IF, reg);
1740
Alison Schofield39823a52015-10-08 21:18:03 -07001741 if (!ret)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001742 PRINT_ER("Error while writing reg WILC_CHANGING_VIR_IF\n");
Alison Schofield39823a52015-10-08 21:18:03 -07001743
Glen Lee178c3832015-10-27 18:27:58 +09001744 mutex_unlock(&wilc->hif_cs);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001745
1746 return ret;
1747}