| .. | .. |
|---|
| 179 | 179 | if (!wcn_ch->cpu_addr) |
|---|
| 180 | 180 | return -ENOMEM; |
|---|
| 181 | 181 | |
|---|
| 182 | | - memset(wcn_ch->cpu_addr, 0, size); |
|---|
| 183 | | - |
|---|
| 184 | 182 | cur_dxe = (struct wcn36xx_dxe_desc *)wcn_ch->cpu_addr; |
|---|
| 185 | 183 | cur_ctl = wcn_ch->head_blk_ctl; |
|---|
| 186 | 184 | |
|---|
| .. | .. |
|---|
| 274 | 272 | return 0; |
|---|
| 275 | 273 | } |
|---|
| 276 | 274 | |
|---|
| 275 | +static void wcn36xx_dxe_disable_ch_int(struct wcn36xx *wcn, u16 wcn_ch) |
|---|
| 276 | +{ |
|---|
| 277 | + int reg_data = 0; |
|---|
| 278 | + |
|---|
| 279 | + wcn36xx_dxe_read_register(wcn, |
|---|
| 280 | + WCN36XX_DXE_INT_MASK_REG, |
|---|
| 281 | + ®_data); |
|---|
| 282 | + |
|---|
| 283 | + reg_data &= ~wcn_ch; |
|---|
| 284 | + |
|---|
| 285 | + wcn36xx_dxe_write_register(wcn, |
|---|
| 286 | + WCN36XX_DXE_INT_MASK_REG, |
|---|
| 287 | + (int)reg_data); |
|---|
| 288 | +} |
|---|
| 289 | + |
|---|
| 277 | 290 | static int wcn36xx_dxe_fill_skb(struct device *dev, |
|---|
| 278 | 291 | struct wcn36xx_dxe_ctl *ctl, |
|---|
| 279 | 292 | gfp_t gfp) |
|---|
| .. | .. |
|---|
| 336 | 349 | spin_lock_irqsave(&wcn->dxe_lock, flags); |
|---|
| 337 | 350 | skb = wcn->tx_ack_skb; |
|---|
| 338 | 351 | wcn->tx_ack_skb = NULL; |
|---|
| 352 | + del_timer(&wcn->tx_ack_timer); |
|---|
| 339 | 353 | spin_unlock_irqrestore(&wcn->dxe_lock, flags); |
|---|
| 340 | 354 | |
|---|
| 341 | 355 | if (!skb) { |
|---|
| .. | .. |
|---|
| 347 | 361 | |
|---|
| 348 | 362 | if (status == 1) |
|---|
| 349 | 363 | info->flags |= IEEE80211_TX_STAT_ACK; |
|---|
| 364 | + else |
|---|
| 365 | + info->flags &= ~IEEE80211_TX_STAT_ACK; |
|---|
| 350 | 366 | |
|---|
| 351 | 367 | wcn36xx_dbg(WCN36XX_DBG_DXE, "dxe tx ack status: %d\n", status); |
|---|
| 368 | + |
|---|
| 369 | + ieee80211_tx_status_irqsafe(wcn->hw, skb); |
|---|
| 370 | + ieee80211_wake_queues(wcn->hw); |
|---|
| 371 | +} |
|---|
| 372 | + |
|---|
| 373 | +static void wcn36xx_dxe_tx_timer(struct timer_list *t) |
|---|
| 374 | +{ |
|---|
| 375 | + struct wcn36xx *wcn = from_timer(wcn, t, tx_ack_timer); |
|---|
| 376 | + struct ieee80211_tx_info *info; |
|---|
| 377 | + unsigned long flags; |
|---|
| 378 | + struct sk_buff *skb; |
|---|
| 379 | + |
|---|
| 380 | + /* TX Timeout */ |
|---|
| 381 | + wcn36xx_dbg(WCN36XX_DBG_DXE, "TX timeout\n"); |
|---|
| 382 | + |
|---|
| 383 | + spin_lock_irqsave(&wcn->dxe_lock, flags); |
|---|
| 384 | + skb = wcn->tx_ack_skb; |
|---|
| 385 | + wcn->tx_ack_skb = NULL; |
|---|
| 386 | + spin_unlock_irqrestore(&wcn->dxe_lock, flags); |
|---|
| 387 | + |
|---|
| 388 | + if (!skb) |
|---|
| 389 | + return; |
|---|
| 390 | + |
|---|
| 391 | + info = IEEE80211_SKB_CB(skb); |
|---|
| 392 | + info->flags &= ~IEEE80211_TX_STAT_ACK; |
|---|
| 393 | + info->flags &= ~IEEE80211_TX_STAT_NOACK_TRANSMITTED; |
|---|
| 352 | 394 | |
|---|
| 353 | 395 | ieee80211_tx_status_irqsafe(wcn->hw, skb); |
|---|
| 354 | 396 | ieee80211_wake_queues(wcn->hw); |
|---|
| .. | .. |
|---|
| 376 | 418 | dma_unmap_single(wcn->dev, ctl->desc->src_addr_l, |
|---|
| 377 | 419 | ctl->skb->len, DMA_TO_DEVICE); |
|---|
| 378 | 420 | info = IEEE80211_SKB_CB(ctl->skb); |
|---|
| 379 | | - if (!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)) { |
|---|
| 380 | | - /* Keep frame until TX status comes */ |
|---|
| 421 | + if (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) { |
|---|
| 422 | + if (info->flags & IEEE80211_TX_CTL_NO_ACK) { |
|---|
| 423 | + info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; |
|---|
| 424 | + ieee80211_tx_status_irqsafe(wcn->hw, ctl->skb); |
|---|
| 425 | + } else { |
|---|
| 426 | + /* Wait for the TX ack indication or timeout... */ |
|---|
| 427 | + spin_lock(&wcn->dxe_lock); |
|---|
| 428 | + if (WARN_ON(wcn->tx_ack_skb)) |
|---|
| 429 | + ieee80211_free_txskb(wcn->hw, wcn->tx_ack_skb); |
|---|
| 430 | + wcn->tx_ack_skb = ctl->skb; /* Tracking ref */ |
|---|
| 431 | + mod_timer(&wcn->tx_ack_timer, jiffies + HZ / 10); |
|---|
| 432 | + spin_unlock(&wcn->dxe_lock); |
|---|
| 433 | + } |
|---|
| 434 | + /* do not free, ownership transferred to mac80211 status cb */ |
|---|
| 435 | + } else { |
|---|
| 381 | 436 | ieee80211_free_txskb(wcn->hw, ctl->skb); |
|---|
| 382 | 437 | } |
|---|
| 383 | 438 | |
|---|
| .. | .. |
|---|
| 436 | 491 | int_reason); |
|---|
| 437 | 492 | |
|---|
| 438 | 493 | if (int_reason & (WCN36XX_CH_STAT_INT_DONE_MASK | |
|---|
| 439 | | - WCN36XX_CH_STAT_INT_ED_MASK)) |
|---|
| 494 | + WCN36XX_CH_STAT_INT_ED_MASK)) { |
|---|
| 440 | 495 | reap_tx_dxes(wcn, &wcn->dxe_tx_h_ch); |
|---|
| 496 | + } |
|---|
| 441 | 497 | } |
|---|
| 442 | 498 | |
|---|
| 443 | 499 | if (int_src & WCN36XX_INT_MASK_CHAN_TX_L) { |
|---|
| .. | .. |
|---|
| 448 | 504 | wcn36xx_dxe_write_register(wcn, |
|---|
| 449 | 505 | WCN36XX_DXE_0_INT_CLR, |
|---|
| 450 | 506 | WCN36XX_INT_MASK_CHAN_TX_L); |
|---|
| 451 | | - |
|---|
| 452 | 507 | |
|---|
| 453 | 508 | if (int_reason & WCN36XX_CH_STAT_INT_ERR_MASK ) { |
|---|
| 454 | 509 | wcn36xx_dxe_write_register(wcn, |
|---|
| .. | .. |
|---|
| 475 | 530 | int_reason); |
|---|
| 476 | 531 | |
|---|
| 477 | 532 | if (int_reason & (WCN36XX_CH_STAT_INT_DONE_MASK | |
|---|
| 478 | | - WCN36XX_CH_STAT_INT_ED_MASK)) |
|---|
| 533 | + WCN36XX_CH_STAT_INT_ED_MASK)) { |
|---|
| 479 | 534 | reap_tx_dxes(wcn, &wcn->dxe_tx_l_ch); |
|---|
| 535 | + } |
|---|
| 480 | 536 | } |
|---|
| 481 | 537 | |
|---|
| 482 | 538 | return IRQ_HANDLED; |
|---|
| .. | .. |
|---|
| 638 | 694 | 16 - (WCN36XX_BD_CHUNK_SIZE % 8); |
|---|
| 639 | 695 | |
|---|
| 640 | 696 | s = wcn->mgmt_mem_pool.chunk_size * WCN36XX_DXE_CH_DESC_NUMB_TX_H; |
|---|
| 641 | | - cpu_addr = dma_alloc_coherent(wcn->dev, s, &wcn->mgmt_mem_pool.phy_addr, |
|---|
| 697 | + cpu_addr = dma_alloc_coherent(wcn->dev, s, |
|---|
| 698 | + &wcn->mgmt_mem_pool.phy_addr, |
|---|
| 642 | 699 | GFP_KERNEL); |
|---|
| 643 | 700 | if (!cpu_addr) |
|---|
| 644 | 701 | goto out_err; |
|---|
| 645 | 702 | |
|---|
| 646 | 703 | wcn->mgmt_mem_pool.virt_addr = cpu_addr; |
|---|
| 647 | | - memset(cpu_addr, 0, s); |
|---|
| 648 | 704 | |
|---|
| 649 | 705 | /* Allocate BD headers for DATA frames */ |
|---|
| 650 | 706 | |
|---|
| .. | .. |
|---|
| 653 | 709 | 16 - (WCN36XX_BD_CHUNK_SIZE % 8); |
|---|
| 654 | 710 | |
|---|
| 655 | 711 | s = wcn->data_mem_pool.chunk_size * WCN36XX_DXE_CH_DESC_NUMB_TX_L; |
|---|
| 656 | | - cpu_addr = dma_alloc_coherent(wcn->dev, s, &wcn->data_mem_pool.phy_addr, |
|---|
| 712 | + cpu_addr = dma_alloc_coherent(wcn->dev, s, |
|---|
| 713 | + &wcn->data_mem_pool.phy_addr, |
|---|
| 657 | 714 | GFP_KERNEL); |
|---|
| 658 | 715 | if (!cpu_addr) |
|---|
| 659 | 716 | goto out_err; |
|---|
| 660 | 717 | |
|---|
| 661 | 718 | wcn->data_mem_pool.virt_addr = cpu_addr; |
|---|
| 662 | | - memset(cpu_addr, 0, s); |
|---|
| 663 | 719 | |
|---|
| 664 | 720 | return 0; |
|---|
| 665 | 721 | |
|---|
| .. | .. |
|---|
| 828 | 884 | WCN36XX_DXE_WQ_TX_L); |
|---|
| 829 | 885 | |
|---|
| 830 | 886 | wcn36xx_dxe_read_register(wcn, WCN36XX_DXE_REG_CH_EN, ®_data); |
|---|
| 831 | | - wcn36xx_dxe_enable_ch_int(wcn, WCN36XX_INT_MASK_CHAN_TX_L); |
|---|
| 832 | 887 | |
|---|
| 833 | 888 | /***************************************/ |
|---|
| 834 | 889 | /* Init descriptors for TX HIGH channel */ |
|---|
| .. | .. |
|---|
| 852 | 907 | |
|---|
| 853 | 908 | wcn36xx_dxe_read_register(wcn, WCN36XX_DXE_REG_CH_EN, ®_data); |
|---|
| 854 | 909 | |
|---|
| 855 | | - /* Enable channel interrupts */ |
|---|
| 856 | | - wcn36xx_dxe_enable_ch_int(wcn, WCN36XX_INT_MASK_CHAN_TX_H); |
|---|
| 857 | | - |
|---|
| 858 | 910 | /***************************************/ |
|---|
| 859 | 911 | /* Init descriptors for RX LOW channel */ |
|---|
| 860 | 912 | /***************************************/ |
|---|
| .. | .. |
|---|
| 863 | 915 | dev_err(wcn->dev, "Error allocating descriptor\n"); |
|---|
| 864 | 916 | goto out_err_rxl_ch; |
|---|
| 865 | 917 | } |
|---|
| 866 | | - |
|---|
| 867 | 918 | |
|---|
| 868 | 919 | /* For RX we need to preallocated buffers */ |
|---|
| 869 | 920 | wcn36xx_dxe_ch_alloc_skb(wcn, &wcn->dxe_rx_l_ch); |
|---|
| .. | .. |
|---|
| 886 | 937 | wcn36xx_dxe_write_register(wcn, |
|---|
| 887 | 938 | WCN36XX_DXE_REG_CTL_RX_L, |
|---|
| 888 | 939 | WCN36XX_DXE_CH_DEFAULT_CTL_RX_L); |
|---|
| 889 | | - |
|---|
| 890 | | - /* Enable channel interrupts */ |
|---|
| 891 | | - wcn36xx_dxe_enable_ch_int(wcn, WCN36XX_INT_MASK_CHAN_RX_L); |
|---|
| 892 | 940 | |
|---|
| 893 | 941 | /***************************************/ |
|---|
| 894 | 942 | /* Init descriptors for RX HIGH channel */ |
|---|
| .. | .. |
|---|
| 921 | 969 | WCN36XX_DXE_REG_CTL_RX_H, |
|---|
| 922 | 970 | WCN36XX_DXE_CH_DEFAULT_CTL_RX_H); |
|---|
| 923 | 971 | |
|---|
| 924 | | - /* Enable channel interrupts */ |
|---|
| 925 | | - wcn36xx_dxe_enable_ch_int(wcn, WCN36XX_INT_MASK_CHAN_RX_H); |
|---|
| 926 | | - |
|---|
| 927 | 972 | ret = wcn36xx_dxe_request_irqs(wcn); |
|---|
| 928 | 973 | if (ret < 0) |
|---|
| 929 | 974 | goto out_err_irq; |
|---|
| 975 | + |
|---|
| 976 | + timer_setup(&wcn->tx_ack_timer, wcn36xx_dxe_tx_timer, 0); |
|---|
| 977 | + |
|---|
| 978 | + /* Enable channel interrupts */ |
|---|
| 979 | + wcn36xx_dxe_enable_ch_int(wcn, WCN36XX_INT_MASK_CHAN_TX_L); |
|---|
| 980 | + wcn36xx_dxe_enable_ch_int(wcn, WCN36XX_INT_MASK_CHAN_TX_H); |
|---|
| 981 | + wcn36xx_dxe_enable_ch_int(wcn, WCN36XX_INT_MASK_CHAN_RX_L); |
|---|
| 982 | + wcn36xx_dxe_enable_ch_int(wcn, WCN36XX_INT_MASK_CHAN_RX_H); |
|---|
| 930 | 983 | |
|---|
| 931 | 984 | return 0; |
|---|
| 932 | 985 | |
|---|
| .. | .. |
|---|
| 944 | 997 | |
|---|
| 945 | 998 | void wcn36xx_dxe_deinit(struct wcn36xx *wcn) |
|---|
| 946 | 999 | { |
|---|
| 1000 | + int reg_data = 0; |
|---|
| 1001 | + |
|---|
| 1002 | + /* Disable channel interrupts */ |
|---|
| 1003 | + wcn36xx_dxe_disable_ch_int(wcn, WCN36XX_INT_MASK_CHAN_RX_H); |
|---|
| 1004 | + wcn36xx_dxe_disable_ch_int(wcn, WCN36XX_INT_MASK_CHAN_RX_L); |
|---|
| 1005 | + wcn36xx_dxe_disable_ch_int(wcn, WCN36XX_INT_MASK_CHAN_TX_H); |
|---|
| 1006 | + wcn36xx_dxe_disable_ch_int(wcn, WCN36XX_INT_MASK_CHAN_TX_L); |
|---|
| 1007 | + |
|---|
| 947 | 1008 | free_irq(wcn->tx_irq, wcn); |
|---|
| 948 | 1009 | free_irq(wcn->rx_irq, wcn); |
|---|
| 1010 | + del_timer(&wcn->tx_ack_timer); |
|---|
| 949 | 1011 | |
|---|
| 950 | 1012 | if (wcn->tx_ack_skb) { |
|---|
| 951 | 1013 | ieee80211_tx_status_irqsafe(wcn->hw, wcn->tx_ack_skb); |
|---|
| 952 | 1014 | wcn->tx_ack_skb = NULL; |
|---|
| 953 | 1015 | } |
|---|
| 954 | 1016 | |
|---|
| 1017 | + /* Put the DXE block into reset before freeing memory */ |
|---|
| 1018 | + reg_data = WCN36XX_DXE_REG_RESET; |
|---|
| 1019 | + wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_REG_CSR_RESET, reg_data); |
|---|
| 1020 | + |
|---|
| 955 | 1021 | wcn36xx_dxe_ch_free_skbs(wcn, &wcn->dxe_rx_l_ch); |
|---|
| 956 | 1022 | wcn36xx_dxe_ch_free_skbs(wcn, &wcn->dxe_rx_h_ch); |
|---|
| 957 | 1023 | |
|---|