mlx4: Modify proxy/tunnel QP mechanism so that guests do no calculations
[linux-2.6-block.git] / drivers / net / ethernet / mellanox / mlx4 / qp.c
index fb2b36759cbf657d66dfa7c245d49306d5a06c58..81e2abe07bbbf656689ba327ab0d4d22368961df 100644 (file)
@@ -67,10 +67,18 @@ void mlx4_qp_event(struct mlx4_dev *dev, u32 qpn, int event_type)
                complete(&qp->free);
 }
 
-static int is_qp0(struct mlx4_dev *dev, struct mlx4_qp *qp)
+/* used for INIT/CLOSE port logic */
+static int is_master_qp0(struct mlx4_dev *dev, struct mlx4_qp *qp, int *real_qp0, int *proxy_qp0)
 {
-       return qp->qpn >= dev->caps.sqp_start &&
-               qp->qpn <= dev->caps.sqp_start + 1;
+       /* this procedure is called after we already know we are on the master */
+       /* qp0 is either the proxy qp0, or the real qp0 */
+       u32 pf_proxy_offset = dev->phys_caps.base_proxy_sqpn + 8 * mlx4_master_func_num(dev);
+       *proxy_qp0 = qp->qpn >= pf_proxy_offset && qp->qpn <= pf_proxy_offset + 1;
+
+       *real_qp0 = qp->qpn >= dev->phys_caps.base_sqpn &&
+               qp->qpn <= dev->phys_caps.base_sqpn + 1;
+
+       return *real_qp0 || *proxy_qp0;
 }
 
 static int __mlx4_qp_modify(struct mlx4_dev *dev, struct mlx4_mtt *mtt,
@@ -122,6 +130,8 @@ static int __mlx4_qp_modify(struct mlx4_dev *dev, struct mlx4_mtt *mtt,
        struct mlx4_priv *priv = mlx4_priv(dev);
        struct mlx4_cmd_mailbox *mailbox;
        int ret = 0;
+       int real_qp0 = 0;
+       int proxy_qp0 = 0;
        u8 port;
 
        if (cur_state >= MLX4_QP_NUM_STATE || new_state >= MLX4_QP_NUM_STATE ||
@@ -133,9 +143,12 @@ static int __mlx4_qp_modify(struct mlx4_dev *dev, struct mlx4_mtt *mtt,
                        MLX4_CMD_2RST_QP, MLX4_CMD_TIME_CLASS_A, native);
                if (mlx4_is_master(dev) && cur_state != MLX4_QP_STATE_ERR &&
                    cur_state != MLX4_QP_STATE_RST &&
-                   is_qp0(dev, qp)) {
+                   is_master_qp0(dev, qp, &real_qp0, &proxy_qp0)) {
                        port = (qp->qpn & 1) + 1;
-                       priv->mfunc.master.qp0_state[port].qp0_active = 0;
+                       if (proxy_qp0)
+                               priv->mfunc.master.qp0_state[port].proxy_qp0_active = 0;
+                       else
+                               priv->mfunc.master.qp0_state[port].qp0_active = 0;
                }
                return ret;
        }
@@ -162,6 +175,23 @@ static int __mlx4_qp_modify(struct mlx4_dev *dev, struct mlx4_mtt *mtt,
                       new_state == MLX4_QP_STATE_RST ? 2 : 0,
                       op[cur_state][new_state], MLX4_CMD_TIME_CLASS_C, native);
 
+       if (mlx4_is_master(dev) && is_master_qp0(dev, qp, &real_qp0, &proxy_qp0)) {
+               port = (qp->qpn & 1) + 1;
+               if (cur_state != MLX4_QP_STATE_ERR &&
+                   cur_state != MLX4_QP_STATE_RST &&
+                   new_state == MLX4_QP_STATE_ERR) {
+                       if (proxy_qp0)
+                               priv->mfunc.master.qp0_state[port].proxy_qp0_active = 0;
+                       else
+                               priv->mfunc.master.qp0_state[port].qp0_active = 0;
+               } else if (new_state == MLX4_QP_STATE_RTR) {
+                       if (proxy_qp0)
+                               priv->mfunc.master.qp0_state[port].proxy_qp0_active = 1;
+                       else
+                               priv->mfunc.master.qp0_state[port].qp0_active = 1;
+               }
+       }
+
        mlx4_free_cmd_mailbox(dev, mailbox);
        return ret;
 }
@@ -392,6 +422,7 @@ int mlx4_init_qp_table(struct mlx4_dev *dev)
        struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table;
        int err;
        int reserved_from_top = 0;
+       int k;
 
        spin_lock_init(&qp_table->lock);
        INIT_RADIX_TREE(&dev->qp_table_tree, GFP_ATOMIC);
@@ -406,7 +437,7 @@ int mlx4_init_qp_table(struct mlx4_dev *dev)
         * We also reserve the MSB of the 24-bit QP number to indicate
         * that a QP is an XRC QP.
         */
-       dev->caps.sqp_start =
+       dev->phys_caps.base_sqpn =
                ALIGN(dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW], 8);
 
        {
@@ -437,13 +468,66 @@ int mlx4_init_qp_table(struct mlx4_dev *dev)
 
        }
 
+       /* Reserve 8 real SQPs in both native and SRIOV modes.
+       * In addition, in SRIOV mode, reserve 8 proxy SQPs per function
+       * (for all PFs and VFs), and 8 corresponding tunnel QPs.
+       * Each proxy SQP works opposite its own tunnel QP.
+       *
+       * The QPs are arranged as follows:
+       * a. 8 real SQPs
+       * b. All the proxy SQPs (8 per function)
+       * c. All the tunnel QPs (8 per function)
+       */
+
        err = mlx4_bitmap_init(&qp_table->bitmap, dev->caps.num_qps,
-                              (1 << 23) - 1, dev->caps.sqp_start + 8,
+                              (1 << 23) - 1, dev->phys_caps.base_sqpn + 8 +
+                              16 * MLX4_MFUNC_MAX * !!mlx4_is_master(dev),
                               reserved_from_top);
        if (err)
                return err;
 
-       return mlx4_CONF_SPECIAL_QP(dev, dev->caps.sqp_start);
+       if (mlx4_is_mfunc(dev)) {
+               /* for PPF use */
+               dev->phys_caps.base_proxy_sqpn = dev->phys_caps.base_sqpn + 8;
+               dev->phys_caps.base_tunnel_sqpn = dev->phys_caps.base_sqpn + 8 + 8 * MLX4_MFUNC_MAX;
+
+               /* In mfunc, calculate proxy and tunnel qp offsets for the PF here,
+                * since the PF does not call mlx4_slave_caps */
+               dev->caps.qp0_tunnel = kcalloc(dev->caps.num_ports, sizeof (u32), GFP_KERNEL);
+               dev->caps.qp0_proxy = kcalloc(dev->caps.num_ports, sizeof (u32), GFP_KERNEL);
+               dev->caps.qp1_tunnel = kcalloc(dev->caps.num_ports, sizeof (u32), GFP_KERNEL);
+               dev->caps.qp1_proxy = kcalloc(dev->caps.num_ports, sizeof (u32), GFP_KERNEL);
+
+               if (!dev->caps.qp0_tunnel || !dev->caps.qp0_proxy ||
+                   !dev->caps.qp1_tunnel || !dev->caps.qp1_proxy) {
+                       err = -ENOMEM;
+                       goto err_mem;
+               }
+
+               for (k = 0; k < dev->caps.num_ports; k++) {
+                       dev->caps.qp0_proxy[k] = dev->phys_caps.base_proxy_sqpn +
+                               8 * mlx4_master_func_num(dev) + k;
+                       dev->caps.qp0_tunnel[k] = dev->caps.qp0_proxy[k] + 8 * MLX4_MFUNC_MAX;
+                       dev->caps.qp1_proxy[k] = dev->phys_caps.base_proxy_sqpn +
+                               8 * mlx4_master_func_num(dev) + MLX4_MAX_PORTS + k;
+                       dev->caps.qp1_tunnel[k] = dev->caps.qp1_proxy[k] + 8 * MLX4_MFUNC_MAX;
+               }
+       }
+
+
+       err = mlx4_CONF_SPECIAL_QP(dev, dev->phys_caps.base_sqpn);
+       if (err)
+               goto err_mem;
+       return 0;
+
+err_mem:
+       kfree(dev->caps.qp0_tunnel);
+       kfree(dev->caps.qp0_proxy);
+       kfree(dev->caps.qp1_tunnel);
+       kfree(dev->caps.qp1_proxy);
+       dev->caps.qp0_tunnel = dev->caps.qp0_proxy =
+               dev->caps.qp1_tunnel = dev->caps.qp1_proxy = NULL;
+       return err;
 }
 
 void mlx4_cleanup_qp_table(struct mlx4_dev *dev)