IB: Add ib_modify_qp_is_ok() library function
authorRoland Dreier <rolandd@cisco.com>
Mon, 13 Feb 2006 20:48:12 +0000 (12:48 -0800)
committerRoland Dreier <rolandd@cisco.com>
Mon, 20 Mar 2006 18:08:12 +0000 (10:08 -0800)
The in-kernel mthca driver contains a table of which attributes are
valid for each queue pair state transition.  It turns out that both
other IB drivers -- ipath and ehca -- which are being prepared for
merging have copied this table, errors and all.

To forestall this code duplication, move this table and the code to
check parameters against it into a midlayer library function,
ib_modify_qp_is_ok().

Signed-off-by: Roland Dreier <rolandd@cisco.com>
drivers/infiniband/core/verbs.c
include/rdma/ib_verbs.h

index 8e0ba16..ca07a2b 100644 (file)
@@ -245,6 +245,258 @@ struct ib_qp *ib_create_qp(struct ib_pd *pd,
 }
 EXPORT_SYMBOL(ib_create_qp);
 
+static const struct {
+       int                     valid;
+       enum ib_qp_attr_mask    req_param[IB_QPT_RAW_ETY + 1];
+       enum ib_qp_attr_mask    opt_param[IB_QPT_RAW_ETY + 1];
+} qp_state_table[IB_QPS_ERR + 1][IB_QPS_ERR + 1] = {
+       [IB_QPS_RESET] = {
+               [IB_QPS_RESET] = { .valid = 1 },
+               [IB_QPS_ERR]   = { .valid = 1 },
+               [IB_QPS_INIT]  = {
+                       .valid = 1,
+                       .req_param = {
+                               [IB_QPT_UD]  = (IB_QP_PKEY_INDEX                |
+                                               IB_QP_PORT                      |
+                                               IB_QP_QKEY),
+                               [IB_QPT_UC]  = (IB_QP_PKEY_INDEX                |
+                                               IB_QP_PORT                      |
+                                               IB_QP_ACCESS_FLAGS),
+                               [IB_QPT_RC]  = (IB_QP_PKEY_INDEX                |
+                                               IB_QP_PORT                      |
+                                               IB_QP_ACCESS_FLAGS),
+                               [IB_QPT_SMI] = (IB_QP_PKEY_INDEX                |
+                                               IB_QP_QKEY),
+                               [IB_QPT_GSI] = (IB_QP_PKEY_INDEX                |
+                                               IB_QP_QKEY),
+                       }
+               },
+       },
+       [IB_QPS_INIT]  = {
+               [IB_QPS_RESET] = { .valid = 1 },
+               [IB_QPS_ERR] =   { .valid = 1 },
+               [IB_QPS_INIT]  = {
+                       .valid = 1,
+                       .opt_param = {
+                               [IB_QPT_UD]  = (IB_QP_PKEY_INDEX                |
+                                               IB_QP_PORT                      |
+                                               IB_QP_QKEY),
+                               [IB_QPT_UC]  = (IB_QP_PKEY_INDEX                |
+                                               IB_QP_PORT                      |
+                                               IB_QP_ACCESS_FLAGS),
+                               [IB_QPT_RC]  = (IB_QP_PKEY_INDEX                |
+                                               IB_QP_PORT                      |
+                                               IB_QP_ACCESS_FLAGS),
+                               [IB_QPT_SMI] = (IB_QP_PKEY_INDEX                |
+                                               IB_QP_QKEY),
+                               [IB_QPT_GSI] = (IB_QP_PKEY_INDEX                |
+                                               IB_QP_QKEY),
+                       }
+               },
+               [IB_QPS_RTR]   = {
+                       .valid = 1,
+                       .req_param = {
+                               [IB_QPT_UC]  = (IB_QP_AV                        |
+                                               IB_QP_PATH_MTU                  |
+                                               IB_QP_DEST_QPN                  |
+                                               IB_QP_RQ_PSN),
+                               [IB_QPT_RC]  = (IB_QP_AV                        |
+                                               IB_QP_PATH_MTU                  |
+                                               IB_QP_DEST_QPN                  |
+                                               IB_QP_RQ_PSN                    |
+                                               IB_QP_MAX_DEST_RD_ATOMIC        |
+                                               IB_QP_MIN_RNR_TIMER),
+                       },
+                       .opt_param = {
+                                [IB_QPT_UD]  = (IB_QP_PKEY_INDEX               |
+                                                IB_QP_QKEY),
+                                [IB_QPT_UC]  = (IB_QP_ALT_PATH                 |
+                                                IB_QP_ACCESS_FLAGS             |
+                                                IB_QP_PKEY_INDEX),
+                                [IB_QPT_RC]  = (IB_QP_ALT_PATH                 |
+                                                IB_QP_ACCESS_FLAGS             |
+                                                IB_QP_PKEY_INDEX),
+                                [IB_QPT_SMI] = (IB_QP_PKEY_INDEX               |
+                                                IB_QP_QKEY),
+                                [IB_QPT_GSI] = (IB_QP_PKEY_INDEX               |
+                                                IB_QP_QKEY),
+                        }
+               }
+       },
+       [IB_QPS_RTR]   = {
+               [IB_QPS_RESET] = { .valid = 1 },
+               [IB_QPS_ERR] =   { .valid = 1 },
+               [IB_QPS_RTS]   = {
+                       .valid = 1,
+                       .req_param = {
+                               [IB_QPT_UD]  = IB_QP_SQ_PSN,
+                               [IB_QPT_UC]  = IB_QP_SQ_PSN,
+                               [IB_QPT_RC]  = (IB_QP_TIMEOUT                   |
+                                               IB_QP_RETRY_CNT                 |
+                                               IB_QP_RNR_RETRY                 |
+                                               IB_QP_SQ_PSN                    |
+                                               IB_QP_MAX_QP_RD_ATOMIC),
+                               [IB_QPT_SMI] = IB_QP_SQ_PSN,
+                               [IB_QPT_GSI] = IB_QP_SQ_PSN,
+                       },
+                       .opt_param = {
+                                [IB_QPT_UD]  = (IB_QP_CUR_STATE                |
+                                                IB_QP_QKEY),
+                                [IB_QPT_UC]  = (IB_QP_CUR_STATE                |
+                                                IB_QP_ALT_PATH                 |
+                                                IB_QP_ACCESS_FLAGS             |
+                                                IB_QP_PATH_MIG_STATE),
+                                [IB_QPT_RC]  = (IB_QP_CUR_STATE                |
+                                                IB_QP_ALT_PATH                 |
+                                                IB_QP_ACCESS_FLAGS             |
+                                                IB_QP_MIN_RNR_TIMER            |
+                                                IB_QP_PATH_MIG_STATE),
+                                [IB_QPT_SMI] = (IB_QP_CUR_STATE                |
+                                                IB_QP_QKEY),
+                                [IB_QPT_GSI] = (IB_QP_CUR_STATE                |
+                                                IB_QP_QKEY),
+                        }
+               }
+       },
+       [IB_QPS_RTS]   = {
+               [IB_QPS_RESET] = { .valid = 1 },
+               [IB_QPS_ERR] =   { .valid = 1 },
+               [IB_QPS_RTS]   = {
+                       .valid = 1,
+                       .opt_param = {
+                               [IB_QPT_UD]  = (IB_QP_CUR_STATE                 |
+                                               IB_QP_QKEY),
+                               [IB_QPT_UC]  = (IB_QP_ACCESS_FLAGS              |
+                                               IB_QP_ALT_PATH                  |
+                                               IB_QP_PATH_MIG_STATE),
+                               [IB_QPT_RC]  = (IB_QP_ACCESS_FLAGS              |
+                                               IB_QP_ALT_PATH                  |
+                                               IB_QP_PATH_MIG_STATE            |
+                                               IB_QP_MIN_RNR_TIMER),
+                               [IB_QPT_SMI] = (IB_QP_CUR_STATE                 |
+                                               IB_QP_QKEY),
+                               [IB_QPT_GSI] = (IB_QP_CUR_STATE                 |
+                                               IB_QP_QKEY),
+                       }
+               },
+               [IB_QPS_SQD]   = {
+                       .valid = 1,
+                       .opt_param = {
+                               [IB_QPT_UD]  = IB_QP_EN_SQD_ASYNC_NOTIFY,
+                               [IB_QPT_UC]  = IB_QP_EN_SQD_ASYNC_NOTIFY,
+                               [IB_QPT_RC]  = IB_QP_EN_SQD_ASYNC_NOTIFY,
+                               [IB_QPT_SMI] = IB_QP_EN_SQD_ASYNC_NOTIFY,
+                               [IB_QPT_GSI] = IB_QP_EN_SQD_ASYNC_NOTIFY
+                       }
+               },
+       },
+       [IB_QPS_SQD]   = {
+               [IB_QPS_RESET] = { .valid = 1 },
+               [IB_QPS_ERR] =   { .valid = 1 },
+               [IB_QPS_RTS]   = {
+                       .valid = 1,
+                       .opt_param = {
+                               [IB_QPT_UD]  = (IB_QP_CUR_STATE                 |
+                                               IB_QP_QKEY),
+                               [IB_QPT_UC]  = (IB_QP_CUR_STATE                 |
+                                               IB_QP_ALT_PATH                  |
+                                               IB_QP_ACCESS_FLAGS              |
+                                               IB_QP_PATH_MIG_STATE),
+                               [IB_QPT_RC]  = (IB_QP_CUR_STATE                 |
+                                               IB_QP_ALT_PATH                  |
+                                               IB_QP_ACCESS_FLAGS              |
+                                               IB_QP_MIN_RNR_TIMER             |
+                                               IB_QP_PATH_MIG_STATE),
+                               [IB_QPT_SMI] = (IB_QP_CUR_STATE                 |
+                                               IB_QP_QKEY),
+                               [IB_QPT_GSI] = (IB_QP_CUR_STATE                 |
+                                               IB_QP_QKEY),
+                       }
+               },
+               [IB_QPS_SQD]   = {
+                       .valid = 1,
+                       .opt_param = {
+                               [IB_QPT_UD]  = (IB_QP_PKEY_INDEX                |
+                                               IB_QP_QKEY),
+                               [IB_QPT_UC]  = (IB_QP_AV                        |
+                                               IB_QP_CUR_STATE                 |
+                                               IB_QP_ALT_PATH                  |
+                                               IB_QP_ACCESS_FLAGS              |
+                                               IB_QP_PKEY_INDEX                |
+                                               IB_QP_PATH_MIG_STATE),
+                               [IB_QPT_RC]  = (IB_QP_PORT                      |
+                                               IB_QP_AV                        |
+                                               IB_QP_TIMEOUT                   |
+                                               IB_QP_RETRY_CNT                 |
+                                               IB_QP_RNR_RETRY                 |
+                                               IB_QP_MAX_QP_RD_ATOMIC          |
+                                               IB_QP_MAX_DEST_RD_ATOMIC        |
+                                               IB_QP_CUR_STATE                 |
+                                               IB_QP_ALT_PATH                  |
+                                               IB_QP_ACCESS_FLAGS              |
+                                               IB_QP_PKEY_INDEX                |
+                                               IB_QP_MIN_RNR_TIMER             |
+                                               IB_QP_PATH_MIG_STATE),
+                               [IB_QPT_SMI] = (IB_QP_PKEY_INDEX                |
+                                               IB_QP_QKEY),
+                               [IB_QPT_GSI] = (IB_QP_PKEY_INDEX                |
+                                               IB_QP_QKEY),
+                       }
+               }
+       },
+       [IB_QPS_SQE]   = {
+               [IB_QPS_RESET] = { .valid = 1 },
+               [IB_QPS_ERR] =   { .valid = 1 },
+               [IB_QPS_RTS]   = {
+                       .valid = 1,
+                       .opt_param = {
+                               [IB_QPT_UD]  = (IB_QP_CUR_STATE                 |
+                                               IB_QP_QKEY),
+                               [IB_QPT_UC]  = (IB_QP_CUR_STATE                 |
+                                               IB_QP_ACCESS_FLAGS),
+                               [IB_QPT_SMI] = (IB_QP_CUR_STATE                 |
+                                               IB_QP_QKEY),
+                               [IB_QPT_GSI] = (IB_QP_CUR_STATE                 |
+                                               IB_QP_QKEY),
+                       }
+               }
+       },
+       [IB_QPS_ERR] = {
+               [IB_QPS_RESET] = { .valid = 1 },
+               [IB_QPS_ERR] =   { .valid = 1 }
+       }
+};
+
+int ib_modify_qp_is_ok(enum ib_qp_state cur_state, enum ib_qp_state next_state,
+                      enum ib_qp_type type, enum ib_qp_attr_mask mask)
+{
+       enum ib_qp_attr_mask req_param, opt_param;
+
+       if (cur_state  < 0 || cur_state  > IB_QPS_ERR ||
+           next_state < 0 || next_state > IB_QPS_ERR)
+               return 0;
+
+       if (mask & IB_QP_CUR_STATE  &&
+           cur_state != IB_QPS_RTR && cur_state != IB_QPS_RTS &&
+           cur_state != IB_QPS_SQD && cur_state != IB_QPS_SQE)
+               return 0;
+
+       if (!qp_state_table[cur_state][next_state].valid)
+               return 0;
+
+       req_param = qp_state_table[cur_state][next_state].req_param[type];
+       opt_param = qp_state_table[cur_state][next_state].opt_param[type];
+
+       if ((mask & req_param) != req_param)
+               return 0;
+
+       if (mask & ~(req_param | opt_param | IB_QP_STATE))
+               return 0;
+
+       return 1;
+}
+EXPORT_SYMBOL(ib_modify_qp_is_ok);
+
 int ib_modify_qp(struct ib_qp *qp,
                 struct ib_qp_attr *qp_attr,
                 int qp_attr_mask)
index 61a4390..010287c 100644 (file)
@@ -990,6 +990,24 @@ static inline int ib_copy_to_udata(struct ib_udata *udata, void *src, size_t len
        return copy_to_user(udata->outbuf, src, len) ? -EFAULT : 0;
 }
 
+/**
+ * ib_modify_qp_is_ok - Check that the supplied attribute mask
+ * contains all required attributes and no attributes not allowed for
+ * the given QP state transition.
+ * @cur_state: Current QP state
+ * @next_state: Next QP state
+ * @type: QP type
+ * @mask: Mask of supplied QP attributes
+ *
+ * This function is a helper function that a low-level driver's
+ * modify_qp method can use to validate the consumer's input.  It
+ * checks that cur_state and next_state are valid QP states, that a
+ * transition from cur_state to next_state is allowed by the IB spec,
+ * and that the attribute mask supplied is allowed for the transition.
+ */
+int ib_modify_qp_is_ok(enum ib_qp_state cur_state, enum ib_qp_state next_state,
+                      enum ib_qp_type type, enum ib_qp_attr_mask mask);
+
 int ib_register_event_handler  (struct ib_event_handler *event_handler);
 int ib_unregister_event_handler(struct ib_event_handler *event_handler);
 void ib_dispatch_event(struct ib_event *event);