1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
24
25#include <linux/interrupt.h>
26#include <linux/soc/qcom/smem_state.h>
27#include "wcn36xx.h"
28#include "txrx.h"
29
30void *wcn36xx_dxe_get_next_bd(struct wcn36xx *wcn, bool is_low)
31{
32 struct wcn36xx_dxe_ch *ch = is_low ?
33 &wcn->dxe_tx_l_ch :
34 &wcn->dxe_tx_h_ch;
35
36 return ch->head_blk_ctl->bd_cpu_addr;
37}
38
39static void wcn36xx_ccu_write_register(struct wcn36xx *wcn, int addr, int data)
40{
41 wcn36xx_dbg(WCN36XX_DBG_DXE,
42 "wcn36xx_ccu_write_register: addr=%x, data=%x\n",
43 addr, data);
44
45 writel(data, wcn->ccu_base + addr);
46}
47
48static void wcn36xx_dxe_write_register(struct wcn36xx *wcn, int addr, int data)
49{
50 wcn36xx_dbg(WCN36XX_DBG_DXE,
51 "wcn36xx_dxe_write_register: addr=%x, data=%x\n",
52 addr, data);
53
54 writel(data, wcn->dxe_base + addr);
55}
56
57static void wcn36xx_dxe_read_register(struct wcn36xx *wcn, int addr, int *data)
58{
59 *data = readl(wcn->dxe_base + addr);
60
61 wcn36xx_dbg(WCN36XX_DBG_DXE,
62 "wcn36xx_dxe_read_register: addr=%x, data=%x\n",
63 addr, *data);
64}
65
66static void wcn36xx_dxe_free_ctl_block(struct wcn36xx_dxe_ch *ch)
67{
68 struct wcn36xx_dxe_ctl *ctl = ch->head_blk_ctl, *next;
69 int i;
70
71 for (i = 0; i < ch->desc_num && ctl; i++) {
72 next = ctl->next;
73 kfree(ctl);
74 ctl = next;
75 }
76}
77
78static int wcn36xx_dxe_allocate_ctl_block(struct wcn36xx_dxe_ch *ch)
79{
80 struct wcn36xx_dxe_ctl *prev_ctl = NULL;
81 struct wcn36xx_dxe_ctl *cur_ctl = NULL;
82 int i;
83
84 spin_lock_init(&ch->lock);
85 for (i = 0; i < ch->desc_num; i++) {
86 cur_ctl = kzalloc(sizeof(*cur_ctl), GFP_KERNEL);
87 if (!cur_ctl)
88 goto out_fail;
89
90 spin_lock_init(&cur_ctl->skb_lock);
91 cur_ctl->ctl_blk_order = i;
92 if (i == 0) {
93 ch->head_blk_ctl = cur_ctl;
94 ch->tail_blk_ctl = cur_ctl;
95 } else if (ch->desc_num - 1 == i) {
96 prev_ctl->next = cur_ctl;
97 cur_ctl->next = ch->head_blk_ctl;
98 } else {
99 prev_ctl->next = cur_ctl;
100 }
101 prev_ctl = cur_ctl;
102 }
103
104 return 0;
105
106out_fail:
107 wcn36xx_dxe_free_ctl_block(ch);
108 return -ENOMEM;
109}
110
111int wcn36xx_dxe_alloc_ctl_blks(struct wcn36xx *wcn)
112{
113 int ret;
114
115 wcn->dxe_tx_l_ch.ch_type = WCN36XX_DXE_CH_TX_L;
116 wcn->dxe_tx_h_ch.ch_type = WCN36XX_DXE_CH_TX_H;
117 wcn->dxe_rx_l_ch.ch_type = WCN36XX_DXE_CH_RX_L;
118 wcn->dxe_rx_h_ch.ch_type = WCN36XX_DXE_CH_RX_H;
119
120 wcn->dxe_tx_l_ch.desc_num = WCN36XX_DXE_CH_DESC_NUMB_TX_L;
121 wcn->dxe_tx_h_ch.desc_num = WCN36XX_DXE_CH_DESC_NUMB_TX_H;
122 wcn->dxe_rx_l_ch.desc_num = WCN36XX_DXE_CH_DESC_NUMB_RX_L;
123 wcn->dxe_rx_h_ch.desc_num = WCN36XX_DXE_CH_DESC_NUMB_RX_H;
124
125 wcn->dxe_tx_l_ch.dxe_wq = WCN36XX_DXE_WQ_TX_L;
126 wcn->dxe_tx_h_ch.dxe_wq = WCN36XX_DXE_WQ_TX_H;
127
128 wcn->dxe_tx_l_ch.ctrl_bd = WCN36XX_DXE_CTRL_TX_L_BD;
129 wcn->dxe_tx_h_ch.ctrl_bd = WCN36XX_DXE_CTRL_TX_H_BD;
130
131 wcn->dxe_tx_l_ch.ctrl_skb = WCN36XX_DXE_CTRL_TX_L_SKB;
132 wcn->dxe_tx_h_ch.ctrl_skb = WCN36XX_DXE_CTRL_TX_H_SKB;
133
134 wcn->dxe_tx_l_ch.reg_ctrl = WCN36XX_DXE_REG_CTL_TX_L;
135 wcn->dxe_tx_h_ch.reg_ctrl = WCN36XX_DXE_REG_CTL_TX_H;
136
137 wcn->dxe_tx_l_ch.def_ctrl = WCN36XX_DXE_CH_DEFAULT_CTL_TX_L;
138 wcn->dxe_tx_h_ch.def_ctrl = WCN36XX_DXE_CH_DEFAULT_CTL_TX_H;
139
140
141 ret = wcn36xx_dxe_allocate_ctl_block(&wcn->dxe_tx_l_ch);
142 if (ret)
143 goto out_err;
144 ret = wcn36xx_dxe_allocate_ctl_block(&wcn->dxe_tx_h_ch);
145 if (ret)
146 goto out_err;
147 ret = wcn36xx_dxe_allocate_ctl_block(&wcn->dxe_rx_l_ch);
148 if (ret)
149 goto out_err;
150 ret = wcn36xx_dxe_allocate_ctl_block(&wcn->dxe_rx_h_ch);
151 if (ret)
152 goto out_err;
153
154
155 ret = qcom_smem_state_update_bits(wcn->tx_enable_state,
156 WCN36XX_SMSM_WLAN_TX_ENABLE |
157 WCN36XX_SMSM_WLAN_TX_RINGS_EMPTY,
158 WCN36XX_SMSM_WLAN_TX_RINGS_EMPTY);
159 if (ret)
160 goto out_err;
161
162 return 0;
163
164out_err:
165 wcn36xx_err("Failed to allocate DXE control blocks\n");
166 wcn36xx_dxe_free_ctl_blks(wcn);
167 return -ENOMEM;
168}
169
170void wcn36xx_dxe_free_ctl_blks(struct wcn36xx *wcn)
171{
172 wcn36xx_dxe_free_ctl_block(&wcn->dxe_tx_l_ch);
173 wcn36xx_dxe_free_ctl_block(&wcn->dxe_tx_h_ch);
174 wcn36xx_dxe_free_ctl_block(&wcn->dxe_rx_l_ch);
175 wcn36xx_dxe_free_ctl_block(&wcn->dxe_rx_h_ch);
176}
177
178static int wcn36xx_dxe_init_descs(struct device *dev, struct wcn36xx_dxe_ch *wcn_ch)
179{
180 struct wcn36xx_dxe_desc *cur_dxe = NULL;
181 struct wcn36xx_dxe_desc *prev_dxe = NULL;
182 struct wcn36xx_dxe_ctl *cur_ctl = NULL;
183 size_t size;
184 int i;
185
186 size = wcn_ch->desc_num * sizeof(struct wcn36xx_dxe_desc);
187 wcn_ch->cpu_addr = dma_alloc_coherent(dev, size, &wcn_ch->dma_addr,
188 GFP_KERNEL);
189 if (!wcn_ch->cpu_addr)
190 return -ENOMEM;
191
192 memset(wcn_ch->cpu_addr, 0, size);
193
194 cur_dxe = (struct wcn36xx_dxe_desc *)wcn_ch->cpu_addr;
195 cur_ctl = wcn_ch->head_blk_ctl;
196
197 for (i = 0; i < wcn_ch->desc_num; i++) {
198 cur_ctl->desc = cur_dxe;
199 cur_ctl->desc_phy_addr = wcn_ch->dma_addr +
200 i * sizeof(struct wcn36xx_dxe_desc);
201
202 switch (wcn_ch->ch_type) {
203 case WCN36XX_DXE_CH_TX_L:
204 cur_dxe->ctrl = WCN36XX_DXE_CTRL_TX_L;
205 cur_dxe->dst_addr_l = WCN36XX_DXE_WQ_TX_L;
206 break;
207 case WCN36XX_DXE_CH_TX_H:
208 cur_dxe->ctrl = WCN36XX_DXE_CTRL_TX_H;
209 cur_dxe->dst_addr_l = WCN36XX_DXE_WQ_TX_H;
210 break;
211 case WCN36XX_DXE_CH_RX_L:
212 cur_dxe->ctrl = WCN36XX_DXE_CTRL_RX_L;
213 cur_dxe->src_addr_l = WCN36XX_DXE_WQ_RX_L;
214 break;
215 case WCN36XX_DXE_CH_RX_H:
216 cur_dxe->ctrl = WCN36XX_DXE_CTRL_RX_H;
217 cur_dxe->src_addr_l = WCN36XX_DXE_WQ_RX_H;
218 break;
219 }
220 if (0 == i) {
221 cur_dxe->phy_next_l = 0;
222 } else if ((0 < i) && (i < wcn_ch->desc_num - 1)) {
223 prev_dxe->phy_next_l =
224 cur_ctl->desc_phy_addr;
225 } else if (i == (wcn_ch->desc_num - 1)) {
226 prev_dxe->phy_next_l =
227 cur_ctl->desc_phy_addr;
228 cur_dxe->phy_next_l =
229 wcn_ch->head_blk_ctl->desc_phy_addr;
230 }
231 cur_ctl = cur_ctl->next;
232 prev_dxe = cur_dxe;
233 cur_dxe++;
234 }
235
236 return 0;
237}
238
239static void wcn36xx_dxe_init_tx_bd(struct wcn36xx_dxe_ch *ch,
240 struct wcn36xx_dxe_mem_pool *pool)
241{
242 int i, chunk_size = pool->chunk_size;
243 dma_addr_t bd_phy_addr = pool->phy_addr;
244 void *bd_cpu_addr = pool->virt_addr;
245 struct wcn36xx_dxe_ctl *cur = ch->head_blk_ctl;
246
247 for (i = 0; i < ch->desc_num; i++) {
248
249
250 if (!(i & 1)) {
251 cur->bd_phy_addr = bd_phy_addr;
252 cur->bd_cpu_addr = bd_cpu_addr;
253 bd_phy_addr += chunk_size;
254 bd_cpu_addr += chunk_size;
255 } else {
256 cur->bd_phy_addr = 0;
257 cur->bd_cpu_addr = NULL;
258 }
259 cur = cur->next;
260 }
261}
262
263static int wcn36xx_dxe_enable_ch_int(struct wcn36xx *wcn, u16 wcn_ch)
264{
265 int reg_data = 0;
266
267 wcn36xx_dxe_read_register(wcn,
268 WCN36XX_DXE_INT_MASK_REG,
269 ®_data);
270
271 reg_data |= wcn_ch;
272
273 wcn36xx_dxe_write_register(wcn,
274 WCN36XX_DXE_INT_MASK_REG,
275 (int)reg_data);
276 return 0;
277}
278
279static int wcn36xx_dxe_fill_skb(struct device *dev, struct wcn36xx_dxe_ctl *ctl)
280{
281 struct wcn36xx_dxe_desc *dxe = ctl->desc;
282 struct sk_buff *skb;
283
284 skb = alloc_skb(WCN36XX_PKT_SIZE, GFP_ATOMIC);
285 if (skb == NULL)
286 return -ENOMEM;
287
288 dxe->dst_addr_l = dma_map_single(dev,
289 skb_tail_pointer(skb),
290 WCN36XX_PKT_SIZE,
291 DMA_FROM_DEVICE);
292 ctl->skb = skb;
293
294 return 0;
295}
296
297static int wcn36xx_dxe_ch_alloc_skb(struct wcn36xx *wcn,
298 struct wcn36xx_dxe_ch *wcn_ch)
299{
300 int i;
301 struct wcn36xx_dxe_ctl *cur_ctl = NULL;
302
303 cur_ctl = wcn_ch->head_blk_ctl;
304
305 for (i = 0; i < wcn_ch->desc_num; i++) {
306 wcn36xx_dxe_fill_skb(wcn->dev, cur_ctl);
307 cur_ctl = cur_ctl->next;
308 }
309
310 return 0;
311}
312
313static void wcn36xx_dxe_ch_free_skbs(struct wcn36xx *wcn,
314 struct wcn36xx_dxe_ch *wcn_ch)
315{
316 struct wcn36xx_dxe_ctl *cur = wcn_ch->head_blk_ctl;
317 int i;
318
319 for (i = 0; i < wcn_ch->desc_num; i++) {
320 kfree_skb(cur->skb);
321 cur = cur->next;
322 }
323}
324
325void wcn36xx_dxe_tx_ack_ind(struct wcn36xx *wcn, u32 status)
326{
327 struct ieee80211_tx_info *info;
328 struct sk_buff *skb;
329 unsigned long flags;
330
331 spin_lock_irqsave(&wcn->dxe_lock, flags);
332 skb = wcn->tx_ack_skb;
333 wcn->tx_ack_skb = NULL;
334 spin_unlock_irqrestore(&wcn->dxe_lock, flags);
335
336 if (!skb) {
337 wcn36xx_warn("Spurious TX complete indication\n");
338 return;
339 }
340
341 info = IEEE80211_SKB_CB(skb);
342
343 if (status == 1)
344 info->flags |= IEEE80211_TX_STAT_ACK;
345
346 wcn36xx_dbg(WCN36XX_DBG_DXE, "dxe tx ack status: %d\n", status);
347
348 ieee80211_tx_status_irqsafe(wcn->hw, skb);
349 ieee80211_wake_queues(wcn->hw);
350}
351
352static void reap_tx_dxes(struct wcn36xx *wcn, struct wcn36xx_dxe_ch *ch)
353{
354 struct wcn36xx_dxe_ctl *ctl;
355 struct ieee80211_tx_info *info;
356 unsigned long flags;
357
358
359
360
361
362
363 spin_lock_irqsave(&ch->lock, flags);
364 ctl = ch->tail_blk_ctl;
365 do {
366 if (ctl->desc->ctrl & WCN36XX_DXE_CTRL_VALID_MASK)
367 break;
368 if (ctl->skb) {
369 dma_unmap_single(wcn->dev, ctl->desc->src_addr_l,
370 ctl->skb->len, DMA_TO_DEVICE);
371 info = IEEE80211_SKB_CB(ctl->skb);
372 if (!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)) {
373
374 ieee80211_free_txskb(wcn->hw, ctl->skb);
375 }
376 spin_lock(&ctl->skb_lock);
377 if (wcn->queues_stopped) {
378 wcn->queues_stopped = false;
379 ieee80211_wake_queues(wcn->hw);
380 }
381 spin_unlock(&ctl->skb_lock);
382
383 ctl->skb = NULL;
384 }
385 ctl = ctl->next;
386 } while (ctl != ch->head_blk_ctl &&
387 !(ctl->desc->ctrl & WCN36XX_DXE_CTRL_VALID_MASK));
388
389 ch->tail_blk_ctl = ctl;
390 spin_unlock_irqrestore(&ch->lock, flags);
391}
392
393static irqreturn_t wcn36xx_irq_tx_complete(int irq, void *dev)
394{
395 struct wcn36xx *wcn = (struct wcn36xx *)dev;
396 int int_src, int_reason;
397
398 wcn36xx_dxe_read_register(wcn, WCN36XX_DXE_INT_SRC_RAW_REG, &int_src);
399
400 if (int_src & WCN36XX_INT_MASK_CHAN_TX_H) {
401 wcn36xx_dxe_read_register(wcn,
402 WCN36XX_DXE_CH_STATUS_REG_ADDR_TX_H,
403 &int_reason);
404
405
406
407 wcn36xx_dxe_write_register(wcn,
408 WCN36XX_DXE_0_INT_CLR,
409 WCN36XX_INT_MASK_CHAN_TX_H);
410
411 wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_0_INT_ED_CLR,
412 WCN36XX_INT_MASK_CHAN_TX_H);
413 wcn36xx_dbg(WCN36XX_DBG_DXE, "dxe tx ready high\n");
414 reap_tx_dxes(wcn, &wcn->dxe_tx_h_ch);
415 }
416
417 if (int_src & WCN36XX_INT_MASK_CHAN_TX_L) {
418 wcn36xx_dxe_read_register(wcn,
419 WCN36XX_DXE_CH_STATUS_REG_ADDR_TX_L,
420 &int_reason);
421
422
423 wcn36xx_dxe_write_register(wcn,
424 WCN36XX_DXE_0_INT_CLR,
425 WCN36XX_INT_MASK_CHAN_TX_L);
426
427 wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_0_INT_ED_CLR,
428 WCN36XX_INT_MASK_CHAN_TX_L);
429 wcn36xx_dbg(WCN36XX_DBG_DXE, "dxe tx ready low\n");
430 reap_tx_dxes(wcn, &wcn->dxe_tx_l_ch);
431 }
432
433 return IRQ_HANDLED;
434}
435
436static irqreturn_t wcn36xx_irq_rx_ready(int irq, void *dev)
437{
438 struct wcn36xx *wcn = (struct wcn36xx *)dev;
439
440 disable_irq_nosync(wcn->rx_irq);
441 wcn36xx_dxe_rx_frame(wcn);
442 enable_irq(wcn->rx_irq);
443 return IRQ_HANDLED;
444}
445
446static int wcn36xx_dxe_request_irqs(struct wcn36xx *wcn)
447{
448 int ret;
449
450 ret = request_irq(wcn->tx_irq, wcn36xx_irq_tx_complete,
451 IRQF_TRIGGER_HIGH, "wcn36xx_tx", wcn);
452 if (ret) {
453 wcn36xx_err("failed to alloc tx irq\n");
454 goto out_err;
455 }
456
457 ret = request_irq(wcn->rx_irq, wcn36xx_irq_rx_ready, IRQF_TRIGGER_HIGH,
458 "wcn36xx_rx", wcn);
459 if (ret) {
460 wcn36xx_err("failed to alloc rx irq\n");
461 goto out_txirq;
462 }
463
464 enable_irq_wake(wcn->rx_irq);
465
466 return 0;
467
468out_txirq:
469 free_irq(wcn->tx_irq, wcn);
470out_err:
471 return ret;
472
473}
474
475static int wcn36xx_rx_handle_packets(struct wcn36xx *wcn,
476 struct wcn36xx_dxe_ch *ch)
477{
478 struct wcn36xx_dxe_ctl *ctl = ch->head_blk_ctl;
479 struct wcn36xx_dxe_desc *dxe = ctl->desc;
480 dma_addr_t dma_addr;
481 struct sk_buff *skb;
482 int ret = 0, int_mask;
483 u32 value;
484
485 if (ch->ch_type == WCN36XX_DXE_CH_RX_L) {
486 value = WCN36XX_DXE_CTRL_RX_L;
487 int_mask = WCN36XX_DXE_INT_CH1_MASK;
488 } else {
489 value = WCN36XX_DXE_CTRL_RX_H;
490 int_mask = WCN36XX_DXE_INT_CH3_MASK;
491 }
492
493 while (!(dxe->ctrl & WCN36XX_DXE_CTRL_VALID_MASK)) {
494 skb = ctl->skb;
495 dma_addr = dxe->dst_addr_l;
496 ret = wcn36xx_dxe_fill_skb(wcn->dev, ctl);
497 if (0 == ret) {
498
499
500
501 dma_unmap_single(wcn->dev, dma_addr, WCN36XX_PKT_SIZE,
502 DMA_FROM_DEVICE);
503 wcn36xx_rx_skb(wcn, skb);
504 }
505
506 dxe->ctrl = value;
507 ctl = ctl->next;
508 dxe = ctl->desc;
509 }
510 wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_ENCH_ADDR, int_mask);
511
512 ch->head_blk_ctl = ctl;
513 return 0;
514}
515
516void wcn36xx_dxe_rx_frame(struct wcn36xx *wcn)
517{
518 int int_src;
519
520 wcn36xx_dxe_read_register(wcn, WCN36XX_DXE_INT_SRC_RAW_REG, &int_src);
521
522
523 if (int_src & WCN36XX_DXE_INT_CH1_MASK) {
524 wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_0_INT_CLR,
525 WCN36XX_DXE_INT_CH1_MASK);
526 wcn36xx_rx_handle_packets(wcn, &(wcn->dxe_rx_l_ch));
527 }
528
529
530 if (int_src & WCN36XX_DXE_INT_CH3_MASK) {
531
532 wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_0_INT_CLR,
533 WCN36XX_DXE_INT_CH3_MASK);
534 wcn36xx_rx_handle_packets(wcn, &(wcn->dxe_rx_h_ch));
535 }
536
537 if (!int_src)
538 wcn36xx_warn("No DXE interrupt pending\n");
539}
540
541int wcn36xx_dxe_allocate_mem_pools(struct wcn36xx *wcn)
542{
543 size_t s;
544 void *cpu_addr;
545
546
547
548
549 wcn->mgmt_mem_pool.chunk_size = WCN36XX_BD_CHUNK_SIZE +
550 16 - (WCN36XX_BD_CHUNK_SIZE % 8);
551
552 s = wcn->mgmt_mem_pool.chunk_size * WCN36XX_DXE_CH_DESC_NUMB_TX_H;
553 cpu_addr = dma_alloc_coherent(wcn->dev, s, &wcn->mgmt_mem_pool.phy_addr,
554 GFP_KERNEL);
555 if (!cpu_addr)
556 goto out_err;
557
558 wcn->mgmt_mem_pool.virt_addr = cpu_addr;
559 memset(cpu_addr, 0, s);
560
561
562
563
564 wcn->data_mem_pool.chunk_size = WCN36XX_BD_CHUNK_SIZE +
565 16 - (WCN36XX_BD_CHUNK_SIZE % 8);
566
567 s = wcn->data_mem_pool.chunk_size * WCN36XX_DXE_CH_DESC_NUMB_TX_L;
568 cpu_addr = dma_alloc_coherent(wcn->dev, s, &wcn->data_mem_pool.phy_addr,
569 GFP_KERNEL);
570 if (!cpu_addr)
571 goto out_err;
572
573 wcn->data_mem_pool.virt_addr = cpu_addr;
574 memset(cpu_addr, 0, s);
575
576 return 0;
577
578out_err:
579 wcn36xx_dxe_free_mem_pools(wcn);
580 wcn36xx_err("Failed to allocate BD mempool\n");
581 return -ENOMEM;
582}
583
584void wcn36xx_dxe_free_mem_pools(struct wcn36xx *wcn)
585{
586 if (wcn->mgmt_mem_pool.virt_addr)
587 dma_free_coherent(wcn->dev, wcn->mgmt_mem_pool.chunk_size *
588 WCN36XX_DXE_CH_DESC_NUMB_TX_H,
589 wcn->mgmt_mem_pool.virt_addr,
590 wcn->mgmt_mem_pool.phy_addr);
591
592 if (wcn->data_mem_pool.virt_addr) {
593 dma_free_coherent(wcn->dev, wcn->data_mem_pool.chunk_size *
594 WCN36XX_DXE_CH_DESC_NUMB_TX_L,
595 wcn->data_mem_pool.virt_addr,
596 wcn->data_mem_pool.phy_addr);
597 }
598}
599
600int wcn36xx_dxe_tx_frame(struct wcn36xx *wcn,
601 struct wcn36xx_vif *vif_priv,
602 struct sk_buff *skb,
603 bool is_low)
604{
605 struct wcn36xx_dxe_ctl *ctl = NULL;
606 struct wcn36xx_dxe_desc *desc = NULL;
607 struct wcn36xx_dxe_ch *ch = NULL;
608 unsigned long flags;
609 int ret;
610
611 ch = is_low ? &wcn->dxe_tx_l_ch : &wcn->dxe_tx_h_ch;
612
613 spin_lock_irqsave(&ch->lock, flags);
614 ctl = ch->head_blk_ctl;
615
616 spin_lock(&ctl->next->skb_lock);
617
618
619
620
621
622
623 if (NULL != ctl->next->skb) {
624 ieee80211_stop_queues(wcn->hw);
625 wcn->queues_stopped = true;
626 spin_unlock(&ctl->next->skb_lock);
627 spin_unlock_irqrestore(&ch->lock, flags);
628 return -EBUSY;
629 }
630 spin_unlock(&ctl->next->skb_lock);
631
632 ctl->skb = NULL;
633 desc = ctl->desc;
634
635
636 desc->src_addr_l = ctl->bd_phy_addr;
637
638 desc->dst_addr_l = ch->dxe_wq;
639 desc->fr_len = sizeof(struct wcn36xx_tx_bd);
640 desc->ctrl = ch->ctrl_bd;
641
642 wcn36xx_dbg(WCN36XX_DBG_DXE, "DXE TX\n");
643
644 wcn36xx_dbg_dump(WCN36XX_DBG_DXE_DUMP, "DESC1 >>> ",
645 (char *)desc, sizeof(*desc));
646 wcn36xx_dbg_dump(WCN36XX_DBG_DXE_DUMP,
647 "BD >>> ", (char *)ctl->bd_cpu_addr,
648 sizeof(struct wcn36xx_tx_bd));
649
650
651 ctl = ctl->next;
652 ctl->skb = skb;
653 desc = ctl->desc;
654 if (ctl->bd_cpu_addr) {
655 wcn36xx_err("bd_cpu_addr cannot be NULL for skb DXE\n");
656 ret = -EINVAL;
657 goto unlock;
658 }
659
660 desc->src_addr_l = dma_map_single(wcn->dev,
661 ctl->skb->data,
662 ctl->skb->len,
663 DMA_TO_DEVICE);
664
665 desc->dst_addr_l = ch->dxe_wq;
666 desc->fr_len = ctl->skb->len;
667
668
669 desc->ctrl = ch->ctrl_skb;
670
671 wcn36xx_dbg_dump(WCN36XX_DBG_DXE_DUMP, "DESC2 >>> ",
672 (char *)desc, sizeof(*desc));
673 wcn36xx_dbg_dump(WCN36XX_DBG_DXE_DUMP, "SKB >>> ",
674 (char *)ctl->skb->data, ctl->skb->len);
675
676
677 ch->head_blk_ctl = ctl->next;
678
679
680
681
682
683
684 if (is_low && vif_priv->pw_state == WCN36XX_BMPS) {
685 qcom_smem_state_update_bits(wcn->tx_rings_empty_state,
686 WCN36XX_SMSM_WLAN_TX_ENABLE,
687 WCN36XX_SMSM_WLAN_TX_ENABLE);
688 } else {
689
690
691
692 wcn36xx_dxe_write_register(wcn,
693 ch->reg_ctrl, ch->def_ctrl);
694 }
695
696 ret = 0;
697unlock:
698 spin_unlock_irqrestore(&ch->lock, flags);
699 return ret;
700}
701
702int wcn36xx_dxe_init(struct wcn36xx *wcn)
703{
704 int reg_data = 0, ret;
705
706 reg_data = WCN36XX_DXE_REG_RESET;
707 wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_REG_CSR_RESET, reg_data);
708
709
710 reg_data = (WCN36XX_DXE_INT_CH3_MASK | WCN36XX_DXE_INT_CH1_MASK) << 16 |
711 WCN36XX_DXE_INT_CH0_MASK | WCN36XX_DXE_INT_CH4_MASK;
712 if (wcn->is_pronto)
713 wcn36xx_ccu_write_register(wcn, WCN36XX_CCU_DXE_INT_SELECT_PRONTO, reg_data);
714 else
715 wcn36xx_ccu_write_register(wcn, WCN36XX_CCU_DXE_INT_SELECT_RIVA, reg_data);
716
717
718
719
720 wcn36xx_dxe_init_descs(wcn->dev, &wcn->dxe_tx_l_ch);
721 wcn36xx_dxe_init_tx_bd(&wcn->dxe_tx_l_ch, &wcn->data_mem_pool);
722
723
724 wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_CH_NEXT_DESC_ADDR_TX_L,
725 wcn->dxe_tx_l_ch.head_blk_ctl->desc_phy_addr);
726
727
728 wcn36xx_dxe_write_register(wcn,
729 WCN36XX_DXE_CH_DEST_ADDR_TX_L,
730 WCN36XX_DXE_WQ_TX_L);
731
732 wcn36xx_dxe_read_register(wcn, WCN36XX_DXE_REG_CH_EN, ®_data);
733 wcn36xx_dxe_enable_ch_int(wcn, WCN36XX_INT_MASK_CHAN_TX_L);
734
735
736
737
738 wcn36xx_dxe_init_descs(wcn->dev, &wcn->dxe_tx_h_ch);
739 wcn36xx_dxe_init_tx_bd(&wcn->dxe_tx_h_ch, &wcn->mgmt_mem_pool);
740
741
742 wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_CH_NEXT_DESC_ADDR_TX_H,
743 wcn->dxe_tx_h_ch.head_blk_ctl->desc_phy_addr);
744
745
746 wcn36xx_dxe_write_register(wcn,
747 WCN36XX_DXE_CH_DEST_ADDR_TX_H,
748 WCN36XX_DXE_WQ_TX_H);
749
750 wcn36xx_dxe_read_register(wcn, WCN36XX_DXE_REG_CH_EN, ®_data);
751
752
753 wcn36xx_dxe_enable_ch_int(wcn, WCN36XX_INT_MASK_CHAN_TX_H);
754
755
756
757
758 wcn36xx_dxe_init_descs(wcn->dev, &wcn->dxe_rx_l_ch);
759
760
761 wcn36xx_dxe_ch_alloc_skb(wcn, &wcn->dxe_rx_l_ch);
762
763
764 wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_CH_NEXT_DESC_ADDR_RX_L,
765 wcn->dxe_rx_l_ch.head_blk_ctl->desc_phy_addr);
766
767
768 wcn36xx_dxe_write_register(wcn,
769 WCN36XX_DXE_CH_SRC_ADDR_RX_L,
770 WCN36XX_DXE_WQ_RX_L);
771
772
773 wcn36xx_dxe_write_register(wcn,
774 WCN36XX_DXE_CH_DEST_ADDR_RX_L,
775 wcn->dxe_rx_l_ch.head_blk_ctl->desc->phy_next_l);
776
777
778 wcn36xx_dxe_write_register(wcn,
779 WCN36XX_DXE_REG_CTL_RX_L,
780 WCN36XX_DXE_CH_DEFAULT_CTL_RX_L);
781
782
783 wcn36xx_dxe_enable_ch_int(wcn, WCN36XX_INT_MASK_CHAN_RX_L);
784
785
786
787
788 wcn36xx_dxe_init_descs(wcn->dev, &wcn->dxe_rx_h_ch);
789
790
791 wcn36xx_dxe_ch_alloc_skb(wcn, &wcn->dxe_rx_h_ch);
792
793
794 wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_CH_NEXT_DESC_ADDR_RX_H,
795 wcn->dxe_rx_h_ch.head_blk_ctl->desc_phy_addr);
796
797
798 wcn36xx_dxe_write_register(wcn,
799 WCN36XX_DXE_CH_SRC_ADDR_RX_H,
800 WCN36XX_DXE_WQ_RX_H);
801
802
803 wcn36xx_dxe_write_register(wcn,
804 WCN36XX_DXE_CH_DEST_ADDR_RX_H,
805 wcn->dxe_rx_h_ch.head_blk_ctl->desc->phy_next_l);
806
807
808 wcn36xx_dxe_write_register(wcn,
809 WCN36XX_DXE_REG_CTL_RX_H,
810 WCN36XX_DXE_CH_DEFAULT_CTL_RX_H);
811
812
813 wcn36xx_dxe_enable_ch_int(wcn, WCN36XX_INT_MASK_CHAN_RX_H);
814
815 ret = wcn36xx_dxe_request_irqs(wcn);
816 if (ret < 0)
817 goto out_err;
818
819 return 0;
820
821out_err:
822 return ret;
823}
824
825void wcn36xx_dxe_deinit(struct wcn36xx *wcn)
826{
827 free_irq(wcn->tx_irq, wcn);
828 free_irq(wcn->rx_irq, wcn);
829
830 if (wcn->tx_ack_skb) {
831 ieee80211_tx_status_irqsafe(wcn->hw, wcn->tx_ack_skb);
832 wcn->tx_ack_skb = NULL;
833 }
834
835 wcn36xx_dxe_ch_free_skbs(wcn, &wcn->dxe_rx_l_ch);
836 wcn36xx_dxe_ch_free_skbs(wcn, &wcn->dxe_rx_h_ch);
837}
838