blob: 83af51bb83e8bd775408b060ee20dd9a0bf4b7a5 [file] [log] [blame]
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001#include "wilc_wlan_if.h"
Arnd Bergmann491880e2015-11-16 15:04:55 +01002#include "wilc_wlan.h"
Tony Cho60bd1002015-10-12 16:56:04 +09003#include "wilc_wfi_netdevice.h"
Glen Lee17e8f162015-10-02 14:22:07 +09004#include "wilc_wlan_cfg.h"
Johnny Kimc5c77ba2015-05-11 14:30:56 +09005
Arnd Bergmann1608c402015-11-16 15:04:53 +01006#ifdef WILC_OPTIMIZE_SLEEP_INT
Glen Lee00215dd2015-11-18 15:11:25 +09007static inline void chip_allow_sleep(struct wilc *wilc);
Arnd Bergmann1608c402015-11-16 15:04:53 +01008#endif
Glen Lee00215dd2015-11-18 15:11:25 +09009static inline void chip_wakeup(struct wilc *wilc);
Chaehyun Limfbc2fe12015-09-15 14:06:16 +090010static u32 dbgflag = N_INIT | N_ERR | N_INTR | N_TXQ | N_RXQ;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090011
Arnd Bergmann562ed3f2015-11-16 15:05:10 +010012/* FIXME: replace with dev_debug() */
Chaehyun Limfbc2fe12015-09-15 14:06:16 +090013static void wilc_debug(u32 flag, char *fmt, ...)
Johnny Kimc5c77ba2015-05-11 14:30:56 +090014{
15 char buf[256];
16 va_list args;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090017
18 if (flag & dbgflag) {
19 va_start(args, fmt);
Hari Prasath Gujulan Elango81053222015-06-22 13:13:58 +000020 vsprintf(buf, fmt, args);
Johnny Kimc5c77ba2015-05-11 14:30:56 +090021 va_end(args);
22
Glen Leed36ec222015-11-18 15:11:36 +090023 wilc_dbg(buf);
Johnny Kimc5c77ba2015-05-11 14:30:56 +090024 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +090025}
26
Leo Kimb7d1e182015-11-06 11:12:30 +090027static CHIP_PS_STATE_T chip_ps_state = CHIP_WAKEDUP;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090028
Arnd Bergmann562ed3f2015-11-16 15:05:10 +010029static inline void acquire_bus(struct wilc *wilc, BUS_ACQUIRE_T acquire)
Johnny Kimc5c77ba2015-05-11 14:30:56 +090030{
Arnd Bergmann562ed3f2015-11-16 15:05:10 +010031 mutex_lock(&wilc->hif_cs);
Johnny Kimc5c77ba2015-05-11 14:30:56 +090032 #ifndef WILC_OPTIMIZE_SLEEP_INT
Leo Kimb7d1e182015-11-06 11:12:30 +090033 if (chip_ps_state != CHIP_WAKEDUP)
Johnny Kimc5c77ba2015-05-11 14:30:56 +090034 #endif
35 {
36 if (acquire == ACQUIRE_AND_WAKEUP)
Glen Lee00215dd2015-11-18 15:11:25 +090037 chip_wakeup(wilc);
Johnny Kimc5c77ba2015-05-11 14:30:56 +090038 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +090039}
Leo Kim2d6973e2015-11-06 11:12:28 +090040
Arnd Bergmann562ed3f2015-11-16 15:05:10 +010041static inline void release_bus(struct wilc *wilc, BUS_RELEASE_T release)
Johnny Kimc5c77ba2015-05-11 14:30:56 +090042{
43 #ifdef WILC_OPTIMIZE_SLEEP_INT
44 if (release == RELEASE_ALLOW_SLEEP)
Glen Lee00215dd2015-11-18 15:11:25 +090045 chip_allow_sleep(wilc);
Johnny Kimc5c77ba2015-05-11 14:30:56 +090046 #endif
Arnd Bergmann562ed3f2015-11-16 15:05:10 +010047 mutex_unlock(&wilc->hif_cs);
Johnny Kimc5c77ba2015-05-11 14:30:56 +090048}
Johnny Kimc5c77ba2015-05-11 14:30:56 +090049
Arnd Bergmann1608c402015-11-16 15:04:53 +010050#ifdef TCP_ACK_FILTER
Johnny Kimc5c77ba2015-05-11 14:30:56 +090051static void wilc_wlan_txq_remove(struct txq_entry_t *tqe)
52{
Leo Kim8739eeb2015-11-06 11:12:29 +090053
Glen Lee67e2a072015-12-21 14:18:12 +090054 if (tqe == wilc->txq_head) {
55 wilc->txq_head = tqe->next;
56 if (wilc->txq_head)
57 wilc->txq_head->prev = NULL;
58 } else if (tqe == wilc->txq_tail) {
59 wilc->txq_tail = (tqe->prev);
60 if (wilc->txq_tail)
61 wilc->txq_tail->next = NULL;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090062 } else {
63 tqe->prev->next = tqe->next;
64 tqe->next->prev = tqe->prev;
65 }
Glen Lee67e2a072015-12-21 14:18:12 +090066 wilc->txq_entries -= 1;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090067}
Arnd Bergmann1608c402015-11-16 15:04:53 +010068#endif
Johnny Kimc5c77ba2015-05-11 14:30:56 +090069
Glen Lee718fc2c2015-10-29 12:18:43 +090070static struct txq_entry_t *
71wilc_wlan_txq_remove_from_head(struct net_device *dev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +090072{
73 struct txq_entry_t *tqe;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090074 unsigned long flags;
Glen Leea4cac482015-12-21 14:18:36 +090075 struct wilc_vif *vif;
Glen Lee718fc2c2015-10-29 12:18:43 +090076 struct wilc *wilc;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +090077
Glen Leea4cac482015-12-21 14:18:36 +090078 vif = netdev_priv(dev);
79 wilc = vif->wilc;
Glen Lee718fc2c2015-10-29 12:18:43 +090080
81 spin_lock_irqsave(&wilc->txq_spinlock, flags);
Glen Lee67e2a072015-12-21 14:18:12 +090082 if (wilc->txq_head) {
83 tqe = wilc->txq_head;
84 wilc->txq_head = tqe->next;
85 if (wilc->txq_head)
86 wilc->txq_head->prev = NULL;
Alison Schofield39823a52015-10-08 21:18:03 -070087
Glen Lee67e2a072015-12-21 14:18:12 +090088 wilc->txq_entries -= 1;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090089 } else {
90 tqe = NULL;
91 }
Glen Lee718fc2c2015-10-29 12:18:43 +090092 spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +090093 return tqe;
94}
95
Glen Lee32f03322015-10-29 12:18:45 +090096static void wilc_wlan_txq_add_to_tail(struct net_device *dev,
97 struct txq_entry_t *tqe)
Johnny Kimc5c77ba2015-05-11 14:30:56 +090098{
Johnny Kimc5c77ba2015-05-11 14:30:56 +090099 unsigned long flags;
Glen Leea4cac482015-12-21 14:18:36 +0900100 struct wilc_vif *vif;
Glen Lee32f03322015-10-29 12:18:45 +0900101 struct wilc *wilc;
102
Glen Leea4cac482015-12-21 14:18:36 +0900103 vif = netdev_priv(dev);
104 wilc = vif->wilc;
Glen Lee32f03322015-10-29 12:18:45 +0900105
106 spin_lock_irqsave(&wilc->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900107
Glen Lee67e2a072015-12-21 14:18:12 +0900108 if (!wilc->txq_head) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900109 tqe->next = NULL;
110 tqe->prev = NULL;
Glen Lee67e2a072015-12-21 14:18:12 +0900111 wilc->txq_head = tqe;
112 wilc->txq_tail = tqe;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900113 } else {
114 tqe->next = NULL;
Glen Lee67e2a072015-12-21 14:18:12 +0900115 tqe->prev = wilc->txq_tail;
116 wilc->txq_tail->next = tqe;
117 wilc->txq_tail = tqe;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900118 }
Glen Lee67e2a072015-12-21 14:18:12 +0900119 wilc->txq_entries += 1;
120 PRINT_D(TX_DBG, "Number of entries in TxQ = %d\n", wilc->txq_entries);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900121
Glen Lee32f03322015-10-29 12:18:45 +0900122 spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900123
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900124 PRINT_D(TX_DBG, "Wake the txq_handling\n");
125
Glen Lee32f03322015-10-29 12:18:45 +0900126 up(&wilc->txq_event);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900127}
128
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100129static int wilc_wlan_txq_add_to_head(struct wilc *wilc, struct txq_entry_t *tqe)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900130{
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900131 unsigned long flags;
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100132 if (wilc_lock_timeout(wilc, &wilc->txq_add_to_head_cs,
Glen Leeb002e202015-09-24 18:15:05 +0900133 CFG_PKTS_TIMEOUT))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900134 return -1;
135
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100136 spin_lock_irqsave(&wilc->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900137
Glen Lee67e2a072015-12-21 14:18:12 +0900138 if (!wilc->txq_head) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900139 tqe->next = NULL;
140 tqe->prev = NULL;
Glen Lee67e2a072015-12-21 14:18:12 +0900141 wilc->txq_head = tqe;
142 wilc->txq_tail = tqe;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900143 } else {
Glen Lee67e2a072015-12-21 14:18:12 +0900144 tqe->next = wilc->txq_head;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900145 tqe->prev = NULL;
Glen Lee67e2a072015-12-21 14:18:12 +0900146 wilc->txq_head->prev = tqe;
147 wilc->txq_head = tqe;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900148 }
Glen Lee67e2a072015-12-21 14:18:12 +0900149 wilc->txq_entries += 1;
150 PRINT_D(TX_DBG, "Number of entries in TxQ = %d\n", wilc->txq_entries);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900151
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100152 spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
153 up(&wilc->txq_add_to_head_cs);
154 up(&wilc->txq_event);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900155 PRINT_D(TX_DBG, "Wake up the txq_handler\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900156
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900157 return 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900158}
159
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900160#ifdef TCP_ACK_FILTER
Leo Kim130a41f2015-11-06 11:12:34 +0900161struct ack_session_info;
162struct ack_session_info {
Leo Kimd06b6cb2015-11-06 11:12:35 +0900163 u32 seq_num;
Leo Kim9d54d3d2015-11-06 11:12:36 +0900164 u32 bigger_ack_num;
Chaehyun Limec53adf2015-09-15 14:06:15 +0900165 u16 src_port;
166 u16 dst_port;
167 u16 status;
Shraddha Barkeeeb1c062015-08-05 01:29:22 +0530168};
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900169
Leo Kim08b90b12015-11-06 11:12:37 +0900170struct pending_acks_info {
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900171 u32 ack_num;
Leo Kim84136972015-11-06 11:12:38 +0900172 u32 session_index;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900173 struct txq_entry_t *txqe;
Leo Kim08b90b12015-11-06 11:12:37 +0900174};
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900175
Arnd Bergmann1608c402015-11-16 15:04:53 +0100176
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900177#define NOT_TCP_ACK (-1)
178
179#define MAX_TCP_SESSION 25
180#define MAX_PENDING_ACKS 256
Arnd Bergmann1608c402015-11-16 15:04:53 +0100181static struct ack_session_info ack_session_info[2 * MAX_TCP_SESSION];
182static struct pending_acks_info pending_acks_info[MAX_PENDING_ACKS];
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900183
Arnd Bergmann1608c402015-11-16 15:04:53 +0100184static u32 pending_base;
185static u32 tcp_session;
186static u32 pending_acks;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900187
Leo Kimef06b5f2015-11-06 11:12:44 +0900188static inline int init_tcp_tracking(void)
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}
Leo Kim2d6973e2015-11-06 11:12:28 +0900192
Leo Kim67620782015-11-06 11:12:45 +0900193static inline int add_tcp_session(u32 src_prt, u32 dst_prt, u32 seq)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900194{
Leo Kim3056ec32015-11-06 11:12:42 +0900195 ack_session_info[tcp_session].seq_num = seq;
196 ack_session_info[tcp_session].bigger_ack_num = 0;
197 ack_session_info[tcp_session].src_port = src_prt;
198 ack_session_info[tcp_session].dst_port = dst_prt;
199 tcp_session++;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900200
Leo Kim3056ec32015-11-06 11:12:42 +0900201 PRINT_D(TCP_ENH, "TCP Session %d to Ack %d\n", tcp_session, seq);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900202 return 0;
203}
204
Leo Kimb801a962015-11-06 11:12:48 +0900205static inline int update_tcp_session(u32 index, u32 ack)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900206{
Leo Kimb801a962015-11-06 11:12:48 +0900207 if (ack > ack_session_info[index].bigger_ack_num)
208 ack_session_info[index].bigger_ack_num = ack;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900209 return 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900210}
Leo Kim2d6973e2015-11-06 11:12:28 +0900211
Leo Kimea03f572015-11-06 11:12:49 +0900212static inline int add_tcp_pending_ack(u32 ack, u32 session_index,
Leo Kim66a43a92015-11-06 11:19:50 +0900213 struct txq_entry_t *txqe)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900214{
Leo Kimd12ac7e2015-11-06 11:12:43 +0900215 if (pending_acks < MAX_PENDING_ACKS) {
Leo Kimb801a962015-11-06 11:12:48 +0900216 pending_acks_info[pending_base + pending_acks].ack_num = ack;
Leo Kimd12ac7e2015-11-06 11:12:43 +0900217 pending_acks_info[pending_base + pending_acks].txqe = txqe;
Leo Kimea03f572015-11-06 11:12:49 +0900218 pending_acks_info[pending_base + pending_acks].session_index = session_index;
Glen Leeb7193022015-12-21 14:18:07 +0900219 txqe->tcp_pending_ack_idx = pending_base + pending_acks;
Leo Kimd12ac7e2015-11-06 11:12:43 +0900220 pending_acks++;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900221 }
222 return 0;
223}
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100224static inline int remove_TCP_related(struct wilc *wilc)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900225{
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900226 unsigned long flags;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900227
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100228 spin_lock_irqsave(&wilc->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900229
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100230 spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900231 return 0;
232}
233
Glen Lee82bb18e2015-10-27 18:28:03 +0900234static inline int tcp_process(struct net_device *dev, struct txq_entry_t *tqe)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900235{
236 int ret;
Chaehyun Lim51e825f2015-09-15 14:06:14 +0900237 u8 *eth_hdr_ptr;
238 u8 *buffer = tqe->buffer;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900239 unsigned short h_proto;
240 int i;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900241 unsigned long flags;
Glen Leea4cac482015-12-21 14:18:36 +0900242 struct wilc_vif *vif;
Glen Lee82bb18e2015-10-27 18:28:03 +0900243 struct wilc *wilc;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900244
Glen Leea4cac482015-12-21 14:18:36 +0900245 vif = netdev_priv(dev);
246 wilc = vif->wilc;
Glen Lee82bb18e2015-10-27 18:28:03 +0900247
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900248
249 eth_hdr_ptr = &buffer[0];
250 h_proto = ntohs(*((unsigned short *)&eth_hdr_ptr[12]));
Leo Kimac087c82015-11-06 11:12:25 +0900251 if (h_proto == 0x0800) {
Chaehyun Lim51e825f2015-09-15 14:06:14 +0900252 u8 *ip_hdr_ptr;
253 u8 protocol;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900254
255 ip_hdr_ptr = &buffer[ETHERNET_HDR_LEN];
256 protocol = ip_hdr_ptr[9];
257
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900258 if (protocol == 0x06) {
Chaehyun Lim51e825f2015-09-15 14:06:14 +0900259 u8 *tcp_hdr_ptr;
Leo Kim51bffa92015-11-06 11:12:52 +0900260 u32 IHL, total_length, data_offset;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900261
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900262 tcp_hdr_ptr = &ip_hdr_ptr[IP_HDR_LEN];
263 IHL = (ip_hdr_ptr[0] & 0xf) << 2;
Leo Kim24e2dac2015-11-06 11:12:51 +0900264 total_length = ((u32)ip_hdr_ptr[2] << 8) +
265 (u32)ip_hdr_ptr[3];
Leo Kim51bffa92015-11-06 11:12:52 +0900266 data_offset = ((u32)tcp_hdr_ptr[12] & 0xf0) >> 2;
267 if (total_length == (IHL + data_offset)) {
Leo Kimf91c5d72015-11-06 11:12:53 +0900268 u32 seq_no, ack_no;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900269
Leo Kim4478c622015-11-06 11:12:54 +0900270 seq_no = ((u32)tcp_hdr_ptr[4] << 24) +
271 ((u32)tcp_hdr_ptr[5] << 16) +
272 ((u32)tcp_hdr_ptr[6] << 8) +
273 (u32)tcp_hdr_ptr[7];
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900274
Leo Kimf91c5d72015-11-06 11:12:53 +0900275 ack_no = ((u32)tcp_hdr_ptr[8] << 24) +
276 ((u32)tcp_hdr_ptr[9] << 16) +
277 ((u32)tcp_hdr_ptr[10] << 8) +
278 (u32)tcp_hdr_ptr[11];
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900279
Leo Kim3056ec32015-11-06 11:12:42 +0900280 for (i = 0; i < tcp_session; i++) {
Leo Kim32065052015-11-06 11:12:39 +0900281 if (ack_session_info[i].seq_num == seq_no) {
Leo Kimf91c5d72015-11-06 11:12:53 +0900282 update_tcp_session(i, ack_no);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900283 break;
284 }
285 }
Leo Kim3056ec32015-11-06 11:12:42 +0900286 if (i == tcp_session)
Leo Kim67620782015-11-06 11:12:45 +0900287 add_tcp_session(0, 0, seq_no);
Alison Schofield39823a52015-10-08 21:18:03 -0700288
Leo Kimf91c5d72015-11-06 11:12:53 +0900289 add_tcp_pending_ack(ack_no, i, tqe);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900290 }
291
292 } else {
293 ret = 0;
294 }
295 } else {
296 ret = 0;
297 }
Glen Lee82bb18e2015-10-27 18:28:03 +0900298 spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900299 return ret;
300}
301
Glen Leec029e992015-10-27 18:27:48 +0900302static int wilc_wlan_txq_filter_dup_tcp_ack(struct net_device *dev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900303{
Glen Leea4cac482015-12-21 14:18:36 +0900304 struct wilc_vif *vif;
Glen Leec029e992015-10-27 18:27:48 +0900305 struct wilc *wilc;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900306 u32 i = 0;
Leo Kim442eda42015-11-06 11:12:55 +0900307 u32 dropped = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900308
Glen Leea4cac482015-12-21 14:18:36 +0900309 vif = netdev_priv(dev);
310 wilc = vif->wilc;
Glen Leec029e992015-10-27 18:27:48 +0900311
Glen Lee67e2a072015-12-21 14:18:12 +0900312 spin_lock_irqsave(&wilc->txq_spinlock, wilc->txq_spinlock_flags);
Leo Kimd12ac7e2015-11-06 11:12:43 +0900313 for (i = pending_base; i < (pending_base + pending_acks); i++) {
Leo Kim2bb17082015-11-06 11:12:40 +0900314 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 +0900315 struct txq_entry_t *tqe;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900316
Leo Kim2bb17082015-11-06 11:12:40 +0900317 PRINT_D(TCP_ENH, "DROP ACK: %u\n",
318 pending_acks_info[i].ack_num);
319 tqe = pending_acks_info[i].txqe;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900320 if (tqe) {
321 wilc_wlan_txq_remove(tqe);
Leo Kimac087c82015-11-06 11:12:25 +0900322 tqe->status = 1;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900323 if (tqe->tx_complete_func)
Leo Kimab12d8c2015-11-06 11:19:54 +0900324 tqe->tx_complete_func(tqe->priv,
325 tqe->status);
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -0700326 kfree(tqe);
Leo Kim442eda42015-11-06 11:12:55 +0900327 dropped++;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900328 }
329 }
330 }
Leo Kimd12ac7e2015-11-06 11:12:43 +0900331 pending_acks = 0;
Leo Kim3056ec32015-11-06 11:12:42 +0900332 tcp_session = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900333
Leo Kim2ae91ed2015-11-06 11:12:41 +0900334 if (pending_base == 0)
335 pending_base = MAX_TCP_SESSION;
Chandra S Gorentla78174ad2015-08-08 17:41:36 +0530336 else
Leo Kim2ae91ed2015-11-06 11:12:41 +0900337 pending_base = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900338
Glen Lee67e2a072015-12-21 14:18:12 +0900339 spin_unlock_irqrestore(&wilc->txq_spinlock, wilc->txq_spinlock_flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900340
Leo Kim442eda42015-11-06 11:12:55 +0900341 while (dropped > 0) {
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100342 wilc_lock_timeout(wilc, &wilc->txq_event, 1);
Leo Kim442eda42015-11-06 11:12:55 +0900343 dropped--;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900344 }
345
346 return 1;
347}
348#endif
349
Arnd Bergmann1608c402015-11-16 15:04:53 +0100350static bool enabled = false;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900351
Arnd Bergmann0e1af732015-11-16 15:04:54 +0100352void wilc_enable_tcp_ack_filter(bool value)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900353{
Leo Kim7c4bafe2015-11-06 11:12:56 +0900354 enabled = value;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900355}
356
Arnd Bergmann1608c402015-11-16 15:04:53 +0100357#ifdef TCP_ACK_FILTER
358static bool is_tcp_ack_filter_enabled(void)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900359{
Leo Kim7c4bafe2015-11-06 11:12:56 +0900360 return enabled;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900361}
Arnd Bergmann1608c402015-11-16 15:04:53 +0100362#endif
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900363
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100364static int wilc_wlan_txq_add_cfg_pkt(struct wilc *wilc, u8 *buffer, u32 buffer_size)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900365{
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900366 struct txq_entry_t *tqe;
367
368 PRINT_D(TX_DBG, "Adding config packet ...\n");
Glen Lee67e2a072015-12-21 14:18:12 +0900369 if (wilc->quit) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900370 PRINT_D(TX_DBG, "Return due to clear function\n");
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100371 up(&wilc->cfg_event);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900372 return 0;
373 }
374
Leo Kim1d401a42015-11-06 11:12:59 +0900375 tqe = kmalloc(sizeof(*tqe), GFP_ATOMIC);
Leo Kima4b17192015-11-06 11:12:31 +0900376 if (!tqe) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900377 PRINT_ER("Failed to allocate memory\n");
378 return 0;
379 }
380
381 tqe->type = WILC_CFG_PKT;
382 tqe->buffer = buffer;
383 tqe->buffer_size = buffer_size;
384 tqe->tx_complete_func = NULL;
385 tqe->priv = NULL;
386#ifdef TCP_ACK_FILTER
Glen Leeb7193022015-12-21 14:18:07 +0900387 tqe->tcp_pending_ack_idx = NOT_TCP_ACK;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900388#endif
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900389 PRINT_D(TX_DBG, "Adding the config packet at the Queue tail\n");
390
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100391 if (wilc_wlan_txq_add_to_head(wilc, tqe))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900392 return 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900393 return 1;
394}
395
Glen Lee691bbd42015-10-27 18:28:02 +0900396int wilc_wlan_txq_add_net_pkt(struct net_device *dev, void *priv, u8 *buffer,
397 u32 buffer_size, wilc_tx_complete_func_t func)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900398{
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900399 struct txq_entry_t *tqe;
Glen Leea4cac482015-12-21 14:18:36 +0900400 struct wilc_vif *vif = netdev_priv(dev);
Glen Lee67e2a072015-12-21 14:18:12 +0900401 struct wilc *wilc;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900402
Glen Leea4cac482015-12-21 14:18:36 +0900403 wilc = vif->wilc;
Glen Lee67e2a072015-12-21 14:18:12 +0900404
405 if (wilc->quit)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900406 return 0;
407
Leo Kim1d401a42015-11-06 11:12:59 +0900408 tqe = kmalloc(sizeof(*tqe), GFP_ATOMIC);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900409
Leo Kima4b17192015-11-06 11:12:31 +0900410 if (!tqe)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900411 return 0;
412 tqe->type = WILC_NET_PKT;
413 tqe->buffer = buffer;
414 tqe->buffer_size = buffer_size;
415 tqe->tx_complete_func = func;
416 tqe->priv = priv;
417
418 PRINT_D(TX_DBG, "Adding mgmt packet at the Queue tail\n");
419#ifdef TCP_ACK_FILTER
Glen Leeb7193022015-12-21 14:18:07 +0900420 tqe->tcp_pending_ack_idx = NOT_TCP_ACK;
Leo Kim44c44172015-11-06 11:12:58 +0900421 if (is_tcp_ack_filter_enabled())
Glen Lee82bb18e2015-10-27 18:28:03 +0900422 tcp_process(dev, tqe);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900423#endif
Glen Lee32f03322015-10-29 12:18:45 +0900424 wilc_wlan_txq_add_to_tail(dev, tqe);
Glen Lee67e2a072015-12-21 14:18:12 +0900425 return wilc->txq_entries;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900426}
Glen Leefcc6ef92015-09-16 18:53:21 +0900427
Glen Lee829c4772015-10-29 12:18:44 +0900428int wilc_wlan_txq_add_mgmt_pkt(struct net_device *dev, void *priv, u8 *buffer,
429 u32 buffer_size, wilc_tx_complete_func_t func)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900430{
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900431 struct txq_entry_t *tqe;
Glen Leea4cac482015-12-21 14:18:36 +0900432 struct wilc_vif *vif = netdev_priv(dev);
Glen Lee67e2a072015-12-21 14:18:12 +0900433 struct wilc *wilc;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900434
Glen Leea4cac482015-12-21 14:18:36 +0900435 wilc = vif->wilc;
Glen Lee67e2a072015-12-21 14:18:12 +0900436
437 if (wilc->quit)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900438 return 0;
439
Leo Kim1d401a42015-11-06 11:12:59 +0900440 tqe = kmalloc(sizeof(*tqe), GFP_KERNEL);
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_MGMT_PKT;
445 tqe->buffer = buffer;
446 tqe->buffer_size = buffer_size;
447 tqe->tx_complete_func = func;
448 tqe->priv = priv;
449#ifdef TCP_ACK_FILTER
Glen Leeb7193022015-12-21 14:18:07 +0900450 tqe->tcp_pending_ack_idx = NOT_TCP_ACK;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900451#endif
452 PRINT_D(TX_DBG, "Adding Network packet at the Queue tail\n");
Glen Lee32f03322015-10-29 12:18:45 +0900453 wilc_wlan_txq_add_to_tail(dev, tqe);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900454 return 1;
455}
Glen Leefcc6ef92015-09-16 18:53:21 +0900456
Glen Lee7af05222015-10-29 12:18:41 +0900457static struct txq_entry_t *wilc_wlan_txq_get_first(struct wilc *wilc)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900458{
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900459 struct txq_entry_t *tqe;
460 unsigned long flags;
461
Glen Lee7af05222015-10-29 12:18:41 +0900462 spin_lock_irqsave(&wilc->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900463
Glen Lee67e2a072015-12-21 14:18:12 +0900464 tqe = wilc->txq_head;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900465
Glen Lee7af05222015-10-29 12:18:41 +0900466 spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900467
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900468 return tqe;
469}
470
Glen Lee50a0b3b2015-10-27 18:28:00 +0900471static struct txq_entry_t *wilc_wlan_txq_get_next(struct wilc *wilc,
472 struct txq_entry_t *tqe)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900473{
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900474 unsigned long flags;
Leo Kim8739eeb2015-11-06 11:12:29 +0900475
Glen Lee50a0b3b2015-10-27 18:28:00 +0900476 spin_lock_irqsave(&wilc->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900477
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900478 tqe = tqe->next;
Glen Lee50a0b3b2015-10-27 18:28:00 +0900479 spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900480
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900481 return tqe;
482}
483
Glen Leed06f3622015-10-27 18:27:59 +0900484static int wilc_wlan_rxq_add(struct wilc *wilc, struct rxq_entry_t *rqe)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900485{
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900486
Glen Lee67e2a072015-12-21 14:18:12 +0900487 if (wilc->quit)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900488 return 0;
489
Glen Leed06f3622015-10-27 18:27:59 +0900490 mutex_lock(&wilc->rxq_cs);
Glen Lee67e2a072015-12-21 14:18:12 +0900491 if (!wilc->rxq_head) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900492 PRINT_D(RX_DBG, "Add to Queue head\n");
493 rqe->next = NULL;
Glen Lee67e2a072015-12-21 14:18:12 +0900494 wilc->rxq_head = rqe;
495 wilc->rxq_tail = rqe;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900496 } else {
497 PRINT_D(RX_DBG, "Add to Queue tail\n");
Glen Lee67e2a072015-12-21 14:18:12 +0900498 wilc->rxq_tail->next = rqe;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900499 rqe->next = NULL;
Glen Lee67e2a072015-12-21 14:18:12 +0900500 wilc->rxq_tail = rqe;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900501 }
Glen Lee67e2a072015-12-21 14:18:12 +0900502 wilc->rxq_entries += 1;
503 PRINT_D(RX_DBG, "Number of queue entries: %d\n", wilc->rxq_entries);
Glen Leed06f3622015-10-27 18:27:59 +0900504 mutex_unlock(&wilc->rxq_cs);
Glen Lee67e2a072015-12-21 14:18:12 +0900505 return wilc->rxq_entries;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900506}
507
Glen Leedb387632015-10-27 18:27:55 +0900508static struct rxq_entry_t *wilc_wlan_rxq_remove(struct wilc *wilc)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900509{
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900510
511 PRINT_D(RX_DBG, "Getting rxQ element\n");
Glen Lee67e2a072015-12-21 14:18:12 +0900512 if (wilc->rxq_head) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900513 struct rxq_entry_t *rqe;
514
Glen Leedb387632015-10-27 18:27:55 +0900515 mutex_lock(&wilc->rxq_cs);
Glen Lee67e2a072015-12-21 14:18:12 +0900516 rqe = wilc->rxq_head;
517 wilc->rxq_head = wilc->rxq_head->next;
518 wilc->rxq_entries -= 1;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900519 PRINT_D(RX_DBG, "RXQ entries decreased\n");
Glen Leedb387632015-10-27 18:27:55 +0900520 mutex_unlock(&wilc->rxq_cs);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900521 return rqe;
522 }
523 PRINT_D(RX_DBG, "Nothing to get from Q\n");
524 return NULL;
525}
526
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900527#ifdef WILC_OPTIMIZE_SLEEP_INT
528
Glen Lee00215dd2015-11-18 15:11:25 +0900529static inline void chip_allow_sleep(struct wilc *wilc)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900530{
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900531 u32 reg = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900532
Glen Leeaf9ae092015-12-21 14:18:09 +0900533 wilc->hif_func->hif_read_reg(wilc, 0xf0, &reg);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900534
Glen Leeaf9ae092015-12-21 14:18:09 +0900535 wilc->hif_func->hif_write_reg(wilc, 0xf0, reg & ~BIT(0));
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900536}
537
Glen Lee00215dd2015-11-18 15:11:25 +0900538static inline void chip_wakeup(struct wilc *wilc)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900539{
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900540 u32 reg, clk_status_reg, trials = 0;
541 u32 sleep_time;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900542
Glen Leea3629a92015-12-21 14:18:10 +0900543 if ((wilc->io_type & 0x1) == HIF_SPI) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900544 do {
Glen Leeaf9ae092015-12-21 14:18:09 +0900545 wilc->hif_func->hif_read_reg(wilc, 1, &reg);
546 wilc->hif_func->hif_write_reg(wilc, 1, reg | BIT(1));
547 wilc->hif_func->hif_write_reg(wilc, 1, reg & ~BIT(1));
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900548
549 do {
Greg Kroah-Hartman80e29c72015-08-14 19:42:23 -0700550 usleep_range(2 * 1000, 2 * 1000);
Glen Lee00215dd2015-11-18 15:11:25 +0900551 if ((wilc_get_chipid(wilc, true) == 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900552 wilc_debug(N_ERR, "Couldn't read chip id. Wake up failed\n");
Alison Schofield39823a52015-10-08 21:18:03 -0700553
Glen Lee00215dd2015-11-18 15:11:25 +0900554 } while ((wilc_get_chipid(wilc, true) == 0) && ((++trials % 3) == 0));
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900555
Glen Lee00215dd2015-11-18 15:11:25 +0900556 } while (wilc_get_chipid(wilc, true) == 0);
Glen Leea3629a92015-12-21 14:18:10 +0900557 } else if ((wilc->io_type & 0x1) == HIF_SDIO) {
Glen Leeaf9ae092015-12-21 14:18:09 +0900558 wilc->hif_func->hif_read_reg(wilc, 0xf0, &reg);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900559 do {
Glen Leeaf9ae092015-12-21 14:18:09 +0900560 wilc->hif_func->hif_write_reg(wilc, 0xf0,
Glen Lee49dcd0d2015-11-18 15:11:26 +0900561 reg | BIT(0));
Glen Leeaf9ae092015-12-21 14:18:09 +0900562 wilc->hif_func->hif_read_reg(wilc, 0xf1,
Glen Lee49dcd0d2015-11-18 15:11:26 +0900563 &clk_status_reg);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900564
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900565 while (((clk_status_reg & 0x1) == 0) && (((++trials) % 3) == 0)) {
Greg Kroah-Hartman80e29c72015-08-14 19:42:23 -0700566 usleep_range(2 * 1000, 2 * 1000);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900567
Glen Leeaf9ae092015-12-21 14:18:09 +0900568 wilc->hif_func->hif_read_reg(wilc, 0xf1,
Glen Lee49dcd0d2015-11-18 15:11:26 +0900569 &clk_status_reg);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900570
Alison Schofield39823a52015-10-08 21:18:03 -0700571 if ((clk_status_reg & 0x1) == 0)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900572 wilc_debug(N_ERR, "clocks still OFF. Wake up failed\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900573 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900574 if ((clk_status_reg & 0x1) == 0) {
Glen Leeaf9ae092015-12-21 14:18:09 +0900575 wilc->hif_func->hif_write_reg(wilc, 0xf0,
Glen Lee49dcd0d2015-11-18 15:11:26 +0900576 reg & (~BIT(0)));
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900577 }
578 } while ((clk_status_reg & 0x1) == 0);
579 }
580
Leo Kimb7d1e182015-11-06 11:12:30 +0900581 if (chip_ps_state == CHIP_SLEEPING_MANUAL) {
Glen Leeaf9ae092015-12-21 14:18:09 +0900582 wilc->hif_func->hif_read_reg(wilc, 0x1C0C, &reg);
Anish Bhattffda2032015-09-29 12:15:49 -0700583 reg &= ~BIT(0);
Glen Leeaf9ae092015-12-21 14:18:09 +0900584 wilc->hif_func->hif_write_reg(wilc, 0x1C0C, reg);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900585
Glen Lee00215dd2015-11-18 15:11:25 +0900586 if (wilc_get_chipid(wilc, false) >= 0x1002b0) {
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900587 u32 val32;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900588
Glen Leeaf9ae092015-12-21 14:18:09 +0900589 wilc->hif_func->hif_read_reg(wilc, 0x1e1c, &val32);
Anish Bhattffda2032015-09-29 12:15:49 -0700590 val32 |= BIT(6);
Glen Leeaf9ae092015-12-21 14:18:09 +0900591 wilc->hif_func->hif_write_reg(wilc, 0x1e1c, val32);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900592
Glen Leeaf9ae092015-12-21 14:18:09 +0900593 wilc->hif_func->hif_read_reg(wilc, 0x1e9c, &val32);
Anish Bhattffda2032015-09-29 12:15:49 -0700594 val32 |= BIT(6);
Glen Leeaf9ae092015-12-21 14:18:09 +0900595 wilc->hif_func->hif_write_reg(wilc, 0x1e9c, val32);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900596 }
597 }
Leo Kimb7d1e182015-11-06 11:12:30 +0900598 chip_ps_state = CHIP_WAKEDUP;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900599}
600#else
Glen Lee00215dd2015-11-18 15:11:25 +0900601static inline void chip_wakeup(struct wilc *wilc)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900602{
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900603 u32 reg, trials = 0;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900604
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900605 do {
Glen Leea3629a92015-12-21 14:18:10 +0900606 if ((wilc->io_type & 0x1) == HIF_SPI) {
Glen Leeaf9ae092015-12-21 14:18:09 +0900607 wilc->hif_func->hif_read_reg(wilc, 1, &reg);
608 wilc->hif_func->hif_write_reg(wilc, 1, reg & ~BIT(1));
609 wilc->hif_func->hif_write_reg(wilc, 1, reg | BIT(1));
610 wilc->hif_func->hif_write_reg(wilc, 1, reg & ~BIT(1));
Glen Leea3629a92015-12-21 14:18:10 +0900611 } else if ((wilc->io_type & 0x1) == HIF_SDIO) {
Glen Leeaf9ae092015-12-21 14:18:09 +0900612 wilc->hif_func->hif_read_reg(wilc, 0xf0, &reg);
613 wilc->hif_func->hif_write_reg(wilc, 0xf0,
Glen Lee49dcd0d2015-11-18 15:11:26 +0900614 reg & ~BIT(0));
Glen Leeaf9ae092015-12-21 14:18:09 +0900615 wilc->hif_func->hif_write_reg(wilc, 0xf0,
Glen Lee49dcd0d2015-11-18 15:11:26 +0900616 reg | BIT(0));
Glen Leeaf9ae092015-12-21 14:18:09 +0900617 wilc->hif_func->hif_write_reg(wilc, 0xf0,
Glen Lee49dcd0d2015-11-18 15:11:26 +0900618 reg & ~BIT(0));
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900619 }
620
621 do {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900622 mdelay(3);
623
Glen Lee00215dd2015-11-18 15:11:25 +0900624 if ((wilc_get_chipid(wilc, true) == 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900625 wilc_debug(N_ERR, "Couldn't read chip id. Wake up failed\n");
Alison Schofield39823a52015-10-08 21:18:03 -0700626
Glen Lee00215dd2015-11-18 15:11:25 +0900627 } while ((wilc_get_chipid(wilc, true) == 0) && ((++trials % 3) == 0));
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900628
Glen Lee00215dd2015-11-18 15:11:25 +0900629 } while (wilc_get_chipid(wilc, true) == 0);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900630
Leo Kimb7d1e182015-11-06 11:12:30 +0900631 if (chip_ps_state == CHIP_SLEEPING_MANUAL) {
Glen Leeaf9ae092015-12-21 14:18:09 +0900632 wilc->hif_func->hif_read_reg(wilc, 0x1C0C, &reg);
Anish Bhattffda2032015-09-29 12:15:49 -0700633 reg &= ~BIT(0);
Glen Leeaf9ae092015-12-21 14:18:09 +0900634 wilc->hif_func->hif_write_reg(wilc, 0x1C0C, reg);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900635
Glen Lee00215dd2015-11-18 15:11:25 +0900636 if (wilc_get_chipid(wilc, false) >= 0x1002b0) {
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900637 u32 val32;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900638
Glen Leeaf9ae092015-12-21 14:18:09 +0900639 wilc->hif_func->hif_read_reg(wilc, 0x1e1c, &val32);
Anish Bhattffda2032015-09-29 12:15:49 -0700640 val32 |= BIT(6);
Glen Leeaf9ae092015-12-21 14:18:09 +0900641 wilc->hif_func->hif_write_reg(wilc, 0x1e1c, val32);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900642
Glen Leeaf9ae092015-12-21 14:18:09 +0900643 wilc->hif_func->hif_read_reg(wilc, 0x1e9c, &val32);
Anish Bhattffda2032015-09-29 12:15:49 -0700644 val32 |= BIT(6);
Glen Leeaf9ae092015-12-21 14:18:09 +0900645 wilc->hif_func->hif_write_reg(wilc, 0x1e9c, val32);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900646 }
647 }
Leo Kimb7d1e182015-11-06 11:12:30 +0900648 chip_ps_state = CHIP_WAKEDUP;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900649}
650#endif
Glen Lee00215dd2015-11-18 15:11:25 +0900651void wilc_chip_sleep_manually(struct wilc *wilc)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900652{
Leo Kimb7d1e182015-11-06 11:12:30 +0900653 if (chip_ps_state != CHIP_WAKEDUP)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900654 return;
Glen Lee00215dd2015-11-18 15:11:25 +0900655 acquire_bus(wilc, ACQUIRE_ONLY);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900656
657#ifdef WILC_OPTIMIZE_SLEEP_INT
Glen Lee00215dd2015-11-18 15:11:25 +0900658 chip_allow_sleep(wilc);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900659#endif
Glen Leeaf9ae092015-12-21 14:18:09 +0900660 wilc->hif_func->hif_write_reg(wilc, 0x10a8, 1);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900661
Leo Kimb7d1e182015-11-06 11:12:30 +0900662 chip_ps_state = CHIP_SLEEPING_MANUAL;
Glen Lee00215dd2015-11-18 15:11:25 +0900663 release_bus(wilc, RELEASE_ONLY);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900664}
665
Leo Kimb1d19292015-11-06 11:13:01 +0900666int wilc_wlan_handle_txq(struct net_device *dev, u32 *txq_count)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900667{
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900668 int i, entries = 0;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900669 u32 sum;
670 u32 reg;
Glen Lee67e2a072015-12-21 14:18:12 +0900671 u8 *txb;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900672 u32 offset = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900673 int vmm_sz = 0;
674 struct txq_entry_t *tqe;
675 int ret = 0;
676 int counter;
677 int timeout;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900678 u32 vmm_table[WILC_VMM_TBL_SIZE];
Glen Leea4cac482015-12-21 14:18:36 +0900679 struct wilc_vif *vif;
Glen Leea1332ca2015-10-27 18:27:47 +0900680 struct wilc *wilc;
681
Glen Leea4cac482015-12-21 14:18:36 +0900682 vif = netdev_priv(dev);
683 wilc = vif->wilc;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900684
Glen Lee67e2a072015-12-21 14:18:12 +0900685 txb = wilc->tx_buffer;
686 wilc->txq_exit = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900687 do {
Glen Lee67e2a072015-12-21 14:18:12 +0900688 if (wilc->quit)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900689 break;
690
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100691 wilc_lock_timeout(wilc, &wilc->txq_add_to_head_cs,
Glen Leeb002e202015-09-24 18:15:05 +0900692 CFG_PKTS_TIMEOUT);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900693#ifdef TCP_ACK_FILTER
Glen Leec029e992015-10-27 18:27:48 +0900694 wilc_wlan_txq_filter_dup_tcp_ack(dev);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900695#endif
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900696 PRINT_D(TX_DBG, "Getting the head of the TxQ\n");
Glen Lee7af05222015-10-29 12:18:41 +0900697 tqe = wilc_wlan_txq_get_first(wilc);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900698 i = 0;
699 sum = 0;
700 do {
Leo Kima4b17192015-11-06 11:12:31 +0900701 if (tqe && (i < (WILC_VMM_TBL_SIZE - 1))) {
Alison Schofield39823a52015-10-08 21:18:03 -0700702 if (tqe->type == WILC_CFG_PKT)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900703 vmm_sz = ETH_CONFIG_PKT_HDR_OFFSET;
Alison Schofield39823a52015-10-08 21:18:03 -0700704
705 else if (tqe->type == WILC_NET_PKT)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900706 vmm_sz = ETH_ETHERNET_HDR_OFFSET;
Alison Schofield39823a52015-10-08 21:18:03 -0700707
708 else
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900709 vmm_sz = HOST_HDR_OFFSET;
Alison Schofield39823a52015-10-08 21:18:03 -0700710
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900711 vmm_sz += tqe->buffer_size;
712 PRINT_D(TX_DBG, "VMM Size before alignment = %d\n", vmm_sz);
Leo Kimac087c82015-11-06 11:12:25 +0900713 if (vmm_sz & 0x3)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900714 vmm_sz = (vmm_sz + 4) & ~0x3;
Leo Kimac087c82015-11-06 11:12:25 +0900715
Alison Schofield39823a52015-10-08 21:18:03 -0700716 if ((sum + vmm_sz) > LINUX_TX_SIZE)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900717 break;
Alison Schofield39823a52015-10-08 21:18:03 -0700718
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900719 PRINT_D(TX_DBG, "VMM Size AFTER alignment = %d\n", vmm_sz);
Leo Kimac087c82015-11-06 11:12:25 +0900720 vmm_table[i] = vmm_sz / 4;
Leo Kimab12d8c2015-11-06 11:19:54 +0900721 PRINT_D(TX_DBG, "VMMTable entry size = %d\n",
722 vmm_table[i]);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900723
724 if (tqe->type == WILC_CFG_PKT) {
Anish Bhattffda2032015-09-29 12:15:49 -0700725 vmm_table[i] |= BIT(10);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900726 PRINT_D(TX_DBG, "VMMTable entry changed for CFG packet = %d\n", vmm_table[i]);
727 }
Glen Lee9e6627a2015-12-21 14:18:08 +0900728 vmm_table[i] = cpu_to_le32(vmm_table[i]);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900729
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900730 i++;
731 sum += vmm_sz;
732 PRINT_D(TX_DBG, "sum = %d\n", sum);
Glen Lee50a0b3b2015-10-27 18:28:00 +0900733 tqe = wilc_wlan_txq_get_next(wilc, tqe);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900734 } else {
735 break;
736 }
737 } while (1);
738
Leo Kimac087c82015-11-06 11:12:25 +0900739 if (i == 0) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900740 PRINT_D(TX_DBG, "Nothing in TX-Q\n");
741 break;
742 } else {
743 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 +0900744 vmm_table[i] = 0x0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900745 }
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100746 acquire_bus(wilc, ACQUIRE_AND_WAKEUP);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900747 counter = 0;
748 do {
Glen Leeaf9ae092015-12-21 14:18:09 +0900749 ret = wilc->hif_func->hif_read_reg(wilc, WILC_HOST_TX_CTRL,
Glen Lee49dcd0d2015-11-18 15:11:26 +0900750 &reg);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900751 if (!ret) {
752 wilc_debug(N_ERR, "[wilc txq]: fail can't read reg vmm_tbl_entry..\n");
753 break;
754 }
755
756 if ((reg & 0x1) == 0) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900757 PRINT_D(TX_DBG, "Writing VMM table ... with Size = %d\n", ((i + 1) * 4));
758 break;
759 } else {
760 counter++;
761 if (counter > 200) {
762 counter = 0;
763 PRINT_D(TX_DBG, "Looping in tx ctrl , forcce quit\n");
Glen Leeaf9ae092015-12-21 14:18:09 +0900764 ret = wilc->hif_func->hif_write_reg(wilc, WILC_HOST_TX_CTRL, 0);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900765 break;
766 }
Chandra S Gorentla17aacd42015-08-08 17:41:35 +0530767 PRINT_WRN(GENERIC_DBG, "[wilc txq]: warn, vmm table not clear yet, wait...\n");
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100768 release_bus(wilc, RELEASE_ALLOW_SLEEP);
Greg Kroah-Hartman2b922cb2015-09-04 09:30:51 -0700769 usleep_range(3000, 3000);
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100770 acquire_bus(wilc, ACQUIRE_AND_WAKEUP);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900771 }
Glen Lee67e2a072015-12-21 14:18:12 +0900772 } while (!wilc->quit);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900773
Alison Schofield39823a52015-10-08 21:18:03 -0700774 if (!ret)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900775 goto _end_;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900776
777 timeout = 200;
778 do {
Glen Leeaf9ae092015-12-21 14:18:09 +0900779 ret = wilc->hif_func->hif_block_tx(wilc, WILC_VMM_TBL_RX_SHADOW_BASE, (u8 *)vmm_table, ((i + 1) * 4));
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900780 if (!ret) {
781 wilc_debug(N_ERR, "ERR block TX of VMM table.\n");
782 break;
783 }
784
Glen Leeaf9ae092015-12-21 14:18:09 +0900785 ret = wilc->hif_func->hif_write_reg(wilc, WILC_HOST_VMM_CTL,
Glen Lee49dcd0d2015-11-18 15:11:26 +0900786 0x2);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900787 if (!ret) {
788 wilc_debug(N_ERR, "[wilc txq]: fail can't write reg host_vmm_ctl..\n");
789 break;
790 }
791
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900792 do {
Glen Leeaf9ae092015-12-21 14:18:09 +0900793 ret = wilc->hif_func->hif_read_reg(wilc, WILC_HOST_VMM_CTL, &reg);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900794 if (!ret) {
795 wilc_debug(N_ERR, "[wilc txq]: fail can't read reg host_vmm_ctl..\n");
796 break;
797 }
798 if ((reg >> 2) & 0x1) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900799 entries = ((reg >> 3) & 0x3f);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900800 break;
801 } else {
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100802 release_bus(wilc, RELEASE_ALLOW_SLEEP);
Greg Kroah-Hartman2b922cb2015-09-04 09:30:51 -0700803 usleep_range(3000, 3000);
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100804 acquire_bus(wilc, ACQUIRE_AND_WAKEUP);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900805 PRINT_WRN(GENERIC_DBG, "Can't get VMM entery - reg = %2x\n", reg);
806 }
807 } while (--timeout);
808 if (timeout <= 0) {
Glen Leeaf9ae092015-12-21 14:18:09 +0900809 ret = wilc->hif_func->hif_write_reg(wilc, WILC_HOST_VMM_CTL, 0x0);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900810 break;
811 }
812
Alison Schofield39823a52015-10-08 21:18:03 -0700813 if (!ret)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900814 break;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900815
816 if (entries == 0) {
Chandra S Gorentla17aacd42015-08-08 17:41:35 +0530817 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 +0900818
Glen Leeaf9ae092015-12-21 14:18:09 +0900819 ret = wilc->hif_func->hif_read_reg(wilc, WILC_HOST_TX_CTRL, &reg);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900820 if (!ret) {
821 wilc_debug(N_ERR, "[wilc txq]: fail can't read reg WILC_HOST_TX_CTRL..\n");
822 break;
823 }
Anish Bhattffda2032015-09-29 12:15:49 -0700824 reg &= ~BIT(0);
Glen Leeaf9ae092015-12-21 14:18:09 +0900825 ret = wilc->hif_func->hif_write_reg(wilc, WILC_HOST_TX_CTRL, reg);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900826 if (!ret) {
827 wilc_debug(N_ERR, "[wilc txq]: fail can't write reg WILC_HOST_TX_CTRL..\n");
828 break;
829 }
830 break;
831 } else {
832 break;
833 }
834 } while (1);
835
Alison Schofield39823a52015-10-08 21:18:03 -0700836 if (!ret)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900837 goto _end_;
Alison Schofield39823a52015-10-08 21:18:03 -0700838
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900839 if (entries == 0) {
840 ret = WILC_TX_ERR_NO_BUF;
841 goto _end_;
842 }
843
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100844 release_bus(wilc, RELEASE_ALLOW_SLEEP);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900845
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900846 offset = 0;
847 i = 0;
848 do {
Glen Lee718fc2c2015-10-29 12:18:43 +0900849 tqe = wilc_wlan_txq_remove_from_head(dev);
Leo Kima4b17192015-11-06 11:12:31 +0900850 if (tqe && (vmm_table[i] != 0)) {
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900851 u32 header, buffer_offset;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900852
Glen Lee9e6627a2015-12-21 14:18:08 +0900853 vmm_table[i] = cpu_to_le32(vmm_table[i]);
Leo Kimac087c82015-11-06 11:12:25 +0900854 vmm_sz = (vmm_table[i] & 0x3ff);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900855 vmm_sz *= 4;
Leo Kimab12d8c2015-11-06 11:19:54 +0900856 header = (tqe->type << 31) |
857 (tqe->buffer_size << 15) |
858 vmm_sz;
Chandra S Gorentla78174ad2015-08-08 17:41:36 +0530859 if (tqe->type == WILC_MGMT_PKT)
Anish Bhattffda2032015-09-29 12:15:49 -0700860 header |= BIT(30);
Chandra S Gorentla78174ad2015-08-08 17:41:36 +0530861 else
Anish Bhattffda2032015-09-29 12:15:49 -0700862 header &= ~BIT(30);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900863
Glen Lee9e6627a2015-12-21 14:18:08 +0900864 header = cpu_to_le32(header);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900865 memcpy(&txb[offset], &header, 4);
866 if (tqe->type == WILC_CFG_PKT) {
867 buffer_offset = ETH_CONFIG_PKT_HDR_OFFSET;
Leo Kim590c0a32015-11-06 11:13:02 +0900868 } else if (tqe->type == WILC_NET_PKT) {
Leo Kim2f7c31f2015-11-06 11:13:03 +0900869 char *bssid = ((struct tx_complete_data *)(tqe->priv))->pBssid;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900870
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900871 buffer_offset = ETH_ETHERNET_HDR_OFFSET;
Leo Kim2f7c31f2015-11-06 11:13:03 +0900872 memcpy(&txb[offset + 4], bssid, 6);
Leo Kim590c0a32015-11-06 11:13:02 +0900873 } else {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900874 buffer_offset = HOST_HDR_OFFSET;
875 }
876
Leo Kimab12d8c2015-11-06 11:19:54 +0900877 memcpy(&txb[offset + buffer_offset],
878 tqe->buffer, tqe->buffer_size);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900879 offset += vmm_sz;
880 i++;
Leo Kimac087c82015-11-06 11:12:25 +0900881 tqe->status = 1;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900882 if (tqe->tx_complete_func)
Leo Kimab12d8c2015-11-06 11:19:54 +0900883 tqe->tx_complete_func(tqe->priv,
884 tqe->status);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900885 #ifdef TCP_ACK_FILTER
Glen Leeb7193022015-12-21 14:18:07 +0900886 if (tqe->tcp_pending_ack_idx != NOT_TCP_ACK)
887 pending_acks_info[tqe->tcp_pending_ack_idx].txqe = NULL;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900888 #endif
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -0700889 kfree(tqe);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900890 } else {
891 break;
892 }
893 } while (--entries);
894
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100895 acquire_bus(wilc, ACQUIRE_AND_WAKEUP);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900896
Glen Leeaf9ae092015-12-21 14:18:09 +0900897 ret = wilc->hif_func->hif_clear_int_ext(wilc, ENABLE_TX_VMM);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900898 if (!ret) {
899 wilc_debug(N_ERR, "[wilc txq]: fail can't start tx VMM ...\n");
900 goto _end_;
901 }
902
Glen Leeaf9ae092015-12-21 14:18:09 +0900903 ret = wilc->hif_func->hif_block_tx_ext(wilc, 0, txb, offset);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900904 if (!ret) {
905 wilc_debug(N_ERR, "[wilc txq]: fail can't block tx ext...\n");
906 goto _end_;
907 }
908
909_end_:
910
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100911 release_bus(wilc, RELEASE_ALLOW_SLEEP);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900912 if (ret != 1)
913 break;
914 } while (0);
Glen Leea1332ca2015-10-27 18:27:47 +0900915 up(&wilc->txq_add_to_head_cs);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900916
Glen Lee67e2a072015-12-21 14:18:12 +0900917 wilc->txq_exit = 1;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900918 PRINT_D(TX_DBG, "THREAD: Exiting txq\n");
Glen Lee67e2a072015-12-21 14:18:12 +0900919 *txq_count = wilc->txq_entries;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900920 return ret;
921}
922
Glen Lee39ce4d32015-10-27 18:27:42 +0900923static void wilc_wlan_handle_rxq(struct wilc *wilc)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900924{
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900925 int offset = 0, size, has_packet = 0;
Chaehyun Lim51e825f2015-09-15 14:06:14 +0900926 u8 *buffer;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900927 struct rxq_entry_t *rqe;
928
Glen Lee67e2a072015-12-21 14:18:12 +0900929 wilc->rxq_exit = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900930
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900931 do {
Glen Lee67e2a072015-12-21 14:18:12 +0900932 if (wilc->quit) {
Chandra S Gorentla17aacd42015-08-08 17:41:35 +0530933 PRINT_D(RX_DBG, "exit 1st do-while due to Clean_UP function\n");
Glen Lee39ce4d32015-10-27 18:27:42 +0900934 up(&wilc->cfg_event);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900935 break;
936 }
Glen Leedb387632015-10-27 18:27:55 +0900937 rqe = wilc_wlan_rxq_remove(wilc);
Leo Kima4b17192015-11-06 11:12:31 +0900938 if (!rqe) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900939 PRINT_D(RX_DBG, "nothing in the queue - exit 1st do-while\n");
940 break;
941 }
942 buffer = rqe->buffer;
943 size = rqe->buffer_size;
Leo Kimab12d8c2015-11-06 11:19:54 +0900944 PRINT_D(RX_DBG, "rxQ entery Size = %d - Address = %p\n",
945 size, buffer);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900946 offset = 0;
947
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900948 do {
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900949 u32 header;
950 u32 pkt_len, pkt_offset, tp_len;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900951 int is_cfg_packet;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900952
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900953 PRINT_D(RX_DBG, "In the 2nd do-while\n");
954 memcpy(&header, &buffer[offset], 4);
Glen Lee9e6627a2015-12-21 14:18:08 +0900955 header = cpu_to_le32(header);
Leo Kimab12d8c2015-11-06 11:19:54 +0900956 PRINT_D(RX_DBG, "Header = %04x - Offset = %d\n",
957 header, offset);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900958
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900959 is_cfg_packet = (header >> 31) & 0x1;
960 pkt_offset = (header >> 22) & 0x1ff;
961 tp_len = (header >> 11) & 0x7ff;
962 pkt_len = header & 0x7ff;
963
964 if (pkt_len == 0 || tp_len == 0) {
965 wilc_debug(N_RXQ, "[wilc rxq]: data corrupt, packet len or tp_len is 0 [%d][%d]\n", pkt_len, tp_len);
966 break;
967 }
968
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900969 #define IS_MANAGMEMENT 0x100
970 #define IS_MANAGMEMENT_CALLBACK 0x080
971 #define IS_MGMT_STATUS_SUCCES 0x040
972
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900973 if (pkt_offset & IS_MANAGMEMENT) {
Leo Kimab12d8c2015-11-06 11:19:54 +0900974 pkt_offset &= ~(IS_MANAGMEMENT |
975 IS_MANAGMEMENT_CALLBACK |
976 IS_MGMT_STATUS_SUCCES);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900977
Glen Lee11f4b2e2015-10-27 18:27:51 +0900978 WILC_WFI_mgmt_rx(wilc, &buffer[offset + HOST_HDR_OFFSET], pkt_len);
Leo Kim590c0a32015-11-06 11:13:02 +0900979 } else {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900980 if (!is_cfg_packet) {
Glen Lee63611672015-09-24 18:14:52 +0900981 if (pkt_len > 0) {
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100982 wilc_frmw_to_linux(wilc,
Glen Leecb1991a2015-10-27 18:27:56 +0900983 &buffer[offset],
Glen Lee63611672015-09-24 18:14:52 +0900984 pkt_len,
985 pkt_offset);
986 has_packet = 1;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900987 }
988 } else {
Leo Kimbcddd482015-11-06 11:20:01 +0900989 struct wilc_cfg_rsp rsp;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900990
Glen Leecd04d222015-12-21 14:18:42 +0900991 wilc_wlan_cfg_indicate_rx(wilc, &buffer[pkt_offset + offset], pkt_len, &rsp);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900992 if (rsp.type == WILC_CFG_RSP) {
Glen Lee67e2a072015-12-21 14:18:12 +0900993 PRINT_D(RX_DBG, "wilc->cfg_seq_no = %d - rsp.seq_no = %d\n", wilc->cfg_seq_no, rsp.seq_no);
994 if (wilc->cfg_seq_no == rsp.seq_no)
Glen Lee39ce4d32015-10-27 18:27:42 +0900995 up(&wilc->cfg_event);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900996 } else if (rsp.type == WILC_CFG_RSP_STATUS) {
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100997 wilc_mac_indicate(wilc, WILC_MAC_INDICATE_STATUS);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900998
999 } else if (rsp.type == WILC_CFG_RSP_SCAN) {
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001000 wilc_mac_indicate(wilc, WILC_MAC_INDICATE_SCAN);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001001 }
1002 }
1003 }
1004 offset += tp_len;
1005 if (offset >= size)
1006 break;
1007 } while (1);
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -07001008 kfree(rqe);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001009
Alison Schofield39823a52015-10-08 21:18:03 -07001010 if (has_packet)
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001011 wilc_rx_complete(wilc);
Alison Schofield39823a52015-10-08 21:18:03 -07001012
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001013 } while (1);
1014
Glen Lee67e2a072015-12-21 14:18:12 +09001015 wilc->rxq_exit = 1;
Chandra S Gorentla17aacd42015-08-08 17:41:35 +05301016 PRINT_D(RX_DBG, "THREAD: Exiting RX thread\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001017}
1018
Glen Lee00215dd2015-11-18 15:11:25 +09001019static void wilc_unknown_isr_ext(struct wilc *wilc)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001020{
Glen Leeaf9ae092015-12-21 14:18:09 +09001021 wilc->hif_func->hif_clear_int_ext(wilc, 0);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001022}
Leo Kim2d6973e2015-11-06 11:12:28 +09001023
Glen Lee00215dd2015-11-18 15:11:25 +09001024static void wilc_pllupdate_isr_ext(struct wilc *wilc, u32 int_stats)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001025{
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001026 int trials = 10;
1027
Glen Leeaf9ae092015-12-21 14:18:09 +09001028 wilc->hif_func->hif_clear_int_ext(wilc, PLL_INT_CLR);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001029
Glen Leea3629a92015-12-21 14:18:10 +09001030 if (wilc->io_type == HIF_SDIO)
Arnd Bergmanne28e84d2015-11-16 15:05:07 +01001031 mdelay(WILC_PLL_TO_SDIO);
1032 else
1033 mdelay(WILC_PLL_TO_SPI);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001034
Glen Lee00215dd2015-11-18 15:11:25 +09001035 while (!(ISWILC1000(wilc_get_chipid(wilc, true)) && --trials)) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001036 PRINT_D(TX_DBG, "PLL update retrying\n");
Greg Kroah-Hartmanc2e4c0f2015-09-03 19:09:50 -07001037 mdelay(1);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001038 }
1039}
1040
Glen Lee00215dd2015-11-18 15:11:25 +09001041static void wilc_sleeptimer_isr_ext(struct wilc *wilc, u32 int_stats1)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001042{
Glen Leeaf9ae092015-12-21 14:18:09 +09001043 wilc->hif_func->hif_clear_int_ext(wilc, SLEEP_INT_CLR);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001044#ifndef WILC_OPTIMIZE_SLEEP_INT
Leo Kimb7d1e182015-11-06 11:12:30 +09001045 chip_ps_state = CHIP_SLEEPING_AUTO;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001046#endif
1047}
1048
Glen Lee3bcd45b2015-10-27 18:27:41 +09001049static void wilc_wlan_handle_isr_ext(struct wilc *wilc, u32 int_status)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001050{
Glen Lee67e2a072015-12-21 14:18:12 +09001051 u32 offset = wilc->rx_buffer_offset;
Chaehyun Lim51e825f2015-09-15 14:06:14 +09001052 u8 *buffer = NULL;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001053 u32 size;
1054 u32 retries = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001055 int ret = 0;
1056 struct rxq_entry_t *rqe;
1057
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001058 size = ((int_status & 0x7fff) << 2);
1059
1060 while (!size && retries < 10) {
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001061 u32 time = 0;
Leo Kimac087c82015-11-06 11:12:25 +09001062
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001063 wilc_debug(N_ERR, "RX Size equal zero ... Trying to read it again for %d time\n", time++);
Glen Leeaf9ae092015-12-21 14:18:09 +09001064 wilc->hif_func->hif_read_size(wilc, &size);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001065 size = ((size & 0x7fff) << 2);
1066 retries++;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001067 }
1068
1069 if (size > 0) {
Glen Lee03eb7262015-09-24 18:15:03 +09001070 if (LINUX_RX_SIZE - offset < size)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001071 offset = 0;
1072
Glen Lee67e2a072015-12-21 14:18:12 +09001073 if (wilc->rx_buffer) {
1074 buffer = &wilc->rx_buffer[offset];
Leo Kim7eb17b82015-11-06 11:13:06 +09001075 } else {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001076 wilc_debug(N_ERR, "[wilc isr]: fail Rx Buffer is NULL...drop the packets (%d)\n", size);
1077 goto _end_;
1078 }
1079
Glen Leeaf9ae092015-12-21 14:18:09 +09001080 wilc->hif_func->hif_clear_int_ext(wilc,
Glen Lee49dcd0d2015-11-18 15:11:26 +09001081 DATA_INT_CLR | ENABLE_RX_VMM);
Glen Leeaf9ae092015-12-21 14:18:09 +09001082 ret = wilc->hif_func->hif_block_rx_ext(wilc, 0, buffer, size);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001083
1084 if (!ret) {
1085 wilc_debug(N_ERR, "[wilc isr]: fail block rx...\n");
1086 goto _end_;
1087 }
1088_end_:
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001089 if (ret) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001090 offset += size;
Glen Lee67e2a072015-12-21 14:18:12 +09001091 wilc->rx_buffer_offset = offset;
Leo Kim13b01e42015-11-06 11:13:04 +09001092 rqe = kmalloc(sizeof(*rqe), GFP_KERNEL);
Leo Kima4b17192015-11-06 11:12:31 +09001093 if (rqe) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001094 rqe->buffer = buffer;
1095 rqe->buffer_size = size;
1096 PRINT_D(RX_DBG, "rxq entery Size= %d - Address = %p\n", rqe->buffer_size, rqe->buffer);
Glen Leed06f3622015-10-27 18:27:59 +09001097 wilc_wlan_rxq_add(wilc, rqe);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001098 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001099 }
1100 }
Glen Lee39ce4d32015-10-27 18:27:42 +09001101 wilc_wlan_handle_rxq(wilc);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001102}
1103
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001104void wilc_handle_isr(struct wilc *wilc)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001105{
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001106 u32 int_status;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001107
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001108 acquire_bus(wilc, ACQUIRE_AND_WAKEUP);
Glen Leeaf9ae092015-12-21 14:18:09 +09001109 wilc->hif_func->hif_read_int(wilc, &int_status);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001110
Alison Schofield39823a52015-10-08 21:18:03 -07001111 if (int_status & PLL_INT_EXT)
Glen Lee00215dd2015-11-18 15:11:25 +09001112 wilc_pllupdate_isr_ext(wilc, int_status);
Alison Schofield39823a52015-10-08 21:18:03 -07001113
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001114 if (int_status & DATA_INT_EXT) {
Glen Lee3bcd45b2015-10-27 18:27:41 +09001115 wilc_wlan_handle_isr_ext(wilc, int_status);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001116 #ifndef WILC_OPTIMIZE_SLEEP_INT
Leo Kimb7d1e182015-11-06 11:12:30 +09001117 chip_ps_state = CHIP_WAKEDUP;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001118 #endif
1119 }
Alison Schofield39823a52015-10-08 21:18:03 -07001120 if (int_status & SLEEP_INT_EXT)
Glen Lee00215dd2015-11-18 15:11:25 +09001121 wilc_sleeptimer_isr_ext(wilc, int_status);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001122
1123 if (!(int_status & (ALL_INT_EXT))) {
Glen Lee00215dd2015-11-18 15:11:25 +09001124 wilc_unknown_isr_ext(wilc);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001125 }
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001126 release_bus(wilc, RELEASE_ALLOW_SLEEP);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001127}
Arnd Bergmann750ffe92015-11-16 15:05:08 +01001128EXPORT_SYMBOL_GPL(wilc_handle_isr);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001129
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001130int wilc_wlan_firmware_download(struct wilc *wilc, const u8 *buffer, u32 buffer_size)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001131{
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001132 u32 offset;
1133 u32 addr, size, size2, blksz;
Chaehyun Lim51e825f2015-09-15 14:06:14 +09001134 u8 *dma_buffer;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001135 int ret = 0;
1136
Anish Bhattffda2032015-09-29 12:15:49 -07001137 blksz = BIT(12);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001138
Greg Kroah-Hartmanf019b9d2015-09-03 18:50:27 -07001139 dma_buffer = kmalloc(blksz, GFP_KERNEL);
Leo Kima4b17192015-11-06 11:12:31 +09001140 if (!dma_buffer) {
Leo Kim92e7d182015-11-06 11:19:55 +09001141 ret = -EIO;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001142 PRINT_ER("Can't allocate buffer for firmware download IO error\n ");
1143 goto _fail_1;
1144 }
1145
1146 PRINT_D(INIT_DBG, "Downloading firmware size = %d ...\n", buffer_size);
Leo Kimac087c82015-11-06 11:12:25 +09001147
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001148 offset = 0;
1149 do {
1150 memcpy(&addr, &buffer[offset], 4);
1151 memcpy(&size, &buffer[offset + 4], 4);
Glen Lee9e6627a2015-12-21 14:18:08 +09001152 addr = cpu_to_le32(addr);
1153 size = cpu_to_le32(size);
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001154 acquire_bus(wilc, ACQUIRE_ONLY);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001155 offset += 8;
1156 while (((int)size) && (offset < buffer_size)) {
Chandra S Gorentla78174ad2015-08-08 17:41:36 +05301157 if (size <= blksz)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001158 size2 = size;
Chandra S Gorentla78174ad2015-08-08 17:41:36 +05301159 else
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001160 size2 = blksz;
Leo Kimac087c82015-11-06 11:12:25 +09001161
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001162 memcpy(dma_buffer, &buffer[offset], size2);
Glen Leeaf9ae092015-12-21 14:18:09 +09001163 ret = wilc->hif_func->hif_block_tx(wilc, addr, dma_buffer,
Glen Lee49dcd0d2015-11-18 15:11:26 +09001164 size2);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001165 if (!ret)
1166 break;
1167
1168 addr += size2;
1169 offset += size2;
1170 size -= size2;
1171 }
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001172 release_bus(wilc, RELEASE_ONLY);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001173
1174 if (!ret) {
Leo Kim92e7d182015-11-06 11:19:55 +09001175 ret = -EIO;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001176 PRINT_ER("Can't download firmware IO error\n ");
1177 goto _fail_;
1178 }
1179 PRINT_D(INIT_DBG, "Offset = %d\n", offset);
1180 } while (offset < buffer_size);
1181
1182_fail_:
1183
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -07001184 kfree(dma_buffer);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001185
1186_fail_1:
1187
1188 return (ret < 0) ? ret : 0;
1189}
1190
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001191int wilc_wlan_start(struct wilc *wilc)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001192{
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001193 u32 reg = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001194 int ret;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001195 u32 chipid;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001196
Glen Leea3629a92015-12-21 14:18:10 +09001197 if (wilc->io_type == HIF_SDIO) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001198 reg = 0;
Leo Kimac087c82015-11-06 11:12:25 +09001199 reg |= BIT(3);
Glen Leea3629a92015-12-21 14:18:10 +09001200 } else if (wilc->io_type == HIF_SPI) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001201 reg = 1;
1202 }
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001203 acquire_bus(wilc, ACQUIRE_ONLY);
Glen Leeaf9ae092015-12-21 14:18:09 +09001204 ret = wilc->hif_func->hif_write_reg(wilc, WILC_VMM_CORE_CFG, reg);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001205 if (!ret) {
1206 wilc_debug(N_ERR, "[wilc start]: fail write reg vmm_core_cfg...\n");
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001207 release_bus(wilc, RELEASE_ONLY);
Leo Kim92e7d182015-11-06 11:19:55 +09001208 ret = -EIO;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001209 return ret;
1210 }
1211 reg = 0;
Glen Leea3629a92015-12-21 14:18:10 +09001212 if (wilc->io_type == HIF_SDIO && wilc->dev_irq_num)
Arnd Bergmannc4d139c2015-11-16 15:05:04 +01001213 reg |= WILC_HAVE_SDIO_IRQ_GPIO;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001214
1215#ifdef WILC_DISABLE_PMU
1216#else
1217 reg |= WILC_HAVE_USE_PMU;
1218#endif
1219
1220#ifdef WILC_SLEEP_CLK_SRC_XO
1221 reg |= WILC_HAVE_SLEEP_CLK_SRC_XO;
1222#elif defined WILC_SLEEP_CLK_SRC_RTC
1223 reg |= WILC_HAVE_SLEEP_CLK_SRC_RTC;
1224#endif
1225
1226#ifdef WILC_EXT_PA_INV_TX_RX
1227 reg |= WILC_HAVE_EXT_PA_INV_TX_RX;
1228#endif
1229
1230 reg |= WILC_HAVE_LEGACY_RF_SETTINGS;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001231#ifdef XTAL_24
1232 reg |= WILC_HAVE_XTAL_24;
1233#endif
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001234#ifdef DISABLE_WILC_UART
1235 reg |= WILC_HAVE_DISABLE_WILC_UART;
1236#endif
1237
Glen Leeaf9ae092015-12-21 14:18:09 +09001238 ret = wilc->hif_func->hif_write_reg(wilc, WILC_GP_REG_1, reg);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001239 if (!ret) {
1240 wilc_debug(N_ERR, "[wilc start]: fail write WILC_GP_REG_1 ...\n");
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001241 release_bus(wilc, RELEASE_ONLY);
Leo Kim92e7d182015-11-06 11:19:55 +09001242 ret = -EIO;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001243 return ret;
1244 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001245
Glen Leeaf9ae092015-12-21 14:18:09 +09001246 wilc->hif_func->hif_sync_ext(wilc, NUM_INT_EXT);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001247
Glen Leeaf9ae092015-12-21 14:18:09 +09001248 ret = wilc->hif_func->hif_read_reg(wilc, 0x1000, &chipid);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001249 if (!ret) {
1250 wilc_debug(N_ERR, "[wilc start]: fail read reg 0x1000 ...\n");
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001251 release_bus(wilc, RELEASE_ONLY);
Leo Kim92e7d182015-11-06 11:19:55 +09001252 ret = -EIO;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001253 return ret;
1254 }
1255
Glen Leeaf9ae092015-12-21 14:18:09 +09001256 wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, &reg);
Anish Bhattffda2032015-09-29 12:15:49 -07001257 if ((reg & BIT(10)) == BIT(10)) {
1258 reg &= ~BIT(10);
Glen Leeaf9ae092015-12-21 14:18:09 +09001259 wilc->hif_func->hif_write_reg(wilc, WILC_GLB_RESET_0, reg);
1260 wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, &reg);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001261 }
1262
Anish Bhattffda2032015-09-29 12:15:49 -07001263 reg |= BIT(10);
Glen Leeaf9ae092015-12-21 14:18:09 +09001264 ret = wilc->hif_func->hif_write_reg(wilc, WILC_GLB_RESET_0, reg);
1265 wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, &reg);
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001266 release_bus(wilc, RELEASE_ONLY);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001267
1268 return (ret < 0) ? ret : 0;
1269}
1270
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001271void wilc_wlan_global_reset(struct wilc *wilc)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001272{
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001273 acquire_bus(wilc, ACQUIRE_AND_WAKEUP);
Glen Leeaf9ae092015-12-21 14:18:09 +09001274 wilc->hif_func->hif_write_reg(wilc, WILC_GLB_RESET_0, 0x0);
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001275 release_bus(wilc, RELEASE_ONLY);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001276}
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001277int wilc_wlan_stop(struct wilc *wilc)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001278{
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001279 u32 reg = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001280 int ret;
Chaehyun Lim51e825f2015-09-15 14:06:14 +09001281 u8 timeout = 10;
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001282 acquire_bus(wilc, ACQUIRE_AND_WAKEUP);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001283
Glen Leeaf9ae092015-12-21 14:18:09 +09001284 ret = wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, &reg);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001285 if (!ret) {
1286 PRINT_ER("Error while reading reg\n");
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001287 release_bus(wilc, RELEASE_ALLOW_SLEEP);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001288 return ret;
1289 }
1290
Anish Bhattffda2032015-09-29 12:15:49 -07001291 reg &= ~BIT(10);
Glen Leeaf9ae092015-12-21 14:18:09 +09001292 ret = wilc->hif_func->hif_write_reg(wilc, WILC_GLB_RESET_0, reg);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001293 if (!ret) {
1294 PRINT_ER("Error while writing reg\n");
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001295 release_bus(wilc, RELEASE_ALLOW_SLEEP);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001296 return ret;
1297 }
1298
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001299 do {
Glen Leeaf9ae092015-12-21 14:18:09 +09001300 ret = wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, &reg);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001301 if (!ret) {
1302 PRINT_ER("Error while reading reg\n");
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001303 release_bus(wilc, RELEASE_ALLOW_SLEEP);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001304 return ret;
1305 }
Leo Kimab12d8c2015-11-06 11:19:54 +09001306 PRINT_D(GENERIC_DBG, "Read RESET Reg %x : Retry%d\n",
1307 reg, timeout);
Leo Kimac087c82015-11-06 11:12:25 +09001308
Anish Bhattffda2032015-09-29 12:15:49 -07001309 if ((reg & BIT(10))) {
Leo Kimab12d8c2015-11-06 11:19:54 +09001310 PRINT_D(GENERIC_DBG, "Bit 10 not reset : Retry %d\n",
1311 timeout);
Anish Bhattffda2032015-09-29 12:15:49 -07001312 reg &= ~BIT(10);
Glen Leeaf9ae092015-12-21 14:18:09 +09001313 ret = wilc->hif_func->hif_write_reg(wilc, WILC_GLB_RESET_0,
Glen Lee49dcd0d2015-11-18 15:11:26 +09001314 reg);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001315 timeout--;
1316 } else {
Leo Kimab12d8c2015-11-06 11:19:54 +09001317 PRINT_D(GENERIC_DBG, "Bit 10 reset after : Retry %d\n",
1318 timeout);
Glen Leeaf9ae092015-12-21 14:18:09 +09001319 ret = wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0,
Glen Lee49dcd0d2015-11-18 15:11:26 +09001320 &reg);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001321 if (!ret) {
1322 PRINT_ER("Error while reading reg\n");
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001323 release_bus(wilc, RELEASE_ALLOW_SLEEP);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001324 return ret;
1325 }
Leo Kimab12d8c2015-11-06 11:19:54 +09001326 PRINT_D(GENERIC_DBG, "Read RESET Reg %x : Retry%d\n",
1327 reg, timeout);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001328 break;
1329 }
1330
1331 } while (timeout);
Anish Bhattffda2032015-09-29 12:15:49 -07001332 reg = (BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(8) | BIT(9) | BIT(26) |
1333 BIT(29) | BIT(30) | BIT(31));
Anish Bhatt65ead4e2015-09-29 12:15:48 -07001334
Glen Leeaf9ae092015-12-21 14:18:09 +09001335 wilc->hif_func->hif_write_reg(wilc, WILC_GLB_RESET_0, reg);
Anish Bhattffda2032015-09-29 12:15:49 -07001336 reg = (u32)~BIT(10);
Anish Bhatt65ead4e2015-09-29 12:15:48 -07001337
Glen Leeaf9ae092015-12-21 14:18:09 +09001338 ret = wilc->hif_func->hif_write_reg(wilc, WILC_GLB_RESET_0, reg);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001339
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001340 release_bus(wilc, RELEASE_ALLOW_SLEEP);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001341
1342 return ret;
1343}
1344
Glen Lee2de7cbe2015-10-27 18:27:54 +09001345void wilc_wlan_cleanup(struct net_device *dev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001346{
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001347 struct txq_entry_t *tqe;
1348 struct rxq_entry_t *rqe;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001349 u32 reg = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001350 int ret;
Glen Leea4cac482015-12-21 14:18:36 +09001351 struct wilc_vif *vif;
Glen Leedb387632015-10-27 18:27:55 +09001352 struct wilc *wilc;
1353
Glen Leea4cac482015-12-21 14:18:36 +09001354 vif = netdev_priv(dev);
1355 wilc = vif->wilc;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001356
Glen Lee67e2a072015-12-21 14:18:12 +09001357 wilc->quit = 1;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001358 do {
Glen Lee718fc2c2015-10-29 12:18:43 +09001359 tqe = wilc_wlan_txq_remove_from_head(dev);
Leo Kima4b17192015-11-06 11:12:31 +09001360 if (!tqe)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001361 break;
1362 if (tqe->tx_complete_func)
1363 tqe->tx_complete_func(tqe->priv, 0);
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -07001364 kfree(tqe);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001365 } while (1);
1366
1367 do {
Glen Leedb387632015-10-27 18:27:55 +09001368 rqe = wilc_wlan_rxq_remove(wilc);
Leo Kima4b17192015-11-06 11:12:31 +09001369 if (!rqe)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001370 break;
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -07001371 kfree(rqe);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001372 } while (1);
1373
Glen Lee67e2a072015-12-21 14:18:12 +09001374 kfree(wilc->rx_buffer);
1375 wilc->rx_buffer = NULL;
1376 kfree(wilc->tx_buffer);
Glen Lee608b0512015-12-21 14:18:50 +09001377 wilc->tx_buffer = NULL;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001378
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001379 acquire_bus(wilc, ACQUIRE_AND_WAKEUP);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001380
Glen Leeaf9ae092015-12-21 14:18:09 +09001381 ret = wilc->hif_func->hif_read_reg(wilc, WILC_GP_REG_0, &reg);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001382 if (!ret) {
1383 PRINT_ER("Error while reading reg\n");
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001384 release_bus(wilc, RELEASE_ALLOW_SLEEP);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001385 }
1386 PRINT_ER("Writing ABORT reg\n");
Glen Leeaf9ae092015-12-21 14:18:09 +09001387 ret = wilc->hif_func->hif_write_reg(wilc, WILC_GP_REG_0,
Glen Lee49dcd0d2015-11-18 15:11:26 +09001388 (reg | ABORT_INT));
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001389 if (!ret) {
1390 PRINT_ER("Error while writing reg\n");
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001391 release_bus(wilc, RELEASE_ALLOW_SLEEP);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001392 }
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001393 release_bus(wilc, RELEASE_ALLOW_SLEEP);
Glen Leeaf9ae092015-12-21 14:18:09 +09001394 wilc->hif_func->hif_deinit(NULL);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001395}
1396
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001397static int wilc_wlan_cfg_commit(struct wilc *wilc, int type, u32 drv_handler)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001398{
Glen Lee67e2a072015-12-21 14:18:12 +09001399 struct wilc_cfg_frame *cfg = &wilc->cfg_frame;
1400 int total_len = wilc->cfg_frame_offset + 4 + DRIVER_HANDLER_SIZE;
1401 int seq_no = wilc->cfg_seq_no % 256;
Leo Kim48641672015-11-06 11:13:08 +09001402 int driver_handler = (u32)drv_handler;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001403
Leo Kim076ef652015-11-06 11:13:07 +09001404 if (type == WILC_CFG_SET)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001405 cfg->wid_header[0] = 'W';
Leo Kim076ef652015-11-06 11:13:07 +09001406 else
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001407 cfg->wid_header[0] = 'Q';
Leo Kimac087c82015-11-06 11:12:25 +09001408 cfg->wid_header[1] = seq_no;
Chaehyun Lim51e825f2015-09-15 14:06:14 +09001409 cfg->wid_header[2] = (u8)total_len;
1410 cfg->wid_header[3] = (u8)(total_len >> 8);
1411 cfg->wid_header[4] = (u8)driver_handler;
1412 cfg->wid_header[5] = (u8)(driver_handler >> 8);
1413 cfg->wid_header[6] = (u8)(driver_handler >> 16);
1414 cfg->wid_header[7] = (u8)(driver_handler >> 24);
Glen Lee67e2a072015-12-21 14:18:12 +09001415 wilc->cfg_seq_no = seq_no;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001416
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001417 if (!wilc_wlan_txq_add_cfg_pkt(wilc, &cfg->wid_header[0], total_len))
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001418 return -1;
1419
1420 return 0;
1421}
1422
Glen Lee89758e12015-11-18 15:11:34 +09001423int wilc_wlan_cfg_set(struct wilc *wilc, int start, u32 wid, u8 *buffer,
1424 u32 buffer_size, int commit, u32 drv_handler)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001425{
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001426 u32 offset;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001427 int ret_size;
1428
Glen Lee67e2a072015-12-21 14:18:12 +09001429 if (wilc->cfg_frame_in_use)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001430 return 0;
1431
1432 if (start)
Glen Lee67e2a072015-12-21 14:18:12 +09001433 wilc->cfg_frame_offset = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001434
Glen Lee67e2a072015-12-21 14:18:12 +09001435 offset = wilc->cfg_frame_offset;
1436 ret_size = wilc_wlan_cfg_set_wid(wilc->cfg_frame.frame, offset,
1437 (u16)wid, buffer, buffer_size);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001438 offset += ret_size;
Glen Lee67e2a072015-12-21 14:18:12 +09001439 wilc->cfg_frame_offset = offset;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001440
1441 if (commit) {
Leo Kimab12d8c2015-11-06 11:19:54 +09001442 PRINT_D(TX_DBG, "[WILC]PACKET Commit with sequence number %d\n",
Glen Lee67e2a072015-12-21 14:18:12 +09001443 wilc->cfg_seq_no);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001444 PRINT_D(RX_DBG, "Processing cfg_set()\n");
Glen Lee67e2a072015-12-21 14:18:12 +09001445 wilc->cfg_frame_in_use = 1;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001446
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001447 if (wilc_wlan_cfg_commit(wilc, WILC_CFG_SET, drv_handler))
Chaehyun Lim5af6b852015-09-17 16:48:48 +09001448 ret_size = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001449
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001450 if (wilc_lock_timeout(wilc, &wilc->cfg_event,
Glen Leeb002e202015-09-24 18:15:05 +09001451 CFG_PKTS_TIMEOUT)) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001452 PRINT_D(TX_DBG, "Set Timed Out\n");
1453 ret_size = 0;
1454 }
Glen Lee67e2a072015-12-21 14:18:12 +09001455 wilc->cfg_frame_in_use = 0;
1456 wilc->cfg_frame_offset = 0;
1457 wilc->cfg_seq_no += 1;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001458 }
1459
1460 return ret_size;
1461}
Leo Kim2d6973e2015-11-06 11:12:28 +09001462
Glen Leed40c99c2015-11-18 15:11:35 +09001463int wilc_wlan_cfg_get(struct wilc *wilc, int start, u32 wid, int commit,
1464 u32 drv_handler)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001465{
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001466 u32 offset;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001467 int ret_size;
1468
Glen Lee67e2a072015-12-21 14:18:12 +09001469 if (wilc->cfg_frame_in_use)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001470 return 0;
1471
1472 if (start)
Glen Lee67e2a072015-12-21 14:18:12 +09001473 wilc->cfg_frame_offset = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001474
Glen Lee67e2a072015-12-21 14:18:12 +09001475 offset = wilc->cfg_frame_offset;
1476 ret_size = wilc_wlan_cfg_get_wid(wilc->cfg_frame.frame, offset,
1477 (u16)wid);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001478 offset += ret_size;
Glen Lee67e2a072015-12-21 14:18:12 +09001479 wilc->cfg_frame_offset = offset;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001480
1481 if (commit) {
Glen Lee67e2a072015-12-21 14:18:12 +09001482 wilc->cfg_frame_in_use = 1;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001483
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001484 if (wilc_wlan_cfg_commit(wilc, WILC_CFG_QUERY, drv_handler))
Chaehyun Lim5af6b852015-09-17 16:48:48 +09001485 ret_size = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001486
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001487 if (wilc_lock_timeout(wilc, &wilc->cfg_event,
Glen Leeb002e202015-09-24 18:15:05 +09001488 CFG_PKTS_TIMEOUT)) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001489 PRINT_D(TX_DBG, "Get Timed Out\n");
1490 ret_size = 0;
1491 }
1492 PRINT_D(GENERIC_DBG, "[WILC]Get Response received\n");
Glen Lee67e2a072015-12-21 14:18:12 +09001493 wilc->cfg_frame_in_use = 0;
1494 wilc->cfg_frame_offset = 0;
1495 wilc->cfg_seq_no += 1;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001496 }
1497
1498 return ret_size;
1499}
1500
Glen Lee894de36b2015-10-01 16:03:42 +09001501int wilc_wlan_cfg_get_val(u32 wid, u8 *buffer, u32 buffer_size)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001502{
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001503 int ret;
1504
Glen Lee355cca22015-10-02 14:22:09 +09001505 ret = wilc_wlan_cfg_get_wid_value((u16)wid, buffer, buffer_size);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001506
1507 return ret;
1508}
1509
Arnd Bergmann1608c402015-11-16 15:04:53 +01001510static u32 init_chip(struct net_device *dev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001511{
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001512 u32 chipid;
1513 u32 reg, ret = 0;
Glen Leea4cac482015-12-21 14:18:36 +09001514 struct wilc_vif *vif;
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001515 struct wilc *wilc;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001516
Glen Leea4cac482015-12-21 14:18:36 +09001517 vif = netdev_priv(dev);
1518 wilc = vif->wilc;
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001519
1520 acquire_bus(wilc, ACQUIRE_ONLY);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001521
Glen Lee00215dd2015-11-18 15:11:25 +09001522 chipid = wilc_get_chipid(wilc, true);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001523
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001524 if ((chipid & 0xfff) != 0xa0) {
Glen Leeaf9ae092015-12-21 14:18:09 +09001525 ret = wilc->hif_func->hif_read_reg(wilc, 0x1118, &reg);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001526 if (!ret) {
1527 wilc_debug(N_ERR, "[wilc start]: fail read reg 0x1118 ...\n");
1528 return ret;
1529 }
Anish Bhattffda2032015-09-29 12:15:49 -07001530 reg |= BIT(0);
Glen Leeaf9ae092015-12-21 14:18:09 +09001531 ret = wilc->hif_func->hif_write_reg(wilc, 0x1118, reg);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001532 if (!ret) {
1533 wilc_debug(N_ERR, "[wilc start]: fail write reg 0x1118 ...\n");
1534 return ret;
1535 }
Glen Leeaf9ae092015-12-21 14:18:09 +09001536 ret = wilc->hif_func->hif_write_reg(wilc, 0xc0000, 0x71);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001537 if (!ret) {
1538 wilc_debug(N_ERR, "[wilc start]: fail write reg 0xc0000 ...\n");
1539 return ret;
1540 }
1541 }
1542
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001543 release_bus(wilc, RELEASE_ONLY);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001544
1545 return ret;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001546}
1547
Glen Lee00215dd2015-11-18 15:11:25 +09001548u32 wilc_get_chipid(struct wilc *wilc, u8 update)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001549{
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001550 static u32 chipid;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001551 u32 tempchipid = 0;
1552 u32 rfrevid;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001553
1554 if (chipid == 0 || update != 0) {
Glen Leeaf9ae092015-12-21 14:18:09 +09001555 wilc->hif_func->hif_read_reg(wilc, 0x1000, &tempchipid);
1556 wilc->hif_func->hif_read_reg(wilc, 0x13f4, &rfrevid);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001557 if (!ISWILC1000(tempchipid)) {
1558 chipid = 0;
1559 goto _fail_;
1560 }
1561 if (tempchipid == 0x1002a0) {
Leo Kimac087c82015-11-06 11:12:25 +09001562 if (rfrevid == 0x1) {
1563 } else {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001564 tempchipid = 0x1002a1;
1565 }
1566 } else if (tempchipid == 0x1002b0) {
Leo Kimac087c82015-11-06 11:12:25 +09001567 if (rfrevid == 3) {
1568 } else if (rfrevid == 4) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001569 tempchipid = 0x1002b1;
Leo Kimac087c82015-11-06 11:12:25 +09001570 } else {
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001571 tempchipid = 0x1002b2;
1572 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001573 }
1574
1575 chipid = tempchipid;
1576 }
1577_fail_:
1578 return chipid;
1579}
1580
Arnd Bergmann4bd7baf2015-11-16 15:04:59 +01001581int wilc_wlan_init(struct net_device *dev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001582{
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001583 int ret = 0;
Glen Leea4cac482015-12-21 14:18:36 +09001584 struct wilc_vif *vif = netdev_priv(dev);
Glen Lee9c800322015-11-06 18:40:22 +09001585 struct wilc *wilc;
1586
Glen Leea4cac482015-12-21 14:18:36 +09001587 wilc = vif->wilc;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001588
1589 PRINT_D(INIT_DBG, "Initializing WILC_Wlan ...\n");
1590
Glen Lee28b01ff2015-12-21 14:18:14 +09001591 if (!wilc->hif_func->hif_init(wilc)) {
Glen Leecdb99232015-11-06 18:39:58 +09001592 ret = -EIO;
1593 goto _fail_;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001594 }
1595
Glen Lee814bc362015-10-02 14:22:11 +09001596 if (!wilc_wlan_cfg_init(wilc_debug)) {
Leo Kim92e7d182015-11-06 11:19:55 +09001597 ret = -ENOBUFS;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001598 goto _fail_;
1599 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001600
Glen Lee67e2a072015-12-21 14:18:12 +09001601 if (!wilc->tx_buffer)
1602 wilc->tx_buffer = kmalloc(LINUX_TX_SIZE, GFP_KERNEL);
1603 PRINT_D(TX_DBG, "wilc->tx_buffer = %p\n", wilc->tx_buffer);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001604
Glen Lee67e2a072015-12-21 14:18:12 +09001605 if (!wilc->tx_buffer) {
Leo Kim92e7d182015-11-06 11:19:55 +09001606 ret = -ENOBUFS;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001607 PRINT_ER("Can't allocate Tx Buffer");
1608 goto _fail_;
1609 }
1610
Glen Lee67e2a072015-12-21 14:18:12 +09001611 if (!wilc->rx_buffer)
1612 wilc->rx_buffer = kmalloc(LINUX_RX_SIZE, GFP_KERNEL);
1613 PRINT_D(TX_DBG, "wilc->rx_buffer =%p\n", wilc->rx_buffer);
1614 if (!wilc->rx_buffer) {
Leo Kim92e7d182015-11-06 11:19:55 +09001615 ret = -ENOBUFS;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001616 PRINT_ER("Can't allocate Rx Buffer");
1617 goto _fail_;
1618 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001619
Glen Leeae6f7722015-10-29 12:18:48 +09001620 if (!init_chip(dev)) {
Leo Kim92e7d182015-11-06 11:19:55 +09001621 ret = -EIO;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001622 goto _fail_;
1623 }
1624#ifdef TCP_ACK_FILTER
Leo Kimef06b5f2015-11-06 11:12:44 +09001625 init_tcp_tracking();
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001626#endif
1627
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001628 return 1;
1629
1630_fail_:
1631
Glen Lee67e2a072015-12-21 14:18:12 +09001632 kfree(wilc->rx_buffer);
1633 wilc->rx_buffer = NULL;
1634 kfree(wilc->tx_buffer);
1635 wilc->tx_buffer = NULL;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001636
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001637 return ret;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001638}
1639
Arnd Bergmann0e1af732015-11-16 15:04:54 +01001640u16 wilc_set_machw_change_vir_if(struct net_device *dev, bool value)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001641{
Chaehyun Limd85f5322015-06-11 14:35:54 +09001642 u16 ret;
Chaehyun Lim4e4467f2015-06-11 14:35:55 +09001643 u32 reg;
Glen Leea4cac482015-12-21 14:18:36 +09001644 struct wilc_vif *vif;
Glen Lee178c3832015-10-27 18:27:58 +09001645 struct wilc *wilc;
1646
Glen Leea4cac482015-12-21 14:18:36 +09001647 vif = netdev_priv(dev);
1648 wilc = vif->wilc;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001649
Glen Lee178c3832015-10-27 18:27:58 +09001650 mutex_lock(&wilc->hif_cs);
Glen Leeaf9ae092015-12-21 14:18:09 +09001651 ret = wilc->hif_func->hif_read_reg(wilc, WILC_CHANGING_VIR_IF,
Glen Lee49dcd0d2015-11-18 15:11:26 +09001652 &reg);
Alison Schofield39823a52015-10-08 21:18:03 -07001653 if (!ret)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001654 PRINT_ER("Error while Reading reg WILC_CHANGING_VIR_IF\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001655
Leo Kimaa313be2015-11-06 11:13:05 +09001656 if (value)
Chaehyun Lim50b51da2015-09-16 20:11:26 +09001657 reg |= BIT(31);
Chandra S Gorentla78174ad2015-08-08 17:41:36 +05301658 else
Chaehyun Lim50b51da2015-09-16 20:11:26 +09001659 reg &= ~BIT(31);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001660
Glen Leeaf9ae092015-12-21 14:18:09 +09001661 ret = wilc->hif_func->hif_write_reg(wilc, WILC_CHANGING_VIR_IF,
Glen Lee49dcd0d2015-11-18 15:11:26 +09001662 reg);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001663
Alison Schofield39823a52015-10-08 21:18:03 -07001664 if (!ret)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001665 PRINT_ER("Error while writing reg WILC_CHANGING_VIR_IF\n");
Alison Schofield39823a52015-10-08 21:18:03 -07001666
Glen Lee178c3832015-10-27 18:27:58 +09001667 mutex_unlock(&wilc->hif_cs);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001668
1669 return ret;
1670}