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

can: peak_canfd: fix firmware < v3.3.0: limit allocation to 32-bit DMA addr only

The DMA logic in firmwares < v3.3.0 embedded in the PCAN-PCIe FD cards
family is not capable of handling a mix of 32-bit and 64-bit logical
addresses. If the board is equipped with 2 or 4 CAN ports, then such a
situation might lead to a PCIe Bus Error "Malformed TLP" packet
as well as "irq xx: nobody cared" issue.

This patch adds a workaround that requests only 32-bit DMA addresses
when these might be allocated outside of the 4 GB area.

This issue has been fixed in firmware v3.3.0 and next.

Signed-off-by: Stephane Grosjean <s.grosjean@peak-system.com>
Cc: linux-stable <stable@vger.kernel.org>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>

authored by

Stephane Grosjean and committed by
Marc Kleine-Budde
5d4c94ed c9ce1fa1

+19
+19
drivers/net/can/peak_canfd/peak_pciefd_main.c
··· 58 58 #define PCIEFD_REG_SYS_VER1 0x0040 /* version reg #1 */ 59 59 #define PCIEFD_REG_SYS_VER2 0x0044 /* version reg #2 */ 60 60 61 + #define PCIEFD_FW_VERSION(x, y, z) (((u32)(x) << 24) | \ 62 + ((u32)(y) << 16) | \ 63 + ((u32)(z) << 8)) 64 + 61 65 /* System Control Registers Bits */ 62 66 #define PCIEFD_SYS_CTL_TS_RST 0x00000001 /* timestamp clock */ 63 67 #define PCIEFD_SYS_CTL_CLK_EN 0x00000002 /* system clock */ ··· 785 781 dev_info(&pdev->dev, 786 782 "%ux CAN-FD PCAN-PCIe FPGA v%u.%u.%u:\n", can_count, 787 783 hw_ver_major, hw_ver_minor, hw_ver_sub); 784 + 785 + #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT 786 + /* FW < v3.3.0 DMA logic doesn't handle correctly the mix of 32-bit and 787 + * 64-bit logical addresses: this workaround forces usage of 32-bit 788 + * DMA addresses only when such a fw is detected. 789 + */ 790 + if (PCIEFD_FW_VERSION(hw_ver_major, hw_ver_minor, hw_ver_sub) < 791 + PCIEFD_FW_VERSION(3, 3, 0)) { 792 + err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); 793 + if (err) 794 + dev_warn(&pdev->dev, 795 + "warning: can't set DMA mask %llxh (err %d)\n", 796 + DMA_BIT_MASK(32), err); 797 + } 798 + #endif 788 799 789 800 /* stop system clock */ 790 801 pciefd_sys_writereg(pciefd, PCIEFD_SYS_CTL_CLK_EN,