xref: /linux/drivers/net/wireless/realtek/rtw89/pci.c (revision 073350da0aa2aead9df7927a1c1046ebf5cdd816)
1e3ec7017SPing-Ke Shih // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2e3ec7017SPing-Ke Shih /* Copyright(c) 2020  Realtek Corporation
3e3ec7017SPing-Ke Shih  */
4e3ec7017SPing-Ke Shih 
5e3ec7017SPing-Ke Shih #include <linux/pci.h>
6e3ec7017SPing-Ke Shih 
7e3ec7017SPing-Ke Shih #include "mac.h"
8e3ec7017SPing-Ke Shih #include "pci.h"
9e3ec7017SPing-Ke Shih #include "reg.h"
10e3ec7017SPing-Ke Shih #include "ser.h"
11e3ec7017SPing-Ke Shih 
12e3ec7017SPing-Ke Shih static bool rtw89_pci_disable_clkreq;
13e3ec7017SPing-Ke Shih static bool rtw89_pci_disable_aspm_l1;
14e3ec7017SPing-Ke Shih static bool rtw89_pci_disable_l1ss;
15e3ec7017SPing-Ke Shih module_param_named(disable_clkreq, rtw89_pci_disable_clkreq, bool, 0644);
16e3ec7017SPing-Ke Shih module_param_named(disable_aspm_l1, rtw89_pci_disable_aspm_l1, bool, 0644);
17e3ec7017SPing-Ke Shih module_param_named(disable_aspm_l1ss, rtw89_pci_disable_l1ss, bool, 0644);
18e3ec7017SPing-Ke Shih MODULE_PARM_DESC(disable_clkreq, "Set Y to disable PCI clkreq support");
19e3ec7017SPing-Ke Shih MODULE_PARM_DESC(disable_aspm_l1, "Set Y to disable PCI ASPM L1 support");
20e3ec7017SPing-Ke Shih MODULE_PARM_DESC(disable_aspm_l1ss, "Set Y to disable PCI L1SS support");
21e3ec7017SPing-Ke Shih 
22e3ec7017SPing-Ke Shih static int rtw89_pci_rst_bdram_pcie(struct rtw89_dev *rtwdev)
23e3ec7017SPing-Ke Shih {
24e3ec7017SPing-Ke Shih 	u32 val;
25e3ec7017SPing-Ke Shih 	int ret;
26e3ec7017SPing-Ke Shih 
27e3ec7017SPing-Ke Shih 	rtw89_write32(rtwdev, R_AX_PCIE_INIT_CFG1,
28e3ec7017SPing-Ke Shih 		      rtw89_read32(rtwdev, R_AX_PCIE_INIT_CFG1) | B_AX_RST_BDRAM);
29e3ec7017SPing-Ke Shih 
30e3ec7017SPing-Ke Shih 	ret = read_poll_timeout_atomic(rtw89_read32, val, !(val & B_AX_RST_BDRAM),
31e3ec7017SPing-Ke Shih 				       1, RTW89_PCI_POLL_BDRAM_RST_CNT, false,
32e3ec7017SPing-Ke Shih 				       rtwdev, R_AX_PCIE_INIT_CFG1);
33e3ec7017SPing-Ke Shih 
34e3ec7017SPing-Ke Shih 	if (ret)
35e3ec7017SPing-Ke Shih 		return -EBUSY;
36e3ec7017SPing-Ke Shih 
37e3ec7017SPing-Ke Shih 	return 0;
38e3ec7017SPing-Ke Shih }
39e3ec7017SPing-Ke Shih 
40e3ec7017SPing-Ke Shih static u32 rtw89_pci_dma_recalc(struct rtw89_dev *rtwdev,
41e3ec7017SPing-Ke Shih 				struct rtw89_pci_dma_ring *bd_ring,
42e3ec7017SPing-Ke Shih 				u32 cur_idx, bool tx)
43e3ec7017SPing-Ke Shih {
44e3ec7017SPing-Ke Shih 	u32 cnt, cur_rp, wp, rp, len;
45e3ec7017SPing-Ke Shih 
46e3ec7017SPing-Ke Shih 	rp = bd_ring->rp;
47e3ec7017SPing-Ke Shih 	wp = bd_ring->wp;
48e3ec7017SPing-Ke Shih 	len = bd_ring->len;
49e3ec7017SPing-Ke Shih 
50e3ec7017SPing-Ke Shih 	cur_rp = FIELD_GET(TXBD_HW_IDX_MASK, cur_idx);
51e3ec7017SPing-Ke Shih 	if (tx)
52e3ec7017SPing-Ke Shih 		cnt = cur_rp >= rp ? cur_rp - rp : len - (rp - cur_rp);
53e3ec7017SPing-Ke Shih 	else
54e3ec7017SPing-Ke Shih 		cnt = cur_rp >= wp ? cur_rp - wp : len - (wp - cur_rp);
55e3ec7017SPing-Ke Shih 
56e3ec7017SPing-Ke Shih 	bd_ring->rp = cur_rp;
57e3ec7017SPing-Ke Shih 
58e3ec7017SPing-Ke Shih 	return cnt;
59e3ec7017SPing-Ke Shih }
60e3ec7017SPing-Ke Shih 
61e3ec7017SPing-Ke Shih static u32 rtw89_pci_txbd_recalc(struct rtw89_dev *rtwdev,
62e3ec7017SPing-Ke Shih 				 struct rtw89_pci_tx_ring *tx_ring)
63e3ec7017SPing-Ke Shih {
64e3ec7017SPing-Ke Shih 	struct rtw89_pci_dma_ring *bd_ring = &tx_ring->bd_ring;
65e4133f26SPing-Ke Shih 	u32 addr_idx = bd_ring->addr.idx;
66e3ec7017SPing-Ke Shih 	u32 cnt, idx;
67e3ec7017SPing-Ke Shih 
68e3ec7017SPing-Ke Shih 	idx = rtw89_read32(rtwdev, addr_idx);
69e3ec7017SPing-Ke Shih 	cnt = rtw89_pci_dma_recalc(rtwdev, bd_ring, idx, true);
70e3ec7017SPing-Ke Shih 
71e3ec7017SPing-Ke Shih 	return cnt;
72e3ec7017SPing-Ke Shih }
73e3ec7017SPing-Ke Shih 
74e3ec7017SPing-Ke Shih static void rtw89_pci_release_fwcmd(struct rtw89_dev *rtwdev,
75e3ec7017SPing-Ke Shih 				    struct rtw89_pci *rtwpci,
76e3ec7017SPing-Ke Shih 				    u32 cnt, bool release_all)
77e3ec7017SPing-Ke Shih {
78e3ec7017SPing-Ke Shih 	struct rtw89_pci_tx_data *tx_data;
79e3ec7017SPing-Ke Shih 	struct sk_buff *skb;
80e3ec7017SPing-Ke Shih 	u32 qlen;
81e3ec7017SPing-Ke Shih 
82e3ec7017SPing-Ke Shih 	while (cnt--) {
83e3ec7017SPing-Ke Shih 		skb = skb_dequeue(&rtwpci->h2c_queue);
84e3ec7017SPing-Ke Shih 		if (!skb) {
85e3ec7017SPing-Ke Shih 			rtw89_err(rtwdev, "failed to pre-release fwcmd\n");
86e3ec7017SPing-Ke Shih 			return;
87e3ec7017SPing-Ke Shih 		}
88e3ec7017SPing-Ke Shih 		skb_queue_tail(&rtwpci->h2c_release_queue, skb);
89e3ec7017SPing-Ke Shih 	}
90e3ec7017SPing-Ke Shih 
91e3ec7017SPing-Ke Shih 	qlen = skb_queue_len(&rtwpci->h2c_release_queue);
92e3ec7017SPing-Ke Shih 	if (!release_all)
93e3ec7017SPing-Ke Shih 	       qlen = qlen > RTW89_PCI_MULTITAG ? qlen - RTW89_PCI_MULTITAG : 0;
94e3ec7017SPing-Ke Shih 
95e3ec7017SPing-Ke Shih 	while (qlen--) {
96e3ec7017SPing-Ke Shih 		skb = skb_dequeue(&rtwpci->h2c_release_queue);
97e3ec7017SPing-Ke Shih 		if (!skb) {
98e3ec7017SPing-Ke Shih 			rtw89_err(rtwdev, "failed to release fwcmd\n");
99e3ec7017SPing-Ke Shih 			return;
100e3ec7017SPing-Ke Shih 		}
101e3ec7017SPing-Ke Shih 		tx_data = RTW89_PCI_TX_SKB_CB(skb);
102e3ec7017SPing-Ke Shih 		dma_unmap_single(&rtwpci->pdev->dev, tx_data->dma, skb->len,
103e3ec7017SPing-Ke Shih 				 DMA_TO_DEVICE);
104e3ec7017SPing-Ke Shih 		dev_kfree_skb_any(skb);
105e3ec7017SPing-Ke Shih 	}
106e3ec7017SPing-Ke Shih }
107e3ec7017SPing-Ke Shih 
108e3ec7017SPing-Ke Shih static void rtw89_pci_reclaim_tx_fwcmd(struct rtw89_dev *rtwdev,
109e3ec7017SPing-Ke Shih 				       struct rtw89_pci *rtwpci)
110e3ec7017SPing-Ke Shih {
111e3ec7017SPing-Ke Shih 	struct rtw89_pci_tx_ring *tx_ring = &rtwpci->tx_rings[RTW89_TXCH_CH12];
112e3ec7017SPing-Ke Shih 	u32 cnt;
113e3ec7017SPing-Ke Shih 
114e3ec7017SPing-Ke Shih 	cnt = rtw89_pci_txbd_recalc(rtwdev, tx_ring);
115e3ec7017SPing-Ke Shih 	if (!cnt)
116e3ec7017SPing-Ke Shih 		return;
117e3ec7017SPing-Ke Shih 	rtw89_pci_release_fwcmd(rtwdev, rtwpci, cnt, false);
118e3ec7017SPing-Ke Shih }
119e3ec7017SPing-Ke Shih 
120e3ec7017SPing-Ke Shih static u32 rtw89_pci_rxbd_recalc(struct rtw89_dev *rtwdev,
121e3ec7017SPing-Ke Shih 				 struct rtw89_pci_rx_ring *rx_ring)
122e3ec7017SPing-Ke Shih {
123e3ec7017SPing-Ke Shih 	struct rtw89_pci_dma_ring *bd_ring = &rx_ring->bd_ring;
124e4133f26SPing-Ke Shih 	u32 addr_idx = bd_ring->addr.idx;
125e3ec7017SPing-Ke Shih 	u32 cnt, idx;
126e3ec7017SPing-Ke Shih 
127e3ec7017SPing-Ke Shih 	idx = rtw89_read32(rtwdev, addr_idx);
128e3ec7017SPing-Ke Shih 	cnt = rtw89_pci_dma_recalc(rtwdev, bd_ring, idx, false);
129e3ec7017SPing-Ke Shih 
130e3ec7017SPing-Ke Shih 	return cnt;
131e3ec7017SPing-Ke Shih }
132e3ec7017SPing-Ke Shih 
133e3ec7017SPing-Ke Shih static void rtw89_pci_sync_skb_for_cpu(struct rtw89_dev *rtwdev,
134e3ec7017SPing-Ke Shih 				       struct sk_buff *skb)
135e3ec7017SPing-Ke Shih {
136e3ec7017SPing-Ke Shih 	struct rtw89_pci_rx_info *rx_info;
137e3ec7017SPing-Ke Shih 	dma_addr_t dma;
138e3ec7017SPing-Ke Shih 
139e3ec7017SPing-Ke Shih 	rx_info = RTW89_PCI_RX_SKB_CB(skb);
140e3ec7017SPing-Ke Shih 	dma = rx_info->dma;
141e3ec7017SPing-Ke Shih 	dma_sync_single_for_cpu(rtwdev->dev, dma, RTW89_PCI_RX_BUF_SIZE,
142e3ec7017SPing-Ke Shih 				DMA_FROM_DEVICE);
143e3ec7017SPing-Ke Shih }
144e3ec7017SPing-Ke Shih 
145e3ec7017SPing-Ke Shih static void rtw89_pci_sync_skb_for_device(struct rtw89_dev *rtwdev,
146e3ec7017SPing-Ke Shih 					  struct sk_buff *skb)
147e3ec7017SPing-Ke Shih {
148e3ec7017SPing-Ke Shih 	struct rtw89_pci_rx_info *rx_info;
149e3ec7017SPing-Ke Shih 	dma_addr_t dma;
150e3ec7017SPing-Ke Shih 
151e3ec7017SPing-Ke Shih 	rx_info = RTW89_PCI_RX_SKB_CB(skb);
152e3ec7017SPing-Ke Shih 	dma = rx_info->dma;
153e3ec7017SPing-Ke Shih 	dma_sync_single_for_device(rtwdev->dev, dma, RTW89_PCI_RX_BUF_SIZE,
154e3ec7017SPing-Ke Shih 				   DMA_FROM_DEVICE);
155e3ec7017SPing-Ke Shih }
156e3ec7017SPing-Ke Shih 
157e3ec7017SPing-Ke Shih static int rtw89_pci_rxbd_info_update(struct rtw89_dev *rtwdev,
158e3ec7017SPing-Ke Shih 				      struct sk_buff *skb)
159e3ec7017SPing-Ke Shih {
160e3ec7017SPing-Ke Shih 	struct rtw89_pci_rxbd_info *rxbd_info;
161e3ec7017SPing-Ke Shih 	struct rtw89_pci_rx_info *rx_info = RTW89_PCI_RX_SKB_CB(skb);
162e3ec7017SPing-Ke Shih 
163e3ec7017SPing-Ke Shih 	rxbd_info = (struct rtw89_pci_rxbd_info *)skb->data;
164e3ec7017SPing-Ke Shih 	rx_info->fs = le32_get_bits(rxbd_info->dword, RTW89_PCI_RXBD_FS);
165e3ec7017SPing-Ke Shih 	rx_info->ls = le32_get_bits(rxbd_info->dword, RTW89_PCI_RXBD_LS);
166e3ec7017SPing-Ke Shih 	rx_info->len = le32_get_bits(rxbd_info->dword, RTW89_PCI_RXBD_WRITE_SIZE);
167e3ec7017SPing-Ke Shih 	rx_info->tag = le32_get_bits(rxbd_info->dword, RTW89_PCI_RXBD_TAG);
168e3ec7017SPing-Ke Shih 
169e3ec7017SPing-Ke Shih 	return 0;
170e3ec7017SPing-Ke Shih }
171e3ec7017SPing-Ke Shih 
172e3ec7017SPing-Ke Shih static bool
173e3ec7017SPing-Ke Shih rtw89_skb_put_rx_data(struct rtw89_dev *rtwdev, bool fs, bool ls,
174e3ec7017SPing-Ke Shih 		      struct sk_buff *new,
175e3ec7017SPing-Ke Shih 		      const struct sk_buff *skb, u32 offset,
176e3ec7017SPing-Ke Shih 		      const struct rtw89_pci_rx_info *rx_info,
177e3ec7017SPing-Ke Shih 		      const struct rtw89_rx_desc_info *desc_info)
178e3ec7017SPing-Ke Shih {
179e3ec7017SPing-Ke Shih 	u32 copy_len = rx_info->len - offset;
180e3ec7017SPing-Ke Shih 
181e3ec7017SPing-Ke Shih 	if (unlikely(skb_tailroom(new) < copy_len)) {
182e3ec7017SPing-Ke Shih 		rtw89_debug(rtwdev, RTW89_DBG_TXRX,
183e3ec7017SPing-Ke Shih 			    "invalid rx data length bd_len=%d desc_len=%d offset=%d (fs=%d ls=%d)\n",
184e3ec7017SPing-Ke Shih 			    rx_info->len, desc_info->pkt_size, offset, fs, ls);
185e3ec7017SPing-Ke Shih 		rtw89_hex_dump(rtwdev, RTW89_DBG_TXRX, "rx_data: ",
186e3ec7017SPing-Ke Shih 			       skb->data, rx_info->len);
187e3ec7017SPing-Ke Shih 		/* length of a single segment skb is desc_info->pkt_size */
188e3ec7017SPing-Ke Shih 		if (fs && ls) {
189e3ec7017SPing-Ke Shih 			copy_len = desc_info->pkt_size;
190e3ec7017SPing-Ke Shih 		} else {
191e3ec7017SPing-Ke Shih 			rtw89_info(rtwdev, "drop rx data due to invalid length\n");
192e3ec7017SPing-Ke Shih 			return false;
193e3ec7017SPing-Ke Shih 		}
194e3ec7017SPing-Ke Shih 	}
195e3ec7017SPing-Ke Shih 
196e3ec7017SPing-Ke Shih 	skb_put_data(new, skb->data + offset, copy_len);
197e3ec7017SPing-Ke Shih 
198e3ec7017SPing-Ke Shih 	return true;
199e3ec7017SPing-Ke Shih }
200e3ec7017SPing-Ke Shih 
201e3ec7017SPing-Ke Shih static u32 rtw89_pci_rxbd_deliver_skbs(struct rtw89_dev *rtwdev,
202e3ec7017SPing-Ke Shih 				       struct rtw89_pci_rx_ring *rx_ring)
203e3ec7017SPing-Ke Shih {
204e3ec7017SPing-Ke Shih 	struct rtw89_pci_dma_ring *bd_ring = &rx_ring->bd_ring;
205e3ec7017SPing-Ke Shih 	struct rtw89_pci_rx_info *rx_info;
206e3ec7017SPing-Ke Shih 	struct rtw89_rx_desc_info *desc_info = &rx_ring->diliver_desc;
207e3ec7017SPing-Ke Shih 	struct sk_buff *new = rx_ring->diliver_skb;
208e3ec7017SPing-Ke Shih 	struct sk_buff *skb;
209e3ec7017SPing-Ke Shih 	u32 rxinfo_size = sizeof(struct rtw89_pci_rxbd_info);
210e3ec7017SPing-Ke Shih 	u32 offset;
211e3ec7017SPing-Ke Shih 	u32 cnt = 1;
212e3ec7017SPing-Ke Shih 	bool fs, ls;
213e3ec7017SPing-Ke Shih 	int ret;
214e3ec7017SPing-Ke Shih 
215e3ec7017SPing-Ke Shih 	skb = rx_ring->buf[bd_ring->wp];
216e3ec7017SPing-Ke Shih 	rtw89_pci_sync_skb_for_cpu(rtwdev, skb);
217e3ec7017SPing-Ke Shih 
218e3ec7017SPing-Ke Shih 	ret = rtw89_pci_rxbd_info_update(rtwdev, skb);
219e3ec7017SPing-Ke Shih 	if (ret) {
220e3ec7017SPing-Ke Shih 		rtw89_err(rtwdev, "failed to update %d RXBD info: %d\n",
221e3ec7017SPing-Ke Shih 			  bd_ring->wp, ret);
222e3ec7017SPing-Ke Shih 		goto err_sync_device;
223e3ec7017SPing-Ke Shih 	}
224e3ec7017SPing-Ke Shih 
225e3ec7017SPing-Ke Shih 	rx_info = RTW89_PCI_RX_SKB_CB(skb);
226e3ec7017SPing-Ke Shih 	fs = rx_info->fs;
227e3ec7017SPing-Ke Shih 	ls = rx_info->ls;
228e3ec7017SPing-Ke Shih 
229e3ec7017SPing-Ke Shih 	if (fs) {
230e3ec7017SPing-Ke Shih 		if (new) {
231e3ec7017SPing-Ke Shih 			rtw89_err(rtwdev, "skb should not be ready before first segment start\n");
232e3ec7017SPing-Ke Shih 			goto err_sync_device;
233e3ec7017SPing-Ke Shih 		}
234e3ec7017SPing-Ke Shih 		if (desc_info->ready) {
235e3ec7017SPing-Ke Shih 			rtw89_warn(rtwdev, "desc info should not be ready before first segment start\n");
236e3ec7017SPing-Ke Shih 			goto err_sync_device;
237e3ec7017SPing-Ke Shih 		}
238e3ec7017SPing-Ke Shih 
239e3ec7017SPing-Ke Shih 		rtw89_core_query_rxdesc(rtwdev, desc_info, skb->data, rxinfo_size);
240e3ec7017SPing-Ke Shih 
241e3ec7017SPing-Ke Shih 		new = dev_alloc_skb(desc_info->pkt_size);
242e3ec7017SPing-Ke Shih 		if (!new)
243e3ec7017SPing-Ke Shih 			goto err_sync_device;
244e3ec7017SPing-Ke Shih 
245e3ec7017SPing-Ke Shih 		rx_ring->diliver_skb = new;
246e3ec7017SPing-Ke Shih 
247e3ec7017SPing-Ke Shih 		/* first segment has RX desc */
248e3ec7017SPing-Ke Shih 		offset = desc_info->offset;
249e3ec7017SPing-Ke Shih 		offset += desc_info->long_rxdesc ? sizeof(struct rtw89_rxdesc_long) :
250e3ec7017SPing-Ke Shih 			  sizeof(struct rtw89_rxdesc_short);
251e3ec7017SPing-Ke Shih 	} else {
252e3ec7017SPing-Ke Shih 		offset = sizeof(struct rtw89_pci_rxbd_info);
253e3ec7017SPing-Ke Shih 		if (!new) {
254e3ec7017SPing-Ke Shih 			rtw89_warn(rtwdev, "no last skb\n");
255e3ec7017SPing-Ke Shih 			goto err_sync_device;
256e3ec7017SPing-Ke Shih 		}
257e3ec7017SPing-Ke Shih 	}
258e3ec7017SPing-Ke Shih 	if (!rtw89_skb_put_rx_data(rtwdev, fs, ls, new, skb, offset, rx_info, desc_info))
259e3ec7017SPing-Ke Shih 		goto err_sync_device;
260e3ec7017SPing-Ke Shih 	rtw89_pci_sync_skb_for_device(rtwdev, skb);
261e3ec7017SPing-Ke Shih 	rtw89_pci_rxbd_increase(rx_ring, 1);
262e3ec7017SPing-Ke Shih 
263e3ec7017SPing-Ke Shih 	if (!desc_info->ready) {
264e3ec7017SPing-Ke Shih 		rtw89_warn(rtwdev, "no rx desc information\n");
265e3ec7017SPing-Ke Shih 		goto err_free_resource;
266e3ec7017SPing-Ke Shih 	}
267e3ec7017SPing-Ke Shih 	if (ls) {
268e3ec7017SPing-Ke Shih 		rtw89_core_rx(rtwdev, desc_info, new);
269e3ec7017SPing-Ke Shih 		rx_ring->diliver_skb = NULL;
270e3ec7017SPing-Ke Shih 		desc_info->ready = false;
271e3ec7017SPing-Ke Shih 	}
272e3ec7017SPing-Ke Shih 
273e3ec7017SPing-Ke Shih 	return cnt;
274e3ec7017SPing-Ke Shih 
275e3ec7017SPing-Ke Shih err_sync_device:
276e3ec7017SPing-Ke Shih 	rtw89_pci_sync_skb_for_device(rtwdev, skb);
277e3ec7017SPing-Ke Shih 	rtw89_pci_rxbd_increase(rx_ring, 1);
278e3ec7017SPing-Ke Shih err_free_resource:
279e3ec7017SPing-Ke Shih 	if (new)
280e3ec7017SPing-Ke Shih 		dev_kfree_skb_any(new);
281e3ec7017SPing-Ke Shih 	rx_ring->diliver_skb = NULL;
282e3ec7017SPing-Ke Shih 	desc_info->ready = false;
283e3ec7017SPing-Ke Shih 
284e3ec7017SPing-Ke Shih 	return cnt;
285e3ec7017SPing-Ke Shih }
286e3ec7017SPing-Ke Shih 
287e3ec7017SPing-Ke Shih static void rtw89_pci_rxbd_deliver(struct rtw89_dev *rtwdev,
288e3ec7017SPing-Ke Shih 				   struct rtw89_pci_rx_ring *rx_ring,
289e3ec7017SPing-Ke Shih 				   u32 cnt)
290e3ec7017SPing-Ke Shih {
291e3ec7017SPing-Ke Shih 	struct rtw89_pci_dma_ring *bd_ring = &rx_ring->bd_ring;
292e3ec7017SPing-Ke Shih 	u32 rx_cnt;
293e3ec7017SPing-Ke Shih 
294e3ec7017SPing-Ke Shih 	while (cnt && rtwdev->napi_budget_countdown > 0) {
295e3ec7017SPing-Ke Shih 		rx_cnt = rtw89_pci_rxbd_deliver_skbs(rtwdev, rx_ring);
296e3ec7017SPing-Ke Shih 		if (!rx_cnt) {
297e3ec7017SPing-Ke Shih 			rtw89_err(rtwdev, "failed to deliver RXBD skb\n");
298e3ec7017SPing-Ke Shih 
299e3ec7017SPing-Ke Shih 			/* skip the rest RXBD bufs */
300e3ec7017SPing-Ke Shih 			rtw89_pci_rxbd_increase(rx_ring, cnt);
301e3ec7017SPing-Ke Shih 			break;
302e3ec7017SPing-Ke Shih 		}
303e3ec7017SPing-Ke Shih 
304e3ec7017SPing-Ke Shih 		cnt -= rx_cnt;
305e3ec7017SPing-Ke Shih 	}
306e3ec7017SPing-Ke Shih 
307e4133f26SPing-Ke Shih 	rtw89_write16(rtwdev, bd_ring->addr.idx, bd_ring->wp);
308e3ec7017SPing-Ke Shih }
309e3ec7017SPing-Ke Shih 
310e3ec7017SPing-Ke Shih static int rtw89_pci_poll_rxq_dma(struct rtw89_dev *rtwdev,
311e3ec7017SPing-Ke Shih 				  struct rtw89_pci *rtwpci, int budget)
312e3ec7017SPing-Ke Shih {
313e3ec7017SPing-Ke Shih 	struct rtw89_pci_rx_ring *rx_ring;
314e3ec7017SPing-Ke Shih 	int countdown = rtwdev->napi_budget_countdown;
315e3ec7017SPing-Ke Shih 	u32 cnt;
316e3ec7017SPing-Ke Shih 
317e3ec7017SPing-Ke Shih 	rx_ring = &rtwpci->rx_rings[RTW89_RXCH_RXQ];
318e3ec7017SPing-Ke Shih 
319e3ec7017SPing-Ke Shih 	cnt = rtw89_pci_rxbd_recalc(rtwdev, rx_ring);
320e3ec7017SPing-Ke Shih 	if (!cnt)
321e3ec7017SPing-Ke Shih 		return 0;
322e3ec7017SPing-Ke Shih 
323e3ec7017SPing-Ke Shih 	cnt = min_t(u32, budget, cnt);
324e3ec7017SPing-Ke Shih 
325e3ec7017SPing-Ke Shih 	rtw89_pci_rxbd_deliver(rtwdev, rx_ring, cnt);
326e3ec7017SPing-Ke Shih 
327e3ec7017SPing-Ke Shih 	/* In case of flushing pending SKBs, the countdown may exceed. */
328e3ec7017SPing-Ke Shih 	if (rtwdev->napi_budget_countdown <= 0)
329e3ec7017SPing-Ke Shih 		return budget;
330e3ec7017SPing-Ke Shih 
331e3ec7017SPing-Ke Shih 	return budget - countdown;
332e3ec7017SPing-Ke Shih }
333e3ec7017SPing-Ke Shih 
334e3ec7017SPing-Ke Shih static void rtw89_pci_tx_status(struct rtw89_dev *rtwdev,
335e3ec7017SPing-Ke Shih 				struct rtw89_pci_tx_ring *tx_ring,
336e3ec7017SPing-Ke Shih 				struct sk_buff *skb, u8 tx_status)
337e3ec7017SPing-Ke Shih {
338e3ec7017SPing-Ke Shih 	struct ieee80211_tx_info *info;
339e3ec7017SPing-Ke Shih 
340e3ec7017SPing-Ke Shih 	info = IEEE80211_SKB_CB(skb);
341e3ec7017SPing-Ke Shih 	ieee80211_tx_info_clear_status(info);
342e3ec7017SPing-Ke Shih 
343e3ec7017SPing-Ke Shih 	if (info->flags & IEEE80211_TX_CTL_NO_ACK)
344e3ec7017SPing-Ke Shih 		info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED;
345e3ec7017SPing-Ke Shih 	if (tx_status == RTW89_TX_DONE) {
346e3ec7017SPing-Ke Shih 		info->flags |= IEEE80211_TX_STAT_ACK;
347e3ec7017SPing-Ke Shih 		tx_ring->tx_acked++;
348e3ec7017SPing-Ke Shih 	} else {
349e3ec7017SPing-Ke Shih 		if (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)
350e3ec7017SPing-Ke Shih 			rtw89_debug(rtwdev, RTW89_DBG_FW,
351e3ec7017SPing-Ke Shih 				    "failed to TX of status %x\n", tx_status);
352e3ec7017SPing-Ke Shih 		switch (tx_status) {
353e3ec7017SPing-Ke Shih 		case RTW89_TX_RETRY_LIMIT:
354e3ec7017SPing-Ke Shih 			tx_ring->tx_retry_lmt++;
355e3ec7017SPing-Ke Shih 			break;
356e3ec7017SPing-Ke Shih 		case RTW89_TX_LIFE_TIME:
357e3ec7017SPing-Ke Shih 			tx_ring->tx_life_time++;
358e3ec7017SPing-Ke Shih 			break;
359e3ec7017SPing-Ke Shih 		case RTW89_TX_MACID_DROP:
360e3ec7017SPing-Ke Shih 			tx_ring->tx_mac_id_drop++;
361e3ec7017SPing-Ke Shih 			break;
362e3ec7017SPing-Ke Shih 		default:
363e3ec7017SPing-Ke Shih 			rtw89_warn(rtwdev, "invalid TX status %x\n", tx_status);
364e3ec7017SPing-Ke Shih 			break;
365e3ec7017SPing-Ke Shih 		}
366e3ec7017SPing-Ke Shih 	}
367e3ec7017SPing-Ke Shih 
368e3ec7017SPing-Ke Shih 	ieee80211_tx_status_ni(rtwdev->hw, skb);
369e3ec7017SPing-Ke Shih }
370e3ec7017SPing-Ke Shih 
371e3ec7017SPing-Ke Shih static void rtw89_pci_reclaim_txbd(struct rtw89_dev *rtwdev, struct rtw89_pci_tx_ring *tx_ring)
372e3ec7017SPing-Ke Shih {
373e3ec7017SPing-Ke Shih 	struct rtw89_pci_tx_wd *txwd;
374e3ec7017SPing-Ke Shih 	u32 cnt;
375e3ec7017SPing-Ke Shih 
376e3ec7017SPing-Ke Shih 	cnt = rtw89_pci_txbd_recalc(rtwdev, tx_ring);
377e3ec7017SPing-Ke Shih 	while (cnt--) {
378e3ec7017SPing-Ke Shih 		txwd = list_first_entry_or_null(&tx_ring->busy_pages, struct rtw89_pci_tx_wd, list);
379e3ec7017SPing-Ke Shih 		if (!txwd) {
380e3ec7017SPing-Ke Shih 			rtw89_warn(rtwdev, "No busy txwd pages available\n");
381e3ec7017SPing-Ke Shih 			break;
382e3ec7017SPing-Ke Shih 		}
383e3ec7017SPing-Ke Shih 
384e3ec7017SPing-Ke Shih 		list_del_init(&txwd->list);
385*d7259cdbSPing-Ke Shih 
386*d7259cdbSPing-Ke Shih 		/* this skb has been freed by RPP */
387*d7259cdbSPing-Ke Shih 		if (skb_queue_len(&txwd->queue) == 0)
388*d7259cdbSPing-Ke Shih 			rtw89_pci_enqueue_txwd(tx_ring, txwd);
389e3ec7017SPing-Ke Shih 	}
390e3ec7017SPing-Ke Shih }
391e3ec7017SPing-Ke Shih 
392e3ec7017SPing-Ke Shih static void rtw89_pci_release_busy_txwd(struct rtw89_dev *rtwdev,
393e3ec7017SPing-Ke Shih 					struct rtw89_pci_tx_ring *tx_ring)
394e3ec7017SPing-Ke Shih {
395e3ec7017SPing-Ke Shih 	struct rtw89_pci_tx_wd_ring *wd_ring = &tx_ring->wd_ring;
396e3ec7017SPing-Ke Shih 	struct rtw89_pci_tx_wd *txwd;
397e3ec7017SPing-Ke Shih 	int i;
398e3ec7017SPing-Ke Shih 
399e3ec7017SPing-Ke Shih 	for (i = 0; i < wd_ring->page_num; i++) {
400e3ec7017SPing-Ke Shih 		txwd = list_first_entry_or_null(&tx_ring->busy_pages, struct rtw89_pci_tx_wd, list);
401e3ec7017SPing-Ke Shih 		if (!txwd)
402e3ec7017SPing-Ke Shih 			break;
403e3ec7017SPing-Ke Shih 
404e3ec7017SPing-Ke Shih 		list_del_init(&txwd->list);
405e3ec7017SPing-Ke Shih 	}
406e3ec7017SPing-Ke Shih }
407e3ec7017SPing-Ke Shih 
408e3ec7017SPing-Ke Shih static void rtw89_pci_release_txwd_skb(struct rtw89_dev *rtwdev,
409e3ec7017SPing-Ke Shih 				       struct rtw89_pci_tx_ring *tx_ring,
410e3ec7017SPing-Ke Shih 				       struct rtw89_pci_tx_wd *txwd, u16 seq,
411e3ec7017SPing-Ke Shih 				       u8 tx_status)
412e3ec7017SPing-Ke Shih {
413e3ec7017SPing-Ke Shih 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
414e3ec7017SPing-Ke Shih 	struct rtw89_pci_tx_data *tx_data;
415e3ec7017SPing-Ke Shih 	struct sk_buff *skb, *tmp;
416e3ec7017SPing-Ke Shih 	u8 txch = tx_ring->txch;
417e3ec7017SPing-Ke Shih 
418e3ec7017SPing-Ke Shih 	if (!list_empty(&txwd->list)) {
41983720268SPing-Ke Shih 		rtw89_pci_reclaim_txbd(rtwdev, tx_ring);
420*d7259cdbSPing-Ke Shih 		/* In low power mode, RPP can receive before updating of TX BD.
421*d7259cdbSPing-Ke Shih 		 * In normal mode, it should not happen so give it a warning.
422*d7259cdbSPing-Ke Shih 		 */
423*d7259cdbSPing-Ke Shih 		if (!rtwpci->low_power && !list_empty(&txwd->list))
424e3ec7017SPing-Ke Shih 			rtw89_warn(rtwdev, "queue %d txwd %d is not idle\n",
425e3ec7017SPing-Ke Shih 				   txch, seq);
426e3ec7017SPing-Ke Shih 	}
427e3ec7017SPing-Ke Shih 
428e3ec7017SPing-Ke Shih 	skb_queue_walk_safe(&txwd->queue, skb, tmp) {
429e3ec7017SPing-Ke Shih 		skb_unlink(skb, &txwd->queue);
430e3ec7017SPing-Ke Shih 
431e3ec7017SPing-Ke Shih 		tx_data = RTW89_PCI_TX_SKB_CB(skb);
432e3ec7017SPing-Ke Shih 		dma_unmap_single(&rtwpci->pdev->dev, tx_data->dma, skb->len,
433e3ec7017SPing-Ke Shih 				 DMA_TO_DEVICE);
434e3ec7017SPing-Ke Shih 
435e3ec7017SPing-Ke Shih 		rtw89_pci_tx_status(rtwdev, tx_ring, skb, tx_status);
436e3ec7017SPing-Ke Shih 	}
437e3ec7017SPing-Ke Shih 
438*d7259cdbSPing-Ke Shih 	if (list_empty(&txwd->list))
439e3ec7017SPing-Ke Shih 		rtw89_pci_enqueue_txwd(tx_ring, txwd);
440e3ec7017SPing-Ke Shih }
441e3ec7017SPing-Ke Shih 
442e3ec7017SPing-Ke Shih static void rtw89_pci_release_rpp(struct rtw89_dev *rtwdev,
443e3ec7017SPing-Ke Shih 				  struct rtw89_pci_rpp_fmt *rpp)
444e3ec7017SPing-Ke Shih {
445e3ec7017SPing-Ke Shih 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
446e3ec7017SPing-Ke Shih 	struct rtw89_pci_tx_ring *tx_ring;
447e3ec7017SPing-Ke Shih 	struct rtw89_pci_tx_wd_ring *wd_ring;
448e3ec7017SPing-Ke Shih 	struct rtw89_pci_tx_wd *txwd;
449e3ec7017SPing-Ke Shih 	u16 seq;
450e3ec7017SPing-Ke Shih 	u8 qsel, tx_status, txch;
451e3ec7017SPing-Ke Shih 
452e3ec7017SPing-Ke Shih 	seq = le32_get_bits(rpp->dword, RTW89_PCI_RPP_SEQ);
453e3ec7017SPing-Ke Shih 	qsel = le32_get_bits(rpp->dword, RTW89_PCI_RPP_QSEL);
454e3ec7017SPing-Ke Shih 	tx_status = le32_get_bits(rpp->dword, RTW89_PCI_RPP_TX_STATUS);
455e3ec7017SPing-Ke Shih 	txch = rtw89_core_get_ch_dma(rtwdev, qsel);
456e3ec7017SPing-Ke Shih 
457e3ec7017SPing-Ke Shih 	if (txch == RTW89_TXCH_CH12) {
458e3ec7017SPing-Ke Shih 		rtw89_warn(rtwdev, "should no fwcmd release report\n");
459e3ec7017SPing-Ke Shih 		return;
460e3ec7017SPing-Ke Shih 	}
461e3ec7017SPing-Ke Shih 
462e3ec7017SPing-Ke Shih 	tx_ring = &rtwpci->tx_rings[txch];
463e3ec7017SPing-Ke Shih 	wd_ring = &tx_ring->wd_ring;
464e3ec7017SPing-Ke Shih 	txwd = &wd_ring->pages[seq];
465e3ec7017SPing-Ke Shih 
466e3ec7017SPing-Ke Shih 	rtw89_pci_release_txwd_skb(rtwdev, tx_ring, txwd, seq, tx_status);
467e3ec7017SPing-Ke Shih }
468e3ec7017SPing-Ke Shih 
469e3ec7017SPing-Ke Shih static void rtw89_pci_release_pending_txwd_skb(struct rtw89_dev *rtwdev,
470e3ec7017SPing-Ke Shih 					       struct rtw89_pci_tx_ring *tx_ring)
471e3ec7017SPing-Ke Shih {
472e3ec7017SPing-Ke Shih 	struct rtw89_pci_tx_wd_ring *wd_ring = &tx_ring->wd_ring;
473e3ec7017SPing-Ke Shih 	struct rtw89_pci_tx_wd *txwd;
474e3ec7017SPing-Ke Shih 	int i;
475e3ec7017SPing-Ke Shih 
476e3ec7017SPing-Ke Shih 	for (i = 0; i < wd_ring->page_num; i++) {
477e3ec7017SPing-Ke Shih 		txwd = &wd_ring->pages[i];
478e3ec7017SPing-Ke Shih 
479e3ec7017SPing-Ke Shih 		if (!list_empty(&txwd->list))
480e3ec7017SPing-Ke Shih 			continue;
481e3ec7017SPing-Ke Shih 
482e3ec7017SPing-Ke Shih 		rtw89_pci_release_txwd_skb(rtwdev, tx_ring, txwd, i, RTW89_TX_MACID_DROP);
483e3ec7017SPing-Ke Shih 	}
484e3ec7017SPing-Ke Shih }
485e3ec7017SPing-Ke Shih 
486e3ec7017SPing-Ke Shih static u32 rtw89_pci_release_tx_skbs(struct rtw89_dev *rtwdev,
487e3ec7017SPing-Ke Shih 				     struct rtw89_pci_rx_ring *rx_ring,
488e3ec7017SPing-Ke Shih 				     u32 max_cnt)
489e3ec7017SPing-Ke Shih {
490e3ec7017SPing-Ke Shih 	struct rtw89_pci_dma_ring *bd_ring = &rx_ring->bd_ring;
491e3ec7017SPing-Ke Shih 	struct rtw89_pci_rx_info *rx_info;
492e3ec7017SPing-Ke Shih 	struct rtw89_pci_rpp_fmt *rpp;
493e3ec7017SPing-Ke Shih 	struct rtw89_rx_desc_info desc_info = {};
494e3ec7017SPing-Ke Shih 	struct sk_buff *skb;
495e3ec7017SPing-Ke Shih 	u32 cnt = 0;
496e3ec7017SPing-Ke Shih 	u32 rpp_size = sizeof(struct rtw89_pci_rpp_fmt);
497e3ec7017SPing-Ke Shih 	u32 rxinfo_size = sizeof(struct rtw89_pci_rxbd_info);
498e3ec7017SPing-Ke Shih 	u32 offset;
499e3ec7017SPing-Ke Shih 	int ret;
500e3ec7017SPing-Ke Shih 
501e3ec7017SPing-Ke Shih 	skb = rx_ring->buf[bd_ring->wp];
502e3ec7017SPing-Ke Shih 	rtw89_pci_sync_skb_for_cpu(rtwdev, skb);
503e3ec7017SPing-Ke Shih 
504e3ec7017SPing-Ke Shih 	ret = rtw89_pci_rxbd_info_update(rtwdev, skb);
505e3ec7017SPing-Ke Shih 	if (ret) {
506e3ec7017SPing-Ke Shih 		rtw89_err(rtwdev, "failed to update %d RXBD info: %d\n",
507e3ec7017SPing-Ke Shih 			  bd_ring->wp, ret);
508e3ec7017SPing-Ke Shih 		goto err_sync_device;
509e3ec7017SPing-Ke Shih 	}
510e3ec7017SPing-Ke Shih 
511e3ec7017SPing-Ke Shih 	rx_info = RTW89_PCI_RX_SKB_CB(skb);
512e3ec7017SPing-Ke Shih 	if (!rx_info->fs || !rx_info->ls) {
513e3ec7017SPing-Ke Shih 		rtw89_err(rtwdev, "cannot process RP frame not set FS/LS\n");
514e3ec7017SPing-Ke Shih 		return cnt;
515e3ec7017SPing-Ke Shih 	}
516e3ec7017SPing-Ke Shih 
517e3ec7017SPing-Ke Shih 	rtw89_core_query_rxdesc(rtwdev, &desc_info, skb->data, rxinfo_size);
518e3ec7017SPing-Ke Shih 
519e3ec7017SPing-Ke Shih 	/* first segment has RX desc */
520e3ec7017SPing-Ke Shih 	offset = desc_info.offset;
521e3ec7017SPing-Ke Shih 	offset += desc_info.long_rxdesc ? sizeof(struct rtw89_rxdesc_long) :
522e3ec7017SPing-Ke Shih 					  sizeof(struct rtw89_rxdesc_short);
523e3ec7017SPing-Ke Shih 	for (; offset + rpp_size <= rx_info->len; offset += rpp_size) {
524e3ec7017SPing-Ke Shih 		rpp = (struct rtw89_pci_rpp_fmt *)(skb->data + offset);
525e3ec7017SPing-Ke Shih 		rtw89_pci_release_rpp(rtwdev, rpp);
526e3ec7017SPing-Ke Shih 	}
527e3ec7017SPing-Ke Shih 
528e3ec7017SPing-Ke Shih 	rtw89_pci_sync_skb_for_device(rtwdev, skb);
529e3ec7017SPing-Ke Shih 	rtw89_pci_rxbd_increase(rx_ring, 1);
530e3ec7017SPing-Ke Shih 	cnt++;
531e3ec7017SPing-Ke Shih 
532e3ec7017SPing-Ke Shih 	return cnt;
533e3ec7017SPing-Ke Shih 
534e3ec7017SPing-Ke Shih err_sync_device:
535e3ec7017SPing-Ke Shih 	rtw89_pci_sync_skb_for_device(rtwdev, skb);
536e3ec7017SPing-Ke Shih 	return 0;
537e3ec7017SPing-Ke Shih }
538e3ec7017SPing-Ke Shih 
539e3ec7017SPing-Ke Shih static void rtw89_pci_release_tx(struct rtw89_dev *rtwdev,
540e3ec7017SPing-Ke Shih 				 struct rtw89_pci_rx_ring *rx_ring,
541e3ec7017SPing-Ke Shih 				 u32 cnt)
542e3ec7017SPing-Ke Shih {
543e3ec7017SPing-Ke Shih 	struct rtw89_pci_dma_ring *bd_ring = &rx_ring->bd_ring;
544e3ec7017SPing-Ke Shih 	u32 release_cnt;
545e3ec7017SPing-Ke Shih 
546e3ec7017SPing-Ke Shih 	while (cnt) {
547e3ec7017SPing-Ke Shih 		release_cnt = rtw89_pci_release_tx_skbs(rtwdev, rx_ring, cnt);
548e3ec7017SPing-Ke Shih 		if (!release_cnt) {
549e3ec7017SPing-Ke Shih 			rtw89_err(rtwdev, "failed to release TX skbs\n");
550e3ec7017SPing-Ke Shih 
551e3ec7017SPing-Ke Shih 			/* skip the rest RXBD bufs */
552e3ec7017SPing-Ke Shih 			rtw89_pci_rxbd_increase(rx_ring, cnt);
553e3ec7017SPing-Ke Shih 			break;
554e3ec7017SPing-Ke Shih 		}
555e3ec7017SPing-Ke Shih 
556e3ec7017SPing-Ke Shih 		cnt -= release_cnt;
557e3ec7017SPing-Ke Shih 	}
558e3ec7017SPing-Ke Shih 
559e4133f26SPing-Ke Shih 	rtw89_write16(rtwdev, bd_ring->addr.idx, bd_ring->wp);
560e3ec7017SPing-Ke Shih }
561e3ec7017SPing-Ke Shih 
562e3ec7017SPing-Ke Shih static int rtw89_pci_poll_rpq_dma(struct rtw89_dev *rtwdev,
563e3ec7017SPing-Ke Shih 				  struct rtw89_pci *rtwpci, int budget)
564e3ec7017SPing-Ke Shih {
565e3ec7017SPing-Ke Shih 	struct rtw89_pci_rx_ring *rx_ring;
566e3ec7017SPing-Ke Shih 	u32 cnt;
567e3ec7017SPing-Ke Shih 	int work_done;
568e3ec7017SPing-Ke Shih 
569e3ec7017SPing-Ke Shih 	rx_ring = &rtwpci->rx_rings[RTW89_RXCH_RPQ];
570e3ec7017SPing-Ke Shih 
571e3ec7017SPing-Ke Shih 	spin_lock_bh(&rtwpci->trx_lock);
572e3ec7017SPing-Ke Shih 
573e3ec7017SPing-Ke Shih 	cnt = rtw89_pci_rxbd_recalc(rtwdev, rx_ring);
574e3ec7017SPing-Ke Shih 	if (cnt == 0)
575e3ec7017SPing-Ke Shih 		goto out_unlock;
576e3ec7017SPing-Ke Shih 
577e3ec7017SPing-Ke Shih 	rtw89_pci_release_tx(rtwdev, rx_ring, cnt);
578e3ec7017SPing-Ke Shih 
579e3ec7017SPing-Ke Shih out_unlock:
580e3ec7017SPing-Ke Shih 	spin_unlock_bh(&rtwpci->trx_lock);
581e3ec7017SPing-Ke Shih 
582e3ec7017SPing-Ke Shih 	/* always release all RPQ */
583e3ec7017SPing-Ke Shih 	work_done = min_t(int, cnt, budget);
584e3ec7017SPing-Ke Shih 	rtwdev->napi_budget_countdown -= work_done;
585e3ec7017SPing-Ke Shih 
586e3ec7017SPing-Ke Shih 	return work_done;
587e3ec7017SPing-Ke Shih }
588e3ec7017SPing-Ke Shih 
589e3ec7017SPing-Ke Shih static void rtw89_pci_isr_rxd_unavail(struct rtw89_dev *rtwdev,
590e3ec7017SPing-Ke Shih 				      struct rtw89_pci *rtwpci)
591e3ec7017SPing-Ke Shih {
592e3ec7017SPing-Ke Shih 	struct rtw89_pci_rx_ring *rx_ring;
593e3ec7017SPing-Ke Shih 	struct rtw89_pci_dma_ring *bd_ring;
594e3ec7017SPing-Ke Shih 	u32 reg_idx;
595e3ec7017SPing-Ke Shih 	u16 hw_idx, hw_idx_next, host_idx;
596e3ec7017SPing-Ke Shih 	int i;
597e3ec7017SPing-Ke Shih 
598e3ec7017SPing-Ke Shih 	for (i = 0; i < RTW89_RXCH_NUM; i++) {
599e3ec7017SPing-Ke Shih 		rx_ring = &rtwpci->rx_rings[i];
600e3ec7017SPing-Ke Shih 		bd_ring = &rx_ring->bd_ring;
601e3ec7017SPing-Ke Shih 
602e4133f26SPing-Ke Shih 		reg_idx = rtw89_read32(rtwdev, bd_ring->addr.idx);
603e3ec7017SPing-Ke Shih 		hw_idx = FIELD_GET(TXBD_HW_IDX_MASK, reg_idx);
604e3ec7017SPing-Ke Shih 		host_idx = FIELD_GET(TXBD_HOST_IDX_MASK, reg_idx);
605e3ec7017SPing-Ke Shih 		hw_idx_next = (hw_idx + 1) % bd_ring->len;
606e3ec7017SPing-Ke Shih 
607e3ec7017SPing-Ke Shih 		if (hw_idx_next == host_idx)
608e3ec7017SPing-Ke Shih 			rtw89_warn(rtwdev, "%d RXD unavailable\n", i);
609e3ec7017SPing-Ke Shih 
610e3ec7017SPing-Ke Shih 		rtw89_debug(rtwdev, RTW89_DBG_TXRX,
611e3ec7017SPing-Ke Shih 			    "%d RXD unavailable, idx=0x%08x, len=%d\n",
612e3ec7017SPing-Ke Shih 			    i, reg_idx, bd_ring->len);
613e3ec7017SPing-Ke Shih 	}
614e3ec7017SPing-Ke Shih }
615e3ec7017SPing-Ke Shih 
616948e521cSPing-Ke Shih void rtw89_pci_recognize_intrs(struct rtw89_dev *rtwdev,
617e3ec7017SPing-Ke Shih 			       struct rtw89_pci *rtwpci,
618e3ec7017SPing-Ke Shih 			       struct rtw89_pci_isrs *isrs)
619e3ec7017SPing-Ke Shih {
620e3ec7017SPing-Ke Shih 	isrs->halt_c2h_isrs = rtw89_read32(rtwdev, R_AX_HISR0) & rtwpci->halt_c2h_intrs;
621e3ec7017SPing-Ke Shih 	isrs->isrs[0] = rtw89_read32(rtwdev, R_AX_PCIE_HISR00) & rtwpci->intrs[0];
622e3ec7017SPing-Ke Shih 	isrs->isrs[1] = rtw89_read32(rtwdev, R_AX_PCIE_HISR10) & rtwpci->intrs[1];
623e3ec7017SPing-Ke Shih 
624e3ec7017SPing-Ke Shih 	rtw89_write32(rtwdev, R_AX_HISR0, isrs->halt_c2h_isrs);
625e3ec7017SPing-Ke Shih 	rtw89_write32(rtwdev, R_AX_PCIE_HISR00, isrs->isrs[0]);
626e3ec7017SPing-Ke Shih 	rtw89_write32(rtwdev, R_AX_PCIE_HISR10, isrs->isrs[1]);
627e3ec7017SPing-Ke Shih }
628948e521cSPing-Ke Shih EXPORT_SYMBOL(rtw89_pci_recognize_intrs);
629948e521cSPing-Ke Shih 
630948e521cSPing-Ke Shih void rtw89_pci_recognize_intrs_v1(struct rtw89_dev *rtwdev,
631948e521cSPing-Ke Shih 				  struct rtw89_pci *rtwpci,
632948e521cSPing-Ke Shih 				  struct rtw89_pci_isrs *isrs)
633948e521cSPing-Ke Shih {
634948e521cSPing-Ke Shih 	isrs->ind_isrs = rtw89_read32(rtwdev, R_AX_PCIE_HISR00_V1) & rtwpci->ind_intrs;
635948e521cSPing-Ke Shih 	isrs->halt_c2h_isrs = isrs->ind_isrs & B_AX_HS0ISR_IND_INT_EN ?
636948e521cSPing-Ke Shih 			      rtw89_read32(rtwdev, R_AX_HISR0) & rtwpci->halt_c2h_intrs : 0;
637948e521cSPing-Ke Shih 	isrs->isrs[0] = isrs->ind_isrs & B_AX_HCI_AXIDMA_INT_EN ?
638948e521cSPing-Ke Shih 			rtw89_read32(rtwdev, R_AX_HAXI_HISR00) & rtwpci->intrs[0] : 0;
639948e521cSPing-Ke Shih 	isrs->isrs[1] = isrs->ind_isrs & B_AX_HS1ISR_IND_INT_EN ?
640948e521cSPing-Ke Shih 			rtw89_read32(rtwdev, R_AX_HISR1) & rtwpci->intrs[1] : 0;
641948e521cSPing-Ke Shih 
642948e521cSPing-Ke Shih 	if (isrs->halt_c2h_isrs)
643948e521cSPing-Ke Shih 		rtw89_write32(rtwdev, R_AX_HISR0, isrs->halt_c2h_isrs);
644948e521cSPing-Ke Shih 	if (isrs->isrs[0])
645948e521cSPing-Ke Shih 		rtw89_write32(rtwdev, R_AX_HAXI_HISR00, isrs->isrs[0]);
646948e521cSPing-Ke Shih 	if (isrs->isrs[1])
647948e521cSPing-Ke Shih 		rtw89_write32(rtwdev, R_AX_HISR1, isrs->isrs[1]);
648948e521cSPing-Ke Shih }
649948e521cSPing-Ke Shih EXPORT_SYMBOL(rtw89_pci_recognize_intrs_v1);
650e3ec7017SPing-Ke Shih 
651e3ec7017SPing-Ke Shih static void rtw89_pci_clear_isr0(struct rtw89_dev *rtwdev, u32 isr00)
652e3ec7017SPing-Ke Shih {
653e3ec7017SPing-Ke Shih 	/* write 1 clear */
654e3ec7017SPing-Ke Shih 	rtw89_write32(rtwdev, R_AX_PCIE_HISR00, isr00);
655e3ec7017SPing-Ke Shih }
656e3ec7017SPing-Ke Shih 
657948e521cSPing-Ke Shih void rtw89_pci_enable_intr(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci)
658e3ec7017SPing-Ke Shih {
659e3ec7017SPing-Ke Shih 	rtw89_write32(rtwdev, R_AX_HIMR0, rtwpci->halt_c2h_intrs);
660e3ec7017SPing-Ke Shih 	rtw89_write32(rtwdev, R_AX_PCIE_HIMR00, rtwpci->intrs[0]);
661e3ec7017SPing-Ke Shih 	rtw89_write32(rtwdev, R_AX_PCIE_HIMR10, rtwpci->intrs[1]);
662e3ec7017SPing-Ke Shih }
663948e521cSPing-Ke Shih EXPORT_SYMBOL(rtw89_pci_enable_intr);
664e3ec7017SPing-Ke Shih 
665948e521cSPing-Ke Shih void rtw89_pci_disable_intr(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci)
666e3ec7017SPing-Ke Shih {
667e3ec7017SPing-Ke Shih 	rtw89_write32(rtwdev, R_AX_HIMR0, 0);
668e3ec7017SPing-Ke Shih 	rtw89_write32(rtwdev, R_AX_PCIE_HIMR00, 0);
669e3ec7017SPing-Ke Shih 	rtw89_write32(rtwdev, R_AX_PCIE_HIMR10, 0);
670e3ec7017SPing-Ke Shih }
671948e521cSPing-Ke Shih EXPORT_SYMBOL(rtw89_pci_disable_intr);
672948e521cSPing-Ke Shih 
673948e521cSPing-Ke Shih void rtw89_pci_enable_intr_v1(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci)
674948e521cSPing-Ke Shih {
675948e521cSPing-Ke Shih 	rtw89_write32(rtwdev, R_AX_PCIE_HIMR00_V1, rtwpci->ind_intrs);
676948e521cSPing-Ke Shih 	rtw89_write32(rtwdev, R_AX_HIMR0, rtwpci->halt_c2h_intrs);
677948e521cSPing-Ke Shih 	rtw89_write32(rtwdev, R_AX_HAXI_HIMR00, rtwpci->intrs[0]);
678948e521cSPing-Ke Shih 	rtw89_write32(rtwdev, R_AX_HIMR1, rtwpci->intrs[1]);
679948e521cSPing-Ke Shih }
680948e521cSPing-Ke Shih EXPORT_SYMBOL(rtw89_pci_enable_intr_v1);
681948e521cSPing-Ke Shih 
682948e521cSPing-Ke Shih void rtw89_pci_disable_intr_v1(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci)
683948e521cSPing-Ke Shih {
684948e521cSPing-Ke Shih 	rtw89_write32(rtwdev, R_AX_PCIE_HIMR00_V1, 0);
685948e521cSPing-Ke Shih }
686948e521cSPing-Ke Shih EXPORT_SYMBOL(rtw89_pci_disable_intr_v1);
687e3ec7017SPing-Ke Shih 
68814f9f479SZong-Zhe Yang static void rtw89_pci_ops_recovery_start(struct rtw89_dev *rtwdev)
68914f9f479SZong-Zhe Yang {
69014f9f479SZong-Zhe Yang 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
69114f9f479SZong-Zhe Yang 	unsigned long flags;
69214f9f479SZong-Zhe Yang 
69314f9f479SZong-Zhe Yang 	spin_lock_irqsave(&rtwpci->irq_lock, flags);
694948e521cSPing-Ke Shih 	rtw89_chip_disable_intr(rtwdev, rtwpci);
695948e521cSPing-Ke Shih 	rtw89_chip_config_intr_mask(rtwdev, RTW89_PCI_INTR_MASK_RECOVERY_START);
696948e521cSPing-Ke Shih 	rtw89_chip_enable_intr(rtwdev, rtwpci);
69714f9f479SZong-Zhe Yang 	spin_unlock_irqrestore(&rtwpci->irq_lock, flags);
69814f9f479SZong-Zhe Yang }
69914f9f479SZong-Zhe Yang 
70014f9f479SZong-Zhe Yang static void rtw89_pci_ops_recovery_complete(struct rtw89_dev *rtwdev)
70114f9f479SZong-Zhe Yang {
70214f9f479SZong-Zhe Yang 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
70314f9f479SZong-Zhe Yang 	unsigned long flags;
70414f9f479SZong-Zhe Yang 
70514f9f479SZong-Zhe Yang 	spin_lock_irqsave(&rtwpci->irq_lock, flags);
706948e521cSPing-Ke Shih 	rtw89_chip_disable_intr(rtwdev, rtwpci);
707948e521cSPing-Ke Shih 	rtw89_chip_config_intr_mask(rtwdev, RTW89_PCI_INTR_MASK_RECOVERY_COMPLETE);
708948e521cSPing-Ke Shih 	rtw89_chip_enable_intr(rtwdev, rtwpci);
70914f9f479SZong-Zhe Yang 	spin_unlock_irqrestore(&rtwpci->irq_lock, flags);
71014f9f479SZong-Zhe Yang }
71114f9f479SZong-Zhe Yang 
712c83dcd05SPing-Ke Shih static void rtw89_pci_low_power_interrupt_handler(struct rtw89_dev *rtwdev)
713c83dcd05SPing-Ke Shih {
714c83dcd05SPing-Ke Shih 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
715c83dcd05SPing-Ke Shih 	int budget = NAPI_POLL_WEIGHT;
716c83dcd05SPing-Ke Shih 
717c83dcd05SPing-Ke Shih 	/* To prevent RXQ get stuck due to run out of budget. */
718c83dcd05SPing-Ke Shih 	rtwdev->napi_budget_countdown = budget;
719c83dcd05SPing-Ke Shih 
720c83dcd05SPing-Ke Shih 	rtw89_pci_poll_rpq_dma(rtwdev, rtwpci, budget);
721c83dcd05SPing-Ke Shih 	rtw89_pci_poll_rxq_dma(rtwdev, rtwpci, budget);
722c83dcd05SPing-Ke Shih }
723c83dcd05SPing-Ke Shih 
724e3ec7017SPing-Ke Shih static irqreturn_t rtw89_pci_interrupt_threadfn(int irq, void *dev)
725e3ec7017SPing-Ke Shih {
726e3ec7017SPing-Ke Shih 	struct rtw89_dev *rtwdev = dev;
727e3ec7017SPing-Ke Shih 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
728e3ec7017SPing-Ke Shih 	struct rtw89_pci_isrs isrs;
729e3ec7017SPing-Ke Shih 	unsigned long flags;
730e3ec7017SPing-Ke Shih 
731e3ec7017SPing-Ke Shih 	spin_lock_irqsave(&rtwpci->irq_lock, flags);
732948e521cSPing-Ke Shih 	rtw89_chip_recognize_intrs(rtwdev, rtwpci, &isrs);
733e3ec7017SPing-Ke Shih 	spin_unlock_irqrestore(&rtwpci->irq_lock, flags);
734e3ec7017SPing-Ke Shih 
735e3ec7017SPing-Ke Shih 	if (unlikely(isrs.isrs[0] & B_AX_RDU_INT))
736e3ec7017SPing-Ke Shih 		rtw89_pci_isr_rxd_unavail(rtwdev, rtwpci);
737e3ec7017SPing-Ke Shih 
738e3ec7017SPing-Ke Shih 	if (unlikely(isrs.halt_c2h_isrs & B_AX_HALT_C2H_INT_EN))
739e3ec7017SPing-Ke Shih 		rtw89_ser_notify(rtwdev, rtw89_mac_get_err_status(rtwdev));
740e3ec7017SPing-Ke Shih 
74114f9f479SZong-Zhe Yang 	if (unlikely(rtwpci->under_recovery))
74298816defSPing-Ke Shih 		goto enable_intr;
74314f9f479SZong-Zhe Yang 
744c83dcd05SPing-Ke Shih 	if (unlikely(rtwpci->low_power)) {
745c83dcd05SPing-Ke Shih 		rtw89_pci_low_power_interrupt_handler(rtwdev);
746c83dcd05SPing-Ke Shih 		goto enable_intr;
747c83dcd05SPing-Ke Shih 	}
748c83dcd05SPing-Ke Shih 
749e3ec7017SPing-Ke Shih 	if (likely(rtwpci->running)) {
750e3ec7017SPing-Ke Shih 		local_bh_disable();
751e3ec7017SPing-Ke Shih 		napi_schedule(&rtwdev->napi);
752e3ec7017SPing-Ke Shih 		local_bh_enable();
753e3ec7017SPing-Ke Shih 	}
754e3ec7017SPing-Ke Shih 
755e3ec7017SPing-Ke Shih 	return IRQ_HANDLED;
756c83dcd05SPing-Ke Shih 
757c83dcd05SPing-Ke Shih enable_intr:
758c83dcd05SPing-Ke Shih 	spin_lock_irqsave(&rtwpci->irq_lock, flags);
759c83dcd05SPing-Ke Shih 	rtw89_chip_enable_intr(rtwdev, rtwpci);
760c83dcd05SPing-Ke Shih 	spin_unlock_irqrestore(&rtwpci->irq_lock, flags);
761c83dcd05SPing-Ke Shih 	return IRQ_HANDLED;
762e3ec7017SPing-Ke Shih }
763e3ec7017SPing-Ke Shih 
764e3ec7017SPing-Ke Shih static irqreturn_t rtw89_pci_interrupt_handler(int irq, void *dev)
765e3ec7017SPing-Ke Shih {
766e3ec7017SPing-Ke Shih 	struct rtw89_dev *rtwdev = dev;
767e3ec7017SPing-Ke Shih 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
768e3ec7017SPing-Ke Shih 	unsigned long flags;
769e3ec7017SPing-Ke Shih 	irqreturn_t irqret = IRQ_WAKE_THREAD;
770e3ec7017SPing-Ke Shih 
771e3ec7017SPing-Ke Shih 	spin_lock_irqsave(&rtwpci->irq_lock, flags);
772e3ec7017SPing-Ke Shih 
773e3ec7017SPing-Ke Shih 	/* If interrupt event is on the road, it is still trigger interrupt
774e3ec7017SPing-Ke Shih 	 * even we have done pci_stop() to turn off IMR.
775e3ec7017SPing-Ke Shih 	 */
776e3ec7017SPing-Ke Shih 	if (unlikely(!rtwpci->running)) {
777e3ec7017SPing-Ke Shih 		irqret = IRQ_HANDLED;
778e3ec7017SPing-Ke Shih 		goto exit;
779e3ec7017SPing-Ke Shih 	}
780e3ec7017SPing-Ke Shih 
781948e521cSPing-Ke Shih 	rtw89_chip_disable_intr(rtwdev, rtwpci);
782e3ec7017SPing-Ke Shih exit:
783e3ec7017SPing-Ke Shih 	spin_unlock_irqrestore(&rtwpci->irq_lock, flags);
784e3ec7017SPing-Ke Shih 
785e3ec7017SPing-Ke Shih 	return irqret;
786e3ec7017SPing-Ke Shih }
787e3ec7017SPing-Ke Shih 
78897d61bf9SPing-Ke Shih #define DEF_TXCHADDRS_TYPE1(info, txch, v...) \
78997d61bf9SPing-Ke Shih 	[RTW89_TXCH_##txch] = { \
79097d61bf9SPing-Ke Shih 		.num = R_AX_##txch##_TXBD_NUM ##v, \
79197d61bf9SPing-Ke Shih 		.idx = R_AX_##txch##_TXBD_IDX ##v, \
79297d61bf9SPing-Ke Shih 		.bdram = R_AX_##txch##_BDRAM_CTRL ##v, \
79397d61bf9SPing-Ke Shih 		.desa_l = R_AX_##txch##_TXBD_DESA_L ##v, \
79497d61bf9SPing-Ke Shih 		.desa_h = R_AX_##txch##_TXBD_DESA_H ##v, \
795e3ec7017SPing-Ke Shih 	}
796e3ec7017SPing-Ke Shih 
79797d61bf9SPing-Ke Shih #define DEF_TXCHADDRS(info, txch, v...) \
79897d61bf9SPing-Ke Shih 	[RTW89_TXCH_##txch] = { \
79997d61bf9SPing-Ke Shih 		.num = R_AX_##txch##_TXBD_NUM, \
80097d61bf9SPing-Ke Shih 		.idx = R_AX_##txch##_TXBD_IDX, \
80197d61bf9SPing-Ke Shih 		.bdram = R_AX_##txch##_BDRAM_CTRL ##v, \
80297d61bf9SPing-Ke Shih 		.desa_l = R_AX_##txch##_TXBD_DESA_L ##v, \
80397d61bf9SPing-Ke Shih 		.desa_h = R_AX_##txch##_TXBD_DESA_H ##v, \
80497d61bf9SPing-Ke Shih 	}
80597d61bf9SPing-Ke Shih 
80697d61bf9SPing-Ke Shih #define DEF_RXCHADDRS(info, rxch, v...) \
80797d61bf9SPing-Ke Shih 	[RTW89_RXCH_##rxch] = { \
80897d61bf9SPing-Ke Shih 		.num = R_AX_##rxch##_RXBD_NUM ##v, \
80997d61bf9SPing-Ke Shih 		.idx = R_AX_##rxch##_RXBD_IDX ##v, \
81097d61bf9SPing-Ke Shih 		.desa_l = R_AX_##rxch##_RXBD_DESA_L ##v, \
81197d61bf9SPing-Ke Shih 		.desa_h = R_AX_##rxch##_RXBD_DESA_H ##v, \
81297d61bf9SPing-Ke Shih 	}
81397d61bf9SPing-Ke Shih 
81497d61bf9SPing-Ke Shih const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set = {
81597d61bf9SPing-Ke Shih 	.tx = {
81697d61bf9SPing-Ke Shih 		DEF_TXCHADDRS(info, ACH0),
81797d61bf9SPing-Ke Shih 		DEF_TXCHADDRS(info, ACH1),
81897d61bf9SPing-Ke Shih 		DEF_TXCHADDRS(info, ACH2),
81997d61bf9SPing-Ke Shih 		DEF_TXCHADDRS(info, ACH3),
82097d61bf9SPing-Ke Shih 		DEF_TXCHADDRS(info, ACH4),
82197d61bf9SPing-Ke Shih 		DEF_TXCHADDRS(info, ACH5),
82297d61bf9SPing-Ke Shih 		DEF_TXCHADDRS(info, ACH6),
82397d61bf9SPing-Ke Shih 		DEF_TXCHADDRS(info, ACH7),
82497d61bf9SPing-Ke Shih 		DEF_TXCHADDRS(info, CH8),
82597d61bf9SPing-Ke Shih 		DEF_TXCHADDRS(info, CH9),
82697d61bf9SPing-Ke Shih 		DEF_TXCHADDRS_TYPE1(info, CH10),
82797d61bf9SPing-Ke Shih 		DEF_TXCHADDRS_TYPE1(info, CH11),
82897d61bf9SPing-Ke Shih 		DEF_TXCHADDRS(info, CH12),
82997d61bf9SPing-Ke Shih 	},
83097d61bf9SPing-Ke Shih 	.rx = {
83197d61bf9SPing-Ke Shih 		DEF_RXCHADDRS(info, RXQ),
83297d61bf9SPing-Ke Shih 		DEF_RXCHADDRS(info, RPQ),
83397d61bf9SPing-Ke Shih 	},
83497d61bf9SPing-Ke Shih };
83597d61bf9SPing-Ke Shih EXPORT_SYMBOL(rtw89_pci_ch_dma_addr_set);
83697d61bf9SPing-Ke Shih 
83797d61bf9SPing-Ke Shih const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set_v1 = {
83897d61bf9SPing-Ke Shih 	.tx = {
83997d61bf9SPing-Ke Shih 		DEF_TXCHADDRS(info, ACH0, _V1),
84097d61bf9SPing-Ke Shih 		DEF_TXCHADDRS(info, ACH1, _V1),
84197d61bf9SPing-Ke Shih 		DEF_TXCHADDRS(info, ACH2, _V1),
84297d61bf9SPing-Ke Shih 		DEF_TXCHADDRS(info, ACH3, _V1),
84397d61bf9SPing-Ke Shih 		DEF_TXCHADDRS(info, ACH4, _V1),
84497d61bf9SPing-Ke Shih 		DEF_TXCHADDRS(info, ACH5, _V1),
84597d61bf9SPing-Ke Shih 		DEF_TXCHADDRS(info, ACH6, _V1),
84697d61bf9SPing-Ke Shih 		DEF_TXCHADDRS(info, ACH7, _V1),
84797d61bf9SPing-Ke Shih 		DEF_TXCHADDRS(info, CH8, _V1),
84897d61bf9SPing-Ke Shih 		DEF_TXCHADDRS(info, CH9, _V1),
84997d61bf9SPing-Ke Shih 		DEF_TXCHADDRS_TYPE1(info, CH10, _V1),
85097d61bf9SPing-Ke Shih 		DEF_TXCHADDRS_TYPE1(info, CH11, _V1),
85197d61bf9SPing-Ke Shih 		DEF_TXCHADDRS(info, CH12, _V1),
85297d61bf9SPing-Ke Shih 	},
85397d61bf9SPing-Ke Shih 	.rx = {
85497d61bf9SPing-Ke Shih 		DEF_RXCHADDRS(info, RXQ, _V1),
85597d61bf9SPing-Ke Shih 		DEF_RXCHADDRS(info, RPQ, _V1),
85697d61bf9SPing-Ke Shih 	},
85797d61bf9SPing-Ke Shih };
85897d61bf9SPing-Ke Shih EXPORT_SYMBOL(rtw89_pci_ch_dma_addr_set_v1);
85997d61bf9SPing-Ke Shih 
86097d61bf9SPing-Ke Shih #undef DEF_TXCHADDRS_TYPE1
86197d61bf9SPing-Ke Shih #undef DEF_TXCHADDRS
86297d61bf9SPing-Ke Shih #undef DEF_RXCHADDRS
86397d61bf9SPing-Ke Shih 
86497d61bf9SPing-Ke Shih static int rtw89_pci_get_txch_addrs(struct rtw89_dev *rtwdev,
86597d61bf9SPing-Ke Shih 				    enum rtw89_tx_channel txch,
86697d61bf9SPing-Ke Shih 				    const struct rtw89_pci_ch_dma_addr **addr)
86797d61bf9SPing-Ke Shih {
86897d61bf9SPing-Ke Shih 	const struct rtw89_pci_info *info = rtwdev->pci_info;
86997d61bf9SPing-Ke Shih 
87097d61bf9SPing-Ke Shih 	if (txch >= RTW89_TXCH_NUM)
87197d61bf9SPing-Ke Shih 		return -EINVAL;
87297d61bf9SPing-Ke Shih 
87397d61bf9SPing-Ke Shih 	*addr = &info->dma_addr_set->tx[txch];
87497d61bf9SPing-Ke Shih 
875e3ec7017SPing-Ke Shih 	return 0;
876e3ec7017SPing-Ke Shih }
877e3ec7017SPing-Ke Shih 
87897d61bf9SPing-Ke Shih static int rtw89_pci_get_rxch_addrs(struct rtw89_dev *rtwdev,
87997d61bf9SPing-Ke Shih 				    enum rtw89_rx_channel rxch,
88097d61bf9SPing-Ke Shih 				    const struct rtw89_pci_ch_dma_addr **addr)
881e3ec7017SPing-Ke Shih {
88297d61bf9SPing-Ke Shih 	const struct rtw89_pci_info *info = rtwdev->pci_info;
88397d61bf9SPing-Ke Shih 
88497d61bf9SPing-Ke Shih 	if (rxch >= RTW89_RXCH_NUM)
885e3ec7017SPing-Ke Shih 		return -EINVAL;
88697d61bf9SPing-Ke Shih 
88797d61bf9SPing-Ke Shih 	*addr = &info->dma_addr_set->rx[rxch];
888e3ec7017SPing-Ke Shih 
889e3ec7017SPing-Ke Shih 	return 0;
890e3ec7017SPing-Ke Shih }
891e3ec7017SPing-Ke Shih 
892e3ec7017SPing-Ke Shih static u32 rtw89_pci_get_avail_txbd_num(struct rtw89_pci_tx_ring *ring)
893e3ec7017SPing-Ke Shih {
894e3ec7017SPing-Ke Shih 	struct rtw89_pci_dma_ring *bd_ring = &ring->bd_ring;
895e3ec7017SPing-Ke Shih 
896e3ec7017SPing-Ke Shih 	/* reserved 1 desc check ring is full or not */
897e3ec7017SPing-Ke Shih 	if (bd_ring->rp > bd_ring->wp)
898e3ec7017SPing-Ke Shih 		return bd_ring->rp - bd_ring->wp - 1;
899e3ec7017SPing-Ke Shih 
900e3ec7017SPing-Ke Shih 	return bd_ring->len - (bd_ring->wp - bd_ring->rp) - 1;
901e3ec7017SPing-Ke Shih }
902e3ec7017SPing-Ke Shih 
903e3ec7017SPing-Ke Shih static
904e3ec7017SPing-Ke Shih u32 __rtw89_pci_check_and_reclaim_tx_fwcmd_resource(struct rtw89_dev *rtwdev)
905e3ec7017SPing-Ke Shih {
906e3ec7017SPing-Ke Shih 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
907e3ec7017SPing-Ke Shih 	struct rtw89_pci_tx_ring *tx_ring = &rtwpci->tx_rings[RTW89_TXCH_CH12];
908e3ec7017SPing-Ke Shih 	u32 cnt;
909e3ec7017SPing-Ke Shih 
910e3ec7017SPing-Ke Shih 	spin_lock_bh(&rtwpci->trx_lock);
911e3ec7017SPing-Ke Shih 	rtw89_pci_reclaim_tx_fwcmd(rtwdev, rtwpci);
912e3ec7017SPing-Ke Shih 	cnt = rtw89_pci_get_avail_txbd_num(tx_ring);
913e3ec7017SPing-Ke Shih 	spin_unlock_bh(&rtwpci->trx_lock);
914e3ec7017SPing-Ke Shih 
915e3ec7017SPing-Ke Shih 	return cnt;
916e3ec7017SPing-Ke Shih }
917e3ec7017SPing-Ke Shih 
91852edbb9fSPing-Ke Shih static
91952edbb9fSPing-Ke Shih u32 __rtw89_pci_check_and_reclaim_tx_resource_noio(struct rtw89_dev *rtwdev,
92052edbb9fSPing-Ke Shih 						   u8 txch)
92152edbb9fSPing-Ke Shih {
92252edbb9fSPing-Ke Shih 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
92352edbb9fSPing-Ke Shih 	struct rtw89_pci_tx_ring *tx_ring = &rtwpci->tx_rings[txch];
92452edbb9fSPing-Ke Shih 	u32 cnt;
92552edbb9fSPing-Ke Shih 
92652edbb9fSPing-Ke Shih 	spin_lock_bh(&rtwpci->trx_lock);
92752edbb9fSPing-Ke Shih 	cnt = rtw89_pci_get_avail_txbd_num(tx_ring);
92852edbb9fSPing-Ke Shih 	spin_unlock_bh(&rtwpci->trx_lock);
92952edbb9fSPing-Ke Shih 
93052edbb9fSPing-Ke Shih 	return cnt;
93152edbb9fSPing-Ke Shih }
93252edbb9fSPing-Ke Shih 
933e3ec7017SPing-Ke Shih static u32 __rtw89_pci_check_and_reclaim_tx_resource(struct rtw89_dev *rtwdev,
934e3ec7017SPing-Ke Shih 						     u8 txch)
935e3ec7017SPing-Ke Shih {
936e3ec7017SPing-Ke Shih 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
937e3ec7017SPing-Ke Shih 	struct rtw89_pci_tx_ring *tx_ring = &rtwpci->tx_rings[txch];
938e3ec7017SPing-Ke Shih 	struct rtw89_pci_tx_wd_ring *wd_ring = &tx_ring->wd_ring;
939e3ec7017SPing-Ke Shih 	u32 bd_cnt, wd_cnt, min_cnt = 0;
940e3ec7017SPing-Ke Shih 	struct rtw89_pci_rx_ring *rx_ring;
941e3ec7017SPing-Ke Shih 	u32 cnt;
942e3ec7017SPing-Ke Shih 
943e3ec7017SPing-Ke Shih 	rx_ring = &rtwpci->rx_rings[RTW89_RXCH_RPQ];
944e3ec7017SPing-Ke Shih 
945e3ec7017SPing-Ke Shih 	spin_lock_bh(&rtwpci->trx_lock);
946e3ec7017SPing-Ke Shih 	bd_cnt = rtw89_pci_get_avail_txbd_num(tx_ring);
947e3ec7017SPing-Ke Shih 	wd_cnt = wd_ring->curr_num;
948e3ec7017SPing-Ke Shih 
949e3ec7017SPing-Ke Shih 	if (wd_cnt == 0 || bd_cnt == 0) {
950e3ec7017SPing-Ke Shih 		cnt = rtw89_pci_rxbd_recalc(rtwdev, rx_ring);
951e3ec7017SPing-Ke Shih 		if (!cnt)
952e3ec7017SPing-Ke Shih 			goto out_unlock;
953e3ec7017SPing-Ke Shih 		rtw89_pci_release_tx(rtwdev, rx_ring, cnt);
95483720268SPing-Ke Shih 
95583720268SPing-Ke Shih 		bd_cnt = rtw89_pci_get_avail_txbd_num(tx_ring);
95683720268SPing-Ke Shih 		if (bd_cnt == 0)
95783720268SPing-Ke Shih 			rtw89_pci_reclaim_txbd(rtwdev, tx_ring);
958e3ec7017SPing-Ke Shih 	}
959e3ec7017SPing-Ke Shih 
960e3ec7017SPing-Ke Shih 	bd_cnt = rtw89_pci_get_avail_txbd_num(tx_ring);
961e3ec7017SPing-Ke Shih 	wd_cnt = wd_ring->curr_num;
962e3ec7017SPing-Ke Shih 	min_cnt = min(bd_cnt, wd_cnt);
963e3ec7017SPing-Ke Shih 	if (min_cnt == 0)
964e3ec7017SPing-Ke Shih 		rtw89_warn(rtwdev, "still no tx resource after reclaim\n");
965e3ec7017SPing-Ke Shih 
966e3ec7017SPing-Ke Shih out_unlock:
967e3ec7017SPing-Ke Shih 	spin_unlock_bh(&rtwpci->trx_lock);
968e3ec7017SPing-Ke Shih 
969e3ec7017SPing-Ke Shih 	return min_cnt;
970e3ec7017SPing-Ke Shih }
971e3ec7017SPing-Ke Shih 
972e3ec7017SPing-Ke Shih static u32 rtw89_pci_check_and_reclaim_tx_resource(struct rtw89_dev *rtwdev,
973e3ec7017SPing-Ke Shih 						   u8 txch)
974e3ec7017SPing-Ke Shih {
97552edbb9fSPing-Ke Shih 	if (rtwdev->hci.paused)
97652edbb9fSPing-Ke Shih 		return __rtw89_pci_check_and_reclaim_tx_resource_noio(rtwdev, txch);
97752edbb9fSPing-Ke Shih 
978e3ec7017SPing-Ke Shih 	if (txch == RTW89_TXCH_CH12)
979e3ec7017SPing-Ke Shih 		return __rtw89_pci_check_and_reclaim_tx_fwcmd_resource(rtwdev);
980e3ec7017SPing-Ke Shih 
981e3ec7017SPing-Ke Shih 	return __rtw89_pci_check_and_reclaim_tx_resource(rtwdev, txch);
982e3ec7017SPing-Ke Shih }
983e3ec7017SPing-Ke Shih 
984e3ec7017SPing-Ke Shih static void __rtw89_pci_tx_kick_off(struct rtw89_dev *rtwdev, struct rtw89_pci_tx_ring *tx_ring)
985e3ec7017SPing-Ke Shih {
98652edbb9fSPing-Ke Shih 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
987e3ec7017SPing-Ke Shih 	struct rtw89_pci_dma_ring *bd_ring = &tx_ring->bd_ring;
988e3ec7017SPing-Ke Shih 	u32 host_idx, addr;
989e3ec7017SPing-Ke Shih 
99052edbb9fSPing-Ke Shih 	spin_lock_bh(&rtwpci->trx_lock);
99152edbb9fSPing-Ke Shih 
992e4133f26SPing-Ke Shih 	addr = bd_ring->addr.idx;
993e3ec7017SPing-Ke Shih 	host_idx = bd_ring->wp;
994e3ec7017SPing-Ke Shih 	rtw89_write16(rtwdev, addr, host_idx);
99552edbb9fSPing-Ke Shih 
99652edbb9fSPing-Ke Shih 	spin_unlock_bh(&rtwpci->trx_lock);
997e3ec7017SPing-Ke Shih }
998e3ec7017SPing-Ke Shih 
999e3ec7017SPing-Ke Shih static void rtw89_pci_tx_bd_ring_update(struct rtw89_dev *rtwdev, struct rtw89_pci_tx_ring *tx_ring,
1000e3ec7017SPing-Ke Shih 					int n_txbd)
1001e3ec7017SPing-Ke Shih {
1002e3ec7017SPing-Ke Shih 	struct rtw89_pci_dma_ring *bd_ring = &tx_ring->bd_ring;
1003e3ec7017SPing-Ke Shih 	u32 host_idx, len;
1004e3ec7017SPing-Ke Shih 
1005e3ec7017SPing-Ke Shih 	len = bd_ring->len;
1006e3ec7017SPing-Ke Shih 	host_idx = bd_ring->wp + n_txbd;
1007e3ec7017SPing-Ke Shih 	host_idx = host_idx < len ? host_idx : host_idx - len;
1008e3ec7017SPing-Ke Shih 
1009e3ec7017SPing-Ke Shih 	bd_ring->wp = host_idx;
1010e3ec7017SPing-Ke Shih }
1011e3ec7017SPing-Ke Shih 
1012e3ec7017SPing-Ke Shih static void rtw89_pci_ops_tx_kick_off(struct rtw89_dev *rtwdev, u8 txch)
1013e3ec7017SPing-Ke Shih {
1014e3ec7017SPing-Ke Shih 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
1015e3ec7017SPing-Ke Shih 	struct rtw89_pci_tx_ring *tx_ring = &rtwpci->tx_rings[txch];
1016e3ec7017SPing-Ke Shih 
101752edbb9fSPing-Ke Shih 	if (rtwdev->hci.paused) {
101852edbb9fSPing-Ke Shih 		set_bit(txch, rtwpci->kick_map);
101952edbb9fSPing-Ke Shih 		return;
102052edbb9fSPing-Ke Shih 	}
102152edbb9fSPing-Ke Shih 
1022e3ec7017SPing-Ke Shih 	__rtw89_pci_tx_kick_off(rtwdev, tx_ring);
102352edbb9fSPing-Ke Shih }
102452edbb9fSPing-Ke Shih 
102552edbb9fSPing-Ke Shih static void rtw89_pci_tx_kick_off_pending(struct rtw89_dev *rtwdev)
102652edbb9fSPing-Ke Shih {
102752edbb9fSPing-Ke Shih 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
102852edbb9fSPing-Ke Shih 	struct rtw89_pci_tx_ring *tx_ring;
102952edbb9fSPing-Ke Shih 	int txch;
103052edbb9fSPing-Ke Shih 
103152edbb9fSPing-Ke Shih 	for (txch = 0; txch < RTW89_TXCH_NUM; txch++) {
103252edbb9fSPing-Ke Shih 		if (!test_and_clear_bit(txch, rtwpci->kick_map))
103352edbb9fSPing-Ke Shih 			continue;
103452edbb9fSPing-Ke Shih 
103552edbb9fSPing-Ke Shih 		tx_ring = &rtwpci->tx_rings[txch];
103652edbb9fSPing-Ke Shih 		__rtw89_pci_tx_kick_off(rtwdev, tx_ring);
103752edbb9fSPing-Ke Shih 	}
1038e3ec7017SPing-Ke Shih }
1039e3ec7017SPing-Ke Shih 
1040e3ec7017SPing-Ke Shih static void __pci_flush_txch(struct rtw89_dev *rtwdev, u8 txch, bool drop)
1041e3ec7017SPing-Ke Shih {
1042e3ec7017SPing-Ke Shih 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
1043e3ec7017SPing-Ke Shih 	struct rtw89_pci_tx_ring *tx_ring = &rtwpci->tx_rings[txch];
1044e3ec7017SPing-Ke Shih 	struct rtw89_pci_dma_ring *bd_ring = &tx_ring->bd_ring;
1045e3ec7017SPing-Ke Shih 	u32 cur_idx, cur_rp;
1046e3ec7017SPing-Ke Shih 	u8 i;
1047e3ec7017SPing-Ke Shih 
1048e3ec7017SPing-Ke Shih 	/* Because the time taked by the I/O is a bit dynamic, it's hard to
1049e3ec7017SPing-Ke Shih 	 * define a reasonable fixed total timeout to use read_poll_timeout*
1050e3ec7017SPing-Ke Shih 	 * helper. Instead, we can ensure a reasonable polling times, so we
1051e3ec7017SPing-Ke Shih 	 * just use for loop with udelay here.
1052e3ec7017SPing-Ke Shih 	 */
1053e3ec7017SPing-Ke Shih 	for (i = 0; i < 60; i++) {
1054e4133f26SPing-Ke Shih 		cur_idx = rtw89_read32(rtwdev, bd_ring->addr.idx);
1055e3ec7017SPing-Ke Shih 		cur_rp = FIELD_GET(TXBD_HW_IDX_MASK, cur_idx);
1056e3ec7017SPing-Ke Shih 		if (cur_rp == bd_ring->wp)
1057e3ec7017SPing-Ke Shih 			return;
1058e3ec7017SPing-Ke Shih 
1059e3ec7017SPing-Ke Shih 		udelay(1);
1060e3ec7017SPing-Ke Shih 	}
1061e3ec7017SPing-Ke Shih 
1062e3ec7017SPing-Ke Shih 	if (!drop)
1063e3ec7017SPing-Ke Shih 		rtw89_info(rtwdev, "timed out to flush pci txch: %d\n", txch);
1064e3ec7017SPing-Ke Shih }
1065e3ec7017SPing-Ke Shih 
1066e3ec7017SPing-Ke Shih static void __rtw89_pci_ops_flush_txchs(struct rtw89_dev *rtwdev, u32 txchs,
1067e3ec7017SPing-Ke Shih 					bool drop)
1068e3ec7017SPing-Ke Shih {
1069e3ec7017SPing-Ke Shih 	u8 i;
1070e3ec7017SPing-Ke Shih 
1071e3ec7017SPing-Ke Shih 	for (i = 0; i < RTW89_TXCH_NUM; i++) {
1072e3ec7017SPing-Ke Shih 		/* It may be unnecessary to flush FWCMD queue. */
1073e3ec7017SPing-Ke Shih 		if (i == RTW89_TXCH_CH12)
1074e3ec7017SPing-Ke Shih 			continue;
1075e3ec7017SPing-Ke Shih 
1076e3ec7017SPing-Ke Shih 		if (txchs & BIT(i))
1077e3ec7017SPing-Ke Shih 			__pci_flush_txch(rtwdev, i, drop);
1078e3ec7017SPing-Ke Shih 	}
1079e3ec7017SPing-Ke Shih }
1080e3ec7017SPing-Ke Shih 
1081e3ec7017SPing-Ke Shih static void rtw89_pci_ops_flush_queues(struct rtw89_dev *rtwdev, u32 queues,
1082e3ec7017SPing-Ke Shih 				       bool drop)
1083e3ec7017SPing-Ke Shih {
1084e3ec7017SPing-Ke Shih 	__rtw89_pci_ops_flush_txchs(rtwdev, BIT(RTW89_TXCH_NUM) - 1, drop);
1085e3ec7017SPing-Ke Shih }
1086e3ec7017SPing-Ke Shih 
10876d5b5d62SPing-Ke Shih u32 rtw89_pci_fill_txaddr_info(struct rtw89_dev *rtwdev,
10886d5b5d62SPing-Ke Shih 			       void *txaddr_info_addr, u32 total_len,
10896d5b5d62SPing-Ke Shih 			       dma_addr_t dma, u8 *add_info_nr)
10906d5b5d62SPing-Ke Shih {
10916d5b5d62SPing-Ke Shih 	struct rtw89_pci_tx_addr_info_32 *txaddr_info = txaddr_info_addr;
10926d5b5d62SPing-Ke Shih 
10936d5b5d62SPing-Ke Shih 	txaddr_info->length = cpu_to_le16(total_len);
10946d5b5d62SPing-Ke Shih 	txaddr_info->option = cpu_to_le16(RTW89_PCI_ADDR_MSDU_LS |
10956d5b5d62SPing-Ke Shih 					  RTW89_PCI_ADDR_NUM(1));
10966d5b5d62SPing-Ke Shih 	txaddr_info->dma = cpu_to_le32(dma);
10976d5b5d62SPing-Ke Shih 
10986d5b5d62SPing-Ke Shih 	*add_info_nr = 1;
10996d5b5d62SPing-Ke Shih 
11006d5b5d62SPing-Ke Shih 	return sizeof(*txaddr_info);
11016d5b5d62SPing-Ke Shih }
11026d5b5d62SPing-Ke Shih EXPORT_SYMBOL(rtw89_pci_fill_txaddr_info);
11036d5b5d62SPing-Ke Shih 
11046d5b5d62SPing-Ke Shih u32 rtw89_pci_fill_txaddr_info_v1(struct rtw89_dev *rtwdev,
11056d5b5d62SPing-Ke Shih 				  void *txaddr_info_addr, u32 total_len,
11066d5b5d62SPing-Ke Shih 				  dma_addr_t dma, u8 *add_info_nr)
11076d5b5d62SPing-Ke Shih {
11086d5b5d62SPing-Ke Shih 	struct rtw89_pci_tx_addr_info_32_v1 *txaddr_info = txaddr_info_addr;
11096d5b5d62SPing-Ke Shih 	u32 remain = total_len;
11106d5b5d62SPing-Ke Shih 	u32 len;
11116d5b5d62SPing-Ke Shih 	u16 length_option;
11126d5b5d62SPing-Ke Shih 	int n;
11136d5b5d62SPing-Ke Shih 
11146d5b5d62SPing-Ke Shih 	for (n = 0; n < RTW89_TXADDR_INFO_NR_V1 && remain; n++) {
11156d5b5d62SPing-Ke Shih 		len = remain >= TXADDR_INFO_LENTHG_V1_MAX ?
11166d5b5d62SPing-Ke Shih 		      TXADDR_INFO_LENTHG_V1_MAX : remain;
11176d5b5d62SPing-Ke Shih 		remain -= len;
11186d5b5d62SPing-Ke Shih 
11196d5b5d62SPing-Ke Shih 		length_option = FIELD_PREP(B_PCIADDR_LEN_V1_MASK, len) |
11206d5b5d62SPing-Ke Shih 				FIELD_PREP(B_PCIADDR_HIGH_SEL_V1_MASK, 0) |
11216d5b5d62SPing-Ke Shih 				FIELD_PREP(B_PCIADDR_LS_V1_MASK, remain == 0);
11226d5b5d62SPing-Ke Shih 		txaddr_info->length_opt = cpu_to_le16(length_option);
11236d5b5d62SPing-Ke Shih 		txaddr_info->dma_low_lsb = cpu_to_le16(FIELD_GET(GENMASK(15, 0), dma));
11246d5b5d62SPing-Ke Shih 		txaddr_info->dma_low_msb = cpu_to_le16(FIELD_GET(GENMASK(31, 16), dma));
11256d5b5d62SPing-Ke Shih 
11266d5b5d62SPing-Ke Shih 		dma += len;
11276d5b5d62SPing-Ke Shih 		txaddr_info++;
11286d5b5d62SPing-Ke Shih 	}
11296d5b5d62SPing-Ke Shih 
11306d5b5d62SPing-Ke Shih 	WARN_ONCE(remain, "length overflow remain=%u total_len=%u",
11316d5b5d62SPing-Ke Shih 		  remain, total_len);
11326d5b5d62SPing-Ke Shih 
11336d5b5d62SPing-Ke Shih 	*add_info_nr = n;
11346d5b5d62SPing-Ke Shih 
11356d5b5d62SPing-Ke Shih 	return n * sizeof(*txaddr_info);
11366d5b5d62SPing-Ke Shih }
11376d5b5d62SPing-Ke Shih EXPORT_SYMBOL(rtw89_pci_fill_txaddr_info_v1);
11386d5b5d62SPing-Ke Shih 
1139e3ec7017SPing-Ke Shih static int rtw89_pci_txwd_submit(struct rtw89_dev *rtwdev,
1140e3ec7017SPing-Ke Shih 				 struct rtw89_pci_tx_ring *tx_ring,
1141e3ec7017SPing-Ke Shih 				 struct rtw89_pci_tx_wd *txwd,
1142e3ec7017SPing-Ke Shih 				 struct rtw89_core_tx_request *tx_req)
1143e3ec7017SPing-Ke Shih {
1144e3ec7017SPing-Ke Shih 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
1145f59acddeSPing-Ke Shih 	const struct rtw89_chip_info *chip = rtwdev->chip;
1146e3ec7017SPing-Ke Shih 	struct rtw89_tx_desc_info *desc_info = &tx_req->desc_info;
1147e3ec7017SPing-Ke Shih 	struct rtw89_txwd_info *txwd_info;
1148e3ec7017SPing-Ke Shih 	struct rtw89_pci_tx_wp_info *txwp_info;
11496d5b5d62SPing-Ke Shih 	void *txaddr_info_addr;
1150e3ec7017SPing-Ke Shih 	struct pci_dev *pdev = rtwpci->pdev;
1151e3ec7017SPing-Ke Shih 	struct sk_buff *skb = tx_req->skb;
1152e3ec7017SPing-Ke Shih 	struct rtw89_pci_tx_data *tx_data = RTW89_PCI_TX_SKB_CB(skb);
1153e3ec7017SPing-Ke Shih 	bool en_wd_info = desc_info->en_wd_info;
1154e3ec7017SPing-Ke Shih 	u32 txwd_len;
1155e3ec7017SPing-Ke Shih 	u32 txwp_len;
1156e3ec7017SPing-Ke Shih 	u32 txaddr_info_len;
1157e3ec7017SPing-Ke Shih 	dma_addr_t dma;
1158e3ec7017SPing-Ke Shih 	int ret;
1159e3ec7017SPing-Ke Shih 
1160e3ec7017SPing-Ke Shih 	dma = dma_map_single(&pdev->dev, skb->data, skb->len, DMA_TO_DEVICE);
1161e3ec7017SPing-Ke Shih 	if (dma_mapping_error(&pdev->dev, dma)) {
1162e3ec7017SPing-Ke Shih 		rtw89_err(rtwdev, "failed to map skb dma data\n");
1163e3ec7017SPing-Ke Shih 		ret = -EBUSY;
1164e3ec7017SPing-Ke Shih 		goto err;
1165e3ec7017SPing-Ke Shih 	}
1166e3ec7017SPing-Ke Shih 
1167e3ec7017SPing-Ke Shih 	tx_data->dma = dma;
1168e3ec7017SPing-Ke Shih 
1169e3ec7017SPing-Ke Shih 	txwp_len = sizeof(*txwp_info);
1170f59acddeSPing-Ke Shih 	txwd_len = chip->txwd_body_size;
1171e3ec7017SPing-Ke Shih 	txwd_len += en_wd_info ? sizeof(*txwd_info) : 0;
1172e3ec7017SPing-Ke Shih 
1173e3ec7017SPing-Ke Shih 	txwp_info = txwd->vaddr + txwd_len;
1174e3ec7017SPing-Ke Shih 	txwp_info->seq0 = cpu_to_le16(txwd->seq | RTW89_PCI_TXWP_VALID);
1175e3ec7017SPing-Ke Shih 	txwp_info->seq1 = 0;
1176e3ec7017SPing-Ke Shih 	txwp_info->seq2 = 0;
1177e3ec7017SPing-Ke Shih 	txwp_info->seq3 = 0;
1178e3ec7017SPing-Ke Shih 
1179e3ec7017SPing-Ke Shih 	tx_ring->tx_cnt++;
11806d5b5d62SPing-Ke Shih 	txaddr_info_addr = txwd->vaddr + txwd_len + txwp_len;
11816d5b5d62SPing-Ke Shih 	txaddr_info_len =
11826d5b5d62SPing-Ke Shih 		rtw89_chip_fill_txaddr_info(rtwdev, txaddr_info_addr, skb->len,
11836d5b5d62SPing-Ke Shih 					    dma, &desc_info->addr_info_nr);
1184e3ec7017SPing-Ke Shih 
1185e3ec7017SPing-Ke Shih 	txwd->len = txwd_len + txwp_len + txaddr_info_len;
1186e3ec7017SPing-Ke Shih 
1187f59acddeSPing-Ke Shih 	rtw89_chip_fill_txdesc(rtwdev, desc_info, txwd->vaddr);
1188f59acddeSPing-Ke Shih 
1189e3ec7017SPing-Ke Shih 	skb_queue_tail(&txwd->queue, skb);
1190e3ec7017SPing-Ke Shih 
1191e3ec7017SPing-Ke Shih 	return 0;
1192e3ec7017SPing-Ke Shih 
1193e3ec7017SPing-Ke Shih err:
1194e3ec7017SPing-Ke Shih 	return ret;
1195e3ec7017SPing-Ke Shih }
1196e3ec7017SPing-Ke Shih 
1197e3ec7017SPing-Ke Shih static int rtw89_pci_fwcmd_submit(struct rtw89_dev *rtwdev,
1198e3ec7017SPing-Ke Shih 				  struct rtw89_pci_tx_ring *tx_ring,
1199e3ec7017SPing-Ke Shih 				  struct rtw89_pci_tx_bd_32 *txbd,
1200e3ec7017SPing-Ke Shih 				  struct rtw89_core_tx_request *tx_req)
1201e3ec7017SPing-Ke Shih {
1202e3ec7017SPing-Ke Shih 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
1203a95bd62eSPing-Ke Shih 	const struct rtw89_chip_info *chip = rtwdev->chip;
1204e3ec7017SPing-Ke Shih 	struct rtw89_tx_desc_info *desc_info = &tx_req->desc_info;
1205a95bd62eSPing-Ke Shih 	void *txdesc;
1206a95bd62eSPing-Ke Shih 	int txdesc_size = chip->h2c_desc_size;
1207e3ec7017SPing-Ke Shih 	struct pci_dev *pdev = rtwpci->pdev;
1208e3ec7017SPing-Ke Shih 	struct sk_buff *skb = tx_req->skb;
1209e3ec7017SPing-Ke Shih 	struct rtw89_pci_tx_data *tx_data = RTW89_PCI_TX_SKB_CB(skb);
1210e3ec7017SPing-Ke Shih 	dma_addr_t dma;
1211e3ec7017SPing-Ke Shih 
1212a95bd62eSPing-Ke Shih 	txdesc = skb_push(skb, txdesc_size);
1213a95bd62eSPing-Ke Shih 	memset(txdesc, 0, txdesc_size);
1214a95bd62eSPing-Ke Shih 	rtw89_chip_fill_txdesc_fwcmd(rtwdev, desc_info, txdesc);
1215e3ec7017SPing-Ke Shih 
1216e3ec7017SPing-Ke Shih 	dma = dma_map_single(&pdev->dev, skb->data, skb->len, DMA_TO_DEVICE);
1217e3ec7017SPing-Ke Shih 	if (dma_mapping_error(&pdev->dev, dma)) {
1218e3ec7017SPing-Ke Shih 		rtw89_err(rtwdev, "failed to map fwcmd dma data\n");
1219e3ec7017SPing-Ke Shih 		return -EBUSY;
1220e3ec7017SPing-Ke Shih 	}
1221e3ec7017SPing-Ke Shih 
1222e3ec7017SPing-Ke Shih 	tx_data->dma = dma;
1223e3ec7017SPing-Ke Shih 	txbd->option = cpu_to_le16(RTW89_PCI_TXBD_OPTION_LS);
1224e3ec7017SPing-Ke Shih 	txbd->length = cpu_to_le16(skb->len);
1225e3ec7017SPing-Ke Shih 	txbd->dma = cpu_to_le32(tx_data->dma);
1226e3ec7017SPing-Ke Shih 	skb_queue_tail(&rtwpci->h2c_queue, skb);
1227e3ec7017SPing-Ke Shih 
1228e3ec7017SPing-Ke Shih 	rtw89_pci_tx_bd_ring_update(rtwdev, tx_ring, 1);
1229e3ec7017SPing-Ke Shih 
1230e3ec7017SPing-Ke Shih 	return 0;
1231e3ec7017SPing-Ke Shih }
1232e3ec7017SPing-Ke Shih 
1233e3ec7017SPing-Ke Shih static int rtw89_pci_txbd_submit(struct rtw89_dev *rtwdev,
1234e3ec7017SPing-Ke Shih 				 struct rtw89_pci_tx_ring *tx_ring,
1235e3ec7017SPing-Ke Shih 				 struct rtw89_pci_tx_bd_32 *txbd,
1236e3ec7017SPing-Ke Shih 				 struct rtw89_core_tx_request *tx_req)
1237e3ec7017SPing-Ke Shih {
1238e3ec7017SPing-Ke Shih 	struct rtw89_pci_tx_wd *txwd;
1239e3ec7017SPing-Ke Shih 	int ret;
1240e3ec7017SPing-Ke Shih 
1241e3ec7017SPing-Ke Shih 	/* FWCMD queue doesn't have wd pages. Instead, it submits the CMD
1242e3ec7017SPing-Ke Shih 	 * buffer with WD BODY only. So here we don't need to check the free
1243e3ec7017SPing-Ke Shih 	 * pages of the wd ring.
1244e3ec7017SPing-Ke Shih 	 */
1245e3ec7017SPing-Ke Shih 	if (tx_ring->txch == RTW89_TXCH_CH12)
1246e3ec7017SPing-Ke Shih 		return rtw89_pci_fwcmd_submit(rtwdev, tx_ring, txbd, tx_req);
1247e3ec7017SPing-Ke Shih 
1248e3ec7017SPing-Ke Shih 	txwd = rtw89_pci_dequeue_txwd(tx_ring);
1249e3ec7017SPing-Ke Shih 	if (!txwd) {
1250e3ec7017SPing-Ke Shih 		rtw89_err(rtwdev, "no available TXWD\n");
1251e3ec7017SPing-Ke Shih 		ret = -ENOSPC;
1252e3ec7017SPing-Ke Shih 		goto err;
1253e3ec7017SPing-Ke Shih 	}
1254e3ec7017SPing-Ke Shih 
1255e3ec7017SPing-Ke Shih 	ret = rtw89_pci_txwd_submit(rtwdev, tx_ring, txwd, tx_req);
1256e3ec7017SPing-Ke Shih 	if (ret) {
1257e3ec7017SPing-Ke Shih 		rtw89_err(rtwdev, "failed to submit TXWD %d\n", txwd->seq);
1258e3ec7017SPing-Ke Shih 		goto err_enqueue_wd;
1259e3ec7017SPing-Ke Shih 	}
1260e3ec7017SPing-Ke Shih 
1261e3ec7017SPing-Ke Shih 	list_add_tail(&txwd->list, &tx_ring->busy_pages);
1262e3ec7017SPing-Ke Shih 
1263e3ec7017SPing-Ke Shih 	txbd->option = cpu_to_le16(RTW89_PCI_TXBD_OPTION_LS);
1264e3ec7017SPing-Ke Shih 	txbd->length = cpu_to_le16(txwd->len);
1265e3ec7017SPing-Ke Shih 	txbd->dma = cpu_to_le32(txwd->paddr);
1266e3ec7017SPing-Ke Shih 
1267e3ec7017SPing-Ke Shih 	rtw89_pci_tx_bd_ring_update(rtwdev, tx_ring, 1);
1268e3ec7017SPing-Ke Shih 
1269e3ec7017SPing-Ke Shih 	return 0;
1270e3ec7017SPing-Ke Shih 
1271e3ec7017SPing-Ke Shih err_enqueue_wd:
1272e3ec7017SPing-Ke Shih 	rtw89_pci_enqueue_txwd(tx_ring, txwd);
1273e3ec7017SPing-Ke Shih err:
1274e3ec7017SPing-Ke Shih 	return ret;
1275e3ec7017SPing-Ke Shih }
1276e3ec7017SPing-Ke Shih 
1277e3ec7017SPing-Ke Shih static int rtw89_pci_tx_write(struct rtw89_dev *rtwdev, struct rtw89_core_tx_request *tx_req,
1278e3ec7017SPing-Ke Shih 			      u8 txch)
1279e3ec7017SPing-Ke Shih {
1280e3ec7017SPing-Ke Shih 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
1281e3ec7017SPing-Ke Shih 	struct rtw89_pci_tx_ring *tx_ring;
1282e3ec7017SPing-Ke Shih 	struct rtw89_pci_tx_bd_32 *txbd;
1283e3ec7017SPing-Ke Shih 	u32 n_avail_txbd;
1284e3ec7017SPing-Ke Shih 	int ret = 0;
1285e3ec7017SPing-Ke Shih 
1286e3ec7017SPing-Ke Shih 	/* check the tx type and dma channel for fw cmd queue */
1287e3ec7017SPing-Ke Shih 	if ((txch == RTW89_TXCH_CH12 ||
1288e3ec7017SPing-Ke Shih 	     tx_req->tx_type == RTW89_CORE_TX_TYPE_FWCMD) &&
1289e3ec7017SPing-Ke Shih 	    (txch != RTW89_TXCH_CH12 ||
1290e3ec7017SPing-Ke Shih 	     tx_req->tx_type != RTW89_CORE_TX_TYPE_FWCMD)) {
1291e3ec7017SPing-Ke Shih 		rtw89_err(rtwdev, "only fw cmd uses dma channel 12\n");
1292e3ec7017SPing-Ke Shih 		return -EINVAL;
1293e3ec7017SPing-Ke Shih 	}
1294e3ec7017SPing-Ke Shih 
1295e3ec7017SPing-Ke Shih 	tx_ring = &rtwpci->tx_rings[txch];
1296e3ec7017SPing-Ke Shih 	spin_lock_bh(&rtwpci->trx_lock);
1297e3ec7017SPing-Ke Shih 
1298e3ec7017SPing-Ke Shih 	n_avail_txbd = rtw89_pci_get_avail_txbd_num(tx_ring);
1299e3ec7017SPing-Ke Shih 	if (n_avail_txbd == 0) {
1300e3ec7017SPing-Ke Shih 		rtw89_err(rtwdev, "no available TXBD\n");
1301e3ec7017SPing-Ke Shih 		ret = -ENOSPC;
1302e3ec7017SPing-Ke Shih 		goto err_unlock;
1303e3ec7017SPing-Ke Shih 	}
1304e3ec7017SPing-Ke Shih 
1305e3ec7017SPing-Ke Shih 	txbd = rtw89_pci_get_next_txbd(tx_ring);
1306e3ec7017SPing-Ke Shih 	ret = rtw89_pci_txbd_submit(rtwdev, tx_ring, txbd, tx_req);
1307e3ec7017SPing-Ke Shih 	if (ret) {
1308e3ec7017SPing-Ke Shih 		rtw89_err(rtwdev, "failed to submit TXBD\n");
1309e3ec7017SPing-Ke Shih 		goto err_unlock;
1310e3ec7017SPing-Ke Shih 	}
1311e3ec7017SPing-Ke Shih 
1312e3ec7017SPing-Ke Shih 	spin_unlock_bh(&rtwpci->trx_lock);
1313e3ec7017SPing-Ke Shih 	return 0;
1314e3ec7017SPing-Ke Shih 
1315e3ec7017SPing-Ke Shih err_unlock:
1316e3ec7017SPing-Ke Shih 	spin_unlock_bh(&rtwpci->trx_lock);
1317e3ec7017SPing-Ke Shih 	return ret;
1318e3ec7017SPing-Ke Shih }
1319e3ec7017SPing-Ke Shih 
1320e3ec7017SPing-Ke Shih static int rtw89_pci_ops_tx_write(struct rtw89_dev *rtwdev, struct rtw89_core_tx_request *tx_req)
1321e3ec7017SPing-Ke Shih {
1322e3ec7017SPing-Ke Shih 	struct rtw89_tx_desc_info *desc_info = &tx_req->desc_info;
1323e3ec7017SPing-Ke Shih 	int ret;
1324e3ec7017SPing-Ke Shih 
1325e3ec7017SPing-Ke Shih 	ret = rtw89_pci_tx_write(rtwdev, tx_req, desc_info->ch_dma);
1326e3ec7017SPing-Ke Shih 	if (ret) {
1327e3ec7017SPing-Ke Shih 		rtw89_err(rtwdev, "failed to TX Queue %d\n", desc_info->ch_dma);
1328e3ec7017SPing-Ke Shih 		return ret;
1329e3ec7017SPing-Ke Shih 	}
1330e3ec7017SPing-Ke Shih 
1331e3ec7017SPing-Ke Shih 	return 0;
1332e3ec7017SPing-Ke Shih }
1333e3ec7017SPing-Ke Shih 
1334e3ec7017SPing-Ke Shih static const struct rtw89_pci_bd_ram bd_ram_table[RTW89_TXCH_NUM] = {
1335e3ec7017SPing-Ke Shih 	[RTW89_TXCH_ACH0] = {.start_idx = 0,  .max_num = 5, .min_num = 2},
1336e3ec7017SPing-Ke Shih 	[RTW89_TXCH_ACH1] = {.start_idx = 5,  .max_num = 5, .min_num = 2},
1337e3ec7017SPing-Ke Shih 	[RTW89_TXCH_ACH2] = {.start_idx = 10, .max_num = 5, .min_num = 2},
1338e3ec7017SPing-Ke Shih 	[RTW89_TXCH_ACH3] = {.start_idx = 15, .max_num = 5, .min_num = 2},
1339e3ec7017SPing-Ke Shih 	[RTW89_TXCH_ACH4] = {.start_idx = 20, .max_num = 5, .min_num = 2},
1340e3ec7017SPing-Ke Shih 	[RTW89_TXCH_ACH5] = {.start_idx = 25, .max_num = 5, .min_num = 2},
1341e3ec7017SPing-Ke Shih 	[RTW89_TXCH_ACH6] = {.start_idx = 30, .max_num = 5, .min_num = 2},
1342e3ec7017SPing-Ke Shih 	[RTW89_TXCH_ACH7] = {.start_idx = 35, .max_num = 5, .min_num = 2},
1343e3ec7017SPing-Ke Shih 	[RTW89_TXCH_CH8]  = {.start_idx = 40, .max_num = 5, .min_num = 1},
1344e3ec7017SPing-Ke Shih 	[RTW89_TXCH_CH9]  = {.start_idx = 45, .max_num = 5, .min_num = 1},
1345e3ec7017SPing-Ke Shih 	[RTW89_TXCH_CH10] = {.start_idx = 50, .max_num = 5, .min_num = 1},
1346e3ec7017SPing-Ke Shih 	[RTW89_TXCH_CH11] = {.start_idx = 55, .max_num = 5, .min_num = 1},
1347e3ec7017SPing-Ke Shih 	[RTW89_TXCH_CH12] = {.start_idx = 60, .max_num = 4, .min_num = 1},
1348e3ec7017SPing-Ke Shih };
1349e3ec7017SPing-Ke Shih 
1350e3ec7017SPing-Ke Shih static void rtw89_pci_reset_trx_rings(struct rtw89_dev *rtwdev)
1351e3ec7017SPing-Ke Shih {
1352e3ec7017SPing-Ke Shih 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
1353e3ec7017SPing-Ke Shih 	struct rtw89_pci_tx_ring *tx_ring;
1354e3ec7017SPing-Ke Shih 	struct rtw89_pci_rx_ring *rx_ring;
1355e3ec7017SPing-Ke Shih 	struct rtw89_pci_dma_ring *bd_ring;
1356e3ec7017SPing-Ke Shih 	const struct rtw89_pci_bd_ram *bd_ram;
1357e3ec7017SPing-Ke Shih 	u32 addr_num;
1358e3ec7017SPing-Ke Shih 	u32 addr_bdram;
1359e3ec7017SPing-Ke Shih 	u32 addr_desa_l;
1360e3ec7017SPing-Ke Shih 	u32 val32;
1361e3ec7017SPing-Ke Shih 	int i;
1362e3ec7017SPing-Ke Shih 
1363e3ec7017SPing-Ke Shih 	for (i = 0; i < RTW89_TXCH_NUM; i++) {
1364e3ec7017SPing-Ke Shih 		tx_ring = &rtwpci->tx_rings[i];
1365e3ec7017SPing-Ke Shih 		bd_ring = &tx_ring->bd_ring;
1366e3ec7017SPing-Ke Shih 		bd_ram = &bd_ram_table[i];
1367e4133f26SPing-Ke Shih 		addr_num = bd_ring->addr.num;
1368e4133f26SPing-Ke Shih 		addr_bdram = bd_ring->addr.bdram;
1369e4133f26SPing-Ke Shih 		addr_desa_l = bd_ring->addr.desa_l;
1370e3ec7017SPing-Ke Shih 		bd_ring->wp = 0;
1371e3ec7017SPing-Ke Shih 		bd_ring->rp = 0;
1372e3ec7017SPing-Ke Shih 
1373e3ec7017SPing-Ke Shih 		val32 = FIELD_PREP(BDRAM_SIDX_MASK, bd_ram->start_idx) |
1374e3ec7017SPing-Ke Shih 			FIELD_PREP(BDRAM_MAX_MASK, bd_ram->max_num) |
1375e3ec7017SPing-Ke Shih 			FIELD_PREP(BDRAM_MIN_MASK, bd_ram->min_num);
1376e3ec7017SPing-Ke Shih 
1377e3ec7017SPing-Ke Shih 		rtw89_write16(rtwdev, addr_num, bd_ring->len);
1378e3ec7017SPing-Ke Shih 		rtw89_write32(rtwdev, addr_bdram, val32);
1379e3ec7017SPing-Ke Shih 		rtw89_write32(rtwdev, addr_desa_l, bd_ring->dma);
1380e3ec7017SPing-Ke Shih 	}
1381e3ec7017SPing-Ke Shih 
1382e3ec7017SPing-Ke Shih 	for (i = 0; i < RTW89_RXCH_NUM; i++) {
1383e3ec7017SPing-Ke Shih 		rx_ring = &rtwpci->rx_rings[i];
1384e3ec7017SPing-Ke Shih 		bd_ring = &rx_ring->bd_ring;
1385e4133f26SPing-Ke Shih 		addr_num = bd_ring->addr.num;
1386e4133f26SPing-Ke Shih 		addr_desa_l = bd_ring->addr.desa_l;
1387e3ec7017SPing-Ke Shih 		bd_ring->wp = 0;
1388e3ec7017SPing-Ke Shih 		bd_ring->rp = 0;
1389e3ec7017SPing-Ke Shih 		rx_ring->diliver_skb = NULL;
1390e3ec7017SPing-Ke Shih 		rx_ring->diliver_desc.ready = false;
1391e3ec7017SPing-Ke Shih 
1392e3ec7017SPing-Ke Shih 		rtw89_write16(rtwdev, addr_num, bd_ring->len);
1393e3ec7017SPing-Ke Shih 		rtw89_write32(rtwdev, addr_desa_l, bd_ring->dma);
1394e3ec7017SPing-Ke Shih 	}
1395e3ec7017SPing-Ke Shih }
1396e3ec7017SPing-Ke Shih 
1397e3ec7017SPing-Ke Shih static void rtw89_pci_release_tx_ring(struct rtw89_dev *rtwdev,
1398e3ec7017SPing-Ke Shih 				      struct rtw89_pci_tx_ring *tx_ring)
1399e3ec7017SPing-Ke Shih {
1400e3ec7017SPing-Ke Shih 	rtw89_pci_release_busy_txwd(rtwdev, tx_ring);
1401e3ec7017SPing-Ke Shih 	rtw89_pci_release_pending_txwd_skb(rtwdev, tx_ring);
1402e3ec7017SPing-Ke Shih }
1403e3ec7017SPing-Ke Shih 
1404e3ec7017SPing-Ke Shih static void rtw89_pci_ops_reset(struct rtw89_dev *rtwdev)
1405e3ec7017SPing-Ke Shih {
1406e3ec7017SPing-Ke Shih 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
1407e3ec7017SPing-Ke Shih 	int txch;
1408e3ec7017SPing-Ke Shih 
1409e3ec7017SPing-Ke Shih 	rtw89_pci_reset_trx_rings(rtwdev);
1410e3ec7017SPing-Ke Shih 
1411e3ec7017SPing-Ke Shih 	spin_lock_bh(&rtwpci->trx_lock);
1412e3ec7017SPing-Ke Shih 	for (txch = 0; txch < RTW89_TXCH_NUM; txch++) {
1413e3ec7017SPing-Ke Shih 		if (txch == RTW89_TXCH_CH12) {
1414e3ec7017SPing-Ke Shih 			rtw89_pci_release_fwcmd(rtwdev, rtwpci,
1415e3ec7017SPing-Ke Shih 						skb_queue_len(&rtwpci->h2c_queue), true);
1416e3ec7017SPing-Ke Shih 			continue;
1417e3ec7017SPing-Ke Shih 		}
1418e3ec7017SPing-Ke Shih 		rtw89_pci_release_tx_ring(rtwdev, &rtwpci->tx_rings[txch]);
1419e3ec7017SPing-Ke Shih 	}
1420e3ec7017SPing-Ke Shih 	spin_unlock_bh(&rtwpci->trx_lock);
1421e3ec7017SPing-Ke Shih }
1422e3ec7017SPing-Ke Shih 
1423948e521cSPing-Ke Shih static void rtw89_pci_enable_intr_lock(struct rtw89_dev *rtwdev)
1424e3ec7017SPing-Ke Shih {
1425e3ec7017SPing-Ke Shih 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
1426e3ec7017SPing-Ke Shih 	unsigned long flags;
1427e3ec7017SPing-Ke Shih 
1428e3ec7017SPing-Ke Shih 	spin_lock_irqsave(&rtwpci->irq_lock, flags);
1429e3ec7017SPing-Ke Shih 	rtwpci->running = true;
1430948e521cSPing-Ke Shih 	rtw89_chip_enable_intr(rtwdev, rtwpci);
1431e3ec7017SPing-Ke Shih 	spin_unlock_irqrestore(&rtwpci->irq_lock, flags);
1432948e521cSPing-Ke Shih }
1433948e521cSPing-Ke Shih 
1434948e521cSPing-Ke Shih static void rtw89_pci_disable_intr_lock(struct rtw89_dev *rtwdev)
1435948e521cSPing-Ke Shih {
1436948e521cSPing-Ke Shih 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
1437948e521cSPing-Ke Shih 	unsigned long flags;
1438948e521cSPing-Ke Shih 
1439948e521cSPing-Ke Shih 	spin_lock_irqsave(&rtwpci->irq_lock, flags);
1440948e521cSPing-Ke Shih 	rtwpci->running = false;
1441948e521cSPing-Ke Shih 	rtw89_chip_disable_intr(rtwdev, rtwpci);
1442948e521cSPing-Ke Shih 	spin_unlock_irqrestore(&rtwpci->irq_lock, flags);
1443948e521cSPing-Ke Shih }
1444948e521cSPing-Ke Shih 
1445948e521cSPing-Ke Shih static int rtw89_pci_ops_start(struct rtw89_dev *rtwdev)
1446948e521cSPing-Ke Shih {
1447948e521cSPing-Ke Shih 	rtw89_core_napi_start(rtwdev);
1448948e521cSPing-Ke Shih 	rtw89_pci_enable_intr_lock(rtwdev);
1449e3ec7017SPing-Ke Shih 
1450e3ec7017SPing-Ke Shih 	return 0;
1451e3ec7017SPing-Ke Shih }
1452e3ec7017SPing-Ke Shih 
1453e3ec7017SPing-Ke Shih static void rtw89_pci_ops_stop(struct rtw89_dev *rtwdev)
1454e3ec7017SPing-Ke Shih {
1455e3ec7017SPing-Ke Shih 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
1456e3ec7017SPing-Ke Shih 	struct pci_dev *pdev = rtwpci->pdev;
1457e3ec7017SPing-Ke Shih 
1458948e521cSPing-Ke Shih 	rtw89_pci_disable_intr_lock(rtwdev);
1459e3ec7017SPing-Ke Shih 	synchronize_irq(pdev->irq);
1460e3ec7017SPing-Ke Shih 	rtw89_core_napi_stop(rtwdev);
1461e3ec7017SPing-Ke Shih }
1462e3ec7017SPing-Ke Shih 
146352edbb9fSPing-Ke Shih static void rtw89_pci_ops_pause(struct rtw89_dev *rtwdev, bool pause)
146452edbb9fSPing-Ke Shih {
146552edbb9fSPing-Ke Shih 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
146652edbb9fSPing-Ke Shih 	struct pci_dev *pdev = rtwpci->pdev;
146752edbb9fSPing-Ke Shih 
146852edbb9fSPing-Ke Shih 	if (pause) {
146952edbb9fSPing-Ke Shih 		rtw89_pci_disable_intr_lock(rtwdev);
147052edbb9fSPing-Ke Shih 		synchronize_irq(pdev->irq);
147152edbb9fSPing-Ke Shih 		if (test_bit(RTW89_FLAG_NAPI_RUNNING, rtwdev->flags))
147252edbb9fSPing-Ke Shih 			napi_synchronize(&rtwdev->napi);
147352edbb9fSPing-Ke Shih 	} else {
147452edbb9fSPing-Ke Shih 		rtw89_pci_enable_intr_lock(rtwdev);
147552edbb9fSPing-Ke Shih 		rtw89_pci_tx_kick_off_pending(rtwdev);
147652edbb9fSPing-Ke Shih 	}
147752edbb9fSPing-Ke Shih }
147852edbb9fSPing-Ke Shih 
147952edbb9fSPing-Ke Shih static
148052edbb9fSPing-Ke Shih void rtw89_pci_switch_bd_idx_addr(struct rtw89_dev *rtwdev, bool low_power)
148152edbb9fSPing-Ke Shih {
148252edbb9fSPing-Ke Shih 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
148352edbb9fSPing-Ke Shih 	const struct rtw89_pci_info *info = rtwdev->pci_info;
148452edbb9fSPing-Ke Shih 	const struct rtw89_pci_bd_idx_addr *bd_idx_addr = info->bd_idx_addr_low_power;
148552edbb9fSPing-Ke Shih 	const struct rtw89_pci_ch_dma_addr_set *dma_addr_set = info->dma_addr_set;
148652edbb9fSPing-Ke Shih 	struct rtw89_pci_tx_ring *tx_ring;
148752edbb9fSPing-Ke Shih 	struct rtw89_pci_rx_ring *rx_ring;
148852edbb9fSPing-Ke Shih 	int i;
148952edbb9fSPing-Ke Shih 
149052edbb9fSPing-Ke Shih 	if (WARN(!bd_idx_addr, "only HCI with low power mode needs this\n"))
149152edbb9fSPing-Ke Shih 		return;
149252edbb9fSPing-Ke Shih 
149352edbb9fSPing-Ke Shih 	for (i = 0; i < RTW89_TXCH_NUM; i++) {
149452edbb9fSPing-Ke Shih 		tx_ring = &rtwpci->tx_rings[i];
149552edbb9fSPing-Ke Shih 		tx_ring->bd_ring.addr.idx = low_power ?
149652edbb9fSPing-Ke Shih 					    bd_idx_addr->tx_bd_addrs[i] :
149752edbb9fSPing-Ke Shih 					    dma_addr_set->tx[i].idx;
149852edbb9fSPing-Ke Shih 	}
149952edbb9fSPing-Ke Shih 
150052edbb9fSPing-Ke Shih 	for (i = 0; i < RTW89_RXCH_NUM; i++) {
150152edbb9fSPing-Ke Shih 		rx_ring = &rtwpci->rx_rings[i];
150252edbb9fSPing-Ke Shih 		rx_ring->bd_ring.addr.idx = low_power ?
150352edbb9fSPing-Ke Shih 					    bd_idx_addr->rx_bd_addrs[i] :
150452edbb9fSPing-Ke Shih 					    dma_addr_set->rx[i].idx;
150552edbb9fSPing-Ke Shih 	}
150652edbb9fSPing-Ke Shih }
150752edbb9fSPing-Ke Shih 
150852edbb9fSPing-Ke Shih static void rtw89_pci_ops_switch_mode(struct rtw89_dev *rtwdev, bool low_power)
150952edbb9fSPing-Ke Shih {
151052edbb9fSPing-Ke Shih 	enum rtw89_pci_intr_mask_cfg cfg;
151152edbb9fSPing-Ke Shih 
151252edbb9fSPing-Ke Shih 	WARN(!rtwdev->hci.paused, "HCI isn't paused\n");
151352edbb9fSPing-Ke Shih 
151452edbb9fSPing-Ke Shih 	cfg = low_power ? RTW89_PCI_INTR_MASK_LOW_POWER : RTW89_PCI_INTR_MASK_NORMAL;
151552edbb9fSPing-Ke Shih 	rtw89_chip_config_intr_mask(rtwdev, cfg);
151652edbb9fSPing-Ke Shih 	rtw89_pci_switch_bd_idx_addr(rtwdev, low_power);
151752edbb9fSPing-Ke Shih }
151852edbb9fSPing-Ke Shih 
1519e3ec7017SPing-Ke Shih static void rtw89_pci_ops_write32(struct rtw89_dev *rtwdev, u32 addr, u32 data);
1520e3ec7017SPing-Ke Shih 
1521e3ec7017SPing-Ke Shih static u32 rtw89_pci_ops_read32_cmac(struct rtw89_dev *rtwdev, u32 addr)
1522e3ec7017SPing-Ke Shih {
1523e3ec7017SPing-Ke Shih 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
1524e3ec7017SPing-Ke Shih 	u32 val = readl(rtwpci->mmap + addr);
1525e3ec7017SPing-Ke Shih 	int count;
1526e3ec7017SPing-Ke Shih 
1527e3ec7017SPing-Ke Shih 	for (count = 0; ; count++) {
1528e3ec7017SPing-Ke Shih 		if (val != RTW89_R32_DEAD)
1529e3ec7017SPing-Ke Shih 			return val;
1530e3ec7017SPing-Ke Shih 		if (count >= MAC_REG_POOL_COUNT) {
1531e3ec7017SPing-Ke Shih 			rtw89_warn(rtwdev, "addr %#x = %#x\n", addr, val);
1532e3ec7017SPing-Ke Shih 			return RTW89_R32_DEAD;
1533e3ec7017SPing-Ke Shih 		}
1534e3ec7017SPing-Ke Shih 		rtw89_pci_ops_write32(rtwdev, R_AX_CK_EN, B_AX_CMAC_ALLCKEN);
1535e3ec7017SPing-Ke Shih 		val = readl(rtwpci->mmap + addr);
1536e3ec7017SPing-Ke Shih 	}
1537e3ec7017SPing-Ke Shih 
1538e3ec7017SPing-Ke Shih 	return val;
1539e3ec7017SPing-Ke Shih }
1540e3ec7017SPing-Ke Shih 
1541e3ec7017SPing-Ke Shih static u8 rtw89_pci_ops_read8(struct rtw89_dev *rtwdev, u32 addr)
1542e3ec7017SPing-Ke Shih {
1543e3ec7017SPing-Ke Shih 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
1544e3ec7017SPing-Ke Shih 	u32 addr32, val32, shift;
1545e3ec7017SPing-Ke Shih 
1546e3ec7017SPing-Ke Shih 	if (!ACCESS_CMAC(addr))
1547e3ec7017SPing-Ke Shih 		return readb(rtwpci->mmap + addr);
1548e3ec7017SPing-Ke Shih 
1549e3ec7017SPing-Ke Shih 	addr32 = addr & ~0x3;
1550e3ec7017SPing-Ke Shih 	shift = (addr & 0x3) * 8;
1551e3ec7017SPing-Ke Shih 	val32 = rtw89_pci_ops_read32_cmac(rtwdev, addr32);
1552e3ec7017SPing-Ke Shih 	return val32 >> shift;
1553e3ec7017SPing-Ke Shih }
1554e3ec7017SPing-Ke Shih 
1555e3ec7017SPing-Ke Shih static u16 rtw89_pci_ops_read16(struct rtw89_dev *rtwdev, u32 addr)
1556e3ec7017SPing-Ke Shih {
1557e3ec7017SPing-Ke Shih 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
1558e3ec7017SPing-Ke Shih 	u32 addr32, val32, shift;
1559e3ec7017SPing-Ke Shih 
1560e3ec7017SPing-Ke Shih 	if (!ACCESS_CMAC(addr))
1561e3ec7017SPing-Ke Shih 		return readw(rtwpci->mmap + addr);
1562e3ec7017SPing-Ke Shih 
1563e3ec7017SPing-Ke Shih 	addr32 = addr & ~0x3;
1564e3ec7017SPing-Ke Shih 	shift = (addr & 0x3) * 8;
1565e3ec7017SPing-Ke Shih 	val32 = rtw89_pci_ops_read32_cmac(rtwdev, addr32);
1566e3ec7017SPing-Ke Shih 	return val32 >> shift;
1567e3ec7017SPing-Ke Shih }
1568e3ec7017SPing-Ke Shih 
1569e3ec7017SPing-Ke Shih static u32 rtw89_pci_ops_read32(struct rtw89_dev *rtwdev, u32 addr)
1570e3ec7017SPing-Ke Shih {
1571e3ec7017SPing-Ke Shih 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
1572e3ec7017SPing-Ke Shih 
1573e3ec7017SPing-Ke Shih 	if (!ACCESS_CMAC(addr))
1574e3ec7017SPing-Ke Shih 		return readl(rtwpci->mmap + addr);
1575e3ec7017SPing-Ke Shih 
1576e3ec7017SPing-Ke Shih 	return rtw89_pci_ops_read32_cmac(rtwdev, addr);
1577e3ec7017SPing-Ke Shih }
1578e3ec7017SPing-Ke Shih 
1579e3ec7017SPing-Ke Shih static void rtw89_pci_ops_write8(struct rtw89_dev *rtwdev, u32 addr, u8 data)
1580e3ec7017SPing-Ke Shih {
1581e3ec7017SPing-Ke Shih 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
1582e3ec7017SPing-Ke Shih 
1583e3ec7017SPing-Ke Shih 	writeb(data, rtwpci->mmap + addr);
1584e3ec7017SPing-Ke Shih }
1585e3ec7017SPing-Ke Shih 
1586e3ec7017SPing-Ke Shih static void rtw89_pci_ops_write16(struct rtw89_dev *rtwdev, u32 addr, u16 data)
1587e3ec7017SPing-Ke Shih {
1588e3ec7017SPing-Ke Shih 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
1589e3ec7017SPing-Ke Shih 
1590e3ec7017SPing-Ke Shih 	writew(data, rtwpci->mmap + addr);
1591e3ec7017SPing-Ke Shih }
1592e3ec7017SPing-Ke Shih 
1593e3ec7017SPing-Ke Shih static void rtw89_pci_ops_write32(struct rtw89_dev *rtwdev, u32 addr, u32 data)
1594e3ec7017SPing-Ke Shih {
1595e3ec7017SPing-Ke Shih 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
1596e3ec7017SPing-Ke Shih 
1597e3ec7017SPing-Ke Shih 	writel(data, rtwpci->mmap + addr);
1598e3ec7017SPing-Ke Shih }
1599e3ec7017SPing-Ke Shih 
1600e3ec7017SPing-Ke Shih static void rtw89_pci_ctrl_dma_all(struct rtw89_dev *rtwdev, bool enable)
1601e3ec7017SPing-Ke Shih {
1602740c431cSPing-Ke Shih 	enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id;
1603740c431cSPing-Ke Shih 	const struct rtw89_pci_info *info = rtwdev->pci_info;
1604740c431cSPing-Ke Shih 	u32 txhci_en = info->txhci_en_bit;
1605740c431cSPing-Ke Shih 	u32 rxhci_en = info->rxhci_en_bit;
1606740c431cSPing-Ke Shih 
1607e3ec7017SPing-Ke Shih 	if (enable) {
1608740c431cSPing-Ke Shih 		if (chip_id != RTL8852C)
1609740c431cSPing-Ke Shih 			rtw89_write32_clr(rtwdev, info->dma_stop1_reg,
1610e3ec7017SPing-Ke Shih 					  B_AX_STOP_PCIEIO);
1611740c431cSPing-Ke Shih 		rtw89_write32_set(rtwdev, R_AX_PCIE_INIT_CFG1,
1612740c431cSPing-Ke Shih 				  txhci_en | rxhci_en);
16131e3f2055SChia-Yuan Li 		if (chip_id == RTL8852C)
16141e3f2055SChia-Yuan Li 			rtw89_write32_clr(rtwdev, R_AX_PCIE_INIT_CFG1,
16151e3f2055SChia-Yuan Li 					  B_AX_STOP_AXI_MST);
1616e3ec7017SPing-Ke Shih 	} else {
1617740c431cSPing-Ke Shih 		if (chip_id != RTL8852C)
1618740c431cSPing-Ke Shih 			rtw89_write32_set(rtwdev, info->dma_stop1_reg,
1619e3ec7017SPing-Ke Shih 					  B_AX_STOP_PCIEIO);
16201e3f2055SChia-Yuan Li 		else
1621e3ec7017SPing-Ke Shih 			rtw89_write32_clr(rtwdev, R_AX_PCIE_INIT_CFG1,
16221e3f2055SChia-Yuan Li 					  B_AX_STOP_AXI_MST);
16231e3f2055SChia-Yuan Li 		if (chip_id == RTL8852C)
16241e3f2055SChia-Yuan Li 			rtw89_write32_set(rtwdev, R_AX_PCIE_INIT_CFG1,
16251e3f2055SChia-Yuan Li 					  B_AX_STOP_AXI_MST);
1626e3ec7017SPing-Ke Shih 	}
1627e3ec7017SPing-Ke Shih }
1628e3ec7017SPing-Ke Shih 
1629e3ec7017SPing-Ke Shih static int rtw89_pci_check_mdio(struct rtw89_dev *rtwdev, u8 addr, u8 speed, u16 rw_bit)
1630e3ec7017SPing-Ke Shih {
1631e3ec7017SPing-Ke Shih 	u16 val;
1632e3ec7017SPing-Ke Shih 
1633e3ec7017SPing-Ke Shih 	rtw89_write8(rtwdev, R_AX_MDIO_CFG, addr & 0x1F);
1634e3ec7017SPing-Ke Shih 
1635e3ec7017SPing-Ke Shih 	val = rtw89_read16(rtwdev, R_AX_MDIO_CFG);
1636e3ec7017SPing-Ke Shih 	switch (speed) {
1637e3ec7017SPing-Ke Shih 	case PCIE_PHY_GEN1:
1638e3ec7017SPing-Ke Shih 		if (addr < 0x20)
1639e3ec7017SPing-Ke Shih 			val = u16_replace_bits(val, MDIO_PG0_G1, B_AX_MDIO_PHY_ADDR_MASK);
1640e3ec7017SPing-Ke Shih 		else
1641e3ec7017SPing-Ke Shih 			val = u16_replace_bits(val, MDIO_PG1_G1, B_AX_MDIO_PHY_ADDR_MASK);
1642e3ec7017SPing-Ke Shih 		break;
1643e3ec7017SPing-Ke Shih 	case PCIE_PHY_GEN2:
1644e3ec7017SPing-Ke Shih 		if (addr < 0x20)
1645e3ec7017SPing-Ke Shih 			val = u16_replace_bits(val, MDIO_PG0_G2, B_AX_MDIO_PHY_ADDR_MASK);
1646e3ec7017SPing-Ke Shih 		else
1647e3ec7017SPing-Ke Shih 			val = u16_replace_bits(val, MDIO_PG1_G2, B_AX_MDIO_PHY_ADDR_MASK);
1648e3ec7017SPing-Ke Shih 		break;
1649e3ec7017SPing-Ke Shih 	default:
1650e3ec7017SPing-Ke Shih 		rtw89_err(rtwdev, "[ERR]Error Speed %d!\n", speed);
1651e3ec7017SPing-Ke Shih 		return -EINVAL;
1652e0e037b9SYang Li 	}
1653e3ec7017SPing-Ke Shih 	rtw89_write16(rtwdev, R_AX_MDIO_CFG, val);
1654e3ec7017SPing-Ke Shih 	rtw89_write16_set(rtwdev, R_AX_MDIO_CFG, rw_bit);
1655e3ec7017SPing-Ke Shih 
1656e3ec7017SPing-Ke Shih 	return read_poll_timeout(rtw89_read16, val, !(val & rw_bit), 10, 2000,
1657e3ec7017SPing-Ke Shih 				 false, rtwdev, R_AX_MDIO_CFG);
1658e3ec7017SPing-Ke Shih }
1659e3ec7017SPing-Ke Shih 
1660e3ec7017SPing-Ke Shih static int
1661e3ec7017SPing-Ke Shih rtw89_read16_mdio(struct rtw89_dev *rtwdev, u8 addr, u8 speed, u16 *val)
1662e3ec7017SPing-Ke Shih {
1663e3ec7017SPing-Ke Shih 	int ret;
1664e3ec7017SPing-Ke Shih 
1665e3ec7017SPing-Ke Shih 	ret = rtw89_pci_check_mdio(rtwdev, addr, speed, B_AX_MDIO_RFLAG);
1666e3ec7017SPing-Ke Shih 	if (ret) {
1667e3ec7017SPing-Ke Shih 		rtw89_err(rtwdev, "[ERR]MDIO R16 0x%X fail ret=%d!\n", addr, ret);
1668e3ec7017SPing-Ke Shih 		return ret;
1669e3ec7017SPing-Ke Shih 	}
1670e3ec7017SPing-Ke Shih 	*val = rtw89_read16(rtwdev, R_AX_MDIO_RDATA);
1671e3ec7017SPing-Ke Shih 
1672e3ec7017SPing-Ke Shih 	return 0;
1673e3ec7017SPing-Ke Shih }
1674e3ec7017SPing-Ke Shih 
1675e3ec7017SPing-Ke Shih static int
1676e3ec7017SPing-Ke Shih rtw89_write16_mdio(struct rtw89_dev *rtwdev, u8 addr, u16 data, u8 speed)
1677e3ec7017SPing-Ke Shih {
1678e3ec7017SPing-Ke Shih 	int ret;
1679e3ec7017SPing-Ke Shih 
1680e3ec7017SPing-Ke Shih 	rtw89_write16(rtwdev, R_AX_MDIO_WDATA, data);
1681e3ec7017SPing-Ke Shih 	ret = rtw89_pci_check_mdio(rtwdev, addr, speed, B_AX_MDIO_WFLAG);
1682e3ec7017SPing-Ke Shih 	if (ret) {
1683e3ec7017SPing-Ke Shih 		rtw89_err(rtwdev, "[ERR]MDIO W16 0x%X = %x fail ret=%d!\n", addr, data, ret);
1684e3ec7017SPing-Ke Shih 		return ret;
1685e3ec7017SPing-Ke Shih 	}
1686e3ec7017SPing-Ke Shih 
1687e3ec7017SPing-Ke Shih 	return 0;
1688e3ec7017SPing-Ke Shih }
1689e3ec7017SPing-Ke Shih 
1690740c431cSPing-Ke Shih static int
1691740c431cSPing-Ke Shih rtw89_write16_mdio_mask(struct rtw89_dev *rtwdev, u8 addr, u16 mask, u16 data, u8 speed)
1692740c431cSPing-Ke Shih {
1693740c431cSPing-Ke Shih 	u32 shift;
1694740c431cSPing-Ke Shih 	int ret;
1695740c431cSPing-Ke Shih 	u16 val;
1696740c431cSPing-Ke Shih 
1697740c431cSPing-Ke Shih 	ret = rtw89_read16_mdio(rtwdev, addr, speed, &val);
1698dc4246efSPing-Ke Shih 	if (ret)
1699740c431cSPing-Ke Shih 		return ret;
1700740c431cSPing-Ke Shih 
1701740c431cSPing-Ke Shih 	shift = __ffs(mask);
1702740c431cSPing-Ke Shih 	val &= ~mask;
1703740c431cSPing-Ke Shih 	val |= ((data << shift) & mask);
1704740c431cSPing-Ke Shih 
1705740c431cSPing-Ke Shih 	ret = rtw89_write16_mdio(rtwdev, addr, val, speed);
1706dc4246efSPing-Ke Shih 	if (ret)
1707740c431cSPing-Ke Shih 		return ret;
1708740c431cSPing-Ke Shih 
1709740c431cSPing-Ke Shih 	return 0;
1710740c431cSPing-Ke Shih }
1711740c431cSPing-Ke Shih 
1712e3ec7017SPing-Ke Shih static int rtw89_write16_mdio_set(struct rtw89_dev *rtwdev, u8 addr, u16 mask, u8 speed)
1713e3ec7017SPing-Ke Shih {
1714e3ec7017SPing-Ke Shih 	int ret;
1715e3ec7017SPing-Ke Shih 	u16 val;
1716e3ec7017SPing-Ke Shih 
1717e3ec7017SPing-Ke Shih 	ret = rtw89_read16_mdio(rtwdev, addr, speed, &val);
1718e3ec7017SPing-Ke Shih 	if (ret)
1719e3ec7017SPing-Ke Shih 		return ret;
1720e3ec7017SPing-Ke Shih 	ret = rtw89_write16_mdio(rtwdev, addr, val | mask, speed);
1721e3ec7017SPing-Ke Shih 	if (ret)
1722e3ec7017SPing-Ke Shih 		return ret;
1723e3ec7017SPing-Ke Shih 
1724e3ec7017SPing-Ke Shih 	return 0;
1725e3ec7017SPing-Ke Shih }
1726e3ec7017SPing-Ke Shih 
1727e3ec7017SPing-Ke Shih static int rtw89_write16_mdio_clr(struct rtw89_dev *rtwdev, u8 addr, u16 mask, u8 speed)
1728e3ec7017SPing-Ke Shih {
1729e3ec7017SPing-Ke Shih 	int ret;
1730e3ec7017SPing-Ke Shih 	u16 val;
1731e3ec7017SPing-Ke Shih 
1732e3ec7017SPing-Ke Shih 	ret = rtw89_read16_mdio(rtwdev, addr, speed, &val);
1733e3ec7017SPing-Ke Shih 	if (ret)
1734e3ec7017SPing-Ke Shih 		return ret;
1735e3ec7017SPing-Ke Shih 	ret = rtw89_write16_mdio(rtwdev, addr, val & ~mask, speed);
1736e3ec7017SPing-Ke Shih 	if (ret)
1737e3ec7017SPing-Ke Shih 		return ret;
1738e3ec7017SPing-Ke Shih 
1739e3ec7017SPing-Ke Shih 	return 0;
1740e3ec7017SPing-Ke Shih }
1741e3ec7017SPing-Ke Shih 
1742db38d9cdSChin-Yen Lee static int rtw89_pci_write_config_byte(struct rtw89_dev *rtwdev, u16 addr,
1743db38d9cdSChin-Yen Lee 				       u8 data)
1744e3ec7017SPing-Ke Shih {
1745db38d9cdSChin-Yen Lee 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
1746db38d9cdSChin-Yen Lee 	struct pci_dev *pdev = rtwpci->pdev;
1747e3ec7017SPing-Ke Shih 
1748db38d9cdSChin-Yen Lee 	return pci_write_config_byte(pdev, addr, data);
1749e3ec7017SPing-Ke Shih }
1750e3ec7017SPing-Ke Shih 
1751db38d9cdSChin-Yen Lee static int rtw89_pci_read_config_byte(struct rtw89_dev *rtwdev, u16 addr,
1752db38d9cdSChin-Yen Lee 				      u8 *value)
1753e3ec7017SPing-Ke Shih {
1754db38d9cdSChin-Yen Lee 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
1755db38d9cdSChin-Yen Lee 	struct pci_dev *pdev = rtwpci->pdev;
1756e3ec7017SPing-Ke Shih 
1757db38d9cdSChin-Yen Lee 	return pci_read_config_byte(pdev, addr, value);
1758e3ec7017SPing-Ke Shih }
1759e3ec7017SPing-Ke Shih 
1760db38d9cdSChin-Yen Lee static int rtw89_pci_config_byte_set(struct rtw89_dev *rtwdev, u16 addr,
1761db38d9cdSChin-Yen Lee 				     u8 bit)
1762e3ec7017SPing-Ke Shih {
1763e3ec7017SPing-Ke Shih 	u8 value;
1764e3ec7017SPing-Ke Shih 	int ret;
1765e3ec7017SPing-Ke Shih 
1766db38d9cdSChin-Yen Lee 	ret = rtw89_pci_read_config_byte(rtwdev, addr, &value);
1767e3ec7017SPing-Ke Shih 	if (ret)
1768e3ec7017SPing-Ke Shih 		return ret;
1769e3ec7017SPing-Ke Shih 
1770e3ec7017SPing-Ke Shih 	value |= bit;
1771db38d9cdSChin-Yen Lee 	ret = rtw89_pci_write_config_byte(rtwdev, addr, value);
1772e3ec7017SPing-Ke Shih 
1773e3ec7017SPing-Ke Shih 	return ret;
1774e3ec7017SPing-Ke Shih }
1775e3ec7017SPing-Ke Shih 
1776db38d9cdSChin-Yen Lee static int rtw89_pci_config_byte_clr(struct rtw89_dev *rtwdev, u16 addr,
1777db38d9cdSChin-Yen Lee 				     u8 bit)
1778e3ec7017SPing-Ke Shih {
1779e3ec7017SPing-Ke Shih 	u8 value;
1780e3ec7017SPing-Ke Shih 	int ret;
1781e3ec7017SPing-Ke Shih 
1782db38d9cdSChin-Yen Lee 	ret = rtw89_pci_read_config_byte(rtwdev, addr, &value);
1783e3ec7017SPing-Ke Shih 	if (ret)
1784e3ec7017SPing-Ke Shih 		return ret;
1785e3ec7017SPing-Ke Shih 
1786e3ec7017SPing-Ke Shih 	value &= ~bit;
1787db38d9cdSChin-Yen Lee 	ret = rtw89_pci_write_config_byte(rtwdev, addr, value);
1788e3ec7017SPing-Ke Shih 
1789e3ec7017SPing-Ke Shih 	return ret;
1790e3ec7017SPing-Ke Shih }
1791e3ec7017SPing-Ke Shih 
1792e3ec7017SPing-Ke Shih static int
1793e3ec7017SPing-Ke Shih __get_target(struct rtw89_dev *rtwdev, u16 *target, enum rtw89_pcie_phy phy_rate)
1794e3ec7017SPing-Ke Shih {
1795e3ec7017SPing-Ke Shih 	u16 val, tar;
1796e3ec7017SPing-Ke Shih 	int ret;
1797e3ec7017SPing-Ke Shih 
1798e3ec7017SPing-Ke Shih 	/* Enable counter */
1799e3ec7017SPing-Ke Shih 	ret = rtw89_read16_mdio(rtwdev, RAC_CTRL_PPR_V1, phy_rate, &val);
1800e3ec7017SPing-Ke Shih 	if (ret)
1801e3ec7017SPing-Ke Shih 		return ret;
1802e3ec7017SPing-Ke Shih 	ret = rtw89_write16_mdio(rtwdev, RAC_CTRL_PPR_V1, val & ~B_AX_CLK_CALIB_EN,
1803e3ec7017SPing-Ke Shih 				 phy_rate);
1804e3ec7017SPing-Ke Shih 	if (ret)
1805e3ec7017SPing-Ke Shih 		return ret;
1806e3ec7017SPing-Ke Shih 	ret = rtw89_write16_mdio(rtwdev, RAC_CTRL_PPR_V1, val | B_AX_CLK_CALIB_EN,
1807e3ec7017SPing-Ke Shih 				 phy_rate);
1808e3ec7017SPing-Ke Shih 	if (ret)
1809e3ec7017SPing-Ke Shih 		return ret;
1810e3ec7017SPing-Ke Shih 
1811e3ec7017SPing-Ke Shih 	fsleep(300);
1812e3ec7017SPing-Ke Shih 
1813e3ec7017SPing-Ke Shih 	ret = rtw89_read16_mdio(rtwdev, RAC_CTRL_PPR_V1, phy_rate, &tar);
1814e3ec7017SPing-Ke Shih 	if (ret)
1815e3ec7017SPing-Ke Shih 		return ret;
1816e3ec7017SPing-Ke Shih 	ret = rtw89_write16_mdio(rtwdev, RAC_CTRL_PPR_V1, val & ~B_AX_CLK_CALIB_EN,
1817e3ec7017SPing-Ke Shih 				 phy_rate);
1818e3ec7017SPing-Ke Shih 	if (ret)
1819e3ec7017SPing-Ke Shih 		return ret;
1820e3ec7017SPing-Ke Shih 
1821e3ec7017SPing-Ke Shih 	tar = tar & 0x0FFF;
1822e3ec7017SPing-Ke Shih 	if (tar == 0 || tar == 0x0FFF) {
1823e3ec7017SPing-Ke Shih 		rtw89_err(rtwdev, "[ERR]Get target failed.\n");
1824e3ec7017SPing-Ke Shih 		return -EINVAL;
1825e3ec7017SPing-Ke Shih 	}
1826e3ec7017SPing-Ke Shih 
1827e3ec7017SPing-Ke Shih 	*target = tar;
1828e3ec7017SPing-Ke Shih 
1829e3ec7017SPing-Ke Shih 	return 0;
1830e3ec7017SPing-Ke Shih }
1831e3ec7017SPing-Ke Shih 
1832e3ec7017SPing-Ke Shih static int rtw89_pci_auto_refclk_cal(struct rtw89_dev *rtwdev, bool autook_en)
1833e3ec7017SPing-Ke Shih {
1834e3ec7017SPing-Ke Shih 	enum rtw89_pcie_phy phy_rate;
1835e3ec7017SPing-Ke Shih 	u16 val16, mgn_set, div_set, tar;
1836e3ec7017SPing-Ke Shih 	u8 val8, bdr_ori;
1837e3ec7017SPing-Ke Shih 	bool l1_flag = false;
1838e3ec7017SPing-Ke Shih 	int ret = 0;
1839e3ec7017SPing-Ke Shih 
1840740c431cSPing-Ke Shih 	if (rtwdev->chip->chip_id != RTL8852B)
1841e3ec7017SPing-Ke Shih 		return 0;
1842e3ec7017SPing-Ke Shih 
1843db38d9cdSChin-Yen Lee 	ret = rtw89_pci_read_config_byte(rtwdev, RTW89_PCIE_PHY_RATE, &val8);
1844e3ec7017SPing-Ke Shih 	if (ret) {
1845db38d9cdSChin-Yen Lee 		rtw89_err(rtwdev, "[ERR]pci config read %X\n",
1846db38d9cdSChin-Yen Lee 			  RTW89_PCIE_PHY_RATE);
1847e3ec7017SPing-Ke Shih 		return ret;
1848e3ec7017SPing-Ke Shih 	}
1849e3ec7017SPing-Ke Shih 
1850e3ec7017SPing-Ke Shih 	if (FIELD_GET(RTW89_PCIE_PHY_RATE_MASK, val8) == 0x1) {
1851e3ec7017SPing-Ke Shih 		phy_rate = PCIE_PHY_GEN1;
1852e3ec7017SPing-Ke Shih 	} else if (FIELD_GET(RTW89_PCIE_PHY_RATE_MASK, val8) == 0x2) {
1853e3ec7017SPing-Ke Shih 		phy_rate = PCIE_PHY_GEN2;
1854e3ec7017SPing-Ke Shih 	} else {
1855e3ec7017SPing-Ke Shih 		rtw89_err(rtwdev, "[ERR]PCIe PHY rate %#x not support\n", val8);
1856e3ec7017SPing-Ke Shih 		return -EOPNOTSUPP;
1857e3ec7017SPing-Ke Shih 	}
1858e3ec7017SPing-Ke Shih 	/* Disable L1BD */
1859db38d9cdSChin-Yen Lee 	ret = rtw89_pci_read_config_byte(rtwdev, RTW89_PCIE_L1_CTRL, &bdr_ori);
1860e3ec7017SPing-Ke Shih 	if (ret) {
1861db38d9cdSChin-Yen Lee 		rtw89_err(rtwdev, "[ERR]pci config read %X\n", RTW89_PCIE_L1_CTRL);
1862e3ec7017SPing-Ke Shih 		return ret;
1863e3ec7017SPing-Ke Shih 	}
1864e3ec7017SPing-Ke Shih 
1865e3ec7017SPing-Ke Shih 	if (bdr_ori & RTW89_PCIE_BIT_L1) {
1866db38d9cdSChin-Yen Lee 		ret = rtw89_pci_write_config_byte(rtwdev, RTW89_PCIE_L1_CTRL,
1867e3ec7017SPing-Ke Shih 						  bdr_ori & ~RTW89_PCIE_BIT_L1);
1868e3ec7017SPing-Ke Shih 		if (ret) {
1869db38d9cdSChin-Yen Lee 			rtw89_err(rtwdev, "[ERR]pci config write %X\n",
1870db38d9cdSChin-Yen Lee 				  RTW89_PCIE_L1_CTRL);
1871e3ec7017SPing-Ke Shih 			return ret;
1872e3ec7017SPing-Ke Shih 		}
1873e3ec7017SPing-Ke Shih 		l1_flag = true;
1874e3ec7017SPing-Ke Shih 	}
1875e3ec7017SPing-Ke Shih 
1876e3ec7017SPing-Ke Shih 	ret = rtw89_read16_mdio(rtwdev, RAC_CTRL_PPR_V1, phy_rate, &val16);
1877e3ec7017SPing-Ke Shih 	if (ret) {
1878e3ec7017SPing-Ke Shih 		rtw89_err(rtwdev, "[ERR]mdio_r16_pcie %X\n", RAC_CTRL_PPR_V1);
1879e3ec7017SPing-Ke Shih 		goto end;
1880e3ec7017SPing-Ke Shih 	}
1881e3ec7017SPing-Ke Shih 
1882e3ec7017SPing-Ke Shih 	if (val16 & B_AX_CALIB_EN) {
1883e3ec7017SPing-Ke Shih 		ret = rtw89_write16_mdio(rtwdev, RAC_CTRL_PPR_V1,
1884e3ec7017SPing-Ke Shih 					 val16 & ~B_AX_CALIB_EN, phy_rate);
1885e3ec7017SPing-Ke Shih 		if (ret) {
1886e3ec7017SPing-Ke Shih 			rtw89_err(rtwdev, "[ERR]mdio_w16_pcie %X\n", RAC_CTRL_PPR_V1);
1887e3ec7017SPing-Ke Shih 			goto end;
1888e3ec7017SPing-Ke Shih 		}
1889e3ec7017SPing-Ke Shih 	}
1890e3ec7017SPing-Ke Shih 
1891e3ec7017SPing-Ke Shih 	if (!autook_en)
1892e3ec7017SPing-Ke Shih 		goto end;
1893e3ec7017SPing-Ke Shih 	/* Set div */
1894e3ec7017SPing-Ke Shih 	ret = rtw89_write16_mdio_clr(rtwdev, RAC_CTRL_PPR_V1, B_AX_DIV, phy_rate);
1895e3ec7017SPing-Ke Shih 	if (ret) {
1896e3ec7017SPing-Ke Shih 		rtw89_err(rtwdev, "[ERR]mdio_w16_pcie %X\n", RAC_CTRL_PPR_V1);
1897e3ec7017SPing-Ke Shih 		goto end;
1898e3ec7017SPing-Ke Shih 	}
1899e3ec7017SPing-Ke Shih 
1900e3ec7017SPing-Ke Shih 	/* Obtain div and margin */
1901e3ec7017SPing-Ke Shih 	ret = __get_target(rtwdev, &tar, phy_rate);
1902e3ec7017SPing-Ke Shih 	if (ret) {
1903e3ec7017SPing-Ke Shih 		rtw89_err(rtwdev, "[ERR]1st get target fail %d\n", ret);
1904e3ec7017SPing-Ke Shih 		goto end;
1905e3ec7017SPing-Ke Shih 	}
1906e3ec7017SPing-Ke Shih 
1907e3ec7017SPing-Ke Shih 	mgn_set = tar * INTF_INTGRA_HOSTREF_V1 / INTF_INTGRA_MINREF_V1 - tar;
1908e3ec7017SPing-Ke Shih 
1909e3ec7017SPing-Ke Shih 	if (mgn_set >= 128) {
1910e3ec7017SPing-Ke Shih 		div_set = 0x0003;
1911e3ec7017SPing-Ke Shih 		mgn_set = 0x000F;
1912e3ec7017SPing-Ke Shih 	} else if (mgn_set >= 64) {
1913e3ec7017SPing-Ke Shih 		div_set = 0x0003;
1914e3ec7017SPing-Ke Shih 		mgn_set >>= 3;
1915e3ec7017SPing-Ke Shih 	} else if (mgn_set >= 32) {
1916e3ec7017SPing-Ke Shih 		div_set = 0x0002;
1917e3ec7017SPing-Ke Shih 		mgn_set >>= 2;
1918e3ec7017SPing-Ke Shih 	} else if (mgn_set >= 16) {
1919e3ec7017SPing-Ke Shih 		div_set = 0x0001;
1920e3ec7017SPing-Ke Shih 		mgn_set >>= 1;
1921e3ec7017SPing-Ke Shih 	} else if (mgn_set == 0) {
1922e3ec7017SPing-Ke Shih 		rtw89_err(rtwdev, "[ERR]cal mgn is 0,tar = %d\n", tar);
1923e3ec7017SPing-Ke Shih 		goto end;
1924e3ec7017SPing-Ke Shih 	} else {
1925e3ec7017SPing-Ke Shih 		div_set = 0x0000;
1926e3ec7017SPing-Ke Shih 	}
1927e3ec7017SPing-Ke Shih 
1928e3ec7017SPing-Ke Shih 	ret = rtw89_read16_mdio(rtwdev, RAC_CTRL_PPR_V1, phy_rate, &val16);
1929e3ec7017SPing-Ke Shih 	if (ret) {
1930e3ec7017SPing-Ke Shih 		rtw89_err(rtwdev, "[ERR]mdio_r16_pcie %X\n", RAC_CTRL_PPR_V1);
1931e3ec7017SPing-Ke Shih 		goto end;
1932e3ec7017SPing-Ke Shih 	}
1933e3ec7017SPing-Ke Shih 
1934e3ec7017SPing-Ke Shih 	val16 |= u16_encode_bits(div_set, B_AX_DIV);
1935e3ec7017SPing-Ke Shih 
1936e3ec7017SPing-Ke Shih 	ret = rtw89_write16_mdio(rtwdev, RAC_CTRL_PPR_V1, val16, phy_rate);
1937e3ec7017SPing-Ke Shih 	if (ret) {
1938e3ec7017SPing-Ke Shih 		rtw89_err(rtwdev, "[ERR]mdio_w16_pcie %X\n", RAC_CTRL_PPR_V1);
1939e3ec7017SPing-Ke Shih 		goto end;
1940e3ec7017SPing-Ke Shih 	}
1941e3ec7017SPing-Ke Shih 
1942e3ec7017SPing-Ke Shih 	ret = __get_target(rtwdev, &tar, phy_rate);
1943e3ec7017SPing-Ke Shih 	if (ret) {
1944e3ec7017SPing-Ke Shih 		rtw89_err(rtwdev, "[ERR]2nd get target fail %d\n", ret);
1945e3ec7017SPing-Ke Shih 		goto end;
1946e3ec7017SPing-Ke Shih 	}
1947e3ec7017SPing-Ke Shih 
1948e3ec7017SPing-Ke Shih 	rtw89_debug(rtwdev, RTW89_DBG_HCI, "[TRACE]target = 0x%X, div = 0x%X, margin = 0x%X\n",
1949e3ec7017SPing-Ke Shih 		    tar, div_set, mgn_set);
1950e3ec7017SPing-Ke Shih 	ret = rtw89_write16_mdio(rtwdev, RAC_SET_PPR_V1,
1951e3ec7017SPing-Ke Shih 				 (tar & 0x0FFF) | (mgn_set << 12), phy_rate);
1952e3ec7017SPing-Ke Shih 	if (ret) {
1953e3ec7017SPing-Ke Shih 		rtw89_err(rtwdev, "[ERR]mdio_w16_pcie %X\n", RAC_SET_PPR_V1);
1954e3ec7017SPing-Ke Shih 		goto end;
1955e3ec7017SPing-Ke Shih 	}
1956e3ec7017SPing-Ke Shih 
1957e3ec7017SPing-Ke Shih 	/* Enable function */
1958e3ec7017SPing-Ke Shih 	ret = rtw89_write16_mdio_set(rtwdev, RAC_CTRL_PPR_V1, B_AX_CALIB_EN, phy_rate);
1959e3ec7017SPing-Ke Shih 	if (ret) {
1960e3ec7017SPing-Ke Shih 		rtw89_err(rtwdev, "[ERR]mdio_w16_pcie %X\n", RAC_CTRL_PPR_V1);
1961e3ec7017SPing-Ke Shih 		goto end;
1962e3ec7017SPing-Ke Shih 	}
1963e3ec7017SPing-Ke Shih 
1964e3ec7017SPing-Ke Shih 	/* CLK delay = 0 */
1965db38d9cdSChin-Yen Lee 	ret = rtw89_pci_write_config_byte(rtwdev, RTW89_PCIE_CLK_CTRL,
1966db38d9cdSChin-Yen Lee 					  PCIE_CLKDLY_HW_0);
1967e3ec7017SPing-Ke Shih 
1968e3ec7017SPing-Ke Shih end:
1969e3ec7017SPing-Ke Shih 	/* Set L1BD to ori */
1970e3ec7017SPing-Ke Shih 	if (l1_flag) {
1971db38d9cdSChin-Yen Lee 		ret = rtw89_pci_write_config_byte(rtwdev, RTW89_PCIE_L1_CTRL,
1972db38d9cdSChin-Yen Lee 						  bdr_ori);
1973e3ec7017SPing-Ke Shih 		if (ret) {
1974db38d9cdSChin-Yen Lee 			rtw89_err(rtwdev, "[ERR]pci config write %X\n",
1975db38d9cdSChin-Yen Lee 				  RTW89_PCIE_L1_CTRL);
1976e3ec7017SPing-Ke Shih 			return ret;
1977e3ec7017SPing-Ke Shih 		}
1978e3ec7017SPing-Ke Shih 	}
1979e3ec7017SPing-Ke Shih 
1980e3ec7017SPing-Ke Shih 	return ret;
1981e3ec7017SPing-Ke Shih }
1982e3ec7017SPing-Ke Shih 
1983e3ec7017SPing-Ke Shih static int rtw89_pci_deglitch_setting(struct rtw89_dev *rtwdev)
1984e3ec7017SPing-Ke Shih {
198522a66e7cSPing-Ke Shih 	enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id;
1986e3ec7017SPing-Ke Shih 	int ret;
1987e3ec7017SPing-Ke Shih 
198822a66e7cSPing-Ke Shih 	if (chip_id == RTL8852A) {
1989e3ec7017SPing-Ke Shih 		ret = rtw89_write16_mdio_clr(rtwdev, RAC_ANA24, B_AX_DEGLITCH,
1990e3ec7017SPing-Ke Shih 					     PCIE_PHY_GEN1);
1991e3ec7017SPing-Ke Shih 		if (ret)
1992e3ec7017SPing-Ke Shih 			return ret;
1993e3ec7017SPing-Ke Shih 		ret = rtw89_write16_mdio_clr(rtwdev, RAC_ANA24, B_AX_DEGLITCH,
1994e3ec7017SPing-Ke Shih 					     PCIE_PHY_GEN2);
1995e3ec7017SPing-Ke Shih 		if (ret)
1996e3ec7017SPing-Ke Shih 			return ret;
199722a66e7cSPing-Ke Shih 	} else if (chip_id == RTL8852C) {
199822a66e7cSPing-Ke Shih 		rtw89_write16_clr(rtwdev, R_RAC_DIRECT_OFFSET_G1 + RAC_ANA24 * 2,
199922a66e7cSPing-Ke Shih 				  B_AX_DEGLITCH);
200022a66e7cSPing-Ke Shih 		rtw89_write16_clr(rtwdev, R_RAC_DIRECT_OFFSET_G2 + RAC_ANA24 * 2,
200122a66e7cSPing-Ke Shih 				  B_AX_DEGLITCH);
200222a66e7cSPing-Ke Shih 	}
2003e3ec7017SPing-Ke Shih 
2004e3ec7017SPing-Ke Shih 	return 0;
2005e3ec7017SPing-Ke Shih }
2006e3ec7017SPing-Ke Shih 
2007e3ec7017SPing-Ke Shih static void rtw89_pci_rxdma_prefth(struct rtw89_dev *rtwdev)
2008e3ec7017SPing-Ke Shih {
2009740c431cSPing-Ke Shih 	if (rtwdev->chip->chip_id != RTL8852A)
2010740c431cSPing-Ke Shih 		return;
2011740c431cSPing-Ke Shih 
2012e3ec7017SPing-Ke Shih 	rtw89_write32_set(rtwdev, R_AX_PCIE_INIT_CFG1, B_AX_DIS_RXDMA_PRE);
2013e3ec7017SPing-Ke Shih }
2014e3ec7017SPing-Ke Shih 
2015e3ec7017SPing-Ke Shih static void rtw89_pci_l1off_pwroff(struct rtw89_dev *rtwdev)
2016e3ec7017SPing-Ke Shih {
2017740c431cSPing-Ke Shih 	if (rtwdev->chip->chip_id != RTL8852A && rtwdev->chip->chip_id != RTL8852B)
2018e3ec7017SPing-Ke Shih 		return;
2019e3ec7017SPing-Ke Shih 
2020e3ec7017SPing-Ke Shih 	rtw89_write32_clr(rtwdev, R_AX_PCIE_PS_CTRL, B_AX_L1OFF_PWR_OFF_EN);
2021e3ec7017SPing-Ke Shih }
2022e3ec7017SPing-Ke Shih 
2023e3ec7017SPing-Ke Shih static u32 rtw89_pci_l2_rxen_lat(struct rtw89_dev *rtwdev)
2024e3ec7017SPing-Ke Shih {
2025e3ec7017SPing-Ke Shih 	int ret;
2026e3ec7017SPing-Ke Shih 
2027740c431cSPing-Ke Shih 	if (rtwdev->chip->chip_id != RTL8852A)
2028e3ec7017SPing-Ke Shih 		return 0;
2029e3ec7017SPing-Ke Shih 
2030e3ec7017SPing-Ke Shih 	ret = rtw89_write16_mdio_clr(rtwdev, RAC_ANA26, B_AX_RXEN,
2031e3ec7017SPing-Ke Shih 				     PCIE_PHY_GEN1);
2032e3ec7017SPing-Ke Shih 	if (ret)
2033e3ec7017SPing-Ke Shih 		return ret;
2034e3ec7017SPing-Ke Shih 
2035e3ec7017SPing-Ke Shih 	ret = rtw89_write16_mdio_clr(rtwdev, RAC_ANA26, B_AX_RXEN,
2036e3ec7017SPing-Ke Shih 				     PCIE_PHY_GEN2);
2037e3ec7017SPing-Ke Shih 	if (ret)
2038e3ec7017SPing-Ke Shih 		return ret;
2039e3ec7017SPing-Ke Shih 
2040e3ec7017SPing-Ke Shih 	return 0;
2041e3ec7017SPing-Ke Shih }
2042e3ec7017SPing-Ke Shih 
2043e3ec7017SPing-Ke Shih static void rtw89_pci_aphy_pwrcut(struct rtw89_dev *rtwdev)
2044e3ec7017SPing-Ke Shih {
2045e3ec7017SPing-Ke Shih 	if (rtwdev->chip->chip_id != RTL8852A)
2046e3ec7017SPing-Ke Shih 		return;
2047e3ec7017SPing-Ke Shih 
2048e3ec7017SPing-Ke Shih 	rtw89_write32_clr(rtwdev, R_AX_SYS_PW_CTRL, B_AX_PSUS_OFF_CAPC_EN);
2049e3ec7017SPing-Ke Shih }
2050e3ec7017SPing-Ke Shih 
2051e3ec7017SPing-Ke Shih static void rtw89_pci_hci_ldo(struct rtw89_dev *rtwdev)
2052e3ec7017SPing-Ke Shih {
20531e3f2055SChia-Yuan Li 	if (rtwdev->chip->chip_id == RTL8852A ||
20541e3f2055SChia-Yuan Li 	    rtwdev->chip->chip_id == RTL8852B) {
2055e3ec7017SPing-Ke Shih 		rtw89_write32_set(rtwdev, R_AX_SYS_SDIO_CTRL,
2056e3ec7017SPing-Ke Shih 				  B_AX_PCIE_DIS_L2_CTRL_LDO_HCI);
2057e3ec7017SPing-Ke Shih 		rtw89_write32_clr(rtwdev, R_AX_SYS_SDIO_CTRL,
2058e3ec7017SPing-Ke Shih 				  B_AX_PCIE_DIS_WLSUS_AFT_PDN);
20591e3f2055SChia-Yuan Li 	} else if (rtwdev->chip->chip_id == RTL8852C) {
20601e3f2055SChia-Yuan Li 		rtw89_write32_clr(rtwdev, R_AX_SYS_SDIO_CTRL,
20611e3f2055SChia-Yuan Li 				  B_AX_PCIE_DIS_L2_CTRL_LDO_HCI);
20621e3f2055SChia-Yuan Li 	}
2063e3ec7017SPing-Ke Shih }
2064e3ec7017SPing-Ke Shih 
2065740c431cSPing-Ke Shih static int rtw89_pci_dphy_delay(struct rtw89_dev *rtwdev)
2066740c431cSPing-Ke Shih {
2067740c431cSPing-Ke Shih 	if (rtwdev->chip->chip_id != RTL8852B)
2068740c431cSPing-Ke Shih 		return 0;
2069740c431cSPing-Ke Shih 
2070740c431cSPing-Ke Shih 	return rtw89_write16_mdio_mask(rtwdev, RAC_REG_REV2, BAC_CMU_EN_DLY_MASK,
2071740c431cSPing-Ke Shih 				       PCIE_DPHY_DLY_25US, PCIE_PHY_GEN1);
2072740c431cSPing-Ke Shih }
2073740c431cSPing-Ke Shih 
2074740c431cSPing-Ke Shih static void rtw89_pci_power_wake(struct rtw89_dev *rtwdev, bool pwr_up)
2075740c431cSPing-Ke Shih {
2076740c431cSPing-Ke Shih 	if (pwr_up)
2077740c431cSPing-Ke Shih 		rtw89_write32_set(rtwdev, R_AX_HCI_OPT_CTRL, BIT_WAKE_CTRL);
2078740c431cSPing-Ke Shih 	else
2079740c431cSPing-Ke Shih 		rtw89_write32_clr(rtwdev, R_AX_HCI_OPT_CTRL, BIT_WAKE_CTRL);
2080740c431cSPing-Ke Shih }
2081740c431cSPing-Ke Shih 
2082740c431cSPing-Ke Shih static void rtw89_pci_autoload_hang(struct rtw89_dev *rtwdev)
2083740c431cSPing-Ke Shih {
2084740c431cSPing-Ke Shih 	if (rtwdev->chip->chip_id != RTL8852C)
2085740c431cSPing-Ke Shih 		return;
2086740c431cSPing-Ke Shih 
2087740c431cSPing-Ke Shih 	rtw89_write32_set(rtwdev, R_AX_PCIE_BG_CLR, B_AX_BG_CLR_ASYNC_M3);
2088740c431cSPing-Ke Shih 	rtw89_write32_clr(rtwdev, R_AX_PCIE_BG_CLR, B_AX_BG_CLR_ASYNC_M3);
2089740c431cSPing-Ke Shih }
2090740c431cSPing-Ke Shih 
2091740c431cSPing-Ke Shih static void rtw89_pci_l12_vmain(struct rtw89_dev *rtwdev)
2092740c431cSPing-Ke Shih {
20931e3f2055SChia-Yuan Li 	if (!(rtwdev->chip->chip_id == RTL8852C && rtwdev->hal.cv == CHIP_CAV))
2094740c431cSPing-Ke Shih 		return;
2095740c431cSPing-Ke Shih 
2096740c431cSPing-Ke Shih 	rtw89_write32_set(rtwdev, R_AX_SYS_SDIO_CTRL, B_AX_PCIE_FORCE_PWR_NGAT);
2097740c431cSPing-Ke Shih }
2098740c431cSPing-Ke Shih 
20991e3f2055SChia-Yuan Li static void rtw89_pci_gen2_force_ib(struct rtw89_dev *rtwdev)
21001e3f2055SChia-Yuan Li {
21011e3f2055SChia-Yuan Li 	if (!(rtwdev->chip->chip_id == RTL8852C && rtwdev->hal.cv == CHIP_CAV))
21021e3f2055SChia-Yuan Li 		return;
21031e3f2055SChia-Yuan Li 
21041e3f2055SChia-Yuan Li 	rtw89_write32_set(rtwdev, R_AX_PMC_DBG_CTRL2,
21051e3f2055SChia-Yuan Li 			  B_AX_SYSON_DIS_PMCR_AX_WRMSK);
21061e3f2055SChia-Yuan Li 	rtw89_write32_set(rtwdev, R_AX_HCI_BG_CTRL, B_AX_BG_CLR_ASYNC_M3);
21071e3f2055SChia-Yuan Li 	rtw89_write32_clr(rtwdev, R_AX_PMC_DBG_CTRL2,
21081e3f2055SChia-Yuan Li 			  B_AX_SYSON_DIS_PMCR_AX_WRMSK);
21091e3f2055SChia-Yuan Li }
21101e3f2055SChia-Yuan Li 
2111e1e7a574SPing-Ke Shih static void rtw89_pci_l1_ent_lat(struct rtw89_dev *rtwdev)
2112e1e7a574SPing-Ke Shih {
2113e1e7a574SPing-Ke Shih 	if (rtwdev->chip->chip_id != RTL8852C)
2114e1e7a574SPing-Ke Shih 		return;
2115e1e7a574SPing-Ke Shih 
2116e1e7a574SPing-Ke Shih 	rtw89_write32_clr(rtwdev, R_AX_PCIE_PS_CTRL_V1, B_AX_SEL_REQ_ENTR_L1);
2117e1e7a574SPing-Ke Shih }
2118e1e7a574SPing-Ke Shih 
2119e1e7a574SPing-Ke Shih static void rtw89_pci_wd_exit_l1(struct rtw89_dev *rtwdev)
2120e1e7a574SPing-Ke Shih {
2121e1e7a574SPing-Ke Shih 	if (rtwdev->chip->chip_id != RTL8852C)
2122e1e7a574SPing-Ke Shih 		return;
2123e1e7a574SPing-Ke Shih 
2124e1e7a574SPing-Ke Shih 	rtw89_write32_set(rtwdev, R_AX_PCIE_PS_CTRL_V1, B_AX_DMAC0_EXIT_L1_EN);
2125e1e7a574SPing-Ke Shih }
2126e1e7a574SPing-Ke Shih 
2127e3ec7017SPing-Ke Shih static void rtw89_pci_set_sic(struct rtw89_dev *rtwdev)
2128e3ec7017SPing-Ke Shih {
2129e3ec7017SPing-Ke Shih 	if (rtwdev->chip->chip_id == RTL8852C)
2130e3ec7017SPing-Ke Shih 		return;
2131e3ec7017SPing-Ke Shih 
2132e3ec7017SPing-Ke Shih 	rtw89_write32_clr(rtwdev, R_AX_PCIE_EXP_CTRL,
2133e3ec7017SPing-Ke Shih 			  B_AX_SIC_EN_FORCE_CLKREQ);
2134e3ec7017SPing-Ke Shih }
2135e3ec7017SPing-Ke Shih 
21361e3f2055SChia-Yuan Li static void rtw89_pci_set_lbc(struct rtw89_dev *rtwdev)
21371e3f2055SChia-Yuan Li {
21381e3f2055SChia-Yuan Li 	const struct rtw89_pci_info *info = rtwdev->pci_info;
21391e3f2055SChia-Yuan Li 	u32 lbc;
21401e3f2055SChia-Yuan Li 
21411e3f2055SChia-Yuan Li 	if (rtwdev->chip->chip_id == RTL8852C)
21421e3f2055SChia-Yuan Li 		return;
21431e3f2055SChia-Yuan Li 
21441e3f2055SChia-Yuan Li 	lbc = rtw89_read32(rtwdev, R_AX_LBC_WATCHDOG);
21451e3f2055SChia-Yuan Li 	if (info->lbc_en == MAC_AX_PCIE_ENABLE) {
21461e3f2055SChia-Yuan Li 		lbc = u32_replace_bits(lbc, info->lbc_tmr, B_AX_LBC_TIMER);
21471e3f2055SChia-Yuan Li 		lbc |= B_AX_LBC_FLAG | B_AX_LBC_EN;
21481e3f2055SChia-Yuan Li 		rtw89_write32(rtwdev, R_AX_LBC_WATCHDOG, lbc);
21491e3f2055SChia-Yuan Li 	} else {
21501e3f2055SChia-Yuan Li 		lbc &= ~B_AX_LBC_EN;
21511e3f2055SChia-Yuan Li 	}
21521e3f2055SChia-Yuan Li 	rtw89_write32_set(rtwdev, R_AX_LBC_WATCHDOG, lbc);
21531e3f2055SChia-Yuan Li }
21541e3f2055SChia-Yuan Li 
2155b9467e94SPing-Ke Shih static void rtw89_pci_set_io_rcy(struct rtw89_dev *rtwdev)
2156b9467e94SPing-Ke Shih {
2157b9467e94SPing-Ke Shih 	const struct rtw89_pci_info *info = rtwdev->pci_info;
2158b9467e94SPing-Ke Shih 	u32 val32;
2159b9467e94SPing-Ke Shih 
2160b9467e94SPing-Ke Shih 	if (rtwdev->chip->chip_id != RTL8852C)
2161b9467e94SPing-Ke Shih 		return;
2162b9467e94SPing-Ke Shih 
2163b9467e94SPing-Ke Shih 	if (info->io_rcy_en == MAC_AX_PCIE_ENABLE) {
2164b9467e94SPing-Ke Shih 		val32 = FIELD_PREP(B_AX_PCIE_WDT_TIMER_M1_MASK,
2165b9467e94SPing-Ke Shih 				   info->io_rcy_tmr);
2166b9467e94SPing-Ke Shih 		rtw89_write32(rtwdev, R_AX_PCIE_WDT_TIMER_M1, val32);
2167b9467e94SPing-Ke Shih 		rtw89_write32(rtwdev, R_AX_PCIE_WDT_TIMER_M2, val32);
2168b9467e94SPing-Ke Shih 		rtw89_write32(rtwdev, R_AX_PCIE_WDT_TIMER_E0, val32);
2169b9467e94SPing-Ke Shih 
2170b9467e94SPing-Ke Shih 		rtw89_write32_set(rtwdev, R_AX_PCIE_IO_RCY_M1, B_AX_PCIE_IO_RCY_WDT_MODE_M1);
2171b9467e94SPing-Ke Shih 		rtw89_write32_set(rtwdev, R_AX_PCIE_IO_RCY_M2, B_AX_PCIE_IO_RCY_WDT_MODE_M2);
2172b9467e94SPing-Ke Shih 		rtw89_write32_set(rtwdev, R_AX_PCIE_IO_RCY_E0, B_AX_PCIE_IO_RCY_WDT_MODE_E0);
2173b9467e94SPing-Ke Shih 	} else {
2174b9467e94SPing-Ke Shih 		rtw89_write32_clr(rtwdev, R_AX_PCIE_IO_RCY_M1, B_AX_PCIE_IO_RCY_WDT_MODE_M1);
2175b9467e94SPing-Ke Shih 		rtw89_write32_clr(rtwdev, R_AX_PCIE_IO_RCY_M2, B_AX_PCIE_IO_RCY_WDT_MODE_M2);
2176b9467e94SPing-Ke Shih 		rtw89_write32_clr(rtwdev, R_AX_PCIE_IO_RCY_E0, B_AX_PCIE_IO_RCY_WDT_MODE_E0);
2177b9467e94SPing-Ke Shih 	}
2178b9467e94SPing-Ke Shih 
2179b9467e94SPing-Ke Shih 	rtw89_write32_clr(rtwdev, R_AX_PCIE_IO_RCY_S1, B_AX_PCIE_IO_RCY_WDT_MODE_S1);
2180b9467e94SPing-Ke Shih }
2181b9467e94SPing-Ke Shih 
2182e3ec7017SPing-Ke Shih static void rtw89_pci_set_dbg(struct rtw89_dev *rtwdev)
2183e3ec7017SPing-Ke Shih {
2184e3ec7017SPing-Ke Shih 	if (rtwdev->chip->chip_id == RTL8852C)
2185e3ec7017SPing-Ke Shih 		return;
2186e3ec7017SPing-Ke Shih 
2187e3ec7017SPing-Ke Shih 	rtw89_write32_set(rtwdev, R_AX_PCIE_DBG_CTRL,
2188e3ec7017SPing-Ke Shih 			  B_AX_ASFF_FULL_NO_STK | B_AX_EN_STUCK_DBG);
2189e3ec7017SPing-Ke Shih 
2190e3ec7017SPing-Ke Shih 	if (rtwdev->chip->chip_id == RTL8852A)
2191e3ec7017SPing-Ke Shih 		rtw89_write32_set(rtwdev, R_AX_PCIE_EXP_CTRL,
2192e3ec7017SPing-Ke Shih 				  B_AX_EN_CHKDSC_NO_RX_STUCK);
2193e3ec7017SPing-Ke Shih }
2194e3ec7017SPing-Ke Shih 
21951e3f2055SChia-Yuan Li static void rtw89_pci_set_keep_reg(struct rtw89_dev *rtwdev)
21961e3f2055SChia-Yuan Li {
21971e3f2055SChia-Yuan Li 	if (rtwdev->chip->chip_id == RTL8852C)
21981e3f2055SChia-Yuan Li 		return;
21991e3f2055SChia-Yuan Li 
22001e3f2055SChia-Yuan Li 	rtw89_write32_set(rtwdev, R_AX_PCIE_INIT_CFG1,
22011e3f2055SChia-Yuan Li 			  B_AX_PCIE_TXRST_KEEP_REG | B_AX_PCIE_RXRST_KEEP_REG);
22021e3f2055SChia-Yuan Li }
22031e3f2055SChia-Yuan Li 
2204e3ec7017SPing-Ke Shih static void rtw89_pci_clr_idx_all(struct rtw89_dev *rtwdev)
2205e3ec7017SPing-Ke Shih {
2206740c431cSPing-Ke Shih 	const struct rtw89_pci_info *info = rtwdev->pci_info;
2207740c431cSPing-Ke Shih 	enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id;
2208e3ec7017SPing-Ke Shih 	u32 val = B_AX_CLR_ACH0_IDX | B_AX_CLR_ACH1_IDX | B_AX_CLR_ACH2_IDX |
2209e3ec7017SPing-Ke Shih 		  B_AX_CLR_ACH3_IDX | B_AX_CLR_CH8_IDX | B_AX_CLR_CH9_IDX |
2210e3ec7017SPing-Ke Shih 		  B_AX_CLR_CH12_IDX;
2211740c431cSPing-Ke Shih 	u32 rxbd_rwptr_clr = info->rxbd_rwptr_clr_reg;
2212740c431cSPing-Ke Shih 	u32 txbd_rwptr_clr2 = info->txbd_rwptr_clr2_reg;
2213e3ec7017SPing-Ke Shih 
2214740c431cSPing-Ke Shih 	if (chip_id == RTL8852A || chip_id == RTL8852C)
2215e3ec7017SPing-Ke Shih 		val |= B_AX_CLR_ACH4_IDX | B_AX_CLR_ACH5_IDX |
2216e3ec7017SPing-Ke Shih 		       B_AX_CLR_ACH6_IDX | B_AX_CLR_ACH7_IDX;
2217e3ec7017SPing-Ke Shih 	/* clear DMA indexes */
2218e3ec7017SPing-Ke Shih 	rtw89_write32_set(rtwdev, R_AX_TXBD_RWPTR_CLR1, val);
2219740c431cSPing-Ke Shih 	if (chip_id == RTL8852A || chip_id == RTL8852C)
2220740c431cSPing-Ke Shih 		rtw89_write32_set(rtwdev, txbd_rwptr_clr2,
2221e3ec7017SPing-Ke Shih 				  B_AX_CLR_CH10_IDX | B_AX_CLR_CH11_IDX);
2222740c431cSPing-Ke Shih 	rtw89_write32_set(rtwdev, rxbd_rwptr_clr,
2223e3ec7017SPing-Ke Shih 			  B_AX_CLR_RXQ_IDX | B_AX_CLR_RPQ_IDX);
2224e3ec7017SPing-Ke Shih }
2225e3ec7017SPing-Ke Shih 
22261e3f2055SChia-Yuan Li static int rtw89_poll_txdma_ch_idle_pcie(struct rtw89_dev *rtwdev)
22271e3f2055SChia-Yuan Li {
22281e3f2055SChia-Yuan Li 	const struct rtw89_pci_info *info = rtwdev->pci_info;
22291e3f2055SChia-Yuan Li 	u32 ret, check, dma_busy;
22301e3f2055SChia-Yuan Li 	u32 dma_busy1 = info->dma_busy1_reg;
22311e3f2055SChia-Yuan Li 	u32 dma_busy2 = info->dma_busy2_reg;
22321e3f2055SChia-Yuan Li 
22331e3f2055SChia-Yuan Li 	check = B_AX_ACH0_BUSY | B_AX_ACH1_BUSY | B_AX_ACH2_BUSY |
22341e3f2055SChia-Yuan Li 		B_AX_ACH3_BUSY | B_AX_ACH4_BUSY | B_AX_ACH5_BUSY |
22351e3f2055SChia-Yuan Li 		B_AX_ACH6_BUSY | B_AX_ACH7_BUSY | B_AX_CH8_BUSY |
22361e3f2055SChia-Yuan Li 		B_AX_CH9_BUSY | B_AX_CH12_BUSY;
22371e3f2055SChia-Yuan Li 
22381e3f2055SChia-Yuan Li 	ret = read_poll_timeout(rtw89_read32, dma_busy, (dma_busy & check) == 0,
22391e3f2055SChia-Yuan Li 				10, 100, false, rtwdev, dma_busy1);
22401e3f2055SChia-Yuan Li 	if (ret)
22411e3f2055SChia-Yuan Li 		return ret;
22421e3f2055SChia-Yuan Li 
22431e3f2055SChia-Yuan Li 	check = B_AX_CH10_BUSY | B_AX_CH11_BUSY;
22441e3f2055SChia-Yuan Li 
22451e3f2055SChia-Yuan Li 	ret = read_poll_timeout(rtw89_read32, dma_busy, (dma_busy & check) == 0,
22461e3f2055SChia-Yuan Li 				10, 100, false, rtwdev, dma_busy2);
22471e3f2055SChia-Yuan Li 	if (ret)
22481e3f2055SChia-Yuan Li 		return ret;
22491e3f2055SChia-Yuan Li 
22501e3f2055SChia-Yuan Li 	return 0;
22511e3f2055SChia-Yuan Li }
22521e3f2055SChia-Yuan Li 
22531e3f2055SChia-Yuan Li static int rtw89_poll_rxdma_ch_idle_pcie(struct rtw89_dev *rtwdev)
22541e3f2055SChia-Yuan Li {
22551e3f2055SChia-Yuan Li 	const struct rtw89_pci_info *info = rtwdev->pci_info;
22561e3f2055SChia-Yuan Li 	u32 ret, check, dma_busy;
22571e3f2055SChia-Yuan Li 	u32 dma_busy3 = info->dma_busy3_reg;
22581e3f2055SChia-Yuan Li 
22591e3f2055SChia-Yuan Li 	check = B_AX_RXQ_BUSY | B_AX_RPQ_BUSY;
22601e3f2055SChia-Yuan Li 
22611e3f2055SChia-Yuan Li 	ret = read_poll_timeout(rtw89_read32, dma_busy, (dma_busy & check) == 0,
22621e3f2055SChia-Yuan Li 				10, 100, false, rtwdev, dma_busy3);
22631e3f2055SChia-Yuan Li 	if (ret)
22641e3f2055SChia-Yuan Li 		return ret;
22651e3f2055SChia-Yuan Li 
22661e3f2055SChia-Yuan Li 	return 0;
22671e3f2055SChia-Yuan Li }
22681e3f2055SChia-Yuan Li 
22691e3f2055SChia-Yuan Li static int rtw89_pci_poll_dma_all_idle(struct rtw89_dev *rtwdev)
22701e3f2055SChia-Yuan Li {
22711e3f2055SChia-Yuan Li 	u32 ret;
22721e3f2055SChia-Yuan Li 
22731e3f2055SChia-Yuan Li 	ret = rtw89_poll_txdma_ch_idle_pcie(rtwdev);
22741e3f2055SChia-Yuan Li 	if (ret) {
22751e3f2055SChia-Yuan Li 		rtw89_err(rtwdev, "txdma ch busy\n");
22761e3f2055SChia-Yuan Li 		return ret;
22771e3f2055SChia-Yuan Li 	}
22781e3f2055SChia-Yuan Li 
22791e3f2055SChia-Yuan Li 	ret = rtw89_poll_rxdma_ch_idle_pcie(rtwdev);
22801e3f2055SChia-Yuan Li 	if (ret) {
22811e3f2055SChia-Yuan Li 		rtw89_err(rtwdev, "rxdma ch busy\n");
22821e3f2055SChia-Yuan Li 		return ret;
22831e3f2055SChia-Yuan Li 	}
22841e3f2055SChia-Yuan Li 
22851e3f2055SChia-Yuan Li 	return 0;
22861e3f2055SChia-Yuan Li }
22871e3f2055SChia-Yuan Li 
2288b9467e94SPing-Ke Shih static int rtw89_pci_mode_op(struct rtw89_dev *rtwdev)
2289b9467e94SPing-Ke Shih {
2290b9467e94SPing-Ke Shih 	const struct rtw89_pci_info *info = rtwdev->pci_info;
2291b9467e94SPing-Ke Shih 	enum mac_ax_bd_trunc_mode txbd_trunc_mode = info->txbd_trunc_mode;
2292b9467e94SPing-Ke Shih 	enum mac_ax_bd_trunc_mode rxbd_trunc_mode = info->rxbd_trunc_mode;
2293b9467e94SPing-Ke Shih 	enum mac_ax_rxbd_mode rxbd_mode = info->rxbd_mode;
2294b9467e94SPing-Ke Shih 	enum mac_ax_tag_mode tag_mode = info->tag_mode;
2295b9467e94SPing-Ke Shih 	enum mac_ax_wd_dma_intvl wd_dma_idle_intvl = info->wd_dma_idle_intvl;
2296b9467e94SPing-Ke Shih 	enum mac_ax_wd_dma_intvl wd_dma_act_intvl = info->wd_dma_act_intvl;
2297b9467e94SPing-Ke Shih 	enum mac_ax_tx_burst tx_burst = info->tx_burst;
2298b9467e94SPing-Ke Shih 	enum mac_ax_rx_burst rx_burst = info->rx_burst;
2299b9467e94SPing-Ke Shih 	enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id;
2300b9467e94SPing-Ke Shih 	u8 cv = rtwdev->hal.cv;
2301b9467e94SPing-Ke Shih 	u32 val32;
2302b9467e94SPing-Ke Shih 
2303b9467e94SPing-Ke Shih 	if (txbd_trunc_mode == MAC_AX_BD_TRUNC) {
2304b9467e94SPing-Ke Shih 		if (chip_id == RTL8852A && cv == CHIP_CBV)
2305b9467e94SPing-Ke Shih 			rtw89_write32_set(rtwdev, R_AX_PCIE_INIT_CFG1, B_AX_TX_TRUNC_MODE);
2306b9467e94SPing-Ke Shih 	} else if (txbd_trunc_mode == MAC_AX_BD_NORM) {
2307b9467e94SPing-Ke Shih 		if (chip_id == RTL8852A || chip_id == RTL8852B)
2308b9467e94SPing-Ke Shih 			rtw89_write32_clr(rtwdev, R_AX_PCIE_INIT_CFG1, B_AX_TX_TRUNC_MODE);
2309b9467e94SPing-Ke Shih 	}
2310b9467e94SPing-Ke Shih 
2311b9467e94SPing-Ke Shih 	if (rxbd_trunc_mode == MAC_AX_BD_TRUNC) {
2312b9467e94SPing-Ke Shih 		if (chip_id == RTL8852A && cv == CHIP_CBV)
2313b9467e94SPing-Ke Shih 			rtw89_write32_set(rtwdev, R_AX_PCIE_INIT_CFG1, B_AX_RX_TRUNC_MODE);
2314b9467e94SPing-Ke Shih 	} else if (rxbd_trunc_mode == MAC_AX_BD_NORM) {
2315b9467e94SPing-Ke Shih 		if (chip_id == RTL8852A || chip_id == RTL8852B)
2316b9467e94SPing-Ke Shih 			rtw89_write32_clr(rtwdev, R_AX_PCIE_INIT_CFG1, B_AX_RX_TRUNC_MODE);
2317b9467e94SPing-Ke Shih 	}
2318b9467e94SPing-Ke Shih 
2319b9467e94SPing-Ke Shih 	if (rxbd_mode == MAC_AX_RXBD_PKT) {
2320b9467e94SPing-Ke Shih 		rtw89_write32_clr(rtwdev, info->init_cfg_reg, info->rxbd_mode_bit);
2321b9467e94SPing-Ke Shih 	} else if (rxbd_mode == MAC_AX_RXBD_SEP) {
2322b9467e94SPing-Ke Shih 		rtw89_write32_set(rtwdev, info->init_cfg_reg, info->rxbd_mode_bit);
2323b9467e94SPing-Ke Shih 
2324b9467e94SPing-Ke Shih 		if (chip_id == RTL8852A || chip_id == RTL8852B)
2325b9467e94SPing-Ke Shih 			rtw89_write32_mask(rtwdev, R_AX_PCIE_INIT_CFG2,
2326b9467e94SPing-Ke Shih 					   B_AX_PCIE_RX_APPLEN_MASK, 0);
2327b9467e94SPing-Ke Shih 	}
2328b9467e94SPing-Ke Shih 
2329b9467e94SPing-Ke Shih 	if (chip_id == RTL8852A || chip_id == RTL8852B) {
2330b9467e94SPing-Ke Shih 		rtw89_write32_mask(rtwdev, R_AX_PCIE_INIT_CFG1, B_AX_PCIE_MAX_TXDMA_MASK, tx_burst);
2331b9467e94SPing-Ke Shih 		rtw89_write32_mask(rtwdev, R_AX_PCIE_INIT_CFG1, B_AX_PCIE_MAX_RXDMA_MASK, rx_burst);
2332b9467e94SPing-Ke Shih 	} else if (chip_id == RTL8852C) {
2333b9467e94SPing-Ke Shih 		rtw89_write32_mask(rtwdev, R_AX_HAXI_INIT_CFG1, B_AX_HAXI_MAX_TXDMA_MASK, tx_burst);
2334b9467e94SPing-Ke Shih 		rtw89_write32_mask(rtwdev, R_AX_HAXI_INIT_CFG1, B_AX_HAXI_MAX_RXDMA_MASK, rx_burst);
2335b9467e94SPing-Ke Shih 	}
2336b9467e94SPing-Ke Shih 
2337b9467e94SPing-Ke Shih 	if (chip_id == RTL8852A || chip_id == RTL8852B) {
2338b9467e94SPing-Ke Shih 		if (tag_mode == MAC_AX_TAG_SGL) {
2339b9467e94SPing-Ke Shih 			val32 = rtw89_read32(rtwdev, R_AX_PCIE_INIT_CFG1) &
2340b9467e94SPing-Ke Shih 					    ~B_AX_LATENCY_CONTROL;
2341b9467e94SPing-Ke Shih 			rtw89_write32(rtwdev, R_AX_PCIE_INIT_CFG1, val32);
2342b9467e94SPing-Ke Shih 		} else if (tag_mode == MAC_AX_TAG_MULTI) {
2343b9467e94SPing-Ke Shih 			val32 = rtw89_read32(rtwdev, R_AX_PCIE_INIT_CFG1) |
2344b9467e94SPing-Ke Shih 					    B_AX_LATENCY_CONTROL;
2345b9467e94SPing-Ke Shih 			rtw89_write32(rtwdev, R_AX_PCIE_INIT_CFG1, val32);
2346b9467e94SPing-Ke Shih 		}
2347b9467e94SPing-Ke Shih 	}
2348b9467e94SPing-Ke Shih 
2349b9467e94SPing-Ke Shih 	rtw89_write32_mask(rtwdev, info->exp_ctrl_reg, info->max_tag_num_mask,
2350b9467e94SPing-Ke Shih 			   info->multi_tag_num);
2351b9467e94SPing-Ke Shih 
2352b9467e94SPing-Ke Shih 	if (chip_id == RTL8852A || chip_id == RTL8852B) {
2353b9467e94SPing-Ke Shih 		rtw89_write32_mask(rtwdev, R_AX_PCIE_INIT_CFG2, B_AX_WD_ITVL_IDLE,
2354b9467e94SPing-Ke Shih 				   wd_dma_idle_intvl);
2355b9467e94SPing-Ke Shih 		rtw89_write32_mask(rtwdev, R_AX_PCIE_INIT_CFG2, B_AX_WD_ITVL_ACT,
2356b9467e94SPing-Ke Shih 				   wd_dma_act_intvl);
2357b9467e94SPing-Ke Shih 	} else if (chip_id == RTL8852C) {
2358b9467e94SPing-Ke Shih 		rtw89_write32_mask(rtwdev, R_AX_HAXI_INIT_CFG1, B_AX_WD_ITVL_IDLE_V1_MASK,
2359b9467e94SPing-Ke Shih 				   wd_dma_idle_intvl);
2360b9467e94SPing-Ke Shih 		rtw89_write32_mask(rtwdev, R_AX_HAXI_INIT_CFG1, B_AX_WD_ITVL_ACT_V1_MASK,
2361b9467e94SPing-Ke Shih 				   wd_dma_act_intvl);
2362b9467e94SPing-Ke Shih 	}
2363b9467e94SPing-Ke Shih 
2364b9467e94SPing-Ke Shih 	if (txbd_trunc_mode == MAC_AX_BD_TRUNC) {
2365b9467e94SPing-Ke Shih 		rtw89_write32_set(rtwdev, R_AX_TX_ADDRESS_INFO_MODE_SETTING,
2366b9467e94SPing-Ke Shih 				  B_AX_HOST_ADDR_INFO_8B_SEL);
2367b9467e94SPing-Ke Shih 		rtw89_write32_clr(rtwdev, R_AX_PKTIN_SETTING, B_AX_WD_ADDR_INFO_LENGTH);
2368b9467e94SPing-Ke Shih 	} else if (txbd_trunc_mode == MAC_AX_BD_NORM) {
2369b9467e94SPing-Ke Shih 		rtw89_write32_clr(rtwdev, R_AX_TX_ADDRESS_INFO_MODE_SETTING,
2370b9467e94SPing-Ke Shih 				  B_AX_HOST_ADDR_INFO_8B_SEL);
2371b9467e94SPing-Ke Shih 		rtw89_write32_set(rtwdev, R_AX_PKTIN_SETTING, B_AX_WD_ADDR_INFO_LENGTH);
2372b9467e94SPing-Ke Shih 	}
2373b9467e94SPing-Ke Shih 
2374b9467e94SPing-Ke Shih 	return 0;
2375b9467e94SPing-Ke Shih }
2376b9467e94SPing-Ke Shih 
2377e3ec7017SPing-Ke Shih static int rtw89_pci_ops_deinit(struct rtw89_dev *rtwdev)
2378e3ec7017SPing-Ke Shih {
23790db862fbSPing-Ke Shih 	const struct rtw89_pci_info *info = rtwdev->pci_info;
23800db862fbSPing-Ke Shih 
2381e3ec7017SPing-Ke Shih 	if (rtwdev->chip->chip_id == RTL8852A) {
2382e3ec7017SPing-Ke Shih 		/* ltr sw trigger */
2383e3ec7017SPing-Ke Shih 		rtw89_write32_set(rtwdev, R_AX_LTR_CTRL_0, B_AX_APP_LTR_IDLE);
2384e3ec7017SPing-Ke Shih 	}
23850db862fbSPing-Ke Shih 	info->ltr_set(rtwdev, false);
2386e3ec7017SPing-Ke Shih 	rtw89_pci_ctrl_dma_all(rtwdev, false);
2387e3ec7017SPing-Ke Shih 	rtw89_pci_clr_idx_all(rtwdev);
2388e3ec7017SPing-Ke Shih 
2389e3ec7017SPing-Ke Shih 	return 0;
2390e3ec7017SPing-Ke Shih }
2391e3ec7017SPing-Ke Shih 
2392e3ec7017SPing-Ke Shih static int rtw89_pci_ops_mac_pre_init(struct rtw89_dev *rtwdev)
2393e3ec7017SPing-Ke Shih {
2394740c431cSPing-Ke Shih 	const struct rtw89_pci_info *info = rtwdev->pci_info;
2395e3ec7017SPing-Ke Shih 	int ret;
2396e3ec7017SPing-Ke Shih 
2397e3ec7017SPing-Ke Shih 	rtw89_pci_rxdma_prefth(rtwdev);
2398e3ec7017SPing-Ke Shih 	rtw89_pci_l1off_pwroff(rtwdev);
2399e3ec7017SPing-Ke Shih 	rtw89_pci_deglitch_setting(rtwdev);
2400e3ec7017SPing-Ke Shih 	ret = rtw89_pci_l2_rxen_lat(rtwdev);
2401e3ec7017SPing-Ke Shih 	if (ret) {
2402e3ec7017SPing-Ke Shih 		rtw89_err(rtwdev, "[ERR] pcie l2 rxen lat %d\n", ret);
2403e3ec7017SPing-Ke Shih 		return ret;
2404e3ec7017SPing-Ke Shih 	}
2405e3ec7017SPing-Ke Shih 
2406e3ec7017SPing-Ke Shih 	rtw89_pci_aphy_pwrcut(rtwdev);
2407e3ec7017SPing-Ke Shih 	rtw89_pci_hci_ldo(rtwdev);
2408740c431cSPing-Ke Shih 	rtw89_pci_dphy_delay(rtwdev);
2409e3ec7017SPing-Ke Shih 
2410e3ec7017SPing-Ke Shih 	ret = rtw89_pci_auto_refclk_cal(rtwdev, false);
2411e3ec7017SPing-Ke Shih 	if (ret) {
2412e3ec7017SPing-Ke Shih 		rtw89_err(rtwdev, "[ERR] pcie autok fail %d\n", ret);
2413e3ec7017SPing-Ke Shih 		return ret;
2414e3ec7017SPing-Ke Shih 	}
2415e3ec7017SPing-Ke Shih 
2416740c431cSPing-Ke Shih 	rtw89_pci_power_wake(rtwdev, true);
2417740c431cSPing-Ke Shih 	rtw89_pci_autoload_hang(rtwdev);
2418740c431cSPing-Ke Shih 	rtw89_pci_l12_vmain(rtwdev);
24191e3f2055SChia-Yuan Li 	rtw89_pci_gen2_force_ib(rtwdev);
2420e1e7a574SPing-Ke Shih 	rtw89_pci_l1_ent_lat(rtwdev);
2421e1e7a574SPing-Ke Shih 	rtw89_pci_wd_exit_l1(rtwdev);
2422e3ec7017SPing-Ke Shih 	rtw89_pci_set_sic(rtwdev);
24231e3f2055SChia-Yuan Li 	rtw89_pci_set_lbc(rtwdev);
2424b9467e94SPing-Ke Shih 	rtw89_pci_set_io_rcy(rtwdev);
2425e3ec7017SPing-Ke Shih 	rtw89_pci_set_dbg(rtwdev);
24261e3f2055SChia-Yuan Li 	rtw89_pci_set_keep_reg(rtwdev);
2427740c431cSPing-Ke Shih 
2428740c431cSPing-Ke Shih 	rtw89_write32_set(rtwdev, info->dma_stop1_reg, B_AX_STOP_WPDMA);
2429e3ec7017SPing-Ke Shih 
2430e3ec7017SPing-Ke Shih 	/* stop DMA activities */
2431e3ec7017SPing-Ke Shih 	rtw89_pci_ctrl_dma_all(rtwdev, false);
2432e3ec7017SPing-Ke Shih 
24331e3f2055SChia-Yuan Li 	ret = rtw89_pci_poll_dma_all_idle(rtwdev);
2434e3ec7017SPing-Ke Shih 	if (ret) {
24351e3f2055SChia-Yuan Li 		rtw89_err(rtwdev, "[ERR] poll pcie dma all idle\n");
2436e3ec7017SPing-Ke Shih 		return ret;
2437e3ec7017SPing-Ke Shih 	}
2438e3ec7017SPing-Ke Shih 
2439e3ec7017SPing-Ke Shih 	rtw89_pci_clr_idx_all(rtwdev);
2440b9467e94SPing-Ke Shih 	rtw89_pci_mode_op(rtwdev);
2441e3ec7017SPing-Ke Shih 
2442e3ec7017SPing-Ke Shih 	/* fill TRX BD indexes */
2443e3ec7017SPing-Ke Shih 	rtw89_pci_ops_reset(rtwdev);
2444e3ec7017SPing-Ke Shih 
2445e3ec7017SPing-Ke Shih 	ret = rtw89_pci_rst_bdram_pcie(rtwdev);
2446e3ec7017SPing-Ke Shih 	if (ret) {
2447e3ec7017SPing-Ke Shih 		rtw89_warn(rtwdev, "reset bdram busy\n");
2448e3ec7017SPing-Ke Shih 		return ret;
2449e3ec7017SPing-Ke Shih 	}
2450e3ec7017SPing-Ke Shih 
2451e3ec7017SPing-Ke Shih 	/* enable FW CMD queue to download firmware */
2452740c431cSPing-Ke Shih 	rtw89_write32_set(rtwdev, info->dma_stop1_reg, B_AX_TX_STOP1_ALL);
2453740c431cSPing-Ke Shih 	rtw89_write32_clr(rtwdev, info->dma_stop1_reg, B_AX_STOP_CH12);
2454740c431cSPing-Ke Shih 	rtw89_write32_set(rtwdev, info->dma_stop2_reg, B_AX_TX_STOP2_ALL);
2455e3ec7017SPing-Ke Shih 
2456e3ec7017SPing-Ke Shih 	/* start DMA activities */
2457e3ec7017SPing-Ke Shih 	rtw89_pci_ctrl_dma_all(rtwdev, true);
2458e3ec7017SPing-Ke Shih 
2459e3ec7017SPing-Ke Shih 	return 0;
2460e3ec7017SPing-Ke Shih }
2461e3ec7017SPing-Ke Shih 
24620db862fbSPing-Ke Shih int rtw89_pci_ltr_set(struct rtw89_dev *rtwdev, bool en)
2463e3ec7017SPing-Ke Shih {
2464e3ec7017SPing-Ke Shih 	u32 val;
2465e3ec7017SPing-Ke Shih 
24660db862fbSPing-Ke Shih 	if (!en)
24670db862fbSPing-Ke Shih 		return 0;
24680db862fbSPing-Ke Shih 
2469e3ec7017SPing-Ke Shih 	val = rtw89_read32(rtwdev, R_AX_LTR_CTRL_0);
2470e3ec7017SPing-Ke Shih 	if (rtw89_pci_ltr_is_err_reg_val(val))
2471e3ec7017SPing-Ke Shih 		return -EINVAL;
2472e3ec7017SPing-Ke Shih 	val = rtw89_read32(rtwdev, R_AX_LTR_CTRL_1);
2473e3ec7017SPing-Ke Shih 	if (rtw89_pci_ltr_is_err_reg_val(val))
2474e3ec7017SPing-Ke Shih 		return -EINVAL;
2475e3ec7017SPing-Ke Shih 	val = rtw89_read32(rtwdev, R_AX_LTR_IDLE_LATENCY);
2476e3ec7017SPing-Ke Shih 	if (rtw89_pci_ltr_is_err_reg_val(val))
2477e3ec7017SPing-Ke Shih 		return -EINVAL;
2478e3ec7017SPing-Ke Shih 	val = rtw89_read32(rtwdev, R_AX_LTR_ACTIVE_LATENCY);
2479e3ec7017SPing-Ke Shih 	if (rtw89_pci_ltr_is_err_reg_val(val))
2480e3ec7017SPing-Ke Shih 		return -EINVAL;
2481e3ec7017SPing-Ke Shih 
2482e3ec7017SPing-Ke Shih 	rtw89_write32_clr(rtwdev, R_AX_LTR_CTRL_0, B_AX_LTR_HW_EN);
2483e3ec7017SPing-Ke Shih 	rtw89_write32_set(rtwdev, R_AX_LTR_CTRL_0, B_AX_LTR_EN);
2484e3ec7017SPing-Ke Shih 	rtw89_write32_mask(rtwdev, R_AX_LTR_CTRL_0, B_AX_LTR_SPACE_IDX_MASK,
2485e3ec7017SPing-Ke Shih 			   PCI_LTR_SPC_500US);
2486e3ec7017SPing-Ke Shih 	rtw89_write32_mask(rtwdev, R_AX_LTR_CTRL_0, B_AX_LTR_IDLE_TIMER_IDX_MASK,
2487e3ec7017SPing-Ke Shih 			   PCI_LTR_IDLE_TIMER_800US);
2488e3ec7017SPing-Ke Shih 	rtw89_write32_mask(rtwdev, R_AX_LTR_CTRL_1, B_AX_LTR_RX0_TH_MASK, 0x28);
2489e3ec7017SPing-Ke Shih 	rtw89_write32_mask(rtwdev, R_AX_LTR_CTRL_1, B_AX_LTR_RX1_TH_MASK, 0x28);
2490e3ec7017SPing-Ke Shih 	rtw89_write32(rtwdev, R_AX_LTR_IDLE_LATENCY, 0x88e088e0);
2491e3ec7017SPing-Ke Shih 	rtw89_write32(rtwdev, R_AX_LTR_ACTIVE_LATENCY, 0x880b880b);
2492e3ec7017SPing-Ke Shih 
2493e3ec7017SPing-Ke Shih 	return 0;
2494e3ec7017SPing-Ke Shih }
24950db862fbSPing-Ke Shih EXPORT_SYMBOL(rtw89_pci_ltr_set);
24960db862fbSPing-Ke Shih 
24970db862fbSPing-Ke Shih int rtw89_pci_ltr_set_v1(struct rtw89_dev *rtwdev, bool en)
24980db862fbSPing-Ke Shih {
24990db862fbSPing-Ke Shih 	u32 dec_ctrl;
25000db862fbSPing-Ke Shih 	u32 val32;
25010db862fbSPing-Ke Shih 
25020db862fbSPing-Ke Shih 	val32 = rtw89_read32(rtwdev, R_AX_LTR_CTRL_0);
25030db862fbSPing-Ke Shih 	if (rtw89_pci_ltr_is_err_reg_val(val32))
25040db862fbSPing-Ke Shih 		return -EINVAL;
25050db862fbSPing-Ke Shih 	val32 = rtw89_read32(rtwdev, R_AX_LTR_CTRL_1);
25060db862fbSPing-Ke Shih 	if (rtw89_pci_ltr_is_err_reg_val(val32))
25070db862fbSPing-Ke Shih 		return -EINVAL;
25080db862fbSPing-Ke Shih 	dec_ctrl = rtw89_read32(rtwdev, R_AX_LTR_DEC_CTRL);
25090db862fbSPing-Ke Shih 	if (rtw89_pci_ltr_is_err_reg_val(dec_ctrl))
25100db862fbSPing-Ke Shih 		return -EINVAL;
25110db862fbSPing-Ke Shih 	val32 = rtw89_read32(rtwdev, R_AX_LTR_LATENCY_IDX3);
25120db862fbSPing-Ke Shih 	if (rtw89_pci_ltr_is_err_reg_val(val32))
25130db862fbSPing-Ke Shih 		return -EINVAL;
25140db862fbSPing-Ke Shih 	val32 = rtw89_read32(rtwdev, R_AX_LTR_LATENCY_IDX0);
25150db862fbSPing-Ke Shih 	if (rtw89_pci_ltr_is_err_reg_val(val32))
25160db862fbSPing-Ke Shih 		return -EINVAL;
25170db862fbSPing-Ke Shih 
25180db862fbSPing-Ke Shih 	if (!en) {
25190db862fbSPing-Ke Shih 		dec_ctrl &= ~(LTR_EN_BITS | B_AX_LTR_IDX_DRV_MASK | B_AX_LTR_HW_DEC_EN);
25200db862fbSPing-Ke Shih 		dec_ctrl |= FIELD_PREP(B_AX_LTR_IDX_DRV_MASK, PCIE_LTR_IDX_IDLE) |
25210db862fbSPing-Ke Shih 			    B_AX_LTR_REQ_DRV;
25220db862fbSPing-Ke Shih 	} else {
25230db862fbSPing-Ke Shih 		dec_ctrl |= B_AX_LTR_HW_DEC_EN;
25240db862fbSPing-Ke Shih 	}
25250db862fbSPing-Ke Shih 
25260db862fbSPing-Ke Shih 	dec_ctrl &= ~B_AX_LTR_SPACE_IDX_V1_MASK;
25270db862fbSPing-Ke Shih 	dec_ctrl |= FIELD_PREP(B_AX_LTR_SPACE_IDX_V1_MASK, PCI_LTR_SPC_500US);
25280db862fbSPing-Ke Shih 
25290db862fbSPing-Ke Shih 	if (en)
25300db862fbSPing-Ke Shih 		rtw89_write32_set(rtwdev, R_AX_LTR_CTRL_0,
25310db862fbSPing-Ke Shih 				  B_AX_LTR_WD_NOEMP_CHK_V1 | B_AX_LTR_HW_EN);
25320db862fbSPing-Ke Shih 	rtw89_write32_mask(rtwdev, R_AX_LTR_CTRL_0, B_AX_LTR_IDLE_TIMER_IDX_MASK,
25330db862fbSPing-Ke Shih 			   PCI_LTR_IDLE_TIMER_3_2MS);
25340db862fbSPing-Ke Shih 	rtw89_write32_mask(rtwdev, R_AX_LTR_CTRL_1, B_AX_LTR_RX0_TH_MASK, 0x28);
25350db862fbSPing-Ke Shih 	rtw89_write32_mask(rtwdev, R_AX_LTR_CTRL_1, B_AX_LTR_RX1_TH_MASK, 0x28);
25360db862fbSPing-Ke Shih 	rtw89_write32(rtwdev, R_AX_LTR_DEC_CTRL, dec_ctrl);
25370db862fbSPing-Ke Shih 	rtw89_write32(rtwdev, R_AX_LTR_LATENCY_IDX3, 0x90039003);
25380db862fbSPing-Ke Shih 	rtw89_write32(rtwdev, R_AX_LTR_LATENCY_IDX0, 0x880b880b);
25390db862fbSPing-Ke Shih 
25400db862fbSPing-Ke Shih 	return 0;
25410db862fbSPing-Ke Shih }
25420db862fbSPing-Ke Shih EXPORT_SYMBOL(rtw89_pci_ltr_set_v1);
2543e3ec7017SPing-Ke Shih 
2544e3ec7017SPing-Ke Shih static int rtw89_pci_ops_mac_post_init(struct rtw89_dev *rtwdev)
2545e3ec7017SPing-Ke Shih {
2546740c431cSPing-Ke Shih 	const struct rtw89_pci_info *info = rtwdev->pci_info;
2547bab9e239SPing-Ke Shih 	enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id;
2548e3ec7017SPing-Ke Shih 	int ret;
2549e3ec7017SPing-Ke Shih 
25500db862fbSPing-Ke Shih 	ret = info->ltr_set(rtwdev, true);
2551e3ec7017SPing-Ke Shih 	if (ret) {
2552e3ec7017SPing-Ke Shih 		rtw89_err(rtwdev, "pci ltr set fail\n");
2553e3ec7017SPing-Ke Shih 		return ret;
2554e3ec7017SPing-Ke Shih 	}
2555bab9e239SPing-Ke Shih 	if (chip_id == RTL8852A) {
2556e3ec7017SPing-Ke Shih 		/* ltr sw trigger */
2557e3ec7017SPing-Ke Shih 		rtw89_write32_set(rtwdev, R_AX_LTR_CTRL_0, B_AX_APP_LTR_ACT);
2558e3ec7017SPing-Ke Shih 	}
2559bab9e239SPing-Ke Shih 	if (chip_id == RTL8852A || chip_id == RTL8852B) {
2560e3ec7017SPing-Ke Shih 		/* ADDR info 8-byte mode */
2561e3ec7017SPing-Ke Shih 		rtw89_write32_set(rtwdev, R_AX_TX_ADDRESS_INFO_MODE_SETTING,
2562e3ec7017SPing-Ke Shih 				  B_AX_HOST_ADDR_INFO_8B_SEL);
2563e3ec7017SPing-Ke Shih 		rtw89_write32_clr(rtwdev, R_AX_PKTIN_SETTING, B_AX_WD_ADDR_INFO_LENGTH);
2564bab9e239SPing-Ke Shih 	}
2565e3ec7017SPing-Ke Shih 
2566e3ec7017SPing-Ke Shih 	/* enable DMA for all queues */
2567740c431cSPing-Ke Shih 	rtw89_write32_clr(rtwdev, info->dma_stop1_reg, B_AX_TX_STOP1_ALL);
2568740c431cSPing-Ke Shih 	rtw89_write32_clr(rtwdev, info->dma_stop2_reg, B_AX_TX_STOP2_ALL);
2569e3ec7017SPing-Ke Shih 
2570e3ec7017SPing-Ke Shih 	/* Release PCI IO */
2571740c431cSPing-Ke Shih 	rtw89_write32_clr(rtwdev, info->dma_stop1_reg,
2572e3ec7017SPing-Ke Shih 			  B_AX_STOP_WPDMA | B_AX_STOP_PCIEIO);
2573e3ec7017SPing-Ke Shih 
2574e3ec7017SPing-Ke Shih 	return 0;
2575e3ec7017SPing-Ke Shih }
2576e3ec7017SPing-Ke Shih 
2577e3ec7017SPing-Ke Shih static int rtw89_pci_claim_device(struct rtw89_dev *rtwdev,
2578e3ec7017SPing-Ke Shih 				  struct pci_dev *pdev)
2579e3ec7017SPing-Ke Shih {
2580e3ec7017SPing-Ke Shih 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
2581e3ec7017SPing-Ke Shih 	int ret;
2582e3ec7017SPing-Ke Shih 
2583e3ec7017SPing-Ke Shih 	ret = pci_enable_device(pdev);
2584e3ec7017SPing-Ke Shih 	if (ret) {
2585e3ec7017SPing-Ke Shih 		rtw89_err(rtwdev, "failed to enable pci device\n");
2586e3ec7017SPing-Ke Shih 		return ret;
2587e3ec7017SPing-Ke Shih 	}
2588e3ec7017SPing-Ke Shih 
2589e3ec7017SPing-Ke Shih 	pci_set_master(pdev);
2590e3ec7017SPing-Ke Shih 	pci_set_drvdata(pdev, rtwdev->hw);
2591e3ec7017SPing-Ke Shih 
2592e3ec7017SPing-Ke Shih 	rtwpci->pdev = pdev;
2593e3ec7017SPing-Ke Shih 
2594e3ec7017SPing-Ke Shih 	return 0;
2595e3ec7017SPing-Ke Shih }
2596e3ec7017SPing-Ke Shih 
2597e3ec7017SPing-Ke Shih static void rtw89_pci_declaim_device(struct rtw89_dev *rtwdev,
2598e3ec7017SPing-Ke Shih 				     struct pci_dev *pdev)
2599e3ec7017SPing-Ke Shih {
2600e3ec7017SPing-Ke Shih 	pci_clear_master(pdev);
2601e3ec7017SPing-Ke Shih 	pci_disable_device(pdev);
2602e3ec7017SPing-Ke Shih }
2603e3ec7017SPing-Ke Shih 
2604e3ec7017SPing-Ke Shih static int rtw89_pci_setup_mapping(struct rtw89_dev *rtwdev,
2605e3ec7017SPing-Ke Shih 				   struct pci_dev *pdev)
2606e3ec7017SPing-Ke Shih {
2607e3ec7017SPing-Ke Shih 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
2608e3ec7017SPing-Ke Shih 	unsigned long resource_len;
2609e3ec7017SPing-Ke Shih 	u8 bar_id = 2;
2610e3ec7017SPing-Ke Shih 	int ret;
2611e3ec7017SPing-Ke Shih 
2612e3ec7017SPing-Ke Shih 	ret = pci_request_regions(pdev, KBUILD_MODNAME);
2613e3ec7017SPing-Ke Shih 	if (ret) {
2614e3ec7017SPing-Ke Shih 		rtw89_err(rtwdev, "failed to request pci regions\n");
2615e3ec7017SPing-Ke Shih 		goto err;
2616e3ec7017SPing-Ke Shih 	}
2617e3ec7017SPing-Ke Shih 
2618e3ec7017SPing-Ke Shih 	ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
2619e3ec7017SPing-Ke Shih 	if (ret) {
2620e3ec7017SPing-Ke Shih 		rtw89_err(rtwdev, "failed to set dma mask to 32-bit\n");
2621e3ec7017SPing-Ke Shih 		goto err_release_regions;
2622e3ec7017SPing-Ke Shih 	}
2623e3ec7017SPing-Ke Shih 
2624e3ec7017SPing-Ke Shih 	ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
2625e3ec7017SPing-Ke Shih 	if (ret) {
2626e3ec7017SPing-Ke Shih 		rtw89_err(rtwdev, "failed to set consistent dma mask to 32-bit\n");
2627e3ec7017SPing-Ke Shih 		goto err_release_regions;
2628e3ec7017SPing-Ke Shih 	}
2629e3ec7017SPing-Ke Shih 
2630e3ec7017SPing-Ke Shih 	resource_len = pci_resource_len(pdev, bar_id);
2631e3ec7017SPing-Ke Shih 	rtwpci->mmap = pci_iomap(pdev, bar_id, resource_len);
2632e3ec7017SPing-Ke Shih 	if (!rtwpci->mmap) {
2633e3ec7017SPing-Ke Shih 		rtw89_err(rtwdev, "failed to map pci io\n");
2634e3ec7017SPing-Ke Shih 		ret = -EIO;
2635e3ec7017SPing-Ke Shih 		goto err_release_regions;
2636e3ec7017SPing-Ke Shih 	}
2637e3ec7017SPing-Ke Shih 
2638e3ec7017SPing-Ke Shih 	return 0;
2639e3ec7017SPing-Ke Shih 
2640e3ec7017SPing-Ke Shih err_release_regions:
2641e3ec7017SPing-Ke Shih 	pci_release_regions(pdev);
2642e3ec7017SPing-Ke Shih err:
2643e3ec7017SPing-Ke Shih 	return ret;
2644e3ec7017SPing-Ke Shih }
2645e3ec7017SPing-Ke Shih 
2646e3ec7017SPing-Ke Shih static void rtw89_pci_clear_mapping(struct rtw89_dev *rtwdev,
2647e3ec7017SPing-Ke Shih 				    struct pci_dev *pdev)
2648e3ec7017SPing-Ke Shih {
2649e3ec7017SPing-Ke Shih 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
2650e3ec7017SPing-Ke Shih 
2651e3ec7017SPing-Ke Shih 	if (rtwpci->mmap) {
2652e3ec7017SPing-Ke Shih 		pci_iounmap(pdev, rtwpci->mmap);
2653e3ec7017SPing-Ke Shih 		pci_release_regions(pdev);
2654e3ec7017SPing-Ke Shih 	}
2655e3ec7017SPing-Ke Shih }
2656e3ec7017SPing-Ke Shih 
2657e3ec7017SPing-Ke Shih static void rtw89_pci_free_tx_wd_ring(struct rtw89_dev *rtwdev,
2658e3ec7017SPing-Ke Shih 				      struct pci_dev *pdev,
2659e3ec7017SPing-Ke Shih 				      struct rtw89_pci_tx_ring *tx_ring)
2660e3ec7017SPing-Ke Shih {
2661e3ec7017SPing-Ke Shih 	struct rtw89_pci_tx_wd_ring *wd_ring = &tx_ring->wd_ring;
2662e3ec7017SPing-Ke Shih 	u8 *head = wd_ring->head;
2663e3ec7017SPing-Ke Shih 	dma_addr_t dma = wd_ring->dma;
2664e3ec7017SPing-Ke Shih 	u32 page_size = wd_ring->page_size;
2665e3ec7017SPing-Ke Shih 	u32 page_num = wd_ring->page_num;
2666e3ec7017SPing-Ke Shih 	u32 ring_sz = page_size * page_num;
2667e3ec7017SPing-Ke Shih 
2668e3ec7017SPing-Ke Shih 	dma_free_coherent(&pdev->dev, ring_sz, head, dma);
2669e3ec7017SPing-Ke Shih 	wd_ring->head = NULL;
2670e3ec7017SPing-Ke Shih }
2671e3ec7017SPing-Ke Shih 
2672e3ec7017SPing-Ke Shih static void rtw89_pci_free_tx_ring(struct rtw89_dev *rtwdev,
2673e3ec7017SPing-Ke Shih 				   struct pci_dev *pdev,
2674e3ec7017SPing-Ke Shih 				   struct rtw89_pci_tx_ring *tx_ring)
2675e3ec7017SPing-Ke Shih {
2676e3ec7017SPing-Ke Shih 	int ring_sz;
2677e3ec7017SPing-Ke Shih 	u8 *head;
2678e3ec7017SPing-Ke Shih 	dma_addr_t dma;
2679e3ec7017SPing-Ke Shih 
2680e3ec7017SPing-Ke Shih 	head = tx_ring->bd_ring.head;
2681e3ec7017SPing-Ke Shih 	dma = tx_ring->bd_ring.dma;
2682e3ec7017SPing-Ke Shih 	ring_sz = tx_ring->bd_ring.desc_size * tx_ring->bd_ring.len;
2683e3ec7017SPing-Ke Shih 	dma_free_coherent(&pdev->dev, ring_sz, head, dma);
2684e3ec7017SPing-Ke Shih 
2685e3ec7017SPing-Ke Shih 	tx_ring->bd_ring.head = NULL;
2686e3ec7017SPing-Ke Shih }
2687e3ec7017SPing-Ke Shih 
2688e3ec7017SPing-Ke Shih static void rtw89_pci_free_tx_rings(struct rtw89_dev *rtwdev,
2689e3ec7017SPing-Ke Shih 				    struct pci_dev *pdev)
2690e3ec7017SPing-Ke Shih {
2691e3ec7017SPing-Ke Shih 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
2692e3ec7017SPing-Ke Shih 	struct rtw89_pci_tx_ring *tx_ring;
2693e3ec7017SPing-Ke Shih 	int i;
2694e3ec7017SPing-Ke Shih 
2695e3ec7017SPing-Ke Shih 	for (i = 0; i < RTW89_TXCH_NUM; i++) {
2696e3ec7017SPing-Ke Shih 		tx_ring = &rtwpci->tx_rings[i];
2697e3ec7017SPing-Ke Shih 		rtw89_pci_free_tx_wd_ring(rtwdev, pdev, tx_ring);
2698e3ec7017SPing-Ke Shih 		rtw89_pci_free_tx_ring(rtwdev, pdev, tx_ring);
2699e3ec7017SPing-Ke Shih 	}
2700e3ec7017SPing-Ke Shih }
2701e3ec7017SPing-Ke Shih 
2702e3ec7017SPing-Ke Shih static void rtw89_pci_free_rx_ring(struct rtw89_dev *rtwdev,
2703e3ec7017SPing-Ke Shih 				   struct pci_dev *pdev,
2704e3ec7017SPing-Ke Shih 				   struct rtw89_pci_rx_ring *rx_ring)
2705e3ec7017SPing-Ke Shih {
2706e3ec7017SPing-Ke Shih 	struct rtw89_pci_rx_info *rx_info;
2707e3ec7017SPing-Ke Shih 	struct sk_buff *skb;
2708e3ec7017SPing-Ke Shih 	dma_addr_t dma;
2709e3ec7017SPing-Ke Shih 	u32 buf_sz;
2710e3ec7017SPing-Ke Shih 	u8 *head;
2711e3ec7017SPing-Ke Shih 	int ring_sz = rx_ring->bd_ring.desc_size * rx_ring->bd_ring.len;
2712e3ec7017SPing-Ke Shih 	int i;
2713e3ec7017SPing-Ke Shih 
2714e3ec7017SPing-Ke Shih 	buf_sz = rx_ring->buf_sz;
2715e3ec7017SPing-Ke Shih 	for (i = 0; i < rx_ring->bd_ring.len; i++) {
2716e3ec7017SPing-Ke Shih 		skb = rx_ring->buf[i];
2717e3ec7017SPing-Ke Shih 		if (!skb)
2718e3ec7017SPing-Ke Shih 			continue;
2719e3ec7017SPing-Ke Shih 
2720e3ec7017SPing-Ke Shih 		rx_info = RTW89_PCI_RX_SKB_CB(skb);
2721e3ec7017SPing-Ke Shih 		dma = rx_info->dma;
2722e3ec7017SPing-Ke Shih 		dma_unmap_single(&pdev->dev, dma, buf_sz, DMA_FROM_DEVICE);
2723e3ec7017SPing-Ke Shih 		dev_kfree_skb(skb);
2724e3ec7017SPing-Ke Shih 		rx_ring->buf[i] = NULL;
2725e3ec7017SPing-Ke Shih 	}
2726e3ec7017SPing-Ke Shih 
2727e3ec7017SPing-Ke Shih 	head = rx_ring->bd_ring.head;
2728e3ec7017SPing-Ke Shih 	dma = rx_ring->bd_ring.dma;
2729e3ec7017SPing-Ke Shih 	dma_free_coherent(&pdev->dev, ring_sz, head, dma);
2730e3ec7017SPing-Ke Shih 
2731e3ec7017SPing-Ke Shih 	rx_ring->bd_ring.head = NULL;
2732e3ec7017SPing-Ke Shih }
2733e3ec7017SPing-Ke Shih 
2734e3ec7017SPing-Ke Shih static void rtw89_pci_free_rx_rings(struct rtw89_dev *rtwdev,
2735e3ec7017SPing-Ke Shih 				    struct pci_dev *pdev)
2736e3ec7017SPing-Ke Shih {
2737e3ec7017SPing-Ke Shih 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
2738e3ec7017SPing-Ke Shih 	struct rtw89_pci_rx_ring *rx_ring;
2739e3ec7017SPing-Ke Shih 	int i;
2740e3ec7017SPing-Ke Shih 
2741e3ec7017SPing-Ke Shih 	for (i = 0; i < RTW89_RXCH_NUM; i++) {
2742e3ec7017SPing-Ke Shih 		rx_ring = &rtwpci->rx_rings[i];
2743e3ec7017SPing-Ke Shih 		rtw89_pci_free_rx_ring(rtwdev, pdev, rx_ring);
2744e3ec7017SPing-Ke Shih 	}
2745e3ec7017SPing-Ke Shih }
2746e3ec7017SPing-Ke Shih 
2747e3ec7017SPing-Ke Shih static void rtw89_pci_free_trx_rings(struct rtw89_dev *rtwdev,
2748e3ec7017SPing-Ke Shih 				     struct pci_dev *pdev)
2749e3ec7017SPing-Ke Shih {
2750e3ec7017SPing-Ke Shih 	rtw89_pci_free_rx_rings(rtwdev, pdev);
2751e3ec7017SPing-Ke Shih 	rtw89_pci_free_tx_rings(rtwdev, pdev);
2752e3ec7017SPing-Ke Shih }
2753e3ec7017SPing-Ke Shih 
2754e3ec7017SPing-Ke Shih static int rtw89_pci_init_rx_bd(struct rtw89_dev *rtwdev, struct pci_dev *pdev,
2755e3ec7017SPing-Ke Shih 				struct rtw89_pci_rx_ring *rx_ring,
2756e3ec7017SPing-Ke Shih 				struct sk_buff *skb, int buf_sz, u32 idx)
2757e3ec7017SPing-Ke Shih {
2758e3ec7017SPing-Ke Shih 	struct rtw89_pci_rx_info *rx_info;
2759e3ec7017SPing-Ke Shih 	struct rtw89_pci_rx_bd_32 *rx_bd;
2760e3ec7017SPing-Ke Shih 	dma_addr_t dma;
2761e3ec7017SPing-Ke Shih 
2762e3ec7017SPing-Ke Shih 	if (!skb)
2763e3ec7017SPing-Ke Shih 		return -EINVAL;
2764e3ec7017SPing-Ke Shih 
2765e3ec7017SPing-Ke Shih 	dma = dma_map_single(&pdev->dev, skb->data, buf_sz, DMA_FROM_DEVICE);
2766e3ec7017SPing-Ke Shih 	if (dma_mapping_error(&pdev->dev, dma))
2767e3ec7017SPing-Ke Shih 		return -EBUSY;
2768e3ec7017SPing-Ke Shih 
2769e3ec7017SPing-Ke Shih 	rx_info = RTW89_PCI_RX_SKB_CB(skb);
2770e3ec7017SPing-Ke Shih 	rx_bd = RTW89_PCI_RX_BD(rx_ring, idx);
2771e3ec7017SPing-Ke Shih 
2772e3ec7017SPing-Ke Shih 	memset(rx_bd, 0, sizeof(*rx_bd));
2773e3ec7017SPing-Ke Shih 	rx_bd->buf_size = cpu_to_le16(buf_sz);
2774e3ec7017SPing-Ke Shih 	rx_bd->dma = cpu_to_le32(dma);
2775e3ec7017SPing-Ke Shih 	rx_info->dma = dma;
2776e3ec7017SPing-Ke Shih 
2777e3ec7017SPing-Ke Shih 	return 0;
2778e3ec7017SPing-Ke Shih }
2779e3ec7017SPing-Ke Shih 
2780e3ec7017SPing-Ke Shih static int rtw89_pci_alloc_tx_wd_ring(struct rtw89_dev *rtwdev,
2781e3ec7017SPing-Ke Shih 				      struct pci_dev *pdev,
2782e3ec7017SPing-Ke Shih 				      struct rtw89_pci_tx_ring *tx_ring,
2783e3ec7017SPing-Ke Shih 				      enum rtw89_tx_channel txch)
2784e3ec7017SPing-Ke Shih {
2785e3ec7017SPing-Ke Shih 	struct rtw89_pci_tx_wd_ring *wd_ring = &tx_ring->wd_ring;
2786e3ec7017SPing-Ke Shih 	struct rtw89_pci_tx_wd *txwd;
2787e3ec7017SPing-Ke Shih 	dma_addr_t dma;
2788e3ec7017SPing-Ke Shih 	dma_addr_t cur_paddr;
2789e3ec7017SPing-Ke Shih 	u8 *head;
2790e3ec7017SPing-Ke Shih 	u8 *cur_vaddr;
2791e3ec7017SPing-Ke Shih 	u32 page_size = RTW89_PCI_TXWD_PAGE_SIZE;
2792e3ec7017SPing-Ke Shih 	u32 page_num = RTW89_PCI_TXWD_NUM_MAX;
2793e3ec7017SPing-Ke Shih 	u32 ring_sz = page_size * page_num;
2794e3ec7017SPing-Ke Shih 	u32 page_offset;
2795e3ec7017SPing-Ke Shih 	int i;
2796e3ec7017SPing-Ke Shih 
2797e3ec7017SPing-Ke Shih 	/* FWCMD queue doesn't use txwd as pages */
2798e3ec7017SPing-Ke Shih 	if (txch == RTW89_TXCH_CH12)
2799e3ec7017SPing-Ke Shih 		return 0;
2800e3ec7017SPing-Ke Shih 
2801e3ec7017SPing-Ke Shih 	head = dma_alloc_coherent(&pdev->dev, ring_sz, &dma, GFP_KERNEL);
2802e3ec7017SPing-Ke Shih 	if (!head)
2803e3ec7017SPing-Ke Shih 		return -ENOMEM;
2804e3ec7017SPing-Ke Shih 
2805e3ec7017SPing-Ke Shih 	INIT_LIST_HEAD(&wd_ring->free_pages);
2806e3ec7017SPing-Ke Shih 	wd_ring->head = head;
2807e3ec7017SPing-Ke Shih 	wd_ring->dma = dma;
2808e3ec7017SPing-Ke Shih 	wd_ring->page_size = page_size;
2809e3ec7017SPing-Ke Shih 	wd_ring->page_num = page_num;
2810e3ec7017SPing-Ke Shih 
2811e3ec7017SPing-Ke Shih 	page_offset = 0;
2812e3ec7017SPing-Ke Shih 	for (i = 0; i < page_num; i++) {
2813e3ec7017SPing-Ke Shih 		txwd = &wd_ring->pages[i];
2814e3ec7017SPing-Ke Shih 		cur_paddr = dma + page_offset;
2815e3ec7017SPing-Ke Shih 		cur_vaddr = head + page_offset;
2816e3ec7017SPing-Ke Shih 
2817e3ec7017SPing-Ke Shih 		skb_queue_head_init(&txwd->queue);
2818e3ec7017SPing-Ke Shih 		INIT_LIST_HEAD(&txwd->list);
2819e3ec7017SPing-Ke Shih 		txwd->paddr = cur_paddr;
2820e3ec7017SPing-Ke Shih 		txwd->vaddr = cur_vaddr;
2821e3ec7017SPing-Ke Shih 		txwd->len = page_size;
2822e3ec7017SPing-Ke Shih 		txwd->seq = i;
2823e3ec7017SPing-Ke Shih 		rtw89_pci_enqueue_txwd(tx_ring, txwd);
2824e3ec7017SPing-Ke Shih 
2825e3ec7017SPing-Ke Shih 		page_offset += page_size;
2826e3ec7017SPing-Ke Shih 	}
2827e3ec7017SPing-Ke Shih 
2828e3ec7017SPing-Ke Shih 	return 0;
2829e3ec7017SPing-Ke Shih }
2830e3ec7017SPing-Ke Shih 
2831e3ec7017SPing-Ke Shih static int rtw89_pci_alloc_tx_ring(struct rtw89_dev *rtwdev,
2832e3ec7017SPing-Ke Shih 				   struct pci_dev *pdev,
2833e3ec7017SPing-Ke Shih 				   struct rtw89_pci_tx_ring *tx_ring,
2834e3ec7017SPing-Ke Shih 				   u32 desc_size, u32 len,
2835e3ec7017SPing-Ke Shih 				   enum rtw89_tx_channel txch)
2836e3ec7017SPing-Ke Shih {
283797d61bf9SPing-Ke Shih 	const struct rtw89_pci_ch_dma_addr *txch_addr;
2838e3ec7017SPing-Ke Shih 	int ring_sz = desc_size * len;
2839e3ec7017SPing-Ke Shih 	u8 *head;
2840e3ec7017SPing-Ke Shih 	dma_addr_t dma;
2841e3ec7017SPing-Ke Shih 	int ret;
2842e3ec7017SPing-Ke Shih 
2843e3ec7017SPing-Ke Shih 	ret = rtw89_pci_alloc_tx_wd_ring(rtwdev, pdev, tx_ring, txch);
2844e3ec7017SPing-Ke Shih 	if (ret) {
2845e3ec7017SPing-Ke Shih 		rtw89_err(rtwdev, "failed to alloc txwd ring of txch %d\n", txch);
2846e3ec7017SPing-Ke Shih 		goto err;
2847e3ec7017SPing-Ke Shih 	}
2848e3ec7017SPing-Ke Shih 
284997d61bf9SPing-Ke Shih 	ret = rtw89_pci_get_txch_addrs(rtwdev, txch, &txch_addr);
2850e3ec7017SPing-Ke Shih 	if (ret) {
2851e3ec7017SPing-Ke Shih 		rtw89_err(rtwdev, "failed to get address of txch %d", txch);
2852e3ec7017SPing-Ke Shih 		goto err_free_wd_ring;
2853e3ec7017SPing-Ke Shih 	}
2854e3ec7017SPing-Ke Shih 
2855e3ec7017SPing-Ke Shih 	head = dma_alloc_coherent(&pdev->dev, ring_sz, &dma, GFP_KERNEL);
2856e3ec7017SPing-Ke Shih 	if (!head) {
2857e3ec7017SPing-Ke Shih 		ret = -ENOMEM;
2858e3ec7017SPing-Ke Shih 		goto err_free_wd_ring;
2859e3ec7017SPing-Ke Shih 	}
2860e3ec7017SPing-Ke Shih 
2861e3ec7017SPing-Ke Shih 	INIT_LIST_HEAD(&tx_ring->busy_pages);
2862e3ec7017SPing-Ke Shih 	tx_ring->bd_ring.head = head;
2863e3ec7017SPing-Ke Shih 	tx_ring->bd_ring.dma = dma;
2864e3ec7017SPing-Ke Shih 	tx_ring->bd_ring.len = len;
2865e3ec7017SPing-Ke Shih 	tx_ring->bd_ring.desc_size = desc_size;
2866e4133f26SPing-Ke Shih 	tx_ring->bd_ring.addr = *txch_addr;
2867e3ec7017SPing-Ke Shih 	tx_ring->bd_ring.wp = 0;
2868e3ec7017SPing-Ke Shih 	tx_ring->bd_ring.rp = 0;
2869e3ec7017SPing-Ke Shih 	tx_ring->txch = txch;
2870e3ec7017SPing-Ke Shih 
2871e3ec7017SPing-Ke Shih 	return 0;
2872e3ec7017SPing-Ke Shih 
2873e3ec7017SPing-Ke Shih err_free_wd_ring:
2874e3ec7017SPing-Ke Shih 	rtw89_pci_free_tx_wd_ring(rtwdev, pdev, tx_ring);
2875e3ec7017SPing-Ke Shih err:
2876e3ec7017SPing-Ke Shih 	return ret;
2877e3ec7017SPing-Ke Shih }
2878e3ec7017SPing-Ke Shih 
2879e3ec7017SPing-Ke Shih static int rtw89_pci_alloc_tx_rings(struct rtw89_dev *rtwdev,
2880e3ec7017SPing-Ke Shih 				    struct pci_dev *pdev)
2881e3ec7017SPing-Ke Shih {
2882e3ec7017SPing-Ke Shih 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
2883e3ec7017SPing-Ke Shih 	struct rtw89_pci_tx_ring *tx_ring;
2884e3ec7017SPing-Ke Shih 	u32 desc_size;
2885e3ec7017SPing-Ke Shih 	u32 len;
2886e3ec7017SPing-Ke Shih 	u32 i, tx_allocated;
2887e3ec7017SPing-Ke Shih 	int ret;
2888e3ec7017SPing-Ke Shih 
2889e3ec7017SPing-Ke Shih 	for (i = 0; i < RTW89_TXCH_NUM; i++) {
2890e3ec7017SPing-Ke Shih 		tx_ring = &rtwpci->tx_rings[i];
2891e3ec7017SPing-Ke Shih 		desc_size = sizeof(struct rtw89_pci_tx_bd_32);
2892e3ec7017SPing-Ke Shih 		len = RTW89_PCI_TXBD_NUM_MAX;
2893e3ec7017SPing-Ke Shih 		ret = rtw89_pci_alloc_tx_ring(rtwdev, pdev, tx_ring,
2894e3ec7017SPing-Ke Shih 					      desc_size, len, i);
2895e3ec7017SPing-Ke Shih 		if (ret) {
2896e3ec7017SPing-Ke Shih 			rtw89_err(rtwdev, "failed to alloc tx ring %d\n", i);
2897e3ec7017SPing-Ke Shih 			goto err_free;
2898e3ec7017SPing-Ke Shih 		}
2899e3ec7017SPing-Ke Shih 	}
2900e3ec7017SPing-Ke Shih 
2901e3ec7017SPing-Ke Shih 	return 0;
2902e3ec7017SPing-Ke Shih 
2903e3ec7017SPing-Ke Shih err_free:
2904e3ec7017SPing-Ke Shih 	tx_allocated = i;
2905e3ec7017SPing-Ke Shih 	for (i = 0; i < tx_allocated; i++) {
2906e3ec7017SPing-Ke Shih 		tx_ring = &rtwpci->tx_rings[i];
2907e3ec7017SPing-Ke Shih 		rtw89_pci_free_tx_ring(rtwdev, pdev, tx_ring);
2908e3ec7017SPing-Ke Shih 	}
2909e3ec7017SPing-Ke Shih 
2910e3ec7017SPing-Ke Shih 	return ret;
2911e3ec7017SPing-Ke Shih }
2912e3ec7017SPing-Ke Shih 
2913e3ec7017SPing-Ke Shih static int rtw89_pci_alloc_rx_ring(struct rtw89_dev *rtwdev,
2914e3ec7017SPing-Ke Shih 				   struct pci_dev *pdev,
2915e3ec7017SPing-Ke Shih 				   struct rtw89_pci_rx_ring *rx_ring,
2916e3ec7017SPing-Ke Shih 				   u32 desc_size, u32 len, u32 rxch)
2917e3ec7017SPing-Ke Shih {
291897d61bf9SPing-Ke Shih 	const struct rtw89_pci_ch_dma_addr *rxch_addr;
2919e3ec7017SPing-Ke Shih 	struct sk_buff *skb;
2920e3ec7017SPing-Ke Shih 	u8 *head;
2921e3ec7017SPing-Ke Shih 	dma_addr_t dma;
2922e3ec7017SPing-Ke Shih 	int ring_sz = desc_size * len;
2923e3ec7017SPing-Ke Shih 	int buf_sz = RTW89_PCI_RX_BUF_SIZE;
2924e3ec7017SPing-Ke Shih 	int i, allocated;
2925e3ec7017SPing-Ke Shih 	int ret;
2926e3ec7017SPing-Ke Shih 
292797d61bf9SPing-Ke Shih 	ret = rtw89_pci_get_rxch_addrs(rtwdev, rxch, &rxch_addr);
2928e3ec7017SPing-Ke Shih 	if (ret) {
2929e3ec7017SPing-Ke Shih 		rtw89_err(rtwdev, "failed to get address of rxch %d", rxch);
2930e3ec7017SPing-Ke Shih 		return ret;
2931e3ec7017SPing-Ke Shih 	}
2932e3ec7017SPing-Ke Shih 
2933e3ec7017SPing-Ke Shih 	head = dma_alloc_coherent(&pdev->dev, ring_sz, &dma, GFP_KERNEL);
2934e3ec7017SPing-Ke Shih 	if (!head) {
2935e3ec7017SPing-Ke Shih 		ret = -ENOMEM;
2936e3ec7017SPing-Ke Shih 		goto err;
2937e3ec7017SPing-Ke Shih 	}
2938e3ec7017SPing-Ke Shih 
2939e3ec7017SPing-Ke Shih 	rx_ring->bd_ring.head = head;
2940e3ec7017SPing-Ke Shih 	rx_ring->bd_ring.dma = dma;
2941e3ec7017SPing-Ke Shih 	rx_ring->bd_ring.len = len;
2942e3ec7017SPing-Ke Shih 	rx_ring->bd_ring.desc_size = desc_size;
2943e4133f26SPing-Ke Shih 	rx_ring->bd_ring.addr = *rxch_addr;
2944e3ec7017SPing-Ke Shih 	rx_ring->bd_ring.wp = 0;
2945e3ec7017SPing-Ke Shih 	rx_ring->bd_ring.rp = 0;
2946e3ec7017SPing-Ke Shih 	rx_ring->buf_sz = buf_sz;
2947e3ec7017SPing-Ke Shih 	rx_ring->diliver_skb = NULL;
2948e3ec7017SPing-Ke Shih 	rx_ring->diliver_desc.ready = false;
2949e3ec7017SPing-Ke Shih 
2950e3ec7017SPing-Ke Shih 	for (i = 0; i < len; i++) {
2951e3ec7017SPing-Ke Shih 		skb = dev_alloc_skb(buf_sz);
2952e3ec7017SPing-Ke Shih 		if (!skb) {
2953e3ec7017SPing-Ke Shih 			ret = -ENOMEM;
2954e3ec7017SPing-Ke Shih 			goto err_free;
2955e3ec7017SPing-Ke Shih 		}
2956e3ec7017SPing-Ke Shih 
2957e3ec7017SPing-Ke Shih 		memset(skb->data, 0, buf_sz);
2958e3ec7017SPing-Ke Shih 		rx_ring->buf[i] = skb;
2959e3ec7017SPing-Ke Shih 		ret = rtw89_pci_init_rx_bd(rtwdev, pdev, rx_ring, skb,
2960e3ec7017SPing-Ke Shih 					   buf_sz, i);
2961e3ec7017SPing-Ke Shih 		if (ret) {
2962e3ec7017SPing-Ke Shih 			rtw89_err(rtwdev, "failed to init rx buf %d\n", i);
2963e3ec7017SPing-Ke Shih 			dev_kfree_skb_any(skb);
2964e3ec7017SPing-Ke Shih 			rx_ring->buf[i] = NULL;
2965e3ec7017SPing-Ke Shih 			goto err_free;
2966e3ec7017SPing-Ke Shih 		}
2967e3ec7017SPing-Ke Shih 	}
2968e3ec7017SPing-Ke Shih 
2969e3ec7017SPing-Ke Shih 	return 0;
2970e3ec7017SPing-Ke Shih 
2971e3ec7017SPing-Ke Shih err_free:
2972e3ec7017SPing-Ke Shih 	allocated = i;
2973e3ec7017SPing-Ke Shih 	for (i = 0; i < allocated; i++) {
2974e3ec7017SPing-Ke Shih 		skb = rx_ring->buf[i];
2975e3ec7017SPing-Ke Shih 		if (!skb)
2976e3ec7017SPing-Ke Shih 			continue;
2977e3ec7017SPing-Ke Shih 		dma = *((dma_addr_t *)skb->cb);
2978e3ec7017SPing-Ke Shih 		dma_unmap_single(&pdev->dev, dma, buf_sz, DMA_FROM_DEVICE);
2979e3ec7017SPing-Ke Shih 		dev_kfree_skb(skb);
2980e3ec7017SPing-Ke Shih 		rx_ring->buf[i] = NULL;
2981e3ec7017SPing-Ke Shih 	}
2982e3ec7017SPing-Ke Shih 
2983e3ec7017SPing-Ke Shih 	head = rx_ring->bd_ring.head;
2984e3ec7017SPing-Ke Shih 	dma = rx_ring->bd_ring.dma;
2985e3ec7017SPing-Ke Shih 	dma_free_coherent(&pdev->dev, ring_sz, head, dma);
2986e3ec7017SPing-Ke Shih 
2987e3ec7017SPing-Ke Shih 	rx_ring->bd_ring.head = NULL;
2988e3ec7017SPing-Ke Shih err:
2989e3ec7017SPing-Ke Shih 	return ret;
2990e3ec7017SPing-Ke Shih }
2991e3ec7017SPing-Ke Shih 
2992e3ec7017SPing-Ke Shih static int rtw89_pci_alloc_rx_rings(struct rtw89_dev *rtwdev,
2993e3ec7017SPing-Ke Shih 				    struct pci_dev *pdev)
2994e3ec7017SPing-Ke Shih {
2995e3ec7017SPing-Ke Shih 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
2996e3ec7017SPing-Ke Shih 	struct rtw89_pci_rx_ring *rx_ring;
2997e3ec7017SPing-Ke Shih 	u32 desc_size;
2998e3ec7017SPing-Ke Shih 	u32 len;
2999e3ec7017SPing-Ke Shih 	int i, rx_allocated;
3000e3ec7017SPing-Ke Shih 	int ret;
3001e3ec7017SPing-Ke Shih 
3002e3ec7017SPing-Ke Shih 	for (i = 0; i < RTW89_RXCH_NUM; i++) {
3003e3ec7017SPing-Ke Shih 		rx_ring = &rtwpci->rx_rings[i];
3004e3ec7017SPing-Ke Shih 		desc_size = sizeof(struct rtw89_pci_rx_bd_32);
3005e3ec7017SPing-Ke Shih 		len = RTW89_PCI_RXBD_NUM_MAX;
3006e3ec7017SPing-Ke Shih 		ret = rtw89_pci_alloc_rx_ring(rtwdev, pdev, rx_ring,
3007e3ec7017SPing-Ke Shih 					      desc_size, len, i);
3008e3ec7017SPing-Ke Shih 		if (ret) {
3009e3ec7017SPing-Ke Shih 			rtw89_err(rtwdev, "failed to alloc rx ring %d\n", i);
3010e3ec7017SPing-Ke Shih 			goto err_free;
3011e3ec7017SPing-Ke Shih 		}
3012e3ec7017SPing-Ke Shih 	}
3013e3ec7017SPing-Ke Shih 
3014e3ec7017SPing-Ke Shih 	return 0;
3015e3ec7017SPing-Ke Shih 
3016e3ec7017SPing-Ke Shih err_free:
3017e3ec7017SPing-Ke Shih 	rx_allocated = i;
3018e3ec7017SPing-Ke Shih 	for (i = 0; i < rx_allocated; i++) {
3019e3ec7017SPing-Ke Shih 		rx_ring = &rtwpci->rx_rings[i];
3020e3ec7017SPing-Ke Shih 		rtw89_pci_free_rx_ring(rtwdev, pdev, rx_ring);
3021e3ec7017SPing-Ke Shih 	}
3022e3ec7017SPing-Ke Shih 
3023e3ec7017SPing-Ke Shih 	return ret;
3024e3ec7017SPing-Ke Shih }
3025e3ec7017SPing-Ke Shih 
3026e3ec7017SPing-Ke Shih static int rtw89_pci_alloc_trx_rings(struct rtw89_dev *rtwdev,
3027e3ec7017SPing-Ke Shih 				     struct pci_dev *pdev)
3028e3ec7017SPing-Ke Shih {
3029e3ec7017SPing-Ke Shih 	int ret;
3030e3ec7017SPing-Ke Shih 
3031e3ec7017SPing-Ke Shih 	ret = rtw89_pci_alloc_tx_rings(rtwdev, pdev);
3032e3ec7017SPing-Ke Shih 	if (ret) {
3033e3ec7017SPing-Ke Shih 		rtw89_err(rtwdev, "failed to alloc dma tx rings\n");
3034e3ec7017SPing-Ke Shih 		goto err;
3035e3ec7017SPing-Ke Shih 	}
3036e3ec7017SPing-Ke Shih 
3037e3ec7017SPing-Ke Shih 	ret = rtw89_pci_alloc_rx_rings(rtwdev, pdev);
3038e3ec7017SPing-Ke Shih 	if (ret) {
3039e3ec7017SPing-Ke Shih 		rtw89_err(rtwdev, "failed to alloc dma rx rings\n");
3040e3ec7017SPing-Ke Shih 		goto err_free_tx_rings;
3041e3ec7017SPing-Ke Shih 	}
3042e3ec7017SPing-Ke Shih 
3043e3ec7017SPing-Ke Shih 	return 0;
3044e3ec7017SPing-Ke Shih 
3045e3ec7017SPing-Ke Shih err_free_tx_rings:
3046e3ec7017SPing-Ke Shih 	rtw89_pci_free_tx_rings(rtwdev, pdev);
3047e3ec7017SPing-Ke Shih err:
3048e3ec7017SPing-Ke Shih 	return ret;
3049e3ec7017SPing-Ke Shih }
3050e3ec7017SPing-Ke Shih 
3051e3ec7017SPing-Ke Shih static void rtw89_pci_h2c_init(struct rtw89_dev *rtwdev,
3052e3ec7017SPing-Ke Shih 			       struct rtw89_pci *rtwpci)
3053e3ec7017SPing-Ke Shih {
3054e3ec7017SPing-Ke Shih 	skb_queue_head_init(&rtwpci->h2c_queue);
3055e3ec7017SPing-Ke Shih 	skb_queue_head_init(&rtwpci->h2c_release_queue);
3056e3ec7017SPing-Ke Shih }
3057e3ec7017SPing-Ke Shih 
3058e3ec7017SPing-Ke Shih static int rtw89_pci_setup_resource(struct rtw89_dev *rtwdev,
3059e3ec7017SPing-Ke Shih 				    struct pci_dev *pdev)
3060e3ec7017SPing-Ke Shih {
3061e3ec7017SPing-Ke Shih 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
3062e3ec7017SPing-Ke Shih 	int ret;
3063e3ec7017SPing-Ke Shih 
3064e3ec7017SPing-Ke Shih 	ret = rtw89_pci_setup_mapping(rtwdev, pdev);
3065e3ec7017SPing-Ke Shih 	if (ret) {
3066e3ec7017SPing-Ke Shih 		rtw89_err(rtwdev, "failed to setup pci mapping\n");
3067e3ec7017SPing-Ke Shih 		goto err;
3068e3ec7017SPing-Ke Shih 	}
3069e3ec7017SPing-Ke Shih 
3070e3ec7017SPing-Ke Shih 	ret = rtw89_pci_alloc_trx_rings(rtwdev, pdev);
3071e3ec7017SPing-Ke Shih 	if (ret) {
3072e3ec7017SPing-Ke Shih 		rtw89_err(rtwdev, "failed to alloc pci trx rings\n");
3073e3ec7017SPing-Ke Shih 		goto err_pci_unmap;
3074e3ec7017SPing-Ke Shih 	}
3075e3ec7017SPing-Ke Shih 
3076e3ec7017SPing-Ke Shih 	rtw89_pci_h2c_init(rtwdev, rtwpci);
3077e3ec7017SPing-Ke Shih 
3078e3ec7017SPing-Ke Shih 	spin_lock_init(&rtwpci->irq_lock);
3079e3ec7017SPing-Ke Shih 	spin_lock_init(&rtwpci->trx_lock);
3080e3ec7017SPing-Ke Shih 
3081e3ec7017SPing-Ke Shih 	return 0;
3082e3ec7017SPing-Ke Shih 
3083e3ec7017SPing-Ke Shih err_pci_unmap:
3084e3ec7017SPing-Ke Shih 	rtw89_pci_clear_mapping(rtwdev, pdev);
3085e3ec7017SPing-Ke Shih err:
3086e3ec7017SPing-Ke Shih 	return ret;
3087e3ec7017SPing-Ke Shih }
3088e3ec7017SPing-Ke Shih 
3089e3ec7017SPing-Ke Shih static void rtw89_pci_clear_resource(struct rtw89_dev *rtwdev,
3090e3ec7017SPing-Ke Shih 				     struct pci_dev *pdev)
3091e3ec7017SPing-Ke Shih {
3092e3ec7017SPing-Ke Shih 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
3093e3ec7017SPing-Ke Shih 
3094e3ec7017SPing-Ke Shih 	rtw89_pci_free_trx_rings(rtwdev, pdev);
3095e3ec7017SPing-Ke Shih 	rtw89_pci_clear_mapping(rtwdev, pdev);
3096e3ec7017SPing-Ke Shih 	rtw89_pci_release_fwcmd(rtwdev, rtwpci,
3097e3ec7017SPing-Ke Shih 				skb_queue_len(&rtwpci->h2c_queue), true);
3098e3ec7017SPing-Ke Shih }
3099e3ec7017SPing-Ke Shih 
3100948e521cSPing-Ke Shih void rtw89_pci_config_intr_mask(struct rtw89_dev *rtwdev)
3101e3ec7017SPing-Ke Shih {
3102e3ec7017SPing-Ke Shih 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
3103e3ec7017SPing-Ke Shih 
3104e3ec7017SPing-Ke Shih 	rtwpci->halt_c2h_intrs = B_AX_HALT_C2H_INT_EN | 0;
3105948e521cSPing-Ke Shih 
3106948e521cSPing-Ke Shih 	if (rtwpci->under_recovery) {
3107948e521cSPing-Ke Shih 		rtwpci->intrs[0] = 0;
3108948e521cSPing-Ke Shih 		rtwpci->intrs[1] = 0;
3109948e521cSPing-Ke Shih 	} else {
3110e3ec7017SPing-Ke Shih 		rtwpci->intrs[0] = B_AX_TXDMA_STUCK_INT_EN |
3111e3ec7017SPing-Ke Shih 				   B_AX_RXDMA_INT_EN |
3112e3ec7017SPing-Ke Shih 				   B_AX_RXP1DMA_INT_EN |
3113e3ec7017SPing-Ke Shih 				   B_AX_RPQDMA_INT_EN |
3114e3ec7017SPing-Ke Shih 				   B_AX_RXDMA_STUCK_INT_EN |
3115e3ec7017SPing-Ke Shih 				   B_AX_RDU_INT_EN |
3116e3ec7017SPing-Ke Shih 				   B_AX_RPQBD_FULL_INT_EN |
3117e3ec7017SPing-Ke Shih 				   B_AX_HS0ISR_IND_INT_EN;
3118e3ec7017SPing-Ke Shih 
3119e3ec7017SPing-Ke Shih 		rtwpci->intrs[1] = B_AX_HC10ISR_IND_INT_EN;
3120e3ec7017SPing-Ke Shih 	}
3121948e521cSPing-Ke Shih }
3122948e521cSPing-Ke Shih EXPORT_SYMBOL(rtw89_pci_config_intr_mask);
3123948e521cSPing-Ke Shih 
3124948e521cSPing-Ke Shih static void rtw89_pci_recovery_intr_mask_v1(struct rtw89_dev *rtwdev)
3125948e521cSPing-Ke Shih {
3126948e521cSPing-Ke Shih 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
3127948e521cSPing-Ke Shih 
3128948e521cSPing-Ke Shih 	rtwpci->ind_intrs = B_AX_HS0ISR_IND_INT_EN;
3129948e521cSPing-Ke Shih 	rtwpci->halt_c2h_intrs = B_AX_HALT_C2H_INT_EN;
3130948e521cSPing-Ke Shih 	rtwpci->intrs[0] = 0;
3131948e521cSPing-Ke Shih 	rtwpci->intrs[1] = 0;
3132948e521cSPing-Ke Shih }
3133948e521cSPing-Ke Shih 
3134948e521cSPing-Ke Shih static void rtw89_pci_default_intr_mask_v1(struct rtw89_dev *rtwdev)
3135948e521cSPing-Ke Shih {
3136948e521cSPing-Ke Shih 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
3137948e521cSPing-Ke Shih 
3138948e521cSPing-Ke Shih 	rtwpci->ind_intrs = B_AX_HCI_AXIDMA_INT_EN |
3139948e521cSPing-Ke Shih 			    B_AX_HS1ISR_IND_INT_EN |
3140948e521cSPing-Ke Shih 			    B_AX_HS0ISR_IND_INT_EN;
3141948e521cSPing-Ke Shih 	rtwpci->halt_c2h_intrs = B_AX_HALT_C2H_INT_EN;
3142948e521cSPing-Ke Shih 	rtwpci->intrs[0] = B_AX_TXDMA_STUCK_INT_EN |
3143948e521cSPing-Ke Shih 			   B_AX_RXDMA_INT_EN |
3144948e521cSPing-Ke Shih 			   B_AX_RXP1DMA_INT_EN |
3145948e521cSPing-Ke Shih 			   B_AX_RPQDMA_INT_EN |
3146948e521cSPing-Ke Shih 			   B_AX_RXDMA_STUCK_INT_EN |
3147948e521cSPing-Ke Shih 			   B_AX_RDU_INT_EN |
3148948e521cSPing-Ke Shih 			   B_AX_RPQBD_FULL_INT_EN;
3149948e521cSPing-Ke Shih 	rtwpci->intrs[1] = B_AX_GPIO18_INT_EN;
3150948e521cSPing-Ke Shih }
3151948e521cSPing-Ke Shih 
3152948e521cSPing-Ke Shih static void rtw89_pci_low_power_intr_mask_v1(struct rtw89_dev *rtwdev)
3153948e521cSPing-Ke Shih {
3154948e521cSPing-Ke Shih 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
3155948e521cSPing-Ke Shih 
3156948e521cSPing-Ke Shih 	rtwpci->ind_intrs = B_AX_HS1ISR_IND_INT_EN |
3157948e521cSPing-Ke Shih 			    B_AX_HS0ISR_IND_INT_EN;
3158948e521cSPing-Ke Shih 	rtwpci->halt_c2h_intrs = B_AX_HALT_C2H_INT_EN;
3159948e521cSPing-Ke Shih 	rtwpci->intrs[0] = 0;
3160948e521cSPing-Ke Shih 	rtwpci->intrs[1] = B_AX_GPIO18_INT_EN;
3161948e521cSPing-Ke Shih }
3162948e521cSPing-Ke Shih 
3163948e521cSPing-Ke Shih void rtw89_pci_config_intr_mask_v1(struct rtw89_dev *rtwdev)
3164948e521cSPing-Ke Shih {
3165948e521cSPing-Ke Shih 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
3166948e521cSPing-Ke Shih 
3167948e521cSPing-Ke Shih 	if (rtwpci->under_recovery)
3168948e521cSPing-Ke Shih 		rtw89_pci_recovery_intr_mask_v1(rtwdev);
3169948e521cSPing-Ke Shih 	else if (rtwpci->low_power)
3170948e521cSPing-Ke Shih 		rtw89_pci_low_power_intr_mask_v1(rtwdev);
3171948e521cSPing-Ke Shih 	else
3172948e521cSPing-Ke Shih 		rtw89_pci_default_intr_mask_v1(rtwdev);
3173948e521cSPing-Ke Shih }
3174948e521cSPing-Ke Shih EXPORT_SYMBOL(rtw89_pci_config_intr_mask_v1);
3175e3ec7017SPing-Ke Shih 
3176e3ec7017SPing-Ke Shih static int rtw89_pci_request_irq(struct rtw89_dev *rtwdev,
3177e3ec7017SPing-Ke Shih 				 struct pci_dev *pdev)
3178e3ec7017SPing-Ke Shih {
3179e3ec7017SPing-Ke Shih 	unsigned long flags = 0;
3180e3ec7017SPing-Ke Shih 	int ret;
3181e3ec7017SPing-Ke Shih 
3182e3ec7017SPing-Ke Shih 	flags |= PCI_IRQ_LEGACY | PCI_IRQ_MSI;
3183e3ec7017SPing-Ke Shih 	ret = pci_alloc_irq_vectors(pdev, 1, 1, flags);
3184e3ec7017SPing-Ke Shih 	if (ret < 0) {
3185e3ec7017SPing-Ke Shih 		rtw89_err(rtwdev, "failed to alloc irq vectors, ret %d\n", ret);
3186e3ec7017SPing-Ke Shih 		goto err;
3187e3ec7017SPing-Ke Shih 	}
3188e3ec7017SPing-Ke Shih 
3189e3ec7017SPing-Ke Shih 	ret = devm_request_threaded_irq(rtwdev->dev, pdev->irq,
3190e3ec7017SPing-Ke Shih 					rtw89_pci_interrupt_handler,
3191e3ec7017SPing-Ke Shih 					rtw89_pci_interrupt_threadfn,
3192e3ec7017SPing-Ke Shih 					IRQF_SHARED, KBUILD_MODNAME, rtwdev);
3193e3ec7017SPing-Ke Shih 	if (ret) {
3194e3ec7017SPing-Ke Shih 		rtw89_err(rtwdev, "failed to request threaded irq\n");
3195e3ec7017SPing-Ke Shih 		goto err_free_vector;
3196e3ec7017SPing-Ke Shih 	}
3197e3ec7017SPing-Ke Shih 
3198948e521cSPing-Ke Shih 	rtw89_chip_config_intr_mask(rtwdev, RTW89_PCI_INTR_MASK_RESET);
3199e3ec7017SPing-Ke Shih 
3200e3ec7017SPing-Ke Shih 	return 0;
3201e3ec7017SPing-Ke Shih 
3202e3ec7017SPing-Ke Shih err_free_vector:
3203e3ec7017SPing-Ke Shih 	pci_free_irq_vectors(pdev);
3204e3ec7017SPing-Ke Shih err:
3205e3ec7017SPing-Ke Shih 	return ret;
3206e3ec7017SPing-Ke Shih }
3207e3ec7017SPing-Ke Shih 
3208e3ec7017SPing-Ke Shih static void rtw89_pci_free_irq(struct rtw89_dev *rtwdev,
3209e3ec7017SPing-Ke Shih 			       struct pci_dev *pdev)
3210e3ec7017SPing-Ke Shih {
3211e3ec7017SPing-Ke Shih 	devm_free_irq(rtwdev->dev, pdev->irq, rtwdev);
3212e3ec7017SPing-Ke Shih 	pci_free_irq_vectors(pdev);
3213e3ec7017SPing-Ke Shih }
3214e3ec7017SPing-Ke Shih 
3215e3ec7017SPing-Ke Shih static void rtw89_pci_clkreq_set(struct rtw89_dev *rtwdev, bool enable)
3216e3ec7017SPing-Ke Shih {
3217e3ec7017SPing-Ke Shih 	int ret;
3218e3ec7017SPing-Ke Shih 
3219e3ec7017SPing-Ke Shih 	if (rtw89_pci_disable_clkreq)
3220e3ec7017SPing-Ke Shih 		return;
3221e3ec7017SPing-Ke Shih 
3222db38d9cdSChin-Yen Lee 	ret = rtw89_pci_write_config_byte(rtwdev, RTW89_PCIE_CLK_CTRL,
3223e3ec7017SPing-Ke Shih 					  PCIE_CLKDLY_HW_30US);
3224e3ec7017SPing-Ke Shih 	if (ret)
3225e3ec7017SPing-Ke Shih 		rtw89_err(rtwdev, "failed to set CLKREQ Delay\n");
3226e3ec7017SPing-Ke Shih 
3227e3ec7017SPing-Ke Shih 	if (enable)
3228db38d9cdSChin-Yen Lee 		ret = rtw89_pci_config_byte_set(rtwdev, RTW89_PCIE_L1_CTRL,
3229e3ec7017SPing-Ke Shih 						RTW89_PCIE_BIT_CLK);
3230e3ec7017SPing-Ke Shih 	else
3231db38d9cdSChin-Yen Lee 		ret = rtw89_pci_config_byte_clr(rtwdev, RTW89_PCIE_L1_CTRL,
3232e3ec7017SPing-Ke Shih 						RTW89_PCIE_BIT_CLK);
3233e3ec7017SPing-Ke Shih 	if (ret)
3234e3ec7017SPing-Ke Shih 		rtw89_err(rtwdev, "failed to %s CLKREQ_L1, ret=%d",
3235e3ec7017SPing-Ke Shih 			  enable ? "set" : "unset", ret);
3236e3ec7017SPing-Ke Shih }
3237e3ec7017SPing-Ke Shih 
3238e3ec7017SPing-Ke Shih static void rtw89_pci_aspm_set(struct rtw89_dev *rtwdev, bool enable)
3239e3ec7017SPing-Ke Shih {
3240e3ec7017SPing-Ke Shih 	u8 value = 0;
3241e3ec7017SPing-Ke Shih 	int ret;
3242e3ec7017SPing-Ke Shih 
3243e3ec7017SPing-Ke Shih 	if (rtw89_pci_disable_aspm_l1)
3244e3ec7017SPing-Ke Shih 		return;
3245e3ec7017SPing-Ke Shih 
3246db38d9cdSChin-Yen Lee 	ret = rtw89_pci_read_config_byte(rtwdev, RTW89_PCIE_ASPM_CTRL, &value);
3247e3ec7017SPing-Ke Shih 	if (ret)
3248e3ec7017SPing-Ke Shih 		rtw89_err(rtwdev, "failed to read ASPM Delay\n");
3249e3ec7017SPing-Ke Shih 
3250e3ec7017SPing-Ke Shih 	value &= ~(RTW89_L1DLY_MASK | RTW89_L0DLY_MASK);
3251e3ec7017SPing-Ke Shih 	value |= FIELD_PREP(RTW89_L1DLY_MASK, PCIE_L1DLY_16US) |
3252e3ec7017SPing-Ke Shih 		 FIELD_PREP(RTW89_L0DLY_MASK, PCIE_L0SDLY_4US);
3253e3ec7017SPing-Ke Shih 
3254db38d9cdSChin-Yen Lee 	ret = rtw89_pci_write_config_byte(rtwdev, RTW89_PCIE_ASPM_CTRL, value);
3255e3ec7017SPing-Ke Shih 	if (ret)
3256e3ec7017SPing-Ke Shih 		rtw89_err(rtwdev, "failed to read ASPM Delay\n");
3257e3ec7017SPing-Ke Shih 
3258e3ec7017SPing-Ke Shih 	if (enable)
3259db38d9cdSChin-Yen Lee 		ret = rtw89_pci_config_byte_set(rtwdev, RTW89_PCIE_L1_CTRL,
3260e3ec7017SPing-Ke Shih 						RTW89_PCIE_BIT_L1);
3261e3ec7017SPing-Ke Shih 	else
3262db38d9cdSChin-Yen Lee 		ret = rtw89_pci_config_byte_clr(rtwdev, RTW89_PCIE_L1_CTRL,
3263e3ec7017SPing-Ke Shih 						RTW89_PCIE_BIT_L1);
3264e3ec7017SPing-Ke Shih 	if (ret)
3265e3ec7017SPing-Ke Shih 		rtw89_err(rtwdev, "failed to %s ASPM L1, ret=%d",
3266e3ec7017SPing-Ke Shih 			  enable ? "set" : "unset", ret);
3267e3ec7017SPing-Ke Shih }
3268e3ec7017SPing-Ke Shih 
3269e3ec7017SPing-Ke Shih static void rtw89_pci_recalc_int_mit(struct rtw89_dev *rtwdev)
3270e3ec7017SPing-Ke Shih {
3271e3ec7017SPing-Ke Shih 	struct rtw89_traffic_stats *stats = &rtwdev->stats;
3272e3ec7017SPing-Ke Shih 	enum rtw89_tfc_lv tx_tfc_lv = stats->tx_tfc_lv;
3273e3ec7017SPing-Ke Shih 	enum rtw89_tfc_lv rx_tfc_lv = stats->rx_tfc_lv;
3274e3ec7017SPing-Ke Shih 	u32 val = 0;
3275e3ec7017SPing-Ke Shih 
3276e3ec7017SPing-Ke Shih 	if (!rtwdev->scanning &&
3277e3ec7017SPing-Ke Shih 	    (tx_tfc_lv >= RTW89_TFC_HIGH || rx_tfc_lv >= RTW89_TFC_HIGH))
3278e3ec7017SPing-Ke Shih 		val = B_AX_RXMIT_RXP2_SEL | B_AX_RXMIT_RXP1_SEL |
3279e3ec7017SPing-Ke Shih 		      FIELD_PREP(B_AX_RXCOUNTER_MATCH_MASK, RTW89_PCI_RXBD_NUM_MAX / 2) |
3280e3ec7017SPing-Ke Shih 		      FIELD_PREP(B_AX_RXTIMER_UNIT_MASK, AX_RXTIMER_UNIT_64US) |
3281e3ec7017SPing-Ke Shih 		      FIELD_PREP(B_AX_RXTIMER_MATCH_MASK, 2048 / 64);
3282e3ec7017SPing-Ke Shih 
3283e3ec7017SPing-Ke Shih 	rtw89_write32(rtwdev, R_AX_INT_MIT_RX, val);
3284e3ec7017SPing-Ke Shih }
3285e3ec7017SPing-Ke Shih 
3286e3ec7017SPing-Ke Shih static void rtw89_pci_link_cfg(struct rtw89_dev *rtwdev)
3287e3ec7017SPing-Ke Shih {
3288e3ec7017SPing-Ke Shih 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
3289e3ec7017SPing-Ke Shih 	struct pci_dev *pdev = rtwpci->pdev;
3290e3ec7017SPing-Ke Shih 	u16 link_ctrl;
3291e3ec7017SPing-Ke Shih 	int ret;
3292e3ec7017SPing-Ke Shih 
3293e3ec7017SPing-Ke Shih 	/* Though there is standard PCIE configuration space to set the
3294e3ec7017SPing-Ke Shih 	 * link control register, but by Realtek's design, driver should
3295e3ec7017SPing-Ke Shih 	 * check if host supports CLKREQ/ASPM to enable the HW module.
3296e3ec7017SPing-Ke Shih 	 *
3297e3ec7017SPing-Ke Shih 	 * These functions are implemented by two HW modules associated,
3298e3ec7017SPing-Ke Shih 	 * one is responsible to access PCIE configuration space to
3299e3ec7017SPing-Ke Shih 	 * follow the host settings, and another is in charge of doing
3300e3ec7017SPing-Ke Shih 	 * CLKREQ/ASPM mechanisms, it is default disabled. Because sometimes
3301e3ec7017SPing-Ke Shih 	 * the host does not support it, and due to some reasons or wrong
3302e3ec7017SPing-Ke Shih 	 * settings (ex. CLKREQ# not Bi-Direction), it could lead to device
3303e3ec7017SPing-Ke Shih 	 * loss if HW misbehaves on the link.
3304e3ec7017SPing-Ke Shih 	 *
3305e3ec7017SPing-Ke Shih 	 * Hence it's designed that driver should first check the PCIE
3306e3ec7017SPing-Ke Shih 	 * configuration space is sync'ed and enabled, then driver can turn
3307e3ec7017SPing-Ke Shih 	 * on the other module that is actually working on the mechanism.
3308e3ec7017SPing-Ke Shih 	 */
3309e3ec7017SPing-Ke Shih 	ret = pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &link_ctrl);
3310e3ec7017SPing-Ke Shih 	if (ret) {
3311e3ec7017SPing-Ke Shih 		rtw89_err(rtwdev, "failed to read PCI cap, ret=%d\n", ret);
3312e3ec7017SPing-Ke Shih 		return;
3313e3ec7017SPing-Ke Shih 	}
3314e3ec7017SPing-Ke Shih 
3315e3ec7017SPing-Ke Shih 	if (link_ctrl & PCI_EXP_LNKCTL_CLKREQ_EN)
3316e3ec7017SPing-Ke Shih 		rtw89_pci_clkreq_set(rtwdev, true);
3317e3ec7017SPing-Ke Shih 
3318e3ec7017SPing-Ke Shih 	if (link_ctrl & PCI_EXP_LNKCTL_ASPM_L1)
3319e3ec7017SPing-Ke Shih 		rtw89_pci_aspm_set(rtwdev, true);
3320e3ec7017SPing-Ke Shih }
3321e3ec7017SPing-Ke Shih 
3322e3ec7017SPing-Ke Shih static void rtw89_pci_l1ss_set(struct rtw89_dev *rtwdev, bool enable)
3323e3ec7017SPing-Ke Shih {
3324e3ec7017SPing-Ke Shih 	int ret;
3325e3ec7017SPing-Ke Shih 
3326e3ec7017SPing-Ke Shih 	if (enable)
3327db38d9cdSChin-Yen Lee 		ret = rtw89_pci_config_byte_set(rtwdev, RTW89_PCIE_TIMER_CTRL,
3328e3ec7017SPing-Ke Shih 						RTW89_PCIE_BIT_L1SUB);
3329e3ec7017SPing-Ke Shih 	else
3330db38d9cdSChin-Yen Lee 		ret = rtw89_pci_config_byte_clr(rtwdev, RTW89_PCIE_TIMER_CTRL,
3331e3ec7017SPing-Ke Shih 						RTW89_PCIE_BIT_L1SUB);
3332e3ec7017SPing-Ke Shih 	if (ret)
3333e3ec7017SPing-Ke Shih 		rtw89_err(rtwdev, "failed to %s L1SS, ret=%d",
3334e3ec7017SPing-Ke Shih 			  enable ? "set" : "unset", ret);
3335e3ec7017SPing-Ke Shih }
3336e3ec7017SPing-Ke Shih 
3337e3ec7017SPing-Ke Shih static void rtw89_pci_l1ss_cfg(struct rtw89_dev *rtwdev)
3338e3ec7017SPing-Ke Shih {
3339e3ec7017SPing-Ke Shih 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
3340e3ec7017SPing-Ke Shih 	struct pci_dev *pdev = rtwpci->pdev;
3341e3ec7017SPing-Ke Shih 	u32 l1ss_cap_ptr, l1ss_ctrl;
3342e3ec7017SPing-Ke Shih 
3343e3ec7017SPing-Ke Shih 	if (rtw89_pci_disable_l1ss)
3344e3ec7017SPing-Ke Shih 		return;
3345e3ec7017SPing-Ke Shih 
3346e3ec7017SPing-Ke Shih 	l1ss_cap_ptr = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_L1SS);
3347e3ec7017SPing-Ke Shih 	if (!l1ss_cap_ptr)
3348e3ec7017SPing-Ke Shih 		return;
3349e3ec7017SPing-Ke Shih 
3350e3ec7017SPing-Ke Shih 	pci_read_config_dword(pdev, l1ss_cap_ptr + PCI_L1SS_CTL1, &l1ss_ctrl);
3351e3ec7017SPing-Ke Shih 
3352e3ec7017SPing-Ke Shih 	if (l1ss_ctrl & PCI_L1SS_CTL1_L1SS_MASK)
3353e3ec7017SPing-Ke Shih 		rtw89_pci_l1ss_set(rtwdev, true);
3354e3ec7017SPing-Ke Shih }
3355e3ec7017SPing-Ke Shih 
3356e3ec7017SPing-Ke Shih static void rtw89_pci_ctrl_dma_all_pcie(struct rtw89_dev *rtwdev, u8 en)
3357e3ec7017SPing-Ke Shih {
3358740c431cSPing-Ke Shih 	const struct rtw89_pci_info *info = rtwdev->pci_info;
3359e3ec7017SPing-Ke Shih 	u32 val32;
3360e3ec7017SPing-Ke Shih 
3361e3ec7017SPing-Ke Shih 	if (en == MAC_AX_FUNC_EN) {
3362e3ec7017SPing-Ke Shih 		val32 = B_AX_STOP_PCIEIO;
3363740c431cSPing-Ke Shih 		rtw89_write32_clr(rtwdev, info->dma_stop1_reg, val32);
3364e3ec7017SPing-Ke Shih 
3365e3ec7017SPing-Ke Shih 		val32 = B_AX_TXHCI_EN | B_AX_RXHCI_EN;
3366e3ec7017SPing-Ke Shih 		rtw89_write32_set(rtwdev, R_AX_PCIE_INIT_CFG1, val32);
3367e3ec7017SPing-Ke Shih 	} else {
3368e3ec7017SPing-Ke Shih 		val32 = B_AX_STOP_PCIEIO;
3369740c431cSPing-Ke Shih 		rtw89_write32_set(rtwdev, info->dma_stop1_reg, val32);
3370e3ec7017SPing-Ke Shih 
3371e3ec7017SPing-Ke Shih 		val32 = B_AX_TXHCI_EN | B_AX_RXHCI_EN;
3372e3ec7017SPing-Ke Shih 		rtw89_write32_clr(rtwdev, R_AX_PCIE_INIT_CFG1, val32);
3373e3ec7017SPing-Ke Shih 	}
3374e3ec7017SPing-Ke Shih }
3375e3ec7017SPing-Ke Shih 
3376e3ec7017SPing-Ke Shih static int rtw89_pci_poll_io_idle(struct rtw89_dev *rtwdev)
3377e3ec7017SPing-Ke Shih {
3378e3ec7017SPing-Ke Shih 	int ret = 0;
3379e3ec7017SPing-Ke Shih 	u32 sts;
3380e3ec7017SPing-Ke Shih 	u32 busy = B_AX_PCIEIO_BUSY | B_AX_PCIEIO_TX_BUSY | B_AX_PCIEIO_RX_BUSY;
3381e3ec7017SPing-Ke Shih 
3382e3ec7017SPing-Ke Shih 	ret = read_poll_timeout_atomic(rtw89_read32, sts, (sts & busy) == 0x0,
3383e3ec7017SPing-Ke Shih 				       10, 1000, false, rtwdev,
3384e3ec7017SPing-Ke Shih 				       R_AX_PCIE_DMA_BUSY1);
3385e3ec7017SPing-Ke Shih 	if (ret) {
3386e3ec7017SPing-Ke Shih 		rtw89_err(rtwdev, "pci dmach busy1 0x%X\n",
3387e3ec7017SPing-Ke Shih 			  rtw89_read32(rtwdev, R_AX_PCIE_DMA_BUSY1));
3388e3ec7017SPing-Ke Shih 		return -EINVAL;
3389e3ec7017SPing-Ke Shih 	}
3390e3ec7017SPing-Ke Shih 	return ret;
3391e3ec7017SPing-Ke Shih }
3392e3ec7017SPing-Ke Shih 
3393e3ec7017SPing-Ke Shih static int rtw89_pci_lv1rst_stop_dma(struct rtw89_dev *rtwdev)
3394e3ec7017SPing-Ke Shih {
3395e3ec7017SPing-Ke Shih 	u32 val, dma_rst = 0;
3396e3ec7017SPing-Ke Shih 	int ret;
3397e3ec7017SPing-Ke Shih 
3398e3ec7017SPing-Ke Shih 	rtw89_pci_ctrl_dma_all_pcie(rtwdev, MAC_AX_FUNC_DIS);
3399e3ec7017SPing-Ke Shih 	ret = rtw89_pci_poll_io_idle(rtwdev);
3400e3ec7017SPing-Ke Shih 	if (ret) {
3401e3ec7017SPing-Ke Shih 		val = rtw89_read32(rtwdev, R_AX_DBG_ERR_FLAG);
3402e3ec7017SPing-Ke Shih 		rtw89_debug(rtwdev, RTW89_DBG_HCI,
3403e3ec7017SPing-Ke Shih 			    "[PCIe] poll_io_idle fail, before 0x%08x: 0x%08x\n",
3404e3ec7017SPing-Ke Shih 			    R_AX_DBG_ERR_FLAG, val);
3405e3ec7017SPing-Ke Shih 		if (val & B_AX_TX_STUCK || val & B_AX_PCIE_TXBD_LEN0)
3406e3ec7017SPing-Ke Shih 			dma_rst |= B_AX_HCI_TXDMA_EN;
3407e3ec7017SPing-Ke Shih 		if (val & B_AX_RX_STUCK)
3408e3ec7017SPing-Ke Shih 			dma_rst |= B_AX_HCI_RXDMA_EN;
3409e3ec7017SPing-Ke Shih 		val = rtw89_read32(rtwdev, R_AX_HCI_FUNC_EN);
3410e3ec7017SPing-Ke Shih 		rtw89_write32(rtwdev, R_AX_HCI_FUNC_EN, val & ~dma_rst);
3411e3ec7017SPing-Ke Shih 		rtw89_write32(rtwdev, R_AX_HCI_FUNC_EN, val | dma_rst);
3412e3ec7017SPing-Ke Shih 		ret = rtw89_pci_poll_io_idle(rtwdev);
3413e3ec7017SPing-Ke Shih 		val = rtw89_read32(rtwdev, R_AX_DBG_ERR_FLAG);
3414e3ec7017SPing-Ke Shih 		rtw89_debug(rtwdev, RTW89_DBG_HCI,
3415e3ec7017SPing-Ke Shih 			    "[PCIe] poll_io_idle fail, after 0x%08x: 0x%08x\n",
3416e3ec7017SPing-Ke Shih 			    R_AX_DBG_ERR_FLAG, val);
3417e3ec7017SPing-Ke Shih 	}
3418e3ec7017SPing-Ke Shih 
3419e3ec7017SPing-Ke Shih 	return ret;
3420e3ec7017SPing-Ke Shih }
3421e3ec7017SPing-Ke Shih 
3422e3ec7017SPing-Ke Shih static void rtw89_pci_ctrl_hci_dma_en(struct rtw89_dev *rtwdev, u8 en)
3423e3ec7017SPing-Ke Shih {
3424e3ec7017SPing-Ke Shih 	u32 val32;
3425e3ec7017SPing-Ke Shih 
3426e3ec7017SPing-Ke Shih 	if (en == MAC_AX_FUNC_EN) {
3427e3ec7017SPing-Ke Shih 		val32 = B_AX_HCI_TXDMA_EN | B_AX_HCI_RXDMA_EN;
3428e3ec7017SPing-Ke Shih 		rtw89_write32_set(rtwdev, R_AX_HCI_FUNC_EN, val32);
3429e3ec7017SPing-Ke Shih 	} else {
3430e3ec7017SPing-Ke Shih 		val32 = B_AX_HCI_TXDMA_EN | B_AX_HCI_RXDMA_EN;
3431e3ec7017SPing-Ke Shih 		rtw89_write32_clr(rtwdev, R_AX_HCI_FUNC_EN, val32);
3432e3ec7017SPing-Ke Shih 	}
3433e3ec7017SPing-Ke Shih }
3434e3ec7017SPing-Ke Shih 
3435e3ec7017SPing-Ke Shih static int rtw89_pci_rst_bdram(struct rtw89_dev *rtwdev)
3436e3ec7017SPing-Ke Shih {
3437e3ec7017SPing-Ke Shih 	int ret = 0;
3438e3ec7017SPing-Ke Shih 	u32 val32, sts;
3439e3ec7017SPing-Ke Shih 
3440e3ec7017SPing-Ke Shih 	val32 = B_AX_RST_BDRAM;
3441e3ec7017SPing-Ke Shih 	rtw89_write32_set(rtwdev, R_AX_PCIE_INIT_CFG1, val32);
3442e3ec7017SPing-Ke Shih 
3443e3ec7017SPing-Ke Shih 	ret = read_poll_timeout_atomic(rtw89_read32, sts,
3444e3ec7017SPing-Ke Shih 				       (sts & B_AX_RST_BDRAM) == 0x0, 1, 100,
3445e3ec7017SPing-Ke Shih 				       true, rtwdev, R_AX_PCIE_INIT_CFG1);
3446e3ec7017SPing-Ke Shih 	return ret;
3447e3ec7017SPing-Ke Shih }
3448e3ec7017SPing-Ke Shih 
3449e3ec7017SPing-Ke Shih static int rtw89_pci_lv1rst_start_dma(struct rtw89_dev *rtwdev)
3450e3ec7017SPing-Ke Shih {
3451e3ec7017SPing-Ke Shih 	u32 ret;
3452e3ec7017SPing-Ke Shih 
3453e3ec7017SPing-Ke Shih 	rtw89_pci_ctrl_hci_dma_en(rtwdev, MAC_AX_FUNC_DIS);
3454e3ec7017SPing-Ke Shih 	rtw89_pci_ctrl_hci_dma_en(rtwdev, MAC_AX_FUNC_EN);
3455e3ec7017SPing-Ke Shih 	rtw89_pci_clr_idx_all(rtwdev);
3456e3ec7017SPing-Ke Shih 
3457e3ec7017SPing-Ke Shih 	ret = rtw89_pci_rst_bdram(rtwdev);
3458e3ec7017SPing-Ke Shih 	if (ret)
3459e3ec7017SPing-Ke Shih 		return ret;
3460e3ec7017SPing-Ke Shih 
3461e3ec7017SPing-Ke Shih 	rtw89_pci_ctrl_dma_all_pcie(rtwdev, MAC_AX_FUNC_EN);
3462e3ec7017SPing-Ke Shih 	return ret;
3463e3ec7017SPing-Ke Shih }
3464e3ec7017SPing-Ke Shih 
3465e3ec7017SPing-Ke Shih static int rtw89_pci_ops_mac_lv1_recovery(struct rtw89_dev *rtwdev,
3466e3ec7017SPing-Ke Shih 					  enum rtw89_lv1_rcvy_step step)
3467e3ec7017SPing-Ke Shih {
3468e3ec7017SPing-Ke Shih 	int ret;
3469e3ec7017SPing-Ke Shih 
3470e3ec7017SPing-Ke Shih 	switch (step) {
3471e3ec7017SPing-Ke Shih 	case RTW89_LV1_RCVY_STEP_1:
3472e3ec7017SPing-Ke Shih 		ret = rtw89_pci_lv1rst_stop_dma(rtwdev);
3473e3ec7017SPing-Ke Shih 		if (ret)
3474e3ec7017SPing-Ke Shih 			rtw89_err(rtwdev, "lv1 rcvy pci stop dma fail\n");
3475e3ec7017SPing-Ke Shih 
3476e3ec7017SPing-Ke Shih 		break;
3477e3ec7017SPing-Ke Shih 
3478e3ec7017SPing-Ke Shih 	case RTW89_LV1_RCVY_STEP_2:
3479e3ec7017SPing-Ke Shih 		ret = rtw89_pci_lv1rst_start_dma(rtwdev);
3480e3ec7017SPing-Ke Shih 		if (ret)
3481e3ec7017SPing-Ke Shih 			rtw89_err(rtwdev, "lv1 rcvy pci start dma fail\n");
3482e3ec7017SPing-Ke Shih 		break;
3483e3ec7017SPing-Ke Shih 
3484e3ec7017SPing-Ke Shih 	default:
3485e3ec7017SPing-Ke Shih 		return -EINVAL;
3486e3ec7017SPing-Ke Shih 	}
3487e3ec7017SPing-Ke Shih 
3488e3ec7017SPing-Ke Shih 	return ret;
3489e3ec7017SPing-Ke Shih }
3490e3ec7017SPing-Ke Shih 
3491e3ec7017SPing-Ke Shih static void rtw89_pci_ops_dump_err_status(struct rtw89_dev *rtwdev)
3492e3ec7017SPing-Ke Shih {
3493e3ec7017SPing-Ke Shih 	rtw89_info(rtwdev, "R_AX_RPQ_RXBD_IDX =0x%08x\n",
3494e3ec7017SPing-Ke Shih 		   rtw89_read32(rtwdev, R_AX_RPQ_RXBD_IDX));
3495e3ec7017SPing-Ke Shih 	rtw89_info(rtwdev, "R_AX_DBG_ERR_FLAG=0x%08x\n",
3496e3ec7017SPing-Ke Shih 		   rtw89_read32(rtwdev, R_AX_DBG_ERR_FLAG));
3497e3ec7017SPing-Ke Shih 	rtw89_info(rtwdev, "R_AX_LBC_WATCHDOG=0x%08x\n",
3498e3ec7017SPing-Ke Shih 		   rtw89_read32(rtwdev, R_AX_LBC_WATCHDOG));
3499e3ec7017SPing-Ke Shih }
3500e3ec7017SPing-Ke Shih 
3501e3ec7017SPing-Ke Shih static int rtw89_pci_napi_poll(struct napi_struct *napi, int budget)
3502e3ec7017SPing-Ke Shih {
3503e3ec7017SPing-Ke Shih 	struct rtw89_dev *rtwdev = container_of(napi, struct rtw89_dev, napi);
3504e3ec7017SPing-Ke Shih 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
3505e3ec7017SPing-Ke Shih 	unsigned long flags;
3506e3ec7017SPing-Ke Shih 	int work_done;
3507e3ec7017SPing-Ke Shih 
3508e3ec7017SPing-Ke Shih 	rtwdev->napi_budget_countdown = budget;
3509e3ec7017SPing-Ke Shih 
3510e3ec7017SPing-Ke Shih 	rtw89_pci_clear_isr0(rtwdev, B_AX_RPQDMA_INT | B_AX_RPQBD_FULL_INT);
3511e3ec7017SPing-Ke Shih 	work_done = rtw89_pci_poll_rpq_dma(rtwdev, rtwpci, rtwdev->napi_budget_countdown);
3512e3ec7017SPing-Ke Shih 	if (work_done == budget)
3513e3ec7017SPing-Ke Shih 		return budget;
3514e3ec7017SPing-Ke Shih 
3515e3ec7017SPing-Ke Shih 	rtw89_pci_clear_isr0(rtwdev, B_AX_RXP1DMA_INT | B_AX_RXDMA_INT | B_AX_RDU_INT);
3516e3ec7017SPing-Ke Shih 	work_done += rtw89_pci_poll_rxq_dma(rtwdev, rtwpci, rtwdev->napi_budget_countdown);
3517e3ec7017SPing-Ke Shih 	if (work_done < budget && napi_complete_done(napi, work_done)) {
3518e3ec7017SPing-Ke Shih 		spin_lock_irqsave(&rtwpci->irq_lock, flags);
3519e3ec7017SPing-Ke Shih 		if (likely(rtwpci->running))
3520948e521cSPing-Ke Shih 			rtw89_chip_enable_intr(rtwdev, rtwpci);
3521e3ec7017SPing-Ke Shih 		spin_unlock_irqrestore(&rtwpci->irq_lock, flags);
3522e3ec7017SPing-Ke Shih 	}
3523e3ec7017SPing-Ke Shih 
3524e3ec7017SPing-Ke Shih 	return work_done;
3525e3ec7017SPing-Ke Shih }
3526e3ec7017SPing-Ke Shih 
3527e3ec7017SPing-Ke Shih static int __maybe_unused rtw89_pci_suspend(struct device *dev)
3528e3ec7017SPing-Ke Shih {
3529e3ec7017SPing-Ke Shih 	struct ieee80211_hw *hw = dev_get_drvdata(dev);
3530e3ec7017SPing-Ke Shih 	struct rtw89_dev *rtwdev = hw->priv;
3531e3ec7017SPing-Ke Shih 
3532e3ec7017SPing-Ke Shih 	rtw89_write32_clr(rtwdev, R_AX_SYS_SDIO_CTRL,
3533e3ec7017SPing-Ke Shih 			  B_AX_PCIE_DIS_L2_CTRL_LDO_HCI);
3534e3ec7017SPing-Ke Shih 	rtw89_write32_set(rtwdev, R_AX_RSV_CTRL, B_AX_WLOCK_1C_BIT6);
3535e3ec7017SPing-Ke Shih 	rtw89_write32_set(rtwdev, R_AX_RSV_CTRL, B_AX_R_DIS_PRST);
3536e3ec7017SPing-Ke Shih 	rtw89_write32_clr(rtwdev, R_AX_RSV_CTRL, B_AX_WLOCK_1C_BIT6);
3537e3ec7017SPing-Ke Shih 	rtw89_write32_set(rtwdev, R_AX_PCIE_INIT_CFG1,
3538e3ec7017SPing-Ke Shih 			  B_AX_PCIE_PERST_KEEP_REG | B_AX_PCIE_TRAIN_KEEP_REG);
3539e3ec7017SPing-Ke Shih 
3540e3ec7017SPing-Ke Shih 	return 0;
3541e3ec7017SPing-Ke Shih }
3542e3ec7017SPing-Ke Shih 
3543e3ec7017SPing-Ke Shih static void rtw89_pci_l2_hci_ldo(struct rtw89_dev *rtwdev)
3544e3ec7017SPing-Ke Shih {
3545e3ec7017SPing-Ke Shih 	if (rtwdev->chip->chip_id == RTL8852C)
3546e3ec7017SPing-Ke Shih 		return;
3547e3ec7017SPing-Ke Shih 
3548e3ec7017SPing-Ke Shih 	/* Hardware need write the reg twice to ensure the setting work */
3549db38d9cdSChin-Yen Lee 	rtw89_pci_write_config_byte(rtwdev, RTW89_PCIE_RST_MSTATE,
3550e3ec7017SPing-Ke Shih 				    RTW89_PCIE_BIT_CFG_RST_MSTATE);
3551db38d9cdSChin-Yen Lee 	rtw89_pci_write_config_byte(rtwdev, RTW89_PCIE_RST_MSTATE,
3552e3ec7017SPing-Ke Shih 				    RTW89_PCIE_BIT_CFG_RST_MSTATE);
3553e3ec7017SPing-Ke Shih }
3554e3ec7017SPing-Ke Shih 
3555e3ec7017SPing-Ke Shih static int __maybe_unused rtw89_pci_resume(struct device *dev)
3556e3ec7017SPing-Ke Shih {
3557e3ec7017SPing-Ke Shih 	struct ieee80211_hw *hw = dev_get_drvdata(dev);
3558e3ec7017SPing-Ke Shih 	struct rtw89_dev *rtwdev = hw->priv;
3559e3ec7017SPing-Ke Shih 
3560e3ec7017SPing-Ke Shih 	rtw89_write32_set(rtwdev, R_AX_SYS_SDIO_CTRL,
3561e3ec7017SPing-Ke Shih 			  B_AX_PCIE_DIS_L2_CTRL_LDO_HCI);
3562e3ec7017SPing-Ke Shih 	rtw89_write32_set(rtwdev, R_AX_RSV_CTRL, B_AX_WLOCK_1C_BIT6);
3563e3ec7017SPing-Ke Shih 	rtw89_write32_clr(rtwdev, R_AX_RSV_CTRL, B_AX_R_DIS_PRST);
3564e3ec7017SPing-Ke Shih 	rtw89_write32_clr(rtwdev, R_AX_RSV_CTRL, B_AX_WLOCK_1C_BIT6);
3565e3ec7017SPing-Ke Shih 	rtw89_write32_clr(rtwdev, R_AX_PCIE_INIT_CFG1,
3566e3ec7017SPing-Ke Shih 			  B_AX_PCIE_PERST_KEEP_REG | B_AX_PCIE_TRAIN_KEEP_REG);
3567e3ec7017SPing-Ke Shih 	rtw89_pci_l2_hci_ldo(rtwdev);
3568e3ec7017SPing-Ke Shih 	rtw89_pci_link_cfg(rtwdev);
3569e3ec7017SPing-Ke Shih 	rtw89_pci_l1ss_cfg(rtwdev);
3570e3ec7017SPing-Ke Shih 
3571e3ec7017SPing-Ke Shih 	return 0;
3572e3ec7017SPing-Ke Shih }
3573e3ec7017SPing-Ke Shih 
3574e3ec7017SPing-Ke Shih SIMPLE_DEV_PM_OPS(rtw89_pm_ops, rtw89_pci_suspend, rtw89_pci_resume);
3575e3ec7017SPing-Ke Shih EXPORT_SYMBOL(rtw89_pm_ops);
3576e3ec7017SPing-Ke Shih 
3577e3ec7017SPing-Ke Shih static const struct rtw89_hci_ops rtw89_pci_ops = {
3578e3ec7017SPing-Ke Shih 	.tx_write	= rtw89_pci_ops_tx_write,
3579e3ec7017SPing-Ke Shih 	.tx_kick_off	= rtw89_pci_ops_tx_kick_off,
3580e3ec7017SPing-Ke Shih 	.flush_queues	= rtw89_pci_ops_flush_queues,
3581e3ec7017SPing-Ke Shih 	.reset		= rtw89_pci_ops_reset,
3582e3ec7017SPing-Ke Shih 	.start		= rtw89_pci_ops_start,
3583e3ec7017SPing-Ke Shih 	.stop		= rtw89_pci_ops_stop,
358452edbb9fSPing-Ke Shih 	.pause		= rtw89_pci_ops_pause,
358552edbb9fSPing-Ke Shih 	.switch_mode	= rtw89_pci_ops_switch_mode,
3586e3ec7017SPing-Ke Shih 	.recalc_int_mit = rtw89_pci_recalc_int_mit,
3587e3ec7017SPing-Ke Shih 
3588e3ec7017SPing-Ke Shih 	.read8		= rtw89_pci_ops_read8,
3589e3ec7017SPing-Ke Shih 	.read16		= rtw89_pci_ops_read16,
3590e3ec7017SPing-Ke Shih 	.read32		= rtw89_pci_ops_read32,
3591e3ec7017SPing-Ke Shih 	.write8		= rtw89_pci_ops_write8,
3592e3ec7017SPing-Ke Shih 	.write16	= rtw89_pci_ops_write16,
3593e3ec7017SPing-Ke Shih 	.write32	= rtw89_pci_ops_write32,
3594e3ec7017SPing-Ke Shih 
3595e3ec7017SPing-Ke Shih 	.mac_pre_init	= rtw89_pci_ops_mac_pre_init,
3596e3ec7017SPing-Ke Shih 	.mac_post_init	= rtw89_pci_ops_mac_post_init,
3597e3ec7017SPing-Ke Shih 	.deinit		= rtw89_pci_ops_deinit,
3598e3ec7017SPing-Ke Shih 
3599e3ec7017SPing-Ke Shih 	.check_and_reclaim_tx_resource = rtw89_pci_check_and_reclaim_tx_resource,
3600e3ec7017SPing-Ke Shih 	.mac_lv1_rcvy	= rtw89_pci_ops_mac_lv1_recovery,
3601e3ec7017SPing-Ke Shih 	.dump_err_status = rtw89_pci_ops_dump_err_status,
3602e3ec7017SPing-Ke Shih 	.napi_poll	= rtw89_pci_napi_poll,
360314f9f479SZong-Zhe Yang 
360414f9f479SZong-Zhe Yang 	.recovery_start = rtw89_pci_ops_recovery_start,
360514f9f479SZong-Zhe Yang 	.recovery_complete = rtw89_pci_ops_recovery_complete,
3606e3ec7017SPing-Ke Shih };
3607e3ec7017SPing-Ke Shih 
3608861e58c8SZong-Zhe Yang int rtw89_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
3609e3ec7017SPing-Ke Shih {
3610e3ec7017SPing-Ke Shih 	struct ieee80211_hw *hw;
3611e3ec7017SPing-Ke Shih 	struct rtw89_dev *rtwdev;
3612861e58c8SZong-Zhe Yang 	const struct rtw89_driver_info *info;
3613e1757e80SPing-Ke Shih 	const struct rtw89_pci_info *pci_info;
3614e3ec7017SPing-Ke Shih 	int driver_data_size;
3615e3ec7017SPing-Ke Shih 	int ret;
3616e3ec7017SPing-Ke Shih 
3617e3ec7017SPing-Ke Shih 	driver_data_size = sizeof(struct rtw89_dev) + sizeof(struct rtw89_pci);
3618e3ec7017SPing-Ke Shih 	hw = ieee80211_alloc_hw(driver_data_size, &rtw89_ops);
3619e3ec7017SPing-Ke Shih 	if (!hw) {
3620e3ec7017SPing-Ke Shih 		dev_err(&pdev->dev, "failed to allocate hw\n");
3621e3ec7017SPing-Ke Shih 		return -ENOMEM;
3622e3ec7017SPing-Ke Shih 	}
3623e3ec7017SPing-Ke Shih 
3624e1757e80SPing-Ke Shih 	info = (const struct rtw89_driver_info *)id->driver_data;
3625e1757e80SPing-Ke Shih 	pci_info = info->bus.pci;
3626e1757e80SPing-Ke Shih 
3627e3ec7017SPing-Ke Shih 	rtwdev = hw->priv;
3628e3ec7017SPing-Ke Shih 	rtwdev->hw = hw;
3629e3ec7017SPing-Ke Shih 	rtwdev->dev = &pdev->dev;
3630861e58c8SZong-Zhe Yang 	rtwdev->chip = info->chip;
36314a9e48acSPing-Ke Shih 	rtwdev->pci_info = info->bus.pci;
3632e1757e80SPing-Ke Shih 	rtwdev->hci.ops = &rtw89_pci_ops;
3633e1757e80SPing-Ke Shih 	rtwdev->hci.type = RTW89_HCI_TYPE_PCIE;
3634e1757e80SPing-Ke Shih 	rtwdev->hci.rpwm_addr = pci_info->rpwm_addr;
3635e1757e80SPing-Ke Shih 	rtwdev->hci.cpwm_addr = pci_info->cpwm_addr;
3636e1757e80SPing-Ke Shih 
3637e1757e80SPing-Ke Shih 	SET_IEEE80211_DEV(rtwdev->hw, &pdev->dev);
3638e3ec7017SPing-Ke Shih 
3639e3ec7017SPing-Ke Shih 	ret = rtw89_core_init(rtwdev);
3640e3ec7017SPing-Ke Shih 	if (ret) {
3641e3ec7017SPing-Ke Shih 		rtw89_err(rtwdev, "failed to initialise core\n");
3642e3ec7017SPing-Ke Shih 		goto err_release_hw;
3643e3ec7017SPing-Ke Shih 	}
3644e3ec7017SPing-Ke Shih 
3645e3ec7017SPing-Ke Shih 	ret = rtw89_pci_claim_device(rtwdev, pdev);
3646e3ec7017SPing-Ke Shih 	if (ret) {
3647e3ec7017SPing-Ke Shih 		rtw89_err(rtwdev, "failed to claim pci device\n");
3648e3ec7017SPing-Ke Shih 		goto err_core_deinit;
3649e3ec7017SPing-Ke Shih 	}
3650e3ec7017SPing-Ke Shih 
3651e3ec7017SPing-Ke Shih 	ret = rtw89_pci_setup_resource(rtwdev, pdev);
3652e3ec7017SPing-Ke Shih 	if (ret) {
3653e3ec7017SPing-Ke Shih 		rtw89_err(rtwdev, "failed to setup pci resource\n");
3654e3ec7017SPing-Ke Shih 		goto err_declaim_pci;
3655e3ec7017SPing-Ke Shih 	}
3656e3ec7017SPing-Ke Shih 
3657e3ec7017SPing-Ke Shih 	ret = rtw89_chip_info_setup(rtwdev);
3658e3ec7017SPing-Ke Shih 	if (ret) {
3659e3ec7017SPing-Ke Shih 		rtw89_err(rtwdev, "failed to setup chip information\n");
3660e3ec7017SPing-Ke Shih 		goto err_clear_resource;
3661e3ec7017SPing-Ke Shih 	}
3662e3ec7017SPing-Ke Shih 
3663e3ec7017SPing-Ke Shih 	rtw89_pci_link_cfg(rtwdev);
3664e3ec7017SPing-Ke Shih 	rtw89_pci_l1ss_cfg(rtwdev);
3665e3ec7017SPing-Ke Shih 
3666e3ec7017SPing-Ke Shih 	ret = rtw89_core_register(rtwdev);
3667e3ec7017SPing-Ke Shih 	if (ret) {
3668e3ec7017SPing-Ke Shih 		rtw89_err(rtwdev, "failed to register core\n");
3669e3ec7017SPing-Ke Shih 		goto err_clear_resource;
3670e3ec7017SPing-Ke Shih 	}
3671e3ec7017SPing-Ke Shih 
3672e3ec7017SPing-Ke Shih 	rtw89_core_napi_init(rtwdev);
3673e3ec7017SPing-Ke Shih 
3674e3ec7017SPing-Ke Shih 	ret = rtw89_pci_request_irq(rtwdev, pdev);
3675e3ec7017SPing-Ke Shih 	if (ret) {
3676e3ec7017SPing-Ke Shih 		rtw89_err(rtwdev, "failed to request pci irq\n");
3677e3ec7017SPing-Ke Shih 		goto err_unregister;
3678e3ec7017SPing-Ke Shih 	}
3679e3ec7017SPing-Ke Shih 
3680e3ec7017SPing-Ke Shih 	return 0;
3681e3ec7017SPing-Ke Shih 
3682e3ec7017SPing-Ke Shih err_unregister:
3683e3ec7017SPing-Ke Shih 	rtw89_core_napi_deinit(rtwdev);
3684e3ec7017SPing-Ke Shih 	rtw89_core_unregister(rtwdev);
3685e3ec7017SPing-Ke Shih err_clear_resource:
3686e3ec7017SPing-Ke Shih 	rtw89_pci_clear_resource(rtwdev, pdev);
3687e3ec7017SPing-Ke Shih err_declaim_pci:
3688e3ec7017SPing-Ke Shih 	rtw89_pci_declaim_device(rtwdev, pdev);
3689e3ec7017SPing-Ke Shih err_core_deinit:
3690e3ec7017SPing-Ke Shih 	rtw89_core_deinit(rtwdev);
3691e3ec7017SPing-Ke Shih err_release_hw:
3692e3ec7017SPing-Ke Shih 	ieee80211_free_hw(hw);
3693e3ec7017SPing-Ke Shih 
3694e3ec7017SPing-Ke Shih 	return ret;
3695e3ec7017SPing-Ke Shih }
3696861e58c8SZong-Zhe Yang EXPORT_SYMBOL(rtw89_pci_probe);
3697e3ec7017SPing-Ke Shih 
3698861e58c8SZong-Zhe Yang void rtw89_pci_remove(struct pci_dev *pdev)
3699e3ec7017SPing-Ke Shih {
3700e3ec7017SPing-Ke Shih 	struct ieee80211_hw *hw = pci_get_drvdata(pdev);
3701e3ec7017SPing-Ke Shih 	struct rtw89_dev *rtwdev;
3702e3ec7017SPing-Ke Shih 
3703e3ec7017SPing-Ke Shih 	rtwdev = hw->priv;
3704e3ec7017SPing-Ke Shih 
3705e3ec7017SPing-Ke Shih 	rtw89_pci_free_irq(rtwdev, pdev);
3706e3ec7017SPing-Ke Shih 	rtw89_core_napi_deinit(rtwdev);
3707e3ec7017SPing-Ke Shih 	rtw89_core_unregister(rtwdev);
3708e3ec7017SPing-Ke Shih 	rtw89_pci_clear_resource(rtwdev, pdev);
3709e3ec7017SPing-Ke Shih 	rtw89_pci_declaim_device(rtwdev, pdev);
3710e3ec7017SPing-Ke Shih 	rtw89_core_deinit(rtwdev);
3711e3ec7017SPing-Ke Shih 	ieee80211_free_hw(hw);
3712e3ec7017SPing-Ke Shih }
3713861e58c8SZong-Zhe Yang EXPORT_SYMBOL(rtw89_pci_remove);
3714e3ec7017SPing-Ke Shih 
3715e3ec7017SPing-Ke Shih MODULE_AUTHOR("Realtek Corporation");
3716e3ec7017SPing-Ke Shih MODULE_DESCRIPTION("Realtek 802.11ax wireless PCI driver");
3717e3ec7017SPing-Ke Shih MODULE_LICENSE("Dual BSD/GPL");
3718