1e3037485SYan-Hsuan Chuang // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2e3037485SYan-Hsuan Chuang /* Copyright(c) 2018-2019 Realtek Corporation
3e3037485SYan-Hsuan Chuang */
4e3037485SYan-Hsuan Chuang
5e3037485SYan-Hsuan Chuang #include <linux/module.h>
6e3037485SYan-Hsuan Chuang #include <linux/pci.h>
7e3037485SYan-Hsuan Chuang #include "main.h"
8e3037485SYan-Hsuan Chuang #include "pci.h"
978622104SYan-Hsuan Chuang #include "reg.h"
10e3037485SYan-Hsuan Chuang #include "tx.h"
11e3037485SYan-Hsuan Chuang #include "rx.h"
120d762f03SYan-Hsuan Chuang #include "fw.h"
1327e117e4SYan-Hsuan Chuang #include "ps.h"
14e3037485SYan-Hsuan Chuang #include "debug.h"
15e3037485SYan-Hsuan Chuang
1679066903SYu-Yen Ting static bool rtw_disable_msi;
1768aa716bSYan-Hsuan Chuang static bool rtw_pci_disable_aspm;
1879066903SYu-Yen Ting module_param_named(disable_msi, rtw_disable_msi, bool, 0644);
1968aa716bSYan-Hsuan Chuang module_param_named(disable_aspm, rtw_pci_disable_aspm, bool, 0644);
2079066903SYu-Yen Ting MODULE_PARM_DESC(disable_msi, "Set Y to disable MSI interrupt support");
2168aa716bSYan-Hsuan Chuang MODULE_PARM_DESC(disable_aspm, "Set Y to disable PCI ASPM support");
2279066903SYu-Yen Ting
23e3037485SYan-Hsuan Chuang static u32 rtw_pci_tx_queue_idx_addr[] = {
24e3037485SYan-Hsuan Chuang [RTW_TX_QUEUE_BK] = RTK_PCI_TXBD_IDX_BKQ,
25e3037485SYan-Hsuan Chuang [RTW_TX_QUEUE_BE] = RTK_PCI_TXBD_IDX_BEQ,
26e3037485SYan-Hsuan Chuang [RTW_TX_QUEUE_VI] = RTK_PCI_TXBD_IDX_VIQ,
27e3037485SYan-Hsuan Chuang [RTW_TX_QUEUE_VO] = RTK_PCI_TXBD_IDX_VOQ,
28e3037485SYan-Hsuan Chuang [RTW_TX_QUEUE_MGMT] = RTK_PCI_TXBD_IDX_MGMTQ,
29e3037485SYan-Hsuan Chuang [RTW_TX_QUEUE_HI0] = RTK_PCI_TXBD_IDX_HI0Q,
30e3037485SYan-Hsuan Chuang [RTW_TX_QUEUE_H2C] = RTK_PCI_TXBD_IDX_H2CQ,
31e3037485SYan-Hsuan Chuang };
32e3037485SYan-Hsuan Chuang
rtw_pci_get_tx_qsel(struct sk_buff * skb,enum rtw_tx_queue_type queue)33c9089796SMartin Blumenstingl static u8 rtw_pci_get_tx_qsel(struct sk_buff *skb,
34c9089796SMartin Blumenstingl enum rtw_tx_queue_type queue)
35e3037485SYan-Hsuan Chuang {
36e3037485SYan-Hsuan Chuang switch (queue) {
37e3037485SYan-Hsuan Chuang case RTW_TX_QUEUE_BCN:
38e3037485SYan-Hsuan Chuang return TX_DESC_QSEL_BEACON;
39e3037485SYan-Hsuan Chuang case RTW_TX_QUEUE_H2C:
40e3037485SYan-Hsuan Chuang return TX_DESC_QSEL_H2C;
41e3037485SYan-Hsuan Chuang case RTW_TX_QUEUE_MGMT:
42e3037485SYan-Hsuan Chuang return TX_DESC_QSEL_MGMT;
43e3037485SYan-Hsuan Chuang case RTW_TX_QUEUE_HI0:
44e3037485SYan-Hsuan Chuang return TX_DESC_QSEL_HIGH;
45e3037485SYan-Hsuan Chuang default:
46e3037485SYan-Hsuan Chuang return skb->priority;
47e3037485SYan-Hsuan Chuang }
48e3037485SYan-Hsuan Chuang };
49e3037485SYan-Hsuan Chuang
rtw_pci_read8(struct rtw_dev * rtwdev,u32 addr)50e3037485SYan-Hsuan Chuang static u8 rtw_pci_read8(struct rtw_dev *rtwdev, u32 addr)
51e3037485SYan-Hsuan Chuang {
52e3037485SYan-Hsuan Chuang struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
53e3037485SYan-Hsuan Chuang
54e3037485SYan-Hsuan Chuang return readb(rtwpci->mmap + addr);
55e3037485SYan-Hsuan Chuang }
56e3037485SYan-Hsuan Chuang
rtw_pci_read16(struct rtw_dev * rtwdev,u32 addr)57e3037485SYan-Hsuan Chuang static u16 rtw_pci_read16(struct rtw_dev *rtwdev, u32 addr)
58e3037485SYan-Hsuan Chuang {
59e3037485SYan-Hsuan Chuang struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
60e3037485SYan-Hsuan Chuang
61e3037485SYan-Hsuan Chuang return readw(rtwpci->mmap + addr);
62e3037485SYan-Hsuan Chuang }
63e3037485SYan-Hsuan Chuang
rtw_pci_read32(struct rtw_dev * rtwdev,u32 addr)64e3037485SYan-Hsuan Chuang static u32 rtw_pci_read32(struct rtw_dev *rtwdev, u32 addr)
65e3037485SYan-Hsuan Chuang {
66e3037485SYan-Hsuan Chuang struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
67e3037485SYan-Hsuan Chuang
68e3037485SYan-Hsuan Chuang return readl(rtwpci->mmap + addr);
69e3037485SYan-Hsuan Chuang }
70e3037485SYan-Hsuan Chuang
rtw_pci_write8(struct rtw_dev * rtwdev,u32 addr,u8 val)71e3037485SYan-Hsuan Chuang static void rtw_pci_write8(struct rtw_dev *rtwdev, u32 addr, u8 val)
72e3037485SYan-Hsuan Chuang {
73e3037485SYan-Hsuan Chuang struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
74e3037485SYan-Hsuan Chuang
75e3037485SYan-Hsuan Chuang writeb(val, rtwpci->mmap + addr);
76e3037485SYan-Hsuan Chuang }
77e3037485SYan-Hsuan Chuang
rtw_pci_write16(struct rtw_dev * rtwdev,u32 addr,u16 val)78e3037485SYan-Hsuan Chuang static void rtw_pci_write16(struct rtw_dev *rtwdev, u32 addr, u16 val)
79e3037485SYan-Hsuan Chuang {
80e3037485SYan-Hsuan Chuang struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
81e3037485SYan-Hsuan Chuang
82e3037485SYan-Hsuan Chuang writew(val, rtwpci->mmap + addr);
83e3037485SYan-Hsuan Chuang }
84e3037485SYan-Hsuan Chuang
rtw_pci_write32(struct rtw_dev * rtwdev,u32 addr,u32 val)85e3037485SYan-Hsuan Chuang static void rtw_pci_write32(struct rtw_dev *rtwdev, u32 addr, u32 val)
86e3037485SYan-Hsuan Chuang {
87e3037485SYan-Hsuan Chuang struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
88e3037485SYan-Hsuan Chuang
89e3037485SYan-Hsuan Chuang writel(val, rtwpci->mmap + addr);
90e3037485SYan-Hsuan Chuang }
91e3037485SYan-Hsuan Chuang
rtw_pci_free_tx_ring_skbs(struct rtw_dev * rtwdev,struct rtw_pci_tx_ring * tx_ring)92dc579ca5SYan-Hsuan Chuang static void rtw_pci_free_tx_ring_skbs(struct rtw_dev *rtwdev,
93e3037485SYan-Hsuan Chuang struct rtw_pci_tx_ring *tx_ring)
94e3037485SYan-Hsuan Chuang {
95e3037485SYan-Hsuan Chuang struct pci_dev *pdev = to_pci_dev(rtwdev->dev);
96e3037485SYan-Hsuan Chuang struct rtw_pci_tx_data *tx_data;
97e3037485SYan-Hsuan Chuang struct sk_buff *skb, *tmp;
98e3037485SYan-Hsuan Chuang dma_addr_t dma;
99e3037485SYan-Hsuan Chuang
100e3037485SYan-Hsuan Chuang /* free every skb remained in tx list */
101e3037485SYan-Hsuan Chuang skb_queue_walk_safe(&tx_ring->queue, skb, tmp) {
102e3037485SYan-Hsuan Chuang __skb_unlink(skb, &tx_ring->queue);
103e3037485SYan-Hsuan Chuang tx_data = rtw_pci_get_tx_data(skb);
104e3037485SYan-Hsuan Chuang dma = tx_data->dma;
105e3037485SYan-Hsuan Chuang
10624712ea9SChristophe JAILLET dma_unmap_single(&pdev->dev, dma, skb->len, DMA_TO_DEVICE);
107e3037485SYan-Hsuan Chuang dev_kfree_skb_any(skb);
108e3037485SYan-Hsuan Chuang }
109dc579ca5SYan-Hsuan Chuang }
110dc579ca5SYan-Hsuan Chuang
rtw_pci_free_tx_ring(struct rtw_dev * rtwdev,struct rtw_pci_tx_ring * tx_ring)111dc579ca5SYan-Hsuan Chuang static void rtw_pci_free_tx_ring(struct rtw_dev *rtwdev,
112dc579ca5SYan-Hsuan Chuang struct rtw_pci_tx_ring *tx_ring)
113dc579ca5SYan-Hsuan Chuang {
114dc579ca5SYan-Hsuan Chuang struct pci_dev *pdev = to_pci_dev(rtwdev->dev);
115dc579ca5SYan-Hsuan Chuang u8 *head = tx_ring->r.head;
116dc579ca5SYan-Hsuan Chuang u32 len = tx_ring->r.len;
117dc579ca5SYan-Hsuan Chuang int ring_sz = len * tx_ring->r.desc_size;
118dc579ca5SYan-Hsuan Chuang
119dc579ca5SYan-Hsuan Chuang rtw_pci_free_tx_ring_skbs(rtwdev, tx_ring);
120e3037485SYan-Hsuan Chuang
121e3037485SYan-Hsuan Chuang /* free the ring itself */
12224712ea9SChristophe JAILLET dma_free_coherent(&pdev->dev, ring_sz, head, tx_ring->r.dma);
123e3037485SYan-Hsuan Chuang tx_ring->r.head = NULL;
124e3037485SYan-Hsuan Chuang }
125e3037485SYan-Hsuan Chuang
rtw_pci_free_rx_ring_skbs(struct rtw_dev * rtwdev,struct rtw_pci_rx_ring * rx_ring)126dc579ca5SYan-Hsuan Chuang static void rtw_pci_free_rx_ring_skbs(struct rtw_dev *rtwdev,
127e3037485SYan-Hsuan Chuang struct rtw_pci_rx_ring *rx_ring)
128e3037485SYan-Hsuan Chuang {
129e3037485SYan-Hsuan Chuang struct pci_dev *pdev = to_pci_dev(rtwdev->dev);
130e3037485SYan-Hsuan Chuang struct sk_buff *skb;
131e3037485SYan-Hsuan Chuang int buf_sz = RTK_PCI_RX_BUF_SIZE;
132dc579ca5SYan-Hsuan Chuang dma_addr_t dma;
133e3037485SYan-Hsuan Chuang int i;
134e3037485SYan-Hsuan Chuang
135e3037485SYan-Hsuan Chuang for (i = 0; i < rx_ring->r.len; i++) {
136e3037485SYan-Hsuan Chuang skb = rx_ring->buf[i];
137e3037485SYan-Hsuan Chuang if (!skb)
138e3037485SYan-Hsuan Chuang continue;
139e3037485SYan-Hsuan Chuang
140e3037485SYan-Hsuan Chuang dma = *((dma_addr_t *)skb->cb);
14124712ea9SChristophe JAILLET dma_unmap_single(&pdev->dev, dma, buf_sz, DMA_FROM_DEVICE);
142e3037485SYan-Hsuan Chuang dev_kfree_skb(skb);
143e3037485SYan-Hsuan Chuang rx_ring->buf[i] = NULL;
144e3037485SYan-Hsuan Chuang }
145dc579ca5SYan-Hsuan Chuang }
146dc579ca5SYan-Hsuan Chuang
rtw_pci_free_rx_ring(struct rtw_dev * rtwdev,struct rtw_pci_rx_ring * rx_ring)147dc579ca5SYan-Hsuan Chuang static void rtw_pci_free_rx_ring(struct rtw_dev *rtwdev,
148dc579ca5SYan-Hsuan Chuang struct rtw_pci_rx_ring *rx_ring)
149dc579ca5SYan-Hsuan Chuang {
150dc579ca5SYan-Hsuan Chuang struct pci_dev *pdev = to_pci_dev(rtwdev->dev);
151dc579ca5SYan-Hsuan Chuang u8 *head = rx_ring->r.head;
152dc579ca5SYan-Hsuan Chuang int ring_sz = rx_ring->r.desc_size * rx_ring->r.len;
153dc579ca5SYan-Hsuan Chuang
154dc579ca5SYan-Hsuan Chuang rtw_pci_free_rx_ring_skbs(rtwdev, rx_ring);
155e3037485SYan-Hsuan Chuang
15624712ea9SChristophe JAILLET dma_free_coherent(&pdev->dev, ring_sz, head, rx_ring->r.dma);
157e3037485SYan-Hsuan Chuang }
158e3037485SYan-Hsuan Chuang
rtw_pci_free_trx_ring(struct rtw_dev * rtwdev)159e3037485SYan-Hsuan Chuang static void rtw_pci_free_trx_ring(struct rtw_dev *rtwdev)
160e3037485SYan-Hsuan Chuang {
161e3037485SYan-Hsuan Chuang struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
162e3037485SYan-Hsuan Chuang struct rtw_pci_tx_ring *tx_ring;
163e3037485SYan-Hsuan Chuang struct rtw_pci_rx_ring *rx_ring;
164e3037485SYan-Hsuan Chuang int i;
165e3037485SYan-Hsuan Chuang
166e3037485SYan-Hsuan Chuang for (i = 0; i < RTK_MAX_TX_QUEUE_NUM; i++) {
167e3037485SYan-Hsuan Chuang tx_ring = &rtwpci->tx_rings[i];
168e3037485SYan-Hsuan Chuang rtw_pci_free_tx_ring(rtwdev, tx_ring);
169e3037485SYan-Hsuan Chuang }
170e3037485SYan-Hsuan Chuang
171e3037485SYan-Hsuan Chuang for (i = 0; i < RTK_MAX_RX_QUEUE_NUM; i++) {
172e3037485SYan-Hsuan Chuang rx_ring = &rtwpci->rx_rings[i];
173e3037485SYan-Hsuan Chuang rtw_pci_free_rx_ring(rtwdev, rx_ring);
174e3037485SYan-Hsuan Chuang }
175e3037485SYan-Hsuan Chuang }
176e3037485SYan-Hsuan Chuang
rtw_pci_init_tx_ring(struct rtw_dev * rtwdev,struct rtw_pci_tx_ring * tx_ring,u8 desc_size,u32 len)177e3037485SYan-Hsuan Chuang static int rtw_pci_init_tx_ring(struct rtw_dev *rtwdev,
178e3037485SYan-Hsuan Chuang struct rtw_pci_tx_ring *tx_ring,
179e3037485SYan-Hsuan Chuang u8 desc_size, u32 len)
180e3037485SYan-Hsuan Chuang {
181e3037485SYan-Hsuan Chuang struct pci_dev *pdev = to_pci_dev(rtwdev->dev);
182e3037485SYan-Hsuan Chuang int ring_sz = desc_size * len;
183e3037485SYan-Hsuan Chuang dma_addr_t dma;
184e3037485SYan-Hsuan Chuang u8 *head;
185e3037485SYan-Hsuan Chuang
186a5697a65SYan-Hsuan Chuang if (len > TRX_BD_IDX_MASK) {
187a5697a65SYan-Hsuan Chuang rtw_err(rtwdev, "len %d exceeds maximum TX entries\n", len);
188a5697a65SYan-Hsuan Chuang return -EINVAL;
189a5697a65SYan-Hsuan Chuang }
190a5697a65SYan-Hsuan Chuang
19124712ea9SChristophe JAILLET head = dma_alloc_coherent(&pdev->dev, ring_sz, &dma, GFP_KERNEL);
192e3037485SYan-Hsuan Chuang if (!head) {
193e3037485SYan-Hsuan Chuang rtw_err(rtwdev, "failed to allocate tx ring\n");
194e3037485SYan-Hsuan Chuang return -ENOMEM;
195e3037485SYan-Hsuan Chuang }
196e3037485SYan-Hsuan Chuang
197e3037485SYan-Hsuan Chuang skb_queue_head_init(&tx_ring->queue);
198e3037485SYan-Hsuan Chuang tx_ring->r.head = head;
199e3037485SYan-Hsuan Chuang tx_ring->r.dma = dma;
200e3037485SYan-Hsuan Chuang tx_ring->r.len = len;
201e3037485SYan-Hsuan Chuang tx_ring->r.desc_size = desc_size;
202e3037485SYan-Hsuan Chuang tx_ring->r.wp = 0;
203e3037485SYan-Hsuan Chuang tx_ring->r.rp = 0;
204e3037485SYan-Hsuan Chuang
205e3037485SYan-Hsuan Chuang return 0;
206e3037485SYan-Hsuan Chuang }
207e3037485SYan-Hsuan Chuang
rtw_pci_reset_rx_desc(struct rtw_dev * rtwdev,struct sk_buff * skb,struct rtw_pci_rx_ring * rx_ring,u32 idx,u32 desc_sz)208e3037485SYan-Hsuan Chuang static int rtw_pci_reset_rx_desc(struct rtw_dev *rtwdev, struct sk_buff *skb,
209e3037485SYan-Hsuan Chuang struct rtw_pci_rx_ring *rx_ring,
210e3037485SYan-Hsuan Chuang u32 idx, u32 desc_sz)
211e3037485SYan-Hsuan Chuang {
212e3037485SYan-Hsuan Chuang struct pci_dev *pdev = to_pci_dev(rtwdev->dev);
213e3037485SYan-Hsuan Chuang struct rtw_pci_rx_buffer_desc *buf_desc;
214e3037485SYan-Hsuan Chuang int buf_sz = RTK_PCI_RX_BUF_SIZE;
215e3037485SYan-Hsuan Chuang dma_addr_t dma;
216e3037485SYan-Hsuan Chuang
217e3037485SYan-Hsuan Chuang if (!skb)
218e3037485SYan-Hsuan Chuang return -EINVAL;
219e3037485SYan-Hsuan Chuang
22024712ea9SChristophe JAILLET dma = dma_map_single(&pdev->dev, skb->data, buf_sz, DMA_FROM_DEVICE);
22124712ea9SChristophe JAILLET if (dma_mapping_error(&pdev->dev, dma))
222e3037485SYan-Hsuan Chuang return -EBUSY;
223e3037485SYan-Hsuan Chuang
224e3037485SYan-Hsuan Chuang *((dma_addr_t *)skb->cb) = dma;
225e3037485SYan-Hsuan Chuang buf_desc = (struct rtw_pci_rx_buffer_desc *)(rx_ring->r.head +
226e3037485SYan-Hsuan Chuang idx * desc_sz);
227e3037485SYan-Hsuan Chuang memset(buf_desc, 0, sizeof(*buf_desc));
228e3037485SYan-Hsuan Chuang buf_desc->buf_size = cpu_to_le16(RTK_PCI_RX_BUF_SIZE);
229e3037485SYan-Hsuan Chuang buf_desc->dma = cpu_to_le32(dma);
230e3037485SYan-Hsuan Chuang
231e3037485SYan-Hsuan Chuang return 0;
232e3037485SYan-Hsuan Chuang }
233e3037485SYan-Hsuan Chuang
rtw_pci_sync_rx_desc_device(struct rtw_dev * rtwdev,dma_addr_t dma,struct rtw_pci_rx_ring * rx_ring,u32 idx,u32 desc_sz)23429b68a92SJian-Hong Pan static void rtw_pci_sync_rx_desc_device(struct rtw_dev *rtwdev, dma_addr_t dma,
23529b68a92SJian-Hong Pan struct rtw_pci_rx_ring *rx_ring,
23629b68a92SJian-Hong Pan u32 idx, u32 desc_sz)
23729b68a92SJian-Hong Pan {
23829b68a92SJian-Hong Pan struct device *dev = rtwdev->dev;
23929b68a92SJian-Hong Pan struct rtw_pci_rx_buffer_desc *buf_desc;
24029b68a92SJian-Hong Pan int buf_sz = RTK_PCI_RX_BUF_SIZE;
24129b68a92SJian-Hong Pan
24229b68a92SJian-Hong Pan dma_sync_single_for_device(dev, dma, buf_sz, DMA_FROM_DEVICE);
24329b68a92SJian-Hong Pan
24429b68a92SJian-Hong Pan buf_desc = (struct rtw_pci_rx_buffer_desc *)(rx_ring->r.head +
24529b68a92SJian-Hong Pan idx * desc_sz);
24629b68a92SJian-Hong Pan memset(buf_desc, 0, sizeof(*buf_desc));
24729b68a92SJian-Hong Pan buf_desc->buf_size = cpu_to_le16(RTK_PCI_RX_BUF_SIZE);
24829b68a92SJian-Hong Pan buf_desc->dma = cpu_to_le32(dma);
24929b68a92SJian-Hong Pan }
25029b68a92SJian-Hong Pan
rtw_pci_init_rx_ring(struct rtw_dev * rtwdev,struct rtw_pci_rx_ring * rx_ring,u8 desc_size,u32 len)251e3037485SYan-Hsuan Chuang static int rtw_pci_init_rx_ring(struct rtw_dev *rtwdev,
252e3037485SYan-Hsuan Chuang struct rtw_pci_rx_ring *rx_ring,
253e3037485SYan-Hsuan Chuang u8 desc_size, u32 len)
254e3037485SYan-Hsuan Chuang {
255e3037485SYan-Hsuan Chuang struct pci_dev *pdev = to_pci_dev(rtwdev->dev);
256e3037485SYan-Hsuan Chuang struct sk_buff *skb = NULL;
257e3037485SYan-Hsuan Chuang dma_addr_t dma;
258e3037485SYan-Hsuan Chuang u8 *head;
259e3037485SYan-Hsuan Chuang int ring_sz = desc_size * len;
260e3037485SYan-Hsuan Chuang int buf_sz = RTK_PCI_RX_BUF_SIZE;
261e3037485SYan-Hsuan Chuang int i, allocated;
262e3037485SYan-Hsuan Chuang int ret = 0;
263e3037485SYan-Hsuan Chuang
26424712ea9SChristophe JAILLET head = dma_alloc_coherent(&pdev->dev, ring_sz, &dma, GFP_KERNEL);
265e3037485SYan-Hsuan Chuang if (!head) {
266e3037485SYan-Hsuan Chuang rtw_err(rtwdev, "failed to allocate rx ring\n");
267e3037485SYan-Hsuan Chuang return -ENOMEM;
268e3037485SYan-Hsuan Chuang }
269e3037485SYan-Hsuan Chuang rx_ring->r.head = head;
270e3037485SYan-Hsuan Chuang
271e3037485SYan-Hsuan Chuang for (i = 0; i < len; i++) {
272e3037485SYan-Hsuan Chuang skb = dev_alloc_skb(buf_sz);
273e3037485SYan-Hsuan Chuang if (!skb) {
274e3037485SYan-Hsuan Chuang allocated = i;
275e3037485SYan-Hsuan Chuang ret = -ENOMEM;
276e3037485SYan-Hsuan Chuang goto err_out;
277e3037485SYan-Hsuan Chuang }
278e3037485SYan-Hsuan Chuang
279e3037485SYan-Hsuan Chuang memset(skb->data, 0, buf_sz);
280e3037485SYan-Hsuan Chuang rx_ring->buf[i] = skb;
281e3037485SYan-Hsuan Chuang ret = rtw_pci_reset_rx_desc(rtwdev, skb, rx_ring, i, desc_size);
282e3037485SYan-Hsuan Chuang if (ret) {
283e3037485SYan-Hsuan Chuang allocated = i;
284e3037485SYan-Hsuan Chuang dev_kfree_skb_any(skb);
285e3037485SYan-Hsuan Chuang goto err_out;
286e3037485SYan-Hsuan Chuang }
287e3037485SYan-Hsuan Chuang }
288e3037485SYan-Hsuan Chuang
289e3037485SYan-Hsuan Chuang rx_ring->r.dma = dma;
290e3037485SYan-Hsuan Chuang rx_ring->r.len = len;
291e3037485SYan-Hsuan Chuang rx_ring->r.desc_size = desc_size;
292e3037485SYan-Hsuan Chuang rx_ring->r.wp = 0;
293e3037485SYan-Hsuan Chuang rx_ring->r.rp = 0;
294e3037485SYan-Hsuan Chuang
295e3037485SYan-Hsuan Chuang return 0;
296e3037485SYan-Hsuan Chuang
297e3037485SYan-Hsuan Chuang err_out:
298e3037485SYan-Hsuan Chuang for (i = 0; i < allocated; i++) {
299e3037485SYan-Hsuan Chuang skb = rx_ring->buf[i];
300e3037485SYan-Hsuan Chuang if (!skb)
301e3037485SYan-Hsuan Chuang continue;
302e3037485SYan-Hsuan Chuang dma = *((dma_addr_t *)skb->cb);
30324712ea9SChristophe JAILLET dma_unmap_single(&pdev->dev, dma, buf_sz, DMA_FROM_DEVICE);
304e3037485SYan-Hsuan Chuang dev_kfree_skb_any(skb);
305e3037485SYan-Hsuan Chuang rx_ring->buf[i] = NULL;
306e3037485SYan-Hsuan Chuang }
30724712ea9SChristophe JAILLET dma_free_coherent(&pdev->dev, ring_sz, head, dma);
308e3037485SYan-Hsuan Chuang
309e3037485SYan-Hsuan Chuang rtw_err(rtwdev, "failed to init rx buffer\n");
310e3037485SYan-Hsuan Chuang
311e3037485SYan-Hsuan Chuang return ret;
312e3037485SYan-Hsuan Chuang }
313e3037485SYan-Hsuan Chuang
rtw_pci_init_trx_ring(struct rtw_dev * rtwdev)314e3037485SYan-Hsuan Chuang static int rtw_pci_init_trx_ring(struct rtw_dev *rtwdev)
315e3037485SYan-Hsuan Chuang {
316e3037485SYan-Hsuan Chuang struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
317e3037485SYan-Hsuan Chuang struct rtw_pci_tx_ring *tx_ring;
318e3037485SYan-Hsuan Chuang struct rtw_pci_rx_ring *rx_ring;
319dcbf179cSPing-Ke Shih const struct rtw_chip_info *chip = rtwdev->chip;
320e3037485SYan-Hsuan Chuang int i = 0, j = 0, tx_alloced = 0, rx_alloced = 0;
321e3037485SYan-Hsuan Chuang int tx_desc_size, rx_desc_size;
322e3037485SYan-Hsuan Chuang u32 len;
323e3037485SYan-Hsuan Chuang int ret;
324e3037485SYan-Hsuan Chuang
325e3037485SYan-Hsuan Chuang tx_desc_size = chip->tx_buf_desc_sz;
326e3037485SYan-Hsuan Chuang
327e3037485SYan-Hsuan Chuang for (i = 0; i < RTK_MAX_TX_QUEUE_NUM; i++) {
328e3037485SYan-Hsuan Chuang tx_ring = &rtwpci->tx_rings[i];
329e3037485SYan-Hsuan Chuang len = max_num_of_tx_queue(i);
330e3037485SYan-Hsuan Chuang ret = rtw_pci_init_tx_ring(rtwdev, tx_ring, tx_desc_size, len);
331e3037485SYan-Hsuan Chuang if (ret)
332e3037485SYan-Hsuan Chuang goto out;
333e3037485SYan-Hsuan Chuang }
334e3037485SYan-Hsuan Chuang
335e3037485SYan-Hsuan Chuang rx_desc_size = chip->rx_buf_desc_sz;
336e3037485SYan-Hsuan Chuang
337e3037485SYan-Hsuan Chuang for (j = 0; j < RTK_MAX_RX_QUEUE_NUM; j++) {
338e3037485SYan-Hsuan Chuang rx_ring = &rtwpci->rx_rings[j];
339e3037485SYan-Hsuan Chuang ret = rtw_pci_init_rx_ring(rtwdev, rx_ring, rx_desc_size,
340e3037485SYan-Hsuan Chuang RTK_MAX_RX_DESC_NUM);
341e3037485SYan-Hsuan Chuang if (ret)
342e3037485SYan-Hsuan Chuang goto out;
343e3037485SYan-Hsuan Chuang }
344e3037485SYan-Hsuan Chuang
345e3037485SYan-Hsuan Chuang return 0;
346e3037485SYan-Hsuan Chuang
347e3037485SYan-Hsuan Chuang out:
348e3037485SYan-Hsuan Chuang tx_alloced = i;
349e3037485SYan-Hsuan Chuang for (i = 0; i < tx_alloced; i++) {
350e3037485SYan-Hsuan Chuang tx_ring = &rtwpci->tx_rings[i];
351e3037485SYan-Hsuan Chuang rtw_pci_free_tx_ring(rtwdev, tx_ring);
352e3037485SYan-Hsuan Chuang }
353e3037485SYan-Hsuan Chuang
354e3037485SYan-Hsuan Chuang rx_alloced = j;
355e3037485SYan-Hsuan Chuang for (j = 0; j < rx_alloced; j++) {
356e3037485SYan-Hsuan Chuang rx_ring = &rtwpci->rx_rings[j];
357e3037485SYan-Hsuan Chuang rtw_pci_free_rx_ring(rtwdev, rx_ring);
358e3037485SYan-Hsuan Chuang }
359e3037485SYan-Hsuan Chuang
360e3037485SYan-Hsuan Chuang return ret;
361e3037485SYan-Hsuan Chuang }
362e3037485SYan-Hsuan Chuang
rtw_pci_deinit(struct rtw_dev * rtwdev)363e3037485SYan-Hsuan Chuang static void rtw_pci_deinit(struct rtw_dev *rtwdev)
364e3037485SYan-Hsuan Chuang {
365e3037485SYan-Hsuan Chuang rtw_pci_free_trx_ring(rtwdev);
366e3037485SYan-Hsuan Chuang }
367e3037485SYan-Hsuan Chuang
rtw_pci_init(struct rtw_dev * rtwdev)368e3037485SYan-Hsuan Chuang static int rtw_pci_init(struct rtw_dev *rtwdev)
369e3037485SYan-Hsuan Chuang {
370e3037485SYan-Hsuan Chuang struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
371e3037485SYan-Hsuan Chuang int ret = 0;
372e3037485SYan-Hsuan Chuang
373e3037485SYan-Hsuan Chuang rtwpci->irq_mask[0] = IMR_HIGHDOK |
374e3037485SYan-Hsuan Chuang IMR_MGNTDOK |
375e3037485SYan-Hsuan Chuang IMR_BKDOK |
376e3037485SYan-Hsuan Chuang IMR_BEDOK |
377e3037485SYan-Hsuan Chuang IMR_VIDOK |
378e3037485SYan-Hsuan Chuang IMR_VODOK |
379e3037485SYan-Hsuan Chuang IMR_ROK |
380e3037485SYan-Hsuan Chuang IMR_BCNDMAINT_E |
3815c831644STzu-En Huang IMR_C2HCMD |
382e3037485SYan-Hsuan Chuang 0;
383e3037485SYan-Hsuan Chuang rtwpci->irq_mask[1] = IMR_TXFOVW |
384e3037485SYan-Hsuan Chuang 0;
385e3037485SYan-Hsuan Chuang rtwpci->irq_mask[3] = IMR_H2CDOK |
386e3037485SYan-Hsuan Chuang 0;
387e3037485SYan-Hsuan Chuang spin_lock_init(&rtwpci->irq_lock);
38857fb39e2SBrian Norris spin_lock_init(&rtwpci->hwirq_lock);
389e3037485SYan-Hsuan Chuang ret = rtw_pci_init_trx_ring(rtwdev);
390e3037485SYan-Hsuan Chuang
391e3037485SYan-Hsuan Chuang return ret;
392e3037485SYan-Hsuan Chuang }
393e3037485SYan-Hsuan Chuang
rtw_pci_reset_buf_desc(struct rtw_dev * rtwdev)394e3037485SYan-Hsuan Chuang static void rtw_pci_reset_buf_desc(struct rtw_dev *rtwdev)
395e3037485SYan-Hsuan Chuang {
396e3037485SYan-Hsuan Chuang struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
397e3037485SYan-Hsuan Chuang u32 len;
398e3037485SYan-Hsuan Chuang u8 tmp;
399e3037485SYan-Hsuan Chuang dma_addr_t dma;
400e3037485SYan-Hsuan Chuang
401e3037485SYan-Hsuan Chuang tmp = rtw_read8(rtwdev, RTK_PCI_CTRL + 3);
402e3037485SYan-Hsuan Chuang rtw_write8(rtwdev, RTK_PCI_CTRL + 3, tmp | 0xf7);
403e3037485SYan-Hsuan Chuang
404e3037485SYan-Hsuan Chuang dma = rtwpci->tx_rings[RTW_TX_QUEUE_BCN].r.dma;
405e3037485SYan-Hsuan Chuang rtw_write32(rtwdev, RTK_PCI_TXBD_DESA_BCNQ, dma);
406e3037485SYan-Hsuan Chuang
4077907b52dSPing-Ke Shih if (!rtw_chip_wcpu_11n(rtwdev)) {
408e3037485SYan-Hsuan Chuang len = rtwpci->tx_rings[RTW_TX_QUEUE_H2C].r.len;
409e3037485SYan-Hsuan Chuang dma = rtwpci->tx_rings[RTW_TX_QUEUE_H2C].r.dma;
410e3037485SYan-Hsuan Chuang rtwpci->tx_rings[RTW_TX_QUEUE_H2C].r.rp = 0;
411e3037485SYan-Hsuan Chuang rtwpci->tx_rings[RTW_TX_QUEUE_H2C].r.wp = 0;
412a5697a65SYan-Hsuan Chuang rtw_write16(rtwdev, RTK_PCI_TXBD_NUM_H2CQ, len & TRX_BD_IDX_MASK);
413e3037485SYan-Hsuan Chuang rtw_write32(rtwdev, RTK_PCI_TXBD_DESA_H2CQ, dma);
4147907b52dSPing-Ke Shih }
415e3037485SYan-Hsuan Chuang
416e3037485SYan-Hsuan Chuang len = rtwpci->tx_rings[RTW_TX_QUEUE_BK].r.len;
417e3037485SYan-Hsuan Chuang dma = rtwpci->tx_rings[RTW_TX_QUEUE_BK].r.dma;
418e3037485SYan-Hsuan Chuang rtwpci->tx_rings[RTW_TX_QUEUE_BK].r.rp = 0;
419e3037485SYan-Hsuan Chuang rtwpci->tx_rings[RTW_TX_QUEUE_BK].r.wp = 0;
420a5697a65SYan-Hsuan Chuang rtw_write16(rtwdev, RTK_PCI_TXBD_NUM_BKQ, len & TRX_BD_IDX_MASK);
421e3037485SYan-Hsuan Chuang rtw_write32(rtwdev, RTK_PCI_TXBD_DESA_BKQ, dma);
422e3037485SYan-Hsuan Chuang
423e3037485SYan-Hsuan Chuang len = rtwpci->tx_rings[RTW_TX_QUEUE_BE].r.len;
424e3037485SYan-Hsuan Chuang dma = rtwpci->tx_rings[RTW_TX_QUEUE_BE].r.dma;
425e3037485SYan-Hsuan Chuang rtwpci->tx_rings[RTW_TX_QUEUE_BE].r.rp = 0;
426e3037485SYan-Hsuan Chuang rtwpci->tx_rings[RTW_TX_QUEUE_BE].r.wp = 0;
427a5697a65SYan-Hsuan Chuang rtw_write16(rtwdev, RTK_PCI_TXBD_NUM_BEQ, len & TRX_BD_IDX_MASK);
428e3037485SYan-Hsuan Chuang rtw_write32(rtwdev, RTK_PCI_TXBD_DESA_BEQ, dma);
429e3037485SYan-Hsuan Chuang
430e3037485SYan-Hsuan Chuang len = rtwpci->tx_rings[RTW_TX_QUEUE_VO].r.len;
431e3037485SYan-Hsuan Chuang dma = rtwpci->tx_rings[RTW_TX_QUEUE_VO].r.dma;
432e3037485SYan-Hsuan Chuang rtwpci->tx_rings[RTW_TX_QUEUE_VO].r.rp = 0;
433e3037485SYan-Hsuan Chuang rtwpci->tx_rings[RTW_TX_QUEUE_VO].r.wp = 0;
434a5697a65SYan-Hsuan Chuang rtw_write16(rtwdev, RTK_PCI_TXBD_NUM_VOQ, len & TRX_BD_IDX_MASK);
435e3037485SYan-Hsuan Chuang rtw_write32(rtwdev, RTK_PCI_TXBD_DESA_VOQ, dma);
436e3037485SYan-Hsuan Chuang
437e3037485SYan-Hsuan Chuang len = rtwpci->tx_rings[RTW_TX_QUEUE_VI].r.len;
438e3037485SYan-Hsuan Chuang dma = rtwpci->tx_rings[RTW_TX_QUEUE_VI].r.dma;
439e3037485SYan-Hsuan Chuang rtwpci->tx_rings[RTW_TX_QUEUE_VI].r.rp = 0;
440e3037485SYan-Hsuan Chuang rtwpci->tx_rings[RTW_TX_QUEUE_VI].r.wp = 0;
441a5697a65SYan-Hsuan Chuang rtw_write16(rtwdev, RTK_PCI_TXBD_NUM_VIQ, len & TRX_BD_IDX_MASK);
442e3037485SYan-Hsuan Chuang rtw_write32(rtwdev, RTK_PCI_TXBD_DESA_VIQ, dma);
443e3037485SYan-Hsuan Chuang
444e3037485SYan-Hsuan Chuang len = rtwpci->tx_rings[RTW_TX_QUEUE_MGMT].r.len;
445e3037485SYan-Hsuan Chuang dma = rtwpci->tx_rings[RTW_TX_QUEUE_MGMT].r.dma;
446e3037485SYan-Hsuan Chuang rtwpci->tx_rings[RTW_TX_QUEUE_MGMT].r.rp = 0;
447e3037485SYan-Hsuan Chuang rtwpci->tx_rings[RTW_TX_QUEUE_MGMT].r.wp = 0;
448a5697a65SYan-Hsuan Chuang rtw_write16(rtwdev, RTK_PCI_TXBD_NUM_MGMTQ, len & TRX_BD_IDX_MASK);
449e3037485SYan-Hsuan Chuang rtw_write32(rtwdev, RTK_PCI_TXBD_DESA_MGMTQ, dma);
450e3037485SYan-Hsuan Chuang
451e3037485SYan-Hsuan Chuang len = rtwpci->tx_rings[RTW_TX_QUEUE_HI0].r.len;
452e3037485SYan-Hsuan Chuang dma = rtwpci->tx_rings[RTW_TX_QUEUE_HI0].r.dma;
453e3037485SYan-Hsuan Chuang rtwpci->tx_rings[RTW_TX_QUEUE_HI0].r.rp = 0;
454e3037485SYan-Hsuan Chuang rtwpci->tx_rings[RTW_TX_QUEUE_HI0].r.wp = 0;
455a5697a65SYan-Hsuan Chuang rtw_write16(rtwdev, RTK_PCI_TXBD_NUM_HI0Q, len & TRX_BD_IDX_MASK);
456e3037485SYan-Hsuan Chuang rtw_write32(rtwdev, RTK_PCI_TXBD_DESA_HI0Q, dma);
457e3037485SYan-Hsuan Chuang
458e3037485SYan-Hsuan Chuang len = rtwpci->rx_rings[RTW_RX_QUEUE_MPDU].r.len;
459e3037485SYan-Hsuan Chuang dma = rtwpci->rx_rings[RTW_RX_QUEUE_MPDU].r.dma;
460e3037485SYan-Hsuan Chuang rtwpci->rx_rings[RTW_RX_QUEUE_MPDU].r.rp = 0;
461e3037485SYan-Hsuan Chuang rtwpci->rx_rings[RTW_RX_QUEUE_MPDU].r.wp = 0;
462a5697a65SYan-Hsuan Chuang rtw_write16(rtwdev, RTK_PCI_RXBD_NUM_MPDUQ, len & TRX_BD_IDX_MASK);
463e3037485SYan-Hsuan Chuang rtw_write32(rtwdev, RTK_PCI_RXBD_DESA_MPDUQ, dma);
464e3037485SYan-Hsuan Chuang
465e3037485SYan-Hsuan Chuang /* reset read/write point */
466e3037485SYan-Hsuan Chuang rtw_write32(rtwdev, RTK_PCI_TXBD_RWPTR_CLR, 0xffffffff);
467e3037485SYan-Hsuan Chuang
4686f0b0d28SYan-Hsuan Chuang /* reset H2C Queue index in a single write */
4697907b52dSPing-Ke Shih if (rtw_chip_wcpu_11ac(rtwdev))
4706f0b0d28SYan-Hsuan Chuang rtw_write32_set(rtwdev, RTK_PCI_TXBD_H2CQ_CSR,
4716f0b0d28SYan-Hsuan Chuang BIT_CLR_H2CQ_HOST_IDX | BIT_CLR_H2CQ_HW_IDX);
472e3037485SYan-Hsuan Chuang }
473e3037485SYan-Hsuan Chuang
rtw_pci_reset_trx_ring(struct rtw_dev * rtwdev)474e3037485SYan-Hsuan Chuang static void rtw_pci_reset_trx_ring(struct rtw_dev *rtwdev)
475e3037485SYan-Hsuan Chuang {
476e3037485SYan-Hsuan Chuang rtw_pci_reset_buf_desc(rtwdev);
477e3037485SYan-Hsuan Chuang }
478e3037485SYan-Hsuan Chuang
rtw_pci_enable_interrupt(struct rtw_dev * rtwdev,struct rtw_pci * rtwpci,bool exclude_rx)479e3037485SYan-Hsuan Chuang static void rtw_pci_enable_interrupt(struct rtw_dev *rtwdev,
4809e2fd298SPo-Hao Huang struct rtw_pci *rtwpci, bool exclude_rx)
481e3037485SYan-Hsuan Chuang {
48257fb39e2SBrian Norris unsigned long flags;
4839e2fd298SPo-Hao Huang u32 imr0_unmask = exclude_rx ? IMR_ROK : 0;
48457fb39e2SBrian Norris
48557fb39e2SBrian Norris spin_lock_irqsave(&rtwpci->hwirq_lock, flags);
48657fb39e2SBrian Norris
4879e2fd298SPo-Hao Huang rtw_write32(rtwdev, RTK_PCI_HIMR0, rtwpci->irq_mask[0] & ~imr0_unmask);
488e3037485SYan-Hsuan Chuang rtw_write32(rtwdev, RTK_PCI_HIMR1, rtwpci->irq_mask[1]);
4897907b52dSPing-Ke Shih if (rtw_chip_wcpu_11ac(rtwdev))
490e3037485SYan-Hsuan Chuang rtw_write32(rtwdev, RTK_PCI_HIMR3, rtwpci->irq_mask[3]);
4917907b52dSPing-Ke Shih
492e3037485SYan-Hsuan Chuang rtwpci->irq_enabled = true;
49357fb39e2SBrian Norris
49457fb39e2SBrian Norris spin_unlock_irqrestore(&rtwpci->hwirq_lock, flags);
495e3037485SYan-Hsuan Chuang }
496e3037485SYan-Hsuan Chuang
rtw_pci_disable_interrupt(struct rtw_dev * rtwdev,struct rtw_pci * rtwpci)497e3037485SYan-Hsuan Chuang static void rtw_pci_disable_interrupt(struct rtw_dev *rtwdev,
498e3037485SYan-Hsuan Chuang struct rtw_pci *rtwpci)
499e3037485SYan-Hsuan Chuang {
50057fb39e2SBrian Norris unsigned long flags;
50157fb39e2SBrian Norris
50257fb39e2SBrian Norris spin_lock_irqsave(&rtwpci->hwirq_lock, flags);
50357fb39e2SBrian Norris
50457fb39e2SBrian Norris if (!rtwpci->irq_enabled)
50557fb39e2SBrian Norris goto out;
50657fb39e2SBrian Norris
507e3037485SYan-Hsuan Chuang rtw_write32(rtwdev, RTK_PCI_HIMR0, 0);
508e3037485SYan-Hsuan Chuang rtw_write32(rtwdev, RTK_PCI_HIMR1, 0);
5097907b52dSPing-Ke Shih if (rtw_chip_wcpu_11ac(rtwdev))
510e3037485SYan-Hsuan Chuang rtw_write32(rtwdev, RTK_PCI_HIMR3, 0);
5117907b52dSPing-Ke Shih
512e3037485SYan-Hsuan Chuang rtwpci->irq_enabled = false;
51357fb39e2SBrian Norris
51457fb39e2SBrian Norris out:
51557fb39e2SBrian Norris spin_unlock_irqrestore(&rtwpci->hwirq_lock, flags);
516e3037485SYan-Hsuan Chuang }
517e3037485SYan-Hsuan Chuang
rtw_pci_dma_reset(struct rtw_dev * rtwdev,struct rtw_pci * rtwpci)518e3037485SYan-Hsuan Chuang static void rtw_pci_dma_reset(struct rtw_dev *rtwdev, struct rtw_pci *rtwpci)
519e3037485SYan-Hsuan Chuang {
520e3037485SYan-Hsuan Chuang /* reset dma and rx tag */
521e3037485SYan-Hsuan Chuang rtw_write32_set(rtwdev, RTK_PCI_CTRL,
522e3037485SYan-Hsuan Chuang BIT_RST_TRXDMA_INTF | BIT_RX_TAG_EN);
523e3037485SYan-Hsuan Chuang rtwpci->rx_tag = 0;
524e3037485SYan-Hsuan Chuang }
525e3037485SYan-Hsuan Chuang
rtw_pci_setup(struct rtw_dev * rtwdev)526fd30e891SChin-Yen Lee static int rtw_pci_setup(struct rtw_dev *rtwdev)
527fd30e891SChin-Yen Lee {
528fd30e891SChin-Yen Lee struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
529fd30e891SChin-Yen Lee
530fd30e891SChin-Yen Lee rtw_pci_reset_trx_ring(rtwdev);
531fd30e891SChin-Yen Lee rtw_pci_dma_reset(rtwdev, rtwpci);
532fd30e891SChin-Yen Lee
533fd30e891SChin-Yen Lee return 0;
534fd30e891SChin-Yen Lee }
535fd30e891SChin-Yen Lee
rtw_pci_dma_release(struct rtw_dev * rtwdev,struct rtw_pci * rtwpci)5360e41edcdSYan-Hsuan Chuang static void rtw_pci_dma_release(struct rtw_dev *rtwdev, struct rtw_pci *rtwpci)
5370e41edcdSYan-Hsuan Chuang {
5380e41edcdSYan-Hsuan Chuang struct rtw_pci_tx_ring *tx_ring;
539c9089796SMartin Blumenstingl enum rtw_tx_queue_type queue;
5400e41edcdSYan-Hsuan Chuang
54125cab7e7SChin-Yen Lee rtw_pci_reset_trx_ring(rtwdev);
5420e41edcdSYan-Hsuan Chuang for (queue = 0; queue < RTK_MAX_TX_QUEUE_NUM; queue++) {
5430e41edcdSYan-Hsuan Chuang tx_ring = &rtwpci->tx_rings[queue];
5440e41edcdSYan-Hsuan Chuang rtw_pci_free_tx_ring_skbs(rtwdev, tx_ring);
5450e41edcdSYan-Hsuan Chuang }
5460e41edcdSYan-Hsuan Chuang }
5470e41edcdSYan-Hsuan Chuang
rtw_pci_napi_start(struct rtw_dev * rtwdev)5489e2fd298SPo-Hao Huang static void rtw_pci_napi_start(struct rtw_dev *rtwdev)
5499e2fd298SPo-Hao Huang {
5509e2fd298SPo-Hao Huang struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
5519e2fd298SPo-Hao Huang
5529e2fd298SPo-Hao Huang if (test_and_set_bit(RTW_PCI_FLAG_NAPI_RUNNING, rtwpci->flags))
5539e2fd298SPo-Hao Huang return;
5549e2fd298SPo-Hao Huang
5559e2fd298SPo-Hao Huang napi_enable(&rtwpci->napi);
5569e2fd298SPo-Hao Huang }
5579e2fd298SPo-Hao Huang
rtw_pci_napi_stop(struct rtw_dev * rtwdev)5589e2fd298SPo-Hao Huang static void rtw_pci_napi_stop(struct rtw_dev *rtwdev)
5599e2fd298SPo-Hao Huang {
5609e2fd298SPo-Hao Huang struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
5619e2fd298SPo-Hao Huang
5629e2fd298SPo-Hao Huang if (!test_and_clear_bit(RTW_PCI_FLAG_NAPI_RUNNING, rtwpci->flags))
5639e2fd298SPo-Hao Huang return;
5649e2fd298SPo-Hao Huang
5659e2fd298SPo-Hao Huang napi_synchronize(&rtwpci->napi);
5669e2fd298SPo-Hao Huang napi_disable(&rtwpci->napi);
5679e2fd298SPo-Hao Huang }
5689e2fd298SPo-Hao Huang
rtw_pci_start(struct rtw_dev * rtwdev)569e3037485SYan-Hsuan Chuang static int rtw_pci_start(struct rtw_dev *rtwdev)
570e3037485SYan-Hsuan Chuang {
571e3037485SYan-Hsuan Chuang struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
572e3037485SYan-Hsuan Chuang
5737bd3760cSPo-Hao Huang rtw_pci_napi_start(rtwdev);
5747bd3760cSPo-Hao Huang
57557fb39e2SBrian Norris spin_lock_bh(&rtwpci->irq_lock);
5767bd3760cSPo-Hao Huang rtwpci->running = true;
5779e2fd298SPo-Hao Huang rtw_pci_enable_interrupt(rtwdev, rtwpci, false);
57857fb39e2SBrian Norris spin_unlock_bh(&rtwpci->irq_lock);
579e3037485SYan-Hsuan Chuang
580e3037485SYan-Hsuan Chuang return 0;
581e3037485SYan-Hsuan Chuang }
582e3037485SYan-Hsuan Chuang
rtw_pci_stop(struct rtw_dev * rtwdev)583e3037485SYan-Hsuan Chuang static void rtw_pci_stop(struct rtw_dev *rtwdev)
584e3037485SYan-Hsuan Chuang {
585e3037485SYan-Hsuan Chuang struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
5867bd3760cSPo-Hao Huang struct pci_dev *pdev = rtwpci->pdev;
587e3037485SYan-Hsuan Chuang
5887bd3760cSPo-Hao Huang spin_lock_bh(&rtwpci->irq_lock);
5897bd3760cSPo-Hao Huang rtwpci->running = false;
5907bd3760cSPo-Hao Huang rtw_pci_disable_interrupt(rtwdev, rtwpci);
5917bd3760cSPo-Hao Huang spin_unlock_bh(&rtwpci->irq_lock);
5927bd3760cSPo-Hao Huang
5937bd3760cSPo-Hao Huang synchronize_irq(pdev->irq);
5949e2fd298SPo-Hao Huang rtw_pci_napi_stop(rtwdev);
5959e2fd298SPo-Hao Huang
59657fb39e2SBrian Norris spin_lock_bh(&rtwpci->irq_lock);
5970e41edcdSYan-Hsuan Chuang rtw_pci_dma_release(rtwdev, rtwpci);
59857fb39e2SBrian Norris spin_unlock_bh(&rtwpci->irq_lock);
599e3037485SYan-Hsuan Chuang }
600e3037485SYan-Hsuan Chuang
rtw_pci_deep_ps_enter(struct rtw_dev * rtwdev)60127e117e4SYan-Hsuan Chuang static void rtw_pci_deep_ps_enter(struct rtw_dev *rtwdev)
60227e117e4SYan-Hsuan Chuang {
60327e117e4SYan-Hsuan Chuang struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
60427e117e4SYan-Hsuan Chuang struct rtw_pci_tx_ring *tx_ring;
605c9089796SMartin Blumenstingl enum rtw_tx_queue_type queue;
60627e117e4SYan-Hsuan Chuang bool tx_empty = true;
60727e117e4SYan-Hsuan Chuang
6085d5d68bcSChin-Yen Lee if (rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_TX_WAKE))
6095d5d68bcSChin-Yen Lee goto enter_deep_ps;
6105d5d68bcSChin-Yen Lee
61127e117e4SYan-Hsuan Chuang lockdep_assert_held(&rtwpci->irq_lock);
61227e117e4SYan-Hsuan Chuang
61327e117e4SYan-Hsuan Chuang /* Deep PS state is not allowed to TX-DMA */
61427e117e4SYan-Hsuan Chuang for (queue = 0; queue < RTK_MAX_TX_QUEUE_NUM; queue++) {
61527e117e4SYan-Hsuan Chuang /* BCN queue is rsvd page, does not have DMA interrupt
61627e117e4SYan-Hsuan Chuang * H2C queue is managed by firmware
61727e117e4SYan-Hsuan Chuang */
61827e117e4SYan-Hsuan Chuang if (queue == RTW_TX_QUEUE_BCN ||
61927e117e4SYan-Hsuan Chuang queue == RTW_TX_QUEUE_H2C)
62027e117e4SYan-Hsuan Chuang continue;
62127e117e4SYan-Hsuan Chuang
62227e117e4SYan-Hsuan Chuang tx_ring = &rtwpci->tx_rings[queue];
62327e117e4SYan-Hsuan Chuang
62427e117e4SYan-Hsuan Chuang /* check if there is any skb DMAing */
62527e117e4SYan-Hsuan Chuang if (skb_queue_len(&tx_ring->queue)) {
62627e117e4SYan-Hsuan Chuang tx_empty = false;
62727e117e4SYan-Hsuan Chuang break;
62827e117e4SYan-Hsuan Chuang }
62927e117e4SYan-Hsuan Chuang }
63027e117e4SYan-Hsuan Chuang
63127e117e4SYan-Hsuan Chuang if (!tx_empty) {
63227e117e4SYan-Hsuan Chuang rtw_dbg(rtwdev, RTW_DBG_PS,
63327e117e4SYan-Hsuan Chuang "TX path not empty, cannot enter deep power save state\n");
63427e117e4SYan-Hsuan Chuang return;
63527e117e4SYan-Hsuan Chuang }
6365d5d68bcSChin-Yen Lee enter_deep_ps:
63727e117e4SYan-Hsuan Chuang set_bit(RTW_FLAG_LEISURE_PS_DEEP, rtwdev->flags);
63827e117e4SYan-Hsuan Chuang rtw_power_mode_change(rtwdev, true);
63927e117e4SYan-Hsuan Chuang }
64027e117e4SYan-Hsuan Chuang
rtw_pci_deep_ps_leave(struct rtw_dev * rtwdev)64127e117e4SYan-Hsuan Chuang static void rtw_pci_deep_ps_leave(struct rtw_dev *rtwdev)
64227e117e4SYan-Hsuan Chuang {
64327e117e4SYan-Hsuan Chuang struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
64427e117e4SYan-Hsuan Chuang
64527e117e4SYan-Hsuan Chuang lockdep_assert_held(&rtwpci->irq_lock);
64627e117e4SYan-Hsuan Chuang
64727e117e4SYan-Hsuan Chuang if (test_and_clear_bit(RTW_FLAG_LEISURE_PS_DEEP, rtwdev->flags))
64827e117e4SYan-Hsuan Chuang rtw_power_mode_change(rtwdev, false);
64927e117e4SYan-Hsuan Chuang }
65027e117e4SYan-Hsuan Chuang
rtw_pci_deep_ps(struct rtw_dev * rtwdev,bool enter)65127e117e4SYan-Hsuan Chuang static void rtw_pci_deep_ps(struct rtw_dev *rtwdev, bool enter)
65227e117e4SYan-Hsuan Chuang {
65327e117e4SYan-Hsuan Chuang struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
65427e117e4SYan-Hsuan Chuang
65557fb39e2SBrian Norris spin_lock_bh(&rtwpci->irq_lock);
65627e117e4SYan-Hsuan Chuang
65727e117e4SYan-Hsuan Chuang if (enter && !test_bit(RTW_FLAG_LEISURE_PS_DEEP, rtwdev->flags))
65827e117e4SYan-Hsuan Chuang rtw_pci_deep_ps_enter(rtwdev);
65927e117e4SYan-Hsuan Chuang
66027e117e4SYan-Hsuan Chuang if (!enter && test_bit(RTW_FLAG_LEISURE_PS_DEEP, rtwdev->flags))
66127e117e4SYan-Hsuan Chuang rtw_pci_deep_ps_leave(rtwdev);
66227e117e4SYan-Hsuan Chuang
66357fb39e2SBrian Norris spin_unlock_bh(&rtwpci->irq_lock);
66427e117e4SYan-Hsuan Chuang }
66527e117e4SYan-Hsuan Chuang
rtw_pci_release_rsvd_page(struct rtw_pci * rtwpci,struct rtw_pci_tx_ring * ring)666e3037485SYan-Hsuan Chuang static void rtw_pci_release_rsvd_page(struct rtw_pci *rtwpci,
667e3037485SYan-Hsuan Chuang struct rtw_pci_tx_ring *ring)
668e3037485SYan-Hsuan Chuang {
669e3037485SYan-Hsuan Chuang struct sk_buff *prev = skb_dequeue(&ring->queue);
670e3037485SYan-Hsuan Chuang struct rtw_pci_tx_data *tx_data;
671e3037485SYan-Hsuan Chuang dma_addr_t dma;
672e3037485SYan-Hsuan Chuang
673e3037485SYan-Hsuan Chuang if (!prev)
674e3037485SYan-Hsuan Chuang return;
675e3037485SYan-Hsuan Chuang
676e3037485SYan-Hsuan Chuang tx_data = rtw_pci_get_tx_data(prev);
677e3037485SYan-Hsuan Chuang dma = tx_data->dma;
67824712ea9SChristophe JAILLET dma_unmap_single(&rtwpci->pdev->dev, dma, prev->len, DMA_TO_DEVICE);
679e3037485SYan-Hsuan Chuang dev_kfree_skb_any(prev);
680e3037485SYan-Hsuan Chuang }
681e3037485SYan-Hsuan Chuang
rtw_pci_dma_check(struct rtw_dev * rtwdev,struct rtw_pci_rx_ring * rx_ring,u32 idx)682e3037485SYan-Hsuan Chuang static void rtw_pci_dma_check(struct rtw_dev *rtwdev,
683e3037485SYan-Hsuan Chuang struct rtw_pci_rx_ring *rx_ring,
684e3037485SYan-Hsuan Chuang u32 idx)
685e3037485SYan-Hsuan Chuang {
686e3037485SYan-Hsuan Chuang struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
687dcbf179cSPing-Ke Shih const struct rtw_chip_info *chip = rtwdev->chip;
688e3037485SYan-Hsuan Chuang struct rtw_pci_rx_buffer_desc *buf_desc;
689e3037485SYan-Hsuan Chuang u32 desc_sz = chip->rx_buf_desc_sz;
690e3037485SYan-Hsuan Chuang u16 total_pkt_size;
691e3037485SYan-Hsuan Chuang
692e3037485SYan-Hsuan Chuang buf_desc = (struct rtw_pci_rx_buffer_desc *)(rx_ring->r.head +
693e3037485SYan-Hsuan Chuang idx * desc_sz);
694e3037485SYan-Hsuan Chuang total_pkt_size = le16_to_cpu(buf_desc->total_pkt_size);
695e3037485SYan-Hsuan Chuang
696e3037485SYan-Hsuan Chuang /* rx tag mismatch, throw a warning */
697e3037485SYan-Hsuan Chuang if (total_pkt_size != rtwpci->rx_tag)
698e3037485SYan-Hsuan Chuang rtw_warn(rtwdev, "pci bus timeout, check dma status\n");
699e3037485SYan-Hsuan Chuang
700e3037485SYan-Hsuan Chuang rtwpci->rx_tag = (rtwpci->rx_tag + 1) % RX_TAG_MAX;
701e3037485SYan-Hsuan Chuang }
702e3037485SYan-Hsuan Chuang
__pci_get_hw_tx_ring_rp(struct rtw_dev * rtwdev,u8 pci_q)7037b33ec8bSZong-Zhe Yang static u32 __pci_get_hw_tx_ring_rp(struct rtw_dev *rtwdev, u8 pci_q)
7047b33ec8bSZong-Zhe Yang {
7057b33ec8bSZong-Zhe Yang u32 bd_idx_addr = rtw_pci_tx_queue_idx_addr[pci_q];
7067b33ec8bSZong-Zhe Yang u32 bd_idx = rtw_read16(rtwdev, bd_idx_addr + 2);
7077b33ec8bSZong-Zhe Yang
7087b33ec8bSZong-Zhe Yang return FIELD_GET(TRX_BD_IDX_MASK, bd_idx);
7097b33ec8bSZong-Zhe Yang }
7107b33ec8bSZong-Zhe Yang
__pci_flush_queue(struct rtw_dev * rtwdev,u8 pci_q,bool drop)7117b33ec8bSZong-Zhe Yang static void __pci_flush_queue(struct rtw_dev *rtwdev, u8 pci_q, bool drop)
7127b33ec8bSZong-Zhe Yang {
7137b33ec8bSZong-Zhe Yang struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
7147b33ec8bSZong-Zhe Yang struct rtw_pci_tx_ring *ring = &rtwpci->tx_rings[pci_q];
7157b33ec8bSZong-Zhe Yang u32 cur_rp;
7167b33ec8bSZong-Zhe Yang u8 i;
7177b33ec8bSZong-Zhe Yang
7187b33ec8bSZong-Zhe Yang /* Because the time taked by the I/O in __pci_get_hw_tx_ring_rp is a
7197b33ec8bSZong-Zhe Yang * bit dynamic, it's hard to define a reasonable fixed total timeout to
7207b33ec8bSZong-Zhe Yang * use read_poll_timeout* helper. Instead, we can ensure a reasonable
7217b33ec8bSZong-Zhe Yang * polling times, so we just use for loop with udelay here.
7227b33ec8bSZong-Zhe Yang */
7237b33ec8bSZong-Zhe Yang for (i = 0; i < 30; i++) {
7247b33ec8bSZong-Zhe Yang cur_rp = __pci_get_hw_tx_ring_rp(rtwdev, pci_q);
7257b33ec8bSZong-Zhe Yang if (cur_rp == ring->r.wp)
7267b33ec8bSZong-Zhe Yang return;
7277b33ec8bSZong-Zhe Yang
7287b33ec8bSZong-Zhe Yang udelay(1);
7297b33ec8bSZong-Zhe Yang }
7307b33ec8bSZong-Zhe Yang
7317b33ec8bSZong-Zhe Yang if (!drop)
7327b33ec8bSZong-Zhe Yang rtw_warn(rtwdev, "timed out to flush pci tx ring[%d]\n", pci_q);
7337b33ec8bSZong-Zhe Yang }
7347b33ec8bSZong-Zhe Yang
__rtw_pci_flush_queues(struct rtw_dev * rtwdev,u32 pci_queues,bool drop)7357b33ec8bSZong-Zhe Yang static void __rtw_pci_flush_queues(struct rtw_dev *rtwdev, u32 pci_queues,
7367b33ec8bSZong-Zhe Yang bool drop)
7377b33ec8bSZong-Zhe Yang {
7387b33ec8bSZong-Zhe Yang u8 q;
7397b33ec8bSZong-Zhe Yang
7407b33ec8bSZong-Zhe Yang for (q = 0; q < RTK_MAX_TX_QUEUE_NUM; q++) {
7419e09fbc5SPo-Hao Huang /* Unnecessary to flush BCN, H2C and HI tx queues. */
7429e09fbc5SPo-Hao Huang if (q == RTW_TX_QUEUE_BCN || q == RTW_TX_QUEUE_H2C ||
7439e09fbc5SPo-Hao Huang q == RTW_TX_QUEUE_HI0)
7447b33ec8bSZong-Zhe Yang continue;
7457b33ec8bSZong-Zhe Yang
7467b33ec8bSZong-Zhe Yang if (pci_queues & BIT(q))
7477b33ec8bSZong-Zhe Yang __pci_flush_queue(rtwdev, q, drop);
7487b33ec8bSZong-Zhe Yang }
7497b33ec8bSZong-Zhe Yang }
7507b33ec8bSZong-Zhe Yang
rtw_pci_flush_queues(struct rtw_dev * rtwdev,u32 queues,bool drop)7517b33ec8bSZong-Zhe Yang static void rtw_pci_flush_queues(struct rtw_dev *rtwdev, u32 queues, bool drop)
7527b33ec8bSZong-Zhe Yang {
7537b33ec8bSZong-Zhe Yang u32 pci_queues = 0;
7547b33ec8bSZong-Zhe Yang u8 i;
7557b33ec8bSZong-Zhe Yang
7567b33ec8bSZong-Zhe Yang /* If all of the hardware queues are requested to flush,
7577b33ec8bSZong-Zhe Yang * flush all of the pci queues.
7587b33ec8bSZong-Zhe Yang */
7597b33ec8bSZong-Zhe Yang if (queues == BIT(rtwdev->hw->queues) - 1) {
7607b33ec8bSZong-Zhe Yang pci_queues = BIT(RTK_MAX_TX_QUEUE_NUM) - 1;
7617b33ec8bSZong-Zhe Yang } else {
7627b33ec8bSZong-Zhe Yang for (i = 0; i < rtwdev->hw->queues; i++)
7637b33ec8bSZong-Zhe Yang if (queues & BIT(i))
7647b6e9df9SMartin Blumenstingl pci_queues |= BIT(rtw_tx_ac_to_hwq(i));
7657b33ec8bSZong-Zhe Yang }
7667b33ec8bSZong-Zhe Yang
7677b33ec8bSZong-Zhe Yang __rtw_pci_flush_queues(rtwdev, pci_queues, drop);
7687b33ec8bSZong-Zhe Yang }
7697b33ec8bSZong-Zhe Yang
rtw_pci_tx_kick_off_queue(struct rtw_dev * rtwdev,enum rtw_tx_queue_type queue)770c9089796SMartin Blumenstingl static void rtw_pci_tx_kick_off_queue(struct rtw_dev *rtwdev,
771c9089796SMartin Blumenstingl enum rtw_tx_queue_type queue)
772aaab5d0eSYan-Hsuan Chuang {
773aaab5d0eSYan-Hsuan Chuang struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
774aaab5d0eSYan-Hsuan Chuang struct rtw_pci_tx_ring *ring;
775aaab5d0eSYan-Hsuan Chuang u32 bd_idx;
776aaab5d0eSYan-Hsuan Chuang
777aaab5d0eSYan-Hsuan Chuang ring = &rtwpci->tx_rings[queue];
778aaab5d0eSYan-Hsuan Chuang bd_idx = rtw_pci_tx_queue_idx_addr[queue];
779aaab5d0eSYan-Hsuan Chuang
780aaab5d0eSYan-Hsuan Chuang spin_lock_bh(&rtwpci->irq_lock);
7815d5d68bcSChin-Yen Lee if (!rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_TX_WAKE))
782aaab5d0eSYan-Hsuan Chuang rtw_pci_deep_ps_leave(rtwdev);
783aaab5d0eSYan-Hsuan Chuang rtw_write16(rtwdev, bd_idx, ring->r.wp & TRX_BD_IDX_MASK);
784aaab5d0eSYan-Hsuan Chuang spin_unlock_bh(&rtwpci->irq_lock);
785aaab5d0eSYan-Hsuan Chuang }
786aaab5d0eSYan-Hsuan Chuang
rtw_pci_tx_kick_off(struct rtw_dev * rtwdev)787aaab5d0eSYan-Hsuan Chuang static void rtw_pci_tx_kick_off(struct rtw_dev *rtwdev)
788aaab5d0eSYan-Hsuan Chuang {
789aaab5d0eSYan-Hsuan Chuang struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
790c9089796SMartin Blumenstingl enum rtw_tx_queue_type queue;
791aaab5d0eSYan-Hsuan Chuang
792aaab5d0eSYan-Hsuan Chuang for (queue = 0; queue < RTK_MAX_TX_QUEUE_NUM; queue++)
793aaab5d0eSYan-Hsuan Chuang if (test_and_clear_bit(queue, rtwpci->tx_queued))
794aaab5d0eSYan-Hsuan Chuang rtw_pci_tx_kick_off_queue(rtwdev, queue);
795aaab5d0eSYan-Hsuan Chuang }
796aaab5d0eSYan-Hsuan Chuang
rtw_pci_tx_write_data(struct rtw_dev * rtwdev,struct rtw_tx_pkt_info * pkt_info,struct sk_buff * skb,enum rtw_tx_queue_type queue)797aaab5d0eSYan-Hsuan Chuang static int rtw_pci_tx_write_data(struct rtw_dev *rtwdev,
798e3037485SYan-Hsuan Chuang struct rtw_tx_pkt_info *pkt_info,
799c9089796SMartin Blumenstingl struct sk_buff *skb,
800c9089796SMartin Blumenstingl enum rtw_tx_queue_type queue)
801e3037485SYan-Hsuan Chuang {
802e3037485SYan-Hsuan Chuang struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
803dcbf179cSPing-Ke Shih const struct rtw_chip_info *chip = rtwdev->chip;
804e3037485SYan-Hsuan Chuang struct rtw_pci_tx_ring *ring;
805e3037485SYan-Hsuan Chuang struct rtw_pci_tx_data *tx_data;
806e3037485SYan-Hsuan Chuang dma_addr_t dma;
807e3037485SYan-Hsuan Chuang u32 tx_pkt_desc_sz = chip->tx_pkt_desc_sz;
808e3037485SYan-Hsuan Chuang u32 tx_buf_desc_sz = chip->tx_buf_desc_sz;
809e3037485SYan-Hsuan Chuang u32 size;
810e3037485SYan-Hsuan Chuang u32 psb_len;
811e3037485SYan-Hsuan Chuang u8 *pkt_desc;
812e3037485SYan-Hsuan Chuang struct rtw_pci_tx_buffer_desc *buf_desc;
813e3037485SYan-Hsuan Chuang
814e3037485SYan-Hsuan Chuang ring = &rtwpci->tx_rings[queue];
815e3037485SYan-Hsuan Chuang
816e3037485SYan-Hsuan Chuang size = skb->len;
817e3037485SYan-Hsuan Chuang
818e3037485SYan-Hsuan Chuang if (queue == RTW_TX_QUEUE_BCN)
819e3037485SYan-Hsuan Chuang rtw_pci_release_rsvd_page(rtwpci, ring);
820e3037485SYan-Hsuan Chuang else if (!avail_desc(ring->r.wp, ring->r.rp, ring->r.len))
821e3037485SYan-Hsuan Chuang return -ENOSPC;
822e3037485SYan-Hsuan Chuang
823e3037485SYan-Hsuan Chuang pkt_desc = skb_push(skb, chip->tx_pkt_desc_sz);
824e3037485SYan-Hsuan Chuang memset(pkt_desc, 0, tx_pkt_desc_sz);
825e3037485SYan-Hsuan Chuang pkt_info->qsel = rtw_pci_get_tx_qsel(skb, queue);
826e3037485SYan-Hsuan Chuang rtw_tx_fill_tx_desc(pkt_info, skb);
82724712ea9SChristophe JAILLET dma = dma_map_single(&rtwpci->pdev->dev, skb->data, skb->len,
82824712ea9SChristophe JAILLET DMA_TO_DEVICE);
82924712ea9SChristophe JAILLET if (dma_mapping_error(&rtwpci->pdev->dev, dma))
830e3037485SYan-Hsuan Chuang return -EBUSY;
831e3037485SYan-Hsuan Chuang
832e3037485SYan-Hsuan Chuang /* after this we got dma mapped, there is no way back */
833e3037485SYan-Hsuan Chuang buf_desc = get_tx_buffer_desc(ring, tx_buf_desc_sz);
834e3037485SYan-Hsuan Chuang memset(buf_desc, 0, tx_buf_desc_sz);
835e3037485SYan-Hsuan Chuang psb_len = (skb->len - 1) / 128 + 1;
836e3037485SYan-Hsuan Chuang if (queue == RTW_TX_QUEUE_BCN)
837e3037485SYan-Hsuan Chuang psb_len |= 1 << RTK_PCI_TXBD_OWN_OFFSET;
838e3037485SYan-Hsuan Chuang
839e3037485SYan-Hsuan Chuang buf_desc[0].psb_len = cpu_to_le16(psb_len);
840e3037485SYan-Hsuan Chuang buf_desc[0].buf_size = cpu_to_le16(tx_pkt_desc_sz);
841e3037485SYan-Hsuan Chuang buf_desc[0].dma = cpu_to_le32(dma);
842e3037485SYan-Hsuan Chuang buf_desc[1].buf_size = cpu_to_le16(size);
843e3037485SYan-Hsuan Chuang buf_desc[1].dma = cpu_to_le32(dma + tx_pkt_desc_sz);
844e3037485SYan-Hsuan Chuang
845e3037485SYan-Hsuan Chuang tx_data = rtw_pci_get_tx_data(skb);
846e3037485SYan-Hsuan Chuang tx_data->dma = dma;
847e3037485SYan-Hsuan Chuang tx_data->sn = pkt_info->sn;
84827e117e4SYan-Hsuan Chuang
84957fb39e2SBrian Norris spin_lock_bh(&rtwpci->irq_lock);
85027e117e4SYan-Hsuan Chuang
851e3037485SYan-Hsuan Chuang skb_queue_tail(&ring->queue, skb);
852e3037485SYan-Hsuan Chuang
853aaab5d0eSYan-Hsuan Chuang if (queue == RTW_TX_QUEUE_BCN)
854aaab5d0eSYan-Hsuan Chuang goto out_unlock;
855aaab5d0eSYan-Hsuan Chuang
856aaab5d0eSYan-Hsuan Chuang /* update write-index, and kick it off later */
857aaab5d0eSYan-Hsuan Chuang set_bit(queue, rtwpci->tx_queued);
858e3037485SYan-Hsuan Chuang if (++ring->r.wp >= ring->r.len)
859e3037485SYan-Hsuan Chuang ring->r.wp = 0;
860e3037485SYan-Hsuan Chuang
861aaab5d0eSYan-Hsuan Chuang out_unlock:
86257fb39e2SBrian Norris spin_unlock_bh(&rtwpci->irq_lock);
863e3037485SYan-Hsuan Chuang
864e3037485SYan-Hsuan Chuang return 0;
865e3037485SYan-Hsuan Chuang }
866e3037485SYan-Hsuan Chuang
rtw_pci_write_data_rsvd_page(struct rtw_dev * rtwdev,u8 * buf,u32 size)867e3037485SYan-Hsuan Chuang static int rtw_pci_write_data_rsvd_page(struct rtw_dev *rtwdev, u8 *buf,
868e3037485SYan-Hsuan Chuang u32 size)
869e3037485SYan-Hsuan Chuang {
870e3037485SYan-Hsuan Chuang struct sk_buff *skb;
871da14a040SYan-Hsuan Chuang struct rtw_tx_pkt_info pkt_info = {0};
872aaab5d0eSYan-Hsuan Chuang u8 reg_bcn_work;
873aaab5d0eSYan-Hsuan Chuang int ret;
874e3037485SYan-Hsuan Chuang
875da14a040SYan-Hsuan Chuang skb = rtw_tx_write_data_rsvd_page_get(rtwdev, &pkt_info, buf, size);
876e3037485SYan-Hsuan Chuang if (!skb)
877e3037485SYan-Hsuan Chuang return -ENOMEM;
878e3037485SYan-Hsuan Chuang
879aaab5d0eSYan-Hsuan Chuang ret = rtw_pci_tx_write_data(rtwdev, &pkt_info, skb, RTW_TX_QUEUE_BCN);
880aaab5d0eSYan-Hsuan Chuang if (ret) {
881aaab5d0eSYan-Hsuan Chuang rtw_err(rtwdev, "failed to write rsvd page data\n");
882aaab5d0eSYan-Hsuan Chuang return ret;
883aaab5d0eSYan-Hsuan Chuang }
884aaab5d0eSYan-Hsuan Chuang
885aaab5d0eSYan-Hsuan Chuang /* reserved pages go through beacon queue */
886aaab5d0eSYan-Hsuan Chuang reg_bcn_work = rtw_read8(rtwdev, RTK_PCI_TXBD_BCN_WORK);
887aaab5d0eSYan-Hsuan Chuang reg_bcn_work |= BIT_PCI_BCNQ_FLAG;
888aaab5d0eSYan-Hsuan Chuang rtw_write8(rtwdev, RTK_PCI_TXBD_BCN_WORK, reg_bcn_work);
889aaab5d0eSYan-Hsuan Chuang
890aaab5d0eSYan-Hsuan Chuang return 0;
891e3037485SYan-Hsuan Chuang }
892e3037485SYan-Hsuan Chuang
rtw_pci_write_data_h2c(struct rtw_dev * rtwdev,u8 * buf,u32 size)893e3037485SYan-Hsuan Chuang static int rtw_pci_write_data_h2c(struct rtw_dev *rtwdev, u8 *buf, u32 size)
894e3037485SYan-Hsuan Chuang {
895e3037485SYan-Hsuan Chuang struct sk_buff *skb;
896da14a040SYan-Hsuan Chuang struct rtw_tx_pkt_info pkt_info = {0};
897aaab5d0eSYan-Hsuan Chuang int ret;
898e3037485SYan-Hsuan Chuang
899da14a040SYan-Hsuan Chuang skb = rtw_tx_write_data_h2c_get(rtwdev, &pkt_info, buf, size);
900e3037485SYan-Hsuan Chuang if (!skb)
901e3037485SYan-Hsuan Chuang return -ENOMEM;
902e3037485SYan-Hsuan Chuang
903aaab5d0eSYan-Hsuan Chuang ret = rtw_pci_tx_write_data(rtwdev, &pkt_info, skb, RTW_TX_QUEUE_H2C);
904aaab5d0eSYan-Hsuan Chuang if (ret) {
905aaab5d0eSYan-Hsuan Chuang rtw_err(rtwdev, "failed to write h2c data\n");
906aaab5d0eSYan-Hsuan Chuang return ret;
907e3037485SYan-Hsuan Chuang }
908e3037485SYan-Hsuan Chuang
909aaab5d0eSYan-Hsuan Chuang rtw_pci_tx_kick_off_queue(rtwdev, RTW_TX_QUEUE_H2C);
910aaab5d0eSYan-Hsuan Chuang
911aaab5d0eSYan-Hsuan Chuang return 0;
912aaab5d0eSYan-Hsuan Chuang }
913aaab5d0eSYan-Hsuan Chuang
rtw_pci_tx_write(struct rtw_dev * rtwdev,struct rtw_tx_pkt_info * pkt_info,struct sk_buff * skb)914aaab5d0eSYan-Hsuan Chuang static int rtw_pci_tx_write(struct rtw_dev *rtwdev,
915e3037485SYan-Hsuan Chuang struct rtw_tx_pkt_info *pkt_info,
916e3037485SYan-Hsuan Chuang struct sk_buff *skb)
917e3037485SYan-Hsuan Chuang {
9187b6e9df9SMartin Blumenstingl enum rtw_tx_queue_type queue = rtw_tx_queue_mapping(skb);
919e3037485SYan-Hsuan Chuang struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
920e3037485SYan-Hsuan Chuang struct rtw_pci_tx_ring *ring;
921e3037485SYan-Hsuan Chuang int ret;
922e3037485SYan-Hsuan Chuang
923aaab5d0eSYan-Hsuan Chuang ret = rtw_pci_tx_write_data(rtwdev, pkt_info, skb, queue);
924e3037485SYan-Hsuan Chuang if (ret)
925e3037485SYan-Hsuan Chuang return ret;
926e3037485SYan-Hsuan Chuang
927e3037485SYan-Hsuan Chuang ring = &rtwpci->tx_rings[queue];
928a548909dSYu-Yen Ting spin_lock_bh(&rtwpci->irq_lock);
929e3037485SYan-Hsuan Chuang if (avail_desc(ring->r.wp, ring->r.rp, ring->r.len) < 2) {
930e3037485SYan-Hsuan Chuang ieee80211_stop_queue(rtwdev->hw, skb_get_queue_mapping(skb));
931e3037485SYan-Hsuan Chuang ring->queue_stopped = true;
932e3037485SYan-Hsuan Chuang }
933a548909dSYu-Yen Ting spin_unlock_bh(&rtwpci->irq_lock);
934e3037485SYan-Hsuan Chuang
935e3037485SYan-Hsuan Chuang return 0;
936e3037485SYan-Hsuan Chuang }
937e3037485SYan-Hsuan Chuang
rtw_pci_tx_isr(struct rtw_dev * rtwdev,struct rtw_pci * rtwpci,u8 hw_queue)938e3037485SYan-Hsuan Chuang static void rtw_pci_tx_isr(struct rtw_dev *rtwdev, struct rtw_pci *rtwpci,
939e3037485SYan-Hsuan Chuang u8 hw_queue)
940e3037485SYan-Hsuan Chuang {
941e3037485SYan-Hsuan Chuang struct ieee80211_hw *hw = rtwdev->hw;
942e3037485SYan-Hsuan Chuang struct ieee80211_tx_info *info;
943e3037485SYan-Hsuan Chuang struct rtw_pci_tx_ring *ring;
944e3037485SYan-Hsuan Chuang struct rtw_pci_tx_data *tx_data;
945e3037485SYan-Hsuan Chuang struct sk_buff *skb;
946e3037485SYan-Hsuan Chuang u32 count;
947e3037485SYan-Hsuan Chuang u32 bd_idx_addr;
948a548909dSYu-Yen Ting u32 bd_idx, cur_rp, rp_idx;
949e3037485SYan-Hsuan Chuang u16 q_map;
950e3037485SYan-Hsuan Chuang
951e3037485SYan-Hsuan Chuang ring = &rtwpci->tx_rings[hw_queue];
952e3037485SYan-Hsuan Chuang
953e3037485SYan-Hsuan Chuang bd_idx_addr = rtw_pci_tx_queue_idx_addr[hw_queue];
954e3037485SYan-Hsuan Chuang bd_idx = rtw_read32(rtwdev, bd_idx_addr);
955e3037485SYan-Hsuan Chuang cur_rp = bd_idx >> 16;
956a5697a65SYan-Hsuan Chuang cur_rp &= TRX_BD_IDX_MASK;
957a548909dSYu-Yen Ting rp_idx = ring->r.rp;
958e3037485SYan-Hsuan Chuang if (cur_rp >= ring->r.rp)
959e3037485SYan-Hsuan Chuang count = cur_rp - ring->r.rp;
960e3037485SYan-Hsuan Chuang else
961e3037485SYan-Hsuan Chuang count = ring->r.len - (ring->r.rp - cur_rp);
962e3037485SYan-Hsuan Chuang
963e3037485SYan-Hsuan Chuang while (count--) {
964e3037485SYan-Hsuan Chuang skb = skb_dequeue(&ring->queue);
965f4f84ff8SYan-Hsuan Chuang if (!skb) {
966f4f84ff8SYan-Hsuan Chuang rtw_err(rtwdev, "failed to dequeue %d skb TX queue %d, BD=0x%08x, rp %d -> %d\n",
967f4f84ff8SYan-Hsuan Chuang count, hw_queue, bd_idx, ring->r.rp, cur_rp);
968f4f84ff8SYan-Hsuan Chuang break;
969f4f84ff8SYan-Hsuan Chuang }
970e3037485SYan-Hsuan Chuang tx_data = rtw_pci_get_tx_data(skb);
97124712ea9SChristophe JAILLET dma_unmap_single(&rtwpci->pdev->dev, tx_data->dma, skb->len,
97224712ea9SChristophe JAILLET DMA_TO_DEVICE);
973e3037485SYan-Hsuan Chuang
974e3037485SYan-Hsuan Chuang /* just free command packets from host to card */
975e3037485SYan-Hsuan Chuang if (hw_queue == RTW_TX_QUEUE_H2C) {
976e3037485SYan-Hsuan Chuang dev_kfree_skb_irq(skb);
977e3037485SYan-Hsuan Chuang continue;
978e3037485SYan-Hsuan Chuang }
979e3037485SYan-Hsuan Chuang
980e3037485SYan-Hsuan Chuang if (ring->queue_stopped &&
981a548909dSYu-Yen Ting avail_desc(ring->r.wp, rp_idx, ring->r.len) > 4) {
982e3037485SYan-Hsuan Chuang q_map = skb_get_queue_mapping(skb);
983e3037485SYan-Hsuan Chuang ieee80211_wake_queue(hw, q_map);
984e3037485SYan-Hsuan Chuang ring->queue_stopped = false;
985e3037485SYan-Hsuan Chuang }
986e3037485SYan-Hsuan Chuang
987a548909dSYu-Yen Ting if (++rp_idx >= ring->r.len)
988a548909dSYu-Yen Ting rp_idx = 0;
989a548909dSYu-Yen Ting
990e3037485SYan-Hsuan Chuang skb_pull(skb, rtwdev->chip->tx_pkt_desc_sz);
991e3037485SYan-Hsuan Chuang
992e3037485SYan-Hsuan Chuang info = IEEE80211_SKB_CB(skb);
993e3037485SYan-Hsuan Chuang
994e3037485SYan-Hsuan Chuang /* enqueue to wait for tx report */
995e3037485SYan-Hsuan Chuang if (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) {
996e3037485SYan-Hsuan Chuang rtw_tx_report_enqueue(rtwdev, skb, tx_data->sn);
997e3037485SYan-Hsuan Chuang continue;
998e3037485SYan-Hsuan Chuang }
999e3037485SYan-Hsuan Chuang
1000e3037485SYan-Hsuan Chuang /* always ACK for others, then they won't be marked as drop */
1001e3037485SYan-Hsuan Chuang if (info->flags & IEEE80211_TX_CTL_NO_ACK)
1002e3037485SYan-Hsuan Chuang info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED;
1003e3037485SYan-Hsuan Chuang else
1004e3037485SYan-Hsuan Chuang info->flags |= IEEE80211_TX_STAT_ACK;
1005e3037485SYan-Hsuan Chuang
1006e3037485SYan-Hsuan Chuang ieee80211_tx_info_clear_status(info);
1007e3037485SYan-Hsuan Chuang ieee80211_tx_status_irqsafe(hw, skb);
1008e3037485SYan-Hsuan Chuang }
1009e3037485SYan-Hsuan Chuang
1010e3037485SYan-Hsuan Chuang ring->r.rp = cur_rp;
1011e3037485SYan-Hsuan Chuang }
1012e3037485SYan-Hsuan Chuang
rtw_pci_rx_isr(struct rtw_dev * rtwdev)10139e2fd298SPo-Hao Huang static void rtw_pci_rx_isr(struct rtw_dev *rtwdev)
10149e2fd298SPo-Hao Huang {
10159e2fd298SPo-Hao Huang struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
10169e2fd298SPo-Hao Huang struct napi_struct *napi = &rtwpci->napi;
10179e2fd298SPo-Hao Huang
10189e2fd298SPo-Hao Huang napi_schedule(napi);
10199e2fd298SPo-Hao Huang }
10209e2fd298SPo-Hao Huang
rtw_pci_get_hw_rx_ring_nr(struct rtw_dev * rtwdev,struct rtw_pci * rtwpci)10219e2fd298SPo-Hao Huang static int rtw_pci_get_hw_rx_ring_nr(struct rtw_dev *rtwdev,
10229e2fd298SPo-Hao Huang struct rtw_pci *rtwpci)
10239e2fd298SPo-Hao Huang {
10249e2fd298SPo-Hao Huang struct rtw_pci_rx_ring *ring;
10259e2fd298SPo-Hao Huang int count = 0;
10269e2fd298SPo-Hao Huang u32 tmp, cur_wp;
10279e2fd298SPo-Hao Huang
10289e2fd298SPo-Hao Huang ring = &rtwpci->rx_rings[RTW_RX_QUEUE_MPDU];
10299e2fd298SPo-Hao Huang tmp = rtw_read32(rtwdev, RTK_PCI_RXBD_IDX_MPDUQ);
10309e2fd298SPo-Hao Huang cur_wp = u32_get_bits(tmp, TRX_BD_HW_IDX_MASK);
10319e2fd298SPo-Hao Huang if (cur_wp >= ring->r.wp)
10329e2fd298SPo-Hao Huang count = cur_wp - ring->r.wp;
10339e2fd298SPo-Hao Huang else
10349e2fd298SPo-Hao Huang count = ring->r.len - (ring->r.wp - cur_wp);
10359e2fd298SPo-Hao Huang
10369e2fd298SPo-Hao Huang return count;
10379e2fd298SPo-Hao Huang }
10389e2fd298SPo-Hao Huang
rtw_pci_rx_napi(struct rtw_dev * rtwdev,struct rtw_pci * rtwpci,u8 hw_queue,u32 limit)10399e2fd298SPo-Hao Huang static u32 rtw_pci_rx_napi(struct rtw_dev *rtwdev, struct rtw_pci *rtwpci,
10409e2fd298SPo-Hao Huang u8 hw_queue, u32 limit)
1041e3037485SYan-Hsuan Chuang {
1042dcbf179cSPing-Ke Shih const struct rtw_chip_info *chip = rtwdev->chip;
10439e2fd298SPo-Hao Huang struct napi_struct *napi = &rtwpci->napi;
10449e2fd298SPo-Hao Huang struct rtw_pci_rx_ring *ring = &rtwpci->rx_rings[RTW_RX_QUEUE_MPDU];
1045e3037485SYan-Hsuan Chuang struct rtw_rx_pkt_stat pkt_stat;
1046e3037485SYan-Hsuan Chuang struct ieee80211_rx_status rx_status;
1047e3037485SYan-Hsuan Chuang struct sk_buff *skb, *new;
10489e2fd298SPo-Hao Huang u32 cur_rp = ring->r.rp;
10499e2fd298SPo-Hao Huang u32 count, rx_done = 0;
1050e3037485SYan-Hsuan Chuang u32 pkt_offset;
1051e3037485SYan-Hsuan Chuang u32 pkt_desc_sz = chip->rx_pkt_desc_sz;
1052e3037485SYan-Hsuan Chuang u32 buf_desc_sz = chip->rx_buf_desc_sz;
1053ee6db78fSJian-Hong Pan u32 new_len;
1054e3037485SYan-Hsuan Chuang u8 *rx_desc;
1055e3037485SYan-Hsuan Chuang dma_addr_t dma;
1056e3037485SYan-Hsuan Chuang
10579e2fd298SPo-Hao Huang count = rtw_pci_get_hw_rx_ring_nr(rtwdev, rtwpci);
10589e2fd298SPo-Hao Huang count = min(count, limit);
1059e3037485SYan-Hsuan Chuang
1060e3037485SYan-Hsuan Chuang while (count--) {
1061e3037485SYan-Hsuan Chuang rtw_pci_dma_check(rtwdev, ring, cur_rp);
1062e3037485SYan-Hsuan Chuang skb = ring->buf[cur_rp];
1063e3037485SYan-Hsuan Chuang dma = *((dma_addr_t *)skb->cb);
106429b68a92SJian-Hong Pan dma_sync_single_for_cpu(rtwdev->dev, dma, RTK_PCI_RX_BUF_SIZE,
106529b68a92SJian-Hong Pan DMA_FROM_DEVICE);
1066e3037485SYan-Hsuan Chuang rx_desc = skb->data;
1067e3037485SYan-Hsuan Chuang chip->ops->query_rx_desc(rtwdev, rx_desc, &pkt_stat, &rx_status);
1068e3037485SYan-Hsuan Chuang
1069e3037485SYan-Hsuan Chuang /* offset from rx_desc to payload */
1070e3037485SYan-Hsuan Chuang pkt_offset = pkt_desc_sz + pkt_stat.drv_info_sz +
1071e3037485SYan-Hsuan Chuang pkt_stat.shift;
1072e3037485SYan-Hsuan Chuang
1073ee6db78fSJian-Hong Pan /* allocate a new skb for this frame,
1074ee6db78fSJian-Hong Pan * discard the frame if none available
1075ee6db78fSJian-Hong Pan */
1076ee6db78fSJian-Hong Pan new_len = pkt_stat.pkt_len + pkt_offset;
1077ee6db78fSJian-Hong Pan new = dev_alloc_skb(new_len);
1078ee6db78fSJian-Hong Pan if (WARN_ONCE(!new, "rx routine starvation\n"))
1079ee6db78fSJian-Hong Pan goto next_rp;
1080e3037485SYan-Hsuan Chuang
1081ee6db78fSJian-Hong Pan /* put the DMA data including rx_desc from phy to new skb */
1082ee6db78fSJian-Hong Pan skb_put_data(new, skb->data, new_len);
1083ee6db78fSJian-Hong Pan
1084ee6db78fSJian-Hong Pan if (pkt_stat.is_c2h) {
10850d762f03SYan-Hsuan Chuang rtw_fw_c2h_cmd_rx_irqsafe(rtwdev, pkt_offset, new);
1086e3037485SYan-Hsuan Chuang } else {
1087ee6db78fSJian-Hong Pan /* remove rx_desc */
1088ee6db78fSJian-Hong Pan skb_pull(new, pkt_offset);
1089e3037485SYan-Hsuan Chuang
1090ee6db78fSJian-Hong Pan rtw_rx_stats(rtwdev, pkt_stat.vif, new);
1091e3037485SYan-Hsuan Chuang memcpy(new->cb, &rx_status, sizeof(rx_status));
10929e2fd298SPo-Hao Huang ieee80211_rx_napi(rtwdev->hw, NULL, new, napi);
10939e2fd298SPo-Hao Huang rx_done++;
1094e3037485SYan-Hsuan Chuang }
1095e3037485SYan-Hsuan Chuang
1096ee6db78fSJian-Hong Pan next_rp:
1097ee6db78fSJian-Hong Pan /* new skb delivered to mac80211, re-enable original skb DMA */
109829b68a92SJian-Hong Pan rtw_pci_sync_rx_desc_device(rtwdev, dma, ring, cur_rp,
109929b68a92SJian-Hong Pan buf_desc_sz);
1100e3037485SYan-Hsuan Chuang
1101e3037485SYan-Hsuan Chuang /* host read next element in ring */
1102e3037485SYan-Hsuan Chuang if (++cur_rp >= ring->r.len)
1103e3037485SYan-Hsuan Chuang cur_rp = 0;
1104e3037485SYan-Hsuan Chuang }
1105e3037485SYan-Hsuan Chuang
1106e3037485SYan-Hsuan Chuang ring->r.rp = cur_rp;
11079e2fd298SPo-Hao Huang /* 'rp', the last position we have read, is seen as previous posistion
11089e2fd298SPo-Hao Huang * of 'wp' that is used to calculate 'count' next time.
11099e2fd298SPo-Hao Huang */
11109e2fd298SPo-Hao Huang ring->r.wp = cur_rp;
1111e3037485SYan-Hsuan Chuang rtw_write16(rtwdev, RTK_PCI_RXBD_IDX_MPDUQ, ring->r.rp);
11129e2fd298SPo-Hao Huang
11139e2fd298SPo-Hao Huang return rx_done;
1114e3037485SYan-Hsuan Chuang }
1115e3037485SYan-Hsuan Chuang
rtw_pci_irq_recognized(struct rtw_dev * rtwdev,struct rtw_pci * rtwpci,u32 * irq_status)1116e3037485SYan-Hsuan Chuang static void rtw_pci_irq_recognized(struct rtw_dev *rtwdev,
1117e3037485SYan-Hsuan Chuang struct rtw_pci *rtwpci, u32 *irq_status)
1118e3037485SYan-Hsuan Chuang {
111957fb39e2SBrian Norris unsigned long flags;
112057fb39e2SBrian Norris
112157fb39e2SBrian Norris spin_lock_irqsave(&rtwpci->hwirq_lock, flags);
112257fb39e2SBrian Norris
1123e3037485SYan-Hsuan Chuang irq_status[0] = rtw_read32(rtwdev, RTK_PCI_HISR0);
1124e3037485SYan-Hsuan Chuang irq_status[1] = rtw_read32(rtwdev, RTK_PCI_HISR1);
11257907b52dSPing-Ke Shih if (rtw_chip_wcpu_11ac(rtwdev))
1126e3037485SYan-Hsuan Chuang irq_status[3] = rtw_read32(rtwdev, RTK_PCI_HISR3);
11277907b52dSPing-Ke Shih else
11287907b52dSPing-Ke Shih irq_status[3] = 0;
1129e3037485SYan-Hsuan Chuang irq_status[0] &= rtwpci->irq_mask[0];
1130e3037485SYan-Hsuan Chuang irq_status[1] &= rtwpci->irq_mask[1];
1131e3037485SYan-Hsuan Chuang irq_status[3] &= rtwpci->irq_mask[3];
1132e3037485SYan-Hsuan Chuang rtw_write32(rtwdev, RTK_PCI_HISR0, irq_status[0]);
1133e3037485SYan-Hsuan Chuang rtw_write32(rtwdev, RTK_PCI_HISR1, irq_status[1]);
11347907b52dSPing-Ke Shih if (rtw_chip_wcpu_11ac(rtwdev))
1135e3037485SYan-Hsuan Chuang rtw_write32(rtwdev, RTK_PCI_HISR3, irq_status[3]);
113657fb39e2SBrian Norris
113757fb39e2SBrian Norris spin_unlock_irqrestore(&rtwpci->hwirq_lock, flags);
1138e3037485SYan-Hsuan Chuang }
1139e3037485SYan-Hsuan Chuang
rtw_pci_interrupt_handler(int irq,void * dev)1140e3037485SYan-Hsuan Chuang static irqreturn_t rtw_pci_interrupt_handler(int irq, void *dev)
1141e3037485SYan-Hsuan Chuang {
1142e3037485SYan-Hsuan Chuang struct rtw_dev *rtwdev = dev;
1143e3037485SYan-Hsuan Chuang struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
1144e3037485SYan-Hsuan Chuang
1145b3d07736SJian-Hong Pan /* disable RTW PCI interrupt to avoid more interrupts before the end of
1146b3d07736SJian-Hong Pan * thread function
114779066903SYu-Yen Ting *
114879066903SYu-Yen Ting * disable HIMR here to also avoid new HISR flag being raised before
114979066903SYu-Yen Ting * the HISRs have been Write-1-cleared for MSI. If not all of the HISRs
115079066903SYu-Yen Ting * are cleared, the edge-triggered interrupt will not be generated when
115179066903SYu-Yen Ting * a new HISR flag is set.
1152b3d07736SJian-Hong Pan */
1153b3d07736SJian-Hong Pan rtw_pci_disable_interrupt(rtwdev, rtwpci);
1154b3d07736SJian-Hong Pan
1155b3d07736SJian-Hong Pan return IRQ_WAKE_THREAD;
1156b3d07736SJian-Hong Pan }
1157b3d07736SJian-Hong Pan
rtw_pci_interrupt_threadfn(int irq,void * dev)1158b3d07736SJian-Hong Pan static irqreturn_t rtw_pci_interrupt_threadfn(int irq, void *dev)
1159b3d07736SJian-Hong Pan {
1160b3d07736SJian-Hong Pan struct rtw_dev *rtwdev = dev;
1161b3d07736SJian-Hong Pan struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
1162b3d07736SJian-Hong Pan u32 irq_status[4];
11639e2fd298SPo-Hao Huang bool rx = false;
1164b3d07736SJian-Hong Pan
116557fb39e2SBrian Norris spin_lock_bh(&rtwpci->irq_lock);
1166e3037485SYan-Hsuan Chuang rtw_pci_irq_recognized(rtwdev, rtwpci, irq_status);
1167e3037485SYan-Hsuan Chuang
1168e3037485SYan-Hsuan Chuang if (irq_status[0] & IMR_MGNTDOK)
1169e3037485SYan-Hsuan Chuang rtw_pci_tx_isr(rtwdev, rtwpci, RTW_TX_QUEUE_MGMT);
1170e3037485SYan-Hsuan Chuang if (irq_status[0] & IMR_HIGHDOK)
1171e3037485SYan-Hsuan Chuang rtw_pci_tx_isr(rtwdev, rtwpci, RTW_TX_QUEUE_HI0);
1172e3037485SYan-Hsuan Chuang if (irq_status[0] & IMR_BEDOK)
1173e3037485SYan-Hsuan Chuang rtw_pci_tx_isr(rtwdev, rtwpci, RTW_TX_QUEUE_BE);
1174e3037485SYan-Hsuan Chuang if (irq_status[0] & IMR_BKDOK)
1175e3037485SYan-Hsuan Chuang rtw_pci_tx_isr(rtwdev, rtwpci, RTW_TX_QUEUE_BK);
1176e3037485SYan-Hsuan Chuang if (irq_status[0] & IMR_VODOK)
1177e3037485SYan-Hsuan Chuang rtw_pci_tx_isr(rtwdev, rtwpci, RTW_TX_QUEUE_VO);
1178e3037485SYan-Hsuan Chuang if (irq_status[0] & IMR_VIDOK)
1179e3037485SYan-Hsuan Chuang rtw_pci_tx_isr(rtwdev, rtwpci, RTW_TX_QUEUE_VI);
1180e3037485SYan-Hsuan Chuang if (irq_status[3] & IMR_H2CDOK)
1181e3037485SYan-Hsuan Chuang rtw_pci_tx_isr(rtwdev, rtwpci, RTW_TX_QUEUE_H2C);
11829e2fd298SPo-Hao Huang if (irq_status[0] & IMR_ROK) {
11839e2fd298SPo-Hao Huang rtw_pci_rx_isr(rtwdev);
11849e2fd298SPo-Hao Huang rx = true;
11859e2fd298SPo-Hao Huang }
11865c831644STzu-En Huang if (unlikely(irq_status[0] & IMR_C2HCMD))
11875c831644STzu-En Huang rtw_fw_c2h_cmd_isr(rtwdev);
1188e3037485SYan-Hsuan Chuang
1189b3d07736SJian-Hong Pan /* all of the jobs for this interrupt have been done */
11907bd3760cSPo-Hao Huang if (rtwpci->running)
11919e2fd298SPo-Hao Huang rtw_pci_enable_interrupt(rtwdev, rtwpci, rx);
119257fb39e2SBrian Norris spin_unlock_bh(&rtwpci->irq_lock);
1193e3037485SYan-Hsuan Chuang
1194e3037485SYan-Hsuan Chuang return IRQ_HANDLED;
1195e3037485SYan-Hsuan Chuang }
1196e3037485SYan-Hsuan Chuang
rtw_pci_io_mapping(struct rtw_dev * rtwdev,struct pci_dev * pdev)1197e3037485SYan-Hsuan Chuang static int rtw_pci_io_mapping(struct rtw_dev *rtwdev,
1198e3037485SYan-Hsuan Chuang struct pci_dev *pdev)
1199e3037485SYan-Hsuan Chuang {
1200e3037485SYan-Hsuan Chuang struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
1201e3037485SYan-Hsuan Chuang unsigned long len;
1202e3037485SYan-Hsuan Chuang u8 bar_id = 2;
1203e3037485SYan-Hsuan Chuang int ret;
1204e3037485SYan-Hsuan Chuang
1205e3037485SYan-Hsuan Chuang ret = pci_request_regions(pdev, KBUILD_MODNAME);
1206e3037485SYan-Hsuan Chuang if (ret) {
1207e3037485SYan-Hsuan Chuang rtw_err(rtwdev, "failed to request pci regions\n");
1208e3037485SYan-Hsuan Chuang return ret;
1209e3037485SYan-Hsuan Chuang }
1210e3037485SYan-Hsuan Chuang
1211e3037485SYan-Hsuan Chuang len = pci_resource_len(pdev, bar_id);
1212e3037485SYan-Hsuan Chuang rtwpci->mmap = pci_iomap(pdev, bar_id, len);
1213e3037485SYan-Hsuan Chuang if (!rtwpci->mmap) {
1214191f6b08SDejin Zheng pci_release_regions(pdev);
1215e3037485SYan-Hsuan Chuang rtw_err(rtwdev, "failed to map pci memory\n");
1216e3037485SYan-Hsuan Chuang return -ENOMEM;
1217e3037485SYan-Hsuan Chuang }
1218e3037485SYan-Hsuan Chuang
1219e3037485SYan-Hsuan Chuang return 0;
1220e3037485SYan-Hsuan Chuang }
1221e3037485SYan-Hsuan Chuang
rtw_pci_io_unmapping(struct rtw_dev * rtwdev,struct pci_dev * pdev)1222e3037485SYan-Hsuan Chuang static void rtw_pci_io_unmapping(struct rtw_dev *rtwdev,
1223e3037485SYan-Hsuan Chuang struct pci_dev *pdev)
1224e3037485SYan-Hsuan Chuang {
1225e3037485SYan-Hsuan Chuang struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
1226e3037485SYan-Hsuan Chuang
1227e3037485SYan-Hsuan Chuang if (rtwpci->mmap) {
1228e3037485SYan-Hsuan Chuang pci_iounmap(pdev, rtwpci->mmap);
1229e3037485SYan-Hsuan Chuang pci_release_regions(pdev);
1230e3037485SYan-Hsuan Chuang }
1231e3037485SYan-Hsuan Chuang }
1232e3037485SYan-Hsuan Chuang
rtw_dbi_write8(struct rtw_dev * rtwdev,u16 addr,u8 data)1233e3037485SYan-Hsuan Chuang static void rtw_dbi_write8(struct rtw_dev *rtwdev, u16 addr, u8 data)
1234e3037485SYan-Hsuan Chuang {
1235e3037485SYan-Hsuan Chuang u16 write_addr;
123683a5a2d7SYan-Hsuan Chuang u16 remainder = addr & ~(BITS_DBI_WREN | BITS_DBI_ADDR_MASK);
1237e3037485SYan-Hsuan Chuang u8 flag;
1238ff3297f6SYan-Hsuan Chuang u8 cnt;
1239e3037485SYan-Hsuan Chuang
124083a5a2d7SYan-Hsuan Chuang write_addr = addr & BITS_DBI_ADDR_MASK;
124183a5a2d7SYan-Hsuan Chuang write_addr |= u16_encode_bits(BIT(remainder), BITS_DBI_WREN);
1242e3037485SYan-Hsuan Chuang rtw_write8(rtwdev, REG_DBI_WDATA_V1 + remainder, data);
1243e3037485SYan-Hsuan Chuang rtw_write16(rtwdev, REG_DBI_FLAG_V1, write_addr);
124483a5a2d7SYan-Hsuan Chuang rtw_write8(rtwdev, REG_DBI_FLAG_V1 + 2, BIT_DBI_WFLAG >> 16);
1245e3037485SYan-Hsuan Chuang
1246ff3297f6SYan-Hsuan Chuang for (cnt = 0; cnt < RTW_PCI_WR_RETRY_CNT; cnt++) {
1247e3037485SYan-Hsuan Chuang flag = rtw_read8(rtwdev, REG_DBI_FLAG_V1 + 2);
1248ff3297f6SYan-Hsuan Chuang if (flag == 0)
1249ff3297f6SYan-Hsuan Chuang return;
1250ff3297f6SYan-Hsuan Chuang
1251e3037485SYan-Hsuan Chuang udelay(10);
1252e3037485SYan-Hsuan Chuang }
1253e3037485SYan-Hsuan Chuang
1254ff3297f6SYan-Hsuan Chuang WARN(flag, "failed to write to DBI register, addr=0x%04x\n", addr);
1255e3037485SYan-Hsuan Chuang }
1256e3037485SYan-Hsuan Chuang
rtw_dbi_read8(struct rtw_dev * rtwdev,u16 addr,u8 * value)1257d2e2c47eSYan-Hsuan Chuang static int rtw_dbi_read8(struct rtw_dev *rtwdev, u16 addr, u8 *value)
1258d2e2c47eSYan-Hsuan Chuang {
1259d2e2c47eSYan-Hsuan Chuang u16 read_addr = addr & BITS_DBI_ADDR_MASK;
1260d2e2c47eSYan-Hsuan Chuang u8 flag;
1261d2e2c47eSYan-Hsuan Chuang u8 cnt;
1262d2e2c47eSYan-Hsuan Chuang
1263d2e2c47eSYan-Hsuan Chuang rtw_write16(rtwdev, REG_DBI_FLAG_V1, read_addr);
1264d2e2c47eSYan-Hsuan Chuang rtw_write8(rtwdev, REG_DBI_FLAG_V1 + 2, BIT_DBI_RFLAG >> 16);
1265d2e2c47eSYan-Hsuan Chuang
1266d2e2c47eSYan-Hsuan Chuang for (cnt = 0; cnt < RTW_PCI_WR_RETRY_CNT; cnt++) {
1267d2e2c47eSYan-Hsuan Chuang flag = rtw_read8(rtwdev, REG_DBI_FLAG_V1 + 2);
1268d2e2c47eSYan-Hsuan Chuang if (flag == 0) {
1269d2e2c47eSYan-Hsuan Chuang read_addr = REG_DBI_RDATA_V1 + (addr & 3);
1270d2e2c47eSYan-Hsuan Chuang *value = rtw_read8(rtwdev, read_addr);
1271d2e2c47eSYan-Hsuan Chuang return 0;
1272d2e2c47eSYan-Hsuan Chuang }
1273d2e2c47eSYan-Hsuan Chuang
1274d2e2c47eSYan-Hsuan Chuang udelay(10);
1275d2e2c47eSYan-Hsuan Chuang }
1276d2e2c47eSYan-Hsuan Chuang
1277d2e2c47eSYan-Hsuan Chuang WARN(1, "failed to read DBI register, addr=0x%04x\n", addr);
1278d2e2c47eSYan-Hsuan Chuang return -EIO;
1279d2e2c47eSYan-Hsuan Chuang }
1280d2e2c47eSYan-Hsuan Chuang
rtw_mdio_write(struct rtw_dev * rtwdev,u8 addr,u16 data,bool g1)1281e3037485SYan-Hsuan Chuang static void rtw_mdio_write(struct rtw_dev *rtwdev, u8 addr, u16 data, bool g1)
1282e3037485SYan-Hsuan Chuang {
1283e3037485SYan-Hsuan Chuang u8 page;
1284e3037485SYan-Hsuan Chuang u8 wflag;
1285ff3297f6SYan-Hsuan Chuang u8 cnt;
1286e3037485SYan-Hsuan Chuang
1287e3037485SYan-Hsuan Chuang rtw_write16(rtwdev, REG_MDIO_V1, data);
1288e3037485SYan-Hsuan Chuang
128983a5a2d7SYan-Hsuan Chuang page = addr < RTW_PCI_MDIO_PG_SZ ? 0 : 1;
129083a5a2d7SYan-Hsuan Chuang page += g1 ? RTW_PCI_MDIO_PG_OFFS_G1 : RTW_PCI_MDIO_PG_OFFS_G2;
129183a5a2d7SYan-Hsuan Chuang rtw_write8(rtwdev, REG_PCIE_MIX_CFG, addr & BITS_MDIO_ADDR_MASK);
1292e3037485SYan-Hsuan Chuang rtw_write8(rtwdev, REG_PCIE_MIX_CFG + 3, page);
1293e3037485SYan-Hsuan Chuang rtw_write32_mask(rtwdev, REG_PCIE_MIX_CFG, BIT_MDIO_WFLAG_V1, 1);
1294e3037485SYan-Hsuan Chuang
1295ff3297f6SYan-Hsuan Chuang for (cnt = 0; cnt < RTW_PCI_WR_RETRY_CNT; cnt++) {
1296e3037485SYan-Hsuan Chuang wflag = rtw_read32_mask(rtwdev, REG_PCIE_MIX_CFG,
1297e3037485SYan-Hsuan Chuang BIT_MDIO_WFLAG_V1);
1298ff3297f6SYan-Hsuan Chuang if (wflag == 0)
1299ff3297f6SYan-Hsuan Chuang return;
1300ff3297f6SYan-Hsuan Chuang
1301ff3297f6SYan-Hsuan Chuang udelay(10);
1302e3037485SYan-Hsuan Chuang }
1303e3037485SYan-Hsuan Chuang
1304ff3297f6SYan-Hsuan Chuang WARN(wflag, "failed to write to MDIO register, addr=0x%02x\n", addr);
1305e3037485SYan-Hsuan Chuang }
1306e3037485SYan-Hsuan Chuang
rtw_pci_clkreq_set(struct rtw_dev * rtwdev,bool enable)1307d2e2c47eSYan-Hsuan Chuang static void rtw_pci_clkreq_set(struct rtw_dev *rtwdev, bool enable)
1308d2e2c47eSYan-Hsuan Chuang {
1309d2e2c47eSYan-Hsuan Chuang u8 value;
1310d2e2c47eSYan-Hsuan Chuang int ret;
1311d2e2c47eSYan-Hsuan Chuang
131268aa716bSYan-Hsuan Chuang if (rtw_pci_disable_aspm)
131368aa716bSYan-Hsuan Chuang return;
131468aa716bSYan-Hsuan Chuang
1315d2e2c47eSYan-Hsuan Chuang ret = rtw_dbi_read8(rtwdev, RTK_PCIE_LINK_CFG, &value);
1316d2e2c47eSYan-Hsuan Chuang if (ret) {
1317d2e2c47eSYan-Hsuan Chuang rtw_err(rtwdev, "failed to read CLKREQ_L1, ret=%d", ret);
1318d2e2c47eSYan-Hsuan Chuang return;
1319d2e2c47eSYan-Hsuan Chuang }
1320d2e2c47eSYan-Hsuan Chuang
1321d2e2c47eSYan-Hsuan Chuang if (enable)
1322d2e2c47eSYan-Hsuan Chuang value |= BIT_CLKREQ_SW_EN;
1323d2e2c47eSYan-Hsuan Chuang else
1324d2e2c47eSYan-Hsuan Chuang value &= ~BIT_CLKREQ_SW_EN;
1325d2e2c47eSYan-Hsuan Chuang
1326d2e2c47eSYan-Hsuan Chuang rtw_dbi_write8(rtwdev, RTK_PCIE_LINK_CFG, value);
1327d2e2c47eSYan-Hsuan Chuang }
1328d2e2c47eSYan-Hsuan Chuang
rtw_pci_clkreq_pad_low(struct rtw_dev * rtwdev,bool enable)13298d52b46cSChin-Yen Lee static void rtw_pci_clkreq_pad_low(struct rtw_dev *rtwdev, bool enable)
13308d52b46cSChin-Yen Lee {
13318d52b46cSChin-Yen Lee u8 value;
13328d52b46cSChin-Yen Lee int ret;
13338d52b46cSChin-Yen Lee
13348d52b46cSChin-Yen Lee ret = rtw_dbi_read8(rtwdev, RTK_PCIE_LINK_CFG, &value);
13358d52b46cSChin-Yen Lee if (ret) {
13368d52b46cSChin-Yen Lee rtw_err(rtwdev, "failed to read CLKREQ_L1, ret=%d", ret);
13378d52b46cSChin-Yen Lee return;
13388d52b46cSChin-Yen Lee }
13398d52b46cSChin-Yen Lee
13408d52b46cSChin-Yen Lee if (enable)
13418d52b46cSChin-Yen Lee value &= ~BIT_CLKREQ_N_PAD;
13428d52b46cSChin-Yen Lee else
13438d52b46cSChin-Yen Lee value |= BIT_CLKREQ_N_PAD;
13448d52b46cSChin-Yen Lee
13458d52b46cSChin-Yen Lee rtw_dbi_write8(rtwdev, RTK_PCIE_LINK_CFG, value);
13468d52b46cSChin-Yen Lee }
13478d52b46cSChin-Yen Lee
rtw_pci_aspm_set(struct rtw_dev * rtwdev,bool enable)13483dff7c6eSYan-Hsuan Chuang static void rtw_pci_aspm_set(struct rtw_dev *rtwdev, bool enable)
13493dff7c6eSYan-Hsuan Chuang {
13503dff7c6eSYan-Hsuan Chuang u8 value;
13513dff7c6eSYan-Hsuan Chuang int ret;
13523dff7c6eSYan-Hsuan Chuang
135368aa716bSYan-Hsuan Chuang if (rtw_pci_disable_aspm)
135468aa716bSYan-Hsuan Chuang return;
135568aa716bSYan-Hsuan Chuang
13563dff7c6eSYan-Hsuan Chuang ret = rtw_dbi_read8(rtwdev, RTK_PCIE_LINK_CFG, &value);
13573dff7c6eSYan-Hsuan Chuang if (ret) {
13583dff7c6eSYan-Hsuan Chuang rtw_err(rtwdev, "failed to read ASPM, ret=%d", ret);
13593dff7c6eSYan-Hsuan Chuang return;
13603dff7c6eSYan-Hsuan Chuang }
13613dff7c6eSYan-Hsuan Chuang
13623dff7c6eSYan-Hsuan Chuang if (enable)
13633dff7c6eSYan-Hsuan Chuang value |= BIT_L1_SW_EN;
13643dff7c6eSYan-Hsuan Chuang else
13653dff7c6eSYan-Hsuan Chuang value &= ~BIT_L1_SW_EN;
13663dff7c6eSYan-Hsuan Chuang
13673dff7c6eSYan-Hsuan Chuang rtw_dbi_write8(rtwdev, RTK_PCIE_LINK_CFG, value);
13683dff7c6eSYan-Hsuan Chuang }
13693dff7c6eSYan-Hsuan Chuang
rtw_pci_link_ps(struct rtw_dev * rtwdev,bool enter)13703dff7c6eSYan-Hsuan Chuang static void rtw_pci_link_ps(struct rtw_dev *rtwdev, bool enter)
13713dff7c6eSYan-Hsuan Chuang {
13723dff7c6eSYan-Hsuan Chuang struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
13733dff7c6eSYan-Hsuan Chuang
13743dff7c6eSYan-Hsuan Chuang /* Like CLKREQ, ASPM is also implemented by two HW modules, and can
13753dff7c6eSYan-Hsuan Chuang * only be enabled when host supports it.
13763dff7c6eSYan-Hsuan Chuang *
13773dff7c6eSYan-Hsuan Chuang * And ASPM mechanism should be enabled when driver/firmware enters
13783dff7c6eSYan-Hsuan Chuang * power save mode, without having heavy traffic. Because we've
13793dff7c6eSYan-Hsuan Chuang * experienced some inter-operability issues that the link tends
13803dff7c6eSYan-Hsuan Chuang * to enter L1 state on the fly even when driver is having high
13813dff7c6eSYan-Hsuan Chuang * throughput. This is probably because the ASPM behavior slightly
13823dff7c6eSYan-Hsuan Chuang * varies from different SOC.
13833dff7c6eSYan-Hsuan Chuang */
138424f5e38aSKai-Heng Feng if (!(rtwpci->link_ctrl & PCI_EXP_LNKCTL_ASPM_L1))
138524f5e38aSKai-Heng Feng return;
138624f5e38aSKai-Heng Feng
138724f5e38aSKai-Heng Feng if ((enter && atomic_dec_if_positive(&rtwpci->link_usage) == 0) ||
138824f5e38aSKai-Heng Feng (!enter && atomic_inc_return(&rtwpci->link_usage) == 1))
13893dff7c6eSYan-Hsuan Chuang rtw_pci_aspm_set(rtwdev, enter);
13903dff7c6eSYan-Hsuan Chuang }
13913dff7c6eSYan-Hsuan Chuang
rtw_pci_link_cfg(struct rtw_dev * rtwdev)1392d2e2c47eSYan-Hsuan Chuang static void rtw_pci_link_cfg(struct rtw_dev *rtwdev)
1393d2e2c47eSYan-Hsuan Chuang {
1394dcbf179cSPing-Ke Shih const struct rtw_chip_info *chip = rtwdev->chip;
1395d2e2c47eSYan-Hsuan Chuang struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
1396d2e2c47eSYan-Hsuan Chuang struct pci_dev *pdev = rtwpci->pdev;
1397d2e2c47eSYan-Hsuan Chuang u16 link_ctrl;
1398d2e2c47eSYan-Hsuan Chuang int ret;
1399d2e2c47eSYan-Hsuan Chuang
14002a422555SYan-Hsuan Chuang /* RTL8822CE has enabled REFCLK auto calibration, it does not need
14012a422555SYan-Hsuan Chuang * to add clock delay to cover the REFCLK timing gap.
14022a422555SYan-Hsuan Chuang */
14032a422555SYan-Hsuan Chuang if (chip->id == RTW_CHIP_TYPE_8822C)
14042a422555SYan-Hsuan Chuang rtw_dbi_write8(rtwdev, RTK_PCIE_CLKDLY_CTRL, 0);
14052a422555SYan-Hsuan Chuang
1406d2e2c47eSYan-Hsuan Chuang /* Though there is standard PCIE configuration space to set the
1407d2e2c47eSYan-Hsuan Chuang * link control register, but by Realtek's design, driver should
1408d2e2c47eSYan-Hsuan Chuang * check if host supports CLKREQ/ASPM to enable the HW module.
1409d2e2c47eSYan-Hsuan Chuang *
1410d2e2c47eSYan-Hsuan Chuang * These functions are implemented by two HW modules associated,
1411d2e2c47eSYan-Hsuan Chuang * one is responsible to access PCIE configuration space to
1412d2e2c47eSYan-Hsuan Chuang * follow the host settings, and another is in charge of doing
1413d2e2c47eSYan-Hsuan Chuang * CLKREQ/ASPM mechanisms, it is default disabled. Because sometimes
1414d2e2c47eSYan-Hsuan Chuang * the host does not support it, and due to some reasons or wrong
1415d2e2c47eSYan-Hsuan Chuang * settings (ex. CLKREQ# not Bi-Direction), it could lead to device
1416d2e2c47eSYan-Hsuan Chuang * loss if HW misbehaves on the link.
1417d2e2c47eSYan-Hsuan Chuang *
1418d2e2c47eSYan-Hsuan Chuang * Hence it's designed that driver should first check the PCIE
1419d2e2c47eSYan-Hsuan Chuang * configuration space is sync'ed and enabled, then driver can turn
1420d2e2c47eSYan-Hsuan Chuang * on the other module that is actually working on the mechanism.
1421d2e2c47eSYan-Hsuan Chuang */
1422d2e2c47eSYan-Hsuan Chuang ret = pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &link_ctrl);
1423d2e2c47eSYan-Hsuan Chuang if (ret) {
1424d2e2c47eSYan-Hsuan Chuang rtw_err(rtwdev, "failed to read PCI cap, ret=%d\n", ret);
1425d2e2c47eSYan-Hsuan Chuang return;
1426d2e2c47eSYan-Hsuan Chuang }
1427d2e2c47eSYan-Hsuan Chuang
1428d2e2c47eSYan-Hsuan Chuang if (link_ctrl & PCI_EXP_LNKCTL_CLKREQ_EN)
1429d2e2c47eSYan-Hsuan Chuang rtw_pci_clkreq_set(rtwdev, true);
1430d2e2c47eSYan-Hsuan Chuang
1431d2e2c47eSYan-Hsuan Chuang rtwpci->link_ctrl = link_ctrl;
1432d2e2c47eSYan-Hsuan Chuang }
1433d2e2c47eSYan-Hsuan Chuang
rtw_pci_interface_cfg(struct rtw_dev * rtwdev)143478622104SYan-Hsuan Chuang static void rtw_pci_interface_cfg(struct rtw_dev *rtwdev)
143578622104SYan-Hsuan Chuang {
1436dcbf179cSPing-Ke Shih const struct rtw_chip_info *chip = rtwdev->chip;
143778622104SYan-Hsuan Chuang
143878622104SYan-Hsuan Chuang switch (chip->id) {
143978622104SYan-Hsuan Chuang case RTW_CHIP_TYPE_8822C:
144078622104SYan-Hsuan Chuang if (rtwdev->hal.cut_version >= RTW_CHIP_VER_CUT_D)
144178622104SYan-Hsuan Chuang rtw_write32_mask(rtwdev, REG_HCI_MIX_CFG,
144278622104SYan-Hsuan Chuang BIT_PCIE_EMAC_PDN_AUX_TO_FAST_CLK, 1);
144378622104SYan-Hsuan Chuang break;
144478622104SYan-Hsuan Chuang default:
144578622104SYan-Hsuan Chuang break;
144678622104SYan-Hsuan Chuang }
144778622104SYan-Hsuan Chuang }
144878622104SYan-Hsuan Chuang
rtw_pci_phy_cfg(struct rtw_dev * rtwdev)1449e3037485SYan-Hsuan Chuang static void rtw_pci_phy_cfg(struct rtw_dev *rtwdev)
1450e3037485SYan-Hsuan Chuang {
14519ebacb1eSPo-Hao Huang struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
1452dcbf179cSPing-Ke Shih const struct rtw_chip_info *chip = rtwdev->chip;
14539ebacb1eSPo-Hao Huang struct pci_dev *pdev = rtwpci->pdev;
1454d49f2c50SJoe Perches const struct rtw_intf_phy_para *para;
1455e3037485SYan-Hsuan Chuang u16 cut;
1456e3037485SYan-Hsuan Chuang u16 value;
1457e3037485SYan-Hsuan Chuang u16 offset;
1458e3037485SYan-Hsuan Chuang int i;
14599ebacb1eSPo-Hao Huang int ret;
1460e3037485SYan-Hsuan Chuang
1461e3037485SYan-Hsuan Chuang cut = BIT(0) << rtwdev->hal.cut_version;
1462e3037485SYan-Hsuan Chuang
1463e3037485SYan-Hsuan Chuang for (i = 0; i < chip->intf_table->n_gen1_para; i++) {
1464e3037485SYan-Hsuan Chuang para = &chip->intf_table->gen1_para[i];
1465e3037485SYan-Hsuan Chuang if (!(para->cut_mask & cut))
1466e3037485SYan-Hsuan Chuang continue;
1467e3037485SYan-Hsuan Chuang if (para->offset == 0xffff)
1468e3037485SYan-Hsuan Chuang break;
1469e3037485SYan-Hsuan Chuang offset = para->offset;
1470e3037485SYan-Hsuan Chuang value = para->value;
1471e3037485SYan-Hsuan Chuang if (para->ip_sel == RTW_IP_SEL_PHY)
1472e3037485SYan-Hsuan Chuang rtw_mdio_write(rtwdev, offset, value, true);
1473e3037485SYan-Hsuan Chuang else
1474e3037485SYan-Hsuan Chuang rtw_dbi_write8(rtwdev, offset, value);
1475e3037485SYan-Hsuan Chuang }
1476e3037485SYan-Hsuan Chuang
1477e3037485SYan-Hsuan Chuang for (i = 0; i < chip->intf_table->n_gen2_para; i++) {
1478e3037485SYan-Hsuan Chuang para = &chip->intf_table->gen2_para[i];
1479e3037485SYan-Hsuan Chuang if (!(para->cut_mask & cut))
1480e3037485SYan-Hsuan Chuang continue;
1481e3037485SYan-Hsuan Chuang if (para->offset == 0xffff)
1482e3037485SYan-Hsuan Chuang break;
1483e3037485SYan-Hsuan Chuang offset = para->offset;
1484e3037485SYan-Hsuan Chuang value = para->value;
1485e3037485SYan-Hsuan Chuang if (para->ip_sel == RTW_IP_SEL_PHY)
1486e3037485SYan-Hsuan Chuang rtw_mdio_write(rtwdev, offset, value, false);
1487e3037485SYan-Hsuan Chuang else
1488e3037485SYan-Hsuan Chuang rtw_dbi_write8(rtwdev, offset, value);
1489e3037485SYan-Hsuan Chuang }
1490d2e2c47eSYan-Hsuan Chuang
1491d2e2c47eSYan-Hsuan Chuang rtw_pci_link_cfg(rtwdev);
14929ebacb1eSPo-Hao Huang
14939ebacb1eSPo-Hao Huang /* Disable 8821ce completion timeout by default */
14949ebacb1eSPo-Hao Huang if (chip->id == RTW_CHIP_TYPE_8821C) {
14959ebacb1eSPo-Hao Huang ret = pcie_capability_set_word(pdev, PCI_EXP_DEVCTL2,
14969ebacb1eSPo-Hao Huang PCI_EXP_DEVCTL2_COMP_TMOUT_DIS);
14979ebacb1eSPo-Hao Huang if (ret)
14989ebacb1eSPo-Hao Huang rtw_err(rtwdev, "failed to set PCI cap, ret = %d\n",
14999ebacb1eSPo-Hao Huang ret);
15009ebacb1eSPo-Hao Huang }
1501e3037485SYan-Hsuan Chuang }
1502e3037485SYan-Hsuan Chuang
rtw_pci_suspend(struct device * dev)15037dc7c416SArnd Bergmann static int __maybe_unused rtw_pci_suspend(struct device *dev)
150444bc17f7SChin-Yen Lee {
15058d52b46cSChin-Yen Lee struct ieee80211_hw *hw = dev_get_drvdata(dev);
15068d52b46cSChin-Yen Lee struct rtw_dev *rtwdev = hw->priv;
1507dcbf179cSPing-Ke Shih const struct rtw_chip_info *chip = rtwdev->chip;
15088d52b46cSChin-Yen Lee struct rtw_efuse *efuse = &rtwdev->efuse;
15098d52b46cSChin-Yen Lee
15108d52b46cSChin-Yen Lee if (chip->id == RTW_CHIP_TYPE_8822C && efuse->rfe_option == 6)
15118d52b46cSChin-Yen Lee rtw_pci_clkreq_pad_low(rtwdev, true);
151244bc17f7SChin-Yen Lee return 0;
151344bc17f7SChin-Yen Lee }
151444bc17f7SChin-Yen Lee
rtw_pci_resume(struct device * dev)15157dc7c416SArnd Bergmann static int __maybe_unused rtw_pci_resume(struct device *dev)
151644bc17f7SChin-Yen Lee {
15178d52b46cSChin-Yen Lee struct ieee80211_hw *hw = dev_get_drvdata(dev);
15188d52b46cSChin-Yen Lee struct rtw_dev *rtwdev = hw->priv;
1519dcbf179cSPing-Ke Shih const struct rtw_chip_info *chip = rtwdev->chip;
15208d52b46cSChin-Yen Lee struct rtw_efuse *efuse = &rtwdev->efuse;
15218d52b46cSChin-Yen Lee
15228d52b46cSChin-Yen Lee if (chip->id == RTW_CHIP_TYPE_8822C && efuse->rfe_option == 6)
15238d52b46cSChin-Yen Lee rtw_pci_clkreq_pad_low(rtwdev, false);
152444bc17f7SChin-Yen Lee return 0;
152544bc17f7SChin-Yen Lee }
152644bc17f7SChin-Yen Lee
152772f256c2SZong-Zhe Yang SIMPLE_DEV_PM_OPS(rtw_pm_ops, rtw_pci_suspend, rtw_pci_resume);
152872f256c2SZong-Zhe Yang EXPORT_SYMBOL(rtw_pm_ops);
152944bc17f7SChin-Yen Lee
rtw_pci_claim(struct rtw_dev * rtwdev,struct pci_dev * pdev)1530e3037485SYan-Hsuan Chuang static int rtw_pci_claim(struct rtw_dev *rtwdev, struct pci_dev *pdev)
1531e3037485SYan-Hsuan Chuang {
1532e3037485SYan-Hsuan Chuang int ret;
1533e3037485SYan-Hsuan Chuang
1534e3037485SYan-Hsuan Chuang ret = pci_enable_device(pdev);
1535e3037485SYan-Hsuan Chuang if (ret) {
1536e3037485SYan-Hsuan Chuang rtw_err(rtwdev, "failed to enable pci device\n");
1537e3037485SYan-Hsuan Chuang return ret;
1538e3037485SYan-Hsuan Chuang }
1539e3037485SYan-Hsuan Chuang
1540e3037485SYan-Hsuan Chuang pci_set_master(pdev);
1541e3037485SYan-Hsuan Chuang pci_set_drvdata(pdev, rtwdev->hw);
1542e3037485SYan-Hsuan Chuang SET_IEEE80211_DEV(rtwdev->hw, &pdev->dev);
1543e3037485SYan-Hsuan Chuang
1544e3037485SYan-Hsuan Chuang return 0;
1545e3037485SYan-Hsuan Chuang }
1546e3037485SYan-Hsuan Chuang
rtw_pci_declaim(struct rtw_dev * rtwdev,struct pci_dev * pdev)1547e3037485SYan-Hsuan Chuang static void rtw_pci_declaim(struct rtw_dev *rtwdev, struct pci_dev *pdev)
1548e3037485SYan-Hsuan Chuang {
1549e3037485SYan-Hsuan Chuang pci_disable_device(pdev);
1550e3037485SYan-Hsuan Chuang }
1551e3037485SYan-Hsuan Chuang
rtw_pci_setup_resource(struct rtw_dev * rtwdev,struct pci_dev * pdev)1552e3037485SYan-Hsuan Chuang static int rtw_pci_setup_resource(struct rtw_dev *rtwdev, struct pci_dev *pdev)
1553e3037485SYan-Hsuan Chuang {
1554e3037485SYan-Hsuan Chuang struct rtw_pci *rtwpci;
1555e3037485SYan-Hsuan Chuang int ret;
1556e3037485SYan-Hsuan Chuang
1557e3037485SYan-Hsuan Chuang rtwpci = (struct rtw_pci *)rtwdev->priv;
1558e3037485SYan-Hsuan Chuang rtwpci->pdev = pdev;
1559e3037485SYan-Hsuan Chuang
1560e3037485SYan-Hsuan Chuang /* after this driver can access to hw registers */
1561e3037485SYan-Hsuan Chuang ret = rtw_pci_io_mapping(rtwdev, pdev);
1562e3037485SYan-Hsuan Chuang if (ret) {
1563e3037485SYan-Hsuan Chuang rtw_err(rtwdev, "failed to request pci io region\n");
1564e3037485SYan-Hsuan Chuang goto err_out;
1565e3037485SYan-Hsuan Chuang }
1566e3037485SYan-Hsuan Chuang
1567e3037485SYan-Hsuan Chuang ret = rtw_pci_init(rtwdev);
1568e3037485SYan-Hsuan Chuang if (ret) {
1569e3037485SYan-Hsuan Chuang rtw_err(rtwdev, "failed to allocate pci resources\n");
1570e3037485SYan-Hsuan Chuang goto err_io_unmap;
1571e3037485SYan-Hsuan Chuang }
1572e3037485SYan-Hsuan Chuang
1573e3037485SYan-Hsuan Chuang return 0;
1574e3037485SYan-Hsuan Chuang
1575e3037485SYan-Hsuan Chuang err_io_unmap:
1576e3037485SYan-Hsuan Chuang rtw_pci_io_unmapping(rtwdev, pdev);
1577e3037485SYan-Hsuan Chuang
1578e3037485SYan-Hsuan Chuang err_out:
1579e3037485SYan-Hsuan Chuang return ret;
1580e3037485SYan-Hsuan Chuang }
1581e3037485SYan-Hsuan Chuang
rtw_pci_destroy(struct rtw_dev * rtwdev,struct pci_dev * pdev)1582e3037485SYan-Hsuan Chuang static void rtw_pci_destroy(struct rtw_dev *rtwdev, struct pci_dev *pdev)
1583e3037485SYan-Hsuan Chuang {
1584e3037485SYan-Hsuan Chuang rtw_pci_deinit(rtwdev);
1585e3037485SYan-Hsuan Chuang rtw_pci_io_unmapping(rtwdev, pdev);
1586e3037485SYan-Hsuan Chuang }
1587e3037485SYan-Hsuan Chuang
1588e3037485SYan-Hsuan Chuang static struct rtw_hci_ops rtw_pci_ops = {
1589aaab5d0eSYan-Hsuan Chuang .tx_write = rtw_pci_tx_write,
1590aaab5d0eSYan-Hsuan Chuang .tx_kick_off = rtw_pci_tx_kick_off,
15917b33ec8bSZong-Zhe Yang .flush_queues = rtw_pci_flush_queues,
1592e3037485SYan-Hsuan Chuang .setup = rtw_pci_setup,
1593e3037485SYan-Hsuan Chuang .start = rtw_pci_start,
1594e3037485SYan-Hsuan Chuang .stop = rtw_pci_stop,
159527e117e4SYan-Hsuan Chuang .deep_ps = rtw_pci_deep_ps,
15963dff7c6eSYan-Hsuan Chuang .link_ps = rtw_pci_link_ps,
159778622104SYan-Hsuan Chuang .interface_cfg = rtw_pci_interface_cfg,
1598e3037485SYan-Hsuan Chuang
1599e3037485SYan-Hsuan Chuang .read8 = rtw_pci_read8,
1600e3037485SYan-Hsuan Chuang .read16 = rtw_pci_read16,
1601e3037485SYan-Hsuan Chuang .read32 = rtw_pci_read32,
1602e3037485SYan-Hsuan Chuang .write8 = rtw_pci_write8,
1603e3037485SYan-Hsuan Chuang .write16 = rtw_pci_write16,
1604e3037485SYan-Hsuan Chuang .write32 = rtw_pci_write32,
1605e3037485SYan-Hsuan Chuang .write_data_rsvd_page = rtw_pci_write_data_rsvd_page,
1606e3037485SYan-Hsuan Chuang .write_data_h2c = rtw_pci_write_data_h2c,
1607e3037485SYan-Hsuan Chuang };
1608e3037485SYan-Hsuan Chuang
rtw_pci_request_irq(struct rtw_dev * rtwdev,struct pci_dev * pdev)160979066903SYu-Yen Ting static int rtw_pci_request_irq(struct rtw_dev *rtwdev, struct pci_dev *pdev)
161079066903SYu-Yen Ting {
161179066903SYu-Yen Ting unsigned int flags = PCI_IRQ_LEGACY;
161279066903SYu-Yen Ting int ret;
161379066903SYu-Yen Ting
161479066903SYu-Yen Ting if (!rtw_disable_msi)
161579066903SYu-Yen Ting flags |= PCI_IRQ_MSI;
161679066903SYu-Yen Ting
161779066903SYu-Yen Ting ret = pci_alloc_irq_vectors(pdev, 1, 1, flags);
161879066903SYu-Yen Ting if (ret < 0) {
161979066903SYu-Yen Ting rtw_err(rtwdev, "failed to alloc PCI irq vectors\n");
162079066903SYu-Yen Ting return ret;
162179066903SYu-Yen Ting }
162279066903SYu-Yen Ting
162379066903SYu-Yen Ting ret = devm_request_threaded_irq(rtwdev->dev, pdev->irq,
162479066903SYu-Yen Ting rtw_pci_interrupt_handler,
162579066903SYu-Yen Ting rtw_pci_interrupt_threadfn,
162679066903SYu-Yen Ting IRQF_SHARED, KBUILD_MODNAME, rtwdev);
162779066903SYu-Yen Ting if (ret) {
162879066903SYu-Yen Ting rtw_err(rtwdev, "failed to request irq %d\n", ret);
162979066903SYu-Yen Ting pci_free_irq_vectors(pdev);
163079066903SYu-Yen Ting }
163179066903SYu-Yen Ting
163279066903SYu-Yen Ting return ret;
163379066903SYu-Yen Ting }
163479066903SYu-Yen Ting
rtw_pci_free_irq(struct rtw_dev * rtwdev,struct pci_dev * pdev)163579066903SYu-Yen Ting static void rtw_pci_free_irq(struct rtw_dev *rtwdev, struct pci_dev *pdev)
163679066903SYu-Yen Ting {
163779066903SYu-Yen Ting devm_free_irq(rtwdev->dev, pdev->irq, rtwdev);
163879066903SYu-Yen Ting pci_free_irq_vectors(pdev);
163979066903SYu-Yen Ting }
164079066903SYu-Yen Ting
rtw_pci_napi_poll(struct napi_struct * napi,int budget)16419e2fd298SPo-Hao Huang static int rtw_pci_napi_poll(struct napi_struct *napi, int budget)
16429e2fd298SPo-Hao Huang {
16439e2fd298SPo-Hao Huang struct rtw_pci *rtwpci = container_of(napi, struct rtw_pci, napi);
16449e2fd298SPo-Hao Huang struct rtw_dev *rtwdev = container_of((void *)rtwpci, struct rtw_dev,
16459e2fd298SPo-Hao Huang priv);
16469e2fd298SPo-Hao Huang int work_done = 0;
16479e2fd298SPo-Hao Huang
164824f5e38aSKai-Heng Feng if (rtwpci->rx_no_aspm)
164924f5e38aSKai-Heng Feng rtw_pci_link_ps(rtwdev, false);
165024f5e38aSKai-Heng Feng
16519e2fd298SPo-Hao Huang while (work_done < budget) {
16529e2fd298SPo-Hao Huang u32 work_done_once;
16539e2fd298SPo-Hao Huang
16549e2fd298SPo-Hao Huang work_done_once = rtw_pci_rx_napi(rtwdev, rtwpci, RTW_RX_QUEUE_MPDU,
16559e2fd298SPo-Hao Huang budget - work_done);
16569e2fd298SPo-Hao Huang if (work_done_once == 0)
16579e2fd298SPo-Hao Huang break;
16589e2fd298SPo-Hao Huang work_done += work_done_once;
16599e2fd298SPo-Hao Huang }
16609e2fd298SPo-Hao Huang if (work_done < budget) {
16619e2fd298SPo-Hao Huang napi_complete_done(napi, work_done);
16629e2fd298SPo-Hao Huang spin_lock_bh(&rtwpci->irq_lock);
16637bd3760cSPo-Hao Huang if (rtwpci->running)
16649e2fd298SPo-Hao Huang rtw_pci_enable_interrupt(rtwdev, rtwpci, false);
16659e2fd298SPo-Hao Huang spin_unlock_bh(&rtwpci->irq_lock);
16669e2fd298SPo-Hao Huang /* When ISR happens during polling and before napi_complete
16679e2fd298SPo-Hao Huang * while no further data is received. Data on the dma_ring will
16689e2fd298SPo-Hao Huang * not be processed immediately. Check whether dma ring is
16699e2fd298SPo-Hao Huang * empty and perform napi_schedule accordingly.
16709e2fd298SPo-Hao Huang */
16719e2fd298SPo-Hao Huang if (rtw_pci_get_hw_rx_ring_nr(rtwdev, rtwpci))
16729e2fd298SPo-Hao Huang napi_schedule(napi);
16739e2fd298SPo-Hao Huang }
167424f5e38aSKai-Heng Feng if (rtwpci->rx_no_aspm)
167524f5e38aSKai-Heng Feng rtw_pci_link_ps(rtwdev, true);
16769e2fd298SPo-Hao Huang
16779e2fd298SPo-Hao Huang return work_done;
16789e2fd298SPo-Hao Huang }
16799e2fd298SPo-Hao Huang
rtw_pci_napi_init(struct rtw_dev * rtwdev)16809e2fd298SPo-Hao Huang static void rtw_pci_napi_init(struct rtw_dev *rtwdev)
16819e2fd298SPo-Hao Huang {
16829e2fd298SPo-Hao Huang struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
16839e2fd298SPo-Hao Huang
16849e2fd298SPo-Hao Huang init_dummy_netdev(&rtwpci->netdev);
1685b48b89f9SJakub Kicinski netif_napi_add(&rtwpci->netdev, &rtwpci->napi, rtw_pci_napi_poll);
16869e2fd298SPo-Hao Huang }
16879e2fd298SPo-Hao Huang
rtw_pci_napi_deinit(struct rtw_dev * rtwdev)16889e2fd298SPo-Hao Huang static void rtw_pci_napi_deinit(struct rtw_dev *rtwdev)
16899e2fd298SPo-Hao Huang {
16909e2fd298SPo-Hao Huang struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
16919e2fd298SPo-Hao Huang
16929e2fd298SPo-Hao Huang rtw_pci_napi_stop(rtwdev);
16939e2fd298SPo-Hao Huang netif_napi_del(&rtwpci->napi);
16949e2fd298SPo-Hao Huang }
16959e2fd298SPo-Hao Huang
rtw_pci_probe(struct pci_dev * pdev,const struct pci_device_id * id)169672f256c2SZong-Zhe Yang int rtw_pci_probe(struct pci_dev *pdev,
1697e3037485SYan-Hsuan Chuang const struct pci_device_id *id)
1698e3037485SYan-Hsuan Chuang {
169924f5e38aSKai-Heng Feng struct pci_dev *bridge = pci_upstream_bridge(pdev);
1700e3037485SYan-Hsuan Chuang struct ieee80211_hw *hw;
1701e3037485SYan-Hsuan Chuang struct rtw_dev *rtwdev;
170224f5e38aSKai-Heng Feng struct rtw_pci *rtwpci;
1703e3037485SYan-Hsuan Chuang int drv_data_size;
1704e3037485SYan-Hsuan Chuang int ret;
1705e3037485SYan-Hsuan Chuang
1706e3037485SYan-Hsuan Chuang drv_data_size = sizeof(struct rtw_dev) + sizeof(struct rtw_pci);
1707e3037485SYan-Hsuan Chuang hw = ieee80211_alloc_hw(drv_data_size, &rtw_ops);
1708e3037485SYan-Hsuan Chuang if (!hw) {
1709e3037485SYan-Hsuan Chuang dev_err(&pdev->dev, "failed to allocate hw\n");
1710e3037485SYan-Hsuan Chuang return -ENOMEM;
1711e3037485SYan-Hsuan Chuang }
1712e3037485SYan-Hsuan Chuang
1713e3037485SYan-Hsuan Chuang rtwdev = hw->priv;
1714e3037485SYan-Hsuan Chuang rtwdev->hw = hw;
1715e3037485SYan-Hsuan Chuang rtwdev->dev = &pdev->dev;
1716e3037485SYan-Hsuan Chuang rtwdev->chip = (struct rtw_chip_info *)id->driver_data;
1717e3037485SYan-Hsuan Chuang rtwdev->hci.ops = &rtw_pci_ops;
1718e3037485SYan-Hsuan Chuang rtwdev->hci.type = RTW_HCI_TYPE_PCIE;
1719e3037485SYan-Hsuan Chuang
172024f5e38aSKai-Heng Feng rtwpci = (struct rtw_pci *)rtwdev->priv;
172124f5e38aSKai-Heng Feng atomic_set(&rtwpci->link_usage, 1);
172224f5e38aSKai-Heng Feng
1723e3037485SYan-Hsuan Chuang ret = rtw_core_init(rtwdev);
1724e3037485SYan-Hsuan Chuang if (ret)
1725e3037485SYan-Hsuan Chuang goto err_release_hw;
1726e3037485SYan-Hsuan Chuang
1727e3037485SYan-Hsuan Chuang rtw_dbg(rtwdev, RTW_DBG_PCI,
1728e3037485SYan-Hsuan Chuang "rtw88 pci probe: vendor=0x%4.04X device=0x%4.04X rev=%d\n",
1729e3037485SYan-Hsuan Chuang pdev->vendor, pdev->device, pdev->revision);
1730e3037485SYan-Hsuan Chuang
1731e3037485SYan-Hsuan Chuang ret = rtw_pci_claim(rtwdev, pdev);
1732e3037485SYan-Hsuan Chuang if (ret) {
1733e3037485SYan-Hsuan Chuang rtw_err(rtwdev, "failed to claim pci device\n");
1734e3037485SYan-Hsuan Chuang goto err_deinit_core;
1735e3037485SYan-Hsuan Chuang }
1736e3037485SYan-Hsuan Chuang
1737e3037485SYan-Hsuan Chuang ret = rtw_pci_setup_resource(rtwdev, pdev);
1738e3037485SYan-Hsuan Chuang if (ret) {
1739e3037485SYan-Hsuan Chuang rtw_err(rtwdev, "failed to setup pci resources\n");
1740e3037485SYan-Hsuan Chuang goto err_pci_declaim;
1741e3037485SYan-Hsuan Chuang }
1742e3037485SYan-Hsuan Chuang
17439e2fd298SPo-Hao Huang rtw_pci_napi_init(rtwdev);
17449e2fd298SPo-Hao Huang
1745e3037485SYan-Hsuan Chuang ret = rtw_chip_info_setup(rtwdev);
1746e3037485SYan-Hsuan Chuang if (ret) {
1747e3037485SYan-Hsuan Chuang rtw_err(rtwdev, "failed to setup chip information\n");
1748e3037485SYan-Hsuan Chuang goto err_destroy_pci;
1749e3037485SYan-Hsuan Chuang }
1750e3037485SYan-Hsuan Chuang
175124f5e38aSKai-Heng Feng /* Disable PCIe ASPM L1 while doing NAPI poll for 8821CE */
1752b9eb5f07SJimmy Hon if (rtwdev->chip->id == RTW_CHIP_TYPE_8821C && bridge->vendor == PCI_VENDOR_ID_INTEL)
175324f5e38aSKai-Heng Feng rtwpci->rx_no_aspm = true;
175424f5e38aSKai-Heng Feng
1755474264d5SYan-Hsuan Chuang rtw_pci_phy_cfg(rtwdev);
1756474264d5SYan-Hsuan Chuang
1757e3037485SYan-Hsuan Chuang ret = rtw_register_hw(rtwdev, hw);
1758e3037485SYan-Hsuan Chuang if (ret) {
1759e3037485SYan-Hsuan Chuang rtw_err(rtwdev, "failed to register hw\n");
1760e3037485SYan-Hsuan Chuang goto err_destroy_pci;
1761e3037485SYan-Hsuan Chuang }
1762e3037485SYan-Hsuan Chuang
176379066903SYu-Yen Ting ret = rtw_pci_request_irq(rtwdev, pdev);
1764e3037485SYan-Hsuan Chuang if (ret) {
1765e3037485SYan-Hsuan Chuang ieee80211_unregister_hw(hw);
1766e3037485SYan-Hsuan Chuang goto err_destroy_pci;
1767e3037485SYan-Hsuan Chuang }
1768e3037485SYan-Hsuan Chuang
1769e3037485SYan-Hsuan Chuang return 0;
1770e3037485SYan-Hsuan Chuang
1771e3037485SYan-Hsuan Chuang err_destroy_pci:
17729e2fd298SPo-Hao Huang rtw_pci_napi_deinit(rtwdev);
1773e3037485SYan-Hsuan Chuang rtw_pci_destroy(rtwdev, pdev);
1774e3037485SYan-Hsuan Chuang
1775e3037485SYan-Hsuan Chuang err_pci_declaim:
1776e3037485SYan-Hsuan Chuang rtw_pci_declaim(rtwdev, pdev);
1777e3037485SYan-Hsuan Chuang
1778e3037485SYan-Hsuan Chuang err_deinit_core:
1779e3037485SYan-Hsuan Chuang rtw_core_deinit(rtwdev);
1780e3037485SYan-Hsuan Chuang
1781e3037485SYan-Hsuan Chuang err_release_hw:
1782e3037485SYan-Hsuan Chuang ieee80211_free_hw(hw);
1783e3037485SYan-Hsuan Chuang
1784e3037485SYan-Hsuan Chuang return ret;
1785e3037485SYan-Hsuan Chuang }
178672f256c2SZong-Zhe Yang EXPORT_SYMBOL(rtw_pci_probe);
1787e3037485SYan-Hsuan Chuang
rtw_pci_remove(struct pci_dev * pdev)178872f256c2SZong-Zhe Yang void rtw_pci_remove(struct pci_dev *pdev)
1789e3037485SYan-Hsuan Chuang {
1790e3037485SYan-Hsuan Chuang struct ieee80211_hw *hw = pci_get_drvdata(pdev);
1791e3037485SYan-Hsuan Chuang struct rtw_dev *rtwdev;
1792e3037485SYan-Hsuan Chuang struct rtw_pci *rtwpci;
1793e3037485SYan-Hsuan Chuang
1794e3037485SYan-Hsuan Chuang if (!hw)
1795e3037485SYan-Hsuan Chuang return;
1796e3037485SYan-Hsuan Chuang
1797e3037485SYan-Hsuan Chuang rtwdev = hw->priv;
1798e3037485SYan-Hsuan Chuang rtwpci = (struct rtw_pci *)rtwdev->priv;
1799e3037485SYan-Hsuan Chuang
1800e3037485SYan-Hsuan Chuang rtw_unregister_hw(rtwdev, hw);
1801e3037485SYan-Hsuan Chuang rtw_pci_disable_interrupt(rtwdev, rtwpci);
18029e2fd298SPo-Hao Huang rtw_pci_napi_deinit(rtwdev);
1803e3037485SYan-Hsuan Chuang rtw_pci_destroy(rtwdev, pdev);
1804e3037485SYan-Hsuan Chuang rtw_pci_declaim(rtwdev, pdev);
180579066903SYu-Yen Ting rtw_pci_free_irq(rtwdev, pdev);
1806e3037485SYan-Hsuan Chuang rtw_core_deinit(rtwdev);
1807e3037485SYan-Hsuan Chuang ieee80211_free_hw(hw);
1808e3037485SYan-Hsuan Chuang }
180972f256c2SZong-Zhe Yang EXPORT_SYMBOL(rtw_pci_remove);
1810e3037485SYan-Hsuan Chuang
rtw_pci_shutdown(struct pci_dev * pdev)181172f256c2SZong-Zhe Yang void rtw_pci_shutdown(struct pci_dev *pdev)
181205202746SPing-Ke Shih {
181305202746SPing-Ke Shih struct ieee80211_hw *hw = pci_get_drvdata(pdev);
181405202746SPing-Ke Shih struct rtw_dev *rtwdev;
1815dcbf179cSPing-Ke Shih const struct rtw_chip_info *chip;
181605202746SPing-Ke Shih
181705202746SPing-Ke Shih if (!hw)
181805202746SPing-Ke Shih return;
181905202746SPing-Ke Shih
182005202746SPing-Ke Shih rtwdev = hw->priv;
182105202746SPing-Ke Shih chip = rtwdev->chip;
182205202746SPing-Ke Shih
182305202746SPing-Ke Shih if (chip->ops->shutdown)
182405202746SPing-Ke Shih chip->ops->shutdown(rtwdev);
182544492e70SKai-Heng Feng
182644492e70SKai-Heng Feng pci_set_power_state(pdev, PCI_D3hot);
182705202746SPing-Ke Shih }
182872f256c2SZong-Zhe Yang EXPORT_SYMBOL(rtw_pci_shutdown);
182905202746SPing-Ke Shih
1830e3037485SYan-Hsuan Chuang MODULE_AUTHOR("Realtek Corporation");
1831*5d7cf67fSAlan Stern MODULE_DESCRIPTION("Realtek PCI 802.11ac wireless driver");
1832e3037485SYan-Hsuan Chuang MODULE_LICENSE("Dual BSD/GPL");
1833