IB/mlx4: Optimize do_slave_init
[linux-2.6-microblaze.git] / drivers / infiniband / hw / mlx4 / main.c
index cc64400..8be6db8 100644 (file)
@@ -132,14 +132,35 @@ static int num_ib_ports(struct mlx4_dev *dev)
 }
 
 static int mlx4_ib_query_device(struct ib_device *ibdev,
-                               struct ib_device_attr *props)
+                               struct ib_device_attr *props,
+                               struct ib_udata *uhw)
 {
        struct mlx4_ib_dev *dev = to_mdev(ibdev);
        struct ib_smp *in_mad  = NULL;
        struct ib_smp *out_mad = NULL;
        int err = -ENOMEM;
        int have_ib_ports;
+       struct mlx4_uverbs_ex_query_device cmd;
+       struct mlx4_uverbs_ex_query_device_resp resp = {.comp_mask = 0};
+       struct mlx4_clock_params clock_params;
 
+       if (uhw->inlen) {
+               if (uhw->inlen < sizeof(cmd))
+                       return -EINVAL;
+
+               err = ib_copy_from_udata(&cmd, uhw, sizeof(cmd));
+               if (err)
+                       return err;
+
+               if (cmd.comp_mask)
+                       return -EINVAL;
+
+               if (cmd.reserved)
+                       return -EINVAL;
+       }
+
+       resp.response_length = offsetof(typeof(resp), response_length) +
+               sizeof(resp.response_length);
        in_mad  = kzalloc(sizeof *in_mad, GFP_KERNEL);
        out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL);
        if (!in_mad || !out_mad)
@@ -229,7 +250,25 @@ static int mlx4_ib_query_device(struct ib_device *ibdev,
        props->max_total_mcast_qp_attach = props->max_mcast_qp_attach *
                                           props->max_mcast_grp;
        props->max_map_per_fmr = dev->dev->caps.max_fmr_maps;
+       props->hca_core_clock = dev->dev->caps.hca_core_clock * 1000UL;
+       props->timestamp_mask = 0xFFFFFFFFFFFFULL;
 
+       if (!mlx4_is_slave(dev->dev))
+               err = mlx4_get_internal_clock_params(dev->dev, &clock_params);
+
+       if (uhw->outlen >= resp.response_length + sizeof(resp.hca_core_clock_offset)) {
+               resp.response_length += sizeof(resp.hca_core_clock_offset);
+               if (!err && !mlx4_is_slave(dev->dev)) {
+                       resp.comp_mask |= QUERY_DEVICE_RESP_MASK_TIMESTAMP;
+                       resp.hca_core_clock_offset = clock_params.offset % PAGE_SIZE;
+               }
+       }
+
+       if (uhw->outlen) {
+               err = ib_copy_to_udata(uhw, &resp, resp.response_length);
+               if (err)
+                       goto out;
+       }
 out:
        kfree(in_mad);
        kfree(out_mad);
@@ -712,8 +751,24 @@ static int mlx4_ib_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
                                       dev->dev->caps.num_uars,
                                       PAGE_SIZE, vma->vm_page_prot))
                        return -EAGAIN;
-       } else
+       } else if (vma->vm_pgoff == 3) {
+               struct mlx4_clock_params params;
+               int ret = mlx4_get_internal_clock_params(dev->dev, &params);
+
+               if (ret)
+                       return ret;
+
+               vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+               if (io_remap_pfn_range(vma, vma->vm_start,
+                                      (pci_resource_start(dev->dev->persist->pdev,
+                                                          params.bar) +
+                                       params.offset)
+                                      >> PAGE_SHIFT,
+                                      PAGE_SIZE, vma->vm_page_prot))
+                       return -EAGAIN;
+       } else {
                return -EINVAL;
+       }
 
        return 0;
 }
@@ -758,6 +813,7 @@ static struct ib_xrcd *mlx4_ib_alloc_xrcd(struct ib_device *ibdev,
                                          struct ib_udata *udata)
 {
        struct mlx4_ib_xrcd *xrcd;
+       struct ib_cq_init_attr cq_attr = {};
        int err;
 
        if (!(to_mdev(ibdev)->dev->caps.flags & MLX4_DEV_CAP_FLAG_XRC))
@@ -777,7 +833,8 @@ static struct ib_xrcd *mlx4_ib_alloc_xrcd(struct ib_device *ibdev,
                goto err2;
        }
 
-       xrcd->cq = ib_create_cq(ibdev, NULL, NULL, xrcd, 1, 0);
+       cq_attr.cqe = 1;
+       xrcd->cq = ib_create_cq(ibdev, NULL, NULL, xrcd, &cq_attr);
        if (IS_ERR(xrcd->cq)) {
                err = PTR_ERR(xrcd->cq);
                goto err3;
@@ -1090,7 +1147,7 @@ static int __mlx4_ib_create_flow(struct ib_qp *qp, struct ib_flow_attr *flow_att
 
        ret = mlx4_cmd_imm(mdev->dev, mailbox->dma, reg_id, size >> 2, 0,
                           MLX4_QP_FLOW_STEERING_ATTACH, MLX4_CMD_TIME_CLASS_A,
-                          MLX4_CMD_NATIVE);
+                          MLX4_CMD_WRAPPED);
        if (ret == -ENOMEM)
                pr_err("mcg table is full. Fail to register network rule.\n");
        else if (ret == -ENXIO)
@@ -1107,7 +1164,7 @@ static int __mlx4_ib_destroy_flow(struct mlx4_dev *dev, u64 reg_id)
        int err;
        err = mlx4_cmd(dev, reg_id, 0, 0,
                       MLX4_QP_FLOW_STEERING_DETACH, MLX4_CMD_TIME_CLASS_A,
-                      MLX4_CMD_NATIVE);
+                      MLX4_CMD_WRAPPED);
        if (err)
                pr_err("Fail to detach network rule. registration id = 0x%llx\n",
                       reg_id);
@@ -1185,7 +1242,6 @@ static struct ib_flow *mlx4_ib_create_flow(struct ib_qp *qp,
                                            &mflow->reg_id[i].id);
                if (err)
                        goto err_create_flow;
-               i++;
                if (is_bonded) {
                        /* Application always sees one port so the mirror rule
                         * must be on port #2
@@ -1200,6 +1256,7 @@ static struct ib_flow *mlx4_ib_create_flow(struct ib_qp *qp,
                        j++;
                }
 
+               i++;
        }
 
        if (i < ARRAY_SIZE(type) && flow_attr->type == IB_FLOW_ATTR_NORMAL) {
@@ -1207,7 +1264,7 @@ static struct ib_flow *mlx4_ib_create_flow(struct ib_qp *qp,
                                               &mflow->reg_id[i].id);
                if (err)
                        goto err_create_flow;
-               i++;
+
                if (is_bonded) {
                        flow_attr->port = 2;
                        err = mlx4_ib_tunnel_steer_add(qp, flow_attr,
@@ -1218,6 +1275,7 @@ static struct ib_flow *mlx4_ib_create_flow(struct ib_qp *qp,
                        j++;
                }
                /* function to create mirror rule */
+               i++;
        }
 
        return &mflow->ibflow;
@@ -2041,77 +2099,75 @@ static void init_pkeys(struct mlx4_ib_dev *ibdev)
 
 static void mlx4_ib_alloc_eqs(struct mlx4_dev *dev, struct mlx4_ib_dev *ibdev)
 {
-       char name[80];
-       int eq_per_port = 0;
-       int added_eqs = 0;
-       int total_eqs = 0;
-       int i, j, eq;
+       int i, j, eq = 0, total_eqs = 0;
 
-       /* Legacy mode or comp_pool is not large enough */
-       if (dev->caps.comp_pool == 0 ||
-           dev->caps.num_ports > dev->caps.comp_pool)
-               return;
-
-       eq_per_port = dev->caps.comp_pool / dev->caps.num_ports;
-
-       /* Init eq table */
-       added_eqs = 0;
-       mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_IB)
-               added_eqs += eq_per_port;
-
-       total_eqs = dev->caps.num_comp_vectors + added_eqs;
-
-       ibdev->eq_table = kzalloc(total_eqs * sizeof(int), GFP_KERNEL);
+       ibdev->eq_table = kcalloc(dev->caps.num_comp_vectors,
+                                 sizeof(ibdev->eq_table[0]), GFP_KERNEL);
        if (!ibdev->eq_table)
                return;
 
-       ibdev->eq_added = added_eqs;
-
-       eq = 0;
-       mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_IB) {
-               for (j = 0; j < eq_per_port; j++) {
-                       snprintf(name, sizeof(name), "mlx4-ib-%d-%d@%s",
-                                i, j, dev->persist->pdev->bus->name);
-                       /* Set IRQ for specific name (per ring) */
-                       if (mlx4_assign_eq(dev, name, NULL,
-                                          &ibdev->eq_table[eq])) {
-                               /* Use legacy (same as mlx4_en driver) */
-                               pr_warn("Can't allocate EQ %d; reverting to legacy\n", eq);
-                               ibdev->eq_table[eq] =
-                                       (eq % dev->caps.num_comp_vectors);
-                       }
-                       eq++;
+       for (i = 1; i <= dev->caps.num_ports; i++) {
+               for (j = 0; j < mlx4_get_eqs_per_port(dev, i);
+                    j++, total_eqs++) {
+                       if (i > 1 &&  mlx4_is_eq_shared(dev, total_eqs))
+                               continue;
+                       ibdev->eq_table[eq] = total_eqs;
+                       if (!mlx4_assign_eq(dev, i,
+                                           &ibdev->eq_table[eq]))
+                               eq++;
+                       else
+                               ibdev->eq_table[eq] = -1;
                }
        }
 
-       /* Fill the reset of the vector with legacy EQ */
-       for (i = 0, eq = added_eqs; i < dev->caps.num_comp_vectors; i++)
-               ibdev->eq_table[eq++] = i;
+       for (i = eq; i < dev->caps.num_comp_vectors;
+            ibdev->eq_table[i++] = -1)
+               ;
 
        /* Advertise the new number of EQs to clients */
-       ibdev->ib_dev.num_comp_vectors = total_eqs;
+       ibdev->ib_dev.num_comp_vectors = eq;
 }
 
 static void mlx4_ib_free_eqs(struct mlx4_dev *dev, struct mlx4_ib_dev *ibdev)
 {
        int i;
+       int total_eqs = ibdev->ib_dev.num_comp_vectors;
 
-       /* no additional eqs were added */
+       /* no eqs were allocated */
        if (!ibdev->eq_table)
                return;
 
        /* Reset the advertised EQ number */
-       ibdev->ib_dev.num_comp_vectors = dev->caps.num_comp_vectors;
+       ibdev->ib_dev.num_comp_vectors = 0;
 
-       /* Free only the added eqs */
-       for (i = 0; i < ibdev->eq_added; i++) {
-               /* Don't free legacy eqs if used */
-               if (ibdev->eq_table[i] <= dev->caps.num_comp_vectors)
-                       continue;
+       for (i = 0; i < total_eqs; i++)
                mlx4_release_eq(dev, ibdev->eq_table[i]);
-       }
 
        kfree(ibdev->eq_table);
+       ibdev->eq_table = NULL;
+}
+
+static int mlx4_port_immutable(struct ib_device *ibdev, u8 port_num,
+                              struct ib_port_immutable *immutable)
+{
+       struct ib_port_attr attr;
+       int err;
+
+       err = mlx4_ib_query_port(ibdev, port_num, &attr);
+       if (err)
+               return err;
+
+       immutable->pkey_tbl_len = attr.pkey_tbl_len;
+       immutable->gid_tbl_len = attr.gid_tbl_len;
+
+       if (mlx4_ib_port_link_layer(ibdev, port_num) == IB_LINK_LAYER_INFINIBAND)
+               immutable->core_cap_flags = RDMA_CORE_PORT_IBA_IB;
+       else
+               immutable->core_cap_flags = RDMA_CORE_PORT_IBA_ROCE;
+
+       immutable->max_mad_size = IB_MGMT_MAD_SIZE;
+
+       return 0;
 }
 
 static void *mlx4_ib_add(struct mlx4_dev *dev)
@@ -2123,6 +2179,8 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
        struct mlx4_ib_iboe *iboe;
        int ib_num_ports = 0;
        int num_req_counters;
+       int allocated;
+       u32 counter_index;
 
        pr_info_once("%s", mlx4_ib_version);
 
@@ -2241,6 +2299,7 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
        ibdev->ib_dev.attach_mcast      = mlx4_ib_mcg_attach;
        ibdev->ib_dev.detach_mcast      = mlx4_ib_mcg_detach;
        ibdev->ib_dev.process_mad       = mlx4_ib_process_mad;
+       ibdev->ib_dev.get_port_immutable = mlx4_port_immutable;
 
        if (!mlx4_is_slave(ibdev->dev)) {
                ibdev->ib_dev.alloc_fmr         = mlx4_ib_fmr_alloc;
@@ -2278,6 +2337,10 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
                        (1ull << IB_USER_VERBS_EX_CMD_DESTROY_FLOW);
        }
 
+       ibdev->ib_dev.uverbs_ex_cmd_mask |=
+               (1ull << IB_USER_VERBS_EX_CMD_QUERY_DEVICE) |
+               (1ull << IB_USER_VERBS_EX_CMD_CREATE_CQ);
+
        mlx4_ib_alloc_eqs(dev, ibdev);
 
        spin_lock_init(&iboe->lock);
@@ -2288,19 +2351,31 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
        num_req_counters = mlx4_is_bonded(dev) ? 1 : ibdev->num_ports;
        for (i = 0; i < num_req_counters; ++i) {
                mutex_init(&ibdev->qp1_proxy_lock[i]);
+               allocated = 0;
                if (mlx4_ib_port_link_layer(&ibdev->ib_dev, i + 1) ==
                                                IB_LINK_LAYER_ETHERNET) {
-                       err = mlx4_counter_alloc(ibdev->dev, &ibdev->counters[i]);
+                       err = mlx4_counter_alloc(ibdev->dev, &counter_index);
+                       /* if failed to allocate a new counter, use default */
                        if (err)
-                               ibdev->counters[i] = -1;
-               } else {
-                       ibdev->counters[i] = -1;
+                               counter_index =
+                                       mlx4_get_default_counter_index(dev,
+                                                                      i + 1);
+                       else
+                               allocated = 1;
+               } else { /* IB_LINK_LAYER_INFINIBAND use the default counter */
+                       counter_index = mlx4_get_default_counter_index(dev,
+                                                                      i + 1);
                }
+               ibdev->counters[i].index = counter_index;
+               ibdev->counters[i].allocated = allocated;
+               pr_info("counter index %d for port %d allocated %d\n",
+                       counter_index, i + 1, allocated);
        }
        if (mlx4_is_bonded(dev))
-               for (i = 1; i < ibdev->num_ports ; ++i)
-                       ibdev->counters[i] = ibdev->counters[0];
-
+               for (i = 1; i < ibdev->num_ports ; ++i) {
+                       ibdev->counters[i].index = ibdev->counters[0].index;
+                       ibdev->counters[i].allocated = 0;
+               }
 
        mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_IB)
                ib_num_ports++;
@@ -2440,10 +2515,12 @@ err_steer_qp_release:
                mlx4_qp_release_range(dev, ibdev->steer_qpn_base,
                                      ibdev->steer_qpn_count);
 err_counter:
-       for (; i; --i)
-               if (ibdev->counters[i - 1] != -1)
-                       mlx4_counter_free(ibdev->dev, ibdev->counters[i - 1]);
-
+       for (i = 0; i < ibdev->num_ports; ++i) {
+               if (ibdev->counters[i].index != -1 &&
+                   ibdev->counters[i].allocated)
+                       mlx4_counter_free(ibdev->dev,
+                                         ibdev->counters[i].index);
+       }
 err_map:
        iounmap(ibdev->uar_map);
 
@@ -2560,8 +2637,9 @@ static void mlx4_ib_remove(struct mlx4_dev *dev, void *ibdev_ptr)
 
        iounmap(ibdev->uar_map);
        for (p = 0; p < ibdev->num_ports; ++p)
-               if (ibdev->counters[p] != -1)
-                       mlx4_counter_free(ibdev->dev, ibdev->counters[p]);
+               if (ibdev->counters[p].index != -1 &&
+                   ibdev->counters[p].allocated)
+                       mlx4_counter_free(ibdev->dev, ibdev->counters[p].index);
        mlx4_foreach_port(p, dev, MLX4_PORT_TYPE_IB)
                mlx4_CLOSE_PORT(dev, p);
 
@@ -2592,31 +2670,33 @@ static void do_slave_init(struct mlx4_ib_dev *ibdev, int slave, int do_init)
        dm = kcalloc(ports, sizeof(*dm), GFP_ATOMIC);
        if (!dm) {
                pr_err("failed to allocate memory for tunneling qp update\n");
-               goto out;
+               return;
        }
 
        for (i = 0; i < ports; i++) {
                dm[i] = kmalloc(sizeof (struct mlx4_ib_demux_work), GFP_ATOMIC);
                if (!dm[i]) {
                        pr_err("failed to allocate memory for tunneling qp update work struct\n");
-                       for (i = 0; i < dev->caps.num_ports; i++) {
-                               if (dm[i])
-                                       kfree(dm[i]);
-                       }
+                       while (--i >= 0)
+                               kfree(dm[i]);
                        goto out;
                }
-       }
-       /* initialize or tear down tunnel QPs for the slave */
-       for (i = 0; i < ports; i++) {
                INIT_WORK(&dm[i]->work, mlx4_ib_tunnels_update_work);
                dm[i]->port = first_port + i + 1;
                dm[i]->slave = slave;
                dm[i]->do_init = do_init;
                dm[i]->dev = ibdev;
-               spin_lock_irqsave(&ibdev->sriov.going_down_lock, flags);
-               if (!ibdev->sriov.is_going_down)
+       }
+       /* initialize or tear down tunnel QPs for the slave */
+       spin_lock_irqsave(&ibdev->sriov.going_down_lock, flags);
+       if (!ibdev->sriov.is_going_down) {
+               for (i = 0; i < ports; i++)
                        queue_work(ibdev->sriov.demux[i].ud_wq, &dm[i]->work);
                spin_unlock_irqrestore(&ibdev->sriov.going_down_lock, flags);
+       } else {
+               spin_unlock_irqrestore(&ibdev->sriov.going_down_lock, flags);
+               for (i = 0; i < ports; i++)
+                       kfree(dm[i]);
        }
 out:
        kfree(dm);