mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-21 06:50:25 +00:00
wifi: rtw89: pci: validate RX tag for RXQ and RPQ
PCI RX ring is a kind of read/write index ring, and DMA and ring index are asynchronous, so suddenly driver gets newer index ahead before DMA. To resolve this rare situation, we use a RX tag as helpers to make sure DMA is done. The RX tag is a 13-bit value, and range is from 1 ~ 0x1FFF, but 0 isn't used so should be skipped. Only enable this validation to coming WiFi 7 chips, because existing chips use different design and don't really meet this situation. Add missed rx_ring_eq_is_full for 8851BE by the way. Signed-off-by: Ping-Ke Shih <pkshih@realtek.com> Signed-off-by: Kalle Valo <kvalo@kernel.org> Link: https://msgid.link/20240121071826.10159-4-pkshih@realtek.com
This commit is contained in:
parent
26cdaee43d
commit
0bc7d1d4e6
7 changed files with 63 additions and 7 deletions
|
@ -155,8 +155,8 @@ static void rtw89_pci_sync_skb_for_device(struct rtw89_dev *rtwdev,
|
||||||
DMA_FROM_DEVICE);
|
DMA_FROM_DEVICE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rtw89_pci_rxbd_info_update(struct rtw89_dev *rtwdev,
|
static void rtw89_pci_rxbd_info_update(struct rtw89_dev *rtwdev,
|
||||||
struct sk_buff *skb)
|
struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
struct rtw89_pci_rxbd_info *rxbd_info;
|
struct rtw89_pci_rxbd_info *rxbd_info;
|
||||||
struct rtw89_pci_rx_info *rx_info = RTW89_PCI_RX_SKB_CB(skb);
|
struct rtw89_pci_rx_info *rx_info = RTW89_PCI_RX_SKB_CB(skb);
|
||||||
|
@ -166,10 +166,58 @@ static int rtw89_pci_rxbd_info_update(struct rtw89_dev *rtwdev,
|
||||||
rx_info->ls = le32_get_bits(rxbd_info->dword, RTW89_PCI_RXBD_LS);
|
rx_info->ls = le32_get_bits(rxbd_info->dword, RTW89_PCI_RXBD_LS);
|
||||||
rx_info->len = le32_get_bits(rxbd_info->dword, RTW89_PCI_RXBD_WRITE_SIZE);
|
rx_info->len = le32_get_bits(rxbd_info->dword, RTW89_PCI_RXBD_WRITE_SIZE);
|
||||||
rx_info->tag = le32_get_bits(rxbd_info->dword, RTW89_PCI_RXBD_TAG);
|
rx_info->tag = le32_get_bits(rxbd_info->dword, RTW89_PCI_RXBD_TAG);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rtw89_pci_validate_rx_tag(struct rtw89_dev *rtwdev,
|
||||||
|
struct rtw89_pci_rx_ring *rx_ring,
|
||||||
|
struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
struct rtw89_pci_rx_info *rx_info = RTW89_PCI_RX_SKB_CB(skb);
|
||||||
|
const struct rtw89_pci_info *info = rtwdev->pci_info;
|
||||||
|
u32 target_rx_tag;
|
||||||
|
|
||||||
|
if (!info->check_rx_tag)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* valid range is 1 ~ 0x1FFF */
|
||||||
|
if (rx_ring->target_rx_tag == 0)
|
||||||
|
target_rx_tag = 1;
|
||||||
|
else
|
||||||
|
target_rx_tag = rx_ring->target_rx_tag;
|
||||||
|
|
||||||
|
if (rx_info->tag != target_rx_tag) {
|
||||||
|
rtw89_debug(rtwdev, RTW89_DBG_UNEXP, "mismatch RX tag 0x%x 0x%x\n",
|
||||||
|
rx_info->tag, target_rx_tag);
|
||||||
|
return -EAGAIN;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int rtw89_pci_sync_skb_for_device_and_validate_rx_info(struct rtw89_dev *rtwdev,
|
||||||
|
struct rtw89_pci_rx_ring *rx_ring,
|
||||||
|
struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
struct rtw89_pci_rx_info *rx_info = RTW89_PCI_RX_SKB_CB(skb);
|
||||||
|
int rx_tag_retry = 100;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
do {
|
||||||
|
rtw89_pci_sync_skb_for_cpu(rtwdev, skb);
|
||||||
|
rtw89_pci_rxbd_info_update(rtwdev, skb);
|
||||||
|
|
||||||
|
ret = rtw89_pci_validate_rx_tag(rtwdev, rx_ring, skb);
|
||||||
|
if (ret != -EAGAIN)
|
||||||
|
break;
|
||||||
|
} while (rx_tag_retry--);
|
||||||
|
|
||||||
|
/* update target rx_tag for next RX */
|
||||||
|
rx_ring->target_rx_tag = rx_info->tag + 1;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static void rtw89_pci_ctrl_txdma_ch_pcie(struct rtw89_dev *rtwdev, bool enable)
|
static void rtw89_pci_ctrl_txdma_ch_pcie(struct rtw89_dev *rtwdev, bool enable)
|
||||||
{
|
{
|
||||||
const struct rtw89_pci_info *info = rtwdev->pci_info;
|
const struct rtw89_pci_info *info = rtwdev->pci_info;
|
||||||
|
@ -259,9 +307,8 @@ static u32 rtw89_pci_rxbd_deliver_skbs(struct rtw89_dev *rtwdev,
|
||||||
|
|
||||||
skb_idx = rtw89_pci_get_rx_skb_idx(rtwdev, bd_ring);
|
skb_idx = rtw89_pci_get_rx_skb_idx(rtwdev, bd_ring);
|
||||||
skb = rx_ring->buf[skb_idx];
|
skb = rx_ring->buf[skb_idx];
|
||||||
rtw89_pci_sync_skb_for_cpu(rtwdev, skb);
|
|
||||||
|
|
||||||
ret = rtw89_pci_rxbd_info_update(rtwdev, skb);
|
ret = rtw89_pci_sync_skb_for_device_and_validate_rx_info(rtwdev, rx_ring, skb);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
rtw89_err(rtwdev, "failed to update %d RXBD info: %d\n",
|
rtw89_err(rtwdev, "failed to update %d RXBD info: %d\n",
|
||||||
bd_ring->wp, ret);
|
bd_ring->wp, ret);
|
||||||
|
@ -549,9 +596,8 @@ static u32 rtw89_pci_release_tx_skbs(struct rtw89_dev *rtwdev,
|
||||||
|
|
||||||
skb_idx = rtw89_pci_get_rx_skb_idx(rtwdev, bd_ring);
|
skb_idx = rtw89_pci_get_rx_skb_idx(rtwdev, bd_ring);
|
||||||
skb = rx_ring->buf[skb_idx];
|
skb = rx_ring->buf[skb_idx];
|
||||||
rtw89_pci_sync_skb_for_cpu(rtwdev, skb);
|
|
||||||
|
|
||||||
ret = rtw89_pci_rxbd_info_update(rtwdev, skb);
|
ret = rtw89_pci_sync_skb_for_device_and_validate_rx_info(rtwdev, rx_ring, skb);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
rtw89_err(rtwdev, "failed to update %d RXBD info: %d\n",
|
rtw89_err(rtwdev, "failed to update %d RXBD info: %d\n",
|
||||||
bd_ring->wp, ret);
|
bd_ring->wp, ret);
|
||||||
|
@ -1550,6 +1596,7 @@ static void rtw89_pci_reset_trx_rings(struct rtw89_dev *rtwdev)
|
||||||
bd_ring->rp = 0;
|
bd_ring->rp = 0;
|
||||||
rx_ring->diliver_skb = NULL;
|
rx_ring->diliver_skb = NULL;
|
||||||
rx_ring->diliver_desc.ready = false;
|
rx_ring->diliver_desc.ready = false;
|
||||||
|
rx_ring->target_rx_tag = 0;
|
||||||
|
|
||||||
rtw89_write16(rtwdev, addr_num, bd_ring->len);
|
rtw89_write16(rtwdev, addr_num, bd_ring->len);
|
||||||
rtw89_write32(rtwdev, addr_desa_l, bd_ring->dma);
|
rtw89_write32(rtwdev, addr_desa_l, bd_ring->dma);
|
||||||
|
@ -3213,6 +3260,7 @@ static int rtw89_pci_alloc_rx_ring(struct rtw89_dev *rtwdev,
|
||||||
rx_ring->buf_sz = buf_sz;
|
rx_ring->buf_sz = buf_sz;
|
||||||
rx_ring->diliver_skb = NULL;
|
rx_ring->diliver_skb = NULL;
|
||||||
rx_ring->diliver_desc.ready = false;
|
rx_ring->diliver_desc.ready = false;
|
||||||
|
rx_ring->target_rx_tag = 0;
|
||||||
|
|
||||||
for (i = 0; i < len; i++) {
|
for (i = 0; i < len; i++) {
|
||||||
skb = dev_alloc_skb(buf_sz);
|
skb = dev_alloc_skb(buf_sz);
|
||||||
|
|
|
@ -1235,6 +1235,7 @@ struct rtw89_pci_info {
|
||||||
enum mac_ax_pcie_func_ctrl io_rcy_en;
|
enum mac_ax_pcie_func_ctrl io_rcy_en;
|
||||||
enum mac_ax_io_rcy_tmr io_rcy_tmr;
|
enum mac_ax_io_rcy_tmr io_rcy_tmr;
|
||||||
bool rx_ring_eq_is_full;
|
bool rx_ring_eq_is_full;
|
||||||
|
bool check_rx_tag;
|
||||||
|
|
||||||
u32 init_cfg_reg;
|
u32 init_cfg_reg;
|
||||||
u32 txhci_en_bit;
|
u32 txhci_en_bit;
|
||||||
|
@ -1277,7 +1278,7 @@ struct rtw89_pci_tx_data {
|
||||||
|
|
||||||
struct rtw89_pci_rx_info {
|
struct rtw89_pci_rx_info {
|
||||||
dma_addr_t dma;
|
dma_addr_t dma;
|
||||||
u32 fs:1, ls:1, tag:11, len:14;
|
u32 fs:1, ls:1, tag:13, len:14;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define RTW89_PCI_TXBD_OPTION_LS BIT(14)
|
#define RTW89_PCI_TXBD_OPTION_LS BIT(14)
|
||||||
|
@ -1406,6 +1407,7 @@ struct rtw89_pci_rx_ring {
|
||||||
u32 buf_sz;
|
u32 buf_sz;
|
||||||
struct sk_buff *diliver_skb;
|
struct sk_buff *diliver_skb;
|
||||||
struct rtw89_rx_desc_info diliver_desc;
|
struct rtw89_rx_desc_info diliver_desc;
|
||||||
|
u32 target_rx_tag:13;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct rtw89_pci_isrs {
|
struct rtw89_pci_isrs {
|
||||||
|
|
|
@ -25,6 +25,8 @@ static const struct rtw89_pci_info rtw8851b_pci_info = {
|
||||||
.autok_en = MAC_AX_PCIE_DISABLE,
|
.autok_en = MAC_AX_PCIE_DISABLE,
|
||||||
.io_rcy_en = MAC_AX_PCIE_DISABLE,
|
.io_rcy_en = MAC_AX_PCIE_DISABLE,
|
||||||
.io_rcy_tmr = MAC_AX_IO_RCY_ANA_TMR_6MS,
|
.io_rcy_tmr = MAC_AX_IO_RCY_ANA_TMR_6MS,
|
||||||
|
.rx_ring_eq_is_full = false,
|
||||||
|
.check_rx_tag = false,
|
||||||
|
|
||||||
.init_cfg_reg = R_AX_PCIE_INIT_CFG1,
|
.init_cfg_reg = R_AX_PCIE_INIT_CFG1,
|
||||||
.txhci_en_bit = B_AX_TXHCI_EN,
|
.txhci_en_bit = B_AX_TXHCI_EN,
|
||||||
|
|
|
@ -26,6 +26,7 @@ static const struct rtw89_pci_info rtw8852a_pci_info = {
|
||||||
.io_rcy_en = MAC_AX_PCIE_DISABLE,
|
.io_rcy_en = MAC_AX_PCIE_DISABLE,
|
||||||
.io_rcy_tmr = MAC_AX_IO_RCY_ANA_TMR_6MS,
|
.io_rcy_tmr = MAC_AX_IO_RCY_ANA_TMR_6MS,
|
||||||
.rx_ring_eq_is_full = false,
|
.rx_ring_eq_is_full = false,
|
||||||
|
.check_rx_tag = false,
|
||||||
|
|
||||||
.init_cfg_reg = R_AX_PCIE_INIT_CFG1,
|
.init_cfg_reg = R_AX_PCIE_INIT_CFG1,
|
||||||
.txhci_en_bit = B_AX_TXHCI_EN,
|
.txhci_en_bit = B_AX_TXHCI_EN,
|
||||||
|
|
|
@ -26,6 +26,7 @@ static const struct rtw89_pci_info rtw8852b_pci_info = {
|
||||||
.io_rcy_en = MAC_AX_PCIE_DISABLE,
|
.io_rcy_en = MAC_AX_PCIE_DISABLE,
|
||||||
.io_rcy_tmr = MAC_AX_IO_RCY_ANA_TMR_6MS,
|
.io_rcy_tmr = MAC_AX_IO_RCY_ANA_TMR_6MS,
|
||||||
.rx_ring_eq_is_full = false,
|
.rx_ring_eq_is_full = false,
|
||||||
|
.check_rx_tag = false,
|
||||||
|
|
||||||
.init_cfg_reg = R_AX_PCIE_INIT_CFG1,
|
.init_cfg_reg = R_AX_PCIE_INIT_CFG1,
|
||||||
.txhci_en_bit = B_AX_TXHCI_EN,
|
.txhci_en_bit = B_AX_TXHCI_EN,
|
||||||
|
|
|
@ -35,6 +35,7 @@ static const struct rtw89_pci_info rtw8852c_pci_info = {
|
||||||
.io_rcy_en = MAC_AX_PCIE_ENABLE,
|
.io_rcy_en = MAC_AX_PCIE_ENABLE,
|
||||||
.io_rcy_tmr = MAC_AX_IO_RCY_ANA_TMR_6MS,
|
.io_rcy_tmr = MAC_AX_IO_RCY_ANA_TMR_6MS,
|
||||||
.rx_ring_eq_is_full = false,
|
.rx_ring_eq_is_full = false,
|
||||||
|
.check_rx_tag = false,
|
||||||
|
|
||||||
.init_cfg_reg = R_AX_HAXI_INIT_CFG1,
|
.init_cfg_reg = R_AX_HAXI_INIT_CFG1,
|
||||||
.txhci_en_bit = B_AX_TXHCI_EN_V1,
|
.txhci_en_bit = B_AX_TXHCI_EN_V1,
|
||||||
|
|
|
@ -26,6 +26,7 @@ static const struct rtw89_pci_info rtw8922a_pci_info = {
|
||||||
.io_rcy_en = MAC_AX_PCIE_ENABLE,
|
.io_rcy_en = MAC_AX_PCIE_ENABLE,
|
||||||
.io_rcy_tmr = MAC_AX_IO_RCY_ANA_TMR_DEF,
|
.io_rcy_tmr = MAC_AX_IO_RCY_ANA_TMR_DEF,
|
||||||
.rx_ring_eq_is_full = true,
|
.rx_ring_eq_is_full = true,
|
||||||
|
.check_rx_tag = true,
|
||||||
|
|
||||||
.init_cfg_reg = R_BE_HAXI_INIT_CFG1,
|
.init_cfg_reg = R_BE_HAXI_INIT_CFG1,
|
||||||
.txhci_en_bit = B_BE_TXDMA_EN,
|
.txhci_en_bit = B_BE_TXDMA_EN,
|
||||||
|
|
Loading…
Add table
Reference in a new issue