Merge tag 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dledford/rdma
[cascardo/linux.git] / drivers / infiniband / hw / mlx4 / mad.c
index 0f21c3a..1672907 100644 (file)
@@ -230,6 +230,8 @@ static void smp_snoop(struct ib_device *ibdev, u8 port_num, const struct ib_mad
            mad->mad_hdr.method == IB_MGMT_METHOD_SET)
                switch (mad->mad_hdr.attr_id) {
                case IB_SMP_ATTR_PORT_INFO:
+                       if (dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_PORT_MNG_CHG_EV)
+                               return;
                        pinfo = (struct ib_port_info *) ((struct ib_smp *) mad)->data;
                        lid = be16_to_cpu(pinfo->lid);
 
@@ -245,6 +247,8 @@ static void smp_snoop(struct ib_device *ibdev, u8 port_num, const struct ib_mad
                        break;
 
                case IB_SMP_ATTR_PKEY_TABLE:
+                       if (dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_PORT_MNG_CHG_EV)
+                               return;
                        if (!mlx4_is_mfunc(dev->dev)) {
                                mlx4_ib_dispatch_event(dev, port_num,
                                                       IB_EVENT_PKEY_CHANGE);
@@ -281,6 +285,8 @@ static void smp_snoop(struct ib_device *ibdev, u8 port_num, const struct ib_mad
                        break;
 
                case IB_SMP_ATTR_GUID_INFO:
+                       if (dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_PORT_MNG_CHG_EV)
+                               return;
                        /* paravirtualized master's guid is guid 0 -- does not change */
                        if (!mlx4_is_master(dev->dev))
                                mlx4_ib_dispatch_event(dev, port_num,
@@ -296,6 +302,26 @@ static void smp_snoop(struct ib_device *ibdev, u8 port_num, const struct ib_mad
                        }
                        break;
 
+               case IB_SMP_ATTR_SL_TO_VL_TABLE:
+                       /* cache sl to vl mapping changes for use in
+                        * filling QP1 LRH VL field when sending packets
+                        */
+                       if (dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_PORT_MNG_CHG_EV &&
+                           dev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_SL_TO_VL_CHANGE_EVENT)
+                               return;
+                       if (!mlx4_is_slave(dev->dev)) {
+                               union sl2vl_tbl_to_u64 sl2vl64;
+                               int jj;
+
+                               for (jj = 0; jj < 8; jj++) {
+                                       sl2vl64.sl8[jj] = ((struct ib_smp *)mad)->data[jj];
+                                       pr_debug("port %u, sl2vl[%d] = %02x\n",
+                                                port_num, jj, sl2vl64.sl8[jj]);
+                               }
+                               atomic64_set(&dev->sl2vl[port_num - 1], sl2vl64.sl64);
+                       }
+                       break;
+
                default:
                        break;
                }
@@ -345,7 +371,8 @@ static void node_desc_override(struct ib_device *dev,
            mad->mad_hdr.method == IB_MGMT_METHOD_GET_RESP &&
            mad->mad_hdr.attr_id == IB_SMP_ATTR_NODE_DESC) {
                spin_lock_irqsave(&to_mdev(dev)->sm_lock, flags);
-               memcpy(((struct ib_smp *) mad)->data, dev->node_desc, 64);
+               memcpy(((struct ib_smp *) mad)->data, dev->node_desc,
+                      IB_DEVICE_NODE_DESC_MAX);
                spin_unlock_irqrestore(&to_mdev(dev)->sm_lock, flags);
        }
 }
@@ -805,8 +832,7 @@ static int ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
                return IB_MAD_RESULT_FAILURE;
 
        if (!out_mad->mad_hdr.status) {
-               if (!(to_mdev(ibdev)->dev->caps.flags & MLX4_DEV_CAP_FLAG_PORT_MNG_CHG_EV))
-                       smp_snoop(ibdev, port_num, in_mad, prev_lid);
+               smp_snoop(ibdev, port_num, in_mad, prev_lid);
                /* slaves get node desc from FW */
                if (!mlx4_is_slave(to_mdev(ibdev)->dev))
                        node_desc_override(ibdev, out_mad);
@@ -1037,6 +1063,23 @@ static void handle_client_rereg_event(struct mlx4_ib_dev *dev, u8 port_num)
                                                    MLX4_EQ_PORT_INFO_CLIENT_REREG_MASK);
                }
        }
+
+       /* Update the sl to vl table from inside client rereg
+        * only if in secure-host mode (snooping is not possible)
+        * and the sl-to-vl change event is not generated by FW.
+        */
+       if (!mlx4_is_slave(dev->dev) &&
+           dev->dev->flags & MLX4_FLAG_SECURE_HOST &&
+           !(dev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_SL_TO_VL_CHANGE_EVENT)) {
+               if (mlx4_is_master(dev->dev))
+                       /* already in work queue from mlx4_ib_event queueing
+                        * mlx4_handle_port_mgmt_change_event, which calls
+                        * this procedure. Therefore, call sl2vl_update directly.
+                        */
+                       mlx4_ib_sl2vl_update(dev, port_num);
+               else
+                       mlx4_sched_ib_sl2vl_update_work(dev, port_num);
+       }
        mlx4_ib_dispatch_event(dev, port_num, IB_EVENT_CLIENT_REREGISTER);
 }
 
@@ -1176,6 +1219,24 @@ void handle_port_mgmt_change_event(struct work_struct *work)
                        handle_slaves_guid_change(dev, port, tbl_block, change_bitmap);
                }
                break;
+
+       case MLX4_DEV_PMC_SUBTYPE_SL_TO_VL_MAP:
+               /* cache sl to vl mapping changes for use in
+                * filling QP1 LRH VL field when sending packets
+                */
+               if (!mlx4_is_slave(dev->dev)) {
+                       union sl2vl_tbl_to_u64 sl2vl64;
+                       int jj;
+
+                       for (jj = 0; jj < 8; jj++) {
+                               sl2vl64.sl8[jj] =
+                                       eqe->event.port_mgmt_change.params.sl2vl_tbl_change_info.sl2vl_table[jj];
+                               pr_debug("port %u, sl2vl[%d] = %02x\n",
+                                        port, jj, sl2vl64.sl8[jj]);
+                       }
+                       atomic64_set(&dev->sl2vl[port - 1], sl2vl64.sl64);
+               }
+               break;
        default:
                pr_warn("Unsupported subtype 0x%x for "
                        "Port Management Change event\n", eqe->subtype);
@@ -1918,7 +1979,7 @@ static int create_pv_resources(struct ib_device *ibdev, int slave, int port,
                goto err_buf;
        }
 
-       ctx->pd = ib_alloc_pd(ctx->ib_dev);
+       ctx->pd = ib_alloc_pd(ctx->ib_dev, 0);
        if (IS_ERR(ctx->pd)) {
                ret = PTR_ERR(ctx->pd);
                pr_err("Couldn't create tunnel PD (%d)\n", ret);
@@ -2091,7 +2152,7 @@ static int mlx4_ib_alloc_demux_ctx(struct mlx4_ib_dev *dev,
        }
 
        snprintf(name, sizeof name, "mlx4_ibt%d", port);
-       ctx->wq = create_singlethread_workqueue(name);
+       ctx->wq = alloc_ordered_workqueue(name, WQ_MEM_RECLAIM);
        if (!ctx->wq) {
                pr_err("Failed to create tunnelling WQ for port %d\n", port);
                ret = -ENOMEM;
@@ -2099,7 +2160,7 @@ static int mlx4_ib_alloc_demux_ctx(struct mlx4_ib_dev *dev,
        }
 
        snprintf(name, sizeof name, "mlx4_ibud%d", port);
-       ctx->ud_wq = create_singlethread_workqueue(name);
+       ctx->ud_wq = alloc_ordered_workqueue(name, WQ_MEM_RECLAIM);
        if (!ctx->ud_wq) {
                pr_err("Failed to create up/down WQ for port %d\n", port);
                ret = -ENOMEM;