|
@@ -144,8 +144,10 @@ struct ib_mr *mlx4_ib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
|
|
|
if (!mr)
|
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
|
|
+ /* Force registering the memory as writable. */
|
|
|
+ /* Used for memory re-registeration. HCA protects the access */
|
|
|
mr->umem = ib_umem_get(pd->uobject->context, start, length,
|
|
|
- access_flags, 0);
|
|
|
+ access_flags | IB_ACCESS_LOCAL_WRITE, 0);
|
|
|
if (IS_ERR(mr->umem)) {
|
|
|
err = PTR_ERR(mr->umem);
|
|
|
goto err_free;
|
|
@@ -183,6 +185,90 @@ err_free:
|
|
|
return ERR_PTR(err);
|
|
|
}
|
|
|
|
|
|
+int mlx4_ib_rereg_user_mr(struct ib_mr *mr, int flags,
|
|
|
+ u64 start, u64 length, u64 virt_addr,
|
|
|
+ int mr_access_flags, struct ib_pd *pd,
|
|
|
+ struct ib_udata *udata)
|
|
|
+{
|
|
|
+ struct mlx4_ib_dev *dev = to_mdev(mr->device);
|
|
|
+ struct mlx4_ib_mr *mmr = to_mmr(mr);
|
|
|
+ struct mlx4_mpt_entry *mpt_entry;
|
|
|
+ struct mlx4_mpt_entry **pmpt_entry = &mpt_entry;
|
|
|
+ int err;
|
|
|
+
|
|
|
+ /* Since we synchronize this call and mlx4_ib_dereg_mr via uverbs,
|
|
|
+ * we assume that the calls can't run concurrently. Otherwise, a
|
|
|
+ * race exists.
|
|
|
+ */
|
|
|
+ err = mlx4_mr_hw_get_mpt(dev->dev, &mmr->mmr, &pmpt_entry);
|
|
|
+
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
+
|
|
|
+ if (flags & IB_MR_REREG_PD) {
|
|
|
+ err = mlx4_mr_hw_change_pd(dev->dev, *pmpt_entry,
|
|
|
+ to_mpd(pd)->pdn);
|
|
|
+
|
|
|
+ if (err)
|
|
|
+ goto release_mpt_entry;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (flags & IB_MR_REREG_ACCESS) {
|
|
|
+ err = mlx4_mr_hw_change_access(dev->dev, *pmpt_entry,
|
|
|
+ convert_access(mr_access_flags));
|
|
|
+
|
|
|
+ if (err)
|
|
|
+ goto release_mpt_entry;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (flags & IB_MR_REREG_TRANS) {
|
|
|
+ int shift;
|
|
|
+ int err;
|
|
|
+ int n;
|
|
|
+
|
|
|
+ mlx4_mr_rereg_mem_cleanup(dev->dev, &mmr->mmr);
|
|
|
+ ib_umem_release(mmr->umem);
|
|
|
+ mmr->umem = ib_umem_get(mr->uobject->context, start, length,
|
|
|
+ mr_access_flags |
|
|
|
+ IB_ACCESS_LOCAL_WRITE,
|
|
|
+ 0);
|
|
|
+ if (IS_ERR(mmr->umem)) {
|
|
|
+ err = PTR_ERR(mmr->umem);
|
|
|
+ mmr->umem = NULL;
|
|
|
+ goto release_mpt_entry;
|
|
|
+ }
|
|
|
+ n = ib_umem_page_count(mmr->umem);
|
|
|
+ shift = ilog2(mmr->umem->page_size);
|
|
|
+
|
|
|
+ mmr->mmr.iova = virt_addr;
|
|
|
+ mmr->mmr.size = length;
|
|
|
+ err = mlx4_mr_rereg_mem_write(dev->dev, &mmr->mmr,
|
|
|
+ virt_addr, length, n, shift,
|
|
|
+ *pmpt_entry);
|
|
|
+ if (err) {
|
|
|
+ ib_umem_release(mmr->umem);
|
|
|
+ goto release_mpt_entry;
|
|
|
+ }
|
|
|
+
|
|
|
+ err = mlx4_ib_umem_write_mtt(dev, &mmr->mmr.mtt, mmr->umem);
|
|
|
+ if (err) {
|
|
|
+ mlx4_mr_rereg_mem_cleanup(dev->dev, &mmr->mmr);
|
|
|
+ ib_umem_release(mmr->umem);
|
|
|
+ goto release_mpt_entry;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* If we couldn't transfer the MR to the HCA, just remember to
|
|
|
+ * return a failure. But dereg_mr will free the resources.
|
|
|
+ */
|
|
|
+ err = mlx4_mr_hw_write_mpt(dev->dev, &mmr->mmr, pmpt_entry);
|
|
|
+
|
|
|
+release_mpt_entry:
|
|
|
+ mlx4_mr_hw_put_mpt(dev->dev, pmpt_entry);
|
|
|
+
|
|
|
+ return err;
|
|
|
+}
|
|
|
+
|
|
|
int mlx4_ib_dereg_mr(struct ib_mr *ibmr)
|
|
|
{
|
|
|
struct mlx4_ib_mr *mr = to_mmr(ibmr);
|