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