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