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