xref: /freebsd/sys/contrib/dev/rtw89/pci.c (revision 6d67aabd63555ab62a2f2b7f52a75ef100a2fe75)
18e93258fSBjoern A. Zeeb // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
28e93258fSBjoern A. Zeeb /* Copyright(c) 2020  Realtek Corporation
38e93258fSBjoern A. Zeeb  */
48e93258fSBjoern A. Zeeb 
58e93258fSBjoern A. Zeeb #if defined(__FreeBSD__)
68e93258fSBjoern A. Zeeb #define	LINUXKPI_PARAM_PREFIX	rtw89_pci_
78e93258fSBjoern A. Zeeb #endif
88e93258fSBjoern A. Zeeb 
98e93258fSBjoern A. Zeeb #include <linux/pci.h>
10c8e7f78aSBjoern A. Zeeb #if defined(__FreeBSD__)
11c8e7f78aSBjoern A. Zeeb #include <sys/rman.h>
12c8e7f78aSBjoern A. Zeeb #endif
138e93258fSBjoern A. Zeeb 
148e93258fSBjoern A. Zeeb #include "mac.h"
158e93258fSBjoern A. Zeeb #include "pci.h"
168e93258fSBjoern A. Zeeb #include "reg.h"
178e93258fSBjoern A. Zeeb #include "ser.h"
188e93258fSBjoern A. Zeeb 
198e93258fSBjoern A. Zeeb static bool rtw89_pci_disable_clkreq;
208e93258fSBjoern A. Zeeb static bool rtw89_pci_disable_aspm_l1;
218e93258fSBjoern A. Zeeb static bool rtw89_pci_disable_l1ss;
228e93258fSBjoern A. Zeeb module_param_named(disable_clkreq, rtw89_pci_disable_clkreq, bool, 0644);
238e93258fSBjoern A. Zeeb module_param_named(disable_aspm_l1, rtw89_pci_disable_aspm_l1, bool, 0644);
248e93258fSBjoern A. Zeeb module_param_named(disable_aspm_l1ss, rtw89_pci_disable_l1ss, bool, 0644);
258e93258fSBjoern A. Zeeb MODULE_PARM_DESC(disable_clkreq, "Set Y to disable PCI clkreq support");
268e93258fSBjoern A. Zeeb MODULE_PARM_DESC(disable_aspm_l1, "Set Y to disable PCI ASPM L1 support");
278e93258fSBjoern A. Zeeb MODULE_PARM_DESC(disable_aspm_l1ss, "Set Y to disable PCI L1SS support");
288e93258fSBjoern A. Zeeb 
29*6d67aabdSBjoern A. Zeeb static int rtw89_pci_get_phy_offset_by_link_speed(struct rtw89_dev *rtwdev,
30*6d67aabdSBjoern A. Zeeb 						  u32 *phy_offset)
31*6d67aabdSBjoern A. Zeeb {
32*6d67aabdSBjoern A. Zeeb 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
33*6d67aabdSBjoern A. Zeeb 	struct pci_dev *pdev = rtwpci->pdev;
34*6d67aabdSBjoern A. Zeeb 	u32 val;
35*6d67aabdSBjoern A. Zeeb 	int ret;
36*6d67aabdSBjoern A. Zeeb 
37*6d67aabdSBjoern A. Zeeb 	ret = pci_read_config_dword(pdev, RTW89_PCIE_L1_STS_V1, &val);
38*6d67aabdSBjoern A. Zeeb 	if (ret)
39*6d67aabdSBjoern A. Zeeb 		return ret;
40*6d67aabdSBjoern A. Zeeb 
41*6d67aabdSBjoern A. Zeeb 	val = u32_get_bits(val, RTW89_BCFG_LINK_SPEED_MASK);
42*6d67aabdSBjoern A. Zeeb 	if (val == RTW89_PCIE_GEN1_SPEED) {
43*6d67aabdSBjoern A. Zeeb 		*phy_offset = R_RAC_DIRECT_OFFSET_G1;
44*6d67aabdSBjoern A. Zeeb 	} else if (val == RTW89_PCIE_GEN2_SPEED) {
45*6d67aabdSBjoern A. Zeeb 		*phy_offset = R_RAC_DIRECT_OFFSET_G2;
46*6d67aabdSBjoern A. Zeeb 	} else {
47*6d67aabdSBjoern A. Zeeb 		rtw89_warn(rtwdev, "Unknown PCI link speed %d\n", val);
48*6d67aabdSBjoern A. Zeeb 		return -EFAULT;
49*6d67aabdSBjoern A. Zeeb 	}
50*6d67aabdSBjoern A. Zeeb 
51*6d67aabdSBjoern A. Zeeb 	return 0;
52*6d67aabdSBjoern A. Zeeb }
53*6d67aabdSBjoern A. Zeeb 
54*6d67aabdSBjoern A. Zeeb static int rtw89_pci_rst_bdram_ax(struct rtw89_dev *rtwdev)
558e93258fSBjoern A. Zeeb {
568e93258fSBjoern A. Zeeb 	u32 val;
578e93258fSBjoern A. Zeeb 	int ret;
588e93258fSBjoern A. Zeeb 
59*6d67aabdSBjoern A. Zeeb 	rtw89_write32_set(rtwdev, R_AX_PCIE_INIT_CFG1, B_AX_RST_BDRAM);
608e93258fSBjoern A. Zeeb 
618e93258fSBjoern A. Zeeb 	ret = read_poll_timeout_atomic(rtw89_read32, val, !(val & B_AX_RST_BDRAM),
628e93258fSBjoern A. Zeeb 				       1, RTW89_PCI_POLL_BDRAM_RST_CNT, false,
638e93258fSBjoern A. Zeeb 				       rtwdev, R_AX_PCIE_INIT_CFG1);
648e93258fSBjoern A. Zeeb 
65*6d67aabdSBjoern A. Zeeb 	return ret;
668e93258fSBjoern A. Zeeb }
678e93258fSBjoern A. Zeeb 
688e93258fSBjoern A. Zeeb static u32 rtw89_pci_dma_recalc(struct rtw89_dev *rtwdev,
698e93258fSBjoern A. Zeeb 				struct rtw89_pci_dma_ring *bd_ring,
708e93258fSBjoern A. Zeeb 				u32 cur_idx, bool tx)
718e93258fSBjoern A. Zeeb {
72*6d67aabdSBjoern A. Zeeb 	const struct rtw89_pci_info *info = rtwdev->pci_info;
738e93258fSBjoern A. Zeeb 	u32 cnt, cur_rp, wp, rp, len;
748e93258fSBjoern A. Zeeb 
758e93258fSBjoern A. Zeeb 	rp = bd_ring->rp;
768e93258fSBjoern A. Zeeb 	wp = bd_ring->wp;
778e93258fSBjoern A. Zeeb 	len = bd_ring->len;
788e93258fSBjoern A. Zeeb 
798e93258fSBjoern A. Zeeb 	cur_rp = FIELD_GET(TXBD_HW_IDX_MASK, cur_idx);
80*6d67aabdSBjoern A. Zeeb 	if (tx) {
818e93258fSBjoern A. Zeeb 		cnt = cur_rp >= rp ? cur_rp - rp : len - (rp - cur_rp);
82*6d67aabdSBjoern A. Zeeb 	} else {
83*6d67aabdSBjoern A. Zeeb 		if (info->rx_ring_eq_is_full)
84*6d67aabdSBjoern A. Zeeb 			wp += 1;
85*6d67aabdSBjoern A. Zeeb 
868e93258fSBjoern A. Zeeb 		cnt = cur_rp >= wp ? cur_rp - wp : len - (wp - cur_rp);
87*6d67aabdSBjoern A. Zeeb 	}
888e93258fSBjoern A. Zeeb 
898e93258fSBjoern A. Zeeb 	bd_ring->rp = cur_rp;
908e93258fSBjoern A. Zeeb 
918e93258fSBjoern A. Zeeb 	return cnt;
928e93258fSBjoern A. Zeeb }
938e93258fSBjoern A. Zeeb 
948e93258fSBjoern A. Zeeb static u32 rtw89_pci_txbd_recalc(struct rtw89_dev *rtwdev,
958e93258fSBjoern A. Zeeb 				 struct rtw89_pci_tx_ring *tx_ring)
968e93258fSBjoern A. Zeeb {
978e93258fSBjoern A. Zeeb 	struct rtw89_pci_dma_ring *bd_ring = &tx_ring->bd_ring;
988e93258fSBjoern A. Zeeb 	u32 addr_idx = bd_ring->addr.idx;
998e93258fSBjoern A. Zeeb 	u32 cnt, idx;
1008e93258fSBjoern A. Zeeb 
1018e93258fSBjoern A. Zeeb 	idx = rtw89_read32(rtwdev, addr_idx);
1028e93258fSBjoern A. Zeeb 	cnt = rtw89_pci_dma_recalc(rtwdev, bd_ring, idx, true);
1038e93258fSBjoern A. Zeeb 
1048e93258fSBjoern A. Zeeb 	return cnt;
1058e93258fSBjoern A. Zeeb }
1068e93258fSBjoern A. Zeeb 
1078e93258fSBjoern A. Zeeb static void rtw89_pci_release_fwcmd(struct rtw89_dev *rtwdev,
1088e93258fSBjoern A. Zeeb 				    struct rtw89_pci *rtwpci,
1098e93258fSBjoern A. Zeeb 				    u32 cnt, bool release_all)
1108e93258fSBjoern A. Zeeb {
1118e93258fSBjoern A. Zeeb 	struct rtw89_pci_tx_data *tx_data;
1128e93258fSBjoern A. Zeeb 	struct sk_buff *skb;
1138e93258fSBjoern A. Zeeb 	u32 qlen;
1148e93258fSBjoern A. Zeeb 
1158e93258fSBjoern A. Zeeb 	while (cnt--) {
1168e93258fSBjoern A. Zeeb 		skb = skb_dequeue(&rtwpci->h2c_queue);
1178e93258fSBjoern A. Zeeb 		if (!skb) {
1188e93258fSBjoern A. Zeeb 			rtw89_err(rtwdev, "failed to pre-release fwcmd\n");
1198e93258fSBjoern A. Zeeb 			return;
1208e93258fSBjoern A. Zeeb 		}
1218e93258fSBjoern A. Zeeb 		skb_queue_tail(&rtwpci->h2c_release_queue, skb);
1228e93258fSBjoern A. Zeeb 	}
1238e93258fSBjoern A. Zeeb 
1248e93258fSBjoern A. Zeeb 	qlen = skb_queue_len(&rtwpci->h2c_release_queue);
1258e93258fSBjoern A. Zeeb 	if (!release_all)
1268e93258fSBjoern A. Zeeb 	       qlen = qlen > RTW89_PCI_MULTITAG ? qlen - RTW89_PCI_MULTITAG : 0;
1278e93258fSBjoern A. Zeeb 
1288e93258fSBjoern A. Zeeb 	while (qlen--) {
1298e93258fSBjoern A. Zeeb 		skb = skb_dequeue(&rtwpci->h2c_release_queue);
1308e93258fSBjoern A. Zeeb 		if (!skb) {
1318e93258fSBjoern A. Zeeb 			rtw89_err(rtwdev, "failed to release fwcmd\n");
1328e93258fSBjoern A. Zeeb 			return;
1338e93258fSBjoern A. Zeeb 		}
1348e93258fSBjoern A. Zeeb 		tx_data = RTW89_PCI_TX_SKB_CB(skb);
1358e93258fSBjoern A. Zeeb 		dma_unmap_single(&rtwpci->pdev->dev, tx_data->dma, skb->len,
1368e93258fSBjoern A. Zeeb 				 DMA_TO_DEVICE);
1378e93258fSBjoern A. Zeeb 		dev_kfree_skb_any(skb);
1388e93258fSBjoern A. Zeeb 	}
1398e93258fSBjoern A. Zeeb }
1408e93258fSBjoern A. Zeeb 
1418e93258fSBjoern A. Zeeb static void rtw89_pci_reclaim_tx_fwcmd(struct rtw89_dev *rtwdev,
1428e93258fSBjoern A. Zeeb 				       struct rtw89_pci *rtwpci)
1438e93258fSBjoern A. Zeeb {
1448e93258fSBjoern A. Zeeb 	struct rtw89_pci_tx_ring *tx_ring = &rtwpci->tx_rings[RTW89_TXCH_CH12];
1458e93258fSBjoern A. Zeeb 	u32 cnt;
1468e93258fSBjoern A. Zeeb 
1478e93258fSBjoern A. Zeeb 	cnt = rtw89_pci_txbd_recalc(rtwdev, tx_ring);
1488e93258fSBjoern A. Zeeb 	if (!cnt)
1498e93258fSBjoern A. Zeeb 		return;
1508e93258fSBjoern A. Zeeb 	rtw89_pci_release_fwcmd(rtwdev, rtwpci, cnt, false);
1518e93258fSBjoern A. Zeeb }
1528e93258fSBjoern A. Zeeb 
1538e93258fSBjoern A. Zeeb static u32 rtw89_pci_rxbd_recalc(struct rtw89_dev *rtwdev,
1548e93258fSBjoern A. Zeeb 				 struct rtw89_pci_rx_ring *rx_ring)
1558e93258fSBjoern A. Zeeb {
1568e93258fSBjoern A. Zeeb 	struct rtw89_pci_dma_ring *bd_ring = &rx_ring->bd_ring;
1578e93258fSBjoern A. Zeeb 	u32 addr_idx = bd_ring->addr.idx;
1588e93258fSBjoern A. Zeeb 	u32 cnt, idx;
1598e93258fSBjoern A. Zeeb 
1608e93258fSBjoern A. Zeeb 	idx = rtw89_read32(rtwdev, addr_idx);
1618e93258fSBjoern A. Zeeb 	cnt = rtw89_pci_dma_recalc(rtwdev, bd_ring, idx, false);
1628e93258fSBjoern A. Zeeb 
1638e93258fSBjoern A. Zeeb 	return cnt;
1648e93258fSBjoern A. Zeeb }
1658e93258fSBjoern A. Zeeb 
1668e93258fSBjoern A. Zeeb static void rtw89_pci_sync_skb_for_cpu(struct rtw89_dev *rtwdev,
1678e93258fSBjoern A. Zeeb 				       struct sk_buff *skb)
1688e93258fSBjoern A. Zeeb {
1698e93258fSBjoern A. Zeeb 	struct rtw89_pci_rx_info *rx_info;
1708e93258fSBjoern A. Zeeb 	dma_addr_t dma;
1718e93258fSBjoern A. Zeeb 
1728e93258fSBjoern A. Zeeb 	rx_info = RTW89_PCI_RX_SKB_CB(skb);
1738e93258fSBjoern A. Zeeb 	dma = rx_info->dma;
1748e93258fSBjoern A. Zeeb 	dma_sync_single_for_cpu(rtwdev->dev, dma, RTW89_PCI_RX_BUF_SIZE,
1758e93258fSBjoern A. Zeeb 				DMA_FROM_DEVICE);
1768e93258fSBjoern A. Zeeb }
1778e93258fSBjoern A. Zeeb 
1788e93258fSBjoern A. Zeeb static void rtw89_pci_sync_skb_for_device(struct rtw89_dev *rtwdev,
1798e93258fSBjoern A. Zeeb 					  struct sk_buff *skb)
1808e93258fSBjoern A. Zeeb {
1818e93258fSBjoern A. Zeeb 	struct rtw89_pci_rx_info *rx_info;
1828e93258fSBjoern A. Zeeb 	dma_addr_t dma;
1838e93258fSBjoern A. Zeeb 
1848e93258fSBjoern A. Zeeb 	rx_info = RTW89_PCI_RX_SKB_CB(skb);
1858e93258fSBjoern A. Zeeb 	dma = rx_info->dma;
1868e93258fSBjoern A. Zeeb 	dma_sync_single_for_device(rtwdev->dev, dma, RTW89_PCI_RX_BUF_SIZE,
1878e93258fSBjoern A. Zeeb 				   DMA_FROM_DEVICE);
1888e93258fSBjoern A. Zeeb }
1898e93258fSBjoern A. Zeeb 
190*6d67aabdSBjoern A. Zeeb static void rtw89_pci_rxbd_info_update(struct rtw89_dev *rtwdev,
1918e93258fSBjoern A. Zeeb 				       struct sk_buff *skb)
1928e93258fSBjoern A. Zeeb {
1938e93258fSBjoern A. Zeeb 	struct rtw89_pci_rx_info *rx_info = RTW89_PCI_RX_SKB_CB(skb);
194*6d67aabdSBjoern A. Zeeb 	struct rtw89_pci_rxbd_info *rxbd_info;
195*6d67aabdSBjoern A. Zeeb 	__le32 info;
1968e93258fSBjoern A. Zeeb 
1978e93258fSBjoern A. Zeeb 	rxbd_info = (struct rtw89_pci_rxbd_info *)skb->data;
198*6d67aabdSBjoern A. Zeeb 	info = rxbd_info->dword;
199*6d67aabdSBjoern A. Zeeb 
200*6d67aabdSBjoern A. Zeeb 	rx_info->fs = le32_get_bits(info, RTW89_PCI_RXBD_FS);
201*6d67aabdSBjoern A. Zeeb 	rx_info->ls = le32_get_bits(info, RTW89_PCI_RXBD_LS);
202*6d67aabdSBjoern A. Zeeb 	rx_info->len = le32_get_bits(info, RTW89_PCI_RXBD_WRITE_SIZE);
203*6d67aabdSBjoern A. Zeeb 	rx_info->tag = le32_get_bits(info, RTW89_PCI_RXBD_TAG);
204*6d67aabdSBjoern A. Zeeb }
205*6d67aabdSBjoern A. Zeeb 
206*6d67aabdSBjoern A. Zeeb static int rtw89_pci_validate_rx_tag(struct rtw89_dev *rtwdev,
207*6d67aabdSBjoern A. Zeeb 				     struct rtw89_pci_rx_ring *rx_ring,
208*6d67aabdSBjoern A. Zeeb 				     struct sk_buff *skb)
209*6d67aabdSBjoern A. Zeeb {
210*6d67aabdSBjoern A. Zeeb 	struct rtw89_pci_rx_info *rx_info = RTW89_PCI_RX_SKB_CB(skb);
211*6d67aabdSBjoern A. Zeeb 	const struct rtw89_pci_info *info = rtwdev->pci_info;
212*6d67aabdSBjoern A. Zeeb 	u32 target_rx_tag;
213*6d67aabdSBjoern A. Zeeb 
214*6d67aabdSBjoern A. Zeeb 	if (!info->check_rx_tag)
215*6d67aabdSBjoern A. Zeeb 		return 0;
216*6d67aabdSBjoern A. Zeeb 
217*6d67aabdSBjoern A. Zeeb 	/* valid range is 1 ~ 0x1FFF */
218*6d67aabdSBjoern A. Zeeb 	if (rx_ring->target_rx_tag == 0)
219*6d67aabdSBjoern A. Zeeb 		target_rx_tag = 1;
220*6d67aabdSBjoern A. Zeeb 	else
221*6d67aabdSBjoern A. Zeeb 		target_rx_tag = rx_ring->target_rx_tag;
222*6d67aabdSBjoern A. Zeeb 
223*6d67aabdSBjoern A. Zeeb 	if (rx_info->tag != target_rx_tag) {
224*6d67aabdSBjoern A. Zeeb 		rtw89_debug(rtwdev, RTW89_DBG_UNEXP, "mismatch RX tag 0x%x 0x%x\n",
225*6d67aabdSBjoern A. Zeeb 			    rx_info->tag, target_rx_tag);
226*6d67aabdSBjoern A. Zeeb 		return -EAGAIN;
227*6d67aabdSBjoern A. Zeeb 	}
2288e93258fSBjoern A. Zeeb 
2298e93258fSBjoern A. Zeeb 	return 0;
2308e93258fSBjoern A. Zeeb }
2318e93258fSBjoern A. Zeeb 
232*6d67aabdSBjoern A. Zeeb static
233*6d67aabdSBjoern A. Zeeb int rtw89_pci_sync_skb_for_device_and_validate_rx_info(struct rtw89_dev *rtwdev,
234*6d67aabdSBjoern A. Zeeb 						       struct rtw89_pci_rx_ring *rx_ring,
235*6d67aabdSBjoern A. Zeeb 						       struct sk_buff *skb)
236*6d67aabdSBjoern A. Zeeb {
237*6d67aabdSBjoern A. Zeeb 	struct rtw89_pci_rx_info *rx_info = RTW89_PCI_RX_SKB_CB(skb);
238*6d67aabdSBjoern A. Zeeb 	int rx_tag_retry = 100;
239*6d67aabdSBjoern A. Zeeb 	int ret;
240*6d67aabdSBjoern A. Zeeb 
241*6d67aabdSBjoern A. Zeeb 	do {
242*6d67aabdSBjoern A. Zeeb 		rtw89_pci_sync_skb_for_cpu(rtwdev, skb);
243*6d67aabdSBjoern A. Zeeb 		rtw89_pci_rxbd_info_update(rtwdev, skb);
244*6d67aabdSBjoern A. Zeeb 
245*6d67aabdSBjoern A. Zeeb 		ret = rtw89_pci_validate_rx_tag(rtwdev, rx_ring, skb);
246*6d67aabdSBjoern A. Zeeb 		if (ret != -EAGAIN)
247*6d67aabdSBjoern A. Zeeb 			break;
248*6d67aabdSBjoern A. Zeeb 	} while (rx_tag_retry--);
249*6d67aabdSBjoern A. Zeeb 
250*6d67aabdSBjoern A. Zeeb 	/* update target rx_tag for next RX */
251*6d67aabdSBjoern A. Zeeb 	rx_ring->target_rx_tag = rx_info->tag + 1;
252*6d67aabdSBjoern A. Zeeb 
253*6d67aabdSBjoern A. Zeeb 	return ret;
254*6d67aabdSBjoern A. Zeeb }
255*6d67aabdSBjoern A. Zeeb 
256*6d67aabdSBjoern A. Zeeb static void rtw89_pci_ctrl_txdma_ch_ax(struct rtw89_dev *rtwdev, bool enable)
257e2340276SBjoern A. Zeeb {
258e2340276SBjoern A. Zeeb 	const struct rtw89_pci_info *info = rtwdev->pci_info;
259e2340276SBjoern A. Zeeb 	const struct rtw89_reg_def *dma_stop1 = &info->dma_stop1;
260e2340276SBjoern A. Zeeb 	const struct rtw89_reg_def *dma_stop2 = &info->dma_stop2;
261e2340276SBjoern A. Zeeb 
262e2340276SBjoern A. Zeeb 	if (enable) {
263e2340276SBjoern A. Zeeb 		rtw89_write32_clr(rtwdev, dma_stop1->addr, dma_stop1->mask);
264e2340276SBjoern A. Zeeb 		if (dma_stop2->addr)
265e2340276SBjoern A. Zeeb 			rtw89_write32_clr(rtwdev, dma_stop2->addr, dma_stop2->mask);
266e2340276SBjoern A. Zeeb 	} else {
267e2340276SBjoern A. Zeeb 		rtw89_write32_set(rtwdev, dma_stop1->addr, dma_stop1->mask);
268e2340276SBjoern A. Zeeb 		if (dma_stop2->addr)
269e2340276SBjoern A. Zeeb 			rtw89_write32_set(rtwdev, dma_stop2->addr, dma_stop2->mask);
270e2340276SBjoern A. Zeeb 	}
271e2340276SBjoern A. Zeeb }
272e2340276SBjoern A. Zeeb 
273*6d67aabdSBjoern A. Zeeb static void rtw89_pci_ctrl_txdma_fw_ch_ax(struct rtw89_dev *rtwdev, bool enable)
274e2340276SBjoern A. Zeeb {
275e2340276SBjoern A. Zeeb 	const struct rtw89_pci_info *info = rtwdev->pci_info;
276e2340276SBjoern A. Zeeb 	const struct rtw89_reg_def *dma_stop1 = &info->dma_stop1;
277e2340276SBjoern A. Zeeb 
278e2340276SBjoern A. Zeeb 	if (enable)
279e2340276SBjoern A. Zeeb 		rtw89_write32_clr(rtwdev, dma_stop1->addr, B_AX_STOP_CH12);
280e2340276SBjoern A. Zeeb 	else
281e2340276SBjoern A. Zeeb 		rtw89_write32_set(rtwdev, dma_stop1->addr, B_AX_STOP_CH12);
282e2340276SBjoern A. Zeeb }
283e2340276SBjoern A. Zeeb 
2848e93258fSBjoern A. Zeeb static bool
2858e93258fSBjoern A. Zeeb rtw89_skb_put_rx_data(struct rtw89_dev *rtwdev, bool fs, bool ls,
2868e93258fSBjoern A. Zeeb 		      struct sk_buff *new,
2878e93258fSBjoern A. Zeeb 		      const struct sk_buff *skb, u32 offset,
2888e93258fSBjoern A. Zeeb 		      const struct rtw89_pci_rx_info *rx_info,
2898e93258fSBjoern A. Zeeb 		      const struct rtw89_rx_desc_info *desc_info)
2908e93258fSBjoern A. Zeeb {
2918e93258fSBjoern A. Zeeb 	u32 copy_len = rx_info->len - offset;
2928e93258fSBjoern A. Zeeb 
2938e93258fSBjoern A. Zeeb 	if (unlikely(skb_tailroom(new) < copy_len)) {
2948e93258fSBjoern A. Zeeb 		rtw89_debug(rtwdev, RTW89_DBG_TXRX,
2958e93258fSBjoern A. Zeeb 			    "invalid rx data length bd_len=%d desc_len=%d offset=%d (fs=%d ls=%d)\n",
2968e93258fSBjoern A. Zeeb 			    rx_info->len, desc_info->pkt_size, offset, fs, ls);
2978e93258fSBjoern A. Zeeb 		rtw89_hex_dump(rtwdev, RTW89_DBG_TXRX, "rx_data: ",
2988e93258fSBjoern A. Zeeb 			       skb->data, rx_info->len);
2998e93258fSBjoern A. Zeeb 		/* length of a single segment skb is desc_info->pkt_size */
3008e93258fSBjoern A. Zeeb 		if (fs && ls) {
3018e93258fSBjoern A. Zeeb 			copy_len = desc_info->pkt_size;
3028e93258fSBjoern A. Zeeb 		} else {
3038e93258fSBjoern A. Zeeb 			rtw89_info(rtwdev, "drop rx data due to invalid length\n");
3048e93258fSBjoern A. Zeeb 			return false;
3058e93258fSBjoern A. Zeeb 		}
3068e93258fSBjoern A. Zeeb 	}
3078e93258fSBjoern A. Zeeb 
3088e93258fSBjoern A. Zeeb 	skb_put_data(new, skb->data + offset, copy_len);
3098e93258fSBjoern A. Zeeb 
3108e93258fSBjoern A. Zeeb 	return true;
3118e93258fSBjoern A. Zeeb }
3128e93258fSBjoern A. Zeeb 
313*6d67aabdSBjoern A. Zeeb static u32 rtw89_pci_get_rx_skb_idx(struct rtw89_dev *rtwdev,
314*6d67aabdSBjoern A. Zeeb 				    struct rtw89_pci_dma_ring *bd_ring)
315*6d67aabdSBjoern A. Zeeb {
316*6d67aabdSBjoern A. Zeeb 	const struct rtw89_pci_info *info = rtwdev->pci_info;
317*6d67aabdSBjoern A. Zeeb 	u32 wp = bd_ring->wp;
318*6d67aabdSBjoern A. Zeeb 
319*6d67aabdSBjoern A. Zeeb 	if (!info->rx_ring_eq_is_full)
320*6d67aabdSBjoern A. Zeeb 		return wp;
321*6d67aabdSBjoern A. Zeeb 
322*6d67aabdSBjoern A. Zeeb 	if (++wp >= bd_ring->len)
323*6d67aabdSBjoern A. Zeeb 		wp = 0;
324*6d67aabdSBjoern A. Zeeb 
325*6d67aabdSBjoern A. Zeeb 	return wp;
326*6d67aabdSBjoern A. Zeeb }
327*6d67aabdSBjoern A. Zeeb 
3288e93258fSBjoern A. Zeeb static u32 rtw89_pci_rxbd_deliver_skbs(struct rtw89_dev *rtwdev,
3298e93258fSBjoern A. Zeeb 				       struct rtw89_pci_rx_ring *rx_ring)
3308e93258fSBjoern A. Zeeb {
3318e93258fSBjoern A. Zeeb 	struct rtw89_pci_dma_ring *bd_ring = &rx_ring->bd_ring;
3328e93258fSBjoern A. Zeeb 	struct rtw89_pci_rx_info *rx_info;
3338e93258fSBjoern A. Zeeb 	struct rtw89_rx_desc_info *desc_info = &rx_ring->diliver_desc;
3348e93258fSBjoern A. Zeeb 	struct sk_buff *new = rx_ring->diliver_skb;
3358e93258fSBjoern A. Zeeb 	struct sk_buff *skb;
3368e93258fSBjoern A. Zeeb 	u32 rxinfo_size = sizeof(struct rtw89_pci_rxbd_info);
337*6d67aabdSBjoern A. Zeeb 	u32 skb_idx;
3388e93258fSBjoern A. Zeeb 	u32 offset;
3398e93258fSBjoern A. Zeeb 	u32 cnt = 1;
3408e93258fSBjoern A. Zeeb 	bool fs, ls;
3418e93258fSBjoern A. Zeeb 	int ret;
3428e93258fSBjoern A. Zeeb 
343*6d67aabdSBjoern A. Zeeb 	skb_idx = rtw89_pci_get_rx_skb_idx(rtwdev, bd_ring);
344*6d67aabdSBjoern A. Zeeb 	skb = rx_ring->buf[skb_idx];
3458e93258fSBjoern A. Zeeb 
346*6d67aabdSBjoern A. Zeeb 	ret = rtw89_pci_sync_skb_for_device_and_validate_rx_info(rtwdev, rx_ring, skb);
3478e93258fSBjoern A. Zeeb 	if (ret) {
3488e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "failed to update %d RXBD info: %d\n",
3498e93258fSBjoern A. Zeeb 			  bd_ring->wp, ret);
3508e93258fSBjoern A. Zeeb 		goto err_sync_device;
3518e93258fSBjoern A. Zeeb 	}
3528e93258fSBjoern A. Zeeb 
3538e93258fSBjoern A. Zeeb 	rx_info = RTW89_PCI_RX_SKB_CB(skb);
3548e93258fSBjoern A. Zeeb 	fs = rx_info->fs;
3558e93258fSBjoern A. Zeeb 	ls = rx_info->ls;
3568e93258fSBjoern A. Zeeb 
3578e93258fSBjoern A. Zeeb 	if (fs) {
3588e93258fSBjoern A. Zeeb 		if (new) {
3598e93258fSBjoern A. Zeeb 			rtw89_debug(rtwdev, RTW89_DBG_UNEXP,
3608e93258fSBjoern A. Zeeb 				    "skb should not be ready before first segment start\n");
3618e93258fSBjoern A. Zeeb 			goto err_sync_device;
3628e93258fSBjoern A. Zeeb 		}
3638e93258fSBjoern A. Zeeb 		if (desc_info->ready) {
3648e93258fSBjoern A. Zeeb 			rtw89_warn(rtwdev, "desc info should not be ready before first segment start\n");
3658e93258fSBjoern A. Zeeb 			goto err_sync_device;
3668e93258fSBjoern A. Zeeb 		}
3678e93258fSBjoern A. Zeeb 
368e2340276SBjoern A. Zeeb 		rtw89_chip_query_rxdesc(rtwdev, desc_info, skb->data, rxinfo_size);
3698e93258fSBjoern A. Zeeb 
370e2340276SBjoern A. Zeeb 		new = rtw89_alloc_skb_for_rx(rtwdev, desc_info->pkt_size);
3718e93258fSBjoern A. Zeeb 		if (!new)
3728e93258fSBjoern A. Zeeb 			goto err_sync_device;
3738e93258fSBjoern A. Zeeb 
3748e93258fSBjoern A. Zeeb 		rx_ring->diliver_skb = new;
3758e93258fSBjoern A. Zeeb 
3768e93258fSBjoern A. Zeeb 		/* first segment has RX desc */
377e2340276SBjoern A. Zeeb 		offset = desc_info->offset + desc_info->rxd_len;
3788e93258fSBjoern A. Zeeb 	} else {
3798e93258fSBjoern A. Zeeb 		offset = sizeof(struct rtw89_pci_rxbd_info);
3808e93258fSBjoern A. Zeeb 		if (!new) {
3818e93258fSBjoern A. Zeeb 			rtw89_debug(rtwdev, RTW89_DBG_UNEXP, "no last skb\n");
3828e93258fSBjoern A. Zeeb 			goto err_sync_device;
3838e93258fSBjoern A. Zeeb 		}
3848e93258fSBjoern A. Zeeb 	}
3858e93258fSBjoern A. Zeeb 	if (!rtw89_skb_put_rx_data(rtwdev, fs, ls, new, skb, offset, rx_info, desc_info))
3868e93258fSBjoern A. Zeeb 		goto err_sync_device;
3878e93258fSBjoern A. Zeeb 	rtw89_pci_sync_skb_for_device(rtwdev, skb);
3888e93258fSBjoern A. Zeeb 	rtw89_pci_rxbd_increase(rx_ring, 1);
3898e93258fSBjoern A. Zeeb 
3908e93258fSBjoern A. Zeeb 	if (!desc_info->ready) {
3918e93258fSBjoern A. Zeeb 		rtw89_warn(rtwdev, "no rx desc information\n");
3928e93258fSBjoern A. Zeeb 		goto err_free_resource;
3938e93258fSBjoern A. Zeeb 	}
3948e93258fSBjoern A. Zeeb 	if (ls) {
3958e93258fSBjoern A. Zeeb 		rtw89_core_rx(rtwdev, desc_info, new);
3968e93258fSBjoern A. Zeeb 		rx_ring->diliver_skb = NULL;
3978e93258fSBjoern A. Zeeb 		desc_info->ready = false;
3988e93258fSBjoern A. Zeeb 	}
3998e93258fSBjoern A. Zeeb 
4008e93258fSBjoern A. Zeeb 	return cnt;
4018e93258fSBjoern A. Zeeb 
4028e93258fSBjoern A. Zeeb err_sync_device:
4038e93258fSBjoern A. Zeeb 	rtw89_pci_sync_skb_for_device(rtwdev, skb);
4048e93258fSBjoern A. Zeeb 	rtw89_pci_rxbd_increase(rx_ring, 1);
4058e93258fSBjoern A. Zeeb err_free_resource:
4068e93258fSBjoern A. Zeeb 	if (new)
4078e93258fSBjoern A. Zeeb 		dev_kfree_skb_any(new);
4088e93258fSBjoern A. Zeeb 	rx_ring->diliver_skb = NULL;
4098e93258fSBjoern A. Zeeb 	desc_info->ready = false;
4108e93258fSBjoern A. Zeeb 
4118e93258fSBjoern A. Zeeb 	return cnt;
4128e93258fSBjoern A. Zeeb }
4138e93258fSBjoern A. Zeeb 
4148e93258fSBjoern A. Zeeb static void rtw89_pci_rxbd_deliver(struct rtw89_dev *rtwdev,
4158e93258fSBjoern A. Zeeb 				   struct rtw89_pci_rx_ring *rx_ring,
4168e93258fSBjoern A. Zeeb 				   u32 cnt)
4178e93258fSBjoern A. Zeeb {
4188e93258fSBjoern A. Zeeb 	struct rtw89_pci_dma_ring *bd_ring = &rx_ring->bd_ring;
4198e93258fSBjoern A. Zeeb 	u32 rx_cnt;
4208e93258fSBjoern A. Zeeb 
4218e93258fSBjoern A. Zeeb 	while (cnt && rtwdev->napi_budget_countdown > 0) {
4228e93258fSBjoern A. Zeeb 		rx_cnt = rtw89_pci_rxbd_deliver_skbs(rtwdev, rx_ring);
4238e93258fSBjoern A. Zeeb 		if (!rx_cnt) {
4248e93258fSBjoern A. Zeeb 			rtw89_err(rtwdev, "failed to deliver RXBD skb\n");
4258e93258fSBjoern A. Zeeb 
4268e93258fSBjoern A. Zeeb 			/* skip the rest RXBD bufs */
4278e93258fSBjoern A. Zeeb 			rtw89_pci_rxbd_increase(rx_ring, cnt);
4288e93258fSBjoern A. Zeeb 			break;
4298e93258fSBjoern A. Zeeb 		}
4308e93258fSBjoern A. Zeeb 
4318e93258fSBjoern A. Zeeb 		cnt -= rx_cnt;
4328e93258fSBjoern A. Zeeb 	}
4338e93258fSBjoern A. Zeeb 
4348e93258fSBjoern A. Zeeb 	rtw89_write16(rtwdev, bd_ring->addr.idx, bd_ring->wp);
4358e93258fSBjoern A. Zeeb }
4368e93258fSBjoern A. Zeeb 
4378e93258fSBjoern A. Zeeb static int rtw89_pci_poll_rxq_dma(struct rtw89_dev *rtwdev,
4388e93258fSBjoern A. Zeeb 				  struct rtw89_pci *rtwpci, int budget)
4398e93258fSBjoern A. Zeeb {
4408e93258fSBjoern A. Zeeb 	struct rtw89_pci_rx_ring *rx_ring;
4418e93258fSBjoern A. Zeeb 	int countdown = rtwdev->napi_budget_countdown;
4428e93258fSBjoern A. Zeeb 	u32 cnt;
4438e93258fSBjoern A. Zeeb 
4448e93258fSBjoern A. Zeeb 	rx_ring = &rtwpci->rx_rings[RTW89_RXCH_RXQ];
4458e93258fSBjoern A. Zeeb 
4468e93258fSBjoern A. Zeeb 	cnt = rtw89_pci_rxbd_recalc(rtwdev, rx_ring);
4478e93258fSBjoern A. Zeeb 	if (!cnt)
4488e93258fSBjoern A. Zeeb 		return 0;
4498e93258fSBjoern A. Zeeb 
4508e93258fSBjoern A. Zeeb 	cnt = min_t(u32, budget, cnt);
4518e93258fSBjoern A. Zeeb 
4528e93258fSBjoern A. Zeeb 	rtw89_pci_rxbd_deliver(rtwdev, rx_ring, cnt);
4538e93258fSBjoern A. Zeeb 
4548e93258fSBjoern A. Zeeb 	/* In case of flushing pending SKBs, the countdown may exceed. */
4558e93258fSBjoern A. Zeeb 	if (rtwdev->napi_budget_countdown <= 0)
4568e93258fSBjoern A. Zeeb 		return budget;
4578e93258fSBjoern A. Zeeb 
4588e93258fSBjoern A. Zeeb 	return budget - countdown;
4598e93258fSBjoern A. Zeeb }
4608e93258fSBjoern A. Zeeb 
4618e93258fSBjoern A. Zeeb static void rtw89_pci_tx_status(struct rtw89_dev *rtwdev,
4628e93258fSBjoern A. Zeeb 				struct rtw89_pci_tx_ring *tx_ring,
4638e93258fSBjoern A. Zeeb 				struct sk_buff *skb, u8 tx_status)
4648e93258fSBjoern A. Zeeb {
465e2340276SBjoern A. Zeeb 	struct rtw89_tx_skb_data *skb_data = RTW89_TX_SKB_CB(skb);
4668e93258fSBjoern A. Zeeb 	struct ieee80211_tx_info *info;
4678e93258fSBjoern A. Zeeb 
468e2340276SBjoern A. Zeeb 	rtw89_core_tx_wait_complete(rtwdev, skb_data, tx_status == RTW89_TX_DONE);
469e2340276SBjoern A. Zeeb 
4708e93258fSBjoern A. Zeeb 	info = IEEE80211_SKB_CB(skb);
4718e93258fSBjoern A. Zeeb 	ieee80211_tx_info_clear_status(info);
4728e93258fSBjoern A. Zeeb 
4738e93258fSBjoern A. Zeeb 	if (info->flags & IEEE80211_TX_CTL_NO_ACK)
4748e93258fSBjoern A. Zeeb 		info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED;
4758e93258fSBjoern A. Zeeb 	if (tx_status == RTW89_TX_DONE) {
4768e93258fSBjoern A. Zeeb 		info->flags |= IEEE80211_TX_STAT_ACK;
4778e93258fSBjoern A. Zeeb 		tx_ring->tx_acked++;
4788e93258fSBjoern A. Zeeb 	} else {
4798e93258fSBjoern A. Zeeb 		if (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)
4808e93258fSBjoern A. Zeeb 			rtw89_debug(rtwdev, RTW89_DBG_FW,
4818e93258fSBjoern A. Zeeb 				    "failed to TX of status %x\n", tx_status);
4828e93258fSBjoern A. Zeeb 		switch (tx_status) {
4838e93258fSBjoern A. Zeeb 		case RTW89_TX_RETRY_LIMIT:
4848e93258fSBjoern A. Zeeb 			tx_ring->tx_retry_lmt++;
4858e93258fSBjoern A. Zeeb 			break;
4868e93258fSBjoern A. Zeeb 		case RTW89_TX_LIFE_TIME:
4878e93258fSBjoern A. Zeeb 			tx_ring->tx_life_time++;
4888e93258fSBjoern A. Zeeb 			break;
4898e93258fSBjoern A. Zeeb 		case RTW89_TX_MACID_DROP:
4908e93258fSBjoern A. Zeeb 			tx_ring->tx_mac_id_drop++;
4918e93258fSBjoern A. Zeeb 			break;
4928e93258fSBjoern A. Zeeb 		default:
4938e93258fSBjoern A. Zeeb 			rtw89_warn(rtwdev, "invalid TX status %x\n", tx_status);
4948e93258fSBjoern A. Zeeb 			break;
4958e93258fSBjoern A. Zeeb 		}
4968e93258fSBjoern A. Zeeb 	}
4978e93258fSBjoern A. Zeeb 
4988e93258fSBjoern A. Zeeb 	ieee80211_tx_status_ni(rtwdev->hw, skb);
4998e93258fSBjoern A. Zeeb }
5008e93258fSBjoern A. Zeeb 
5018e93258fSBjoern A. Zeeb static void rtw89_pci_reclaim_txbd(struct rtw89_dev *rtwdev, struct rtw89_pci_tx_ring *tx_ring)
5028e93258fSBjoern A. Zeeb {
5038e93258fSBjoern A. Zeeb 	struct rtw89_pci_tx_wd *txwd;
5048e93258fSBjoern A. Zeeb 	u32 cnt;
5058e93258fSBjoern A. Zeeb 
5068e93258fSBjoern A. Zeeb 	cnt = rtw89_pci_txbd_recalc(rtwdev, tx_ring);
5078e93258fSBjoern A. Zeeb 	while (cnt--) {
5088e93258fSBjoern A. Zeeb 		txwd = list_first_entry_or_null(&tx_ring->busy_pages, struct rtw89_pci_tx_wd, list);
5098e93258fSBjoern A. Zeeb 		if (!txwd) {
5108e93258fSBjoern A. Zeeb 			rtw89_warn(rtwdev, "No busy txwd pages available\n");
5118e93258fSBjoern A. Zeeb 			break;
5128e93258fSBjoern A. Zeeb 		}
5138e93258fSBjoern A. Zeeb 
5148e93258fSBjoern A. Zeeb 		list_del_init(&txwd->list);
5158e93258fSBjoern A. Zeeb 
5168e93258fSBjoern A. Zeeb 		/* this skb has been freed by RPP */
5178e93258fSBjoern A. Zeeb 		if (skb_queue_len(&txwd->queue) == 0)
5188e93258fSBjoern A. Zeeb 			rtw89_pci_enqueue_txwd(tx_ring, txwd);
5198e93258fSBjoern A. Zeeb 	}
5208e93258fSBjoern A. Zeeb }
5218e93258fSBjoern A. Zeeb 
5228e93258fSBjoern A. Zeeb static void rtw89_pci_release_busy_txwd(struct rtw89_dev *rtwdev,
5238e93258fSBjoern A. Zeeb 					struct rtw89_pci_tx_ring *tx_ring)
5248e93258fSBjoern A. Zeeb {
5258e93258fSBjoern A. Zeeb 	struct rtw89_pci_tx_wd_ring *wd_ring = &tx_ring->wd_ring;
5268e93258fSBjoern A. Zeeb 	struct rtw89_pci_tx_wd *txwd;
5278e93258fSBjoern A. Zeeb 	int i;
5288e93258fSBjoern A. Zeeb 
5298e93258fSBjoern A. Zeeb 	for (i = 0; i < wd_ring->page_num; i++) {
5308e93258fSBjoern A. Zeeb 		txwd = list_first_entry_or_null(&tx_ring->busy_pages, struct rtw89_pci_tx_wd, list);
5318e93258fSBjoern A. Zeeb 		if (!txwd)
5328e93258fSBjoern A. Zeeb 			break;
5338e93258fSBjoern A. Zeeb 
5348e93258fSBjoern A. Zeeb 		list_del_init(&txwd->list);
5358e93258fSBjoern A. Zeeb 	}
5368e93258fSBjoern A. Zeeb }
5378e93258fSBjoern A. Zeeb 
5388e93258fSBjoern A. Zeeb static void rtw89_pci_release_txwd_skb(struct rtw89_dev *rtwdev,
5398e93258fSBjoern A. Zeeb 				       struct rtw89_pci_tx_ring *tx_ring,
5408e93258fSBjoern A. Zeeb 				       struct rtw89_pci_tx_wd *txwd, u16 seq,
5418e93258fSBjoern A. Zeeb 				       u8 tx_status)
5428e93258fSBjoern A. Zeeb {
5438e93258fSBjoern A. Zeeb 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
5448e93258fSBjoern A. Zeeb 	struct rtw89_pci_tx_data *tx_data;
5458e93258fSBjoern A. Zeeb 	struct sk_buff *skb, *tmp;
5468e93258fSBjoern A. Zeeb 	u8 txch = tx_ring->txch;
5478e93258fSBjoern A. Zeeb 
5488e93258fSBjoern A. Zeeb 	if (!list_empty(&txwd->list)) {
5498e93258fSBjoern A. Zeeb 		rtw89_pci_reclaim_txbd(rtwdev, tx_ring);
5508e93258fSBjoern A. Zeeb 		/* In low power mode, RPP can receive before updating of TX BD.
5518e93258fSBjoern A. Zeeb 		 * In normal mode, it should not happen so give it a warning.
5528e93258fSBjoern A. Zeeb 		 */
5538e93258fSBjoern A. Zeeb 		if (!rtwpci->low_power && !list_empty(&txwd->list))
5548e93258fSBjoern A. Zeeb 			rtw89_warn(rtwdev, "queue %d txwd %d is not idle\n",
5558e93258fSBjoern A. Zeeb 				   txch, seq);
5568e93258fSBjoern A. Zeeb 	}
5578e93258fSBjoern A. Zeeb 
5588e93258fSBjoern A. Zeeb 	skb_queue_walk_safe(&txwd->queue, skb, tmp) {
5598e93258fSBjoern A. Zeeb 		skb_unlink(skb, &txwd->queue);
5608e93258fSBjoern A. Zeeb 
5618e93258fSBjoern A. Zeeb 		tx_data = RTW89_PCI_TX_SKB_CB(skb);
5628e93258fSBjoern A. Zeeb 		dma_unmap_single(&rtwpci->pdev->dev, tx_data->dma, skb->len,
5638e93258fSBjoern A. Zeeb 				 DMA_TO_DEVICE);
5648e93258fSBjoern A. Zeeb 
5658e93258fSBjoern A. Zeeb 		rtw89_pci_tx_status(rtwdev, tx_ring, skb, tx_status);
5668e93258fSBjoern A. Zeeb 	}
5678e93258fSBjoern A. Zeeb 
5688e93258fSBjoern A. Zeeb 	if (list_empty(&txwd->list))
5698e93258fSBjoern A. Zeeb 		rtw89_pci_enqueue_txwd(tx_ring, txwd);
5708e93258fSBjoern A. Zeeb }
5718e93258fSBjoern A. Zeeb 
5728e93258fSBjoern A. Zeeb static void rtw89_pci_release_rpp(struct rtw89_dev *rtwdev,
5738e93258fSBjoern A. Zeeb 				  struct rtw89_pci_rpp_fmt *rpp)
5748e93258fSBjoern A. Zeeb {
5758e93258fSBjoern A. Zeeb 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
5768e93258fSBjoern A. Zeeb 	struct rtw89_pci_tx_ring *tx_ring;
5778e93258fSBjoern A. Zeeb 	struct rtw89_pci_tx_wd_ring *wd_ring;
5788e93258fSBjoern A. Zeeb 	struct rtw89_pci_tx_wd *txwd;
5798e93258fSBjoern A. Zeeb 	u16 seq;
5808e93258fSBjoern A. Zeeb 	u8 qsel, tx_status, txch;
5818e93258fSBjoern A. Zeeb 
5828e93258fSBjoern A. Zeeb 	seq = le32_get_bits(rpp->dword, RTW89_PCI_RPP_SEQ);
5838e93258fSBjoern A. Zeeb 	qsel = le32_get_bits(rpp->dword, RTW89_PCI_RPP_QSEL);
5848e93258fSBjoern A. Zeeb 	tx_status = le32_get_bits(rpp->dword, RTW89_PCI_RPP_TX_STATUS);
5858e93258fSBjoern A. Zeeb 	txch = rtw89_core_get_ch_dma(rtwdev, qsel);
5868e93258fSBjoern A. Zeeb 
5878e93258fSBjoern A. Zeeb 	if (txch == RTW89_TXCH_CH12) {
5888e93258fSBjoern A. Zeeb 		rtw89_warn(rtwdev, "should no fwcmd release report\n");
5898e93258fSBjoern A. Zeeb 		return;
5908e93258fSBjoern A. Zeeb 	}
5918e93258fSBjoern A. Zeeb 
5928e93258fSBjoern A. Zeeb 	tx_ring = &rtwpci->tx_rings[txch];
5938e93258fSBjoern A. Zeeb 	wd_ring = &tx_ring->wd_ring;
5948e93258fSBjoern A. Zeeb 	txwd = &wd_ring->pages[seq];
5958e93258fSBjoern A. Zeeb 
5968e93258fSBjoern A. Zeeb 	rtw89_pci_release_txwd_skb(rtwdev, tx_ring, txwd, seq, tx_status);
5978e93258fSBjoern A. Zeeb }
5988e93258fSBjoern A. Zeeb 
5998e93258fSBjoern A. Zeeb static void rtw89_pci_release_pending_txwd_skb(struct rtw89_dev *rtwdev,
6008e93258fSBjoern A. Zeeb 					       struct rtw89_pci_tx_ring *tx_ring)
6018e93258fSBjoern A. Zeeb {
6028e93258fSBjoern A. Zeeb 	struct rtw89_pci_tx_wd_ring *wd_ring = &tx_ring->wd_ring;
6038e93258fSBjoern A. Zeeb 	struct rtw89_pci_tx_wd *txwd;
6048e93258fSBjoern A. Zeeb 	int i;
6058e93258fSBjoern A. Zeeb 
6068e93258fSBjoern A. Zeeb 	for (i = 0; i < wd_ring->page_num; i++) {
6078e93258fSBjoern A. Zeeb 		txwd = &wd_ring->pages[i];
6088e93258fSBjoern A. Zeeb 
6098e93258fSBjoern A. Zeeb 		if (!list_empty(&txwd->list))
6108e93258fSBjoern A. Zeeb 			continue;
6118e93258fSBjoern A. Zeeb 
6128e93258fSBjoern A. Zeeb 		rtw89_pci_release_txwd_skb(rtwdev, tx_ring, txwd, i, RTW89_TX_MACID_DROP);
6138e93258fSBjoern A. Zeeb 	}
6148e93258fSBjoern A. Zeeb }
6158e93258fSBjoern A. Zeeb 
6168e93258fSBjoern A. Zeeb static u32 rtw89_pci_release_tx_skbs(struct rtw89_dev *rtwdev,
6178e93258fSBjoern A. Zeeb 				     struct rtw89_pci_rx_ring *rx_ring,
6188e93258fSBjoern A. Zeeb 				     u32 max_cnt)
6198e93258fSBjoern A. Zeeb {
6208e93258fSBjoern A. Zeeb 	struct rtw89_pci_dma_ring *bd_ring = &rx_ring->bd_ring;
6218e93258fSBjoern A. Zeeb 	struct rtw89_pci_rx_info *rx_info;
6228e93258fSBjoern A. Zeeb 	struct rtw89_pci_rpp_fmt *rpp;
6238e93258fSBjoern A. Zeeb 	struct rtw89_rx_desc_info desc_info = {};
6248e93258fSBjoern A. Zeeb 	struct sk_buff *skb;
6258e93258fSBjoern A. Zeeb 	u32 cnt = 0;
6268e93258fSBjoern A. Zeeb 	u32 rpp_size = sizeof(struct rtw89_pci_rpp_fmt);
6278e93258fSBjoern A. Zeeb 	u32 rxinfo_size = sizeof(struct rtw89_pci_rxbd_info);
628*6d67aabdSBjoern A. Zeeb 	u32 skb_idx;
6298e93258fSBjoern A. Zeeb 	u32 offset;
6308e93258fSBjoern A. Zeeb 	int ret;
6318e93258fSBjoern A. Zeeb 
632*6d67aabdSBjoern A. Zeeb 	skb_idx = rtw89_pci_get_rx_skb_idx(rtwdev, bd_ring);
633*6d67aabdSBjoern A. Zeeb 	skb = rx_ring->buf[skb_idx];
6348e93258fSBjoern A. Zeeb 
635*6d67aabdSBjoern A. Zeeb 	ret = rtw89_pci_sync_skb_for_device_and_validate_rx_info(rtwdev, rx_ring, skb);
6368e93258fSBjoern A. Zeeb 	if (ret) {
6378e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "failed to update %d RXBD info: %d\n",
6388e93258fSBjoern A. Zeeb 			  bd_ring->wp, ret);
6398e93258fSBjoern A. Zeeb 		goto err_sync_device;
6408e93258fSBjoern A. Zeeb 	}
6418e93258fSBjoern A. Zeeb 
6428e93258fSBjoern A. Zeeb 	rx_info = RTW89_PCI_RX_SKB_CB(skb);
6438e93258fSBjoern A. Zeeb 	if (!rx_info->fs || !rx_info->ls) {
6448e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "cannot process RP frame not set FS/LS\n");
6458e93258fSBjoern A. Zeeb 		return cnt;
6468e93258fSBjoern A. Zeeb 	}
6478e93258fSBjoern A. Zeeb 
648e2340276SBjoern A. Zeeb 	rtw89_chip_query_rxdesc(rtwdev, &desc_info, skb->data, rxinfo_size);
6498e93258fSBjoern A. Zeeb 
6508e93258fSBjoern A. Zeeb 	/* first segment has RX desc */
651e2340276SBjoern A. Zeeb 	offset = desc_info.offset + desc_info.rxd_len;
6528e93258fSBjoern A. Zeeb 	for (; offset + rpp_size <= rx_info->len; offset += rpp_size) {
6538e93258fSBjoern A. Zeeb 		rpp = (struct rtw89_pci_rpp_fmt *)(skb->data + offset);
6548e93258fSBjoern A. Zeeb 		rtw89_pci_release_rpp(rtwdev, rpp);
6558e93258fSBjoern A. Zeeb 	}
6568e93258fSBjoern A. Zeeb 
6578e93258fSBjoern A. Zeeb 	rtw89_pci_sync_skb_for_device(rtwdev, skb);
6588e93258fSBjoern A. Zeeb 	rtw89_pci_rxbd_increase(rx_ring, 1);
6598e93258fSBjoern A. Zeeb 	cnt++;
6608e93258fSBjoern A. Zeeb 
6618e93258fSBjoern A. Zeeb 	return cnt;
6628e93258fSBjoern A. Zeeb 
6638e93258fSBjoern A. Zeeb err_sync_device:
6648e93258fSBjoern A. Zeeb 	rtw89_pci_sync_skb_for_device(rtwdev, skb);
6658e93258fSBjoern A. Zeeb 	return 0;
6668e93258fSBjoern A. Zeeb }
6678e93258fSBjoern A. Zeeb 
6688e93258fSBjoern A. Zeeb static void rtw89_pci_release_tx(struct rtw89_dev *rtwdev,
6698e93258fSBjoern A. Zeeb 				 struct rtw89_pci_rx_ring *rx_ring,
6708e93258fSBjoern A. Zeeb 				 u32 cnt)
6718e93258fSBjoern A. Zeeb {
6728e93258fSBjoern A. Zeeb 	struct rtw89_pci_dma_ring *bd_ring = &rx_ring->bd_ring;
6738e93258fSBjoern A. Zeeb 	u32 release_cnt;
6748e93258fSBjoern A. Zeeb 
6758e93258fSBjoern A. Zeeb 	while (cnt) {
6768e93258fSBjoern A. Zeeb 		release_cnt = rtw89_pci_release_tx_skbs(rtwdev, rx_ring, cnt);
6778e93258fSBjoern A. Zeeb 		if (!release_cnt) {
6788e93258fSBjoern A. Zeeb 			rtw89_err(rtwdev, "failed to release TX skbs\n");
6798e93258fSBjoern A. Zeeb 
6808e93258fSBjoern A. Zeeb 			/* skip the rest RXBD bufs */
6818e93258fSBjoern A. Zeeb 			rtw89_pci_rxbd_increase(rx_ring, cnt);
6828e93258fSBjoern A. Zeeb 			break;
6838e93258fSBjoern A. Zeeb 		}
6848e93258fSBjoern A. Zeeb 
6858e93258fSBjoern A. Zeeb 		cnt -= release_cnt;
6868e93258fSBjoern A. Zeeb 	}
6878e93258fSBjoern A. Zeeb 
6888e93258fSBjoern A. Zeeb 	rtw89_write16(rtwdev, bd_ring->addr.idx, bd_ring->wp);
6898e93258fSBjoern A. Zeeb }
6908e93258fSBjoern A. Zeeb 
6918e93258fSBjoern A. Zeeb static int rtw89_pci_poll_rpq_dma(struct rtw89_dev *rtwdev,
6928e93258fSBjoern A. Zeeb 				  struct rtw89_pci *rtwpci, int budget)
6938e93258fSBjoern A. Zeeb {
6948e93258fSBjoern A. Zeeb 	struct rtw89_pci_rx_ring *rx_ring;
6958e93258fSBjoern A. Zeeb 	u32 cnt;
6968e93258fSBjoern A. Zeeb 	int work_done;
6978e93258fSBjoern A. Zeeb 
6988e93258fSBjoern A. Zeeb 	rx_ring = &rtwpci->rx_rings[RTW89_RXCH_RPQ];
6998e93258fSBjoern A. Zeeb 
7008e93258fSBjoern A. Zeeb 	spin_lock_bh(&rtwpci->trx_lock);
7018e93258fSBjoern A. Zeeb 
7028e93258fSBjoern A. Zeeb 	cnt = rtw89_pci_rxbd_recalc(rtwdev, rx_ring);
7038e93258fSBjoern A. Zeeb 	if (cnt == 0)
7048e93258fSBjoern A. Zeeb 		goto out_unlock;
7058e93258fSBjoern A. Zeeb 
7068e93258fSBjoern A. Zeeb 	rtw89_pci_release_tx(rtwdev, rx_ring, cnt);
7078e93258fSBjoern A. Zeeb 
7088e93258fSBjoern A. Zeeb out_unlock:
7098e93258fSBjoern A. Zeeb 	spin_unlock_bh(&rtwpci->trx_lock);
7108e93258fSBjoern A. Zeeb 
7118e93258fSBjoern A. Zeeb 	/* always release all RPQ */
7128e93258fSBjoern A. Zeeb 	work_done = min_t(int, cnt, budget);
7138e93258fSBjoern A. Zeeb 	rtwdev->napi_budget_countdown -= work_done;
7148e93258fSBjoern A. Zeeb 
7158e93258fSBjoern A. Zeeb 	return work_done;
7168e93258fSBjoern A. Zeeb }
7178e93258fSBjoern A. Zeeb 
7188e93258fSBjoern A. Zeeb static void rtw89_pci_isr_rxd_unavail(struct rtw89_dev *rtwdev,
7198e93258fSBjoern A. Zeeb 				      struct rtw89_pci *rtwpci)
7208e93258fSBjoern A. Zeeb {
7218e93258fSBjoern A. Zeeb 	struct rtw89_pci_rx_ring *rx_ring;
7228e93258fSBjoern A. Zeeb 	struct rtw89_pci_dma_ring *bd_ring;
7238e93258fSBjoern A. Zeeb 	u32 reg_idx;
7248e93258fSBjoern A. Zeeb 	u16 hw_idx, hw_idx_next, host_idx;
7258e93258fSBjoern A. Zeeb 	int i;
7268e93258fSBjoern A. Zeeb 
7278e93258fSBjoern A. Zeeb 	for (i = 0; i < RTW89_RXCH_NUM; i++) {
7288e93258fSBjoern A. Zeeb 		rx_ring = &rtwpci->rx_rings[i];
7298e93258fSBjoern A. Zeeb 		bd_ring = &rx_ring->bd_ring;
7308e93258fSBjoern A. Zeeb 
7318e93258fSBjoern A. Zeeb 		reg_idx = rtw89_read32(rtwdev, bd_ring->addr.idx);
7328e93258fSBjoern A. Zeeb 		hw_idx = FIELD_GET(TXBD_HW_IDX_MASK, reg_idx);
7338e93258fSBjoern A. Zeeb 		host_idx = FIELD_GET(TXBD_HOST_IDX_MASK, reg_idx);
7348e93258fSBjoern A. Zeeb 		hw_idx_next = (hw_idx + 1) % bd_ring->len;
7358e93258fSBjoern A. Zeeb 
7368e93258fSBjoern A. Zeeb 		if (hw_idx_next == host_idx)
7378e93258fSBjoern A. Zeeb 			rtw89_debug(rtwdev, RTW89_DBG_UNEXP, "%d RXD unavailable\n", i);
7388e93258fSBjoern A. Zeeb 
7398e93258fSBjoern A. Zeeb 		rtw89_debug(rtwdev, RTW89_DBG_TXRX,
7408e93258fSBjoern A. Zeeb 			    "%d RXD unavailable, idx=0x%08x, len=%d\n",
7418e93258fSBjoern A. Zeeb 			    i, reg_idx, bd_ring->len);
7428e93258fSBjoern A. Zeeb 	}
7438e93258fSBjoern A. Zeeb }
7448e93258fSBjoern A. Zeeb 
7458e93258fSBjoern A. Zeeb void rtw89_pci_recognize_intrs(struct rtw89_dev *rtwdev,
7468e93258fSBjoern A. Zeeb 			       struct rtw89_pci *rtwpci,
7478e93258fSBjoern A. Zeeb 			       struct rtw89_pci_isrs *isrs)
7488e93258fSBjoern A. Zeeb {
7498e93258fSBjoern A. Zeeb 	isrs->halt_c2h_isrs = rtw89_read32(rtwdev, R_AX_HISR0) & rtwpci->halt_c2h_intrs;
7508e93258fSBjoern A. Zeeb 	isrs->isrs[0] = rtw89_read32(rtwdev, R_AX_PCIE_HISR00) & rtwpci->intrs[0];
7518e93258fSBjoern A. Zeeb 	isrs->isrs[1] = rtw89_read32(rtwdev, R_AX_PCIE_HISR10) & rtwpci->intrs[1];
7528e93258fSBjoern A. Zeeb 
7538e93258fSBjoern A. Zeeb 	rtw89_write32(rtwdev, R_AX_HISR0, isrs->halt_c2h_isrs);
7548e93258fSBjoern A. Zeeb 	rtw89_write32(rtwdev, R_AX_PCIE_HISR00, isrs->isrs[0]);
7558e93258fSBjoern A. Zeeb 	rtw89_write32(rtwdev, R_AX_PCIE_HISR10, isrs->isrs[1]);
7568e93258fSBjoern A. Zeeb }
7578e93258fSBjoern A. Zeeb EXPORT_SYMBOL(rtw89_pci_recognize_intrs);
7588e93258fSBjoern A. Zeeb 
7598e93258fSBjoern A. Zeeb void rtw89_pci_recognize_intrs_v1(struct rtw89_dev *rtwdev,
7608e93258fSBjoern A. Zeeb 				  struct rtw89_pci *rtwpci,
7618e93258fSBjoern A. Zeeb 				  struct rtw89_pci_isrs *isrs)
7628e93258fSBjoern A. Zeeb {
7638e93258fSBjoern A. Zeeb 	isrs->ind_isrs = rtw89_read32(rtwdev, R_AX_PCIE_HISR00_V1) & rtwpci->ind_intrs;
7648e93258fSBjoern A. Zeeb 	isrs->halt_c2h_isrs = isrs->ind_isrs & B_AX_HS0ISR_IND_INT_EN ?
7658e93258fSBjoern A. Zeeb 			      rtw89_read32(rtwdev, R_AX_HISR0) & rtwpci->halt_c2h_intrs : 0;
7668e93258fSBjoern A. Zeeb 	isrs->isrs[0] = isrs->ind_isrs & B_AX_HCI_AXIDMA_INT_EN ?
7678e93258fSBjoern A. Zeeb 			rtw89_read32(rtwdev, R_AX_HAXI_HISR00) & rtwpci->intrs[0] : 0;
7688e93258fSBjoern A. Zeeb 	isrs->isrs[1] = isrs->ind_isrs & B_AX_HS1ISR_IND_INT_EN ?
7698e93258fSBjoern A. Zeeb 			rtw89_read32(rtwdev, R_AX_HISR1) & rtwpci->intrs[1] : 0;
7708e93258fSBjoern A. Zeeb 
7718e93258fSBjoern A. Zeeb 	if (isrs->halt_c2h_isrs)
7728e93258fSBjoern A. Zeeb 		rtw89_write32(rtwdev, R_AX_HISR0, isrs->halt_c2h_isrs);
7738e93258fSBjoern A. Zeeb 	if (isrs->isrs[0])
7748e93258fSBjoern A. Zeeb 		rtw89_write32(rtwdev, R_AX_HAXI_HISR00, isrs->isrs[0]);
7758e93258fSBjoern A. Zeeb 	if (isrs->isrs[1])
7768e93258fSBjoern A. Zeeb 		rtw89_write32(rtwdev, R_AX_HISR1, isrs->isrs[1]);
7778e93258fSBjoern A. Zeeb }
7788e93258fSBjoern A. Zeeb EXPORT_SYMBOL(rtw89_pci_recognize_intrs_v1);
7798e93258fSBjoern A. Zeeb 
780*6d67aabdSBjoern A. Zeeb void rtw89_pci_recognize_intrs_v2(struct rtw89_dev *rtwdev,
781*6d67aabdSBjoern A. Zeeb 				  struct rtw89_pci *rtwpci,
782*6d67aabdSBjoern A. Zeeb 				  struct rtw89_pci_isrs *isrs)
7838e93258fSBjoern A. Zeeb {
784*6d67aabdSBjoern A. Zeeb 	isrs->ind_isrs = rtw89_read32(rtwdev, R_BE_PCIE_HISR) & rtwpci->ind_intrs;
785*6d67aabdSBjoern A. Zeeb 	isrs->halt_c2h_isrs = isrs->ind_isrs & B_BE_HS0ISR_IND_INT ?
786*6d67aabdSBjoern A. Zeeb 			      rtw89_read32(rtwdev, R_BE_HISR0) & rtwpci->halt_c2h_intrs : 0;
787*6d67aabdSBjoern A. Zeeb 	isrs->isrs[0] = isrs->ind_isrs & B_BE_HCI_AXIDMA_INT ?
788*6d67aabdSBjoern A. Zeeb 			rtw89_read32(rtwdev, R_BE_HAXI_HISR00) & rtwpci->intrs[0] : 0;
789*6d67aabdSBjoern A. Zeeb 	isrs->isrs[1] = rtw89_read32(rtwdev, R_BE_PCIE_DMA_ISR) & rtwpci->intrs[1];
790*6d67aabdSBjoern A. Zeeb 
791*6d67aabdSBjoern A. Zeeb 	if (isrs->halt_c2h_isrs)
792*6d67aabdSBjoern A. Zeeb 		rtw89_write32(rtwdev, R_BE_HISR0, isrs->halt_c2h_isrs);
793*6d67aabdSBjoern A. Zeeb 	if (isrs->isrs[0])
794*6d67aabdSBjoern A. Zeeb 		rtw89_write32(rtwdev, R_BE_HAXI_HISR00, isrs->isrs[0]);
795*6d67aabdSBjoern A. Zeeb 	if (isrs->isrs[1])
796*6d67aabdSBjoern A. Zeeb 		rtw89_write32(rtwdev, R_BE_PCIE_DMA_ISR, isrs->isrs[1]);
797*6d67aabdSBjoern A. Zeeb 	rtw89_write32(rtwdev, R_BE_PCIE_HISR, isrs->ind_isrs);
7988e93258fSBjoern A. Zeeb }
799*6d67aabdSBjoern A. Zeeb EXPORT_SYMBOL(rtw89_pci_recognize_intrs_v2);
8008e93258fSBjoern A. Zeeb 
8018e93258fSBjoern A. Zeeb void rtw89_pci_enable_intr(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci)
8028e93258fSBjoern A. Zeeb {
8038e93258fSBjoern A. Zeeb 	rtw89_write32(rtwdev, R_AX_HIMR0, rtwpci->halt_c2h_intrs);
8048e93258fSBjoern A. Zeeb 	rtw89_write32(rtwdev, R_AX_PCIE_HIMR00, rtwpci->intrs[0]);
8058e93258fSBjoern A. Zeeb 	rtw89_write32(rtwdev, R_AX_PCIE_HIMR10, rtwpci->intrs[1]);
8068e93258fSBjoern A. Zeeb }
8078e93258fSBjoern A. Zeeb EXPORT_SYMBOL(rtw89_pci_enable_intr);
8088e93258fSBjoern A. Zeeb 
8098e93258fSBjoern A. Zeeb void rtw89_pci_disable_intr(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci)
8108e93258fSBjoern A. Zeeb {
8118e93258fSBjoern A. Zeeb 	rtw89_write32(rtwdev, R_AX_HIMR0, 0);
8128e93258fSBjoern A. Zeeb 	rtw89_write32(rtwdev, R_AX_PCIE_HIMR00, 0);
8138e93258fSBjoern A. Zeeb 	rtw89_write32(rtwdev, R_AX_PCIE_HIMR10, 0);
8148e93258fSBjoern A. Zeeb }
8158e93258fSBjoern A. Zeeb EXPORT_SYMBOL(rtw89_pci_disable_intr);
8168e93258fSBjoern A. Zeeb 
8178e93258fSBjoern A. Zeeb void rtw89_pci_enable_intr_v1(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci)
8188e93258fSBjoern A. Zeeb {
8198e93258fSBjoern A. Zeeb 	rtw89_write32(rtwdev, R_AX_PCIE_HIMR00_V1, rtwpci->ind_intrs);
8208e93258fSBjoern A. Zeeb 	rtw89_write32(rtwdev, R_AX_HIMR0, rtwpci->halt_c2h_intrs);
8218e93258fSBjoern A. Zeeb 	rtw89_write32(rtwdev, R_AX_HAXI_HIMR00, rtwpci->intrs[0]);
8228e93258fSBjoern A. Zeeb 	rtw89_write32(rtwdev, R_AX_HIMR1, rtwpci->intrs[1]);
8238e93258fSBjoern A. Zeeb }
8248e93258fSBjoern A. Zeeb EXPORT_SYMBOL(rtw89_pci_enable_intr_v1);
8258e93258fSBjoern A. Zeeb 
8268e93258fSBjoern A. Zeeb void rtw89_pci_disable_intr_v1(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci)
8278e93258fSBjoern A. Zeeb {
8288e93258fSBjoern A. Zeeb 	rtw89_write32(rtwdev, R_AX_PCIE_HIMR00_V1, 0);
8298e93258fSBjoern A. Zeeb }
8308e93258fSBjoern A. Zeeb EXPORT_SYMBOL(rtw89_pci_disable_intr_v1);
8318e93258fSBjoern A. Zeeb 
832*6d67aabdSBjoern A. Zeeb void rtw89_pci_enable_intr_v2(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci)
833*6d67aabdSBjoern A. Zeeb {
834*6d67aabdSBjoern A. Zeeb 	rtw89_write32(rtwdev, R_BE_HIMR0, rtwpci->halt_c2h_intrs);
835*6d67aabdSBjoern A. Zeeb 	rtw89_write32(rtwdev, R_BE_HAXI_HIMR00, rtwpci->intrs[0]);
836*6d67aabdSBjoern A. Zeeb 	rtw89_write32(rtwdev, R_BE_PCIE_DMA_IMR_0_V1, rtwpci->intrs[1]);
837*6d67aabdSBjoern A. Zeeb 	rtw89_write32(rtwdev, R_BE_PCIE_HIMR0, rtwpci->ind_intrs);
838*6d67aabdSBjoern A. Zeeb }
839*6d67aabdSBjoern A. Zeeb EXPORT_SYMBOL(rtw89_pci_enable_intr_v2);
840*6d67aabdSBjoern A. Zeeb 
841*6d67aabdSBjoern A. Zeeb void rtw89_pci_disable_intr_v2(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci)
842*6d67aabdSBjoern A. Zeeb {
843*6d67aabdSBjoern A. Zeeb 	rtw89_write32(rtwdev, R_BE_PCIE_HIMR0, 0);
844*6d67aabdSBjoern A. Zeeb 	rtw89_write32(rtwdev, R_BE_PCIE_DMA_IMR_0_V1, 0);
845*6d67aabdSBjoern A. Zeeb }
846*6d67aabdSBjoern A. Zeeb EXPORT_SYMBOL(rtw89_pci_disable_intr_v2);
847*6d67aabdSBjoern A. Zeeb 
8488e93258fSBjoern A. Zeeb static void rtw89_pci_ops_recovery_start(struct rtw89_dev *rtwdev)
8498e93258fSBjoern A. Zeeb {
8508e93258fSBjoern A. Zeeb 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
8518e93258fSBjoern A. Zeeb 	unsigned long flags;
8528e93258fSBjoern A. Zeeb 
8538e93258fSBjoern A. Zeeb 	spin_lock_irqsave(&rtwpci->irq_lock, flags);
8548e93258fSBjoern A. Zeeb 	rtw89_chip_disable_intr(rtwdev, rtwpci);
8558e93258fSBjoern A. Zeeb 	rtw89_chip_config_intr_mask(rtwdev, RTW89_PCI_INTR_MASK_RECOVERY_START);
8568e93258fSBjoern A. Zeeb 	rtw89_chip_enable_intr(rtwdev, rtwpci);
8578e93258fSBjoern A. Zeeb 	spin_unlock_irqrestore(&rtwpci->irq_lock, flags);
8588e93258fSBjoern A. Zeeb }
8598e93258fSBjoern A. Zeeb 
8608e93258fSBjoern A. Zeeb static void rtw89_pci_ops_recovery_complete(struct rtw89_dev *rtwdev)
8618e93258fSBjoern A. Zeeb {
8628e93258fSBjoern A. Zeeb 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
8638e93258fSBjoern A. Zeeb 	unsigned long flags;
8648e93258fSBjoern A. Zeeb 
8658e93258fSBjoern A. Zeeb 	spin_lock_irqsave(&rtwpci->irq_lock, flags);
8668e93258fSBjoern A. Zeeb 	rtw89_chip_disable_intr(rtwdev, rtwpci);
8678e93258fSBjoern A. Zeeb 	rtw89_chip_config_intr_mask(rtwdev, RTW89_PCI_INTR_MASK_RECOVERY_COMPLETE);
8688e93258fSBjoern A. Zeeb 	rtw89_chip_enable_intr(rtwdev, rtwpci);
8698e93258fSBjoern A. Zeeb 	spin_unlock_irqrestore(&rtwpci->irq_lock, flags);
8708e93258fSBjoern A. Zeeb }
8718e93258fSBjoern A. Zeeb 
8728e93258fSBjoern A. Zeeb static void rtw89_pci_low_power_interrupt_handler(struct rtw89_dev *rtwdev)
8738e93258fSBjoern A. Zeeb {
8748e93258fSBjoern A. Zeeb 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
8758e93258fSBjoern A. Zeeb 	int budget = NAPI_POLL_WEIGHT;
8768e93258fSBjoern A. Zeeb 
8778e93258fSBjoern A. Zeeb 	/* To prevent RXQ get stuck due to run out of budget. */
8788e93258fSBjoern A. Zeeb 	rtwdev->napi_budget_countdown = budget;
8798e93258fSBjoern A. Zeeb 
8808e93258fSBjoern A. Zeeb 	rtw89_pci_poll_rpq_dma(rtwdev, rtwpci, budget);
8818e93258fSBjoern A. Zeeb 	rtw89_pci_poll_rxq_dma(rtwdev, rtwpci, budget);
8828e93258fSBjoern A. Zeeb }
8838e93258fSBjoern A. Zeeb 
8848e93258fSBjoern A. Zeeb static irqreturn_t rtw89_pci_interrupt_threadfn(int irq, void *dev)
8858e93258fSBjoern A. Zeeb {
8868e93258fSBjoern A. Zeeb 	struct rtw89_dev *rtwdev = dev;
8878e93258fSBjoern A. Zeeb 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
888*6d67aabdSBjoern A. Zeeb 	const struct rtw89_pci_info *info = rtwdev->pci_info;
889*6d67aabdSBjoern A. Zeeb 	const struct rtw89_pci_gen_def *gen_def = info->gen_def;
8908e93258fSBjoern A. Zeeb 	struct rtw89_pci_isrs isrs;
8918e93258fSBjoern A. Zeeb 	unsigned long flags;
8928e93258fSBjoern A. Zeeb 
8938e93258fSBjoern A. Zeeb 	spin_lock_irqsave(&rtwpci->irq_lock, flags);
8948e93258fSBjoern A. Zeeb 	rtw89_chip_recognize_intrs(rtwdev, rtwpci, &isrs);
8958e93258fSBjoern A. Zeeb 	spin_unlock_irqrestore(&rtwpci->irq_lock, flags);
8968e93258fSBjoern A. Zeeb 
897*6d67aabdSBjoern A. Zeeb 	if (unlikely(isrs.isrs[0] & gen_def->isr_rdu))
8988e93258fSBjoern A. Zeeb 		rtw89_pci_isr_rxd_unavail(rtwdev, rtwpci);
8998e93258fSBjoern A. Zeeb 
900*6d67aabdSBjoern A. Zeeb 	if (unlikely(isrs.halt_c2h_isrs & gen_def->isr_halt_c2h))
9018e93258fSBjoern A. Zeeb 		rtw89_ser_notify(rtwdev, rtw89_mac_get_err_status(rtwdev));
9028e93258fSBjoern A. Zeeb 
903*6d67aabdSBjoern A. Zeeb 	if (unlikely(isrs.halt_c2h_isrs & gen_def->isr_wdt_timeout))
9048e93258fSBjoern A. Zeeb 		rtw89_ser_notify(rtwdev, MAC_AX_ERR_L2_ERR_WDT_TIMEOUT_INT);
9058e93258fSBjoern A. Zeeb 
9068e93258fSBjoern A. Zeeb 	if (unlikely(rtwpci->under_recovery))
9078e93258fSBjoern A. Zeeb 		goto enable_intr;
9088e93258fSBjoern A. Zeeb 
9098e93258fSBjoern A. Zeeb 	if (unlikely(rtwpci->low_power)) {
9108e93258fSBjoern A. Zeeb 		rtw89_pci_low_power_interrupt_handler(rtwdev);
9118e93258fSBjoern A. Zeeb 		goto enable_intr;
9128e93258fSBjoern A. Zeeb 	}
9138e93258fSBjoern A. Zeeb 
9148e93258fSBjoern A. Zeeb 	if (likely(rtwpci->running)) {
9158e93258fSBjoern A. Zeeb 		local_bh_disable();
9168e93258fSBjoern A. Zeeb 		napi_schedule(&rtwdev->napi);
9178e93258fSBjoern A. Zeeb 		local_bh_enable();
9188e93258fSBjoern A. Zeeb 	}
9198e93258fSBjoern A. Zeeb 
9208e93258fSBjoern A. Zeeb 	return IRQ_HANDLED;
9218e93258fSBjoern A. Zeeb 
9228e93258fSBjoern A. Zeeb enable_intr:
9238e93258fSBjoern A. Zeeb 	spin_lock_irqsave(&rtwpci->irq_lock, flags);
9248e93258fSBjoern A. Zeeb 	if (likely(rtwpci->running))
9258e93258fSBjoern A. Zeeb 		rtw89_chip_enable_intr(rtwdev, rtwpci);
9268e93258fSBjoern A. Zeeb 	spin_unlock_irqrestore(&rtwpci->irq_lock, flags);
9278e93258fSBjoern A. Zeeb 	return IRQ_HANDLED;
9288e93258fSBjoern A. Zeeb }
9298e93258fSBjoern A. Zeeb 
9308e93258fSBjoern A. Zeeb static irqreturn_t rtw89_pci_interrupt_handler(int irq, void *dev)
9318e93258fSBjoern A. Zeeb {
9328e93258fSBjoern A. Zeeb 	struct rtw89_dev *rtwdev = dev;
9338e93258fSBjoern A. Zeeb 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
9348e93258fSBjoern A. Zeeb 	unsigned long flags;
9358e93258fSBjoern A. Zeeb 	irqreturn_t irqret = IRQ_WAKE_THREAD;
9368e93258fSBjoern A. Zeeb 
9378e93258fSBjoern A. Zeeb 	spin_lock_irqsave(&rtwpci->irq_lock, flags);
9388e93258fSBjoern A. Zeeb 
9398e93258fSBjoern A. Zeeb 	/* If interrupt event is on the road, it is still trigger interrupt
9408e93258fSBjoern A. Zeeb 	 * even we have done pci_stop() to turn off IMR.
9418e93258fSBjoern A. Zeeb 	 */
9428e93258fSBjoern A. Zeeb 	if (unlikely(!rtwpci->running)) {
9438e93258fSBjoern A. Zeeb 		irqret = IRQ_HANDLED;
9448e93258fSBjoern A. Zeeb 		goto exit;
9458e93258fSBjoern A. Zeeb 	}
9468e93258fSBjoern A. Zeeb 
9478e93258fSBjoern A. Zeeb 	rtw89_chip_disable_intr(rtwdev, rtwpci);
9488e93258fSBjoern A. Zeeb exit:
9498e93258fSBjoern A. Zeeb 	spin_unlock_irqrestore(&rtwpci->irq_lock, flags);
9508e93258fSBjoern A. Zeeb 
9518e93258fSBjoern A. Zeeb 	return irqret;
9528e93258fSBjoern A. Zeeb }
9538e93258fSBjoern A. Zeeb 
954*6d67aabdSBjoern A. Zeeb #define DEF_TXCHADDRS_TYPE2(gen, ch_idx, txch, v...) \
955*6d67aabdSBjoern A. Zeeb 	[RTW89_TXCH_##ch_idx] = { \
956*6d67aabdSBjoern A. Zeeb 		.num = R_##gen##_##txch##_TXBD_NUM ##v, \
957*6d67aabdSBjoern A. Zeeb 		.idx = R_##gen##_##txch##_TXBD_IDX ##v, \
958*6d67aabdSBjoern A. Zeeb 		.bdram = 0, \
959*6d67aabdSBjoern A. Zeeb 		.desa_l = R_##gen##_##txch##_TXBD_DESA_L ##v, \
960*6d67aabdSBjoern A. Zeeb 		.desa_h = R_##gen##_##txch##_TXBD_DESA_H ##v, \
961*6d67aabdSBjoern A. Zeeb 	}
962*6d67aabdSBjoern A. Zeeb 
9638e93258fSBjoern A. Zeeb #define DEF_TXCHADDRS_TYPE1(info, txch, v...) \
9648e93258fSBjoern A. Zeeb 	[RTW89_TXCH_##txch] = { \
9658e93258fSBjoern A. Zeeb 		.num = R_AX_##txch##_TXBD_NUM ##v, \
9668e93258fSBjoern A. Zeeb 		.idx = R_AX_##txch##_TXBD_IDX ##v, \
9678e93258fSBjoern A. Zeeb 		.bdram = R_AX_##txch##_BDRAM_CTRL ##v, \
9688e93258fSBjoern A. Zeeb 		.desa_l = R_AX_##txch##_TXBD_DESA_L ##v, \
9698e93258fSBjoern A. Zeeb 		.desa_h = R_AX_##txch##_TXBD_DESA_H ##v, \
9708e93258fSBjoern A. Zeeb 	}
9718e93258fSBjoern A. Zeeb 
9728e93258fSBjoern A. Zeeb #define DEF_TXCHADDRS(info, txch, v...) \
9738e93258fSBjoern A. Zeeb 	[RTW89_TXCH_##txch] = { \
9748e93258fSBjoern A. Zeeb 		.num = R_AX_##txch##_TXBD_NUM, \
9758e93258fSBjoern A. Zeeb 		.idx = R_AX_##txch##_TXBD_IDX, \
9768e93258fSBjoern A. Zeeb 		.bdram = R_AX_##txch##_BDRAM_CTRL ##v, \
9778e93258fSBjoern A. Zeeb 		.desa_l = R_AX_##txch##_TXBD_DESA_L ##v, \
9788e93258fSBjoern A. Zeeb 		.desa_h = R_AX_##txch##_TXBD_DESA_H ##v, \
9798e93258fSBjoern A. Zeeb 	}
9808e93258fSBjoern A. Zeeb 
981*6d67aabdSBjoern A. Zeeb #define DEF_RXCHADDRS(gen, ch_idx, rxch, v...) \
982*6d67aabdSBjoern A. Zeeb 	[RTW89_RXCH_##ch_idx] = { \
983*6d67aabdSBjoern A. Zeeb 		.num = R_##gen##_##rxch##_RXBD_NUM ##v, \
984*6d67aabdSBjoern A. Zeeb 		.idx = R_##gen##_##rxch##_RXBD_IDX ##v, \
985*6d67aabdSBjoern A. Zeeb 		.desa_l = R_##gen##_##rxch##_RXBD_DESA_L ##v, \
986*6d67aabdSBjoern A. Zeeb 		.desa_h = R_##gen##_##rxch##_RXBD_DESA_H ##v, \
9878e93258fSBjoern A. Zeeb 	}
9888e93258fSBjoern A. Zeeb 
9898e93258fSBjoern A. Zeeb const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set = {
9908e93258fSBjoern A. Zeeb 	.tx = {
9918e93258fSBjoern A. Zeeb 		DEF_TXCHADDRS(info, ACH0),
9928e93258fSBjoern A. Zeeb 		DEF_TXCHADDRS(info, ACH1),
9938e93258fSBjoern A. Zeeb 		DEF_TXCHADDRS(info, ACH2),
9948e93258fSBjoern A. Zeeb 		DEF_TXCHADDRS(info, ACH3),
9958e93258fSBjoern A. Zeeb 		DEF_TXCHADDRS(info, ACH4),
9968e93258fSBjoern A. Zeeb 		DEF_TXCHADDRS(info, ACH5),
9978e93258fSBjoern A. Zeeb 		DEF_TXCHADDRS(info, ACH6),
9988e93258fSBjoern A. Zeeb 		DEF_TXCHADDRS(info, ACH7),
9998e93258fSBjoern A. Zeeb 		DEF_TXCHADDRS(info, CH8),
10008e93258fSBjoern A. Zeeb 		DEF_TXCHADDRS(info, CH9),
10018e93258fSBjoern A. Zeeb 		DEF_TXCHADDRS_TYPE1(info, CH10),
10028e93258fSBjoern A. Zeeb 		DEF_TXCHADDRS_TYPE1(info, CH11),
10038e93258fSBjoern A. Zeeb 		DEF_TXCHADDRS(info, CH12),
10048e93258fSBjoern A. Zeeb 	},
10058e93258fSBjoern A. Zeeb 	.rx = {
1006*6d67aabdSBjoern A. Zeeb 		DEF_RXCHADDRS(AX, RXQ, RXQ),
1007*6d67aabdSBjoern A. Zeeb 		DEF_RXCHADDRS(AX, RPQ, RPQ),
10088e93258fSBjoern A. Zeeb 	},
10098e93258fSBjoern A. Zeeb };
10108e93258fSBjoern A. Zeeb EXPORT_SYMBOL(rtw89_pci_ch_dma_addr_set);
10118e93258fSBjoern A. Zeeb 
10128e93258fSBjoern A. Zeeb const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set_v1 = {
10138e93258fSBjoern A. Zeeb 	.tx = {
10148e93258fSBjoern A. Zeeb 		DEF_TXCHADDRS(info, ACH0, _V1),
10158e93258fSBjoern A. Zeeb 		DEF_TXCHADDRS(info, ACH1, _V1),
10168e93258fSBjoern A. Zeeb 		DEF_TXCHADDRS(info, ACH2, _V1),
10178e93258fSBjoern A. Zeeb 		DEF_TXCHADDRS(info, ACH3, _V1),
10188e93258fSBjoern A. Zeeb 		DEF_TXCHADDRS(info, ACH4, _V1),
10198e93258fSBjoern A. Zeeb 		DEF_TXCHADDRS(info, ACH5, _V1),
10208e93258fSBjoern A. Zeeb 		DEF_TXCHADDRS(info, ACH6, _V1),
10218e93258fSBjoern A. Zeeb 		DEF_TXCHADDRS(info, ACH7, _V1),
10228e93258fSBjoern A. Zeeb 		DEF_TXCHADDRS(info, CH8, _V1),
10238e93258fSBjoern A. Zeeb 		DEF_TXCHADDRS(info, CH9, _V1),
10248e93258fSBjoern A. Zeeb 		DEF_TXCHADDRS_TYPE1(info, CH10, _V1),
10258e93258fSBjoern A. Zeeb 		DEF_TXCHADDRS_TYPE1(info, CH11, _V1),
10268e93258fSBjoern A. Zeeb 		DEF_TXCHADDRS(info, CH12, _V1),
10278e93258fSBjoern A. Zeeb 	},
10288e93258fSBjoern A. Zeeb 	.rx = {
1029*6d67aabdSBjoern A. Zeeb 		DEF_RXCHADDRS(AX, RXQ, RXQ, _V1),
1030*6d67aabdSBjoern A. Zeeb 		DEF_RXCHADDRS(AX, RPQ, RPQ, _V1),
10318e93258fSBjoern A. Zeeb 	},
10328e93258fSBjoern A. Zeeb };
10338e93258fSBjoern A. Zeeb EXPORT_SYMBOL(rtw89_pci_ch_dma_addr_set_v1);
10348e93258fSBjoern A. Zeeb 
1035*6d67aabdSBjoern A. Zeeb const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set_be = {
1036*6d67aabdSBjoern A. Zeeb 	.tx = {
1037*6d67aabdSBjoern A. Zeeb 		DEF_TXCHADDRS_TYPE2(BE, ACH0, CH0, _V1),
1038*6d67aabdSBjoern A. Zeeb 		DEF_TXCHADDRS_TYPE2(BE, ACH1, CH1, _V1),
1039*6d67aabdSBjoern A. Zeeb 		DEF_TXCHADDRS_TYPE2(BE, ACH2, CH2, _V1),
1040*6d67aabdSBjoern A. Zeeb 		DEF_TXCHADDRS_TYPE2(BE, ACH3, CH3, _V1),
1041*6d67aabdSBjoern A. Zeeb 		DEF_TXCHADDRS_TYPE2(BE, ACH4, CH4, _V1),
1042*6d67aabdSBjoern A. Zeeb 		DEF_TXCHADDRS_TYPE2(BE, ACH5, CH5, _V1),
1043*6d67aabdSBjoern A. Zeeb 		DEF_TXCHADDRS_TYPE2(BE, ACH6, CH6, _V1),
1044*6d67aabdSBjoern A. Zeeb 		DEF_TXCHADDRS_TYPE2(BE, ACH7, CH7, _V1),
1045*6d67aabdSBjoern A. Zeeb 		DEF_TXCHADDRS_TYPE2(BE, CH8, CH8, _V1),
1046*6d67aabdSBjoern A. Zeeb 		DEF_TXCHADDRS_TYPE2(BE, CH9, CH9, _V1),
1047*6d67aabdSBjoern A. Zeeb 		DEF_TXCHADDRS_TYPE2(BE, CH10, CH10, _V1),
1048*6d67aabdSBjoern A. Zeeb 		DEF_TXCHADDRS_TYPE2(BE, CH11, CH11, _V1),
1049*6d67aabdSBjoern A. Zeeb 		DEF_TXCHADDRS_TYPE2(BE, CH12, CH12, _V1),
1050*6d67aabdSBjoern A. Zeeb 	},
1051*6d67aabdSBjoern A. Zeeb 	.rx = {
1052*6d67aabdSBjoern A. Zeeb 		DEF_RXCHADDRS(BE, RXQ, RXQ0, _V1),
1053*6d67aabdSBjoern A. Zeeb 		DEF_RXCHADDRS(BE, RPQ, RPQ0, _V1),
1054*6d67aabdSBjoern A. Zeeb 	},
1055*6d67aabdSBjoern A. Zeeb };
1056*6d67aabdSBjoern A. Zeeb EXPORT_SYMBOL(rtw89_pci_ch_dma_addr_set_be);
1057*6d67aabdSBjoern A. Zeeb 
10588e93258fSBjoern A. Zeeb #undef DEF_TXCHADDRS_TYPE1
10598e93258fSBjoern A. Zeeb #undef DEF_TXCHADDRS
10608e93258fSBjoern A. Zeeb #undef DEF_RXCHADDRS
10618e93258fSBjoern A. Zeeb 
10628e93258fSBjoern A. Zeeb static int rtw89_pci_get_txch_addrs(struct rtw89_dev *rtwdev,
10638e93258fSBjoern A. Zeeb 				    enum rtw89_tx_channel txch,
10648e93258fSBjoern A. Zeeb 				    const struct rtw89_pci_ch_dma_addr **addr)
10658e93258fSBjoern A. Zeeb {
10668e93258fSBjoern A. Zeeb 	const struct rtw89_pci_info *info = rtwdev->pci_info;
10678e93258fSBjoern A. Zeeb 
10688e93258fSBjoern A. Zeeb 	if (txch >= RTW89_TXCH_NUM)
10698e93258fSBjoern A. Zeeb 		return -EINVAL;
10708e93258fSBjoern A. Zeeb 
10718e93258fSBjoern A. Zeeb 	*addr = &info->dma_addr_set->tx[txch];
10728e93258fSBjoern A. Zeeb 
10738e93258fSBjoern A. Zeeb 	return 0;
10748e93258fSBjoern A. Zeeb }
10758e93258fSBjoern A. Zeeb 
10768e93258fSBjoern A. Zeeb static int rtw89_pci_get_rxch_addrs(struct rtw89_dev *rtwdev,
10778e93258fSBjoern A. Zeeb 				    enum rtw89_rx_channel rxch,
10788e93258fSBjoern A. Zeeb 				    const struct rtw89_pci_ch_dma_addr **addr)
10798e93258fSBjoern A. Zeeb {
10808e93258fSBjoern A. Zeeb 	const struct rtw89_pci_info *info = rtwdev->pci_info;
10818e93258fSBjoern A. Zeeb 
10828e93258fSBjoern A. Zeeb 	if (rxch >= RTW89_RXCH_NUM)
10838e93258fSBjoern A. Zeeb 		return -EINVAL;
10848e93258fSBjoern A. Zeeb 
10858e93258fSBjoern A. Zeeb 	*addr = &info->dma_addr_set->rx[rxch];
10868e93258fSBjoern A. Zeeb 
10878e93258fSBjoern A. Zeeb 	return 0;
10888e93258fSBjoern A. Zeeb }
10898e93258fSBjoern A. Zeeb 
10908e93258fSBjoern A. Zeeb static u32 rtw89_pci_get_avail_txbd_num(struct rtw89_pci_tx_ring *ring)
10918e93258fSBjoern A. Zeeb {
10928e93258fSBjoern A. Zeeb 	struct rtw89_pci_dma_ring *bd_ring = &ring->bd_ring;
10938e93258fSBjoern A. Zeeb 
10948e93258fSBjoern A. Zeeb 	/* reserved 1 desc check ring is full or not */
10958e93258fSBjoern A. Zeeb 	if (bd_ring->rp > bd_ring->wp)
10968e93258fSBjoern A. Zeeb 		return bd_ring->rp - bd_ring->wp - 1;
10978e93258fSBjoern A. Zeeb 
10988e93258fSBjoern A. Zeeb 	return bd_ring->len - (bd_ring->wp - bd_ring->rp) - 1;
10998e93258fSBjoern A. Zeeb }
11008e93258fSBjoern A. Zeeb 
11018e93258fSBjoern A. Zeeb static
11028e93258fSBjoern A. Zeeb u32 __rtw89_pci_check_and_reclaim_tx_fwcmd_resource(struct rtw89_dev *rtwdev)
11038e93258fSBjoern A. Zeeb {
11048e93258fSBjoern A. Zeeb 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
11058e93258fSBjoern A. Zeeb 	struct rtw89_pci_tx_ring *tx_ring = &rtwpci->tx_rings[RTW89_TXCH_CH12];
11068e93258fSBjoern A. Zeeb 	u32 cnt;
11078e93258fSBjoern A. Zeeb 
11088e93258fSBjoern A. Zeeb 	spin_lock_bh(&rtwpci->trx_lock);
11098e93258fSBjoern A. Zeeb 	rtw89_pci_reclaim_tx_fwcmd(rtwdev, rtwpci);
11108e93258fSBjoern A. Zeeb 	cnt = rtw89_pci_get_avail_txbd_num(tx_ring);
11118e93258fSBjoern A. Zeeb 	spin_unlock_bh(&rtwpci->trx_lock);
11128e93258fSBjoern A. Zeeb 
11138e93258fSBjoern A. Zeeb 	return cnt;
11148e93258fSBjoern A. Zeeb }
11158e93258fSBjoern A. Zeeb 
11168e93258fSBjoern A. Zeeb static
11178e93258fSBjoern A. Zeeb u32 __rtw89_pci_check_and_reclaim_tx_resource_noio(struct rtw89_dev *rtwdev,
11188e93258fSBjoern A. Zeeb 						   u8 txch)
11198e93258fSBjoern A. Zeeb {
11208e93258fSBjoern A. Zeeb 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
11218e93258fSBjoern A. Zeeb 	struct rtw89_pci_tx_ring *tx_ring = &rtwpci->tx_rings[txch];
11228e93258fSBjoern A. Zeeb 	struct rtw89_pci_tx_wd_ring *wd_ring = &tx_ring->wd_ring;
11238e93258fSBjoern A. Zeeb 	u32 cnt;
11248e93258fSBjoern A. Zeeb 
11258e93258fSBjoern A. Zeeb 	spin_lock_bh(&rtwpci->trx_lock);
11268e93258fSBjoern A. Zeeb 	cnt = rtw89_pci_get_avail_txbd_num(tx_ring);
1127*6d67aabdSBjoern A. Zeeb 	if (txch != RTW89_TXCH_CH12)
11288e93258fSBjoern A. Zeeb 		cnt = min(cnt, wd_ring->curr_num);
11298e93258fSBjoern A. Zeeb 	spin_unlock_bh(&rtwpci->trx_lock);
11308e93258fSBjoern A. Zeeb 
11318e93258fSBjoern A. Zeeb 	return cnt;
11328e93258fSBjoern A. Zeeb }
11338e93258fSBjoern A. Zeeb 
11348e93258fSBjoern A. Zeeb static u32 __rtw89_pci_check_and_reclaim_tx_resource(struct rtw89_dev *rtwdev,
11358e93258fSBjoern A. Zeeb 						     u8 txch)
11368e93258fSBjoern A. Zeeb {
11378e93258fSBjoern A. Zeeb 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
11388e93258fSBjoern A. Zeeb 	struct rtw89_pci_tx_ring *tx_ring = &rtwpci->tx_rings[txch];
11398e93258fSBjoern A. Zeeb 	struct rtw89_pci_tx_wd_ring *wd_ring = &tx_ring->wd_ring;
1140e2340276SBjoern A. Zeeb 	const struct rtw89_chip_info *chip = rtwdev->chip;
11418e93258fSBjoern A. Zeeb 	u32 bd_cnt, wd_cnt, min_cnt = 0;
11428e93258fSBjoern A. Zeeb 	struct rtw89_pci_rx_ring *rx_ring;
1143e2340276SBjoern A. Zeeb 	enum rtw89_debug_mask debug_mask;
11448e93258fSBjoern A. Zeeb 	u32 cnt;
11458e93258fSBjoern A. Zeeb 
11468e93258fSBjoern A. Zeeb 	rx_ring = &rtwpci->rx_rings[RTW89_RXCH_RPQ];
11478e93258fSBjoern A. Zeeb 
11488e93258fSBjoern A. Zeeb 	spin_lock_bh(&rtwpci->trx_lock);
11498e93258fSBjoern A. Zeeb 	bd_cnt = rtw89_pci_get_avail_txbd_num(tx_ring);
11508e93258fSBjoern A. Zeeb 	wd_cnt = wd_ring->curr_num;
11518e93258fSBjoern A. Zeeb 
11528e93258fSBjoern A. Zeeb 	if (wd_cnt == 0 || bd_cnt == 0) {
11538e93258fSBjoern A. Zeeb 		cnt = rtw89_pci_rxbd_recalc(rtwdev, rx_ring);
11548e93258fSBjoern A. Zeeb 		if (cnt)
11558e93258fSBjoern A. Zeeb 			rtw89_pci_release_tx(rtwdev, rx_ring, cnt);
11568e93258fSBjoern A. Zeeb 		else if (wd_cnt == 0)
11578e93258fSBjoern A. Zeeb 			goto out_unlock;
11588e93258fSBjoern A. Zeeb 
11598e93258fSBjoern A. Zeeb 		bd_cnt = rtw89_pci_get_avail_txbd_num(tx_ring);
11608e93258fSBjoern A. Zeeb 		if (bd_cnt == 0)
11618e93258fSBjoern A. Zeeb 			rtw89_pci_reclaim_txbd(rtwdev, tx_ring);
11628e93258fSBjoern A. Zeeb 	}
11638e93258fSBjoern A. Zeeb 
11648e93258fSBjoern A. Zeeb 	bd_cnt = rtw89_pci_get_avail_txbd_num(tx_ring);
11658e93258fSBjoern A. Zeeb 	wd_cnt = wd_ring->curr_num;
11668e93258fSBjoern A. Zeeb 	min_cnt = min(bd_cnt, wd_cnt);
1167e2340276SBjoern A. Zeeb 	if (min_cnt == 0) {
1168e2340276SBjoern A. Zeeb 		/* This message can be frequently shown in low power mode or
1169e2340276SBjoern A. Zeeb 		 * high traffic with small FIFO chips, and we have recognized it as normal
1170e2340276SBjoern A. Zeeb 		 * behavior, so print with mask RTW89_DBG_TXRX in these situations.
1171e2340276SBjoern A. Zeeb 		 */
1172e2340276SBjoern A. Zeeb 		if (rtwpci->low_power || chip->small_fifo_size)
1173e2340276SBjoern A. Zeeb 			debug_mask = RTW89_DBG_TXRX;
1174e2340276SBjoern A. Zeeb 		else
1175e2340276SBjoern A. Zeeb 			debug_mask = RTW89_DBG_UNEXP;
1176e2340276SBjoern A. Zeeb 
1177e2340276SBjoern A. Zeeb 		rtw89_debug(rtwdev, debug_mask,
11788e93258fSBjoern A. Zeeb 			    "still no tx resource after reclaim: wd_cnt=%d bd_cnt=%d\n",
11798e93258fSBjoern A. Zeeb 			    wd_cnt, bd_cnt);
1180e2340276SBjoern A. Zeeb 	}
11818e93258fSBjoern A. Zeeb 
11828e93258fSBjoern A. Zeeb out_unlock:
11838e93258fSBjoern A. Zeeb 	spin_unlock_bh(&rtwpci->trx_lock);
11848e93258fSBjoern A. Zeeb 
11858e93258fSBjoern A. Zeeb 	return min_cnt;
11868e93258fSBjoern A. Zeeb }
11878e93258fSBjoern A. Zeeb 
11888e93258fSBjoern A. Zeeb static u32 rtw89_pci_check_and_reclaim_tx_resource(struct rtw89_dev *rtwdev,
11898e93258fSBjoern A. Zeeb 						   u8 txch)
11908e93258fSBjoern A. Zeeb {
11918e93258fSBjoern A. Zeeb 	if (rtwdev->hci.paused)
11928e93258fSBjoern A. Zeeb 		return __rtw89_pci_check_and_reclaim_tx_resource_noio(rtwdev, txch);
11938e93258fSBjoern A. Zeeb 
11948e93258fSBjoern A. Zeeb 	if (txch == RTW89_TXCH_CH12)
11958e93258fSBjoern A. Zeeb 		return __rtw89_pci_check_and_reclaim_tx_fwcmd_resource(rtwdev);
11968e93258fSBjoern A. Zeeb 
11978e93258fSBjoern A. Zeeb 	return __rtw89_pci_check_and_reclaim_tx_resource(rtwdev, txch);
11988e93258fSBjoern A. Zeeb }
11998e93258fSBjoern A. Zeeb 
12008e93258fSBjoern A. Zeeb static void __rtw89_pci_tx_kick_off(struct rtw89_dev *rtwdev, struct rtw89_pci_tx_ring *tx_ring)
12018e93258fSBjoern A. Zeeb {
12028e93258fSBjoern A. Zeeb 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
12038e93258fSBjoern A. Zeeb 	struct rtw89_pci_dma_ring *bd_ring = &tx_ring->bd_ring;
12048e93258fSBjoern A. Zeeb 	u32 host_idx, addr;
12058e93258fSBjoern A. Zeeb 
12068e93258fSBjoern A. Zeeb 	spin_lock_bh(&rtwpci->trx_lock);
12078e93258fSBjoern A. Zeeb 
12088e93258fSBjoern A. Zeeb 	addr = bd_ring->addr.idx;
12098e93258fSBjoern A. Zeeb 	host_idx = bd_ring->wp;
12108e93258fSBjoern A. Zeeb 	rtw89_write16(rtwdev, addr, host_idx);
12118e93258fSBjoern A. Zeeb 
12128e93258fSBjoern A. Zeeb 	spin_unlock_bh(&rtwpci->trx_lock);
12138e93258fSBjoern A. Zeeb }
12148e93258fSBjoern A. Zeeb 
12158e93258fSBjoern A. Zeeb static void rtw89_pci_tx_bd_ring_update(struct rtw89_dev *rtwdev, struct rtw89_pci_tx_ring *tx_ring,
12168e93258fSBjoern A. Zeeb 					int n_txbd)
12178e93258fSBjoern A. Zeeb {
12188e93258fSBjoern A. Zeeb 	struct rtw89_pci_dma_ring *bd_ring = &tx_ring->bd_ring;
12198e93258fSBjoern A. Zeeb 	u32 host_idx, len;
12208e93258fSBjoern A. Zeeb 
12218e93258fSBjoern A. Zeeb 	len = bd_ring->len;
12228e93258fSBjoern A. Zeeb 	host_idx = bd_ring->wp + n_txbd;
12238e93258fSBjoern A. Zeeb 	host_idx = host_idx < len ? host_idx : host_idx - len;
12248e93258fSBjoern A. Zeeb 
12258e93258fSBjoern A. Zeeb 	bd_ring->wp = host_idx;
12268e93258fSBjoern A. Zeeb }
12278e93258fSBjoern A. Zeeb 
12288e93258fSBjoern A. Zeeb static void rtw89_pci_ops_tx_kick_off(struct rtw89_dev *rtwdev, u8 txch)
12298e93258fSBjoern A. Zeeb {
12308e93258fSBjoern A. Zeeb 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
12318e93258fSBjoern A. Zeeb 	struct rtw89_pci_tx_ring *tx_ring = &rtwpci->tx_rings[txch];
12328e93258fSBjoern A. Zeeb 
12338e93258fSBjoern A. Zeeb 	if (rtwdev->hci.paused) {
12348e93258fSBjoern A. Zeeb 		set_bit(txch, rtwpci->kick_map);
12358e93258fSBjoern A. Zeeb 		return;
12368e93258fSBjoern A. Zeeb 	}
12378e93258fSBjoern A. Zeeb 
12388e93258fSBjoern A. Zeeb 	__rtw89_pci_tx_kick_off(rtwdev, tx_ring);
12398e93258fSBjoern A. Zeeb }
12408e93258fSBjoern A. Zeeb 
12418e93258fSBjoern A. Zeeb static void rtw89_pci_tx_kick_off_pending(struct rtw89_dev *rtwdev)
12428e93258fSBjoern A. Zeeb {
12438e93258fSBjoern A. Zeeb 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
12448e93258fSBjoern A. Zeeb 	struct rtw89_pci_tx_ring *tx_ring;
12458e93258fSBjoern A. Zeeb 	int txch;
12468e93258fSBjoern A. Zeeb 
12478e93258fSBjoern A. Zeeb 	for (txch = 0; txch < RTW89_TXCH_NUM; txch++) {
12488e93258fSBjoern A. Zeeb 		if (!test_and_clear_bit(txch, rtwpci->kick_map))
12498e93258fSBjoern A. Zeeb 			continue;
12508e93258fSBjoern A. Zeeb 
12518e93258fSBjoern A. Zeeb 		tx_ring = &rtwpci->tx_rings[txch];
12528e93258fSBjoern A. Zeeb 		__rtw89_pci_tx_kick_off(rtwdev, tx_ring);
12538e93258fSBjoern A. Zeeb 	}
12548e93258fSBjoern A. Zeeb }
12558e93258fSBjoern A. Zeeb 
12568e93258fSBjoern A. Zeeb static void __pci_flush_txch(struct rtw89_dev *rtwdev, u8 txch, bool drop)
12578e93258fSBjoern A. Zeeb {
12588e93258fSBjoern A. Zeeb 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
12598e93258fSBjoern A. Zeeb 	struct rtw89_pci_tx_ring *tx_ring = &rtwpci->tx_rings[txch];
12608e93258fSBjoern A. Zeeb 	struct rtw89_pci_dma_ring *bd_ring = &tx_ring->bd_ring;
12618e93258fSBjoern A. Zeeb 	u32 cur_idx, cur_rp;
12628e93258fSBjoern A. Zeeb 	u8 i;
12638e93258fSBjoern A. Zeeb 
12648e93258fSBjoern A. Zeeb 	/* Because the time taked by the I/O is a bit dynamic, it's hard to
12658e93258fSBjoern A. Zeeb 	 * define a reasonable fixed total timeout to use read_poll_timeout*
12668e93258fSBjoern A. Zeeb 	 * helper. Instead, we can ensure a reasonable polling times, so we
12678e93258fSBjoern A. Zeeb 	 * just use for loop with udelay here.
12688e93258fSBjoern A. Zeeb 	 */
12698e93258fSBjoern A. Zeeb 	for (i = 0; i < 60; i++) {
12708e93258fSBjoern A. Zeeb 		cur_idx = rtw89_read32(rtwdev, bd_ring->addr.idx);
12718e93258fSBjoern A. Zeeb 		cur_rp = FIELD_GET(TXBD_HW_IDX_MASK, cur_idx);
12728e93258fSBjoern A. Zeeb 		if (cur_rp == bd_ring->wp)
12738e93258fSBjoern A. Zeeb 			return;
12748e93258fSBjoern A. Zeeb 
12758e93258fSBjoern A. Zeeb 		udelay(1);
12768e93258fSBjoern A. Zeeb 	}
12778e93258fSBjoern A. Zeeb 
12788e93258fSBjoern A. Zeeb 	if (!drop)
12798e93258fSBjoern A. Zeeb 		rtw89_info(rtwdev, "timed out to flush pci txch: %d\n", txch);
12808e93258fSBjoern A. Zeeb }
12818e93258fSBjoern A. Zeeb 
12828e93258fSBjoern A. Zeeb static void __rtw89_pci_ops_flush_txchs(struct rtw89_dev *rtwdev, u32 txchs,
12838e93258fSBjoern A. Zeeb 					bool drop)
12848e93258fSBjoern A. Zeeb {
1285e2340276SBjoern A. Zeeb 	const struct rtw89_pci_info *info = rtwdev->pci_info;
12868e93258fSBjoern A. Zeeb 	u8 i;
12878e93258fSBjoern A. Zeeb 
12888e93258fSBjoern A. Zeeb 	for (i = 0; i < RTW89_TXCH_NUM; i++) {
12898e93258fSBjoern A. Zeeb 		/* It may be unnecessary to flush FWCMD queue. */
12908e93258fSBjoern A. Zeeb 		if (i == RTW89_TXCH_CH12)
12918e93258fSBjoern A. Zeeb 			continue;
1292e2340276SBjoern A. Zeeb 		if (info->tx_dma_ch_mask & BIT(i))
1293e2340276SBjoern A. Zeeb 			continue;
12948e93258fSBjoern A. Zeeb 
12958e93258fSBjoern A. Zeeb 		if (txchs & BIT(i))
12968e93258fSBjoern A. Zeeb 			__pci_flush_txch(rtwdev, i, drop);
12978e93258fSBjoern A. Zeeb 	}
12988e93258fSBjoern A. Zeeb }
12998e93258fSBjoern A. Zeeb 
13008e93258fSBjoern A. Zeeb static void rtw89_pci_ops_flush_queues(struct rtw89_dev *rtwdev, u32 queues,
13018e93258fSBjoern A. Zeeb 				       bool drop)
13028e93258fSBjoern A. Zeeb {
13038e93258fSBjoern A. Zeeb 	__rtw89_pci_ops_flush_txchs(rtwdev, BIT(RTW89_TXCH_NUM) - 1, drop);
13048e93258fSBjoern A. Zeeb }
13058e93258fSBjoern A. Zeeb 
13068e93258fSBjoern A. Zeeb u32 rtw89_pci_fill_txaddr_info(struct rtw89_dev *rtwdev,
13078e93258fSBjoern A. Zeeb 			       void *txaddr_info_addr, u32 total_len,
13088e93258fSBjoern A. Zeeb 			       dma_addr_t dma, u8 *add_info_nr)
13098e93258fSBjoern A. Zeeb {
13108e93258fSBjoern A. Zeeb 	struct rtw89_pci_tx_addr_info_32 *txaddr_info = txaddr_info_addr;
1311*6d67aabdSBjoern A. Zeeb 	__le16 option;
13128e93258fSBjoern A. Zeeb 
13138e93258fSBjoern A. Zeeb 	txaddr_info->length = cpu_to_le16(total_len);
1314*6d67aabdSBjoern A. Zeeb 	option = cpu_to_le16(RTW89_PCI_ADDR_MSDU_LS | RTW89_PCI_ADDR_NUM(1));
1315*6d67aabdSBjoern A. Zeeb 	option |= le16_encode_bits(upper_32_bits(dma), RTW89_PCI_ADDR_HIGH_MASK);
1316*6d67aabdSBjoern A. Zeeb 	txaddr_info->option = option;
13178e93258fSBjoern A. Zeeb 	txaddr_info->dma = cpu_to_le32(dma);
13188e93258fSBjoern A. Zeeb 
13198e93258fSBjoern A. Zeeb 	*add_info_nr = 1;
13208e93258fSBjoern A. Zeeb 
13218e93258fSBjoern A. Zeeb 	return sizeof(*txaddr_info);
13228e93258fSBjoern A. Zeeb }
13238e93258fSBjoern A. Zeeb EXPORT_SYMBOL(rtw89_pci_fill_txaddr_info);
13248e93258fSBjoern A. Zeeb 
13258e93258fSBjoern A. Zeeb u32 rtw89_pci_fill_txaddr_info_v1(struct rtw89_dev *rtwdev,
13268e93258fSBjoern A. Zeeb 				  void *txaddr_info_addr, u32 total_len,
13278e93258fSBjoern A. Zeeb 				  dma_addr_t dma, u8 *add_info_nr)
13288e93258fSBjoern A. Zeeb {
13298e93258fSBjoern A. Zeeb 	struct rtw89_pci_tx_addr_info_32_v1 *txaddr_info = txaddr_info_addr;
13308e93258fSBjoern A. Zeeb 	u32 remain = total_len;
13318e93258fSBjoern A. Zeeb 	u32 len;
13328e93258fSBjoern A. Zeeb 	u16 length_option;
13338e93258fSBjoern A. Zeeb 	int n;
13348e93258fSBjoern A. Zeeb 
13358e93258fSBjoern A. Zeeb 	for (n = 0; n < RTW89_TXADDR_INFO_NR_V1 && remain; n++) {
13368e93258fSBjoern A. Zeeb 		len = remain >= TXADDR_INFO_LENTHG_V1_MAX ?
13378e93258fSBjoern A. Zeeb 		      TXADDR_INFO_LENTHG_V1_MAX : remain;
13388e93258fSBjoern A. Zeeb 		remain -= len;
13398e93258fSBjoern A. Zeeb 
13408e93258fSBjoern A. Zeeb 		length_option = FIELD_PREP(B_PCIADDR_LEN_V1_MASK, len) |
13418e93258fSBjoern A. Zeeb 				FIELD_PREP(B_PCIADDR_HIGH_SEL_V1_MASK, 0) |
13428e93258fSBjoern A. Zeeb 				FIELD_PREP(B_PCIADDR_LS_V1_MASK, remain == 0);
1343*6d67aabdSBjoern A. Zeeb 		length_option |= u16_encode_bits(upper_32_bits(dma),
1344*6d67aabdSBjoern A. Zeeb 						 B_PCIADDR_HIGH_SEL_V1_MASK);
13458e93258fSBjoern A. Zeeb 		txaddr_info->length_opt = cpu_to_le16(length_option);
13468e93258fSBjoern A. Zeeb 		txaddr_info->dma_low_lsb = cpu_to_le16(FIELD_GET(GENMASK(15, 0), dma));
13478e93258fSBjoern A. Zeeb 		txaddr_info->dma_low_msb = cpu_to_le16(FIELD_GET(GENMASK(31, 16), dma));
13488e93258fSBjoern A. Zeeb 
13498e93258fSBjoern A. Zeeb 		dma += len;
13508e93258fSBjoern A. Zeeb 		txaddr_info++;
13518e93258fSBjoern A. Zeeb 	}
13528e93258fSBjoern A. Zeeb 
13538e93258fSBjoern A. Zeeb 	WARN_ONCE(remain, "length overflow remain=%u total_len=%u",
13548e93258fSBjoern A. Zeeb 		  remain, total_len);
13558e93258fSBjoern A. Zeeb 
13568e93258fSBjoern A. Zeeb 	*add_info_nr = n;
13578e93258fSBjoern A. Zeeb 
13588e93258fSBjoern A. Zeeb 	return n * sizeof(*txaddr_info);
13598e93258fSBjoern A. Zeeb }
13608e93258fSBjoern A. Zeeb EXPORT_SYMBOL(rtw89_pci_fill_txaddr_info_v1);
13618e93258fSBjoern A. Zeeb 
13628e93258fSBjoern A. Zeeb static int rtw89_pci_txwd_submit(struct rtw89_dev *rtwdev,
13638e93258fSBjoern A. Zeeb 				 struct rtw89_pci_tx_ring *tx_ring,
13648e93258fSBjoern A. Zeeb 				 struct rtw89_pci_tx_wd *txwd,
13658e93258fSBjoern A. Zeeb 				 struct rtw89_core_tx_request *tx_req)
13668e93258fSBjoern A. Zeeb {
13678e93258fSBjoern A. Zeeb 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
13688e93258fSBjoern A. Zeeb 	const struct rtw89_chip_info *chip = rtwdev->chip;
13698e93258fSBjoern A. Zeeb 	struct rtw89_tx_desc_info *desc_info = &tx_req->desc_info;
13708e93258fSBjoern A. Zeeb 	struct rtw89_pci_tx_wp_info *txwp_info;
13718e93258fSBjoern A. Zeeb 	void *txaddr_info_addr;
13728e93258fSBjoern A. Zeeb 	struct pci_dev *pdev = rtwpci->pdev;
13738e93258fSBjoern A. Zeeb 	struct sk_buff *skb = tx_req->skb;
13748e93258fSBjoern A. Zeeb 	struct rtw89_pci_tx_data *tx_data = RTW89_PCI_TX_SKB_CB(skb);
1375e2340276SBjoern A. Zeeb 	struct rtw89_tx_skb_data *skb_data = RTW89_TX_SKB_CB(skb);
13768e93258fSBjoern A. Zeeb 	bool en_wd_info = desc_info->en_wd_info;
13778e93258fSBjoern A. Zeeb 	u32 txwd_len;
13788e93258fSBjoern A. Zeeb 	u32 txwp_len;
13798e93258fSBjoern A. Zeeb 	u32 txaddr_info_len;
13808e93258fSBjoern A. Zeeb 	dma_addr_t dma;
13818e93258fSBjoern A. Zeeb 	int ret;
13828e93258fSBjoern A. Zeeb 
13838e93258fSBjoern A. Zeeb 	dma = dma_map_single(&pdev->dev, skb->data, skb->len, DMA_TO_DEVICE);
13848e93258fSBjoern A. Zeeb 	if (dma_mapping_error(&pdev->dev, dma)) {
13858e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "failed to map skb dma data\n");
13868e93258fSBjoern A. Zeeb 		ret = -EBUSY;
13878e93258fSBjoern A. Zeeb 		goto err;
13888e93258fSBjoern A. Zeeb 	}
13898e93258fSBjoern A. Zeeb 
13908e93258fSBjoern A. Zeeb 	tx_data->dma = dma;
1391e2340276SBjoern A. Zeeb 	rcu_assign_pointer(skb_data->wait, NULL);
13928e93258fSBjoern A. Zeeb 
13938e93258fSBjoern A. Zeeb 	txwp_len = sizeof(*txwp_info);
13948e93258fSBjoern A. Zeeb 	txwd_len = chip->txwd_body_size;
1395*6d67aabdSBjoern A. Zeeb 	txwd_len += en_wd_info ? chip->txwd_info_size : 0;
13968e93258fSBjoern A. Zeeb 
13978e93258fSBjoern A. Zeeb #if defined(__linux__)
13988e93258fSBjoern A. Zeeb 	txwp_info = txwd->vaddr + txwd_len;
13998e93258fSBjoern A. Zeeb #elif defined(__FreeBSD__)
14008e93258fSBjoern A. Zeeb 	txwp_info = (struct rtw89_pci_tx_wp_info *)((u8 *)txwd->vaddr + txwd_len);
14018e93258fSBjoern A. Zeeb #endif
14028e93258fSBjoern A. Zeeb 	txwp_info->seq0 = cpu_to_le16(txwd->seq | RTW89_PCI_TXWP_VALID);
14038e93258fSBjoern A. Zeeb 	txwp_info->seq1 = 0;
14048e93258fSBjoern A. Zeeb 	txwp_info->seq2 = 0;
14058e93258fSBjoern A. Zeeb 	txwp_info->seq3 = 0;
14068e93258fSBjoern A. Zeeb 
14078e93258fSBjoern A. Zeeb 	tx_ring->tx_cnt++;
14088e93258fSBjoern A. Zeeb #if defined(__linux__)
14098e93258fSBjoern A. Zeeb 	txaddr_info_addr = txwd->vaddr + txwd_len + txwp_len;
14108e93258fSBjoern A. Zeeb #elif defined(__FreeBSD__)
14118e93258fSBjoern A. Zeeb 	txaddr_info_addr = (u8 *)txwd->vaddr + txwd_len + txwp_len;
14128e93258fSBjoern A. Zeeb #endif
14138e93258fSBjoern A. Zeeb 	txaddr_info_len =
14148e93258fSBjoern A. Zeeb 		rtw89_chip_fill_txaddr_info(rtwdev, txaddr_info_addr, skb->len,
14158e93258fSBjoern A. Zeeb 					    dma, &desc_info->addr_info_nr);
14168e93258fSBjoern A. Zeeb 
14178e93258fSBjoern A. Zeeb 	txwd->len = txwd_len + txwp_len + txaddr_info_len;
14188e93258fSBjoern A. Zeeb 
14198e93258fSBjoern A. Zeeb 	rtw89_chip_fill_txdesc(rtwdev, desc_info, txwd->vaddr);
14208e93258fSBjoern A. Zeeb 
14218e93258fSBjoern A. Zeeb 	skb_queue_tail(&txwd->queue, skb);
14228e93258fSBjoern A. Zeeb 
14238e93258fSBjoern A. Zeeb 	return 0;
14248e93258fSBjoern A. Zeeb 
14258e93258fSBjoern A. Zeeb err:
14268e93258fSBjoern A. Zeeb 	return ret;
14278e93258fSBjoern A. Zeeb }
14288e93258fSBjoern A. Zeeb 
14298e93258fSBjoern A. Zeeb static int rtw89_pci_fwcmd_submit(struct rtw89_dev *rtwdev,
14308e93258fSBjoern A. Zeeb 				  struct rtw89_pci_tx_ring *tx_ring,
14318e93258fSBjoern A. Zeeb 				  struct rtw89_pci_tx_bd_32 *txbd,
14328e93258fSBjoern A. Zeeb 				  struct rtw89_core_tx_request *tx_req)
14338e93258fSBjoern A. Zeeb {
14348e93258fSBjoern A. Zeeb 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
14358e93258fSBjoern A. Zeeb 	const struct rtw89_chip_info *chip = rtwdev->chip;
14368e93258fSBjoern A. Zeeb 	struct rtw89_tx_desc_info *desc_info = &tx_req->desc_info;
14378e93258fSBjoern A. Zeeb 	void *txdesc;
14388e93258fSBjoern A. Zeeb 	int txdesc_size = chip->h2c_desc_size;
14398e93258fSBjoern A. Zeeb 	struct pci_dev *pdev = rtwpci->pdev;
14408e93258fSBjoern A. Zeeb 	struct sk_buff *skb = tx_req->skb;
14418e93258fSBjoern A. Zeeb 	struct rtw89_pci_tx_data *tx_data = RTW89_PCI_TX_SKB_CB(skb);
14428e93258fSBjoern A. Zeeb 	dma_addr_t dma;
1443*6d67aabdSBjoern A. Zeeb 	__le16 opt;
14448e93258fSBjoern A. Zeeb 
14458e93258fSBjoern A. Zeeb 	txdesc = skb_push(skb, txdesc_size);
14468e93258fSBjoern A. Zeeb 	memset(txdesc, 0, txdesc_size);
14478e93258fSBjoern A. Zeeb 	rtw89_chip_fill_txdesc_fwcmd(rtwdev, desc_info, txdesc);
14488e93258fSBjoern A. Zeeb 
14498e93258fSBjoern A. Zeeb 	dma = dma_map_single(&pdev->dev, skb->data, skb->len, DMA_TO_DEVICE);
14508e93258fSBjoern A. Zeeb 	if (dma_mapping_error(&pdev->dev, dma)) {
14518e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "failed to map fwcmd dma data\n");
14528e93258fSBjoern A. Zeeb 		return -EBUSY;
14538e93258fSBjoern A. Zeeb 	}
14548e93258fSBjoern A. Zeeb 
14558e93258fSBjoern A. Zeeb 	tx_data->dma = dma;
1456*6d67aabdSBjoern A. Zeeb 	opt = cpu_to_le16(RTW89_PCI_TXBD_OPT_LS);
1457*6d67aabdSBjoern A. Zeeb 	opt |= le16_encode_bits(upper_32_bits(dma), RTW89_PCI_TXBD_OPT_DMA_HI);
1458*6d67aabdSBjoern A. Zeeb 	txbd->opt = opt;
14598e93258fSBjoern A. Zeeb 	txbd->length = cpu_to_le16(skb->len);
14608e93258fSBjoern A. Zeeb 	txbd->dma = cpu_to_le32(tx_data->dma);
14618e93258fSBjoern A. Zeeb 	skb_queue_tail(&rtwpci->h2c_queue, skb);
14628e93258fSBjoern A. Zeeb 
14638e93258fSBjoern A. Zeeb 	rtw89_pci_tx_bd_ring_update(rtwdev, tx_ring, 1);
14648e93258fSBjoern A. Zeeb 
14658e93258fSBjoern A. Zeeb 	return 0;
14668e93258fSBjoern A. Zeeb }
14678e93258fSBjoern A. Zeeb 
14688e93258fSBjoern A. Zeeb static int rtw89_pci_txbd_submit(struct rtw89_dev *rtwdev,
14698e93258fSBjoern A. Zeeb 				 struct rtw89_pci_tx_ring *tx_ring,
14708e93258fSBjoern A. Zeeb 				 struct rtw89_pci_tx_bd_32 *txbd,
14718e93258fSBjoern A. Zeeb 				 struct rtw89_core_tx_request *tx_req)
14728e93258fSBjoern A. Zeeb {
14738e93258fSBjoern A. Zeeb 	struct rtw89_pci_tx_wd *txwd;
1474*6d67aabdSBjoern A. Zeeb 	__le16 opt;
14758e93258fSBjoern A. Zeeb 	int ret;
14768e93258fSBjoern A. Zeeb 
14778e93258fSBjoern A. Zeeb 	/* FWCMD queue doesn't have wd pages. Instead, it submits the CMD
14788e93258fSBjoern A. Zeeb 	 * buffer with WD BODY only. So here we don't need to check the free
14798e93258fSBjoern A. Zeeb 	 * pages of the wd ring.
14808e93258fSBjoern A. Zeeb 	 */
14818e93258fSBjoern A. Zeeb 	if (tx_ring->txch == RTW89_TXCH_CH12)
14828e93258fSBjoern A. Zeeb 		return rtw89_pci_fwcmd_submit(rtwdev, tx_ring, txbd, tx_req);
14838e93258fSBjoern A. Zeeb 
14848e93258fSBjoern A. Zeeb 	txwd = rtw89_pci_dequeue_txwd(tx_ring);
14858e93258fSBjoern A. Zeeb 	if (!txwd) {
14868e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "no available TXWD\n");
14878e93258fSBjoern A. Zeeb 		ret = -ENOSPC;
14888e93258fSBjoern A. Zeeb 		goto err;
14898e93258fSBjoern A. Zeeb 	}
14908e93258fSBjoern A. Zeeb 
14918e93258fSBjoern A. Zeeb 	ret = rtw89_pci_txwd_submit(rtwdev, tx_ring, txwd, tx_req);
14928e93258fSBjoern A. Zeeb 	if (ret) {
14938e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "failed to submit TXWD %d\n", txwd->seq);
14948e93258fSBjoern A. Zeeb 		goto err_enqueue_wd;
14958e93258fSBjoern A. Zeeb 	}
14968e93258fSBjoern A. Zeeb 
14978e93258fSBjoern A. Zeeb 	list_add_tail(&txwd->list, &tx_ring->busy_pages);
14988e93258fSBjoern A. Zeeb 
1499*6d67aabdSBjoern A. Zeeb 	opt = cpu_to_le16(RTW89_PCI_TXBD_OPT_LS);
1500*6d67aabdSBjoern A. Zeeb 	opt |= le16_encode_bits(upper_32_bits(txwd->paddr), RTW89_PCI_TXBD_OPT_DMA_HI);
1501*6d67aabdSBjoern A. Zeeb 	txbd->opt = opt;
15028e93258fSBjoern A. Zeeb 	txbd->length = cpu_to_le16(txwd->len);
15038e93258fSBjoern A. Zeeb 	txbd->dma = cpu_to_le32(txwd->paddr);
15048e93258fSBjoern A. Zeeb 
15058e93258fSBjoern A. Zeeb 	rtw89_pci_tx_bd_ring_update(rtwdev, tx_ring, 1);
15068e93258fSBjoern A. Zeeb 
15078e93258fSBjoern A. Zeeb 	return 0;
15088e93258fSBjoern A. Zeeb 
15098e93258fSBjoern A. Zeeb err_enqueue_wd:
15108e93258fSBjoern A. Zeeb 	rtw89_pci_enqueue_txwd(tx_ring, txwd);
15118e93258fSBjoern A. Zeeb err:
15128e93258fSBjoern A. Zeeb 	return ret;
15138e93258fSBjoern A. Zeeb }
15148e93258fSBjoern A. Zeeb 
15158e93258fSBjoern A. Zeeb static int rtw89_pci_tx_write(struct rtw89_dev *rtwdev, struct rtw89_core_tx_request *tx_req,
15168e93258fSBjoern A. Zeeb 			      u8 txch)
15178e93258fSBjoern A. Zeeb {
15188e93258fSBjoern A. Zeeb 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
15198e93258fSBjoern A. Zeeb 	struct rtw89_pci_tx_ring *tx_ring;
15208e93258fSBjoern A. Zeeb 	struct rtw89_pci_tx_bd_32 *txbd;
15218e93258fSBjoern A. Zeeb 	u32 n_avail_txbd;
15228e93258fSBjoern A. Zeeb 	int ret = 0;
15238e93258fSBjoern A. Zeeb 
15248e93258fSBjoern A. Zeeb 	/* check the tx type and dma channel for fw cmd queue */
15258e93258fSBjoern A. Zeeb 	if ((txch == RTW89_TXCH_CH12 ||
15268e93258fSBjoern A. Zeeb 	     tx_req->tx_type == RTW89_CORE_TX_TYPE_FWCMD) &&
15278e93258fSBjoern A. Zeeb 	    (txch != RTW89_TXCH_CH12 ||
15288e93258fSBjoern A. Zeeb 	     tx_req->tx_type != RTW89_CORE_TX_TYPE_FWCMD)) {
15298e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "only fw cmd uses dma channel 12\n");
15308e93258fSBjoern A. Zeeb 		return -EINVAL;
15318e93258fSBjoern A. Zeeb 	}
15328e93258fSBjoern A. Zeeb 
15338e93258fSBjoern A. Zeeb 	tx_ring = &rtwpci->tx_rings[txch];
15348e93258fSBjoern A. Zeeb 	spin_lock_bh(&rtwpci->trx_lock);
15358e93258fSBjoern A. Zeeb 
15368e93258fSBjoern A. Zeeb 	n_avail_txbd = rtw89_pci_get_avail_txbd_num(tx_ring);
15378e93258fSBjoern A. Zeeb 	if (n_avail_txbd == 0) {
15388e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "no available TXBD\n");
15398e93258fSBjoern A. Zeeb 		ret = -ENOSPC;
15408e93258fSBjoern A. Zeeb 		goto err_unlock;
15418e93258fSBjoern A. Zeeb 	}
15428e93258fSBjoern A. Zeeb 
15438e93258fSBjoern A. Zeeb 	txbd = rtw89_pci_get_next_txbd(tx_ring);
15448e93258fSBjoern A. Zeeb 	ret = rtw89_pci_txbd_submit(rtwdev, tx_ring, txbd, tx_req);
15458e93258fSBjoern A. Zeeb 	if (ret) {
15468e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "failed to submit TXBD\n");
15478e93258fSBjoern A. Zeeb 		goto err_unlock;
15488e93258fSBjoern A. Zeeb 	}
15498e93258fSBjoern A. Zeeb 
15508e93258fSBjoern A. Zeeb 	spin_unlock_bh(&rtwpci->trx_lock);
15518e93258fSBjoern A. Zeeb 	return 0;
15528e93258fSBjoern A. Zeeb 
15538e93258fSBjoern A. Zeeb err_unlock:
15548e93258fSBjoern A. Zeeb 	spin_unlock_bh(&rtwpci->trx_lock);
15558e93258fSBjoern A. Zeeb 	return ret;
15568e93258fSBjoern A. Zeeb }
15578e93258fSBjoern A. Zeeb 
15588e93258fSBjoern A. Zeeb static int rtw89_pci_ops_tx_write(struct rtw89_dev *rtwdev, struct rtw89_core_tx_request *tx_req)
15598e93258fSBjoern A. Zeeb {
15608e93258fSBjoern A. Zeeb 	struct rtw89_tx_desc_info *desc_info = &tx_req->desc_info;
15618e93258fSBjoern A. Zeeb 	int ret;
15628e93258fSBjoern A. Zeeb 
15638e93258fSBjoern A. Zeeb 	ret = rtw89_pci_tx_write(rtwdev, tx_req, desc_info->ch_dma);
15648e93258fSBjoern A. Zeeb 	if (ret) {
15658e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "failed to TX Queue %d\n", desc_info->ch_dma);
15668e93258fSBjoern A. Zeeb 		return ret;
15678e93258fSBjoern A. Zeeb 	}
15688e93258fSBjoern A. Zeeb 
15698e93258fSBjoern A. Zeeb 	return 0;
15708e93258fSBjoern A. Zeeb }
15718e93258fSBjoern A. Zeeb 
1572e2340276SBjoern A. Zeeb const struct rtw89_pci_bd_ram rtw89_bd_ram_table_dual[RTW89_TXCH_NUM] = {
15738e93258fSBjoern A. Zeeb 	[RTW89_TXCH_ACH0] = {.start_idx = 0,  .max_num = 5, .min_num = 2},
15748e93258fSBjoern A. Zeeb 	[RTW89_TXCH_ACH1] = {.start_idx = 5,  .max_num = 5, .min_num = 2},
15758e93258fSBjoern A. Zeeb 	[RTW89_TXCH_ACH2] = {.start_idx = 10, .max_num = 5, .min_num = 2},
15768e93258fSBjoern A. Zeeb 	[RTW89_TXCH_ACH3] = {.start_idx = 15, .max_num = 5, .min_num = 2},
15778e93258fSBjoern A. Zeeb 	[RTW89_TXCH_ACH4] = {.start_idx = 20, .max_num = 5, .min_num = 2},
15788e93258fSBjoern A. Zeeb 	[RTW89_TXCH_ACH5] = {.start_idx = 25, .max_num = 5, .min_num = 2},
15798e93258fSBjoern A. Zeeb 	[RTW89_TXCH_ACH6] = {.start_idx = 30, .max_num = 5, .min_num = 2},
15808e93258fSBjoern A. Zeeb 	[RTW89_TXCH_ACH7] = {.start_idx = 35, .max_num = 5, .min_num = 2},
15818e93258fSBjoern A. Zeeb 	[RTW89_TXCH_CH8]  = {.start_idx = 40, .max_num = 5, .min_num = 1},
15828e93258fSBjoern A. Zeeb 	[RTW89_TXCH_CH9]  = {.start_idx = 45, .max_num = 5, .min_num = 1},
15838e93258fSBjoern A. Zeeb 	[RTW89_TXCH_CH10] = {.start_idx = 50, .max_num = 5, .min_num = 1},
15848e93258fSBjoern A. Zeeb 	[RTW89_TXCH_CH11] = {.start_idx = 55, .max_num = 5, .min_num = 1},
15858e93258fSBjoern A. Zeeb 	[RTW89_TXCH_CH12] = {.start_idx = 60, .max_num = 4, .min_num = 1},
15868e93258fSBjoern A. Zeeb };
1587e2340276SBjoern A. Zeeb EXPORT_SYMBOL(rtw89_bd_ram_table_dual);
1588e2340276SBjoern A. Zeeb 
1589e2340276SBjoern A. Zeeb const struct rtw89_pci_bd_ram rtw89_bd_ram_table_single[RTW89_TXCH_NUM] = {
1590e2340276SBjoern A. Zeeb 	[RTW89_TXCH_ACH0] = {.start_idx = 0,  .max_num = 5, .min_num = 2},
1591e2340276SBjoern A. Zeeb 	[RTW89_TXCH_ACH1] = {.start_idx = 5,  .max_num = 5, .min_num = 2},
1592e2340276SBjoern A. Zeeb 	[RTW89_TXCH_ACH2] = {.start_idx = 10, .max_num = 5, .min_num = 2},
1593e2340276SBjoern A. Zeeb 	[RTW89_TXCH_ACH3] = {.start_idx = 15, .max_num = 5, .min_num = 2},
1594e2340276SBjoern A. Zeeb 	[RTW89_TXCH_CH8]  = {.start_idx = 20, .max_num = 4, .min_num = 1},
1595e2340276SBjoern A. Zeeb 	[RTW89_TXCH_CH9]  = {.start_idx = 24, .max_num = 4, .min_num = 1},
1596e2340276SBjoern A. Zeeb 	[RTW89_TXCH_CH12] = {.start_idx = 28, .max_num = 4, .min_num = 1},
1597e2340276SBjoern A. Zeeb };
1598e2340276SBjoern A. Zeeb EXPORT_SYMBOL(rtw89_bd_ram_table_single);
15998e93258fSBjoern A. Zeeb 
1600*6d67aabdSBjoern A. Zeeb static void rtw89_pci_init_wp_16sel(struct rtw89_dev *rtwdev)
1601*6d67aabdSBjoern A. Zeeb {
1602*6d67aabdSBjoern A. Zeeb 	const struct rtw89_pci_info *info = rtwdev->pci_info;
1603*6d67aabdSBjoern A. Zeeb 	u32 addr = info->wp_sel_addr;
1604*6d67aabdSBjoern A. Zeeb 	u32 val;
1605*6d67aabdSBjoern A. Zeeb 	int i;
1606*6d67aabdSBjoern A. Zeeb 
1607*6d67aabdSBjoern A. Zeeb 	if (!info->wp_sel_addr)
1608*6d67aabdSBjoern A. Zeeb 		return;
1609*6d67aabdSBjoern A. Zeeb 
1610*6d67aabdSBjoern A. Zeeb 	for (i = 0; i < 16; i += 4) {
1611*6d67aabdSBjoern A. Zeeb 		val = u32_encode_bits(i + 0, MASKBYTE0) |
1612*6d67aabdSBjoern A. Zeeb 		      u32_encode_bits(i + 1, MASKBYTE1) |
1613*6d67aabdSBjoern A. Zeeb 		      u32_encode_bits(i + 2, MASKBYTE2) |
1614*6d67aabdSBjoern A. Zeeb 		      u32_encode_bits(i + 3, MASKBYTE3);
1615*6d67aabdSBjoern A. Zeeb 		rtw89_write32(rtwdev, addr + i, val);
1616*6d67aabdSBjoern A. Zeeb 	}
1617*6d67aabdSBjoern A. Zeeb }
1618*6d67aabdSBjoern A. Zeeb 
16198e93258fSBjoern A. Zeeb static void rtw89_pci_reset_trx_rings(struct rtw89_dev *rtwdev)
16208e93258fSBjoern A. Zeeb {
16218e93258fSBjoern A. Zeeb 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
1622e2340276SBjoern A. Zeeb 	const struct rtw89_pci_info *info = rtwdev->pci_info;
1623e2340276SBjoern A. Zeeb 	const struct rtw89_pci_bd_ram *bd_ram_table = *info->bd_ram_table;
16248e93258fSBjoern A. Zeeb 	struct rtw89_pci_tx_ring *tx_ring;
16258e93258fSBjoern A. Zeeb 	struct rtw89_pci_rx_ring *rx_ring;
16268e93258fSBjoern A. Zeeb 	struct rtw89_pci_dma_ring *bd_ring;
16278e93258fSBjoern A. Zeeb 	const struct rtw89_pci_bd_ram *bd_ram;
16288e93258fSBjoern A. Zeeb 	u32 addr_num;
1629*6d67aabdSBjoern A. Zeeb 	u32 addr_idx;
16308e93258fSBjoern A. Zeeb 	u32 addr_bdram;
16318e93258fSBjoern A. Zeeb 	u32 addr_desa_l;
16328e93258fSBjoern A. Zeeb 	u32 val32;
16338e93258fSBjoern A. Zeeb 	int i;
16348e93258fSBjoern A. Zeeb 
16358e93258fSBjoern A. Zeeb 	for (i = 0; i < RTW89_TXCH_NUM; i++) {
1636e2340276SBjoern A. Zeeb 		if (info->tx_dma_ch_mask & BIT(i))
1637e2340276SBjoern A. Zeeb 			continue;
1638e2340276SBjoern A. Zeeb 
16398e93258fSBjoern A. Zeeb 		tx_ring = &rtwpci->tx_rings[i];
16408e93258fSBjoern A. Zeeb 		bd_ring = &tx_ring->bd_ring;
1641*6d67aabdSBjoern A. Zeeb 		bd_ram = bd_ram_table ? &bd_ram_table[i] : NULL;
16428e93258fSBjoern A. Zeeb 		addr_num = bd_ring->addr.num;
16438e93258fSBjoern A. Zeeb 		addr_bdram = bd_ring->addr.bdram;
16448e93258fSBjoern A. Zeeb 		addr_desa_l = bd_ring->addr.desa_l;
16458e93258fSBjoern A. Zeeb 		bd_ring->wp = 0;
16468e93258fSBjoern A. Zeeb 		bd_ring->rp = 0;
16478e93258fSBjoern A. Zeeb 
1648*6d67aabdSBjoern A. Zeeb 		rtw89_write16(rtwdev, addr_num, bd_ring->len);
1649*6d67aabdSBjoern A. Zeeb 		if (addr_bdram && bd_ram) {
16508e93258fSBjoern A. Zeeb 			val32 = FIELD_PREP(BDRAM_SIDX_MASK, bd_ram->start_idx) |
16518e93258fSBjoern A. Zeeb 				FIELD_PREP(BDRAM_MAX_MASK, bd_ram->max_num) |
16528e93258fSBjoern A. Zeeb 				FIELD_PREP(BDRAM_MIN_MASK, bd_ram->min_num);
16538e93258fSBjoern A. Zeeb 
16548e93258fSBjoern A. Zeeb 			rtw89_write32(rtwdev, addr_bdram, val32);
1655*6d67aabdSBjoern A. Zeeb 		}
16568e93258fSBjoern A. Zeeb 		rtw89_write32(rtwdev, addr_desa_l, bd_ring->dma);
1657*6d67aabdSBjoern A. Zeeb 		rtw89_write32(rtwdev, addr_desa_l + 4, upper_32_bits(bd_ring->dma));
16588e93258fSBjoern A. Zeeb 	}
16598e93258fSBjoern A. Zeeb 
16608e93258fSBjoern A. Zeeb 	for (i = 0; i < RTW89_RXCH_NUM; i++) {
16618e93258fSBjoern A. Zeeb 		rx_ring = &rtwpci->rx_rings[i];
16628e93258fSBjoern A. Zeeb 		bd_ring = &rx_ring->bd_ring;
16638e93258fSBjoern A. Zeeb 		addr_num = bd_ring->addr.num;
1664*6d67aabdSBjoern A. Zeeb 		addr_idx = bd_ring->addr.idx;
16658e93258fSBjoern A. Zeeb 		addr_desa_l = bd_ring->addr.desa_l;
1666*6d67aabdSBjoern A. Zeeb 		if (info->rx_ring_eq_is_full)
1667*6d67aabdSBjoern A. Zeeb 			bd_ring->wp = bd_ring->len - 1;
1668*6d67aabdSBjoern A. Zeeb 		else
16698e93258fSBjoern A. Zeeb 			bd_ring->wp = 0;
16708e93258fSBjoern A. Zeeb 		bd_ring->rp = 0;
16718e93258fSBjoern A. Zeeb 		rx_ring->diliver_skb = NULL;
16728e93258fSBjoern A. Zeeb 		rx_ring->diliver_desc.ready = false;
1673*6d67aabdSBjoern A. Zeeb 		rx_ring->target_rx_tag = 0;
16748e93258fSBjoern A. Zeeb 
16758e93258fSBjoern A. Zeeb 		rtw89_write16(rtwdev, addr_num, bd_ring->len);
16768e93258fSBjoern A. Zeeb 		rtw89_write32(rtwdev, addr_desa_l, bd_ring->dma);
1677*6d67aabdSBjoern A. Zeeb 		rtw89_write32(rtwdev, addr_desa_l + 4, upper_32_bits(bd_ring->dma));
1678*6d67aabdSBjoern A. Zeeb 
1679*6d67aabdSBjoern A. Zeeb 		if (info->rx_ring_eq_is_full)
1680*6d67aabdSBjoern A. Zeeb 			rtw89_write16(rtwdev, addr_idx, bd_ring->wp);
16818e93258fSBjoern A. Zeeb 	}
1682*6d67aabdSBjoern A. Zeeb 
1683*6d67aabdSBjoern A. Zeeb 	rtw89_pci_init_wp_16sel(rtwdev);
16848e93258fSBjoern A. Zeeb }
16858e93258fSBjoern A. Zeeb 
16868e93258fSBjoern A. Zeeb static void rtw89_pci_release_tx_ring(struct rtw89_dev *rtwdev,
16878e93258fSBjoern A. Zeeb 				      struct rtw89_pci_tx_ring *tx_ring)
16888e93258fSBjoern A. Zeeb {
16898e93258fSBjoern A. Zeeb 	rtw89_pci_release_busy_txwd(rtwdev, tx_ring);
16908e93258fSBjoern A. Zeeb 	rtw89_pci_release_pending_txwd_skb(rtwdev, tx_ring);
16918e93258fSBjoern A. Zeeb }
16928e93258fSBjoern A. Zeeb 
1693*6d67aabdSBjoern A. Zeeb void rtw89_pci_ops_reset(struct rtw89_dev *rtwdev)
16948e93258fSBjoern A. Zeeb {
16958e93258fSBjoern A. Zeeb 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
1696e2340276SBjoern A. Zeeb 	const struct rtw89_pci_info *info = rtwdev->pci_info;
16978e93258fSBjoern A. Zeeb 	int txch;
16988e93258fSBjoern A. Zeeb 
16998e93258fSBjoern A. Zeeb 	rtw89_pci_reset_trx_rings(rtwdev);
17008e93258fSBjoern A. Zeeb 
17018e93258fSBjoern A. Zeeb 	spin_lock_bh(&rtwpci->trx_lock);
17028e93258fSBjoern A. Zeeb 	for (txch = 0; txch < RTW89_TXCH_NUM; txch++) {
1703e2340276SBjoern A. Zeeb 		if (info->tx_dma_ch_mask & BIT(txch))
1704e2340276SBjoern A. Zeeb 			continue;
17058e93258fSBjoern A. Zeeb 		if (txch == RTW89_TXCH_CH12) {
17068e93258fSBjoern A. Zeeb 			rtw89_pci_release_fwcmd(rtwdev, rtwpci,
17078e93258fSBjoern A. Zeeb 						skb_queue_len(&rtwpci->h2c_queue), true);
17088e93258fSBjoern A. Zeeb 			continue;
17098e93258fSBjoern A. Zeeb 		}
17108e93258fSBjoern A. Zeeb 		rtw89_pci_release_tx_ring(rtwdev, &rtwpci->tx_rings[txch]);
17118e93258fSBjoern A. Zeeb 	}
17128e93258fSBjoern A. Zeeb 	spin_unlock_bh(&rtwpci->trx_lock);
17138e93258fSBjoern A. Zeeb }
17148e93258fSBjoern A. Zeeb 
17158e93258fSBjoern A. Zeeb static void rtw89_pci_enable_intr_lock(struct rtw89_dev *rtwdev)
17168e93258fSBjoern A. Zeeb {
17178e93258fSBjoern A. Zeeb 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
17188e93258fSBjoern A. Zeeb 	unsigned long flags;
17198e93258fSBjoern A. Zeeb 
17208e93258fSBjoern A. Zeeb 	spin_lock_irqsave(&rtwpci->irq_lock, flags);
17218e93258fSBjoern A. Zeeb 	rtwpci->running = true;
17228e93258fSBjoern A. Zeeb 	rtw89_chip_enable_intr(rtwdev, rtwpci);
17238e93258fSBjoern A. Zeeb 	spin_unlock_irqrestore(&rtwpci->irq_lock, flags);
17248e93258fSBjoern A. Zeeb }
17258e93258fSBjoern A. Zeeb 
17268e93258fSBjoern A. Zeeb static void rtw89_pci_disable_intr_lock(struct rtw89_dev *rtwdev)
17278e93258fSBjoern A. Zeeb {
17288e93258fSBjoern A. Zeeb 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
17298e93258fSBjoern A. Zeeb 	unsigned long flags;
17308e93258fSBjoern A. Zeeb 
17318e93258fSBjoern A. Zeeb 	spin_lock_irqsave(&rtwpci->irq_lock, flags);
17328e93258fSBjoern A. Zeeb 	rtwpci->running = false;
17338e93258fSBjoern A. Zeeb 	rtw89_chip_disable_intr(rtwdev, rtwpci);
17348e93258fSBjoern A. Zeeb 	spin_unlock_irqrestore(&rtwpci->irq_lock, flags);
17358e93258fSBjoern A. Zeeb }
17368e93258fSBjoern A. Zeeb 
17378e93258fSBjoern A. Zeeb static int rtw89_pci_ops_start(struct rtw89_dev *rtwdev)
17388e93258fSBjoern A. Zeeb {
17398e93258fSBjoern A. Zeeb 	rtw89_core_napi_start(rtwdev);
17408e93258fSBjoern A. Zeeb 	rtw89_pci_enable_intr_lock(rtwdev);
17418e93258fSBjoern A. Zeeb 
17428e93258fSBjoern A. Zeeb 	return 0;
17438e93258fSBjoern A. Zeeb }
17448e93258fSBjoern A. Zeeb 
17458e93258fSBjoern A. Zeeb static void rtw89_pci_ops_stop(struct rtw89_dev *rtwdev)
17468e93258fSBjoern A. Zeeb {
17478e93258fSBjoern A. Zeeb 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
17488e93258fSBjoern A. Zeeb 	struct pci_dev *pdev = rtwpci->pdev;
17498e93258fSBjoern A. Zeeb 
17508e93258fSBjoern A. Zeeb 	rtw89_pci_disable_intr_lock(rtwdev);
17518e93258fSBjoern A. Zeeb 	synchronize_irq(pdev->irq);
17528e93258fSBjoern A. Zeeb 	rtw89_core_napi_stop(rtwdev);
17538e93258fSBjoern A. Zeeb }
17548e93258fSBjoern A. Zeeb 
17558e93258fSBjoern A. Zeeb static void rtw89_pci_ops_pause(struct rtw89_dev *rtwdev, bool pause)
17568e93258fSBjoern A. Zeeb {
17578e93258fSBjoern A. Zeeb 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
17588e93258fSBjoern A. Zeeb 	struct pci_dev *pdev = rtwpci->pdev;
17598e93258fSBjoern A. Zeeb 
17608e93258fSBjoern A. Zeeb 	if (pause) {
17618e93258fSBjoern A. Zeeb 		rtw89_pci_disable_intr_lock(rtwdev);
17628e93258fSBjoern A. Zeeb 		synchronize_irq(pdev->irq);
17638e93258fSBjoern A. Zeeb 		if (test_bit(RTW89_FLAG_NAPI_RUNNING, rtwdev->flags))
17648e93258fSBjoern A. Zeeb 			napi_synchronize(&rtwdev->napi);
17658e93258fSBjoern A. Zeeb 	} else {
17668e93258fSBjoern A. Zeeb 		rtw89_pci_enable_intr_lock(rtwdev);
17678e93258fSBjoern A. Zeeb 		rtw89_pci_tx_kick_off_pending(rtwdev);
17688e93258fSBjoern A. Zeeb 	}
17698e93258fSBjoern A. Zeeb }
17708e93258fSBjoern A. Zeeb 
17718e93258fSBjoern A. Zeeb static
17728e93258fSBjoern A. Zeeb void rtw89_pci_switch_bd_idx_addr(struct rtw89_dev *rtwdev, bool low_power)
17738e93258fSBjoern A. Zeeb {
17748e93258fSBjoern A. Zeeb 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
17758e93258fSBjoern A. Zeeb 	const struct rtw89_pci_info *info = rtwdev->pci_info;
17768e93258fSBjoern A. Zeeb 	const struct rtw89_pci_bd_idx_addr *bd_idx_addr = info->bd_idx_addr_low_power;
17778e93258fSBjoern A. Zeeb 	const struct rtw89_pci_ch_dma_addr_set *dma_addr_set = info->dma_addr_set;
17788e93258fSBjoern A. Zeeb 	struct rtw89_pci_tx_ring *tx_ring;
17798e93258fSBjoern A. Zeeb 	struct rtw89_pci_rx_ring *rx_ring;
17808e93258fSBjoern A. Zeeb 	int i;
17818e93258fSBjoern A. Zeeb 
17828e93258fSBjoern A. Zeeb 	if (WARN(!bd_idx_addr, "only HCI with low power mode needs this\n"))
17838e93258fSBjoern A. Zeeb 		return;
17848e93258fSBjoern A. Zeeb 
17858e93258fSBjoern A. Zeeb 	for (i = 0; i < RTW89_TXCH_NUM; i++) {
17868e93258fSBjoern A. Zeeb 		tx_ring = &rtwpci->tx_rings[i];
17878e93258fSBjoern A. Zeeb 		tx_ring->bd_ring.addr.idx = low_power ?
17888e93258fSBjoern A. Zeeb 					    bd_idx_addr->tx_bd_addrs[i] :
17898e93258fSBjoern A. Zeeb 					    dma_addr_set->tx[i].idx;
17908e93258fSBjoern A. Zeeb 	}
17918e93258fSBjoern A. Zeeb 
17928e93258fSBjoern A. Zeeb 	for (i = 0; i < RTW89_RXCH_NUM; i++) {
17938e93258fSBjoern A. Zeeb 		rx_ring = &rtwpci->rx_rings[i];
17948e93258fSBjoern A. Zeeb 		rx_ring->bd_ring.addr.idx = low_power ?
17958e93258fSBjoern A. Zeeb 					    bd_idx_addr->rx_bd_addrs[i] :
17968e93258fSBjoern A. Zeeb 					    dma_addr_set->rx[i].idx;
17978e93258fSBjoern A. Zeeb 	}
17988e93258fSBjoern A. Zeeb }
17998e93258fSBjoern A. Zeeb 
18008e93258fSBjoern A. Zeeb static void rtw89_pci_ops_switch_mode(struct rtw89_dev *rtwdev, bool low_power)
18018e93258fSBjoern A. Zeeb {
18028e93258fSBjoern A. Zeeb 	enum rtw89_pci_intr_mask_cfg cfg;
18038e93258fSBjoern A. Zeeb 
18048e93258fSBjoern A. Zeeb 	WARN(!rtwdev->hci.paused, "HCI isn't paused\n");
18058e93258fSBjoern A. Zeeb 
18068e93258fSBjoern A. Zeeb 	cfg = low_power ? RTW89_PCI_INTR_MASK_LOW_POWER : RTW89_PCI_INTR_MASK_NORMAL;
18078e93258fSBjoern A. Zeeb 	rtw89_chip_config_intr_mask(rtwdev, cfg);
18088e93258fSBjoern A. Zeeb 	rtw89_pci_switch_bd_idx_addr(rtwdev, low_power);
18098e93258fSBjoern A. Zeeb }
18108e93258fSBjoern A. Zeeb 
18118e93258fSBjoern A. Zeeb static void rtw89_pci_ops_write32(struct rtw89_dev *rtwdev, u32 addr, u32 data);
18128e93258fSBjoern A. Zeeb 
18138e93258fSBjoern A. Zeeb static u32 rtw89_pci_ops_read32_cmac(struct rtw89_dev *rtwdev, u32 addr)
18148e93258fSBjoern A. Zeeb {
18158e93258fSBjoern A. Zeeb 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
18168e93258fSBjoern A. Zeeb #if defined(__linux__)
18178e93258fSBjoern A. Zeeb 	u32 val = readl(rtwpci->mmap + addr);
18188e93258fSBjoern A. Zeeb #elif defined(__FreeBSD__)
18198e93258fSBjoern A. Zeeb 	u32 val;
18208e93258fSBjoern A. Zeeb 
18218e93258fSBjoern A. Zeeb 	val = bus_read_4((struct resource *)rtwpci->mmap, addr);
18228e93258fSBjoern A. Zeeb 	rtw89_debug(rtwdev, RTW89_DBG_IO_RW, "R32 (%#010x) -> %#010x\n", addr, val);
18238e93258fSBjoern A. Zeeb #endif
18248e93258fSBjoern A. Zeeb 	int count;
18258e93258fSBjoern A. Zeeb 
18268e93258fSBjoern A. Zeeb 	for (count = 0; ; count++) {
18278e93258fSBjoern A. Zeeb 		if (val != RTW89_R32_DEAD)
18288e93258fSBjoern A. Zeeb 			return val;
18298e93258fSBjoern A. Zeeb 		if (count >= MAC_REG_POOL_COUNT) {
18308e93258fSBjoern A. Zeeb 			rtw89_warn(rtwdev, "addr %#x = %#x\n", addr, val);
18318e93258fSBjoern A. Zeeb 			return RTW89_R32_DEAD;
18328e93258fSBjoern A. Zeeb 		}
18338e93258fSBjoern A. Zeeb 		rtw89_pci_ops_write32(rtwdev, R_AX_CK_EN, B_AX_CMAC_ALLCKEN);
18348e93258fSBjoern A. Zeeb #if defined(__linux__)
18358e93258fSBjoern A. Zeeb 		val = readl(rtwpci->mmap + addr);
18368e93258fSBjoern A. Zeeb #elif defined(__FreeBSD__)
18378e93258fSBjoern A. Zeeb 		val = bus_read_4((struct resource *)rtwpci->mmap, addr);
18388e93258fSBjoern A. Zeeb 		rtw89_debug(rtwdev, RTW89_DBG_IO_RW, "R32 (%#010x) -> %#010x\n", addr, val);
18398e93258fSBjoern A. Zeeb #endif
18408e93258fSBjoern A. Zeeb 	}
18418e93258fSBjoern A. Zeeb 
18428e93258fSBjoern A. Zeeb 	return val;
18438e93258fSBjoern A. Zeeb }
18448e93258fSBjoern A. Zeeb 
18458e93258fSBjoern A. Zeeb static u8 rtw89_pci_ops_read8(struct rtw89_dev *rtwdev, u32 addr)
18468e93258fSBjoern A. Zeeb {
18478e93258fSBjoern A. Zeeb 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
18488e93258fSBjoern A. Zeeb 	u32 addr32, val32, shift;
18498e93258fSBjoern A. Zeeb 
18508e93258fSBjoern A. Zeeb 	if (!ACCESS_CMAC(addr))
18518e93258fSBjoern A. Zeeb #if defined(__linux__)
18528e93258fSBjoern A. Zeeb 		return readb(rtwpci->mmap + addr);
18538e93258fSBjoern A. Zeeb #elif defined(__FreeBSD__)
18548e93258fSBjoern A. Zeeb 	{
18558e93258fSBjoern A. Zeeb 		u8 val;
18568e93258fSBjoern A. Zeeb 
18578e93258fSBjoern A. Zeeb 		val = bus_read_1((struct resource *)rtwpci->mmap, addr);
18588e93258fSBjoern A. Zeeb 		rtw89_debug(rtwdev, RTW89_DBG_IO_RW, "R08 (%#010x) -> %#04x\n", addr, val);
18598e93258fSBjoern A. Zeeb 		return (val);
18608e93258fSBjoern A. Zeeb 	}
18618e93258fSBjoern A. Zeeb #endif
18628e93258fSBjoern A. Zeeb 
18638e93258fSBjoern A. Zeeb 	addr32 = addr & ~0x3;
18648e93258fSBjoern A. Zeeb 	shift = (addr & 0x3) * 8;
18658e93258fSBjoern A. Zeeb 	val32 = rtw89_pci_ops_read32_cmac(rtwdev, addr32);
18668e93258fSBjoern A. Zeeb 	return val32 >> shift;
18678e93258fSBjoern A. Zeeb }
18688e93258fSBjoern A. Zeeb 
18698e93258fSBjoern A. Zeeb static u16 rtw89_pci_ops_read16(struct rtw89_dev *rtwdev, u32 addr)
18708e93258fSBjoern A. Zeeb {
18718e93258fSBjoern A. Zeeb 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
18728e93258fSBjoern A. Zeeb 	u32 addr32, val32, shift;
18738e93258fSBjoern A. Zeeb 
18748e93258fSBjoern A. Zeeb 	if (!ACCESS_CMAC(addr))
18758e93258fSBjoern A. Zeeb #if defined(__linux__)
18768e93258fSBjoern A. Zeeb 		return readw(rtwpci->mmap + addr);
18778e93258fSBjoern A. Zeeb #elif defined(__FreeBSD__)
18788e93258fSBjoern A. Zeeb 	{
18798e93258fSBjoern A. Zeeb 		u16 val;
18808e93258fSBjoern A. Zeeb 
18818e93258fSBjoern A. Zeeb 		val = bus_read_2((struct resource *)rtwpci->mmap, addr);
18828e93258fSBjoern A. Zeeb 		rtw89_debug(rtwdev, RTW89_DBG_IO_RW, "R16 (%#010x) -> %#06x\n", addr, val);
18838e93258fSBjoern A. Zeeb 		return (val);
18848e93258fSBjoern A. Zeeb 	}
18858e93258fSBjoern A. Zeeb #endif
18868e93258fSBjoern A. Zeeb 
18878e93258fSBjoern A. Zeeb 	addr32 = addr & ~0x3;
18888e93258fSBjoern A. Zeeb 	shift = (addr & 0x3) * 8;
18898e93258fSBjoern A. Zeeb 	val32 = rtw89_pci_ops_read32_cmac(rtwdev, addr32);
18908e93258fSBjoern A. Zeeb 	return val32 >> shift;
18918e93258fSBjoern A. Zeeb }
18928e93258fSBjoern A. Zeeb 
18938e93258fSBjoern A. Zeeb static u32 rtw89_pci_ops_read32(struct rtw89_dev *rtwdev, u32 addr)
18948e93258fSBjoern A. Zeeb {
18958e93258fSBjoern A. Zeeb 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
18968e93258fSBjoern A. Zeeb 
18978e93258fSBjoern A. Zeeb 	if (!ACCESS_CMAC(addr))
18988e93258fSBjoern A. Zeeb #if defined(__linux__)
18998e93258fSBjoern A. Zeeb 		return readl(rtwpci->mmap + addr);
19008e93258fSBjoern A. Zeeb #elif defined(__FreeBSD__)
19018e93258fSBjoern A. Zeeb 	{
19028e93258fSBjoern A. Zeeb 		u32 val;
19038e93258fSBjoern A. Zeeb 
19048e93258fSBjoern A. Zeeb 		val = bus_read_4((struct resource *)rtwpci->mmap, addr);
19058e93258fSBjoern A. Zeeb 		rtw89_debug(rtwdev, RTW89_DBG_IO_RW, "R32 (%#010x) -> %#010x\n", addr, val);
19068e93258fSBjoern A. Zeeb 		return (val);
19078e93258fSBjoern A. Zeeb 	}
19088e93258fSBjoern A. Zeeb #endif
19098e93258fSBjoern A. Zeeb 
19108e93258fSBjoern A. Zeeb 	return rtw89_pci_ops_read32_cmac(rtwdev, addr);
19118e93258fSBjoern A. Zeeb }
19128e93258fSBjoern A. Zeeb 
19138e93258fSBjoern A. Zeeb static void rtw89_pci_ops_write8(struct rtw89_dev *rtwdev, u32 addr, u8 data)
19148e93258fSBjoern A. Zeeb {
19158e93258fSBjoern A. Zeeb 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
19168e93258fSBjoern A. Zeeb 
19178e93258fSBjoern A. Zeeb #if defined(__linux__)
19188e93258fSBjoern A. Zeeb 	writeb(data, rtwpci->mmap + addr);
19198e93258fSBjoern A. Zeeb #elif defined(__FreeBSD__)
19208e93258fSBjoern A. Zeeb 	rtw89_debug(rtwdev, RTW89_DBG_IO_RW, "W08 (%#010x) <- %#04x\n", addr, data);
19218e93258fSBjoern A. Zeeb 	return (bus_write_1((struct resource *)rtwpci->mmap, addr, data));
19228e93258fSBjoern A. Zeeb #endif
19238e93258fSBjoern A. Zeeb }
19248e93258fSBjoern A. Zeeb 
19258e93258fSBjoern A. Zeeb static void rtw89_pci_ops_write16(struct rtw89_dev *rtwdev, u32 addr, u16 data)
19268e93258fSBjoern A. Zeeb {
19278e93258fSBjoern A. Zeeb 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
19288e93258fSBjoern A. Zeeb 
19298e93258fSBjoern A. Zeeb #if defined(__linux__)
19308e93258fSBjoern A. Zeeb 	writew(data, rtwpci->mmap + addr);
19318e93258fSBjoern A. Zeeb #elif defined(__FreeBSD__)
19328e93258fSBjoern A. Zeeb 	rtw89_debug(rtwdev, RTW89_DBG_IO_RW, "W16 (%#010x) <- %#06x\n", addr, data);
19338e93258fSBjoern A. Zeeb 	return (bus_write_2((struct resource *)rtwpci->mmap, addr, data));
19348e93258fSBjoern A. Zeeb #endif
19358e93258fSBjoern A. Zeeb }
19368e93258fSBjoern A. Zeeb 
19378e93258fSBjoern A. Zeeb static void rtw89_pci_ops_write32(struct rtw89_dev *rtwdev, u32 addr, u32 data)
19388e93258fSBjoern A. Zeeb {
19398e93258fSBjoern A. Zeeb 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
19408e93258fSBjoern A. Zeeb 
19418e93258fSBjoern A. Zeeb #if defined(__linux__)
19428e93258fSBjoern A. Zeeb 	writel(data, rtwpci->mmap + addr);
19438e93258fSBjoern A. Zeeb #elif defined(__FreeBSD__)
19448e93258fSBjoern A. Zeeb 	rtw89_debug(rtwdev, RTW89_DBG_IO_RW, "W32 (%#010x) <- %#010x\n", addr, data);
19458e93258fSBjoern A. Zeeb 	return (bus_write_4((struct resource *)rtwpci->mmap, addr, data));
19468e93258fSBjoern A. Zeeb #endif
19478e93258fSBjoern A. Zeeb }
19488e93258fSBjoern A. Zeeb 
1949e2340276SBjoern A. Zeeb static void rtw89_pci_ctrl_dma_trx(struct rtw89_dev *rtwdev, bool enable)
1950e2340276SBjoern A. Zeeb {
1951e2340276SBjoern A. Zeeb 	const struct rtw89_pci_info *info = rtwdev->pci_info;
1952e2340276SBjoern A. Zeeb 
1953e2340276SBjoern A. Zeeb 	if (enable)
1954e2340276SBjoern A. Zeeb 		rtw89_write32_set(rtwdev, info->init_cfg_reg,
1955e2340276SBjoern A. Zeeb 				  info->rxhci_en_bit | info->txhci_en_bit);
1956e2340276SBjoern A. Zeeb 	else
1957e2340276SBjoern A. Zeeb 		rtw89_write32_clr(rtwdev, info->init_cfg_reg,
1958e2340276SBjoern A. Zeeb 				  info->rxhci_en_bit | info->txhci_en_bit);
1959e2340276SBjoern A. Zeeb }
1960e2340276SBjoern A. Zeeb 
1961e2340276SBjoern A. Zeeb static void rtw89_pci_ctrl_dma_io(struct rtw89_dev *rtwdev, bool enable)
19628e93258fSBjoern A. Zeeb {
1963*6d67aabdSBjoern A. Zeeb 	const struct rtw89_pci_info *info = rtwdev->pci_info;
1964*6d67aabdSBjoern A. Zeeb 	const struct rtw89_reg_def *reg = &info->dma_io_stop;
1965e2340276SBjoern A. Zeeb 
1966e2340276SBjoern A. Zeeb 	if (enable)
1967*6d67aabdSBjoern A. Zeeb 		rtw89_write32_clr(rtwdev, reg->addr, reg->mask);
1968e2340276SBjoern A. Zeeb 	else
1969*6d67aabdSBjoern A. Zeeb 		rtw89_write32_set(rtwdev, reg->addr, reg->mask);
1970e2340276SBjoern A. Zeeb }
1971e2340276SBjoern A. Zeeb 
1972*6d67aabdSBjoern A. Zeeb void rtw89_pci_ctrl_dma_all(struct rtw89_dev *rtwdev, bool enable)
1973e2340276SBjoern A. Zeeb {
1974e2340276SBjoern A. Zeeb 	rtw89_pci_ctrl_dma_io(rtwdev, enable);
1975e2340276SBjoern A. Zeeb 	rtw89_pci_ctrl_dma_trx(rtwdev, enable);
19768e93258fSBjoern A. Zeeb }
19778e93258fSBjoern A. Zeeb 
19788e93258fSBjoern A. Zeeb static int rtw89_pci_check_mdio(struct rtw89_dev *rtwdev, u8 addr, u8 speed, u16 rw_bit)
19798e93258fSBjoern A. Zeeb {
19808e93258fSBjoern A. Zeeb 	u16 val;
19818e93258fSBjoern A. Zeeb 
19828e93258fSBjoern A. Zeeb 	rtw89_write8(rtwdev, R_AX_MDIO_CFG, addr & 0x1F);
19838e93258fSBjoern A. Zeeb 
19848e93258fSBjoern A. Zeeb 	val = rtw89_read16(rtwdev, R_AX_MDIO_CFG);
19858e93258fSBjoern A. Zeeb 	switch (speed) {
19868e93258fSBjoern A. Zeeb 	case PCIE_PHY_GEN1:
19878e93258fSBjoern A. Zeeb 		if (addr < 0x20)
19888e93258fSBjoern A. Zeeb 			val = u16_replace_bits(val, MDIO_PG0_G1, B_AX_MDIO_PHY_ADDR_MASK);
19898e93258fSBjoern A. Zeeb 		else
19908e93258fSBjoern A. Zeeb 			val = u16_replace_bits(val, MDIO_PG1_G1, B_AX_MDIO_PHY_ADDR_MASK);
19918e93258fSBjoern A. Zeeb 		break;
19928e93258fSBjoern A. Zeeb 	case PCIE_PHY_GEN2:
19938e93258fSBjoern A. Zeeb 		if (addr < 0x20)
19948e93258fSBjoern A. Zeeb 			val = u16_replace_bits(val, MDIO_PG0_G2, B_AX_MDIO_PHY_ADDR_MASK);
19958e93258fSBjoern A. Zeeb 		else
19968e93258fSBjoern A. Zeeb 			val = u16_replace_bits(val, MDIO_PG1_G2, B_AX_MDIO_PHY_ADDR_MASK);
19978e93258fSBjoern A. Zeeb 		break;
19988e93258fSBjoern A. Zeeb 	default:
19998e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "[ERR]Error Speed %d!\n", speed);
20008e93258fSBjoern A. Zeeb 		return -EINVAL;
20018e93258fSBjoern A. Zeeb 	}
20028e93258fSBjoern A. Zeeb 	rtw89_write16(rtwdev, R_AX_MDIO_CFG, val);
20038e93258fSBjoern A. Zeeb 	rtw89_write16_set(rtwdev, R_AX_MDIO_CFG, rw_bit);
20048e93258fSBjoern A. Zeeb 
20058e93258fSBjoern A. Zeeb 	return read_poll_timeout(rtw89_read16, val, !(val & rw_bit), 10, 2000,
20068e93258fSBjoern A. Zeeb 				 false, rtwdev, R_AX_MDIO_CFG);
20078e93258fSBjoern A. Zeeb }
20088e93258fSBjoern A. Zeeb 
20098e93258fSBjoern A. Zeeb static int
20108e93258fSBjoern A. Zeeb rtw89_read16_mdio(struct rtw89_dev *rtwdev, u8 addr, u8 speed, u16 *val)
20118e93258fSBjoern A. Zeeb {
20128e93258fSBjoern A. Zeeb 	int ret;
20138e93258fSBjoern A. Zeeb 
20148e93258fSBjoern A. Zeeb 	ret = rtw89_pci_check_mdio(rtwdev, addr, speed, B_AX_MDIO_RFLAG);
20158e93258fSBjoern A. Zeeb 	if (ret) {
20168e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "[ERR]MDIO R16 0x%X fail ret=%d!\n", addr, ret);
20178e93258fSBjoern A. Zeeb 		return ret;
20188e93258fSBjoern A. Zeeb 	}
20198e93258fSBjoern A. Zeeb 	*val = rtw89_read16(rtwdev, R_AX_MDIO_RDATA);
20208e93258fSBjoern A. Zeeb 
20218e93258fSBjoern A. Zeeb 	return 0;
20228e93258fSBjoern A. Zeeb }
20238e93258fSBjoern A. Zeeb 
20248e93258fSBjoern A. Zeeb static int
20258e93258fSBjoern A. Zeeb rtw89_write16_mdio(struct rtw89_dev *rtwdev, u8 addr, u16 data, u8 speed)
20268e93258fSBjoern A. Zeeb {
20278e93258fSBjoern A. Zeeb 	int ret;
20288e93258fSBjoern A. Zeeb 
20298e93258fSBjoern A. Zeeb 	rtw89_write16(rtwdev, R_AX_MDIO_WDATA, data);
20308e93258fSBjoern A. Zeeb 	ret = rtw89_pci_check_mdio(rtwdev, addr, speed, B_AX_MDIO_WFLAG);
20318e93258fSBjoern A. Zeeb 	if (ret) {
20328e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "[ERR]MDIO W16 0x%X = %x fail ret=%d!\n", addr, data, ret);
20338e93258fSBjoern A. Zeeb 		return ret;
20348e93258fSBjoern A. Zeeb 	}
20358e93258fSBjoern A. Zeeb 
20368e93258fSBjoern A. Zeeb 	return 0;
20378e93258fSBjoern A. Zeeb }
20388e93258fSBjoern A. Zeeb 
20398e93258fSBjoern A. Zeeb static int
20408e93258fSBjoern A. Zeeb rtw89_write16_mdio_mask(struct rtw89_dev *rtwdev, u8 addr, u16 mask, u16 data, u8 speed)
20418e93258fSBjoern A. Zeeb {
20428e93258fSBjoern A. Zeeb 	u32 shift;
20438e93258fSBjoern A. Zeeb 	int ret;
20448e93258fSBjoern A. Zeeb 	u16 val;
20458e93258fSBjoern A. Zeeb 
20468e93258fSBjoern A. Zeeb 	ret = rtw89_read16_mdio(rtwdev, addr, speed, &val);
20478e93258fSBjoern A. Zeeb 	if (ret)
20488e93258fSBjoern A. Zeeb 		return ret;
20498e93258fSBjoern A. Zeeb 
20508e93258fSBjoern A. Zeeb 	shift = __ffs(mask);
20518e93258fSBjoern A. Zeeb 	val &= ~mask;
20528e93258fSBjoern A. Zeeb 	val |= ((data << shift) & mask);
20538e93258fSBjoern A. Zeeb 
20548e93258fSBjoern A. Zeeb 	ret = rtw89_write16_mdio(rtwdev, addr, val, speed);
20558e93258fSBjoern A. Zeeb 	if (ret)
20568e93258fSBjoern A. Zeeb 		return ret;
20578e93258fSBjoern A. Zeeb 
20588e93258fSBjoern A. Zeeb 	return 0;
20598e93258fSBjoern A. Zeeb }
20608e93258fSBjoern A. Zeeb 
20618e93258fSBjoern A. Zeeb static int rtw89_write16_mdio_set(struct rtw89_dev *rtwdev, u8 addr, u16 mask, u8 speed)
20628e93258fSBjoern A. Zeeb {
20638e93258fSBjoern A. Zeeb 	int ret;
20648e93258fSBjoern A. Zeeb 	u16 val;
20658e93258fSBjoern A. Zeeb 
20668e93258fSBjoern A. Zeeb 	ret = rtw89_read16_mdio(rtwdev, addr, speed, &val);
20678e93258fSBjoern A. Zeeb 	if (ret)
20688e93258fSBjoern A. Zeeb 		return ret;
20698e93258fSBjoern A. Zeeb 	ret = rtw89_write16_mdio(rtwdev, addr, val | mask, speed);
20708e93258fSBjoern A. Zeeb 	if (ret)
20718e93258fSBjoern A. Zeeb 		return ret;
20728e93258fSBjoern A. Zeeb 
20738e93258fSBjoern A. Zeeb 	return 0;
20748e93258fSBjoern A. Zeeb }
20758e93258fSBjoern A. Zeeb 
20768e93258fSBjoern A. Zeeb static int rtw89_write16_mdio_clr(struct rtw89_dev *rtwdev, u8 addr, u16 mask, u8 speed)
20778e93258fSBjoern A. Zeeb {
20788e93258fSBjoern A. Zeeb 	int ret;
20798e93258fSBjoern A. Zeeb 	u16 val;
20808e93258fSBjoern A. Zeeb 
20818e93258fSBjoern A. Zeeb 	ret = rtw89_read16_mdio(rtwdev, addr, speed, &val);
20828e93258fSBjoern A. Zeeb 	if (ret)
20838e93258fSBjoern A. Zeeb 		return ret;
20848e93258fSBjoern A. Zeeb 	ret = rtw89_write16_mdio(rtwdev, addr, val & ~mask, speed);
20858e93258fSBjoern A. Zeeb 	if (ret)
20868e93258fSBjoern A. Zeeb 		return ret;
20878e93258fSBjoern A. Zeeb 
20888e93258fSBjoern A. Zeeb 	return 0;
20898e93258fSBjoern A. Zeeb }
20908e93258fSBjoern A. Zeeb 
2091*6d67aabdSBjoern A. Zeeb static int rtw89_dbi_write8(struct rtw89_dev *rtwdev, u16 addr, u8 data)
2092*6d67aabdSBjoern A. Zeeb {
2093*6d67aabdSBjoern A. Zeeb 	u16 addr_2lsb = addr & B_AX_DBI_2LSB;
2094*6d67aabdSBjoern A. Zeeb 	u16 write_addr;
2095*6d67aabdSBjoern A. Zeeb 	u8 flag;
2096*6d67aabdSBjoern A. Zeeb 	int ret;
2097*6d67aabdSBjoern A. Zeeb 
2098*6d67aabdSBjoern A. Zeeb 	write_addr = addr & B_AX_DBI_ADDR_MSK;
2099*6d67aabdSBjoern A. Zeeb 	write_addr |= u16_encode_bits(BIT(addr_2lsb), B_AX_DBI_WREN_MSK);
2100*6d67aabdSBjoern A. Zeeb 	rtw89_write8(rtwdev, R_AX_DBI_WDATA + addr_2lsb, data);
2101*6d67aabdSBjoern A. Zeeb 	rtw89_write16(rtwdev, R_AX_DBI_FLAG, write_addr);
2102*6d67aabdSBjoern A. Zeeb 	rtw89_write8(rtwdev, R_AX_DBI_FLAG + 2, B_AX_DBI_WFLAG >> 16);
2103*6d67aabdSBjoern A. Zeeb 
2104*6d67aabdSBjoern A. Zeeb 	ret = read_poll_timeout_atomic(rtw89_read8, flag, !flag, 10,
2105*6d67aabdSBjoern A. Zeeb 				       10 * RTW89_PCI_WR_RETRY_CNT, false,
2106*6d67aabdSBjoern A. Zeeb 				       rtwdev, R_AX_DBI_FLAG + 2);
2107*6d67aabdSBjoern A. Zeeb 	if (ret)
2108*6d67aabdSBjoern A. Zeeb 		rtw89_err(rtwdev, "failed to write DBI register, addr=0x%X\n",
2109*6d67aabdSBjoern A. Zeeb 			  addr);
2110*6d67aabdSBjoern A. Zeeb 
2111*6d67aabdSBjoern A. Zeeb 	return ret;
2112*6d67aabdSBjoern A. Zeeb }
2113*6d67aabdSBjoern A. Zeeb 
2114*6d67aabdSBjoern A. Zeeb static int rtw89_dbi_read8(struct rtw89_dev *rtwdev, u16 addr, u8 *value)
2115*6d67aabdSBjoern A. Zeeb {
2116*6d67aabdSBjoern A. Zeeb 	u16 read_addr = addr & B_AX_DBI_ADDR_MSK;
2117*6d67aabdSBjoern A. Zeeb 	u8 flag;
2118*6d67aabdSBjoern A. Zeeb 	int ret;
2119*6d67aabdSBjoern A. Zeeb 
2120*6d67aabdSBjoern A. Zeeb 	rtw89_write16(rtwdev, R_AX_DBI_FLAG, read_addr);
2121*6d67aabdSBjoern A. Zeeb 	rtw89_write8(rtwdev, R_AX_DBI_FLAG + 2, B_AX_DBI_RFLAG >> 16);
2122*6d67aabdSBjoern A. Zeeb 
2123*6d67aabdSBjoern A. Zeeb 	ret = read_poll_timeout_atomic(rtw89_read8, flag, !flag, 10,
2124*6d67aabdSBjoern A. Zeeb 				       10 * RTW89_PCI_WR_RETRY_CNT, false,
2125*6d67aabdSBjoern A. Zeeb 				       rtwdev, R_AX_DBI_FLAG + 2);
2126*6d67aabdSBjoern A. Zeeb 	if (ret) {
2127*6d67aabdSBjoern A. Zeeb 		rtw89_err(rtwdev, "failed to read DBI register, addr=0x%X\n",
2128*6d67aabdSBjoern A. Zeeb 			  addr);
2129*6d67aabdSBjoern A. Zeeb 		return ret;
2130*6d67aabdSBjoern A. Zeeb 	}
2131*6d67aabdSBjoern A. Zeeb 
2132*6d67aabdSBjoern A. Zeeb 	read_addr = R_AX_DBI_RDATA + (addr & 3);
2133*6d67aabdSBjoern A. Zeeb 	*value = rtw89_read8(rtwdev, read_addr);
2134*6d67aabdSBjoern A. Zeeb 
2135*6d67aabdSBjoern A. Zeeb 	return 0;
2136*6d67aabdSBjoern A. Zeeb }
2137*6d67aabdSBjoern A. Zeeb 
21388e93258fSBjoern A. Zeeb static int rtw89_pci_write_config_byte(struct rtw89_dev *rtwdev, u16 addr,
21398e93258fSBjoern A. Zeeb 				       u8 data)
21408e93258fSBjoern A. Zeeb {
21418e93258fSBjoern A. Zeeb 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
2142*6d67aabdSBjoern A. Zeeb 	enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id;
21438e93258fSBjoern A. Zeeb 	struct pci_dev *pdev = rtwpci->pdev;
2144*6d67aabdSBjoern A. Zeeb 	int ret;
21458e93258fSBjoern A. Zeeb 
2146*6d67aabdSBjoern A. Zeeb 	ret = pci_write_config_byte(pdev, addr, data);
2147*6d67aabdSBjoern A. Zeeb 	if (!ret)
2148*6d67aabdSBjoern A. Zeeb 		return 0;
2149*6d67aabdSBjoern A. Zeeb 
2150*6d67aabdSBjoern A. Zeeb 	if (chip_id == RTL8852A || rtw89_is_rtl885xb(rtwdev))
2151*6d67aabdSBjoern A. Zeeb 		ret = rtw89_dbi_write8(rtwdev, addr, data);
2152*6d67aabdSBjoern A. Zeeb 
2153*6d67aabdSBjoern A. Zeeb 	return ret;
21548e93258fSBjoern A. Zeeb }
21558e93258fSBjoern A. Zeeb 
21568e93258fSBjoern A. Zeeb static int rtw89_pci_read_config_byte(struct rtw89_dev *rtwdev, u16 addr,
21578e93258fSBjoern A. Zeeb 				      u8 *value)
21588e93258fSBjoern A. Zeeb {
21598e93258fSBjoern A. Zeeb 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
2160*6d67aabdSBjoern A. Zeeb 	enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id;
21618e93258fSBjoern A. Zeeb 	struct pci_dev *pdev = rtwpci->pdev;
2162*6d67aabdSBjoern A. Zeeb 	int ret;
21638e93258fSBjoern A. Zeeb 
2164*6d67aabdSBjoern A. Zeeb 	ret = pci_read_config_byte(pdev, addr, value);
2165*6d67aabdSBjoern A. Zeeb 	if (!ret)
2166*6d67aabdSBjoern A. Zeeb 		return 0;
2167*6d67aabdSBjoern A. Zeeb 
2168*6d67aabdSBjoern A. Zeeb 	if (chip_id == RTL8852A || rtw89_is_rtl885xb(rtwdev))
2169*6d67aabdSBjoern A. Zeeb 		ret = rtw89_dbi_read8(rtwdev, addr, value);
2170*6d67aabdSBjoern A. Zeeb 
2171*6d67aabdSBjoern A. Zeeb 	return ret;
21728e93258fSBjoern A. Zeeb }
21738e93258fSBjoern A. Zeeb 
21748e93258fSBjoern A. Zeeb static int rtw89_pci_config_byte_set(struct rtw89_dev *rtwdev, u16 addr,
21758e93258fSBjoern A. Zeeb 				     u8 bit)
21768e93258fSBjoern A. Zeeb {
21778e93258fSBjoern A. Zeeb 	u8 value;
21788e93258fSBjoern A. Zeeb 	int ret;
21798e93258fSBjoern A. Zeeb 
21808e93258fSBjoern A. Zeeb 	ret = rtw89_pci_read_config_byte(rtwdev, addr, &value);
21818e93258fSBjoern A. Zeeb 	if (ret)
21828e93258fSBjoern A. Zeeb 		return ret;
21838e93258fSBjoern A. Zeeb 
21848e93258fSBjoern A. Zeeb 	value |= bit;
21858e93258fSBjoern A. Zeeb 	ret = rtw89_pci_write_config_byte(rtwdev, addr, value);
21868e93258fSBjoern A. Zeeb 
21878e93258fSBjoern A. Zeeb 	return ret;
21888e93258fSBjoern A. Zeeb }
21898e93258fSBjoern A. Zeeb 
21908e93258fSBjoern A. Zeeb static int rtw89_pci_config_byte_clr(struct rtw89_dev *rtwdev, u16 addr,
21918e93258fSBjoern A. Zeeb 				     u8 bit)
21928e93258fSBjoern A. Zeeb {
21938e93258fSBjoern A. Zeeb 	u8 value;
21948e93258fSBjoern A. Zeeb 	int ret;
21958e93258fSBjoern A. Zeeb 
21968e93258fSBjoern A. Zeeb 	ret = rtw89_pci_read_config_byte(rtwdev, addr, &value);
21978e93258fSBjoern A. Zeeb 	if (ret)
21988e93258fSBjoern A. Zeeb 		return ret;
21998e93258fSBjoern A. Zeeb 
22008e93258fSBjoern A. Zeeb 	value &= ~bit;
22018e93258fSBjoern A. Zeeb 	ret = rtw89_pci_write_config_byte(rtwdev, addr, value);
22028e93258fSBjoern A. Zeeb 
22038e93258fSBjoern A. Zeeb 	return ret;
22048e93258fSBjoern A. Zeeb }
22058e93258fSBjoern A. Zeeb 
22068e93258fSBjoern A. Zeeb static int
22078e93258fSBjoern A. Zeeb __get_target(struct rtw89_dev *rtwdev, u16 *target, enum rtw89_pcie_phy phy_rate)
22088e93258fSBjoern A. Zeeb {
22098e93258fSBjoern A. Zeeb 	u16 val, tar;
22108e93258fSBjoern A. Zeeb 	int ret;
22118e93258fSBjoern A. Zeeb 
22128e93258fSBjoern A. Zeeb 	/* Enable counter */
22138e93258fSBjoern A. Zeeb 	ret = rtw89_read16_mdio(rtwdev, RAC_CTRL_PPR_V1, phy_rate, &val);
22148e93258fSBjoern A. Zeeb 	if (ret)
22158e93258fSBjoern A. Zeeb 		return ret;
22168e93258fSBjoern A. Zeeb 	ret = rtw89_write16_mdio(rtwdev, RAC_CTRL_PPR_V1, val & ~B_AX_CLK_CALIB_EN,
22178e93258fSBjoern A. Zeeb 				 phy_rate);
22188e93258fSBjoern A. Zeeb 	if (ret)
22198e93258fSBjoern A. Zeeb 		return ret;
22208e93258fSBjoern A. Zeeb 	ret = rtw89_write16_mdio(rtwdev, RAC_CTRL_PPR_V1, val | B_AX_CLK_CALIB_EN,
22218e93258fSBjoern A. Zeeb 				 phy_rate);
22228e93258fSBjoern A. Zeeb 	if (ret)
22238e93258fSBjoern A. Zeeb 		return ret;
22248e93258fSBjoern A. Zeeb 
22258e93258fSBjoern A. Zeeb 	fsleep(300);
22268e93258fSBjoern A. Zeeb 
22278e93258fSBjoern A. Zeeb 	ret = rtw89_read16_mdio(rtwdev, RAC_CTRL_PPR_V1, phy_rate, &tar);
22288e93258fSBjoern A. Zeeb 	if (ret)
22298e93258fSBjoern A. Zeeb 		return ret;
22308e93258fSBjoern A. Zeeb 	ret = rtw89_write16_mdio(rtwdev, RAC_CTRL_PPR_V1, val & ~B_AX_CLK_CALIB_EN,
22318e93258fSBjoern A. Zeeb 				 phy_rate);
22328e93258fSBjoern A. Zeeb 	if (ret)
22338e93258fSBjoern A. Zeeb 		return ret;
22348e93258fSBjoern A. Zeeb 
22358e93258fSBjoern A. Zeeb 	tar = tar & 0x0FFF;
22368e93258fSBjoern A. Zeeb 	if (tar == 0 || tar == 0x0FFF) {
22378e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "[ERR]Get target failed.\n");
22388e93258fSBjoern A. Zeeb 		return -EINVAL;
22398e93258fSBjoern A. Zeeb 	}
22408e93258fSBjoern A. Zeeb 
22418e93258fSBjoern A. Zeeb 	*target = tar;
22428e93258fSBjoern A. Zeeb 
22438e93258fSBjoern A. Zeeb 	return 0;
22448e93258fSBjoern A. Zeeb }
22458e93258fSBjoern A. Zeeb 
2246e2340276SBjoern A. Zeeb static int rtw89_pci_autok_x(struct rtw89_dev *rtwdev)
2247e2340276SBjoern A. Zeeb {
2248e2340276SBjoern A. Zeeb 	int ret;
2249e2340276SBjoern A. Zeeb 
2250*6d67aabdSBjoern A. Zeeb 	if (!rtw89_is_rtl885xb(rtwdev))
2251e2340276SBjoern A. Zeeb 		return 0;
2252e2340276SBjoern A. Zeeb 
2253e2340276SBjoern A. Zeeb 	ret = rtw89_write16_mdio_mask(rtwdev, RAC_REG_FLD_0, BAC_AUTOK_N_MASK,
2254e2340276SBjoern A. Zeeb 				      PCIE_AUTOK_4, PCIE_PHY_GEN1);
2255e2340276SBjoern A. Zeeb 	return ret;
2256e2340276SBjoern A. Zeeb }
2257e2340276SBjoern A. Zeeb 
22588e93258fSBjoern A. Zeeb static int rtw89_pci_auto_refclk_cal(struct rtw89_dev *rtwdev, bool autook_en)
22598e93258fSBjoern A. Zeeb {
22608e93258fSBjoern A. Zeeb 	enum rtw89_pcie_phy phy_rate;
22618e93258fSBjoern A. Zeeb 	u16 val16, mgn_set, div_set, tar;
22628e93258fSBjoern A. Zeeb 	u8 val8, bdr_ori;
22638e93258fSBjoern A. Zeeb 	bool l1_flag = false;
22648e93258fSBjoern A. Zeeb 	int ret = 0;
22658e93258fSBjoern A. Zeeb 
2266*6d67aabdSBjoern A. Zeeb 	if (!rtw89_is_rtl885xb(rtwdev))
22678e93258fSBjoern A. Zeeb 		return 0;
22688e93258fSBjoern A. Zeeb 
22698e93258fSBjoern A. Zeeb 	ret = rtw89_pci_read_config_byte(rtwdev, RTW89_PCIE_PHY_RATE, &val8);
22708e93258fSBjoern A. Zeeb 	if (ret) {
22718e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "[ERR]pci config read %X\n",
22728e93258fSBjoern A. Zeeb 			  RTW89_PCIE_PHY_RATE);
22738e93258fSBjoern A. Zeeb 		return ret;
22748e93258fSBjoern A. Zeeb 	}
22758e93258fSBjoern A. Zeeb 
22768e93258fSBjoern A. Zeeb 	if (FIELD_GET(RTW89_PCIE_PHY_RATE_MASK, val8) == 0x1) {
22778e93258fSBjoern A. Zeeb 		phy_rate = PCIE_PHY_GEN1;
22788e93258fSBjoern A. Zeeb 	} else if (FIELD_GET(RTW89_PCIE_PHY_RATE_MASK, val8) == 0x2) {
22798e93258fSBjoern A. Zeeb 		phy_rate = PCIE_PHY_GEN2;
22808e93258fSBjoern A. Zeeb 	} else {
22818e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "[ERR]PCIe PHY rate %#x not support\n", val8);
22828e93258fSBjoern A. Zeeb 		return -EOPNOTSUPP;
22838e93258fSBjoern A. Zeeb 	}
22848e93258fSBjoern A. Zeeb 	/* Disable L1BD */
22858e93258fSBjoern A. Zeeb 	ret = rtw89_pci_read_config_byte(rtwdev, RTW89_PCIE_L1_CTRL, &bdr_ori);
22868e93258fSBjoern A. Zeeb 	if (ret) {
22878e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "[ERR]pci config read %X\n", RTW89_PCIE_L1_CTRL);
22888e93258fSBjoern A. Zeeb 		return ret;
22898e93258fSBjoern A. Zeeb 	}
22908e93258fSBjoern A. Zeeb 
22918e93258fSBjoern A. Zeeb 	if (bdr_ori & RTW89_PCIE_BIT_L1) {
22928e93258fSBjoern A. Zeeb 		ret = rtw89_pci_write_config_byte(rtwdev, RTW89_PCIE_L1_CTRL,
22938e93258fSBjoern A. Zeeb 						  bdr_ori & ~RTW89_PCIE_BIT_L1);
22948e93258fSBjoern A. Zeeb 		if (ret) {
22958e93258fSBjoern A. Zeeb 			rtw89_err(rtwdev, "[ERR]pci config write %X\n",
22968e93258fSBjoern A. Zeeb 				  RTW89_PCIE_L1_CTRL);
22978e93258fSBjoern A. Zeeb 			return ret;
22988e93258fSBjoern A. Zeeb 		}
22998e93258fSBjoern A. Zeeb 		l1_flag = true;
23008e93258fSBjoern A. Zeeb 	}
23018e93258fSBjoern A. Zeeb 
23028e93258fSBjoern A. Zeeb 	ret = rtw89_read16_mdio(rtwdev, RAC_CTRL_PPR_V1, phy_rate, &val16);
23038e93258fSBjoern A. Zeeb 	if (ret) {
23048e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "[ERR]mdio_r16_pcie %X\n", RAC_CTRL_PPR_V1);
23058e93258fSBjoern A. Zeeb 		goto end;
23068e93258fSBjoern A. Zeeb 	}
23078e93258fSBjoern A. Zeeb 
23088e93258fSBjoern A. Zeeb 	if (val16 & B_AX_CALIB_EN) {
23098e93258fSBjoern A. Zeeb 		ret = rtw89_write16_mdio(rtwdev, RAC_CTRL_PPR_V1,
23108e93258fSBjoern A. Zeeb 					 val16 & ~B_AX_CALIB_EN, phy_rate);
23118e93258fSBjoern A. Zeeb 		if (ret) {
23128e93258fSBjoern A. Zeeb 			rtw89_err(rtwdev, "[ERR]mdio_w16_pcie %X\n", RAC_CTRL_PPR_V1);
23138e93258fSBjoern A. Zeeb 			goto end;
23148e93258fSBjoern A. Zeeb 		}
23158e93258fSBjoern A. Zeeb 	}
23168e93258fSBjoern A. Zeeb 
23178e93258fSBjoern A. Zeeb 	if (!autook_en)
23188e93258fSBjoern A. Zeeb 		goto end;
23198e93258fSBjoern A. Zeeb 	/* Set div */
23208e93258fSBjoern A. Zeeb 	ret = rtw89_write16_mdio_clr(rtwdev, RAC_CTRL_PPR_V1, B_AX_DIV, phy_rate);
23218e93258fSBjoern A. Zeeb 	if (ret) {
23228e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "[ERR]mdio_w16_pcie %X\n", RAC_CTRL_PPR_V1);
23238e93258fSBjoern A. Zeeb 		goto end;
23248e93258fSBjoern A. Zeeb 	}
23258e93258fSBjoern A. Zeeb 
23268e93258fSBjoern A. Zeeb 	/* Obtain div and margin */
23278e93258fSBjoern A. Zeeb 	ret = __get_target(rtwdev, &tar, phy_rate);
23288e93258fSBjoern A. Zeeb 	if (ret) {
23298e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "[ERR]1st get target fail %d\n", ret);
23308e93258fSBjoern A. Zeeb 		goto end;
23318e93258fSBjoern A. Zeeb 	}
23328e93258fSBjoern A. Zeeb 
23338e93258fSBjoern A. Zeeb 	mgn_set = tar * INTF_INTGRA_HOSTREF_V1 / INTF_INTGRA_MINREF_V1 - tar;
23348e93258fSBjoern A. Zeeb 
23358e93258fSBjoern A. Zeeb 	if (mgn_set >= 128) {
23368e93258fSBjoern A. Zeeb 		div_set = 0x0003;
23378e93258fSBjoern A. Zeeb 		mgn_set = 0x000F;
23388e93258fSBjoern A. Zeeb 	} else if (mgn_set >= 64) {
23398e93258fSBjoern A. Zeeb 		div_set = 0x0003;
23408e93258fSBjoern A. Zeeb 		mgn_set >>= 3;
23418e93258fSBjoern A. Zeeb 	} else if (mgn_set >= 32) {
23428e93258fSBjoern A. Zeeb 		div_set = 0x0002;
23438e93258fSBjoern A. Zeeb 		mgn_set >>= 2;
23448e93258fSBjoern A. Zeeb 	} else if (mgn_set >= 16) {
23458e93258fSBjoern A. Zeeb 		div_set = 0x0001;
23468e93258fSBjoern A. Zeeb 		mgn_set >>= 1;
23478e93258fSBjoern A. Zeeb 	} else if (mgn_set == 0) {
23488e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "[ERR]cal mgn is 0,tar = %d\n", tar);
23498e93258fSBjoern A. Zeeb 		goto end;
23508e93258fSBjoern A. Zeeb 	} else {
23518e93258fSBjoern A. Zeeb 		div_set = 0x0000;
23528e93258fSBjoern A. Zeeb 	}
23538e93258fSBjoern A. Zeeb 
23548e93258fSBjoern A. Zeeb 	ret = rtw89_read16_mdio(rtwdev, RAC_CTRL_PPR_V1, phy_rate, &val16);
23558e93258fSBjoern A. Zeeb 	if (ret) {
23568e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "[ERR]mdio_r16_pcie %X\n", RAC_CTRL_PPR_V1);
23578e93258fSBjoern A. Zeeb 		goto end;
23588e93258fSBjoern A. Zeeb 	}
23598e93258fSBjoern A. Zeeb 
23608e93258fSBjoern A. Zeeb 	val16 |= u16_encode_bits(div_set, B_AX_DIV);
23618e93258fSBjoern A. Zeeb 
23628e93258fSBjoern A. Zeeb 	ret = rtw89_write16_mdio(rtwdev, RAC_CTRL_PPR_V1, val16, phy_rate);
23638e93258fSBjoern A. Zeeb 	if (ret) {
23648e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "[ERR]mdio_w16_pcie %X\n", RAC_CTRL_PPR_V1);
23658e93258fSBjoern A. Zeeb 		goto end;
23668e93258fSBjoern A. Zeeb 	}
23678e93258fSBjoern A. Zeeb 
23688e93258fSBjoern A. Zeeb 	ret = __get_target(rtwdev, &tar, phy_rate);
23698e93258fSBjoern A. Zeeb 	if (ret) {
23708e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "[ERR]2nd get target fail %d\n", ret);
23718e93258fSBjoern A. Zeeb 		goto end;
23728e93258fSBjoern A. Zeeb 	}
23738e93258fSBjoern A. Zeeb 
23748e93258fSBjoern A. Zeeb 	rtw89_debug(rtwdev, RTW89_DBG_HCI, "[TRACE]target = 0x%X, div = 0x%X, margin = 0x%X\n",
23758e93258fSBjoern A. Zeeb 		    tar, div_set, mgn_set);
23768e93258fSBjoern A. Zeeb 	ret = rtw89_write16_mdio(rtwdev, RAC_SET_PPR_V1,
23778e93258fSBjoern A. Zeeb 				 (tar & 0x0FFF) | (mgn_set << 12), phy_rate);
23788e93258fSBjoern A. Zeeb 	if (ret) {
23798e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "[ERR]mdio_w16_pcie %X\n", RAC_SET_PPR_V1);
23808e93258fSBjoern A. Zeeb 		goto end;
23818e93258fSBjoern A. Zeeb 	}
23828e93258fSBjoern A. Zeeb 
23838e93258fSBjoern A. Zeeb 	/* Enable function */
23848e93258fSBjoern A. Zeeb 	ret = rtw89_write16_mdio_set(rtwdev, RAC_CTRL_PPR_V1, B_AX_CALIB_EN, phy_rate);
23858e93258fSBjoern A. Zeeb 	if (ret) {
23868e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "[ERR]mdio_w16_pcie %X\n", RAC_CTRL_PPR_V1);
23878e93258fSBjoern A. Zeeb 		goto end;
23888e93258fSBjoern A. Zeeb 	}
23898e93258fSBjoern A. Zeeb 
23908e93258fSBjoern A. Zeeb 	/* CLK delay = 0 */
23918e93258fSBjoern A. Zeeb 	ret = rtw89_pci_write_config_byte(rtwdev, RTW89_PCIE_CLK_CTRL,
23928e93258fSBjoern A. Zeeb 					  PCIE_CLKDLY_HW_0);
23938e93258fSBjoern A. Zeeb 
23948e93258fSBjoern A. Zeeb end:
23958e93258fSBjoern A. Zeeb 	/* Set L1BD to ori */
23968e93258fSBjoern A. Zeeb 	if (l1_flag) {
23978e93258fSBjoern A. Zeeb 		ret = rtw89_pci_write_config_byte(rtwdev, RTW89_PCIE_L1_CTRL,
23988e93258fSBjoern A. Zeeb 						  bdr_ori);
23998e93258fSBjoern A. Zeeb 		if (ret) {
24008e93258fSBjoern A. Zeeb 			rtw89_err(rtwdev, "[ERR]pci config write %X\n",
24018e93258fSBjoern A. Zeeb 				  RTW89_PCIE_L1_CTRL);
24028e93258fSBjoern A. Zeeb 			return ret;
24038e93258fSBjoern A. Zeeb 		}
24048e93258fSBjoern A. Zeeb 	}
24058e93258fSBjoern A. Zeeb 
24068e93258fSBjoern A. Zeeb 	return ret;
24078e93258fSBjoern A. Zeeb }
24088e93258fSBjoern A. Zeeb 
24098e93258fSBjoern A. Zeeb static int rtw89_pci_deglitch_setting(struct rtw89_dev *rtwdev)
24108e93258fSBjoern A. Zeeb {
24118e93258fSBjoern A. Zeeb 	enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id;
24128e93258fSBjoern A. Zeeb 	int ret;
24138e93258fSBjoern A. Zeeb 
24148e93258fSBjoern A. Zeeb 	if (chip_id == RTL8852A) {
24158e93258fSBjoern A. Zeeb 		ret = rtw89_write16_mdio_clr(rtwdev, RAC_ANA24, B_AX_DEGLITCH,
24168e93258fSBjoern A. Zeeb 					     PCIE_PHY_GEN1);
24178e93258fSBjoern A. Zeeb 		if (ret)
24188e93258fSBjoern A. Zeeb 			return ret;
24198e93258fSBjoern A. Zeeb 		ret = rtw89_write16_mdio_clr(rtwdev, RAC_ANA24, B_AX_DEGLITCH,
24208e93258fSBjoern A. Zeeb 					     PCIE_PHY_GEN2);
24218e93258fSBjoern A. Zeeb 		if (ret)
24228e93258fSBjoern A. Zeeb 			return ret;
24238e93258fSBjoern A. Zeeb 	} else if (chip_id == RTL8852C) {
24248e93258fSBjoern A. Zeeb 		rtw89_write16_clr(rtwdev, R_RAC_DIRECT_OFFSET_G1 + RAC_ANA24 * 2,
24258e93258fSBjoern A. Zeeb 				  B_AX_DEGLITCH);
24268e93258fSBjoern A. Zeeb 		rtw89_write16_clr(rtwdev, R_RAC_DIRECT_OFFSET_G2 + RAC_ANA24 * 2,
24278e93258fSBjoern A. Zeeb 				  B_AX_DEGLITCH);
24288e93258fSBjoern A. Zeeb 	}
24298e93258fSBjoern A. Zeeb 
24308e93258fSBjoern A. Zeeb 	return 0;
24318e93258fSBjoern A. Zeeb }
24328e93258fSBjoern A. Zeeb 
2433*6d67aabdSBjoern A. Zeeb static void rtw89_pci_disable_eq(struct rtw89_dev *rtwdev)
2434*6d67aabdSBjoern A. Zeeb {
2435*6d67aabdSBjoern A. Zeeb 	u16 g1_oobs, g2_oobs;
2436*6d67aabdSBjoern A. Zeeb 	u32 backup_aspm;
2437*6d67aabdSBjoern A. Zeeb 	u32 phy_offset;
2438*6d67aabdSBjoern A. Zeeb 	u16 oobs_val;
2439*6d67aabdSBjoern A. Zeeb 	int ret;
2440*6d67aabdSBjoern A. Zeeb 
2441*6d67aabdSBjoern A. Zeeb 	if (rtwdev->chip->chip_id != RTL8852C)
2442*6d67aabdSBjoern A. Zeeb 		return;
2443*6d67aabdSBjoern A. Zeeb 
2444*6d67aabdSBjoern A. Zeeb 	g1_oobs = rtw89_read16_mask(rtwdev, R_RAC_DIRECT_OFFSET_G1 +
2445*6d67aabdSBjoern A. Zeeb 					    RAC_ANA09 * RAC_MULT, BAC_OOBS_SEL);
2446*6d67aabdSBjoern A. Zeeb 	g2_oobs = rtw89_read16_mask(rtwdev, R_RAC_DIRECT_OFFSET_G2 +
2447*6d67aabdSBjoern A. Zeeb 					    RAC_ANA09 * RAC_MULT, BAC_OOBS_SEL);
2448*6d67aabdSBjoern A. Zeeb 	if (g1_oobs && g2_oobs)
2449*6d67aabdSBjoern A. Zeeb 		return;
2450*6d67aabdSBjoern A. Zeeb 
2451*6d67aabdSBjoern A. Zeeb 	backup_aspm = rtw89_read32(rtwdev, R_AX_PCIE_MIX_CFG_V1);
2452*6d67aabdSBjoern A. Zeeb 	rtw89_write32_clr(rtwdev, R_AX_PCIE_MIX_CFG_V1, B_AX_ASPM_CTRL_MASK);
2453*6d67aabdSBjoern A. Zeeb 
2454*6d67aabdSBjoern A. Zeeb 	ret = rtw89_pci_get_phy_offset_by_link_speed(rtwdev, &phy_offset);
2455*6d67aabdSBjoern A. Zeeb 	if (ret)
2456*6d67aabdSBjoern A. Zeeb 		goto out;
2457*6d67aabdSBjoern A. Zeeb 
2458*6d67aabdSBjoern A. Zeeb 	rtw89_write16_set(rtwdev, phy_offset + RAC_ANA0D * RAC_MULT, BAC_RX_TEST_EN);
2459*6d67aabdSBjoern A. Zeeb 	rtw89_write16(rtwdev, phy_offset + RAC_ANA10 * RAC_MULT, ADDR_SEL_PINOUT_DIS_VAL);
2460*6d67aabdSBjoern A. Zeeb 	rtw89_write16_set(rtwdev, phy_offset + RAC_ANA19 * RAC_MULT, B_PCIE_BIT_RD_SEL);
2461*6d67aabdSBjoern A. Zeeb 
2462*6d67aabdSBjoern A. Zeeb 	oobs_val = rtw89_read16_mask(rtwdev, phy_offset + RAC_ANA1F * RAC_MULT,
2463*6d67aabdSBjoern A. Zeeb 				     OOBS_LEVEL_MASK);
2464*6d67aabdSBjoern A. Zeeb 
2465*6d67aabdSBjoern A. Zeeb 	rtw89_write16_mask(rtwdev, R_RAC_DIRECT_OFFSET_G1 + RAC_ANA03 * RAC_MULT,
2466*6d67aabdSBjoern A. Zeeb 			   OOBS_SEN_MASK, oobs_val);
2467*6d67aabdSBjoern A. Zeeb 	rtw89_write16_set(rtwdev, R_RAC_DIRECT_OFFSET_G1 + RAC_ANA09 * RAC_MULT,
2468*6d67aabdSBjoern A. Zeeb 			  BAC_OOBS_SEL);
2469*6d67aabdSBjoern A. Zeeb 
2470*6d67aabdSBjoern A. Zeeb 	rtw89_write16_mask(rtwdev, R_RAC_DIRECT_OFFSET_G2 + RAC_ANA03 * RAC_MULT,
2471*6d67aabdSBjoern A. Zeeb 			   OOBS_SEN_MASK, oobs_val);
2472*6d67aabdSBjoern A. Zeeb 	rtw89_write16_set(rtwdev, R_RAC_DIRECT_OFFSET_G2 + RAC_ANA09 * RAC_MULT,
2473*6d67aabdSBjoern A. Zeeb 			  BAC_OOBS_SEL);
2474*6d67aabdSBjoern A. Zeeb 
2475*6d67aabdSBjoern A. Zeeb out:
2476*6d67aabdSBjoern A. Zeeb 	rtw89_write32(rtwdev, R_AX_PCIE_MIX_CFG_V1, backup_aspm);
2477*6d67aabdSBjoern A. Zeeb }
2478*6d67aabdSBjoern A. Zeeb 
2479*6d67aabdSBjoern A. Zeeb static void rtw89_pci_ber(struct rtw89_dev *rtwdev)
2480*6d67aabdSBjoern A. Zeeb {
2481*6d67aabdSBjoern A. Zeeb 	u32 phy_offset;
2482*6d67aabdSBjoern A. Zeeb 
2483*6d67aabdSBjoern A. Zeeb 	if (!test_bit(RTW89_QUIRK_PCI_BER, rtwdev->quirks))
2484*6d67aabdSBjoern A. Zeeb 		return;
2485*6d67aabdSBjoern A. Zeeb 
2486*6d67aabdSBjoern A. Zeeb 	phy_offset = R_RAC_DIRECT_OFFSET_G1;
2487*6d67aabdSBjoern A. Zeeb 	rtw89_write16(rtwdev, phy_offset + RAC_ANA1E * RAC_MULT, RAC_ANA1E_G1_VAL);
2488*6d67aabdSBjoern A. Zeeb 	rtw89_write16(rtwdev, phy_offset + RAC_ANA2E * RAC_MULT, RAC_ANA2E_VAL);
2489*6d67aabdSBjoern A. Zeeb 
2490*6d67aabdSBjoern A. Zeeb 	phy_offset = R_RAC_DIRECT_OFFSET_G2;
2491*6d67aabdSBjoern A. Zeeb 	rtw89_write16(rtwdev, phy_offset + RAC_ANA1E * RAC_MULT, RAC_ANA1E_G2_VAL);
2492*6d67aabdSBjoern A. Zeeb 	rtw89_write16(rtwdev, phy_offset + RAC_ANA2E * RAC_MULT, RAC_ANA2E_VAL);
2493*6d67aabdSBjoern A. Zeeb }
2494*6d67aabdSBjoern A. Zeeb 
24958e93258fSBjoern A. Zeeb static void rtw89_pci_rxdma_prefth(struct rtw89_dev *rtwdev)
24968e93258fSBjoern A. Zeeb {
24978e93258fSBjoern A. Zeeb 	if (rtwdev->chip->chip_id != RTL8852A)
24988e93258fSBjoern A. Zeeb 		return;
24998e93258fSBjoern A. Zeeb 
25008e93258fSBjoern A. Zeeb 	rtw89_write32_set(rtwdev, R_AX_PCIE_INIT_CFG1, B_AX_DIS_RXDMA_PRE);
25018e93258fSBjoern A. Zeeb }
25028e93258fSBjoern A. Zeeb 
25038e93258fSBjoern A. Zeeb static void rtw89_pci_l1off_pwroff(struct rtw89_dev *rtwdev)
25048e93258fSBjoern A. Zeeb {
2505e2340276SBjoern A. Zeeb 	enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id;
2506e2340276SBjoern A. Zeeb 
2507*6d67aabdSBjoern A. Zeeb 	if (chip_id != RTL8852A && !rtw89_is_rtl885xb(rtwdev))
25088e93258fSBjoern A. Zeeb 		return;
25098e93258fSBjoern A. Zeeb 
25108e93258fSBjoern A. Zeeb 	rtw89_write32_clr(rtwdev, R_AX_PCIE_PS_CTRL, B_AX_L1OFF_PWR_OFF_EN);
25118e93258fSBjoern A. Zeeb }
25128e93258fSBjoern A. Zeeb 
25138e93258fSBjoern A. Zeeb static u32 rtw89_pci_l2_rxen_lat(struct rtw89_dev *rtwdev)
25148e93258fSBjoern A. Zeeb {
25158e93258fSBjoern A. Zeeb 	int ret;
25168e93258fSBjoern A. Zeeb 
25178e93258fSBjoern A. Zeeb 	if (rtwdev->chip->chip_id != RTL8852A)
25188e93258fSBjoern A. Zeeb 		return 0;
25198e93258fSBjoern A. Zeeb 
25208e93258fSBjoern A. Zeeb 	ret = rtw89_write16_mdio_clr(rtwdev, RAC_ANA26, B_AX_RXEN,
25218e93258fSBjoern A. Zeeb 				     PCIE_PHY_GEN1);
25228e93258fSBjoern A. Zeeb 	if (ret)
25238e93258fSBjoern A. Zeeb 		return ret;
25248e93258fSBjoern A. Zeeb 
25258e93258fSBjoern A. Zeeb 	ret = rtw89_write16_mdio_clr(rtwdev, RAC_ANA26, B_AX_RXEN,
25268e93258fSBjoern A. Zeeb 				     PCIE_PHY_GEN2);
25278e93258fSBjoern A. Zeeb 	if (ret)
25288e93258fSBjoern A. Zeeb 		return ret;
25298e93258fSBjoern A. Zeeb 
25308e93258fSBjoern A. Zeeb 	return 0;
25318e93258fSBjoern A. Zeeb }
25328e93258fSBjoern A. Zeeb 
25338e93258fSBjoern A. Zeeb static void rtw89_pci_aphy_pwrcut(struct rtw89_dev *rtwdev)
25348e93258fSBjoern A. Zeeb {
2535e2340276SBjoern A. Zeeb 	enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id;
2536e2340276SBjoern A. Zeeb 
2537*6d67aabdSBjoern A. Zeeb 	if (chip_id != RTL8852A && !rtw89_is_rtl885xb(rtwdev))
25388e93258fSBjoern A. Zeeb 		return;
25398e93258fSBjoern A. Zeeb 
25408e93258fSBjoern A. Zeeb 	rtw89_write32_clr(rtwdev, R_AX_SYS_PW_CTRL, B_AX_PSUS_OFF_CAPC_EN);
25418e93258fSBjoern A. Zeeb }
25428e93258fSBjoern A. Zeeb 
25438e93258fSBjoern A. Zeeb static void rtw89_pci_hci_ldo(struct rtw89_dev *rtwdev)
25448e93258fSBjoern A. Zeeb {
2545e2340276SBjoern A. Zeeb 	enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id;
2546e2340276SBjoern A. Zeeb 
2547*6d67aabdSBjoern A. Zeeb 	if (chip_id == RTL8852A || rtw89_is_rtl885xb(rtwdev)) {
25488e93258fSBjoern A. Zeeb 		rtw89_write32_set(rtwdev, R_AX_SYS_SDIO_CTRL,
25498e93258fSBjoern A. Zeeb 				  B_AX_PCIE_DIS_L2_CTRL_LDO_HCI);
25508e93258fSBjoern A. Zeeb 		rtw89_write32_clr(rtwdev, R_AX_SYS_SDIO_CTRL,
25518e93258fSBjoern A. Zeeb 				  B_AX_PCIE_DIS_WLSUS_AFT_PDN);
25528e93258fSBjoern A. Zeeb 	} else if (rtwdev->chip->chip_id == RTL8852C) {
25538e93258fSBjoern A. Zeeb 		rtw89_write32_clr(rtwdev, R_AX_SYS_SDIO_CTRL,
25548e93258fSBjoern A. Zeeb 				  B_AX_PCIE_DIS_L2_CTRL_LDO_HCI);
25558e93258fSBjoern A. Zeeb 	}
25568e93258fSBjoern A. Zeeb }
25578e93258fSBjoern A. Zeeb 
25588e93258fSBjoern A. Zeeb static int rtw89_pci_dphy_delay(struct rtw89_dev *rtwdev)
25598e93258fSBjoern A. Zeeb {
2560*6d67aabdSBjoern A. Zeeb 	if (!rtw89_is_rtl885xb(rtwdev))
25618e93258fSBjoern A. Zeeb 		return 0;
25628e93258fSBjoern A. Zeeb 
25638e93258fSBjoern A. Zeeb 	return rtw89_write16_mdio_mask(rtwdev, RAC_REG_REV2, BAC_CMU_EN_DLY_MASK,
25648e93258fSBjoern A. Zeeb 				       PCIE_DPHY_DLY_25US, PCIE_PHY_GEN1);
25658e93258fSBjoern A. Zeeb }
25668e93258fSBjoern A. Zeeb 
25678e93258fSBjoern A. Zeeb static void rtw89_pci_power_wake(struct rtw89_dev *rtwdev, bool pwr_up)
25688e93258fSBjoern A. Zeeb {
25698e93258fSBjoern A. Zeeb 	if (pwr_up)
25708e93258fSBjoern A. Zeeb 		rtw89_write32_set(rtwdev, R_AX_HCI_OPT_CTRL, BIT_WAKE_CTRL);
25718e93258fSBjoern A. Zeeb 	else
25728e93258fSBjoern A. Zeeb 		rtw89_write32_clr(rtwdev, R_AX_HCI_OPT_CTRL, BIT_WAKE_CTRL);
25738e93258fSBjoern A. Zeeb }
25748e93258fSBjoern A. Zeeb 
25758e93258fSBjoern A. Zeeb static void rtw89_pci_autoload_hang(struct rtw89_dev *rtwdev)
25768e93258fSBjoern A. Zeeb {
25778e93258fSBjoern A. Zeeb 	if (rtwdev->chip->chip_id != RTL8852C)
25788e93258fSBjoern A. Zeeb 		return;
25798e93258fSBjoern A. Zeeb 
25808e93258fSBjoern A. Zeeb 	rtw89_write32_set(rtwdev, R_AX_PCIE_BG_CLR, B_AX_BG_CLR_ASYNC_M3);
25818e93258fSBjoern A. Zeeb 	rtw89_write32_clr(rtwdev, R_AX_PCIE_BG_CLR, B_AX_BG_CLR_ASYNC_M3);
25828e93258fSBjoern A. Zeeb }
25838e93258fSBjoern A. Zeeb 
25848e93258fSBjoern A. Zeeb static void rtw89_pci_l12_vmain(struct rtw89_dev *rtwdev)
25858e93258fSBjoern A. Zeeb {
25868e93258fSBjoern A. Zeeb 	if (!(rtwdev->chip->chip_id == RTL8852C && rtwdev->hal.cv == CHIP_CAV))
25878e93258fSBjoern A. Zeeb 		return;
25888e93258fSBjoern A. Zeeb 
25898e93258fSBjoern A. Zeeb 	rtw89_write32_set(rtwdev, R_AX_SYS_SDIO_CTRL, B_AX_PCIE_FORCE_PWR_NGAT);
25908e93258fSBjoern A. Zeeb }
25918e93258fSBjoern A. Zeeb 
25928e93258fSBjoern A. Zeeb static void rtw89_pci_gen2_force_ib(struct rtw89_dev *rtwdev)
25938e93258fSBjoern A. Zeeb {
25948e93258fSBjoern A. Zeeb 	if (!(rtwdev->chip->chip_id == RTL8852C && rtwdev->hal.cv == CHIP_CAV))
25958e93258fSBjoern A. Zeeb 		return;
25968e93258fSBjoern A. Zeeb 
25978e93258fSBjoern A. Zeeb 	rtw89_write32_set(rtwdev, R_AX_PMC_DBG_CTRL2,
25988e93258fSBjoern A. Zeeb 			  B_AX_SYSON_DIS_PMCR_AX_WRMSK);
25998e93258fSBjoern A. Zeeb 	rtw89_write32_set(rtwdev, R_AX_HCI_BG_CTRL, B_AX_BG_CLR_ASYNC_M3);
26008e93258fSBjoern A. Zeeb 	rtw89_write32_clr(rtwdev, R_AX_PMC_DBG_CTRL2,
26018e93258fSBjoern A. Zeeb 			  B_AX_SYSON_DIS_PMCR_AX_WRMSK);
26028e93258fSBjoern A. Zeeb }
26038e93258fSBjoern A. Zeeb 
26048e93258fSBjoern A. Zeeb static void rtw89_pci_l1_ent_lat(struct rtw89_dev *rtwdev)
26058e93258fSBjoern A. Zeeb {
26068e93258fSBjoern A. Zeeb 	if (rtwdev->chip->chip_id != RTL8852C)
26078e93258fSBjoern A. Zeeb 		return;
26088e93258fSBjoern A. Zeeb 
26098e93258fSBjoern A. Zeeb 	rtw89_write32_clr(rtwdev, R_AX_PCIE_PS_CTRL_V1, B_AX_SEL_REQ_ENTR_L1);
26108e93258fSBjoern A. Zeeb }
26118e93258fSBjoern A. Zeeb 
26128e93258fSBjoern A. Zeeb static void rtw89_pci_wd_exit_l1(struct rtw89_dev *rtwdev)
26138e93258fSBjoern A. Zeeb {
26148e93258fSBjoern A. Zeeb 	if (rtwdev->chip->chip_id != RTL8852C)
26158e93258fSBjoern A. Zeeb 		return;
26168e93258fSBjoern A. Zeeb 
26178e93258fSBjoern A. Zeeb 	rtw89_write32_set(rtwdev, R_AX_PCIE_PS_CTRL_V1, B_AX_DMAC0_EXIT_L1_EN);
26188e93258fSBjoern A. Zeeb }
26198e93258fSBjoern A. Zeeb 
26208e93258fSBjoern A. Zeeb static void rtw89_pci_set_sic(struct rtw89_dev *rtwdev)
26218e93258fSBjoern A. Zeeb {
26228e93258fSBjoern A. Zeeb 	if (rtwdev->chip->chip_id == RTL8852C)
26238e93258fSBjoern A. Zeeb 		return;
26248e93258fSBjoern A. Zeeb 
26258e93258fSBjoern A. Zeeb 	rtw89_write32_clr(rtwdev, R_AX_PCIE_EXP_CTRL,
26268e93258fSBjoern A. Zeeb 			  B_AX_SIC_EN_FORCE_CLKREQ);
26278e93258fSBjoern A. Zeeb }
26288e93258fSBjoern A. Zeeb 
26298e93258fSBjoern A. Zeeb static void rtw89_pci_set_lbc(struct rtw89_dev *rtwdev)
26308e93258fSBjoern A. Zeeb {
26318e93258fSBjoern A. Zeeb 	const struct rtw89_pci_info *info = rtwdev->pci_info;
26328e93258fSBjoern A. Zeeb 	u32 lbc;
26338e93258fSBjoern A. Zeeb 
26348e93258fSBjoern A. Zeeb 	if (rtwdev->chip->chip_id == RTL8852C)
26358e93258fSBjoern A. Zeeb 		return;
26368e93258fSBjoern A. Zeeb 
26378e93258fSBjoern A. Zeeb 	lbc = rtw89_read32(rtwdev, R_AX_LBC_WATCHDOG);
26388e93258fSBjoern A. Zeeb 	if (info->lbc_en == MAC_AX_PCIE_ENABLE) {
26398e93258fSBjoern A. Zeeb 		lbc = u32_replace_bits(lbc, info->lbc_tmr, B_AX_LBC_TIMER);
26408e93258fSBjoern A. Zeeb 		lbc |= B_AX_LBC_FLAG | B_AX_LBC_EN;
26418e93258fSBjoern A. Zeeb 		rtw89_write32(rtwdev, R_AX_LBC_WATCHDOG, lbc);
26428e93258fSBjoern A. Zeeb 	} else {
26438e93258fSBjoern A. Zeeb 		lbc &= ~B_AX_LBC_EN;
26448e93258fSBjoern A. Zeeb 	}
26458e93258fSBjoern A. Zeeb 	rtw89_write32_set(rtwdev, R_AX_LBC_WATCHDOG, lbc);
26468e93258fSBjoern A. Zeeb }
26478e93258fSBjoern A. Zeeb 
26488e93258fSBjoern A. Zeeb static void rtw89_pci_set_io_rcy(struct rtw89_dev *rtwdev)
26498e93258fSBjoern A. Zeeb {
26508e93258fSBjoern A. Zeeb 	const struct rtw89_pci_info *info = rtwdev->pci_info;
26518e93258fSBjoern A. Zeeb 	u32 val32;
26528e93258fSBjoern A. Zeeb 
26538e93258fSBjoern A. Zeeb 	if (rtwdev->chip->chip_id != RTL8852C)
26548e93258fSBjoern A. Zeeb 		return;
26558e93258fSBjoern A. Zeeb 
26568e93258fSBjoern A. Zeeb 	if (info->io_rcy_en == MAC_AX_PCIE_ENABLE) {
26578e93258fSBjoern A. Zeeb 		val32 = FIELD_PREP(B_AX_PCIE_WDT_TIMER_M1_MASK,
26588e93258fSBjoern A. Zeeb 				   info->io_rcy_tmr);
26598e93258fSBjoern A. Zeeb 		rtw89_write32(rtwdev, R_AX_PCIE_WDT_TIMER_M1, val32);
26608e93258fSBjoern A. Zeeb 		rtw89_write32(rtwdev, R_AX_PCIE_WDT_TIMER_M2, val32);
26618e93258fSBjoern A. Zeeb 		rtw89_write32(rtwdev, R_AX_PCIE_WDT_TIMER_E0, val32);
26628e93258fSBjoern A. Zeeb 
26638e93258fSBjoern A. Zeeb 		rtw89_write32_set(rtwdev, R_AX_PCIE_IO_RCY_M1, B_AX_PCIE_IO_RCY_WDT_MODE_M1);
26648e93258fSBjoern A. Zeeb 		rtw89_write32_set(rtwdev, R_AX_PCIE_IO_RCY_M2, B_AX_PCIE_IO_RCY_WDT_MODE_M2);
26658e93258fSBjoern A. Zeeb 		rtw89_write32_set(rtwdev, R_AX_PCIE_IO_RCY_E0, B_AX_PCIE_IO_RCY_WDT_MODE_E0);
26668e93258fSBjoern A. Zeeb 	} else {
26678e93258fSBjoern A. Zeeb 		rtw89_write32_clr(rtwdev, R_AX_PCIE_IO_RCY_M1, B_AX_PCIE_IO_RCY_WDT_MODE_M1);
26688e93258fSBjoern A. Zeeb 		rtw89_write32_clr(rtwdev, R_AX_PCIE_IO_RCY_M2, B_AX_PCIE_IO_RCY_WDT_MODE_M2);
26698e93258fSBjoern A. Zeeb 		rtw89_write32_clr(rtwdev, R_AX_PCIE_IO_RCY_E0, B_AX_PCIE_IO_RCY_WDT_MODE_E0);
26708e93258fSBjoern A. Zeeb 	}
26718e93258fSBjoern A. Zeeb 
26728e93258fSBjoern A. Zeeb 	rtw89_write32_clr(rtwdev, R_AX_PCIE_IO_RCY_S1, B_AX_PCIE_IO_RCY_WDT_MODE_S1);
26738e93258fSBjoern A. Zeeb }
26748e93258fSBjoern A. Zeeb 
26758e93258fSBjoern A. Zeeb static void rtw89_pci_set_dbg(struct rtw89_dev *rtwdev)
26768e93258fSBjoern A. Zeeb {
26778e93258fSBjoern A. Zeeb 	if (rtwdev->chip->chip_id == RTL8852C)
26788e93258fSBjoern A. Zeeb 		return;
26798e93258fSBjoern A. Zeeb 
26808e93258fSBjoern A. Zeeb 	rtw89_write32_set(rtwdev, R_AX_PCIE_DBG_CTRL,
26818e93258fSBjoern A. Zeeb 			  B_AX_ASFF_FULL_NO_STK | B_AX_EN_STUCK_DBG);
26828e93258fSBjoern A. Zeeb 
26838e93258fSBjoern A. Zeeb 	if (rtwdev->chip->chip_id == RTL8852A)
26848e93258fSBjoern A. Zeeb 		rtw89_write32_set(rtwdev, R_AX_PCIE_EXP_CTRL,
26858e93258fSBjoern A. Zeeb 				  B_AX_EN_CHKDSC_NO_RX_STUCK);
26868e93258fSBjoern A. Zeeb }
26878e93258fSBjoern A. Zeeb 
26888e93258fSBjoern A. Zeeb static void rtw89_pci_set_keep_reg(struct rtw89_dev *rtwdev)
26898e93258fSBjoern A. Zeeb {
26908e93258fSBjoern A. Zeeb 	if (rtwdev->chip->chip_id == RTL8852C)
26918e93258fSBjoern A. Zeeb 		return;
26928e93258fSBjoern A. Zeeb 
26938e93258fSBjoern A. Zeeb 	rtw89_write32_set(rtwdev, R_AX_PCIE_INIT_CFG1,
26948e93258fSBjoern A. Zeeb 			  B_AX_PCIE_TXRST_KEEP_REG | B_AX_PCIE_RXRST_KEEP_REG);
26958e93258fSBjoern A. Zeeb }
26968e93258fSBjoern A. Zeeb 
2697*6d67aabdSBjoern A. Zeeb static void rtw89_pci_clr_idx_all_ax(struct rtw89_dev *rtwdev)
26988e93258fSBjoern A. Zeeb {
26998e93258fSBjoern A. Zeeb 	const struct rtw89_pci_info *info = rtwdev->pci_info;
27008e93258fSBjoern A. Zeeb 	enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id;
27018e93258fSBjoern A. Zeeb 	u32 val = B_AX_CLR_ACH0_IDX | B_AX_CLR_ACH1_IDX | B_AX_CLR_ACH2_IDX |
27028e93258fSBjoern A. Zeeb 		  B_AX_CLR_ACH3_IDX | B_AX_CLR_CH8_IDX | B_AX_CLR_CH9_IDX |
27038e93258fSBjoern A. Zeeb 		  B_AX_CLR_CH12_IDX;
27048e93258fSBjoern A. Zeeb 	u32 rxbd_rwptr_clr = info->rxbd_rwptr_clr_reg;
27058e93258fSBjoern A. Zeeb 	u32 txbd_rwptr_clr2 = info->txbd_rwptr_clr2_reg;
27068e93258fSBjoern A. Zeeb 
27078e93258fSBjoern A. Zeeb 	if (chip_id == RTL8852A || chip_id == RTL8852C)
27088e93258fSBjoern A. Zeeb 		val |= B_AX_CLR_ACH4_IDX | B_AX_CLR_ACH5_IDX |
27098e93258fSBjoern A. Zeeb 		       B_AX_CLR_ACH6_IDX | B_AX_CLR_ACH7_IDX;
27108e93258fSBjoern A. Zeeb 	/* clear DMA indexes */
27118e93258fSBjoern A. Zeeb 	rtw89_write32_set(rtwdev, R_AX_TXBD_RWPTR_CLR1, val);
27128e93258fSBjoern A. Zeeb 	if (chip_id == RTL8852A || chip_id == RTL8852C)
27138e93258fSBjoern A. Zeeb 		rtw89_write32_set(rtwdev, txbd_rwptr_clr2,
27148e93258fSBjoern A. Zeeb 				  B_AX_CLR_CH10_IDX | B_AX_CLR_CH11_IDX);
27158e93258fSBjoern A. Zeeb 	rtw89_write32_set(rtwdev, rxbd_rwptr_clr,
27168e93258fSBjoern A. Zeeb 			  B_AX_CLR_RXQ_IDX | B_AX_CLR_RPQ_IDX);
27178e93258fSBjoern A. Zeeb }
27188e93258fSBjoern A. Zeeb 
2719*6d67aabdSBjoern A. Zeeb static int rtw89_pci_poll_txdma_ch_idle_ax(struct rtw89_dev *rtwdev)
27208e93258fSBjoern A. Zeeb {
27218e93258fSBjoern A. Zeeb 	const struct rtw89_pci_info *info = rtwdev->pci_info;
27228e93258fSBjoern A. Zeeb 	u32 ret, check, dma_busy;
2723e2340276SBjoern A. Zeeb 	u32 dma_busy1 = info->dma_busy1.addr;
27248e93258fSBjoern A. Zeeb 	u32 dma_busy2 = info->dma_busy2_reg;
27258e93258fSBjoern A. Zeeb 
2726e2340276SBjoern A. Zeeb 	check = info->dma_busy1.mask;
27278e93258fSBjoern A. Zeeb 
27288e93258fSBjoern A. Zeeb 	ret = read_poll_timeout(rtw89_read32, dma_busy, (dma_busy & check) == 0,
27298e93258fSBjoern A. Zeeb 				10, 100, false, rtwdev, dma_busy1);
27308e93258fSBjoern A. Zeeb 	if (ret)
27318e93258fSBjoern A. Zeeb 		return ret;
27328e93258fSBjoern A. Zeeb 
2733e2340276SBjoern A. Zeeb 	if (!dma_busy2)
2734e2340276SBjoern A. Zeeb 		return 0;
2735e2340276SBjoern A. Zeeb 
27368e93258fSBjoern A. Zeeb 	check = B_AX_CH10_BUSY | B_AX_CH11_BUSY;
27378e93258fSBjoern A. Zeeb 
27388e93258fSBjoern A. Zeeb 	ret = read_poll_timeout(rtw89_read32, dma_busy, (dma_busy & check) == 0,
27398e93258fSBjoern A. Zeeb 				10, 100, false, rtwdev, dma_busy2);
27408e93258fSBjoern A. Zeeb 	if (ret)
27418e93258fSBjoern A. Zeeb 		return ret;
27428e93258fSBjoern A. Zeeb 
27438e93258fSBjoern A. Zeeb 	return 0;
27448e93258fSBjoern A. Zeeb }
27458e93258fSBjoern A. Zeeb 
2746*6d67aabdSBjoern A. Zeeb static int rtw89_pci_poll_rxdma_ch_idle_ax(struct rtw89_dev *rtwdev)
27478e93258fSBjoern A. Zeeb {
27488e93258fSBjoern A. Zeeb 	const struct rtw89_pci_info *info = rtwdev->pci_info;
27498e93258fSBjoern A. Zeeb 	u32 ret, check, dma_busy;
27508e93258fSBjoern A. Zeeb 	u32 dma_busy3 = info->dma_busy3_reg;
27518e93258fSBjoern A. Zeeb 
27528e93258fSBjoern A. Zeeb 	check = B_AX_RXQ_BUSY | B_AX_RPQ_BUSY;
27538e93258fSBjoern A. Zeeb 
27548e93258fSBjoern A. Zeeb 	ret = read_poll_timeout(rtw89_read32, dma_busy, (dma_busy & check) == 0,
27558e93258fSBjoern A. Zeeb 				10, 100, false, rtwdev, dma_busy3);
27568e93258fSBjoern A. Zeeb 	if (ret)
27578e93258fSBjoern A. Zeeb 		return ret;
27588e93258fSBjoern A. Zeeb 
27598e93258fSBjoern A. Zeeb 	return 0;
27608e93258fSBjoern A. Zeeb }
27618e93258fSBjoern A. Zeeb 
27628e93258fSBjoern A. Zeeb static int rtw89_pci_poll_dma_all_idle(struct rtw89_dev *rtwdev)
27638e93258fSBjoern A. Zeeb {
27648e93258fSBjoern A. Zeeb 	u32 ret;
27658e93258fSBjoern A. Zeeb 
2766*6d67aabdSBjoern A. Zeeb 	ret = rtw89_pci_poll_txdma_ch_idle_ax(rtwdev);
27678e93258fSBjoern A. Zeeb 	if (ret) {
27688e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "txdma ch busy\n");
27698e93258fSBjoern A. Zeeb 		return ret;
27708e93258fSBjoern A. Zeeb 	}
27718e93258fSBjoern A. Zeeb 
2772*6d67aabdSBjoern A. Zeeb 	ret = rtw89_pci_poll_rxdma_ch_idle_ax(rtwdev);
27738e93258fSBjoern A. Zeeb 	if (ret) {
27748e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "rxdma ch busy\n");
27758e93258fSBjoern A. Zeeb 		return ret;
27768e93258fSBjoern A. Zeeb 	}
27778e93258fSBjoern A. Zeeb 
27788e93258fSBjoern A. Zeeb 	return 0;
27798e93258fSBjoern A. Zeeb }
27808e93258fSBjoern A. Zeeb 
27818e93258fSBjoern A. Zeeb static int rtw89_pci_mode_op(struct rtw89_dev *rtwdev)
27828e93258fSBjoern A. Zeeb {
27838e93258fSBjoern A. Zeeb 	const struct rtw89_pci_info *info = rtwdev->pci_info;
27848e93258fSBjoern A. Zeeb 	enum mac_ax_bd_trunc_mode txbd_trunc_mode = info->txbd_trunc_mode;
27858e93258fSBjoern A. Zeeb 	enum mac_ax_bd_trunc_mode rxbd_trunc_mode = info->rxbd_trunc_mode;
27868e93258fSBjoern A. Zeeb 	enum mac_ax_rxbd_mode rxbd_mode = info->rxbd_mode;
27878e93258fSBjoern A. Zeeb 	enum mac_ax_tag_mode tag_mode = info->tag_mode;
27888e93258fSBjoern A. Zeeb 	enum mac_ax_wd_dma_intvl wd_dma_idle_intvl = info->wd_dma_idle_intvl;
27898e93258fSBjoern A. Zeeb 	enum mac_ax_wd_dma_intvl wd_dma_act_intvl = info->wd_dma_act_intvl;
27908e93258fSBjoern A. Zeeb 	enum mac_ax_tx_burst tx_burst = info->tx_burst;
27918e93258fSBjoern A. Zeeb 	enum mac_ax_rx_burst rx_burst = info->rx_burst;
27928e93258fSBjoern A. Zeeb 	enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id;
27938e93258fSBjoern A. Zeeb 	u8 cv = rtwdev->hal.cv;
27948e93258fSBjoern A. Zeeb 	u32 val32;
27958e93258fSBjoern A. Zeeb 
27968e93258fSBjoern A. Zeeb 	if (txbd_trunc_mode == MAC_AX_BD_TRUNC) {
27978e93258fSBjoern A. Zeeb 		if (chip_id == RTL8852A && cv == CHIP_CBV)
27988e93258fSBjoern A. Zeeb 			rtw89_write32_set(rtwdev, R_AX_PCIE_INIT_CFG1, B_AX_TX_TRUNC_MODE);
27998e93258fSBjoern A. Zeeb 	} else if (txbd_trunc_mode == MAC_AX_BD_NORM) {
28008e93258fSBjoern A. Zeeb 		if (chip_id == RTL8852A || chip_id == RTL8852B)
28018e93258fSBjoern A. Zeeb 			rtw89_write32_clr(rtwdev, R_AX_PCIE_INIT_CFG1, B_AX_TX_TRUNC_MODE);
28028e93258fSBjoern A. Zeeb 	}
28038e93258fSBjoern A. Zeeb 
28048e93258fSBjoern A. Zeeb 	if (rxbd_trunc_mode == MAC_AX_BD_TRUNC) {
28058e93258fSBjoern A. Zeeb 		if (chip_id == RTL8852A && cv == CHIP_CBV)
28068e93258fSBjoern A. Zeeb 			rtw89_write32_set(rtwdev, R_AX_PCIE_INIT_CFG1, B_AX_RX_TRUNC_MODE);
28078e93258fSBjoern A. Zeeb 	} else if (rxbd_trunc_mode == MAC_AX_BD_NORM) {
28088e93258fSBjoern A. Zeeb 		if (chip_id == RTL8852A || chip_id == RTL8852B)
28098e93258fSBjoern A. Zeeb 			rtw89_write32_clr(rtwdev, R_AX_PCIE_INIT_CFG1, B_AX_RX_TRUNC_MODE);
28108e93258fSBjoern A. Zeeb 	}
28118e93258fSBjoern A. Zeeb 
28128e93258fSBjoern A. Zeeb 	if (rxbd_mode == MAC_AX_RXBD_PKT) {
28138e93258fSBjoern A. Zeeb 		rtw89_write32_clr(rtwdev, info->init_cfg_reg, info->rxbd_mode_bit);
28148e93258fSBjoern A. Zeeb 	} else if (rxbd_mode == MAC_AX_RXBD_SEP) {
28158e93258fSBjoern A. Zeeb 		rtw89_write32_set(rtwdev, info->init_cfg_reg, info->rxbd_mode_bit);
28168e93258fSBjoern A. Zeeb 
28178e93258fSBjoern A. Zeeb 		if (chip_id == RTL8852A || chip_id == RTL8852B)
28188e93258fSBjoern A. Zeeb 			rtw89_write32_mask(rtwdev, R_AX_PCIE_INIT_CFG2,
28198e93258fSBjoern A. Zeeb 					   B_AX_PCIE_RX_APPLEN_MASK, 0);
28208e93258fSBjoern A. Zeeb 	}
28218e93258fSBjoern A. Zeeb 
2822*6d67aabdSBjoern A. Zeeb 	if (chip_id == RTL8852A || rtw89_is_rtl885xb(rtwdev)) {
28238e93258fSBjoern A. Zeeb 		rtw89_write32_mask(rtwdev, R_AX_PCIE_INIT_CFG1, B_AX_PCIE_MAX_TXDMA_MASK, tx_burst);
28248e93258fSBjoern A. Zeeb 		rtw89_write32_mask(rtwdev, R_AX_PCIE_INIT_CFG1, B_AX_PCIE_MAX_RXDMA_MASK, rx_burst);
28258e93258fSBjoern A. Zeeb 	} else if (chip_id == RTL8852C) {
28268e93258fSBjoern A. Zeeb 		rtw89_write32_mask(rtwdev, R_AX_HAXI_INIT_CFG1, B_AX_HAXI_MAX_TXDMA_MASK, tx_burst);
28278e93258fSBjoern A. Zeeb 		rtw89_write32_mask(rtwdev, R_AX_HAXI_INIT_CFG1, B_AX_HAXI_MAX_RXDMA_MASK, rx_burst);
28288e93258fSBjoern A. Zeeb 	}
28298e93258fSBjoern A. Zeeb 
2830*6d67aabdSBjoern A. Zeeb 	if (chip_id == RTL8852A || rtw89_is_rtl885xb(rtwdev)) {
28318e93258fSBjoern A. Zeeb 		if (tag_mode == MAC_AX_TAG_SGL) {
28328e93258fSBjoern A. Zeeb 			val32 = rtw89_read32(rtwdev, R_AX_PCIE_INIT_CFG1) &
28338e93258fSBjoern A. Zeeb 					    ~B_AX_LATENCY_CONTROL;
28348e93258fSBjoern A. Zeeb 			rtw89_write32(rtwdev, R_AX_PCIE_INIT_CFG1, val32);
28358e93258fSBjoern A. Zeeb 		} else if (tag_mode == MAC_AX_TAG_MULTI) {
28368e93258fSBjoern A. Zeeb 			val32 = rtw89_read32(rtwdev, R_AX_PCIE_INIT_CFG1) |
28378e93258fSBjoern A. Zeeb 					    B_AX_LATENCY_CONTROL;
28388e93258fSBjoern A. Zeeb 			rtw89_write32(rtwdev, R_AX_PCIE_INIT_CFG1, val32);
28398e93258fSBjoern A. Zeeb 		}
28408e93258fSBjoern A. Zeeb 	}
28418e93258fSBjoern A. Zeeb 
28428e93258fSBjoern A. Zeeb 	rtw89_write32_mask(rtwdev, info->exp_ctrl_reg, info->max_tag_num_mask,
28438e93258fSBjoern A. Zeeb 			   info->multi_tag_num);
28448e93258fSBjoern A. Zeeb 
2845*6d67aabdSBjoern A. Zeeb 	if (chip_id == RTL8852A || rtw89_is_rtl885xb(rtwdev)) {
28468e93258fSBjoern A. Zeeb 		rtw89_write32_mask(rtwdev, R_AX_PCIE_INIT_CFG2, B_AX_WD_ITVL_IDLE,
28478e93258fSBjoern A. Zeeb 				   wd_dma_idle_intvl);
28488e93258fSBjoern A. Zeeb 		rtw89_write32_mask(rtwdev, R_AX_PCIE_INIT_CFG2, B_AX_WD_ITVL_ACT,
28498e93258fSBjoern A. Zeeb 				   wd_dma_act_intvl);
28508e93258fSBjoern A. Zeeb 	} else if (chip_id == RTL8852C) {
28518e93258fSBjoern A. Zeeb 		rtw89_write32_mask(rtwdev, R_AX_HAXI_INIT_CFG1, B_AX_WD_ITVL_IDLE_V1_MASK,
28528e93258fSBjoern A. Zeeb 				   wd_dma_idle_intvl);
28538e93258fSBjoern A. Zeeb 		rtw89_write32_mask(rtwdev, R_AX_HAXI_INIT_CFG1, B_AX_WD_ITVL_ACT_V1_MASK,
28548e93258fSBjoern A. Zeeb 				   wd_dma_act_intvl);
28558e93258fSBjoern A. Zeeb 	}
28568e93258fSBjoern A. Zeeb 
28578e93258fSBjoern A. Zeeb 	if (txbd_trunc_mode == MAC_AX_BD_TRUNC) {
28588e93258fSBjoern A. Zeeb 		rtw89_write32_set(rtwdev, R_AX_TX_ADDRESS_INFO_MODE_SETTING,
28598e93258fSBjoern A. Zeeb 				  B_AX_HOST_ADDR_INFO_8B_SEL);
28608e93258fSBjoern A. Zeeb 		rtw89_write32_clr(rtwdev, R_AX_PKTIN_SETTING, B_AX_WD_ADDR_INFO_LENGTH);
28618e93258fSBjoern A. Zeeb 	} else if (txbd_trunc_mode == MAC_AX_BD_NORM) {
28628e93258fSBjoern A. Zeeb 		rtw89_write32_clr(rtwdev, R_AX_TX_ADDRESS_INFO_MODE_SETTING,
28638e93258fSBjoern A. Zeeb 				  B_AX_HOST_ADDR_INFO_8B_SEL);
28648e93258fSBjoern A. Zeeb 		rtw89_write32_set(rtwdev, R_AX_PKTIN_SETTING, B_AX_WD_ADDR_INFO_LENGTH);
28658e93258fSBjoern A. Zeeb 	}
28668e93258fSBjoern A. Zeeb 
28678e93258fSBjoern A. Zeeb 	return 0;
28688e93258fSBjoern A. Zeeb }
28698e93258fSBjoern A. Zeeb 
28708e93258fSBjoern A. Zeeb static int rtw89_pci_ops_deinit(struct rtw89_dev *rtwdev)
28718e93258fSBjoern A. Zeeb {
28728e93258fSBjoern A. Zeeb 	const struct rtw89_pci_info *info = rtwdev->pci_info;
28738e93258fSBjoern A. Zeeb 
28748e93258fSBjoern A. Zeeb 	if (rtwdev->chip->chip_id == RTL8852A) {
28758e93258fSBjoern A. Zeeb 		/* ltr sw trigger */
28768e93258fSBjoern A. Zeeb 		rtw89_write32_set(rtwdev, R_AX_LTR_CTRL_0, B_AX_APP_LTR_IDLE);
28778e93258fSBjoern A. Zeeb 	}
28788e93258fSBjoern A. Zeeb 	info->ltr_set(rtwdev, false);
28798e93258fSBjoern A. Zeeb 	rtw89_pci_ctrl_dma_all(rtwdev, false);
28808e93258fSBjoern A. Zeeb 	rtw89_pci_clr_idx_all(rtwdev);
28818e93258fSBjoern A. Zeeb 
28828e93258fSBjoern A. Zeeb 	return 0;
28838e93258fSBjoern A. Zeeb }
28848e93258fSBjoern A. Zeeb 
2885*6d67aabdSBjoern A. Zeeb static int rtw89_pci_ops_mac_pre_init_ax(struct rtw89_dev *rtwdev)
28868e93258fSBjoern A. Zeeb {
28878e93258fSBjoern A. Zeeb 	const struct rtw89_pci_info *info = rtwdev->pci_info;
28888e93258fSBjoern A. Zeeb 	int ret;
28898e93258fSBjoern A. Zeeb 
2890*6d67aabdSBjoern A. Zeeb 	rtw89_pci_ber(rtwdev);
28918e93258fSBjoern A. Zeeb 	rtw89_pci_rxdma_prefth(rtwdev);
28928e93258fSBjoern A. Zeeb 	rtw89_pci_l1off_pwroff(rtwdev);
28938e93258fSBjoern A. Zeeb 	rtw89_pci_deglitch_setting(rtwdev);
28948e93258fSBjoern A. Zeeb 	ret = rtw89_pci_l2_rxen_lat(rtwdev);
28958e93258fSBjoern A. Zeeb 	if (ret) {
28968e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "[ERR] pcie l2 rxen lat %d\n", ret);
28978e93258fSBjoern A. Zeeb 		return ret;
28988e93258fSBjoern A. Zeeb 	}
28998e93258fSBjoern A. Zeeb 
29008e93258fSBjoern A. Zeeb 	rtw89_pci_aphy_pwrcut(rtwdev);
29018e93258fSBjoern A. Zeeb 	rtw89_pci_hci_ldo(rtwdev);
29028e93258fSBjoern A. Zeeb 	rtw89_pci_dphy_delay(rtwdev);
29038e93258fSBjoern A. Zeeb 
2904e2340276SBjoern A. Zeeb 	ret = rtw89_pci_autok_x(rtwdev);
2905e2340276SBjoern A. Zeeb 	if (ret) {
2906e2340276SBjoern A. Zeeb 		rtw89_err(rtwdev, "[ERR] pcie autok_x fail %d\n", ret);
2907e2340276SBjoern A. Zeeb 		return ret;
2908e2340276SBjoern A. Zeeb 	}
2909e2340276SBjoern A. Zeeb 
29108e93258fSBjoern A. Zeeb 	ret = rtw89_pci_auto_refclk_cal(rtwdev, false);
29118e93258fSBjoern A. Zeeb 	if (ret) {
29128e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "[ERR] pcie autok fail %d\n", ret);
29138e93258fSBjoern A. Zeeb 		return ret;
29148e93258fSBjoern A. Zeeb 	}
29158e93258fSBjoern A. Zeeb 
29168e93258fSBjoern A. Zeeb 	rtw89_pci_power_wake(rtwdev, true);
29178e93258fSBjoern A. Zeeb 	rtw89_pci_autoload_hang(rtwdev);
29188e93258fSBjoern A. Zeeb 	rtw89_pci_l12_vmain(rtwdev);
29198e93258fSBjoern A. Zeeb 	rtw89_pci_gen2_force_ib(rtwdev);
29208e93258fSBjoern A. Zeeb 	rtw89_pci_l1_ent_lat(rtwdev);
29218e93258fSBjoern A. Zeeb 	rtw89_pci_wd_exit_l1(rtwdev);
29228e93258fSBjoern A. Zeeb 	rtw89_pci_set_sic(rtwdev);
29238e93258fSBjoern A. Zeeb 	rtw89_pci_set_lbc(rtwdev);
29248e93258fSBjoern A. Zeeb 	rtw89_pci_set_io_rcy(rtwdev);
29258e93258fSBjoern A. Zeeb 	rtw89_pci_set_dbg(rtwdev);
29268e93258fSBjoern A. Zeeb 	rtw89_pci_set_keep_reg(rtwdev);
29278e93258fSBjoern A. Zeeb 
2928e2340276SBjoern A. Zeeb 	rtw89_write32_set(rtwdev, info->dma_stop1.addr, B_AX_STOP_WPDMA);
29298e93258fSBjoern A. Zeeb 
29308e93258fSBjoern A. Zeeb 	/* stop DMA activities */
29318e93258fSBjoern A. Zeeb 	rtw89_pci_ctrl_dma_all(rtwdev, false);
29328e93258fSBjoern A. Zeeb 
29338e93258fSBjoern A. Zeeb 	ret = rtw89_pci_poll_dma_all_idle(rtwdev);
29348e93258fSBjoern A. Zeeb 	if (ret) {
29358e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "[ERR] poll pcie dma all idle\n");
29368e93258fSBjoern A. Zeeb 		return ret;
29378e93258fSBjoern A. Zeeb 	}
29388e93258fSBjoern A. Zeeb 
29398e93258fSBjoern A. Zeeb 	rtw89_pci_clr_idx_all(rtwdev);
29408e93258fSBjoern A. Zeeb 	rtw89_pci_mode_op(rtwdev);
29418e93258fSBjoern A. Zeeb 
29428e93258fSBjoern A. Zeeb 	/* fill TRX BD indexes */
29438e93258fSBjoern A. Zeeb 	rtw89_pci_ops_reset(rtwdev);
29448e93258fSBjoern A. Zeeb 
2945*6d67aabdSBjoern A. Zeeb 	ret = rtw89_pci_rst_bdram_ax(rtwdev);
29468e93258fSBjoern A. Zeeb 	if (ret) {
29478e93258fSBjoern A. Zeeb 		rtw89_warn(rtwdev, "reset bdram busy\n");
29488e93258fSBjoern A. Zeeb 		return ret;
29498e93258fSBjoern A. Zeeb 	}
29508e93258fSBjoern A. Zeeb 
2951e2340276SBjoern A. Zeeb 	/* disable all channels except to FW CMD channel to download firmware */
2952*6d67aabdSBjoern A. Zeeb 	rtw89_pci_ctrl_txdma_ch_ax(rtwdev, false);
2953*6d67aabdSBjoern A. Zeeb 	rtw89_pci_ctrl_txdma_fw_ch_ax(rtwdev, true);
29548e93258fSBjoern A. Zeeb 
29558e93258fSBjoern A. Zeeb 	/* start DMA activities */
29568e93258fSBjoern A. Zeeb 	rtw89_pci_ctrl_dma_all(rtwdev, true);
29578e93258fSBjoern A. Zeeb 
29588e93258fSBjoern A. Zeeb 	return 0;
29598e93258fSBjoern A. Zeeb }
29608e93258fSBjoern A. Zeeb 
29618e93258fSBjoern A. Zeeb int rtw89_pci_ltr_set(struct rtw89_dev *rtwdev, bool en)
29628e93258fSBjoern A. Zeeb {
29638e93258fSBjoern A. Zeeb 	u32 val;
29648e93258fSBjoern A. Zeeb 
29658e93258fSBjoern A. Zeeb 	if (!en)
29668e93258fSBjoern A. Zeeb 		return 0;
29678e93258fSBjoern A. Zeeb 
29688e93258fSBjoern A. Zeeb 	val = rtw89_read32(rtwdev, R_AX_LTR_CTRL_0);
29698e93258fSBjoern A. Zeeb 	if (rtw89_pci_ltr_is_err_reg_val(val))
29708e93258fSBjoern A. Zeeb 		return -EINVAL;
29718e93258fSBjoern A. Zeeb 	val = rtw89_read32(rtwdev, R_AX_LTR_CTRL_1);
29728e93258fSBjoern A. Zeeb 	if (rtw89_pci_ltr_is_err_reg_val(val))
29738e93258fSBjoern A. Zeeb 		return -EINVAL;
29748e93258fSBjoern A. Zeeb 	val = rtw89_read32(rtwdev, R_AX_LTR_IDLE_LATENCY);
29758e93258fSBjoern A. Zeeb 	if (rtw89_pci_ltr_is_err_reg_val(val))
29768e93258fSBjoern A. Zeeb 		return -EINVAL;
29778e93258fSBjoern A. Zeeb 	val = rtw89_read32(rtwdev, R_AX_LTR_ACTIVE_LATENCY);
29788e93258fSBjoern A. Zeeb 	if (rtw89_pci_ltr_is_err_reg_val(val))
29798e93258fSBjoern A. Zeeb 		return -EINVAL;
29808e93258fSBjoern A. Zeeb 
2981e2340276SBjoern A. Zeeb 	rtw89_write32_set(rtwdev, R_AX_LTR_CTRL_0, B_AX_LTR_HW_EN | B_AX_LTR_EN |
2982e2340276SBjoern A. Zeeb 						   B_AX_LTR_WD_NOEMP_CHK);
29838e93258fSBjoern A. Zeeb 	rtw89_write32_mask(rtwdev, R_AX_LTR_CTRL_0, B_AX_LTR_SPACE_IDX_MASK,
29848e93258fSBjoern A. Zeeb 			   PCI_LTR_SPC_500US);
29858e93258fSBjoern A. Zeeb 	rtw89_write32_mask(rtwdev, R_AX_LTR_CTRL_0, B_AX_LTR_IDLE_TIMER_IDX_MASK,
2986e2340276SBjoern A. Zeeb 			   PCI_LTR_IDLE_TIMER_3_2MS);
29878e93258fSBjoern A. Zeeb 	rtw89_write32_mask(rtwdev, R_AX_LTR_CTRL_1, B_AX_LTR_RX0_TH_MASK, 0x28);
29888e93258fSBjoern A. Zeeb 	rtw89_write32_mask(rtwdev, R_AX_LTR_CTRL_1, B_AX_LTR_RX1_TH_MASK, 0x28);
2989e2340276SBjoern A. Zeeb 	rtw89_write32(rtwdev, R_AX_LTR_IDLE_LATENCY, 0x90039003);
29908e93258fSBjoern A. Zeeb 	rtw89_write32(rtwdev, R_AX_LTR_ACTIVE_LATENCY, 0x880b880b);
29918e93258fSBjoern A. Zeeb 
29928e93258fSBjoern A. Zeeb 	return 0;
29938e93258fSBjoern A. Zeeb }
29948e93258fSBjoern A. Zeeb EXPORT_SYMBOL(rtw89_pci_ltr_set);
29958e93258fSBjoern A. Zeeb 
29968e93258fSBjoern A. Zeeb int rtw89_pci_ltr_set_v1(struct rtw89_dev *rtwdev, bool en)
29978e93258fSBjoern A. Zeeb {
29988e93258fSBjoern A. Zeeb 	u32 dec_ctrl;
29998e93258fSBjoern A. Zeeb 	u32 val32;
30008e93258fSBjoern A. Zeeb 
30018e93258fSBjoern A. Zeeb 	val32 = rtw89_read32(rtwdev, R_AX_LTR_CTRL_0);
30028e93258fSBjoern A. Zeeb 	if (rtw89_pci_ltr_is_err_reg_val(val32))
30038e93258fSBjoern A. Zeeb 		return -EINVAL;
30048e93258fSBjoern A. Zeeb 	val32 = rtw89_read32(rtwdev, R_AX_LTR_CTRL_1);
30058e93258fSBjoern A. Zeeb 	if (rtw89_pci_ltr_is_err_reg_val(val32))
30068e93258fSBjoern A. Zeeb 		return -EINVAL;
30078e93258fSBjoern A. Zeeb 	dec_ctrl = rtw89_read32(rtwdev, R_AX_LTR_DEC_CTRL);
30088e93258fSBjoern A. Zeeb 	if (rtw89_pci_ltr_is_err_reg_val(dec_ctrl))
30098e93258fSBjoern A. Zeeb 		return -EINVAL;
30108e93258fSBjoern A. Zeeb 	val32 = rtw89_read32(rtwdev, R_AX_LTR_LATENCY_IDX3);
30118e93258fSBjoern A. Zeeb 	if (rtw89_pci_ltr_is_err_reg_val(val32))
30128e93258fSBjoern A. Zeeb 		return -EINVAL;
30138e93258fSBjoern A. Zeeb 	val32 = rtw89_read32(rtwdev, R_AX_LTR_LATENCY_IDX0);
30148e93258fSBjoern A. Zeeb 	if (rtw89_pci_ltr_is_err_reg_val(val32))
30158e93258fSBjoern A. Zeeb 		return -EINVAL;
30168e93258fSBjoern A. Zeeb 
30178e93258fSBjoern A. Zeeb 	if (!en) {
30188e93258fSBjoern A. Zeeb 		dec_ctrl &= ~(LTR_EN_BITS | B_AX_LTR_IDX_DRV_MASK | B_AX_LTR_HW_DEC_EN);
30198e93258fSBjoern A. Zeeb 		dec_ctrl |= FIELD_PREP(B_AX_LTR_IDX_DRV_MASK, PCIE_LTR_IDX_IDLE) |
30208e93258fSBjoern A. Zeeb 			    B_AX_LTR_REQ_DRV;
30218e93258fSBjoern A. Zeeb 	} else {
30228e93258fSBjoern A. Zeeb 		dec_ctrl |= B_AX_LTR_HW_DEC_EN;
30238e93258fSBjoern A. Zeeb 	}
30248e93258fSBjoern A. Zeeb 
30258e93258fSBjoern A. Zeeb 	dec_ctrl &= ~B_AX_LTR_SPACE_IDX_V1_MASK;
30268e93258fSBjoern A. Zeeb 	dec_ctrl |= FIELD_PREP(B_AX_LTR_SPACE_IDX_V1_MASK, PCI_LTR_SPC_500US);
30278e93258fSBjoern A. Zeeb 
30288e93258fSBjoern A. Zeeb 	if (en)
30298e93258fSBjoern A. Zeeb 		rtw89_write32_set(rtwdev, R_AX_LTR_CTRL_0,
30308e93258fSBjoern A. Zeeb 				  B_AX_LTR_WD_NOEMP_CHK_V1 | B_AX_LTR_HW_EN);
30318e93258fSBjoern A. Zeeb 	rtw89_write32_mask(rtwdev, R_AX_LTR_CTRL_0, B_AX_LTR_IDLE_TIMER_IDX_MASK,
30328e93258fSBjoern A. Zeeb 			   PCI_LTR_IDLE_TIMER_3_2MS);
30338e93258fSBjoern A. Zeeb 	rtw89_write32_mask(rtwdev, R_AX_LTR_CTRL_1, B_AX_LTR_RX0_TH_MASK, 0x28);
30348e93258fSBjoern A. Zeeb 	rtw89_write32_mask(rtwdev, R_AX_LTR_CTRL_1, B_AX_LTR_RX1_TH_MASK, 0x28);
30358e93258fSBjoern A. Zeeb 	rtw89_write32(rtwdev, R_AX_LTR_DEC_CTRL, dec_ctrl);
30368e93258fSBjoern A. Zeeb 	rtw89_write32(rtwdev, R_AX_LTR_LATENCY_IDX3, 0x90039003);
30378e93258fSBjoern A. Zeeb 	rtw89_write32(rtwdev, R_AX_LTR_LATENCY_IDX0, 0x880b880b);
30388e93258fSBjoern A. Zeeb 
30398e93258fSBjoern A. Zeeb 	return 0;
30408e93258fSBjoern A. Zeeb }
30418e93258fSBjoern A. Zeeb EXPORT_SYMBOL(rtw89_pci_ltr_set_v1);
30428e93258fSBjoern A. Zeeb 
3043*6d67aabdSBjoern A. Zeeb static int rtw89_pci_ops_mac_post_init_ax(struct rtw89_dev *rtwdev)
30448e93258fSBjoern A. Zeeb {
30458e93258fSBjoern A. Zeeb 	const struct rtw89_pci_info *info = rtwdev->pci_info;
30468e93258fSBjoern A. Zeeb 	enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id;
30478e93258fSBjoern A. Zeeb 	int ret;
30488e93258fSBjoern A. Zeeb 
30498e93258fSBjoern A. Zeeb 	ret = info->ltr_set(rtwdev, true);
30508e93258fSBjoern A. Zeeb 	if (ret) {
30518e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "pci ltr set fail\n");
30528e93258fSBjoern A. Zeeb 		return ret;
30538e93258fSBjoern A. Zeeb 	}
30548e93258fSBjoern A. Zeeb 	if (chip_id == RTL8852A) {
30558e93258fSBjoern A. Zeeb 		/* ltr sw trigger */
30568e93258fSBjoern A. Zeeb 		rtw89_write32_set(rtwdev, R_AX_LTR_CTRL_0, B_AX_APP_LTR_ACT);
30578e93258fSBjoern A. Zeeb 	}
3058*6d67aabdSBjoern A. Zeeb 	if (chip_id == RTL8852A || rtw89_is_rtl885xb(rtwdev)) {
30598e93258fSBjoern A. Zeeb 		/* ADDR info 8-byte mode */
30608e93258fSBjoern A. Zeeb 		rtw89_write32_set(rtwdev, R_AX_TX_ADDRESS_INFO_MODE_SETTING,
30618e93258fSBjoern A. Zeeb 				  B_AX_HOST_ADDR_INFO_8B_SEL);
30628e93258fSBjoern A. Zeeb 		rtw89_write32_clr(rtwdev, R_AX_PKTIN_SETTING, B_AX_WD_ADDR_INFO_LENGTH);
30638e93258fSBjoern A. Zeeb 	}
30648e93258fSBjoern A. Zeeb 
30658e93258fSBjoern A. Zeeb 	/* enable DMA for all queues */
3066*6d67aabdSBjoern A. Zeeb 	rtw89_pci_ctrl_txdma_ch_ax(rtwdev, true);
30678e93258fSBjoern A. Zeeb 
30688e93258fSBjoern A. Zeeb 	/* Release PCI IO */
3069e2340276SBjoern A. Zeeb 	rtw89_write32_clr(rtwdev, info->dma_stop1.addr,
30708e93258fSBjoern A. Zeeb 			  B_AX_STOP_WPDMA | B_AX_STOP_PCIEIO);
30718e93258fSBjoern A. Zeeb 
30728e93258fSBjoern A. Zeeb 	return 0;
30738e93258fSBjoern A. Zeeb }
30748e93258fSBjoern A. Zeeb 
30758e93258fSBjoern A. Zeeb static int rtw89_pci_claim_device(struct rtw89_dev *rtwdev,
30768e93258fSBjoern A. Zeeb 				  struct pci_dev *pdev)
30778e93258fSBjoern A. Zeeb {
30788e93258fSBjoern A. Zeeb 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
30798e93258fSBjoern A. Zeeb 	int ret;
30808e93258fSBjoern A. Zeeb 
30818e93258fSBjoern A. Zeeb 	ret = pci_enable_device(pdev);
30828e93258fSBjoern A. Zeeb 	if (ret) {
30838e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "failed to enable pci device\n");
30848e93258fSBjoern A. Zeeb 		return ret;
30858e93258fSBjoern A. Zeeb 	}
30868e93258fSBjoern A. Zeeb 
30878e93258fSBjoern A. Zeeb 	pci_set_master(pdev);
30888e93258fSBjoern A. Zeeb 	pci_set_drvdata(pdev, rtwdev->hw);
30898e93258fSBjoern A. Zeeb 
30908e93258fSBjoern A. Zeeb 	rtwpci->pdev = pdev;
30918e93258fSBjoern A. Zeeb 
30928e93258fSBjoern A. Zeeb 	return 0;
30938e93258fSBjoern A. Zeeb }
30948e93258fSBjoern A. Zeeb 
30958e93258fSBjoern A. Zeeb static void rtw89_pci_declaim_device(struct rtw89_dev *rtwdev,
30968e93258fSBjoern A. Zeeb 				     struct pci_dev *pdev)
30978e93258fSBjoern A. Zeeb {
30988e93258fSBjoern A. Zeeb 	pci_disable_device(pdev);
30998e93258fSBjoern A. Zeeb }
31008e93258fSBjoern A. Zeeb 
3101*6d67aabdSBjoern A. Zeeb static void rtw89_pci_cfg_dac(struct rtw89_dev *rtwdev)
3102*6d67aabdSBjoern A. Zeeb {
3103*6d67aabdSBjoern A. Zeeb 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
3104*6d67aabdSBjoern A. Zeeb 	const struct rtw89_chip_info *chip = rtwdev->chip;
3105*6d67aabdSBjoern A. Zeeb 
3106*6d67aabdSBjoern A. Zeeb 	if (!rtwpci->enable_dac)
3107*6d67aabdSBjoern A. Zeeb 		return;
3108*6d67aabdSBjoern A. Zeeb 
3109*6d67aabdSBjoern A. Zeeb 	switch (chip->chip_id) {
3110*6d67aabdSBjoern A. Zeeb 	case RTL8852A:
3111*6d67aabdSBjoern A. Zeeb 	case RTL8852B:
3112*6d67aabdSBjoern A. Zeeb 	case RTL8851B:
3113*6d67aabdSBjoern A. Zeeb 	case RTL8852BT:
3114*6d67aabdSBjoern A. Zeeb 		break;
3115*6d67aabdSBjoern A. Zeeb 	default:
3116*6d67aabdSBjoern A. Zeeb 		return;
3117*6d67aabdSBjoern A. Zeeb 	}
3118*6d67aabdSBjoern A. Zeeb 
3119*6d67aabdSBjoern A. Zeeb 	rtw89_pci_config_byte_set(rtwdev, RTW89_PCIE_L1_CTRL, RTW89_PCIE_BIT_EN_64BITS);
3120*6d67aabdSBjoern A. Zeeb }
3121*6d67aabdSBjoern A. Zeeb 
31228e93258fSBjoern A. Zeeb static int rtw89_pci_setup_mapping(struct rtw89_dev *rtwdev,
31238e93258fSBjoern A. Zeeb 				   struct pci_dev *pdev)
31248e93258fSBjoern A. Zeeb {
31258e93258fSBjoern A. Zeeb 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
31268e93258fSBjoern A. Zeeb 	unsigned long resource_len;
31278e93258fSBjoern A. Zeeb 	u8 bar_id = 2;
31288e93258fSBjoern A. Zeeb 	int ret;
31298e93258fSBjoern A. Zeeb 
31308e93258fSBjoern A. Zeeb 	ret = pci_request_regions(pdev, KBUILD_MODNAME);
31318e93258fSBjoern A. Zeeb 	if (ret) {
31328e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "failed to request pci regions\n");
31338e93258fSBjoern A. Zeeb 		goto err;
31348e93258fSBjoern A. Zeeb 	}
31358e93258fSBjoern A. Zeeb 
3136*6d67aabdSBjoern A. Zeeb 	ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(36));
3137*6d67aabdSBjoern A. Zeeb 	if (!ret) {
3138*6d67aabdSBjoern A. Zeeb 		rtwpci->enable_dac = true;
3139*6d67aabdSBjoern A. Zeeb 		rtw89_pci_cfg_dac(rtwdev);
3140*6d67aabdSBjoern A. Zeeb 	} else {
3141*6d67aabdSBjoern A. Zeeb 		ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
31428e93258fSBjoern A. Zeeb 		if (ret) {
3143*6d67aabdSBjoern A. Zeeb 			rtw89_err(rtwdev,
3144*6d67aabdSBjoern A. Zeeb 				  "failed to set dma and consistent mask to 32/36-bit\n");
31458e93258fSBjoern A. Zeeb 			goto err_release_regions;
31468e93258fSBjoern A. Zeeb 		}
31478e93258fSBjoern A. Zeeb 	}
31488e93258fSBjoern A. Zeeb 
31498e93258fSBjoern A. Zeeb #if defined(__FreeBSD__)
31508e93258fSBjoern A. Zeeb 	linuxkpi_pcim_want_to_use_bus_functions(pdev);
31518e93258fSBjoern A. Zeeb #endif
31528e93258fSBjoern A. Zeeb 	resource_len = pci_resource_len(pdev, bar_id);
31538e93258fSBjoern A. Zeeb 	rtwpci->mmap = pci_iomap(pdev, bar_id, resource_len);
31548e93258fSBjoern A. Zeeb 	if (!rtwpci->mmap) {
31558e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "failed to map pci io\n");
31568e93258fSBjoern A. Zeeb 		ret = -EIO;
31578e93258fSBjoern A. Zeeb 		goto err_release_regions;
31588e93258fSBjoern A. Zeeb 	}
31598e93258fSBjoern A. Zeeb 
31608e93258fSBjoern A. Zeeb 	return 0;
31618e93258fSBjoern A. Zeeb 
31628e93258fSBjoern A. Zeeb err_release_regions:
31638e93258fSBjoern A. Zeeb 	pci_release_regions(pdev);
31648e93258fSBjoern A. Zeeb err:
31658e93258fSBjoern A. Zeeb 	return ret;
31668e93258fSBjoern A. Zeeb }
31678e93258fSBjoern A. Zeeb 
31688e93258fSBjoern A. Zeeb static void rtw89_pci_clear_mapping(struct rtw89_dev *rtwdev,
31698e93258fSBjoern A. Zeeb 				    struct pci_dev *pdev)
31708e93258fSBjoern A. Zeeb {
31718e93258fSBjoern A. Zeeb 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
31728e93258fSBjoern A. Zeeb 
31738e93258fSBjoern A. Zeeb 	if (rtwpci->mmap) {
31748e93258fSBjoern A. Zeeb 		pci_iounmap(pdev, rtwpci->mmap);
31758e93258fSBjoern A. Zeeb 		pci_release_regions(pdev);
31768e93258fSBjoern A. Zeeb 	}
31778e93258fSBjoern A. Zeeb }
31788e93258fSBjoern A. Zeeb 
31798e93258fSBjoern A. Zeeb static void rtw89_pci_free_tx_wd_ring(struct rtw89_dev *rtwdev,
31808e93258fSBjoern A. Zeeb 				      struct pci_dev *pdev,
31818e93258fSBjoern A. Zeeb 				      struct rtw89_pci_tx_ring *tx_ring)
31828e93258fSBjoern A. Zeeb {
31838e93258fSBjoern A. Zeeb 	struct rtw89_pci_tx_wd_ring *wd_ring = &tx_ring->wd_ring;
31848e93258fSBjoern A. Zeeb 	u8 *head = wd_ring->head;
31858e93258fSBjoern A. Zeeb 	dma_addr_t dma = wd_ring->dma;
31868e93258fSBjoern A. Zeeb 	u32 page_size = wd_ring->page_size;
31878e93258fSBjoern A. Zeeb 	u32 page_num = wd_ring->page_num;
31888e93258fSBjoern A. Zeeb 	u32 ring_sz = page_size * page_num;
31898e93258fSBjoern A. Zeeb 
31908e93258fSBjoern A. Zeeb 	dma_free_coherent(&pdev->dev, ring_sz, head, dma);
31918e93258fSBjoern A. Zeeb 	wd_ring->head = NULL;
31928e93258fSBjoern A. Zeeb }
31938e93258fSBjoern A. Zeeb 
31948e93258fSBjoern A. Zeeb static void rtw89_pci_free_tx_ring(struct rtw89_dev *rtwdev,
31958e93258fSBjoern A. Zeeb 				   struct pci_dev *pdev,
31968e93258fSBjoern A. Zeeb 				   struct rtw89_pci_tx_ring *tx_ring)
31978e93258fSBjoern A. Zeeb {
31988e93258fSBjoern A. Zeeb 	int ring_sz;
31998e93258fSBjoern A. Zeeb 	u8 *head;
32008e93258fSBjoern A. Zeeb 	dma_addr_t dma;
32018e93258fSBjoern A. Zeeb 
32028e93258fSBjoern A. Zeeb 	head = tx_ring->bd_ring.head;
32038e93258fSBjoern A. Zeeb 	dma = tx_ring->bd_ring.dma;
32048e93258fSBjoern A. Zeeb 	ring_sz = tx_ring->bd_ring.desc_size * tx_ring->bd_ring.len;
32058e93258fSBjoern A. Zeeb 	dma_free_coherent(&pdev->dev, ring_sz, head, dma);
32068e93258fSBjoern A. Zeeb 
32078e93258fSBjoern A. Zeeb 	tx_ring->bd_ring.head = NULL;
32088e93258fSBjoern A. Zeeb }
32098e93258fSBjoern A. Zeeb 
32108e93258fSBjoern A. Zeeb static void rtw89_pci_free_tx_rings(struct rtw89_dev *rtwdev,
32118e93258fSBjoern A. Zeeb 				    struct pci_dev *pdev)
32128e93258fSBjoern A. Zeeb {
32138e93258fSBjoern A. Zeeb 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
3214e2340276SBjoern A. Zeeb 	const struct rtw89_pci_info *info = rtwdev->pci_info;
32158e93258fSBjoern A. Zeeb 	struct rtw89_pci_tx_ring *tx_ring;
32168e93258fSBjoern A. Zeeb 	int i;
32178e93258fSBjoern A. Zeeb 
32188e93258fSBjoern A. Zeeb 	for (i = 0; i < RTW89_TXCH_NUM; i++) {
3219e2340276SBjoern A. Zeeb 		if (info->tx_dma_ch_mask & BIT(i))
3220e2340276SBjoern A. Zeeb 			continue;
32218e93258fSBjoern A. Zeeb 		tx_ring = &rtwpci->tx_rings[i];
32228e93258fSBjoern A. Zeeb 		rtw89_pci_free_tx_wd_ring(rtwdev, pdev, tx_ring);
32238e93258fSBjoern A. Zeeb 		rtw89_pci_free_tx_ring(rtwdev, pdev, tx_ring);
32248e93258fSBjoern A. Zeeb 	}
32258e93258fSBjoern A. Zeeb }
32268e93258fSBjoern A. Zeeb 
32278e93258fSBjoern A. Zeeb static void rtw89_pci_free_rx_ring(struct rtw89_dev *rtwdev,
32288e93258fSBjoern A. Zeeb 				   struct pci_dev *pdev,
32298e93258fSBjoern A. Zeeb 				   struct rtw89_pci_rx_ring *rx_ring)
32308e93258fSBjoern A. Zeeb {
32318e93258fSBjoern A. Zeeb 	struct rtw89_pci_rx_info *rx_info;
32328e93258fSBjoern A. Zeeb 	struct sk_buff *skb;
32338e93258fSBjoern A. Zeeb 	dma_addr_t dma;
32348e93258fSBjoern A. Zeeb 	u32 buf_sz;
32358e93258fSBjoern A. Zeeb 	u8 *head;
32368e93258fSBjoern A. Zeeb 	int ring_sz = rx_ring->bd_ring.desc_size * rx_ring->bd_ring.len;
32378e93258fSBjoern A. Zeeb 	int i;
32388e93258fSBjoern A. Zeeb 
32398e93258fSBjoern A. Zeeb 	buf_sz = rx_ring->buf_sz;
32408e93258fSBjoern A. Zeeb 	for (i = 0; i < rx_ring->bd_ring.len; i++) {
32418e93258fSBjoern A. Zeeb 		skb = rx_ring->buf[i];
32428e93258fSBjoern A. Zeeb 		if (!skb)
32438e93258fSBjoern A. Zeeb 			continue;
32448e93258fSBjoern A. Zeeb 
32458e93258fSBjoern A. Zeeb 		rx_info = RTW89_PCI_RX_SKB_CB(skb);
32468e93258fSBjoern A. Zeeb 		dma = rx_info->dma;
32478e93258fSBjoern A. Zeeb 		dma_unmap_single(&pdev->dev, dma, buf_sz, DMA_FROM_DEVICE);
32488e93258fSBjoern A. Zeeb 		dev_kfree_skb(skb);
32498e93258fSBjoern A. Zeeb 		rx_ring->buf[i] = NULL;
32508e93258fSBjoern A. Zeeb 	}
32518e93258fSBjoern A. Zeeb 
32528e93258fSBjoern A. Zeeb 	head = rx_ring->bd_ring.head;
32538e93258fSBjoern A. Zeeb 	dma = rx_ring->bd_ring.dma;
32548e93258fSBjoern A. Zeeb 	dma_free_coherent(&pdev->dev, ring_sz, head, dma);
32558e93258fSBjoern A. Zeeb 
32568e93258fSBjoern A. Zeeb 	rx_ring->bd_ring.head = NULL;
32578e93258fSBjoern A. Zeeb }
32588e93258fSBjoern A. Zeeb 
32598e93258fSBjoern A. Zeeb static void rtw89_pci_free_rx_rings(struct rtw89_dev *rtwdev,
32608e93258fSBjoern A. Zeeb 				    struct pci_dev *pdev)
32618e93258fSBjoern A. Zeeb {
32628e93258fSBjoern A. Zeeb 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
32638e93258fSBjoern A. Zeeb 	struct rtw89_pci_rx_ring *rx_ring;
32648e93258fSBjoern A. Zeeb 	int i;
32658e93258fSBjoern A. Zeeb 
32668e93258fSBjoern A. Zeeb 	for (i = 0; i < RTW89_RXCH_NUM; i++) {
32678e93258fSBjoern A. Zeeb 		rx_ring = &rtwpci->rx_rings[i];
32688e93258fSBjoern A. Zeeb 		rtw89_pci_free_rx_ring(rtwdev, pdev, rx_ring);
32698e93258fSBjoern A. Zeeb 	}
32708e93258fSBjoern A. Zeeb }
32718e93258fSBjoern A. Zeeb 
32728e93258fSBjoern A. Zeeb static void rtw89_pci_free_trx_rings(struct rtw89_dev *rtwdev,
32738e93258fSBjoern A. Zeeb 				     struct pci_dev *pdev)
32748e93258fSBjoern A. Zeeb {
32758e93258fSBjoern A. Zeeb 	rtw89_pci_free_rx_rings(rtwdev, pdev);
32768e93258fSBjoern A. Zeeb 	rtw89_pci_free_tx_rings(rtwdev, pdev);
32778e93258fSBjoern A. Zeeb }
32788e93258fSBjoern A. Zeeb 
32798e93258fSBjoern A. Zeeb static int rtw89_pci_init_rx_bd(struct rtw89_dev *rtwdev, struct pci_dev *pdev,
32808e93258fSBjoern A. Zeeb 				struct rtw89_pci_rx_ring *rx_ring,
32818e93258fSBjoern A. Zeeb 				struct sk_buff *skb, int buf_sz, u32 idx)
32828e93258fSBjoern A. Zeeb {
32838e93258fSBjoern A. Zeeb 	struct rtw89_pci_rx_info *rx_info;
32848e93258fSBjoern A. Zeeb 	struct rtw89_pci_rx_bd_32 *rx_bd;
32858e93258fSBjoern A. Zeeb 	dma_addr_t dma;
32868e93258fSBjoern A. Zeeb 
32878e93258fSBjoern A. Zeeb 	if (!skb)
32888e93258fSBjoern A. Zeeb 		return -EINVAL;
32898e93258fSBjoern A. Zeeb 
32908e93258fSBjoern A. Zeeb 	dma = dma_map_single(&pdev->dev, skb->data, buf_sz, DMA_FROM_DEVICE);
32918e93258fSBjoern A. Zeeb 	if (dma_mapping_error(&pdev->dev, dma))
32928e93258fSBjoern A. Zeeb 		return -EBUSY;
32938e93258fSBjoern A. Zeeb 
32948e93258fSBjoern A. Zeeb 	rx_info = RTW89_PCI_RX_SKB_CB(skb);
32958e93258fSBjoern A. Zeeb 	rx_bd = RTW89_PCI_RX_BD(rx_ring, idx);
32968e93258fSBjoern A. Zeeb 
32978e93258fSBjoern A. Zeeb 	memset(rx_bd, 0, sizeof(*rx_bd));
32988e93258fSBjoern A. Zeeb 	rx_bd->buf_size = cpu_to_le16(buf_sz);
32998e93258fSBjoern A. Zeeb 	rx_bd->dma = cpu_to_le32(dma);
3300*6d67aabdSBjoern A. Zeeb 	rx_bd->opt = le16_encode_bits(upper_32_bits(dma), RTW89_PCI_RXBD_OPT_DMA_HI);
33018e93258fSBjoern A. Zeeb 	rx_info->dma = dma;
33028e93258fSBjoern A. Zeeb 
33038e93258fSBjoern A. Zeeb 	return 0;
33048e93258fSBjoern A. Zeeb }
33058e93258fSBjoern A. Zeeb 
33068e93258fSBjoern A. Zeeb static int rtw89_pci_alloc_tx_wd_ring(struct rtw89_dev *rtwdev,
33078e93258fSBjoern A. Zeeb 				      struct pci_dev *pdev,
33088e93258fSBjoern A. Zeeb 				      struct rtw89_pci_tx_ring *tx_ring,
33098e93258fSBjoern A. Zeeb 				      enum rtw89_tx_channel txch)
33108e93258fSBjoern A. Zeeb {
33118e93258fSBjoern A. Zeeb 	struct rtw89_pci_tx_wd_ring *wd_ring = &tx_ring->wd_ring;
33128e93258fSBjoern A. Zeeb 	struct rtw89_pci_tx_wd *txwd;
33138e93258fSBjoern A. Zeeb 	dma_addr_t dma;
33148e93258fSBjoern A. Zeeb 	dma_addr_t cur_paddr;
33158e93258fSBjoern A. Zeeb 	u8 *head;
33168e93258fSBjoern A. Zeeb 	u8 *cur_vaddr;
33178e93258fSBjoern A. Zeeb 	u32 page_size = RTW89_PCI_TXWD_PAGE_SIZE;
33188e93258fSBjoern A. Zeeb 	u32 page_num = RTW89_PCI_TXWD_NUM_MAX;
33198e93258fSBjoern A. Zeeb 	u32 ring_sz = page_size * page_num;
33208e93258fSBjoern A. Zeeb 	u32 page_offset;
33218e93258fSBjoern A. Zeeb 	int i;
33228e93258fSBjoern A. Zeeb 
33238e93258fSBjoern A. Zeeb 	/* FWCMD queue doesn't use txwd as pages */
33248e93258fSBjoern A. Zeeb 	if (txch == RTW89_TXCH_CH12)
33258e93258fSBjoern A. Zeeb 		return 0;
33268e93258fSBjoern A. Zeeb 
33278e93258fSBjoern A. Zeeb 	head = dma_alloc_coherent(&pdev->dev, ring_sz, &dma, GFP_KERNEL);
33288e93258fSBjoern A. Zeeb 	if (!head)
33298e93258fSBjoern A. Zeeb 		return -ENOMEM;
33308e93258fSBjoern A. Zeeb 
33318e93258fSBjoern A. Zeeb 	INIT_LIST_HEAD(&wd_ring->free_pages);
33328e93258fSBjoern A. Zeeb 	wd_ring->head = head;
33338e93258fSBjoern A. Zeeb 	wd_ring->dma = dma;
33348e93258fSBjoern A. Zeeb 	wd_ring->page_size = page_size;
33358e93258fSBjoern A. Zeeb 	wd_ring->page_num = page_num;
33368e93258fSBjoern A. Zeeb 
33378e93258fSBjoern A. Zeeb 	page_offset = 0;
33388e93258fSBjoern A. Zeeb 	for (i = 0; i < page_num; i++) {
33398e93258fSBjoern A. Zeeb 		txwd = &wd_ring->pages[i];
33408e93258fSBjoern A. Zeeb 		cur_paddr = dma + page_offset;
33418e93258fSBjoern A. Zeeb 		cur_vaddr = head + page_offset;
33428e93258fSBjoern A. Zeeb 
33438e93258fSBjoern A. Zeeb 		skb_queue_head_init(&txwd->queue);
33448e93258fSBjoern A. Zeeb 		INIT_LIST_HEAD(&txwd->list);
33458e93258fSBjoern A. Zeeb 		txwd->paddr = cur_paddr;
33468e93258fSBjoern A. Zeeb 		txwd->vaddr = cur_vaddr;
33478e93258fSBjoern A. Zeeb 		txwd->len = page_size;
33488e93258fSBjoern A. Zeeb 		txwd->seq = i;
33498e93258fSBjoern A. Zeeb 		rtw89_pci_enqueue_txwd(tx_ring, txwd);
33508e93258fSBjoern A. Zeeb 
33518e93258fSBjoern A. Zeeb 		page_offset += page_size;
33528e93258fSBjoern A. Zeeb 	}
33538e93258fSBjoern A. Zeeb 
33548e93258fSBjoern A. Zeeb 	return 0;
33558e93258fSBjoern A. Zeeb }
33568e93258fSBjoern A. Zeeb 
33578e93258fSBjoern A. Zeeb static int rtw89_pci_alloc_tx_ring(struct rtw89_dev *rtwdev,
33588e93258fSBjoern A. Zeeb 				   struct pci_dev *pdev,
33598e93258fSBjoern A. Zeeb 				   struct rtw89_pci_tx_ring *tx_ring,
33608e93258fSBjoern A. Zeeb 				   u32 desc_size, u32 len,
33618e93258fSBjoern A. Zeeb 				   enum rtw89_tx_channel txch)
33628e93258fSBjoern A. Zeeb {
33638e93258fSBjoern A. Zeeb 	const struct rtw89_pci_ch_dma_addr *txch_addr;
33648e93258fSBjoern A. Zeeb 	int ring_sz = desc_size * len;
33658e93258fSBjoern A. Zeeb 	u8 *head;
33668e93258fSBjoern A. Zeeb 	dma_addr_t dma;
33678e93258fSBjoern A. Zeeb 	int ret;
33688e93258fSBjoern A. Zeeb 
33698e93258fSBjoern A. Zeeb 	ret = rtw89_pci_alloc_tx_wd_ring(rtwdev, pdev, tx_ring, txch);
33708e93258fSBjoern A. Zeeb 	if (ret) {
33718e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "failed to alloc txwd ring of txch %d\n", txch);
33728e93258fSBjoern A. Zeeb 		goto err;
33738e93258fSBjoern A. Zeeb 	}
33748e93258fSBjoern A. Zeeb 
33758e93258fSBjoern A. Zeeb 	ret = rtw89_pci_get_txch_addrs(rtwdev, txch, &txch_addr);
33768e93258fSBjoern A. Zeeb 	if (ret) {
33778e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "failed to get address of txch %d", txch);
33788e93258fSBjoern A. Zeeb 		goto err_free_wd_ring;
33798e93258fSBjoern A. Zeeb 	}
33808e93258fSBjoern A. Zeeb 
33818e93258fSBjoern A. Zeeb 	head = dma_alloc_coherent(&pdev->dev, ring_sz, &dma, GFP_KERNEL);
33828e93258fSBjoern A. Zeeb 	if (!head) {
33838e93258fSBjoern A. Zeeb 		ret = -ENOMEM;
33848e93258fSBjoern A. Zeeb 		goto err_free_wd_ring;
33858e93258fSBjoern A. Zeeb 	}
33868e93258fSBjoern A. Zeeb 
33878e93258fSBjoern A. Zeeb 	INIT_LIST_HEAD(&tx_ring->busy_pages);
33888e93258fSBjoern A. Zeeb 	tx_ring->bd_ring.head = head;
33898e93258fSBjoern A. Zeeb 	tx_ring->bd_ring.dma = dma;
33908e93258fSBjoern A. Zeeb 	tx_ring->bd_ring.len = len;
33918e93258fSBjoern A. Zeeb 	tx_ring->bd_ring.desc_size = desc_size;
33928e93258fSBjoern A. Zeeb 	tx_ring->bd_ring.addr = *txch_addr;
33938e93258fSBjoern A. Zeeb 	tx_ring->bd_ring.wp = 0;
33948e93258fSBjoern A. Zeeb 	tx_ring->bd_ring.rp = 0;
33958e93258fSBjoern A. Zeeb 	tx_ring->txch = txch;
33968e93258fSBjoern A. Zeeb 
33978e93258fSBjoern A. Zeeb 	return 0;
33988e93258fSBjoern A. Zeeb 
33998e93258fSBjoern A. Zeeb err_free_wd_ring:
34008e93258fSBjoern A. Zeeb 	rtw89_pci_free_tx_wd_ring(rtwdev, pdev, tx_ring);
34018e93258fSBjoern A. Zeeb err:
34028e93258fSBjoern A. Zeeb 	return ret;
34038e93258fSBjoern A. Zeeb }
34048e93258fSBjoern A. Zeeb 
34058e93258fSBjoern A. Zeeb static int rtw89_pci_alloc_tx_rings(struct rtw89_dev *rtwdev,
34068e93258fSBjoern A. Zeeb 				    struct pci_dev *pdev)
34078e93258fSBjoern A. Zeeb {
34088e93258fSBjoern A. Zeeb 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
3409e2340276SBjoern A. Zeeb 	const struct rtw89_pci_info *info = rtwdev->pci_info;
34108e93258fSBjoern A. Zeeb 	struct rtw89_pci_tx_ring *tx_ring;
34118e93258fSBjoern A. Zeeb 	u32 desc_size;
34128e93258fSBjoern A. Zeeb 	u32 len;
34138e93258fSBjoern A. Zeeb 	u32 i, tx_allocated;
34148e93258fSBjoern A. Zeeb 	int ret;
34158e93258fSBjoern A. Zeeb 
34168e93258fSBjoern A. Zeeb 	for (i = 0; i < RTW89_TXCH_NUM; i++) {
3417e2340276SBjoern A. Zeeb 		if (info->tx_dma_ch_mask & BIT(i))
3418e2340276SBjoern A. Zeeb 			continue;
34198e93258fSBjoern A. Zeeb 		tx_ring = &rtwpci->tx_rings[i];
34208e93258fSBjoern A. Zeeb 		desc_size = sizeof(struct rtw89_pci_tx_bd_32);
34218e93258fSBjoern A. Zeeb 		len = RTW89_PCI_TXBD_NUM_MAX;
34228e93258fSBjoern A. Zeeb 		ret = rtw89_pci_alloc_tx_ring(rtwdev, pdev, tx_ring,
34238e93258fSBjoern A. Zeeb 					      desc_size, len, i);
34248e93258fSBjoern A. Zeeb 		if (ret) {
34258e93258fSBjoern A. Zeeb #if defined(__linux__)
34268e93258fSBjoern A. Zeeb 			rtw89_err(rtwdev, "failed to alloc tx ring %d\n", i);
34278e93258fSBjoern A. Zeeb #elif defined(__FreeBSD__)
34288e93258fSBjoern A. Zeeb 			rtw89_err(rtwdev, "failed to alloc tx ring %d: ret=%d\n", i, ret);
34298e93258fSBjoern A. Zeeb #endif
34308e93258fSBjoern A. Zeeb 			goto err_free;
34318e93258fSBjoern A. Zeeb 		}
34328e93258fSBjoern A. Zeeb 	}
34338e93258fSBjoern A. Zeeb 
34348e93258fSBjoern A. Zeeb 	return 0;
34358e93258fSBjoern A. Zeeb 
34368e93258fSBjoern A. Zeeb err_free:
34378e93258fSBjoern A. Zeeb 	tx_allocated = i;
34388e93258fSBjoern A. Zeeb 	for (i = 0; i < tx_allocated; i++) {
34398e93258fSBjoern A. Zeeb 		tx_ring = &rtwpci->tx_rings[i];
34408e93258fSBjoern A. Zeeb 		rtw89_pci_free_tx_ring(rtwdev, pdev, tx_ring);
34418e93258fSBjoern A. Zeeb 	}
34428e93258fSBjoern A. Zeeb 
34438e93258fSBjoern A. Zeeb 	return ret;
34448e93258fSBjoern A. Zeeb }
34458e93258fSBjoern A. Zeeb 
34468e93258fSBjoern A. Zeeb static int rtw89_pci_alloc_rx_ring(struct rtw89_dev *rtwdev,
34478e93258fSBjoern A. Zeeb 				   struct pci_dev *pdev,
34488e93258fSBjoern A. Zeeb 				   struct rtw89_pci_rx_ring *rx_ring,
34498e93258fSBjoern A. Zeeb 				   u32 desc_size, u32 len, u32 rxch)
34508e93258fSBjoern A. Zeeb {
3451*6d67aabdSBjoern A. Zeeb 	const struct rtw89_pci_info *info = rtwdev->pci_info;
34528e93258fSBjoern A. Zeeb 	const struct rtw89_pci_ch_dma_addr *rxch_addr;
34538e93258fSBjoern A. Zeeb 	struct sk_buff *skb;
34548e93258fSBjoern A. Zeeb 	u8 *head;
34558e93258fSBjoern A. Zeeb 	dma_addr_t dma;
34568e93258fSBjoern A. Zeeb 	int ring_sz = desc_size * len;
34578e93258fSBjoern A. Zeeb 	int buf_sz = RTW89_PCI_RX_BUF_SIZE;
34588e93258fSBjoern A. Zeeb 	int i, allocated;
34598e93258fSBjoern A. Zeeb 	int ret;
34608e93258fSBjoern A. Zeeb 
34618e93258fSBjoern A. Zeeb 	ret = rtw89_pci_get_rxch_addrs(rtwdev, rxch, &rxch_addr);
34628e93258fSBjoern A. Zeeb 	if (ret) {
34638e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "failed to get address of rxch %d", rxch);
34648e93258fSBjoern A. Zeeb 		return ret;
34658e93258fSBjoern A. Zeeb 	}
34668e93258fSBjoern A. Zeeb 
34678e93258fSBjoern A. Zeeb 	head = dma_alloc_coherent(&pdev->dev, ring_sz, &dma, GFP_KERNEL);
34688e93258fSBjoern A. Zeeb 	if (!head) {
34698e93258fSBjoern A. Zeeb 		ret = -ENOMEM;
34708e93258fSBjoern A. Zeeb 		goto err;
34718e93258fSBjoern A. Zeeb 	}
34728e93258fSBjoern A. Zeeb 
34738e93258fSBjoern A. Zeeb 	rx_ring->bd_ring.head = head;
34748e93258fSBjoern A. Zeeb 	rx_ring->bd_ring.dma = dma;
34758e93258fSBjoern A. Zeeb 	rx_ring->bd_ring.len = len;
34768e93258fSBjoern A. Zeeb 	rx_ring->bd_ring.desc_size = desc_size;
34778e93258fSBjoern A. Zeeb 	rx_ring->bd_ring.addr = *rxch_addr;
3478*6d67aabdSBjoern A. Zeeb 	if (info->rx_ring_eq_is_full)
3479*6d67aabdSBjoern A. Zeeb 		rx_ring->bd_ring.wp = len - 1;
3480*6d67aabdSBjoern A. Zeeb 	else
34818e93258fSBjoern A. Zeeb 		rx_ring->bd_ring.wp = 0;
34828e93258fSBjoern A. Zeeb 	rx_ring->bd_ring.rp = 0;
34838e93258fSBjoern A. Zeeb 	rx_ring->buf_sz = buf_sz;
34848e93258fSBjoern A. Zeeb 	rx_ring->diliver_skb = NULL;
34858e93258fSBjoern A. Zeeb 	rx_ring->diliver_desc.ready = false;
3486*6d67aabdSBjoern A. Zeeb 	rx_ring->target_rx_tag = 0;
34878e93258fSBjoern A. Zeeb 
34888e93258fSBjoern A. Zeeb 	for (i = 0; i < len; i++) {
34898e93258fSBjoern A. Zeeb 		skb = dev_alloc_skb(buf_sz);
34908e93258fSBjoern A. Zeeb 		if (!skb) {
34918e93258fSBjoern A. Zeeb 			ret = -ENOMEM;
34928e93258fSBjoern A. Zeeb 			goto err_free;
34938e93258fSBjoern A. Zeeb 		}
34948e93258fSBjoern A. Zeeb 
34958e93258fSBjoern A. Zeeb 		memset(skb->data, 0, buf_sz);
34968e93258fSBjoern A. Zeeb 		rx_ring->buf[i] = skb;
34978e93258fSBjoern A. Zeeb 		ret = rtw89_pci_init_rx_bd(rtwdev, pdev, rx_ring, skb,
34988e93258fSBjoern A. Zeeb 					   buf_sz, i);
34998e93258fSBjoern A. Zeeb 		if (ret) {
35008e93258fSBjoern A. Zeeb #if defined(__linux__)
35018e93258fSBjoern A. Zeeb 			rtw89_err(rtwdev, "failed to init rx buf %d\n", i);
35028e93258fSBjoern A. Zeeb #elif defined(__FreeBSD__)
35038e93258fSBjoern A. Zeeb 			rtw89_err(rtwdev, "failed to init rx buf %d ret=%d\n", i, ret);
35048e93258fSBjoern A. Zeeb #endif
35058e93258fSBjoern A. Zeeb 			dev_kfree_skb_any(skb);
35068e93258fSBjoern A. Zeeb 			rx_ring->buf[i] = NULL;
35078e93258fSBjoern A. Zeeb 			goto err_free;
35088e93258fSBjoern A. Zeeb 		}
35098e93258fSBjoern A. Zeeb 	}
35108e93258fSBjoern A. Zeeb 
35118e93258fSBjoern A. Zeeb 	return 0;
35128e93258fSBjoern A. Zeeb 
35138e93258fSBjoern A. Zeeb err_free:
35148e93258fSBjoern A. Zeeb 	allocated = i;
35158e93258fSBjoern A. Zeeb 	for (i = 0; i < allocated; i++) {
35168e93258fSBjoern A. Zeeb 		skb = rx_ring->buf[i];
35178e93258fSBjoern A. Zeeb 		if (!skb)
35188e93258fSBjoern A. Zeeb 			continue;
35198e93258fSBjoern A. Zeeb 		dma = *((dma_addr_t *)skb->cb);
35208e93258fSBjoern A. Zeeb 		dma_unmap_single(&pdev->dev, dma, buf_sz, DMA_FROM_DEVICE);
35218e93258fSBjoern A. Zeeb 		dev_kfree_skb(skb);
35228e93258fSBjoern A. Zeeb 		rx_ring->buf[i] = NULL;
35238e93258fSBjoern A. Zeeb 	}
35248e93258fSBjoern A. Zeeb 
35258e93258fSBjoern A. Zeeb 	head = rx_ring->bd_ring.head;
35268e93258fSBjoern A. Zeeb 	dma = rx_ring->bd_ring.dma;
35278e93258fSBjoern A. Zeeb 	dma_free_coherent(&pdev->dev, ring_sz, head, dma);
35288e93258fSBjoern A. Zeeb 
35298e93258fSBjoern A. Zeeb 	rx_ring->bd_ring.head = NULL;
35308e93258fSBjoern A. Zeeb err:
35318e93258fSBjoern A. Zeeb 	return ret;
35328e93258fSBjoern A. Zeeb }
35338e93258fSBjoern A. Zeeb 
35348e93258fSBjoern A. Zeeb static int rtw89_pci_alloc_rx_rings(struct rtw89_dev *rtwdev,
35358e93258fSBjoern A. Zeeb 				    struct pci_dev *pdev)
35368e93258fSBjoern A. Zeeb {
35378e93258fSBjoern A. Zeeb 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
35388e93258fSBjoern A. Zeeb 	struct rtw89_pci_rx_ring *rx_ring;
35398e93258fSBjoern A. Zeeb 	u32 desc_size;
35408e93258fSBjoern A. Zeeb 	u32 len;
35418e93258fSBjoern A. Zeeb 	int i, rx_allocated;
35428e93258fSBjoern A. Zeeb 	int ret;
35438e93258fSBjoern A. Zeeb 
35448e93258fSBjoern A. Zeeb 	for (i = 0; i < RTW89_RXCH_NUM; i++) {
35458e93258fSBjoern A. Zeeb 		rx_ring = &rtwpci->rx_rings[i];
35468e93258fSBjoern A. Zeeb 		desc_size = sizeof(struct rtw89_pci_rx_bd_32);
35478e93258fSBjoern A. Zeeb 		len = RTW89_PCI_RXBD_NUM_MAX;
35488e93258fSBjoern A. Zeeb 		ret = rtw89_pci_alloc_rx_ring(rtwdev, pdev, rx_ring,
35498e93258fSBjoern A. Zeeb 					      desc_size, len, i);
35508e93258fSBjoern A. Zeeb 		if (ret) {
35518e93258fSBjoern A. Zeeb 			rtw89_err(rtwdev, "failed to alloc rx ring %d\n", i);
35528e93258fSBjoern A. Zeeb 			goto err_free;
35538e93258fSBjoern A. Zeeb 		}
35548e93258fSBjoern A. Zeeb 	}
35558e93258fSBjoern A. Zeeb 
35568e93258fSBjoern A. Zeeb 	return 0;
35578e93258fSBjoern A. Zeeb 
35588e93258fSBjoern A. Zeeb err_free:
35598e93258fSBjoern A. Zeeb 	rx_allocated = i;
35608e93258fSBjoern A. Zeeb 	for (i = 0; i < rx_allocated; i++) {
35618e93258fSBjoern A. Zeeb 		rx_ring = &rtwpci->rx_rings[i];
35628e93258fSBjoern A. Zeeb 		rtw89_pci_free_rx_ring(rtwdev, pdev, rx_ring);
35638e93258fSBjoern A. Zeeb 	}
35648e93258fSBjoern A. Zeeb 
35658e93258fSBjoern A. Zeeb 	return ret;
35668e93258fSBjoern A. Zeeb }
35678e93258fSBjoern A. Zeeb 
35688e93258fSBjoern A. Zeeb static int rtw89_pci_alloc_trx_rings(struct rtw89_dev *rtwdev,
35698e93258fSBjoern A. Zeeb 				     struct pci_dev *pdev)
35708e93258fSBjoern A. Zeeb {
35718e93258fSBjoern A. Zeeb 	int ret;
35728e93258fSBjoern A. Zeeb 
35738e93258fSBjoern A. Zeeb 	ret = rtw89_pci_alloc_tx_rings(rtwdev, pdev);
35748e93258fSBjoern A. Zeeb 	if (ret) {
35758e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "failed to alloc dma tx rings\n");
35768e93258fSBjoern A. Zeeb 		goto err;
35778e93258fSBjoern A. Zeeb 	}
35788e93258fSBjoern A. Zeeb 
35798e93258fSBjoern A. Zeeb 	ret = rtw89_pci_alloc_rx_rings(rtwdev, pdev);
35808e93258fSBjoern A. Zeeb 	if (ret) {
35818e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "failed to alloc dma rx rings\n");
35828e93258fSBjoern A. Zeeb 		goto err_free_tx_rings;
35838e93258fSBjoern A. Zeeb 	}
35848e93258fSBjoern A. Zeeb 
35858e93258fSBjoern A. Zeeb 	return 0;
35868e93258fSBjoern A. Zeeb 
35878e93258fSBjoern A. Zeeb err_free_tx_rings:
35888e93258fSBjoern A. Zeeb 	rtw89_pci_free_tx_rings(rtwdev, pdev);
35898e93258fSBjoern A. Zeeb err:
35908e93258fSBjoern A. Zeeb 	return ret;
35918e93258fSBjoern A. Zeeb }
35928e93258fSBjoern A. Zeeb 
35938e93258fSBjoern A. Zeeb static void rtw89_pci_h2c_init(struct rtw89_dev *rtwdev,
35948e93258fSBjoern A. Zeeb 			       struct rtw89_pci *rtwpci)
35958e93258fSBjoern A. Zeeb {
35968e93258fSBjoern A. Zeeb 	skb_queue_head_init(&rtwpci->h2c_queue);
35978e93258fSBjoern A. Zeeb 	skb_queue_head_init(&rtwpci->h2c_release_queue);
35988e93258fSBjoern A. Zeeb }
35998e93258fSBjoern A. Zeeb 
36008e93258fSBjoern A. Zeeb static int rtw89_pci_setup_resource(struct rtw89_dev *rtwdev,
36018e93258fSBjoern A. Zeeb 				    struct pci_dev *pdev)
36028e93258fSBjoern A. Zeeb {
36038e93258fSBjoern A. Zeeb 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
36048e93258fSBjoern A. Zeeb 	int ret;
36058e93258fSBjoern A. Zeeb 
36068e93258fSBjoern A. Zeeb 	ret = rtw89_pci_setup_mapping(rtwdev, pdev);
36078e93258fSBjoern A. Zeeb 	if (ret) {
36088e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "failed to setup pci mapping\n");
36098e93258fSBjoern A. Zeeb 		goto err;
36108e93258fSBjoern A. Zeeb 	}
36118e93258fSBjoern A. Zeeb 
36128e93258fSBjoern A. Zeeb 	ret = rtw89_pci_alloc_trx_rings(rtwdev, pdev);
36138e93258fSBjoern A. Zeeb 	if (ret) {
36148e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "failed to alloc pci trx rings\n");
36158e93258fSBjoern A. Zeeb 		goto err_pci_unmap;
36168e93258fSBjoern A. Zeeb 	}
36178e93258fSBjoern A. Zeeb 
36188e93258fSBjoern A. Zeeb 	rtw89_pci_h2c_init(rtwdev, rtwpci);
36198e93258fSBjoern A. Zeeb 
36208e93258fSBjoern A. Zeeb 	spin_lock_init(&rtwpci->irq_lock);
36218e93258fSBjoern A. Zeeb 	spin_lock_init(&rtwpci->trx_lock);
36228e93258fSBjoern A. Zeeb 
36238e93258fSBjoern A. Zeeb 	return 0;
36248e93258fSBjoern A. Zeeb 
36258e93258fSBjoern A. Zeeb err_pci_unmap:
36268e93258fSBjoern A. Zeeb 	rtw89_pci_clear_mapping(rtwdev, pdev);
36278e93258fSBjoern A. Zeeb err:
36288e93258fSBjoern A. Zeeb 	return ret;
36298e93258fSBjoern A. Zeeb }
36308e93258fSBjoern A. Zeeb 
36318e93258fSBjoern A. Zeeb static void rtw89_pci_clear_resource(struct rtw89_dev *rtwdev,
36328e93258fSBjoern A. Zeeb 				     struct pci_dev *pdev)
36338e93258fSBjoern A. Zeeb {
36348e93258fSBjoern A. Zeeb 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
36358e93258fSBjoern A. Zeeb 
36368e93258fSBjoern A. Zeeb 	rtw89_pci_free_trx_rings(rtwdev, pdev);
36378e93258fSBjoern A. Zeeb 	rtw89_pci_clear_mapping(rtwdev, pdev);
36388e93258fSBjoern A. Zeeb 	rtw89_pci_release_fwcmd(rtwdev, rtwpci,
36398e93258fSBjoern A. Zeeb 				skb_queue_len(&rtwpci->h2c_queue), true);
36408e93258fSBjoern A. Zeeb }
36418e93258fSBjoern A. Zeeb 
36428e93258fSBjoern A. Zeeb void rtw89_pci_config_intr_mask(struct rtw89_dev *rtwdev)
36438e93258fSBjoern A. Zeeb {
36448e93258fSBjoern A. Zeeb 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
3645e2340276SBjoern A. Zeeb 	const struct rtw89_chip_info *chip = rtwdev->chip;
3646e2340276SBjoern A. Zeeb 	u32 hs0isr_ind_int_en = B_AX_HS0ISR_IND_INT_EN;
3647e2340276SBjoern A. Zeeb 
3648e2340276SBjoern A. Zeeb 	if (chip->chip_id == RTL8851B)
3649e2340276SBjoern A. Zeeb 		hs0isr_ind_int_en = B_AX_HS0ISR_IND_INT_EN_WKARND;
36508e93258fSBjoern A. Zeeb 
36518e93258fSBjoern A. Zeeb 	rtwpci->halt_c2h_intrs = B_AX_HALT_C2H_INT_EN | 0;
36528e93258fSBjoern A. Zeeb 
36538e93258fSBjoern A. Zeeb 	if (rtwpci->under_recovery) {
3654e2340276SBjoern A. Zeeb 		rtwpci->intrs[0] = hs0isr_ind_int_en;
36558e93258fSBjoern A. Zeeb 		rtwpci->intrs[1] = 0;
36568e93258fSBjoern A. Zeeb 	} else {
36578e93258fSBjoern A. Zeeb 		rtwpci->intrs[0] = B_AX_TXDMA_STUCK_INT_EN |
36588e93258fSBjoern A. Zeeb 				   B_AX_RXDMA_INT_EN |
36598e93258fSBjoern A. Zeeb 				   B_AX_RXP1DMA_INT_EN |
36608e93258fSBjoern A. Zeeb 				   B_AX_RPQDMA_INT_EN |
36618e93258fSBjoern A. Zeeb 				   B_AX_RXDMA_STUCK_INT_EN |
36628e93258fSBjoern A. Zeeb 				   B_AX_RDU_INT_EN |
36638e93258fSBjoern A. Zeeb 				   B_AX_RPQBD_FULL_INT_EN |
3664e2340276SBjoern A. Zeeb 				   hs0isr_ind_int_en;
36658e93258fSBjoern A. Zeeb 
36668e93258fSBjoern A. Zeeb 		rtwpci->intrs[1] = B_AX_HC10ISR_IND_INT_EN;
36678e93258fSBjoern A. Zeeb 	}
36688e93258fSBjoern A. Zeeb }
36698e93258fSBjoern A. Zeeb EXPORT_SYMBOL(rtw89_pci_config_intr_mask);
36708e93258fSBjoern A. Zeeb 
36718e93258fSBjoern A. Zeeb static void rtw89_pci_recovery_intr_mask_v1(struct rtw89_dev *rtwdev)
36728e93258fSBjoern A. Zeeb {
36738e93258fSBjoern A. Zeeb 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
36748e93258fSBjoern A. Zeeb 
36758e93258fSBjoern A. Zeeb 	rtwpci->ind_intrs = B_AX_HS0ISR_IND_INT_EN;
36768e93258fSBjoern A. Zeeb 	rtwpci->halt_c2h_intrs = B_AX_HALT_C2H_INT_EN | B_AX_WDT_TIMEOUT_INT_EN;
36778e93258fSBjoern A. Zeeb 	rtwpci->intrs[0] = 0;
36788e93258fSBjoern A. Zeeb 	rtwpci->intrs[1] = 0;
36798e93258fSBjoern A. Zeeb }
36808e93258fSBjoern A. Zeeb 
36818e93258fSBjoern A. Zeeb static void rtw89_pci_default_intr_mask_v1(struct rtw89_dev *rtwdev)
36828e93258fSBjoern A. Zeeb {
36838e93258fSBjoern A. Zeeb 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
36848e93258fSBjoern A. Zeeb 
36858e93258fSBjoern A. Zeeb 	rtwpci->ind_intrs = B_AX_HCI_AXIDMA_INT_EN |
36868e93258fSBjoern A. Zeeb 			    B_AX_HS1ISR_IND_INT_EN |
36878e93258fSBjoern A. Zeeb 			    B_AX_HS0ISR_IND_INT_EN;
36888e93258fSBjoern A. Zeeb 	rtwpci->halt_c2h_intrs = B_AX_HALT_C2H_INT_EN | B_AX_WDT_TIMEOUT_INT_EN;
36898e93258fSBjoern A. Zeeb 	rtwpci->intrs[0] = B_AX_TXDMA_STUCK_INT_EN |
36908e93258fSBjoern A. Zeeb 			   B_AX_RXDMA_INT_EN |
36918e93258fSBjoern A. Zeeb 			   B_AX_RXP1DMA_INT_EN |
36928e93258fSBjoern A. Zeeb 			   B_AX_RPQDMA_INT_EN |
36938e93258fSBjoern A. Zeeb 			   B_AX_RXDMA_STUCK_INT_EN |
36948e93258fSBjoern A. Zeeb 			   B_AX_RDU_INT_EN |
36958e93258fSBjoern A. Zeeb 			   B_AX_RPQBD_FULL_INT_EN;
36968e93258fSBjoern A. Zeeb 	rtwpci->intrs[1] = B_AX_GPIO18_INT_EN;
36978e93258fSBjoern A. Zeeb }
36988e93258fSBjoern A. Zeeb 
36998e93258fSBjoern A. Zeeb static void rtw89_pci_low_power_intr_mask_v1(struct rtw89_dev *rtwdev)
37008e93258fSBjoern A. Zeeb {
37018e93258fSBjoern A. Zeeb 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
37028e93258fSBjoern A. Zeeb 
37038e93258fSBjoern A. Zeeb 	rtwpci->ind_intrs = B_AX_HS1ISR_IND_INT_EN |
37048e93258fSBjoern A. Zeeb 			    B_AX_HS0ISR_IND_INT_EN;
37058e93258fSBjoern A. Zeeb 	rtwpci->halt_c2h_intrs = B_AX_HALT_C2H_INT_EN | B_AX_WDT_TIMEOUT_INT_EN;
37068e93258fSBjoern A. Zeeb 	rtwpci->intrs[0] = 0;
37078e93258fSBjoern A. Zeeb 	rtwpci->intrs[1] = B_AX_GPIO18_INT_EN;
37088e93258fSBjoern A. Zeeb }
37098e93258fSBjoern A. Zeeb 
37108e93258fSBjoern A. Zeeb void rtw89_pci_config_intr_mask_v1(struct rtw89_dev *rtwdev)
37118e93258fSBjoern A. Zeeb {
37128e93258fSBjoern A. Zeeb 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
37138e93258fSBjoern A. Zeeb 
37148e93258fSBjoern A. Zeeb 	if (rtwpci->under_recovery)
37158e93258fSBjoern A. Zeeb 		rtw89_pci_recovery_intr_mask_v1(rtwdev);
37168e93258fSBjoern A. Zeeb 	else if (rtwpci->low_power)
37178e93258fSBjoern A. Zeeb 		rtw89_pci_low_power_intr_mask_v1(rtwdev);
37188e93258fSBjoern A. Zeeb 	else
37198e93258fSBjoern A. Zeeb 		rtw89_pci_default_intr_mask_v1(rtwdev);
37208e93258fSBjoern A. Zeeb }
37218e93258fSBjoern A. Zeeb EXPORT_SYMBOL(rtw89_pci_config_intr_mask_v1);
37228e93258fSBjoern A. Zeeb 
3723*6d67aabdSBjoern A. Zeeb static void rtw89_pci_recovery_intr_mask_v2(struct rtw89_dev *rtwdev)
3724*6d67aabdSBjoern A. Zeeb {
3725*6d67aabdSBjoern A. Zeeb 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
3726*6d67aabdSBjoern A. Zeeb 
3727*6d67aabdSBjoern A. Zeeb 	rtwpci->ind_intrs = B_BE_HS0_IND_INT_EN0;
3728*6d67aabdSBjoern A. Zeeb 	rtwpci->halt_c2h_intrs = B_BE_HALT_C2H_INT_EN | B_BE_WDT_TIMEOUT_INT_EN;
3729*6d67aabdSBjoern A. Zeeb 	rtwpci->intrs[0] = 0;
3730*6d67aabdSBjoern A. Zeeb 	rtwpci->intrs[1] = 0;
3731*6d67aabdSBjoern A. Zeeb }
3732*6d67aabdSBjoern A. Zeeb 
3733*6d67aabdSBjoern A. Zeeb static void rtw89_pci_default_intr_mask_v2(struct rtw89_dev *rtwdev)
3734*6d67aabdSBjoern A. Zeeb {
3735*6d67aabdSBjoern A. Zeeb 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
3736*6d67aabdSBjoern A. Zeeb 
3737*6d67aabdSBjoern A. Zeeb 	rtwpci->ind_intrs = B_BE_HCI_AXIDMA_INT_EN0 |
3738*6d67aabdSBjoern A. Zeeb 			    B_BE_HS0_IND_INT_EN0;
3739*6d67aabdSBjoern A. Zeeb 	rtwpci->halt_c2h_intrs = B_BE_HALT_C2H_INT_EN | B_BE_WDT_TIMEOUT_INT_EN;
3740*6d67aabdSBjoern A. Zeeb 	rtwpci->intrs[0] = B_BE_RDU_CH1_INT_IMR_V1 |
3741*6d67aabdSBjoern A. Zeeb 			   B_BE_RDU_CH0_INT_IMR_V1;
3742*6d67aabdSBjoern A. Zeeb 	rtwpci->intrs[1] = B_BE_PCIE_RX_RX0P2_IMR0_V1 |
3743*6d67aabdSBjoern A. Zeeb 			   B_BE_PCIE_RX_RPQ0_IMR0_V1;
3744*6d67aabdSBjoern A. Zeeb }
3745*6d67aabdSBjoern A. Zeeb 
3746*6d67aabdSBjoern A. Zeeb static void rtw89_pci_low_power_intr_mask_v2(struct rtw89_dev *rtwdev)
3747*6d67aabdSBjoern A. Zeeb {
3748*6d67aabdSBjoern A. Zeeb 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
3749*6d67aabdSBjoern A. Zeeb 
3750*6d67aabdSBjoern A. Zeeb 	rtwpci->ind_intrs = B_BE_HS0_IND_INT_EN0 |
3751*6d67aabdSBjoern A. Zeeb 			    B_BE_HS1_IND_INT_EN0;
3752*6d67aabdSBjoern A. Zeeb 	rtwpci->halt_c2h_intrs = B_BE_HALT_C2H_INT_EN | B_BE_WDT_TIMEOUT_INT_EN;
3753*6d67aabdSBjoern A. Zeeb 	rtwpci->intrs[0] = 0;
3754*6d67aabdSBjoern A. Zeeb 	rtwpci->intrs[1] = B_BE_PCIE_RX_RX0P2_IMR0_V1 |
3755*6d67aabdSBjoern A. Zeeb 			   B_BE_PCIE_RX_RPQ0_IMR0_V1;
3756*6d67aabdSBjoern A. Zeeb }
3757*6d67aabdSBjoern A. Zeeb 
3758*6d67aabdSBjoern A. Zeeb void rtw89_pci_config_intr_mask_v2(struct rtw89_dev *rtwdev)
3759*6d67aabdSBjoern A. Zeeb {
3760*6d67aabdSBjoern A. Zeeb 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
3761*6d67aabdSBjoern A. Zeeb 
3762*6d67aabdSBjoern A. Zeeb 	if (rtwpci->under_recovery)
3763*6d67aabdSBjoern A. Zeeb 		rtw89_pci_recovery_intr_mask_v2(rtwdev);
3764*6d67aabdSBjoern A. Zeeb 	else if (rtwpci->low_power)
3765*6d67aabdSBjoern A. Zeeb 		rtw89_pci_low_power_intr_mask_v2(rtwdev);
3766*6d67aabdSBjoern A. Zeeb 	else
3767*6d67aabdSBjoern A. Zeeb 		rtw89_pci_default_intr_mask_v2(rtwdev);
3768*6d67aabdSBjoern A. Zeeb }
3769*6d67aabdSBjoern A. Zeeb EXPORT_SYMBOL(rtw89_pci_config_intr_mask_v2);
3770*6d67aabdSBjoern A. Zeeb 
37718e93258fSBjoern A. Zeeb static int rtw89_pci_request_irq(struct rtw89_dev *rtwdev,
37728e93258fSBjoern A. Zeeb 				 struct pci_dev *pdev)
37738e93258fSBjoern A. Zeeb {
37748e93258fSBjoern A. Zeeb 	unsigned long flags = 0;
37758e93258fSBjoern A. Zeeb 	int ret;
37768e93258fSBjoern A. Zeeb 
3777*6d67aabdSBjoern A. Zeeb 	flags |= PCI_IRQ_INTX | PCI_IRQ_MSI;
37788e93258fSBjoern A. Zeeb 	ret = pci_alloc_irq_vectors(pdev, 1, 1, flags);
37798e93258fSBjoern A. Zeeb 	if (ret < 0) {
37808e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "failed to alloc irq vectors, ret %d\n", ret);
37818e93258fSBjoern A. Zeeb 		goto err;
37828e93258fSBjoern A. Zeeb 	}
37838e93258fSBjoern A. Zeeb 
37848e93258fSBjoern A. Zeeb 	ret = devm_request_threaded_irq(rtwdev->dev, pdev->irq,
37858e93258fSBjoern A. Zeeb 					rtw89_pci_interrupt_handler,
37868e93258fSBjoern A. Zeeb 					rtw89_pci_interrupt_threadfn,
37878e93258fSBjoern A. Zeeb 					IRQF_SHARED, KBUILD_MODNAME, rtwdev);
37888e93258fSBjoern A. Zeeb 	if (ret) {
37898e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "failed to request threaded irq\n");
37908e93258fSBjoern A. Zeeb 		goto err_free_vector;
37918e93258fSBjoern A. Zeeb 	}
37928e93258fSBjoern A. Zeeb 
37938e93258fSBjoern A. Zeeb 	rtw89_chip_config_intr_mask(rtwdev, RTW89_PCI_INTR_MASK_RESET);
37948e93258fSBjoern A. Zeeb 
37958e93258fSBjoern A. Zeeb 	return 0;
37968e93258fSBjoern A. Zeeb 
37978e93258fSBjoern A. Zeeb err_free_vector:
37988e93258fSBjoern A. Zeeb 	pci_free_irq_vectors(pdev);
37998e93258fSBjoern A. Zeeb err:
38008e93258fSBjoern A. Zeeb 	return ret;
38018e93258fSBjoern A. Zeeb }
38028e93258fSBjoern A. Zeeb 
38038e93258fSBjoern A. Zeeb static void rtw89_pci_free_irq(struct rtw89_dev *rtwdev,
38048e93258fSBjoern A. Zeeb 			       struct pci_dev *pdev)
38058e93258fSBjoern A. Zeeb {
38068e93258fSBjoern A. Zeeb 	devm_free_irq(rtwdev->dev, pdev->irq, rtwdev);
38078e93258fSBjoern A. Zeeb 	pci_free_irq_vectors(pdev);
38088e93258fSBjoern A. Zeeb }
38098e93258fSBjoern A. Zeeb 
38108e93258fSBjoern A. Zeeb static u16 gray_code_to_bin(u16 gray_code, u32 bit_num)
38118e93258fSBjoern A. Zeeb {
38128e93258fSBjoern A. Zeeb 	u16 bin = 0, gray_bit;
38138e93258fSBjoern A. Zeeb 	u32 bit_idx;
38148e93258fSBjoern A. Zeeb 
38158e93258fSBjoern A. Zeeb 	for (bit_idx = 0; bit_idx < bit_num; bit_idx++) {
38168e93258fSBjoern A. Zeeb 		gray_bit = (gray_code >> bit_idx) & 0x1;
38178e93258fSBjoern A. Zeeb 		if (bit_num - bit_idx > 1)
38188e93258fSBjoern A. Zeeb 			gray_bit ^= (gray_code >> (bit_idx + 1)) & 0x1;
38198e93258fSBjoern A. Zeeb 		bin |= (gray_bit << bit_idx);
38208e93258fSBjoern A. Zeeb 	}
38218e93258fSBjoern A. Zeeb 
38228e93258fSBjoern A. Zeeb 	return bin;
38238e93258fSBjoern A. Zeeb }
38248e93258fSBjoern A. Zeeb 
38258e93258fSBjoern A. Zeeb static int rtw89_pci_filter_out(struct rtw89_dev *rtwdev)
38268e93258fSBjoern A. Zeeb {
38278e93258fSBjoern A. Zeeb 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
38288e93258fSBjoern A. Zeeb 	struct pci_dev *pdev = rtwpci->pdev;
38298e93258fSBjoern A. Zeeb 	u16 val16, filter_out_val;
38308e93258fSBjoern A. Zeeb 	u32 val, phy_offset;
38318e93258fSBjoern A. Zeeb 	int ret;
38328e93258fSBjoern A. Zeeb 
38338e93258fSBjoern A. Zeeb 	if (rtwdev->chip->chip_id != RTL8852C)
38348e93258fSBjoern A. Zeeb 		return 0;
38358e93258fSBjoern A. Zeeb 
38368e93258fSBjoern A. Zeeb 	val = rtw89_read32_mask(rtwdev, R_AX_PCIE_MIX_CFG_V1, B_AX_ASPM_CTRL_MASK);
38378e93258fSBjoern A. Zeeb 	if (val == B_AX_ASPM_CTRL_L1)
38388e93258fSBjoern A. Zeeb 		return 0;
38398e93258fSBjoern A. Zeeb 
38408e93258fSBjoern A. Zeeb 	ret = pci_read_config_dword(pdev, RTW89_PCIE_L1_STS_V1, &val);
38418e93258fSBjoern A. Zeeb 	if (ret)
38428e93258fSBjoern A. Zeeb 		return ret;
38438e93258fSBjoern A. Zeeb 
38448e93258fSBjoern A. Zeeb 	val = FIELD_GET(RTW89_BCFG_LINK_SPEED_MASK, val);
38458e93258fSBjoern A. Zeeb 	if (val == RTW89_PCIE_GEN1_SPEED) {
38468e93258fSBjoern A. Zeeb 		phy_offset = R_RAC_DIRECT_OFFSET_G1;
38478e93258fSBjoern A. Zeeb 	} else if (val == RTW89_PCIE_GEN2_SPEED) {
38488e93258fSBjoern A. Zeeb 		phy_offset = R_RAC_DIRECT_OFFSET_G2;
38498e93258fSBjoern A. Zeeb 		val16 = rtw89_read16(rtwdev, phy_offset + RAC_ANA10 * RAC_MULT);
38508e93258fSBjoern A. Zeeb 		rtw89_write16_set(rtwdev, phy_offset + RAC_ANA10 * RAC_MULT,
38518e93258fSBjoern A. Zeeb 				  val16 | B_PCIE_BIT_PINOUT_DIS);
38528e93258fSBjoern A. Zeeb 		rtw89_write16_set(rtwdev, phy_offset + RAC_ANA19 * RAC_MULT,
38538e93258fSBjoern A. Zeeb 				  val16 & ~B_PCIE_BIT_RD_SEL);
38548e93258fSBjoern A. Zeeb 
38558e93258fSBjoern A. Zeeb 		val16 = rtw89_read16_mask(rtwdev,
38568e93258fSBjoern A. Zeeb 					  phy_offset + RAC_ANA1F * RAC_MULT,
38578e93258fSBjoern A. Zeeb 					  FILTER_OUT_EQ_MASK);
38588e93258fSBjoern A. Zeeb 		val16 = gray_code_to_bin(val16, hweight16(val16));
38598e93258fSBjoern A. Zeeb 		filter_out_val = rtw89_read16(rtwdev, phy_offset + RAC_ANA24 *
38608e93258fSBjoern A. Zeeb 					      RAC_MULT);
38618e93258fSBjoern A. Zeeb 		filter_out_val &= ~REG_FILTER_OUT_MASK;
38628e93258fSBjoern A. Zeeb 		filter_out_val |= FIELD_PREP(REG_FILTER_OUT_MASK, val16);
38638e93258fSBjoern A. Zeeb 
38648e93258fSBjoern A. Zeeb 		rtw89_write16(rtwdev, phy_offset + RAC_ANA24 * RAC_MULT,
38658e93258fSBjoern A. Zeeb 			      filter_out_val);
38668e93258fSBjoern A. Zeeb 		rtw89_write16_set(rtwdev, phy_offset + RAC_ANA0A * RAC_MULT,
38678e93258fSBjoern A. Zeeb 				  B_BAC_EQ_SEL);
38688e93258fSBjoern A. Zeeb 		rtw89_write16_set(rtwdev,
38698e93258fSBjoern A. Zeeb 				  R_RAC_DIRECT_OFFSET_G1 + RAC_ANA0C * RAC_MULT,
38708e93258fSBjoern A. Zeeb 				  B_PCIE_BIT_PSAVE);
38718e93258fSBjoern A. Zeeb 	} else {
38728e93258fSBjoern A. Zeeb 		return -EOPNOTSUPP;
38738e93258fSBjoern A. Zeeb 	}
38748e93258fSBjoern A. Zeeb 	rtw89_write16_set(rtwdev, phy_offset + RAC_ANA0C * RAC_MULT,
38758e93258fSBjoern A. Zeeb 			  B_PCIE_BIT_PSAVE);
38768e93258fSBjoern A. Zeeb 
38778e93258fSBjoern A. Zeeb 	return 0;
38788e93258fSBjoern A. Zeeb }
38798e93258fSBjoern A. Zeeb 
38808e93258fSBjoern A. Zeeb static void rtw89_pci_clkreq_set(struct rtw89_dev *rtwdev, bool enable)
38818e93258fSBjoern A. Zeeb {
3882*6d67aabdSBjoern A. Zeeb 	const struct rtw89_pci_info *info = rtwdev->pci_info;
3883*6d67aabdSBjoern A. Zeeb 	const struct rtw89_pci_gen_def *gen_def = info->gen_def;
38848e93258fSBjoern A. Zeeb 
38858e93258fSBjoern A. Zeeb 	if (rtw89_pci_disable_clkreq)
38868e93258fSBjoern A. Zeeb 		return;
38878e93258fSBjoern A. Zeeb 
3888*6d67aabdSBjoern A. Zeeb 	gen_def->clkreq_set(rtwdev, enable);
3889*6d67aabdSBjoern A. Zeeb }
3890*6d67aabdSBjoern A. Zeeb 
3891*6d67aabdSBjoern A. Zeeb static void rtw89_pci_clkreq_set_ax(struct rtw89_dev *rtwdev, bool enable)
3892*6d67aabdSBjoern A. Zeeb {
3893*6d67aabdSBjoern A. Zeeb 	enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id;
3894*6d67aabdSBjoern A. Zeeb 	int ret;
3895*6d67aabdSBjoern A. Zeeb 
38968e93258fSBjoern A. Zeeb 	ret = rtw89_pci_write_config_byte(rtwdev, RTW89_PCIE_CLK_CTRL,
38978e93258fSBjoern A. Zeeb 					  PCIE_CLKDLY_HW_30US);
38988e93258fSBjoern A. Zeeb 	if (ret)
38998e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "failed to set CLKREQ Delay\n");
39008e93258fSBjoern A. Zeeb 
3901*6d67aabdSBjoern A. Zeeb 	if (chip_id == RTL8852A || rtw89_is_rtl885xb(rtwdev)) {
39028e93258fSBjoern A. Zeeb 		if (enable)
39038e93258fSBjoern A. Zeeb 			ret = rtw89_pci_config_byte_set(rtwdev,
39048e93258fSBjoern A. Zeeb 							RTW89_PCIE_L1_CTRL,
39058e93258fSBjoern A. Zeeb 							RTW89_PCIE_BIT_CLK);
39068e93258fSBjoern A. Zeeb 		else
39078e93258fSBjoern A. Zeeb 			ret = rtw89_pci_config_byte_clr(rtwdev,
39088e93258fSBjoern A. Zeeb 							RTW89_PCIE_L1_CTRL,
39098e93258fSBjoern A. Zeeb 							RTW89_PCIE_BIT_CLK);
39108e93258fSBjoern A. Zeeb 		if (ret)
39118e93258fSBjoern A. Zeeb 			rtw89_err(rtwdev, "failed to %s CLKREQ_L1, ret=%d",
39128e93258fSBjoern A. Zeeb 				  enable ? "set" : "unset", ret);
39138e93258fSBjoern A. Zeeb 	} else if (chip_id == RTL8852C) {
39148e93258fSBjoern A. Zeeb 		rtw89_write32_set(rtwdev, R_AX_PCIE_LAT_CTRL,
39158e93258fSBjoern A. Zeeb 				  B_AX_CLK_REQ_SEL_OPT | B_AX_CLK_REQ_SEL);
39168e93258fSBjoern A. Zeeb 		if (enable)
39178e93258fSBjoern A. Zeeb 			rtw89_write32_set(rtwdev, R_AX_L1_CLK_CTRL,
39188e93258fSBjoern A. Zeeb 					  B_AX_CLK_REQ_N);
39198e93258fSBjoern A. Zeeb 		else
39208e93258fSBjoern A. Zeeb 			rtw89_write32_clr(rtwdev, R_AX_L1_CLK_CTRL,
39218e93258fSBjoern A. Zeeb 					  B_AX_CLK_REQ_N);
39228e93258fSBjoern A. Zeeb 	}
39238e93258fSBjoern A. Zeeb }
39248e93258fSBjoern A. Zeeb 
39258e93258fSBjoern A. Zeeb static void rtw89_pci_aspm_set(struct rtw89_dev *rtwdev, bool enable)
39268e93258fSBjoern A. Zeeb {
3927*6d67aabdSBjoern A. Zeeb 	const struct rtw89_pci_info *info = rtwdev->pci_info;
3928*6d67aabdSBjoern A. Zeeb 	const struct rtw89_pci_gen_def *gen_def = info->gen_def;
39298e93258fSBjoern A. Zeeb 
39308e93258fSBjoern A. Zeeb 	if (rtw89_pci_disable_aspm_l1)
39318e93258fSBjoern A. Zeeb 		return;
39328e93258fSBjoern A. Zeeb 
3933*6d67aabdSBjoern A. Zeeb 	gen_def->aspm_set(rtwdev, enable);
3934*6d67aabdSBjoern A. Zeeb }
3935*6d67aabdSBjoern A. Zeeb 
3936*6d67aabdSBjoern A. Zeeb static void rtw89_pci_aspm_set_ax(struct rtw89_dev *rtwdev, bool enable)
3937*6d67aabdSBjoern A. Zeeb {
3938*6d67aabdSBjoern A. Zeeb 	enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id;
3939*6d67aabdSBjoern A. Zeeb 	u8 value = 0;
3940*6d67aabdSBjoern A. Zeeb 	int ret;
3941*6d67aabdSBjoern A. Zeeb 
39428e93258fSBjoern A. Zeeb 	ret = rtw89_pci_read_config_byte(rtwdev, RTW89_PCIE_ASPM_CTRL, &value);
39438e93258fSBjoern A. Zeeb 	if (ret)
3944*6d67aabdSBjoern A. Zeeb 		rtw89_warn(rtwdev, "failed to read ASPM Delay\n");
39458e93258fSBjoern A. Zeeb 
3946*6d67aabdSBjoern A. Zeeb 	u8p_replace_bits(&value, PCIE_L1DLY_16US, RTW89_L1DLY_MASK);
3947*6d67aabdSBjoern A. Zeeb 	u8p_replace_bits(&value, PCIE_L0SDLY_4US, RTW89_L0DLY_MASK);
39488e93258fSBjoern A. Zeeb 
39498e93258fSBjoern A. Zeeb 	ret = rtw89_pci_write_config_byte(rtwdev, RTW89_PCIE_ASPM_CTRL, value);
39508e93258fSBjoern A. Zeeb 	if (ret)
3951*6d67aabdSBjoern A. Zeeb 		rtw89_warn(rtwdev, "failed to read ASPM Delay\n");
39528e93258fSBjoern A. Zeeb 
3953*6d67aabdSBjoern A. Zeeb 	if (chip_id == RTL8852A || rtw89_is_rtl885xb(rtwdev)) {
39548e93258fSBjoern A. Zeeb 		if (enable)
39558e93258fSBjoern A. Zeeb 			ret = rtw89_pci_config_byte_set(rtwdev,
39568e93258fSBjoern A. Zeeb 							RTW89_PCIE_L1_CTRL,
39578e93258fSBjoern A. Zeeb 							RTW89_PCIE_BIT_L1);
39588e93258fSBjoern A. Zeeb 		else
39598e93258fSBjoern A. Zeeb 			ret = rtw89_pci_config_byte_clr(rtwdev,
39608e93258fSBjoern A. Zeeb 							RTW89_PCIE_L1_CTRL,
39618e93258fSBjoern A. Zeeb 							RTW89_PCIE_BIT_L1);
39628e93258fSBjoern A. Zeeb 	} else if (chip_id == RTL8852C) {
39638e93258fSBjoern A. Zeeb 		if (enable)
39648e93258fSBjoern A. Zeeb 			rtw89_write32_set(rtwdev, R_AX_PCIE_MIX_CFG_V1,
39658e93258fSBjoern A. Zeeb 					  B_AX_ASPM_CTRL_L1);
39668e93258fSBjoern A. Zeeb 		else
39678e93258fSBjoern A. Zeeb 			rtw89_write32_clr(rtwdev, R_AX_PCIE_MIX_CFG_V1,
39688e93258fSBjoern A. Zeeb 					  B_AX_ASPM_CTRL_L1);
39698e93258fSBjoern A. Zeeb 	}
39708e93258fSBjoern A. Zeeb 	if (ret)
39718e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "failed to %s ASPM L1, ret=%d",
39728e93258fSBjoern A. Zeeb 			  enable ? "set" : "unset", ret);
39738e93258fSBjoern A. Zeeb }
39748e93258fSBjoern A. Zeeb 
39758e93258fSBjoern A. Zeeb static void rtw89_pci_recalc_int_mit(struct rtw89_dev *rtwdev)
39768e93258fSBjoern A. Zeeb {
3977*6d67aabdSBjoern A. Zeeb 	enum rtw89_chip_gen chip_gen = rtwdev->chip->chip_gen;
3978*6d67aabdSBjoern A. Zeeb 	const struct rtw89_pci_info *info = rtwdev->pci_info;
39798e93258fSBjoern A. Zeeb 	struct rtw89_traffic_stats *stats = &rtwdev->stats;
39808e93258fSBjoern A. Zeeb 	enum rtw89_tfc_lv tx_tfc_lv = stats->tx_tfc_lv;
39818e93258fSBjoern A. Zeeb 	enum rtw89_tfc_lv rx_tfc_lv = stats->rx_tfc_lv;
39828e93258fSBjoern A. Zeeb 	u32 val = 0;
39838e93258fSBjoern A. Zeeb 
3984*6d67aabdSBjoern A. Zeeb 	if (rtwdev->scanning ||
3985*6d67aabdSBjoern A. Zeeb 	    (tx_tfc_lv < RTW89_TFC_HIGH && rx_tfc_lv < RTW89_TFC_HIGH))
3986*6d67aabdSBjoern A. Zeeb 		goto out;
3987*6d67aabdSBjoern A. Zeeb 
3988*6d67aabdSBjoern A. Zeeb 	if (chip_gen == RTW89_CHIP_BE)
3989*6d67aabdSBjoern A. Zeeb 		val = B_BE_PCIE_MIT_RX0P2_EN | B_BE_PCIE_MIT_RX0P1_EN;
3990*6d67aabdSBjoern A. Zeeb 	else
39918e93258fSBjoern A. Zeeb 		val = B_AX_RXMIT_RXP2_SEL | B_AX_RXMIT_RXP1_SEL |
39928e93258fSBjoern A. Zeeb 		      FIELD_PREP(B_AX_RXCOUNTER_MATCH_MASK, RTW89_PCI_RXBD_NUM_MAX / 2) |
39938e93258fSBjoern A. Zeeb 		      FIELD_PREP(B_AX_RXTIMER_UNIT_MASK, AX_RXTIMER_UNIT_64US) |
39948e93258fSBjoern A. Zeeb 		      FIELD_PREP(B_AX_RXTIMER_MATCH_MASK, 2048 / 64);
39958e93258fSBjoern A. Zeeb 
3996*6d67aabdSBjoern A. Zeeb out:
3997*6d67aabdSBjoern A. Zeeb 	rtw89_write32(rtwdev, info->mit_addr, val);
39988e93258fSBjoern A. Zeeb }
39998e93258fSBjoern A. Zeeb 
40008e93258fSBjoern A. Zeeb static void rtw89_pci_link_cfg(struct rtw89_dev *rtwdev)
40018e93258fSBjoern A. Zeeb {
40028e93258fSBjoern A. Zeeb 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
40038e93258fSBjoern A. Zeeb 	struct pci_dev *pdev = rtwpci->pdev;
40048e93258fSBjoern A. Zeeb 	u16 link_ctrl;
40058e93258fSBjoern A. Zeeb 	int ret;
40068e93258fSBjoern A. Zeeb 
40078e93258fSBjoern A. Zeeb 	/* Though there is standard PCIE configuration space to set the
40088e93258fSBjoern A. Zeeb 	 * link control register, but by Realtek's design, driver should
40098e93258fSBjoern A. Zeeb 	 * check if host supports CLKREQ/ASPM to enable the HW module.
40108e93258fSBjoern A. Zeeb 	 *
40118e93258fSBjoern A. Zeeb 	 * These functions are implemented by two HW modules associated,
40128e93258fSBjoern A. Zeeb 	 * one is responsible to access PCIE configuration space to
40138e93258fSBjoern A. Zeeb 	 * follow the host settings, and another is in charge of doing
40148e93258fSBjoern A. Zeeb 	 * CLKREQ/ASPM mechanisms, it is default disabled. Because sometimes
40158e93258fSBjoern A. Zeeb 	 * the host does not support it, and due to some reasons or wrong
40168e93258fSBjoern A. Zeeb 	 * settings (ex. CLKREQ# not Bi-Direction), it could lead to device
40178e93258fSBjoern A. Zeeb 	 * loss if HW misbehaves on the link.
40188e93258fSBjoern A. Zeeb 	 *
40198e93258fSBjoern A. Zeeb 	 * Hence it's designed that driver should first check the PCIE
40208e93258fSBjoern A. Zeeb 	 * configuration space is sync'ed and enabled, then driver can turn
40218e93258fSBjoern A. Zeeb 	 * on the other module that is actually working on the mechanism.
40228e93258fSBjoern A. Zeeb 	 */
40238e93258fSBjoern A. Zeeb 	ret = pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &link_ctrl);
40248e93258fSBjoern A. Zeeb 	if (ret) {
40258e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "failed to read PCI cap, ret=%d\n", ret);
40268e93258fSBjoern A. Zeeb 		return;
40278e93258fSBjoern A. Zeeb 	}
40288e93258fSBjoern A. Zeeb 
40298e93258fSBjoern A. Zeeb 	if (link_ctrl & PCI_EXP_LNKCTL_CLKREQ_EN)
40308e93258fSBjoern A. Zeeb 		rtw89_pci_clkreq_set(rtwdev, true);
40318e93258fSBjoern A. Zeeb 
40328e93258fSBjoern A. Zeeb 	if (link_ctrl & PCI_EXP_LNKCTL_ASPM_L1)
40338e93258fSBjoern A. Zeeb 		rtw89_pci_aspm_set(rtwdev, true);
40348e93258fSBjoern A. Zeeb }
40358e93258fSBjoern A. Zeeb 
40368e93258fSBjoern A. Zeeb static void rtw89_pci_l1ss_set(struct rtw89_dev *rtwdev, bool enable)
40378e93258fSBjoern A. Zeeb {
4038*6d67aabdSBjoern A. Zeeb 	const struct rtw89_pci_info *info = rtwdev->pci_info;
4039*6d67aabdSBjoern A. Zeeb 	const struct rtw89_pci_gen_def *gen_def = info->gen_def;
4040*6d67aabdSBjoern A. Zeeb 
4041*6d67aabdSBjoern A. Zeeb 	if (rtw89_pci_disable_l1ss)
4042*6d67aabdSBjoern A. Zeeb 		return;
4043*6d67aabdSBjoern A. Zeeb 
4044*6d67aabdSBjoern A. Zeeb 	gen_def->l1ss_set(rtwdev, enable);
4045*6d67aabdSBjoern A. Zeeb }
4046*6d67aabdSBjoern A. Zeeb 
4047*6d67aabdSBjoern A. Zeeb static void rtw89_pci_l1ss_set_ax(struct rtw89_dev *rtwdev, bool enable)
4048*6d67aabdSBjoern A. Zeeb {
40498e93258fSBjoern A. Zeeb 	enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id;
40508e93258fSBjoern A. Zeeb 	int ret;
40518e93258fSBjoern A. Zeeb 
4052*6d67aabdSBjoern A. Zeeb 	if (chip_id == RTL8852A || rtw89_is_rtl885xb(rtwdev)) {
40538e93258fSBjoern A. Zeeb 		if (enable)
40548e93258fSBjoern A. Zeeb 			ret = rtw89_pci_config_byte_set(rtwdev,
40558e93258fSBjoern A. Zeeb 							RTW89_PCIE_TIMER_CTRL,
40568e93258fSBjoern A. Zeeb 							RTW89_PCIE_BIT_L1SUB);
40578e93258fSBjoern A. Zeeb 		else
40588e93258fSBjoern A. Zeeb 			ret = rtw89_pci_config_byte_clr(rtwdev,
40598e93258fSBjoern A. Zeeb 							RTW89_PCIE_TIMER_CTRL,
40608e93258fSBjoern A. Zeeb 							RTW89_PCIE_BIT_L1SUB);
40618e93258fSBjoern A. Zeeb 		if (ret)
40628e93258fSBjoern A. Zeeb 			rtw89_err(rtwdev, "failed to %s L1SS, ret=%d",
40638e93258fSBjoern A. Zeeb 				  enable ? "set" : "unset", ret);
40648e93258fSBjoern A. Zeeb 	} else if (chip_id == RTL8852C) {
40658e93258fSBjoern A. Zeeb 		ret = rtw89_pci_config_byte_clr(rtwdev, RTW89_PCIE_L1SS_STS_V1,
40668e93258fSBjoern A. Zeeb 						RTW89_PCIE_BIT_ASPM_L11 |
40678e93258fSBjoern A. Zeeb 						RTW89_PCIE_BIT_PCI_L11);
40688e93258fSBjoern A. Zeeb 		if (ret)
40698e93258fSBjoern A. Zeeb 			rtw89_warn(rtwdev, "failed to unset ASPM L1.1, ret=%d", ret);
40708e93258fSBjoern A. Zeeb 		if (enable)
40718e93258fSBjoern A. Zeeb 			rtw89_write32_clr(rtwdev, R_AX_PCIE_MIX_CFG_V1,
40728e93258fSBjoern A. Zeeb 					  B_AX_L1SUB_DISABLE);
40738e93258fSBjoern A. Zeeb 		else
40748e93258fSBjoern A. Zeeb 			rtw89_write32_set(rtwdev, R_AX_PCIE_MIX_CFG_V1,
40758e93258fSBjoern A. Zeeb 					  B_AX_L1SUB_DISABLE);
40768e93258fSBjoern A. Zeeb 	}
40778e93258fSBjoern A. Zeeb }
40788e93258fSBjoern A. Zeeb 
40798e93258fSBjoern A. Zeeb static void rtw89_pci_l1ss_cfg(struct rtw89_dev *rtwdev)
40808e93258fSBjoern A. Zeeb {
40818e93258fSBjoern A. Zeeb 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
40828e93258fSBjoern A. Zeeb 	struct pci_dev *pdev = rtwpci->pdev;
40838e93258fSBjoern A. Zeeb 	u32 l1ss_cap_ptr, l1ss_ctrl;
40848e93258fSBjoern A. Zeeb 
40858e93258fSBjoern A. Zeeb 	if (rtw89_pci_disable_l1ss)
40868e93258fSBjoern A. Zeeb 		return;
40878e93258fSBjoern A. Zeeb 
40888e93258fSBjoern A. Zeeb 	l1ss_cap_ptr = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_L1SS);
40898e93258fSBjoern A. Zeeb 	if (!l1ss_cap_ptr)
40908e93258fSBjoern A. Zeeb 		return;
40918e93258fSBjoern A. Zeeb 
40928e93258fSBjoern A. Zeeb 	pci_read_config_dword(pdev, l1ss_cap_ptr + PCI_L1SS_CTL1, &l1ss_ctrl);
40938e93258fSBjoern A. Zeeb 
40948e93258fSBjoern A. Zeeb 	if (l1ss_ctrl & PCI_L1SS_CTL1_L1SS_MASK)
40958e93258fSBjoern A. Zeeb 		rtw89_pci_l1ss_set(rtwdev, true);
40968e93258fSBjoern A. Zeeb }
40978e93258fSBjoern A. Zeeb 
4098*6d67aabdSBjoern A. Zeeb static int rtw89_pci_poll_io_idle_ax(struct rtw89_dev *rtwdev)
40998e93258fSBjoern A. Zeeb {
41008e93258fSBjoern A. Zeeb 	int ret = 0;
41018e93258fSBjoern A. Zeeb 	u32 sts;
41028e93258fSBjoern A. Zeeb 	u32 busy = B_AX_PCIEIO_BUSY | B_AX_PCIEIO_TX_BUSY | B_AX_PCIEIO_RX_BUSY;
41038e93258fSBjoern A. Zeeb 
41048e93258fSBjoern A. Zeeb 	ret = read_poll_timeout_atomic(rtw89_read32, sts, (sts & busy) == 0x0,
41058e93258fSBjoern A. Zeeb 				       10, 1000, false, rtwdev,
41068e93258fSBjoern A. Zeeb 				       R_AX_PCIE_DMA_BUSY1);
41078e93258fSBjoern A. Zeeb 	if (ret) {
41088e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "pci dmach busy1 0x%X\n",
41098e93258fSBjoern A. Zeeb 			  rtw89_read32(rtwdev, R_AX_PCIE_DMA_BUSY1));
41108e93258fSBjoern A. Zeeb 		return -EINVAL;
41118e93258fSBjoern A. Zeeb 	}
41128e93258fSBjoern A. Zeeb 	return ret;
41138e93258fSBjoern A. Zeeb }
41148e93258fSBjoern A. Zeeb 
4115*6d67aabdSBjoern A. Zeeb static int rtw89_pci_lv1rst_stop_dma_ax(struct rtw89_dev *rtwdev)
41168e93258fSBjoern A. Zeeb {
4117e2340276SBjoern A. Zeeb 	u32 val;
41188e93258fSBjoern A. Zeeb 	int ret;
41198e93258fSBjoern A. Zeeb 
4120e2340276SBjoern A. Zeeb 	if (rtwdev->chip->chip_id == RTL8852C)
4121e2340276SBjoern A. Zeeb 		return 0;
4122e2340276SBjoern A. Zeeb 
4123e2340276SBjoern A. Zeeb 	rtw89_pci_ctrl_dma_all(rtwdev, false);
4124*6d67aabdSBjoern A. Zeeb 	ret = rtw89_pci_poll_io_idle_ax(rtwdev);
41258e93258fSBjoern A. Zeeb 	if (ret) {
41268e93258fSBjoern A. Zeeb 		val = rtw89_read32(rtwdev, R_AX_DBG_ERR_FLAG);
41278e93258fSBjoern A. Zeeb 		rtw89_debug(rtwdev, RTW89_DBG_HCI,
41288e93258fSBjoern A. Zeeb 			    "[PCIe] poll_io_idle fail, before 0x%08x: 0x%08x\n",
41298e93258fSBjoern A. Zeeb 			    R_AX_DBG_ERR_FLAG, val);
41308e93258fSBjoern A. Zeeb 		if (val & B_AX_TX_STUCK || val & B_AX_PCIE_TXBD_LEN0)
4131e2340276SBjoern A. Zeeb 			rtw89_mac_ctrl_hci_dma_tx(rtwdev, false);
41328e93258fSBjoern A. Zeeb 		if (val & B_AX_RX_STUCK)
4133e2340276SBjoern A. Zeeb 			rtw89_mac_ctrl_hci_dma_rx(rtwdev, false);
4134e2340276SBjoern A. Zeeb 		rtw89_mac_ctrl_hci_dma_trx(rtwdev, true);
4135*6d67aabdSBjoern A. Zeeb 		ret = rtw89_pci_poll_io_idle_ax(rtwdev);
41368e93258fSBjoern A. Zeeb 		val = rtw89_read32(rtwdev, R_AX_DBG_ERR_FLAG);
41378e93258fSBjoern A. Zeeb 		rtw89_debug(rtwdev, RTW89_DBG_HCI,
41388e93258fSBjoern A. Zeeb 			    "[PCIe] poll_io_idle fail, after 0x%08x: 0x%08x\n",
41398e93258fSBjoern A. Zeeb 			    R_AX_DBG_ERR_FLAG, val);
41408e93258fSBjoern A. Zeeb 	}
41418e93258fSBjoern A. Zeeb 
41428e93258fSBjoern A. Zeeb 	return ret;
41438e93258fSBjoern A. Zeeb }
41448e93258fSBjoern A. Zeeb 
4145*6d67aabdSBjoern A. Zeeb static int rtw89_pci_lv1rst_start_dma_ax(struct rtw89_dev *rtwdev)
41468e93258fSBjoern A. Zeeb {
41478e93258fSBjoern A. Zeeb 	u32 ret;
41488e93258fSBjoern A. Zeeb 
4149e2340276SBjoern A. Zeeb 	if (rtwdev->chip->chip_id == RTL8852C)
4150e2340276SBjoern A. Zeeb 		return 0;
4151e2340276SBjoern A. Zeeb 
4152e2340276SBjoern A. Zeeb 	rtw89_mac_ctrl_hci_dma_trx(rtwdev, false);
4153e2340276SBjoern A. Zeeb 	rtw89_mac_ctrl_hci_dma_trx(rtwdev, true);
41548e93258fSBjoern A. Zeeb 	rtw89_pci_clr_idx_all(rtwdev);
41558e93258fSBjoern A. Zeeb 
4156*6d67aabdSBjoern A. Zeeb 	ret = rtw89_pci_rst_bdram_ax(rtwdev);
41578e93258fSBjoern A. Zeeb 	if (ret)
41588e93258fSBjoern A. Zeeb 		return ret;
41598e93258fSBjoern A. Zeeb 
4160e2340276SBjoern A. Zeeb 	rtw89_pci_ctrl_dma_all(rtwdev, true);
41618e93258fSBjoern A. Zeeb 	return ret;
41628e93258fSBjoern A. Zeeb }
41638e93258fSBjoern A. Zeeb 
41648e93258fSBjoern A. Zeeb static int rtw89_pci_ops_mac_lv1_recovery(struct rtw89_dev *rtwdev,
41658e93258fSBjoern A. Zeeb 					  enum rtw89_lv1_rcvy_step step)
41668e93258fSBjoern A. Zeeb {
4167*6d67aabdSBjoern A. Zeeb 	const struct rtw89_pci_info *info = rtwdev->pci_info;
4168*6d67aabdSBjoern A. Zeeb 	const struct rtw89_pci_gen_def *gen_def = info->gen_def;
41698e93258fSBjoern A. Zeeb 	int ret;
41708e93258fSBjoern A. Zeeb 
41718e93258fSBjoern A. Zeeb 	switch (step) {
41728e93258fSBjoern A. Zeeb 	case RTW89_LV1_RCVY_STEP_1:
4173*6d67aabdSBjoern A. Zeeb 		ret = gen_def->lv1rst_stop_dma(rtwdev);
41748e93258fSBjoern A. Zeeb 		if (ret)
41758e93258fSBjoern A. Zeeb 			rtw89_err(rtwdev, "lv1 rcvy pci stop dma fail\n");
41768e93258fSBjoern A. Zeeb 
41778e93258fSBjoern A. Zeeb 		break;
41788e93258fSBjoern A. Zeeb 
41798e93258fSBjoern A. Zeeb 	case RTW89_LV1_RCVY_STEP_2:
4180*6d67aabdSBjoern A. Zeeb 		ret = gen_def->lv1rst_start_dma(rtwdev);
41818e93258fSBjoern A. Zeeb 		if (ret)
41828e93258fSBjoern A. Zeeb 			rtw89_err(rtwdev, "lv1 rcvy pci start dma fail\n");
41838e93258fSBjoern A. Zeeb 		break;
41848e93258fSBjoern A. Zeeb 
41858e93258fSBjoern A. Zeeb 	default:
41868e93258fSBjoern A. Zeeb 		return -EINVAL;
41878e93258fSBjoern A. Zeeb 	}
41888e93258fSBjoern A. Zeeb 
41898e93258fSBjoern A. Zeeb 	return ret;
41908e93258fSBjoern A. Zeeb }
41918e93258fSBjoern A. Zeeb 
41928e93258fSBjoern A. Zeeb static void rtw89_pci_ops_dump_err_status(struct rtw89_dev *rtwdev)
41938e93258fSBjoern A. Zeeb {
4194*6d67aabdSBjoern A. Zeeb 	if (rtwdev->chip->chip_gen == RTW89_CHIP_BE)
4195*6d67aabdSBjoern A. Zeeb 		return;
4196*6d67aabdSBjoern A. Zeeb 
4197*6d67aabdSBjoern A. Zeeb 	if (rtwdev->chip->chip_id == RTL8852C) {
4198*6d67aabdSBjoern A. Zeeb 		rtw89_info(rtwdev, "R_AX_DBG_ERR_FLAG=0x%08x\n",
4199*6d67aabdSBjoern A. Zeeb 			   rtw89_read32(rtwdev, R_AX_DBG_ERR_FLAG_V1));
4200*6d67aabdSBjoern A. Zeeb 		rtw89_info(rtwdev, "R_AX_LBC_WATCHDOG=0x%08x\n",
4201*6d67aabdSBjoern A. Zeeb 			   rtw89_read32(rtwdev, R_AX_LBC_WATCHDOG_V1));
4202*6d67aabdSBjoern A. Zeeb 	} else {
42038e93258fSBjoern A. Zeeb 		rtw89_info(rtwdev, "R_AX_RPQ_RXBD_IDX =0x%08x\n",
42048e93258fSBjoern A. Zeeb 			   rtw89_read32(rtwdev, R_AX_RPQ_RXBD_IDX));
42058e93258fSBjoern A. Zeeb 		rtw89_info(rtwdev, "R_AX_DBG_ERR_FLAG=0x%08x\n",
42068e93258fSBjoern A. Zeeb 			   rtw89_read32(rtwdev, R_AX_DBG_ERR_FLAG));
42078e93258fSBjoern A. Zeeb 		rtw89_info(rtwdev, "R_AX_LBC_WATCHDOG=0x%08x\n",
42088e93258fSBjoern A. Zeeb 			   rtw89_read32(rtwdev, R_AX_LBC_WATCHDOG));
42098e93258fSBjoern A. Zeeb 	}
4210*6d67aabdSBjoern A. Zeeb }
42118e93258fSBjoern A. Zeeb 
42128e93258fSBjoern A. Zeeb static int rtw89_pci_napi_poll(struct napi_struct *napi, int budget)
42138e93258fSBjoern A. Zeeb {
42148e93258fSBjoern A. Zeeb 	struct rtw89_dev *rtwdev = container_of(napi, struct rtw89_dev, napi);
42158e93258fSBjoern A. Zeeb 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
4216*6d67aabdSBjoern A. Zeeb 	const struct rtw89_pci_info *info = rtwdev->pci_info;
4217*6d67aabdSBjoern A. Zeeb 	const struct rtw89_pci_gen_def *gen_def = info->gen_def;
42188e93258fSBjoern A. Zeeb 	unsigned long flags;
42198e93258fSBjoern A. Zeeb 	int work_done;
42208e93258fSBjoern A. Zeeb 
42218e93258fSBjoern A. Zeeb 	rtwdev->napi_budget_countdown = budget;
42228e93258fSBjoern A. Zeeb 
4223*6d67aabdSBjoern A. Zeeb 	rtw89_write32(rtwdev, gen_def->isr_clear_rpq.addr, gen_def->isr_clear_rpq.data);
42248e93258fSBjoern A. Zeeb 	work_done = rtw89_pci_poll_rpq_dma(rtwdev, rtwpci, rtwdev->napi_budget_countdown);
42258e93258fSBjoern A. Zeeb 	if (work_done == budget)
42268e93258fSBjoern A. Zeeb 		return budget;
42278e93258fSBjoern A. Zeeb 
4228*6d67aabdSBjoern A. Zeeb 	rtw89_write32(rtwdev, gen_def->isr_clear_rxq.addr, gen_def->isr_clear_rxq.data);
42298e93258fSBjoern A. Zeeb 	work_done += rtw89_pci_poll_rxq_dma(rtwdev, rtwpci, rtwdev->napi_budget_countdown);
42308e93258fSBjoern A. Zeeb 	if (work_done < budget && napi_complete_done(napi, work_done)) {
42318e93258fSBjoern A. Zeeb 		spin_lock_irqsave(&rtwpci->irq_lock, flags);
42328e93258fSBjoern A. Zeeb 		if (likely(rtwpci->running))
42338e93258fSBjoern A. Zeeb 			rtw89_chip_enable_intr(rtwdev, rtwpci);
42348e93258fSBjoern A. Zeeb 		spin_unlock_irqrestore(&rtwpci->irq_lock, flags);
42358e93258fSBjoern A. Zeeb 	}
42368e93258fSBjoern A. Zeeb 
42378e93258fSBjoern A. Zeeb 	return work_done;
42388e93258fSBjoern A. Zeeb }
42398e93258fSBjoern A. Zeeb 
42408e93258fSBjoern A. Zeeb static int __maybe_unused rtw89_pci_suspend(struct device *dev)
42418e93258fSBjoern A. Zeeb {
42428e93258fSBjoern A. Zeeb 	struct ieee80211_hw *hw = dev_get_drvdata(dev);
42438e93258fSBjoern A. Zeeb 	struct rtw89_dev *rtwdev = hw->priv;
42448e93258fSBjoern A. Zeeb 	enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id;
42458e93258fSBjoern A. Zeeb 
42468e93258fSBjoern A. Zeeb 	rtw89_write32_set(rtwdev, R_AX_RSV_CTRL, B_AX_WLOCK_1C_BIT6);
42478e93258fSBjoern A. Zeeb 	rtw89_write32_set(rtwdev, R_AX_RSV_CTRL, B_AX_R_DIS_PRST);
42488e93258fSBjoern A. Zeeb 	rtw89_write32_clr(rtwdev, R_AX_RSV_CTRL, B_AX_WLOCK_1C_BIT6);
4249*6d67aabdSBjoern A. Zeeb 	if (chip_id == RTL8852A || rtw89_is_rtl885xb(rtwdev)) {
42508e93258fSBjoern A. Zeeb 		rtw89_write32_clr(rtwdev, R_AX_SYS_SDIO_CTRL,
42518e93258fSBjoern A. Zeeb 				  B_AX_PCIE_DIS_L2_CTRL_LDO_HCI);
42528e93258fSBjoern A. Zeeb 		rtw89_write32_set(rtwdev, R_AX_PCIE_INIT_CFG1,
42538e93258fSBjoern A. Zeeb 				  B_AX_PCIE_PERST_KEEP_REG | B_AX_PCIE_TRAIN_KEEP_REG);
42548e93258fSBjoern A. Zeeb 	} else {
42558e93258fSBjoern A. Zeeb 		rtw89_write32_clr(rtwdev, R_AX_PCIE_PS_CTRL_V1,
42568e93258fSBjoern A. Zeeb 				  B_AX_CMAC_EXIT_L1_EN | B_AX_DMAC0_EXIT_L1_EN);
42578e93258fSBjoern A. Zeeb 	}
42588e93258fSBjoern A. Zeeb 
42598e93258fSBjoern A. Zeeb 	return 0;
42608e93258fSBjoern A. Zeeb }
42618e93258fSBjoern A. Zeeb 
42628e93258fSBjoern A. Zeeb static void rtw89_pci_l2_hci_ldo(struct rtw89_dev *rtwdev)
42638e93258fSBjoern A. Zeeb {
42648e93258fSBjoern A. Zeeb 	if (rtwdev->chip->chip_id == RTL8852C)
42658e93258fSBjoern A. Zeeb 		return;
42668e93258fSBjoern A. Zeeb 
42678e93258fSBjoern A. Zeeb 	/* Hardware need write the reg twice to ensure the setting work */
42688e93258fSBjoern A. Zeeb 	rtw89_pci_write_config_byte(rtwdev, RTW89_PCIE_RST_MSTATE,
42698e93258fSBjoern A. Zeeb 				    RTW89_PCIE_BIT_CFG_RST_MSTATE);
42708e93258fSBjoern A. Zeeb 	rtw89_pci_write_config_byte(rtwdev, RTW89_PCIE_RST_MSTATE,
42718e93258fSBjoern A. Zeeb 				    RTW89_PCIE_BIT_CFG_RST_MSTATE);
42728e93258fSBjoern A. Zeeb }
42738e93258fSBjoern A. Zeeb 
42748e93258fSBjoern A. Zeeb static int __maybe_unused rtw89_pci_resume(struct device *dev)
42758e93258fSBjoern A. Zeeb {
42768e93258fSBjoern A. Zeeb 	struct ieee80211_hw *hw = dev_get_drvdata(dev);
42778e93258fSBjoern A. Zeeb 	struct rtw89_dev *rtwdev = hw->priv;
42788e93258fSBjoern A. Zeeb 	enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id;
42798e93258fSBjoern A. Zeeb 
42808e93258fSBjoern A. Zeeb 	rtw89_write32_set(rtwdev, R_AX_RSV_CTRL, B_AX_WLOCK_1C_BIT6);
42818e93258fSBjoern A. Zeeb 	rtw89_write32_clr(rtwdev, R_AX_RSV_CTRL, B_AX_R_DIS_PRST);
42828e93258fSBjoern A. Zeeb 	rtw89_write32_clr(rtwdev, R_AX_RSV_CTRL, B_AX_WLOCK_1C_BIT6);
4283*6d67aabdSBjoern A. Zeeb 	if (chip_id == RTL8852A || rtw89_is_rtl885xb(rtwdev)) {
42848e93258fSBjoern A. Zeeb 		rtw89_write32_set(rtwdev, R_AX_SYS_SDIO_CTRL,
42858e93258fSBjoern A. Zeeb 				  B_AX_PCIE_DIS_L2_CTRL_LDO_HCI);
42868e93258fSBjoern A. Zeeb 		rtw89_write32_clr(rtwdev, R_AX_PCIE_INIT_CFG1,
42878e93258fSBjoern A. Zeeb 				  B_AX_PCIE_PERST_KEEP_REG | B_AX_PCIE_TRAIN_KEEP_REG);
42888e93258fSBjoern A. Zeeb 	} else {
42898e93258fSBjoern A. Zeeb 		rtw89_write32_set(rtwdev, R_AX_PCIE_PS_CTRL_V1,
42908e93258fSBjoern A. Zeeb 				  B_AX_CMAC_EXIT_L1_EN | B_AX_DMAC0_EXIT_L1_EN);
42918e93258fSBjoern A. Zeeb 		rtw89_write32_clr(rtwdev, R_AX_PCIE_PS_CTRL_V1,
42928e93258fSBjoern A. Zeeb 				  B_AX_SEL_REQ_ENTR_L1);
42938e93258fSBjoern A. Zeeb 	}
42948e93258fSBjoern A. Zeeb 	rtw89_pci_l2_hci_ldo(rtwdev);
4295*6d67aabdSBjoern A. Zeeb 	rtw89_pci_disable_eq(rtwdev);
4296*6d67aabdSBjoern A. Zeeb 	rtw89_pci_cfg_dac(rtwdev);
42978e93258fSBjoern A. Zeeb 	rtw89_pci_filter_out(rtwdev);
42988e93258fSBjoern A. Zeeb 	rtw89_pci_link_cfg(rtwdev);
42998e93258fSBjoern A. Zeeb 	rtw89_pci_l1ss_cfg(rtwdev);
43008e93258fSBjoern A. Zeeb 
43018e93258fSBjoern A. Zeeb 	return 0;
43028e93258fSBjoern A. Zeeb }
43038e93258fSBjoern A. Zeeb 
43048e93258fSBjoern A. Zeeb SIMPLE_DEV_PM_OPS(rtw89_pm_ops, rtw89_pci_suspend, rtw89_pci_resume);
43058e93258fSBjoern A. Zeeb EXPORT_SYMBOL(rtw89_pm_ops);
43068e93258fSBjoern A. Zeeb 
4307*6d67aabdSBjoern A. Zeeb const struct rtw89_pci_gen_def rtw89_pci_gen_ax = {
4308*6d67aabdSBjoern A. Zeeb 	.isr_rdu = B_AX_RDU_INT,
4309*6d67aabdSBjoern A. Zeeb 	.isr_halt_c2h = B_AX_HALT_C2H_INT_EN,
4310*6d67aabdSBjoern A. Zeeb 	.isr_wdt_timeout = B_AX_WDT_TIMEOUT_INT_EN,
4311*6d67aabdSBjoern A. Zeeb 	.isr_clear_rpq = {R_AX_PCIE_HISR00, B_AX_RPQDMA_INT | B_AX_RPQBD_FULL_INT},
4312*6d67aabdSBjoern A. Zeeb 	.isr_clear_rxq = {R_AX_PCIE_HISR00, B_AX_RXP1DMA_INT | B_AX_RXDMA_INT |
4313*6d67aabdSBjoern A. Zeeb 					    B_AX_RDU_INT},
4314*6d67aabdSBjoern A. Zeeb 
4315*6d67aabdSBjoern A. Zeeb 	.mac_pre_init = rtw89_pci_ops_mac_pre_init_ax,
4316*6d67aabdSBjoern A. Zeeb 	.mac_pre_deinit = NULL,
4317*6d67aabdSBjoern A. Zeeb 	.mac_post_init = rtw89_pci_ops_mac_post_init_ax,
4318*6d67aabdSBjoern A. Zeeb 
4319*6d67aabdSBjoern A. Zeeb 	.clr_idx_all = rtw89_pci_clr_idx_all_ax,
4320*6d67aabdSBjoern A. Zeeb 	.rst_bdram = rtw89_pci_rst_bdram_ax,
4321*6d67aabdSBjoern A. Zeeb 
4322*6d67aabdSBjoern A. Zeeb 	.lv1rst_stop_dma = rtw89_pci_lv1rst_stop_dma_ax,
4323*6d67aabdSBjoern A. Zeeb 	.lv1rst_start_dma = rtw89_pci_lv1rst_start_dma_ax,
4324*6d67aabdSBjoern A. Zeeb 
4325*6d67aabdSBjoern A. Zeeb 	.ctrl_txdma_ch = rtw89_pci_ctrl_txdma_ch_ax,
4326*6d67aabdSBjoern A. Zeeb 	.ctrl_txdma_fw_ch = rtw89_pci_ctrl_txdma_fw_ch_ax,
4327*6d67aabdSBjoern A. Zeeb 	.poll_txdma_ch_idle = rtw89_pci_poll_txdma_ch_idle_ax,
4328*6d67aabdSBjoern A. Zeeb 
4329*6d67aabdSBjoern A. Zeeb 	.aspm_set = rtw89_pci_aspm_set_ax,
4330*6d67aabdSBjoern A. Zeeb 	.clkreq_set = rtw89_pci_clkreq_set_ax,
4331*6d67aabdSBjoern A. Zeeb 	.l1ss_set = rtw89_pci_l1ss_set_ax,
4332*6d67aabdSBjoern A. Zeeb };
4333*6d67aabdSBjoern A. Zeeb EXPORT_SYMBOL(rtw89_pci_gen_ax);
4334*6d67aabdSBjoern A. Zeeb 
43358e93258fSBjoern A. Zeeb static const struct rtw89_hci_ops rtw89_pci_ops = {
43368e93258fSBjoern A. Zeeb 	.tx_write	= rtw89_pci_ops_tx_write,
43378e93258fSBjoern A. Zeeb 	.tx_kick_off	= rtw89_pci_ops_tx_kick_off,
43388e93258fSBjoern A. Zeeb 	.flush_queues	= rtw89_pci_ops_flush_queues,
43398e93258fSBjoern A. Zeeb 	.reset		= rtw89_pci_ops_reset,
43408e93258fSBjoern A. Zeeb 	.start		= rtw89_pci_ops_start,
43418e93258fSBjoern A. Zeeb 	.stop		= rtw89_pci_ops_stop,
43428e93258fSBjoern A. Zeeb 	.pause		= rtw89_pci_ops_pause,
43438e93258fSBjoern A. Zeeb 	.switch_mode	= rtw89_pci_ops_switch_mode,
43448e93258fSBjoern A. Zeeb 	.recalc_int_mit = rtw89_pci_recalc_int_mit,
43458e93258fSBjoern A. Zeeb 
43468e93258fSBjoern A. Zeeb 	.read8		= rtw89_pci_ops_read8,
43478e93258fSBjoern A. Zeeb 	.read16		= rtw89_pci_ops_read16,
43488e93258fSBjoern A. Zeeb 	.read32		= rtw89_pci_ops_read32,
43498e93258fSBjoern A. Zeeb 	.write8		= rtw89_pci_ops_write8,
43508e93258fSBjoern A. Zeeb 	.write16	= rtw89_pci_ops_write16,
43518e93258fSBjoern A. Zeeb 	.write32	= rtw89_pci_ops_write32,
43528e93258fSBjoern A. Zeeb 
43538e93258fSBjoern A. Zeeb 	.mac_pre_init	= rtw89_pci_ops_mac_pre_init,
4354*6d67aabdSBjoern A. Zeeb 	.mac_pre_deinit	= rtw89_pci_ops_mac_pre_deinit,
43558e93258fSBjoern A. Zeeb 	.mac_post_init	= rtw89_pci_ops_mac_post_init,
43568e93258fSBjoern A. Zeeb 	.deinit		= rtw89_pci_ops_deinit,
43578e93258fSBjoern A. Zeeb 
43588e93258fSBjoern A. Zeeb 	.check_and_reclaim_tx_resource = rtw89_pci_check_and_reclaim_tx_resource,
43598e93258fSBjoern A. Zeeb 	.mac_lv1_rcvy	= rtw89_pci_ops_mac_lv1_recovery,
43608e93258fSBjoern A. Zeeb 	.dump_err_status = rtw89_pci_ops_dump_err_status,
43618e93258fSBjoern A. Zeeb 	.napi_poll	= rtw89_pci_napi_poll,
43628e93258fSBjoern A. Zeeb 
43638e93258fSBjoern A. Zeeb 	.recovery_start = rtw89_pci_ops_recovery_start,
43648e93258fSBjoern A. Zeeb 	.recovery_complete = rtw89_pci_ops_recovery_complete,
4365e2340276SBjoern A. Zeeb 
4366*6d67aabdSBjoern A. Zeeb 	.ctrl_txdma_ch	= rtw89_pci_ctrl_txdma_ch,
4367*6d67aabdSBjoern A. Zeeb 	.ctrl_txdma_fw_ch = rtw89_pci_ctrl_txdma_fw_ch,
4368e2340276SBjoern A. Zeeb 	.ctrl_trxhci	= rtw89_pci_ctrl_dma_trx,
4369*6d67aabdSBjoern A. Zeeb 	.poll_txdma_ch_idle = rtw89_pci_poll_txdma_ch_idle,
4370*6d67aabdSBjoern A. Zeeb 
4371e2340276SBjoern A. Zeeb 	.clr_idx_all	= rtw89_pci_clr_idx_all,
4372e2340276SBjoern A. Zeeb 	.clear		= rtw89_pci_clear_resource,
4373e2340276SBjoern A. Zeeb 	.disable_intr	= rtw89_pci_disable_intr_lock,
4374e2340276SBjoern A. Zeeb 	.enable_intr	= rtw89_pci_enable_intr_lock,
4375*6d67aabdSBjoern A. Zeeb 	.rst_bdram	= rtw89_pci_reset_bdram,
43768e93258fSBjoern A. Zeeb };
43778e93258fSBjoern A. Zeeb 
43788e93258fSBjoern A. Zeeb int rtw89_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
43798e93258fSBjoern A. Zeeb {
43808e93258fSBjoern A. Zeeb 	struct rtw89_dev *rtwdev;
43818e93258fSBjoern A. Zeeb 	const struct rtw89_driver_info *info;
43828e93258fSBjoern A. Zeeb 	const struct rtw89_pci_info *pci_info;
43838e93258fSBjoern A. Zeeb 	int ret;
43848e93258fSBjoern A. Zeeb 
43858e93258fSBjoern A. Zeeb 	info = (const struct rtw89_driver_info *)id->driver_data;
43868e93258fSBjoern A. Zeeb 
43878e93258fSBjoern A. Zeeb 	rtwdev = rtw89_alloc_ieee80211_hw(&pdev->dev,
43888e93258fSBjoern A. Zeeb 					  sizeof(struct rtw89_pci),
43898e93258fSBjoern A. Zeeb 					  info->chip);
43908e93258fSBjoern A. Zeeb 	if (!rtwdev) {
43918e93258fSBjoern A. Zeeb 		dev_err(&pdev->dev, "failed to allocate hw\n");
43928e93258fSBjoern A. Zeeb 		return -ENOMEM;
43938e93258fSBjoern A. Zeeb 	}
43948e93258fSBjoern A. Zeeb 
43958e93258fSBjoern A. Zeeb 	pci_info = info->bus.pci;
43968e93258fSBjoern A. Zeeb 
43978e93258fSBjoern A. Zeeb 	rtwdev->pci_info = info->bus.pci;
43988e93258fSBjoern A. Zeeb 	rtwdev->hci.ops = &rtw89_pci_ops;
43998e93258fSBjoern A. Zeeb 	rtwdev->hci.type = RTW89_HCI_TYPE_PCIE;
44008e93258fSBjoern A. Zeeb 	rtwdev->hci.rpwm_addr = pci_info->rpwm_addr;
44018e93258fSBjoern A. Zeeb 	rtwdev->hci.cpwm_addr = pci_info->cpwm_addr;
44028e93258fSBjoern A. Zeeb 
4403*6d67aabdSBjoern A. Zeeb 	rtw89_check_quirks(rtwdev, info->quirks);
4404*6d67aabdSBjoern A. Zeeb 
44058e93258fSBjoern A. Zeeb 	SET_IEEE80211_DEV(rtwdev->hw, &pdev->dev);
44068e93258fSBjoern A. Zeeb 
44078e93258fSBjoern A. Zeeb 	ret = rtw89_core_init(rtwdev);
44088e93258fSBjoern A. Zeeb 	if (ret) {
44098e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "failed to initialise core\n");
44108e93258fSBjoern A. Zeeb 		goto err_release_hw;
44118e93258fSBjoern A. Zeeb 	}
44128e93258fSBjoern A. Zeeb 
44138e93258fSBjoern A. Zeeb 	ret = rtw89_pci_claim_device(rtwdev, pdev);
44148e93258fSBjoern A. Zeeb 	if (ret) {
44158e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "failed to claim pci device\n");
44168e93258fSBjoern A. Zeeb 		goto err_core_deinit;
44178e93258fSBjoern A. Zeeb 	}
44188e93258fSBjoern A. Zeeb 
44198e93258fSBjoern A. Zeeb 	ret = rtw89_pci_setup_resource(rtwdev, pdev);
44208e93258fSBjoern A. Zeeb 	if (ret) {
44218e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "failed to setup pci resource\n");
44228e93258fSBjoern A. Zeeb 		goto err_declaim_pci;
44238e93258fSBjoern A. Zeeb 	}
44248e93258fSBjoern A. Zeeb 
44258e93258fSBjoern A. Zeeb 	ret = rtw89_chip_info_setup(rtwdev);
44268e93258fSBjoern A. Zeeb 	if (ret) {
44278e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "failed to setup chip information\n");
44288e93258fSBjoern A. Zeeb 		goto err_clear_resource;
44298e93258fSBjoern A. Zeeb 	}
44308e93258fSBjoern A. Zeeb 
4431*6d67aabdSBjoern A. Zeeb 	rtw89_pci_disable_eq(rtwdev);
44328e93258fSBjoern A. Zeeb 	rtw89_pci_filter_out(rtwdev);
44338e93258fSBjoern A. Zeeb 	rtw89_pci_link_cfg(rtwdev);
44348e93258fSBjoern A. Zeeb 	rtw89_pci_l1ss_cfg(rtwdev);
44358e93258fSBjoern A. Zeeb 
4436*6d67aabdSBjoern A. Zeeb 	ret = rtw89_core_napi_init(rtwdev);
4437*6d67aabdSBjoern A. Zeeb 	if (ret) {
4438*6d67aabdSBjoern A. Zeeb 		rtw89_err(rtwdev, "failed to init napi\n");
4439*6d67aabdSBjoern A. Zeeb 		goto err_clear_resource;
4440*6d67aabdSBjoern A. Zeeb 	}
44418e93258fSBjoern A. Zeeb 
44428e93258fSBjoern A. Zeeb 	ret = rtw89_pci_request_irq(rtwdev, pdev);
44438e93258fSBjoern A. Zeeb 	if (ret) {
44448e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "failed to request pci irq\n");
4445e2340276SBjoern A. Zeeb 		goto err_deinit_napi;
4446e2340276SBjoern A. Zeeb 	}
4447e2340276SBjoern A. Zeeb 
4448e2340276SBjoern A. Zeeb 	ret = rtw89_core_register(rtwdev);
4449e2340276SBjoern A. Zeeb 	if (ret) {
4450e2340276SBjoern A. Zeeb 		rtw89_err(rtwdev, "failed to register core\n");
4451e2340276SBjoern A. Zeeb 		goto err_free_irq;
44528e93258fSBjoern A. Zeeb 	}
44538e93258fSBjoern A. Zeeb 
4454*6d67aabdSBjoern A. Zeeb 	set_bit(RTW89_FLAG_PROBE_DONE, rtwdev->flags);
4455*6d67aabdSBjoern A. Zeeb 
44568e93258fSBjoern A. Zeeb 	return 0;
44578e93258fSBjoern A. Zeeb 
4458e2340276SBjoern A. Zeeb err_free_irq:
4459e2340276SBjoern A. Zeeb 	rtw89_pci_free_irq(rtwdev, pdev);
4460e2340276SBjoern A. Zeeb err_deinit_napi:
44618e93258fSBjoern A. Zeeb 	rtw89_core_napi_deinit(rtwdev);
44628e93258fSBjoern A. Zeeb err_clear_resource:
44638e93258fSBjoern A. Zeeb 	rtw89_pci_clear_resource(rtwdev, pdev);
44648e93258fSBjoern A. Zeeb err_declaim_pci:
44658e93258fSBjoern A. Zeeb 	rtw89_pci_declaim_device(rtwdev, pdev);
44668e93258fSBjoern A. Zeeb err_core_deinit:
44678e93258fSBjoern A. Zeeb 	rtw89_core_deinit(rtwdev);
44688e93258fSBjoern A. Zeeb err_release_hw:
44698e93258fSBjoern A. Zeeb 	rtw89_free_ieee80211_hw(rtwdev);
44708e93258fSBjoern A. Zeeb 
44718e93258fSBjoern A. Zeeb 	return ret;
44728e93258fSBjoern A. Zeeb }
44738e93258fSBjoern A. Zeeb EXPORT_SYMBOL(rtw89_pci_probe);
44748e93258fSBjoern A. Zeeb 
44758e93258fSBjoern A. Zeeb void rtw89_pci_remove(struct pci_dev *pdev)
44768e93258fSBjoern A. Zeeb {
44778e93258fSBjoern A. Zeeb 	struct ieee80211_hw *hw = pci_get_drvdata(pdev);
44788e93258fSBjoern A. Zeeb 	struct rtw89_dev *rtwdev;
44798e93258fSBjoern A. Zeeb 
44808e93258fSBjoern A. Zeeb 	rtwdev = hw->priv;
44818e93258fSBjoern A. Zeeb 
44828e93258fSBjoern A. Zeeb 	rtw89_pci_free_irq(rtwdev, pdev);
44838e93258fSBjoern A. Zeeb 	rtw89_core_napi_deinit(rtwdev);
44848e93258fSBjoern A. Zeeb 	rtw89_core_unregister(rtwdev);
44858e93258fSBjoern A. Zeeb 	rtw89_pci_clear_resource(rtwdev, pdev);
44868e93258fSBjoern A. Zeeb 	rtw89_pci_declaim_device(rtwdev, pdev);
44878e93258fSBjoern A. Zeeb 	rtw89_core_deinit(rtwdev);
44888e93258fSBjoern A. Zeeb 	rtw89_free_ieee80211_hw(rtwdev);
44898e93258fSBjoern A. Zeeb }
44908e93258fSBjoern A. Zeeb EXPORT_SYMBOL(rtw89_pci_remove);
44918e93258fSBjoern A. Zeeb 
44928e93258fSBjoern A. Zeeb MODULE_AUTHOR("Realtek Corporation");
4493*6d67aabdSBjoern A. Zeeb MODULE_DESCRIPTION("Realtek PCI 802.11ax wireless driver");
44948e93258fSBjoern A. Zeeb MODULE_LICENSE("Dual BSD/GPL");
44958e93258fSBjoern A. Zeeb #if defined(__FreeBSD__)
44968e93258fSBjoern A. Zeeb MODULE_VERSION(rtw89_pci, 1);
44978e93258fSBjoern A. Zeeb MODULE_DEPEND(rtw89_pci, linuxkpi, 1, 1, 1);
44988e93258fSBjoern A. Zeeb MODULE_DEPEND(rtw89_pci, linuxkpi_wlan, 1, 1, 1);
44998e93258fSBjoern A. Zeeb #ifdef CONFIG_RTW89_DEBUGFS
45001a2b5573SBjoern A. Zeeb MODULE_DEPEND(rtw89_pci, lindebugfs, 1, 1, 1);
45018e93258fSBjoern A. Zeeb #endif
45028e93258fSBjoern A. Zeeb #endif
4503