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