162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 262306a36Sopenharmony_ci/* Copyright(c) 2020 Realtek Corporation 362306a36Sopenharmony_ci */ 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci#include <linux/pci.h> 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include "mac.h" 862306a36Sopenharmony_ci#include "pci.h" 962306a36Sopenharmony_ci#include "reg.h" 1062306a36Sopenharmony_ci#include "ser.h" 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_cistatic bool rtw89_pci_disable_clkreq; 1362306a36Sopenharmony_cistatic bool rtw89_pci_disable_aspm_l1; 1462306a36Sopenharmony_cistatic bool rtw89_pci_disable_l1ss; 1562306a36Sopenharmony_cimodule_param_named(disable_clkreq, rtw89_pci_disable_clkreq, bool, 0644); 1662306a36Sopenharmony_cimodule_param_named(disable_aspm_l1, rtw89_pci_disable_aspm_l1, bool, 0644); 1762306a36Sopenharmony_cimodule_param_named(disable_aspm_l1ss, rtw89_pci_disable_l1ss, bool, 0644); 1862306a36Sopenharmony_ciMODULE_PARM_DESC(disable_clkreq, "Set Y to disable PCI clkreq support"); 1962306a36Sopenharmony_ciMODULE_PARM_DESC(disable_aspm_l1, "Set Y to disable PCI ASPM L1 support"); 2062306a36Sopenharmony_ciMODULE_PARM_DESC(disable_aspm_l1ss, "Set Y to disable PCI L1SS support"); 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cistatic int rtw89_pci_rst_bdram_pcie(struct rtw89_dev *rtwdev) 2362306a36Sopenharmony_ci{ 2462306a36Sopenharmony_ci u32 val; 2562306a36Sopenharmony_ci int ret; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci rtw89_write32(rtwdev, R_AX_PCIE_INIT_CFG1, 2862306a36Sopenharmony_ci rtw89_read32(rtwdev, R_AX_PCIE_INIT_CFG1) | B_AX_RST_BDRAM); 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci ret = read_poll_timeout_atomic(rtw89_read32, val, !(val & B_AX_RST_BDRAM), 3162306a36Sopenharmony_ci 1, RTW89_PCI_POLL_BDRAM_RST_CNT, false, 3262306a36Sopenharmony_ci rtwdev, R_AX_PCIE_INIT_CFG1); 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci if (ret) 3562306a36Sopenharmony_ci return -EBUSY; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci return 0; 3862306a36Sopenharmony_ci} 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic u32 rtw89_pci_dma_recalc(struct rtw89_dev *rtwdev, 4162306a36Sopenharmony_ci struct rtw89_pci_dma_ring *bd_ring, 4262306a36Sopenharmony_ci u32 cur_idx, bool tx) 4362306a36Sopenharmony_ci{ 4462306a36Sopenharmony_ci u32 cnt, cur_rp, wp, rp, len; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci rp = bd_ring->rp; 4762306a36Sopenharmony_ci wp = bd_ring->wp; 4862306a36Sopenharmony_ci len = bd_ring->len; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci cur_rp = FIELD_GET(TXBD_HW_IDX_MASK, cur_idx); 5162306a36Sopenharmony_ci if (tx) 5262306a36Sopenharmony_ci cnt = cur_rp >= rp ? cur_rp - rp : len - (rp - cur_rp); 5362306a36Sopenharmony_ci else 5462306a36Sopenharmony_ci cnt = cur_rp >= wp ? cur_rp - wp : len - (wp - cur_rp); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci bd_ring->rp = cur_rp; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci return cnt; 5962306a36Sopenharmony_ci} 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistatic u32 rtw89_pci_txbd_recalc(struct rtw89_dev *rtwdev, 6262306a36Sopenharmony_ci struct rtw89_pci_tx_ring *tx_ring) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci struct rtw89_pci_dma_ring *bd_ring = &tx_ring->bd_ring; 6562306a36Sopenharmony_ci u32 addr_idx = bd_ring->addr.idx; 6662306a36Sopenharmony_ci u32 cnt, idx; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci idx = rtw89_read32(rtwdev, addr_idx); 6962306a36Sopenharmony_ci cnt = rtw89_pci_dma_recalc(rtwdev, bd_ring, idx, true); 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci return cnt; 7262306a36Sopenharmony_ci} 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cistatic void rtw89_pci_release_fwcmd(struct rtw89_dev *rtwdev, 7562306a36Sopenharmony_ci struct rtw89_pci *rtwpci, 7662306a36Sopenharmony_ci u32 cnt, bool release_all) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci struct rtw89_pci_tx_data *tx_data; 7962306a36Sopenharmony_ci struct sk_buff *skb; 8062306a36Sopenharmony_ci u32 qlen; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci while (cnt--) { 8362306a36Sopenharmony_ci skb = skb_dequeue(&rtwpci->h2c_queue); 8462306a36Sopenharmony_ci if (!skb) { 8562306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to pre-release fwcmd\n"); 8662306a36Sopenharmony_ci return; 8762306a36Sopenharmony_ci } 8862306a36Sopenharmony_ci skb_queue_tail(&rtwpci->h2c_release_queue, skb); 8962306a36Sopenharmony_ci } 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci qlen = skb_queue_len(&rtwpci->h2c_release_queue); 9262306a36Sopenharmony_ci if (!release_all) 9362306a36Sopenharmony_ci qlen = qlen > RTW89_PCI_MULTITAG ? qlen - RTW89_PCI_MULTITAG : 0; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci while (qlen--) { 9662306a36Sopenharmony_ci skb = skb_dequeue(&rtwpci->h2c_release_queue); 9762306a36Sopenharmony_ci if (!skb) { 9862306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to release fwcmd\n"); 9962306a36Sopenharmony_ci return; 10062306a36Sopenharmony_ci } 10162306a36Sopenharmony_ci tx_data = RTW89_PCI_TX_SKB_CB(skb); 10262306a36Sopenharmony_ci dma_unmap_single(&rtwpci->pdev->dev, tx_data->dma, skb->len, 10362306a36Sopenharmony_ci DMA_TO_DEVICE); 10462306a36Sopenharmony_ci dev_kfree_skb_any(skb); 10562306a36Sopenharmony_ci } 10662306a36Sopenharmony_ci} 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cistatic void rtw89_pci_reclaim_tx_fwcmd(struct rtw89_dev *rtwdev, 10962306a36Sopenharmony_ci struct rtw89_pci *rtwpci) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci struct rtw89_pci_tx_ring *tx_ring = &rtwpci->tx_rings[RTW89_TXCH_CH12]; 11262306a36Sopenharmony_ci u32 cnt; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci cnt = rtw89_pci_txbd_recalc(rtwdev, tx_ring); 11562306a36Sopenharmony_ci if (!cnt) 11662306a36Sopenharmony_ci return; 11762306a36Sopenharmony_ci rtw89_pci_release_fwcmd(rtwdev, rtwpci, cnt, false); 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_cistatic u32 rtw89_pci_rxbd_recalc(struct rtw89_dev *rtwdev, 12162306a36Sopenharmony_ci struct rtw89_pci_rx_ring *rx_ring) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci struct rtw89_pci_dma_ring *bd_ring = &rx_ring->bd_ring; 12462306a36Sopenharmony_ci u32 addr_idx = bd_ring->addr.idx; 12562306a36Sopenharmony_ci u32 cnt, idx; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci idx = rtw89_read32(rtwdev, addr_idx); 12862306a36Sopenharmony_ci cnt = rtw89_pci_dma_recalc(rtwdev, bd_ring, idx, false); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci return cnt; 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cistatic void rtw89_pci_sync_skb_for_cpu(struct rtw89_dev *rtwdev, 13462306a36Sopenharmony_ci struct sk_buff *skb) 13562306a36Sopenharmony_ci{ 13662306a36Sopenharmony_ci struct rtw89_pci_rx_info *rx_info; 13762306a36Sopenharmony_ci dma_addr_t dma; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci rx_info = RTW89_PCI_RX_SKB_CB(skb); 14062306a36Sopenharmony_ci dma = rx_info->dma; 14162306a36Sopenharmony_ci dma_sync_single_for_cpu(rtwdev->dev, dma, RTW89_PCI_RX_BUF_SIZE, 14262306a36Sopenharmony_ci DMA_FROM_DEVICE); 14362306a36Sopenharmony_ci} 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_cistatic void rtw89_pci_sync_skb_for_device(struct rtw89_dev *rtwdev, 14662306a36Sopenharmony_ci struct sk_buff *skb) 14762306a36Sopenharmony_ci{ 14862306a36Sopenharmony_ci struct rtw89_pci_rx_info *rx_info; 14962306a36Sopenharmony_ci dma_addr_t dma; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci rx_info = RTW89_PCI_RX_SKB_CB(skb); 15262306a36Sopenharmony_ci dma = rx_info->dma; 15362306a36Sopenharmony_ci dma_sync_single_for_device(rtwdev->dev, dma, RTW89_PCI_RX_BUF_SIZE, 15462306a36Sopenharmony_ci DMA_FROM_DEVICE); 15562306a36Sopenharmony_ci} 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_cistatic int rtw89_pci_rxbd_info_update(struct rtw89_dev *rtwdev, 15862306a36Sopenharmony_ci struct sk_buff *skb) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci struct rtw89_pci_rxbd_info *rxbd_info; 16162306a36Sopenharmony_ci struct rtw89_pci_rx_info *rx_info = RTW89_PCI_RX_SKB_CB(skb); 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci rxbd_info = (struct rtw89_pci_rxbd_info *)skb->data; 16462306a36Sopenharmony_ci rx_info->fs = le32_get_bits(rxbd_info->dword, RTW89_PCI_RXBD_FS); 16562306a36Sopenharmony_ci rx_info->ls = le32_get_bits(rxbd_info->dword, RTW89_PCI_RXBD_LS); 16662306a36Sopenharmony_ci rx_info->len = le32_get_bits(rxbd_info->dword, RTW89_PCI_RXBD_WRITE_SIZE); 16762306a36Sopenharmony_ci rx_info->tag = le32_get_bits(rxbd_info->dword, RTW89_PCI_RXBD_TAG); 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci return 0; 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_cistatic void rtw89_pci_ctrl_txdma_ch_pcie(struct rtw89_dev *rtwdev, bool enable) 17362306a36Sopenharmony_ci{ 17462306a36Sopenharmony_ci const struct rtw89_pci_info *info = rtwdev->pci_info; 17562306a36Sopenharmony_ci const struct rtw89_reg_def *dma_stop1 = &info->dma_stop1; 17662306a36Sopenharmony_ci const struct rtw89_reg_def *dma_stop2 = &info->dma_stop2; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci if (enable) { 17962306a36Sopenharmony_ci rtw89_write32_clr(rtwdev, dma_stop1->addr, dma_stop1->mask); 18062306a36Sopenharmony_ci if (dma_stop2->addr) 18162306a36Sopenharmony_ci rtw89_write32_clr(rtwdev, dma_stop2->addr, dma_stop2->mask); 18262306a36Sopenharmony_ci } else { 18362306a36Sopenharmony_ci rtw89_write32_set(rtwdev, dma_stop1->addr, dma_stop1->mask); 18462306a36Sopenharmony_ci if (dma_stop2->addr) 18562306a36Sopenharmony_ci rtw89_write32_set(rtwdev, dma_stop2->addr, dma_stop2->mask); 18662306a36Sopenharmony_ci } 18762306a36Sopenharmony_ci} 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_cistatic void rtw89_pci_ctrl_txdma_fw_ch_pcie(struct rtw89_dev *rtwdev, bool enable) 19062306a36Sopenharmony_ci{ 19162306a36Sopenharmony_ci const struct rtw89_pci_info *info = rtwdev->pci_info; 19262306a36Sopenharmony_ci const struct rtw89_reg_def *dma_stop1 = &info->dma_stop1; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci if (enable) 19562306a36Sopenharmony_ci rtw89_write32_clr(rtwdev, dma_stop1->addr, B_AX_STOP_CH12); 19662306a36Sopenharmony_ci else 19762306a36Sopenharmony_ci rtw89_write32_set(rtwdev, dma_stop1->addr, B_AX_STOP_CH12); 19862306a36Sopenharmony_ci} 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_cistatic bool 20162306a36Sopenharmony_cirtw89_skb_put_rx_data(struct rtw89_dev *rtwdev, bool fs, bool ls, 20262306a36Sopenharmony_ci struct sk_buff *new, 20362306a36Sopenharmony_ci const struct sk_buff *skb, u32 offset, 20462306a36Sopenharmony_ci const struct rtw89_pci_rx_info *rx_info, 20562306a36Sopenharmony_ci const struct rtw89_rx_desc_info *desc_info) 20662306a36Sopenharmony_ci{ 20762306a36Sopenharmony_ci u32 copy_len = rx_info->len - offset; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci if (unlikely(skb_tailroom(new) < copy_len)) { 21062306a36Sopenharmony_ci rtw89_debug(rtwdev, RTW89_DBG_TXRX, 21162306a36Sopenharmony_ci "invalid rx data length bd_len=%d desc_len=%d offset=%d (fs=%d ls=%d)\n", 21262306a36Sopenharmony_ci rx_info->len, desc_info->pkt_size, offset, fs, ls); 21362306a36Sopenharmony_ci rtw89_hex_dump(rtwdev, RTW89_DBG_TXRX, "rx_data: ", 21462306a36Sopenharmony_ci skb->data, rx_info->len); 21562306a36Sopenharmony_ci /* length of a single segment skb is desc_info->pkt_size */ 21662306a36Sopenharmony_ci if (fs && ls) { 21762306a36Sopenharmony_ci copy_len = desc_info->pkt_size; 21862306a36Sopenharmony_ci } else { 21962306a36Sopenharmony_ci rtw89_info(rtwdev, "drop rx data due to invalid length\n"); 22062306a36Sopenharmony_ci return false; 22162306a36Sopenharmony_ci } 22262306a36Sopenharmony_ci } 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci skb_put_data(new, skb->data + offset, copy_len); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci return true; 22762306a36Sopenharmony_ci} 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_cistatic u32 rtw89_pci_rxbd_deliver_skbs(struct rtw89_dev *rtwdev, 23062306a36Sopenharmony_ci struct rtw89_pci_rx_ring *rx_ring) 23162306a36Sopenharmony_ci{ 23262306a36Sopenharmony_ci struct rtw89_pci_dma_ring *bd_ring = &rx_ring->bd_ring; 23362306a36Sopenharmony_ci struct rtw89_pci_rx_info *rx_info; 23462306a36Sopenharmony_ci struct rtw89_rx_desc_info *desc_info = &rx_ring->diliver_desc; 23562306a36Sopenharmony_ci struct sk_buff *new = rx_ring->diliver_skb; 23662306a36Sopenharmony_ci struct sk_buff *skb; 23762306a36Sopenharmony_ci u32 rxinfo_size = sizeof(struct rtw89_pci_rxbd_info); 23862306a36Sopenharmony_ci u32 offset; 23962306a36Sopenharmony_ci u32 cnt = 1; 24062306a36Sopenharmony_ci bool fs, ls; 24162306a36Sopenharmony_ci int ret; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci skb = rx_ring->buf[bd_ring->wp]; 24462306a36Sopenharmony_ci rtw89_pci_sync_skb_for_cpu(rtwdev, skb); 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci ret = rtw89_pci_rxbd_info_update(rtwdev, skb); 24762306a36Sopenharmony_ci if (ret) { 24862306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to update %d RXBD info: %d\n", 24962306a36Sopenharmony_ci bd_ring->wp, ret); 25062306a36Sopenharmony_ci goto err_sync_device; 25162306a36Sopenharmony_ci } 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci rx_info = RTW89_PCI_RX_SKB_CB(skb); 25462306a36Sopenharmony_ci fs = rx_info->fs; 25562306a36Sopenharmony_ci ls = rx_info->ls; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci if (fs) { 25862306a36Sopenharmony_ci if (new) { 25962306a36Sopenharmony_ci rtw89_debug(rtwdev, RTW89_DBG_UNEXP, 26062306a36Sopenharmony_ci "skb should not be ready before first segment start\n"); 26162306a36Sopenharmony_ci goto err_sync_device; 26262306a36Sopenharmony_ci } 26362306a36Sopenharmony_ci if (desc_info->ready) { 26462306a36Sopenharmony_ci rtw89_warn(rtwdev, "desc info should not be ready before first segment start\n"); 26562306a36Sopenharmony_ci goto err_sync_device; 26662306a36Sopenharmony_ci } 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci rtw89_chip_query_rxdesc(rtwdev, desc_info, skb->data, rxinfo_size); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci new = rtw89_alloc_skb_for_rx(rtwdev, desc_info->pkt_size); 27162306a36Sopenharmony_ci if (!new) 27262306a36Sopenharmony_ci goto err_sync_device; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci rx_ring->diliver_skb = new; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci /* first segment has RX desc */ 27762306a36Sopenharmony_ci offset = desc_info->offset + desc_info->rxd_len; 27862306a36Sopenharmony_ci } else { 27962306a36Sopenharmony_ci offset = sizeof(struct rtw89_pci_rxbd_info); 28062306a36Sopenharmony_ci if (!new) { 28162306a36Sopenharmony_ci rtw89_debug(rtwdev, RTW89_DBG_UNEXP, "no last skb\n"); 28262306a36Sopenharmony_ci goto err_sync_device; 28362306a36Sopenharmony_ci } 28462306a36Sopenharmony_ci } 28562306a36Sopenharmony_ci if (!rtw89_skb_put_rx_data(rtwdev, fs, ls, new, skb, offset, rx_info, desc_info)) 28662306a36Sopenharmony_ci goto err_sync_device; 28762306a36Sopenharmony_ci rtw89_pci_sync_skb_for_device(rtwdev, skb); 28862306a36Sopenharmony_ci rtw89_pci_rxbd_increase(rx_ring, 1); 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci if (!desc_info->ready) { 29162306a36Sopenharmony_ci rtw89_warn(rtwdev, "no rx desc information\n"); 29262306a36Sopenharmony_ci goto err_free_resource; 29362306a36Sopenharmony_ci } 29462306a36Sopenharmony_ci if (ls) { 29562306a36Sopenharmony_ci rtw89_core_rx(rtwdev, desc_info, new); 29662306a36Sopenharmony_ci rx_ring->diliver_skb = NULL; 29762306a36Sopenharmony_ci desc_info->ready = false; 29862306a36Sopenharmony_ci } 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci return cnt; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_cierr_sync_device: 30362306a36Sopenharmony_ci rtw89_pci_sync_skb_for_device(rtwdev, skb); 30462306a36Sopenharmony_ci rtw89_pci_rxbd_increase(rx_ring, 1); 30562306a36Sopenharmony_cierr_free_resource: 30662306a36Sopenharmony_ci if (new) 30762306a36Sopenharmony_ci dev_kfree_skb_any(new); 30862306a36Sopenharmony_ci rx_ring->diliver_skb = NULL; 30962306a36Sopenharmony_ci desc_info->ready = false; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci return cnt; 31262306a36Sopenharmony_ci} 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_cistatic void rtw89_pci_rxbd_deliver(struct rtw89_dev *rtwdev, 31562306a36Sopenharmony_ci struct rtw89_pci_rx_ring *rx_ring, 31662306a36Sopenharmony_ci u32 cnt) 31762306a36Sopenharmony_ci{ 31862306a36Sopenharmony_ci struct rtw89_pci_dma_ring *bd_ring = &rx_ring->bd_ring; 31962306a36Sopenharmony_ci u32 rx_cnt; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci while (cnt && rtwdev->napi_budget_countdown > 0) { 32262306a36Sopenharmony_ci rx_cnt = rtw89_pci_rxbd_deliver_skbs(rtwdev, rx_ring); 32362306a36Sopenharmony_ci if (!rx_cnt) { 32462306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to deliver RXBD skb\n"); 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci /* skip the rest RXBD bufs */ 32762306a36Sopenharmony_ci rtw89_pci_rxbd_increase(rx_ring, cnt); 32862306a36Sopenharmony_ci break; 32962306a36Sopenharmony_ci } 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci cnt -= rx_cnt; 33262306a36Sopenharmony_ci } 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci rtw89_write16(rtwdev, bd_ring->addr.idx, bd_ring->wp); 33562306a36Sopenharmony_ci} 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_cistatic int rtw89_pci_poll_rxq_dma(struct rtw89_dev *rtwdev, 33862306a36Sopenharmony_ci struct rtw89_pci *rtwpci, int budget) 33962306a36Sopenharmony_ci{ 34062306a36Sopenharmony_ci struct rtw89_pci_rx_ring *rx_ring; 34162306a36Sopenharmony_ci int countdown = rtwdev->napi_budget_countdown; 34262306a36Sopenharmony_ci u32 cnt; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci rx_ring = &rtwpci->rx_rings[RTW89_RXCH_RXQ]; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci cnt = rtw89_pci_rxbd_recalc(rtwdev, rx_ring); 34762306a36Sopenharmony_ci if (!cnt) 34862306a36Sopenharmony_ci return 0; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci cnt = min_t(u32, budget, cnt); 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci rtw89_pci_rxbd_deliver(rtwdev, rx_ring, cnt); 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci /* In case of flushing pending SKBs, the countdown may exceed. */ 35562306a36Sopenharmony_ci if (rtwdev->napi_budget_countdown <= 0) 35662306a36Sopenharmony_ci return budget; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci return budget - countdown; 35962306a36Sopenharmony_ci} 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_cistatic void rtw89_pci_tx_status(struct rtw89_dev *rtwdev, 36262306a36Sopenharmony_ci struct rtw89_pci_tx_ring *tx_ring, 36362306a36Sopenharmony_ci struct sk_buff *skb, u8 tx_status) 36462306a36Sopenharmony_ci{ 36562306a36Sopenharmony_ci struct rtw89_tx_skb_data *skb_data = RTW89_TX_SKB_CB(skb); 36662306a36Sopenharmony_ci struct ieee80211_tx_info *info; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci rtw89_core_tx_wait_complete(rtwdev, skb_data, tx_status == RTW89_TX_DONE); 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci info = IEEE80211_SKB_CB(skb); 37162306a36Sopenharmony_ci ieee80211_tx_info_clear_status(info); 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci if (info->flags & IEEE80211_TX_CTL_NO_ACK) 37462306a36Sopenharmony_ci info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; 37562306a36Sopenharmony_ci if (tx_status == RTW89_TX_DONE) { 37662306a36Sopenharmony_ci info->flags |= IEEE80211_TX_STAT_ACK; 37762306a36Sopenharmony_ci tx_ring->tx_acked++; 37862306a36Sopenharmony_ci } else { 37962306a36Sopenharmony_ci if (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) 38062306a36Sopenharmony_ci rtw89_debug(rtwdev, RTW89_DBG_FW, 38162306a36Sopenharmony_ci "failed to TX of status %x\n", tx_status); 38262306a36Sopenharmony_ci switch (tx_status) { 38362306a36Sopenharmony_ci case RTW89_TX_RETRY_LIMIT: 38462306a36Sopenharmony_ci tx_ring->tx_retry_lmt++; 38562306a36Sopenharmony_ci break; 38662306a36Sopenharmony_ci case RTW89_TX_LIFE_TIME: 38762306a36Sopenharmony_ci tx_ring->tx_life_time++; 38862306a36Sopenharmony_ci break; 38962306a36Sopenharmony_ci case RTW89_TX_MACID_DROP: 39062306a36Sopenharmony_ci tx_ring->tx_mac_id_drop++; 39162306a36Sopenharmony_ci break; 39262306a36Sopenharmony_ci default: 39362306a36Sopenharmony_ci rtw89_warn(rtwdev, "invalid TX status %x\n", tx_status); 39462306a36Sopenharmony_ci break; 39562306a36Sopenharmony_ci } 39662306a36Sopenharmony_ci } 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci ieee80211_tx_status_ni(rtwdev->hw, skb); 39962306a36Sopenharmony_ci} 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_cistatic void rtw89_pci_reclaim_txbd(struct rtw89_dev *rtwdev, struct rtw89_pci_tx_ring *tx_ring) 40262306a36Sopenharmony_ci{ 40362306a36Sopenharmony_ci struct rtw89_pci_tx_wd *txwd; 40462306a36Sopenharmony_ci u32 cnt; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci cnt = rtw89_pci_txbd_recalc(rtwdev, tx_ring); 40762306a36Sopenharmony_ci while (cnt--) { 40862306a36Sopenharmony_ci txwd = list_first_entry_or_null(&tx_ring->busy_pages, struct rtw89_pci_tx_wd, list); 40962306a36Sopenharmony_ci if (!txwd) { 41062306a36Sopenharmony_ci rtw89_warn(rtwdev, "No busy txwd pages available\n"); 41162306a36Sopenharmony_ci break; 41262306a36Sopenharmony_ci } 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci list_del_init(&txwd->list); 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci /* this skb has been freed by RPP */ 41762306a36Sopenharmony_ci if (skb_queue_len(&txwd->queue) == 0) 41862306a36Sopenharmony_ci rtw89_pci_enqueue_txwd(tx_ring, txwd); 41962306a36Sopenharmony_ci } 42062306a36Sopenharmony_ci} 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_cistatic void rtw89_pci_release_busy_txwd(struct rtw89_dev *rtwdev, 42362306a36Sopenharmony_ci struct rtw89_pci_tx_ring *tx_ring) 42462306a36Sopenharmony_ci{ 42562306a36Sopenharmony_ci struct rtw89_pci_tx_wd_ring *wd_ring = &tx_ring->wd_ring; 42662306a36Sopenharmony_ci struct rtw89_pci_tx_wd *txwd; 42762306a36Sopenharmony_ci int i; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci for (i = 0; i < wd_ring->page_num; i++) { 43062306a36Sopenharmony_ci txwd = list_first_entry_or_null(&tx_ring->busy_pages, struct rtw89_pci_tx_wd, list); 43162306a36Sopenharmony_ci if (!txwd) 43262306a36Sopenharmony_ci break; 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci list_del_init(&txwd->list); 43562306a36Sopenharmony_ci } 43662306a36Sopenharmony_ci} 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_cistatic void rtw89_pci_release_txwd_skb(struct rtw89_dev *rtwdev, 43962306a36Sopenharmony_ci struct rtw89_pci_tx_ring *tx_ring, 44062306a36Sopenharmony_ci struct rtw89_pci_tx_wd *txwd, u16 seq, 44162306a36Sopenharmony_ci u8 tx_status) 44262306a36Sopenharmony_ci{ 44362306a36Sopenharmony_ci struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; 44462306a36Sopenharmony_ci struct rtw89_pci_tx_data *tx_data; 44562306a36Sopenharmony_ci struct sk_buff *skb, *tmp; 44662306a36Sopenharmony_ci u8 txch = tx_ring->txch; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci if (!list_empty(&txwd->list)) { 44962306a36Sopenharmony_ci rtw89_pci_reclaim_txbd(rtwdev, tx_ring); 45062306a36Sopenharmony_ci /* In low power mode, RPP can receive before updating of TX BD. 45162306a36Sopenharmony_ci * In normal mode, it should not happen so give it a warning. 45262306a36Sopenharmony_ci */ 45362306a36Sopenharmony_ci if (!rtwpci->low_power && !list_empty(&txwd->list)) 45462306a36Sopenharmony_ci rtw89_warn(rtwdev, "queue %d txwd %d is not idle\n", 45562306a36Sopenharmony_ci txch, seq); 45662306a36Sopenharmony_ci } 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci skb_queue_walk_safe(&txwd->queue, skb, tmp) { 45962306a36Sopenharmony_ci skb_unlink(skb, &txwd->queue); 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci tx_data = RTW89_PCI_TX_SKB_CB(skb); 46262306a36Sopenharmony_ci dma_unmap_single(&rtwpci->pdev->dev, tx_data->dma, skb->len, 46362306a36Sopenharmony_ci DMA_TO_DEVICE); 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci rtw89_pci_tx_status(rtwdev, tx_ring, skb, tx_status); 46662306a36Sopenharmony_ci } 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci if (list_empty(&txwd->list)) 46962306a36Sopenharmony_ci rtw89_pci_enqueue_txwd(tx_ring, txwd); 47062306a36Sopenharmony_ci} 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_cistatic void rtw89_pci_release_rpp(struct rtw89_dev *rtwdev, 47362306a36Sopenharmony_ci struct rtw89_pci_rpp_fmt *rpp) 47462306a36Sopenharmony_ci{ 47562306a36Sopenharmony_ci struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; 47662306a36Sopenharmony_ci struct rtw89_pci_tx_ring *tx_ring; 47762306a36Sopenharmony_ci struct rtw89_pci_tx_wd_ring *wd_ring; 47862306a36Sopenharmony_ci struct rtw89_pci_tx_wd *txwd; 47962306a36Sopenharmony_ci u16 seq; 48062306a36Sopenharmony_ci u8 qsel, tx_status, txch; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci seq = le32_get_bits(rpp->dword, RTW89_PCI_RPP_SEQ); 48362306a36Sopenharmony_ci qsel = le32_get_bits(rpp->dword, RTW89_PCI_RPP_QSEL); 48462306a36Sopenharmony_ci tx_status = le32_get_bits(rpp->dword, RTW89_PCI_RPP_TX_STATUS); 48562306a36Sopenharmony_ci txch = rtw89_core_get_ch_dma(rtwdev, qsel); 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci if (txch == RTW89_TXCH_CH12) { 48862306a36Sopenharmony_ci rtw89_warn(rtwdev, "should no fwcmd release report\n"); 48962306a36Sopenharmony_ci return; 49062306a36Sopenharmony_ci } 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci tx_ring = &rtwpci->tx_rings[txch]; 49362306a36Sopenharmony_ci wd_ring = &tx_ring->wd_ring; 49462306a36Sopenharmony_ci txwd = &wd_ring->pages[seq]; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci rtw89_pci_release_txwd_skb(rtwdev, tx_ring, txwd, seq, tx_status); 49762306a36Sopenharmony_ci} 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_cistatic void rtw89_pci_release_pending_txwd_skb(struct rtw89_dev *rtwdev, 50062306a36Sopenharmony_ci struct rtw89_pci_tx_ring *tx_ring) 50162306a36Sopenharmony_ci{ 50262306a36Sopenharmony_ci struct rtw89_pci_tx_wd_ring *wd_ring = &tx_ring->wd_ring; 50362306a36Sopenharmony_ci struct rtw89_pci_tx_wd *txwd; 50462306a36Sopenharmony_ci int i; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci for (i = 0; i < wd_ring->page_num; i++) { 50762306a36Sopenharmony_ci txwd = &wd_ring->pages[i]; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci if (!list_empty(&txwd->list)) 51062306a36Sopenharmony_ci continue; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci rtw89_pci_release_txwd_skb(rtwdev, tx_ring, txwd, i, RTW89_TX_MACID_DROP); 51362306a36Sopenharmony_ci } 51462306a36Sopenharmony_ci} 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_cistatic u32 rtw89_pci_release_tx_skbs(struct rtw89_dev *rtwdev, 51762306a36Sopenharmony_ci struct rtw89_pci_rx_ring *rx_ring, 51862306a36Sopenharmony_ci u32 max_cnt) 51962306a36Sopenharmony_ci{ 52062306a36Sopenharmony_ci struct rtw89_pci_dma_ring *bd_ring = &rx_ring->bd_ring; 52162306a36Sopenharmony_ci struct rtw89_pci_rx_info *rx_info; 52262306a36Sopenharmony_ci struct rtw89_pci_rpp_fmt *rpp; 52362306a36Sopenharmony_ci struct rtw89_rx_desc_info desc_info = {}; 52462306a36Sopenharmony_ci struct sk_buff *skb; 52562306a36Sopenharmony_ci u32 cnt = 0; 52662306a36Sopenharmony_ci u32 rpp_size = sizeof(struct rtw89_pci_rpp_fmt); 52762306a36Sopenharmony_ci u32 rxinfo_size = sizeof(struct rtw89_pci_rxbd_info); 52862306a36Sopenharmony_ci u32 offset; 52962306a36Sopenharmony_ci int ret; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci skb = rx_ring->buf[bd_ring->wp]; 53262306a36Sopenharmony_ci rtw89_pci_sync_skb_for_cpu(rtwdev, skb); 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci ret = rtw89_pci_rxbd_info_update(rtwdev, skb); 53562306a36Sopenharmony_ci if (ret) { 53662306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to update %d RXBD info: %d\n", 53762306a36Sopenharmony_ci bd_ring->wp, ret); 53862306a36Sopenharmony_ci goto err_sync_device; 53962306a36Sopenharmony_ci } 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci rx_info = RTW89_PCI_RX_SKB_CB(skb); 54262306a36Sopenharmony_ci if (!rx_info->fs || !rx_info->ls) { 54362306a36Sopenharmony_ci rtw89_err(rtwdev, "cannot process RP frame not set FS/LS\n"); 54462306a36Sopenharmony_ci return cnt; 54562306a36Sopenharmony_ci } 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci rtw89_chip_query_rxdesc(rtwdev, &desc_info, skb->data, rxinfo_size); 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci /* first segment has RX desc */ 55062306a36Sopenharmony_ci offset = desc_info.offset + desc_info.rxd_len; 55162306a36Sopenharmony_ci for (; offset + rpp_size <= rx_info->len; offset += rpp_size) { 55262306a36Sopenharmony_ci rpp = (struct rtw89_pci_rpp_fmt *)(skb->data + offset); 55362306a36Sopenharmony_ci rtw89_pci_release_rpp(rtwdev, rpp); 55462306a36Sopenharmony_ci } 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci rtw89_pci_sync_skb_for_device(rtwdev, skb); 55762306a36Sopenharmony_ci rtw89_pci_rxbd_increase(rx_ring, 1); 55862306a36Sopenharmony_ci cnt++; 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci return cnt; 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_cierr_sync_device: 56362306a36Sopenharmony_ci rtw89_pci_sync_skb_for_device(rtwdev, skb); 56462306a36Sopenharmony_ci return 0; 56562306a36Sopenharmony_ci} 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_cistatic void rtw89_pci_release_tx(struct rtw89_dev *rtwdev, 56862306a36Sopenharmony_ci struct rtw89_pci_rx_ring *rx_ring, 56962306a36Sopenharmony_ci u32 cnt) 57062306a36Sopenharmony_ci{ 57162306a36Sopenharmony_ci struct rtw89_pci_dma_ring *bd_ring = &rx_ring->bd_ring; 57262306a36Sopenharmony_ci u32 release_cnt; 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci while (cnt) { 57562306a36Sopenharmony_ci release_cnt = rtw89_pci_release_tx_skbs(rtwdev, rx_ring, cnt); 57662306a36Sopenharmony_ci if (!release_cnt) { 57762306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to release TX skbs\n"); 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci /* skip the rest RXBD bufs */ 58062306a36Sopenharmony_ci rtw89_pci_rxbd_increase(rx_ring, cnt); 58162306a36Sopenharmony_ci break; 58262306a36Sopenharmony_ci } 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci cnt -= release_cnt; 58562306a36Sopenharmony_ci } 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci rtw89_write16(rtwdev, bd_ring->addr.idx, bd_ring->wp); 58862306a36Sopenharmony_ci} 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_cistatic int rtw89_pci_poll_rpq_dma(struct rtw89_dev *rtwdev, 59162306a36Sopenharmony_ci struct rtw89_pci *rtwpci, int budget) 59262306a36Sopenharmony_ci{ 59362306a36Sopenharmony_ci struct rtw89_pci_rx_ring *rx_ring; 59462306a36Sopenharmony_ci u32 cnt; 59562306a36Sopenharmony_ci int work_done; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci rx_ring = &rtwpci->rx_rings[RTW89_RXCH_RPQ]; 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci spin_lock_bh(&rtwpci->trx_lock); 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci cnt = rtw89_pci_rxbd_recalc(rtwdev, rx_ring); 60262306a36Sopenharmony_ci if (cnt == 0) 60362306a36Sopenharmony_ci goto out_unlock; 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci rtw89_pci_release_tx(rtwdev, rx_ring, cnt); 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ciout_unlock: 60862306a36Sopenharmony_ci spin_unlock_bh(&rtwpci->trx_lock); 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci /* always release all RPQ */ 61162306a36Sopenharmony_ci work_done = min_t(int, cnt, budget); 61262306a36Sopenharmony_ci rtwdev->napi_budget_countdown -= work_done; 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci return work_done; 61562306a36Sopenharmony_ci} 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_cistatic void rtw89_pci_isr_rxd_unavail(struct rtw89_dev *rtwdev, 61862306a36Sopenharmony_ci struct rtw89_pci *rtwpci) 61962306a36Sopenharmony_ci{ 62062306a36Sopenharmony_ci struct rtw89_pci_rx_ring *rx_ring; 62162306a36Sopenharmony_ci struct rtw89_pci_dma_ring *bd_ring; 62262306a36Sopenharmony_ci u32 reg_idx; 62362306a36Sopenharmony_ci u16 hw_idx, hw_idx_next, host_idx; 62462306a36Sopenharmony_ci int i; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci for (i = 0; i < RTW89_RXCH_NUM; i++) { 62762306a36Sopenharmony_ci rx_ring = &rtwpci->rx_rings[i]; 62862306a36Sopenharmony_ci bd_ring = &rx_ring->bd_ring; 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci reg_idx = rtw89_read32(rtwdev, bd_ring->addr.idx); 63162306a36Sopenharmony_ci hw_idx = FIELD_GET(TXBD_HW_IDX_MASK, reg_idx); 63262306a36Sopenharmony_ci host_idx = FIELD_GET(TXBD_HOST_IDX_MASK, reg_idx); 63362306a36Sopenharmony_ci hw_idx_next = (hw_idx + 1) % bd_ring->len; 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci if (hw_idx_next == host_idx) 63662306a36Sopenharmony_ci rtw89_debug(rtwdev, RTW89_DBG_UNEXP, "%d RXD unavailable\n", i); 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci rtw89_debug(rtwdev, RTW89_DBG_TXRX, 63962306a36Sopenharmony_ci "%d RXD unavailable, idx=0x%08x, len=%d\n", 64062306a36Sopenharmony_ci i, reg_idx, bd_ring->len); 64162306a36Sopenharmony_ci } 64262306a36Sopenharmony_ci} 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_civoid rtw89_pci_recognize_intrs(struct rtw89_dev *rtwdev, 64562306a36Sopenharmony_ci struct rtw89_pci *rtwpci, 64662306a36Sopenharmony_ci struct rtw89_pci_isrs *isrs) 64762306a36Sopenharmony_ci{ 64862306a36Sopenharmony_ci isrs->halt_c2h_isrs = rtw89_read32(rtwdev, R_AX_HISR0) & rtwpci->halt_c2h_intrs; 64962306a36Sopenharmony_ci isrs->isrs[0] = rtw89_read32(rtwdev, R_AX_PCIE_HISR00) & rtwpci->intrs[0]; 65062306a36Sopenharmony_ci isrs->isrs[1] = rtw89_read32(rtwdev, R_AX_PCIE_HISR10) & rtwpci->intrs[1]; 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci rtw89_write32(rtwdev, R_AX_HISR0, isrs->halt_c2h_isrs); 65362306a36Sopenharmony_ci rtw89_write32(rtwdev, R_AX_PCIE_HISR00, isrs->isrs[0]); 65462306a36Sopenharmony_ci rtw89_write32(rtwdev, R_AX_PCIE_HISR10, isrs->isrs[1]); 65562306a36Sopenharmony_ci} 65662306a36Sopenharmony_ciEXPORT_SYMBOL(rtw89_pci_recognize_intrs); 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_civoid rtw89_pci_recognize_intrs_v1(struct rtw89_dev *rtwdev, 65962306a36Sopenharmony_ci struct rtw89_pci *rtwpci, 66062306a36Sopenharmony_ci struct rtw89_pci_isrs *isrs) 66162306a36Sopenharmony_ci{ 66262306a36Sopenharmony_ci isrs->ind_isrs = rtw89_read32(rtwdev, R_AX_PCIE_HISR00_V1) & rtwpci->ind_intrs; 66362306a36Sopenharmony_ci isrs->halt_c2h_isrs = isrs->ind_isrs & B_AX_HS0ISR_IND_INT_EN ? 66462306a36Sopenharmony_ci rtw89_read32(rtwdev, R_AX_HISR0) & rtwpci->halt_c2h_intrs : 0; 66562306a36Sopenharmony_ci isrs->isrs[0] = isrs->ind_isrs & B_AX_HCI_AXIDMA_INT_EN ? 66662306a36Sopenharmony_ci rtw89_read32(rtwdev, R_AX_HAXI_HISR00) & rtwpci->intrs[0] : 0; 66762306a36Sopenharmony_ci isrs->isrs[1] = isrs->ind_isrs & B_AX_HS1ISR_IND_INT_EN ? 66862306a36Sopenharmony_ci rtw89_read32(rtwdev, R_AX_HISR1) & rtwpci->intrs[1] : 0; 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci if (isrs->halt_c2h_isrs) 67162306a36Sopenharmony_ci rtw89_write32(rtwdev, R_AX_HISR0, isrs->halt_c2h_isrs); 67262306a36Sopenharmony_ci if (isrs->isrs[0]) 67362306a36Sopenharmony_ci rtw89_write32(rtwdev, R_AX_HAXI_HISR00, isrs->isrs[0]); 67462306a36Sopenharmony_ci if (isrs->isrs[1]) 67562306a36Sopenharmony_ci rtw89_write32(rtwdev, R_AX_HISR1, isrs->isrs[1]); 67662306a36Sopenharmony_ci} 67762306a36Sopenharmony_ciEXPORT_SYMBOL(rtw89_pci_recognize_intrs_v1); 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_cistatic void rtw89_pci_clear_isr0(struct rtw89_dev *rtwdev, u32 isr00) 68062306a36Sopenharmony_ci{ 68162306a36Sopenharmony_ci /* write 1 clear */ 68262306a36Sopenharmony_ci rtw89_write32(rtwdev, R_AX_PCIE_HISR00, isr00); 68362306a36Sopenharmony_ci} 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_civoid rtw89_pci_enable_intr(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci) 68662306a36Sopenharmony_ci{ 68762306a36Sopenharmony_ci rtw89_write32(rtwdev, R_AX_HIMR0, rtwpci->halt_c2h_intrs); 68862306a36Sopenharmony_ci rtw89_write32(rtwdev, R_AX_PCIE_HIMR00, rtwpci->intrs[0]); 68962306a36Sopenharmony_ci rtw89_write32(rtwdev, R_AX_PCIE_HIMR10, rtwpci->intrs[1]); 69062306a36Sopenharmony_ci} 69162306a36Sopenharmony_ciEXPORT_SYMBOL(rtw89_pci_enable_intr); 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_civoid rtw89_pci_disable_intr(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci) 69462306a36Sopenharmony_ci{ 69562306a36Sopenharmony_ci rtw89_write32(rtwdev, R_AX_HIMR0, 0); 69662306a36Sopenharmony_ci rtw89_write32(rtwdev, R_AX_PCIE_HIMR00, 0); 69762306a36Sopenharmony_ci rtw89_write32(rtwdev, R_AX_PCIE_HIMR10, 0); 69862306a36Sopenharmony_ci} 69962306a36Sopenharmony_ciEXPORT_SYMBOL(rtw89_pci_disable_intr); 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_civoid rtw89_pci_enable_intr_v1(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci) 70262306a36Sopenharmony_ci{ 70362306a36Sopenharmony_ci rtw89_write32(rtwdev, R_AX_PCIE_HIMR00_V1, rtwpci->ind_intrs); 70462306a36Sopenharmony_ci rtw89_write32(rtwdev, R_AX_HIMR0, rtwpci->halt_c2h_intrs); 70562306a36Sopenharmony_ci rtw89_write32(rtwdev, R_AX_HAXI_HIMR00, rtwpci->intrs[0]); 70662306a36Sopenharmony_ci rtw89_write32(rtwdev, R_AX_HIMR1, rtwpci->intrs[1]); 70762306a36Sopenharmony_ci} 70862306a36Sopenharmony_ciEXPORT_SYMBOL(rtw89_pci_enable_intr_v1); 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_civoid rtw89_pci_disable_intr_v1(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci) 71162306a36Sopenharmony_ci{ 71262306a36Sopenharmony_ci rtw89_write32(rtwdev, R_AX_PCIE_HIMR00_V1, 0); 71362306a36Sopenharmony_ci} 71462306a36Sopenharmony_ciEXPORT_SYMBOL(rtw89_pci_disable_intr_v1); 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_cistatic void rtw89_pci_ops_recovery_start(struct rtw89_dev *rtwdev) 71762306a36Sopenharmony_ci{ 71862306a36Sopenharmony_ci struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; 71962306a36Sopenharmony_ci unsigned long flags; 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci spin_lock_irqsave(&rtwpci->irq_lock, flags); 72262306a36Sopenharmony_ci rtw89_chip_disable_intr(rtwdev, rtwpci); 72362306a36Sopenharmony_ci rtw89_chip_config_intr_mask(rtwdev, RTW89_PCI_INTR_MASK_RECOVERY_START); 72462306a36Sopenharmony_ci rtw89_chip_enable_intr(rtwdev, rtwpci); 72562306a36Sopenharmony_ci spin_unlock_irqrestore(&rtwpci->irq_lock, flags); 72662306a36Sopenharmony_ci} 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_cistatic void rtw89_pci_ops_recovery_complete(struct rtw89_dev *rtwdev) 72962306a36Sopenharmony_ci{ 73062306a36Sopenharmony_ci struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; 73162306a36Sopenharmony_ci unsigned long flags; 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci spin_lock_irqsave(&rtwpci->irq_lock, flags); 73462306a36Sopenharmony_ci rtw89_chip_disable_intr(rtwdev, rtwpci); 73562306a36Sopenharmony_ci rtw89_chip_config_intr_mask(rtwdev, RTW89_PCI_INTR_MASK_RECOVERY_COMPLETE); 73662306a36Sopenharmony_ci rtw89_chip_enable_intr(rtwdev, rtwpci); 73762306a36Sopenharmony_ci spin_unlock_irqrestore(&rtwpci->irq_lock, flags); 73862306a36Sopenharmony_ci} 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_cistatic void rtw89_pci_low_power_interrupt_handler(struct rtw89_dev *rtwdev) 74162306a36Sopenharmony_ci{ 74262306a36Sopenharmony_ci struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; 74362306a36Sopenharmony_ci int budget = NAPI_POLL_WEIGHT; 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci /* To prevent RXQ get stuck due to run out of budget. */ 74662306a36Sopenharmony_ci rtwdev->napi_budget_countdown = budget; 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci rtw89_pci_poll_rpq_dma(rtwdev, rtwpci, budget); 74962306a36Sopenharmony_ci rtw89_pci_poll_rxq_dma(rtwdev, rtwpci, budget); 75062306a36Sopenharmony_ci} 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_cistatic irqreturn_t rtw89_pci_interrupt_threadfn(int irq, void *dev) 75362306a36Sopenharmony_ci{ 75462306a36Sopenharmony_ci struct rtw89_dev *rtwdev = dev; 75562306a36Sopenharmony_ci struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; 75662306a36Sopenharmony_ci struct rtw89_pci_isrs isrs; 75762306a36Sopenharmony_ci unsigned long flags; 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci spin_lock_irqsave(&rtwpci->irq_lock, flags); 76062306a36Sopenharmony_ci rtw89_chip_recognize_intrs(rtwdev, rtwpci, &isrs); 76162306a36Sopenharmony_ci spin_unlock_irqrestore(&rtwpci->irq_lock, flags); 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci if (unlikely(isrs.isrs[0] & B_AX_RDU_INT)) 76462306a36Sopenharmony_ci rtw89_pci_isr_rxd_unavail(rtwdev, rtwpci); 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci if (unlikely(isrs.halt_c2h_isrs & B_AX_HALT_C2H_INT_EN)) 76762306a36Sopenharmony_ci rtw89_ser_notify(rtwdev, rtw89_mac_get_err_status(rtwdev)); 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci if (unlikely(isrs.halt_c2h_isrs & B_AX_WDT_TIMEOUT_INT_EN)) 77062306a36Sopenharmony_ci rtw89_ser_notify(rtwdev, MAC_AX_ERR_L2_ERR_WDT_TIMEOUT_INT); 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci if (unlikely(rtwpci->under_recovery)) 77362306a36Sopenharmony_ci goto enable_intr; 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci if (unlikely(rtwpci->low_power)) { 77662306a36Sopenharmony_ci rtw89_pci_low_power_interrupt_handler(rtwdev); 77762306a36Sopenharmony_ci goto enable_intr; 77862306a36Sopenharmony_ci } 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci if (likely(rtwpci->running)) { 78162306a36Sopenharmony_ci local_bh_disable(); 78262306a36Sopenharmony_ci napi_schedule(&rtwdev->napi); 78362306a36Sopenharmony_ci local_bh_enable(); 78462306a36Sopenharmony_ci } 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci return IRQ_HANDLED; 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_cienable_intr: 78962306a36Sopenharmony_ci spin_lock_irqsave(&rtwpci->irq_lock, flags); 79062306a36Sopenharmony_ci if (likely(rtwpci->running)) 79162306a36Sopenharmony_ci rtw89_chip_enable_intr(rtwdev, rtwpci); 79262306a36Sopenharmony_ci spin_unlock_irqrestore(&rtwpci->irq_lock, flags); 79362306a36Sopenharmony_ci return IRQ_HANDLED; 79462306a36Sopenharmony_ci} 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_cistatic irqreturn_t rtw89_pci_interrupt_handler(int irq, void *dev) 79762306a36Sopenharmony_ci{ 79862306a36Sopenharmony_ci struct rtw89_dev *rtwdev = dev; 79962306a36Sopenharmony_ci struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; 80062306a36Sopenharmony_ci unsigned long flags; 80162306a36Sopenharmony_ci irqreturn_t irqret = IRQ_WAKE_THREAD; 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci spin_lock_irqsave(&rtwpci->irq_lock, flags); 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci /* If interrupt event is on the road, it is still trigger interrupt 80662306a36Sopenharmony_ci * even we have done pci_stop() to turn off IMR. 80762306a36Sopenharmony_ci */ 80862306a36Sopenharmony_ci if (unlikely(!rtwpci->running)) { 80962306a36Sopenharmony_ci irqret = IRQ_HANDLED; 81062306a36Sopenharmony_ci goto exit; 81162306a36Sopenharmony_ci } 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci rtw89_chip_disable_intr(rtwdev, rtwpci); 81462306a36Sopenharmony_ciexit: 81562306a36Sopenharmony_ci spin_unlock_irqrestore(&rtwpci->irq_lock, flags); 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci return irqret; 81862306a36Sopenharmony_ci} 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci#define DEF_TXCHADDRS_TYPE1(info, txch, v...) \ 82162306a36Sopenharmony_ci [RTW89_TXCH_##txch] = { \ 82262306a36Sopenharmony_ci .num = R_AX_##txch##_TXBD_NUM ##v, \ 82362306a36Sopenharmony_ci .idx = R_AX_##txch##_TXBD_IDX ##v, \ 82462306a36Sopenharmony_ci .bdram = R_AX_##txch##_BDRAM_CTRL ##v, \ 82562306a36Sopenharmony_ci .desa_l = R_AX_##txch##_TXBD_DESA_L ##v, \ 82662306a36Sopenharmony_ci .desa_h = R_AX_##txch##_TXBD_DESA_H ##v, \ 82762306a36Sopenharmony_ci } 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci#define DEF_TXCHADDRS(info, txch, v...) \ 83062306a36Sopenharmony_ci [RTW89_TXCH_##txch] = { \ 83162306a36Sopenharmony_ci .num = R_AX_##txch##_TXBD_NUM, \ 83262306a36Sopenharmony_ci .idx = R_AX_##txch##_TXBD_IDX, \ 83362306a36Sopenharmony_ci .bdram = R_AX_##txch##_BDRAM_CTRL ##v, \ 83462306a36Sopenharmony_ci .desa_l = R_AX_##txch##_TXBD_DESA_L ##v, \ 83562306a36Sopenharmony_ci .desa_h = R_AX_##txch##_TXBD_DESA_H ##v, \ 83662306a36Sopenharmony_ci } 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci#define DEF_RXCHADDRS(info, rxch, v...) \ 83962306a36Sopenharmony_ci [RTW89_RXCH_##rxch] = { \ 84062306a36Sopenharmony_ci .num = R_AX_##rxch##_RXBD_NUM ##v, \ 84162306a36Sopenharmony_ci .idx = R_AX_##rxch##_RXBD_IDX ##v, \ 84262306a36Sopenharmony_ci .desa_l = R_AX_##rxch##_RXBD_DESA_L ##v, \ 84362306a36Sopenharmony_ci .desa_h = R_AX_##rxch##_RXBD_DESA_H ##v, \ 84462306a36Sopenharmony_ci } 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ciconst struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set = { 84762306a36Sopenharmony_ci .tx = { 84862306a36Sopenharmony_ci DEF_TXCHADDRS(info, ACH0), 84962306a36Sopenharmony_ci DEF_TXCHADDRS(info, ACH1), 85062306a36Sopenharmony_ci DEF_TXCHADDRS(info, ACH2), 85162306a36Sopenharmony_ci DEF_TXCHADDRS(info, ACH3), 85262306a36Sopenharmony_ci DEF_TXCHADDRS(info, ACH4), 85362306a36Sopenharmony_ci DEF_TXCHADDRS(info, ACH5), 85462306a36Sopenharmony_ci DEF_TXCHADDRS(info, ACH6), 85562306a36Sopenharmony_ci DEF_TXCHADDRS(info, ACH7), 85662306a36Sopenharmony_ci DEF_TXCHADDRS(info, CH8), 85762306a36Sopenharmony_ci DEF_TXCHADDRS(info, CH9), 85862306a36Sopenharmony_ci DEF_TXCHADDRS_TYPE1(info, CH10), 85962306a36Sopenharmony_ci DEF_TXCHADDRS_TYPE1(info, CH11), 86062306a36Sopenharmony_ci DEF_TXCHADDRS(info, CH12), 86162306a36Sopenharmony_ci }, 86262306a36Sopenharmony_ci .rx = { 86362306a36Sopenharmony_ci DEF_RXCHADDRS(info, RXQ), 86462306a36Sopenharmony_ci DEF_RXCHADDRS(info, RPQ), 86562306a36Sopenharmony_ci }, 86662306a36Sopenharmony_ci}; 86762306a36Sopenharmony_ciEXPORT_SYMBOL(rtw89_pci_ch_dma_addr_set); 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ciconst struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set_v1 = { 87062306a36Sopenharmony_ci .tx = { 87162306a36Sopenharmony_ci DEF_TXCHADDRS(info, ACH0, _V1), 87262306a36Sopenharmony_ci DEF_TXCHADDRS(info, ACH1, _V1), 87362306a36Sopenharmony_ci DEF_TXCHADDRS(info, ACH2, _V1), 87462306a36Sopenharmony_ci DEF_TXCHADDRS(info, ACH3, _V1), 87562306a36Sopenharmony_ci DEF_TXCHADDRS(info, ACH4, _V1), 87662306a36Sopenharmony_ci DEF_TXCHADDRS(info, ACH5, _V1), 87762306a36Sopenharmony_ci DEF_TXCHADDRS(info, ACH6, _V1), 87862306a36Sopenharmony_ci DEF_TXCHADDRS(info, ACH7, _V1), 87962306a36Sopenharmony_ci DEF_TXCHADDRS(info, CH8, _V1), 88062306a36Sopenharmony_ci DEF_TXCHADDRS(info, CH9, _V1), 88162306a36Sopenharmony_ci DEF_TXCHADDRS_TYPE1(info, CH10, _V1), 88262306a36Sopenharmony_ci DEF_TXCHADDRS_TYPE1(info, CH11, _V1), 88362306a36Sopenharmony_ci DEF_TXCHADDRS(info, CH12, _V1), 88462306a36Sopenharmony_ci }, 88562306a36Sopenharmony_ci .rx = { 88662306a36Sopenharmony_ci DEF_RXCHADDRS(info, RXQ, _V1), 88762306a36Sopenharmony_ci DEF_RXCHADDRS(info, RPQ, _V1), 88862306a36Sopenharmony_ci }, 88962306a36Sopenharmony_ci}; 89062306a36Sopenharmony_ciEXPORT_SYMBOL(rtw89_pci_ch_dma_addr_set_v1); 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci#undef DEF_TXCHADDRS_TYPE1 89362306a36Sopenharmony_ci#undef DEF_TXCHADDRS 89462306a36Sopenharmony_ci#undef DEF_RXCHADDRS 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_cistatic int rtw89_pci_get_txch_addrs(struct rtw89_dev *rtwdev, 89762306a36Sopenharmony_ci enum rtw89_tx_channel txch, 89862306a36Sopenharmony_ci const struct rtw89_pci_ch_dma_addr **addr) 89962306a36Sopenharmony_ci{ 90062306a36Sopenharmony_ci const struct rtw89_pci_info *info = rtwdev->pci_info; 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci if (txch >= RTW89_TXCH_NUM) 90362306a36Sopenharmony_ci return -EINVAL; 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci *addr = &info->dma_addr_set->tx[txch]; 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci return 0; 90862306a36Sopenharmony_ci} 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_cistatic int rtw89_pci_get_rxch_addrs(struct rtw89_dev *rtwdev, 91162306a36Sopenharmony_ci enum rtw89_rx_channel rxch, 91262306a36Sopenharmony_ci const struct rtw89_pci_ch_dma_addr **addr) 91362306a36Sopenharmony_ci{ 91462306a36Sopenharmony_ci const struct rtw89_pci_info *info = rtwdev->pci_info; 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci if (rxch >= RTW89_RXCH_NUM) 91762306a36Sopenharmony_ci return -EINVAL; 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci *addr = &info->dma_addr_set->rx[rxch]; 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci return 0; 92262306a36Sopenharmony_ci} 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_cistatic u32 rtw89_pci_get_avail_txbd_num(struct rtw89_pci_tx_ring *ring) 92562306a36Sopenharmony_ci{ 92662306a36Sopenharmony_ci struct rtw89_pci_dma_ring *bd_ring = &ring->bd_ring; 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci /* reserved 1 desc check ring is full or not */ 92962306a36Sopenharmony_ci if (bd_ring->rp > bd_ring->wp) 93062306a36Sopenharmony_ci return bd_ring->rp - bd_ring->wp - 1; 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci return bd_ring->len - (bd_ring->wp - bd_ring->rp) - 1; 93362306a36Sopenharmony_ci} 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_cistatic 93662306a36Sopenharmony_ciu32 __rtw89_pci_check_and_reclaim_tx_fwcmd_resource(struct rtw89_dev *rtwdev) 93762306a36Sopenharmony_ci{ 93862306a36Sopenharmony_ci struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; 93962306a36Sopenharmony_ci struct rtw89_pci_tx_ring *tx_ring = &rtwpci->tx_rings[RTW89_TXCH_CH12]; 94062306a36Sopenharmony_ci u32 cnt; 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci spin_lock_bh(&rtwpci->trx_lock); 94362306a36Sopenharmony_ci rtw89_pci_reclaim_tx_fwcmd(rtwdev, rtwpci); 94462306a36Sopenharmony_ci cnt = rtw89_pci_get_avail_txbd_num(tx_ring); 94562306a36Sopenharmony_ci spin_unlock_bh(&rtwpci->trx_lock); 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci return cnt; 94862306a36Sopenharmony_ci} 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_cistatic 95162306a36Sopenharmony_ciu32 __rtw89_pci_check_and_reclaim_tx_resource_noio(struct rtw89_dev *rtwdev, 95262306a36Sopenharmony_ci u8 txch) 95362306a36Sopenharmony_ci{ 95462306a36Sopenharmony_ci struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; 95562306a36Sopenharmony_ci struct rtw89_pci_tx_ring *tx_ring = &rtwpci->tx_rings[txch]; 95662306a36Sopenharmony_ci struct rtw89_pci_tx_wd_ring *wd_ring = &tx_ring->wd_ring; 95762306a36Sopenharmony_ci u32 cnt; 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci spin_lock_bh(&rtwpci->trx_lock); 96062306a36Sopenharmony_ci cnt = rtw89_pci_get_avail_txbd_num(tx_ring); 96162306a36Sopenharmony_ci cnt = min(cnt, wd_ring->curr_num); 96262306a36Sopenharmony_ci spin_unlock_bh(&rtwpci->trx_lock); 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci return cnt; 96562306a36Sopenharmony_ci} 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_cistatic u32 __rtw89_pci_check_and_reclaim_tx_resource(struct rtw89_dev *rtwdev, 96862306a36Sopenharmony_ci u8 txch) 96962306a36Sopenharmony_ci{ 97062306a36Sopenharmony_ci struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; 97162306a36Sopenharmony_ci struct rtw89_pci_tx_ring *tx_ring = &rtwpci->tx_rings[txch]; 97262306a36Sopenharmony_ci struct rtw89_pci_tx_wd_ring *wd_ring = &tx_ring->wd_ring; 97362306a36Sopenharmony_ci const struct rtw89_chip_info *chip = rtwdev->chip; 97462306a36Sopenharmony_ci u32 bd_cnt, wd_cnt, min_cnt = 0; 97562306a36Sopenharmony_ci struct rtw89_pci_rx_ring *rx_ring; 97662306a36Sopenharmony_ci enum rtw89_debug_mask debug_mask; 97762306a36Sopenharmony_ci u32 cnt; 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci rx_ring = &rtwpci->rx_rings[RTW89_RXCH_RPQ]; 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci spin_lock_bh(&rtwpci->trx_lock); 98262306a36Sopenharmony_ci bd_cnt = rtw89_pci_get_avail_txbd_num(tx_ring); 98362306a36Sopenharmony_ci wd_cnt = wd_ring->curr_num; 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci if (wd_cnt == 0 || bd_cnt == 0) { 98662306a36Sopenharmony_ci cnt = rtw89_pci_rxbd_recalc(rtwdev, rx_ring); 98762306a36Sopenharmony_ci if (cnt) 98862306a36Sopenharmony_ci rtw89_pci_release_tx(rtwdev, rx_ring, cnt); 98962306a36Sopenharmony_ci else if (wd_cnt == 0) 99062306a36Sopenharmony_ci goto out_unlock; 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci bd_cnt = rtw89_pci_get_avail_txbd_num(tx_ring); 99362306a36Sopenharmony_ci if (bd_cnt == 0) 99462306a36Sopenharmony_ci rtw89_pci_reclaim_txbd(rtwdev, tx_ring); 99562306a36Sopenharmony_ci } 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci bd_cnt = rtw89_pci_get_avail_txbd_num(tx_ring); 99862306a36Sopenharmony_ci wd_cnt = wd_ring->curr_num; 99962306a36Sopenharmony_ci min_cnt = min(bd_cnt, wd_cnt); 100062306a36Sopenharmony_ci if (min_cnt == 0) { 100162306a36Sopenharmony_ci /* This message can be frequently shown in low power mode or 100262306a36Sopenharmony_ci * high traffic with small FIFO chips, and we have recognized it as normal 100362306a36Sopenharmony_ci * behavior, so print with mask RTW89_DBG_TXRX in these situations. 100462306a36Sopenharmony_ci */ 100562306a36Sopenharmony_ci if (rtwpci->low_power || chip->small_fifo_size) 100662306a36Sopenharmony_ci debug_mask = RTW89_DBG_TXRX; 100762306a36Sopenharmony_ci else 100862306a36Sopenharmony_ci debug_mask = RTW89_DBG_UNEXP; 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci rtw89_debug(rtwdev, debug_mask, 101162306a36Sopenharmony_ci "still no tx resource after reclaim: wd_cnt=%d bd_cnt=%d\n", 101262306a36Sopenharmony_ci wd_cnt, bd_cnt); 101362306a36Sopenharmony_ci } 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ciout_unlock: 101662306a36Sopenharmony_ci spin_unlock_bh(&rtwpci->trx_lock); 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci return min_cnt; 101962306a36Sopenharmony_ci} 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_cistatic u32 rtw89_pci_check_and_reclaim_tx_resource(struct rtw89_dev *rtwdev, 102262306a36Sopenharmony_ci u8 txch) 102362306a36Sopenharmony_ci{ 102462306a36Sopenharmony_ci if (rtwdev->hci.paused) 102562306a36Sopenharmony_ci return __rtw89_pci_check_and_reclaim_tx_resource_noio(rtwdev, txch); 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci if (txch == RTW89_TXCH_CH12) 102862306a36Sopenharmony_ci return __rtw89_pci_check_and_reclaim_tx_fwcmd_resource(rtwdev); 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci return __rtw89_pci_check_and_reclaim_tx_resource(rtwdev, txch); 103162306a36Sopenharmony_ci} 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_cistatic void __rtw89_pci_tx_kick_off(struct rtw89_dev *rtwdev, struct rtw89_pci_tx_ring *tx_ring) 103462306a36Sopenharmony_ci{ 103562306a36Sopenharmony_ci struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; 103662306a36Sopenharmony_ci struct rtw89_pci_dma_ring *bd_ring = &tx_ring->bd_ring; 103762306a36Sopenharmony_ci u32 host_idx, addr; 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci spin_lock_bh(&rtwpci->trx_lock); 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci addr = bd_ring->addr.idx; 104262306a36Sopenharmony_ci host_idx = bd_ring->wp; 104362306a36Sopenharmony_ci rtw89_write16(rtwdev, addr, host_idx); 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_ci spin_unlock_bh(&rtwpci->trx_lock); 104662306a36Sopenharmony_ci} 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_cistatic void rtw89_pci_tx_bd_ring_update(struct rtw89_dev *rtwdev, struct rtw89_pci_tx_ring *tx_ring, 104962306a36Sopenharmony_ci int n_txbd) 105062306a36Sopenharmony_ci{ 105162306a36Sopenharmony_ci struct rtw89_pci_dma_ring *bd_ring = &tx_ring->bd_ring; 105262306a36Sopenharmony_ci u32 host_idx, len; 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci len = bd_ring->len; 105562306a36Sopenharmony_ci host_idx = bd_ring->wp + n_txbd; 105662306a36Sopenharmony_ci host_idx = host_idx < len ? host_idx : host_idx - len; 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci bd_ring->wp = host_idx; 105962306a36Sopenharmony_ci} 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_cistatic void rtw89_pci_ops_tx_kick_off(struct rtw89_dev *rtwdev, u8 txch) 106262306a36Sopenharmony_ci{ 106362306a36Sopenharmony_ci struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; 106462306a36Sopenharmony_ci struct rtw89_pci_tx_ring *tx_ring = &rtwpci->tx_rings[txch]; 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_ci if (rtwdev->hci.paused) { 106762306a36Sopenharmony_ci set_bit(txch, rtwpci->kick_map); 106862306a36Sopenharmony_ci return; 106962306a36Sopenharmony_ci } 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci __rtw89_pci_tx_kick_off(rtwdev, tx_ring); 107262306a36Sopenharmony_ci} 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_cistatic void rtw89_pci_tx_kick_off_pending(struct rtw89_dev *rtwdev) 107562306a36Sopenharmony_ci{ 107662306a36Sopenharmony_ci struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; 107762306a36Sopenharmony_ci struct rtw89_pci_tx_ring *tx_ring; 107862306a36Sopenharmony_ci int txch; 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci for (txch = 0; txch < RTW89_TXCH_NUM; txch++) { 108162306a36Sopenharmony_ci if (!test_and_clear_bit(txch, rtwpci->kick_map)) 108262306a36Sopenharmony_ci continue; 108362306a36Sopenharmony_ci 108462306a36Sopenharmony_ci tx_ring = &rtwpci->tx_rings[txch]; 108562306a36Sopenharmony_ci __rtw89_pci_tx_kick_off(rtwdev, tx_ring); 108662306a36Sopenharmony_ci } 108762306a36Sopenharmony_ci} 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_cistatic void __pci_flush_txch(struct rtw89_dev *rtwdev, u8 txch, bool drop) 109062306a36Sopenharmony_ci{ 109162306a36Sopenharmony_ci struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; 109262306a36Sopenharmony_ci struct rtw89_pci_tx_ring *tx_ring = &rtwpci->tx_rings[txch]; 109362306a36Sopenharmony_ci struct rtw89_pci_dma_ring *bd_ring = &tx_ring->bd_ring; 109462306a36Sopenharmony_ci u32 cur_idx, cur_rp; 109562306a36Sopenharmony_ci u8 i; 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_ci /* Because the time taked by the I/O is a bit dynamic, it's hard to 109862306a36Sopenharmony_ci * define a reasonable fixed total timeout to use read_poll_timeout* 109962306a36Sopenharmony_ci * helper. Instead, we can ensure a reasonable polling times, so we 110062306a36Sopenharmony_ci * just use for loop with udelay here. 110162306a36Sopenharmony_ci */ 110262306a36Sopenharmony_ci for (i = 0; i < 60; i++) { 110362306a36Sopenharmony_ci cur_idx = rtw89_read32(rtwdev, bd_ring->addr.idx); 110462306a36Sopenharmony_ci cur_rp = FIELD_GET(TXBD_HW_IDX_MASK, cur_idx); 110562306a36Sopenharmony_ci if (cur_rp == bd_ring->wp) 110662306a36Sopenharmony_ci return; 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci udelay(1); 110962306a36Sopenharmony_ci } 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci if (!drop) 111262306a36Sopenharmony_ci rtw89_info(rtwdev, "timed out to flush pci txch: %d\n", txch); 111362306a36Sopenharmony_ci} 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_cistatic void __rtw89_pci_ops_flush_txchs(struct rtw89_dev *rtwdev, u32 txchs, 111662306a36Sopenharmony_ci bool drop) 111762306a36Sopenharmony_ci{ 111862306a36Sopenharmony_ci const struct rtw89_pci_info *info = rtwdev->pci_info; 111962306a36Sopenharmony_ci u8 i; 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci for (i = 0; i < RTW89_TXCH_NUM; i++) { 112262306a36Sopenharmony_ci /* It may be unnecessary to flush FWCMD queue. */ 112362306a36Sopenharmony_ci if (i == RTW89_TXCH_CH12) 112462306a36Sopenharmony_ci continue; 112562306a36Sopenharmony_ci if (info->tx_dma_ch_mask & BIT(i)) 112662306a36Sopenharmony_ci continue; 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_ci if (txchs & BIT(i)) 112962306a36Sopenharmony_ci __pci_flush_txch(rtwdev, i, drop); 113062306a36Sopenharmony_ci } 113162306a36Sopenharmony_ci} 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_cistatic void rtw89_pci_ops_flush_queues(struct rtw89_dev *rtwdev, u32 queues, 113462306a36Sopenharmony_ci bool drop) 113562306a36Sopenharmony_ci{ 113662306a36Sopenharmony_ci __rtw89_pci_ops_flush_txchs(rtwdev, BIT(RTW89_TXCH_NUM) - 1, drop); 113762306a36Sopenharmony_ci} 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_ciu32 rtw89_pci_fill_txaddr_info(struct rtw89_dev *rtwdev, 114062306a36Sopenharmony_ci void *txaddr_info_addr, u32 total_len, 114162306a36Sopenharmony_ci dma_addr_t dma, u8 *add_info_nr) 114262306a36Sopenharmony_ci{ 114362306a36Sopenharmony_ci struct rtw89_pci_tx_addr_info_32 *txaddr_info = txaddr_info_addr; 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci txaddr_info->length = cpu_to_le16(total_len); 114662306a36Sopenharmony_ci txaddr_info->option = cpu_to_le16(RTW89_PCI_ADDR_MSDU_LS | 114762306a36Sopenharmony_ci RTW89_PCI_ADDR_NUM(1)); 114862306a36Sopenharmony_ci txaddr_info->dma = cpu_to_le32(dma); 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_ci *add_info_nr = 1; 115162306a36Sopenharmony_ci 115262306a36Sopenharmony_ci return sizeof(*txaddr_info); 115362306a36Sopenharmony_ci} 115462306a36Sopenharmony_ciEXPORT_SYMBOL(rtw89_pci_fill_txaddr_info); 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_ciu32 rtw89_pci_fill_txaddr_info_v1(struct rtw89_dev *rtwdev, 115762306a36Sopenharmony_ci void *txaddr_info_addr, u32 total_len, 115862306a36Sopenharmony_ci dma_addr_t dma, u8 *add_info_nr) 115962306a36Sopenharmony_ci{ 116062306a36Sopenharmony_ci struct rtw89_pci_tx_addr_info_32_v1 *txaddr_info = txaddr_info_addr; 116162306a36Sopenharmony_ci u32 remain = total_len; 116262306a36Sopenharmony_ci u32 len; 116362306a36Sopenharmony_ci u16 length_option; 116462306a36Sopenharmony_ci int n; 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci for (n = 0; n < RTW89_TXADDR_INFO_NR_V1 && remain; n++) { 116762306a36Sopenharmony_ci len = remain >= TXADDR_INFO_LENTHG_V1_MAX ? 116862306a36Sopenharmony_ci TXADDR_INFO_LENTHG_V1_MAX : remain; 116962306a36Sopenharmony_ci remain -= len; 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_ci length_option = FIELD_PREP(B_PCIADDR_LEN_V1_MASK, len) | 117262306a36Sopenharmony_ci FIELD_PREP(B_PCIADDR_HIGH_SEL_V1_MASK, 0) | 117362306a36Sopenharmony_ci FIELD_PREP(B_PCIADDR_LS_V1_MASK, remain == 0); 117462306a36Sopenharmony_ci txaddr_info->length_opt = cpu_to_le16(length_option); 117562306a36Sopenharmony_ci txaddr_info->dma_low_lsb = cpu_to_le16(FIELD_GET(GENMASK(15, 0), dma)); 117662306a36Sopenharmony_ci txaddr_info->dma_low_msb = cpu_to_le16(FIELD_GET(GENMASK(31, 16), dma)); 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_ci dma += len; 117962306a36Sopenharmony_ci txaddr_info++; 118062306a36Sopenharmony_ci } 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci WARN_ONCE(remain, "length overflow remain=%u total_len=%u", 118362306a36Sopenharmony_ci remain, total_len); 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci *add_info_nr = n; 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_ci return n * sizeof(*txaddr_info); 118862306a36Sopenharmony_ci} 118962306a36Sopenharmony_ciEXPORT_SYMBOL(rtw89_pci_fill_txaddr_info_v1); 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_cistatic int rtw89_pci_txwd_submit(struct rtw89_dev *rtwdev, 119262306a36Sopenharmony_ci struct rtw89_pci_tx_ring *tx_ring, 119362306a36Sopenharmony_ci struct rtw89_pci_tx_wd *txwd, 119462306a36Sopenharmony_ci struct rtw89_core_tx_request *tx_req) 119562306a36Sopenharmony_ci{ 119662306a36Sopenharmony_ci struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; 119762306a36Sopenharmony_ci const struct rtw89_chip_info *chip = rtwdev->chip; 119862306a36Sopenharmony_ci struct rtw89_tx_desc_info *desc_info = &tx_req->desc_info; 119962306a36Sopenharmony_ci struct rtw89_txwd_info *txwd_info; 120062306a36Sopenharmony_ci struct rtw89_pci_tx_wp_info *txwp_info; 120162306a36Sopenharmony_ci void *txaddr_info_addr; 120262306a36Sopenharmony_ci struct pci_dev *pdev = rtwpci->pdev; 120362306a36Sopenharmony_ci struct sk_buff *skb = tx_req->skb; 120462306a36Sopenharmony_ci struct rtw89_pci_tx_data *tx_data = RTW89_PCI_TX_SKB_CB(skb); 120562306a36Sopenharmony_ci struct rtw89_tx_skb_data *skb_data = RTW89_TX_SKB_CB(skb); 120662306a36Sopenharmony_ci bool en_wd_info = desc_info->en_wd_info; 120762306a36Sopenharmony_ci u32 txwd_len; 120862306a36Sopenharmony_ci u32 txwp_len; 120962306a36Sopenharmony_ci u32 txaddr_info_len; 121062306a36Sopenharmony_ci dma_addr_t dma; 121162306a36Sopenharmony_ci int ret; 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci dma = dma_map_single(&pdev->dev, skb->data, skb->len, DMA_TO_DEVICE); 121462306a36Sopenharmony_ci if (dma_mapping_error(&pdev->dev, dma)) { 121562306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to map skb dma data\n"); 121662306a36Sopenharmony_ci ret = -EBUSY; 121762306a36Sopenharmony_ci goto err; 121862306a36Sopenharmony_ci } 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_ci tx_data->dma = dma; 122162306a36Sopenharmony_ci rcu_assign_pointer(skb_data->wait, NULL); 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_ci txwp_len = sizeof(*txwp_info); 122462306a36Sopenharmony_ci txwd_len = chip->txwd_body_size; 122562306a36Sopenharmony_ci txwd_len += en_wd_info ? sizeof(*txwd_info) : 0; 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_ci txwp_info = txwd->vaddr + txwd_len; 122862306a36Sopenharmony_ci txwp_info->seq0 = cpu_to_le16(txwd->seq | RTW89_PCI_TXWP_VALID); 122962306a36Sopenharmony_ci txwp_info->seq1 = 0; 123062306a36Sopenharmony_ci txwp_info->seq2 = 0; 123162306a36Sopenharmony_ci txwp_info->seq3 = 0; 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci tx_ring->tx_cnt++; 123462306a36Sopenharmony_ci txaddr_info_addr = txwd->vaddr + txwd_len + txwp_len; 123562306a36Sopenharmony_ci txaddr_info_len = 123662306a36Sopenharmony_ci rtw89_chip_fill_txaddr_info(rtwdev, txaddr_info_addr, skb->len, 123762306a36Sopenharmony_ci dma, &desc_info->addr_info_nr); 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_ci txwd->len = txwd_len + txwp_len + txaddr_info_len; 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci rtw89_chip_fill_txdesc(rtwdev, desc_info, txwd->vaddr); 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci skb_queue_tail(&txwd->queue, skb); 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci return 0; 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_cierr: 124862306a36Sopenharmony_ci return ret; 124962306a36Sopenharmony_ci} 125062306a36Sopenharmony_ci 125162306a36Sopenharmony_cistatic int rtw89_pci_fwcmd_submit(struct rtw89_dev *rtwdev, 125262306a36Sopenharmony_ci struct rtw89_pci_tx_ring *tx_ring, 125362306a36Sopenharmony_ci struct rtw89_pci_tx_bd_32 *txbd, 125462306a36Sopenharmony_ci struct rtw89_core_tx_request *tx_req) 125562306a36Sopenharmony_ci{ 125662306a36Sopenharmony_ci struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; 125762306a36Sopenharmony_ci const struct rtw89_chip_info *chip = rtwdev->chip; 125862306a36Sopenharmony_ci struct rtw89_tx_desc_info *desc_info = &tx_req->desc_info; 125962306a36Sopenharmony_ci void *txdesc; 126062306a36Sopenharmony_ci int txdesc_size = chip->h2c_desc_size; 126162306a36Sopenharmony_ci struct pci_dev *pdev = rtwpci->pdev; 126262306a36Sopenharmony_ci struct sk_buff *skb = tx_req->skb; 126362306a36Sopenharmony_ci struct rtw89_pci_tx_data *tx_data = RTW89_PCI_TX_SKB_CB(skb); 126462306a36Sopenharmony_ci dma_addr_t dma; 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci txdesc = skb_push(skb, txdesc_size); 126762306a36Sopenharmony_ci memset(txdesc, 0, txdesc_size); 126862306a36Sopenharmony_ci rtw89_chip_fill_txdesc_fwcmd(rtwdev, desc_info, txdesc); 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_ci dma = dma_map_single(&pdev->dev, skb->data, skb->len, DMA_TO_DEVICE); 127162306a36Sopenharmony_ci if (dma_mapping_error(&pdev->dev, dma)) { 127262306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to map fwcmd dma data\n"); 127362306a36Sopenharmony_ci return -EBUSY; 127462306a36Sopenharmony_ci } 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci tx_data->dma = dma; 127762306a36Sopenharmony_ci txbd->option = cpu_to_le16(RTW89_PCI_TXBD_OPTION_LS); 127862306a36Sopenharmony_ci txbd->length = cpu_to_le16(skb->len); 127962306a36Sopenharmony_ci txbd->dma = cpu_to_le32(tx_data->dma); 128062306a36Sopenharmony_ci skb_queue_tail(&rtwpci->h2c_queue, skb); 128162306a36Sopenharmony_ci 128262306a36Sopenharmony_ci rtw89_pci_tx_bd_ring_update(rtwdev, tx_ring, 1); 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_ci return 0; 128562306a36Sopenharmony_ci} 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_cistatic int rtw89_pci_txbd_submit(struct rtw89_dev *rtwdev, 128862306a36Sopenharmony_ci struct rtw89_pci_tx_ring *tx_ring, 128962306a36Sopenharmony_ci struct rtw89_pci_tx_bd_32 *txbd, 129062306a36Sopenharmony_ci struct rtw89_core_tx_request *tx_req) 129162306a36Sopenharmony_ci{ 129262306a36Sopenharmony_ci struct rtw89_pci_tx_wd *txwd; 129362306a36Sopenharmony_ci int ret; 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ci /* FWCMD queue doesn't have wd pages. Instead, it submits the CMD 129662306a36Sopenharmony_ci * buffer with WD BODY only. So here we don't need to check the free 129762306a36Sopenharmony_ci * pages of the wd ring. 129862306a36Sopenharmony_ci */ 129962306a36Sopenharmony_ci if (tx_ring->txch == RTW89_TXCH_CH12) 130062306a36Sopenharmony_ci return rtw89_pci_fwcmd_submit(rtwdev, tx_ring, txbd, tx_req); 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci txwd = rtw89_pci_dequeue_txwd(tx_ring); 130362306a36Sopenharmony_ci if (!txwd) { 130462306a36Sopenharmony_ci rtw89_err(rtwdev, "no available TXWD\n"); 130562306a36Sopenharmony_ci ret = -ENOSPC; 130662306a36Sopenharmony_ci goto err; 130762306a36Sopenharmony_ci } 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_ci ret = rtw89_pci_txwd_submit(rtwdev, tx_ring, txwd, tx_req); 131062306a36Sopenharmony_ci if (ret) { 131162306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to submit TXWD %d\n", txwd->seq); 131262306a36Sopenharmony_ci goto err_enqueue_wd; 131362306a36Sopenharmony_ci } 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_ci list_add_tail(&txwd->list, &tx_ring->busy_pages); 131662306a36Sopenharmony_ci 131762306a36Sopenharmony_ci txbd->option = cpu_to_le16(RTW89_PCI_TXBD_OPTION_LS); 131862306a36Sopenharmony_ci txbd->length = cpu_to_le16(txwd->len); 131962306a36Sopenharmony_ci txbd->dma = cpu_to_le32(txwd->paddr); 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_ci rtw89_pci_tx_bd_ring_update(rtwdev, tx_ring, 1); 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_ci return 0; 132462306a36Sopenharmony_ci 132562306a36Sopenharmony_cierr_enqueue_wd: 132662306a36Sopenharmony_ci rtw89_pci_enqueue_txwd(tx_ring, txwd); 132762306a36Sopenharmony_cierr: 132862306a36Sopenharmony_ci return ret; 132962306a36Sopenharmony_ci} 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_cistatic int rtw89_pci_tx_write(struct rtw89_dev *rtwdev, struct rtw89_core_tx_request *tx_req, 133262306a36Sopenharmony_ci u8 txch) 133362306a36Sopenharmony_ci{ 133462306a36Sopenharmony_ci struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; 133562306a36Sopenharmony_ci struct rtw89_pci_tx_ring *tx_ring; 133662306a36Sopenharmony_ci struct rtw89_pci_tx_bd_32 *txbd; 133762306a36Sopenharmony_ci u32 n_avail_txbd; 133862306a36Sopenharmony_ci int ret = 0; 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_ci /* check the tx type and dma channel for fw cmd queue */ 134162306a36Sopenharmony_ci if ((txch == RTW89_TXCH_CH12 || 134262306a36Sopenharmony_ci tx_req->tx_type == RTW89_CORE_TX_TYPE_FWCMD) && 134362306a36Sopenharmony_ci (txch != RTW89_TXCH_CH12 || 134462306a36Sopenharmony_ci tx_req->tx_type != RTW89_CORE_TX_TYPE_FWCMD)) { 134562306a36Sopenharmony_ci rtw89_err(rtwdev, "only fw cmd uses dma channel 12\n"); 134662306a36Sopenharmony_ci return -EINVAL; 134762306a36Sopenharmony_ci } 134862306a36Sopenharmony_ci 134962306a36Sopenharmony_ci tx_ring = &rtwpci->tx_rings[txch]; 135062306a36Sopenharmony_ci spin_lock_bh(&rtwpci->trx_lock); 135162306a36Sopenharmony_ci 135262306a36Sopenharmony_ci n_avail_txbd = rtw89_pci_get_avail_txbd_num(tx_ring); 135362306a36Sopenharmony_ci if (n_avail_txbd == 0) { 135462306a36Sopenharmony_ci rtw89_err(rtwdev, "no available TXBD\n"); 135562306a36Sopenharmony_ci ret = -ENOSPC; 135662306a36Sopenharmony_ci goto err_unlock; 135762306a36Sopenharmony_ci } 135862306a36Sopenharmony_ci 135962306a36Sopenharmony_ci txbd = rtw89_pci_get_next_txbd(tx_ring); 136062306a36Sopenharmony_ci ret = rtw89_pci_txbd_submit(rtwdev, tx_ring, txbd, tx_req); 136162306a36Sopenharmony_ci if (ret) { 136262306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to submit TXBD\n"); 136362306a36Sopenharmony_ci goto err_unlock; 136462306a36Sopenharmony_ci } 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_ci spin_unlock_bh(&rtwpci->trx_lock); 136762306a36Sopenharmony_ci return 0; 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_cierr_unlock: 137062306a36Sopenharmony_ci spin_unlock_bh(&rtwpci->trx_lock); 137162306a36Sopenharmony_ci return ret; 137262306a36Sopenharmony_ci} 137362306a36Sopenharmony_ci 137462306a36Sopenharmony_cistatic int rtw89_pci_ops_tx_write(struct rtw89_dev *rtwdev, struct rtw89_core_tx_request *tx_req) 137562306a36Sopenharmony_ci{ 137662306a36Sopenharmony_ci struct rtw89_tx_desc_info *desc_info = &tx_req->desc_info; 137762306a36Sopenharmony_ci int ret; 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_ci ret = rtw89_pci_tx_write(rtwdev, tx_req, desc_info->ch_dma); 138062306a36Sopenharmony_ci if (ret) { 138162306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to TX Queue %d\n", desc_info->ch_dma); 138262306a36Sopenharmony_ci return ret; 138362306a36Sopenharmony_ci } 138462306a36Sopenharmony_ci 138562306a36Sopenharmony_ci return 0; 138662306a36Sopenharmony_ci} 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_ciconst struct rtw89_pci_bd_ram rtw89_bd_ram_table_dual[RTW89_TXCH_NUM] = { 138962306a36Sopenharmony_ci [RTW89_TXCH_ACH0] = {.start_idx = 0, .max_num = 5, .min_num = 2}, 139062306a36Sopenharmony_ci [RTW89_TXCH_ACH1] = {.start_idx = 5, .max_num = 5, .min_num = 2}, 139162306a36Sopenharmony_ci [RTW89_TXCH_ACH2] = {.start_idx = 10, .max_num = 5, .min_num = 2}, 139262306a36Sopenharmony_ci [RTW89_TXCH_ACH3] = {.start_idx = 15, .max_num = 5, .min_num = 2}, 139362306a36Sopenharmony_ci [RTW89_TXCH_ACH4] = {.start_idx = 20, .max_num = 5, .min_num = 2}, 139462306a36Sopenharmony_ci [RTW89_TXCH_ACH5] = {.start_idx = 25, .max_num = 5, .min_num = 2}, 139562306a36Sopenharmony_ci [RTW89_TXCH_ACH6] = {.start_idx = 30, .max_num = 5, .min_num = 2}, 139662306a36Sopenharmony_ci [RTW89_TXCH_ACH7] = {.start_idx = 35, .max_num = 5, .min_num = 2}, 139762306a36Sopenharmony_ci [RTW89_TXCH_CH8] = {.start_idx = 40, .max_num = 5, .min_num = 1}, 139862306a36Sopenharmony_ci [RTW89_TXCH_CH9] = {.start_idx = 45, .max_num = 5, .min_num = 1}, 139962306a36Sopenharmony_ci [RTW89_TXCH_CH10] = {.start_idx = 50, .max_num = 5, .min_num = 1}, 140062306a36Sopenharmony_ci [RTW89_TXCH_CH11] = {.start_idx = 55, .max_num = 5, .min_num = 1}, 140162306a36Sopenharmony_ci [RTW89_TXCH_CH12] = {.start_idx = 60, .max_num = 4, .min_num = 1}, 140262306a36Sopenharmony_ci}; 140362306a36Sopenharmony_ciEXPORT_SYMBOL(rtw89_bd_ram_table_dual); 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_ciconst struct rtw89_pci_bd_ram rtw89_bd_ram_table_single[RTW89_TXCH_NUM] = { 140662306a36Sopenharmony_ci [RTW89_TXCH_ACH0] = {.start_idx = 0, .max_num = 5, .min_num = 2}, 140762306a36Sopenharmony_ci [RTW89_TXCH_ACH1] = {.start_idx = 5, .max_num = 5, .min_num = 2}, 140862306a36Sopenharmony_ci [RTW89_TXCH_ACH2] = {.start_idx = 10, .max_num = 5, .min_num = 2}, 140962306a36Sopenharmony_ci [RTW89_TXCH_ACH3] = {.start_idx = 15, .max_num = 5, .min_num = 2}, 141062306a36Sopenharmony_ci [RTW89_TXCH_CH8] = {.start_idx = 20, .max_num = 4, .min_num = 1}, 141162306a36Sopenharmony_ci [RTW89_TXCH_CH9] = {.start_idx = 24, .max_num = 4, .min_num = 1}, 141262306a36Sopenharmony_ci [RTW89_TXCH_CH12] = {.start_idx = 28, .max_num = 4, .min_num = 1}, 141362306a36Sopenharmony_ci}; 141462306a36Sopenharmony_ciEXPORT_SYMBOL(rtw89_bd_ram_table_single); 141562306a36Sopenharmony_ci 141662306a36Sopenharmony_cistatic void rtw89_pci_reset_trx_rings(struct rtw89_dev *rtwdev) 141762306a36Sopenharmony_ci{ 141862306a36Sopenharmony_ci struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; 141962306a36Sopenharmony_ci const struct rtw89_pci_info *info = rtwdev->pci_info; 142062306a36Sopenharmony_ci const struct rtw89_pci_bd_ram *bd_ram_table = *info->bd_ram_table; 142162306a36Sopenharmony_ci struct rtw89_pci_tx_ring *tx_ring; 142262306a36Sopenharmony_ci struct rtw89_pci_rx_ring *rx_ring; 142362306a36Sopenharmony_ci struct rtw89_pci_dma_ring *bd_ring; 142462306a36Sopenharmony_ci const struct rtw89_pci_bd_ram *bd_ram; 142562306a36Sopenharmony_ci u32 addr_num; 142662306a36Sopenharmony_ci u32 addr_bdram; 142762306a36Sopenharmony_ci u32 addr_desa_l; 142862306a36Sopenharmony_ci u32 val32; 142962306a36Sopenharmony_ci int i; 143062306a36Sopenharmony_ci 143162306a36Sopenharmony_ci for (i = 0; i < RTW89_TXCH_NUM; i++) { 143262306a36Sopenharmony_ci if (info->tx_dma_ch_mask & BIT(i)) 143362306a36Sopenharmony_ci continue; 143462306a36Sopenharmony_ci 143562306a36Sopenharmony_ci tx_ring = &rtwpci->tx_rings[i]; 143662306a36Sopenharmony_ci bd_ring = &tx_ring->bd_ring; 143762306a36Sopenharmony_ci bd_ram = &bd_ram_table[i]; 143862306a36Sopenharmony_ci addr_num = bd_ring->addr.num; 143962306a36Sopenharmony_ci addr_bdram = bd_ring->addr.bdram; 144062306a36Sopenharmony_ci addr_desa_l = bd_ring->addr.desa_l; 144162306a36Sopenharmony_ci bd_ring->wp = 0; 144262306a36Sopenharmony_ci bd_ring->rp = 0; 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ci val32 = FIELD_PREP(BDRAM_SIDX_MASK, bd_ram->start_idx) | 144562306a36Sopenharmony_ci FIELD_PREP(BDRAM_MAX_MASK, bd_ram->max_num) | 144662306a36Sopenharmony_ci FIELD_PREP(BDRAM_MIN_MASK, bd_ram->min_num); 144762306a36Sopenharmony_ci 144862306a36Sopenharmony_ci rtw89_write16(rtwdev, addr_num, bd_ring->len); 144962306a36Sopenharmony_ci rtw89_write32(rtwdev, addr_bdram, val32); 145062306a36Sopenharmony_ci rtw89_write32(rtwdev, addr_desa_l, bd_ring->dma); 145162306a36Sopenharmony_ci } 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_ci for (i = 0; i < RTW89_RXCH_NUM; i++) { 145462306a36Sopenharmony_ci rx_ring = &rtwpci->rx_rings[i]; 145562306a36Sopenharmony_ci bd_ring = &rx_ring->bd_ring; 145662306a36Sopenharmony_ci addr_num = bd_ring->addr.num; 145762306a36Sopenharmony_ci addr_desa_l = bd_ring->addr.desa_l; 145862306a36Sopenharmony_ci bd_ring->wp = 0; 145962306a36Sopenharmony_ci bd_ring->rp = 0; 146062306a36Sopenharmony_ci rx_ring->diliver_skb = NULL; 146162306a36Sopenharmony_ci rx_ring->diliver_desc.ready = false; 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_ci rtw89_write16(rtwdev, addr_num, bd_ring->len); 146462306a36Sopenharmony_ci rtw89_write32(rtwdev, addr_desa_l, bd_ring->dma); 146562306a36Sopenharmony_ci } 146662306a36Sopenharmony_ci} 146762306a36Sopenharmony_ci 146862306a36Sopenharmony_cistatic void rtw89_pci_release_tx_ring(struct rtw89_dev *rtwdev, 146962306a36Sopenharmony_ci struct rtw89_pci_tx_ring *tx_ring) 147062306a36Sopenharmony_ci{ 147162306a36Sopenharmony_ci rtw89_pci_release_busy_txwd(rtwdev, tx_ring); 147262306a36Sopenharmony_ci rtw89_pci_release_pending_txwd_skb(rtwdev, tx_ring); 147362306a36Sopenharmony_ci} 147462306a36Sopenharmony_ci 147562306a36Sopenharmony_cistatic void rtw89_pci_ops_reset(struct rtw89_dev *rtwdev) 147662306a36Sopenharmony_ci{ 147762306a36Sopenharmony_ci struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; 147862306a36Sopenharmony_ci const struct rtw89_pci_info *info = rtwdev->pci_info; 147962306a36Sopenharmony_ci int txch; 148062306a36Sopenharmony_ci 148162306a36Sopenharmony_ci rtw89_pci_reset_trx_rings(rtwdev); 148262306a36Sopenharmony_ci 148362306a36Sopenharmony_ci spin_lock_bh(&rtwpci->trx_lock); 148462306a36Sopenharmony_ci for (txch = 0; txch < RTW89_TXCH_NUM; txch++) { 148562306a36Sopenharmony_ci if (info->tx_dma_ch_mask & BIT(txch)) 148662306a36Sopenharmony_ci continue; 148762306a36Sopenharmony_ci if (txch == RTW89_TXCH_CH12) { 148862306a36Sopenharmony_ci rtw89_pci_release_fwcmd(rtwdev, rtwpci, 148962306a36Sopenharmony_ci skb_queue_len(&rtwpci->h2c_queue), true); 149062306a36Sopenharmony_ci continue; 149162306a36Sopenharmony_ci } 149262306a36Sopenharmony_ci rtw89_pci_release_tx_ring(rtwdev, &rtwpci->tx_rings[txch]); 149362306a36Sopenharmony_ci } 149462306a36Sopenharmony_ci spin_unlock_bh(&rtwpci->trx_lock); 149562306a36Sopenharmony_ci} 149662306a36Sopenharmony_ci 149762306a36Sopenharmony_cistatic void rtw89_pci_enable_intr_lock(struct rtw89_dev *rtwdev) 149862306a36Sopenharmony_ci{ 149962306a36Sopenharmony_ci struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; 150062306a36Sopenharmony_ci unsigned long flags; 150162306a36Sopenharmony_ci 150262306a36Sopenharmony_ci spin_lock_irqsave(&rtwpci->irq_lock, flags); 150362306a36Sopenharmony_ci rtwpci->running = true; 150462306a36Sopenharmony_ci rtw89_chip_enable_intr(rtwdev, rtwpci); 150562306a36Sopenharmony_ci spin_unlock_irqrestore(&rtwpci->irq_lock, flags); 150662306a36Sopenharmony_ci} 150762306a36Sopenharmony_ci 150862306a36Sopenharmony_cistatic void rtw89_pci_disable_intr_lock(struct rtw89_dev *rtwdev) 150962306a36Sopenharmony_ci{ 151062306a36Sopenharmony_ci struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; 151162306a36Sopenharmony_ci unsigned long flags; 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_ci spin_lock_irqsave(&rtwpci->irq_lock, flags); 151462306a36Sopenharmony_ci rtwpci->running = false; 151562306a36Sopenharmony_ci rtw89_chip_disable_intr(rtwdev, rtwpci); 151662306a36Sopenharmony_ci spin_unlock_irqrestore(&rtwpci->irq_lock, flags); 151762306a36Sopenharmony_ci} 151862306a36Sopenharmony_ci 151962306a36Sopenharmony_cistatic int rtw89_pci_ops_start(struct rtw89_dev *rtwdev) 152062306a36Sopenharmony_ci{ 152162306a36Sopenharmony_ci rtw89_core_napi_start(rtwdev); 152262306a36Sopenharmony_ci rtw89_pci_enable_intr_lock(rtwdev); 152362306a36Sopenharmony_ci 152462306a36Sopenharmony_ci return 0; 152562306a36Sopenharmony_ci} 152662306a36Sopenharmony_ci 152762306a36Sopenharmony_cistatic void rtw89_pci_ops_stop(struct rtw89_dev *rtwdev) 152862306a36Sopenharmony_ci{ 152962306a36Sopenharmony_ci struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; 153062306a36Sopenharmony_ci struct pci_dev *pdev = rtwpci->pdev; 153162306a36Sopenharmony_ci 153262306a36Sopenharmony_ci rtw89_pci_disable_intr_lock(rtwdev); 153362306a36Sopenharmony_ci synchronize_irq(pdev->irq); 153462306a36Sopenharmony_ci rtw89_core_napi_stop(rtwdev); 153562306a36Sopenharmony_ci} 153662306a36Sopenharmony_ci 153762306a36Sopenharmony_cistatic void rtw89_pci_ops_pause(struct rtw89_dev *rtwdev, bool pause) 153862306a36Sopenharmony_ci{ 153962306a36Sopenharmony_ci struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; 154062306a36Sopenharmony_ci struct pci_dev *pdev = rtwpci->pdev; 154162306a36Sopenharmony_ci 154262306a36Sopenharmony_ci if (pause) { 154362306a36Sopenharmony_ci rtw89_pci_disable_intr_lock(rtwdev); 154462306a36Sopenharmony_ci synchronize_irq(pdev->irq); 154562306a36Sopenharmony_ci if (test_bit(RTW89_FLAG_NAPI_RUNNING, rtwdev->flags)) 154662306a36Sopenharmony_ci napi_synchronize(&rtwdev->napi); 154762306a36Sopenharmony_ci } else { 154862306a36Sopenharmony_ci rtw89_pci_enable_intr_lock(rtwdev); 154962306a36Sopenharmony_ci rtw89_pci_tx_kick_off_pending(rtwdev); 155062306a36Sopenharmony_ci } 155162306a36Sopenharmony_ci} 155262306a36Sopenharmony_ci 155362306a36Sopenharmony_cistatic 155462306a36Sopenharmony_civoid rtw89_pci_switch_bd_idx_addr(struct rtw89_dev *rtwdev, bool low_power) 155562306a36Sopenharmony_ci{ 155662306a36Sopenharmony_ci struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; 155762306a36Sopenharmony_ci const struct rtw89_pci_info *info = rtwdev->pci_info; 155862306a36Sopenharmony_ci const struct rtw89_pci_bd_idx_addr *bd_idx_addr = info->bd_idx_addr_low_power; 155962306a36Sopenharmony_ci const struct rtw89_pci_ch_dma_addr_set *dma_addr_set = info->dma_addr_set; 156062306a36Sopenharmony_ci struct rtw89_pci_tx_ring *tx_ring; 156162306a36Sopenharmony_ci struct rtw89_pci_rx_ring *rx_ring; 156262306a36Sopenharmony_ci int i; 156362306a36Sopenharmony_ci 156462306a36Sopenharmony_ci if (WARN(!bd_idx_addr, "only HCI with low power mode needs this\n")) 156562306a36Sopenharmony_ci return; 156662306a36Sopenharmony_ci 156762306a36Sopenharmony_ci for (i = 0; i < RTW89_TXCH_NUM; i++) { 156862306a36Sopenharmony_ci tx_ring = &rtwpci->tx_rings[i]; 156962306a36Sopenharmony_ci tx_ring->bd_ring.addr.idx = low_power ? 157062306a36Sopenharmony_ci bd_idx_addr->tx_bd_addrs[i] : 157162306a36Sopenharmony_ci dma_addr_set->tx[i].idx; 157262306a36Sopenharmony_ci } 157362306a36Sopenharmony_ci 157462306a36Sopenharmony_ci for (i = 0; i < RTW89_RXCH_NUM; i++) { 157562306a36Sopenharmony_ci rx_ring = &rtwpci->rx_rings[i]; 157662306a36Sopenharmony_ci rx_ring->bd_ring.addr.idx = low_power ? 157762306a36Sopenharmony_ci bd_idx_addr->rx_bd_addrs[i] : 157862306a36Sopenharmony_ci dma_addr_set->rx[i].idx; 157962306a36Sopenharmony_ci } 158062306a36Sopenharmony_ci} 158162306a36Sopenharmony_ci 158262306a36Sopenharmony_cistatic void rtw89_pci_ops_switch_mode(struct rtw89_dev *rtwdev, bool low_power) 158362306a36Sopenharmony_ci{ 158462306a36Sopenharmony_ci enum rtw89_pci_intr_mask_cfg cfg; 158562306a36Sopenharmony_ci 158662306a36Sopenharmony_ci WARN(!rtwdev->hci.paused, "HCI isn't paused\n"); 158762306a36Sopenharmony_ci 158862306a36Sopenharmony_ci cfg = low_power ? RTW89_PCI_INTR_MASK_LOW_POWER : RTW89_PCI_INTR_MASK_NORMAL; 158962306a36Sopenharmony_ci rtw89_chip_config_intr_mask(rtwdev, cfg); 159062306a36Sopenharmony_ci rtw89_pci_switch_bd_idx_addr(rtwdev, low_power); 159162306a36Sopenharmony_ci} 159262306a36Sopenharmony_ci 159362306a36Sopenharmony_cistatic void rtw89_pci_ops_write32(struct rtw89_dev *rtwdev, u32 addr, u32 data); 159462306a36Sopenharmony_ci 159562306a36Sopenharmony_cistatic u32 rtw89_pci_ops_read32_cmac(struct rtw89_dev *rtwdev, u32 addr) 159662306a36Sopenharmony_ci{ 159762306a36Sopenharmony_ci struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; 159862306a36Sopenharmony_ci u32 val = readl(rtwpci->mmap + addr); 159962306a36Sopenharmony_ci int count; 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_ci for (count = 0; ; count++) { 160262306a36Sopenharmony_ci if (val != RTW89_R32_DEAD) 160362306a36Sopenharmony_ci return val; 160462306a36Sopenharmony_ci if (count >= MAC_REG_POOL_COUNT) { 160562306a36Sopenharmony_ci rtw89_warn(rtwdev, "addr %#x = %#x\n", addr, val); 160662306a36Sopenharmony_ci return RTW89_R32_DEAD; 160762306a36Sopenharmony_ci } 160862306a36Sopenharmony_ci rtw89_pci_ops_write32(rtwdev, R_AX_CK_EN, B_AX_CMAC_ALLCKEN); 160962306a36Sopenharmony_ci val = readl(rtwpci->mmap + addr); 161062306a36Sopenharmony_ci } 161162306a36Sopenharmony_ci 161262306a36Sopenharmony_ci return val; 161362306a36Sopenharmony_ci} 161462306a36Sopenharmony_ci 161562306a36Sopenharmony_cistatic u8 rtw89_pci_ops_read8(struct rtw89_dev *rtwdev, u32 addr) 161662306a36Sopenharmony_ci{ 161762306a36Sopenharmony_ci struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; 161862306a36Sopenharmony_ci u32 addr32, val32, shift; 161962306a36Sopenharmony_ci 162062306a36Sopenharmony_ci if (!ACCESS_CMAC(addr)) 162162306a36Sopenharmony_ci return readb(rtwpci->mmap + addr); 162262306a36Sopenharmony_ci 162362306a36Sopenharmony_ci addr32 = addr & ~0x3; 162462306a36Sopenharmony_ci shift = (addr & 0x3) * 8; 162562306a36Sopenharmony_ci val32 = rtw89_pci_ops_read32_cmac(rtwdev, addr32); 162662306a36Sopenharmony_ci return val32 >> shift; 162762306a36Sopenharmony_ci} 162862306a36Sopenharmony_ci 162962306a36Sopenharmony_cistatic u16 rtw89_pci_ops_read16(struct rtw89_dev *rtwdev, u32 addr) 163062306a36Sopenharmony_ci{ 163162306a36Sopenharmony_ci struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; 163262306a36Sopenharmony_ci u32 addr32, val32, shift; 163362306a36Sopenharmony_ci 163462306a36Sopenharmony_ci if (!ACCESS_CMAC(addr)) 163562306a36Sopenharmony_ci return readw(rtwpci->mmap + addr); 163662306a36Sopenharmony_ci 163762306a36Sopenharmony_ci addr32 = addr & ~0x3; 163862306a36Sopenharmony_ci shift = (addr & 0x3) * 8; 163962306a36Sopenharmony_ci val32 = rtw89_pci_ops_read32_cmac(rtwdev, addr32); 164062306a36Sopenharmony_ci return val32 >> shift; 164162306a36Sopenharmony_ci} 164262306a36Sopenharmony_ci 164362306a36Sopenharmony_cistatic u32 rtw89_pci_ops_read32(struct rtw89_dev *rtwdev, u32 addr) 164462306a36Sopenharmony_ci{ 164562306a36Sopenharmony_ci struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; 164662306a36Sopenharmony_ci 164762306a36Sopenharmony_ci if (!ACCESS_CMAC(addr)) 164862306a36Sopenharmony_ci return readl(rtwpci->mmap + addr); 164962306a36Sopenharmony_ci 165062306a36Sopenharmony_ci return rtw89_pci_ops_read32_cmac(rtwdev, addr); 165162306a36Sopenharmony_ci} 165262306a36Sopenharmony_ci 165362306a36Sopenharmony_cistatic void rtw89_pci_ops_write8(struct rtw89_dev *rtwdev, u32 addr, u8 data) 165462306a36Sopenharmony_ci{ 165562306a36Sopenharmony_ci struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; 165662306a36Sopenharmony_ci 165762306a36Sopenharmony_ci writeb(data, rtwpci->mmap + addr); 165862306a36Sopenharmony_ci} 165962306a36Sopenharmony_ci 166062306a36Sopenharmony_cistatic void rtw89_pci_ops_write16(struct rtw89_dev *rtwdev, u32 addr, u16 data) 166162306a36Sopenharmony_ci{ 166262306a36Sopenharmony_ci struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; 166362306a36Sopenharmony_ci 166462306a36Sopenharmony_ci writew(data, rtwpci->mmap + addr); 166562306a36Sopenharmony_ci} 166662306a36Sopenharmony_ci 166762306a36Sopenharmony_cistatic void rtw89_pci_ops_write32(struct rtw89_dev *rtwdev, u32 addr, u32 data) 166862306a36Sopenharmony_ci{ 166962306a36Sopenharmony_ci struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; 167062306a36Sopenharmony_ci 167162306a36Sopenharmony_ci writel(data, rtwpci->mmap + addr); 167262306a36Sopenharmony_ci} 167362306a36Sopenharmony_ci 167462306a36Sopenharmony_cistatic void rtw89_pci_ctrl_dma_trx(struct rtw89_dev *rtwdev, bool enable) 167562306a36Sopenharmony_ci{ 167662306a36Sopenharmony_ci const struct rtw89_pci_info *info = rtwdev->pci_info; 167762306a36Sopenharmony_ci 167862306a36Sopenharmony_ci if (enable) 167962306a36Sopenharmony_ci rtw89_write32_set(rtwdev, info->init_cfg_reg, 168062306a36Sopenharmony_ci info->rxhci_en_bit | info->txhci_en_bit); 168162306a36Sopenharmony_ci else 168262306a36Sopenharmony_ci rtw89_write32_clr(rtwdev, info->init_cfg_reg, 168362306a36Sopenharmony_ci info->rxhci_en_bit | info->txhci_en_bit); 168462306a36Sopenharmony_ci} 168562306a36Sopenharmony_ci 168662306a36Sopenharmony_cistatic void rtw89_pci_ctrl_dma_io(struct rtw89_dev *rtwdev, bool enable) 168762306a36Sopenharmony_ci{ 168862306a36Sopenharmony_ci enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; 168962306a36Sopenharmony_ci u32 reg, mask; 169062306a36Sopenharmony_ci 169162306a36Sopenharmony_ci if (chip_id == RTL8852C) { 169262306a36Sopenharmony_ci reg = R_AX_HAXI_INIT_CFG1; 169362306a36Sopenharmony_ci mask = B_AX_STOP_AXI_MST; 169462306a36Sopenharmony_ci } else { 169562306a36Sopenharmony_ci reg = R_AX_PCIE_DMA_STOP1; 169662306a36Sopenharmony_ci mask = B_AX_STOP_PCIEIO; 169762306a36Sopenharmony_ci } 169862306a36Sopenharmony_ci 169962306a36Sopenharmony_ci if (enable) 170062306a36Sopenharmony_ci rtw89_write32_clr(rtwdev, reg, mask); 170162306a36Sopenharmony_ci else 170262306a36Sopenharmony_ci rtw89_write32_set(rtwdev, reg, mask); 170362306a36Sopenharmony_ci} 170462306a36Sopenharmony_ci 170562306a36Sopenharmony_cistatic void rtw89_pci_ctrl_dma_all(struct rtw89_dev *rtwdev, bool enable) 170662306a36Sopenharmony_ci{ 170762306a36Sopenharmony_ci rtw89_pci_ctrl_dma_io(rtwdev, enable); 170862306a36Sopenharmony_ci rtw89_pci_ctrl_dma_trx(rtwdev, enable); 170962306a36Sopenharmony_ci} 171062306a36Sopenharmony_ci 171162306a36Sopenharmony_cistatic int rtw89_pci_check_mdio(struct rtw89_dev *rtwdev, u8 addr, u8 speed, u16 rw_bit) 171262306a36Sopenharmony_ci{ 171362306a36Sopenharmony_ci u16 val; 171462306a36Sopenharmony_ci 171562306a36Sopenharmony_ci rtw89_write8(rtwdev, R_AX_MDIO_CFG, addr & 0x1F); 171662306a36Sopenharmony_ci 171762306a36Sopenharmony_ci val = rtw89_read16(rtwdev, R_AX_MDIO_CFG); 171862306a36Sopenharmony_ci switch (speed) { 171962306a36Sopenharmony_ci case PCIE_PHY_GEN1: 172062306a36Sopenharmony_ci if (addr < 0x20) 172162306a36Sopenharmony_ci val = u16_replace_bits(val, MDIO_PG0_G1, B_AX_MDIO_PHY_ADDR_MASK); 172262306a36Sopenharmony_ci else 172362306a36Sopenharmony_ci val = u16_replace_bits(val, MDIO_PG1_G1, B_AX_MDIO_PHY_ADDR_MASK); 172462306a36Sopenharmony_ci break; 172562306a36Sopenharmony_ci case PCIE_PHY_GEN2: 172662306a36Sopenharmony_ci if (addr < 0x20) 172762306a36Sopenharmony_ci val = u16_replace_bits(val, MDIO_PG0_G2, B_AX_MDIO_PHY_ADDR_MASK); 172862306a36Sopenharmony_ci else 172962306a36Sopenharmony_ci val = u16_replace_bits(val, MDIO_PG1_G2, B_AX_MDIO_PHY_ADDR_MASK); 173062306a36Sopenharmony_ci break; 173162306a36Sopenharmony_ci default: 173262306a36Sopenharmony_ci rtw89_err(rtwdev, "[ERR]Error Speed %d!\n", speed); 173362306a36Sopenharmony_ci return -EINVAL; 173462306a36Sopenharmony_ci } 173562306a36Sopenharmony_ci rtw89_write16(rtwdev, R_AX_MDIO_CFG, val); 173662306a36Sopenharmony_ci rtw89_write16_set(rtwdev, R_AX_MDIO_CFG, rw_bit); 173762306a36Sopenharmony_ci 173862306a36Sopenharmony_ci return read_poll_timeout(rtw89_read16, val, !(val & rw_bit), 10, 2000, 173962306a36Sopenharmony_ci false, rtwdev, R_AX_MDIO_CFG); 174062306a36Sopenharmony_ci} 174162306a36Sopenharmony_ci 174262306a36Sopenharmony_cistatic int 174362306a36Sopenharmony_cirtw89_read16_mdio(struct rtw89_dev *rtwdev, u8 addr, u8 speed, u16 *val) 174462306a36Sopenharmony_ci{ 174562306a36Sopenharmony_ci int ret; 174662306a36Sopenharmony_ci 174762306a36Sopenharmony_ci ret = rtw89_pci_check_mdio(rtwdev, addr, speed, B_AX_MDIO_RFLAG); 174862306a36Sopenharmony_ci if (ret) { 174962306a36Sopenharmony_ci rtw89_err(rtwdev, "[ERR]MDIO R16 0x%X fail ret=%d!\n", addr, ret); 175062306a36Sopenharmony_ci return ret; 175162306a36Sopenharmony_ci } 175262306a36Sopenharmony_ci *val = rtw89_read16(rtwdev, R_AX_MDIO_RDATA); 175362306a36Sopenharmony_ci 175462306a36Sopenharmony_ci return 0; 175562306a36Sopenharmony_ci} 175662306a36Sopenharmony_ci 175762306a36Sopenharmony_cistatic int 175862306a36Sopenharmony_cirtw89_write16_mdio(struct rtw89_dev *rtwdev, u8 addr, u16 data, u8 speed) 175962306a36Sopenharmony_ci{ 176062306a36Sopenharmony_ci int ret; 176162306a36Sopenharmony_ci 176262306a36Sopenharmony_ci rtw89_write16(rtwdev, R_AX_MDIO_WDATA, data); 176362306a36Sopenharmony_ci ret = rtw89_pci_check_mdio(rtwdev, addr, speed, B_AX_MDIO_WFLAG); 176462306a36Sopenharmony_ci if (ret) { 176562306a36Sopenharmony_ci rtw89_err(rtwdev, "[ERR]MDIO W16 0x%X = %x fail ret=%d!\n", addr, data, ret); 176662306a36Sopenharmony_ci return ret; 176762306a36Sopenharmony_ci } 176862306a36Sopenharmony_ci 176962306a36Sopenharmony_ci return 0; 177062306a36Sopenharmony_ci} 177162306a36Sopenharmony_ci 177262306a36Sopenharmony_cistatic int 177362306a36Sopenharmony_cirtw89_write16_mdio_mask(struct rtw89_dev *rtwdev, u8 addr, u16 mask, u16 data, u8 speed) 177462306a36Sopenharmony_ci{ 177562306a36Sopenharmony_ci u32 shift; 177662306a36Sopenharmony_ci int ret; 177762306a36Sopenharmony_ci u16 val; 177862306a36Sopenharmony_ci 177962306a36Sopenharmony_ci ret = rtw89_read16_mdio(rtwdev, addr, speed, &val); 178062306a36Sopenharmony_ci if (ret) 178162306a36Sopenharmony_ci return ret; 178262306a36Sopenharmony_ci 178362306a36Sopenharmony_ci shift = __ffs(mask); 178462306a36Sopenharmony_ci val &= ~mask; 178562306a36Sopenharmony_ci val |= ((data << shift) & mask); 178662306a36Sopenharmony_ci 178762306a36Sopenharmony_ci ret = rtw89_write16_mdio(rtwdev, addr, val, speed); 178862306a36Sopenharmony_ci if (ret) 178962306a36Sopenharmony_ci return ret; 179062306a36Sopenharmony_ci 179162306a36Sopenharmony_ci return 0; 179262306a36Sopenharmony_ci} 179362306a36Sopenharmony_ci 179462306a36Sopenharmony_cistatic int rtw89_write16_mdio_set(struct rtw89_dev *rtwdev, u8 addr, u16 mask, u8 speed) 179562306a36Sopenharmony_ci{ 179662306a36Sopenharmony_ci int ret; 179762306a36Sopenharmony_ci u16 val; 179862306a36Sopenharmony_ci 179962306a36Sopenharmony_ci ret = rtw89_read16_mdio(rtwdev, addr, speed, &val); 180062306a36Sopenharmony_ci if (ret) 180162306a36Sopenharmony_ci return ret; 180262306a36Sopenharmony_ci ret = rtw89_write16_mdio(rtwdev, addr, val | mask, speed); 180362306a36Sopenharmony_ci if (ret) 180462306a36Sopenharmony_ci return ret; 180562306a36Sopenharmony_ci 180662306a36Sopenharmony_ci return 0; 180762306a36Sopenharmony_ci} 180862306a36Sopenharmony_ci 180962306a36Sopenharmony_cistatic int rtw89_write16_mdio_clr(struct rtw89_dev *rtwdev, u8 addr, u16 mask, u8 speed) 181062306a36Sopenharmony_ci{ 181162306a36Sopenharmony_ci int ret; 181262306a36Sopenharmony_ci u16 val; 181362306a36Sopenharmony_ci 181462306a36Sopenharmony_ci ret = rtw89_read16_mdio(rtwdev, addr, speed, &val); 181562306a36Sopenharmony_ci if (ret) 181662306a36Sopenharmony_ci return ret; 181762306a36Sopenharmony_ci ret = rtw89_write16_mdio(rtwdev, addr, val & ~mask, speed); 181862306a36Sopenharmony_ci if (ret) 181962306a36Sopenharmony_ci return ret; 182062306a36Sopenharmony_ci 182162306a36Sopenharmony_ci return 0; 182262306a36Sopenharmony_ci} 182362306a36Sopenharmony_ci 182462306a36Sopenharmony_cistatic int rtw89_pci_write_config_byte(struct rtw89_dev *rtwdev, u16 addr, 182562306a36Sopenharmony_ci u8 data) 182662306a36Sopenharmony_ci{ 182762306a36Sopenharmony_ci struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; 182862306a36Sopenharmony_ci struct pci_dev *pdev = rtwpci->pdev; 182962306a36Sopenharmony_ci 183062306a36Sopenharmony_ci return pci_write_config_byte(pdev, addr, data); 183162306a36Sopenharmony_ci} 183262306a36Sopenharmony_ci 183362306a36Sopenharmony_cistatic int rtw89_pci_read_config_byte(struct rtw89_dev *rtwdev, u16 addr, 183462306a36Sopenharmony_ci u8 *value) 183562306a36Sopenharmony_ci{ 183662306a36Sopenharmony_ci struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; 183762306a36Sopenharmony_ci struct pci_dev *pdev = rtwpci->pdev; 183862306a36Sopenharmony_ci 183962306a36Sopenharmony_ci return pci_read_config_byte(pdev, addr, value); 184062306a36Sopenharmony_ci} 184162306a36Sopenharmony_ci 184262306a36Sopenharmony_cistatic int rtw89_pci_config_byte_set(struct rtw89_dev *rtwdev, u16 addr, 184362306a36Sopenharmony_ci u8 bit) 184462306a36Sopenharmony_ci{ 184562306a36Sopenharmony_ci u8 value; 184662306a36Sopenharmony_ci int ret; 184762306a36Sopenharmony_ci 184862306a36Sopenharmony_ci ret = rtw89_pci_read_config_byte(rtwdev, addr, &value); 184962306a36Sopenharmony_ci if (ret) 185062306a36Sopenharmony_ci return ret; 185162306a36Sopenharmony_ci 185262306a36Sopenharmony_ci value |= bit; 185362306a36Sopenharmony_ci ret = rtw89_pci_write_config_byte(rtwdev, addr, value); 185462306a36Sopenharmony_ci 185562306a36Sopenharmony_ci return ret; 185662306a36Sopenharmony_ci} 185762306a36Sopenharmony_ci 185862306a36Sopenharmony_cistatic int rtw89_pci_config_byte_clr(struct rtw89_dev *rtwdev, u16 addr, 185962306a36Sopenharmony_ci u8 bit) 186062306a36Sopenharmony_ci{ 186162306a36Sopenharmony_ci u8 value; 186262306a36Sopenharmony_ci int ret; 186362306a36Sopenharmony_ci 186462306a36Sopenharmony_ci ret = rtw89_pci_read_config_byte(rtwdev, addr, &value); 186562306a36Sopenharmony_ci if (ret) 186662306a36Sopenharmony_ci return ret; 186762306a36Sopenharmony_ci 186862306a36Sopenharmony_ci value &= ~bit; 186962306a36Sopenharmony_ci ret = rtw89_pci_write_config_byte(rtwdev, addr, value); 187062306a36Sopenharmony_ci 187162306a36Sopenharmony_ci return ret; 187262306a36Sopenharmony_ci} 187362306a36Sopenharmony_ci 187462306a36Sopenharmony_cistatic int 187562306a36Sopenharmony_ci__get_target(struct rtw89_dev *rtwdev, u16 *target, enum rtw89_pcie_phy phy_rate) 187662306a36Sopenharmony_ci{ 187762306a36Sopenharmony_ci u16 val, tar; 187862306a36Sopenharmony_ci int ret; 187962306a36Sopenharmony_ci 188062306a36Sopenharmony_ci /* Enable counter */ 188162306a36Sopenharmony_ci ret = rtw89_read16_mdio(rtwdev, RAC_CTRL_PPR_V1, phy_rate, &val); 188262306a36Sopenharmony_ci if (ret) 188362306a36Sopenharmony_ci return ret; 188462306a36Sopenharmony_ci ret = rtw89_write16_mdio(rtwdev, RAC_CTRL_PPR_V1, val & ~B_AX_CLK_CALIB_EN, 188562306a36Sopenharmony_ci phy_rate); 188662306a36Sopenharmony_ci if (ret) 188762306a36Sopenharmony_ci return ret; 188862306a36Sopenharmony_ci ret = rtw89_write16_mdio(rtwdev, RAC_CTRL_PPR_V1, val | B_AX_CLK_CALIB_EN, 188962306a36Sopenharmony_ci phy_rate); 189062306a36Sopenharmony_ci if (ret) 189162306a36Sopenharmony_ci return ret; 189262306a36Sopenharmony_ci 189362306a36Sopenharmony_ci fsleep(300); 189462306a36Sopenharmony_ci 189562306a36Sopenharmony_ci ret = rtw89_read16_mdio(rtwdev, RAC_CTRL_PPR_V1, phy_rate, &tar); 189662306a36Sopenharmony_ci if (ret) 189762306a36Sopenharmony_ci return ret; 189862306a36Sopenharmony_ci ret = rtw89_write16_mdio(rtwdev, RAC_CTRL_PPR_V1, val & ~B_AX_CLK_CALIB_EN, 189962306a36Sopenharmony_ci phy_rate); 190062306a36Sopenharmony_ci if (ret) 190162306a36Sopenharmony_ci return ret; 190262306a36Sopenharmony_ci 190362306a36Sopenharmony_ci tar = tar & 0x0FFF; 190462306a36Sopenharmony_ci if (tar == 0 || tar == 0x0FFF) { 190562306a36Sopenharmony_ci rtw89_err(rtwdev, "[ERR]Get target failed.\n"); 190662306a36Sopenharmony_ci return -EINVAL; 190762306a36Sopenharmony_ci } 190862306a36Sopenharmony_ci 190962306a36Sopenharmony_ci *target = tar; 191062306a36Sopenharmony_ci 191162306a36Sopenharmony_ci return 0; 191262306a36Sopenharmony_ci} 191362306a36Sopenharmony_ci 191462306a36Sopenharmony_cistatic int rtw89_pci_autok_x(struct rtw89_dev *rtwdev) 191562306a36Sopenharmony_ci{ 191662306a36Sopenharmony_ci enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; 191762306a36Sopenharmony_ci int ret; 191862306a36Sopenharmony_ci 191962306a36Sopenharmony_ci if (chip_id != RTL8852B && chip_id != RTL8851B) 192062306a36Sopenharmony_ci return 0; 192162306a36Sopenharmony_ci 192262306a36Sopenharmony_ci ret = rtw89_write16_mdio_mask(rtwdev, RAC_REG_FLD_0, BAC_AUTOK_N_MASK, 192362306a36Sopenharmony_ci PCIE_AUTOK_4, PCIE_PHY_GEN1); 192462306a36Sopenharmony_ci return ret; 192562306a36Sopenharmony_ci} 192662306a36Sopenharmony_ci 192762306a36Sopenharmony_cistatic int rtw89_pci_auto_refclk_cal(struct rtw89_dev *rtwdev, bool autook_en) 192862306a36Sopenharmony_ci{ 192962306a36Sopenharmony_ci enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; 193062306a36Sopenharmony_ci enum rtw89_pcie_phy phy_rate; 193162306a36Sopenharmony_ci u16 val16, mgn_set, div_set, tar; 193262306a36Sopenharmony_ci u8 val8, bdr_ori; 193362306a36Sopenharmony_ci bool l1_flag = false; 193462306a36Sopenharmony_ci int ret = 0; 193562306a36Sopenharmony_ci 193662306a36Sopenharmony_ci if (chip_id != RTL8852B && chip_id != RTL8851B) 193762306a36Sopenharmony_ci return 0; 193862306a36Sopenharmony_ci 193962306a36Sopenharmony_ci ret = rtw89_pci_read_config_byte(rtwdev, RTW89_PCIE_PHY_RATE, &val8); 194062306a36Sopenharmony_ci if (ret) { 194162306a36Sopenharmony_ci rtw89_err(rtwdev, "[ERR]pci config read %X\n", 194262306a36Sopenharmony_ci RTW89_PCIE_PHY_RATE); 194362306a36Sopenharmony_ci return ret; 194462306a36Sopenharmony_ci } 194562306a36Sopenharmony_ci 194662306a36Sopenharmony_ci if (FIELD_GET(RTW89_PCIE_PHY_RATE_MASK, val8) == 0x1) { 194762306a36Sopenharmony_ci phy_rate = PCIE_PHY_GEN1; 194862306a36Sopenharmony_ci } else if (FIELD_GET(RTW89_PCIE_PHY_RATE_MASK, val8) == 0x2) { 194962306a36Sopenharmony_ci phy_rate = PCIE_PHY_GEN2; 195062306a36Sopenharmony_ci } else { 195162306a36Sopenharmony_ci rtw89_err(rtwdev, "[ERR]PCIe PHY rate %#x not support\n", val8); 195262306a36Sopenharmony_ci return -EOPNOTSUPP; 195362306a36Sopenharmony_ci } 195462306a36Sopenharmony_ci /* Disable L1BD */ 195562306a36Sopenharmony_ci ret = rtw89_pci_read_config_byte(rtwdev, RTW89_PCIE_L1_CTRL, &bdr_ori); 195662306a36Sopenharmony_ci if (ret) { 195762306a36Sopenharmony_ci rtw89_err(rtwdev, "[ERR]pci config read %X\n", RTW89_PCIE_L1_CTRL); 195862306a36Sopenharmony_ci return ret; 195962306a36Sopenharmony_ci } 196062306a36Sopenharmony_ci 196162306a36Sopenharmony_ci if (bdr_ori & RTW89_PCIE_BIT_L1) { 196262306a36Sopenharmony_ci ret = rtw89_pci_write_config_byte(rtwdev, RTW89_PCIE_L1_CTRL, 196362306a36Sopenharmony_ci bdr_ori & ~RTW89_PCIE_BIT_L1); 196462306a36Sopenharmony_ci if (ret) { 196562306a36Sopenharmony_ci rtw89_err(rtwdev, "[ERR]pci config write %X\n", 196662306a36Sopenharmony_ci RTW89_PCIE_L1_CTRL); 196762306a36Sopenharmony_ci return ret; 196862306a36Sopenharmony_ci } 196962306a36Sopenharmony_ci l1_flag = true; 197062306a36Sopenharmony_ci } 197162306a36Sopenharmony_ci 197262306a36Sopenharmony_ci ret = rtw89_read16_mdio(rtwdev, RAC_CTRL_PPR_V1, phy_rate, &val16); 197362306a36Sopenharmony_ci if (ret) { 197462306a36Sopenharmony_ci rtw89_err(rtwdev, "[ERR]mdio_r16_pcie %X\n", RAC_CTRL_PPR_V1); 197562306a36Sopenharmony_ci goto end; 197662306a36Sopenharmony_ci } 197762306a36Sopenharmony_ci 197862306a36Sopenharmony_ci if (val16 & B_AX_CALIB_EN) { 197962306a36Sopenharmony_ci ret = rtw89_write16_mdio(rtwdev, RAC_CTRL_PPR_V1, 198062306a36Sopenharmony_ci val16 & ~B_AX_CALIB_EN, phy_rate); 198162306a36Sopenharmony_ci if (ret) { 198262306a36Sopenharmony_ci rtw89_err(rtwdev, "[ERR]mdio_w16_pcie %X\n", RAC_CTRL_PPR_V1); 198362306a36Sopenharmony_ci goto end; 198462306a36Sopenharmony_ci } 198562306a36Sopenharmony_ci } 198662306a36Sopenharmony_ci 198762306a36Sopenharmony_ci if (!autook_en) 198862306a36Sopenharmony_ci goto end; 198962306a36Sopenharmony_ci /* Set div */ 199062306a36Sopenharmony_ci ret = rtw89_write16_mdio_clr(rtwdev, RAC_CTRL_PPR_V1, B_AX_DIV, phy_rate); 199162306a36Sopenharmony_ci if (ret) { 199262306a36Sopenharmony_ci rtw89_err(rtwdev, "[ERR]mdio_w16_pcie %X\n", RAC_CTRL_PPR_V1); 199362306a36Sopenharmony_ci goto end; 199462306a36Sopenharmony_ci } 199562306a36Sopenharmony_ci 199662306a36Sopenharmony_ci /* Obtain div and margin */ 199762306a36Sopenharmony_ci ret = __get_target(rtwdev, &tar, phy_rate); 199862306a36Sopenharmony_ci if (ret) { 199962306a36Sopenharmony_ci rtw89_err(rtwdev, "[ERR]1st get target fail %d\n", ret); 200062306a36Sopenharmony_ci goto end; 200162306a36Sopenharmony_ci } 200262306a36Sopenharmony_ci 200362306a36Sopenharmony_ci mgn_set = tar * INTF_INTGRA_HOSTREF_V1 / INTF_INTGRA_MINREF_V1 - tar; 200462306a36Sopenharmony_ci 200562306a36Sopenharmony_ci if (mgn_set >= 128) { 200662306a36Sopenharmony_ci div_set = 0x0003; 200762306a36Sopenharmony_ci mgn_set = 0x000F; 200862306a36Sopenharmony_ci } else if (mgn_set >= 64) { 200962306a36Sopenharmony_ci div_set = 0x0003; 201062306a36Sopenharmony_ci mgn_set >>= 3; 201162306a36Sopenharmony_ci } else if (mgn_set >= 32) { 201262306a36Sopenharmony_ci div_set = 0x0002; 201362306a36Sopenharmony_ci mgn_set >>= 2; 201462306a36Sopenharmony_ci } else if (mgn_set >= 16) { 201562306a36Sopenharmony_ci div_set = 0x0001; 201662306a36Sopenharmony_ci mgn_set >>= 1; 201762306a36Sopenharmony_ci } else if (mgn_set == 0) { 201862306a36Sopenharmony_ci rtw89_err(rtwdev, "[ERR]cal mgn is 0,tar = %d\n", tar); 201962306a36Sopenharmony_ci goto end; 202062306a36Sopenharmony_ci } else { 202162306a36Sopenharmony_ci div_set = 0x0000; 202262306a36Sopenharmony_ci } 202362306a36Sopenharmony_ci 202462306a36Sopenharmony_ci ret = rtw89_read16_mdio(rtwdev, RAC_CTRL_PPR_V1, phy_rate, &val16); 202562306a36Sopenharmony_ci if (ret) { 202662306a36Sopenharmony_ci rtw89_err(rtwdev, "[ERR]mdio_r16_pcie %X\n", RAC_CTRL_PPR_V1); 202762306a36Sopenharmony_ci goto end; 202862306a36Sopenharmony_ci } 202962306a36Sopenharmony_ci 203062306a36Sopenharmony_ci val16 |= u16_encode_bits(div_set, B_AX_DIV); 203162306a36Sopenharmony_ci 203262306a36Sopenharmony_ci ret = rtw89_write16_mdio(rtwdev, RAC_CTRL_PPR_V1, val16, phy_rate); 203362306a36Sopenharmony_ci if (ret) { 203462306a36Sopenharmony_ci rtw89_err(rtwdev, "[ERR]mdio_w16_pcie %X\n", RAC_CTRL_PPR_V1); 203562306a36Sopenharmony_ci goto end; 203662306a36Sopenharmony_ci } 203762306a36Sopenharmony_ci 203862306a36Sopenharmony_ci ret = __get_target(rtwdev, &tar, phy_rate); 203962306a36Sopenharmony_ci if (ret) { 204062306a36Sopenharmony_ci rtw89_err(rtwdev, "[ERR]2nd get target fail %d\n", ret); 204162306a36Sopenharmony_ci goto end; 204262306a36Sopenharmony_ci } 204362306a36Sopenharmony_ci 204462306a36Sopenharmony_ci rtw89_debug(rtwdev, RTW89_DBG_HCI, "[TRACE]target = 0x%X, div = 0x%X, margin = 0x%X\n", 204562306a36Sopenharmony_ci tar, div_set, mgn_set); 204662306a36Sopenharmony_ci ret = rtw89_write16_mdio(rtwdev, RAC_SET_PPR_V1, 204762306a36Sopenharmony_ci (tar & 0x0FFF) | (mgn_set << 12), phy_rate); 204862306a36Sopenharmony_ci if (ret) { 204962306a36Sopenharmony_ci rtw89_err(rtwdev, "[ERR]mdio_w16_pcie %X\n", RAC_SET_PPR_V1); 205062306a36Sopenharmony_ci goto end; 205162306a36Sopenharmony_ci } 205262306a36Sopenharmony_ci 205362306a36Sopenharmony_ci /* Enable function */ 205462306a36Sopenharmony_ci ret = rtw89_write16_mdio_set(rtwdev, RAC_CTRL_PPR_V1, B_AX_CALIB_EN, phy_rate); 205562306a36Sopenharmony_ci if (ret) { 205662306a36Sopenharmony_ci rtw89_err(rtwdev, "[ERR]mdio_w16_pcie %X\n", RAC_CTRL_PPR_V1); 205762306a36Sopenharmony_ci goto end; 205862306a36Sopenharmony_ci } 205962306a36Sopenharmony_ci 206062306a36Sopenharmony_ci /* CLK delay = 0 */ 206162306a36Sopenharmony_ci ret = rtw89_pci_write_config_byte(rtwdev, RTW89_PCIE_CLK_CTRL, 206262306a36Sopenharmony_ci PCIE_CLKDLY_HW_0); 206362306a36Sopenharmony_ci 206462306a36Sopenharmony_ciend: 206562306a36Sopenharmony_ci /* Set L1BD to ori */ 206662306a36Sopenharmony_ci if (l1_flag) { 206762306a36Sopenharmony_ci ret = rtw89_pci_write_config_byte(rtwdev, RTW89_PCIE_L1_CTRL, 206862306a36Sopenharmony_ci bdr_ori); 206962306a36Sopenharmony_ci if (ret) { 207062306a36Sopenharmony_ci rtw89_err(rtwdev, "[ERR]pci config write %X\n", 207162306a36Sopenharmony_ci RTW89_PCIE_L1_CTRL); 207262306a36Sopenharmony_ci return ret; 207362306a36Sopenharmony_ci } 207462306a36Sopenharmony_ci } 207562306a36Sopenharmony_ci 207662306a36Sopenharmony_ci return ret; 207762306a36Sopenharmony_ci} 207862306a36Sopenharmony_ci 207962306a36Sopenharmony_cistatic int rtw89_pci_deglitch_setting(struct rtw89_dev *rtwdev) 208062306a36Sopenharmony_ci{ 208162306a36Sopenharmony_ci enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; 208262306a36Sopenharmony_ci int ret; 208362306a36Sopenharmony_ci 208462306a36Sopenharmony_ci if (chip_id == RTL8852A) { 208562306a36Sopenharmony_ci ret = rtw89_write16_mdio_clr(rtwdev, RAC_ANA24, B_AX_DEGLITCH, 208662306a36Sopenharmony_ci PCIE_PHY_GEN1); 208762306a36Sopenharmony_ci if (ret) 208862306a36Sopenharmony_ci return ret; 208962306a36Sopenharmony_ci ret = rtw89_write16_mdio_clr(rtwdev, RAC_ANA24, B_AX_DEGLITCH, 209062306a36Sopenharmony_ci PCIE_PHY_GEN2); 209162306a36Sopenharmony_ci if (ret) 209262306a36Sopenharmony_ci return ret; 209362306a36Sopenharmony_ci } else if (chip_id == RTL8852C) { 209462306a36Sopenharmony_ci rtw89_write16_clr(rtwdev, R_RAC_DIRECT_OFFSET_G1 + RAC_ANA24 * 2, 209562306a36Sopenharmony_ci B_AX_DEGLITCH); 209662306a36Sopenharmony_ci rtw89_write16_clr(rtwdev, R_RAC_DIRECT_OFFSET_G2 + RAC_ANA24 * 2, 209762306a36Sopenharmony_ci B_AX_DEGLITCH); 209862306a36Sopenharmony_ci } 209962306a36Sopenharmony_ci 210062306a36Sopenharmony_ci return 0; 210162306a36Sopenharmony_ci} 210262306a36Sopenharmony_ci 210362306a36Sopenharmony_cistatic void rtw89_pci_rxdma_prefth(struct rtw89_dev *rtwdev) 210462306a36Sopenharmony_ci{ 210562306a36Sopenharmony_ci if (rtwdev->chip->chip_id != RTL8852A) 210662306a36Sopenharmony_ci return; 210762306a36Sopenharmony_ci 210862306a36Sopenharmony_ci rtw89_write32_set(rtwdev, R_AX_PCIE_INIT_CFG1, B_AX_DIS_RXDMA_PRE); 210962306a36Sopenharmony_ci} 211062306a36Sopenharmony_ci 211162306a36Sopenharmony_cistatic void rtw89_pci_l1off_pwroff(struct rtw89_dev *rtwdev) 211262306a36Sopenharmony_ci{ 211362306a36Sopenharmony_ci enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; 211462306a36Sopenharmony_ci 211562306a36Sopenharmony_ci if (chip_id != RTL8852A && chip_id != RTL8852B && chip_id != RTL8851B) 211662306a36Sopenharmony_ci return; 211762306a36Sopenharmony_ci 211862306a36Sopenharmony_ci rtw89_write32_clr(rtwdev, R_AX_PCIE_PS_CTRL, B_AX_L1OFF_PWR_OFF_EN); 211962306a36Sopenharmony_ci} 212062306a36Sopenharmony_ci 212162306a36Sopenharmony_cistatic u32 rtw89_pci_l2_rxen_lat(struct rtw89_dev *rtwdev) 212262306a36Sopenharmony_ci{ 212362306a36Sopenharmony_ci int ret; 212462306a36Sopenharmony_ci 212562306a36Sopenharmony_ci if (rtwdev->chip->chip_id != RTL8852A) 212662306a36Sopenharmony_ci return 0; 212762306a36Sopenharmony_ci 212862306a36Sopenharmony_ci ret = rtw89_write16_mdio_clr(rtwdev, RAC_ANA26, B_AX_RXEN, 212962306a36Sopenharmony_ci PCIE_PHY_GEN1); 213062306a36Sopenharmony_ci if (ret) 213162306a36Sopenharmony_ci return ret; 213262306a36Sopenharmony_ci 213362306a36Sopenharmony_ci ret = rtw89_write16_mdio_clr(rtwdev, RAC_ANA26, B_AX_RXEN, 213462306a36Sopenharmony_ci PCIE_PHY_GEN2); 213562306a36Sopenharmony_ci if (ret) 213662306a36Sopenharmony_ci return ret; 213762306a36Sopenharmony_ci 213862306a36Sopenharmony_ci return 0; 213962306a36Sopenharmony_ci} 214062306a36Sopenharmony_ci 214162306a36Sopenharmony_cistatic void rtw89_pci_aphy_pwrcut(struct rtw89_dev *rtwdev) 214262306a36Sopenharmony_ci{ 214362306a36Sopenharmony_ci enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; 214462306a36Sopenharmony_ci 214562306a36Sopenharmony_ci if (chip_id != RTL8852A && chip_id != RTL8852B && chip_id != RTL8851B) 214662306a36Sopenharmony_ci return; 214762306a36Sopenharmony_ci 214862306a36Sopenharmony_ci rtw89_write32_clr(rtwdev, R_AX_SYS_PW_CTRL, B_AX_PSUS_OFF_CAPC_EN); 214962306a36Sopenharmony_ci} 215062306a36Sopenharmony_ci 215162306a36Sopenharmony_cistatic void rtw89_pci_hci_ldo(struct rtw89_dev *rtwdev) 215262306a36Sopenharmony_ci{ 215362306a36Sopenharmony_ci enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; 215462306a36Sopenharmony_ci 215562306a36Sopenharmony_ci if (chip_id == RTL8852A || chip_id == RTL8852B || chip_id == RTL8851B) { 215662306a36Sopenharmony_ci rtw89_write32_set(rtwdev, R_AX_SYS_SDIO_CTRL, 215762306a36Sopenharmony_ci B_AX_PCIE_DIS_L2_CTRL_LDO_HCI); 215862306a36Sopenharmony_ci rtw89_write32_clr(rtwdev, R_AX_SYS_SDIO_CTRL, 215962306a36Sopenharmony_ci B_AX_PCIE_DIS_WLSUS_AFT_PDN); 216062306a36Sopenharmony_ci } else if (rtwdev->chip->chip_id == RTL8852C) { 216162306a36Sopenharmony_ci rtw89_write32_clr(rtwdev, R_AX_SYS_SDIO_CTRL, 216262306a36Sopenharmony_ci B_AX_PCIE_DIS_L2_CTRL_LDO_HCI); 216362306a36Sopenharmony_ci } 216462306a36Sopenharmony_ci} 216562306a36Sopenharmony_ci 216662306a36Sopenharmony_cistatic int rtw89_pci_dphy_delay(struct rtw89_dev *rtwdev) 216762306a36Sopenharmony_ci{ 216862306a36Sopenharmony_ci enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; 216962306a36Sopenharmony_ci 217062306a36Sopenharmony_ci if (chip_id != RTL8852B && chip_id != RTL8851B) 217162306a36Sopenharmony_ci return 0; 217262306a36Sopenharmony_ci 217362306a36Sopenharmony_ci return rtw89_write16_mdio_mask(rtwdev, RAC_REG_REV2, BAC_CMU_EN_DLY_MASK, 217462306a36Sopenharmony_ci PCIE_DPHY_DLY_25US, PCIE_PHY_GEN1); 217562306a36Sopenharmony_ci} 217662306a36Sopenharmony_ci 217762306a36Sopenharmony_cistatic void rtw89_pci_power_wake(struct rtw89_dev *rtwdev, bool pwr_up) 217862306a36Sopenharmony_ci{ 217962306a36Sopenharmony_ci if (pwr_up) 218062306a36Sopenharmony_ci rtw89_write32_set(rtwdev, R_AX_HCI_OPT_CTRL, BIT_WAKE_CTRL); 218162306a36Sopenharmony_ci else 218262306a36Sopenharmony_ci rtw89_write32_clr(rtwdev, R_AX_HCI_OPT_CTRL, BIT_WAKE_CTRL); 218362306a36Sopenharmony_ci} 218462306a36Sopenharmony_ci 218562306a36Sopenharmony_cistatic void rtw89_pci_autoload_hang(struct rtw89_dev *rtwdev) 218662306a36Sopenharmony_ci{ 218762306a36Sopenharmony_ci if (rtwdev->chip->chip_id != RTL8852C) 218862306a36Sopenharmony_ci return; 218962306a36Sopenharmony_ci 219062306a36Sopenharmony_ci rtw89_write32_set(rtwdev, R_AX_PCIE_BG_CLR, B_AX_BG_CLR_ASYNC_M3); 219162306a36Sopenharmony_ci rtw89_write32_clr(rtwdev, R_AX_PCIE_BG_CLR, B_AX_BG_CLR_ASYNC_M3); 219262306a36Sopenharmony_ci} 219362306a36Sopenharmony_ci 219462306a36Sopenharmony_cistatic void rtw89_pci_l12_vmain(struct rtw89_dev *rtwdev) 219562306a36Sopenharmony_ci{ 219662306a36Sopenharmony_ci if (!(rtwdev->chip->chip_id == RTL8852C && rtwdev->hal.cv == CHIP_CAV)) 219762306a36Sopenharmony_ci return; 219862306a36Sopenharmony_ci 219962306a36Sopenharmony_ci rtw89_write32_set(rtwdev, R_AX_SYS_SDIO_CTRL, B_AX_PCIE_FORCE_PWR_NGAT); 220062306a36Sopenharmony_ci} 220162306a36Sopenharmony_ci 220262306a36Sopenharmony_cistatic void rtw89_pci_gen2_force_ib(struct rtw89_dev *rtwdev) 220362306a36Sopenharmony_ci{ 220462306a36Sopenharmony_ci if (!(rtwdev->chip->chip_id == RTL8852C && rtwdev->hal.cv == CHIP_CAV)) 220562306a36Sopenharmony_ci return; 220662306a36Sopenharmony_ci 220762306a36Sopenharmony_ci rtw89_write32_set(rtwdev, R_AX_PMC_DBG_CTRL2, 220862306a36Sopenharmony_ci B_AX_SYSON_DIS_PMCR_AX_WRMSK); 220962306a36Sopenharmony_ci rtw89_write32_set(rtwdev, R_AX_HCI_BG_CTRL, B_AX_BG_CLR_ASYNC_M3); 221062306a36Sopenharmony_ci rtw89_write32_clr(rtwdev, R_AX_PMC_DBG_CTRL2, 221162306a36Sopenharmony_ci B_AX_SYSON_DIS_PMCR_AX_WRMSK); 221262306a36Sopenharmony_ci} 221362306a36Sopenharmony_ci 221462306a36Sopenharmony_cistatic void rtw89_pci_l1_ent_lat(struct rtw89_dev *rtwdev) 221562306a36Sopenharmony_ci{ 221662306a36Sopenharmony_ci if (rtwdev->chip->chip_id != RTL8852C) 221762306a36Sopenharmony_ci return; 221862306a36Sopenharmony_ci 221962306a36Sopenharmony_ci rtw89_write32_clr(rtwdev, R_AX_PCIE_PS_CTRL_V1, B_AX_SEL_REQ_ENTR_L1); 222062306a36Sopenharmony_ci} 222162306a36Sopenharmony_ci 222262306a36Sopenharmony_cistatic void rtw89_pci_wd_exit_l1(struct rtw89_dev *rtwdev) 222362306a36Sopenharmony_ci{ 222462306a36Sopenharmony_ci if (rtwdev->chip->chip_id != RTL8852C) 222562306a36Sopenharmony_ci return; 222662306a36Sopenharmony_ci 222762306a36Sopenharmony_ci rtw89_write32_set(rtwdev, R_AX_PCIE_PS_CTRL_V1, B_AX_DMAC0_EXIT_L1_EN); 222862306a36Sopenharmony_ci} 222962306a36Sopenharmony_ci 223062306a36Sopenharmony_cistatic void rtw89_pci_set_sic(struct rtw89_dev *rtwdev) 223162306a36Sopenharmony_ci{ 223262306a36Sopenharmony_ci if (rtwdev->chip->chip_id == RTL8852C) 223362306a36Sopenharmony_ci return; 223462306a36Sopenharmony_ci 223562306a36Sopenharmony_ci rtw89_write32_clr(rtwdev, R_AX_PCIE_EXP_CTRL, 223662306a36Sopenharmony_ci B_AX_SIC_EN_FORCE_CLKREQ); 223762306a36Sopenharmony_ci} 223862306a36Sopenharmony_ci 223962306a36Sopenharmony_cistatic void rtw89_pci_set_lbc(struct rtw89_dev *rtwdev) 224062306a36Sopenharmony_ci{ 224162306a36Sopenharmony_ci const struct rtw89_pci_info *info = rtwdev->pci_info; 224262306a36Sopenharmony_ci u32 lbc; 224362306a36Sopenharmony_ci 224462306a36Sopenharmony_ci if (rtwdev->chip->chip_id == RTL8852C) 224562306a36Sopenharmony_ci return; 224662306a36Sopenharmony_ci 224762306a36Sopenharmony_ci lbc = rtw89_read32(rtwdev, R_AX_LBC_WATCHDOG); 224862306a36Sopenharmony_ci if (info->lbc_en == MAC_AX_PCIE_ENABLE) { 224962306a36Sopenharmony_ci lbc = u32_replace_bits(lbc, info->lbc_tmr, B_AX_LBC_TIMER); 225062306a36Sopenharmony_ci lbc |= B_AX_LBC_FLAG | B_AX_LBC_EN; 225162306a36Sopenharmony_ci rtw89_write32(rtwdev, R_AX_LBC_WATCHDOG, lbc); 225262306a36Sopenharmony_ci } else { 225362306a36Sopenharmony_ci lbc &= ~B_AX_LBC_EN; 225462306a36Sopenharmony_ci } 225562306a36Sopenharmony_ci rtw89_write32_set(rtwdev, R_AX_LBC_WATCHDOG, lbc); 225662306a36Sopenharmony_ci} 225762306a36Sopenharmony_ci 225862306a36Sopenharmony_cistatic void rtw89_pci_set_io_rcy(struct rtw89_dev *rtwdev) 225962306a36Sopenharmony_ci{ 226062306a36Sopenharmony_ci const struct rtw89_pci_info *info = rtwdev->pci_info; 226162306a36Sopenharmony_ci u32 val32; 226262306a36Sopenharmony_ci 226362306a36Sopenharmony_ci if (rtwdev->chip->chip_id != RTL8852C) 226462306a36Sopenharmony_ci return; 226562306a36Sopenharmony_ci 226662306a36Sopenharmony_ci if (info->io_rcy_en == MAC_AX_PCIE_ENABLE) { 226762306a36Sopenharmony_ci val32 = FIELD_PREP(B_AX_PCIE_WDT_TIMER_M1_MASK, 226862306a36Sopenharmony_ci info->io_rcy_tmr); 226962306a36Sopenharmony_ci rtw89_write32(rtwdev, R_AX_PCIE_WDT_TIMER_M1, val32); 227062306a36Sopenharmony_ci rtw89_write32(rtwdev, R_AX_PCIE_WDT_TIMER_M2, val32); 227162306a36Sopenharmony_ci rtw89_write32(rtwdev, R_AX_PCIE_WDT_TIMER_E0, val32); 227262306a36Sopenharmony_ci 227362306a36Sopenharmony_ci rtw89_write32_set(rtwdev, R_AX_PCIE_IO_RCY_M1, B_AX_PCIE_IO_RCY_WDT_MODE_M1); 227462306a36Sopenharmony_ci rtw89_write32_set(rtwdev, R_AX_PCIE_IO_RCY_M2, B_AX_PCIE_IO_RCY_WDT_MODE_M2); 227562306a36Sopenharmony_ci rtw89_write32_set(rtwdev, R_AX_PCIE_IO_RCY_E0, B_AX_PCIE_IO_RCY_WDT_MODE_E0); 227662306a36Sopenharmony_ci } else { 227762306a36Sopenharmony_ci rtw89_write32_clr(rtwdev, R_AX_PCIE_IO_RCY_M1, B_AX_PCIE_IO_RCY_WDT_MODE_M1); 227862306a36Sopenharmony_ci rtw89_write32_clr(rtwdev, R_AX_PCIE_IO_RCY_M2, B_AX_PCIE_IO_RCY_WDT_MODE_M2); 227962306a36Sopenharmony_ci rtw89_write32_clr(rtwdev, R_AX_PCIE_IO_RCY_E0, B_AX_PCIE_IO_RCY_WDT_MODE_E0); 228062306a36Sopenharmony_ci } 228162306a36Sopenharmony_ci 228262306a36Sopenharmony_ci rtw89_write32_clr(rtwdev, R_AX_PCIE_IO_RCY_S1, B_AX_PCIE_IO_RCY_WDT_MODE_S1); 228362306a36Sopenharmony_ci} 228462306a36Sopenharmony_ci 228562306a36Sopenharmony_cistatic void rtw89_pci_set_dbg(struct rtw89_dev *rtwdev) 228662306a36Sopenharmony_ci{ 228762306a36Sopenharmony_ci if (rtwdev->chip->chip_id == RTL8852C) 228862306a36Sopenharmony_ci return; 228962306a36Sopenharmony_ci 229062306a36Sopenharmony_ci rtw89_write32_set(rtwdev, R_AX_PCIE_DBG_CTRL, 229162306a36Sopenharmony_ci B_AX_ASFF_FULL_NO_STK | B_AX_EN_STUCK_DBG); 229262306a36Sopenharmony_ci 229362306a36Sopenharmony_ci if (rtwdev->chip->chip_id == RTL8852A) 229462306a36Sopenharmony_ci rtw89_write32_set(rtwdev, R_AX_PCIE_EXP_CTRL, 229562306a36Sopenharmony_ci B_AX_EN_CHKDSC_NO_RX_STUCK); 229662306a36Sopenharmony_ci} 229762306a36Sopenharmony_ci 229862306a36Sopenharmony_cistatic void rtw89_pci_set_keep_reg(struct rtw89_dev *rtwdev) 229962306a36Sopenharmony_ci{ 230062306a36Sopenharmony_ci if (rtwdev->chip->chip_id == RTL8852C) 230162306a36Sopenharmony_ci return; 230262306a36Sopenharmony_ci 230362306a36Sopenharmony_ci rtw89_write32_set(rtwdev, R_AX_PCIE_INIT_CFG1, 230462306a36Sopenharmony_ci B_AX_PCIE_TXRST_KEEP_REG | B_AX_PCIE_RXRST_KEEP_REG); 230562306a36Sopenharmony_ci} 230662306a36Sopenharmony_ci 230762306a36Sopenharmony_cistatic void rtw89_pci_clr_idx_all(struct rtw89_dev *rtwdev) 230862306a36Sopenharmony_ci{ 230962306a36Sopenharmony_ci const struct rtw89_pci_info *info = rtwdev->pci_info; 231062306a36Sopenharmony_ci enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; 231162306a36Sopenharmony_ci u32 val = B_AX_CLR_ACH0_IDX | B_AX_CLR_ACH1_IDX | B_AX_CLR_ACH2_IDX | 231262306a36Sopenharmony_ci B_AX_CLR_ACH3_IDX | B_AX_CLR_CH8_IDX | B_AX_CLR_CH9_IDX | 231362306a36Sopenharmony_ci B_AX_CLR_CH12_IDX; 231462306a36Sopenharmony_ci u32 rxbd_rwptr_clr = info->rxbd_rwptr_clr_reg; 231562306a36Sopenharmony_ci u32 txbd_rwptr_clr2 = info->txbd_rwptr_clr2_reg; 231662306a36Sopenharmony_ci 231762306a36Sopenharmony_ci if (chip_id == RTL8852A || chip_id == RTL8852C) 231862306a36Sopenharmony_ci val |= B_AX_CLR_ACH4_IDX | B_AX_CLR_ACH5_IDX | 231962306a36Sopenharmony_ci B_AX_CLR_ACH6_IDX | B_AX_CLR_ACH7_IDX; 232062306a36Sopenharmony_ci /* clear DMA indexes */ 232162306a36Sopenharmony_ci rtw89_write32_set(rtwdev, R_AX_TXBD_RWPTR_CLR1, val); 232262306a36Sopenharmony_ci if (chip_id == RTL8852A || chip_id == RTL8852C) 232362306a36Sopenharmony_ci rtw89_write32_set(rtwdev, txbd_rwptr_clr2, 232462306a36Sopenharmony_ci B_AX_CLR_CH10_IDX | B_AX_CLR_CH11_IDX); 232562306a36Sopenharmony_ci rtw89_write32_set(rtwdev, rxbd_rwptr_clr, 232662306a36Sopenharmony_ci B_AX_CLR_RXQ_IDX | B_AX_CLR_RPQ_IDX); 232762306a36Sopenharmony_ci} 232862306a36Sopenharmony_ci 232962306a36Sopenharmony_cistatic int rtw89_poll_txdma_ch_idle_pcie(struct rtw89_dev *rtwdev) 233062306a36Sopenharmony_ci{ 233162306a36Sopenharmony_ci const struct rtw89_pci_info *info = rtwdev->pci_info; 233262306a36Sopenharmony_ci u32 ret, check, dma_busy; 233362306a36Sopenharmony_ci u32 dma_busy1 = info->dma_busy1.addr; 233462306a36Sopenharmony_ci u32 dma_busy2 = info->dma_busy2_reg; 233562306a36Sopenharmony_ci 233662306a36Sopenharmony_ci check = info->dma_busy1.mask; 233762306a36Sopenharmony_ci 233862306a36Sopenharmony_ci ret = read_poll_timeout(rtw89_read32, dma_busy, (dma_busy & check) == 0, 233962306a36Sopenharmony_ci 10, 100, false, rtwdev, dma_busy1); 234062306a36Sopenharmony_ci if (ret) 234162306a36Sopenharmony_ci return ret; 234262306a36Sopenharmony_ci 234362306a36Sopenharmony_ci if (!dma_busy2) 234462306a36Sopenharmony_ci return 0; 234562306a36Sopenharmony_ci 234662306a36Sopenharmony_ci check = B_AX_CH10_BUSY | B_AX_CH11_BUSY; 234762306a36Sopenharmony_ci 234862306a36Sopenharmony_ci ret = read_poll_timeout(rtw89_read32, dma_busy, (dma_busy & check) == 0, 234962306a36Sopenharmony_ci 10, 100, false, rtwdev, dma_busy2); 235062306a36Sopenharmony_ci if (ret) 235162306a36Sopenharmony_ci return ret; 235262306a36Sopenharmony_ci 235362306a36Sopenharmony_ci return 0; 235462306a36Sopenharmony_ci} 235562306a36Sopenharmony_ci 235662306a36Sopenharmony_cistatic int rtw89_poll_rxdma_ch_idle_pcie(struct rtw89_dev *rtwdev) 235762306a36Sopenharmony_ci{ 235862306a36Sopenharmony_ci const struct rtw89_pci_info *info = rtwdev->pci_info; 235962306a36Sopenharmony_ci u32 ret, check, dma_busy; 236062306a36Sopenharmony_ci u32 dma_busy3 = info->dma_busy3_reg; 236162306a36Sopenharmony_ci 236262306a36Sopenharmony_ci check = B_AX_RXQ_BUSY | B_AX_RPQ_BUSY; 236362306a36Sopenharmony_ci 236462306a36Sopenharmony_ci ret = read_poll_timeout(rtw89_read32, dma_busy, (dma_busy & check) == 0, 236562306a36Sopenharmony_ci 10, 100, false, rtwdev, dma_busy3); 236662306a36Sopenharmony_ci if (ret) 236762306a36Sopenharmony_ci return ret; 236862306a36Sopenharmony_ci 236962306a36Sopenharmony_ci return 0; 237062306a36Sopenharmony_ci} 237162306a36Sopenharmony_ci 237262306a36Sopenharmony_cistatic int rtw89_pci_poll_dma_all_idle(struct rtw89_dev *rtwdev) 237362306a36Sopenharmony_ci{ 237462306a36Sopenharmony_ci u32 ret; 237562306a36Sopenharmony_ci 237662306a36Sopenharmony_ci ret = rtw89_poll_txdma_ch_idle_pcie(rtwdev); 237762306a36Sopenharmony_ci if (ret) { 237862306a36Sopenharmony_ci rtw89_err(rtwdev, "txdma ch busy\n"); 237962306a36Sopenharmony_ci return ret; 238062306a36Sopenharmony_ci } 238162306a36Sopenharmony_ci 238262306a36Sopenharmony_ci ret = rtw89_poll_rxdma_ch_idle_pcie(rtwdev); 238362306a36Sopenharmony_ci if (ret) { 238462306a36Sopenharmony_ci rtw89_err(rtwdev, "rxdma ch busy\n"); 238562306a36Sopenharmony_ci return ret; 238662306a36Sopenharmony_ci } 238762306a36Sopenharmony_ci 238862306a36Sopenharmony_ci return 0; 238962306a36Sopenharmony_ci} 239062306a36Sopenharmony_ci 239162306a36Sopenharmony_cistatic int rtw89_pci_mode_op(struct rtw89_dev *rtwdev) 239262306a36Sopenharmony_ci{ 239362306a36Sopenharmony_ci const struct rtw89_pci_info *info = rtwdev->pci_info; 239462306a36Sopenharmony_ci enum mac_ax_bd_trunc_mode txbd_trunc_mode = info->txbd_trunc_mode; 239562306a36Sopenharmony_ci enum mac_ax_bd_trunc_mode rxbd_trunc_mode = info->rxbd_trunc_mode; 239662306a36Sopenharmony_ci enum mac_ax_rxbd_mode rxbd_mode = info->rxbd_mode; 239762306a36Sopenharmony_ci enum mac_ax_tag_mode tag_mode = info->tag_mode; 239862306a36Sopenharmony_ci enum mac_ax_wd_dma_intvl wd_dma_idle_intvl = info->wd_dma_idle_intvl; 239962306a36Sopenharmony_ci enum mac_ax_wd_dma_intvl wd_dma_act_intvl = info->wd_dma_act_intvl; 240062306a36Sopenharmony_ci enum mac_ax_tx_burst tx_burst = info->tx_burst; 240162306a36Sopenharmony_ci enum mac_ax_rx_burst rx_burst = info->rx_burst; 240262306a36Sopenharmony_ci enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; 240362306a36Sopenharmony_ci u8 cv = rtwdev->hal.cv; 240462306a36Sopenharmony_ci u32 val32; 240562306a36Sopenharmony_ci 240662306a36Sopenharmony_ci if (txbd_trunc_mode == MAC_AX_BD_TRUNC) { 240762306a36Sopenharmony_ci if (chip_id == RTL8852A && cv == CHIP_CBV) 240862306a36Sopenharmony_ci rtw89_write32_set(rtwdev, R_AX_PCIE_INIT_CFG1, B_AX_TX_TRUNC_MODE); 240962306a36Sopenharmony_ci } else if (txbd_trunc_mode == MAC_AX_BD_NORM) { 241062306a36Sopenharmony_ci if (chip_id == RTL8852A || chip_id == RTL8852B) 241162306a36Sopenharmony_ci rtw89_write32_clr(rtwdev, R_AX_PCIE_INIT_CFG1, B_AX_TX_TRUNC_MODE); 241262306a36Sopenharmony_ci } 241362306a36Sopenharmony_ci 241462306a36Sopenharmony_ci if (rxbd_trunc_mode == MAC_AX_BD_TRUNC) { 241562306a36Sopenharmony_ci if (chip_id == RTL8852A && cv == CHIP_CBV) 241662306a36Sopenharmony_ci rtw89_write32_set(rtwdev, R_AX_PCIE_INIT_CFG1, B_AX_RX_TRUNC_MODE); 241762306a36Sopenharmony_ci } else if (rxbd_trunc_mode == MAC_AX_BD_NORM) { 241862306a36Sopenharmony_ci if (chip_id == RTL8852A || chip_id == RTL8852B) 241962306a36Sopenharmony_ci rtw89_write32_clr(rtwdev, R_AX_PCIE_INIT_CFG1, B_AX_RX_TRUNC_MODE); 242062306a36Sopenharmony_ci } 242162306a36Sopenharmony_ci 242262306a36Sopenharmony_ci if (rxbd_mode == MAC_AX_RXBD_PKT) { 242362306a36Sopenharmony_ci rtw89_write32_clr(rtwdev, info->init_cfg_reg, info->rxbd_mode_bit); 242462306a36Sopenharmony_ci } else if (rxbd_mode == MAC_AX_RXBD_SEP) { 242562306a36Sopenharmony_ci rtw89_write32_set(rtwdev, info->init_cfg_reg, info->rxbd_mode_bit); 242662306a36Sopenharmony_ci 242762306a36Sopenharmony_ci if (chip_id == RTL8852A || chip_id == RTL8852B) 242862306a36Sopenharmony_ci rtw89_write32_mask(rtwdev, R_AX_PCIE_INIT_CFG2, 242962306a36Sopenharmony_ci B_AX_PCIE_RX_APPLEN_MASK, 0); 243062306a36Sopenharmony_ci } 243162306a36Sopenharmony_ci 243262306a36Sopenharmony_ci if (chip_id == RTL8852A || chip_id == RTL8852B) { 243362306a36Sopenharmony_ci rtw89_write32_mask(rtwdev, R_AX_PCIE_INIT_CFG1, B_AX_PCIE_MAX_TXDMA_MASK, tx_burst); 243462306a36Sopenharmony_ci rtw89_write32_mask(rtwdev, R_AX_PCIE_INIT_CFG1, B_AX_PCIE_MAX_RXDMA_MASK, rx_burst); 243562306a36Sopenharmony_ci } else if (chip_id == RTL8852C) { 243662306a36Sopenharmony_ci rtw89_write32_mask(rtwdev, R_AX_HAXI_INIT_CFG1, B_AX_HAXI_MAX_TXDMA_MASK, tx_burst); 243762306a36Sopenharmony_ci rtw89_write32_mask(rtwdev, R_AX_HAXI_INIT_CFG1, B_AX_HAXI_MAX_RXDMA_MASK, rx_burst); 243862306a36Sopenharmony_ci } 243962306a36Sopenharmony_ci 244062306a36Sopenharmony_ci if (chip_id == RTL8852A || chip_id == RTL8852B) { 244162306a36Sopenharmony_ci if (tag_mode == MAC_AX_TAG_SGL) { 244262306a36Sopenharmony_ci val32 = rtw89_read32(rtwdev, R_AX_PCIE_INIT_CFG1) & 244362306a36Sopenharmony_ci ~B_AX_LATENCY_CONTROL; 244462306a36Sopenharmony_ci rtw89_write32(rtwdev, R_AX_PCIE_INIT_CFG1, val32); 244562306a36Sopenharmony_ci } else if (tag_mode == MAC_AX_TAG_MULTI) { 244662306a36Sopenharmony_ci val32 = rtw89_read32(rtwdev, R_AX_PCIE_INIT_CFG1) | 244762306a36Sopenharmony_ci B_AX_LATENCY_CONTROL; 244862306a36Sopenharmony_ci rtw89_write32(rtwdev, R_AX_PCIE_INIT_CFG1, val32); 244962306a36Sopenharmony_ci } 245062306a36Sopenharmony_ci } 245162306a36Sopenharmony_ci 245262306a36Sopenharmony_ci rtw89_write32_mask(rtwdev, info->exp_ctrl_reg, info->max_tag_num_mask, 245362306a36Sopenharmony_ci info->multi_tag_num); 245462306a36Sopenharmony_ci 245562306a36Sopenharmony_ci if (chip_id == RTL8852A || chip_id == RTL8852B) { 245662306a36Sopenharmony_ci rtw89_write32_mask(rtwdev, R_AX_PCIE_INIT_CFG2, B_AX_WD_ITVL_IDLE, 245762306a36Sopenharmony_ci wd_dma_idle_intvl); 245862306a36Sopenharmony_ci rtw89_write32_mask(rtwdev, R_AX_PCIE_INIT_CFG2, B_AX_WD_ITVL_ACT, 245962306a36Sopenharmony_ci wd_dma_act_intvl); 246062306a36Sopenharmony_ci } else if (chip_id == RTL8852C) { 246162306a36Sopenharmony_ci rtw89_write32_mask(rtwdev, R_AX_HAXI_INIT_CFG1, B_AX_WD_ITVL_IDLE_V1_MASK, 246262306a36Sopenharmony_ci wd_dma_idle_intvl); 246362306a36Sopenharmony_ci rtw89_write32_mask(rtwdev, R_AX_HAXI_INIT_CFG1, B_AX_WD_ITVL_ACT_V1_MASK, 246462306a36Sopenharmony_ci wd_dma_act_intvl); 246562306a36Sopenharmony_ci } 246662306a36Sopenharmony_ci 246762306a36Sopenharmony_ci if (txbd_trunc_mode == MAC_AX_BD_TRUNC) { 246862306a36Sopenharmony_ci rtw89_write32_set(rtwdev, R_AX_TX_ADDRESS_INFO_MODE_SETTING, 246962306a36Sopenharmony_ci B_AX_HOST_ADDR_INFO_8B_SEL); 247062306a36Sopenharmony_ci rtw89_write32_clr(rtwdev, R_AX_PKTIN_SETTING, B_AX_WD_ADDR_INFO_LENGTH); 247162306a36Sopenharmony_ci } else if (txbd_trunc_mode == MAC_AX_BD_NORM) { 247262306a36Sopenharmony_ci rtw89_write32_clr(rtwdev, R_AX_TX_ADDRESS_INFO_MODE_SETTING, 247362306a36Sopenharmony_ci B_AX_HOST_ADDR_INFO_8B_SEL); 247462306a36Sopenharmony_ci rtw89_write32_set(rtwdev, R_AX_PKTIN_SETTING, B_AX_WD_ADDR_INFO_LENGTH); 247562306a36Sopenharmony_ci } 247662306a36Sopenharmony_ci 247762306a36Sopenharmony_ci return 0; 247862306a36Sopenharmony_ci} 247962306a36Sopenharmony_ci 248062306a36Sopenharmony_cistatic int rtw89_pci_ops_deinit(struct rtw89_dev *rtwdev) 248162306a36Sopenharmony_ci{ 248262306a36Sopenharmony_ci const struct rtw89_pci_info *info = rtwdev->pci_info; 248362306a36Sopenharmony_ci 248462306a36Sopenharmony_ci if (rtwdev->chip->chip_id == RTL8852A) { 248562306a36Sopenharmony_ci /* ltr sw trigger */ 248662306a36Sopenharmony_ci rtw89_write32_set(rtwdev, R_AX_LTR_CTRL_0, B_AX_APP_LTR_IDLE); 248762306a36Sopenharmony_ci } 248862306a36Sopenharmony_ci info->ltr_set(rtwdev, false); 248962306a36Sopenharmony_ci rtw89_pci_ctrl_dma_all(rtwdev, false); 249062306a36Sopenharmony_ci rtw89_pci_clr_idx_all(rtwdev); 249162306a36Sopenharmony_ci 249262306a36Sopenharmony_ci return 0; 249362306a36Sopenharmony_ci} 249462306a36Sopenharmony_ci 249562306a36Sopenharmony_cistatic int rtw89_pci_ops_mac_pre_init(struct rtw89_dev *rtwdev) 249662306a36Sopenharmony_ci{ 249762306a36Sopenharmony_ci const struct rtw89_pci_info *info = rtwdev->pci_info; 249862306a36Sopenharmony_ci int ret; 249962306a36Sopenharmony_ci 250062306a36Sopenharmony_ci rtw89_pci_rxdma_prefth(rtwdev); 250162306a36Sopenharmony_ci rtw89_pci_l1off_pwroff(rtwdev); 250262306a36Sopenharmony_ci rtw89_pci_deglitch_setting(rtwdev); 250362306a36Sopenharmony_ci ret = rtw89_pci_l2_rxen_lat(rtwdev); 250462306a36Sopenharmony_ci if (ret) { 250562306a36Sopenharmony_ci rtw89_err(rtwdev, "[ERR] pcie l2 rxen lat %d\n", ret); 250662306a36Sopenharmony_ci return ret; 250762306a36Sopenharmony_ci } 250862306a36Sopenharmony_ci 250962306a36Sopenharmony_ci rtw89_pci_aphy_pwrcut(rtwdev); 251062306a36Sopenharmony_ci rtw89_pci_hci_ldo(rtwdev); 251162306a36Sopenharmony_ci rtw89_pci_dphy_delay(rtwdev); 251262306a36Sopenharmony_ci 251362306a36Sopenharmony_ci ret = rtw89_pci_autok_x(rtwdev); 251462306a36Sopenharmony_ci if (ret) { 251562306a36Sopenharmony_ci rtw89_err(rtwdev, "[ERR] pcie autok_x fail %d\n", ret); 251662306a36Sopenharmony_ci return ret; 251762306a36Sopenharmony_ci } 251862306a36Sopenharmony_ci 251962306a36Sopenharmony_ci ret = rtw89_pci_auto_refclk_cal(rtwdev, false); 252062306a36Sopenharmony_ci if (ret) { 252162306a36Sopenharmony_ci rtw89_err(rtwdev, "[ERR] pcie autok fail %d\n", ret); 252262306a36Sopenharmony_ci return ret; 252362306a36Sopenharmony_ci } 252462306a36Sopenharmony_ci 252562306a36Sopenharmony_ci rtw89_pci_power_wake(rtwdev, true); 252662306a36Sopenharmony_ci rtw89_pci_autoload_hang(rtwdev); 252762306a36Sopenharmony_ci rtw89_pci_l12_vmain(rtwdev); 252862306a36Sopenharmony_ci rtw89_pci_gen2_force_ib(rtwdev); 252962306a36Sopenharmony_ci rtw89_pci_l1_ent_lat(rtwdev); 253062306a36Sopenharmony_ci rtw89_pci_wd_exit_l1(rtwdev); 253162306a36Sopenharmony_ci rtw89_pci_set_sic(rtwdev); 253262306a36Sopenharmony_ci rtw89_pci_set_lbc(rtwdev); 253362306a36Sopenharmony_ci rtw89_pci_set_io_rcy(rtwdev); 253462306a36Sopenharmony_ci rtw89_pci_set_dbg(rtwdev); 253562306a36Sopenharmony_ci rtw89_pci_set_keep_reg(rtwdev); 253662306a36Sopenharmony_ci 253762306a36Sopenharmony_ci rtw89_write32_set(rtwdev, info->dma_stop1.addr, B_AX_STOP_WPDMA); 253862306a36Sopenharmony_ci 253962306a36Sopenharmony_ci /* stop DMA activities */ 254062306a36Sopenharmony_ci rtw89_pci_ctrl_dma_all(rtwdev, false); 254162306a36Sopenharmony_ci 254262306a36Sopenharmony_ci ret = rtw89_pci_poll_dma_all_idle(rtwdev); 254362306a36Sopenharmony_ci if (ret) { 254462306a36Sopenharmony_ci rtw89_err(rtwdev, "[ERR] poll pcie dma all idle\n"); 254562306a36Sopenharmony_ci return ret; 254662306a36Sopenharmony_ci } 254762306a36Sopenharmony_ci 254862306a36Sopenharmony_ci rtw89_pci_clr_idx_all(rtwdev); 254962306a36Sopenharmony_ci rtw89_pci_mode_op(rtwdev); 255062306a36Sopenharmony_ci 255162306a36Sopenharmony_ci /* fill TRX BD indexes */ 255262306a36Sopenharmony_ci rtw89_pci_ops_reset(rtwdev); 255362306a36Sopenharmony_ci 255462306a36Sopenharmony_ci ret = rtw89_pci_rst_bdram_pcie(rtwdev); 255562306a36Sopenharmony_ci if (ret) { 255662306a36Sopenharmony_ci rtw89_warn(rtwdev, "reset bdram busy\n"); 255762306a36Sopenharmony_ci return ret; 255862306a36Sopenharmony_ci } 255962306a36Sopenharmony_ci 256062306a36Sopenharmony_ci /* disable all channels except to FW CMD channel to download firmware */ 256162306a36Sopenharmony_ci rtw89_pci_ctrl_txdma_ch_pcie(rtwdev, false); 256262306a36Sopenharmony_ci rtw89_pci_ctrl_txdma_fw_ch_pcie(rtwdev, true); 256362306a36Sopenharmony_ci 256462306a36Sopenharmony_ci /* start DMA activities */ 256562306a36Sopenharmony_ci rtw89_pci_ctrl_dma_all(rtwdev, true); 256662306a36Sopenharmony_ci 256762306a36Sopenharmony_ci return 0; 256862306a36Sopenharmony_ci} 256962306a36Sopenharmony_ci 257062306a36Sopenharmony_ciint rtw89_pci_ltr_set(struct rtw89_dev *rtwdev, bool en) 257162306a36Sopenharmony_ci{ 257262306a36Sopenharmony_ci u32 val; 257362306a36Sopenharmony_ci 257462306a36Sopenharmony_ci if (!en) 257562306a36Sopenharmony_ci return 0; 257662306a36Sopenharmony_ci 257762306a36Sopenharmony_ci val = rtw89_read32(rtwdev, R_AX_LTR_CTRL_0); 257862306a36Sopenharmony_ci if (rtw89_pci_ltr_is_err_reg_val(val)) 257962306a36Sopenharmony_ci return -EINVAL; 258062306a36Sopenharmony_ci val = rtw89_read32(rtwdev, R_AX_LTR_CTRL_1); 258162306a36Sopenharmony_ci if (rtw89_pci_ltr_is_err_reg_val(val)) 258262306a36Sopenharmony_ci return -EINVAL; 258362306a36Sopenharmony_ci val = rtw89_read32(rtwdev, R_AX_LTR_IDLE_LATENCY); 258462306a36Sopenharmony_ci if (rtw89_pci_ltr_is_err_reg_val(val)) 258562306a36Sopenharmony_ci return -EINVAL; 258662306a36Sopenharmony_ci val = rtw89_read32(rtwdev, R_AX_LTR_ACTIVE_LATENCY); 258762306a36Sopenharmony_ci if (rtw89_pci_ltr_is_err_reg_val(val)) 258862306a36Sopenharmony_ci return -EINVAL; 258962306a36Sopenharmony_ci 259062306a36Sopenharmony_ci rtw89_write32_set(rtwdev, R_AX_LTR_CTRL_0, B_AX_LTR_HW_EN | B_AX_LTR_EN | 259162306a36Sopenharmony_ci B_AX_LTR_WD_NOEMP_CHK); 259262306a36Sopenharmony_ci rtw89_write32_mask(rtwdev, R_AX_LTR_CTRL_0, B_AX_LTR_SPACE_IDX_MASK, 259362306a36Sopenharmony_ci PCI_LTR_SPC_500US); 259462306a36Sopenharmony_ci rtw89_write32_mask(rtwdev, R_AX_LTR_CTRL_0, B_AX_LTR_IDLE_TIMER_IDX_MASK, 259562306a36Sopenharmony_ci PCI_LTR_IDLE_TIMER_3_2MS); 259662306a36Sopenharmony_ci rtw89_write32_mask(rtwdev, R_AX_LTR_CTRL_1, B_AX_LTR_RX0_TH_MASK, 0x28); 259762306a36Sopenharmony_ci rtw89_write32_mask(rtwdev, R_AX_LTR_CTRL_1, B_AX_LTR_RX1_TH_MASK, 0x28); 259862306a36Sopenharmony_ci rtw89_write32(rtwdev, R_AX_LTR_IDLE_LATENCY, 0x90039003); 259962306a36Sopenharmony_ci rtw89_write32(rtwdev, R_AX_LTR_ACTIVE_LATENCY, 0x880b880b); 260062306a36Sopenharmony_ci 260162306a36Sopenharmony_ci return 0; 260262306a36Sopenharmony_ci} 260362306a36Sopenharmony_ciEXPORT_SYMBOL(rtw89_pci_ltr_set); 260462306a36Sopenharmony_ci 260562306a36Sopenharmony_ciint rtw89_pci_ltr_set_v1(struct rtw89_dev *rtwdev, bool en) 260662306a36Sopenharmony_ci{ 260762306a36Sopenharmony_ci u32 dec_ctrl; 260862306a36Sopenharmony_ci u32 val32; 260962306a36Sopenharmony_ci 261062306a36Sopenharmony_ci val32 = rtw89_read32(rtwdev, R_AX_LTR_CTRL_0); 261162306a36Sopenharmony_ci if (rtw89_pci_ltr_is_err_reg_val(val32)) 261262306a36Sopenharmony_ci return -EINVAL; 261362306a36Sopenharmony_ci val32 = rtw89_read32(rtwdev, R_AX_LTR_CTRL_1); 261462306a36Sopenharmony_ci if (rtw89_pci_ltr_is_err_reg_val(val32)) 261562306a36Sopenharmony_ci return -EINVAL; 261662306a36Sopenharmony_ci dec_ctrl = rtw89_read32(rtwdev, R_AX_LTR_DEC_CTRL); 261762306a36Sopenharmony_ci if (rtw89_pci_ltr_is_err_reg_val(dec_ctrl)) 261862306a36Sopenharmony_ci return -EINVAL; 261962306a36Sopenharmony_ci val32 = rtw89_read32(rtwdev, R_AX_LTR_LATENCY_IDX3); 262062306a36Sopenharmony_ci if (rtw89_pci_ltr_is_err_reg_val(val32)) 262162306a36Sopenharmony_ci return -EINVAL; 262262306a36Sopenharmony_ci val32 = rtw89_read32(rtwdev, R_AX_LTR_LATENCY_IDX0); 262362306a36Sopenharmony_ci if (rtw89_pci_ltr_is_err_reg_val(val32)) 262462306a36Sopenharmony_ci return -EINVAL; 262562306a36Sopenharmony_ci 262662306a36Sopenharmony_ci if (!en) { 262762306a36Sopenharmony_ci dec_ctrl &= ~(LTR_EN_BITS | B_AX_LTR_IDX_DRV_MASK | B_AX_LTR_HW_DEC_EN); 262862306a36Sopenharmony_ci dec_ctrl |= FIELD_PREP(B_AX_LTR_IDX_DRV_MASK, PCIE_LTR_IDX_IDLE) | 262962306a36Sopenharmony_ci B_AX_LTR_REQ_DRV; 263062306a36Sopenharmony_ci } else { 263162306a36Sopenharmony_ci dec_ctrl |= B_AX_LTR_HW_DEC_EN; 263262306a36Sopenharmony_ci } 263362306a36Sopenharmony_ci 263462306a36Sopenharmony_ci dec_ctrl &= ~B_AX_LTR_SPACE_IDX_V1_MASK; 263562306a36Sopenharmony_ci dec_ctrl |= FIELD_PREP(B_AX_LTR_SPACE_IDX_V1_MASK, PCI_LTR_SPC_500US); 263662306a36Sopenharmony_ci 263762306a36Sopenharmony_ci if (en) 263862306a36Sopenharmony_ci rtw89_write32_set(rtwdev, R_AX_LTR_CTRL_0, 263962306a36Sopenharmony_ci B_AX_LTR_WD_NOEMP_CHK_V1 | B_AX_LTR_HW_EN); 264062306a36Sopenharmony_ci rtw89_write32_mask(rtwdev, R_AX_LTR_CTRL_0, B_AX_LTR_IDLE_TIMER_IDX_MASK, 264162306a36Sopenharmony_ci PCI_LTR_IDLE_TIMER_3_2MS); 264262306a36Sopenharmony_ci rtw89_write32_mask(rtwdev, R_AX_LTR_CTRL_1, B_AX_LTR_RX0_TH_MASK, 0x28); 264362306a36Sopenharmony_ci rtw89_write32_mask(rtwdev, R_AX_LTR_CTRL_1, B_AX_LTR_RX1_TH_MASK, 0x28); 264462306a36Sopenharmony_ci rtw89_write32(rtwdev, R_AX_LTR_DEC_CTRL, dec_ctrl); 264562306a36Sopenharmony_ci rtw89_write32(rtwdev, R_AX_LTR_LATENCY_IDX3, 0x90039003); 264662306a36Sopenharmony_ci rtw89_write32(rtwdev, R_AX_LTR_LATENCY_IDX0, 0x880b880b); 264762306a36Sopenharmony_ci 264862306a36Sopenharmony_ci return 0; 264962306a36Sopenharmony_ci} 265062306a36Sopenharmony_ciEXPORT_SYMBOL(rtw89_pci_ltr_set_v1); 265162306a36Sopenharmony_ci 265262306a36Sopenharmony_cistatic int rtw89_pci_ops_mac_post_init(struct rtw89_dev *rtwdev) 265362306a36Sopenharmony_ci{ 265462306a36Sopenharmony_ci const struct rtw89_pci_info *info = rtwdev->pci_info; 265562306a36Sopenharmony_ci enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; 265662306a36Sopenharmony_ci int ret; 265762306a36Sopenharmony_ci 265862306a36Sopenharmony_ci ret = info->ltr_set(rtwdev, true); 265962306a36Sopenharmony_ci if (ret) { 266062306a36Sopenharmony_ci rtw89_err(rtwdev, "pci ltr set fail\n"); 266162306a36Sopenharmony_ci return ret; 266262306a36Sopenharmony_ci } 266362306a36Sopenharmony_ci if (chip_id == RTL8852A) { 266462306a36Sopenharmony_ci /* ltr sw trigger */ 266562306a36Sopenharmony_ci rtw89_write32_set(rtwdev, R_AX_LTR_CTRL_0, B_AX_APP_LTR_ACT); 266662306a36Sopenharmony_ci } 266762306a36Sopenharmony_ci if (chip_id == RTL8852A || chip_id == RTL8852B) { 266862306a36Sopenharmony_ci /* ADDR info 8-byte mode */ 266962306a36Sopenharmony_ci rtw89_write32_set(rtwdev, R_AX_TX_ADDRESS_INFO_MODE_SETTING, 267062306a36Sopenharmony_ci B_AX_HOST_ADDR_INFO_8B_SEL); 267162306a36Sopenharmony_ci rtw89_write32_clr(rtwdev, R_AX_PKTIN_SETTING, B_AX_WD_ADDR_INFO_LENGTH); 267262306a36Sopenharmony_ci } 267362306a36Sopenharmony_ci 267462306a36Sopenharmony_ci /* enable DMA for all queues */ 267562306a36Sopenharmony_ci rtw89_pci_ctrl_txdma_ch_pcie(rtwdev, true); 267662306a36Sopenharmony_ci 267762306a36Sopenharmony_ci /* Release PCI IO */ 267862306a36Sopenharmony_ci rtw89_write32_clr(rtwdev, info->dma_stop1.addr, 267962306a36Sopenharmony_ci B_AX_STOP_WPDMA | B_AX_STOP_PCIEIO); 268062306a36Sopenharmony_ci 268162306a36Sopenharmony_ci return 0; 268262306a36Sopenharmony_ci} 268362306a36Sopenharmony_ci 268462306a36Sopenharmony_cistatic int rtw89_pci_claim_device(struct rtw89_dev *rtwdev, 268562306a36Sopenharmony_ci struct pci_dev *pdev) 268662306a36Sopenharmony_ci{ 268762306a36Sopenharmony_ci struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; 268862306a36Sopenharmony_ci int ret; 268962306a36Sopenharmony_ci 269062306a36Sopenharmony_ci ret = pci_enable_device(pdev); 269162306a36Sopenharmony_ci if (ret) { 269262306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to enable pci device\n"); 269362306a36Sopenharmony_ci return ret; 269462306a36Sopenharmony_ci } 269562306a36Sopenharmony_ci 269662306a36Sopenharmony_ci pci_set_master(pdev); 269762306a36Sopenharmony_ci pci_set_drvdata(pdev, rtwdev->hw); 269862306a36Sopenharmony_ci 269962306a36Sopenharmony_ci rtwpci->pdev = pdev; 270062306a36Sopenharmony_ci 270162306a36Sopenharmony_ci return 0; 270262306a36Sopenharmony_ci} 270362306a36Sopenharmony_ci 270462306a36Sopenharmony_cistatic void rtw89_pci_declaim_device(struct rtw89_dev *rtwdev, 270562306a36Sopenharmony_ci struct pci_dev *pdev) 270662306a36Sopenharmony_ci{ 270762306a36Sopenharmony_ci pci_disable_device(pdev); 270862306a36Sopenharmony_ci} 270962306a36Sopenharmony_ci 271062306a36Sopenharmony_cistatic int rtw89_pci_setup_mapping(struct rtw89_dev *rtwdev, 271162306a36Sopenharmony_ci struct pci_dev *pdev) 271262306a36Sopenharmony_ci{ 271362306a36Sopenharmony_ci struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; 271462306a36Sopenharmony_ci unsigned long resource_len; 271562306a36Sopenharmony_ci u8 bar_id = 2; 271662306a36Sopenharmony_ci int ret; 271762306a36Sopenharmony_ci 271862306a36Sopenharmony_ci ret = pci_request_regions(pdev, KBUILD_MODNAME); 271962306a36Sopenharmony_ci if (ret) { 272062306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to request pci regions\n"); 272162306a36Sopenharmony_ci goto err; 272262306a36Sopenharmony_ci } 272362306a36Sopenharmony_ci 272462306a36Sopenharmony_ci ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); 272562306a36Sopenharmony_ci if (ret) { 272662306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to set dma mask to 32-bit\n"); 272762306a36Sopenharmony_ci goto err_release_regions; 272862306a36Sopenharmony_ci } 272962306a36Sopenharmony_ci 273062306a36Sopenharmony_ci ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); 273162306a36Sopenharmony_ci if (ret) { 273262306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to set consistent dma mask to 32-bit\n"); 273362306a36Sopenharmony_ci goto err_release_regions; 273462306a36Sopenharmony_ci } 273562306a36Sopenharmony_ci 273662306a36Sopenharmony_ci resource_len = pci_resource_len(pdev, bar_id); 273762306a36Sopenharmony_ci rtwpci->mmap = pci_iomap(pdev, bar_id, resource_len); 273862306a36Sopenharmony_ci if (!rtwpci->mmap) { 273962306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to map pci io\n"); 274062306a36Sopenharmony_ci ret = -EIO; 274162306a36Sopenharmony_ci goto err_release_regions; 274262306a36Sopenharmony_ci } 274362306a36Sopenharmony_ci 274462306a36Sopenharmony_ci return 0; 274562306a36Sopenharmony_ci 274662306a36Sopenharmony_cierr_release_regions: 274762306a36Sopenharmony_ci pci_release_regions(pdev); 274862306a36Sopenharmony_cierr: 274962306a36Sopenharmony_ci return ret; 275062306a36Sopenharmony_ci} 275162306a36Sopenharmony_ci 275262306a36Sopenharmony_cistatic void rtw89_pci_clear_mapping(struct rtw89_dev *rtwdev, 275362306a36Sopenharmony_ci struct pci_dev *pdev) 275462306a36Sopenharmony_ci{ 275562306a36Sopenharmony_ci struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; 275662306a36Sopenharmony_ci 275762306a36Sopenharmony_ci if (rtwpci->mmap) { 275862306a36Sopenharmony_ci pci_iounmap(pdev, rtwpci->mmap); 275962306a36Sopenharmony_ci pci_release_regions(pdev); 276062306a36Sopenharmony_ci } 276162306a36Sopenharmony_ci} 276262306a36Sopenharmony_ci 276362306a36Sopenharmony_cistatic void rtw89_pci_free_tx_wd_ring(struct rtw89_dev *rtwdev, 276462306a36Sopenharmony_ci struct pci_dev *pdev, 276562306a36Sopenharmony_ci struct rtw89_pci_tx_ring *tx_ring) 276662306a36Sopenharmony_ci{ 276762306a36Sopenharmony_ci struct rtw89_pci_tx_wd_ring *wd_ring = &tx_ring->wd_ring; 276862306a36Sopenharmony_ci u8 *head = wd_ring->head; 276962306a36Sopenharmony_ci dma_addr_t dma = wd_ring->dma; 277062306a36Sopenharmony_ci u32 page_size = wd_ring->page_size; 277162306a36Sopenharmony_ci u32 page_num = wd_ring->page_num; 277262306a36Sopenharmony_ci u32 ring_sz = page_size * page_num; 277362306a36Sopenharmony_ci 277462306a36Sopenharmony_ci dma_free_coherent(&pdev->dev, ring_sz, head, dma); 277562306a36Sopenharmony_ci wd_ring->head = NULL; 277662306a36Sopenharmony_ci} 277762306a36Sopenharmony_ci 277862306a36Sopenharmony_cistatic void rtw89_pci_free_tx_ring(struct rtw89_dev *rtwdev, 277962306a36Sopenharmony_ci struct pci_dev *pdev, 278062306a36Sopenharmony_ci struct rtw89_pci_tx_ring *tx_ring) 278162306a36Sopenharmony_ci{ 278262306a36Sopenharmony_ci int ring_sz; 278362306a36Sopenharmony_ci u8 *head; 278462306a36Sopenharmony_ci dma_addr_t dma; 278562306a36Sopenharmony_ci 278662306a36Sopenharmony_ci head = tx_ring->bd_ring.head; 278762306a36Sopenharmony_ci dma = tx_ring->bd_ring.dma; 278862306a36Sopenharmony_ci ring_sz = tx_ring->bd_ring.desc_size * tx_ring->bd_ring.len; 278962306a36Sopenharmony_ci dma_free_coherent(&pdev->dev, ring_sz, head, dma); 279062306a36Sopenharmony_ci 279162306a36Sopenharmony_ci tx_ring->bd_ring.head = NULL; 279262306a36Sopenharmony_ci} 279362306a36Sopenharmony_ci 279462306a36Sopenharmony_cistatic void rtw89_pci_free_tx_rings(struct rtw89_dev *rtwdev, 279562306a36Sopenharmony_ci struct pci_dev *pdev) 279662306a36Sopenharmony_ci{ 279762306a36Sopenharmony_ci struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; 279862306a36Sopenharmony_ci const struct rtw89_pci_info *info = rtwdev->pci_info; 279962306a36Sopenharmony_ci struct rtw89_pci_tx_ring *tx_ring; 280062306a36Sopenharmony_ci int i; 280162306a36Sopenharmony_ci 280262306a36Sopenharmony_ci for (i = 0; i < RTW89_TXCH_NUM; i++) { 280362306a36Sopenharmony_ci if (info->tx_dma_ch_mask & BIT(i)) 280462306a36Sopenharmony_ci continue; 280562306a36Sopenharmony_ci tx_ring = &rtwpci->tx_rings[i]; 280662306a36Sopenharmony_ci rtw89_pci_free_tx_wd_ring(rtwdev, pdev, tx_ring); 280762306a36Sopenharmony_ci rtw89_pci_free_tx_ring(rtwdev, pdev, tx_ring); 280862306a36Sopenharmony_ci } 280962306a36Sopenharmony_ci} 281062306a36Sopenharmony_ci 281162306a36Sopenharmony_cistatic void rtw89_pci_free_rx_ring(struct rtw89_dev *rtwdev, 281262306a36Sopenharmony_ci struct pci_dev *pdev, 281362306a36Sopenharmony_ci struct rtw89_pci_rx_ring *rx_ring) 281462306a36Sopenharmony_ci{ 281562306a36Sopenharmony_ci struct rtw89_pci_rx_info *rx_info; 281662306a36Sopenharmony_ci struct sk_buff *skb; 281762306a36Sopenharmony_ci dma_addr_t dma; 281862306a36Sopenharmony_ci u32 buf_sz; 281962306a36Sopenharmony_ci u8 *head; 282062306a36Sopenharmony_ci int ring_sz = rx_ring->bd_ring.desc_size * rx_ring->bd_ring.len; 282162306a36Sopenharmony_ci int i; 282262306a36Sopenharmony_ci 282362306a36Sopenharmony_ci buf_sz = rx_ring->buf_sz; 282462306a36Sopenharmony_ci for (i = 0; i < rx_ring->bd_ring.len; i++) { 282562306a36Sopenharmony_ci skb = rx_ring->buf[i]; 282662306a36Sopenharmony_ci if (!skb) 282762306a36Sopenharmony_ci continue; 282862306a36Sopenharmony_ci 282962306a36Sopenharmony_ci rx_info = RTW89_PCI_RX_SKB_CB(skb); 283062306a36Sopenharmony_ci dma = rx_info->dma; 283162306a36Sopenharmony_ci dma_unmap_single(&pdev->dev, dma, buf_sz, DMA_FROM_DEVICE); 283262306a36Sopenharmony_ci dev_kfree_skb(skb); 283362306a36Sopenharmony_ci rx_ring->buf[i] = NULL; 283462306a36Sopenharmony_ci } 283562306a36Sopenharmony_ci 283662306a36Sopenharmony_ci head = rx_ring->bd_ring.head; 283762306a36Sopenharmony_ci dma = rx_ring->bd_ring.dma; 283862306a36Sopenharmony_ci dma_free_coherent(&pdev->dev, ring_sz, head, dma); 283962306a36Sopenharmony_ci 284062306a36Sopenharmony_ci rx_ring->bd_ring.head = NULL; 284162306a36Sopenharmony_ci} 284262306a36Sopenharmony_ci 284362306a36Sopenharmony_cistatic void rtw89_pci_free_rx_rings(struct rtw89_dev *rtwdev, 284462306a36Sopenharmony_ci struct pci_dev *pdev) 284562306a36Sopenharmony_ci{ 284662306a36Sopenharmony_ci struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; 284762306a36Sopenharmony_ci struct rtw89_pci_rx_ring *rx_ring; 284862306a36Sopenharmony_ci int i; 284962306a36Sopenharmony_ci 285062306a36Sopenharmony_ci for (i = 0; i < RTW89_RXCH_NUM; i++) { 285162306a36Sopenharmony_ci rx_ring = &rtwpci->rx_rings[i]; 285262306a36Sopenharmony_ci rtw89_pci_free_rx_ring(rtwdev, pdev, rx_ring); 285362306a36Sopenharmony_ci } 285462306a36Sopenharmony_ci} 285562306a36Sopenharmony_ci 285662306a36Sopenharmony_cistatic void rtw89_pci_free_trx_rings(struct rtw89_dev *rtwdev, 285762306a36Sopenharmony_ci struct pci_dev *pdev) 285862306a36Sopenharmony_ci{ 285962306a36Sopenharmony_ci rtw89_pci_free_rx_rings(rtwdev, pdev); 286062306a36Sopenharmony_ci rtw89_pci_free_tx_rings(rtwdev, pdev); 286162306a36Sopenharmony_ci} 286262306a36Sopenharmony_ci 286362306a36Sopenharmony_cistatic int rtw89_pci_init_rx_bd(struct rtw89_dev *rtwdev, struct pci_dev *pdev, 286462306a36Sopenharmony_ci struct rtw89_pci_rx_ring *rx_ring, 286562306a36Sopenharmony_ci struct sk_buff *skb, int buf_sz, u32 idx) 286662306a36Sopenharmony_ci{ 286762306a36Sopenharmony_ci struct rtw89_pci_rx_info *rx_info; 286862306a36Sopenharmony_ci struct rtw89_pci_rx_bd_32 *rx_bd; 286962306a36Sopenharmony_ci dma_addr_t dma; 287062306a36Sopenharmony_ci 287162306a36Sopenharmony_ci if (!skb) 287262306a36Sopenharmony_ci return -EINVAL; 287362306a36Sopenharmony_ci 287462306a36Sopenharmony_ci dma = dma_map_single(&pdev->dev, skb->data, buf_sz, DMA_FROM_DEVICE); 287562306a36Sopenharmony_ci if (dma_mapping_error(&pdev->dev, dma)) 287662306a36Sopenharmony_ci return -EBUSY; 287762306a36Sopenharmony_ci 287862306a36Sopenharmony_ci rx_info = RTW89_PCI_RX_SKB_CB(skb); 287962306a36Sopenharmony_ci rx_bd = RTW89_PCI_RX_BD(rx_ring, idx); 288062306a36Sopenharmony_ci 288162306a36Sopenharmony_ci memset(rx_bd, 0, sizeof(*rx_bd)); 288262306a36Sopenharmony_ci rx_bd->buf_size = cpu_to_le16(buf_sz); 288362306a36Sopenharmony_ci rx_bd->dma = cpu_to_le32(dma); 288462306a36Sopenharmony_ci rx_info->dma = dma; 288562306a36Sopenharmony_ci 288662306a36Sopenharmony_ci return 0; 288762306a36Sopenharmony_ci} 288862306a36Sopenharmony_ci 288962306a36Sopenharmony_cistatic int rtw89_pci_alloc_tx_wd_ring(struct rtw89_dev *rtwdev, 289062306a36Sopenharmony_ci struct pci_dev *pdev, 289162306a36Sopenharmony_ci struct rtw89_pci_tx_ring *tx_ring, 289262306a36Sopenharmony_ci enum rtw89_tx_channel txch) 289362306a36Sopenharmony_ci{ 289462306a36Sopenharmony_ci struct rtw89_pci_tx_wd_ring *wd_ring = &tx_ring->wd_ring; 289562306a36Sopenharmony_ci struct rtw89_pci_tx_wd *txwd; 289662306a36Sopenharmony_ci dma_addr_t dma; 289762306a36Sopenharmony_ci dma_addr_t cur_paddr; 289862306a36Sopenharmony_ci u8 *head; 289962306a36Sopenharmony_ci u8 *cur_vaddr; 290062306a36Sopenharmony_ci u32 page_size = RTW89_PCI_TXWD_PAGE_SIZE; 290162306a36Sopenharmony_ci u32 page_num = RTW89_PCI_TXWD_NUM_MAX; 290262306a36Sopenharmony_ci u32 ring_sz = page_size * page_num; 290362306a36Sopenharmony_ci u32 page_offset; 290462306a36Sopenharmony_ci int i; 290562306a36Sopenharmony_ci 290662306a36Sopenharmony_ci /* FWCMD queue doesn't use txwd as pages */ 290762306a36Sopenharmony_ci if (txch == RTW89_TXCH_CH12) 290862306a36Sopenharmony_ci return 0; 290962306a36Sopenharmony_ci 291062306a36Sopenharmony_ci head = dma_alloc_coherent(&pdev->dev, ring_sz, &dma, GFP_KERNEL); 291162306a36Sopenharmony_ci if (!head) 291262306a36Sopenharmony_ci return -ENOMEM; 291362306a36Sopenharmony_ci 291462306a36Sopenharmony_ci INIT_LIST_HEAD(&wd_ring->free_pages); 291562306a36Sopenharmony_ci wd_ring->head = head; 291662306a36Sopenharmony_ci wd_ring->dma = dma; 291762306a36Sopenharmony_ci wd_ring->page_size = page_size; 291862306a36Sopenharmony_ci wd_ring->page_num = page_num; 291962306a36Sopenharmony_ci 292062306a36Sopenharmony_ci page_offset = 0; 292162306a36Sopenharmony_ci for (i = 0; i < page_num; i++) { 292262306a36Sopenharmony_ci txwd = &wd_ring->pages[i]; 292362306a36Sopenharmony_ci cur_paddr = dma + page_offset; 292462306a36Sopenharmony_ci cur_vaddr = head + page_offset; 292562306a36Sopenharmony_ci 292662306a36Sopenharmony_ci skb_queue_head_init(&txwd->queue); 292762306a36Sopenharmony_ci INIT_LIST_HEAD(&txwd->list); 292862306a36Sopenharmony_ci txwd->paddr = cur_paddr; 292962306a36Sopenharmony_ci txwd->vaddr = cur_vaddr; 293062306a36Sopenharmony_ci txwd->len = page_size; 293162306a36Sopenharmony_ci txwd->seq = i; 293262306a36Sopenharmony_ci rtw89_pci_enqueue_txwd(tx_ring, txwd); 293362306a36Sopenharmony_ci 293462306a36Sopenharmony_ci page_offset += page_size; 293562306a36Sopenharmony_ci } 293662306a36Sopenharmony_ci 293762306a36Sopenharmony_ci return 0; 293862306a36Sopenharmony_ci} 293962306a36Sopenharmony_ci 294062306a36Sopenharmony_cistatic int rtw89_pci_alloc_tx_ring(struct rtw89_dev *rtwdev, 294162306a36Sopenharmony_ci struct pci_dev *pdev, 294262306a36Sopenharmony_ci struct rtw89_pci_tx_ring *tx_ring, 294362306a36Sopenharmony_ci u32 desc_size, u32 len, 294462306a36Sopenharmony_ci enum rtw89_tx_channel txch) 294562306a36Sopenharmony_ci{ 294662306a36Sopenharmony_ci const struct rtw89_pci_ch_dma_addr *txch_addr; 294762306a36Sopenharmony_ci int ring_sz = desc_size * len; 294862306a36Sopenharmony_ci u8 *head; 294962306a36Sopenharmony_ci dma_addr_t dma; 295062306a36Sopenharmony_ci int ret; 295162306a36Sopenharmony_ci 295262306a36Sopenharmony_ci ret = rtw89_pci_alloc_tx_wd_ring(rtwdev, pdev, tx_ring, txch); 295362306a36Sopenharmony_ci if (ret) { 295462306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to alloc txwd ring of txch %d\n", txch); 295562306a36Sopenharmony_ci goto err; 295662306a36Sopenharmony_ci } 295762306a36Sopenharmony_ci 295862306a36Sopenharmony_ci ret = rtw89_pci_get_txch_addrs(rtwdev, txch, &txch_addr); 295962306a36Sopenharmony_ci if (ret) { 296062306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to get address of txch %d", txch); 296162306a36Sopenharmony_ci goto err_free_wd_ring; 296262306a36Sopenharmony_ci } 296362306a36Sopenharmony_ci 296462306a36Sopenharmony_ci head = dma_alloc_coherent(&pdev->dev, ring_sz, &dma, GFP_KERNEL); 296562306a36Sopenharmony_ci if (!head) { 296662306a36Sopenharmony_ci ret = -ENOMEM; 296762306a36Sopenharmony_ci goto err_free_wd_ring; 296862306a36Sopenharmony_ci } 296962306a36Sopenharmony_ci 297062306a36Sopenharmony_ci INIT_LIST_HEAD(&tx_ring->busy_pages); 297162306a36Sopenharmony_ci tx_ring->bd_ring.head = head; 297262306a36Sopenharmony_ci tx_ring->bd_ring.dma = dma; 297362306a36Sopenharmony_ci tx_ring->bd_ring.len = len; 297462306a36Sopenharmony_ci tx_ring->bd_ring.desc_size = desc_size; 297562306a36Sopenharmony_ci tx_ring->bd_ring.addr = *txch_addr; 297662306a36Sopenharmony_ci tx_ring->bd_ring.wp = 0; 297762306a36Sopenharmony_ci tx_ring->bd_ring.rp = 0; 297862306a36Sopenharmony_ci tx_ring->txch = txch; 297962306a36Sopenharmony_ci 298062306a36Sopenharmony_ci return 0; 298162306a36Sopenharmony_ci 298262306a36Sopenharmony_cierr_free_wd_ring: 298362306a36Sopenharmony_ci rtw89_pci_free_tx_wd_ring(rtwdev, pdev, tx_ring); 298462306a36Sopenharmony_cierr: 298562306a36Sopenharmony_ci return ret; 298662306a36Sopenharmony_ci} 298762306a36Sopenharmony_ci 298862306a36Sopenharmony_cistatic int rtw89_pci_alloc_tx_rings(struct rtw89_dev *rtwdev, 298962306a36Sopenharmony_ci struct pci_dev *pdev) 299062306a36Sopenharmony_ci{ 299162306a36Sopenharmony_ci struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; 299262306a36Sopenharmony_ci const struct rtw89_pci_info *info = rtwdev->pci_info; 299362306a36Sopenharmony_ci struct rtw89_pci_tx_ring *tx_ring; 299462306a36Sopenharmony_ci u32 desc_size; 299562306a36Sopenharmony_ci u32 len; 299662306a36Sopenharmony_ci u32 i, tx_allocated; 299762306a36Sopenharmony_ci int ret; 299862306a36Sopenharmony_ci 299962306a36Sopenharmony_ci for (i = 0; i < RTW89_TXCH_NUM; i++) { 300062306a36Sopenharmony_ci if (info->tx_dma_ch_mask & BIT(i)) 300162306a36Sopenharmony_ci continue; 300262306a36Sopenharmony_ci tx_ring = &rtwpci->tx_rings[i]; 300362306a36Sopenharmony_ci desc_size = sizeof(struct rtw89_pci_tx_bd_32); 300462306a36Sopenharmony_ci len = RTW89_PCI_TXBD_NUM_MAX; 300562306a36Sopenharmony_ci ret = rtw89_pci_alloc_tx_ring(rtwdev, pdev, tx_ring, 300662306a36Sopenharmony_ci desc_size, len, i); 300762306a36Sopenharmony_ci if (ret) { 300862306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to alloc tx ring %d\n", i); 300962306a36Sopenharmony_ci goto err_free; 301062306a36Sopenharmony_ci } 301162306a36Sopenharmony_ci } 301262306a36Sopenharmony_ci 301362306a36Sopenharmony_ci return 0; 301462306a36Sopenharmony_ci 301562306a36Sopenharmony_cierr_free: 301662306a36Sopenharmony_ci tx_allocated = i; 301762306a36Sopenharmony_ci for (i = 0; i < tx_allocated; i++) { 301862306a36Sopenharmony_ci tx_ring = &rtwpci->tx_rings[i]; 301962306a36Sopenharmony_ci rtw89_pci_free_tx_ring(rtwdev, pdev, tx_ring); 302062306a36Sopenharmony_ci } 302162306a36Sopenharmony_ci 302262306a36Sopenharmony_ci return ret; 302362306a36Sopenharmony_ci} 302462306a36Sopenharmony_ci 302562306a36Sopenharmony_cistatic int rtw89_pci_alloc_rx_ring(struct rtw89_dev *rtwdev, 302662306a36Sopenharmony_ci struct pci_dev *pdev, 302762306a36Sopenharmony_ci struct rtw89_pci_rx_ring *rx_ring, 302862306a36Sopenharmony_ci u32 desc_size, u32 len, u32 rxch) 302962306a36Sopenharmony_ci{ 303062306a36Sopenharmony_ci const struct rtw89_pci_ch_dma_addr *rxch_addr; 303162306a36Sopenharmony_ci struct sk_buff *skb; 303262306a36Sopenharmony_ci u8 *head; 303362306a36Sopenharmony_ci dma_addr_t dma; 303462306a36Sopenharmony_ci int ring_sz = desc_size * len; 303562306a36Sopenharmony_ci int buf_sz = RTW89_PCI_RX_BUF_SIZE; 303662306a36Sopenharmony_ci int i, allocated; 303762306a36Sopenharmony_ci int ret; 303862306a36Sopenharmony_ci 303962306a36Sopenharmony_ci ret = rtw89_pci_get_rxch_addrs(rtwdev, rxch, &rxch_addr); 304062306a36Sopenharmony_ci if (ret) { 304162306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to get address of rxch %d", rxch); 304262306a36Sopenharmony_ci return ret; 304362306a36Sopenharmony_ci } 304462306a36Sopenharmony_ci 304562306a36Sopenharmony_ci head = dma_alloc_coherent(&pdev->dev, ring_sz, &dma, GFP_KERNEL); 304662306a36Sopenharmony_ci if (!head) { 304762306a36Sopenharmony_ci ret = -ENOMEM; 304862306a36Sopenharmony_ci goto err; 304962306a36Sopenharmony_ci } 305062306a36Sopenharmony_ci 305162306a36Sopenharmony_ci rx_ring->bd_ring.head = head; 305262306a36Sopenharmony_ci rx_ring->bd_ring.dma = dma; 305362306a36Sopenharmony_ci rx_ring->bd_ring.len = len; 305462306a36Sopenharmony_ci rx_ring->bd_ring.desc_size = desc_size; 305562306a36Sopenharmony_ci rx_ring->bd_ring.addr = *rxch_addr; 305662306a36Sopenharmony_ci rx_ring->bd_ring.wp = 0; 305762306a36Sopenharmony_ci rx_ring->bd_ring.rp = 0; 305862306a36Sopenharmony_ci rx_ring->buf_sz = buf_sz; 305962306a36Sopenharmony_ci rx_ring->diliver_skb = NULL; 306062306a36Sopenharmony_ci rx_ring->diliver_desc.ready = false; 306162306a36Sopenharmony_ci 306262306a36Sopenharmony_ci for (i = 0; i < len; i++) { 306362306a36Sopenharmony_ci skb = dev_alloc_skb(buf_sz); 306462306a36Sopenharmony_ci if (!skb) { 306562306a36Sopenharmony_ci ret = -ENOMEM; 306662306a36Sopenharmony_ci goto err_free; 306762306a36Sopenharmony_ci } 306862306a36Sopenharmony_ci 306962306a36Sopenharmony_ci memset(skb->data, 0, buf_sz); 307062306a36Sopenharmony_ci rx_ring->buf[i] = skb; 307162306a36Sopenharmony_ci ret = rtw89_pci_init_rx_bd(rtwdev, pdev, rx_ring, skb, 307262306a36Sopenharmony_ci buf_sz, i); 307362306a36Sopenharmony_ci if (ret) { 307462306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to init rx buf %d\n", i); 307562306a36Sopenharmony_ci dev_kfree_skb_any(skb); 307662306a36Sopenharmony_ci rx_ring->buf[i] = NULL; 307762306a36Sopenharmony_ci goto err_free; 307862306a36Sopenharmony_ci } 307962306a36Sopenharmony_ci } 308062306a36Sopenharmony_ci 308162306a36Sopenharmony_ci return 0; 308262306a36Sopenharmony_ci 308362306a36Sopenharmony_cierr_free: 308462306a36Sopenharmony_ci allocated = i; 308562306a36Sopenharmony_ci for (i = 0; i < allocated; i++) { 308662306a36Sopenharmony_ci skb = rx_ring->buf[i]; 308762306a36Sopenharmony_ci if (!skb) 308862306a36Sopenharmony_ci continue; 308962306a36Sopenharmony_ci dma = *((dma_addr_t *)skb->cb); 309062306a36Sopenharmony_ci dma_unmap_single(&pdev->dev, dma, buf_sz, DMA_FROM_DEVICE); 309162306a36Sopenharmony_ci dev_kfree_skb(skb); 309262306a36Sopenharmony_ci rx_ring->buf[i] = NULL; 309362306a36Sopenharmony_ci } 309462306a36Sopenharmony_ci 309562306a36Sopenharmony_ci head = rx_ring->bd_ring.head; 309662306a36Sopenharmony_ci dma = rx_ring->bd_ring.dma; 309762306a36Sopenharmony_ci dma_free_coherent(&pdev->dev, ring_sz, head, dma); 309862306a36Sopenharmony_ci 309962306a36Sopenharmony_ci rx_ring->bd_ring.head = NULL; 310062306a36Sopenharmony_cierr: 310162306a36Sopenharmony_ci return ret; 310262306a36Sopenharmony_ci} 310362306a36Sopenharmony_ci 310462306a36Sopenharmony_cistatic int rtw89_pci_alloc_rx_rings(struct rtw89_dev *rtwdev, 310562306a36Sopenharmony_ci struct pci_dev *pdev) 310662306a36Sopenharmony_ci{ 310762306a36Sopenharmony_ci struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; 310862306a36Sopenharmony_ci struct rtw89_pci_rx_ring *rx_ring; 310962306a36Sopenharmony_ci u32 desc_size; 311062306a36Sopenharmony_ci u32 len; 311162306a36Sopenharmony_ci int i, rx_allocated; 311262306a36Sopenharmony_ci int ret; 311362306a36Sopenharmony_ci 311462306a36Sopenharmony_ci for (i = 0; i < RTW89_RXCH_NUM; i++) { 311562306a36Sopenharmony_ci rx_ring = &rtwpci->rx_rings[i]; 311662306a36Sopenharmony_ci desc_size = sizeof(struct rtw89_pci_rx_bd_32); 311762306a36Sopenharmony_ci len = RTW89_PCI_RXBD_NUM_MAX; 311862306a36Sopenharmony_ci ret = rtw89_pci_alloc_rx_ring(rtwdev, pdev, rx_ring, 311962306a36Sopenharmony_ci desc_size, len, i); 312062306a36Sopenharmony_ci if (ret) { 312162306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to alloc rx ring %d\n", i); 312262306a36Sopenharmony_ci goto err_free; 312362306a36Sopenharmony_ci } 312462306a36Sopenharmony_ci } 312562306a36Sopenharmony_ci 312662306a36Sopenharmony_ci return 0; 312762306a36Sopenharmony_ci 312862306a36Sopenharmony_cierr_free: 312962306a36Sopenharmony_ci rx_allocated = i; 313062306a36Sopenharmony_ci for (i = 0; i < rx_allocated; i++) { 313162306a36Sopenharmony_ci rx_ring = &rtwpci->rx_rings[i]; 313262306a36Sopenharmony_ci rtw89_pci_free_rx_ring(rtwdev, pdev, rx_ring); 313362306a36Sopenharmony_ci } 313462306a36Sopenharmony_ci 313562306a36Sopenharmony_ci return ret; 313662306a36Sopenharmony_ci} 313762306a36Sopenharmony_ci 313862306a36Sopenharmony_cistatic int rtw89_pci_alloc_trx_rings(struct rtw89_dev *rtwdev, 313962306a36Sopenharmony_ci struct pci_dev *pdev) 314062306a36Sopenharmony_ci{ 314162306a36Sopenharmony_ci int ret; 314262306a36Sopenharmony_ci 314362306a36Sopenharmony_ci ret = rtw89_pci_alloc_tx_rings(rtwdev, pdev); 314462306a36Sopenharmony_ci if (ret) { 314562306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to alloc dma tx rings\n"); 314662306a36Sopenharmony_ci goto err; 314762306a36Sopenharmony_ci } 314862306a36Sopenharmony_ci 314962306a36Sopenharmony_ci ret = rtw89_pci_alloc_rx_rings(rtwdev, pdev); 315062306a36Sopenharmony_ci if (ret) { 315162306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to alloc dma rx rings\n"); 315262306a36Sopenharmony_ci goto err_free_tx_rings; 315362306a36Sopenharmony_ci } 315462306a36Sopenharmony_ci 315562306a36Sopenharmony_ci return 0; 315662306a36Sopenharmony_ci 315762306a36Sopenharmony_cierr_free_tx_rings: 315862306a36Sopenharmony_ci rtw89_pci_free_tx_rings(rtwdev, pdev); 315962306a36Sopenharmony_cierr: 316062306a36Sopenharmony_ci return ret; 316162306a36Sopenharmony_ci} 316262306a36Sopenharmony_ci 316362306a36Sopenharmony_cistatic void rtw89_pci_h2c_init(struct rtw89_dev *rtwdev, 316462306a36Sopenharmony_ci struct rtw89_pci *rtwpci) 316562306a36Sopenharmony_ci{ 316662306a36Sopenharmony_ci skb_queue_head_init(&rtwpci->h2c_queue); 316762306a36Sopenharmony_ci skb_queue_head_init(&rtwpci->h2c_release_queue); 316862306a36Sopenharmony_ci} 316962306a36Sopenharmony_ci 317062306a36Sopenharmony_cistatic int rtw89_pci_setup_resource(struct rtw89_dev *rtwdev, 317162306a36Sopenharmony_ci struct pci_dev *pdev) 317262306a36Sopenharmony_ci{ 317362306a36Sopenharmony_ci struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; 317462306a36Sopenharmony_ci int ret; 317562306a36Sopenharmony_ci 317662306a36Sopenharmony_ci ret = rtw89_pci_setup_mapping(rtwdev, pdev); 317762306a36Sopenharmony_ci if (ret) { 317862306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to setup pci mapping\n"); 317962306a36Sopenharmony_ci goto err; 318062306a36Sopenharmony_ci } 318162306a36Sopenharmony_ci 318262306a36Sopenharmony_ci ret = rtw89_pci_alloc_trx_rings(rtwdev, pdev); 318362306a36Sopenharmony_ci if (ret) { 318462306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to alloc pci trx rings\n"); 318562306a36Sopenharmony_ci goto err_pci_unmap; 318662306a36Sopenharmony_ci } 318762306a36Sopenharmony_ci 318862306a36Sopenharmony_ci rtw89_pci_h2c_init(rtwdev, rtwpci); 318962306a36Sopenharmony_ci 319062306a36Sopenharmony_ci spin_lock_init(&rtwpci->irq_lock); 319162306a36Sopenharmony_ci spin_lock_init(&rtwpci->trx_lock); 319262306a36Sopenharmony_ci 319362306a36Sopenharmony_ci return 0; 319462306a36Sopenharmony_ci 319562306a36Sopenharmony_cierr_pci_unmap: 319662306a36Sopenharmony_ci rtw89_pci_clear_mapping(rtwdev, pdev); 319762306a36Sopenharmony_cierr: 319862306a36Sopenharmony_ci return ret; 319962306a36Sopenharmony_ci} 320062306a36Sopenharmony_ci 320162306a36Sopenharmony_cistatic void rtw89_pci_clear_resource(struct rtw89_dev *rtwdev, 320262306a36Sopenharmony_ci struct pci_dev *pdev) 320362306a36Sopenharmony_ci{ 320462306a36Sopenharmony_ci struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; 320562306a36Sopenharmony_ci 320662306a36Sopenharmony_ci rtw89_pci_free_trx_rings(rtwdev, pdev); 320762306a36Sopenharmony_ci rtw89_pci_clear_mapping(rtwdev, pdev); 320862306a36Sopenharmony_ci rtw89_pci_release_fwcmd(rtwdev, rtwpci, 320962306a36Sopenharmony_ci skb_queue_len(&rtwpci->h2c_queue), true); 321062306a36Sopenharmony_ci} 321162306a36Sopenharmony_ci 321262306a36Sopenharmony_civoid rtw89_pci_config_intr_mask(struct rtw89_dev *rtwdev) 321362306a36Sopenharmony_ci{ 321462306a36Sopenharmony_ci struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; 321562306a36Sopenharmony_ci const struct rtw89_chip_info *chip = rtwdev->chip; 321662306a36Sopenharmony_ci u32 hs0isr_ind_int_en = B_AX_HS0ISR_IND_INT_EN; 321762306a36Sopenharmony_ci 321862306a36Sopenharmony_ci if (chip->chip_id == RTL8851B) 321962306a36Sopenharmony_ci hs0isr_ind_int_en = B_AX_HS0ISR_IND_INT_EN_WKARND; 322062306a36Sopenharmony_ci 322162306a36Sopenharmony_ci rtwpci->halt_c2h_intrs = B_AX_HALT_C2H_INT_EN | 0; 322262306a36Sopenharmony_ci 322362306a36Sopenharmony_ci if (rtwpci->under_recovery) { 322462306a36Sopenharmony_ci rtwpci->intrs[0] = hs0isr_ind_int_en; 322562306a36Sopenharmony_ci rtwpci->intrs[1] = 0; 322662306a36Sopenharmony_ci } else { 322762306a36Sopenharmony_ci rtwpci->intrs[0] = B_AX_TXDMA_STUCK_INT_EN | 322862306a36Sopenharmony_ci B_AX_RXDMA_INT_EN | 322962306a36Sopenharmony_ci B_AX_RXP1DMA_INT_EN | 323062306a36Sopenharmony_ci B_AX_RPQDMA_INT_EN | 323162306a36Sopenharmony_ci B_AX_RXDMA_STUCK_INT_EN | 323262306a36Sopenharmony_ci B_AX_RDU_INT_EN | 323362306a36Sopenharmony_ci B_AX_RPQBD_FULL_INT_EN | 323462306a36Sopenharmony_ci hs0isr_ind_int_en; 323562306a36Sopenharmony_ci 323662306a36Sopenharmony_ci rtwpci->intrs[1] = B_AX_HC10ISR_IND_INT_EN; 323762306a36Sopenharmony_ci } 323862306a36Sopenharmony_ci} 323962306a36Sopenharmony_ciEXPORT_SYMBOL(rtw89_pci_config_intr_mask); 324062306a36Sopenharmony_ci 324162306a36Sopenharmony_cistatic void rtw89_pci_recovery_intr_mask_v1(struct rtw89_dev *rtwdev) 324262306a36Sopenharmony_ci{ 324362306a36Sopenharmony_ci struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; 324462306a36Sopenharmony_ci 324562306a36Sopenharmony_ci rtwpci->ind_intrs = B_AX_HS0ISR_IND_INT_EN; 324662306a36Sopenharmony_ci rtwpci->halt_c2h_intrs = B_AX_HALT_C2H_INT_EN | B_AX_WDT_TIMEOUT_INT_EN; 324762306a36Sopenharmony_ci rtwpci->intrs[0] = 0; 324862306a36Sopenharmony_ci rtwpci->intrs[1] = 0; 324962306a36Sopenharmony_ci} 325062306a36Sopenharmony_ci 325162306a36Sopenharmony_cistatic void rtw89_pci_default_intr_mask_v1(struct rtw89_dev *rtwdev) 325262306a36Sopenharmony_ci{ 325362306a36Sopenharmony_ci struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; 325462306a36Sopenharmony_ci 325562306a36Sopenharmony_ci rtwpci->ind_intrs = B_AX_HCI_AXIDMA_INT_EN | 325662306a36Sopenharmony_ci B_AX_HS1ISR_IND_INT_EN | 325762306a36Sopenharmony_ci B_AX_HS0ISR_IND_INT_EN; 325862306a36Sopenharmony_ci rtwpci->halt_c2h_intrs = B_AX_HALT_C2H_INT_EN | B_AX_WDT_TIMEOUT_INT_EN; 325962306a36Sopenharmony_ci rtwpci->intrs[0] = B_AX_TXDMA_STUCK_INT_EN | 326062306a36Sopenharmony_ci B_AX_RXDMA_INT_EN | 326162306a36Sopenharmony_ci B_AX_RXP1DMA_INT_EN | 326262306a36Sopenharmony_ci B_AX_RPQDMA_INT_EN | 326362306a36Sopenharmony_ci B_AX_RXDMA_STUCK_INT_EN | 326462306a36Sopenharmony_ci B_AX_RDU_INT_EN | 326562306a36Sopenharmony_ci B_AX_RPQBD_FULL_INT_EN; 326662306a36Sopenharmony_ci rtwpci->intrs[1] = B_AX_GPIO18_INT_EN; 326762306a36Sopenharmony_ci} 326862306a36Sopenharmony_ci 326962306a36Sopenharmony_cistatic void rtw89_pci_low_power_intr_mask_v1(struct rtw89_dev *rtwdev) 327062306a36Sopenharmony_ci{ 327162306a36Sopenharmony_ci struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; 327262306a36Sopenharmony_ci 327362306a36Sopenharmony_ci rtwpci->ind_intrs = B_AX_HS1ISR_IND_INT_EN | 327462306a36Sopenharmony_ci B_AX_HS0ISR_IND_INT_EN; 327562306a36Sopenharmony_ci rtwpci->halt_c2h_intrs = B_AX_HALT_C2H_INT_EN | B_AX_WDT_TIMEOUT_INT_EN; 327662306a36Sopenharmony_ci rtwpci->intrs[0] = 0; 327762306a36Sopenharmony_ci rtwpci->intrs[1] = B_AX_GPIO18_INT_EN; 327862306a36Sopenharmony_ci} 327962306a36Sopenharmony_ci 328062306a36Sopenharmony_civoid rtw89_pci_config_intr_mask_v1(struct rtw89_dev *rtwdev) 328162306a36Sopenharmony_ci{ 328262306a36Sopenharmony_ci struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; 328362306a36Sopenharmony_ci 328462306a36Sopenharmony_ci if (rtwpci->under_recovery) 328562306a36Sopenharmony_ci rtw89_pci_recovery_intr_mask_v1(rtwdev); 328662306a36Sopenharmony_ci else if (rtwpci->low_power) 328762306a36Sopenharmony_ci rtw89_pci_low_power_intr_mask_v1(rtwdev); 328862306a36Sopenharmony_ci else 328962306a36Sopenharmony_ci rtw89_pci_default_intr_mask_v1(rtwdev); 329062306a36Sopenharmony_ci} 329162306a36Sopenharmony_ciEXPORT_SYMBOL(rtw89_pci_config_intr_mask_v1); 329262306a36Sopenharmony_ci 329362306a36Sopenharmony_cistatic int rtw89_pci_request_irq(struct rtw89_dev *rtwdev, 329462306a36Sopenharmony_ci struct pci_dev *pdev) 329562306a36Sopenharmony_ci{ 329662306a36Sopenharmony_ci unsigned long flags = 0; 329762306a36Sopenharmony_ci int ret; 329862306a36Sopenharmony_ci 329962306a36Sopenharmony_ci flags |= PCI_IRQ_LEGACY | PCI_IRQ_MSI; 330062306a36Sopenharmony_ci ret = pci_alloc_irq_vectors(pdev, 1, 1, flags); 330162306a36Sopenharmony_ci if (ret < 0) { 330262306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to alloc irq vectors, ret %d\n", ret); 330362306a36Sopenharmony_ci goto err; 330462306a36Sopenharmony_ci } 330562306a36Sopenharmony_ci 330662306a36Sopenharmony_ci ret = devm_request_threaded_irq(rtwdev->dev, pdev->irq, 330762306a36Sopenharmony_ci rtw89_pci_interrupt_handler, 330862306a36Sopenharmony_ci rtw89_pci_interrupt_threadfn, 330962306a36Sopenharmony_ci IRQF_SHARED, KBUILD_MODNAME, rtwdev); 331062306a36Sopenharmony_ci if (ret) { 331162306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to request threaded irq\n"); 331262306a36Sopenharmony_ci goto err_free_vector; 331362306a36Sopenharmony_ci } 331462306a36Sopenharmony_ci 331562306a36Sopenharmony_ci rtw89_chip_config_intr_mask(rtwdev, RTW89_PCI_INTR_MASK_RESET); 331662306a36Sopenharmony_ci 331762306a36Sopenharmony_ci return 0; 331862306a36Sopenharmony_ci 331962306a36Sopenharmony_cierr_free_vector: 332062306a36Sopenharmony_ci pci_free_irq_vectors(pdev); 332162306a36Sopenharmony_cierr: 332262306a36Sopenharmony_ci return ret; 332362306a36Sopenharmony_ci} 332462306a36Sopenharmony_ci 332562306a36Sopenharmony_cistatic void rtw89_pci_free_irq(struct rtw89_dev *rtwdev, 332662306a36Sopenharmony_ci struct pci_dev *pdev) 332762306a36Sopenharmony_ci{ 332862306a36Sopenharmony_ci devm_free_irq(rtwdev->dev, pdev->irq, rtwdev); 332962306a36Sopenharmony_ci pci_free_irq_vectors(pdev); 333062306a36Sopenharmony_ci} 333162306a36Sopenharmony_ci 333262306a36Sopenharmony_cistatic u16 gray_code_to_bin(u16 gray_code, u32 bit_num) 333362306a36Sopenharmony_ci{ 333462306a36Sopenharmony_ci u16 bin = 0, gray_bit; 333562306a36Sopenharmony_ci u32 bit_idx; 333662306a36Sopenharmony_ci 333762306a36Sopenharmony_ci for (bit_idx = 0; bit_idx < bit_num; bit_idx++) { 333862306a36Sopenharmony_ci gray_bit = (gray_code >> bit_idx) & 0x1; 333962306a36Sopenharmony_ci if (bit_num - bit_idx > 1) 334062306a36Sopenharmony_ci gray_bit ^= (gray_code >> (bit_idx + 1)) & 0x1; 334162306a36Sopenharmony_ci bin |= (gray_bit << bit_idx); 334262306a36Sopenharmony_ci } 334362306a36Sopenharmony_ci 334462306a36Sopenharmony_ci return bin; 334562306a36Sopenharmony_ci} 334662306a36Sopenharmony_ci 334762306a36Sopenharmony_cistatic int rtw89_pci_filter_out(struct rtw89_dev *rtwdev) 334862306a36Sopenharmony_ci{ 334962306a36Sopenharmony_ci struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; 335062306a36Sopenharmony_ci struct pci_dev *pdev = rtwpci->pdev; 335162306a36Sopenharmony_ci u16 val16, filter_out_val; 335262306a36Sopenharmony_ci u32 val, phy_offset; 335362306a36Sopenharmony_ci int ret; 335462306a36Sopenharmony_ci 335562306a36Sopenharmony_ci if (rtwdev->chip->chip_id != RTL8852C) 335662306a36Sopenharmony_ci return 0; 335762306a36Sopenharmony_ci 335862306a36Sopenharmony_ci val = rtw89_read32_mask(rtwdev, R_AX_PCIE_MIX_CFG_V1, B_AX_ASPM_CTRL_MASK); 335962306a36Sopenharmony_ci if (val == B_AX_ASPM_CTRL_L1) 336062306a36Sopenharmony_ci return 0; 336162306a36Sopenharmony_ci 336262306a36Sopenharmony_ci ret = pci_read_config_dword(pdev, RTW89_PCIE_L1_STS_V1, &val); 336362306a36Sopenharmony_ci if (ret) 336462306a36Sopenharmony_ci return ret; 336562306a36Sopenharmony_ci 336662306a36Sopenharmony_ci val = FIELD_GET(RTW89_BCFG_LINK_SPEED_MASK, val); 336762306a36Sopenharmony_ci if (val == RTW89_PCIE_GEN1_SPEED) { 336862306a36Sopenharmony_ci phy_offset = R_RAC_DIRECT_OFFSET_G1; 336962306a36Sopenharmony_ci } else if (val == RTW89_PCIE_GEN2_SPEED) { 337062306a36Sopenharmony_ci phy_offset = R_RAC_DIRECT_OFFSET_G2; 337162306a36Sopenharmony_ci val16 = rtw89_read16(rtwdev, phy_offset + RAC_ANA10 * RAC_MULT); 337262306a36Sopenharmony_ci rtw89_write16_set(rtwdev, phy_offset + RAC_ANA10 * RAC_MULT, 337362306a36Sopenharmony_ci val16 | B_PCIE_BIT_PINOUT_DIS); 337462306a36Sopenharmony_ci rtw89_write16_set(rtwdev, phy_offset + RAC_ANA19 * RAC_MULT, 337562306a36Sopenharmony_ci val16 & ~B_PCIE_BIT_RD_SEL); 337662306a36Sopenharmony_ci 337762306a36Sopenharmony_ci val16 = rtw89_read16_mask(rtwdev, 337862306a36Sopenharmony_ci phy_offset + RAC_ANA1F * RAC_MULT, 337962306a36Sopenharmony_ci FILTER_OUT_EQ_MASK); 338062306a36Sopenharmony_ci val16 = gray_code_to_bin(val16, hweight16(val16)); 338162306a36Sopenharmony_ci filter_out_val = rtw89_read16(rtwdev, phy_offset + RAC_ANA24 * 338262306a36Sopenharmony_ci RAC_MULT); 338362306a36Sopenharmony_ci filter_out_val &= ~REG_FILTER_OUT_MASK; 338462306a36Sopenharmony_ci filter_out_val |= FIELD_PREP(REG_FILTER_OUT_MASK, val16); 338562306a36Sopenharmony_ci 338662306a36Sopenharmony_ci rtw89_write16(rtwdev, phy_offset + RAC_ANA24 * RAC_MULT, 338762306a36Sopenharmony_ci filter_out_val); 338862306a36Sopenharmony_ci rtw89_write16_set(rtwdev, phy_offset + RAC_ANA0A * RAC_MULT, 338962306a36Sopenharmony_ci B_BAC_EQ_SEL); 339062306a36Sopenharmony_ci rtw89_write16_set(rtwdev, 339162306a36Sopenharmony_ci R_RAC_DIRECT_OFFSET_G1 + RAC_ANA0C * RAC_MULT, 339262306a36Sopenharmony_ci B_PCIE_BIT_PSAVE); 339362306a36Sopenharmony_ci } else { 339462306a36Sopenharmony_ci return -EOPNOTSUPP; 339562306a36Sopenharmony_ci } 339662306a36Sopenharmony_ci rtw89_write16_set(rtwdev, phy_offset + RAC_ANA0C * RAC_MULT, 339762306a36Sopenharmony_ci B_PCIE_BIT_PSAVE); 339862306a36Sopenharmony_ci 339962306a36Sopenharmony_ci return 0; 340062306a36Sopenharmony_ci} 340162306a36Sopenharmony_ci 340262306a36Sopenharmony_cistatic void rtw89_pci_clkreq_set(struct rtw89_dev *rtwdev, bool enable) 340362306a36Sopenharmony_ci{ 340462306a36Sopenharmony_ci enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; 340562306a36Sopenharmony_ci int ret; 340662306a36Sopenharmony_ci 340762306a36Sopenharmony_ci if (rtw89_pci_disable_clkreq) 340862306a36Sopenharmony_ci return; 340962306a36Sopenharmony_ci 341062306a36Sopenharmony_ci ret = rtw89_pci_write_config_byte(rtwdev, RTW89_PCIE_CLK_CTRL, 341162306a36Sopenharmony_ci PCIE_CLKDLY_HW_30US); 341262306a36Sopenharmony_ci if (ret) 341362306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to set CLKREQ Delay\n"); 341462306a36Sopenharmony_ci 341562306a36Sopenharmony_ci if (chip_id == RTL8852A || chip_id == RTL8852B || chip_id == RTL8851B) { 341662306a36Sopenharmony_ci if (enable) 341762306a36Sopenharmony_ci ret = rtw89_pci_config_byte_set(rtwdev, 341862306a36Sopenharmony_ci RTW89_PCIE_L1_CTRL, 341962306a36Sopenharmony_ci RTW89_PCIE_BIT_CLK); 342062306a36Sopenharmony_ci else 342162306a36Sopenharmony_ci ret = rtw89_pci_config_byte_clr(rtwdev, 342262306a36Sopenharmony_ci RTW89_PCIE_L1_CTRL, 342362306a36Sopenharmony_ci RTW89_PCIE_BIT_CLK); 342462306a36Sopenharmony_ci if (ret) 342562306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to %s CLKREQ_L1, ret=%d", 342662306a36Sopenharmony_ci enable ? "set" : "unset", ret); 342762306a36Sopenharmony_ci } else if (chip_id == RTL8852C) { 342862306a36Sopenharmony_ci rtw89_write32_set(rtwdev, R_AX_PCIE_LAT_CTRL, 342962306a36Sopenharmony_ci B_AX_CLK_REQ_SEL_OPT | B_AX_CLK_REQ_SEL); 343062306a36Sopenharmony_ci if (enable) 343162306a36Sopenharmony_ci rtw89_write32_set(rtwdev, R_AX_L1_CLK_CTRL, 343262306a36Sopenharmony_ci B_AX_CLK_REQ_N); 343362306a36Sopenharmony_ci else 343462306a36Sopenharmony_ci rtw89_write32_clr(rtwdev, R_AX_L1_CLK_CTRL, 343562306a36Sopenharmony_ci B_AX_CLK_REQ_N); 343662306a36Sopenharmony_ci } 343762306a36Sopenharmony_ci} 343862306a36Sopenharmony_ci 343962306a36Sopenharmony_cistatic void rtw89_pci_aspm_set(struct rtw89_dev *rtwdev, bool enable) 344062306a36Sopenharmony_ci{ 344162306a36Sopenharmony_ci enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; 344262306a36Sopenharmony_ci u8 value = 0; 344362306a36Sopenharmony_ci int ret; 344462306a36Sopenharmony_ci 344562306a36Sopenharmony_ci if (rtw89_pci_disable_aspm_l1) 344662306a36Sopenharmony_ci return; 344762306a36Sopenharmony_ci 344862306a36Sopenharmony_ci ret = rtw89_pci_read_config_byte(rtwdev, RTW89_PCIE_ASPM_CTRL, &value); 344962306a36Sopenharmony_ci if (ret) 345062306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to read ASPM Delay\n"); 345162306a36Sopenharmony_ci 345262306a36Sopenharmony_ci value &= ~(RTW89_L1DLY_MASK | RTW89_L0DLY_MASK); 345362306a36Sopenharmony_ci value |= FIELD_PREP(RTW89_L1DLY_MASK, PCIE_L1DLY_16US) | 345462306a36Sopenharmony_ci FIELD_PREP(RTW89_L0DLY_MASK, PCIE_L0SDLY_4US); 345562306a36Sopenharmony_ci 345662306a36Sopenharmony_ci ret = rtw89_pci_write_config_byte(rtwdev, RTW89_PCIE_ASPM_CTRL, value); 345762306a36Sopenharmony_ci if (ret) 345862306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to read ASPM Delay\n"); 345962306a36Sopenharmony_ci 346062306a36Sopenharmony_ci if (chip_id == RTL8852A || chip_id == RTL8852B || chip_id == RTL8851B) { 346162306a36Sopenharmony_ci if (enable) 346262306a36Sopenharmony_ci ret = rtw89_pci_config_byte_set(rtwdev, 346362306a36Sopenharmony_ci RTW89_PCIE_L1_CTRL, 346462306a36Sopenharmony_ci RTW89_PCIE_BIT_L1); 346562306a36Sopenharmony_ci else 346662306a36Sopenharmony_ci ret = rtw89_pci_config_byte_clr(rtwdev, 346762306a36Sopenharmony_ci RTW89_PCIE_L1_CTRL, 346862306a36Sopenharmony_ci RTW89_PCIE_BIT_L1); 346962306a36Sopenharmony_ci } else if (chip_id == RTL8852C) { 347062306a36Sopenharmony_ci if (enable) 347162306a36Sopenharmony_ci rtw89_write32_set(rtwdev, R_AX_PCIE_MIX_CFG_V1, 347262306a36Sopenharmony_ci B_AX_ASPM_CTRL_L1); 347362306a36Sopenharmony_ci else 347462306a36Sopenharmony_ci rtw89_write32_clr(rtwdev, R_AX_PCIE_MIX_CFG_V1, 347562306a36Sopenharmony_ci B_AX_ASPM_CTRL_L1); 347662306a36Sopenharmony_ci } 347762306a36Sopenharmony_ci if (ret) 347862306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to %s ASPM L1, ret=%d", 347962306a36Sopenharmony_ci enable ? "set" : "unset", ret); 348062306a36Sopenharmony_ci} 348162306a36Sopenharmony_ci 348262306a36Sopenharmony_cistatic void rtw89_pci_recalc_int_mit(struct rtw89_dev *rtwdev) 348362306a36Sopenharmony_ci{ 348462306a36Sopenharmony_ci struct rtw89_traffic_stats *stats = &rtwdev->stats; 348562306a36Sopenharmony_ci enum rtw89_tfc_lv tx_tfc_lv = stats->tx_tfc_lv; 348662306a36Sopenharmony_ci enum rtw89_tfc_lv rx_tfc_lv = stats->rx_tfc_lv; 348762306a36Sopenharmony_ci u32 val = 0; 348862306a36Sopenharmony_ci 348962306a36Sopenharmony_ci if (!rtwdev->scanning && 349062306a36Sopenharmony_ci (tx_tfc_lv >= RTW89_TFC_HIGH || rx_tfc_lv >= RTW89_TFC_HIGH)) 349162306a36Sopenharmony_ci val = B_AX_RXMIT_RXP2_SEL | B_AX_RXMIT_RXP1_SEL | 349262306a36Sopenharmony_ci FIELD_PREP(B_AX_RXCOUNTER_MATCH_MASK, RTW89_PCI_RXBD_NUM_MAX / 2) | 349362306a36Sopenharmony_ci FIELD_PREP(B_AX_RXTIMER_UNIT_MASK, AX_RXTIMER_UNIT_64US) | 349462306a36Sopenharmony_ci FIELD_PREP(B_AX_RXTIMER_MATCH_MASK, 2048 / 64); 349562306a36Sopenharmony_ci 349662306a36Sopenharmony_ci rtw89_write32(rtwdev, R_AX_INT_MIT_RX, val); 349762306a36Sopenharmony_ci} 349862306a36Sopenharmony_ci 349962306a36Sopenharmony_cistatic void rtw89_pci_link_cfg(struct rtw89_dev *rtwdev) 350062306a36Sopenharmony_ci{ 350162306a36Sopenharmony_ci struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; 350262306a36Sopenharmony_ci struct pci_dev *pdev = rtwpci->pdev; 350362306a36Sopenharmony_ci u16 link_ctrl; 350462306a36Sopenharmony_ci int ret; 350562306a36Sopenharmony_ci 350662306a36Sopenharmony_ci /* Though there is standard PCIE configuration space to set the 350762306a36Sopenharmony_ci * link control register, but by Realtek's design, driver should 350862306a36Sopenharmony_ci * check if host supports CLKREQ/ASPM to enable the HW module. 350962306a36Sopenharmony_ci * 351062306a36Sopenharmony_ci * These functions are implemented by two HW modules associated, 351162306a36Sopenharmony_ci * one is responsible to access PCIE configuration space to 351262306a36Sopenharmony_ci * follow the host settings, and another is in charge of doing 351362306a36Sopenharmony_ci * CLKREQ/ASPM mechanisms, it is default disabled. Because sometimes 351462306a36Sopenharmony_ci * the host does not support it, and due to some reasons or wrong 351562306a36Sopenharmony_ci * settings (ex. CLKREQ# not Bi-Direction), it could lead to device 351662306a36Sopenharmony_ci * loss if HW misbehaves on the link. 351762306a36Sopenharmony_ci * 351862306a36Sopenharmony_ci * Hence it's designed that driver should first check the PCIE 351962306a36Sopenharmony_ci * configuration space is sync'ed and enabled, then driver can turn 352062306a36Sopenharmony_ci * on the other module that is actually working on the mechanism. 352162306a36Sopenharmony_ci */ 352262306a36Sopenharmony_ci ret = pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &link_ctrl); 352362306a36Sopenharmony_ci if (ret) { 352462306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to read PCI cap, ret=%d\n", ret); 352562306a36Sopenharmony_ci return; 352662306a36Sopenharmony_ci } 352762306a36Sopenharmony_ci 352862306a36Sopenharmony_ci if (link_ctrl & PCI_EXP_LNKCTL_CLKREQ_EN) 352962306a36Sopenharmony_ci rtw89_pci_clkreq_set(rtwdev, true); 353062306a36Sopenharmony_ci 353162306a36Sopenharmony_ci if (link_ctrl & PCI_EXP_LNKCTL_ASPM_L1) 353262306a36Sopenharmony_ci rtw89_pci_aspm_set(rtwdev, true); 353362306a36Sopenharmony_ci} 353462306a36Sopenharmony_ci 353562306a36Sopenharmony_cistatic void rtw89_pci_l1ss_set(struct rtw89_dev *rtwdev, bool enable) 353662306a36Sopenharmony_ci{ 353762306a36Sopenharmony_ci enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; 353862306a36Sopenharmony_ci int ret; 353962306a36Sopenharmony_ci 354062306a36Sopenharmony_ci if (chip_id == RTL8852A || chip_id == RTL8852B || chip_id == RTL8851B) { 354162306a36Sopenharmony_ci if (enable) 354262306a36Sopenharmony_ci ret = rtw89_pci_config_byte_set(rtwdev, 354362306a36Sopenharmony_ci RTW89_PCIE_TIMER_CTRL, 354462306a36Sopenharmony_ci RTW89_PCIE_BIT_L1SUB); 354562306a36Sopenharmony_ci else 354662306a36Sopenharmony_ci ret = rtw89_pci_config_byte_clr(rtwdev, 354762306a36Sopenharmony_ci RTW89_PCIE_TIMER_CTRL, 354862306a36Sopenharmony_ci RTW89_PCIE_BIT_L1SUB); 354962306a36Sopenharmony_ci if (ret) 355062306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to %s L1SS, ret=%d", 355162306a36Sopenharmony_ci enable ? "set" : "unset", ret); 355262306a36Sopenharmony_ci } else if (chip_id == RTL8852C) { 355362306a36Sopenharmony_ci ret = rtw89_pci_config_byte_clr(rtwdev, RTW89_PCIE_L1SS_STS_V1, 355462306a36Sopenharmony_ci RTW89_PCIE_BIT_ASPM_L11 | 355562306a36Sopenharmony_ci RTW89_PCIE_BIT_PCI_L11); 355662306a36Sopenharmony_ci if (ret) 355762306a36Sopenharmony_ci rtw89_warn(rtwdev, "failed to unset ASPM L1.1, ret=%d", ret); 355862306a36Sopenharmony_ci if (enable) 355962306a36Sopenharmony_ci rtw89_write32_clr(rtwdev, R_AX_PCIE_MIX_CFG_V1, 356062306a36Sopenharmony_ci B_AX_L1SUB_DISABLE); 356162306a36Sopenharmony_ci else 356262306a36Sopenharmony_ci rtw89_write32_set(rtwdev, R_AX_PCIE_MIX_CFG_V1, 356362306a36Sopenharmony_ci B_AX_L1SUB_DISABLE); 356462306a36Sopenharmony_ci } 356562306a36Sopenharmony_ci} 356662306a36Sopenharmony_ci 356762306a36Sopenharmony_cistatic void rtw89_pci_l1ss_cfg(struct rtw89_dev *rtwdev) 356862306a36Sopenharmony_ci{ 356962306a36Sopenharmony_ci struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; 357062306a36Sopenharmony_ci struct pci_dev *pdev = rtwpci->pdev; 357162306a36Sopenharmony_ci u32 l1ss_cap_ptr, l1ss_ctrl; 357262306a36Sopenharmony_ci 357362306a36Sopenharmony_ci if (rtw89_pci_disable_l1ss) 357462306a36Sopenharmony_ci return; 357562306a36Sopenharmony_ci 357662306a36Sopenharmony_ci l1ss_cap_ptr = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_L1SS); 357762306a36Sopenharmony_ci if (!l1ss_cap_ptr) 357862306a36Sopenharmony_ci return; 357962306a36Sopenharmony_ci 358062306a36Sopenharmony_ci pci_read_config_dword(pdev, l1ss_cap_ptr + PCI_L1SS_CTL1, &l1ss_ctrl); 358162306a36Sopenharmony_ci 358262306a36Sopenharmony_ci if (l1ss_ctrl & PCI_L1SS_CTL1_L1SS_MASK) 358362306a36Sopenharmony_ci rtw89_pci_l1ss_set(rtwdev, true); 358462306a36Sopenharmony_ci} 358562306a36Sopenharmony_ci 358662306a36Sopenharmony_cistatic int rtw89_pci_poll_io_idle(struct rtw89_dev *rtwdev) 358762306a36Sopenharmony_ci{ 358862306a36Sopenharmony_ci int ret = 0; 358962306a36Sopenharmony_ci u32 sts; 359062306a36Sopenharmony_ci u32 busy = B_AX_PCIEIO_BUSY | B_AX_PCIEIO_TX_BUSY | B_AX_PCIEIO_RX_BUSY; 359162306a36Sopenharmony_ci 359262306a36Sopenharmony_ci ret = read_poll_timeout_atomic(rtw89_read32, sts, (sts & busy) == 0x0, 359362306a36Sopenharmony_ci 10, 1000, false, rtwdev, 359462306a36Sopenharmony_ci R_AX_PCIE_DMA_BUSY1); 359562306a36Sopenharmony_ci if (ret) { 359662306a36Sopenharmony_ci rtw89_err(rtwdev, "pci dmach busy1 0x%X\n", 359762306a36Sopenharmony_ci rtw89_read32(rtwdev, R_AX_PCIE_DMA_BUSY1)); 359862306a36Sopenharmony_ci return -EINVAL; 359962306a36Sopenharmony_ci } 360062306a36Sopenharmony_ci return ret; 360162306a36Sopenharmony_ci} 360262306a36Sopenharmony_ci 360362306a36Sopenharmony_cistatic int rtw89_pci_lv1rst_stop_dma(struct rtw89_dev *rtwdev) 360462306a36Sopenharmony_ci{ 360562306a36Sopenharmony_ci u32 val; 360662306a36Sopenharmony_ci int ret; 360762306a36Sopenharmony_ci 360862306a36Sopenharmony_ci if (rtwdev->chip->chip_id == RTL8852C) 360962306a36Sopenharmony_ci return 0; 361062306a36Sopenharmony_ci 361162306a36Sopenharmony_ci rtw89_pci_ctrl_dma_all(rtwdev, false); 361262306a36Sopenharmony_ci ret = rtw89_pci_poll_io_idle(rtwdev); 361362306a36Sopenharmony_ci if (ret) { 361462306a36Sopenharmony_ci val = rtw89_read32(rtwdev, R_AX_DBG_ERR_FLAG); 361562306a36Sopenharmony_ci rtw89_debug(rtwdev, RTW89_DBG_HCI, 361662306a36Sopenharmony_ci "[PCIe] poll_io_idle fail, before 0x%08x: 0x%08x\n", 361762306a36Sopenharmony_ci R_AX_DBG_ERR_FLAG, val); 361862306a36Sopenharmony_ci if (val & B_AX_TX_STUCK || val & B_AX_PCIE_TXBD_LEN0) 361962306a36Sopenharmony_ci rtw89_mac_ctrl_hci_dma_tx(rtwdev, false); 362062306a36Sopenharmony_ci if (val & B_AX_RX_STUCK) 362162306a36Sopenharmony_ci rtw89_mac_ctrl_hci_dma_rx(rtwdev, false); 362262306a36Sopenharmony_ci rtw89_mac_ctrl_hci_dma_trx(rtwdev, true); 362362306a36Sopenharmony_ci ret = rtw89_pci_poll_io_idle(rtwdev); 362462306a36Sopenharmony_ci val = rtw89_read32(rtwdev, R_AX_DBG_ERR_FLAG); 362562306a36Sopenharmony_ci rtw89_debug(rtwdev, RTW89_DBG_HCI, 362662306a36Sopenharmony_ci "[PCIe] poll_io_idle fail, after 0x%08x: 0x%08x\n", 362762306a36Sopenharmony_ci R_AX_DBG_ERR_FLAG, val); 362862306a36Sopenharmony_ci } 362962306a36Sopenharmony_ci 363062306a36Sopenharmony_ci return ret; 363162306a36Sopenharmony_ci} 363262306a36Sopenharmony_ci 363362306a36Sopenharmony_ci 363462306a36Sopenharmony_ci 363562306a36Sopenharmony_cistatic int rtw89_pci_rst_bdram(struct rtw89_dev *rtwdev) 363662306a36Sopenharmony_ci{ 363762306a36Sopenharmony_ci int ret = 0; 363862306a36Sopenharmony_ci u32 val32, sts; 363962306a36Sopenharmony_ci 364062306a36Sopenharmony_ci val32 = B_AX_RST_BDRAM; 364162306a36Sopenharmony_ci rtw89_write32_set(rtwdev, R_AX_PCIE_INIT_CFG1, val32); 364262306a36Sopenharmony_ci 364362306a36Sopenharmony_ci ret = read_poll_timeout_atomic(rtw89_read32, sts, 364462306a36Sopenharmony_ci (sts & B_AX_RST_BDRAM) == 0x0, 1, 100, 364562306a36Sopenharmony_ci true, rtwdev, R_AX_PCIE_INIT_CFG1); 364662306a36Sopenharmony_ci return ret; 364762306a36Sopenharmony_ci} 364862306a36Sopenharmony_ci 364962306a36Sopenharmony_cistatic int rtw89_pci_lv1rst_start_dma(struct rtw89_dev *rtwdev) 365062306a36Sopenharmony_ci{ 365162306a36Sopenharmony_ci u32 ret; 365262306a36Sopenharmony_ci 365362306a36Sopenharmony_ci if (rtwdev->chip->chip_id == RTL8852C) 365462306a36Sopenharmony_ci return 0; 365562306a36Sopenharmony_ci 365662306a36Sopenharmony_ci rtw89_mac_ctrl_hci_dma_trx(rtwdev, false); 365762306a36Sopenharmony_ci rtw89_mac_ctrl_hci_dma_trx(rtwdev, true); 365862306a36Sopenharmony_ci rtw89_pci_clr_idx_all(rtwdev); 365962306a36Sopenharmony_ci 366062306a36Sopenharmony_ci ret = rtw89_pci_rst_bdram(rtwdev); 366162306a36Sopenharmony_ci if (ret) 366262306a36Sopenharmony_ci return ret; 366362306a36Sopenharmony_ci 366462306a36Sopenharmony_ci rtw89_pci_ctrl_dma_all(rtwdev, true); 366562306a36Sopenharmony_ci return ret; 366662306a36Sopenharmony_ci} 366762306a36Sopenharmony_ci 366862306a36Sopenharmony_cistatic int rtw89_pci_ops_mac_lv1_recovery(struct rtw89_dev *rtwdev, 366962306a36Sopenharmony_ci enum rtw89_lv1_rcvy_step step) 367062306a36Sopenharmony_ci{ 367162306a36Sopenharmony_ci int ret; 367262306a36Sopenharmony_ci 367362306a36Sopenharmony_ci switch (step) { 367462306a36Sopenharmony_ci case RTW89_LV1_RCVY_STEP_1: 367562306a36Sopenharmony_ci ret = rtw89_pci_lv1rst_stop_dma(rtwdev); 367662306a36Sopenharmony_ci if (ret) 367762306a36Sopenharmony_ci rtw89_err(rtwdev, "lv1 rcvy pci stop dma fail\n"); 367862306a36Sopenharmony_ci 367962306a36Sopenharmony_ci break; 368062306a36Sopenharmony_ci 368162306a36Sopenharmony_ci case RTW89_LV1_RCVY_STEP_2: 368262306a36Sopenharmony_ci ret = rtw89_pci_lv1rst_start_dma(rtwdev); 368362306a36Sopenharmony_ci if (ret) 368462306a36Sopenharmony_ci rtw89_err(rtwdev, "lv1 rcvy pci start dma fail\n"); 368562306a36Sopenharmony_ci break; 368662306a36Sopenharmony_ci 368762306a36Sopenharmony_ci default: 368862306a36Sopenharmony_ci return -EINVAL; 368962306a36Sopenharmony_ci } 369062306a36Sopenharmony_ci 369162306a36Sopenharmony_ci return ret; 369262306a36Sopenharmony_ci} 369362306a36Sopenharmony_ci 369462306a36Sopenharmony_cistatic void rtw89_pci_ops_dump_err_status(struct rtw89_dev *rtwdev) 369562306a36Sopenharmony_ci{ 369662306a36Sopenharmony_ci rtw89_info(rtwdev, "R_AX_RPQ_RXBD_IDX =0x%08x\n", 369762306a36Sopenharmony_ci rtw89_read32(rtwdev, R_AX_RPQ_RXBD_IDX)); 369862306a36Sopenharmony_ci rtw89_info(rtwdev, "R_AX_DBG_ERR_FLAG=0x%08x\n", 369962306a36Sopenharmony_ci rtw89_read32(rtwdev, R_AX_DBG_ERR_FLAG)); 370062306a36Sopenharmony_ci rtw89_info(rtwdev, "R_AX_LBC_WATCHDOG=0x%08x\n", 370162306a36Sopenharmony_ci rtw89_read32(rtwdev, R_AX_LBC_WATCHDOG)); 370262306a36Sopenharmony_ci} 370362306a36Sopenharmony_ci 370462306a36Sopenharmony_cistatic int rtw89_pci_napi_poll(struct napi_struct *napi, int budget) 370562306a36Sopenharmony_ci{ 370662306a36Sopenharmony_ci struct rtw89_dev *rtwdev = container_of(napi, struct rtw89_dev, napi); 370762306a36Sopenharmony_ci struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; 370862306a36Sopenharmony_ci unsigned long flags; 370962306a36Sopenharmony_ci int work_done; 371062306a36Sopenharmony_ci 371162306a36Sopenharmony_ci rtwdev->napi_budget_countdown = budget; 371262306a36Sopenharmony_ci 371362306a36Sopenharmony_ci rtw89_pci_clear_isr0(rtwdev, B_AX_RPQDMA_INT | B_AX_RPQBD_FULL_INT); 371462306a36Sopenharmony_ci work_done = rtw89_pci_poll_rpq_dma(rtwdev, rtwpci, rtwdev->napi_budget_countdown); 371562306a36Sopenharmony_ci if (work_done == budget) 371662306a36Sopenharmony_ci return budget; 371762306a36Sopenharmony_ci 371862306a36Sopenharmony_ci rtw89_pci_clear_isr0(rtwdev, B_AX_RXP1DMA_INT | B_AX_RXDMA_INT | B_AX_RDU_INT); 371962306a36Sopenharmony_ci work_done += rtw89_pci_poll_rxq_dma(rtwdev, rtwpci, rtwdev->napi_budget_countdown); 372062306a36Sopenharmony_ci if (work_done < budget && napi_complete_done(napi, work_done)) { 372162306a36Sopenharmony_ci spin_lock_irqsave(&rtwpci->irq_lock, flags); 372262306a36Sopenharmony_ci if (likely(rtwpci->running)) 372362306a36Sopenharmony_ci rtw89_chip_enable_intr(rtwdev, rtwpci); 372462306a36Sopenharmony_ci spin_unlock_irqrestore(&rtwpci->irq_lock, flags); 372562306a36Sopenharmony_ci } 372662306a36Sopenharmony_ci 372762306a36Sopenharmony_ci return work_done; 372862306a36Sopenharmony_ci} 372962306a36Sopenharmony_ci 373062306a36Sopenharmony_cistatic int __maybe_unused rtw89_pci_suspend(struct device *dev) 373162306a36Sopenharmony_ci{ 373262306a36Sopenharmony_ci struct ieee80211_hw *hw = dev_get_drvdata(dev); 373362306a36Sopenharmony_ci struct rtw89_dev *rtwdev = hw->priv; 373462306a36Sopenharmony_ci enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; 373562306a36Sopenharmony_ci 373662306a36Sopenharmony_ci rtw89_write32_set(rtwdev, R_AX_RSV_CTRL, B_AX_WLOCK_1C_BIT6); 373762306a36Sopenharmony_ci rtw89_write32_set(rtwdev, R_AX_RSV_CTRL, B_AX_R_DIS_PRST); 373862306a36Sopenharmony_ci rtw89_write32_clr(rtwdev, R_AX_RSV_CTRL, B_AX_WLOCK_1C_BIT6); 373962306a36Sopenharmony_ci if (chip_id == RTL8852A || chip_id == RTL8852B || chip_id == RTL8851B) { 374062306a36Sopenharmony_ci rtw89_write32_clr(rtwdev, R_AX_SYS_SDIO_CTRL, 374162306a36Sopenharmony_ci B_AX_PCIE_DIS_L2_CTRL_LDO_HCI); 374262306a36Sopenharmony_ci rtw89_write32_set(rtwdev, R_AX_PCIE_INIT_CFG1, 374362306a36Sopenharmony_ci B_AX_PCIE_PERST_KEEP_REG | B_AX_PCIE_TRAIN_KEEP_REG); 374462306a36Sopenharmony_ci } else { 374562306a36Sopenharmony_ci rtw89_write32_clr(rtwdev, R_AX_PCIE_PS_CTRL_V1, 374662306a36Sopenharmony_ci B_AX_CMAC_EXIT_L1_EN | B_AX_DMAC0_EXIT_L1_EN); 374762306a36Sopenharmony_ci } 374862306a36Sopenharmony_ci 374962306a36Sopenharmony_ci return 0; 375062306a36Sopenharmony_ci} 375162306a36Sopenharmony_ci 375262306a36Sopenharmony_cistatic void rtw89_pci_l2_hci_ldo(struct rtw89_dev *rtwdev) 375362306a36Sopenharmony_ci{ 375462306a36Sopenharmony_ci if (rtwdev->chip->chip_id == RTL8852C) 375562306a36Sopenharmony_ci return; 375662306a36Sopenharmony_ci 375762306a36Sopenharmony_ci /* Hardware need write the reg twice to ensure the setting work */ 375862306a36Sopenharmony_ci rtw89_pci_write_config_byte(rtwdev, RTW89_PCIE_RST_MSTATE, 375962306a36Sopenharmony_ci RTW89_PCIE_BIT_CFG_RST_MSTATE); 376062306a36Sopenharmony_ci rtw89_pci_write_config_byte(rtwdev, RTW89_PCIE_RST_MSTATE, 376162306a36Sopenharmony_ci RTW89_PCIE_BIT_CFG_RST_MSTATE); 376262306a36Sopenharmony_ci} 376362306a36Sopenharmony_ci 376462306a36Sopenharmony_cistatic int __maybe_unused rtw89_pci_resume(struct device *dev) 376562306a36Sopenharmony_ci{ 376662306a36Sopenharmony_ci struct ieee80211_hw *hw = dev_get_drvdata(dev); 376762306a36Sopenharmony_ci struct rtw89_dev *rtwdev = hw->priv; 376862306a36Sopenharmony_ci enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; 376962306a36Sopenharmony_ci 377062306a36Sopenharmony_ci rtw89_write32_set(rtwdev, R_AX_RSV_CTRL, B_AX_WLOCK_1C_BIT6); 377162306a36Sopenharmony_ci rtw89_write32_clr(rtwdev, R_AX_RSV_CTRL, B_AX_R_DIS_PRST); 377262306a36Sopenharmony_ci rtw89_write32_clr(rtwdev, R_AX_RSV_CTRL, B_AX_WLOCK_1C_BIT6); 377362306a36Sopenharmony_ci if (chip_id == RTL8852A || chip_id == RTL8852B || chip_id == RTL8851B) { 377462306a36Sopenharmony_ci rtw89_write32_set(rtwdev, R_AX_SYS_SDIO_CTRL, 377562306a36Sopenharmony_ci B_AX_PCIE_DIS_L2_CTRL_LDO_HCI); 377662306a36Sopenharmony_ci rtw89_write32_clr(rtwdev, R_AX_PCIE_INIT_CFG1, 377762306a36Sopenharmony_ci B_AX_PCIE_PERST_KEEP_REG | B_AX_PCIE_TRAIN_KEEP_REG); 377862306a36Sopenharmony_ci } else { 377962306a36Sopenharmony_ci rtw89_write32_set(rtwdev, R_AX_PCIE_PS_CTRL_V1, 378062306a36Sopenharmony_ci B_AX_CMAC_EXIT_L1_EN | B_AX_DMAC0_EXIT_L1_EN); 378162306a36Sopenharmony_ci rtw89_write32_clr(rtwdev, R_AX_PCIE_PS_CTRL_V1, 378262306a36Sopenharmony_ci B_AX_SEL_REQ_ENTR_L1); 378362306a36Sopenharmony_ci } 378462306a36Sopenharmony_ci rtw89_pci_l2_hci_ldo(rtwdev); 378562306a36Sopenharmony_ci rtw89_pci_filter_out(rtwdev); 378662306a36Sopenharmony_ci rtw89_pci_link_cfg(rtwdev); 378762306a36Sopenharmony_ci rtw89_pci_l1ss_cfg(rtwdev); 378862306a36Sopenharmony_ci 378962306a36Sopenharmony_ci return 0; 379062306a36Sopenharmony_ci} 379162306a36Sopenharmony_ci 379262306a36Sopenharmony_ciSIMPLE_DEV_PM_OPS(rtw89_pm_ops, rtw89_pci_suspend, rtw89_pci_resume); 379362306a36Sopenharmony_ciEXPORT_SYMBOL(rtw89_pm_ops); 379462306a36Sopenharmony_ci 379562306a36Sopenharmony_cistatic const struct rtw89_hci_ops rtw89_pci_ops = { 379662306a36Sopenharmony_ci .tx_write = rtw89_pci_ops_tx_write, 379762306a36Sopenharmony_ci .tx_kick_off = rtw89_pci_ops_tx_kick_off, 379862306a36Sopenharmony_ci .flush_queues = rtw89_pci_ops_flush_queues, 379962306a36Sopenharmony_ci .reset = rtw89_pci_ops_reset, 380062306a36Sopenharmony_ci .start = rtw89_pci_ops_start, 380162306a36Sopenharmony_ci .stop = rtw89_pci_ops_stop, 380262306a36Sopenharmony_ci .pause = rtw89_pci_ops_pause, 380362306a36Sopenharmony_ci .switch_mode = rtw89_pci_ops_switch_mode, 380462306a36Sopenharmony_ci .recalc_int_mit = rtw89_pci_recalc_int_mit, 380562306a36Sopenharmony_ci 380662306a36Sopenharmony_ci .read8 = rtw89_pci_ops_read8, 380762306a36Sopenharmony_ci .read16 = rtw89_pci_ops_read16, 380862306a36Sopenharmony_ci .read32 = rtw89_pci_ops_read32, 380962306a36Sopenharmony_ci .write8 = rtw89_pci_ops_write8, 381062306a36Sopenharmony_ci .write16 = rtw89_pci_ops_write16, 381162306a36Sopenharmony_ci .write32 = rtw89_pci_ops_write32, 381262306a36Sopenharmony_ci 381362306a36Sopenharmony_ci .mac_pre_init = rtw89_pci_ops_mac_pre_init, 381462306a36Sopenharmony_ci .mac_post_init = rtw89_pci_ops_mac_post_init, 381562306a36Sopenharmony_ci .deinit = rtw89_pci_ops_deinit, 381662306a36Sopenharmony_ci 381762306a36Sopenharmony_ci .check_and_reclaim_tx_resource = rtw89_pci_check_and_reclaim_tx_resource, 381862306a36Sopenharmony_ci .mac_lv1_rcvy = rtw89_pci_ops_mac_lv1_recovery, 381962306a36Sopenharmony_ci .dump_err_status = rtw89_pci_ops_dump_err_status, 382062306a36Sopenharmony_ci .napi_poll = rtw89_pci_napi_poll, 382162306a36Sopenharmony_ci 382262306a36Sopenharmony_ci .recovery_start = rtw89_pci_ops_recovery_start, 382362306a36Sopenharmony_ci .recovery_complete = rtw89_pci_ops_recovery_complete, 382462306a36Sopenharmony_ci 382562306a36Sopenharmony_ci .ctrl_txdma_ch = rtw89_pci_ctrl_txdma_ch_pcie, 382662306a36Sopenharmony_ci .ctrl_txdma_fw_ch = rtw89_pci_ctrl_txdma_fw_ch_pcie, 382762306a36Sopenharmony_ci .ctrl_trxhci = rtw89_pci_ctrl_dma_trx, 382862306a36Sopenharmony_ci .poll_txdma_ch = rtw89_poll_txdma_ch_idle_pcie, 382962306a36Sopenharmony_ci .clr_idx_all = rtw89_pci_clr_idx_all, 383062306a36Sopenharmony_ci .clear = rtw89_pci_clear_resource, 383162306a36Sopenharmony_ci .disable_intr = rtw89_pci_disable_intr_lock, 383262306a36Sopenharmony_ci .enable_intr = rtw89_pci_enable_intr_lock, 383362306a36Sopenharmony_ci .rst_bdram = rtw89_pci_rst_bdram_pcie, 383462306a36Sopenharmony_ci}; 383562306a36Sopenharmony_ci 383662306a36Sopenharmony_ciint rtw89_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) 383762306a36Sopenharmony_ci{ 383862306a36Sopenharmony_ci struct rtw89_dev *rtwdev; 383962306a36Sopenharmony_ci const struct rtw89_driver_info *info; 384062306a36Sopenharmony_ci const struct rtw89_pci_info *pci_info; 384162306a36Sopenharmony_ci int ret; 384262306a36Sopenharmony_ci 384362306a36Sopenharmony_ci info = (const struct rtw89_driver_info *)id->driver_data; 384462306a36Sopenharmony_ci 384562306a36Sopenharmony_ci rtwdev = rtw89_alloc_ieee80211_hw(&pdev->dev, 384662306a36Sopenharmony_ci sizeof(struct rtw89_pci), 384762306a36Sopenharmony_ci info->chip); 384862306a36Sopenharmony_ci if (!rtwdev) { 384962306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to allocate hw\n"); 385062306a36Sopenharmony_ci return -ENOMEM; 385162306a36Sopenharmony_ci } 385262306a36Sopenharmony_ci 385362306a36Sopenharmony_ci pci_info = info->bus.pci; 385462306a36Sopenharmony_ci 385562306a36Sopenharmony_ci rtwdev->pci_info = info->bus.pci; 385662306a36Sopenharmony_ci rtwdev->hci.ops = &rtw89_pci_ops; 385762306a36Sopenharmony_ci rtwdev->hci.type = RTW89_HCI_TYPE_PCIE; 385862306a36Sopenharmony_ci rtwdev->hci.rpwm_addr = pci_info->rpwm_addr; 385962306a36Sopenharmony_ci rtwdev->hci.cpwm_addr = pci_info->cpwm_addr; 386062306a36Sopenharmony_ci 386162306a36Sopenharmony_ci SET_IEEE80211_DEV(rtwdev->hw, &pdev->dev); 386262306a36Sopenharmony_ci 386362306a36Sopenharmony_ci ret = rtw89_core_init(rtwdev); 386462306a36Sopenharmony_ci if (ret) { 386562306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to initialise core\n"); 386662306a36Sopenharmony_ci goto err_release_hw; 386762306a36Sopenharmony_ci } 386862306a36Sopenharmony_ci 386962306a36Sopenharmony_ci ret = rtw89_pci_claim_device(rtwdev, pdev); 387062306a36Sopenharmony_ci if (ret) { 387162306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to claim pci device\n"); 387262306a36Sopenharmony_ci goto err_core_deinit; 387362306a36Sopenharmony_ci } 387462306a36Sopenharmony_ci 387562306a36Sopenharmony_ci ret = rtw89_pci_setup_resource(rtwdev, pdev); 387662306a36Sopenharmony_ci if (ret) { 387762306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to setup pci resource\n"); 387862306a36Sopenharmony_ci goto err_declaim_pci; 387962306a36Sopenharmony_ci } 388062306a36Sopenharmony_ci 388162306a36Sopenharmony_ci ret = rtw89_chip_info_setup(rtwdev); 388262306a36Sopenharmony_ci if (ret) { 388362306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to setup chip information\n"); 388462306a36Sopenharmony_ci goto err_clear_resource; 388562306a36Sopenharmony_ci } 388662306a36Sopenharmony_ci 388762306a36Sopenharmony_ci rtw89_pci_filter_out(rtwdev); 388862306a36Sopenharmony_ci rtw89_pci_link_cfg(rtwdev); 388962306a36Sopenharmony_ci rtw89_pci_l1ss_cfg(rtwdev); 389062306a36Sopenharmony_ci 389162306a36Sopenharmony_ci rtw89_core_napi_init(rtwdev); 389262306a36Sopenharmony_ci 389362306a36Sopenharmony_ci ret = rtw89_pci_request_irq(rtwdev, pdev); 389462306a36Sopenharmony_ci if (ret) { 389562306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to request pci irq\n"); 389662306a36Sopenharmony_ci goto err_deinit_napi; 389762306a36Sopenharmony_ci } 389862306a36Sopenharmony_ci 389962306a36Sopenharmony_ci ret = rtw89_core_register(rtwdev); 390062306a36Sopenharmony_ci if (ret) { 390162306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to register core\n"); 390262306a36Sopenharmony_ci goto err_free_irq; 390362306a36Sopenharmony_ci } 390462306a36Sopenharmony_ci 390562306a36Sopenharmony_ci return 0; 390662306a36Sopenharmony_ci 390762306a36Sopenharmony_cierr_free_irq: 390862306a36Sopenharmony_ci rtw89_pci_free_irq(rtwdev, pdev); 390962306a36Sopenharmony_cierr_deinit_napi: 391062306a36Sopenharmony_ci rtw89_core_napi_deinit(rtwdev); 391162306a36Sopenharmony_cierr_clear_resource: 391262306a36Sopenharmony_ci rtw89_pci_clear_resource(rtwdev, pdev); 391362306a36Sopenharmony_cierr_declaim_pci: 391462306a36Sopenharmony_ci rtw89_pci_declaim_device(rtwdev, pdev); 391562306a36Sopenharmony_cierr_core_deinit: 391662306a36Sopenharmony_ci rtw89_core_deinit(rtwdev); 391762306a36Sopenharmony_cierr_release_hw: 391862306a36Sopenharmony_ci rtw89_free_ieee80211_hw(rtwdev); 391962306a36Sopenharmony_ci 392062306a36Sopenharmony_ci return ret; 392162306a36Sopenharmony_ci} 392262306a36Sopenharmony_ciEXPORT_SYMBOL(rtw89_pci_probe); 392362306a36Sopenharmony_ci 392462306a36Sopenharmony_civoid rtw89_pci_remove(struct pci_dev *pdev) 392562306a36Sopenharmony_ci{ 392662306a36Sopenharmony_ci struct ieee80211_hw *hw = pci_get_drvdata(pdev); 392762306a36Sopenharmony_ci struct rtw89_dev *rtwdev; 392862306a36Sopenharmony_ci 392962306a36Sopenharmony_ci rtwdev = hw->priv; 393062306a36Sopenharmony_ci 393162306a36Sopenharmony_ci rtw89_pci_free_irq(rtwdev, pdev); 393262306a36Sopenharmony_ci rtw89_core_napi_deinit(rtwdev); 393362306a36Sopenharmony_ci rtw89_core_unregister(rtwdev); 393462306a36Sopenharmony_ci rtw89_pci_clear_resource(rtwdev, pdev); 393562306a36Sopenharmony_ci rtw89_pci_declaim_device(rtwdev, pdev); 393662306a36Sopenharmony_ci rtw89_core_deinit(rtwdev); 393762306a36Sopenharmony_ci rtw89_free_ieee80211_hw(rtwdev); 393862306a36Sopenharmony_ci} 393962306a36Sopenharmony_ciEXPORT_SYMBOL(rtw89_pci_remove); 394062306a36Sopenharmony_ci 394162306a36Sopenharmony_ciMODULE_AUTHOR("Realtek Corporation"); 394262306a36Sopenharmony_ciMODULE_DESCRIPTION("Realtek PCI 802.11ax wireless driver"); 394362306a36Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 3944