162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
262306a36Sopenharmony_ci/* Copyright(c) 2018-2019  Realtek Corporation
362306a36Sopenharmony_ci */
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#include <linux/module.h>
662306a36Sopenharmony_ci#include <linux/pci.h>
762306a36Sopenharmony_ci#include "main.h"
862306a36Sopenharmony_ci#include "pci.h"
962306a36Sopenharmony_ci#include "reg.h"
1062306a36Sopenharmony_ci#include "tx.h"
1162306a36Sopenharmony_ci#include "rx.h"
1262306a36Sopenharmony_ci#include "fw.h"
1362306a36Sopenharmony_ci#include "ps.h"
1462306a36Sopenharmony_ci#include "debug.h"
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_cistatic bool rtw_disable_msi;
1762306a36Sopenharmony_cistatic bool rtw_pci_disable_aspm;
1862306a36Sopenharmony_cimodule_param_named(disable_msi, rtw_disable_msi, bool, 0644);
1962306a36Sopenharmony_cimodule_param_named(disable_aspm, rtw_pci_disable_aspm, bool, 0644);
2062306a36Sopenharmony_ciMODULE_PARM_DESC(disable_msi, "Set Y to disable MSI interrupt support");
2162306a36Sopenharmony_ciMODULE_PARM_DESC(disable_aspm, "Set Y to disable PCI ASPM support");
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_cistatic u32 rtw_pci_tx_queue_idx_addr[] = {
2462306a36Sopenharmony_ci	[RTW_TX_QUEUE_BK]	= RTK_PCI_TXBD_IDX_BKQ,
2562306a36Sopenharmony_ci	[RTW_TX_QUEUE_BE]	= RTK_PCI_TXBD_IDX_BEQ,
2662306a36Sopenharmony_ci	[RTW_TX_QUEUE_VI]	= RTK_PCI_TXBD_IDX_VIQ,
2762306a36Sopenharmony_ci	[RTW_TX_QUEUE_VO]	= RTK_PCI_TXBD_IDX_VOQ,
2862306a36Sopenharmony_ci	[RTW_TX_QUEUE_MGMT]	= RTK_PCI_TXBD_IDX_MGMTQ,
2962306a36Sopenharmony_ci	[RTW_TX_QUEUE_HI0]	= RTK_PCI_TXBD_IDX_HI0Q,
3062306a36Sopenharmony_ci	[RTW_TX_QUEUE_H2C]	= RTK_PCI_TXBD_IDX_H2CQ,
3162306a36Sopenharmony_ci};
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_cistatic u8 rtw_pci_get_tx_qsel(struct sk_buff *skb,
3462306a36Sopenharmony_ci			      enum rtw_tx_queue_type queue)
3562306a36Sopenharmony_ci{
3662306a36Sopenharmony_ci	switch (queue) {
3762306a36Sopenharmony_ci	case RTW_TX_QUEUE_BCN:
3862306a36Sopenharmony_ci		return TX_DESC_QSEL_BEACON;
3962306a36Sopenharmony_ci	case RTW_TX_QUEUE_H2C:
4062306a36Sopenharmony_ci		return TX_DESC_QSEL_H2C;
4162306a36Sopenharmony_ci	case RTW_TX_QUEUE_MGMT:
4262306a36Sopenharmony_ci		return TX_DESC_QSEL_MGMT;
4362306a36Sopenharmony_ci	case RTW_TX_QUEUE_HI0:
4462306a36Sopenharmony_ci		return TX_DESC_QSEL_HIGH;
4562306a36Sopenharmony_ci	default:
4662306a36Sopenharmony_ci		return skb->priority;
4762306a36Sopenharmony_ci	}
4862306a36Sopenharmony_ci};
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_cistatic u8 rtw_pci_read8(struct rtw_dev *rtwdev, u32 addr)
5162306a36Sopenharmony_ci{
5262306a36Sopenharmony_ci	struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	return readb(rtwpci->mmap + addr);
5562306a36Sopenharmony_ci}
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_cistatic u16 rtw_pci_read16(struct rtw_dev *rtwdev, u32 addr)
5862306a36Sopenharmony_ci{
5962306a36Sopenharmony_ci	struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	return readw(rtwpci->mmap + addr);
6262306a36Sopenharmony_ci}
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cistatic u32 rtw_pci_read32(struct rtw_dev *rtwdev, u32 addr)
6562306a36Sopenharmony_ci{
6662306a36Sopenharmony_ci	struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	return readl(rtwpci->mmap + addr);
6962306a36Sopenharmony_ci}
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_cistatic void rtw_pci_write8(struct rtw_dev *rtwdev, u32 addr, u8 val)
7262306a36Sopenharmony_ci{
7362306a36Sopenharmony_ci	struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	writeb(val, rtwpci->mmap + addr);
7662306a36Sopenharmony_ci}
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_cistatic void rtw_pci_write16(struct rtw_dev *rtwdev, u32 addr, u16 val)
7962306a36Sopenharmony_ci{
8062306a36Sopenharmony_ci	struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	writew(val, rtwpci->mmap + addr);
8362306a36Sopenharmony_ci}
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_cistatic void rtw_pci_write32(struct rtw_dev *rtwdev, u32 addr, u32 val)
8662306a36Sopenharmony_ci{
8762306a36Sopenharmony_ci	struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	writel(val, rtwpci->mmap + addr);
9062306a36Sopenharmony_ci}
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_cistatic void rtw_pci_free_tx_ring_skbs(struct rtw_dev *rtwdev,
9362306a36Sopenharmony_ci				      struct rtw_pci_tx_ring *tx_ring)
9462306a36Sopenharmony_ci{
9562306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(rtwdev->dev);
9662306a36Sopenharmony_ci	struct rtw_pci_tx_data *tx_data;
9762306a36Sopenharmony_ci	struct sk_buff *skb, *tmp;
9862306a36Sopenharmony_ci	dma_addr_t dma;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	/* free every skb remained in tx list */
10162306a36Sopenharmony_ci	skb_queue_walk_safe(&tx_ring->queue, skb, tmp) {
10262306a36Sopenharmony_ci		__skb_unlink(skb, &tx_ring->queue);
10362306a36Sopenharmony_ci		tx_data = rtw_pci_get_tx_data(skb);
10462306a36Sopenharmony_ci		dma = tx_data->dma;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci		dma_unmap_single(&pdev->dev, dma, skb->len, DMA_TO_DEVICE);
10762306a36Sopenharmony_ci		dev_kfree_skb_any(skb);
10862306a36Sopenharmony_ci	}
10962306a36Sopenharmony_ci}
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_cistatic void rtw_pci_free_tx_ring(struct rtw_dev *rtwdev,
11262306a36Sopenharmony_ci				 struct rtw_pci_tx_ring *tx_ring)
11362306a36Sopenharmony_ci{
11462306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(rtwdev->dev);
11562306a36Sopenharmony_ci	u8 *head = tx_ring->r.head;
11662306a36Sopenharmony_ci	u32 len = tx_ring->r.len;
11762306a36Sopenharmony_ci	int ring_sz = len * tx_ring->r.desc_size;
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	rtw_pci_free_tx_ring_skbs(rtwdev, tx_ring);
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	/* free the ring itself */
12262306a36Sopenharmony_ci	dma_free_coherent(&pdev->dev, ring_sz, head, tx_ring->r.dma);
12362306a36Sopenharmony_ci	tx_ring->r.head = NULL;
12462306a36Sopenharmony_ci}
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_cistatic void rtw_pci_free_rx_ring_skbs(struct rtw_dev *rtwdev,
12762306a36Sopenharmony_ci				      struct rtw_pci_rx_ring *rx_ring)
12862306a36Sopenharmony_ci{
12962306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(rtwdev->dev);
13062306a36Sopenharmony_ci	struct sk_buff *skb;
13162306a36Sopenharmony_ci	int buf_sz = RTK_PCI_RX_BUF_SIZE;
13262306a36Sopenharmony_ci	dma_addr_t dma;
13362306a36Sopenharmony_ci	int i;
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	for (i = 0; i < rx_ring->r.len; i++) {
13662306a36Sopenharmony_ci		skb = rx_ring->buf[i];
13762306a36Sopenharmony_ci		if (!skb)
13862306a36Sopenharmony_ci			continue;
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci		dma = *((dma_addr_t *)skb->cb);
14162306a36Sopenharmony_ci		dma_unmap_single(&pdev->dev, dma, buf_sz, DMA_FROM_DEVICE);
14262306a36Sopenharmony_ci		dev_kfree_skb(skb);
14362306a36Sopenharmony_ci		rx_ring->buf[i] = NULL;
14462306a36Sopenharmony_ci	}
14562306a36Sopenharmony_ci}
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_cistatic void rtw_pci_free_rx_ring(struct rtw_dev *rtwdev,
14862306a36Sopenharmony_ci				 struct rtw_pci_rx_ring *rx_ring)
14962306a36Sopenharmony_ci{
15062306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(rtwdev->dev);
15162306a36Sopenharmony_ci	u8 *head = rx_ring->r.head;
15262306a36Sopenharmony_ci	int ring_sz = rx_ring->r.desc_size * rx_ring->r.len;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	rtw_pci_free_rx_ring_skbs(rtwdev, rx_ring);
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	dma_free_coherent(&pdev->dev, ring_sz, head, rx_ring->r.dma);
15762306a36Sopenharmony_ci}
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_cistatic void rtw_pci_free_trx_ring(struct rtw_dev *rtwdev)
16062306a36Sopenharmony_ci{
16162306a36Sopenharmony_ci	struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
16262306a36Sopenharmony_ci	struct rtw_pci_tx_ring *tx_ring;
16362306a36Sopenharmony_ci	struct rtw_pci_rx_ring *rx_ring;
16462306a36Sopenharmony_ci	int i;
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	for (i = 0; i < RTK_MAX_TX_QUEUE_NUM; i++) {
16762306a36Sopenharmony_ci		tx_ring = &rtwpci->tx_rings[i];
16862306a36Sopenharmony_ci		rtw_pci_free_tx_ring(rtwdev, tx_ring);
16962306a36Sopenharmony_ci	}
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	for (i = 0; i < RTK_MAX_RX_QUEUE_NUM; i++) {
17262306a36Sopenharmony_ci		rx_ring = &rtwpci->rx_rings[i];
17362306a36Sopenharmony_ci		rtw_pci_free_rx_ring(rtwdev, rx_ring);
17462306a36Sopenharmony_ci	}
17562306a36Sopenharmony_ci}
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_cistatic int rtw_pci_init_tx_ring(struct rtw_dev *rtwdev,
17862306a36Sopenharmony_ci				struct rtw_pci_tx_ring *tx_ring,
17962306a36Sopenharmony_ci				u8 desc_size, u32 len)
18062306a36Sopenharmony_ci{
18162306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(rtwdev->dev);
18262306a36Sopenharmony_ci	int ring_sz = desc_size * len;
18362306a36Sopenharmony_ci	dma_addr_t dma;
18462306a36Sopenharmony_ci	u8 *head;
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	if (len > TRX_BD_IDX_MASK) {
18762306a36Sopenharmony_ci		rtw_err(rtwdev, "len %d exceeds maximum TX entries\n", len);
18862306a36Sopenharmony_ci		return -EINVAL;
18962306a36Sopenharmony_ci	}
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	head = dma_alloc_coherent(&pdev->dev, ring_sz, &dma, GFP_KERNEL);
19262306a36Sopenharmony_ci	if (!head) {
19362306a36Sopenharmony_ci		rtw_err(rtwdev, "failed to allocate tx ring\n");
19462306a36Sopenharmony_ci		return -ENOMEM;
19562306a36Sopenharmony_ci	}
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	skb_queue_head_init(&tx_ring->queue);
19862306a36Sopenharmony_ci	tx_ring->r.head = head;
19962306a36Sopenharmony_ci	tx_ring->r.dma = dma;
20062306a36Sopenharmony_ci	tx_ring->r.len = len;
20162306a36Sopenharmony_ci	tx_ring->r.desc_size = desc_size;
20262306a36Sopenharmony_ci	tx_ring->r.wp = 0;
20362306a36Sopenharmony_ci	tx_ring->r.rp = 0;
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	return 0;
20662306a36Sopenharmony_ci}
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_cistatic int rtw_pci_reset_rx_desc(struct rtw_dev *rtwdev, struct sk_buff *skb,
20962306a36Sopenharmony_ci				 struct rtw_pci_rx_ring *rx_ring,
21062306a36Sopenharmony_ci				 u32 idx, u32 desc_sz)
21162306a36Sopenharmony_ci{
21262306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(rtwdev->dev);
21362306a36Sopenharmony_ci	struct rtw_pci_rx_buffer_desc *buf_desc;
21462306a36Sopenharmony_ci	int buf_sz = RTK_PCI_RX_BUF_SIZE;
21562306a36Sopenharmony_ci	dma_addr_t dma;
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	if (!skb)
21862306a36Sopenharmony_ci		return -EINVAL;
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	dma = dma_map_single(&pdev->dev, skb->data, buf_sz, DMA_FROM_DEVICE);
22162306a36Sopenharmony_ci	if (dma_mapping_error(&pdev->dev, dma))
22262306a36Sopenharmony_ci		return -EBUSY;
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	*((dma_addr_t *)skb->cb) = dma;
22562306a36Sopenharmony_ci	buf_desc = (struct rtw_pci_rx_buffer_desc *)(rx_ring->r.head +
22662306a36Sopenharmony_ci						     idx * desc_sz);
22762306a36Sopenharmony_ci	memset(buf_desc, 0, sizeof(*buf_desc));
22862306a36Sopenharmony_ci	buf_desc->buf_size = cpu_to_le16(RTK_PCI_RX_BUF_SIZE);
22962306a36Sopenharmony_ci	buf_desc->dma = cpu_to_le32(dma);
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	return 0;
23262306a36Sopenharmony_ci}
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_cistatic void rtw_pci_sync_rx_desc_device(struct rtw_dev *rtwdev, dma_addr_t dma,
23562306a36Sopenharmony_ci					struct rtw_pci_rx_ring *rx_ring,
23662306a36Sopenharmony_ci					u32 idx, u32 desc_sz)
23762306a36Sopenharmony_ci{
23862306a36Sopenharmony_ci	struct device *dev = rtwdev->dev;
23962306a36Sopenharmony_ci	struct rtw_pci_rx_buffer_desc *buf_desc;
24062306a36Sopenharmony_ci	int buf_sz = RTK_PCI_RX_BUF_SIZE;
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	dma_sync_single_for_device(dev, dma, buf_sz, DMA_FROM_DEVICE);
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	buf_desc = (struct rtw_pci_rx_buffer_desc *)(rx_ring->r.head +
24562306a36Sopenharmony_ci						     idx * desc_sz);
24662306a36Sopenharmony_ci	memset(buf_desc, 0, sizeof(*buf_desc));
24762306a36Sopenharmony_ci	buf_desc->buf_size = cpu_to_le16(RTK_PCI_RX_BUF_SIZE);
24862306a36Sopenharmony_ci	buf_desc->dma = cpu_to_le32(dma);
24962306a36Sopenharmony_ci}
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_cistatic int rtw_pci_init_rx_ring(struct rtw_dev *rtwdev,
25262306a36Sopenharmony_ci				struct rtw_pci_rx_ring *rx_ring,
25362306a36Sopenharmony_ci				u8 desc_size, u32 len)
25462306a36Sopenharmony_ci{
25562306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(rtwdev->dev);
25662306a36Sopenharmony_ci	struct sk_buff *skb = NULL;
25762306a36Sopenharmony_ci	dma_addr_t dma;
25862306a36Sopenharmony_ci	u8 *head;
25962306a36Sopenharmony_ci	int ring_sz = desc_size * len;
26062306a36Sopenharmony_ci	int buf_sz = RTK_PCI_RX_BUF_SIZE;
26162306a36Sopenharmony_ci	int i, allocated;
26262306a36Sopenharmony_ci	int ret = 0;
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	head = dma_alloc_coherent(&pdev->dev, ring_sz, &dma, GFP_KERNEL);
26562306a36Sopenharmony_ci	if (!head) {
26662306a36Sopenharmony_ci		rtw_err(rtwdev, "failed to allocate rx ring\n");
26762306a36Sopenharmony_ci		return -ENOMEM;
26862306a36Sopenharmony_ci	}
26962306a36Sopenharmony_ci	rx_ring->r.head = head;
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	for (i = 0; i < len; i++) {
27262306a36Sopenharmony_ci		skb = dev_alloc_skb(buf_sz);
27362306a36Sopenharmony_ci		if (!skb) {
27462306a36Sopenharmony_ci			allocated = i;
27562306a36Sopenharmony_ci			ret = -ENOMEM;
27662306a36Sopenharmony_ci			goto err_out;
27762306a36Sopenharmony_ci		}
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci		memset(skb->data, 0, buf_sz);
28062306a36Sopenharmony_ci		rx_ring->buf[i] = skb;
28162306a36Sopenharmony_ci		ret = rtw_pci_reset_rx_desc(rtwdev, skb, rx_ring, i, desc_size);
28262306a36Sopenharmony_ci		if (ret) {
28362306a36Sopenharmony_ci			allocated = i;
28462306a36Sopenharmony_ci			dev_kfree_skb_any(skb);
28562306a36Sopenharmony_ci			goto err_out;
28662306a36Sopenharmony_ci		}
28762306a36Sopenharmony_ci	}
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	rx_ring->r.dma = dma;
29062306a36Sopenharmony_ci	rx_ring->r.len = len;
29162306a36Sopenharmony_ci	rx_ring->r.desc_size = desc_size;
29262306a36Sopenharmony_ci	rx_ring->r.wp = 0;
29362306a36Sopenharmony_ci	rx_ring->r.rp = 0;
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	return 0;
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_cierr_out:
29862306a36Sopenharmony_ci	for (i = 0; i < allocated; i++) {
29962306a36Sopenharmony_ci		skb = rx_ring->buf[i];
30062306a36Sopenharmony_ci		if (!skb)
30162306a36Sopenharmony_ci			continue;
30262306a36Sopenharmony_ci		dma = *((dma_addr_t *)skb->cb);
30362306a36Sopenharmony_ci		dma_unmap_single(&pdev->dev, dma, buf_sz, DMA_FROM_DEVICE);
30462306a36Sopenharmony_ci		dev_kfree_skb_any(skb);
30562306a36Sopenharmony_ci		rx_ring->buf[i] = NULL;
30662306a36Sopenharmony_ci	}
30762306a36Sopenharmony_ci	dma_free_coherent(&pdev->dev, ring_sz, head, dma);
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	rtw_err(rtwdev, "failed to init rx buffer\n");
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	return ret;
31262306a36Sopenharmony_ci}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_cistatic int rtw_pci_init_trx_ring(struct rtw_dev *rtwdev)
31562306a36Sopenharmony_ci{
31662306a36Sopenharmony_ci	struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
31762306a36Sopenharmony_ci	struct rtw_pci_tx_ring *tx_ring;
31862306a36Sopenharmony_ci	struct rtw_pci_rx_ring *rx_ring;
31962306a36Sopenharmony_ci	const struct rtw_chip_info *chip = rtwdev->chip;
32062306a36Sopenharmony_ci	int i = 0, j = 0, tx_alloced = 0, rx_alloced = 0;
32162306a36Sopenharmony_ci	int tx_desc_size, rx_desc_size;
32262306a36Sopenharmony_ci	u32 len;
32362306a36Sopenharmony_ci	int ret;
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	tx_desc_size = chip->tx_buf_desc_sz;
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	for (i = 0; i < RTK_MAX_TX_QUEUE_NUM; i++) {
32862306a36Sopenharmony_ci		tx_ring = &rtwpci->tx_rings[i];
32962306a36Sopenharmony_ci		len = max_num_of_tx_queue(i);
33062306a36Sopenharmony_ci		ret = rtw_pci_init_tx_ring(rtwdev, tx_ring, tx_desc_size, len);
33162306a36Sopenharmony_ci		if (ret)
33262306a36Sopenharmony_ci			goto out;
33362306a36Sopenharmony_ci	}
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	rx_desc_size = chip->rx_buf_desc_sz;
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	for (j = 0; j < RTK_MAX_RX_QUEUE_NUM; j++) {
33862306a36Sopenharmony_ci		rx_ring = &rtwpci->rx_rings[j];
33962306a36Sopenharmony_ci		ret = rtw_pci_init_rx_ring(rtwdev, rx_ring, rx_desc_size,
34062306a36Sopenharmony_ci					   RTK_MAX_RX_DESC_NUM);
34162306a36Sopenharmony_ci		if (ret)
34262306a36Sopenharmony_ci			goto out;
34362306a36Sopenharmony_ci	}
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	return 0;
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ciout:
34862306a36Sopenharmony_ci	tx_alloced = i;
34962306a36Sopenharmony_ci	for (i = 0; i < tx_alloced; i++) {
35062306a36Sopenharmony_ci		tx_ring = &rtwpci->tx_rings[i];
35162306a36Sopenharmony_ci		rtw_pci_free_tx_ring(rtwdev, tx_ring);
35262306a36Sopenharmony_ci	}
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	rx_alloced = j;
35562306a36Sopenharmony_ci	for (j = 0; j < rx_alloced; j++) {
35662306a36Sopenharmony_ci		rx_ring = &rtwpci->rx_rings[j];
35762306a36Sopenharmony_ci		rtw_pci_free_rx_ring(rtwdev, rx_ring);
35862306a36Sopenharmony_ci	}
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	return ret;
36162306a36Sopenharmony_ci}
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_cistatic void rtw_pci_deinit(struct rtw_dev *rtwdev)
36462306a36Sopenharmony_ci{
36562306a36Sopenharmony_ci	rtw_pci_free_trx_ring(rtwdev);
36662306a36Sopenharmony_ci}
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_cistatic int rtw_pci_init(struct rtw_dev *rtwdev)
36962306a36Sopenharmony_ci{
37062306a36Sopenharmony_ci	struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
37162306a36Sopenharmony_ci	int ret = 0;
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	rtwpci->irq_mask[0] = IMR_HIGHDOK |
37462306a36Sopenharmony_ci			      IMR_MGNTDOK |
37562306a36Sopenharmony_ci			      IMR_BKDOK |
37662306a36Sopenharmony_ci			      IMR_BEDOK |
37762306a36Sopenharmony_ci			      IMR_VIDOK |
37862306a36Sopenharmony_ci			      IMR_VODOK |
37962306a36Sopenharmony_ci			      IMR_ROK |
38062306a36Sopenharmony_ci			      IMR_BCNDMAINT_E |
38162306a36Sopenharmony_ci			      IMR_C2HCMD |
38262306a36Sopenharmony_ci			      0;
38362306a36Sopenharmony_ci	rtwpci->irq_mask[1] = IMR_TXFOVW |
38462306a36Sopenharmony_ci			      0;
38562306a36Sopenharmony_ci	rtwpci->irq_mask[3] = IMR_H2CDOK |
38662306a36Sopenharmony_ci			      0;
38762306a36Sopenharmony_ci	spin_lock_init(&rtwpci->irq_lock);
38862306a36Sopenharmony_ci	spin_lock_init(&rtwpci->hwirq_lock);
38962306a36Sopenharmony_ci	ret = rtw_pci_init_trx_ring(rtwdev);
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	return ret;
39262306a36Sopenharmony_ci}
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_cistatic void rtw_pci_reset_buf_desc(struct rtw_dev *rtwdev)
39562306a36Sopenharmony_ci{
39662306a36Sopenharmony_ci	struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
39762306a36Sopenharmony_ci	u32 len;
39862306a36Sopenharmony_ci	u8 tmp;
39962306a36Sopenharmony_ci	dma_addr_t dma;
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	tmp = rtw_read8(rtwdev, RTK_PCI_CTRL + 3);
40262306a36Sopenharmony_ci	rtw_write8(rtwdev, RTK_PCI_CTRL + 3, tmp | 0xf7);
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	dma = rtwpci->tx_rings[RTW_TX_QUEUE_BCN].r.dma;
40562306a36Sopenharmony_ci	rtw_write32(rtwdev, RTK_PCI_TXBD_DESA_BCNQ, dma);
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	if (!rtw_chip_wcpu_11n(rtwdev)) {
40862306a36Sopenharmony_ci		len = rtwpci->tx_rings[RTW_TX_QUEUE_H2C].r.len;
40962306a36Sopenharmony_ci		dma = rtwpci->tx_rings[RTW_TX_QUEUE_H2C].r.dma;
41062306a36Sopenharmony_ci		rtwpci->tx_rings[RTW_TX_QUEUE_H2C].r.rp = 0;
41162306a36Sopenharmony_ci		rtwpci->tx_rings[RTW_TX_QUEUE_H2C].r.wp = 0;
41262306a36Sopenharmony_ci		rtw_write16(rtwdev, RTK_PCI_TXBD_NUM_H2CQ, len & TRX_BD_IDX_MASK);
41362306a36Sopenharmony_ci		rtw_write32(rtwdev, RTK_PCI_TXBD_DESA_H2CQ, dma);
41462306a36Sopenharmony_ci	}
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	len = rtwpci->tx_rings[RTW_TX_QUEUE_BK].r.len;
41762306a36Sopenharmony_ci	dma = rtwpci->tx_rings[RTW_TX_QUEUE_BK].r.dma;
41862306a36Sopenharmony_ci	rtwpci->tx_rings[RTW_TX_QUEUE_BK].r.rp = 0;
41962306a36Sopenharmony_ci	rtwpci->tx_rings[RTW_TX_QUEUE_BK].r.wp = 0;
42062306a36Sopenharmony_ci	rtw_write16(rtwdev, RTK_PCI_TXBD_NUM_BKQ, len & TRX_BD_IDX_MASK);
42162306a36Sopenharmony_ci	rtw_write32(rtwdev, RTK_PCI_TXBD_DESA_BKQ, dma);
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	len = rtwpci->tx_rings[RTW_TX_QUEUE_BE].r.len;
42462306a36Sopenharmony_ci	dma = rtwpci->tx_rings[RTW_TX_QUEUE_BE].r.dma;
42562306a36Sopenharmony_ci	rtwpci->tx_rings[RTW_TX_QUEUE_BE].r.rp = 0;
42662306a36Sopenharmony_ci	rtwpci->tx_rings[RTW_TX_QUEUE_BE].r.wp = 0;
42762306a36Sopenharmony_ci	rtw_write16(rtwdev, RTK_PCI_TXBD_NUM_BEQ, len & TRX_BD_IDX_MASK);
42862306a36Sopenharmony_ci	rtw_write32(rtwdev, RTK_PCI_TXBD_DESA_BEQ, dma);
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	len = rtwpci->tx_rings[RTW_TX_QUEUE_VO].r.len;
43162306a36Sopenharmony_ci	dma = rtwpci->tx_rings[RTW_TX_QUEUE_VO].r.dma;
43262306a36Sopenharmony_ci	rtwpci->tx_rings[RTW_TX_QUEUE_VO].r.rp = 0;
43362306a36Sopenharmony_ci	rtwpci->tx_rings[RTW_TX_QUEUE_VO].r.wp = 0;
43462306a36Sopenharmony_ci	rtw_write16(rtwdev, RTK_PCI_TXBD_NUM_VOQ, len & TRX_BD_IDX_MASK);
43562306a36Sopenharmony_ci	rtw_write32(rtwdev, RTK_PCI_TXBD_DESA_VOQ, dma);
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	len = rtwpci->tx_rings[RTW_TX_QUEUE_VI].r.len;
43862306a36Sopenharmony_ci	dma = rtwpci->tx_rings[RTW_TX_QUEUE_VI].r.dma;
43962306a36Sopenharmony_ci	rtwpci->tx_rings[RTW_TX_QUEUE_VI].r.rp = 0;
44062306a36Sopenharmony_ci	rtwpci->tx_rings[RTW_TX_QUEUE_VI].r.wp = 0;
44162306a36Sopenharmony_ci	rtw_write16(rtwdev, RTK_PCI_TXBD_NUM_VIQ, len & TRX_BD_IDX_MASK);
44262306a36Sopenharmony_ci	rtw_write32(rtwdev, RTK_PCI_TXBD_DESA_VIQ, dma);
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	len = rtwpci->tx_rings[RTW_TX_QUEUE_MGMT].r.len;
44562306a36Sopenharmony_ci	dma = rtwpci->tx_rings[RTW_TX_QUEUE_MGMT].r.dma;
44662306a36Sopenharmony_ci	rtwpci->tx_rings[RTW_TX_QUEUE_MGMT].r.rp = 0;
44762306a36Sopenharmony_ci	rtwpci->tx_rings[RTW_TX_QUEUE_MGMT].r.wp = 0;
44862306a36Sopenharmony_ci	rtw_write16(rtwdev, RTK_PCI_TXBD_NUM_MGMTQ, len & TRX_BD_IDX_MASK);
44962306a36Sopenharmony_ci	rtw_write32(rtwdev, RTK_PCI_TXBD_DESA_MGMTQ, dma);
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	len = rtwpci->tx_rings[RTW_TX_QUEUE_HI0].r.len;
45262306a36Sopenharmony_ci	dma = rtwpci->tx_rings[RTW_TX_QUEUE_HI0].r.dma;
45362306a36Sopenharmony_ci	rtwpci->tx_rings[RTW_TX_QUEUE_HI0].r.rp = 0;
45462306a36Sopenharmony_ci	rtwpci->tx_rings[RTW_TX_QUEUE_HI0].r.wp = 0;
45562306a36Sopenharmony_ci	rtw_write16(rtwdev, RTK_PCI_TXBD_NUM_HI0Q, len & TRX_BD_IDX_MASK);
45662306a36Sopenharmony_ci	rtw_write32(rtwdev, RTK_PCI_TXBD_DESA_HI0Q, dma);
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	len = rtwpci->rx_rings[RTW_RX_QUEUE_MPDU].r.len;
45962306a36Sopenharmony_ci	dma = rtwpci->rx_rings[RTW_RX_QUEUE_MPDU].r.dma;
46062306a36Sopenharmony_ci	rtwpci->rx_rings[RTW_RX_QUEUE_MPDU].r.rp = 0;
46162306a36Sopenharmony_ci	rtwpci->rx_rings[RTW_RX_QUEUE_MPDU].r.wp = 0;
46262306a36Sopenharmony_ci	rtw_write16(rtwdev, RTK_PCI_RXBD_NUM_MPDUQ, len & TRX_BD_IDX_MASK);
46362306a36Sopenharmony_ci	rtw_write32(rtwdev, RTK_PCI_RXBD_DESA_MPDUQ, dma);
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	/* reset read/write point */
46662306a36Sopenharmony_ci	rtw_write32(rtwdev, RTK_PCI_TXBD_RWPTR_CLR, 0xffffffff);
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	/* reset H2C Queue index in a single write */
46962306a36Sopenharmony_ci	if (rtw_chip_wcpu_11ac(rtwdev))
47062306a36Sopenharmony_ci		rtw_write32_set(rtwdev, RTK_PCI_TXBD_H2CQ_CSR,
47162306a36Sopenharmony_ci				BIT_CLR_H2CQ_HOST_IDX | BIT_CLR_H2CQ_HW_IDX);
47262306a36Sopenharmony_ci}
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_cistatic void rtw_pci_reset_trx_ring(struct rtw_dev *rtwdev)
47562306a36Sopenharmony_ci{
47662306a36Sopenharmony_ci	rtw_pci_reset_buf_desc(rtwdev);
47762306a36Sopenharmony_ci}
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_cistatic void rtw_pci_enable_interrupt(struct rtw_dev *rtwdev,
48062306a36Sopenharmony_ci				     struct rtw_pci *rtwpci, bool exclude_rx)
48162306a36Sopenharmony_ci{
48262306a36Sopenharmony_ci	unsigned long flags;
48362306a36Sopenharmony_ci	u32 imr0_unmask = exclude_rx ? IMR_ROK : 0;
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	spin_lock_irqsave(&rtwpci->hwirq_lock, flags);
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	rtw_write32(rtwdev, RTK_PCI_HIMR0, rtwpci->irq_mask[0] & ~imr0_unmask);
48862306a36Sopenharmony_ci	rtw_write32(rtwdev, RTK_PCI_HIMR1, rtwpci->irq_mask[1]);
48962306a36Sopenharmony_ci	if (rtw_chip_wcpu_11ac(rtwdev))
49062306a36Sopenharmony_ci		rtw_write32(rtwdev, RTK_PCI_HIMR3, rtwpci->irq_mask[3]);
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	rtwpci->irq_enabled = true;
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	spin_unlock_irqrestore(&rtwpci->hwirq_lock, flags);
49562306a36Sopenharmony_ci}
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_cistatic void rtw_pci_disable_interrupt(struct rtw_dev *rtwdev,
49862306a36Sopenharmony_ci				      struct rtw_pci *rtwpci)
49962306a36Sopenharmony_ci{
50062306a36Sopenharmony_ci	unsigned long flags;
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	spin_lock_irqsave(&rtwpci->hwirq_lock, flags);
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	if (!rtwpci->irq_enabled)
50562306a36Sopenharmony_ci		goto out;
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	rtw_write32(rtwdev, RTK_PCI_HIMR0, 0);
50862306a36Sopenharmony_ci	rtw_write32(rtwdev, RTK_PCI_HIMR1, 0);
50962306a36Sopenharmony_ci	if (rtw_chip_wcpu_11ac(rtwdev))
51062306a36Sopenharmony_ci		rtw_write32(rtwdev, RTK_PCI_HIMR3, 0);
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	rtwpci->irq_enabled = false;
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ciout:
51562306a36Sopenharmony_ci	spin_unlock_irqrestore(&rtwpci->hwirq_lock, flags);
51662306a36Sopenharmony_ci}
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_cistatic void rtw_pci_dma_reset(struct rtw_dev *rtwdev, struct rtw_pci *rtwpci)
51962306a36Sopenharmony_ci{
52062306a36Sopenharmony_ci	/* reset dma and rx tag */
52162306a36Sopenharmony_ci	rtw_write32_set(rtwdev, RTK_PCI_CTRL,
52262306a36Sopenharmony_ci			BIT_RST_TRXDMA_INTF | BIT_RX_TAG_EN);
52362306a36Sopenharmony_ci	rtwpci->rx_tag = 0;
52462306a36Sopenharmony_ci}
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_cistatic int rtw_pci_setup(struct rtw_dev *rtwdev)
52762306a36Sopenharmony_ci{
52862306a36Sopenharmony_ci	struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	rtw_pci_reset_trx_ring(rtwdev);
53162306a36Sopenharmony_ci	rtw_pci_dma_reset(rtwdev, rtwpci);
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	return 0;
53462306a36Sopenharmony_ci}
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_cistatic void rtw_pci_dma_release(struct rtw_dev *rtwdev, struct rtw_pci *rtwpci)
53762306a36Sopenharmony_ci{
53862306a36Sopenharmony_ci	struct rtw_pci_tx_ring *tx_ring;
53962306a36Sopenharmony_ci	enum rtw_tx_queue_type queue;
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	rtw_pci_reset_trx_ring(rtwdev);
54262306a36Sopenharmony_ci	for (queue = 0; queue < RTK_MAX_TX_QUEUE_NUM; queue++) {
54362306a36Sopenharmony_ci		tx_ring = &rtwpci->tx_rings[queue];
54462306a36Sopenharmony_ci		rtw_pci_free_tx_ring_skbs(rtwdev, tx_ring);
54562306a36Sopenharmony_ci	}
54662306a36Sopenharmony_ci}
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_cistatic void rtw_pci_napi_start(struct rtw_dev *rtwdev)
54962306a36Sopenharmony_ci{
55062306a36Sopenharmony_ci	struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	if (test_and_set_bit(RTW_PCI_FLAG_NAPI_RUNNING, rtwpci->flags))
55362306a36Sopenharmony_ci		return;
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	napi_enable(&rtwpci->napi);
55662306a36Sopenharmony_ci}
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_cistatic void rtw_pci_napi_stop(struct rtw_dev *rtwdev)
55962306a36Sopenharmony_ci{
56062306a36Sopenharmony_ci	struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	if (!test_and_clear_bit(RTW_PCI_FLAG_NAPI_RUNNING, rtwpci->flags))
56362306a36Sopenharmony_ci		return;
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	napi_synchronize(&rtwpci->napi);
56662306a36Sopenharmony_ci	napi_disable(&rtwpci->napi);
56762306a36Sopenharmony_ci}
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_cistatic int rtw_pci_start(struct rtw_dev *rtwdev)
57062306a36Sopenharmony_ci{
57162306a36Sopenharmony_ci	struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	rtw_pci_napi_start(rtwdev);
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	spin_lock_bh(&rtwpci->irq_lock);
57662306a36Sopenharmony_ci	rtwpci->running = true;
57762306a36Sopenharmony_ci	rtw_pci_enable_interrupt(rtwdev, rtwpci, false);
57862306a36Sopenharmony_ci	spin_unlock_bh(&rtwpci->irq_lock);
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	return 0;
58162306a36Sopenharmony_ci}
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_cistatic void rtw_pci_stop(struct rtw_dev *rtwdev)
58462306a36Sopenharmony_ci{
58562306a36Sopenharmony_ci	struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
58662306a36Sopenharmony_ci	struct pci_dev *pdev = rtwpci->pdev;
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	spin_lock_bh(&rtwpci->irq_lock);
58962306a36Sopenharmony_ci	rtwpci->running = false;
59062306a36Sopenharmony_ci	rtw_pci_disable_interrupt(rtwdev, rtwpci);
59162306a36Sopenharmony_ci	spin_unlock_bh(&rtwpci->irq_lock);
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	synchronize_irq(pdev->irq);
59462306a36Sopenharmony_ci	rtw_pci_napi_stop(rtwdev);
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci	spin_lock_bh(&rtwpci->irq_lock);
59762306a36Sopenharmony_ci	rtw_pci_dma_release(rtwdev, rtwpci);
59862306a36Sopenharmony_ci	spin_unlock_bh(&rtwpci->irq_lock);
59962306a36Sopenharmony_ci}
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_cistatic void rtw_pci_deep_ps_enter(struct rtw_dev *rtwdev)
60262306a36Sopenharmony_ci{
60362306a36Sopenharmony_ci	struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
60462306a36Sopenharmony_ci	struct rtw_pci_tx_ring *tx_ring;
60562306a36Sopenharmony_ci	enum rtw_tx_queue_type queue;
60662306a36Sopenharmony_ci	bool tx_empty = true;
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci	if (rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_TX_WAKE))
60962306a36Sopenharmony_ci		goto enter_deep_ps;
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci	lockdep_assert_held(&rtwpci->irq_lock);
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	/* Deep PS state is not allowed to TX-DMA */
61462306a36Sopenharmony_ci	for (queue = 0; queue < RTK_MAX_TX_QUEUE_NUM; queue++) {
61562306a36Sopenharmony_ci		/* BCN queue is rsvd page, does not have DMA interrupt
61662306a36Sopenharmony_ci		 * H2C queue is managed by firmware
61762306a36Sopenharmony_ci		 */
61862306a36Sopenharmony_ci		if (queue == RTW_TX_QUEUE_BCN ||
61962306a36Sopenharmony_ci		    queue == RTW_TX_QUEUE_H2C)
62062306a36Sopenharmony_ci			continue;
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci		tx_ring = &rtwpci->tx_rings[queue];
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci		/* check if there is any skb DMAing */
62562306a36Sopenharmony_ci		if (skb_queue_len(&tx_ring->queue)) {
62662306a36Sopenharmony_ci			tx_empty = false;
62762306a36Sopenharmony_ci			break;
62862306a36Sopenharmony_ci		}
62962306a36Sopenharmony_ci	}
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	if (!tx_empty) {
63262306a36Sopenharmony_ci		rtw_dbg(rtwdev, RTW_DBG_PS,
63362306a36Sopenharmony_ci			"TX path not empty, cannot enter deep power save state\n");
63462306a36Sopenharmony_ci		return;
63562306a36Sopenharmony_ci	}
63662306a36Sopenharmony_cienter_deep_ps:
63762306a36Sopenharmony_ci	set_bit(RTW_FLAG_LEISURE_PS_DEEP, rtwdev->flags);
63862306a36Sopenharmony_ci	rtw_power_mode_change(rtwdev, true);
63962306a36Sopenharmony_ci}
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_cistatic void rtw_pci_deep_ps_leave(struct rtw_dev *rtwdev)
64262306a36Sopenharmony_ci{
64362306a36Sopenharmony_ci	struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	lockdep_assert_held(&rtwpci->irq_lock);
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci	if (test_and_clear_bit(RTW_FLAG_LEISURE_PS_DEEP, rtwdev->flags))
64862306a36Sopenharmony_ci		rtw_power_mode_change(rtwdev, false);
64962306a36Sopenharmony_ci}
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_cistatic void rtw_pci_deep_ps(struct rtw_dev *rtwdev, bool enter)
65262306a36Sopenharmony_ci{
65362306a36Sopenharmony_ci	struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci	spin_lock_bh(&rtwpci->irq_lock);
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	if (enter && !test_bit(RTW_FLAG_LEISURE_PS_DEEP, rtwdev->flags))
65862306a36Sopenharmony_ci		rtw_pci_deep_ps_enter(rtwdev);
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci	if (!enter && test_bit(RTW_FLAG_LEISURE_PS_DEEP, rtwdev->flags))
66162306a36Sopenharmony_ci		rtw_pci_deep_ps_leave(rtwdev);
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci	spin_unlock_bh(&rtwpci->irq_lock);
66462306a36Sopenharmony_ci}
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_cistatic void rtw_pci_release_rsvd_page(struct rtw_pci *rtwpci,
66762306a36Sopenharmony_ci				      struct rtw_pci_tx_ring *ring)
66862306a36Sopenharmony_ci{
66962306a36Sopenharmony_ci	struct sk_buff *prev = skb_dequeue(&ring->queue);
67062306a36Sopenharmony_ci	struct rtw_pci_tx_data *tx_data;
67162306a36Sopenharmony_ci	dma_addr_t dma;
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci	if (!prev)
67462306a36Sopenharmony_ci		return;
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	tx_data = rtw_pci_get_tx_data(prev);
67762306a36Sopenharmony_ci	dma = tx_data->dma;
67862306a36Sopenharmony_ci	dma_unmap_single(&rtwpci->pdev->dev, dma, prev->len, DMA_TO_DEVICE);
67962306a36Sopenharmony_ci	dev_kfree_skb_any(prev);
68062306a36Sopenharmony_ci}
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_cistatic void rtw_pci_dma_check(struct rtw_dev *rtwdev,
68362306a36Sopenharmony_ci			      struct rtw_pci_rx_ring *rx_ring,
68462306a36Sopenharmony_ci			      u32 idx)
68562306a36Sopenharmony_ci{
68662306a36Sopenharmony_ci	struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
68762306a36Sopenharmony_ci	const struct rtw_chip_info *chip = rtwdev->chip;
68862306a36Sopenharmony_ci	struct rtw_pci_rx_buffer_desc *buf_desc;
68962306a36Sopenharmony_ci	u32 desc_sz = chip->rx_buf_desc_sz;
69062306a36Sopenharmony_ci	u16 total_pkt_size;
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci	buf_desc = (struct rtw_pci_rx_buffer_desc *)(rx_ring->r.head +
69362306a36Sopenharmony_ci						     idx * desc_sz);
69462306a36Sopenharmony_ci	total_pkt_size = le16_to_cpu(buf_desc->total_pkt_size);
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	/* rx tag mismatch, throw a warning */
69762306a36Sopenharmony_ci	if (total_pkt_size != rtwpci->rx_tag)
69862306a36Sopenharmony_ci		rtw_warn(rtwdev, "pci bus timeout, check dma status\n");
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci	rtwpci->rx_tag = (rtwpci->rx_tag + 1) % RX_TAG_MAX;
70162306a36Sopenharmony_ci}
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_cistatic u32 __pci_get_hw_tx_ring_rp(struct rtw_dev *rtwdev, u8 pci_q)
70462306a36Sopenharmony_ci{
70562306a36Sopenharmony_ci	u32 bd_idx_addr = rtw_pci_tx_queue_idx_addr[pci_q];
70662306a36Sopenharmony_ci	u32 bd_idx = rtw_read16(rtwdev, bd_idx_addr + 2);
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci	return FIELD_GET(TRX_BD_IDX_MASK, bd_idx);
70962306a36Sopenharmony_ci}
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_cistatic void __pci_flush_queue(struct rtw_dev *rtwdev, u8 pci_q, bool drop)
71262306a36Sopenharmony_ci{
71362306a36Sopenharmony_ci	struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
71462306a36Sopenharmony_ci	struct rtw_pci_tx_ring *ring = &rtwpci->tx_rings[pci_q];
71562306a36Sopenharmony_ci	u32 cur_rp;
71662306a36Sopenharmony_ci	u8 i;
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci	/* Because the time taked by the I/O in __pci_get_hw_tx_ring_rp is a
71962306a36Sopenharmony_ci	 * bit dynamic, it's hard to define a reasonable fixed total timeout to
72062306a36Sopenharmony_ci	 * use read_poll_timeout* helper. Instead, we can ensure a reasonable
72162306a36Sopenharmony_ci	 * polling times, so we just use for loop with udelay here.
72262306a36Sopenharmony_ci	 */
72362306a36Sopenharmony_ci	for (i = 0; i < 30; i++) {
72462306a36Sopenharmony_ci		cur_rp = __pci_get_hw_tx_ring_rp(rtwdev, pci_q);
72562306a36Sopenharmony_ci		if (cur_rp == ring->r.wp)
72662306a36Sopenharmony_ci			return;
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci		udelay(1);
72962306a36Sopenharmony_ci	}
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	if (!drop)
73262306a36Sopenharmony_ci		rtw_warn(rtwdev, "timed out to flush pci tx ring[%d]\n", pci_q);
73362306a36Sopenharmony_ci}
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_cistatic void __rtw_pci_flush_queues(struct rtw_dev *rtwdev, u32 pci_queues,
73662306a36Sopenharmony_ci				   bool drop)
73762306a36Sopenharmony_ci{
73862306a36Sopenharmony_ci	u8 q;
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_ci	for (q = 0; q < RTK_MAX_TX_QUEUE_NUM; q++) {
74162306a36Sopenharmony_ci		/* Unnecessary to flush BCN, H2C and HI tx queues. */
74262306a36Sopenharmony_ci		if (q == RTW_TX_QUEUE_BCN || q == RTW_TX_QUEUE_H2C ||
74362306a36Sopenharmony_ci		    q == RTW_TX_QUEUE_HI0)
74462306a36Sopenharmony_ci			continue;
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_ci		if (pci_queues & BIT(q))
74762306a36Sopenharmony_ci			__pci_flush_queue(rtwdev, q, drop);
74862306a36Sopenharmony_ci	}
74962306a36Sopenharmony_ci}
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_cistatic void rtw_pci_flush_queues(struct rtw_dev *rtwdev, u32 queues, bool drop)
75262306a36Sopenharmony_ci{
75362306a36Sopenharmony_ci	u32 pci_queues = 0;
75462306a36Sopenharmony_ci	u8 i;
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci	/* If all of the hardware queues are requested to flush,
75762306a36Sopenharmony_ci	 * flush all of the pci queues.
75862306a36Sopenharmony_ci	 */
75962306a36Sopenharmony_ci	if (queues == BIT(rtwdev->hw->queues) - 1) {
76062306a36Sopenharmony_ci		pci_queues = BIT(RTK_MAX_TX_QUEUE_NUM) - 1;
76162306a36Sopenharmony_ci	} else {
76262306a36Sopenharmony_ci		for (i = 0; i < rtwdev->hw->queues; i++)
76362306a36Sopenharmony_ci			if (queues & BIT(i))
76462306a36Sopenharmony_ci				pci_queues |= BIT(rtw_tx_ac_to_hwq(i));
76562306a36Sopenharmony_ci	}
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci	__rtw_pci_flush_queues(rtwdev, pci_queues, drop);
76862306a36Sopenharmony_ci}
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_cistatic void rtw_pci_tx_kick_off_queue(struct rtw_dev *rtwdev,
77162306a36Sopenharmony_ci				      enum rtw_tx_queue_type queue)
77262306a36Sopenharmony_ci{
77362306a36Sopenharmony_ci	struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
77462306a36Sopenharmony_ci	struct rtw_pci_tx_ring *ring;
77562306a36Sopenharmony_ci	u32 bd_idx;
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci	ring = &rtwpci->tx_rings[queue];
77862306a36Sopenharmony_ci	bd_idx = rtw_pci_tx_queue_idx_addr[queue];
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci	spin_lock_bh(&rtwpci->irq_lock);
78162306a36Sopenharmony_ci	if (!rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_TX_WAKE))
78262306a36Sopenharmony_ci		rtw_pci_deep_ps_leave(rtwdev);
78362306a36Sopenharmony_ci	rtw_write16(rtwdev, bd_idx, ring->r.wp & TRX_BD_IDX_MASK);
78462306a36Sopenharmony_ci	spin_unlock_bh(&rtwpci->irq_lock);
78562306a36Sopenharmony_ci}
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_cistatic void rtw_pci_tx_kick_off(struct rtw_dev *rtwdev)
78862306a36Sopenharmony_ci{
78962306a36Sopenharmony_ci	struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
79062306a36Sopenharmony_ci	enum rtw_tx_queue_type queue;
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci	for (queue = 0; queue < RTK_MAX_TX_QUEUE_NUM; queue++)
79362306a36Sopenharmony_ci		if (test_and_clear_bit(queue, rtwpci->tx_queued))
79462306a36Sopenharmony_ci			rtw_pci_tx_kick_off_queue(rtwdev, queue);
79562306a36Sopenharmony_ci}
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_cistatic int rtw_pci_tx_write_data(struct rtw_dev *rtwdev,
79862306a36Sopenharmony_ci				 struct rtw_tx_pkt_info *pkt_info,
79962306a36Sopenharmony_ci				 struct sk_buff *skb,
80062306a36Sopenharmony_ci				 enum rtw_tx_queue_type queue)
80162306a36Sopenharmony_ci{
80262306a36Sopenharmony_ci	struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
80362306a36Sopenharmony_ci	const struct rtw_chip_info *chip = rtwdev->chip;
80462306a36Sopenharmony_ci	struct rtw_pci_tx_ring *ring;
80562306a36Sopenharmony_ci	struct rtw_pci_tx_data *tx_data;
80662306a36Sopenharmony_ci	dma_addr_t dma;
80762306a36Sopenharmony_ci	u32 tx_pkt_desc_sz = chip->tx_pkt_desc_sz;
80862306a36Sopenharmony_ci	u32 tx_buf_desc_sz = chip->tx_buf_desc_sz;
80962306a36Sopenharmony_ci	u32 size;
81062306a36Sopenharmony_ci	u32 psb_len;
81162306a36Sopenharmony_ci	u8 *pkt_desc;
81262306a36Sopenharmony_ci	struct rtw_pci_tx_buffer_desc *buf_desc;
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci	ring = &rtwpci->tx_rings[queue];
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci	size = skb->len;
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci	if (queue == RTW_TX_QUEUE_BCN)
81962306a36Sopenharmony_ci		rtw_pci_release_rsvd_page(rtwpci, ring);
82062306a36Sopenharmony_ci	else if (!avail_desc(ring->r.wp, ring->r.rp, ring->r.len))
82162306a36Sopenharmony_ci		return -ENOSPC;
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci	pkt_desc = skb_push(skb, chip->tx_pkt_desc_sz);
82462306a36Sopenharmony_ci	memset(pkt_desc, 0, tx_pkt_desc_sz);
82562306a36Sopenharmony_ci	pkt_info->qsel = rtw_pci_get_tx_qsel(skb, queue);
82662306a36Sopenharmony_ci	rtw_tx_fill_tx_desc(pkt_info, skb);
82762306a36Sopenharmony_ci	dma = dma_map_single(&rtwpci->pdev->dev, skb->data, skb->len,
82862306a36Sopenharmony_ci			     DMA_TO_DEVICE);
82962306a36Sopenharmony_ci	if (dma_mapping_error(&rtwpci->pdev->dev, dma))
83062306a36Sopenharmony_ci		return -EBUSY;
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci	/* after this we got dma mapped, there is no way back */
83362306a36Sopenharmony_ci	buf_desc = get_tx_buffer_desc(ring, tx_buf_desc_sz);
83462306a36Sopenharmony_ci	memset(buf_desc, 0, tx_buf_desc_sz);
83562306a36Sopenharmony_ci	psb_len = (skb->len - 1) / 128 + 1;
83662306a36Sopenharmony_ci	if (queue == RTW_TX_QUEUE_BCN)
83762306a36Sopenharmony_ci		psb_len |= 1 << RTK_PCI_TXBD_OWN_OFFSET;
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci	buf_desc[0].psb_len = cpu_to_le16(psb_len);
84062306a36Sopenharmony_ci	buf_desc[0].buf_size = cpu_to_le16(tx_pkt_desc_sz);
84162306a36Sopenharmony_ci	buf_desc[0].dma = cpu_to_le32(dma);
84262306a36Sopenharmony_ci	buf_desc[1].buf_size = cpu_to_le16(size);
84362306a36Sopenharmony_ci	buf_desc[1].dma = cpu_to_le32(dma + tx_pkt_desc_sz);
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci	tx_data = rtw_pci_get_tx_data(skb);
84662306a36Sopenharmony_ci	tx_data->dma = dma;
84762306a36Sopenharmony_ci	tx_data->sn = pkt_info->sn;
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci	spin_lock_bh(&rtwpci->irq_lock);
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci	skb_queue_tail(&ring->queue, skb);
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci	if (queue == RTW_TX_QUEUE_BCN)
85462306a36Sopenharmony_ci		goto out_unlock;
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci	/* update write-index, and kick it off later */
85762306a36Sopenharmony_ci	set_bit(queue, rtwpci->tx_queued);
85862306a36Sopenharmony_ci	if (++ring->r.wp >= ring->r.len)
85962306a36Sopenharmony_ci		ring->r.wp = 0;
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_ciout_unlock:
86262306a36Sopenharmony_ci	spin_unlock_bh(&rtwpci->irq_lock);
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ci	return 0;
86562306a36Sopenharmony_ci}
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_cistatic int rtw_pci_write_data_rsvd_page(struct rtw_dev *rtwdev, u8 *buf,
86862306a36Sopenharmony_ci					u32 size)
86962306a36Sopenharmony_ci{
87062306a36Sopenharmony_ci	struct sk_buff *skb;
87162306a36Sopenharmony_ci	struct rtw_tx_pkt_info pkt_info = {0};
87262306a36Sopenharmony_ci	u8 reg_bcn_work;
87362306a36Sopenharmony_ci	int ret;
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci	skb = rtw_tx_write_data_rsvd_page_get(rtwdev, &pkt_info, buf, size);
87662306a36Sopenharmony_ci	if (!skb)
87762306a36Sopenharmony_ci		return -ENOMEM;
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci	ret = rtw_pci_tx_write_data(rtwdev, &pkt_info, skb, RTW_TX_QUEUE_BCN);
88062306a36Sopenharmony_ci	if (ret) {
88162306a36Sopenharmony_ci		rtw_err(rtwdev, "failed to write rsvd page data\n");
88262306a36Sopenharmony_ci		return ret;
88362306a36Sopenharmony_ci	}
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci	/* reserved pages go through beacon queue */
88662306a36Sopenharmony_ci	reg_bcn_work = rtw_read8(rtwdev, RTK_PCI_TXBD_BCN_WORK);
88762306a36Sopenharmony_ci	reg_bcn_work |= BIT_PCI_BCNQ_FLAG;
88862306a36Sopenharmony_ci	rtw_write8(rtwdev, RTK_PCI_TXBD_BCN_WORK, reg_bcn_work);
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci	return 0;
89162306a36Sopenharmony_ci}
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_cistatic int rtw_pci_write_data_h2c(struct rtw_dev *rtwdev, u8 *buf, u32 size)
89462306a36Sopenharmony_ci{
89562306a36Sopenharmony_ci	struct sk_buff *skb;
89662306a36Sopenharmony_ci	struct rtw_tx_pkt_info pkt_info = {0};
89762306a36Sopenharmony_ci	int ret;
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_ci	skb = rtw_tx_write_data_h2c_get(rtwdev, &pkt_info, buf, size);
90062306a36Sopenharmony_ci	if (!skb)
90162306a36Sopenharmony_ci		return -ENOMEM;
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci	ret = rtw_pci_tx_write_data(rtwdev, &pkt_info, skb, RTW_TX_QUEUE_H2C);
90462306a36Sopenharmony_ci	if (ret) {
90562306a36Sopenharmony_ci		rtw_err(rtwdev, "failed to write h2c data\n");
90662306a36Sopenharmony_ci		return ret;
90762306a36Sopenharmony_ci	}
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_ci	rtw_pci_tx_kick_off_queue(rtwdev, RTW_TX_QUEUE_H2C);
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci	return 0;
91262306a36Sopenharmony_ci}
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_cistatic int rtw_pci_tx_write(struct rtw_dev *rtwdev,
91562306a36Sopenharmony_ci			    struct rtw_tx_pkt_info *pkt_info,
91662306a36Sopenharmony_ci			    struct sk_buff *skb)
91762306a36Sopenharmony_ci{
91862306a36Sopenharmony_ci	enum rtw_tx_queue_type queue = rtw_tx_queue_mapping(skb);
91962306a36Sopenharmony_ci	struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
92062306a36Sopenharmony_ci	struct rtw_pci_tx_ring *ring;
92162306a36Sopenharmony_ci	int ret;
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci	ret = rtw_pci_tx_write_data(rtwdev, pkt_info, skb, queue);
92462306a36Sopenharmony_ci	if (ret)
92562306a36Sopenharmony_ci		return ret;
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_ci	ring = &rtwpci->tx_rings[queue];
92862306a36Sopenharmony_ci	spin_lock_bh(&rtwpci->irq_lock);
92962306a36Sopenharmony_ci	if (avail_desc(ring->r.wp, ring->r.rp, ring->r.len) < 2) {
93062306a36Sopenharmony_ci		ieee80211_stop_queue(rtwdev->hw, skb_get_queue_mapping(skb));
93162306a36Sopenharmony_ci		ring->queue_stopped = true;
93262306a36Sopenharmony_ci	}
93362306a36Sopenharmony_ci	spin_unlock_bh(&rtwpci->irq_lock);
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci	return 0;
93662306a36Sopenharmony_ci}
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_cistatic void rtw_pci_tx_isr(struct rtw_dev *rtwdev, struct rtw_pci *rtwpci,
93962306a36Sopenharmony_ci			   u8 hw_queue)
94062306a36Sopenharmony_ci{
94162306a36Sopenharmony_ci	struct ieee80211_hw *hw = rtwdev->hw;
94262306a36Sopenharmony_ci	struct ieee80211_tx_info *info;
94362306a36Sopenharmony_ci	struct rtw_pci_tx_ring *ring;
94462306a36Sopenharmony_ci	struct rtw_pci_tx_data *tx_data;
94562306a36Sopenharmony_ci	struct sk_buff *skb;
94662306a36Sopenharmony_ci	u32 count;
94762306a36Sopenharmony_ci	u32 bd_idx_addr;
94862306a36Sopenharmony_ci	u32 bd_idx, cur_rp, rp_idx;
94962306a36Sopenharmony_ci	u16 q_map;
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci	ring = &rtwpci->tx_rings[hw_queue];
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci	bd_idx_addr = rtw_pci_tx_queue_idx_addr[hw_queue];
95462306a36Sopenharmony_ci	bd_idx = rtw_read32(rtwdev, bd_idx_addr);
95562306a36Sopenharmony_ci	cur_rp = bd_idx >> 16;
95662306a36Sopenharmony_ci	cur_rp &= TRX_BD_IDX_MASK;
95762306a36Sopenharmony_ci	rp_idx = ring->r.rp;
95862306a36Sopenharmony_ci	if (cur_rp >= ring->r.rp)
95962306a36Sopenharmony_ci		count = cur_rp - ring->r.rp;
96062306a36Sopenharmony_ci	else
96162306a36Sopenharmony_ci		count = ring->r.len - (ring->r.rp - cur_rp);
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci	while (count--) {
96462306a36Sopenharmony_ci		skb = skb_dequeue(&ring->queue);
96562306a36Sopenharmony_ci		if (!skb) {
96662306a36Sopenharmony_ci			rtw_err(rtwdev, "failed to dequeue %d skb TX queue %d, BD=0x%08x, rp %d -> %d\n",
96762306a36Sopenharmony_ci				count, hw_queue, bd_idx, ring->r.rp, cur_rp);
96862306a36Sopenharmony_ci			break;
96962306a36Sopenharmony_ci		}
97062306a36Sopenharmony_ci		tx_data = rtw_pci_get_tx_data(skb);
97162306a36Sopenharmony_ci		dma_unmap_single(&rtwpci->pdev->dev, tx_data->dma, skb->len,
97262306a36Sopenharmony_ci				 DMA_TO_DEVICE);
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci		/* just free command packets from host to card */
97562306a36Sopenharmony_ci		if (hw_queue == RTW_TX_QUEUE_H2C) {
97662306a36Sopenharmony_ci			dev_kfree_skb_irq(skb);
97762306a36Sopenharmony_ci			continue;
97862306a36Sopenharmony_ci		}
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ci		if (ring->queue_stopped &&
98162306a36Sopenharmony_ci		    avail_desc(ring->r.wp, rp_idx, ring->r.len) > 4) {
98262306a36Sopenharmony_ci			q_map = skb_get_queue_mapping(skb);
98362306a36Sopenharmony_ci			ieee80211_wake_queue(hw, q_map);
98462306a36Sopenharmony_ci			ring->queue_stopped = false;
98562306a36Sopenharmony_ci		}
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci		if (++rp_idx >= ring->r.len)
98862306a36Sopenharmony_ci			rp_idx = 0;
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_ci		skb_pull(skb, rtwdev->chip->tx_pkt_desc_sz);
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_ci		info = IEEE80211_SKB_CB(skb);
99362306a36Sopenharmony_ci
99462306a36Sopenharmony_ci		/* enqueue to wait for tx report */
99562306a36Sopenharmony_ci		if (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) {
99662306a36Sopenharmony_ci			rtw_tx_report_enqueue(rtwdev, skb, tx_data->sn);
99762306a36Sopenharmony_ci			continue;
99862306a36Sopenharmony_ci		}
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_ci		/* always ACK for others, then they won't be marked as drop */
100162306a36Sopenharmony_ci		if (info->flags & IEEE80211_TX_CTL_NO_ACK)
100262306a36Sopenharmony_ci			info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED;
100362306a36Sopenharmony_ci		else
100462306a36Sopenharmony_ci			info->flags |= IEEE80211_TX_STAT_ACK;
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_ci		ieee80211_tx_info_clear_status(info);
100762306a36Sopenharmony_ci		ieee80211_tx_status_irqsafe(hw, skb);
100862306a36Sopenharmony_ci	}
100962306a36Sopenharmony_ci
101062306a36Sopenharmony_ci	ring->r.rp = cur_rp;
101162306a36Sopenharmony_ci}
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_cistatic void rtw_pci_rx_isr(struct rtw_dev *rtwdev)
101462306a36Sopenharmony_ci{
101562306a36Sopenharmony_ci	struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
101662306a36Sopenharmony_ci	struct napi_struct *napi = &rtwpci->napi;
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_ci	napi_schedule(napi);
101962306a36Sopenharmony_ci}
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_cistatic int rtw_pci_get_hw_rx_ring_nr(struct rtw_dev *rtwdev,
102262306a36Sopenharmony_ci				     struct rtw_pci *rtwpci)
102362306a36Sopenharmony_ci{
102462306a36Sopenharmony_ci	struct rtw_pci_rx_ring *ring;
102562306a36Sopenharmony_ci	int count = 0;
102662306a36Sopenharmony_ci	u32 tmp, cur_wp;
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_ci	ring = &rtwpci->rx_rings[RTW_RX_QUEUE_MPDU];
102962306a36Sopenharmony_ci	tmp = rtw_read32(rtwdev, RTK_PCI_RXBD_IDX_MPDUQ);
103062306a36Sopenharmony_ci	cur_wp = u32_get_bits(tmp, TRX_BD_HW_IDX_MASK);
103162306a36Sopenharmony_ci	if (cur_wp >= ring->r.wp)
103262306a36Sopenharmony_ci		count = cur_wp - ring->r.wp;
103362306a36Sopenharmony_ci	else
103462306a36Sopenharmony_ci		count = ring->r.len - (ring->r.wp - cur_wp);
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_ci	return count;
103762306a36Sopenharmony_ci}
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_cistatic u32 rtw_pci_rx_napi(struct rtw_dev *rtwdev, struct rtw_pci *rtwpci,
104062306a36Sopenharmony_ci			   u8 hw_queue, u32 limit)
104162306a36Sopenharmony_ci{
104262306a36Sopenharmony_ci	const struct rtw_chip_info *chip = rtwdev->chip;
104362306a36Sopenharmony_ci	struct napi_struct *napi = &rtwpci->napi;
104462306a36Sopenharmony_ci	struct rtw_pci_rx_ring *ring = &rtwpci->rx_rings[RTW_RX_QUEUE_MPDU];
104562306a36Sopenharmony_ci	struct rtw_rx_pkt_stat pkt_stat;
104662306a36Sopenharmony_ci	struct ieee80211_rx_status rx_status;
104762306a36Sopenharmony_ci	struct sk_buff *skb, *new;
104862306a36Sopenharmony_ci	u32 cur_rp = ring->r.rp;
104962306a36Sopenharmony_ci	u32 count, rx_done = 0;
105062306a36Sopenharmony_ci	u32 pkt_offset;
105162306a36Sopenharmony_ci	u32 pkt_desc_sz = chip->rx_pkt_desc_sz;
105262306a36Sopenharmony_ci	u32 buf_desc_sz = chip->rx_buf_desc_sz;
105362306a36Sopenharmony_ci	u32 new_len;
105462306a36Sopenharmony_ci	u8 *rx_desc;
105562306a36Sopenharmony_ci	dma_addr_t dma;
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_ci	count = rtw_pci_get_hw_rx_ring_nr(rtwdev, rtwpci);
105862306a36Sopenharmony_ci	count = min(count, limit);
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_ci	while (count--) {
106162306a36Sopenharmony_ci		rtw_pci_dma_check(rtwdev, ring, cur_rp);
106262306a36Sopenharmony_ci		skb = ring->buf[cur_rp];
106362306a36Sopenharmony_ci		dma = *((dma_addr_t *)skb->cb);
106462306a36Sopenharmony_ci		dma_sync_single_for_cpu(rtwdev->dev, dma, RTK_PCI_RX_BUF_SIZE,
106562306a36Sopenharmony_ci					DMA_FROM_DEVICE);
106662306a36Sopenharmony_ci		rx_desc = skb->data;
106762306a36Sopenharmony_ci		chip->ops->query_rx_desc(rtwdev, rx_desc, &pkt_stat, &rx_status);
106862306a36Sopenharmony_ci
106962306a36Sopenharmony_ci		/* offset from rx_desc to payload */
107062306a36Sopenharmony_ci		pkt_offset = pkt_desc_sz + pkt_stat.drv_info_sz +
107162306a36Sopenharmony_ci			     pkt_stat.shift;
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci		/* allocate a new skb for this frame,
107462306a36Sopenharmony_ci		 * discard the frame if none available
107562306a36Sopenharmony_ci		 */
107662306a36Sopenharmony_ci		new_len = pkt_stat.pkt_len + pkt_offset;
107762306a36Sopenharmony_ci		new = dev_alloc_skb(new_len);
107862306a36Sopenharmony_ci		if (WARN_ONCE(!new, "rx routine starvation\n"))
107962306a36Sopenharmony_ci			goto next_rp;
108062306a36Sopenharmony_ci
108162306a36Sopenharmony_ci		/* put the DMA data including rx_desc from phy to new skb */
108262306a36Sopenharmony_ci		skb_put_data(new, skb->data, new_len);
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_ci		if (pkt_stat.is_c2h) {
108562306a36Sopenharmony_ci			rtw_fw_c2h_cmd_rx_irqsafe(rtwdev, pkt_offset, new);
108662306a36Sopenharmony_ci		} else {
108762306a36Sopenharmony_ci			/* remove rx_desc */
108862306a36Sopenharmony_ci			skb_pull(new, pkt_offset);
108962306a36Sopenharmony_ci
109062306a36Sopenharmony_ci			rtw_rx_stats(rtwdev, pkt_stat.vif, new);
109162306a36Sopenharmony_ci			memcpy(new->cb, &rx_status, sizeof(rx_status));
109262306a36Sopenharmony_ci			ieee80211_rx_napi(rtwdev->hw, NULL, new, napi);
109362306a36Sopenharmony_ci			rx_done++;
109462306a36Sopenharmony_ci		}
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_cinext_rp:
109762306a36Sopenharmony_ci		/* new skb delivered to mac80211, re-enable original skb DMA */
109862306a36Sopenharmony_ci		rtw_pci_sync_rx_desc_device(rtwdev, dma, ring, cur_rp,
109962306a36Sopenharmony_ci					    buf_desc_sz);
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_ci		/* host read next element in ring */
110262306a36Sopenharmony_ci		if (++cur_rp >= ring->r.len)
110362306a36Sopenharmony_ci			cur_rp = 0;
110462306a36Sopenharmony_ci	}
110562306a36Sopenharmony_ci
110662306a36Sopenharmony_ci	ring->r.rp = cur_rp;
110762306a36Sopenharmony_ci	/* 'rp', the last position we have read, is seen as previous posistion
110862306a36Sopenharmony_ci	 * of 'wp' that is used to calculate 'count' next time.
110962306a36Sopenharmony_ci	 */
111062306a36Sopenharmony_ci	ring->r.wp = cur_rp;
111162306a36Sopenharmony_ci	rtw_write16(rtwdev, RTK_PCI_RXBD_IDX_MPDUQ, ring->r.rp);
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_ci	return rx_done;
111462306a36Sopenharmony_ci}
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_cistatic void rtw_pci_irq_recognized(struct rtw_dev *rtwdev,
111762306a36Sopenharmony_ci				   struct rtw_pci *rtwpci, u32 *irq_status)
111862306a36Sopenharmony_ci{
111962306a36Sopenharmony_ci	unsigned long flags;
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_ci	spin_lock_irqsave(&rtwpci->hwirq_lock, flags);
112262306a36Sopenharmony_ci
112362306a36Sopenharmony_ci	irq_status[0] = rtw_read32(rtwdev, RTK_PCI_HISR0);
112462306a36Sopenharmony_ci	irq_status[1] = rtw_read32(rtwdev, RTK_PCI_HISR1);
112562306a36Sopenharmony_ci	if (rtw_chip_wcpu_11ac(rtwdev))
112662306a36Sopenharmony_ci		irq_status[3] = rtw_read32(rtwdev, RTK_PCI_HISR3);
112762306a36Sopenharmony_ci	else
112862306a36Sopenharmony_ci		irq_status[3] = 0;
112962306a36Sopenharmony_ci	irq_status[0] &= rtwpci->irq_mask[0];
113062306a36Sopenharmony_ci	irq_status[1] &= rtwpci->irq_mask[1];
113162306a36Sopenharmony_ci	irq_status[3] &= rtwpci->irq_mask[3];
113262306a36Sopenharmony_ci	rtw_write32(rtwdev, RTK_PCI_HISR0, irq_status[0]);
113362306a36Sopenharmony_ci	rtw_write32(rtwdev, RTK_PCI_HISR1, irq_status[1]);
113462306a36Sopenharmony_ci	if (rtw_chip_wcpu_11ac(rtwdev))
113562306a36Sopenharmony_ci		rtw_write32(rtwdev, RTK_PCI_HISR3, irq_status[3]);
113662306a36Sopenharmony_ci
113762306a36Sopenharmony_ci	spin_unlock_irqrestore(&rtwpci->hwirq_lock, flags);
113862306a36Sopenharmony_ci}
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_cistatic irqreturn_t rtw_pci_interrupt_handler(int irq, void *dev)
114162306a36Sopenharmony_ci{
114262306a36Sopenharmony_ci	struct rtw_dev *rtwdev = dev;
114362306a36Sopenharmony_ci	struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_ci	/* disable RTW PCI interrupt to avoid more interrupts before the end of
114662306a36Sopenharmony_ci	 * thread function
114762306a36Sopenharmony_ci	 *
114862306a36Sopenharmony_ci	 * disable HIMR here to also avoid new HISR flag being raised before
114962306a36Sopenharmony_ci	 * the HISRs have been Write-1-cleared for MSI. If not all of the HISRs
115062306a36Sopenharmony_ci	 * are cleared, the edge-triggered interrupt will not be generated when
115162306a36Sopenharmony_ci	 * a new HISR flag is set.
115262306a36Sopenharmony_ci	 */
115362306a36Sopenharmony_ci	rtw_pci_disable_interrupt(rtwdev, rtwpci);
115462306a36Sopenharmony_ci
115562306a36Sopenharmony_ci	return IRQ_WAKE_THREAD;
115662306a36Sopenharmony_ci}
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_cistatic irqreturn_t rtw_pci_interrupt_threadfn(int irq, void *dev)
115962306a36Sopenharmony_ci{
116062306a36Sopenharmony_ci	struct rtw_dev *rtwdev = dev;
116162306a36Sopenharmony_ci	struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
116262306a36Sopenharmony_ci	u32 irq_status[4];
116362306a36Sopenharmony_ci	bool rx = false;
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_ci	spin_lock_bh(&rtwpci->irq_lock);
116662306a36Sopenharmony_ci	rtw_pci_irq_recognized(rtwdev, rtwpci, irq_status);
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_ci	if (irq_status[0] & IMR_MGNTDOK)
116962306a36Sopenharmony_ci		rtw_pci_tx_isr(rtwdev, rtwpci, RTW_TX_QUEUE_MGMT);
117062306a36Sopenharmony_ci	if (irq_status[0] & IMR_HIGHDOK)
117162306a36Sopenharmony_ci		rtw_pci_tx_isr(rtwdev, rtwpci, RTW_TX_QUEUE_HI0);
117262306a36Sopenharmony_ci	if (irq_status[0] & IMR_BEDOK)
117362306a36Sopenharmony_ci		rtw_pci_tx_isr(rtwdev, rtwpci, RTW_TX_QUEUE_BE);
117462306a36Sopenharmony_ci	if (irq_status[0] & IMR_BKDOK)
117562306a36Sopenharmony_ci		rtw_pci_tx_isr(rtwdev, rtwpci, RTW_TX_QUEUE_BK);
117662306a36Sopenharmony_ci	if (irq_status[0] & IMR_VODOK)
117762306a36Sopenharmony_ci		rtw_pci_tx_isr(rtwdev, rtwpci, RTW_TX_QUEUE_VO);
117862306a36Sopenharmony_ci	if (irq_status[0] & IMR_VIDOK)
117962306a36Sopenharmony_ci		rtw_pci_tx_isr(rtwdev, rtwpci, RTW_TX_QUEUE_VI);
118062306a36Sopenharmony_ci	if (irq_status[3] & IMR_H2CDOK)
118162306a36Sopenharmony_ci		rtw_pci_tx_isr(rtwdev, rtwpci, RTW_TX_QUEUE_H2C);
118262306a36Sopenharmony_ci	if (irq_status[0] & IMR_ROK) {
118362306a36Sopenharmony_ci		rtw_pci_rx_isr(rtwdev);
118462306a36Sopenharmony_ci		rx = true;
118562306a36Sopenharmony_ci	}
118662306a36Sopenharmony_ci	if (unlikely(irq_status[0] & IMR_C2HCMD))
118762306a36Sopenharmony_ci		rtw_fw_c2h_cmd_isr(rtwdev);
118862306a36Sopenharmony_ci
118962306a36Sopenharmony_ci	/* all of the jobs for this interrupt have been done */
119062306a36Sopenharmony_ci	if (rtwpci->running)
119162306a36Sopenharmony_ci		rtw_pci_enable_interrupt(rtwdev, rtwpci, rx);
119262306a36Sopenharmony_ci	spin_unlock_bh(&rtwpci->irq_lock);
119362306a36Sopenharmony_ci
119462306a36Sopenharmony_ci	return IRQ_HANDLED;
119562306a36Sopenharmony_ci}
119662306a36Sopenharmony_ci
119762306a36Sopenharmony_cistatic int rtw_pci_io_mapping(struct rtw_dev *rtwdev,
119862306a36Sopenharmony_ci			      struct pci_dev *pdev)
119962306a36Sopenharmony_ci{
120062306a36Sopenharmony_ci	struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
120162306a36Sopenharmony_ci	unsigned long len;
120262306a36Sopenharmony_ci	u8 bar_id = 2;
120362306a36Sopenharmony_ci	int ret;
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_ci	ret = pci_request_regions(pdev, KBUILD_MODNAME);
120662306a36Sopenharmony_ci	if (ret) {
120762306a36Sopenharmony_ci		rtw_err(rtwdev, "failed to request pci regions\n");
120862306a36Sopenharmony_ci		return ret;
120962306a36Sopenharmony_ci	}
121062306a36Sopenharmony_ci
121162306a36Sopenharmony_ci	len = pci_resource_len(pdev, bar_id);
121262306a36Sopenharmony_ci	rtwpci->mmap = pci_iomap(pdev, bar_id, len);
121362306a36Sopenharmony_ci	if (!rtwpci->mmap) {
121462306a36Sopenharmony_ci		pci_release_regions(pdev);
121562306a36Sopenharmony_ci		rtw_err(rtwdev, "failed to map pci memory\n");
121662306a36Sopenharmony_ci		return -ENOMEM;
121762306a36Sopenharmony_ci	}
121862306a36Sopenharmony_ci
121962306a36Sopenharmony_ci	return 0;
122062306a36Sopenharmony_ci}
122162306a36Sopenharmony_ci
122262306a36Sopenharmony_cistatic void rtw_pci_io_unmapping(struct rtw_dev *rtwdev,
122362306a36Sopenharmony_ci				 struct pci_dev *pdev)
122462306a36Sopenharmony_ci{
122562306a36Sopenharmony_ci	struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
122662306a36Sopenharmony_ci
122762306a36Sopenharmony_ci	if (rtwpci->mmap) {
122862306a36Sopenharmony_ci		pci_iounmap(pdev, rtwpci->mmap);
122962306a36Sopenharmony_ci		pci_release_regions(pdev);
123062306a36Sopenharmony_ci	}
123162306a36Sopenharmony_ci}
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_cistatic void rtw_dbi_write8(struct rtw_dev *rtwdev, u16 addr, u8 data)
123462306a36Sopenharmony_ci{
123562306a36Sopenharmony_ci	u16 write_addr;
123662306a36Sopenharmony_ci	u16 remainder = addr & ~(BITS_DBI_WREN | BITS_DBI_ADDR_MASK);
123762306a36Sopenharmony_ci	u8 flag;
123862306a36Sopenharmony_ci	u8 cnt;
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_ci	write_addr = addr & BITS_DBI_ADDR_MASK;
124162306a36Sopenharmony_ci	write_addr |= u16_encode_bits(BIT(remainder), BITS_DBI_WREN);
124262306a36Sopenharmony_ci	rtw_write8(rtwdev, REG_DBI_WDATA_V1 + remainder, data);
124362306a36Sopenharmony_ci	rtw_write16(rtwdev, REG_DBI_FLAG_V1, write_addr);
124462306a36Sopenharmony_ci	rtw_write8(rtwdev, REG_DBI_FLAG_V1 + 2, BIT_DBI_WFLAG >> 16);
124562306a36Sopenharmony_ci
124662306a36Sopenharmony_ci	for (cnt = 0; cnt < RTW_PCI_WR_RETRY_CNT; cnt++) {
124762306a36Sopenharmony_ci		flag = rtw_read8(rtwdev, REG_DBI_FLAG_V1 + 2);
124862306a36Sopenharmony_ci		if (flag == 0)
124962306a36Sopenharmony_ci			return;
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_ci		udelay(10);
125262306a36Sopenharmony_ci	}
125362306a36Sopenharmony_ci
125462306a36Sopenharmony_ci	WARN(flag, "failed to write to DBI register, addr=0x%04x\n", addr);
125562306a36Sopenharmony_ci}
125662306a36Sopenharmony_ci
125762306a36Sopenharmony_cistatic int rtw_dbi_read8(struct rtw_dev *rtwdev, u16 addr, u8 *value)
125862306a36Sopenharmony_ci{
125962306a36Sopenharmony_ci	u16 read_addr = addr & BITS_DBI_ADDR_MASK;
126062306a36Sopenharmony_ci	u8 flag;
126162306a36Sopenharmony_ci	u8 cnt;
126262306a36Sopenharmony_ci
126362306a36Sopenharmony_ci	rtw_write16(rtwdev, REG_DBI_FLAG_V1, read_addr);
126462306a36Sopenharmony_ci	rtw_write8(rtwdev, REG_DBI_FLAG_V1 + 2, BIT_DBI_RFLAG >> 16);
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_ci	for (cnt = 0; cnt < RTW_PCI_WR_RETRY_CNT; cnt++) {
126762306a36Sopenharmony_ci		flag = rtw_read8(rtwdev, REG_DBI_FLAG_V1 + 2);
126862306a36Sopenharmony_ci		if (flag == 0) {
126962306a36Sopenharmony_ci			read_addr = REG_DBI_RDATA_V1 + (addr & 3);
127062306a36Sopenharmony_ci			*value = rtw_read8(rtwdev, read_addr);
127162306a36Sopenharmony_ci			return 0;
127262306a36Sopenharmony_ci		}
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_ci		udelay(10);
127562306a36Sopenharmony_ci	}
127662306a36Sopenharmony_ci
127762306a36Sopenharmony_ci	WARN(1, "failed to read DBI register, addr=0x%04x\n", addr);
127862306a36Sopenharmony_ci	return -EIO;
127962306a36Sopenharmony_ci}
128062306a36Sopenharmony_ci
128162306a36Sopenharmony_cistatic void rtw_mdio_write(struct rtw_dev *rtwdev, u8 addr, u16 data, bool g1)
128262306a36Sopenharmony_ci{
128362306a36Sopenharmony_ci	u8 page;
128462306a36Sopenharmony_ci	u8 wflag;
128562306a36Sopenharmony_ci	u8 cnt;
128662306a36Sopenharmony_ci
128762306a36Sopenharmony_ci	rtw_write16(rtwdev, REG_MDIO_V1, data);
128862306a36Sopenharmony_ci
128962306a36Sopenharmony_ci	page = addr < RTW_PCI_MDIO_PG_SZ ? 0 : 1;
129062306a36Sopenharmony_ci	page += g1 ? RTW_PCI_MDIO_PG_OFFS_G1 : RTW_PCI_MDIO_PG_OFFS_G2;
129162306a36Sopenharmony_ci	rtw_write8(rtwdev, REG_PCIE_MIX_CFG, addr & BITS_MDIO_ADDR_MASK);
129262306a36Sopenharmony_ci	rtw_write8(rtwdev, REG_PCIE_MIX_CFG + 3, page);
129362306a36Sopenharmony_ci	rtw_write32_mask(rtwdev, REG_PCIE_MIX_CFG, BIT_MDIO_WFLAG_V1, 1);
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_ci	for (cnt = 0; cnt < RTW_PCI_WR_RETRY_CNT; cnt++) {
129662306a36Sopenharmony_ci		wflag = rtw_read32_mask(rtwdev, REG_PCIE_MIX_CFG,
129762306a36Sopenharmony_ci					BIT_MDIO_WFLAG_V1);
129862306a36Sopenharmony_ci		if (wflag == 0)
129962306a36Sopenharmony_ci			return;
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_ci		udelay(10);
130262306a36Sopenharmony_ci	}
130362306a36Sopenharmony_ci
130462306a36Sopenharmony_ci	WARN(wflag, "failed to write to MDIO register, addr=0x%02x\n", addr);
130562306a36Sopenharmony_ci}
130662306a36Sopenharmony_ci
130762306a36Sopenharmony_cistatic void rtw_pci_clkreq_set(struct rtw_dev *rtwdev, bool enable)
130862306a36Sopenharmony_ci{
130962306a36Sopenharmony_ci	u8 value;
131062306a36Sopenharmony_ci	int ret;
131162306a36Sopenharmony_ci
131262306a36Sopenharmony_ci	if (rtw_pci_disable_aspm)
131362306a36Sopenharmony_ci		return;
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_ci	ret = rtw_dbi_read8(rtwdev, RTK_PCIE_LINK_CFG, &value);
131662306a36Sopenharmony_ci	if (ret) {
131762306a36Sopenharmony_ci		rtw_err(rtwdev, "failed to read CLKREQ_L1, ret=%d", ret);
131862306a36Sopenharmony_ci		return;
131962306a36Sopenharmony_ci	}
132062306a36Sopenharmony_ci
132162306a36Sopenharmony_ci	if (enable)
132262306a36Sopenharmony_ci		value |= BIT_CLKREQ_SW_EN;
132362306a36Sopenharmony_ci	else
132462306a36Sopenharmony_ci		value &= ~BIT_CLKREQ_SW_EN;
132562306a36Sopenharmony_ci
132662306a36Sopenharmony_ci	rtw_dbi_write8(rtwdev, RTK_PCIE_LINK_CFG, value);
132762306a36Sopenharmony_ci}
132862306a36Sopenharmony_ci
132962306a36Sopenharmony_cistatic void rtw_pci_clkreq_pad_low(struct rtw_dev *rtwdev, bool enable)
133062306a36Sopenharmony_ci{
133162306a36Sopenharmony_ci	u8 value;
133262306a36Sopenharmony_ci	int ret;
133362306a36Sopenharmony_ci
133462306a36Sopenharmony_ci	ret = rtw_dbi_read8(rtwdev, RTK_PCIE_LINK_CFG, &value);
133562306a36Sopenharmony_ci	if (ret) {
133662306a36Sopenharmony_ci		rtw_err(rtwdev, "failed to read CLKREQ_L1, ret=%d", ret);
133762306a36Sopenharmony_ci		return;
133862306a36Sopenharmony_ci	}
133962306a36Sopenharmony_ci
134062306a36Sopenharmony_ci	if (enable)
134162306a36Sopenharmony_ci		value &= ~BIT_CLKREQ_N_PAD;
134262306a36Sopenharmony_ci	else
134362306a36Sopenharmony_ci		value |= BIT_CLKREQ_N_PAD;
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_ci	rtw_dbi_write8(rtwdev, RTK_PCIE_LINK_CFG, value);
134662306a36Sopenharmony_ci}
134762306a36Sopenharmony_ci
134862306a36Sopenharmony_cistatic void rtw_pci_aspm_set(struct rtw_dev *rtwdev, bool enable)
134962306a36Sopenharmony_ci{
135062306a36Sopenharmony_ci	u8 value;
135162306a36Sopenharmony_ci	int ret;
135262306a36Sopenharmony_ci
135362306a36Sopenharmony_ci	if (rtw_pci_disable_aspm)
135462306a36Sopenharmony_ci		return;
135562306a36Sopenharmony_ci
135662306a36Sopenharmony_ci	ret = rtw_dbi_read8(rtwdev, RTK_PCIE_LINK_CFG, &value);
135762306a36Sopenharmony_ci	if (ret) {
135862306a36Sopenharmony_ci		rtw_err(rtwdev, "failed to read ASPM, ret=%d", ret);
135962306a36Sopenharmony_ci		return;
136062306a36Sopenharmony_ci	}
136162306a36Sopenharmony_ci
136262306a36Sopenharmony_ci	if (enable)
136362306a36Sopenharmony_ci		value |= BIT_L1_SW_EN;
136462306a36Sopenharmony_ci	else
136562306a36Sopenharmony_ci		value &= ~BIT_L1_SW_EN;
136662306a36Sopenharmony_ci
136762306a36Sopenharmony_ci	rtw_dbi_write8(rtwdev, RTK_PCIE_LINK_CFG, value);
136862306a36Sopenharmony_ci}
136962306a36Sopenharmony_ci
137062306a36Sopenharmony_cistatic void rtw_pci_link_ps(struct rtw_dev *rtwdev, bool enter)
137162306a36Sopenharmony_ci{
137262306a36Sopenharmony_ci	struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
137362306a36Sopenharmony_ci
137462306a36Sopenharmony_ci	/* Like CLKREQ, ASPM is also implemented by two HW modules, and can
137562306a36Sopenharmony_ci	 * only be enabled when host supports it.
137662306a36Sopenharmony_ci	 *
137762306a36Sopenharmony_ci	 * And ASPM mechanism should be enabled when driver/firmware enters
137862306a36Sopenharmony_ci	 * power save mode, without having heavy traffic. Because we've
137962306a36Sopenharmony_ci	 * experienced some inter-operability issues that the link tends
138062306a36Sopenharmony_ci	 * to enter L1 state on the fly even when driver is having high
138162306a36Sopenharmony_ci	 * throughput. This is probably because the ASPM behavior slightly
138262306a36Sopenharmony_ci	 * varies from different SOC.
138362306a36Sopenharmony_ci	 */
138462306a36Sopenharmony_ci	if (!(rtwpci->link_ctrl & PCI_EXP_LNKCTL_ASPM_L1))
138562306a36Sopenharmony_ci		return;
138662306a36Sopenharmony_ci
138762306a36Sopenharmony_ci	if ((enter && atomic_dec_if_positive(&rtwpci->link_usage) == 0) ||
138862306a36Sopenharmony_ci	    (!enter && atomic_inc_return(&rtwpci->link_usage) == 1))
138962306a36Sopenharmony_ci		rtw_pci_aspm_set(rtwdev, enter);
139062306a36Sopenharmony_ci}
139162306a36Sopenharmony_ci
139262306a36Sopenharmony_cistatic void rtw_pci_link_cfg(struct rtw_dev *rtwdev)
139362306a36Sopenharmony_ci{
139462306a36Sopenharmony_ci	const struct rtw_chip_info *chip = rtwdev->chip;
139562306a36Sopenharmony_ci	struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
139662306a36Sopenharmony_ci	struct pci_dev *pdev = rtwpci->pdev;
139762306a36Sopenharmony_ci	u16 link_ctrl;
139862306a36Sopenharmony_ci	int ret;
139962306a36Sopenharmony_ci
140062306a36Sopenharmony_ci	/* RTL8822CE has enabled REFCLK auto calibration, it does not need
140162306a36Sopenharmony_ci	 * to add clock delay to cover the REFCLK timing gap.
140262306a36Sopenharmony_ci	 */
140362306a36Sopenharmony_ci	if (chip->id == RTW_CHIP_TYPE_8822C)
140462306a36Sopenharmony_ci		rtw_dbi_write8(rtwdev, RTK_PCIE_CLKDLY_CTRL, 0);
140562306a36Sopenharmony_ci
140662306a36Sopenharmony_ci	/* Though there is standard PCIE configuration space to set the
140762306a36Sopenharmony_ci	 * link control register, but by Realtek's design, driver should
140862306a36Sopenharmony_ci	 * check if host supports CLKREQ/ASPM to enable the HW module.
140962306a36Sopenharmony_ci	 *
141062306a36Sopenharmony_ci	 * These functions are implemented by two HW modules associated,
141162306a36Sopenharmony_ci	 * one is responsible to access PCIE configuration space to
141262306a36Sopenharmony_ci	 * follow the host settings, and another is in charge of doing
141362306a36Sopenharmony_ci	 * CLKREQ/ASPM mechanisms, it is default disabled. Because sometimes
141462306a36Sopenharmony_ci	 * the host does not support it, and due to some reasons or wrong
141562306a36Sopenharmony_ci	 * settings (ex. CLKREQ# not Bi-Direction), it could lead to device
141662306a36Sopenharmony_ci	 * loss if HW misbehaves on the link.
141762306a36Sopenharmony_ci	 *
141862306a36Sopenharmony_ci	 * Hence it's designed that driver should first check the PCIE
141962306a36Sopenharmony_ci	 * configuration space is sync'ed and enabled, then driver can turn
142062306a36Sopenharmony_ci	 * on the other module that is actually working on the mechanism.
142162306a36Sopenharmony_ci	 */
142262306a36Sopenharmony_ci	ret = pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &link_ctrl);
142362306a36Sopenharmony_ci	if (ret) {
142462306a36Sopenharmony_ci		rtw_err(rtwdev, "failed to read PCI cap, ret=%d\n", ret);
142562306a36Sopenharmony_ci		return;
142662306a36Sopenharmony_ci	}
142762306a36Sopenharmony_ci
142862306a36Sopenharmony_ci	if (link_ctrl & PCI_EXP_LNKCTL_CLKREQ_EN)
142962306a36Sopenharmony_ci		rtw_pci_clkreq_set(rtwdev, true);
143062306a36Sopenharmony_ci
143162306a36Sopenharmony_ci	rtwpci->link_ctrl = link_ctrl;
143262306a36Sopenharmony_ci}
143362306a36Sopenharmony_ci
143462306a36Sopenharmony_cistatic void rtw_pci_interface_cfg(struct rtw_dev *rtwdev)
143562306a36Sopenharmony_ci{
143662306a36Sopenharmony_ci	const struct rtw_chip_info *chip = rtwdev->chip;
143762306a36Sopenharmony_ci
143862306a36Sopenharmony_ci	switch (chip->id) {
143962306a36Sopenharmony_ci	case RTW_CHIP_TYPE_8822C:
144062306a36Sopenharmony_ci		if (rtwdev->hal.cut_version >= RTW_CHIP_VER_CUT_D)
144162306a36Sopenharmony_ci			rtw_write32_mask(rtwdev, REG_HCI_MIX_CFG,
144262306a36Sopenharmony_ci					 BIT_PCIE_EMAC_PDN_AUX_TO_FAST_CLK, 1);
144362306a36Sopenharmony_ci		break;
144462306a36Sopenharmony_ci	default:
144562306a36Sopenharmony_ci		break;
144662306a36Sopenharmony_ci	}
144762306a36Sopenharmony_ci}
144862306a36Sopenharmony_ci
144962306a36Sopenharmony_cistatic void rtw_pci_phy_cfg(struct rtw_dev *rtwdev)
145062306a36Sopenharmony_ci{
145162306a36Sopenharmony_ci	struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
145262306a36Sopenharmony_ci	const struct rtw_chip_info *chip = rtwdev->chip;
145362306a36Sopenharmony_ci	struct pci_dev *pdev = rtwpci->pdev;
145462306a36Sopenharmony_ci	const struct rtw_intf_phy_para *para;
145562306a36Sopenharmony_ci	u16 cut;
145662306a36Sopenharmony_ci	u16 value;
145762306a36Sopenharmony_ci	u16 offset;
145862306a36Sopenharmony_ci	int i;
145962306a36Sopenharmony_ci	int ret;
146062306a36Sopenharmony_ci
146162306a36Sopenharmony_ci	cut = BIT(0) << rtwdev->hal.cut_version;
146262306a36Sopenharmony_ci
146362306a36Sopenharmony_ci	for (i = 0; i < chip->intf_table->n_gen1_para; i++) {
146462306a36Sopenharmony_ci		para = &chip->intf_table->gen1_para[i];
146562306a36Sopenharmony_ci		if (!(para->cut_mask & cut))
146662306a36Sopenharmony_ci			continue;
146762306a36Sopenharmony_ci		if (para->offset == 0xffff)
146862306a36Sopenharmony_ci			break;
146962306a36Sopenharmony_ci		offset = para->offset;
147062306a36Sopenharmony_ci		value = para->value;
147162306a36Sopenharmony_ci		if (para->ip_sel == RTW_IP_SEL_PHY)
147262306a36Sopenharmony_ci			rtw_mdio_write(rtwdev, offset, value, true);
147362306a36Sopenharmony_ci		else
147462306a36Sopenharmony_ci			rtw_dbi_write8(rtwdev, offset, value);
147562306a36Sopenharmony_ci	}
147662306a36Sopenharmony_ci
147762306a36Sopenharmony_ci	for (i = 0; i < chip->intf_table->n_gen2_para; i++) {
147862306a36Sopenharmony_ci		para = &chip->intf_table->gen2_para[i];
147962306a36Sopenharmony_ci		if (!(para->cut_mask & cut))
148062306a36Sopenharmony_ci			continue;
148162306a36Sopenharmony_ci		if (para->offset == 0xffff)
148262306a36Sopenharmony_ci			break;
148362306a36Sopenharmony_ci		offset = para->offset;
148462306a36Sopenharmony_ci		value = para->value;
148562306a36Sopenharmony_ci		if (para->ip_sel == RTW_IP_SEL_PHY)
148662306a36Sopenharmony_ci			rtw_mdio_write(rtwdev, offset, value, false);
148762306a36Sopenharmony_ci		else
148862306a36Sopenharmony_ci			rtw_dbi_write8(rtwdev, offset, value);
148962306a36Sopenharmony_ci	}
149062306a36Sopenharmony_ci
149162306a36Sopenharmony_ci	rtw_pci_link_cfg(rtwdev);
149262306a36Sopenharmony_ci
149362306a36Sopenharmony_ci	/* Disable 8821ce completion timeout by default */
149462306a36Sopenharmony_ci	if (chip->id == RTW_CHIP_TYPE_8821C) {
149562306a36Sopenharmony_ci		ret = pcie_capability_set_word(pdev, PCI_EXP_DEVCTL2,
149662306a36Sopenharmony_ci					       PCI_EXP_DEVCTL2_COMP_TMOUT_DIS);
149762306a36Sopenharmony_ci		if (ret)
149862306a36Sopenharmony_ci			rtw_err(rtwdev, "failed to set PCI cap, ret = %d\n",
149962306a36Sopenharmony_ci				ret);
150062306a36Sopenharmony_ci	}
150162306a36Sopenharmony_ci}
150262306a36Sopenharmony_ci
150362306a36Sopenharmony_cistatic int __maybe_unused rtw_pci_suspend(struct device *dev)
150462306a36Sopenharmony_ci{
150562306a36Sopenharmony_ci	struct ieee80211_hw *hw = dev_get_drvdata(dev);
150662306a36Sopenharmony_ci	struct rtw_dev *rtwdev = hw->priv;
150762306a36Sopenharmony_ci	const struct rtw_chip_info *chip = rtwdev->chip;
150862306a36Sopenharmony_ci	struct rtw_efuse *efuse = &rtwdev->efuse;
150962306a36Sopenharmony_ci
151062306a36Sopenharmony_ci	if (chip->id == RTW_CHIP_TYPE_8822C && efuse->rfe_option == 6)
151162306a36Sopenharmony_ci		rtw_pci_clkreq_pad_low(rtwdev, true);
151262306a36Sopenharmony_ci	return 0;
151362306a36Sopenharmony_ci}
151462306a36Sopenharmony_ci
151562306a36Sopenharmony_cistatic int __maybe_unused rtw_pci_resume(struct device *dev)
151662306a36Sopenharmony_ci{
151762306a36Sopenharmony_ci	struct ieee80211_hw *hw = dev_get_drvdata(dev);
151862306a36Sopenharmony_ci	struct rtw_dev *rtwdev = hw->priv;
151962306a36Sopenharmony_ci	const struct rtw_chip_info *chip = rtwdev->chip;
152062306a36Sopenharmony_ci	struct rtw_efuse *efuse = &rtwdev->efuse;
152162306a36Sopenharmony_ci
152262306a36Sopenharmony_ci	if (chip->id == RTW_CHIP_TYPE_8822C && efuse->rfe_option == 6)
152362306a36Sopenharmony_ci		rtw_pci_clkreq_pad_low(rtwdev, false);
152462306a36Sopenharmony_ci	return 0;
152562306a36Sopenharmony_ci}
152662306a36Sopenharmony_ci
152762306a36Sopenharmony_ciSIMPLE_DEV_PM_OPS(rtw_pm_ops, rtw_pci_suspend, rtw_pci_resume);
152862306a36Sopenharmony_ciEXPORT_SYMBOL(rtw_pm_ops);
152962306a36Sopenharmony_ci
153062306a36Sopenharmony_cistatic int rtw_pci_claim(struct rtw_dev *rtwdev, struct pci_dev *pdev)
153162306a36Sopenharmony_ci{
153262306a36Sopenharmony_ci	int ret;
153362306a36Sopenharmony_ci
153462306a36Sopenharmony_ci	ret = pci_enable_device(pdev);
153562306a36Sopenharmony_ci	if (ret) {
153662306a36Sopenharmony_ci		rtw_err(rtwdev, "failed to enable pci device\n");
153762306a36Sopenharmony_ci		return ret;
153862306a36Sopenharmony_ci	}
153962306a36Sopenharmony_ci
154062306a36Sopenharmony_ci	pci_set_master(pdev);
154162306a36Sopenharmony_ci	pci_set_drvdata(pdev, rtwdev->hw);
154262306a36Sopenharmony_ci	SET_IEEE80211_DEV(rtwdev->hw, &pdev->dev);
154362306a36Sopenharmony_ci
154462306a36Sopenharmony_ci	return 0;
154562306a36Sopenharmony_ci}
154662306a36Sopenharmony_ci
154762306a36Sopenharmony_cistatic void rtw_pci_declaim(struct rtw_dev *rtwdev, struct pci_dev *pdev)
154862306a36Sopenharmony_ci{
154962306a36Sopenharmony_ci	pci_disable_device(pdev);
155062306a36Sopenharmony_ci}
155162306a36Sopenharmony_ci
155262306a36Sopenharmony_cistatic int rtw_pci_setup_resource(struct rtw_dev *rtwdev, struct pci_dev *pdev)
155362306a36Sopenharmony_ci{
155462306a36Sopenharmony_ci	struct rtw_pci *rtwpci;
155562306a36Sopenharmony_ci	int ret;
155662306a36Sopenharmony_ci
155762306a36Sopenharmony_ci	rtwpci = (struct rtw_pci *)rtwdev->priv;
155862306a36Sopenharmony_ci	rtwpci->pdev = pdev;
155962306a36Sopenharmony_ci
156062306a36Sopenharmony_ci	/* after this driver can access to hw registers */
156162306a36Sopenharmony_ci	ret = rtw_pci_io_mapping(rtwdev, pdev);
156262306a36Sopenharmony_ci	if (ret) {
156362306a36Sopenharmony_ci		rtw_err(rtwdev, "failed to request pci io region\n");
156462306a36Sopenharmony_ci		goto err_out;
156562306a36Sopenharmony_ci	}
156662306a36Sopenharmony_ci
156762306a36Sopenharmony_ci	ret = rtw_pci_init(rtwdev);
156862306a36Sopenharmony_ci	if (ret) {
156962306a36Sopenharmony_ci		rtw_err(rtwdev, "failed to allocate pci resources\n");
157062306a36Sopenharmony_ci		goto err_io_unmap;
157162306a36Sopenharmony_ci	}
157262306a36Sopenharmony_ci
157362306a36Sopenharmony_ci	return 0;
157462306a36Sopenharmony_ci
157562306a36Sopenharmony_cierr_io_unmap:
157662306a36Sopenharmony_ci	rtw_pci_io_unmapping(rtwdev, pdev);
157762306a36Sopenharmony_ci
157862306a36Sopenharmony_cierr_out:
157962306a36Sopenharmony_ci	return ret;
158062306a36Sopenharmony_ci}
158162306a36Sopenharmony_ci
158262306a36Sopenharmony_cistatic void rtw_pci_destroy(struct rtw_dev *rtwdev, struct pci_dev *pdev)
158362306a36Sopenharmony_ci{
158462306a36Sopenharmony_ci	rtw_pci_deinit(rtwdev);
158562306a36Sopenharmony_ci	rtw_pci_io_unmapping(rtwdev, pdev);
158662306a36Sopenharmony_ci}
158762306a36Sopenharmony_ci
158862306a36Sopenharmony_cistatic struct rtw_hci_ops rtw_pci_ops = {
158962306a36Sopenharmony_ci	.tx_write = rtw_pci_tx_write,
159062306a36Sopenharmony_ci	.tx_kick_off = rtw_pci_tx_kick_off,
159162306a36Sopenharmony_ci	.flush_queues = rtw_pci_flush_queues,
159262306a36Sopenharmony_ci	.setup = rtw_pci_setup,
159362306a36Sopenharmony_ci	.start = rtw_pci_start,
159462306a36Sopenharmony_ci	.stop = rtw_pci_stop,
159562306a36Sopenharmony_ci	.deep_ps = rtw_pci_deep_ps,
159662306a36Sopenharmony_ci	.link_ps = rtw_pci_link_ps,
159762306a36Sopenharmony_ci	.interface_cfg = rtw_pci_interface_cfg,
159862306a36Sopenharmony_ci
159962306a36Sopenharmony_ci	.read8 = rtw_pci_read8,
160062306a36Sopenharmony_ci	.read16 = rtw_pci_read16,
160162306a36Sopenharmony_ci	.read32 = rtw_pci_read32,
160262306a36Sopenharmony_ci	.write8 = rtw_pci_write8,
160362306a36Sopenharmony_ci	.write16 = rtw_pci_write16,
160462306a36Sopenharmony_ci	.write32 = rtw_pci_write32,
160562306a36Sopenharmony_ci	.write_data_rsvd_page = rtw_pci_write_data_rsvd_page,
160662306a36Sopenharmony_ci	.write_data_h2c = rtw_pci_write_data_h2c,
160762306a36Sopenharmony_ci};
160862306a36Sopenharmony_ci
160962306a36Sopenharmony_cistatic int rtw_pci_request_irq(struct rtw_dev *rtwdev, struct pci_dev *pdev)
161062306a36Sopenharmony_ci{
161162306a36Sopenharmony_ci	unsigned int flags = PCI_IRQ_LEGACY;
161262306a36Sopenharmony_ci	int ret;
161362306a36Sopenharmony_ci
161462306a36Sopenharmony_ci	if (!rtw_disable_msi)
161562306a36Sopenharmony_ci		flags |= PCI_IRQ_MSI;
161662306a36Sopenharmony_ci
161762306a36Sopenharmony_ci	ret = pci_alloc_irq_vectors(pdev, 1, 1, flags);
161862306a36Sopenharmony_ci	if (ret < 0) {
161962306a36Sopenharmony_ci		rtw_err(rtwdev, "failed to alloc PCI irq vectors\n");
162062306a36Sopenharmony_ci		return ret;
162162306a36Sopenharmony_ci	}
162262306a36Sopenharmony_ci
162362306a36Sopenharmony_ci	ret = devm_request_threaded_irq(rtwdev->dev, pdev->irq,
162462306a36Sopenharmony_ci					rtw_pci_interrupt_handler,
162562306a36Sopenharmony_ci					rtw_pci_interrupt_threadfn,
162662306a36Sopenharmony_ci					IRQF_SHARED, KBUILD_MODNAME, rtwdev);
162762306a36Sopenharmony_ci	if (ret) {
162862306a36Sopenharmony_ci		rtw_err(rtwdev, "failed to request irq %d\n", ret);
162962306a36Sopenharmony_ci		pci_free_irq_vectors(pdev);
163062306a36Sopenharmony_ci	}
163162306a36Sopenharmony_ci
163262306a36Sopenharmony_ci	return ret;
163362306a36Sopenharmony_ci}
163462306a36Sopenharmony_ci
163562306a36Sopenharmony_cistatic void rtw_pci_free_irq(struct rtw_dev *rtwdev, struct pci_dev *pdev)
163662306a36Sopenharmony_ci{
163762306a36Sopenharmony_ci	devm_free_irq(rtwdev->dev, pdev->irq, rtwdev);
163862306a36Sopenharmony_ci	pci_free_irq_vectors(pdev);
163962306a36Sopenharmony_ci}
164062306a36Sopenharmony_ci
164162306a36Sopenharmony_cistatic int rtw_pci_napi_poll(struct napi_struct *napi, int budget)
164262306a36Sopenharmony_ci{
164362306a36Sopenharmony_ci	struct rtw_pci *rtwpci = container_of(napi, struct rtw_pci, napi);
164462306a36Sopenharmony_ci	struct rtw_dev *rtwdev = container_of((void *)rtwpci, struct rtw_dev,
164562306a36Sopenharmony_ci					      priv);
164662306a36Sopenharmony_ci	int work_done = 0;
164762306a36Sopenharmony_ci
164862306a36Sopenharmony_ci	if (rtwpci->rx_no_aspm)
164962306a36Sopenharmony_ci		rtw_pci_link_ps(rtwdev, false);
165062306a36Sopenharmony_ci
165162306a36Sopenharmony_ci	while (work_done < budget) {
165262306a36Sopenharmony_ci		u32 work_done_once;
165362306a36Sopenharmony_ci
165462306a36Sopenharmony_ci		work_done_once = rtw_pci_rx_napi(rtwdev, rtwpci, RTW_RX_QUEUE_MPDU,
165562306a36Sopenharmony_ci						 budget - work_done);
165662306a36Sopenharmony_ci		if (work_done_once == 0)
165762306a36Sopenharmony_ci			break;
165862306a36Sopenharmony_ci		work_done += work_done_once;
165962306a36Sopenharmony_ci	}
166062306a36Sopenharmony_ci	if (work_done < budget) {
166162306a36Sopenharmony_ci		napi_complete_done(napi, work_done);
166262306a36Sopenharmony_ci		spin_lock_bh(&rtwpci->irq_lock);
166362306a36Sopenharmony_ci		if (rtwpci->running)
166462306a36Sopenharmony_ci			rtw_pci_enable_interrupt(rtwdev, rtwpci, false);
166562306a36Sopenharmony_ci		spin_unlock_bh(&rtwpci->irq_lock);
166662306a36Sopenharmony_ci		/* When ISR happens during polling and before napi_complete
166762306a36Sopenharmony_ci		 * while no further data is received. Data on the dma_ring will
166862306a36Sopenharmony_ci		 * not be processed immediately. Check whether dma ring is
166962306a36Sopenharmony_ci		 * empty and perform napi_schedule accordingly.
167062306a36Sopenharmony_ci		 */
167162306a36Sopenharmony_ci		if (rtw_pci_get_hw_rx_ring_nr(rtwdev, rtwpci))
167262306a36Sopenharmony_ci			napi_schedule(napi);
167362306a36Sopenharmony_ci	}
167462306a36Sopenharmony_ci	if (rtwpci->rx_no_aspm)
167562306a36Sopenharmony_ci		rtw_pci_link_ps(rtwdev, true);
167662306a36Sopenharmony_ci
167762306a36Sopenharmony_ci	return work_done;
167862306a36Sopenharmony_ci}
167962306a36Sopenharmony_ci
168062306a36Sopenharmony_cistatic void rtw_pci_napi_init(struct rtw_dev *rtwdev)
168162306a36Sopenharmony_ci{
168262306a36Sopenharmony_ci	struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
168362306a36Sopenharmony_ci
168462306a36Sopenharmony_ci	init_dummy_netdev(&rtwpci->netdev);
168562306a36Sopenharmony_ci	netif_napi_add(&rtwpci->netdev, &rtwpci->napi, rtw_pci_napi_poll);
168662306a36Sopenharmony_ci}
168762306a36Sopenharmony_ci
168862306a36Sopenharmony_cistatic void rtw_pci_napi_deinit(struct rtw_dev *rtwdev)
168962306a36Sopenharmony_ci{
169062306a36Sopenharmony_ci	struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
169162306a36Sopenharmony_ci
169262306a36Sopenharmony_ci	rtw_pci_napi_stop(rtwdev);
169362306a36Sopenharmony_ci	netif_napi_del(&rtwpci->napi);
169462306a36Sopenharmony_ci}
169562306a36Sopenharmony_ci
169662306a36Sopenharmony_ciint rtw_pci_probe(struct pci_dev *pdev,
169762306a36Sopenharmony_ci		  const struct pci_device_id *id)
169862306a36Sopenharmony_ci{
169962306a36Sopenharmony_ci	struct pci_dev *bridge = pci_upstream_bridge(pdev);
170062306a36Sopenharmony_ci	struct ieee80211_hw *hw;
170162306a36Sopenharmony_ci	struct rtw_dev *rtwdev;
170262306a36Sopenharmony_ci	struct rtw_pci *rtwpci;
170362306a36Sopenharmony_ci	int drv_data_size;
170462306a36Sopenharmony_ci	int ret;
170562306a36Sopenharmony_ci
170662306a36Sopenharmony_ci	drv_data_size = sizeof(struct rtw_dev) + sizeof(struct rtw_pci);
170762306a36Sopenharmony_ci	hw = ieee80211_alloc_hw(drv_data_size, &rtw_ops);
170862306a36Sopenharmony_ci	if (!hw) {
170962306a36Sopenharmony_ci		dev_err(&pdev->dev, "failed to allocate hw\n");
171062306a36Sopenharmony_ci		return -ENOMEM;
171162306a36Sopenharmony_ci	}
171262306a36Sopenharmony_ci
171362306a36Sopenharmony_ci	rtwdev = hw->priv;
171462306a36Sopenharmony_ci	rtwdev->hw = hw;
171562306a36Sopenharmony_ci	rtwdev->dev = &pdev->dev;
171662306a36Sopenharmony_ci	rtwdev->chip = (struct rtw_chip_info *)id->driver_data;
171762306a36Sopenharmony_ci	rtwdev->hci.ops = &rtw_pci_ops;
171862306a36Sopenharmony_ci	rtwdev->hci.type = RTW_HCI_TYPE_PCIE;
171962306a36Sopenharmony_ci
172062306a36Sopenharmony_ci	rtwpci = (struct rtw_pci *)rtwdev->priv;
172162306a36Sopenharmony_ci	atomic_set(&rtwpci->link_usage, 1);
172262306a36Sopenharmony_ci
172362306a36Sopenharmony_ci	ret = rtw_core_init(rtwdev);
172462306a36Sopenharmony_ci	if (ret)
172562306a36Sopenharmony_ci		goto err_release_hw;
172662306a36Sopenharmony_ci
172762306a36Sopenharmony_ci	rtw_dbg(rtwdev, RTW_DBG_PCI,
172862306a36Sopenharmony_ci		"rtw88 pci probe: vendor=0x%4.04X device=0x%4.04X rev=%d\n",
172962306a36Sopenharmony_ci		pdev->vendor, pdev->device, pdev->revision);
173062306a36Sopenharmony_ci
173162306a36Sopenharmony_ci	ret = rtw_pci_claim(rtwdev, pdev);
173262306a36Sopenharmony_ci	if (ret) {
173362306a36Sopenharmony_ci		rtw_err(rtwdev, "failed to claim pci device\n");
173462306a36Sopenharmony_ci		goto err_deinit_core;
173562306a36Sopenharmony_ci	}
173662306a36Sopenharmony_ci
173762306a36Sopenharmony_ci	ret = rtw_pci_setup_resource(rtwdev, pdev);
173862306a36Sopenharmony_ci	if (ret) {
173962306a36Sopenharmony_ci		rtw_err(rtwdev, "failed to setup pci resources\n");
174062306a36Sopenharmony_ci		goto err_pci_declaim;
174162306a36Sopenharmony_ci	}
174262306a36Sopenharmony_ci
174362306a36Sopenharmony_ci	rtw_pci_napi_init(rtwdev);
174462306a36Sopenharmony_ci
174562306a36Sopenharmony_ci	ret = rtw_chip_info_setup(rtwdev);
174662306a36Sopenharmony_ci	if (ret) {
174762306a36Sopenharmony_ci		rtw_err(rtwdev, "failed to setup chip information\n");
174862306a36Sopenharmony_ci		goto err_destroy_pci;
174962306a36Sopenharmony_ci	}
175062306a36Sopenharmony_ci
175162306a36Sopenharmony_ci	/* Disable PCIe ASPM L1 while doing NAPI poll for 8821CE */
175262306a36Sopenharmony_ci	if (rtwdev->chip->id == RTW_CHIP_TYPE_8821C && bridge->vendor == PCI_VENDOR_ID_INTEL)
175362306a36Sopenharmony_ci		rtwpci->rx_no_aspm = true;
175462306a36Sopenharmony_ci
175562306a36Sopenharmony_ci	rtw_pci_phy_cfg(rtwdev);
175662306a36Sopenharmony_ci
175762306a36Sopenharmony_ci	ret = rtw_register_hw(rtwdev, hw);
175862306a36Sopenharmony_ci	if (ret) {
175962306a36Sopenharmony_ci		rtw_err(rtwdev, "failed to register hw\n");
176062306a36Sopenharmony_ci		goto err_destroy_pci;
176162306a36Sopenharmony_ci	}
176262306a36Sopenharmony_ci
176362306a36Sopenharmony_ci	ret = rtw_pci_request_irq(rtwdev, pdev);
176462306a36Sopenharmony_ci	if (ret) {
176562306a36Sopenharmony_ci		ieee80211_unregister_hw(hw);
176662306a36Sopenharmony_ci		goto err_destroy_pci;
176762306a36Sopenharmony_ci	}
176862306a36Sopenharmony_ci
176962306a36Sopenharmony_ci	return 0;
177062306a36Sopenharmony_ci
177162306a36Sopenharmony_cierr_destroy_pci:
177262306a36Sopenharmony_ci	rtw_pci_napi_deinit(rtwdev);
177362306a36Sopenharmony_ci	rtw_pci_destroy(rtwdev, pdev);
177462306a36Sopenharmony_ci
177562306a36Sopenharmony_cierr_pci_declaim:
177662306a36Sopenharmony_ci	rtw_pci_declaim(rtwdev, pdev);
177762306a36Sopenharmony_ci
177862306a36Sopenharmony_cierr_deinit_core:
177962306a36Sopenharmony_ci	rtw_core_deinit(rtwdev);
178062306a36Sopenharmony_ci
178162306a36Sopenharmony_cierr_release_hw:
178262306a36Sopenharmony_ci	ieee80211_free_hw(hw);
178362306a36Sopenharmony_ci
178462306a36Sopenharmony_ci	return ret;
178562306a36Sopenharmony_ci}
178662306a36Sopenharmony_ciEXPORT_SYMBOL(rtw_pci_probe);
178762306a36Sopenharmony_ci
178862306a36Sopenharmony_civoid rtw_pci_remove(struct pci_dev *pdev)
178962306a36Sopenharmony_ci{
179062306a36Sopenharmony_ci	struct ieee80211_hw *hw = pci_get_drvdata(pdev);
179162306a36Sopenharmony_ci	struct rtw_dev *rtwdev;
179262306a36Sopenharmony_ci	struct rtw_pci *rtwpci;
179362306a36Sopenharmony_ci
179462306a36Sopenharmony_ci	if (!hw)
179562306a36Sopenharmony_ci		return;
179662306a36Sopenharmony_ci
179762306a36Sopenharmony_ci	rtwdev = hw->priv;
179862306a36Sopenharmony_ci	rtwpci = (struct rtw_pci *)rtwdev->priv;
179962306a36Sopenharmony_ci
180062306a36Sopenharmony_ci	rtw_unregister_hw(rtwdev, hw);
180162306a36Sopenharmony_ci	rtw_pci_disable_interrupt(rtwdev, rtwpci);
180262306a36Sopenharmony_ci	rtw_pci_napi_deinit(rtwdev);
180362306a36Sopenharmony_ci	rtw_pci_destroy(rtwdev, pdev);
180462306a36Sopenharmony_ci	rtw_pci_declaim(rtwdev, pdev);
180562306a36Sopenharmony_ci	rtw_pci_free_irq(rtwdev, pdev);
180662306a36Sopenharmony_ci	rtw_core_deinit(rtwdev);
180762306a36Sopenharmony_ci	ieee80211_free_hw(hw);
180862306a36Sopenharmony_ci}
180962306a36Sopenharmony_ciEXPORT_SYMBOL(rtw_pci_remove);
181062306a36Sopenharmony_ci
181162306a36Sopenharmony_civoid rtw_pci_shutdown(struct pci_dev *pdev)
181262306a36Sopenharmony_ci{
181362306a36Sopenharmony_ci	struct ieee80211_hw *hw = pci_get_drvdata(pdev);
181462306a36Sopenharmony_ci	struct rtw_dev *rtwdev;
181562306a36Sopenharmony_ci	const struct rtw_chip_info *chip;
181662306a36Sopenharmony_ci
181762306a36Sopenharmony_ci	if (!hw)
181862306a36Sopenharmony_ci		return;
181962306a36Sopenharmony_ci
182062306a36Sopenharmony_ci	rtwdev = hw->priv;
182162306a36Sopenharmony_ci	chip = rtwdev->chip;
182262306a36Sopenharmony_ci
182362306a36Sopenharmony_ci	if (chip->ops->shutdown)
182462306a36Sopenharmony_ci		chip->ops->shutdown(rtwdev);
182562306a36Sopenharmony_ci
182662306a36Sopenharmony_ci	pci_set_power_state(pdev, PCI_D3hot);
182762306a36Sopenharmony_ci}
182862306a36Sopenharmony_ciEXPORT_SYMBOL(rtw_pci_shutdown);
182962306a36Sopenharmony_ci
183062306a36Sopenharmony_ciMODULE_AUTHOR("Realtek Corporation");
183162306a36Sopenharmony_ciMODULE_DESCRIPTION("Realtek PCI 802.11ac wireless driver");
183262306a36Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL");
1833