From: Bitterblue Smith <rtl8821cerfe2@gmail.com>
To: "linux-wireless@vger.kernel.org" <linux-wireless@vger.kernel.org>
Cc: Ping-Ke Shih <pkshih@realtek.com>
Subject: [PATCH rtw-next 4/5] wifi: rtw88: pci: Add functions to support older chips
Date: Sat, 24 Oct 2026 02:02:10 +0300 [thread overview]
Message-ID: <35e9d20a-4f0c-42c3-9d06-358a5620251c@gmail.com> (raw)
In-Reply-To: <2033f1b1-fb12-4a04-aef4-923590e64463@gmail.com>
Add pci_old.{c,h} to support older chips, like RTL8821AE and RTL8812AE.
They handle the PCI communications differently.
Signed-off-by: Bitterblue Smith <rtl8821cerfe2@gmail.com>
---
drivers/net/wireless/realtek/rtw88/Makefile | 2 +-
drivers/net/wireless/realtek/rtw88/pci.c | 9 +-
drivers/net/wireless/realtek/rtw88/pci.h | 6 +
drivers/net/wireless/realtek/rtw88/pci_old.c | 522 +++++++++++++++++++
drivers/net/wireless/realtek/rtw88/pci_old.h | 39 ++
drivers/net/wireless/realtek/rtw88/reg.h | 3 +
drivers/net/wireless/realtek/rtw88/rx.h | 4 +
drivers/net/wireless/realtek/rtw88/tx.h | 5 +
8 files changed, 584 insertions(+), 6 deletions(-)
create mode 100644 drivers/net/wireless/realtek/rtw88/pci_old.c
create mode 100644 drivers/net/wireless/realtek/rtw88/pci_old.h
diff --git a/drivers/net/wireless/realtek/rtw88/Makefile b/drivers/net/wireless/realtek/rtw88/Makefile
index 6889b3796449..d4007ca2b2ca 100644
--- a/drivers/net/wireless/realtek/rtw88/Makefile
+++ b/drivers/net/wireless/realtek/rtw88/Makefile
@@ -110,7 +110,7 @@ obj-$(CONFIG_RTW88_8814AU) += rtw88_8814au.o
rtw88_8814au-objs := rtw8814au.o
obj-$(CONFIG_RTW88_PCI) += rtw88_pci.o
-rtw88_pci-objs := pci.o
+rtw88_pci-objs := pci.o pci_old.o
obj-$(CONFIG_RTW88_SDIO) += rtw88_sdio.o
rtw88_sdio-objs := sdio.o
diff --git a/drivers/net/wireless/realtek/rtw88/pci.c b/drivers/net/wireless/realtek/rtw88/pci.c
index c51ad15cfba7..35f45e3ede81 100644
--- a/drivers/net/wireless/realtek/rtw88/pci.c
+++ b/drivers/net/wireless/realtek/rtw88/pci.c
@@ -16,7 +16,7 @@
#include "mac.h"
static bool rtw_disable_msi;
-static bool rtw_pci_disable_aspm;
+bool rtw_pci_disable_aspm;
module_param_named(disable_msi, rtw_disable_msi, bool, 0644);
module_param_named(disable_aspm, rtw_pci_disable_aspm, bool, 0644);
MODULE_PARM_DESC(disable_msi, "Set Y to disable MSI interrupt support");
@@ -32,8 +32,7 @@ static const u32 rtw_pci_tx_queue_idx_addr[] = {
[RTW_TX_QUEUE_H2C] = RTK_PCI_TXBD_IDX_H2CQ,
};
-static u8 rtw_pci_get_tx_qsel(struct sk_buff *skb,
- enum rtw_tx_queue_type queue)
+u8 rtw_pci_get_tx_qsel(struct sk_buff *skb, enum rtw_tx_queue_type queue)
{
switch (queue) {
case RTW_TX_QUEUE_BCN:
@@ -675,8 +674,8 @@ static void rtw_pci_deep_ps(struct rtw_dev *rtwdev, bool enter)
spin_unlock_bh(&rtwpci->irq_lock);
}
-static void rtw_pci_release_rsvd_page(struct rtw_pci *rtwpci,
- struct rtw_pci_tx_ring *ring)
+void rtw_pci_release_rsvd_page(struct rtw_pci *rtwpci,
+ struct rtw_pci_tx_ring *ring)
{
struct sk_buff *prev = skb_dequeue(&ring->queue);
struct rtw_pci_tx_data *tx_data;
diff --git a/drivers/net/wireless/realtek/rtw88/pci.h b/drivers/net/wireless/realtek/rtw88/pci.h
index 5ab78ba3255d..92532f842ebc 100644
--- a/drivers/net/wireless/realtek/rtw88/pci.h
+++ b/drivers/net/wireless/realtek/rtw88/pci.h
@@ -144,6 +144,8 @@
/* IMR 3 */
#define IMR_H2CDOK BIT(16)
+extern bool rtw_pci_disable_aspm;
+
enum rtw_pci_flags {
RTW_PCI_FLAG_NAPI_RUNNING,
@@ -268,6 +270,10 @@ extern const struct dev_pm_ops rtw_pm_ops;
extern const struct pci_error_handlers rtw_pci_err_handler;
extern const struct rtw_pci_gen rtw_pci_gen_new;
+u8 rtw_pci_get_tx_qsel(struct sk_buff *skb, enum rtw_tx_queue_type queue);
+void rtw_pci_release_rsvd_page(struct rtw_pci *rtwpci,
+ struct rtw_pci_tx_ring *ring);
+
int rtw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id);
void rtw_pci_remove(struct pci_dev *pdev);
void rtw_pci_shutdown(struct pci_dev *pdev);
diff --git a/drivers/net/wireless/realtek/rtw88/pci_old.c b/drivers/net/wireless/realtek/rtw88/pci_old.c
new file mode 100644
index 000000000000..464b57d8a629
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtw88/pci_old.c
@@ -0,0 +1,522 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/* Copyright(c) 2026 Realtek Corporation
+ */
+
+#include <linux/pci.h>
+#include "main.h"
+#include "debug.h"
+#include "fw.h"
+#include "pci.h"
+#include "pci_old.h"
+#include "reg.h"
+#include "rx.h"
+#include "tx.h"
+
+static int rtw_pci_old_init_tx_ring(struct rtw_dev *rtwdev,
+ struct rtw_pci_tx_ring *tx_ring,
+ u8 desc_size, u32 len)
+{
+ struct pci_dev *pdev = to_pci_dev(rtwdev->dev);
+ struct rtw_tx_desc_pci_old *tx_desc;
+ int ring_sz = desc_size * len;
+ dma_addr_t dma, next;
+ u8 *head;
+ int i;
+
+ head = dma_alloc_coherent(&pdev->dev, ring_sz, &dma, GFP_KERNEL);
+ if (!head) {
+ rtw_err(rtwdev, "failed to allocate tx ring\n");
+ return -ENOMEM;
+ }
+
+ skb_queue_head_init(&tx_ring->queue);
+ tx_ring->r.head = head;
+ tx_ring->r.dma = dma;
+ tx_ring->r.len = len;
+ tx_ring->r.desc_size = desc_size;
+ tx_ring->r.wp = 0;
+ tx_ring->r.rp = 0;
+
+ tx_desc = (struct rtw_tx_desc_pci_old *)head;
+
+ for (i = 0; i < len; i++) {
+ next = dma + ((i + 1) % len) * desc_size;
+
+ le32p_replace_bits(&tx_desc[i].w12, next,
+ RTW_TX_DESC_W12_NEXT_DESC_ADDRESS);
+ }
+
+ return 0;
+}
+
+static int rtw_pci_old_reset_rx_desc(struct rtw_dev *rtwdev,
+ struct sk_buff *skb,
+ struct rtw_pci_rx_ring *rx_ring,
+ u32 idx, u32 desc_sz)
+{
+ struct pci_dev *pdev = to_pci_dev(rtwdev->dev);
+ struct rtw_rx_desc_pci_old *rx_desc;
+ dma_addr_t dma;
+
+ if (!skb)
+ return -EINVAL;
+
+ dma = dma_map_single(&pdev->dev, skb->data, RTK_PCI_RX_BUF_SIZE,
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(&pdev->dev, dma))
+ return -EBUSY;
+
+ *((dma_addr_t *)skb->cb) = dma;
+
+ rx_desc = (struct rtw_rx_desc_pci_old *)rx_ring->r.head;
+
+ memset(&rx_desc[idx], 0, sizeof(*rx_desc));
+
+ le32p_replace_bits(&rx_desc[idx].w6, dma, RTW_RX_DESC_W6_BUF_ADDR);
+ le32p_replace_bits(&rx_desc[idx].w0_5.w0, RTK_PCI_RX_BUF_SIZE,
+ RTW_RX_DESC_W0_PKT_LEN);
+ le32p_replace_bits(&rx_desc[idx].w0_5.w0, 1, RTW_RX_DESC_W0_OWN);
+
+ if (idx == rx_ring->r.len - 1)
+ le32p_replace_bits(&rx_desc[idx].w0_5.w0, 1,
+ RTW_RX_DESC_W0_EOR);
+
+ return 0;
+}
+
+static void rtw_pci_old_reset_buf_desc(struct rtw_dev *rtwdev)
+{
+ static const u32 addr[] = {
+ [RTW_TX_QUEUE_BK] = REG_BKQ_DESA,
+ [RTW_TX_QUEUE_BE] = REG_BEQ_DESA,
+ [RTW_TX_QUEUE_VI] = REG_VIQ_DESA,
+ [RTW_TX_QUEUE_VO] = REG_VOQ_DESA,
+ [RTW_TX_QUEUE_BCN] = REG_BCNQ_DESA,
+ [RTW_TX_QUEUE_MGMT] = REG_MGQ_DESA,
+ [RTW_TX_QUEUE_HI0] = REG_HQ_DESA,
+ };
+ struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
+ struct rtw_pci_tx_ring *ring;
+ u8 queue;
+
+ for (queue = 0; queue <= RTW_TX_QUEUE_HI0; queue++) {
+ ring = &rtwpci->tx_rings[queue];
+
+ ring->r.rp = 0;
+ ring->r.wp = 0;
+ rtw_write32(rtwdev, addr[queue], ring->r.dma);
+ }
+
+ rtwpci->rx_rings[RTW_RX_QUEUE_MPDU].r.rp = 0;
+ rtwpci->rx_rings[RTW_RX_QUEUE_MPDU].r.wp = 0;
+ rtw_write32(rtwdev, REG_RX_DESA,
+ rtwpci->rx_rings[RTW_RX_QUEUE_MPDU].r.dma);
+
+ rtw_write8(rtwdev, RTK_PCI_CTRL + 3, 0x77);
+}
+
+static void rtw_pci_old_reset_dma(struct rtw_dev *rtwdev)
+{
+ u8 mac_power_on, trx_hang, pcie_dma_pause;
+ u32 rxdma;
+
+ mac_power_on = rtw_read8(rtwdev, REG_CR);
+ if (mac_power_on == 0xea)
+ mac_power_on = 0;
+
+ if (!rtw_read8_mask(rtwdev, REG_DBI_CTRL + 3, BIT(2))) {
+ rtw_write8_set(rtwdev, REG_DBI_CTRL + 3, BIT(2));
+ msleep(100);
+ }
+
+ trx_hang = rtw_read8_mask(rtwdev, REG_DBI_CTRL + 3, GENMASK(1, 0));
+
+ if (!trx_hang)
+ return;
+
+ if (trx_hang & BIT(0))
+ rtw_warn(rtwdev, "PCIe TX hang detected, resetting\n");
+
+ if (trx_hang & BIT(1))
+ rtw_warn(rtwdev, "PCIe RX hang detected, resetting\n");
+
+ /* 1. Disable register write lock. */
+ rtw_write8_clr(rtwdev, REG_RSV_CTRL, BIT(1));
+ if (rtwdev->chip->id != RTW_CHIP_TYPE_8812A)
+ rtw_write8_set(rtwdev, REG_PMC_DBG_CTRL2, BIT(2));
+
+ /* 2. Check and pause TRX DMA */
+ rxdma = rtw_read32(rtwdev, REG_RXPKT_NUM);
+ if (!(rxdma & BIT_RW_RELEASE))
+ rtw_write32(rtwdev, REG_RXPKT_NUM, rxdma | BIT_RW_RELEASE);
+
+ pcie_dma_pause = rtw_read8(rtwdev, RTK_PCI_CTRL + 1);
+ if (pcie_dma_pause != 0xFF)
+ rtw_write8(rtwdev, RTK_PCI_CTRL + 1, 0xFF);
+
+ if (mac_power_on)
+ /* 3. reset TRX function */
+ rtw_write8(rtwdev, REG_CR, 0);
+
+ /* 4. Reset PCIe DMA. */
+ rtw_write16_clr(rtwdev, REG_SYS_FUNC_EN, BIT_FEN_PCIED);
+
+ /* 5. Enable PCIe DMA. */
+ rtw_write16_set(rtwdev, REG_SYS_FUNC_EN, BIT_FEN_PCIED);
+
+ if (mac_power_on)
+ /* 6. enable TRX function */
+ rtw_write8(rtwdev, REG_CR, 0xFF);
+
+ /*
+ * 7. Restore PCIe autoload down bit. 8812AE does not have
+ * the definition.
+ */
+ if (rtwdev->chip->id != RTW_CHIP_TYPE_8812A)
+ rtw_write8_set(rtwdev, REG_SYS_STATUS2 + 2, BIT(1));
+
+ /* 8. release TRX DMA */
+ if (!(rxdma & BIT_RW_RELEASE))
+ rtw_write32_clr(rtwdev, REG_RXPKT_NUM, BIT_RW_RELEASE);
+
+ rtw_write8(rtwdev, RTK_PCI_CTRL + 1, pcie_dma_pause);
+
+ /* 9. lock system register */
+ if (rtwdev->chip->id != RTW_CHIP_TYPE_8812A)
+ rtw_write8_clr(rtwdev, REG_PMC_DBG_CTRL2, BIT(2));
+}
+
+static int rtw_pci_old_reset(struct rtw_dev *rtwdev)
+{
+ rtw_pci_old_reset_dma(rtwdev);
+
+ rtw_pci_old_reset_buf_desc(rtwdev);
+
+ rtw_write32(rtwdev, REG_INT_MIG, 0);
+
+ rtw_write32(rtwdev, REG_MCUTST_1, 0);
+
+ rtw_write8(rtwdev, REG_MISC_CTRL, BIT_DIS_SECOND_CCA);
+
+ return 0;
+}
+
+static void rtw_pci_old_flush_queue(struct rtw_dev *rtwdev, u8 pci_q, bool drop)
+{
+ struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
+ struct rtw_pci_tx_ring *ring = &rtwpci->tx_rings[pci_q];
+ u8 i;
+
+ /*
+ * Because the time taked by the I/O in __pci_get_hw_tx_ring_rp is a
+ * bit dynamic, it's hard to define a reasonable fixed total timeout to
+ * use read_poll_timeout* helper. Instead, we can ensure a reasonable
+ * polling times, so we just use for loop with udelay here.
+ */
+ for (i = 0; i < 50; i++) {
+ if (skb_queue_len(&ring->queue) == 0)
+ return;
+
+ udelay(1);
+ }
+
+ if (!drop)
+ rtw_dbg(rtwdev, RTW_DBG_UNEXP,
+ "timed out to flush pci tx ring[%d]\n", pci_q);
+}
+
+static void rtw_pci_old_tx_kick_off_queue(struct rtw_dev *rtwdev,
+ enum rtw_tx_queue_type queue)
+{
+ struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
+ u16 queue_bit;
+
+ spin_lock_bh(&rtwpci->irq_lock);
+
+ if (queue >= RTW_TX_QUEUE_MGMT)
+ queue_bit = BIT(queue + 1);
+ else
+ queue_bit = BIT(queue);
+
+ rtw_write16(rtwdev, RTK_PCI_CTRL, queue_bit);
+
+ spin_unlock_bh(&rtwpci->irq_lock);
+}
+
+static int rtw_pci_old_tx_write_data(struct rtw_dev *rtwdev,
+ struct rtw_tx_pkt_info *pkt_info,
+ struct sk_buff *skb,
+ enum rtw_tx_queue_type queue)
+{
+ struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
+ struct rtw_tx_desc_pci_old *tx_desc;
+ struct rtw_tx_desc tmp_tx_desc = {};
+ struct rtw_pci_tx_data *tx_data;
+ struct rtw_pci_tx_ring *ring;
+ dma_addr_t dma;
+ u32 wp;
+
+ ring = &rtwpci->tx_rings[queue];
+
+ wp = ring->r.wp;
+ tx_desc = (struct rtw_tx_desc_pci_old *)ring->r.head;
+
+ if (queue == RTW_TX_QUEUE_BCN)
+ rtw_pci_release_rsvd_page(rtwpci, ring);
+ else if (le32_get_bits(tx_desc[wp].w0_9.w0, RTW_TX_DESC_W0_OWN))
+ return -ENOSPC;
+
+ dma = dma_map_single(&rtwpci->pdev->dev, skb->data, skb->len,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(&rtwpci->pdev->dev, dma))
+ return -EBUSY;
+
+ pkt_info->qsel = rtw_pci_get_tx_qsel(skb, queue);
+
+ rtw_tx_fill_tx_desc(rtwdev, pkt_info, &tmp_tx_desc);
+
+ /*
+ * OWN (same bit as DISQSELSEQ) can only be set when everything
+ * is ready for DMA, or bad things will happen.
+ */
+ le32p_replace_bits(&tmp_tx_desc.w0, 0, RTW_TX_DESC_W0_OWN);
+
+ memcpy(&tx_desc[wp].w0_9, &tmp_tx_desc, sizeof(tmp_tx_desc));
+
+ le32p_replace_bits(&tx_desc[wp].w0_9.w0, 1, RTW_TX_DESC_W0_FS);
+ le32p_replace_bits(&tx_desc[wp].w0_9.w7, skb->len,
+ RTW_TX_DESC_W7_TX_BUFFER_SIZE);
+ le32p_replace_bits(&tx_desc[wp].w10, dma,
+ RTW_TX_DESC_W10_TX_BUFFER_ADDRESS);
+
+ tx_data = rtw_pci_get_tx_data(skb);
+ tx_data->dma = dma;
+ tx_data->sn = pkt_info->sn;
+
+ spin_lock_bh(&rtwpci->irq_lock);
+
+ skb_queue_tail(&ring->queue, skb);
+
+ /* The hardware must see this bit after all of the above. */
+ wmb();
+ le32p_replace_bits(&tx_desc[wp].w0_9.w0, 1, RTW_TX_DESC_W0_OWN);
+
+ if (queue == RTW_TX_QUEUE_BCN)
+ goto out_unlock;
+
+ /* update write-index, and kick it off later */
+ set_bit(queue, rtwpci->tx_queued);
+
+ ring->r.wp = (ring->r.wp + 1) % ring->r.len;
+
+out_unlock:
+ spin_unlock_bh(&rtwpci->irq_lock);
+
+ return 0;
+}
+
+static void rtw_pci_old_kick_beacon_queue(struct rtw_dev *rtwdev)
+{
+ rtw_write16(rtwdev, RTK_PCI_CTRL, BIT(RTW_TX_QUEUE_BCN));
+}
+
+static void rtw_pci_old_tx_isr(struct rtw_dev *rtwdev,
+ struct rtw_pci *rtwpci, u8 hw_queue)
+{
+ struct ieee80211_hw *hw = rtwdev->hw;
+ struct rtw_tx_desc_pci_old *tx_desc;
+ struct rtw_pci_tx_data *tx_data;
+ struct ieee80211_tx_info *info;
+ struct rtw_pci_tx_ring *ring;
+ struct sk_buff *skb;
+ dma_addr_t dma;
+
+ ring = &rtwpci->tx_rings[hw_queue];
+
+ tx_desc = (struct rtw_tx_desc_pci_old *)ring->r.head;
+
+ while (skb_queue_len(&ring->queue)) {
+ if (le32_get_bits(tx_desc[ring->r.rp].w0_9.w0,
+ RTW_TX_DESC_W0_OWN))
+ return;
+
+ skb = skb_dequeue(&ring->queue);
+
+ tx_data = rtw_pci_get_tx_data(skb);
+
+ dma = le32_get_bits(tx_desc[ring->r.rp].w10,
+ RTW_TX_DESC_W10_TX_BUFFER_ADDRESS);
+
+ if (dma != tx_data->dma)
+ rtw_err(rtwdev,
+ "tx_data dma %pad != tx_desc dma %pad\n",
+ &tx_data->dma, &dma);
+
+ dma_unmap_single(&rtwpci->pdev->dev, dma, skb->len,
+ DMA_TO_DEVICE);
+
+ ring->r.rp = (ring->r.rp + 1) % ring->r.len;
+
+ if (ring->queue_stopped &&
+ avail_desc(ring->r.wp, ring->r.rp, ring->r.len) <= 4) {
+ ieee80211_wake_queue(hw, skb_get_queue_mapping(skb));
+ ring->queue_stopped = false;
+ }
+
+ info = IEEE80211_SKB_CB(skb);
+
+ /* enqueue to wait for tx report */
+ if (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) {
+ rtw_tx_report_enqueue(rtwdev, skb, tx_data->sn);
+ continue;
+ }
+
+ /* always ACK for others, then they won't be marked as drop */
+ if (info->flags & IEEE80211_TX_CTL_NO_ACK)
+ info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED;
+ else
+ info->flags |= IEEE80211_TX_STAT_ACK;
+
+ ieee80211_tx_info_clear_status(info);
+ ieee80211_tx_status_irqsafe(hw, skb);
+ }
+}
+
+static int rtw_pci_old_get_hw_rx_ring_nr(struct rtw_dev *rtwdev,
+ struct rtw_pci *rtwpci)
+{
+ /*
+ * TODO: is it correct? it seems to work, but should we count
+ * the number of occupied buffers for rtw_pci_napi_poll?
+ */
+ return 0;
+}
+
+static u32 rtw_pci_old_rx_napi(struct rtw_dev *rtwdev,
+ struct rtw_pci *rtwpci,
+ u8 hw_queue, u32 limit)
+{
+ struct rtw_pci_rx_ring *ring = &rtwpci->rx_rings[RTW_RX_QUEUE_MPDU];
+ struct ieee80211_rx_status rx_status;
+ struct rtw_rx_desc_pci_old *rx_desc;
+ struct device *dev = rtwdev->dev;
+ struct rtw_rx_pkt_stat pkt_stat;
+ struct sk_buff *skb, *new;
+ u32 cur_rp = ring->r.rp;
+ u32 count, rx_done = 0;
+ dma_addr_t dma;
+ u32 pkt_offset;
+ u32 new_len;
+ u8 *rx_buf;
+ int ret;
+
+ rx_desc = (struct rtw_rx_desc_pci_old *)ring->r.head;
+
+ count = min(ring->r.len, limit);
+
+ while (count--) {
+ /* Wait for data to be filled by hardware */
+ if (le32_get_bits(rx_desc[cur_rp].w0_5.w0, RTW_RX_DESC_W0_OWN))
+ break;
+
+ skb = ring->buf[cur_rp];
+ dma = *((dma_addr_t *)skb->cb);
+ dma_sync_single_for_cpu(dev, dma, RTK_PCI_RX_BUF_SIZE,
+ DMA_FROM_DEVICE);
+
+ rx_buf = skb->data;
+ ret = rtw_rx_query_rx_desc(rtwdev, &rx_desc[cur_rp].w0_5,
+ rx_buf, &pkt_stat, &rx_status);
+ if (ret)
+ goto next_rp;
+
+ pkt_offset = pkt_stat.shift + pkt_stat.drv_info_sz;
+
+ new_len = pkt_stat.pkt_len + pkt_offset;
+ new = dev_alloc_skb(new_len);
+ if (WARN_ONCE(!new, "rx routine starvation\n"))
+ goto next_rp;
+
+ skb_put_data(new, skb->data, new_len);
+
+ if (pkt_stat.is_c2h) {
+ rtw_fw_c2h_cmd_rx_irqsafe(rtwdev, pkt_offset, new);
+ } else {
+ /* remove phy_status */
+ skb_pull(new, pkt_offset);
+
+ rtw_rx_stats(rtwdev, pkt_stat.vif, new);
+ memcpy(new->cb, &rx_status, sizeof(rx_status));
+ ieee80211_rx_napi(rtwdev->hw, NULL, new, &rtwpci->napi);
+ rx_done++;
+ }
+
+next_rp:
+ /* new skb delivered to mac80211, re-enable original skb DMA */
+ dma_sync_single_for_device(dev, dma, RTK_PCI_RX_BUF_SIZE,
+ DMA_FROM_DEVICE);
+
+ /* Reset the descriptor */
+ le32p_replace_bits(&rx_desc[cur_rp].w6, dma, RTW_RX_DESC_W6_BUF_ADDR);
+ le32p_replace_bits(&rx_desc[cur_rp].w0_5.w0,
+ RTK_PCI_RX_BUF_SIZE, RTW_RX_DESC_W0_PKT_LEN);
+ /* The hardware must see this bit after all of the above. */
+ wmb();
+ le32p_replace_bits(&rx_desc[cur_rp].w0_5.w0, 1,
+ RTW_RX_DESC_W0_OWN);
+
+ if (cur_rp == ring->r.len - 1)
+ le32p_replace_bits(&rx_desc[cur_rp].w0_5.w0, 1,
+ RTW_RX_DESC_W0_EOR);
+
+ cur_rp = (cur_rp + 1) % ring->r.len;
+ }
+
+ ring->r.rp = cur_rp;
+
+ return rx_done;
+}
+
+static void rtw_pci_old_clkreq_set(struct rtw_dev *rtwdev, bool enable)
+{
+}
+
+static void rtw_pci_old_aspm_set(struct rtw_dev *rtwdev, bool enable)
+{
+ struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
+ struct pci_dev *pdev = rtwpci->pdev;
+
+ if (rtw_pci_disable_aspm)
+ return;
+
+ if (enable) {
+ pcie_capability_set_word(pdev, PCI_EXP_LNKCTL,
+ PCI_EXP_LNKCTL_CCC | PCI_EXP_LNKCTL_ASPMC);
+
+ pcie_capability_set_word(pdev, PCI_EXP_LNKCTL,
+ PCI_EXP_LNKCTL_CLKREQ_EN);
+ } else {
+ pcie_capability_clear_word(pdev, PCI_EXP_LNKCTL,
+ PCI_EXP_LNKCTL_CLKREQ_EN);
+
+ pcie_capability_clear_and_set_word(pdev, PCI_EXP_LNKCTL,
+ PCI_EXP_LNKCTL_CCC | PCI_EXP_LNKCTL_ASPMC,
+ PCI_EXP_LNKCTL_CCC);
+ }
+}
+
+const struct rtw_pci_gen rtw_pci_gen_old = {
+ .init_tx_ring = rtw_pci_old_init_tx_ring,
+ .reset_rx_desc = rtw_pci_old_reset_rx_desc,
+ .reset = rtw_pci_old_reset,
+ .flush_queue = rtw_pci_old_flush_queue,
+ .tx_kick_off_queue = rtw_pci_old_tx_kick_off_queue,
+ .tx_write_data = rtw_pci_old_tx_write_data,
+ .kick_beacon_queue = rtw_pci_old_kick_beacon_queue,
+ .tx_isr = rtw_pci_old_tx_isr,
+ .get_hw_rx_ring_nr = rtw_pci_old_get_hw_rx_ring_nr,
+ .rx_napi = rtw_pci_old_rx_napi,
+ .clkreq_set = rtw_pci_old_clkreq_set,
+ .aspm_set = rtw_pci_old_aspm_set,
+};
+EXPORT_SYMBOL(rtw_pci_gen_old);
diff --git a/drivers/net/wireless/realtek/rtw88/pci_old.h b/drivers/net/wireless/realtek/rtw88/pci_old.h
new file mode 100644
index 000000000000..56ca3dd1581a
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtw88/pci_old.h
@@ -0,0 +1,39 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2026 Realtek Corporation.*/
+
+#ifndef __RTW_PCI_OLD_H__
+#define __RTW_PCI_OLD_H__
+
+#include "rx.h"
+#include "tx.h"
+
+#define REG_BCNQ_DESA 0x0308
+#define REG_HQ_DESA 0x0310
+#define REG_MGQ_DESA 0x0318
+#define REG_VOQ_DESA 0x0320
+#define REG_VIQ_DESA 0x0328
+#define REG_BEQ_DESA 0x0330
+#define REG_BKQ_DESA 0x0338
+#define REG_RX_DESA 0x0340
+
+#define REG_DBI_CTRL 0x0350
+
+struct rtw_rx_desc_pci_old {
+ struct rtw_rx_desc w0_5;
+ __le32 w6;
+ __le32 w7;
+} __packed;
+
+struct rtw_tx_desc_pci_old {
+ struct rtw_tx_desc w0_9;
+ __le32 w10;
+ __le32 w11;
+ __le32 w12;
+ __le32 w13;
+ __le32 w14;
+ __le32 w15;
+} __packed;
+
+extern const struct rtw_pci_gen rtw_pci_gen_old;
+
+#endif
diff --git a/drivers/net/wireless/realtek/rtw88/reg.h b/drivers/net/wireless/realtek/rtw88/reg.h
index afcdb66fdb9a..b406d0729d16 100644
--- a/drivers/net/wireless/realtek/rtw88/reg.h
+++ b/drivers/net/wireless/realtek/rtw88/reg.h
@@ -11,6 +11,7 @@
#define BIT_FEN_PPLL BIT(7)
#define BIT_FEN_PCIEA BIT(6)
#define BIT_FEN_DIO_PCIE BIT(5)
+#define BIT_FEN_PCIED BIT(8)
#define BIT_FEN_CPUEN BIT(2)
#define BIT_FEN_USBA BIT(2)
#define BIT_FEN_BB_GLB_RST BIT(1)
@@ -188,6 +189,8 @@
#define BIT_USB_MODE_U2 1
#define BIT_USB_MODE_U3 2
+#define REG_PMC_DBG_CTRL2 0x00CC
+
#define REG_EFUSE_ACCESS 0x00CF
#define EFUSE_ACCESS_ON 0x69
#define EFUSE_ACCESS_OFF 0x00
diff --git a/drivers/net/wireless/realtek/rtw88/rx.h b/drivers/net/wireless/realtek/rtw88/rx.h
index ebef85a3f848..d5a6f57b5d87 100644
--- a/drivers/net/wireless/realtek/rtw88/rx.h
+++ b/drivers/net/wireless/realtek/rtw88/rx.h
@@ -31,6 +31,8 @@ struct rtw_rx_desc {
#define RTW_RX_DESC_W0_SHIFT GENMASK(25, 24)
#define RTW_RX_DESC_W0_PHYST BIT(26)
#define RTW_RX_DESC_W0_SWDEC BIT(27)
+#define RTW_RX_DESC_W0_EOR BIT(30)
+#define RTW_RX_DESC_W0_OWN BIT(31)
#define RTW_RX_DESC_W1_MACID GENMASK(6, 0)
@@ -43,6 +45,8 @@ struct rtw_rx_desc {
#define RTW_RX_DESC_W5_TSFL GENMASK(31, 0)
+#define RTW_RX_DESC_W6_BUF_ADDR GENMASK(31, 0)
+
void rtw_rx_stats(struct rtw_dev *rtwdev, struct ieee80211_vif *vif,
struct sk_buff *skb);
int rtw_rx_query_rx_desc(struct rtw_dev *rtwdev, void *rx_desc8,
diff --git a/drivers/net/wireless/realtek/rtw88/tx.h b/drivers/net/wireless/realtek/rtw88/tx.h
index af031c02b4b7..b92f03cf7d54 100644
--- a/drivers/net/wireless/realtek/rtw88/tx.h
+++ b/drivers/net/wireless/realtek/rtw88/tx.h
@@ -27,7 +27,9 @@ struct rtw_tx_desc {
#define RTW_TX_DESC_W0_OFFSET GENMASK(23, 16)
#define RTW_TX_DESC_W0_BMC BIT(24)
#define RTW_TX_DESC_W0_LS BIT(26)
+#define RTW_TX_DESC_W0_FS BIT(27)
#define RTW_TX_DESC_W0_DISQSELSEQ BIT(31)
+#define RTW_TX_DESC_W0_OWN BIT(31)
#define RTW_TX_DESC_W1_MACID GENMASK(7, 0)
#define RTW_TX_DESC_W1_QSEL GENMASK(12, 8)
#define RTW_TX_DESC_W1_RATE_ID GENMASK(20, 16)
@@ -54,11 +56,14 @@ struct rtw_tx_desc {
#define RTW_TX_DESC_W5_DATA_RTS_SHORT BIT(12)
#define RTW_TX_DESC_W6_SW_DEFINE GENMASK(11, 0)
#define RTW_TX_DESC_W7_TXDESC_CHECKSUM GENMASK(15, 0)
+#define RTW_TX_DESC_W7_TX_BUFFER_SIZE GENMASK(15, 0)
#define RTW_TX_DESC_W7_DMA_TXAGG_NUM GENMASK(31, 24)
#define RTW_TX_DESC_W8_EN_HWSEQ BIT(15)
#define RTW_TX_DESC_W9_SW_SEQ GENMASK(23, 12)
#define RTW_TX_DESC_W9_TIM_EN BIT(7)
#define RTW_TX_DESC_W9_TIM_OFFSET GENMASK(6, 0)
+#define RTW_TX_DESC_W10_TX_BUFFER_ADDRESS GENMASK(31, 0)
+#define RTW_TX_DESC_W12_NEXT_DESC_ADDRESS GENMASK(31, 0)
enum rtw_tx_desc_queue_select {
TX_DESC_QSEL_TID0 = 0,
--
2.55.0
next prev parent reply other threads:[~2026-10-23 23:02 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-23 22:57 [PATCH rtw-next 0/5] wifi: rtw88: pci: Support an older design, like RTL8821AE/RTL8812AE Bitterblue Smith
2026-10-23 22:59 ` [PATCH rtw-next 1/5] wifi: rtw88: Pass RX buffer to rtw_rx_query_rx_desc() Bitterblue Smith
2026-10-23 23:00 ` [PATCH rtw-next 2/5] wifi: rtw88: Pass TX descriptor to rtw_tx_fill_tx_desc() Bitterblue Smith
2026-10-23 23:01 ` [PATCH rtw-next 3/5] wifi: rtw88: pci: Introduce struct rtw_pci_gen Bitterblue Smith
2026-10-24 8:41 ` Luka Gejak
2026-10-23 23:02 ` Bitterblue Smith [this message]
2026-10-24 8:36 ` [PATCH rtw-next 4/5] wifi: rtw88: pci: Add functions to support older chips Luka Gejak
2026-10-23 23:05 ` [PATCH rtw-next 5/5] wifi: rtw88: pci: Handle more RX interrupts for RTL8821AE Bitterblue Smith
2026-10-27 1:52 ` [PATCH rtw-next 0/5] wifi: rtw88: pci: Support an older design, like RTL8821AE/RTL8812AE Ping-Ke Shih
2026-10-27 7:25 ` Luka Gejak
2026-10-27 8:07 ` Ping-Ke Shih
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=35e9d20a-4f0c-42c3-9d06-358a5620251c@gmail.com \
--to=rtl8821cerfe2@gmail.com \
--cc=linux-wireless@vger.kernel.org \
--cc=pkshih@realtek.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox