diff options
| author | Haggai Eran <haggaie@mellanox.com> | 2014-12-11 10:04:19 -0500 |
|---|---|---|
| committer | Roland Dreier <roland@purestorage.com> | 2014-12-15 21:18:59 -0500 |
| commit | e420f0c0f3d1022789fcb59b2a0c4b979ce311ba (patch) | |
| tree | 205d214ec065db728f2c7037d58a400f0e3bef8a /drivers/net | |
| parent | 6cb7ff3dcfe6aad6a36a0fd0e928b5bea4fabdd5 (diff) | |
mlx5_core: Add support for page faults events and low level handling
* Add a handler function pointer in the mlx5_core_qp struct for page
fault events. Handle page fault events by calling the handler
function, if not NULL.
* Add on-demand paging capability query command.
* Export command for resuming QPs after page faults.
* Add various constants related to paging support.
Signed-off-by: Sagi Grimberg <sagig@mellanox.com>
Signed-off-by: Shachar Raindel <raindel@mellanox.com>
Signed-off-by: Haggai Eran <haggaie@mellanox.com>
Signed-off-by: Roland Dreier <roland@purestorage.com>
Diffstat (limited to 'drivers/net')
| -rw-r--r-- | drivers/net/ethernet/mellanox/mlx5/core/eq.c | 13 | ||||
| -rw-r--r-- | drivers/net/ethernet/mellanox/mlx5/core/fw.c | 40 | ||||
| -rw-r--r-- | drivers/net/ethernet/mellanox/mlx5/core/qp.c | 119 |
3 files changed, 171 insertions, 1 deletions
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eq.c b/drivers/net/ethernet/mellanox/mlx5/core/eq.c index ab684463780b..da82991239a8 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eq.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eq.c | |||
| @@ -157,6 +157,8 @@ static const char *eqe_type_str(u8 type) | |||
| 157 | return "MLX5_EVENT_TYPE_CMD"; | 157 | return "MLX5_EVENT_TYPE_CMD"; |
| 158 | case MLX5_EVENT_TYPE_PAGE_REQUEST: | 158 | case MLX5_EVENT_TYPE_PAGE_REQUEST: |
| 159 | return "MLX5_EVENT_TYPE_PAGE_REQUEST"; | 159 | return "MLX5_EVENT_TYPE_PAGE_REQUEST"; |
| 160 | case MLX5_EVENT_TYPE_PAGE_FAULT: | ||
| 161 | return "MLX5_EVENT_TYPE_PAGE_FAULT"; | ||
| 160 | default: | 162 | default: |
| 161 | return "Unrecognized event"; | 163 | return "Unrecognized event"; |
| 162 | } | 164 | } |
| @@ -279,6 +281,11 @@ static int mlx5_eq_int(struct mlx5_core_dev *dev, struct mlx5_eq *eq) | |||
| 279 | } | 281 | } |
| 280 | break; | 282 | break; |
| 281 | 283 | ||
| 284 | #ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING | ||
| 285 | case MLX5_EVENT_TYPE_PAGE_FAULT: | ||
| 286 | mlx5_eq_pagefault(dev, eqe); | ||
| 287 | break; | ||
| 288 | #endif | ||
| 282 | 289 | ||
| 283 | default: | 290 | default: |
| 284 | mlx5_core_warn(dev, "Unhandled event 0x%x on EQ 0x%x\n", | 291 | mlx5_core_warn(dev, "Unhandled event 0x%x on EQ 0x%x\n", |
| @@ -446,8 +453,12 @@ void mlx5_eq_cleanup(struct mlx5_core_dev *dev) | |||
| 446 | int mlx5_start_eqs(struct mlx5_core_dev *dev) | 453 | int mlx5_start_eqs(struct mlx5_core_dev *dev) |
| 447 | { | 454 | { |
| 448 | struct mlx5_eq_table *table = &dev->priv.eq_table; | 455 | struct mlx5_eq_table *table = &dev->priv.eq_table; |
| 456 | u32 async_event_mask = MLX5_ASYNC_EVENT_MASK; | ||
| 449 | int err; | 457 | int err; |
| 450 | 458 | ||
| 459 | if (dev->caps.gen.flags & MLX5_DEV_CAP_FLAG_ON_DMND_PG) | ||
| 460 | async_event_mask |= (1ull << MLX5_EVENT_TYPE_PAGE_FAULT); | ||
| 461 | |||
| 451 | err = mlx5_create_map_eq(dev, &table->cmd_eq, MLX5_EQ_VEC_CMD, | 462 | err = mlx5_create_map_eq(dev, &table->cmd_eq, MLX5_EQ_VEC_CMD, |
| 452 | MLX5_NUM_CMD_EQE, 1ull << MLX5_EVENT_TYPE_CMD, | 463 | MLX5_NUM_CMD_EQE, 1ull << MLX5_EVENT_TYPE_CMD, |
| 453 | "mlx5_cmd_eq", &dev->priv.uuari.uars[0]); | 464 | "mlx5_cmd_eq", &dev->priv.uuari.uars[0]); |
| @@ -459,7 +470,7 @@ int mlx5_start_eqs(struct mlx5_core_dev *dev) | |||
| 459 | mlx5_cmd_use_events(dev); | 470 | mlx5_cmd_use_events(dev); |
| 460 | 471 | ||
| 461 | err = mlx5_create_map_eq(dev, &table->async_eq, MLX5_EQ_VEC_ASYNC, | 472 | err = mlx5_create_map_eq(dev, &table->async_eq, MLX5_EQ_VEC_ASYNC, |
| 462 | MLX5_NUM_ASYNC_EQE, MLX5_ASYNC_EVENT_MASK, | 473 | MLX5_NUM_ASYNC_EQE, async_event_mask, |
| 463 | "mlx5_async_eq", &dev->priv.uuari.uars[0]); | 474 | "mlx5_async_eq", &dev->priv.uuari.uars[0]); |
| 464 | if (err) { | 475 | if (err) { |
| 465 | mlx5_core_warn(dev, "failed to create async EQ %d\n", err); | 476 | mlx5_core_warn(dev, "failed to create async EQ %d\n", err); |
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw.c b/drivers/net/ethernet/mellanox/mlx5/core/fw.c index 087c4c797deb..06f9036acd83 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fw.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fw.c | |||
| @@ -69,6 +69,46 @@ int mlx5_cmd_query_hca_cap(struct mlx5_core_dev *dev, struct mlx5_caps *caps) | |||
| 69 | return mlx5_core_get_caps(dev, caps, HCA_CAP_OPMOD_GET_CUR); | 69 | return mlx5_core_get_caps(dev, caps, HCA_CAP_OPMOD_GET_CUR); |
| 70 | } | 70 | } |
| 71 | 71 | ||
| 72 | int mlx5_query_odp_caps(struct mlx5_core_dev *dev, struct mlx5_odp_caps *caps) | ||
| 73 | { | ||
| 74 | u8 in[MLX5_ST_SZ_BYTES(query_hca_cap_in)]; | ||
| 75 | int out_sz = MLX5_ST_SZ_BYTES(query_hca_cap_out); | ||
| 76 | void *out; | ||
| 77 | int err; | ||
| 78 | |||
| 79 | if (!(dev->caps.gen.flags & MLX5_DEV_CAP_FLAG_ON_DMND_PG)) | ||
| 80 | return -ENOTSUPP; | ||
| 81 | |||
| 82 | memset(in, 0, sizeof(in)); | ||
| 83 | out = kzalloc(out_sz, GFP_KERNEL); | ||
| 84 | if (!out) | ||
| 85 | return -ENOMEM; | ||
| 86 | MLX5_SET(query_hca_cap_in, in, opcode, MLX5_CMD_OP_QUERY_HCA_CAP); | ||
| 87 | MLX5_SET(query_hca_cap_in, in, op_mod, HCA_CAP_OPMOD_GET_ODP_CUR); | ||
| 88 | err = mlx5_cmd_exec(dev, in, sizeof(in), out, out_sz); | ||
| 89 | if (err) | ||
| 90 | goto out; | ||
| 91 | |||
| 92 | err = mlx5_cmd_status_to_err_v2(out); | ||
| 93 | if (err) { | ||
| 94 | mlx5_core_warn(dev, "query cur hca ODP caps failed, %d\n", err); | ||
| 95 | goto out; | ||
| 96 | } | ||
| 97 | |||
| 98 | memcpy(caps, MLX5_ADDR_OF(query_hca_cap_out, out, capability_struct), | ||
| 99 | sizeof(*caps)); | ||
| 100 | |||
| 101 | mlx5_core_dbg(dev, "on-demand paging capabilities:\nrc: %08x\nuc: %08x\nud: %08x\n", | ||
| 102 | be32_to_cpu(caps->per_transport_caps.rc_odp_caps), | ||
| 103 | be32_to_cpu(caps->per_transport_caps.uc_odp_caps), | ||
| 104 | be32_to_cpu(caps->per_transport_caps.ud_odp_caps)); | ||
| 105 | |||
| 106 | out: | ||
| 107 | kfree(out); | ||
| 108 | return err; | ||
| 109 | } | ||
| 110 | EXPORT_SYMBOL(mlx5_query_odp_caps); | ||
| 111 | |||
| 72 | int mlx5_cmd_init_hca(struct mlx5_core_dev *dev) | 112 | int mlx5_cmd_init_hca(struct mlx5_core_dev *dev) |
| 73 | { | 113 | { |
| 74 | struct mlx5_cmd_init_hca_mbox_in in; | 114 | struct mlx5_cmd_init_hca_mbox_in in; |
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/qp.c b/drivers/net/ethernet/mellanox/mlx5/core/qp.c index 5261a2b0da43..575d853dbe05 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/qp.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/qp.c | |||
| @@ -88,6 +88,95 @@ void mlx5_rsc_event(struct mlx5_core_dev *dev, u32 rsn, int event_type) | |||
| 88 | mlx5_core_put_rsc(common); | 88 | mlx5_core_put_rsc(common); |
| 89 | } | 89 | } |
| 90 | 90 | ||
| 91 | #ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING | ||
| 92 | void mlx5_eq_pagefault(struct mlx5_core_dev *dev, struct mlx5_eqe *eqe) | ||
| 93 | { | ||
| 94 | struct mlx5_eqe_page_fault *pf_eqe = &eqe->data.page_fault; | ||
| 95 | int qpn = be32_to_cpu(pf_eqe->flags_qpn) & MLX5_QPN_MASK; | ||
| 96 | struct mlx5_core_rsc_common *common = mlx5_get_rsc(dev, qpn); | ||
| 97 | struct mlx5_core_qp *qp = | ||
| 98 | container_of(common, struct mlx5_core_qp, common); | ||
| 99 | struct mlx5_pagefault pfault; | ||
| 100 | |||
| 101 | if (!qp) { | ||
| 102 | mlx5_core_warn(dev, "ODP event for non-existent QP %06x\n", | ||
| 103 | qpn); | ||
| 104 | return; | ||
| 105 | } | ||
| 106 | |||
| 107 | pfault.event_subtype = eqe->sub_type; | ||
| 108 | pfault.flags = (be32_to_cpu(pf_eqe->flags_qpn) >> MLX5_QPN_BITS) & | ||
| 109 | (MLX5_PFAULT_REQUESTOR | MLX5_PFAULT_WRITE | MLX5_PFAULT_RDMA); | ||
| 110 | pfault.bytes_committed = be32_to_cpu( | ||
| 111 | pf_eqe->bytes_committed); | ||
| 112 | |||
| 113 | mlx5_core_dbg(dev, | ||
| 114 | "PAGE_FAULT: subtype: 0x%02x, flags: 0x%02x,\n", | ||
| 115 | eqe->sub_type, pfault.flags); | ||
| 116 | |||
| 117 | switch (eqe->sub_type) { | ||
| 118 | case MLX5_PFAULT_SUBTYPE_RDMA: | ||
| 119 | /* RDMA based event */ | ||
| 120 | pfault.rdma.r_key = | ||
| 121 | be32_to_cpu(pf_eqe->rdma.r_key); | ||
| 122 | pfault.rdma.packet_size = | ||
| 123 | be16_to_cpu(pf_eqe->rdma.packet_length); | ||
| 124 | pfault.rdma.rdma_op_len = | ||
| 125 | be32_to_cpu(pf_eqe->rdma.rdma_op_len); | ||
| 126 | pfault.rdma.rdma_va = | ||
| 127 | be64_to_cpu(pf_eqe->rdma.rdma_va); | ||
| 128 | mlx5_core_dbg(dev, | ||
| 129 | "PAGE_FAULT: qpn: 0x%06x, r_key: 0x%08x,\n", | ||
| 130 | qpn, pfault.rdma.r_key); | ||
| 131 | mlx5_core_dbg(dev, | ||
| 132 | "PAGE_FAULT: rdma_op_len: 0x%08x,\n", | ||
| 133 | pfault.rdma.rdma_op_len); | ||
| 134 | mlx5_core_dbg(dev, | ||
| 135 | "PAGE_FAULT: rdma_va: 0x%016llx,\n", | ||
| 136 | pfault.rdma.rdma_va); | ||
| 137 | mlx5_core_dbg(dev, | ||
| 138 | "PAGE_FAULT: bytes_committed: 0x%06x\n", | ||
| 139 | pfault.bytes_committed); | ||
| 140 | break; | ||
| 141 | |||
| 142 | case MLX5_PFAULT_SUBTYPE_WQE: | ||
| 143 | /* WQE based event */ | ||
| 144 | pfault.wqe.wqe_index = | ||
| 145 | be16_to_cpu(pf_eqe->wqe.wqe_index); | ||
| 146 | pfault.wqe.packet_size = | ||
| 147 | be16_to_cpu(pf_eqe->wqe.packet_length); | ||
| 148 | mlx5_core_dbg(dev, | ||
| 149 | "PAGE_FAULT: qpn: 0x%06x, wqe_index: 0x%04x,\n", | ||
| 150 | qpn, pfault.wqe.wqe_index); | ||
| 151 | mlx5_core_dbg(dev, | ||
| 152 | "PAGE_FAULT: bytes_committed: 0x%06x\n", | ||
| 153 | pfault.bytes_committed); | ||
| 154 | break; | ||
| 155 | |||
| 156 | default: | ||
| 157 | mlx5_core_warn(dev, | ||
| 158 | "Unsupported page fault event sub-type: 0x%02hhx, QP %06x\n", | ||
| 159 | eqe->sub_type, qpn); | ||
| 160 | /* Unsupported page faults should still be resolved by the | ||
| 161 | * page fault handler | ||
| 162 | */ | ||
| 163 | } | ||
| 164 | |||
| 165 | if (qp->pfault_handler) { | ||
| 166 | qp->pfault_handler(qp, &pfault); | ||
| 167 | } else { | ||
| 168 | mlx5_core_err(dev, | ||
| 169 | "ODP event for QP %08x, without a fault handler in QP\n", | ||
| 170 | qpn); | ||
| 171 | /* Page fault will remain unresolved. QP will hang until it is | ||
| 172 | * destroyed | ||
| 173 | */ | ||
| 174 | } | ||
| 175 | |||
| 176 | mlx5_core_put_rsc(common); | ||
| 177 | } | ||
| 178 | #endif | ||
| 179 | |||
| 91 | int mlx5_core_create_qp(struct mlx5_core_dev *dev, | 180 | int mlx5_core_create_qp(struct mlx5_core_dev *dev, |
| 92 | struct mlx5_core_qp *qp, | 181 | struct mlx5_core_qp *qp, |
| 93 | struct mlx5_create_qp_mbox_in *in, | 182 | struct mlx5_create_qp_mbox_in *in, |
| @@ -322,3 +411,33 @@ int mlx5_core_xrcd_dealloc(struct mlx5_core_dev *dev, u32 xrcdn) | |||
| 322 | return err; | 411 | return err; |
| 323 | } | 412 | } |
| 324 | EXPORT_SYMBOL_GPL(mlx5_core_xrcd_dealloc); | 413 | EXPORT_SYMBOL_GPL(mlx5_core_xrcd_dealloc); |
| 414 | |||
| 415 | #ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING | ||
| 416 | int mlx5_core_page_fault_resume(struct mlx5_core_dev *dev, u32 qpn, | ||
| 417 | u8 flags, int error) | ||
| 418 | { | ||
| 419 | struct mlx5_page_fault_resume_mbox_in in; | ||
| 420 | struct mlx5_page_fault_resume_mbox_out out; | ||
| 421 | int err; | ||
| 422 | |||
| 423 | memset(&in, 0, sizeof(in)); | ||
| 424 | memset(&out, 0, sizeof(out)); | ||
| 425 | in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_PAGE_FAULT_RESUME); | ||
| 426 | in.hdr.opmod = 0; | ||
| 427 | flags &= (MLX5_PAGE_FAULT_RESUME_REQUESTOR | | ||
| 428 | MLX5_PAGE_FAULT_RESUME_WRITE | | ||
| 429 | MLX5_PAGE_FAULT_RESUME_RDMA); | ||
| 430 | flags |= (error ? MLX5_PAGE_FAULT_RESUME_ERROR : 0); | ||
| 431 | in.flags_qpn = cpu_to_be32((qpn & MLX5_QPN_MASK) | | ||
| 432 | (flags << MLX5_QPN_BITS)); | ||
| 433 | err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out)); | ||
| 434 | if (err) | ||
| 435 | return err; | ||
| 436 | |||
| 437 | if (out.hdr.status) | ||
| 438 | err = mlx5_cmd_status_to_err(&out.hdr); | ||
| 439 | |||
| 440 | return err; | ||
| 441 | } | ||
| 442 | EXPORT_SYMBOL_GPL(mlx5_core_page_fault_resume); | ||
| 443 | #endif | ||
