Merge branches 'hfi1' and 'iw_cxgb4' into k.o/for-4.7
[cascardo/linux.git] / drivers / staging / rdma / hfi1 / verbs.c
index 89f2aad..9cdc85f 100644 (file)
@@ -545,7 +545,7 @@ static inline int qp_ok(int opcode, struct hfi1_packet *packet)
 
        if (!(ib_rvt_state_ops[packet->qp->state] & RVT_PROCESS_RECV_OK))
                goto dropit;
-       if (((opcode & OPCODE_QP_MASK) == packet->qp->allowed_ops) ||
+       if (((opcode & RVT_OPCODE_QP_MASK) == packet->qp->allowed_ops) ||
            (opcode == IB_OPCODE_CNP))
                return 1;
 dropit:
@@ -1089,16 +1089,16 @@ bail:
 
 /*
  * egress_pkey_matches_entry - return 1 if the pkey matches ent (ent
- * being an entry from the ingress partition key table), return 0
+ * being an entry from the partition key table), return 0
  * otherwise. Use the matching criteria for egress partition keys
  * specified in the OPAv1 spec., section 9.1l.7.
  */
 static inline int egress_pkey_matches_entry(u16 pkey, u16 ent)
 {
        u16 mkey = pkey & PKEY_LOW_15_MASK;
-       u16 ment = ent & PKEY_LOW_15_MASK;
+       u16 mentry = ent & PKEY_LOW_15_MASK;
 
-       if (mkey == ment) {
+       if (mkey == mentry) {
                /*
                 * If pkey[15] is set (full partition member),
                 * is bit 15 in the corresponding table element
@@ -1111,32 +1111,32 @@ static inline int egress_pkey_matches_entry(u16 pkey, u16 ent)
        return 0;
 }
 
-/*
- * egress_pkey_check - return 0 if hdr's pkey matches according to the
- * criteria in the OPAv1 spec., section 9.11.7.
+/**
+ * egress_pkey_check - check P_KEY of a packet
+ * @ppd:    Physical IB port data
+ * @lrh: Local route header
+ * @bth: Base transport header
+ * @sc5:    SC for packet
+ * @s_pkey_index: It will be used for look up optimization for kernel contexts
+ * only. If it is negative value, then it means user contexts is calling this
+ * function.
+ *
+ * It checks if hdr's pkey is valid.
+ *
+ * Return: 0 on success, otherwise, 1
  */
-static inline int egress_pkey_check(struct hfi1_pportdata *ppd,
-                                   struct hfi1_ib_header *hdr,
-                                   struct rvt_qp *qp)
+int egress_pkey_check(struct hfi1_pportdata *ppd, __be16 *lrh, __be32 *bth,
+                     u8 sc5, int8_t s_pkey_index)
 {
-       struct hfi1_qp_priv *priv = qp->priv;
-       struct hfi1_other_headers *ohdr;
        struct hfi1_devdata *dd;
-       int i = 0;
+       int i;
        u16 pkey;
-       u8 lnh, sc5 = priv->s_sc;
+       int is_user_ctxt_mechanism = (s_pkey_index < 0);
 
        if (!(ppd->part_enforce & HFI1_PART_ENFORCE_OUT))
                return 0;
 
-       /* locate the pkey within the headers */
-       lnh = be16_to_cpu(hdr->lrh[0]) & 3;
-       if (lnh == HFI1_LRH_GRH)
-               ohdr = &hdr->u.l.oth;
-       else
-               ohdr = &hdr->u.oth;
-
-       pkey = (u16)be32_to_cpu(ohdr->bth[0]);
+       pkey = (u16)be32_to_cpu(bth[0]);
 
        /* If SC15, pkey[0:14] must be 0x7fff */
        if ((sc5 == 0xf) && ((pkey & PKEY_LOW_15_MASK) != PKEY_LOW_15_MASK))
@@ -1146,28 +1146,37 @@ static inline int egress_pkey_check(struct hfi1_pportdata *ppd,
        if ((pkey & PKEY_LOW_15_MASK) == 0)
                goto bad;
 
-       /* The most likely matching pkey has index qp->s_pkey_index */
-       if (unlikely(!egress_pkey_matches_entry(pkey,
-                                               ppd->pkeys
-                                               [qp->s_pkey_index]))) {
-               /* no match - try the entire table */
-               for (; i < MAX_PKEY_VALUES; i++) {
-                       if (egress_pkey_matches_entry(pkey, ppd->pkeys[i]))
-                               break;
-               }
+       /*
+        * For the kernel contexts only, if a qp is passed into the function,
+        * the most likely matching pkey has index qp->s_pkey_index
+        */
+       if (!is_user_ctxt_mechanism &&
+           egress_pkey_matches_entry(pkey, ppd->pkeys[s_pkey_index])) {
+               return 0;
        }
 
-       if (i < MAX_PKEY_VALUES)
-               return 0;
+       for (i = 0; i < MAX_PKEY_VALUES; i++) {
+               if (egress_pkey_matches_entry(pkey, ppd->pkeys[i]))
+                       return 0;
+       }
 bad:
-       incr_cntr64(&ppd->port_xmit_constraint_errors);
-       dd = ppd->dd;
-       if (!(dd->err_info_xmit_constraint.status & OPA_EI_STATUS_SMASK)) {
-               u16 slid = be16_to_cpu(hdr->lrh[3]);
-
-               dd->err_info_xmit_constraint.status |= OPA_EI_STATUS_SMASK;
-               dd->err_info_xmit_constraint.slid = slid;
-               dd->err_info_xmit_constraint.pkey = pkey;
+       /*
+        * For the user-context mechanism, the P_KEY check would only happen
+        * once per SDMA request, not once per packet.  Therefore, there's no
+        * need to increment the counter for the user-context mechanism.
+        */
+       if (!is_user_ctxt_mechanism) {
+               incr_cntr64(&ppd->port_xmit_constraint_errors);
+               dd = ppd->dd;
+               if (!(dd->err_info_xmit_constraint.status &
+                     OPA_EI_STATUS_SMASK)) {
+                       u16 slid = be16_to_cpu(lrh[3]);
+
+                       dd->err_info_xmit_constraint.status |=
+                               OPA_EI_STATUS_SMASK;
+                       dd->err_info_xmit_constraint.slid = slid;
+                       dd->err_info_xmit_constraint.pkey = pkey;
+               }
        }
        return 1;
 }
@@ -1227,11 +1236,26 @@ int hfi1_verbs_send(struct rvt_qp *qp, struct hfi1_pkt_state *ps)
 {
        struct hfi1_devdata *dd = dd_from_ibdev(qp->ibqp.device);
        struct hfi1_qp_priv *priv = qp->priv;
+       struct hfi1_other_headers *ohdr;
+       struct hfi1_ib_header *hdr;
        send_routine sr;
        int ret;
+       u8 lnh;
+
+       hdr = &ps->s_txreq->phdr.hdr;
+       /* locate the pkey within the headers */
+       lnh = be16_to_cpu(hdr->lrh[0]) & 3;
+       if (lnh == HFI1_LRH_GRH)
+               ohdr = &hdr->u.l.oth;
+       else
+               ohdr = &hdr->u.oth;
 
        sr = get_send_routine(qp, ps->s_txreq);
-       ret = egress_pkey_check(dd->pport, &ps->s_txreq->phdr.hdr, qp);
+       ret = egress_pkey_check(dd->pport,
+                               hdr->lrh,
+                               ohdr->bth,
+                               priv->s_sc,
+                               qp->s_pkey_index);
        if (unlikely(ret)) {
                /*
                 * The value we are returning here does not get propagated to