Commit | Line | Data |
---|---|---|
c5c77ba1 | 1 | #include "wilc_wlan_if.h" |
491880eb | 2 | #include "wilc_wlan.h" |
60bd1003 | 3 | #include "wilc_wfi_netdevice.h" |
17e8f165 | 4 | #include "wilc_wlan_cfg.h" |
c5c77ba1 | 5 | |
1608c403 | 6 | #ifdef WILC_OPTIMIZE_SLEEP_INT |
00215dde | 7 | static inline void chip_allow_sleep(struct wilc *wilc); |
1608c403 | 8 | #endif |
00215dde | 9 | static inline void chip_wakeup(struct wilc *wilc); |
fbc2fe16 | 10 | static u32 dbgflag = N_INIT | N_ERR | N_INTR | N_TXQ | N_RXQ; |
c5c77ba1 | 11 | |
562ed3f1 | 12 | /* FIXME: replace with dev_debug() */ |
fbc2fe16 | 13 | static void wilc_debug(u32 flag, char *fmt, ...) |
c5c77ba1 JK |
14 | { |
15 | char buf[256]; | |
16 | va_list args; | |
c5c77ba1 JK |
17 | |
18 | if (flag & dbgflag) { | |
19 | va_start(args, fmt); | |
81053222 | 20 | vsprintf(buf, fmt, args); |
c5c77ba1 JK |
21 | va_end(args); |
22 | ||
d36ec22d | 23 | wilc_dbg(buf); |
c5c77ba1 | 24 | } |
c5c77ba1 JK |
25 | } |
26 | ||
b7d1e18c | 27 | static CHIP_PS_STATE_T chip_ps_state = CHIP_WAKEDUP; |
c5c77ba1 | 28 | |
562ed3f1 | 29 | static inline void acquire_bus(struct wilc *wilc, BUS_ACQUIRE_T acquire) |
c5c77ba1 | 30 | { |
562ed3f1 | 31 | mutex_lock(&wilc->hif_cs); |
c5c77ba1 | 32 | #ifndef WILC_OPTIMIZE_SLEEP_INT |
b7d1e18c | 33 | if (chip_ps_state != CHIP_WAKEDUP) |
c5c77ba1 JK |
34 | #endif |
35 | { | |
36 | if (acquire == ACQUIRE_AND_WAKEUP) | |
00215dde | 37 | chip_wakeup(wilc); |
c5c77ba1 | 38 | } |
c5c77ba1 | 39 | } |
2d6973e6 | 40 | |
562ed3f1 | 41 | static inline void release_bus(struct wilc *wilc, BUS_RELEASE_T release) |
c5c77ba1 JK |
42 | { |
43 | #ifdef WILC_OPTIMIZE_SLEEP_INT | |
44 | if (release == RELEASE_ALLOW_SLEEP) | |
00215dde | 45 | chip_allow_sleep(wilc); |
c5c77ba1 | 46 | #endif |
562ed3f1 | 47 | mutex_unlock(&wilc->hif_cs); |
c5c77ba1 | 48 | } |
c5c77ba1 | 49 | |
1608c403 | 50 | #ifdef TCP_ACK_FILTER |
c5c77ba1 JK |
51 | static void wilc_wlan_txq_remove(struct txq_entry_t *tqe) |
52 | { | |
67e2a07e GL |
53 | |
54 | 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; | |
c5c77ba1 JK |
62 | } else { |
63 | tqe->prev->next = tqe->next; | |
64 | tqe->next->prev = tqe->prev; | |
65 | } | |
67e2a07e | 66 | wilc->txq_entries -= 1; |
c5c77ba1 | 67 | } |
1608c403 | 68 | #endif |
c5c77ba1 | 69 | |
718fc2c9 GL |
70 | static struct txq_entry_t * |
71 | wilc_wlan_txq_remove_from_head(struct net_device *dev) | |
c5c77ba1 JK |
72 | { |
73 | struct txq_entry_t *tqe; | |
c5c77ba1 | 74 | unsigned long flags; |
a4cac481 | 75 | struct wilc_vif *vif; |
718fc2c9 | 76 | struct wilc *wilc; |
8dfaafd6 | 77 | |
a4cac481 GL |
78 | vif = netdev_priv(dev); |
79 | wilc = vif->wilc; | |
718fc2c9 GL |
80 | |
81 | spin_lock_irqsave(&wilc->txq_spinlock, flags); | |
67e2a07e GL |
82 | 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; | |
39823a50 | 87 | |
67e2a07e | 88 | wilc->txq_entries -= 1; |
c5c77ba1 JK |
89 | } else { |
90 | tqe = NULL; | |
91 | } | |
718fc2c9 | 92 | spin_unlock_irqrestore(&wilc->txq_spinlock, flags); |
c5c77ba1 JK |
93 | return tqe; |
94 | } | |
95 | ||
32f03328 GL |
96 | static void wilc_wlan_txq_add_to_tail(struct net_device *dev, |
97 | struct txq_entry_t *tqe) | |
c5c77ba1 | 98 | { |
c5c77ba1 | 99 | unsigned long flags; |
a4cac481 | 100 | struct wilc_vif *vif; |
32f03328 GL |
101 | struct wilc *wilc; |
102 | ||
a4cac481 GL |
103 | vif = netdev_priv(dev); |
104 | wilc = vif->wilc; | |
32f03328 GL |
105 | |
106 | spin_lock_irqsave(&wilc->txq_spinlock, flags); | |
c5c77ba1 | 107 | |
67e2a07e | 108 | if (!wilc->txq_head) { |
c5c77ba1 JK |
109 | tqe->next = NULL; |
110 | tqe->prev = NULL; | |
67e2a07e GL |
111 | wilc->txq_head = tqe; |
112 | wilc->txq_tail = tqe; | |
c5c77ba1 JK |
113 | } else { |
114 | tqe->next = NULL; | |
67e2a07e GL |
115 | tqe->prev = wilc->txq_tail; |
116 | wilc->txq_tail->next = tqe; | |
117 | wilc->txq_tail = tqe; | |
c5c77ba1 | 118 | } |
67e2a07e GL |
119 | wilc->txq_entries += 1; |
120 | PRINT_D(TX_DBG, "Number of entries in TxQ = %d\n", wilc->txq_entries); | |
c5c77ba1 | 121 | |
32f03328 | 122 | spin_unlock_irqrestore(&wilc->txq_spinlock, flags); |
c5c77ba1 | 123 | |
c5c77ba1 JK |
124 | PRINT_D(TX_DBG, "Wake the txq_handling\n"); |
125 | ||
32f03328 | 126 | up(&wilc->txq_event); |
c5c77ba1 JK |
127 | } |
128 | ||
562ed3f1 | 129 | static int wilc_wlan_txq_add_to_head(struct wilc *wilc, struct txq_entry_t *tqe) |
c5c77ba1 | 130 | { |
c5c77ba1 | 131 | unsigned long flags; |
562ed3f1 | 132 | if (wilc_lock_timeout(wilc, &wilc->txq_add_to_head_cs, |
b002e20d | 133 | CFG_PKTS_TIMEOUT)) |
c5c77ba1 JK |
134 | return -1; |
135 | ||
562ed3f1 | 136 | spin_lock_irqsave(&wilc->txq_spinlock, flags); |
c5c77ba1 | 137 | |
67e2a07e | 138 | if (!wilc->txq_head) { |
c5c77ba1 JK |
139 | tqe->next = NULL; |
140 | tqe->prev = NULL; | |
67e2a07e GL |
141 | wilc->txq_head = tqe; |
142 | wilc->txq_tail = tqe; | |
c5c77ba1 | 143 | } else { |
67e2a07e | 144 | tqe->next = wilc->txq_head; |
c5c77ba1 | 145 | tqe->prev = NULL; |
67e2a07e GL |
146 | wilc->txq_head->prev = tqe; |
147 | wilc->txq_head = tqe; | |
c5c77ba1 | 148 | } |
67e2a07e GL |
149 | wilc->txq_entries += 1; |
150 | PRINT_D(TX_DBG, "Number of entries in TxQ = %d\n", wilc->txq_entries); | |
c5c77ba1 | 151 | |
562ed3f1 AB |
152 | spin_unlock_irqrestore(&wilc->txq_spinlock, flags); |
153 | up(&wilc->txq_add_to_head_cs); | |
154 | up(&wilc->txq_event); | |
c5c77ba1 | 155 | PRINT_D(TX_DBG, "Wake up the txq_handler\n"); |
c5c77ba1 | 156 | |
c5c77ba1 | 157 | return 0; |
c5c77ba1 JK |
158 | } |
159 | ||
c5c77ba1 | 160 | #ifdef TCP_ACK_FILTER |
130a41f0 LK |
161 | struct ack_session_info; |
162 | struct ack_session_info { | |
d06b6cb2 | 163 | u32 seq_num; |
9d54d3d5 | 164 | u32 bigger_ack_num; |
ec53adfe CL |
165 | u16 src_port; |
166 | u16 dst_port; | |
167 | u16 status; | |
eeb1c062 | 168 | }; |
c5c77ba1 | 169 | |
08b90b10 | 170 | struct pending_acks_info { |
fbc2fe16 | 171 | u32 ack_num; |
84136978 | 172 | u32 session_index; |
c5c77ba1 | 173 | struct txq_entry_t *txqe; |
08b90b10 | 174 | }; |
c5c77ba1 | 175 | |
1608c403 | 176 | |
c5c77ba1 JK |
177 | #define NOT_TCP_ACK (-1) |
178 | ||
179 | #define MAX_TCP_SESSION 25 | |
180 | #define MAX_PENDING_ACKS 256 | |
1608c403 AB |
181 | static struct ack_session_info ack_session_info[2 * MAX_TCP_SESSION]; |
182 | static struct pending_acks_info pending_acks_info[MAX_PENDING_ACKS]; | |
c5c77ba1 | 183 | |
1608c403 AB |
184 | static u32 pending_base; |
185 | static u32 tcp_session; | |
186 | static u32 pending_acks; | |
c5c77ba1 | 187 | |
ef06b5f7 | 188 | static inline int init_tcp_tracking(void) |
c5c77ba1 | 189 | { |
c5c77ba1 | 190 | return 0; |
c5c77ba1 | 191 | } |
2d6973e6 | 192 | |
67620788 | 193 | static inline int add_tcp_session(u32 src_prt, u32 dst_prt, u32 seq) |
c5c77ba1 | 194 | { |
3056ec39 LK |
195 | 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++; | |
c5c77ba1 | 200 | |
3056ec39 | 201 | PRINT_D(TCP_ENH, "TCP Session %d to Ack %d\n", tcp_session, seq); |
c5c77ba1 JK |
202 | return 0; |
203 | } | |
204 | ||
b801a96c | 205 | static inline int update_tcp_session(u32 index, u32 ack) |
c5c77ba1 | 206 | { |
b801a96c LK |
207 | if (ack > ack_session_info[index].bigger_ack_num) |
208 | ack_session_info[index].bigger_ack_num = ack; | |
c5c77ba1 | 209 | return 0; |
c5c77ba1 | 210 | } |
2d6973e6 | 211 | |
ea03f57b | 212 | static inline int add_tcp_pending_ack(u32 ack, u32 session_index, |
66a43a91 | 213 | struct txq_entry_t *txqe) |
c5c77ba1 | 214 | { |
d12ac7e2 | 215 | if (pending_acks < MAX_PENDING_ACKS) { |
b801a96c | 216 | pending_acks_info[pending_base + pending_acks].ack_num = ack; |
d12ac7e2 | 217 | pending_acks_info[pending_base + pending_acks].txqe = txqe; |
ea03f57b | 218 | pending_acks_info[pending_base + pending_acks].session_index = session_index; |
b719302d | 219 | txqe->tcp_pending_ack_idx = pending_base + pending_acks; |
d12ac7e2 | 220 | pending_acks++; |
c5c77ba1 JK |
221 | } |
222 | return 0; | |
223 | } | |
562ed3f1 | 224 | static inline int remove_TCP_related(struct wilc *wilc) |
c5c77ba1 | 225 | { |
c5c77ba1 | 226 | unsigned long flags; |
8dfaafd6 | 227 | |
562ed3f1 | 228 | spin_lock_irqsave(&wilc->txq_spinlock, flags); |
c5c77ba1 | 229 | |
562ed3f1 | 230 | spin_unlock_irqrestore(&wilc->txq_spinlock, flags); |
c5c77ba1 JK |
231 | return 0; |
232 | } | |
233 | ||
82bb18e1 | 234 | static inline int tcp_process(struct net_device *dev, struct txq_entry_t *tqe) |
c5c77ba1 JK |
235 | { |
236 | int ret; | |
51e825f7 CL |
237 | u8 *eth_hdr_ptr; |
238 | u8 *buffer = tqe->buffer; | |
c5c77ba1 JK |
239 | unsigned short h_proto; |
240 | int i; | |
c5c77ba1 | 241 | unsigned long flags; |
a4cac481 | 242 | struct wilc_vif *vif; |
82bb18e1 | 243 | struct wilc *wilc; |
8dfaafd6 | 244 | |
a4cac481 GL |
245 | vif = netdev_priv(dev); |
246 | wilc = vif->wilc; | |
82bb18e1 | 247 | |
c5c77ba1 JK |
248 | |
249 | eth_hdr_ptr = &buffer[0]; | |
250 | h_proto = ntohs(*((unsigned short *)ð_hdr_ptr[12])); | |
a045618e | 251 | if (h_proto == ETH_P_IP) { |
51e825f7 CL |
252 | u8 *ip_hdr_ptr; |
253 | u8 protocol; | |
c5c77ba1 JK |
254 | |
255 | ip_hdr_ptr = &buffer[ETHERNET_HDR_LEN]; | |
256 | protocol = ip_hdr_ptr[9]; | |
257 | ||
c5c77ba1 | 258 | if (protocol == 0x06) { |
51e825f7 | 259 | u8 *tcp_hdr_ptr; |
51bffa96 | 260 | u32 IHL, total_length, data_offset; |
8dfaafd6 | 261 | |
c5c77ba1 JK |
262 | tcp_hdr_ptr = &ip_hdr_ptr[IP_HDR_LEN]; |
263 | IHL = (ip_hdr_ptr[0] & 0xf) << 2; | |
24e2dac2 LK |
264 | total_length = ((u32)ip_hdr_ptr[2] << 8) + |
265 | (u32)ip_hdr_ptr[3]; | |
51bffa96 LK |
266 | data_offset = ((u32)tcp_hdr_ptr[12] & 0xf0) >> 2; |
267 | if (total_length == (IHL + data_offset)) { | |
f91c5d77 | 268 | u32 seq_no, ack_no; |
8dfaafd6 | 269 | |
4478c62a LK |
270 | 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]; | |
c5c77ba1 | 274 | |
f91c5d77 LK |
275 | 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]; | |
c5c77ba1 | 279 | |
3056ec39 | 280 | for (i = 0; i < tcp_session; i++) { |
32065054 | 281 | if (ack_session_info[i].seq_num == seq_no) { |
f91c5d77 | 282 | update_tcp_session(i, ack_no); |
c5c77ba1 JK |
283 | break; |
284 | } | |
285 | } | |
3056ec39 | 286 | if (i == tcp_session) |
67620788 | 287 | add_tcp_session(0, 0, seq_no); |
39823a50 | 288 | |
f91c5d77 | 289 | add_tcp_pending_ack(ack_no, i, tqe); |
c5c77ba1 JK |
290 | } |
291 | ||
292 | } else { | |
293 | ret = 0; | |
294 | } | |
295 | } else { | |
296 | ret = 0; | |
297 | } | |
82bb18e1 | 298 | spin_unlock_irqrestore(&wilc->txq_spinlock, flags); |
c5c77ba1 JK |
299 | return ret; |
300 | } | |
301 | ||
c029e99c | 302 | static int wilc_wlan_txq_filter_dup_tcp_ack(struct net_device *dev) |
c5c77ba1 | 303 | { |
a4cac481 | 304 | struct wilc_vif *vif; |
c029e99c | 305 | struct wilc *wilc; |
fbc2fe16 | 306 | u32 i = 0; |
442eda4e | 307 | u32 dropped = 0; |
c5c77ba1 | 308 | |
a4cac481 GL |
309 | vif = netdev_priv(dev); |
310 | wilc = vif->wilc; | |
c029e99c | 311 | |
67e2a07e | 312 | spin_lock_irqsave(&wilc->txq_spinlock, wilc->txq_spinlock_flags); |
d12ac7e2 | 313 | for (i = pending_base; i < (pending_base + pending_acks); i++) { |
2bb17087 | 314 | if (pending_acks_info[i].ack_num < ack_session_info[pending_acks_info[i].session_index].bigger_ack_num) { |
c5c77ba1 | 315 | struct txq_entry_t *tqe; |
8dfaafd6 | 316 | |
2bb17087 LK |
317 | PRINT_D(TCP_ENH, "DROP ACK: %u\n", |
318 | pending_acks_info[i].ack_num); | |
319 | tqe = pending_acks_info[i].txqe; | |
c5c77ba1 JK |
320 | if (tqe) { |
321 | wilc_wlan_txq_remove(tqe); | |
ac087c82 | 322 | tqe->status = 1; |
c5c77ba1 | 323 | if (tqe->tx_complete_func) |
ab12d8c7 LK |
324 | tqe->tx_complete_func(tqe->priv, |
325 | tqe->status); | |
a18dd630 | 326 | kfree(tqe); |
442eda4e | 327 | dropped++; |
c5c77ba1 JK |
328 | } |
329 | } | |
330 | } | |
d12ac7e2 | 331 | pending_acks = 0; |
3056ec39 | 332 | tcp_session = 0; |
c5c77ba1 | 333 | |
2ae91edb LK |
334 | if (pending_base == 0) |
335 | pending_base = MAX_TCP_SESSION; | |
78174ada | 336 | else |
2ae91edb | 337 | pending_base = 0; |
c5c77ba1 | 338 | |
67e2a07e | 339 | spin_unlock_irqrestore(&wilc->txq_spinlock, wilc->txq_spinlock_flags); |
c5c77ba1 | 340 | |
442eda4e | 341 | while (dropped > 0) { |
562ed3f1 | 342 | wilc_lock_timeout(wilc, &wilc->txq_event, 1); |
442eda4e | 343 | dropped--; |
c5c77ba1 JK |
344 | } |
345 | ||
346 | return 1; | |
347 | } | |
348 | #endif | |
349 | ||
1608c403 | 350 | static bool enabled = false; |
c5c77ba1 | 351 | |
0e1af73d | 352 | void wilc_enable_tcp_ack_filter(bool value) |
c5c77ba1 | 353 | { |
7c4bafe9 | 354 | enabled = value; |
c5c77ba1 JK |
355 | } |
356 | ||
1608c403 AB |
357 | #ifdef TCP_ACK_FILTER |
358 | static bool is_tcp_ack_filter_enabled(void) | |
c5c77ba1 | 359 | { |
7c4bafe9 | 360 | return enabled; |
c5c77ba1 | 361 | } |
1608c403 | 362 | #endif |
c5c77ba1 | 363 | |
562ed3f1 | 364 | static int wilc_wlan_txq_add_cfg_pkt(struct wilc *wilc, u8 *buffer, u32 buffer_size) |
c5c77ba1 | 365 | { |
c5c77ba1 JK |
366 | struct txq_entry_t *tqe; |
367 | ||
368 | PRINT_D(TX_DBG, "Adding config packet ...\n"); | |
67e2a07e | 369 | if (wilc->quit) { |
c5c77ba1 | 370 | PRINT_D(TX_DBG, "Return due to clear function\n"); |
562ed3f1 | 371 | up(&wilc->cfg_event); |
c5c77ba1 JK |
372 | return 0; |
373 | } | |
374 | ||
1d401a4d | 375 | tqe = kmalloc(sizeof(*tqe), GFP_ATOMIC); |
a4b17197 | 376 | if (!tqe) { |
c5c77ba1 JK |
377 | 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 | |
b719302d | 387 | tqe->tcp_pending_ack_idx = NOT_TCP_ACK; |
c5c77ba1 | 388 | #endif |
c5c77ba1 JK |
389 | PRINT_D(TX_DBG, "Adding the config packet at the Queue tail\n"); |
390 | ||
562ed3f1 | 391 | if (wilc_wlan_txq_add_to_head(wilc, tqe)) |
c5c77ba1 | 392 | return 0; |
c5c77ba1 JK |
393 | return 1; |
394 | } | |
395 | ||
691bbd42 GL |
396 | int wilc_wlan_txq_add_net_pkt(struct net_device *dev, void *priv, u8 *buffer, |
397 | u32 buffer_size, wilc_tx_complete_func_t func) | |
c5c77ba1 | 398 | { |
c5c77ba1 | 399 | struct txq_entry_t *tqe; |
a4cac481 | 400 | struct wilc_vif *vif = netdev_priv(dev); |
67e2a07e GL |
401 | struct wilc *wilc; |
402 | ||
a4cac481 | 403 | wilc = vif->wilc; |
c5c77ba1 | 404 | |
67e2a07e | 405 | if (wilc->quit) |
c5c77ba1 JK |
406 | return 0; |
407 | ||
1d401a4d | 408 | tqe = kmalloc(sizeof(*tqe), GFP_ATOMIC); |
c5c77ba1 | 409 | |
a4b17197 | 410 | if (!tqe) |
c5c77ba1 JK |
411 | 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 | |
b719302d | 420 | tqe->tcp_pending_ack_idx = NOT_TCP_ACK; |
44c4417d | 421 | if (is_tcp_ack_filter_enabled()) |
82bb18e1 | 422 | tcp_process(dev, tqe); |
c5c77ba1 | 423 | #endif |
32f03328 | 424 | wilc_wlan_txq_add_to_tail(dev, tqe); |
67e2a07e | 425 | return wilc->txq_entries; |
c5c77ba1 | 426 | } |
fcc6ef92 | 427 | |
829c477f GL |
428 | int wilc_wlan_txq_add_mgmt_pkt(struct net_device *dev, void *priv, u8 *buffer, |
429 | u32 buffer_size, wilc_tx_complete_func_t func) | |
c5c77ba1 | 430 | { |
c5c77ba1 | 431 | struct txq_entry_t *tqe; |
a4cac481 | 432 | struct wilc_vif *vif = netdev_priv(dev); |
67e2a07e GL |
433 | struct wilc *wilc; |
434 | ||
a4cac481 | 435 | wilc = vif->wilc; |
c5c77ba1 | 436 | |
67e2a07e | 437 | if (wilc->quit) |
c5c77ba1 JK |
438 | return 0; |
439 | ||
1d401a4d | 440 | tqe = kmalloc(sizeof(*tqe), GFP_KERNEL); |
c5c77ba1 | 441 | |
a4b17197 | 442 | if (!tqe) |
c5c77ba1 JK |
443 | 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 | |
b719302d | 450 | tqe->tcp_pending_ack_idx = NOT_TCP_ACK; |
c5c77ba1 JK |
451 | #endif |
452 | PRINT_D(TX_DBG, "Adding Network packet at the Queue tail\n"); | |
32f03328 | 453 | wilc_wlan_txq_add_to_tail(dev, tqe); |
c5c77ba1 JK |
454 | return 1; |
455 | } | |
fcc6ef92 | 456 | |
7af0522c | 457 | static struct txq_entry_t *wilc_wlan_txq_get_first(struct wilc *wilc) |
c5c77ba1 | 458 | { |
c5c77ba1 JK |
459 | struct txq_entry_t *tqe; |
460 | unsigned long flags; | |
461 | ||
7af0522c | 462 | spin_lock_irqsave(&wilc->txq_spinlock, flags); |
c5c77ba1 | 463 | |
67e2a07e | 464 | tqe = wilc->txq_head; |
c5c77ba1 | 465 | |
7af0522c | 466 | spin_unlock_irqrestore(&wilc->txq_spinlock, flags); |
c5c77ba1 | 467 | |
c5c77ba1 JK |
468 | return tqe; |
469 | } | |
470 | ||
50a0b3b7 GL |
471 | static struct txq_entry_t *wilc_wlan_txq_get_next(struct wilc *wilc, |
472 | struct txq_entry_t *tqe) | |
c5c77ba1 | 473 | { |
c5c77ba1 | 474 | unsigned long flags; |
8739eeba | 475 | |
50a0b3b7 | 476 | spin_lock_irqsave(&wilc->txq_spinlock, flags); |
c5c77ba1 | 477 | |
c5c77ba1 | 478 | tqe = tqe->next; |
50a0b3b7 | 479 | spin_unlock_irqrestore(&wilc->txq_spinlock, flags); |
c5c77ba1 | 480 | |
c5c77ba1 JK |
481 | return tqe; |
482 | } | |
483 | ||
d06f362c | 484 | static int wilc_wlan_rxq_add(struct wilc *wilc, struct rxq_entry_t *rqe) |
c5c77ba1 | 485 | { |
c5c77ba1 | 486 | |
67e2a07e | 487 | if (wilc->quit) |
c5c77ba1 JK |
488 | return 0; |
489 | ||
d06f362c | 490 | mutex_lock(&wilc->rxq_cs); |
67e2a07e | 491 | if (!wilc->rxq_head) { |
c5c77ba1 JK |
492 | PRINT_D(RX_DBG, "Add to Queue head\n"); |
493 | rqe->next = NULL; | |
67e2a07e GL |
494 | wilc->rxq_head = rqe; |
495 | wilc->rxq_tail = rqe; | |
c5c77ba1 JK |
496 | } else { |
497 | PRINT_D(RX_DBG, "Add to Queue tail\n"); | |
67e2a07e | 498 | wilc->rxq_tail->next = rqe; |
c5c77ba1 | 499 | rqe->next = NULL; |
67e2a07e | 500 | wilc->rxq_tail = rqe; |
c5c77ba1 | 501 | } |
67e2a07e GL |
502 | wilc->rxq_entries += 1; |
503 | PRINT_D(RX_DBG, "Number of queue entries: %d\n", wilc->rxq_entries); | |
d06f362c | 504 | mutex_unlock(&wilc->rxq_cs); |
67e2a07e | 505 | return wilc->rxq_entries; |
c5c77ba1 JK |
506 | } |
507 | ||
db387635 | 508 | static struct rxq_entry_t *wilc_wlan_rxq_remove(struct wilc *wilc) |
c5c77ba1 | 509 | { |
c5c77ba1 JK |
510 | |
511 | PRINT_D(RX_DBG, "Getting rxQ element\n"); | |
67e2a07e | 512 | if (wilc->rxq_head) { |
c5c77ba1 JK |
513 | struct rxq_entry_t *rqe; |
514 | ||
db387635 | 515 | mutex_lock(&wilc->rxq_cs); |
67e2a07e GL |
516 | rqe = wilc->rxq_head; |
517 | wilc->rxq_head = wilc->rxq_head->next; | |
518 | wilc->rxq_entries -= 1; | |
c5c77ba1 | 519 | PRINT_D(RX_DBG, "RXQ entries decreased\n"); |
db387635 | 520 | mutex_unlock(&wilc->rxq_cs); |
c5c77ba1 JK |
521 | return rqe; |
522 | } | |
523 | PRINT_D(RX_DBG, "Nothing to get from Q\n"); | |
524 | return NULL; | |
525 | } | |
526 | ||
c5c77ba1 JK |
527 | #ifdef WILC_OPTIMIZE_SLEEP_INT |
528 | ||
00215dde | 529 | static inline void chip_allow_sleep(struct wilc *wilc) |
c5c77ba1 | 530 | { |
fbc2fe16 | 531 | u32 reg = 0; |
c5c77ba1 | 532 | |
af9ae09a | 533 | wilc->hif_func->hif_read_reg(wilc, 0xf0, ®); |
c5c77ba1 | 534 | |
af9ae09a | 535 | wilc->hif_func->hif_write_reg(wilc, 0xf0, reg & ~BIT(0)); |
c5c77ba1 JK |
536 | } |
537 | ||
00215dde | 538 | static inline void chip_wakeup(struct wilc *wilc) |
c5c77ba1 | 539 | { |
fbc2fe16 CL |
540 | u32 reg, clk_status_reg, trials = 0; |
541 | u32 sleep_time; | |
c5c77ba1 | 542 | |
a3629a9e | 543 | if ((wilc->io_type & 0x1) == HIF_SPI) { |
c5c77ba1 | 544 | do { |
af9ae09a GL |
545 | wilc->hif_func->hif_read_reg(wilc, 1, ®); |
546 | wilc->hif_func->hif_write_reg(wilc, 1, reg | BIT(1)); | |
547 | wilc->hif_func->hif_write_reg(wilc, 1, reg & ~BIT(1)); | |
c5c77ba1 JK |
548 | |
549 | do { | |
80e29c7a | 550 | usleep_range(2 * 1000, 2 * 1000); |
00215dde | 551 | if ((wilc_get_chipid(wilc, true) == 0)) |
c5c77ba1 | 552 | wilc_debug(N_ERR, "Couldn't read chip id. Wake up failed\n"); |
39823a50 | 553 | |
00215dde | 554 | } while ((wilc_get_chipid(wilc, true) == 0) && ((++trials % 3) == 0)); |
c5c77ba1 | 555 | |
00215dde | 556 | } while (wilc_get_chipid(wilc, true) == 0); |
a3629a9e | 557 | } else if ((wilc->io_type & 0x1) == HIF_SDIO) { |
af9ae09a | 558 | wilc->hif_func->hif_read_reg(wilc, 0xf0, ®); |
c5c77ba1 | 559 | do { |
af9ae09a | 560 | wilc->hif_func->hif_write_reg(wilc, 0xf0, |
49dcd0dd | 561 | reg | BIT(0)); |
af9ae09a | 562 | wilc->hif_func->hif_read_reg(wilc, 0xf1, |
49dcd0dd | 563 | &clk_status_reg); |
c5c77ba1 | 564 | |
c5c77ba1 | 565 | while (((clk_status_reg & 0x1) == 0) && (((++trials) % 3) == 0)) { |
80e29c7a | 566 | usleep_range(2 * 1000, 2 * 1000); |
c5c77ba1 | 567 | |
af9ae09a | 568 | wilc->hif_func->hif_read_reg(wilc, 0xf1, |
49dcd0dd | 569 | &clk_status_reg); |
c5c77ba1 | 570 | |
39823a50 | 571 | if ((clk_status_reg & 0x1) == 0) |
c5c77ba1 | 572 | wilc_debug(N_ERR, "clocks still OFF. Wake up failed\n"); |
c5c77ba1 | 573 | } |
c5c77ba1 | 574 | if ((clk_status_reg & 0x1) == 0) { |
af9ae09a | 575 | wilc->hif_func->hif_write_reg(wilc, 0xf0, |
49dcd0dd | 576 | reg & (~BIT(0))); |
c5c77ba1 JK |
577 | } |
578 | } while ((clk_status_reg & 0x1) == 0); | |
579 | } | |
580 | ||
b7d1e18c | 581 | if (chip_ps_state == CHIP_SLEEPING_MANUAL) { |
af9ae09a | 582 | wilc->hif_func->hif_read_reg(wilc, 0x1C0C, ®); |
ffda203c | 583 | reg &= ~BIT(0); |
af9ae09a | 584 | wilc->hif_func->hif_write_reg(wilc, 0x1C0C, reg); |
c5c77ba1 | 585 | |
00215dde | 586 | if (wilc_get_chipid(wilc, false) >= 0x1002b0) { |
fbc2fe16 | 587 | u32 val32; |
8dfaafd6 | 588 | |
af9ae09a | 589 | wilc->hif_func->hif_read_reg(wilc, 0x1e1c, &val32); |
ffda203c | 590 | val32 |= BIT(6); |
af9ae09a | 591 | wilc->hif_func->hif_write_reg(wilc, 0x1e1c, val32); |
c5c77ba1 | 592 | |
af9ae09a | 593 | wilc->hif_func->hif_read_reg(wilc, 0x1e9c, &val32); |
ffda203c | 594 | val32 |= BIT(6); |
af9ae09a | 595 | wilc->hif_func->hif_write_reg(wilc, 0x1e9c, val32); |
c5c77ba1 JK |
596 | } |
597 | } | |
b7d1e18c | 598 | chip_ps_state = CHIP_WAKEDUP; |
c5c77ba1 JK |
599 | } |
600 | #else | |
00215dde | 601 | static inline void chip_wakeup(struct wilc *wilc) |
c5c77ba1 | 602 | { |
fbc2fe16 | 603 | u32 reg, trials = 0; |
8dfaafd6 | 604 | |
c5c77ba1 | 605 | do { |
a3629a9e | 606 | if ((wilc->io_type & 0x1) == HIF_SPI) { |
af9ae09a GL |
607 | wilc->hif_func->hif_read_reg(wilc, 1, ®); |
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)); | |
a3629a9e | 611 | } else if ((wilc->io_type & 0x1) == HIF_SDIO) { |
af9ae09a GL |
612 | wilc->hif_func->hif_read_reg(wilc, 0xf0, ®); |
613 | wilc->hif_func->hif_write_reg(wilc, 0xf0, | |
49dcd0dd | 614 | reg & ~BIT(0)); |
af9ae09a | 615 | wilc->hif_func->hif_write_reg(wilc, 0xf0, |
49dcd0dd | 616 | reg | BIT(0)); |
af9ae09a | 617 | wilc->hif_func->hif_write_reg(wilc, 0xf0, |
49dcd0dd | 618 | reg & ~BIT(0)); |
c5c77ba1 JK |
619 | } |
620 | ||
621 | do { | |
c5c77ba1 JK |
622 | mdelay(3); |
623 | ||
00215dde | 624 | if ((wilc_get_chipid(wilc, true) == 0)) |
c5c77ba1 | 625 | wilc_debug(N_ERR, "Couldn't read chip id. Wake up failed\n"); |
39823a50 | 626 | |
00215dde | 627 | } while ((wilc_get_chipid(wilc, true) == 0) && ((++trials % 3) == 0)); |
c5c77ba1 | 628 | |
00215dde | 629 | } while (wilc_get_chipid(wilc, true) == 0); |
c5c77ba1 | 630 | |
b7d1e18c | 631 | if (chip_ps_state == CHIP_SLEEPING_MANUAL) { |
af9ae09a | 632 | wilc->hif_func->hif_read_reg(wilc, 0x1C0C, ®); |
ffda203c | 633 | reg &= ~BIT(0); |
af9ae09a | 634 | wilc->hif_func->hif_write_reg(wilc, 0x1C0C, reg); |
c5c77ba1 | 635 | |
00215dde | 636 | if (wilc_get_chipid(wilc, false) >= 0x1002b0) { |
fbc2fe16 | 637 | u32 val32; |
8dfaafd6 | 638 | |
af9ae09a | 639 | wilc->hif_func->hif_read_reg(wilc, 0x1e1c, &val32); |
ffda203c | 640 | val32 |= BIT(6); |
af9ae09a | 641 | wilc->hif_func->hif_write_reg(wilc, 0x1e1c, val32); |
c5c77ba1 | 642 | |
af9ae09a | 643 | wilc->hif_func->hif_read_reg(wilc, 0x1e9c, &val32); |
ffda203c | 644 | val32 |= BIT(6); |
af9ae09a | 645 | wilc->hif_func->hif_write_reg(wilc, 0x1e9c, val32); |
c5c77ba1 JK |
646 | } |
647 | } | |
b7d1e18c | 648 | chip_ps_state = CHIP_WAKEDUP; |
c5c77ba1 JK |
649 | } |
650 | #endif | |
00215dde | 651 | void wilc_chip_sleep_manually(struct wilc *wilc) |
c5c77ba1 | 652 | { |
b7d1e18c | 653 | if (chip_ps_state != CHIP_WAKEDUP) |
c5c77ba1 | 654 | return; |
00215dde | 655 | acquire_bus(wilc, ACQUIRE_ONLY); |
c5c77ba1 JK |
656 | |
657 | #ifdef WILC_OPTIMIZE_SLEEP_INT | |
00215dde | 658 | chip_allow_sleep(wilc); |
c5c77ba1 | 659 | #endif |
af9ae09a | 660 | wilc->hif_func->hif_write_reg(wilc, 0x10a8, 1); |
c5c77ba1 | 661 | |
b7d1e18c | 662 | chip_ps_state = CHIP_SLEEPING_MANUAL; |
00215dde | 663 | release_bus(wilc, RELEASE_ONLY); |
c5c77ba1 JK |
664 | } |
665 | ||
b1d19298 | 666 | int wilc_wlan_handle_txq(struct net_device *dev, u32 *txq_count) |
c5c77ba1 | 667 | { |
c5c77ba1 | 668 | int i, entries = 0; |
fbc2fe16 CL |
669 | u32 sum; |
670 | u32 reg; | |
67e2a07e | 671 | u8 *txb; |
fbc2fe16 | 672 | u32 offset = 0; |
c5c77ba1 JK |
673 | int vmm_sz = 0; |
674 | struct txq_entry_t *tqe; | |
675 | int ret = 0; | |
676 | int counter; | |
677 | int timeout; | |
fbc2fe16 | 678 | u32 vmm_table[WILC_VMM_TBL_SIZE]; |
a4cac481 | 679 | struct wilc_vif *vif; |
a1332cad GL |
680 | struct wilc *wilc; |
681 | ||
a4cac481 GL |
682 | vif = netdev_priv(dev); |
683 | wilc = vif->wilc; | |
8dfaafd6 | 684 | |
67e2a07e GL |
685 | txb = wilc->tx_buffer; |
686 | wilc->txq_exit = 0; | |
c5c77ba1 | 687 | do { |
67e2a07e | 688 | if (wilc->quit) |
c5c77ba1 JK |
689 | break; |
690 | ||
562ed3f1 | 691 | wilc_lock_timeout(wilc, &wilc->txq_add_to_head_cs, |
b002e20d | 692 | CFG_PKTS_TIMEOUT); |
c5c77ba1 | 693 | #ifdef TCP_ACK_FILTER |
c029e99c | 694 | wilc_wlan_txq_filter_dup_tcp_ack(dev); |
c5c77ba1 | 695 | #endif |
c5c77ba1 | 696 | PRINT_D(TX_DBG, "Getting the head of the TxQ\n"); |
7af0522c | 697 | tqe = wilc_wlan_txq_get_first(wilc); |
c5c77ba1 JK |
698 | i = 0; |
699 | sum = 0; | |
700 | do { | |
a4b17197 | 701 | if (tqe && (i < (WILC_VMM_TBL_SIZE - 1))) { |
39823a50 | 702 | if (tqe->type == WILC_CFG_PKT) |
c5c77ba1 | 703 | vmm_sz = ETH_CONFIG_PKT_HDR_OFFSET; |
39823a50 AS |
704 | |
705 | else if (tqe->type == WILC_NET_PKT) | |
c5c77ba1 | 706 | vmm_sz = ETH_ETHERNET_HDR_OFFSET; |
39823a50 AS |
707 | |
708 | else | |
c5c77ba1 | 709 | vmm_sz = HOST_HDR_OFFSET; |
39823a50 | 710 | |
c5c77ba1 JK |
711 | vmm_sz += tqe->buffer_size; |
712 | PRINT_D(TX_DBG, "VMM Size before alignment = %d\n", vmm_sz); | |
ac087c82 | 713 | if (vmm_sz & 0x3) |
c5c77ba1 | 714 | vmm_sz = (vmm_sz + 4) & ~0x3; |
ac087c82 | 715 | |
39823a50 | 716 | if ((sum + vmm_sz) > LINUX_TX_SIZE) |
c5c77ba1 | 717 | break; |
39823a50 | 718 | |
c5c77ba1 | 719 | PRINT_D(TX_DBG, "VMM Size AFTER alignment = %d\n", vmm_sz); |
ac087c82 | 720 | vmm_table[i] = vmm_sz / 4; |
ab12d8c7 LK |
721 | PRINT_D(TX_DBG, "VMMTable entry size = %d\n", |
722 | vmm_table[i]); | |
c5c77ba1 JK |
723 | |
724 | if (tqe->type == WILC_CFG_PKT) { | |
ffda203c | 725 | vmm_table[i] |= BIT(10); |
c5c77ba1 JK |
726 | PRINT_D(TX_DBG, "VMMTable entry changed for CFG packet = %d\n", vmm_table[i]); |
727 | } | |
9e6627ac | 728 | vmm_table[i] = cpu_to_le32(vmm_table[i]); |
c5c77ba1 | 729 | |
c5c77ba1 JK |
730 | i++; |
731 | sum += vmm_sz; | |
732 | PRINT_D(TX_DBG, "sum = %d\n", sum); | |
50a0b3b7 | 733 | tqe = wilc_wlan_txq_get_next(wilc, tqe); |
c5c77ba1 JK |
734 | } else { |
735 | break; | |
736 | } | |
737 | } while (1); | |
738 | ||
ac087c82 | 739 | if (i == 0) { |
c5c77ba1 JK |
740 | 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); | |
ac087c82 | 744 | vmm_table[i] = 0x0; |
c5c77ba1 | 745 | } |
562ed3f1 | 746 | acquire_bus(wilc, ACQUIRE_AND_WAKEUP); |
c5c77ba1 JK |
747 | counter = 0; |
748 | do { | |
af9ae09a | 749 | ret = wilc->hif_func->hif_read_reg(wilc, WILC_HOST_TX_CTRL, |
49dcd0dd | 750 | ®); |
c5c77ba1 JK |
751 | 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) { | |
c5c77ba1 JK |
757 | 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"); | |
af9ae09a | 764 | ret = wilc->hif_func->hif_write_reg(wilc, WILC_HOST_TX_CTRL, 0); |
c5c77ba1 JK |
765 | break; |
766 | } | |
17aacd43 | 767 | PRINT_WRN(GENERIC_DBG, "[wilc txq]: warn, vmm table not clear yet, wait...\n"); |
562ed3f1 | 768 | release_bus(wilc, RELEASE_ALLOW_SLEEP); |
2b922cbe | 769 | usleep_range(3000, 3000); |
562ed3f1 | 770 | acquire_bus(wilc, ACQUIRE_AND_WAKEUP); |
c5c77ba1 | 771 | } |
67e2a07e | 772 | } while (!wilc->quit); |
c5c77ba1 | 773 | |
39823a50 | 774 | if (!ret) |
c5c77ba1 | 775 | goto _end_; |
c5c77ba1 JK |
776 | |
777 | timeout = 200; | |
778 | do { | |
af9ae09a | 779 | ret = wilc->hif_func->hif_block_tx(wilc, WILC_VMM_TBL_RX_SHADOW_BASE, (u8 *)vmm_table, ((i + 1) * 4)); |
c5c77ba1 JK |
780 | if (!ret) { |
781 | wilc_debug(N_ERR, "ERR block TX of VMM table.\n"); | |
782 | break; | |
783 | } | |
784 | ||
af9ae09a | 785 | ret = wilc->hif_func->hif_write_reg(wilc, WILC_HOST_VMM_CTL, |
49dcd0dd | 786 | 0x2); |
c5c77ba1 JK |
787 | if (!ret) { |
788 | wilc_debug(N_ERR, "[wilc txq]: fail can't write reg host_vmm_ctl..\n"); | |
789 | break; | |
790 | } | |
791 | ||
c5c77ba1 | 792 | do { |
af9ae09a | 793 | ret = wilc->hif_func->hif_read_reg(wilc, WILC_HOST_VMM_CTL, ®); |
c5c77ba1 JK |
794 | 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) { | |
c5c77ba1 | 799 | entries = ((reg >> 3) & 0x3f); |
c5c77ba1 JK |
800 | break; |
801 | } else { | |
562ed3f1 | 802 | release_bus(wilc, RELEASE_ALLOW_SLEEP); |
2b922cbe | 803 | usleep_range(3000, 3000); |
562ed3f1 | 804 | acquire_bus(wilc, ACQUIRE_AND_WAKEUP); |
c5c77ba1 JK |
805 | PRINT_WRN(GENERIC_DBG, "Can't get VMM entery - reg = %2x\n", reg); |
806 | } | |
807 | } while (--timeout); | |
808 | if (timeout <= 0) { | |
af9ae09a | 809 | ret = wilc->hif_func->hif_write_reg(wilc, WILC_HOST_VMM_CTL, 0x0); |
c5c77ba1 JK |
810 | break; |
811 | } | |
812 | ||
39823a50 | 813 | if (!ret) |
c5c77ba1 | 814 | break; |
c5c77ba1 JK |
815 | |
816 | if (entries == 0) { | |
17aacd43 | 817 | 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]); |
c5c77ba1 | 818 | |
af9ae09a | 819 | ret = wilc->hif_func->hif_read_reg(wilc, WILC_HOST_TX_CTRL, ®); |
c5c77ba1 JK |
820 | if (!ret) { |
821 | wilc_debug(N_ERR, "[wilc txq]: fail can't read reg WILC_HOST_TX_CTRL..\n"); | |
822 | break; | |
823 | } | |
ffda203c | 824 | reg &= ~BIT(0); |
af9ae09a | 825 | ret = wilc->hif_func->hif_write_reg(wilc, WILC_HOST_TX_CTRL, reg); |
c5c77ba1 JK |
826 | 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 | ||
39823a50 | 836 | if (!ret) |
c5c77ba1 | 837 | goto _end_; |
39823a50 | 838 | |
c5c77ba1 JK |
839 | if (entries == 0) { |
840 | ret = WILC_TX_ERR_NO_BUF; | |
841 | goto _end_; | |
842 | } | |
843 | ||
562ed3f1 | 844 | release_bus(wilc, RELEASE_ALLOW_SLEEP); |
c5c77ba1 | 845 | |
c5c77ba1 JK |
846 | offset = 0; |
847 | i = 0; | |
848 | do { | |
718fc2c9 | 849 | tqe = wilc_wlan_txq_remove_from_head(dev); |
a4b17197 | 850 | if (tqe && (vmm_table[i] != 0)) { |
fbc2fe16 | 851 | u32 header, buffer_offset; |
c5c77ba1 | 852 | |
9e6627ac | 853 | vmm_table[i] = cpu_to_le32(vmm_table[i]); |
ac087c82 | 854 | vmm_sz = (vmm_table[i] & 0x3ff); |
c5c77ba1 | 855 | vmm_sz *= 4; |
ab12d8c7 LK |
856 | header = (tqe->type << 31) | |
857 | (tqe->buffer_size << 15) | | |
858 | vmm_sz; | |
78174ada | 859 | if (tqe->type == WILC_MGMT_PKT) |
ffda203c | 860 | header |= BIT(30); |
78174ada | 861 | else |
ffda203c | 862 | header &= ~BIT(30); |
c5c77ba1 | 863 | |
9e6627ac | 864 | header = cpu_to_le32(header); |
c5c77ba1 JK |
865 | memcpy(&txb[offset], &header, 4); |
866 | if (tqe->type == WILC_CFG_PKT) { | |
867 | buffer_offset = ETH_CONFIG_PKT_HDR_OFFSET; | |
590c0a39 | 868 | } else if (tqe->type == WILC_NET_PKT) { |
2f7c31fd | 869 | char *bssid = ((struct tx_complete_data *)(tqe->priv))->pBssid; |
8dfaafd6 | 870 | |
c5c77ba1 | 871 | buffer_offset = ETH_ETHERNET_HDR_OFFSET; |
2f7c31fd | 872 | memcpy(&txb[offset + 4], bssid, 6); |
590c0a39 | 873 | } else { |
c5c77ba1 JK |
874 | buffer_offset = HOST_HDR_OFFSET; |
875 | } | |
876 | ||
ab12d8c7 LK |
877 | memcpy(&txb[offset + buffer_offset], |
878 | tqe->buffer, tqe->buffer_size); | |
c5c77ba1 JK |
879 | offset += vmm_sz; |
880 | i++; | |
ac087c82 | 881 | tqe->status = 1; |
c5c77ba1 | 882 | if (tqe->tx_complete_func) |
ab12d8c7 LK |
883 | tqe->tx_complete_func(tqe->priv, |
884 | tqe->status); | |
c5c77ba1 | 885 | #ifdef TCP_ACK_FILTER |
b719302d GL |
886 | if (tqe->tcp_pending_ack_idx != NOT_TCP_ACK) |
887 | pending_acks_info[tqe->tcp_pending_ack_idx].txqe = NULL; | |
c5c77ba1 | 888 | #endif |
a18dd630 | 889 | kfree(tqe); |
c5c77ba1 JK |
890 | } else { |
891 | break; | |
892 | } | |
893 | } while (--entries); | |
894 | ||
562ed3f1 | 895 | acquire_bus(wilc, ACQUIRE_AND_WAKEUP); |
c5c77ba1 | 896 | |
af9ae09a | 897 | ret = wilc->hif_func->hif_clear_int_ext(wilc, ENABLE_TX_VMM); |
c5c77ba1 JK |
898 | if (!ret) { |
899 | wilc_debug(N_ERR, "[wilc txq]: fail can't start tx VMM ...\n"); | |
900 | goto _end_; | |
901 | } | |
902 | ||
af9ae09a | 903 | ret = wilc->hif_func->hif_block_tx_ext(wilc, 0, txb, offset); |
c5c77ba1 JK |
904 | if (!ret) { |
905 | wilc_debug(N_ERR, "[wilc txq]: fail can't block tx ext...\n"); | |
906 | goto _end_; | |
907 | } | |
908 | ||
909 | _end_: | |
910 | ||
562ed3f1 | 911 | release_bus(wilc, RELEASE_ALLOW_SLEEP); |
c5c77ba1 JK |
912 | if (ret != 1) |
913 | break; | |
914 | } while (0); | |
a1332cad | 915 | up(&wilc->txq_add_to_head_cs); |
c5c77ba1 | 916 | |
67e2a07e | 917 | wilc->txq_exit = 1; |
c5c77ba1 | 918 | PRINT_D(TX_DBG, "THREAD: Exiting txq\n"); |
67e2a07e | 919 | *txq_count = wilc->txq_entries; |
c5c77ba1 JK |
920 | return ret; |
921 | } | |
922 | ||
39ce4d3d | 923 | static void wilc_wlan_handle_rxq(struct wilc *wilc) |
c5c77ba1 | 924 | { |
c5c77ba1 | 925 | int offset = 0, size, has_packet = 0; |
51e825f7 | 926 | u8 *buffer; |
c5c77ba1 JK |
927 | struct rxq_entry_t *rqe; |
928 | ||
67e2a07e | 929 | wilc->rxq_exit = 0; |
c5c77ba1 | 930 | |
c5c77ba1 | 931 | do { |
67e2a07e | 932 | if (wilc->quit) { |
17aacd43 | 933 | PRINT_D(RX_DBG, "exit 1st do-while due to Clean_UP function\n"); |
39ce4d3d | 934 | up(&wilc->cfg_event); |
c5c77ba1 JK |
935 | break; |
936 | } | |
db387635 | 937 | rqe = wilc_wlan_rxq_remove(wilc); |
a4b17197 | 938 | if (!rqe) { |
c5c77ba1 JK |
939 | 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; | |
ab12d8c7 LK |
944 | PRINT_D(RX_DBG, "rxQ entery Size = %d - Address = %p\n", |
945 | size, buffer); | |
c5c77ba1 JK |
946 | offset = 0; |
947 | ||
c5c77ba1 | 948 | do { |
fbc2fe16 CL |
949 | u32 header; |
950 | u32 pkt_len, pkt_offset, tp_len; | |
c5c77ba1 | 951 | int is_cfg_packet; |
8dfaafd6 | 952 | |
c5c77ba1 JK |
953 | PRINT_D(RX_DBG, "In the 2nd do-while\n"); |
954 | memcpy(&header, &buffer[offset], 4); | |
9e6627ac | 955 | header = cpu_to_le32(header); |
ab12d8c7 LK |
956 | PRINT_D(RX_DBG, "Header = %04x - Offset = %d\n", |
957 | header, offset); | |
c5c77ba1 | 958 | |
c5c77ba1 JK |
959 | 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 | ||
c5c77ba1 JK |
969 | #define IS_MANAGMEMENT 0x100 |
970 | #define IS_MANAGMEMENT_CALLBACK 0x080 | |
971 | #define IS_MGMT_STATUS_SUCCES 0x040 | |
972 | ||
c5c77ba1 | 973 | if (pkt_offset & IS_MANAGMEMENT) { |
ab12d8c7 LK |
974 | pkt_offset &= ~(IS_MANAGMEMENT | |
975 | IS_MANAGMEMENT_CALLBACK | | |
976 | IS_MGMT_STATUS_SUCCES); | |
c5c77ba1 | 977 | |
11f4b2ee | 978 | WILC_WFI_mgmt_rx(wilc, &buffer[offset + HOST_HDR_OFFSET], pkt_len); |
590c0a39 | 979 | } else { |
c5c77ba1 | 980 | if (!is_cfg_packet) { |
63611670 | 981 | if (pkt_len > 0) { |
562ed3f1 | 982 | wilc_frmw_to_linux(wilc, |
cb1991ac | 983 | &buffer[offset], |
63611670 GL |
984 | pkt_len, |
985 | pkt_offset); | |
986 | has_packet = 1; | |
c5c77ba1 JK |
987 | } |
988 | } else { | |
bcddd48b | 989 | struct wilc_cfg_rsp rsp; |
c5c77ba1 | 990 | |
cd04d221 | 991 | wilc_wlan_cfg_indicate_rx(wilc, &buffer[pkt_offset + offset], pkt_len, &rsp); |
c5c77ba1 | 992 | if (rsp.type == WILC_CFG_RSP) { |
67e2a07e GL |
993 | 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) | |
39ce4d3d | 995 | up(&wilc->cfg_event); |
c5c77ba1 | 996 | } else if (rsp.type == WILC_CFG_RSP_STATUS) { |
562ed3f1 | 997 | wilc_mac_indicate(wilc, WILC_MAC_INDICATE_STATUS); |
c5c77ba1 JK |
998 | |
999 | } else if (rsp.type == WILC_CFG_RSP_SCAN) { | |
562ed3f1 | 1000 | wilc_mac_indicate(wilc, WILC_MAC_INDICATE_SCAN); |
c5c77ba1 JK |
1001 | } |
1002 | } | |
1003 | } | |
1004 | offset += tp_len; | |
1005 | if (offset >= size) | |
1006 | break; | |
1007 | } while (1); | |
a18dd630 | 1008 | kfree(rqe); |
c5c77ba1 | 1009 | |
39823a50 | 1010 | if (has_packet) |
562ed3f1 | 1011 | wilc_rx_complete(wilc); |
39823a50 | 1012 | |
c5c77ba1 JK |
1013 | } while (1); |
1014 | ||
67e2a07e | 1015 | wilc->rxq_exit = 1; |
17aacd43 | 1016 | PRINT_D(RX_DBG, "THREAD: Exiting RX thread\n"); |
c5c77ba1 JK |
1017 | } |
1018 | ||
00215dde | 1019 | static void wilc_unknown_isr_ext(struct wilc *wilc) |
c5c77ba1 | 1020 | { |
af9ae09a | 1021 | wilc->hif_func->hif_clear_int_ext(wilc, 0); |
c5c77ba1 | 1022 | } |
2d6973e6 | 1023 | |
00215dde | 1024 | static void wilc_pllupdate_isr_ext(struct wilc *wilc, u32 int_stats) |
c5c77ba1 | 1025 | { |
c5c77ba1 JK |
1026 | int trials = 10; |
1027 | ||
af9ae09a | 1028 | wilc->hif_func->hif_clear_int_ext(wilc, PLL_INT_CLR); |
c5c77ba1 | 1029 | |
a3629a9e | 1030 | if (wilc->io_type == HIF_SDIO) |
e28e84d2 AB |
1031 | mdelay(WILC_PLL_TO_SDIO); |
1032 | else | |
1033 | mdelay(WILC_PLL_TO_SPI); | |
c5c77ba1 | 1034 | |
00215dde | 1035 | while (!(ISWILC1000(wilc_get_chipid(wilc, true)) && --trials)) { |
c5c77ba1 | 1036 | PRINT_D(TX_DBG, "PLL update retrying\n"); |
c2e4c0f1 | 1037 | mdelay(1); |
c5c77ba1 JK |
1038 | } |
1039 | } | |
1040 | ||
00215dde | 1041 | static void wilc_sleeptimer_isr_ext(struct wilc *wilc, u32 int_stats1) |
c5c77ba1 | 1042 | { |
af9ae09a | 1043 | wilc->hif_func->hif_clear_int_ext(wilc, SLEEP_INT_CLR); |
c5c77ba1 | 1044 | #ifndef WILC_OPTIMIZE_SLEEP_INT |
b7d1e18c | 1045 | chip_ps_state = CHIP_SLEEPING_AUTO; |
c5c77ba1 JK |
1046 | #endif |
1047 | } | |
1048 | ||
3bcd45b6 | 1049 | static void wilc_wlan_handle_isr_ext(struct wilc *wilc, u32 int_status) |
c5c77ba1 | 1050 | { |
67e2a07e | 1051 | u32 offset = wilc->rx_buffer_offset; |
51e825f7 | 1052 | u8 *buffer = NULL; |
fbc2fe16 CL |
1053 | u32 size; |
1054 | u32 retries = 0; | |
c5c77ba1 JK |
1055 | int ret = 0; |
1056 | struct rxq_entry_t *rqe; | |
1057 | ||
c5c77ba1 JK |
1058 | size = ((int_status & 0x7fff) << 2); |
1059 | ||
1060 | while (!size && retries < 10) { | |
fbc2fe16 | 1061 | u32 time = 0; |
ac087c82 | 1062 | |
c5c77ba1 | 1063 | wilc_debug(N_ERR, "RX Size equal zero ... Trying to read it again for %d time\n", time++); |
af9ae09a | 1064 | wilc->hif_func->hif_read_size(wilc, &size); |
c5c77ba1 JK |
1065 | size = ((size & 0x7fff) << 2); |
1066 | retries++; | |
c5c77ba1 JK |
1067 | } |
1068 | ||
1069 | if (size > 0) { | |
03eb7266 | 1070 | if (LINUX_RX_SIZE - offset < size) |
c5c77ba1 JK |
1071 | offset = 0; |
1072 | ||
67e2a07e GL |
1073 | if (wilc->rx_buffer) { |
1074 | buffer = &wilc->rx_buffer[offset]; | |
7eb17b8d | 1075 | } else { |
c5c77ba1 JK |
1076 | wilc_debug(N_ERR, "[wilc isr]: fail Rx Buffer is NULL...drop the packets (%d)\n", size); |
1077 | goto _end_; | |
1078 | } | |
1079 | ||
af9ae09a | 1080 | wilc->hif_func->hif_clear_int_ext(wilc, |
49dcd0dd | 1081 | DATA_INT_CLR | ENABLE_RX_VMM); |
af9ae09a | 1082 | ret = wilc->hif_func->hif_block_rx_ext(wilc, 0, buffer, size); |
c5c77ba1 JK |
1083 | |
1084 | if (!ret) { | |
1085 | wilc_debug(N_ERR, "[wilc isr]: fail block rx...\n"); | |
1086 | goto _end_; | |
1087 | } | |
1088 | _end_: | |
c5c77ba1 | 1089 | if (ret) { |
c5c77ba1 | 1090 | offset += size; |
67e2a07e | 1091 | wilc->rx_buffer_offset = offset; |
13b01e40 | 1092 | rqe = kmalloc(sizeof(*rqe), GFP_KERNEL); |
a4b17197 | 1093 | if (rqe) { |
c5c77ba1 JK |
1094 | 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); | |
d06f362c | 1097 | wilc_wlan_rxq_add(wilc, rqe); |
c5c77ba1 | 1098 | } |
c5c77ba1 JK |
1099 | } |
1100 | } | |
39ce4d3d | 1101 | wilc_wlan_handle_rxq(wilc); |
c5c77ba1 JK |
1102 | } |
1103 | ||
562ed3f1 | 1104 | void wilc_handle_isr(struct wilc *wilc) |
c5c77ba1 | 1105 | { |
fbc2fe16 | 1106 | u32 int_status; |
c5c77ba1 | 1107 | |
562ed3f1 | 1108 | acquire_bus(wilc, ACQUIRE_AND_WAKEUP); |
af9ae09a | 1109 | wilc->hif_func->hif_read_int(wilc, &int_status); |
c5c77ba1 | 1110 | |
39823a50 | 1111 | if (int_status & PLL_INT_EXT) |
00215dde | 1112 | wilc_pllupdate_isr_ext(wilc, int_status); |
39823a50 | 1113 | |
c5c77ba1 | 1114 | if (int_status & DATA_INT_EXT) { |
3bcd45b6 | 1115 | wilc_wlan_handle_isr_ext(wilc, int_status); |
c5c77ba1 | 1116 | #ifndef WILC_OPTIMIZE_SLEEP_INT |
b7d1e18c | 1117 | chip_ps_state = CHIP_WAKEDUP; |
c5c77ba1 JK |
1118 | #endif |
1119 | } | |
39823a50 | 1120 | if (int_status & SLEEP_INT_EXT) |
00215dde | 1121 | wilc_sleeptimer_isr_ext(wilc, int_status); |
c5c77ba1 JK |
1122 | |
1123 | if (!(int_status & (ALL_INT_EXT))) { | |
00215dde | 1124 | wilc_unknown_isr_ext(wilc); |
c5c77ba1 | 1125 | } |
562ed3f1 | 1126 | release_bus(wilc, RELEASE_ALLOW_SLEEP); |
c5c77ba1 | 1127 | } |
750ffe9b | 1128 | EXPORT_SYMBOL_GPL(wilc_handle_isr); |
c5c77ba1 | 1129 | |
562ed3f1 | 1130 | int wilc_wlan_firmware_download(struct wilc *wilc, const u8 *buffer, u32 buffer_size) |
c5c77ba1 | 1131 | { |
fbc2fe16 CL |
1132 | u32 offset; |
1133 | u32 addr, size, size2, blksz; | |
51e825f7 | 1134 | u8 *dma_buffer; |
c5c77ba1 JK |
1135 | int ret = 0; |
1136 | ||
ffda203c | 1137 | blksz = BIT(12); |
c5c77ba1 | 1138 | |
f019b9d9 | 1139 | dma_buffer = kmalloc(blksz, GFP_KERNEL); |
a4b17197 | 1140 | if (!dma_buffer) { |
92e7d188 | 1141 | ret = -EIO; |
c5c77ba1 JK |
1142 | 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); | |
ac087c82 | 1147 | |
c5c77ba1 JK |
1148 | offset = 0; |
1149 | do { | |
1150 | memcpy(&addr, &buffer[offset], 4); | |
1151 | memcpy(&size, &buffer[offset + 4], 4); | |
9e6627ac GL |
1152 | addr = cpu_to_le32(addr); |
1153 | size = cpu_to_le32(size); | |
562ed3f1 | 1154 | acquire_bus(wilc, ACQUIRE_ONLY); |
c5c77ba1 JK |
1155 | offset += 8; |
1156 | while (((int)size) && (offset < buffer_size)) { | |
78174ada | 1157 | if (size <= blksz) |
c5c77ba1 | 1158 | size2 = size; |
78174ada | 1159 | else |
c5c77ba1 | 1160 | size2 = blksz; |
ac087c82 | 1161 | |
c5c77ba1 | 1162 | memcpy(dma_buffer, &buffer[offset], size2); |
af9ae09a | 1163 | ret = wilc->hif_func->hif_block_tx(wilc, addr, dma_buffer, |
49dcd0dd | 1164 | size2); |
c5c77ba1 JK |
1165 | if (!ret) |
1166 | break; | |
1167 | ||
1168 | addr += size2; | |
1169 | offset += size2; | |
1170 | size -= size2; | |
1171 | } | |
562ed3f1 | 1172 | release_bus(wilc, RELEASE_ONLY); |
c5c77ba1 JK |
1173 | |
1174 | if (!ret) { | |
92e7d188 | 1175 | ret = -EIO; |
c5c77ba1 JK |
1176 | 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 | ||
a18dd630 | 1184 | kfree(dma_buffer); |
c5c77ba1 JK |
1185 | |
1186 | _fail_1: | |
1187 | ||
1188 | return (ret < 0) ? ret : 0; | |
1189 | } | |
1190 | ||
562ed3f1 | 1191 | int wilc_wlan_start(struct wilc *wilc) |
c5c77ba1 | 1192 | { |
fbc2fe16 | 1193 | u32 reg = 0; |
c5c77ba1 | 1194 | int ret; |
fbc2fe16 | 1195 | u32 chipid; |
c5c77ba1 | 1196 | |
a3629a9e | 1197 | if (wilc->io_type == HIF_SDIO) { |
c5c77ba1 | 1198 | reg = 0; |
ac087c82 | 1199 | reg |= BIT(3); |
a3629a9e | 1200 | } else if (wilc->io_type == HIF_SPI) { |
c5c77ba1 JK |
1201 | reg = 1; |
1202 | } | |
562ed3f1 | 1203 | acquire_bus(wilc, ACQUIRE_ONLY); |
af9ae09a | 1204 | ret = wilc->hif_func->hif_write_reg(wilc, WILC_VMM_CORE_CFG, reg); |
c5c77ba1 JK |
1205 | if (!ret) { |
1206 | wilc_debug(N_ERR, "[wilc start]: fail write reg vmm_core_cfg...\n"); | |
562ed3f1 | 1207 | release_bus(wilc, RELEASE_ONLY); |
92e7d188 | 1208 | ret = -EIO; |
c5c77ba1 JK |
1209 | return ret; |
1210 | } | |
1211 | reg = 0; | |
a3629a9e | 1212 | if (wilc->io_type == HIF_SDIO && wilc->dev_irq_num) |
c4d139cb | 1213 | reg |= WILC_HAVE_SDIO_IRQ_GPIO; |
c5c77ba1 JK |
1214 | |
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; | |
c5c77ba1 JK |
1231 | #ifdef XTAL_24 |
1232 | reg |= WILC_HAVE_XTAL_24; | |
1233 | #endif | |
c5c77ba1 JK |
1234 | #ifdef DISABLE_WILC_UART |
1235 | reg |= WILC_HAVE_DISABLE_WILC_UART; | |
1236 | #endif | |
1237 | ||
af9ae09a | 1238 | ret = wilc->hif_func->hif_write_reg(wilc, WILC_GP_REG_1, reg); |
c5c77ba1 JK |
1239 | if (!ret) { |
1240 | wilc_debug(N_ERR, "[wilc start]: fail write WILC_GP_REG_1 ...\n"); | |
562ed3f1 | 1241 | release_bus(wilc, RELEASE_ONLY); |
92e7d188 | 1242 | ret = -EIO; |
c5c77ba1 JK |
1243 | return ret; |
1244 | } | |
c5c77ba1 | 1245 | |
af9ae09a | 1246 | wilc->hif_func->hif_sync_ext(wilc, NUM_INT_EXT); |
c5c77ba1 | 1247 | |
af9ae09a | 1248 | ret = wilc->hif_func->hif_read_reg(wilc, 0x1000, &chipid); |
c5c77ba1 JK |
1249 | if (!ret) { |
1250 | wilc_debug(N_ERR, "[wilc start]: fail read reg 0x1000 ...\n"); | |
562ed3f1 | 1251 | release_bus(wilc, RELEASE_ONLY); |
92e7d188 | 1252 | ret = -EIO; |
c5c77ba1 JK |
1253 | return ret; |
1254 | } | |
1255 | ||
af9ae09a | 1256 | wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, ®); |
ffda203c AB |
1257 | if ((reg & BIT(10)) == BIT(10)) { |
1258 | reg &= ~BIT(10); | |
af9ae09a GL |
1259 | wilc->hif_func->hif_write_reg(wilc, WILC_GLB_RESET_0, reg); |
1260 | wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, ®); | |
c5c77ba1 JK |
1261 | } |
1262 | ||
ffda203c | 1263 | reg |= BIT(10); |
af9ae09a GL |
1264 | 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, ®); | |
562ed3f1 | 1266 | release_bus(wilc, RELEASE_ONLY); |
c5c77ba1 JK |
1267 | |
1268 | return (ret < 0) ? ret : 0; | |
1269 | } | |
1270 | ||
562ed3f1 | 1271 | void wilc_wlan_global_reset(struct wilc *wilc) |
c5c77ba1 | 1272 | { |
562ed3f1 | 1273 | acquire_bus(wilc, ACQUIRE_AND_WAKEUP); |
af9ae09a | 1274 | wilc->hif_func->hif_write_reg(wilc, WILC_GLB_RESET_0, 0x0); |
562ed3f1 | 1275 | release_bus(wilc, RELEASE_ONLY); |
c5c77ba1 | 1276 | } |
562ed3f1 | 1277 | int wilc_wlan_stop(struct wilc *wilc) |
c5c77ba1 | 1278 | { |
fbc2fe16 | 1279 | u32 reg = 0; |
c5c77ba1 | 1280 | int ret; |
51e825f7 | 1281 | u8 timeout = 10; |
562ed3f1 | 1282 | acquire_bus(wilc, ACQUIRE_AND_WAKEUP); |
c5c77ba1 | 1283 | |
af9ae09a | 1284 | ret = wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, ®); |
c5c77ba1 JK |
1285 | if (!ret) { |
1286 | PRINT_ER("Error while reading reg\n"); | |
562ed3f1 | 1287 | release_bus(wilc, RELEASE_ALLOW_SLEEP); |
c5c77ba1 JK |
1288 | return ret; |
1289 | } | |
1290 | ||
ffda203c | 1291 | reg &= ~BIT(10); |
af9ae09a | 1292 | ret = wilc->hif_func->hif_write_reg(wilc, WILC_GLB_RESET_0, reg); |
c5c77ba1 JK |
1293 | if (!ret) { |
1294 | PRINT_ER("Error while writing reg\n"); | |
562ed3f1 | 1295 | release_bus(wilc, RELEASE_ALLOW_SLEEP); |
c5c77ba1 JK |
1296 | return ret; |
1297 | } | |
1298 | ||
c5c77ba1 | 1299 | do { |
af9ae09a | 1300 | ret = wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, ®); |
c5c77ba1 JK |
1301 | if (!ret) { |
1302 | PRINT_ER("Error while reading reg\n"); | |
562ed3f1 | 1303 | release_bus(wilc, RELEASE_ALLOW_SLEEP); |
c5c77ba1 JK |
1304 | return ret; |
1305 | } | |
ab12d8c7 LK |
1306 | PRINT_D(GENERIC_DBG, "Read RESET Reg %x : Retry%d\n", |
1307 | reg, timeout); | |
ac087c82 | 1308 | |
ffda203c | 1309 | if ((reg & BIT(10))) { |
ab12d8c7 LK |
1310 | PRINT_D(GENERIC_DBG, "Bit 10 not reset : Retry %d\n", |
1311 | timeout); | |
ffda203c | 1312 | reg &= ~BIT(10); |
af9ae09a | 1313 | ret = wilc->hif_func->hif_write_reg(wilc, WILC_GLB_RESET_0, |
49dcd0dd | 1314 | reg); |
c5c77ba1 JK |
1315 | timeout--; |
1316 | } else { | |
ab12d8c7 LK |
1317 | PRINT_D(GENERIC_DBG, "Bit 10 reset after : Retry %d\n", |
1318 | timeout); | |
af9ae09a | 1319 | ret = wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, |
49dcd0dd | 1320 | ®); |
c5c77ba1 JK |
1321 | if (!ret) { |
1322 | PRINT_ER("Error while reading reg\n"); | |
562ed3f1 | 1323 | release_bus(wilc, RELEASE_ALLOW_SLEEP); |
c5c77ba1 JK |
1324 | return ret; |
1325 | } | |
ab12d8c7 LK |
1326 | PRINT_D(GENERIC_DBG, "Read RESET Reg %x : Retry%d\n", |
1327 | reg, timeout); | |
c5c77ba1 JK |
1328 | break; |
1329 | } | |
1330 | ||
1331 | } while (timeout); | |
ffda203c AB |
1332 | reg = (BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(8) | BIT(9) | BIT(26) | |
1333 | BIT(29) | BIT(30) | BIT(31)); | |
65ead4ec | 1334 | |
af9ae09a | 1335 | wilc->hif_func->hif_write_reg(wilc, WILC_GLB_RESET_0, reg); |
ffda203c | 1336 | reg = (u32)~BIT(10); |
65ead4ec | 1337 | |
af9ae09a | 1338 | ret = wilc->hif_func->hif_write_reg(wilc, WILC_GLB_RESET_0, reg); |
c5c77ba1 | 1339 | |
562ed3f1 | 1340 | release_bus(wilc, RELEASE_ALLOW_SLEEP); |
c5c77ba1 JK |
1341 | |
1342 | return ret; | |
1343 | } | |
1344 | ||
2de7cbec | 1345 | void wilc_wlan_cleanup(struct net_device *dev) |
c5c77ba1 | 1346 | { |
c5c77ba1 JK |
1347 | struct txq_entry_t *tqe; |
1348 | struct rxq_entry_t *rqe; | |
fbc2fe16 | 1349 | u32 reg = 0; |
c5c77ba1 | 1350 | int ret; |
a4cac481 | 1351 | struct wilc_vif *vif; |
db387635 GL |
1352 | struct wilc *wilc; |
1353 | ||
a4cac481 GL |
1354 | vif = netdev_priv(dev); |
1355 | wilc = vif->wilc; | |
c5c77ba1 | 1356 | |
67e2a07e | 1357 | wilc->quit = 1; |
c5c77ba1 | 1358 | do { |
718fc2c9 | 1359 | tqe = wilc_wlan_txq_remove_from_head(dev); |
a4b17197 | 1360 | if (!tqe) |
c5c77ba1 JK |
1361 | break; |
1362 | if (tqe->tx_complete_func) | |
1363 | tqe->tx_complete_func(tqe->priv, 0); | |
a18dd630 | 1364 | kfree(tqe); |
c5c77ba1 JK |
1365 | } while (1); |
1366 | ||
1367 | do { | |
db387635 | 1368 | rqe = wilc_wlan_rxq_remove(wilc); |
a4b17197 | 1369 | if (!rqe) |
c5c77ba1 | 1370 | break; |
a18dd630 | 1371 | kfree(rqe); |
c5c77ba1 JK |
1372 | } while (1); |
1373 | ||
67e2a07e GL |
1374 | kfree(wilc->rx_buffer); |
1375 | wilc->rx_buffer = NULL; | |
1376 | kfree(wilc->tx_buffer); | |
608b0515 | 1377 | wilc->tx_buffer = NULL; |
c5c77ba1 | 1378 | |
562ed3f1 | 1379 | acquire_bus(wilc, ACQUIRE_AND_WAKEUP); |
c5c77ba1 | 1380 | |
af9ae09a | 1381 | ret = wilc->hif_func->hif_read_reg(wilc, WILC_GP_REG_0, ®); |
c5c77ba1 JK |
1382 | if (!ret) { |
1383 | PRINT_ER("Error while reading reg\n"); | |
562ed3f1 | 1384 | release_bus(wilc, RELEASE_ALLOW_SLEEP); |
c5c77ba1 JK |
1385 | } |
1386 | PRINT_ER("Writing ABORT reg\n"); | |
af9ae09a | 1387 | ret = wilc->hif_func->hif_write_reg(wilc, WILC_GP_REG_0, |
49dcd0dd | 1388 | (reg | ABORT_INT)); |
c5c77ba1 JK |
1389 | if (!ret) { |
1390 | PRINT_ER("Error while writing reg\n"); | |
562ed3f1 | 1391 | release_bus(wilc, RELEASE_ALLOW_SLEEP); |
c5c77ba1 | 1392 | } |
562ed3f1 | 1393 | release_bus(wilc, RELEASE_ALLOW_SLEEP); |
af9ae09a | 1394 | wilc->hif_func->hif_deinit(NULL); |
c5c77ba1 JK |
1395 | } |
1396 | ||
562ed3f1 | 1397 | static int wilc_wlan_cfg_commit(struct wilc *wilc, int type, u32 drv_handler) |
c5c77ba1 | 1398 | { |
67e2a07e GL |
1399 | 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; | |
48641679 | 1402 | int driver_handler = (u32)drv_handler; |
c5c77ba1 | 1403 | |
076ef657 | 1404 | if (type == WILC_CFG_SET) |
c5c77ba1 | 1405 | cfg->wid_header[0] = 'W'; |
076ef657 | 1406 | else |
c5c77ba1 | 1407 | cfg->wid_header[0] = 'Q'; |
ac087c82 | 1408 | cfg->wid_header[1] = seq_no; |
51e825f7 CL |
1409 | 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); | |
67e2a07e | 1415 | wilc->cfg_seq_no = seq_no; |
c5c77ba1 | 1416 | |
562ed3f1 | 1417 | if (!wilc_wlan_txq_add_cfg_pkt(wilc, &cfg->wid_header[0], total_len)) |
c5c77ba1 JK |
1418 | return -1; |
1419 | ||
1420 | return 0; | |
1421 | } | |
1422 | ||
89758e13 GL |
1423 | int wilc_wlan_cfg_set(struct wilc *wilc, int start, u32 wid, u8 *buffer, |
1424 | u32 buffer_size, int commit, u32 drv_handler) | |
c5c77ba1 | 1425 | { |
fbc2fe16 | 1426 | u32 offset; |
c5c77ba1 JK |
1427 | int ret_size; |
1428 | ||
67e2a07e | 1429 | if (wilc->cfg_frame_in_use) |
c5c77ba1 JK |
1430 | return 0; |
1431 | ||
1432 | if (start) | |
67e2a07e | 1433 | wilc->cfg_frame_offset = 0; |
c5c77ba1 | 1434 | |
67e2a07e GL |
1435 | offset = wilc->cfg_frame_offset; |
1436 | ret_size = wilc_wlan_cfg_set_wid(wilc->cfg_frame.frame, offset, | |
1437 | (u16)wid, buffer, buffer_size); | |
c5c77ba1 | 1438 | offset += ret_size; |
67e2a07e | 1439 | wilc->cfg_frame_offset = offset; |
c5c77ba1 JK |
1440 | |
1441 | if (commit) { | |
ab12d8c7 | 1442 | PRINT_D(TX_DBG, "[WILC]PACKET Commit with sequence number %d\n", |
67e2a07e | 1443 | wilc->cfg_seq_no); |
c5c77ba1 | 1444 | PRINT_D(RX_DBG, "Processing cfg_set()\n"); |
67e2a07e | 1445 | wilc->cfg_frame_in_use = 1; |
c5c77ba1 | 1446 | |
562ed3f1 | 1447 | if (wilc_wlan_cfg_commit(wilc, WILC_CFG_SET, drv_handler)) |
5af6b85b | 1448 | ret_size = 0; |
c5c77ba1 | 1449 | |
562ed3f1 | 1450 | if (wilc_lock_timeout(wilc, &wilc->cfg_event, |
b002e20d | 1451 | CFG_PKTS_TIMEOUT)) { |
c5c77ba1 JK |
1452 | PRINT_D(TX_DBG, "Set Timed Out\n"); |
1453 | ret_size = 0; | |
1454 | } | |
67e2a07e GL |
1455 | wilc->cfg_frame_in_use = 0; |
1456 | wilc->cfg_frame_offset = 0; | |
1457 | wilc->cfg_seq_no += 1; | |
c5c77ba1 JK |
1458 | } |
1459 | ||
1460 | return ret_size; | |
1461 | } | |
2d6973e6 | 1462 | |
d40c99c7 GL |
1463 | int wilc_wlan_cfg_get(struct wilc *wilc, int start, u32 wid, int commit, |
1464 | u32 drv_handler) | |
c5c77ba1 | 1465 | { |
fbc2fe16 | 1466 | u32 offset; |
c5c77ba1 JK |
1467 | int ret_size; |
1468 | ||
67e2a07e | 1469 | if (wilc->cfg_frame_in_use) |
c5c77ba1 JK |
1470 | return 0; |
1471 | ||
1472 | if (start) | |
67e2a07e | 1473 | wilc->cfg_frame_offset = 0; |
c5c77ba1 | 1474 | |
67e2a07e GL |
1475 | offset = wilc->cfg_frame_offset; |
1476 | ret_size = wilc_wlan_cfg_get_wid(wilc->cfg_frame.frame, offset, | |
1477 | (u16)wid); | |
c5c77ba1 | 1478 | offset += ret_size; |
67e2a07e | 1479 | wilc->cfg_frame_offset = offset; |
c5c77ba1 JK |
1480 | |
1481 | if (commit) { | |
67e2a07e | 1482 | wilc->cfg_frame_in_use = 1; |
c5c77ba1 | 1483 | |
562ed3f1 | 1484 | if (wilc_wlan_cfg_commit(wilc, WILC_CFG_QUERY, drv_handler)) |
5af6b85b | 1485 | ret_size = 0; |
c5c77ba1 | 1486 | |
562ed3f1 | 1487 | if (wilc_lock_timeout(wilc, &wilc->cfg_event, |
b002e20d | 1488 | CFG_PKTS_TIMEOUT)) { |
c5c77ba1 JK |
1489 | PRINT_D(TX_DBG, "Get Timed Out\n"); |
1490 | ret_size = 0; | |
1491 | } | |
1492 | PRINT_D(GENERIC_DBG, "[WILC]Get Response received\n"); | |
67e2a07e GL |
1493 | wilc->cfg_frame_in_use = 0; |
1494 | wilc->cfg_frame_offset = 0; | |
1495 | wilc->cfg_seq_no += 1; | |
c5c77ba1 JK |
1496 | } |
1497 | ||
1498 | return ret_size; | |
1499 | } | |
1500 | ||
894de36b | 1501 | int wilc_wlan_cfg_get_val(u32 wid, u8 *buffer, u32 buffer_size) |
c5c77ba1 | 1502 | { |
c5c77ba1 JK |
1503 | int ret; |
1504 | ||
355cca2a | 1505 | ret = wilc_wlan_cfg_get_wid_value((u16)wid, buffer, buffer_size); |
c5c77ba1 JK |
1506 | |
1507 | return ret; | |
1508 | } | |
1509 | ||
1608c403 | 1510 | static u32 init_chip(struct net_device *dev) |
c5c77ba1 | 1511 | { |
fbc2fe16 CL |
1512 | u32 chipid; |
1513 | u32 reg, ret = 0; | |
a4cac481 | 1514 | struct wilc_vif *vif; |
562ed3f1 AB |
1515 | struct wilc *wilc; |
1516 | ||
a4cac481 GL |
1517 | vif = netdev_priv(dev); |
1518 | wilc = vif->wilc; | |
c5c77ba1 | 1519 | |
562ed3f1 | 1520 | acquire_bus(wilc, ACQUIRE_ONLY); |
c5c77ba1 | 1521 | |
00215dde | 1522 | chipid = wilc_get_chipid(wilc, true); |
c5c77ba1 | 1523 | |
c5c77ba1 | 1524 | if ((chipid & 0xfff) != 0xa0) { |
af9ae09a | 1525 | ret = wilc->hif_func->hif_read_reg(wilc, 0x1118, ®); |
c5c77ba1 JK |
1526 | if (!ret) { |
1527 | wilc_debug(N_ERR, "[wilc start]: fail read reg 0x1118 ...\n"); | |
1528 | return ret; | |
1529 | } | |
ffda203c | 1530 | reg |= BIT(0); |
af9ae09a | 1531 | ret = wilc->hif_func->hif_write_reg(wilc, 0x1118, reg); |
c5c77ba1 JK |
1532 | if (!ret) { |
1533 | wilc_debug(N_ERR, "[wilc start]: fail write reg 0x1118 ...\n"); | |
1534 | return ret; | |
1535 | } | |
af9ae09a | 1536 | ret = wilc->hif_func->hif_write_reg(wilc, 0xc0000, 0x71); |
c5c77ba1 JK |
1537 | if (!ret) { |
1538 | wilc_debug(N_ERR, "[wilc start]: fail write reg 0xc0000 ...\n"); | |
1539 | return ret; | |
1540 | } | |
1541 | } | |
1542 | ||
562ed3f1 | 1543 | release_bus(wilc, RELEASE_ONLY); |
c5c77ba1 JK |
1544 | |
1545 | return ret; | |
c5c77ba1 JK |
1546 | } |
1547 | ||
00215dde | 1548 | u32 wilc_get_chipid(struct wilc *wilc, u8 update) |
c5c77ba1 | 1549 | { |
fbc2fe16 | 1550 | static u32 chipid; |
fbc2fe16 CL |
1551 | u32 tempchipid = 0; |
1552 | u32 rfrevid; | |
c5c77ba1 JK |
1553 | |
1554 | if (chipid == 0 || update != 0) { | |
af9ae09a GL |
1555 | wilc->hif_func->hif_read_reg(wilc, 0x1000, &tempchipid); |
1556 | wilc->hif_func->hif_read_reg(wilc, 0x13f4, &rfrevid); | |
c5c77ba1 JK |
1557 | if (!ISWILC1000(tempchipid)) { |
1558 | chipid = 0; | |
1559 | goto _fail_; | |
1560 | } | |
1561 | if (tempchipid == 0x1002a0) { | |
ac087c82 LK |
1562 | if (rfrevid == 0x1) { |
1563 | } else { | |
c5c77ba1 JK |
1564 | tempchipid = 0x1002a1; |
1565 | } | |
1566 | } else if (tempchipid == 0x1002b0) { | |
ac087c82 LK |
1567 | if (rfrevid == 3) { |
1568 | } else if (rfrevid == 4) { | |
c5c77ba1 | 1569 | tempchipid = 0x1002b1; |
ac087c82 | 1570 | } else { |
c5c77ba1 JK |
1571 | tempchipid = 0x1002b2; |
1572 | } | |
c5c77ba1 JK |
1573 | } |
1574 | ||
1575 | chipid = tempchipid; | |
1576 | } | |
1577 | _fail_: | |
1578 | return chipid; | |
1579 | } | |
1580 | ||
4bd7baf0 | 1581 | int wilc_wlan_init(struct net_device *dev) |
c5c77ba1 | 1582 | { |
c5c77ba1 | 1583 | int ret = 0; |
a4cac481 | 1584 | struct wilc_vif *vif = netdev_priv(dev); |
9c800322 GL |
1585 | struct wilc *wilc; |
1586 | ||
a4cac481 | 1587 | wilc = vif->wilc; |
c5c77ba1 JK |
1588 | |
1589 | PRINT_D(INIT_DBG, "Initializing WILC_Wlan ...\n"); | |
1590 | ||
0c94df02 GL |
1591 | wilc->quit = 0; |
1592 | ||
28b01ff5 | 1593 | if (!wilc->hif_func->hif_init(wilc)) { |
cdb99231 GL |
1594 | ret = -EIO; |
1595 | goto _fail_; | |
1596 | } | |
c5c77ba1 | 1597 | |
814bc368 | 1598 | if (!wilc_wlan_cfg_init(wilc_debug)) { |
92e7d188 | 1599 | ret = -ENOBUFS; |
c5c77ba1 JK |
1600 | goto _fail_; |
1601 | } | |
c5c77ba1 | 1602 | |
67e2a07e GL |
1603 | if (!wilc->tx_buffer) |
1604 | wilc->tx_buffer = kmalloc(LINUX_TX_SIZE, GFP_KERNEL); | |
1605 | PRINT_D(TX_DBG, "wilc->tx_buffer = %p\n", wilc->tx_buffer); | |
c5c77ba1 | 1606 | |
67e2a07e | 1607 | if (!wilc->tx_buffer) { |
92e7d188 | 1608 | ret = -ENOBUFS; |
c5c77ba1 JK |
1609 | PRINT_ER("Can't allocate Tx Buffer"); |
1610 | goto _fail_; | |
1611 | } | |
1612 | ||
67e2a07e GL |
1613 | if (!wilc->rx_buffer) |
1614 | wilc->rx_buffer = kmalloc(LINUX_RX_SIZE, GFP_KERNEL); | |
1615 | PRINT_D(TX_DBG, "wilc->rx_buffer =%p\n", wilc->rx_buffer); | |
1616 | if (!wilc->rx_buffer) { | |
92e7d188 | 1617 | ret = -ENOBUFS; |
c5c77ba1 JK |
1618 | PRINT_ER("Can't allocate Rx Buffer"); |
1619 | goto _fail_; | |
1620 | } | |
c5c77ba1 | 1621 | |
ae6f772d | 1622 | if (!init_chip(dev)) { |
92e7d188 | 1623 | ret = -EIO; |
c5c77ba1 JK |
1624 | goto _fail_; |
1625 | } | |
1626 | #ifdef TCP_ACK_FILTER | |
ef06b5f7 | 1627 | init_tcp_tracking(); |
c5c77ba1 JK |
1628 | #endif |
1629 | ||
c5c77ba1 JK |
1630 | return 1; |
1631 | ||
1632 | _fail_: | |
1633 | ||
67e2a07e GL |
1634 | kfree(wilc->rx_buffer); |
1635 | wilc->rx_buffer = NULL; | |
1636 | kfree(wilc->tx_buffer); | |
1637 | wilc->tx_buffer = NULL; | |
c5c77ba1 | 1638 | |
c5c77ba1 | 1639 | return ret; |
c5c77ba1 JK |
1640 | } |
1641 | ||
0e1af73d | 1642 | u16 wilc_set_machw_change_vir_if(struct net_device *dev, bool value) |
c5c77ba1 | 1643 | { |
d85f5326 | 1644 | u16 ret; |
4e4467fd | 1645 | u32 reg; |
a4cac481 | 1646 | struct wilc_vif *vif; |
178c383f GL |
1647 | struct wilc *wilc; |
1648 | ||
a4cac481 GL |
1649 | vif = netdev_priv(dev); |
1650 | wilc = vif->wilc; | |
c5c77ba1 | 1651 | |
178c383f | 1652 | mutex_lock(&wilc->hif_cs); |
af9ae09a | 1653 | ret = wilc->hif_func->hif_read_reg(wilc, WILC_CHANGING_VIR_IF, |
49dcd0dd | 1654 | ®); |
39823a50 | 1655 | if (!ret) |
c5c77ba1 | 1656 | PRINT_ER("Error while Reading reg WILC_CHANGING_VIR_IF\n"); |
c5c77ba1 | 1657 | |
aa313be3 | 1658 | if (value) |
50b51dac | 1659 | reg |= BIT(31); |
78174ada | 1660 | else |
50b51dac | 1661 | reg &= ~BIT(31); |
c5c77ba1 | 1662 | |
af9ae09a | 1663 | ret = wilc->hif_func->hif_write_reg(wilc, WILC_CHANGING_VIR_IF, |
49dcd0dd | 1664 | reg); |
c5c77ba1 | 1665 | |
39823a50 | 1666 | if (!ret) |
c5c77ba1 | 1667 | PRINT_ER("Error while writing reg WILC_CHANGING_VIR_IF\n"); |
39823a50 | 1668 | |
178c383f | 1669 | mutex_unlock(&wilc->hif_cs); |
c5c77ba1 JK |
1670 | |
1671 | return ret; | |
1672 | } |