blob: a1b6067e12ed356d57fc7672d1224818c7587ab8 [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;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900222u32 Opened_TCP_session;
223u32 Pending_Acks;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900224
Chaehyun Limfed16f22015-09-17 16:48:43 +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
Chaehyun Limfed16f22015-09-17 16:48:43 +0900230static inline int add_TCP_track_session(u32 src_prt, u32 dst_prt, u32 seq)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900231{
Leo Kim32065052015-11-06 11:12:39 +0900232 ack_session_info[Opened_TCP_session].seq_num = seq;
233 ack_session_info[Opened_TCP_session].bigger_ack_num = 0;
234 ack_session_info[Opened_TCP_session].src_port = src_prt;
235 ack_session_info[Opened_TCP_session].dst_port = dst_prt;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900236 Opened_TCP_session++;
237
238 PRINT_D(TCP_ENH, "TCP Session %d to Ack %d\n", Opened_TCP_session, seq);
239 return 0;
240}
241
Chaehyun Limfed16f22015-09-17 16:48:43 +0900242static inline int Update_TCP_track_session(u32 index, u32 Ack)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900243{
Leo Kim32065052015-11-06 11:12:39 +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
Chaehyun Limfed16f22015-09-17 16:48:43 +0900249static inline int add_TCP_Pending_Ack(u32 Ack, u32 Session_index, struct txq_entry_t *txqe)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900250{
Leo Kim821466d2015-11-06 11:12:32 +0900251 total_acks++;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900252 if (Pending_Acks < MAX_PENDING_ACKS) {
Leo Kim2ae91ed2015-11-06 11:12:41 +0900253 pending_acks_info[pending_base + Pending_Acks].ack_num = Ack;
254 pending_acks_info[pending_base + Pending_Acks].txqe = txqe;
255 pending_acks_info[pending_base + Pending_Acks].session_index = Session_index;
256 txqe->tcp_PendingAck_index = pending_base + Pending_Acks;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900257 Pending_Acks++;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900258 } else {
259
260 }
261 return 0;
262}
Chaehyun Limfed16f22015-09-17 16:48:43 +0900263static inline int remove_TCP_related(void)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900264{
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +0530265 wilc_wlan_dev_t *p = &g_wlan;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900266 unsigned long flags;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900267
Glen Lee85e57562015-09-24 18:14:56 +0900268 spin_lock_irqsave(&g_linux_wlan->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900269
Glen Lee85e57562015-09-24 18:14:56 +0900270 spin_unlock_irqrestore(&g_linux_wlan->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900271 return 0;
272}
273
Glen Lee82bb18e2015-10-27 18:28:03 +0900274static inline int tcp_process(struct net_device *dev, struct txq_entry_t *tqe)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900275{
276 int ret;
Chaehyun Lim51e825f2015-09-15 14:06:14 +0900277 u8 *eth_hdr_ptr;
278 u8 *buffer = tqe->buffer;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900279 unsigned short h_proto;
280 int i;
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +0530281 wilc_wlan_dev_t *p = &g_wlan;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900282 unsigned long flags;
Glen Lee82bb18e2015-10-27 18:28:03 +0900283 perInterface_wlan_t *nic;
284 struct wilc *wilc;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900285
Glen Lee82bb18e2015-10-27 18:28:03 +0900286 nic = netdev_priv(dev);
287 wilc = nic->wilc;
288
289 spin_lock_irqsave(&wilc->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900290
291 eth_hdr_ptr = &buffer[0];
292 h_proto = ntohs(*((unsigned short *)&eth_hdr_ptr[12]));
Leo Kimac087c82015-11-06 11:12:25 +0900293 if (h_proto == 0x0800) {
Chaehyun Lim51e825f2015-09-15 14:06:14 +0900294 u8 *ip_hdr_ptr;
295 u8 protocol;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900296
297 ip_hdr_ptr = &buffer[ETHERNET_HDR_LEN];
298 protocol = ip_hdr_ptr[9];
299
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900300 if (protocol == 0x06) {
Chaehyun Lim51e825f2015-09-15 14:06:14 +0900301 u8 *tcp_hdr_ptr;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900302 u32 IHL, Total_Length, Data_offset;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900303
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900304 tcp_hdr_ptr = &ip_hdr_ptr[IP_HDR_LEN];
305 IHL = (ip_hdr_ptr[0] & 0xf) << 2;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900306 Total_Length = (((u32)ip_hdr_ptr[2]) << 8) + ((u32)ip_hdr_ptr[3]);
307 Data_offset = (((u32)tcp_hdr_ptr[12] & 0xf0) >> 2);
Leo Kimac087c82015-11-06 11:12:25 +0900308 if (Total_Length == (IHL + Data_offset)) {
Chaehyun Limfbc2fe12015-09-15 14:06:16 +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
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900313 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 +0900314
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900315 for (i = 0; i < Opened_TCP_session; i++) {
Leo Kim32065052015-11-06 11:12:39 +0900316 if (ack_session_info[i].seq_num == seq_no) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900317 Update_TCP_track_session(i, Ack_no);
318 break;
319 }
320 }
Alison Schofield39823a52015-10-08 21:18:03 -0700321 if (i == Opened_TCP_session)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900322 add_TCP_track_session(0, 0, seq_no);
Alison Schofield39823a52015-10-08 21:18:03 -0700323
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900324 add_TCP_Pending_Ack(Ack_no, i, tqe);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900325 }
326
327 } else {
328 ret = 0;
329 }
330 } else {
331 ret = 0;
332 }
Glen Lee82bb18e2015-10-27 18:28:03 +0900333 spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900334 return ret;
335}
336
Glen Leec029e992015-10-27 18:27:48 +0900337static int wilc_wlan_txq_filter_dup_tcp_ack(struct net_device *dev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900338{
Glen Leec029e992015-10-27 18:27:48 +0900339 perInterface_wlan_t *nic;
340 struct wilc *wilc;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900341 u32 i = 0;
342 u32 Dropped = 0;
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +0530343 wilc_wlan_dev_t *p = &g_wlan;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900344
Glen Leec029e992015-10-27 18:27:48 +0900345 nic = netdev_priv(dev);
346 wilc = nic->wilc;
347
348 spin_lock_irqsave(&wilc->txq_spinlock, p->txq_spinlock_flags);
Leo Kim2ae91ed2015-11-06 11:12:41 +0900349 for (i = pending_base; i < (pending_base + Pending_Acks); i++) {
Leo Kim2bb17082015-11-06 11:12:40 +0900350 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 +0900351 struct txq_entry_t *tqe;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900352
Leo Kim2bb17082015-11-06 11:12:40 +0900353 PRINT_D(TCP_ENH, "DROP ACK: %u\n",
354 pending_acks_info[i].ack_num);
355 tqe = pending_acks_info[i].txqe;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900356 if (tqe) {
357 wilc_wlan_txq_remove(tqe);
Leo Kimeb59da32015-11-06 11:12:33 +0900358 dropped_acks++;
Leo Kimac087c82015-11-06 11:12:25 +0900359 tqe->status = 1;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900360 if (tqe->tx_complete_func)
361 tqe->tx_complete_func(tqe->priv, tqe->status);
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -0700362 kfree(tqe);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900363 Dropped++;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900364 }
365 }
366 }
367 Pending_Acks = 0;
368 Opened_TCP_session = 0;
369
Leo Kim2ae91ed2015-11-06 11:12:41 +0900370 if (pending_base == 0)
371 pending_base = MAX_TCP_SESSION;
Chandra S Gorentla78174ad2015-08-08 17:41:36 +0530372 else
Leo Kim2ae91ed2015-11-06 11:12:41 +0900373 pending_base = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900374
Glen Leec029e992015-10-27 18:27:48 +0900375 spin_unlock_irqrestore(&wilc->txq_spinlock, p->txq_spinlock_flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900376
377 while (Dropped > 0) {
Glen Leec029e992015-10-27 18:27:48 +0900378 linux_wlan_lock_timeout(&wilc->txq_event, 1);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900379 Dropped--;
380 }
381
382 return 1;
383}
384#endif
385
Dean Lee72ed4dc2015-06-12 14:11:44 +0900386bool EnableTCPAckFilter = false;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900387
Dean Lee72ed4dc2015-06-12 14:11:44 +0900388void Enable_TCP_ACK_Filter(bool value)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900389{
390 EnableTCPAckFilter = value;
391}
392
Dean Lee72ed4dc2015-06-12 14:11:44 +0900393bool is_TCP_ACK_Filter_Enabled(void)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900394{
395 return EnableTCPAckFilter;
396}
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900397
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900398static int wilc_wlan_txq_add_cfg_pkt(u8 *buffer, u32 buffer_size)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900399{
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +0530400 wilc_wlan_dev_t *p = &g_wlan;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900401 struct txq_entry_t *tqe;
402
403 PRINT_D(TX_DBG, "Adding config packet ...\n");
404 if (p->quit) {
405 PRINT_D(TX_DBG, "Return due to clear function\n");
Glen Lee6a3b94f2015-09-24 18:14:59 +0900406 up(&g_linux_wlan->cfg_event);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900407 return 0;
408 }
409
Greg Kroah-Hartman47c632d2015-09-03 18:55:43 -0700410 tqe = kmalloc(sizeof(struct txq_entry_t), GFP_ATOMIC);
Leo Kima4b17192015-11-06 11:12:31 +0900411 if (!tqe) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900412 PRINT_ER("Failed to allocate memory\n");
413 return 0;
414 }
415
416 tqe->type = WILC_CFG_PKT;
417 tqe->buffer = buffer;
418 tqe->buffer_size = buffer_size;
419 tqe->tx_complete_func = NULL;
420 tqe->priv = NULL;
421#ifdef TCP_ACK_FILTER
422 tqe->tcp_PendingAck_index = NOT_TCP_ACK;
423#endif
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900424 PRINT_D(TX_DBG, "Adding the config packet at the Queue tail\n");
425
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900426 if (wilc_wlan_txq_add_to_head(tqe))
427 return 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900428 return 1;
429}
430
Glen Lee691bbd42015-10-27 18:28:02 +0900431int wilc_wlan_txq_add_net_pkt(struct net_device *dev, void *priv, u8 *buffer,
432 u32 buffer_size, wilc_tx_complete_func_t func)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900433{
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +0530434 wilc_wlan_dev_t *p = &g_wlan;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900435 struct txq_entry_t *tqe;
436
437 if (p->quit)
438 return 0;
439
Greg Kroah-Hartman47c632d2015-09-03 18:55:43 -0700440 tqe = kmalloc(sizeof(struct txq_entry_t), GFP_ATOMIC);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900441
Leo Kima4b17192015-11-06 11:12:31 +0900442 if (!tqe)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900443 return 0;
444 tqe->type = WILC_NET_PKT;
445 tqe->buffer = buffer;
446 tqe->buffer_size = buffer_size;
447 tqe->tx_complete_func = func;
448 tqe->priv = priv;
449
450 PRINT_D(TX_DBG, "Adding mgmt packet at the Queue tail\n");
451#ifdef TCP_ACK_FILTER
452 tqe->tcp_PendingAck_index = NOT_TCP_ACK;
Abdul Hussain5a66bf22015-06-16 09:44:06 +0000453 if (is_TCP_ACK_Filter_Enabled())
Glen Lee82bb18e2015-10-27 18:28:03 +0900454 tcp_process(dev, tqe);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900455#endif
Glen Lee32f03322015-10-29 12:18:45 +0900456 wilc_wlan_txq_add_to_tail(dev, tqe);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900457 return p->txq_entries;
458}
Glen Leefcc6ef92015-09-16 18:53:21 +0900459
Glen Lee829c4772015-10-29 12:18:44 +0900460int wilc_wlan_txq_add_mgmt_pkt(struct net_device *dev, void *priv, u8 *buffer,
461 u32 buffer_size, wilc_tx_complete_func_t func)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900462{
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +0530463 wilc_wlan_dev_t *p = &g_wlan;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900464 struct txq_entry_t *tqe;
465
466 if (p->quit)
467 return 0;
468
Greg Kroah-Hartman47c632d2015-09-03 18:55:43 -0700469 tqe = kmalloc(sizeof(struct txq_entry_t), GFP_KERNEL);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900470
Leo Kima4b17192015-11-06 11:12:31 +0900471 if (!tqe)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900472 return 0;
473 tqe->type = WILC_MGMT_PKT;
474 tqe->buffer = buffer;
475 tqe->buffer_size = buffer_size;
476 tqe->tx_complete_func = func;
477 tqe->priv = priv;
478#ifdef TCP_ACK_FILTER
479 tqe->tcp_PendingAck_index = NOT_TCP_ACK;
480#endif
481 PRINT_D(TX_DBG, "Adding Network packet at the Queue tail\n");
Glen Lee32f03322015-10-29 12:18:45 +0900482 wilc_wlan_txq_add_to_tail(dev, tqe);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900483 return 1;
484}
Glen Leefcc6ef92015-09-16 18:53:21 +0900485
Glen Lee7af05222015-10-29 12:18:41 +0900486static struct txq_entry_t *wilc_wlan_txq_get_first(struct wilc *wilc)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900487{
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +0530488 wilc_wlan_dev_t *p = &g_wlan;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900489 struct txq_entry_t *tqe;
490 unsigned long flags;
491
Glen Lee7af05222015-10-29 12:18:41 +0900492 spin_lock_irqsave(&wilc->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900493
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900494 tqe = p->txq_head;
495
Glen Lee7af05222015-10-29 12:18:41 +0900496 spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900497
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900498 return tqe;
499}
500
Glen Lee50a0b3b2015-10-27 18:28:00 +0900501static struct txq_entry_t *wilc_wlan_txq_get_next(struct wilc *wilc,
502 struct txq_entry_t *tqe)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900503{
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900504 unsigned long flags;
Leo Kim8739eeb2015-11-06 11:12:29 +0900505
Glen Lee50a0b3b2015-10-27 18:28:00 +0900506 spin_lock_irqsave(&wilc->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900507
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900508 tqe = tqe->next;
Glen Lee50a0b3b2015-10-27 18:28:00 +0900509 spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900510
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900511 return tqe;
512}
513
Glen Leed06f3622015-10-27 18:27:59 +0900514static int wilc_wlan_rxq_add(struct wilc *wilc, struct rxq_entry_t *rqe)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900515{
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +0530516 wilc_wlan_dev_t *p = &g_wlan;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900517
518 if (p->quit)
519 return 0;
520
Glen Leed06f3622015-10-27 18:27:59 +0900521 mutex_lock(&wilc->rxq_cs);
Leo Kima4b17192015-11-06 11:12:31 +0900522 if (!p->rxq_head) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900523 PRINT_D(RX_DBG, "Add to Queue head\n");
524 rqe->next = NULL;
525 p->rxq_head = rqe;
526 p->rxq_tail = rqe;
527 } else {
528 PRINT_D(RX_DBG, "Add to Queue tail\n");
529 p->rxq_tail->next = rqe;
530 rqe->next = NULL;
531 p->rxq_tail = rqe;
532 }
533 p->rxq_entries += 1;
534 PRINT_D(RX_DBG, "Number of queue entries: %d\n", p->rxq_entries);
Glen Leed06f3622015-10-27 18:27:59 +0900535 mutex_unlock(&wilc->rxq_cs);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900536 return p->rxq_entries;
537}
538
Glen Leedb387632015-10-27 18:27:55 +0900539static struct rxq_entry_t *wilc_wlan_rxq_remove(struct wilc *wilc)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900540{
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +0530541 wilc_wlan_dev_t *p = &g_wlan;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900542
543 PRINT_D(RX_DBG, "Getting rxQ element\n");
544 if (p->rxq_head) {
545 struct rxq_entry_t *rqe;
546
Glen Leedb387632015-10-27 18:27:55 +0900547 mutex_lock(&wilc->rxq_cs);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900548 rqe = p->rxq_head;
549 p->rxq_head = p->rxq_head->next;
550 p->rxq_entries -= 1;
551 PRINT_D(RX_DBG, "RXQ entries decreased\n");
Glen Leedb387632015-10-27 18:27:55 +0900552 mutex_unlock(&wilc->rxq_cs);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900553 return rqe;
554 }
555 PRINT_D(RX_DBG, "Nothing to get from Q\n");
556 return NULL;
557}
558
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900559#ifdef WILC_OPTIMIZE_SLEEP_INT
560
Chaehyun Lim9af382b2015-09-16 20:11:27 +0900561static inline void chip_allow_sleep(void)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900562{
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900563 u32 reg = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900564
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900565 g_wlan.hif_func.hif_read_reg(0xf0, &reg);
566
Anish Bhattffda2032015-09-29 12:15:49 -0700567 g_wlan.hif_func.hif_write_reg(0xf0, reg & ~BIT(0));
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900568}
569
Chaehyun Lim9af382b2015-09-16 20:11:27 +0900570static inline void chip_wakeup(void)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900571{
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900572 u32 reg, clk_status_reg, trials = 0;
573 u32 sleep_time;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900574
575 if ((g_wlan.io_func.io_type & 0x1) == HIF_SPI) {
576 do {
577 g_wlan.hif_func.hif_read_reg(1, &reg);
Anish Bhattffda2032015-09-29 12:15:49 -0700578 g_wlan.hif_func.hif_write_reg(1, reg | BIT(1));
Anish Bhattffda2032015-09-29 12:15:49 -0700579 g_wlan.hif_func.hif_write_reg(1, reg & ~BIT(1));
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900580
581 do {
Greg Kroah-Hartman80e29c72015-08-14 19:42:23 -0700582 usleep_range(2 * 1000, 2 * 1000);
Alison Schofield39823a52015-10-08 21:18:03 -0700583 if ((wilc_get_chipid(true) == 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900584 wilc_debug(N_ERR, "Couldn't read chip id. Wake up failed\n");
Alison Schofield39823a52015-10-08 21:18:03 -0700585
Dean Lee72ed4dc2015-06-12 14:11:44 +0900586 } while ((wilc_get_chipid(true) == 0) && ((++trials % 3) == 0));
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900587
Dean Lee72ed4dc2015-06-12 14:11:44 +0900588 } while (wilc_get_chipid(true) == 0);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900589 } else if ((g_wlan.io_func.io_type & 0x1) == HIF_SDIO) {
590 g_wlan.hif_func.hif_read_reg(0xf0, &reg);
591 do {
Anish Bhattffda2032015-09-29 12:15:49 -0700592 g_wlan.hif_func.hif_write_reg(0xf0, reg | BIT(0));
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900593 g_wlan.hif_func.hif_read_reg(0xf1, &clk_status_reg);
594
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900595 while (((clk_status_reg & 0x1) == 0) && (((++trials) % 3) == 0)) {
Greg Kroah-Hartman80e29c72015-08-14 19:42:23 -0700596 usleep_range(2 * 1000, 2 * 1000);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900597
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900598 g_wlan.hif_func.hif_read_reg(0xf1, &clk_status_reg);
599
Alison Schofield39823a52015-10-08 21:18:03 -0700600 if ((clk_status_reg & 0x1) == 0)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900601 wilc_debug(N_ERR, "clocks still OFF. Wake up failed\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900602 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900603 if ((clk_status_reg & 0x1) == 0) {
Anish Bhattffda2032015-09-29 12:15:49 -0700604 g_wlan.hif_func.hif_write_reg(0xf0, reg &
605 (~BIT(0)));
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900606 }
607 } while ((clk_status_reg & 0x1) == 0);
608 }
609
Leo Kimb7d1e182015-11-06 11:12:30 +0900610 if (chip_ps_state == CHIP_SLEEPING_MANUAL) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900611 g_wlan.hif_func.hif_read_reg(0x1C0C, &reg);
Anish Bhattffda2032015-09-29 12:15:49 -0700612 reg &= ~BIT(0);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900613 g_wlan.hif_func.hif_write_reg(0x1C0C, reg);
614
Dean Lee72ed4dc2015-06-12 14:11:44 +0900615 if (wilc_get_chipid(false) >= 0x1002b0) {
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900616 u32 val32;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900617
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900618 g_wlan.hif_func.hif_read_reg(0x1e1c, &val32);
Anish Bhattffda2032015-09-29 12:15:49 -0700619 val32 |= BIT(6);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900620 g_wlan.hif_func.hif_write_reg(0x1e1c, val32);
621
622 g_wlan.hif_func.hif_read_reg(0x1e9c, &val32);
Anish Bhattffda2032015-09-29 12:15:49 -0700623 val32 |= BIT(6);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900624 g_wlan.hif_func.hif_write_reg(0x1e9c, val32);
625 }
626 }
Leo Kimb7d1e182015-11-06 11:12:30 +0900627 chip_ps_state = CHIP_WAKEDUP;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900628}
629#else
Chaehyun Lim9af382b2015-09-16 20:11:27 +0900630static inline void chip_wakeup(void)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900631{
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900632 u32 reg, trials = 0;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900633
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900634 do {
635 if ((g_wlan.io_func.io_type & 0x1) == HIF_SPI) {
636 g_wlan.hif_func.hif_read_reg(1, &reg);
Anish Bhattffda2032015-09-29 12:15:49 -0700637 g_wlan.hif_func.hif_write_reg(1, reg & ~BIT(1));
Anish Bhattffda2032015-09-29 12:15:49 -0700638 g_wlan.hif_func.hif_write_reg(1, reg | BIT(1));
Anish Bhattffda2032015-09-29 12:15:49 -0700639 g_wlan.hif_func.hif_write_reg(1, reg & ~BIT(1));
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900640 } else if ((g_wlan.io_func.io_type & 0x1) == HIF_SDIO) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900641 g_wlan.hif_func.hif_read_reg(0xf0, &reg);
Anish Bhattffda2032015-09-29 12:15:49 -0700642 g_wlan.hif_func.hif_write_reg(0xf0, reg & ~BIT(0));
Anish Bhattffda2032015-09-29 12:15:49 -0700643 g_wlan.hif_func.hif_write_reg(0xf0, reg | BIT(0));
Anish Bhattffda2032015-09-29 12:15:49 -0700644 g_wlan.hif_func.hif_write_reg(0xf0, reg & ~BIT(0));
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900645 }
646
647 do {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900648 mdelay(3);
649
Alison Schofield39823a52015-10-08 21:18:03 -0700650 if ((wilc_get_chipid(true) == 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900651 wilc_debug(N_ERR, "Couldn't read chip id. Wake up failed\n");
Alison Schofield39823a52015-10-08 21:18:03 -0700652
Dean Lee72ed4dc2015-06-12 14:11:44 +0900653 } while ((wilc_get_chipid(true) == 0) && ((++trials % 3) == 0));
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900654
Dean Lee72ed4dc2015-06-12 14:11:44 +0900655 } while (wilc_get_chipid(true) == 0);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900656
Leo Kimb7d1e182015-11-06 11:12:30 +0900657 if (chip_ps_state == CHIP_SLEEPING_MANUAL) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900658 g_wlan.hif_func.hif_read_reg(0x1C0C, &reg);
Anish Bhattffda2032015-09-29 12:15:49 -0700659 reg &= ~BIT(0);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900660 g_wlan.hif_func.hif_write_reg(0x1C0C, reg);
661
Dean Lee72ed4dc2015-06-12 14:11:44 +0900662 if (wilc_get_chipid(false) >= 0x1002b0) {
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900663 u32 val32;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900664
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900665 g_wlan.hif_func.hif_read_reg(0x1e1c, &val32);
Anish Bhattffda2032015-09-29 12:15:49 -0700666 val32 |= BIT(6);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900667 g_wlan.hif_func.hif_write_reg(0x1e1c, val32);
668
669 g_wlan.hif_func.hif_read_reg(0x1e9c, &val32);
Anish Bhattffda2032015-09-29 12:15:49 -0700670 val32 |= BIT(6);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900671 g_wlan.hif_func.hif_write_reg(0x1e9c, val32);
672 }
673 }
Leo Kimb7d1e182015-11-06 11:12:30 +0900674 chip_ps_state = CHIP_WAKEDUP;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900675}
676#endif
Chaehyun Lim4e4467f2015-06-11 14:35:55 +0900677void chip_sleep_manually(u32 u32SleepTime)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900678{
Leo Kimb7d1e182015-11-06 11:12:30 +0900679 if (chip_ps_state != CHIP_WAKEDUP)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900680 return;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900681 acquire_bus(ACQUIRE_ONLY);
682
683#ifdef WILC_OPTIMIZE_SLEEP_INT
684 chip_allow_sleep();
685#endif
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900686 g_wlan.hif_func.hif_write_reg(0x10a8, 1);
687
Leo Kimb7d1e182015-11-06 11:12:30 +0900688 chip_ps_state = CHIP_SLEEPING_MANUAL;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900689 release_bus(RELEASE_ONLY);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900690}
691
Glen Leea1332ca2015-10-27 18:27:47 +0900692int wilc_wlan_handle_txq(struct net_device *dev, u32 *pu32TxqCount)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900693{
694 wilc_wlan_dev_t *p = (wilc_wlan_dev_t *)&g_wlan;
695 int i, entries = 0;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900696 u32 sum;
697 u32 reg;
Chaehyun Lim51e825f2015-09-15 14:06:14 +0900698 u8 *txb = p->tx_buffer;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900699 u32 offset = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900700 int vmm_sz = 0;
701 struct txq_entry_t *tqe;
702 int ret = 0;
703 int counter;
704 int timeout;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900705 u32 vmm_table[WILC_VMM_TBL_SIZE];
Glen Leea1332ca2015-10-27 18:27:47 +0900706 perInterface_wlan_t *nic;
707 struct wilc *wilc;
708
709 nic = netdev_priv(dev);
710 wilc = nic->wilc;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900711
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900712 p->txq_exit = 0;
713 do {
714 if (p->quit)
715 break;
716
Glen Leea1332ca2015-10-27 18:27:47 +0900717 linux_wlan_lock_timeout(&wilc->txq_add_to_head_cs,
Glen Leeb002e202015-09-24 18:15:05 +0900718 CFG_PKTS_TIMEOUT);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900719#ifdef TCP_ACK_FILTER
Glen Leec029e992015-10-27 18:27:48 +0900720 wilc_wlan_txq_filter_dup_tcp_ack(dev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900721#endif
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900722 PRINT_D(TX_DBG, "Getting the head of the TxQ\n");
Glen Lee7af05222015-10-29 12:18:41 +0900723 tqe = wilc_wlan_txq_get_first(wilc);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900724 i = 0;
725 sum = 0;
726 do {
Leo Kima4b17192015-11-06 11:12:31 +0900727 if (tqe && (i < (WILC_VMM_TBL_SIZE - 1))) {
Alison Schofield39823a52015-10-08 21:18:03 -0700728 if (tqe->type == WILC_CFG_PKT)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900729 vmm_sz = ETH_CONFIG_PKT_HDR_OFFSET;
Alison Schofield39823a52015-10-08 21:18:03 -0700730
731 else if (tqe->type == WILC_NET_PKT)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900732 vmm_sz = ETH_ETHERNET_HDR_OFFSET;
Alison Schofield39823a52015-10-08 21:18:03 -0700733
734 else
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900735 vmm_sz = HOST_HDR_OFFSET;
Alison Schofield39823a52015-10-08 21:18:03 -0700736
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900737 vmm_sz += tqe->buffer_size;
738 PRINT_D(TX_DBG, "VMM Size before alignment = %d\n", vmm_sz);
Leo Kimac087c82015-11-06 11:12:25 +0900739 if (vmm_sz & 0x3)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900740 vmm_sz = (vmm_sz + 4) & ~0x3;
Leo Kimac087c82015-11-06 11:12:25 +0900741
Alison Schofield39823a52015-10-08 21:18:03 -0700742 if ((sum + vmm_sz) > LINUX_TX_SIZE)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900743 break;
Alison Schofield39823a52015-10-08 21:18:03 -0700744
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900745 PRINT_D(TX_DBG, "VMM Size AFTER alignment = %d\n", vmm_sz);
Leo Kimac087c82015-11-06 11:12:25 +0900746 vmm_table[i] = vmm_sz / 4;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900747 PRINT_D(TX_DBG, "VMMTable entry size = %d\n", vmm_table[i]);
748
749 if (tqe->type == WILC_CFG_PKT) {
Anish Bhattffda2032015-09-29 12:15:49 -0700750 vmm_table[i] |= BIT(10);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900751 PRINT_D(TX_DBG, "VMMTable entry changed for CFG packet = %d\n", vmm_table[i]);
752 }
753#ifdef BIG_ENDIAN
754 vmm_table[i] = BYTE_SWAP(vmm_table[i]);
755#endif
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900756
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900757 i++;
758 sum += vmm_sz;
759 PRINT_D(TX_DBG, "sum = %d\n", sum);
Glen Lee50a0b3b2015-10-27 18:28:00 +0900760 tqe = wilc_wlan_txq_get_next(wilc, tqe);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900761 } else {
762 break;
763 }
764 } while (1);
765
Leo Kimac087c82015-11-06 11:12:25 +0900766 if (i == 0) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900767 PRINT_D(TX_DBG, "Nothing in TX-Q\n");
768 break;
769 } else {
770 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 +0900771 vmm_table[i] = 0x0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900772 }
773 acquire_bus(ACQUIRE_AND_WAKEUP);
774 counter = 0;
775 do {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900776 ret = p->hif_func.hif_read_reg(WILC_HOST_TX_CTRL, &reg);
777 if (!ret) {
778 wilc_debug(N_ERR, "[wilc txq]: fail can't read reg vmm_tbl_entry..\n");
779 break;
780 }
781
782 if ((reg & 0x1) == 0) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900783 PRINT_D(TX_DBG, "Writing VMM table ... with Size = %d\n", ((i + 1) * 4));
784 break;
785 } else {
786 counter++;
787 if (counter > 200) {
788 counter = 0;
789 PRINT_D(TX_DBG, "Looping in tx ctrl , forcce quit\n");
790 ret = p->hif_func.hif_write_reg(WILC_HOST_TX_CTRL, 0);
791 break;
792 }
Chandra S Gorentla17aacd42015-08-08 17:41:35 +0530793 PRINT_WRN(GENERIC_DBG, "[wilc txq]: warn, vmm table not clear yet, wait...\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900794 release_bus(RELEASE_ALLOW_SLEEP);
Greg Kroah-Hartman2b922cb2015-09-04 09:30:51 -0700795 usleep_range(3000, 3000);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900796 acquire_bus(ACQUIRE_AND_WAKEUP);
797 }
798 } while (!p->quit);
799
Alison Schofield39823a52015-10-08 21:18:03 -0700800 if (!ret)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900801 goto _end_;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900802
803 timeout = 200;
804 do {
Chaehyun Limc3ca6372015-09-20 15:51:19 +0900805 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 +0900806 if (!ret) {
807 wilc_debug(N_ERR, "ERR block TX of VMM table.\n");
808 break;
809 }
810
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900811 ret = p->hif_func.hif_write_reg(WILC_HOST_VMM_CTL, 0x2);
812 if (!ret) {
813 wilc_debug(N_ERR, "[wilc txq]: fail can't write reg host_vmm_ctl..\n");
814 break;
815 }
816
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900817 do {
818 ret = p->hif_func.hif_read_reg(WILC_HOST_VMM_CTL, &reg);
819 if (!ret) {
820 wilc_debug(N_ERR, "[wilc txq]: fail can't read reg host_vmm_ctl..\n");
821 break;
822 }
823 if ((reg >> 2) & 0x1) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900824 entries = ((reg >> 3) & 0x3f);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900825 break;
826 } else {
827 release_bus(RELEASE_ALLOW_SLEEP);
Greg Kroah-Hartman2b922cb2015-09-04 09:30:51 -0700828 usleep_range(3000, 3000);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900829 acquire_bus(ACQUIRE_AND_WAKEUP);
830 PRINT_WRN(GENERIC_DBG, "Can't get VMM entery - reg = %2x\n", reg);
831 }
832 } while (--timeout);
833 if (timeout <= 0) {
834 ret = p->hif_func.hif_write_reg(WILC_HOST_VMM_CTL, 0x0);
835 break;
836 }
837
Alison Schofield39823a52015-10-08 21:18:03 -0700838 if (!ret)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900839 break;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900840
841 if (entries == 0) {
Chandra S Gorentla17aacd42015-08-08 17:41:35 +0530842 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 +0900843
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900844 ret = p->hif_func.hif_read_reg(WILC_HOST_TX_CTRL, &reg);
845 if (!ret) {
846 wilc_debug(N_ERR, "[wilc txq]: fail can't read reg WILC_HOST_TX_CTRL..\n");
847 break;
848 }
Anish Bhattffda2032015-09-29 12:15:49 -0700849 reg &= ~BIT(0);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900850 ret = p->hif_func.hif_write_reg(WILC_HOST_TX_CTRL, reg);
851 if (!ret) {
852 wilc_debug(N_ERR, "[wilc txq]: fail can't write reg WILC_HOST_TX_CTRL..\n");
853 break;
854 }
855 break;
856 } else {
857 break;
858 }
859 } while (1);
860
Alison Schofield39823a52015-10-08 21:18:03 -0700861 if (!ret)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900862 goto _end_;
Alison Schofield39823a52015-10-08 21:18:03 -0700863
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900864 if (entries == 0) {
865 ret = WILC_TX_ERR_NO_BUF;
866 goto _end_;
867 }
868
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900869 release_bus(RELEASE_ALLOW_SLEEP);
870
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900871 offset = 0;
872 i = 0;
873 do {
Glen Lee718fc2c2015-10-29 12:18:43 +0900874 tqe = wilc_wlan_txq_remove_from_head(dev);
Leo Kima4b17192015-11-06 11:12:31 +0900875 if (tqe && (vmm_table[i] != 0)) {
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900876 u32 header, buffer_offset;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900877
878#ifdef BIG_ENDIAN
879 vmm_table[i] = BYTE_SWAP(vmm_table[i]);
880#endif
Leo Kimac087c82015-11-06 11:12:25 +0900881 vmm_sz = (vmm_table[i] & 0x3ff);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900882 vmm_sz *= 4;
883 header = (tqe->type << 31) | (tqe->buffer_size << 15) | vmm_sz;
Chandra S Gorentla78174ad2015-08-08 17:41:36 +0530884 if (tqe->type == WILC_MGMT_PKT)
Anish Bhattffda2032015-09-29 12:15:49 -0700885 header |= BIT(30);
Chandra S Gorentla78174ad2015-08-08 17:41:36 +0530886 else
Anish Bhattffda2032015-09-29 12:15:49 -0700887 header &= ~BIT(30);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900888
889#ifdef BIG_ENDIAN
890 header = BYTE_SWAP(header);
891#endif
892 memcpy(&txb[offset], &header, 4);
893 if (tqe->type == WILC_CFG_PKT) {
894 buffer_offset = ETH_CONFIG_PKT_HDR_OFFSET;
895 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900896 else if (tqe->type == WILC_NET_PKT) {
897 char *pBSSID = ((struct tx_complete_data *)(tqe->priv))->pBssid;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900898
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900899 buffer_offset = ETH_ETHERNET_HDR_OFFSET;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900900 memcpy(&txb[offset + 4], pBSSID, 6);
901 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900902 else {
903 buffer_offset = HOST_HDR_OFFSET;
904 }
905
906 memcpy(&txb[offset + buffer_offset], tqe->buffer, tqe->buffer_size);
907 offset += vmm_sz;
908 i++;
Leo Kimac087c82015-11-06 11:12:25 +0900909 tqe->status = 1;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900910 if (tqe->tx_complete_func)
911 tqe->tx_complete_func(tqe->priv, tqe->status);
912 #ifdef TCP_ACK_FILTER
Alison Schofield39823a52015-10-08 21:18:03 -0700913 if (tqe->tcp_PendingAck_index != NOT_TCP_ACK)
Leo Kim2bb17082015-11-06 11:12:40 +0900914 pending_acks_info[tqe->tcp_PendingAck_index].txqe = NULL;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900915 #endif
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -0700916 kfree(tqe);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900917 } else {
918 break;
919 }
920 } while (--entries);
921
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900922 acquire_bus(ACQUIRE_AND_WAKEUP);
923
924 ret = p->hif_func.hif_clear_int_ext(ENABLE_TX_VMM);
925 if (!ret) {
926 wilc_debug(N_ERR, "[wilc txq]: fail can't start tx VMM ...\n");
927 goto _end_;
928 }
929
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900930 ret = p->hif_func.hif_block_tx_ext(0, txb, offset);
931 if (!ret) {
932 wilc_debug(N_ERR, "[wilc txq]: fail can't block tx ext...\n");
933 goto _end_;
934 }
935
936_end_:
937
938 release_bus(RELEASE_ALLOW_SLEEP);
939 if (ret != 1)
940 break;
941 } while (0);
Glen Leea1332ca2015-10-27 18:27:47 +0900942 up(&wilc->txq_add_to_head_cs);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900943
944 p->txq_exit = 1;
945 PRINT_D(TX_DBG, "THREAD: Exiting txq\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900946 *pu32TxqCount = p->txq_entries;
947 return ret;
948}
949
Glen Lee39ce4d32015-10-27 18:27:42 +0900950static void wilc_wlan_handle_rxq(struct wilc *wilc)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900951{
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +0530952 wilc_wlan_dev_t *p = &g_wlan;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900953 int offset = 0, size, has_packet = 0;
Chaehyun Lim51e825f2015-09-15 14:06:14 +0900954 u8 *buffer;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900955 struct rxq_entry_t *rqe;
956
957 p->rxq_exit = 0;
958
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900959 do {
960 if (p->quit) {
Chandra S Gorentla17aacd42015-08-08 17:41:35 +0530961 PRINT_D(RX_DBG, "exit 1st do-while due to Clean_UP function\n");
Glen Lee39ce4d32015-10-27 18:27:42 +0900962 up(&wilc->cfg_event);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900963 break;
964 }
Glen Leedb387632015-10-27 18:27:55 +0900965 rqe = wilc_wlan_rxq_remove(wilc);
Leo Kima4b17192015-11-06 11:12:31 +0900966 if (!rqe) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900967 PRINT_D(RX_DBG, "nothing in the queue - exit 1st do-while\n");
968 break;
969 }
970 buffer = rqe->buffer;
971 size = rqe->buffer_size;
972 PRINT_D(RX_DBG, "rxQ entery Size = %d - Address = %p\n", size, buffer);
973 offset = 0;
974
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900975 do {
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900976 u32 header;
977 u32 pkt_len, pkt_offset, tp_len;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900978 int is_cfg_packet;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900979
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900980 PRINT_D(RX_DBG, "In the 2nd do-while\n");
981 memcpy(&header, &buffer[offset], 4);
982#ifdef BIG_ENDIAN
983 header = BYTE_SWAP(header);
984#endif
985 PRINT_D(RX_DBG, "Header = %04x - Offset = %d\n", header, offset);
986
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900987 is_cfg_packet = (header >> 31) & 0x1;
988 pkt_offset = (header >> 22) & 0x1ff;
989 tp_len = (header >> 11) & 0x7ff;
990 pkt_len = header & 0x7ff;
991
992 if (pkt_len == 0 || tp_len == 0) {
993 wilc_debug(N_RXQ, "[wilc rxq]: data corrupt, packet len or tp_len is 0 [%d][%d]\n", pkt_len, tp_len);
994 break;
995 }
996
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900997 #define IS_MANAGMEMENT 0x100
998 #define IS_MANAGMEMENT_CALLBACK 0x080
999 #define IS_MGMT_STATUS_SUCCES 0x040
1000
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001001 if (pkt_offset & IS_MANAGMEMENT) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001002 pkt_offset &= ~(IS_MANAGMEMENT | IS_MANAGMEMENT_CALLBACK | IS_MGMT_STATUS_SUCCES);
1003
Glen Lee11f4b2e2015-10-27 18:27:51 +09001004 WILC_WFI_mgmt_rx(wilc, &buffer[offset + HOST_HDR_OFFSET], pkt_len);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001005 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001006 else
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001007 {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001008 if (!is_cfg_packet) {
Glen Lee63611672015-09-24 18:14:52 +09001009 if (pkt_len > 0) {
Glen Leecb1991a2015-10-27 18:27:56 +09001010 frmw_to_linux(wilc,
1011 &buffer[offset],
Glen Lee63611672015-09-24 18:14:52 +09001012 pkt_len,
1013 pkt_offset);
1014 has_packet = 1;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001015 }
1016 } else {
1017 wilc_cfg_rsp_t rsp;
1018
Glen Lee30f535a2015-10-02 14:22:10 +09001019 wilc_wlan_cfg_indicate_rx(&buffer[pkt_offset + offset], pkt_len, &rsp);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001020 if (rsp.type == WILC_CFG_RSP) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001021 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 -07001022 if (p->cfg_seq_no == rsp.seq_no)
Glen Lee39ce4d32015-10-27 18:27:42 +09001023 up(&wilc->cfg_event);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001024 } else if (rsp.type == WILC_CFG_RSP_STATUS) {
Glen Lee64f2b712015-10-27 18:27:43 +09001025 linux_wlan_mac_indicate(wilc, WILC_MAC_INDICATE_STATUS);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001026
1027 } else if (rsp.type == WILC_CFG_RSP_SCAN) {
Glen Lee64f2b712015-10-27 18:27:43 +09001028 linux_wlan_mac_indicate(wilc, WILC_MAC_INDICATE_SCAN);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001029 }
1030 }
1031 }
1032 offset += tp_len;
1033 if (offset >= size)
1034 break;
1035 } while (1);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001036#ifndef MEMORY_STATIC
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -07001037 kfree(buffer);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001038#endif
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -07001039 kfree(rqe);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001040
Alison Schofield39823a52015-10-08 21:18:03 -07001041 if (has_packet)
Glen Leec0cadaa2015-09-24 18:14:54 +09001042 linux_wlan_rx_complete();
Alison Schofield39823a52015-10-08 21:18:03 -07001043
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001044 } while (1);
1045
1046 p->rxq_exit = 1;
Chandra S Gorentla17aacd42015-08-08 17:41:35 +05301047 PRINT_D(RX_DBG, "THREAD: Exiting RX thread\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001048}
1049
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001050static void wilc_unknown_isr_ext(void)
1051{
1052 g_wlan.hif_func.hif_clear_int_ext(0);
1053}
Leo Kim2d6973e2015-11-06 11:12:28 +09001054
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001055static void wilc_pllupdate_isr_ext(u32 int_stats)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001056{
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001057 int trials = 10;
1058
1059 g_wlan.hif_func.hif_clear_int_ext(PLL_INT_CLR);
1060
Greg Kroah-Hartmanc2e4c0f2015-09-03 19:09:50 -07001061 mdelay(WILC_PLL_TO);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001062
Dean Lee72ed4dc2015-06-12 14:11:44 +09001063 while (!(ISWILC1000(wilc_get_chipid(true)) && --trials)) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001064 PRINT_D(TX_DBG, "PLL update retrying\n");
Greg Kroah-Hartmanc2e4c0f2015-09-03 19:09:50 -07001065 mdelay(1);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001066 }
1067}
1068
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001069static void wilc_sleeptimer_isr_ext(u32 int_stats1)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001070{
1071 g_wlan.hif_func.hif_clear_int_ext(SLEEP_INT_CLR);
1072#ifndef WILC_OPTIMIZE_SLEEP_INT
Leo Kimb7d1e182015-11-06 11:12:30 +09001073 chip_ps_state = CHIP_SLEEPING_AUTO;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001074#endif
1075}
1076
Glen Lee3bcd45b2015-10-27 18:27:41 +09001077static void wilc_wlan_handle_isr_ext(struct wilc *wilc, u32 int_status)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001078{
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +05301079 wilc_wlan_dev_t *p = &g_wlan;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001080#ifdef MEMORY_STATIC
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001081 u32 offset = p->rx_buffer_offset;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001082#endif
Chaehyun Lim51e825f2015-09-15 14:06:14 +09001083 u8 *buffer = NULL;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001084 u32 size;
1085 u32 retries = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001086 int ret = 0;
1087 struct rxq_entry_t *rqe;
1088
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001089 size = ((int_status & 0x7fff) << 2);
1090
1091 while (!size && retries < 10) {
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001092 u32 time = 0;
Leo Kimac087c82015-11-06 11:12:25 +09001093
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001094 wilc_debug(N_ERR, "RX Size equal zero ... Trying to read it again for %d time\n", time++);
1095 p->hif_func.hif_read_size(&size);
1096 size = ((size & 0x7fff) << 2);
1097 retries++;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001098 }
1099
1100 if (size > 0) {
1101#ifdef MEMORY_STATIC
Glen Lee03eb7262015-09-24 18:15:03 +09001102 if (LINUX_RX_SIZE - offset < size)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001103 offset = 0;
1104
1105 if (p->rx_buffer)
1106 buffer = &p->rx_buffer[offset];
1107 else {
1108 wilc_debug(N_ERR, "[wilc isr]: fail Rx Buffer is NULL...drop the packets (%d)\n", size);
1109 goto _end_;
1110 }
1111
1112#else
Greg Kroah-Hartmanf019b9d2015-09-03 18:50:27 -07001113 buffer = kmalloc(size, GFP_KERNEL);
Leo Kima4b17192015-11-06 11:12:31 +09001114 if (!buffer) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001115 wilc_debug(N_ERR, "[wilc isr]: fail alloc host memory...drop the packets (%d)\n", size);
Greg Kroah-Hartman80e29c72015-08-14 19:42:23 -07001116 usleep_range(100 * 1000, 100 * 1000);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001117 goto _end_;
1118 }
1119#endif
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001120 p->hif_func.hif_clear_int_ext(DATA_INT_CLR | ENABLE_RX_VMM);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001121 ret = p->hif_func.hif_block_rx_ext(0, buffer, size);
1122
1123 if (!ret) {
1124 wilc_debug(N_ERR, "[wilc isr]: fail block rx...\n");
1125 goto _end_;
1126 }
1127_end_:
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001128 if (ret) {
1129#ifdef MEMORY_STATIC
1130 offset += size;
1131 p->rx_buffer_offset = offset;
1132#endif
Greg Kroah-Hartmanf019b9d2015-09-03 18:50:27 -07001133 rqe = kmalloc(sizeof(struct rxq_entry_t), GFP_KERNEL);
Leo Kima4b17192015-11-06 11:12:31 +09001134 if (rqe) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001135 rqe->buffer = buffer;
1136 rqe->buffer_size = size;
1137 PRINT_D(RX_DBG, "rxq entery Size= %d - Address = %p\n", rqe->buffer_size, rqe->buffer);
Glen Leed06f3622015-10-27 18:27:59 +09001138 wilc_wlan_rxq_add(wilc, rqe);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001139 }
1140 } else {
1141#ifndef MEMORY_STATIC
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -07001142 kfree(buffer);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001143#endif
1144 }
1145 }
Glen Lee39ce4d32015-10-27 18:27:42 +09001146 wilc_wlan_handle_rxq(wilc);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001147}
1148
Glen Lee50b929e2015-10-27 18:27:40 +09001149void wilc_handle_isr(void *wilc)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001150{
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001151 u32 int_status;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001152
1153 acquire_bus(ACQUIRE_AND_WAKEUP);
1154 g_wlan.hif_func.hif_read_int(&int_status);
1155
Alison Schofield39823a52015-10-08 21:18:03 -07001156 if (int_status & PLL_INT_EXT)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001157 wilc_pllupdate_isr_ext(int_status);
Alison Schofield39823a52015-10-08 21:18:03 -07001158
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001159 if (int_status & DATA_INT_EXT) {
Glen Lee3bcd45b2015-10-27 18:27:41 +09001160 wilc_wlan_handle_isr_ext(wilc, int_status);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001161 #ifndef WILC_OPTIMIZE_SLEEP_INT
Leo Kimb7d1e182015-11-06 11:12:30 +09001162 chip_ps_state = CHIP_WAKEDUP;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001163 #endif
1164 }
Alison Schofield39823a52015-10-08 21:18:03 -07001165 if (int_status & SLEEP_INT_EXT)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001166 wilc_sleeptimer_isr_ext(int_status);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001167
1168 if (!(int_status & (ALL_INT_EXT))) {
1169#ifdef WILC_SDIO
1170 PRINT_D(TX_DBG, ">> UNKNOWN_INTERRUPT - 0x%08x\n", int_status);
1171#endif
1172 wilc_unknown_isr_ext();
1173 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001174 release_bus(RELEASE_ALLOW_SLEEP);
1175}
1176
Glen Lee63d7ab82015-10-01 16:03:32 +09001177int wilc_wlan_firmware_download(const u8 *buffer, u32 buffer_size)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001178{
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +05301179 wilc_wlan_dev_t *p = &g_wlan;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001180 u32 offset;
1181 u32 addr, size, size2, blksz;
Chaehyun Lim51e825f2015-09-15 14:06:14 +09001182 u8 *dma_buffer;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001183 int ret = 0;
1184
Anish Bhattffda2032015-09-29 12:15:49 -07001185 blksz = BIT(12);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001186
Greg Kroah-Hartmanf019b9d2015-09-03 18:50:27 -07001187 dma_buffer = kmalloc(blksz, GFP_KERNEL);
Leo Kima4b17192015-11-06 11:12:31 +09001188 if (!dma_buffer) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001189 ret = -5;
1190 PRINT_ER("Can't allocate buffer for firmware download IO error\n ");
1191 goto _fail_1;
1192 }
1193
1194 PRINT_D(INIT_DBG, "Downloading firmware size = %d ...\n", buffer_size);
Leo Kimac087c82015-11-06 11:12:25 +09001195
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001196 offset = 0;
1197 do {
1198 memcpy(&addr, &buffer[offset], 4);
1199 memcpy(&size, &buffer[offset + 4], 4);
1200#ifdef BIG_ENDIAN
1201 addr = BYTE_SWAP(addr);
1202 size = BYTE_SWAP(size);
1203#endif
1204 acquire_bus(ACQUIRE_ONLY);
1205 offset += 8;
1206 while (((int)size) && (offset < buffer_size)) {
Chandra S Gorentla78174ad2015-08-08 17:41:36 +05301207 if (size <= blksz)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001208 size2 = size;
Chandra S Gorentla78174ad2015-08-08 17:41:36 +05301209 else
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001210 size2 = blksz;
Leo Kimac087c82015-11-06 11:12:25 +09001211
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001212 memcpy(dma_buffer, &buffer[offset], size2);
1213 ret = p->hif_func.hif_block_tx(addr, dma_buffer, size2);
1214 if (!ret)
1215 break;
1216
1217 addr += size2;
1218 offset += size2;
1219 size -= size2;
1220 }
1221 release_bus(RELEASE_ONLY);
1222
1223 if (!ret) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001224 ret = -5;
1225 PRINT_ER("Can't download firmware IO error\n ");
1226 goto _fail_;
1227 }
1228 PRINT_D(INIT_DBG, "Offset = %d\n", offset);
1229 } while (offset < buffer_size);
1230
1231_fail_:
1232
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -07001233 kfree(dma_buffer);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001234
1235_fail_1:
1236
1237 return (ret < 0) ? ret : 0;
1238}
1239
Glen Leee42563b2015-10-01 16:03:33 +09001240int wilc_wlan_start(void)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001241{
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +05301242 wilc_wlan_dev_t *p = &g_wlan;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001243 u32 reg = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001244 int ret;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001245 u32 chipid;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001246
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001247 if (p->io_func.io_type == HIF_SDIO) {
1248 reg = 0;
Leo Kimac087c82015-11-06 11:12:25 +09001249 reg |= BIT(3);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001250 } else if (p->io_func.io_type == HIF_SPI) {
1251 reg = 1;
1252 }
1253 acquire_bus(ACQUIRE_ONLY);
1254 ret = p->hif_func.hif_write_reg(WILC_VMM_CORE_CFG, reg);
1255 if (!ret) {
1256 wilc_debug(N_ERR, "[wilc start]: fail write reg vmm_core_cfg...\n");
1257 release_bus(RELEASE_ONLY);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001258 ret = -5;
1259 return ret;
1260 }
1261 reg = 0;
1262#ifdef WILC_SDIO_IRQ_GPIO
1263 reg |= WILC_HAVE_SDIO_IRQ_GPIO;
1264#endif
1265
1266#ifdef WILC_DISABLE_PMU
1267#else
1268 reg |= WILC_HAVE_USE_PMU;
1269#endif
1270
1271#ifdef WILC_SLEEP_CLK_SRC_XO
1272 reg |= WILC_HAVE_SLEEP_CLK_SRC_XO;
1273#elif defined WILC_SLEEP_CLK_SRC_RTC
1274 reg |= WILC_HAVE_SLEEP_CLK_SRC_RTC;
1275#endif
1276
1277#ifdef WILC_EXT_PA_INV_TX_RX
1278 reg |= WILC_HAVE_EXT_PA_INV_TX_RX;
1279#endif
1280
1281 reg |= WILC_HAVE_LEGACY_RF_SETTINGS;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001282#ifdef XTAL_24
1283 reg |= WILC_HAVE_XTAL_24;
1284#endif
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001285#ifdef DISABLE_WILC_UART
1286 reg |= WILC_HAVE_DISABLE_WILC_UART;
1287#endif
1288
1289 ret = p->hif_func.hif_write_reg(WILC_GP_REG_1, reg);
1290 if (!ret) {
1291 wilc_debug(N_ERR, "[wilc start]: fail write WILC_GP_REG_1 ...\n");
1292 release_bus(RELEASE_ONLY);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001293 ret = -5;
1294 return ret;
1295 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001296
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001297 p->hif_func.hif_sync_ext(NUM_INT_EXT);
1298
1299 ret = p->hif_func.hif_read_reg(0x1000, &chipid);
1300 if (!ret) {
1301 wilc_debug(N_ERR, "[wilc start]: fail read reg 0x1000 ...\n");
1302 release_bus(RELEASE_ONLY);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001303 ret = -5;
1304 return ret;
1305 }
1306
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001307 p->hif_func.hif_read_reg(WILC_GLB_RESET_0, &reg);
Anish Bhattffda2032015-09-29 12:15:49 -07001308 if ((reg & BIT(10)) == BIT(10)) {
1309 reg &= ~BIT(10);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001310 p->hif_func.hif_write_reg(WILC_GLB_RESET_0, reg);
1311 p->hif_func.hif_read_reg(WILC_GLB_RESET_0, &reg);
1312 }
1313
Anish Bhattffda2032015-09-29 12:15:49 -07001314 reg |= BIT(10);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001315 ret = p->hif_func.hif_write_reg(WILC_GLB_RESET_0, reg);
1316 p->hif_func.hif_read_reg(WILC_GLB_RESET_0, &reg);
1317 release_bus(RELEASE_ONLY);
1318
1319 return (ret < 0) ? ret : 0;
1320}
1321
1322void wilc_wlan_global_reset(void)
1323{
1324
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +05301325 wilc_wlan_dev_t *p = &g_wlan;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +09001326
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001327 acquire_bus(ACQUIRE_AND_WAKEUP);
1328 p->hif_func.hif_write_reg(WILC_GLB_RESET_0, 0x0);
1329 release_bus(RELEASE_ONLY);
1330}
Glen Lee8cec7412015-10-01 16:03:34 +09001331int wilc_wlan_stop(void)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001332{
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +05301333 wilc_wlan_dev_t *p = &g_wlan;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001334 u32 reg = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001335 int ret;
Chaehyun Lim51e825f2015-09-15 14:06:14 +09001336 u8 timeout = 10;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001337 acquire_bus(ACQUIRE_AND_WAKEUP);
1338
1339 ret = p->hif_func.hif_read_reg(WILC_GLB_RESET_0, &reg);
1340 if (!ret) {
1341 PRINT_ER("Error while reading reg\n");
1342 release_bus(RELEASE_ALLOW_SLEEP);
1343 return ret;
1344 }
1345
Anish Bhattffda2032015-09-29 12:15:49 -07001346 reg &= ~BIT(10);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001347 ret = p->hif_func.hif_write_reg(WILC_GLB_RESET_0, reg);
1348 if (!ret) {
1349 PRINT_ER("Error while writing reg\n");
1350 release_bus(RELEASE_ALLOW_SLEEP);
1351 return ret;
1352 }
1353
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001354 do {
1355 ret = p->hif_func.hif_read_reg(WILC_GLB_RESET_0, &reg);
1356 if (!ret) {
1357 PRINT_ER("Error while reading reg\n");
1358 release_bus(RELEASE_ALLOW_SLEEP);
1359 return ret;
1360 }
1361 PRINT_D(GENERIC_DBG, "Read RESET Reg %x : Retry%d\n", reg, timeout);
Leo Kimac087c82015-11-06 11:12:25 +09001362
Anish Bhattffda2032015-09-29 12:15:49 -07001363 if ((reg & BIT(10))) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001364 PRINT_D(GENERIC_DBG, "Bit 10 not reset : Retry %d\n", timeout);
Anish Bhattffda2032015-09-29 12:15:49 -07001365 reg &= ~BIT(10);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001366 ret = p->hif_func.hif_write_reg(WILC_GLB_RESET_0, reg);
1367 timeout--;
1368 } else {
1369 PRINT_D(GENERIC_DBG, "Bit 10 reset after : Retry %d\n", timeout);
1370 ret = p->hif_func.hif_read_reg(WILC_GLB_RESET_0, &reg);
1371 if (!ret) {
1372 PRINT_ER("Error while reading reg\n");
1373 release_bus(RELEASE_ALLOW_SLEEP);
1374 return ret;
1375 }
1376 PRINT_D(GENERIC_DBG, "Read RESET Reg %x : Retry%d\n", reg, timeout);
1377 break;
1378 }
1379
1380 } while (timeout);
Anish Bhattffda2032015-09-29 12:15:49 -07001381 reg = (BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(8) | BIT(9) | BIT(26) |
1382 BIT(29) | BIT(30) | BIT(31));
Anish Bhatt65ead4e2015-09-29 12:15:48 -07001383
1384 p->hif_func.hif_write_reg(WILC_GLB_RESET_0, reg);
Anish Bhattffda2032015-09-29 12:15:49 -07001385 reg = (u32)~BIT(10);
Anish Bhatt65ead4e2015-09-29 12:15:48 -07001386
1387 ret = p->hif_func.hif_write_reg(WILC_GLB_RESET_0, reg);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001388
1389 release_bus(RELEASE_ALLOW_SLEEP);
1390
1391 return ret;
1392}
1393
Glen Lee2de7cbe2015-10-27 18:27:54 +09001394void wilc_wlan_cleanup(struct net_device *dev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001395{
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +05301396 wilc_wlan_dev_t *p = &g_wlan;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001397 struct txq_entry_t *tqe;
1398 struct rxq_entry_t *rqe;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001399 u32 reg = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001400 int ret;
Glen Leedb387632015-10-27 18:27:55 +09001401 perInterface_wlan_t *nic;
1402 struct wilc *wilc;
1403
1404 nic = netdev_priv(dev);
1405 wilc = nic->wilc;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001406
1407 p->quit = 1;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001408 do {
Glen Lee718fc2c2015-10-29 12:18:43 +09001409 tqe = wilc_wlan_txq_remove_from_head(dev);
Leo Kima4b17192015-11-06 11:12:31 +09001410 if (!tqe)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001411 break;
1412 if (tqe->tx_complete_func)
1413 tqe->tx_complete_func(tqe->priv, 0);
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -07001414 kfree(tqe);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001415 } while (1);
1416
1417 do {
Glen Leedb387632015-10-27 18:27:55 +09001418 rqe = wilc_wlan_rxq_remove(wilc);
Leo Kima4b17192015-11-06 11:12:31 +09001419 if (!rqe)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001420 break;
Javier Martinez Canillas6a272242015-09-22 15:24:50 +02001421#ifndef MEMORY_STATIC
1422 kfree(rqe->buffer);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001423#endif
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -07001424 kfree(rqe);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001425 } while (1);
1426
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001427 #ifdef MEMORY_STATIC
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -07001428 kfree(p->rx_buffer);
1429 p->rx_buffer = NULL;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001430 #endif
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -07001431 kfree(p->tx_buffer);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001432
1433 acquire_bus(ACQUIRE_AND_WAKEUP);
1434
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001435 ret = p->hif_func.hif_read_reg(WILC_GP_REG_0, &reg);
1436 if (!ret) {
1437 PRINT_ER("Error while reading reg\n");
1438 release_bus(RELEASE_ALLOW_SLEEP);
1439 }
1440 PRINT_ER("Writing ABORT reg\n");
1441 ret = p->hif_func.hif_write_reg(WILC_GP_REG_0, (reg | ABORT_INT));
1442 if (!ret) {
1443 PRINT_ER("Error while writing reg\n");
1444 release_bus(RELEASE_ALLOW_SLEEP);
1445 }
1446 release_bus(RELEASE_ALLOW_SLEEP);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001447 p->hif_func.hif_deinit(NULL);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001448}
1449
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001450static int wilc_wlan_cfg_commit(int type, u32 drvHandler)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001451{
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +05301452 wilc_wlan_dev_t *p = &g_wlan;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001453 wilc_cfg_frame_t *cfg = &p->cfg_frame;
1454 int total_len = p->cfg_frame_offset + 4 + DRIVER_HANDLER_SIZE;
1455 int seq_no = p->cfg_seq_no % 256;
Chaehyun Lim4e4467f2015-06-11 14:35:55 +09001456 int driver_handler = (u32)drvHandler;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001457
Leo Kimac087c82015-11-06 11:12:25 +09001458 if (type == WILC_CFG_SET) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001459 cfg->wid_header[0] = 'W';
Leo Kimac087c82015-11-06 11:12:25 +09001460 } else {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001461 cfg->wid_header[0] = 'Q';
1462 }
Leo Kimac087c82015-11-06 11:12:25 +09001463 cfg->wid_header[1] = seq_no;
Chaehyun Lim51e825f2015-09-15 14:06:14 +09001464 cfg->wid_header[2] = (u8)total_len;
1465 cfg->wid_header[3] = (u8)(total_len >> 8);
1466 cfg->wid_header[4] = (u8)driver_handler;
1467 cfg->wid_header[5] = (u8)(driver_handler >> 8);
1468 cfg->wid_header[6] = (u8)(driver_handler >> 16);
1469 cfg->wid_header[7] = (u8)(driver_handler >> 24);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001470 p->cfg_seq_no = seq_no;
1471
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001472 if (!wilc_wlan_txq_add_cfg_pkt(&cfg->wid_header[0], total_len))
1473 return -1;
1474
1475 return 0;
1476}
1477
Glen Lee1028e5a2015-10-01 16:03:40 +09001478int wilc_wlan_cfg_set(int start, u32 wid, u8 *buffer, u32 buffer_size,
1479 int commit, u32 drvHandler)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001480{
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +05301481 wilc_wlan_dev_t *p = &g_wlan;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001482 u32 offset;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001483 int ret_size;
1484
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001485 if (p->cfg_frame_in_use)
1486 return 0;
1487
1488 if (start)
1489 p->cfg_frame_offset = 0;
1490
1491 offset = p->cfg_frame_offset;
Glen Lee17e8f162015-10-02 14:22:07 +09001492 ret_size = wilc_wlan_cfg_set_wid(p->cfg_frame.frame, offset, (u16)wid,
1493 buffer, buffer_size);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001494 offset += ret_size;
1495 p->cfg_frame_offset = offset;
1496
1497 if (commit) {
1498 PRINT_D(TX_DBG, "[WILC]PACKET Commit with sequence number %d\n", p->cfg_seq_no);
1499 PRINT_D(RX_DBG, "Processing cfg_set()\n");
1500 p->cfg_frame_in_use = 1;
1501
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001502 if (wilc_wlan_cfg_commit(WILC_CFG_SET, drvHandler))
Chaehyun Lim5af6b852015-09-17 16:48:48 +09001503 ret_size = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001504
Glen Leeb002e202015-09-24 18:15:05 +09001505 if (linux_wlan_lock_timeout(&g_linux_wlan->cfg_event,
1506 CFG_PKTS_TIMEOUT)) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001507 PRINT_D(TX_DBG, "Set Timed Out\n");
1508 ret_size = 0;
1509 }
1510 p->cfg_frame_in_use = 0;
1511 p->cfg_frame_offset = 0;
1512 p->cfg_seq_no += 1;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001513 }
1514
1515 return ret_size;
1516}
Leo Kim2d6973e2015-11-06 11:12:28 +09001517
Glen Lee07056a82015-10-01 16:03:41 +09001518int wilc_wlan_cfg_get(int start, u32 wid, int commit, u32 drvHandler)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001519{
Shivani Bhardwaj7ee82912015-10-13 17:04:48 +05301520 wilc_wlan_dev_t *p = &g_wlan;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001521 u32 offset;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001522 int ret_size;
1523
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001524 if (p->cfg_frame_in_use)
1525 return 0;
1526
1527 if (start)
1528 p->cfg_frame_offset = 0;
1529
1530 offset = p->cfg_frame_offset;
Glen Leeec1b86b2015-10-02 14:22:08 +09001531 ret_size = wilc_wlan_cfg_get_wid(p->cfg_frame.frame, offset, (u16)wid);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001532 offset += ret_size;
1533 p->cfg_frame_offset = offset;
1534
1535 if (commit) {
1536 p->cfg_frame_in_use = 1;
1537
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001538 if (wilc_wlan_cfg_commit(WILC_CFG_QUERY, drvHandler))
Chaehyun Lim5af6b852015-09-17 16:48:48 +09001539 ret_size = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001540
Glen Leeb002e202015-09-24 18:15:05 +09001541 if (linux_wlan_lock_timeout(&g_linux_wlan->cfg_event,
1542 CFG_PKTS_TIMEOUT)) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001543 PRINT_D(TX_DBG, "Get Timed Out\n");
1544 ret_size = 0;
1545 }
1546 PRINT_D(GENERIC_DBG, "[WILC]Get Response received\n");
1547 p->cfg_frame_in_use = 0;
1548 p->cfg_frame_offset = 0;
1549 p->cfg_seq_no += 1;
1550 }
1551
1552 return ret_size;
1553}
1554
Glen Lee894de36b2015-10-01 16:03:42 +09001555int wilc_wlan_cfg_get_val(u32 wid, u8 *buffer, u32 buffer_size)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001556{
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001557 int ret;
1558
Glen Lee355cca22015-10-02 14:22:09 +09001559 ret = wilc_wlan_cfg_get_wid_value((u16)wid, buffer, buffer_size);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001560
1561 return ret;
1562}
1563
1564void wilc_bus_set_max_speed(void)
1565{
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001566 g_wlan.hif_func.hif_set_max_bus_speed();
1567}
1568
1569void wilc_bus_set_default_speed(void)
1570{
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001571 g_wlan.hif_func.hif_set_default_bus_speed();
1572}
Leo Kim2d6973e2015-11-06 11:12:28 +09001573
Glen Leeae6f7722015-10-29 12:18:48 +09001574u32 init_chip(struct net_device *dev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001575{
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001576 u32 chipid;
1577 u32 reg, ret = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001578
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001579 acquire_bus(ACQUIRE_ONLY);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001580
Dean Lee72ed4dc2015-06-12 14:11:44 +09001581 chipid = wilc_get_chipid(true);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001582
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001583 if ((chipid & 0xfff) != 0xa0) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001584 ret = g_wlan.hif_func.hif_read_reg(0x1118, &reg);
1585 if (!ret) {
1586 wilc_debug(N_ERR, "[wilc start]: fail read reg 0x1118 ...\n");
1587 return ret;
1588 }
Anish Bhattffda2032015-09-29 12:15:49 -07001589 reg |= BIT(0);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001590 ret = g_wlan.hif_func.hif_write_reg(0x1118, reg);
1591 if (!ret) {
1592 wilc_debug(N_ERR, "[wilc start]: fail write reg 0x1118 ...\n");
1593 return ret;
1594 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001595 ret = g_wlan.hif_func.hif_write_reg(0xc0000, 0x71);
1596 if (!ret) {
1597 wilc_debug(N_ERR, "[wilc start]: fail write reg 0xc0000 ...\n");
1598 return ret;
1599 }
1600 }
1601
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001602 release_bus(RELEASE_ONLY);
1603
1604 return ret;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001605}
1606
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001607u32 wilc_get_chipid(u8 update)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001608{
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001609 static u32 chipid;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001610 u32 tempchipid = 0;
1611 u32 rfrevid;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001612
1613 if (chipid == 0 || update != 0) {
1614 g_wlan.hif_func.hif_read_reg(0x1000, &tempchipid);
1615 g_wlan.hif_func.hif_read_reg(0x13f4, &rfrevid);
1616 if (!ISWILC1000(tempchipid)) {
1617 chipid = 0;
1618 goto _fail_;
1619 }
1620 if (tempchipid == 0x1002a0) {
Leo Kimac087c82015-11-06 11:12:25 +09001621 if (rfrevid == 0x1) {
1622 } else {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001623 tempchipid = 0x1002a1;
1624 }
1625 } else if (tempchipid == 0x1002b0) {
Leo Kimac087c82015-11-06 11:12:25 +09001626 if (rfrevid == 3) {
1627 } else if (rfrevid == 4) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001628 tempchipid = 0x1002b1;
Leo Kimac087c82015-11-06 11:12:25 +09001629 } else {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001630 tempchipid = 0x1002b2;
1631 }
1632 } else {
1633 }
1634
1635 chipid = tempchipid;
1636 }
1637_fail_:
1638 return chipid;
1639}
1640
Glen Lee47a466f2015-10-29 12:18:47 +09001641int wilc_wlan_init(struct net_device *dev, wilc_wlan_inp_t *inp)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001642{
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001643 int ret = 0;
1644
1645 PRINT_D(INIT_DBG, "Initializing WILC_Wlan ...\n");
1646
1647 memset((void *)&g_wlan, 0, sizeof(wilc_wlan_dev_t));
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001648 memcpy((void *)&g_wlan.io_func, (void *)&inp->io_func, sizeof(wilc_wlan_io_func_t));
Leo Kimac087c82015-11-06 11:12:25 +09001649
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001650 if ((inp->io_func.io_type & 0x1) == HIF_SDIO) {
1651 if (!hif_sdio.hif_init(inp, wilc_debug)) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001652 ret = -5;
1653 goto _fail_;
1654 }
1655 memcpy((void *)&g_wlan.hif_func, &hif_sdio, sizeof(wilc_hif_func_t));
1656 } else {
1657 if ((inp->io_func.io_type & 0x1) == HIF_SPI) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001658 if (!hif_spi.hif_init(inp, wilc_debug)) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001659 ret = -5;
1660 goto _fail_;
1661 }
1662 memcpy((void *)&g_wlan.hif_func, &hif_spi, sizeof(wilc_hif_func_t));
1663 } else {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001664 ret = -5;
1665 goto _fail_;
1666 }
1667 }
1668
Glen Lee814bc362015-10-02 14:22:11 +09001669 if (!wilc_wlan_cfg_init(wilc_debug)) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001670 ret = -105;
1671 goto _fail_;
1672 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001673
Leo Kima4b17192015-11-06 11:12:31 +09001674 if (!g_wlan.tx_buffer)
Glen Lee7015b5d2015-09-24 18:15:02 +09001675 g_wlan.tx_buffer = kmalloc(LINUX_TX_SIZE, GFP_KERNEL);
Arnd Bergmann7a8fd842015-06-01 21:06:45 +02001676 PRINT_D(TX_DBG, "g_wlan.tx_buffer = %p\n", g_wlan.tx_buffer);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001677
Leo Kima4b17192015-11-06 11:12:31 +09001678 if (!g_wlan.tx_buffer) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001679 ret = -105;
1680 PRINT_ER("Can't allocate Tx Buffer");
1681 goto _fail_;
1682 }
1683
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001684#if defined (MEMORY_STATIC)
Leo Kima4b17192015-11-06 11:12:31 +09001685 if (!g_wlan.rx_buffer)
Glen Lee03eb7262015-09-24 18:15:03 +09001686 g_wlan.rx_buffer = kmalloc(LINUX_RX_SIZE, GFP_KERNEL);
Arnd Bergmann7a8fd842015-06-01 21:06:45 +02001687 PRINT_D(TX_DBG, "g_wlan.rx_buffer =%p\n", g_wlan.rx_buffer);
Leo Kima4b17192015-11-06 11:12:31 +09001688 if (!g_wlan.rx_buffer) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001689 ret = -105;
1690 PRINT_ER("Can't allocate Rx Buffer");
1691 goto _fail_;
1692 }
1693#endif
1694
Glen Leeae6f7722015-10-29 12:18:48 +09001695 if (!init_chip(dev)) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001696 ret = -5;
1697 goto _fail_;
1698 }
1699#ifdef TCP_ACK_FILTER
1700 Init_TCP_tracking();
1701#endif
1702
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001703 return 1;
1704
1705_fail_:
1706
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001707 #ifdef MEMORY_STATIC
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -07001708 kfree(g_wlan.rx_buffer);
1709 g_wlan.rx_buffer = NULL;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001710 #endif
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -07001711 kfree(g_wlan.tx_buffer);
1712 g_wlan.tx_buffer = NULL;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001713
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001714 return ret;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001715}
1716
Leo Kim2ad8c472015-11-05 14:36:35 +09001717u16 set_machw_change_vir_if(struct net_device *dev, bool bValue)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001718{
Chaehyun Limd85f5322015-06-11 14:35:54 +09001719 u16 ret;
Chaehyun Lim4e4467f2015-06-11 14:35:55 +09001720 u32 reg;
Glen Lee178c3832015-10-27 18:27:58 +09001721 perInterface_wlan_t *nic;
1722 struct wilc *wilc;
1723
1724 nic = netdev_priv(dev);
1725 wilc = nic->wilc;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001726
Glen Lee178c3832015-10-27 18:27:58 +09001727 mutex_lock(&wilc->hif_cs);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001728 ret = (&g_wlan)->hif_func.hif_read_reg(WILC_CHANGING_VIR_IF, &reg);
Alison Schofield39823a52015-10-08 21:18:03 -07001729 if (!ret)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001730 PRINT_ER("Error while Reading reg WILC_CHANGING_VIR_IF\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001731
Chandra S Gorentla78174ad2015-08-08 17:41:36 +05301732 if (bValue)
Chaehyun Lim50b51da2015-09-16 20:11:26 +09001733 reg |= BIT(31);
Chandra S Gorentla78174ad2015-08-08 17:41:36 +05301734 else
Chaehyun Lim50b51da2015-09-16 20:11:26 +09001735 reg &= ~BIT(31);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001736
1737 ret = (&g_wlan)->hif_func.hif_write_reg(WILC_CHANGING_VIR_IF, reg);
1738
Alison Schofield39823a52015-10-08 21:18:03 -07001739 if (!ret)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001740 PRINT_ER("Error while writing reg WILC_CHANGING_VIR_IF\n");
Alison Schofield39823a52015-10-08 21:18:03 -07001741
Glen Lee178c3832015-10-27 18:27:58 +09001742 mutex_unlock(&wilc->hif_cs);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001743
1744 return ret;
1745}