Skip to content
Permalink
Browse files
rdma_rxe: Add memory access through MWs
Implement memory access through MWs.
Add rules checks from IBA.

Signed-off-by: Bob Pearson <rpearson@hpe.com>
  • Loading branch information
Bob Pearson authored and intel-lab-lkp committed Sep 18, 2020
1 parent 017b90d commit ea6524464bcccdce769f9a046224290a51dee110
Show file tree
Hide file tree
Showing 6 changed files with 176 additions and 72 deletions.
@@ -100,25 +100,28 @@ enum lookup_type {
lookup_remote,
};

struct rxe_mr *lookup_mr(struct rxe_pd *pd, int access, u32 key,
enum lookup_type type);
int advance_dma_data(struct rxe_dma_info *dma, unsigned int length);

int mr_check_range(struct rxe_mr *mr, u64 iova, size_t length);
int rxe_mr_check_access(struct rxe_qp *qp, struct rxe_mr *mr,
int access, u64 va, u32 resid);

void rxe_mr_cleanup(struct rxe_pool_entry *arg);

int advance_dma_data(struct rxe_dma_info *dma, unsigned int length);

/* rxe_mw.c */
struct ib_mw *rxe_alloc_mw(struct ib_pd *ibpd, enum ib_mw_type type,
struct ib_udata *udata);

int rxe_dealloc_mw(struct ib_mw *ibmw);

void rxe_mw_cleanup(struct rxe_pool_entry *arg);

int rxe_bind_mw(struct rxe_qp *qp, struct rxe_send_wqe *wqe);

int rxe_invalidate_mw(struct rxe_qp *qp, struct rxe_mw *mw);

int rxe_mw_check_access(struct rxe_qp *qp, struct rxe_mw *mw,
int access, u64 va, u32 resid);

void rxe_mw_cleanup(struct rxe_pool_entry *arg);

/* rxe_net.c */
void rxe_loopback(struct sk_buff *skb);
int rxe_send(struct rxe_pkt_info *pkt, struct sk_buff *skb);
@@ -21,7 +21,7 @@ static void rxe_set_mr_lkey(struct rxe_mr *mr)
goto again;
}

int mr_check_range(struct rxe_mr *mr, u64 iova, size_t length)
static int mr_check_range(struct rxe_mr *mr, u64 iova, size_t length)
{
switch (mr->type) {
case RXE_MR_TYPE_DMA:
@@ -380,6 +380,25 @@ int rxe_mr_copy(struct rxe_mr *mr, u64 iova, void *addr, int length,
return err;
}

static struct rxe_mr *lookup_mr(struct rxe_pd *pd, int access, u32 lkey)
{
struct rxe_mr *mr;
struct rxe_dev *rxe = to_rdev(pd->ibpd.device);

mr = rxe_pool_get_key(&rxe->mr_pool, &lkey);
if (!mr)
return NULL;

if (unlikely((mr->ibmr.lkey != lkey) || (mr->pd != pd) ||
(access && !(access & mr->access)) ||
(mr->state != RXE_MEM_STATE_VALID))) {
rxe_drop_ref(mr);
return NULL;
}

return mr;
}

/* copy data in or out of a wqe, i.e. sg list
* under the control of a dma descriptor
*/
@@ -409,7 +428,7 @@ int copy_data(
}

if (sge->length && (offset < sge->length)) {
mr = lookup_mr(pd, access, sge->lkey, lookup_local);
mr = lookup_mr(pd, access, sge->lkey);
if (!mr) {
err = -EINVAL;
goto err1;
@@ -434,8 +453,7 @@ int copy_data(
}

if (sge->length) {
mr = lookup_mr(pd, access, sge->lkey,
lookup_local);
mr = lookup_mr(pd, access, sge->lkey);
if (!mr) {
err = -EINVAL;
goto err1;
@@ -510,32 +528,38 @@ int advance_dma_data(struct rxe_dma_info *dma, unsigned int length)
return 0;
}

/* (1) find the mr corresponding to lkey/rkey
* depending on lookup_type
* (2) verify that the (qp) pd matches the mr pd
* (3) verify that the mr can support the requested access
* (4) verify that mr state is valid
*/
struct rxe_mr *lookup_mr(struct rxe_pd *pd, int access, u32 key,
enum lookup_type type)
int rxe_invalidate_mr(struct rxe_qp *qp, struct rxe_mr *mr)
{
struct rxe_mr *mr;
struct rxe_dev *rxe = to_rdev(pd->ibpd.device);
mr->state = RXE_MEM_STATE_FREE;
return 0;
}

mr = rxe_pool_get_key(&rxe->mr_pool, &key);
if (!mr)
return NULL;
int rxe_mr_check_access(struct rxe_qp *qp, struct rxe_mr *mr,
int access, u64 va, u32 resid)
{
int ret;
struct rxe_pd *pd = to_rpd(mr->ibmr.pd);

if (unlikely((type == lookup_local && mr->lkey != key) ||
(type == lookup_remote && mr->rkey != key) ||
mr->pd != pd ||
(access && !(access & mr->access)) ||
mr->state != RXE_MEM_STATE_VALID)) {
rxe_drop_ref(mr);
mr = NULL;
if (unlikely(mr->state != RXE_MEM_STATE_VALID)) {
pr_err("attempt to access a MR that is not in the valid state\n");
return -EINVAL;
}

return mr;
/* C10-56 */
if (unlikely(pd != qp->pd)) {
pr_err("attempt to access a MR with a different PD than the QP\n");
return -EINVAL;
}

/* C10-57 */
if (unlikely(access && !(access & mr->access))) {
pr_err("attempt to access a MR without required access rights\n");
return -EINVAL;
}

ret = mr_check_range(mr, va, resid);

return ret;
}

void rxe_mr_cleanup(struct rxe_pool_entry *arg)
@@ -318,11 +318,6 @@ int rxe_bind_mw(struct rxe_qp *qp, struct rxe_send_wqe *wqe)

static int check_invalidate_mw(struct rxe_qp *qp, struct rxe_mw *mw)
{
if (unlikely(mw->state != RXE_MEM_STATE_VALID)) {
pr_err_once("attempt to invalidate a MW that is not valid\n");
return -EINVAL;
}

/* o10-37.2.26 */
if (unlikely(mw->ibmw.type == IB_MW_TYPE_1)) {
pr_err_once("attempt to invalidate a type 1 MW\n");
@@ -336,9 +331,11 @@ static void do_invalidate_mw(struct rxe_mw *mw)
{
mw->qp = NULL;

rxe_drop_ref(mw->mr);
atomic_dec(&mw->mr->num_mw);
mw->mr = NULL;
if (mw->mr) {
atomic_dec(&mw->mr->num_mw);
mw->mr = NULL;
rxe_drop_ref(mw->mr);
}

mw->access = 0;
mw->addr = 0;
@@ -364,6 +361,50 @@ int rxe_invalidate_mw(struct rxe_qp *qp, struct rxe_mw *mw)
return ret;
}

int rxe_mw_check_access(struct rxe_qp *qp, struct rxe_mw *mw,
int access, u64 va, u32 resid)
{
struct rxe_pd *pd = to_rpd(mw->ibmw.pd);

if (unlikely(mw->state != RXE_MEM_STATE_VALID)) {
pr_err_once("attempt to access a MW that is not valid\n");
return -EINVAL;
}

/* C10-76.2.1 */
if (unlikely((mw->ibmw.type == IB_MW_TYPE_1) && (pd != qp->pd))) {
pr_err_once("attempt to access a type 1 MW with a different PD than the QP\n");
return -EINVAL;
}

/* o10-37.2.43 */
if (unlikely((mw->ibmw.type == IB_MW_TYPE_2) && (mw->qp != qp))) {
pr_err_once("attempt to access a type 2 MW that is associated with a different QP\n");
return -EINVAL;
}

/* C10-77 */
if (unlikely(access && !(access & mw->access))) {
pr_err_once("attempt to access a MW without sufficient access\n");
return -EINVAL;
}

if (mw->access & IB_ZERO_BASED) {
if (unlikely((va + resid) > mw->length)) {
pr_err_once("attempt to access a ZB MW out of bounds\n");
return -EINVAL;
}
} else {
if (unlikely((va < mw->addr) ||
((va + resid) > (mw->addr + mw->length)))) {
pr_err_once("attempt to access a VA MW out of bounds\n");
return -EINVAL;
}
}

return 0;
}

void rxe_mw_cleanup(struct rxe_pool_entry *arg)
{
struct rxe_mw *mw = container_of(arg, typeof(*mw), pelem);
@@ -604,7 +604,6 @@ int rxe_requester(void *arg)
if (!mr) {
pr_err("No mr for key %#x\n",
wqe->wr.ex.invalidate_rkey);
wqe->state = wqe_state_error;
wqe->status = IB_WC_MW_BIND_ERR;
goto err;
}
@@ -626,7 +625,6 @@ int rxe_requester(void *arg)
case IB_WR_BIND_MW:
ret = rxe_bind_mw(qp, wqe);
if (ret) {
wqe->state = wqe_state_done;
wqe->status = IB_WC_MW_BIND_ERR;
goto err;
}
@@ -636,6 +634,7 @@ int rxe_requester(void *arg)
default:
pr_err_once("unexpected LOCAL WR opcode = %d\n",
wqe->wr.opcode);
wqe->status = IB_WC_LOC_QP_OP_ERR;
goto err;
}

@@ -679,13 +678,7 @@ int rxe_requester(void *arg)
payload = (mask & RXE_WRITE_OR_SEND) ? wqe->dma.resid : 0;
if (payload > mtu) {
if (qp_type(qp) == IB_QPT_UD) {
/* C10-93.1.1: If the total sum of all the buffer lengths specified for a
* UD message exceeds the MTU of the port as returned by QueryHCA, the CI
* shall not emit any packets for this message. Further, the CI shall not
* generate an error due to this condition.
*/

/* fake a successful UD send */
/* C10-93.1.1: fake a successful UD send */
wqe->first_psn = qp->req.psn;
wqe->last_psn = qp->req.psn;
qp->req.psn = (qp->req.psn + 1) & BTH_PSN_MASK;
@@ -750,6 +743,8 @@ int rxe_requester(void *arg)
* to be called again
*/
wqe->state = wqe_state_error;
qp->req.wqe_index = next_index(qp->sq.queue,
qp->req.wqe_index);
__rxe_do_task(&qp->comp.task);
ret = -EAGAIN;
goto done;
@@ -765,8 +760,7 @@ int rxe_requester(void *arg)

again:
/* we come here if we are done with the current wqe but want to
* get called again. Mostly we loop back to next wqe so should
* be all one way or the other
* get called again.
*/
ret = 0;
goto done;

0 comments on commit ea65244

Please sign in to comment.