There are three conditions that must be fulfilled in order to consider a partition match. Those are: 1. Both P_Keys must valid 2. At least one must be a full member 3. The partitions (lower 15 bits) must match In system employing both limited and full membership ports, we see these false warning messages: RDMA CMA: got different BTH P_Key (0x2a00) and primary path P_Key (0xaa00) RDMA CMA: in the future this may cause the request to be dropped even though the partition is the same. See IBTA 10.9.1.2 Special P_Keys and 10.9.3 Partition Key Matching for a reference. Fixes: 84424a7fc793 ("IB/cma: Print warning on different inner and header P_Keys") Signed-off-by: Håkon Bugge <haakon.bugge@xxxxxxxxxx> --- drivers/infiniband/core/cma.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 2b9ffc2..f5bcf7d 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -1368,6 +1368,24 @@ static int cma_save_net_info(struct sockaddr *src_addr, return cma_save_ip_info(src_addr, dst_addr, ib_event, service_id); } +/* + * If at least one of the pkeys is a full member, none of them are + * invalid, and the partitions (lower 15 bits) are equal, we have a + * match. + * + * See IBTA 10.9.1.2 Special P_Keys and 10.9.3 Partition Key Matching + */ + +static bool partition_match(u16 pkey_a, u16 pkey_b) +{ + const u16 fmb = 0x8000; /* Full Member Bit */ + const bool valid_pkeys = (pkey_a & ~fmb) && (pkey_b & ~fmb); + const bool one_full = (pkey_a | pkey_b) & fmb; + const bool same_partition = (pkey_a | fmb) == (pkey_b | fmb); + + return valid_pkeys && one_full && same_partition; +} + static int cma_save_req_info(const struct ib_cm_event *ib_event, struct cma_req_info *req) { @@ -1385,7 +1403,7 @@ static int cma_save_req_info(const struct ib_cm_event *ib_event, req->has_gid = true; req->service_id = req_param->primary_path->service_id; req->pkey = be16_to_cpu(req_param->primary_path->pkey); - if (req->pkey != req_param->bth_pkey) + if (!partition_match(req->pkey, req_param->bth_pkey)) pr_warn_ratelimited("RDMA CMA: got different BTH P_Key (0x%x) and primary path P_Key (0x%x)\n" "RDMA CMA: in the future this may cause the request to be dropped\n", req_param->bth_pkey, req->pkey); @@ -1396,7 +1414,7 @@ static int cma_save_req_info(const struct ib_cm_event *ib_event, req->has_gid = false; req->service_id = sidr_param->service_id; req->pkey = sidr_param->pkey; - if (req->pkey != sidr_param->bth_pkey) + if (!partition_match(req->pkey, sidr_param->bth_pkey)) pr_warn_ratelimited("RDMA CMA: got different BTH P_Key (0x%x) and SIDR request payload P_Key (0x%x)\n" "RDMA CMA: in the future this may cause the request to be dropped\n", sidr_param->bth_pkey, req->pkey); -- 1.8.3.1