From d46d31cdd7dafa26621c5eb334b52cfc2400803b Mon Sep 17 00:00:00 2001 From: Maor Gottlieb Date: Mon, 27 Apr 2015 13:47:56 +0300 Subject: [PATCH] net/mlx4_core: Fix FMR unmapping to allow remapping afterward According to device spec we only need to set ownership bit to SW at FMR unmap, all other stuff we did are redundant and not essential. This fix is ported from Mellanox OFED 3.1. It covers some of the same issues fixed in UEK2 with the following UEK2 commits: bbdc2821db04 "mlx4_core: Avoid recycling old FMR R_Keys too soon" 5bddb281c0f1 "mlx4_ib: unmap FMR should update MPT status to 0xF" Following comments from bbdc2821db04 patch by Olaf Kirch adds more useful information about impact of this change on RDS usage in Oracle applications and copied here to retain useful context. When a FMR is unmapped, mlx4 resets the map count to 0, and clears the upper part of the R_Key which is used as the sequence counter. This poses a problem for RDS, which uses ib_fmr_unmap as a fence operation. RDS assumes that after issuing an unmap, the old R_Keys will be invalid for a "reasonable" period of time. For instance, Oracle processes uses shared memory buffers allocated from a pool of buffers. When a process dies, we want to reclaim these buffers -- but we must make sure there are no pending RDMA operations to/from those buffers. The only way to achieve that is by using unmap and sync the TPT. However, when the sequence count is reset on unmap, there is a high likelihood that a new mapping will be given the same R_Key that was issued a few milliseconds ago. To prevent this, don't reset the sequence count when unmapping a FMR. Orabug: 21473880 Signed-off-by: Maor Gottlieb Signed-off-by: Mukesh Kacker Reviewed-by: Yuval Shaia --- drivers/net/ethernet/mellanox/mlx4/mr.c | 38 ++++++++++++------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/mr.c b/drivers/net/ethernet/mellanox/mlx4/mr.c index 0e770fd75311..52fefef15daf 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mr.c +++ b/drivers/net/ethernet/mellanox/mlx4/mr.c @@ -1125,31 +1125,13 @@ EXPORT_SYMBOL_GPL(mlx4_fmr_enable); void mlx4_fmr_unmap(struct mlx4_dev *dev, struct mlx4_fmr *fmr, u32 *lkey, u32 *rkey) { - u32 key; - if (!fmr->maps) return; - key = key_to_hw_index(fmr->mr.key) & (dev->caps.num_mpts - 1); - + /* To unmap: it is sufficient to take back ownership from HW */ *(u8 *)fmr->mpt = MLX4_MPT_STATUS_SW; - /* Make sure MPT status is visible before changing MPT fields */ - wmb(); - - fmr->mr.key = hw_index_to_key(key); - - fmr->mpt->key = cpu_to_be32(key); - fmr->mpt->lkey = cpu_to_be32(key); - fmr->mpt->length = 0; - fmr->mpt->start = 0; - - /* Make sure MPT data is visible before changing MPT status */ - wmb(); - - *(u8 *)fmr->mpt = MLX4_MPT_STATUS_HW; - - /* Make sure MPT satus is visible */ + /* Make sure MPT status is visible */ wmb(); fmr->maps = 0; @@ -1162,6 +1144,22 @@ int mlx4_fmr_free(struct mlx4_dev *dev, struct mlx4_fmr *fmr) if (fmr->maps) return -EBUSY; + if (fmr->mr.enabled == MLX4_MPT_EN_HW) { + /* In case of FMR was enabled and unmapped + * make sure to give ownership of MPT back to HW + * so HW2SW_MPT command will succeed. + */ + *(u8 *)fmr->mpt = MLX4_MPT_STATUS_SW; + /* Make sure MPT status is visible before changing MPT fields */ + wmb(); + fmr->mpt->length = 0; + fmr->mpt->start = 0; + /* Make sure MPT data is visible before changing MPT status */ + wmb(); + *(u8 *)fmr->mpt = MLX4_MPT_STATUS_HW; + /* make sure MPT status is visible */ + wmb(); + } ret = mlx4_mr_free(dev, &fmr->mr); if (ret) -- 2.50.1