Commit aa70ff09 authored by Ping-Ke Shih's avatar Ping-Ke Shih Committed by Kalle Valo
Browse files

wifi: rtw89: pci: early chips only enable 36-bit DMA on specific PCI hosts



The early chips including RTL8852A, RTL8851B, RTL8852B and RTL8852BT have
interoperability problems of 36-bit DMA with some PCI hosts. Rollback
to 32-bit DMA by default, and only enable 36-bit DMA for tested platforms.

Since all Intel platforms we have can work correctly, add the vendor ID to
white list. Otherwise, list vendor/device ID of bridge we have tested.

Fixes: 1fd4b3fe ("wifi: rtw89: pci: support 36-bit PCI DMA address")
Reported-by: default avatarMarcel Weißenbach <mweissenbach@ignaz.org>
Closes: https://lore.kernel.org/linux-wireless/20240918073237.Horde.VLueh0_KaiDw-9asEEcdM84@ignaz.org/T/#m07c5694df1acb173a42e1a0bab7ac22bd231a2b8


Signed-off-by: default avatarPing-Ke Shih <pkshih@realtek.com>
Tested-by: default avatarMarcel Weißenbach <mweissenbach@ignaz.org>
Signed-off-by: default avatarKalle Valo <kvalo@kernel.org>
Link: https://patch.msgid.link/20240924021633.19861-1-pkshih@realtek.com
parent 52009b41
Loading
Loading
Loading
Loading
+41 −7
Original line number Diff line number Diff line
@@ -3026,24 +3026,54 @@ static void rtw89_pci_declaim_device(struct rtw89_dev *rtwdev,
	pci_disable_device(pdev);
}

static void rtw89_pci_cfg_dac(struct rtw89_dev *rtwdev)
static bool rtw89_pci_chip_is_manual_dac(struct rtw89_dev *rtwdev)
{
	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
	const struct rtw89_chip_info *chip = rtwdev->chip;

	if (!rtwpci->enable_dac)
		return;

	switch (chip->chip_id) {
	case RTL8852A:
	case RTL8852B:
	case RTL8851B:
	case RTL8852BT:
		break;
		return true;
	default:
		return;
		return false;
	}
}

static bool rtw89_pci_is_dac_compatible_bridge(struct rtw89_dev *rtwdev)
{
	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
	struct pci_dev *bridge = pci_upstream_bridge(rtwpci->pdev);

	if (!rtw89_pci_chip_is_manual_dac(rtwdev))
		return true;

	if (!bridge)
		return false;

	switch (bridge->vendor) {
	case PCI_VENDOR_ID_INTEL:
		return true;
	case PCI_VENDOR_ID_ASMEDIA:
		if (bridge->device == 0x2806)
			return true;
		break;
	}

	return false;
}

static void rtw89_pci_cfg_dac(struct rtw89_dev *rtwdev)
{
	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;

	if (!rtwpci->enable_dac)
		return;

	if (!rtw89_pci_chip_is_manual_dac(rtwdev))
		return;

	rtw89_pci_config_byte_set(rtwdev, RTW89_PCIE_L1_CTRL, RTW89_PCIE_BIT_EN_64BITS);
}

@@ -3061,6 +3091,9 @@ static int rtw89_pci_setup_mapping(struct rtw89_dev *rtwdev,
		goto err;
	}

	if (!rtw89_pci_is_dac_compatible_bridge(rtwdev))
		goto no_dac;

	ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(36));
	if (!ret) {
		rtwpci->enable_dac = true;
@@ -3073,6 +3106,7 @@ static int rtw89_pci_setup_mapping(struct rtw89_dev *rtwdev,
			goto err_release_regions;
		}
	}
no_dac:

	resource_len = pci_resource_len(pdev, bar_id);
	rtwpci->mmap = pci_iomap(pdev, bar_id, resource_len);