mirror of
https://github.com/torvalds/linux.git
synced 2026-10-17 14:30:03 +02:00
Stefan Fleischmann reported Intel IOMMU DMA Read faults on BCM57412
NetXtreme-E NICs when transmitting packets on VLAN/macvlan interfaces:
DMAR: [DMA Read NO_PASID] Request device [18:00.0] fault addr 0xfc499000
[fault reason 0x06] PTE Read access is not set
bnxt_en 0000:18:00.0 eno1np0: Abandoning msg {0xb4 0x41a} len: 0 due to firmware status: 0x2000001
...
NETDEV WATCHDOG: eno1np0 (bnxt_en): transmit queue 0 timed out
The fault address (0xfc499000) is on an exact 4KB page boundary,
pointing to a DMA read buffer overrun.
In bnxt_start_xmit(), packets smaller than BNXT_MIN_PKT_SIZE (52 bytes),
such as 42-byte untagged ARP frames, are padded:
if (length < BNXT_MIN_PKT_SIZE) {
pad = BNXT_MIN_PKT_SIZE - length;
if (skb_pad(skb, pad))
goto tx_kick_pending;
length = BNXT_MIN_PKT_SIZE;
}
mapping = dma_map_single(&pdev->dev, skb->data, len, DMA_TO_DEVICE);
...
dma_unmap_len_set(tx_buf, len, len);
However, 'len' was initialized earlier to skb_headlen(skb) (e.g. 42 bytes)
and is left unadjusted after padding. Consequently, dma_map_single() and
dma_unmap_len_set() map and track only 42 bytes.
Later, the hardware TX buffer descriptor is programmed with the padded length:
txbd->tx_bd_len_flags_type =
cpu_to_le32(((len + pad) << TX_BD_LEN_SHIFT) | flags |
TX_BD_FLAGS_PACKET_END);
The NIC DMA engine is thus instructed to read 52 bytes from a region where
only 42 bytes were DMA-mapped. If skb->data ends near the boundary of a 4KB
page (within 'pad' bytes of the next page), the hardware DMA read overruns
into the unmapped adjacent page, triggering an IOMMU fault.
This issue was exposed after commit
|
||
|---|---|---|
| .. | ||
| bnxt_coredump.c | ||
| bnxt_coredump.h | ||
| bnxt_dcb.c | ||
| bnxt_dcb.h | ||
| bnxt_debugfs.c | ||
| bnxt_debugfs.h | ||
| bnxt_devlink.c | ||
| bnxt_devlink.h | ||
| bnxt_dim.c | ||
| bnxt_ethtool.c | ||
| bnxt_ethtool.h | ||
| bnxt_fw_hdr.h | ||
| bnxt_gso.c | ||
| bnxt_gso.h | ||
| bnxt_hwmon.c | ||
| bnxt_hwmon.h | ||
| bnxt_hwrm.c | ||
| bnxt_hwrm.h | ||
| bnxt_nvm_defs.h | ||
| bnxt_ptp.c | ||
| bnxt_ptp.h | ||
| bnxt_sriov.c | ||
| bnxt_sriov.h | ||
| bnxt_tc.c | ||
| bnxt_tc.h | ||
| bnxt_ulp.c | ||
| bnxt_vfr.c | ||
| bnxt_vfr.h | ||
| bnxt_xdp.c | ||
| bnxt_xdp.h | ||
| bnxt.c | ||
| bnxt.h | ||
| Makefile | ||