diff options
Diffstat (limited to 'drivers/infiniband')
-rw-r--r-- | drivers/infiniband/core/uverbs_cmd.c | 59 | ||||
-rw-r--r-- | drivers/infiniband/hw/hns/hns_roce_hw_v1.c | 10 |
2 files changed, 58 insertions, 11 deletions
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index cc06e8404e9b..583d3a10b940 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -1984,15 +1984,64 @@ static int modify_qp(struct ib_uverbs_file *file, goto release_qp; } - if ((cmd->base.attr_mask & IB_QP_AV) && - !rdma_is_port_valid(qp->device, cmd->base.dest.port_num)) { - ret = -EINVAL; - goto release_qp; + if ((cmd->base.attr_mask & IB_QP_AV)) { + if (!rdma_is_port_valid(qp->device, cmd->base.dest.port_num)) { + ret = -EINVAL; + goto release_qp; + } + + if (cmd->base.attr_mask & IB_QP_STATE && + cmd->base.qp_state == IB_QPS_RTR) { + /* We are in INIT->RTR TRANSITION (if we are not, + * this transition will be rejected in subsequent checks). + * In the INIT->RTR transition, we cannot have IB_QP_PORT set, + * but the IB_QP_STATE flag is required. + * + * Since kernel 3.14 (commit dbf727de7440), the uverbs driver, + * when IB_QP_AV is set, has required inclusion of a valid + * port number in the primary AV. (AVs are created and handled + * differently for infiniband and ethernet (RoCE) ports). + * + * Check the port number included in the primary AV against + * the port number in the qp struct, which was set (and saved) + * in the RST->INIT transition. + */ + if (cmd->base.dest.port_num != qp->real_qp->port) { + ret = -EINVAL; + goto release_qp; + } + } else { + /* We are in SQD->SQD. (If we are not, this transition will + * be rejected later in the verbs layer checks). + * Check for both IB_QP_PORT and IB_QP_AV, these can be set + * together in the SQD->SQD transition. + * + * If only IP_QP_AV was set, add in IB_QP_PORT as well (the + * verbs layer driver does not track primary port changes + * resulting from path migration. Thus, in SQD, if the primary + * AV is modified, the primary port should also be modified). + * + * Note that in this transition, the IB_QP_STATE flag + * is not allowed. + */ + if (((cmd->base.attr_mask & (IB_QP_AV | IB_QP_PORT)) + == (IB_QP_AV | IB_QP_PORT)) && + cmd->base.port_num != cmd->base.dest.port_num) { + ret = -EINVAL; + goto release_qp; + } + if ((cmd->base.attr_mask & (IB_QP_AV | IB_QP_PORT)) + == IB_QP_AV) { + cmd->base.attr_mask |= IB_QP_PORT; + cmd->base.port_num = cmd->base.dest.port_num; + } + } } if ((cmd->base.attr_mask & IB_QP_ALT_PATH) && (!rdma_is_port_valid(qp->device, cmd->base.alt_port_num) || - !rdma_is_port_valid(qp->device, cmd->base.alt_dest.port_num))) { + !rdma_is_port_valid(qp->device, cmd->base.alt_dest.port_num) || + cmd->base.alt_port_num != cmd->base.alt_dest.port_num)) { ret = -EINVAL; goto release_qp; } diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c index 8013d69c5ac4..8444234ed092 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c @@ -1435,7 +1435,7 @@ static int hns_roce_v1_reset(struct hns_roce_dev *hr_dev, bool dereset) } fwnode = &dsaf_node->fwnode; } else if (is_acpi_device_node(dev->fwnode)) { - struct acpi_reference_args args; + struct fwnode_reference_args args; ret = acpi_node_get_property_reference(dev->fwnode, "dsaf-handle", 0, &args); @@ -1443,7 +1443,7 @@ static int hns_roce_v1_reset(struct hns_roce_dev *hr_dev, bool dereset) dev_err(dev, "could not find dsaf-handle\n"); return ret; } - fwnode = acpi_fwnode_handle(args.adev); + fwnode = args.fwnode; } else { dev_err(dev, "cannot read data from DT or ACPI\n"); return -ENXIO; @@ -4835,16 +4835,14 @@ static int hns_roce_get_cfg(struct hns_roce_dev *hr_dev) continue; pdev = of_find_device_by_node(net_node); } else if (is_acpi_device_node(dev->fwnode)) { - struct acpi_reference_args args; - struct fwnode_handle *fwnode; + struct fwnode_reference_args args; ret = acpi_node_get_property_reference(dev->fwnode, "eth-handle", i, &args); if (ret) continue; - fwnode = acpi_fwnode_handle(args.adev); - pdev = hns_roce_find_pdev(fwnode); + pdev = hns_roce_find_pdev(args.fwnode); } else { dev_err(dev, "cannot read data from DT or ACPI\n"); return -ENXIO; |