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