From: Leon Romanovsky leonro@nvidia.com
mlx5_umem_needs_ats() enables ATS for any dma-buf whose caller asked for Relaxed Ordering, on the assumption that a switch in the path has CR, RR and DT all set. It also enables it for a buffer already mapped with the peer's bus addresses, which are not translatable at all.
P2PDMA has read the ACS controls, so ask it through dma_buf_p2pdma_map_type(): enable ATS only where the path is not routed directly as it stands, but would be for a Translated Request whose Completions carry Relaxed Ordering. Exporters that name no provider keep the old assumption, since their ACS settings remain hidden.
Signed-off-by: Leon Romanovsky leonro@nvidia.com --- drivers/infiniband/hw/mlx5/mlx5_ib.h | 36 ++------------------------------ drivers/infiniband/hw/mlx5/mr.c | 40 ++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 34 deletions(-)
diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h index e9ddf2e97a76..ab32742b2180 100644 --- a/drivers/infiniband/hw/mlx5/mlx5_ib.h +++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h @@ -1646,40 +1646,8 @@ static inline bool rt_supported(int ts_cap) ts_cap == MLX5_TIMESTAMP_FORMAT_CAP_FREE_RUNNING_AND_REAL_TIME; }
-/* - * PCI Peer to Peer is a trainwreck. If no switch is present then things - * sometimes work, depending on the pci_distance_p2p logic for excluding broken - * root complexes. However if a switch is present in the path, then things get - * really ugly depending on how the switch is setup. This table assumes that the - * root complex is strict and is validating that all req/reps are matches - * perfectly - so any scenario where it sees only half the transaction is a - * failure. - * - * CR/RR/DT ATS RO P2P - * 00X X X OK - * 010 X X fails (request is routed to root but root never sees comp) - * 011 0 X fails (request is routed to root but root never sees comp) - * 011 1 X OK - * 10X X 1 OK - * 101 X 0 fails (completion is routed to root but root didn't see req) - * 110 X 0 SLOW - * 111 0 0 SLOW - * 111 1 0 fails (completion is routed to root but root didn't see req) - * 111 1 1 OK - * - * Unfortunately we cannot reliably know if a switch is present or what the - * CR/RR/DT ACS settings are, as in a VM that is all hidden. Assume that - * CR/RR/DT is 111 if the ATS cap is enabled and follow the last three rows. - * - * For now assume if the umem is a dma_buf then it is P2P. - */ -static inline bool mlx5_umem_needs_ats(struct mlx5_ib_dev *dev, - struct ib_umem *umem, int access_flags) -{ - if (!MLX5_CAP_GEN(dev->mdev, ats) || !umem->is_dmabuf) - return false; - return access_flags & IB_ACCESS_RELAXED_ORDERING; -} +bool mlx5_umem_needs_ats(struct mlx5_ib_dev *dev, struct ib_umem *umem, + int access_flags);
int set_roce_addr(struct mlx5_ib_dev *dev, u32 port_num, unsigned int index, const union ib_gid *gid, diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c index 00e13028762a..286f372e5b0c 100644 --- a/drivers/infiniband/hw/mlx5/mr.c +++ b/drivers/infiniband/hw/mlx5/mr.c @@ -38,6 +38,7 @@ #include <linux/export.h> #include <linux/delay.h> #include <linux/dma-buf.h> +#include <linux/dma-buf-mapping.h> #include <linux/dma-resv.h> #include <rdma/frmr_pools.h> #include <rdma/ib_umem_odp.h> @@ -47,6 +48,45 @@ #include "data_direct.h" #include "dmah.h"
+MODULE_IMPORT_NS("DMA_BUF"); + +bool mlx5_umem_needs_ats(struct mlx5_ib_dev *dev, struct ib_umem *umem, + int access_flags) +{ + struct dma_buf_attachment *attach; + + if (!MLX5_CAP_GEN(dev->mdev, ats) || !umem->is_dmabuf) + return false; + + /* + * The Completer decides whether its Completions carry Relaxed + * Ordering, and only a Request that asked for it can expect them to. + */ + if (!(access_flags & IB_ACCESS_RELAXED_ORDERING)) + return false; + + attach = to_ib_umem_dmabuf(umem)->attach; + switch (dma_buf_p2pdma_map_type(attach, 0)) { + case PCI_P2PDMA_MAP_NONE: + /* Nothing is known about the route, so fall back to the bet. */ + return true; + case PCI_P2PDMA_MAP_BUS_ADDR: + /* + * The path is routed directly already and is programmed with + * the peer's bus addresses. Those are not translatable, so + * ATS would be wrong as well as pointless. + */ + return false; + default: + break; + } + + return dma_buf_p2pdma_map_type(attach, + PCI_P2PDMA_TLP_TRANSLATED | + PCI_P2PDMA_TLP_RELAXED_CPL) == + PCI_P2PDMA_MAP_BUS_ADDR; +} + static int mkey_max_umr_order(struct mlx5_ib_dev *dev) { if (MLX5_CAP_GEN(dev->mdev, umr_extended_translation_offset))