Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: 1fd4b3fe52ef ("wifi: rtw89: pci: support 36-bit PCI DMA address")
Reported-by: Marcel Weißenbach <mweissenbach@ignaz.org>
Closes: https://lore.kernel.org/linux-wireless/20240918073237.Horde.VLueh0_KaiDw-9asEEcdM84@ignaz.org/T/#m07c5694df1acb173a42e1a0bab7ac22bd231a2b8
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
Tested-by: Marcel Weißenbach <mweissenbach@ignaz.org>
Signed-off-by: Kalle Valo <kvalo@kernel.org>
Link: https://patch.msgid.link/20240924021633.19861-1-pkshih@realtek.com

authored by

Ping-Ke Shih and committed by
Kalle Valo
aa70ff09 52009b41

+41 -7
+41 -7
drivers/net/wireless/realtek/rtw89/pci.c
··· 3026 3026 pci_disable_device(pdev); 3027 3027 } 3028 3028 3029 - static void rtw89_pci_cfg_dac(struct rtw89_dev *rtwdev) 3029 + static bool rtw89_pci_chip_is_manual_dac(struct rtw89_dev *rtwdev) 3030 3030 { 3031 - struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; 3032 3031 const struct rtw89_chip_info *chip = rtwdev->chip; 3033 - 3034 - if (!rtwpci->enable_dac) 3035 - return; 3036 3032 3037 3033 switch (chip->chip_id) { 3038 3034 case RTL8852A: 3039 3035 case RTL8852B: 3040 3036 case RTL8851B: 3041 3037 case RTL8852BT: 3042 - break; 3038 + return true; 3043 3039 default: 3044 - return; 3040 + return false; 3045 3041 } 3042 + } 3043 + 3044 + static bool rtw89_pci_is_dac_compatible_bridge(struct rtw89_dev *rtwdev) 3045 + { 3046 + struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; 3047 + struct pci_dev *bridge = pci_upstream_bridge(rtwpci->pdev); 3048 + 3049 + if (!rtw89_pci_chip_is_manual_dac(rtwdev)) 3050 + return true; 3051 + 3052 + if (!bridge) 3053 + return false; 3054 + 3055 + switch (bridge->vendor) { 3056 + case PCI_VENDOR_ID_INTEL: 3057 + return true; 3058 + case PCI_VENDOR_ID_ASMEDIA: 3059 + if (bridge->device == 0x2806) 3060 + return true; 3061 + break; 3062 + } 3063 + 3064 + return false; 3065 + } 3066 + 3067 + static void rtw89_pci_cfg_dac(struct rtw89_dev *rtwdev) 3068 + { 3069 + struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; 3070 + 3071 + if (!rtwpci->enable_dac) 3072 + return; 3073 + 3074 + if (!rtw89_pci_chip_is_manual_dac(rtwdev)) 3075 + return; 3046 3076 3047 3077 rtw89_pci_config_byte_set(rtwdev, RTW89_PCIE_L1_CTRL, RTW89_PCIE_BIT_EN_64BITS); 3048 3078 } ··· 3091 3061 goto err; 3092 3062 } 3093 3063 3064 + if (!rtw89_pci_is_dac_compatible_bridge(rtwdev)) 3065 + goto no_dac; 3066 + 3094 3067 ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(36)); 3095 3068 if (!ret) { 3096 3069 rtwpci->enable_dac = true; ··· 3106 3073 goto err_release_regions; 3107 3074 } 3108 3075 } 3076 + no_dac: 3109 3077 3110 3078 resource_len = pci_resource_len(pdev, bar_id); 3111 3079 rtwpci->mmap = pci_iomap(pdev, bar_id, resource_len);