switch (cap_mode) {
        case HCA_CAP_OPMOD_GET_MAX:
-               memcpy(dev->caps.hca[cap_type].max, hca_caps,
+               memcpy(dev->caps.hca[cap_type]->max, hca_caps,
                       MLX5_UN_SZ_BYTES(hca_cap_union));
                break;
        case HCA_CAP_OPMOD_GET_CUR:
-               memcpy(dev->caps.hca[cap_type].cur, hca_caps,
+               memcpy(dev->caps.hca[cap_type]->cur, hca_caps,
                       MLX5_UN_SZ_BYTES(hca_cap_union));
                break;
        default:
                return err;
 
        set_hca_cap = MLX5_ADDR_OF(set_hca_cap_in, set_ctx, capability);
-       memcpy(set_hca_cap, dev->caps.hca[MLX5_CAP_ODP].cur,
+       memcpy(set_hca_cap, dev->caps.hca[MLX5_CAP_ODP]->cur,
               MLX5_ST_SZ_BYTES(odp_cap));
 
 #define ODP_CAP_SET_MAX(dev, field)                                            \
 
        set_hca_cap = MLX5_ADDR_OF(set_hca_cap_in, set_ctx,
                                   capability);
-       memcpy(set_hca_cap, dev->caps.hca[MLX5_CAP_GENERAL].cur,
+       memcpy(set_hca_cap, dev->caps.hca[MLX5_CAP_GENERAL]->cur,
               MLX5_ST_SZ_BYTES(cmd_hca_cap));
 
        mlx5_core_dbg(dev, "Current Pkey table size %d Setting new size %d\n",
                return 0;
 
        set_hca_cap = MLX5_ADDR_OF(set_hca_cap_in, set_ctx, capability);
-       memcpy(set_hca_cap, dev->caps.hca[MLX5_CAP_ROCE].cur,
+       memcpy(set_hca_cap, dev->caps.hca[MLX5_CAP_ROCE]->cur,
               MLX5_ST_SZ_BYTES(roce_cap));
        MLX5_SET(roce_cap, set_hca_cap, sw_r_roce_src_udp_port, 1);
 
        mutex_unlock(&dev->intf_state_mutex);
 }
 
+static const int types[] = {
+       MLX5_CAP_GENERAL,
+       MLX5_CAP_GENERAL_2,
+       MLX5_CAP_ETHERNET_OFFLOADS,
+       MLX5_CAP_IPOIB_ENHANCED_OFFLOADS,
+       MLX5_CAP_ODP,
+       MLX5_CAP_ATOMIC,
+       MLX5_CAP_ROCE,
+       MLX5_CAP_IPOIB_OFFLOADS,
+       MLX5_CAP_FLOW_TABLE,
+       MLX5_CAP_ESWITCH_FLOW_TABLE,
+       MLX5_CAP_ESWITCH,
+       MLX5_CAP_VECTOR_CALC,
+       MLX5_CAP_QOS,
+       MLX5_CAP_DEBUG,
+       MLX5_CAP_DEV_MEM,
+       MLX5_CAP_DEV_EVENT,
+       MLX5_CAP_TLS,
+       MLX5_CAP_VDPA_EMULATION,
+       MLX5_CAP_IPSEC,
+};
+
+static void mlx5_hca_caps_free(struct mlx5_core_dev *dev)
+{
+       int type;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(types); i++) {
+               type = types[i];
+               kfree(dev->caps.hca[type]);
+       }
+}
+
+static int mlx5_hca_caps_alloc(struct mlx5_core_dev *dev)
+{
+       struct mlx5_hca_cap *cap;
+       int type;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(types); i++) {
+               cap = kzalloc(sizeof(*cap), GFP_KERNEL);
+               if (!cap)
+                       goto err;
+               type = types[i];
+               dev->caps.hca[type] = cap;
+       }
+
+       return 0;
+
+err:
+       mlx5_hca_caps_free(dev);
+       return -ENOMEM;
+}
+
 int mlx5_mdev_init(struct mlx5_core_dev *dev, int profile_idx)
 {
        struct mlx5_priv *priv = &dev->priv;
        if (err)
                goto err_adev_init;
 
+       err = mlx5_hca_caps_alloc(dev);
+       if (err)
+               goto err_hca_caps;
+
        return 0;
 
+err_hca_caps:
+       mlx5_adev_cleanup(dev);
 err_adev_init:
        mlx5_pagealloc_cleanup(dev);
 err_pagealloc_init:
 {
        struct mlx5_priv *priv = &dev->priv;
 
+       mlx5_hca_caps_free(dev);
        mlx5_adev_cleanup(dev);
        mlx5_pagealloc_cleanup(dev);
        mlx5_health_cleanup(dev);
 
        HCA_CAP_OPMOD_GET_CUR   = 1,
 };
 
+/* Any new cap addition must update mlx5_hca_caps_alloc() to allocate
+ * capability memory.
+ */
 enum mlx5_cap_type {
        MLX5_CAP_GENERAL = 0,
        MLX5_CAP_ETHERNET_OFFLOADS,
 
 /* GET Dev Caps macros */
 #define MLX5_CAP_GEN(mdev, cap) \
-       MLX5_GET(cmd_hca_cap, mdev->caps.hca[MLX5_CAP_GENERAL].cur, cap)
+       MLX5_GET(cmd_hca_cap, mdev->caps.hca[MLX5_CAP_GENERAL]->cur, cap)
 
 #define MLX5_CAP_GEN_64(mdev, cap) \
-       MLX5_GET64(cmd_hca_cap, mdev->caps.hca[MLX5_CAP_GENERAL].cur, cap)
+       MLX5_GET64(cmd_hca_cap, mdev->caps.hca[MLX5_CAP_GENERAL]->cur, cap)
 
 #define MLX5_CAP_GEN_MAX(mdev, cap) \
-       MLX5_GET(cmd_hca_cap, mdev->caps.hca[MLX5_CAP_GENERAL].max, cap)
+       MLX5_GET(cmd_hca_cap, mdev->caps.hca[MLX5_CAP_GENERAL]->max, cap)
 
 #define MLX5_CAP_GEN_2(mdev, cap) \
-       MLX5_GET(cmd_hca_cap_2, mdev->caps.hca[MLX5_CAP_GENERAL_2].cur, cap)
+       MLX5_GET(cmd_hca_cap_2, mdev->caps.hca[MLX5_CAP_GENERAL_2]->cur, cap)
 
 #define MLX5_CAP_GEN_2_64(mdev, cap) \
-       MLX5_GET64(cmd_hca_cap_2, mdev->caps.hca[MLX5_CAP_GENERAL_2].cur, cap)
+       MLX5_GET64(cmd_hca_cap_2, mdev->caps.hca[MLX5_CAP_GENERAL_2]->cur, cap)
 
 #define MLX5_CAP_GEN_2_MAX(mdev, cap) \
-       MLX5_GET(cmd_hca_cap_2, mdev->caps.hca[MLX5_CAP_GENERAL_2].max, cap)
+       MLX5_GET(cmd_hca_cap_2, mdev->caps.hca[MLX5_CAP_GENERAL_2]->max, cap)
 
 #define MLX5_CAP_ETH(mdev, cap) \
        MLX5_GET(per_protocol_networking_offload_caps,\
-                mdev->caps.hca[MLX5_CAP_ETHERNET_OFFLOADS].cur, cap)
+                mdev->caps.hca[MLX5_CAP_ETHERNET_OFFLOADS]->cur, cap)
 
 #define MLX5_CAP_ETH_MAX(mdev, cap) \
        MLX5_GET(per_protocol_networking_offload_caps,\
-                mdev->caps.hca[MLX5_CAP_ETHERNET_OFFLOADS].max, cap)
+                mdev->caps.hca[MLX5_CAP_ETHERNET_OFFLOADS]->max, cap)
 
 #define MLX5_CAP_IPOIB_ENHANCED(mdev, cap) \
        MLX5_GET(per_protocol_networking_offload_caps,\
-                mdev->caps.hca[MLX5_CAP_IPOIB_ENHANCED_OFFLOADS].cur, cap)
+                mdev->caps.hca[MLX5_CAP_IPOIB_ENHANCED_OFFLOADS]->cur, cap)
 
 #define MLX5_CAP_ROCE(mdev, cap) \
-       MLX5_GET(roce_cap, mdev->caps.hca[MLX5_CAP_ROCE].cur, cap)
+       MLX5_GET(roce_cap, mdev->caps.hca[MLX5_CAP_ROCE]->cur, cap)
 
 #define MLX5_CAP_ROCE_MAX(mdev, cap) \
-       MLX5_GET(roce_cap, mdev->caps.hca[MLX5_CAP_ROCE].max, cap)
+       MLX5_GET(roce_cap, mdev->caps.hca[MLX5_CAP_ROCE]->max, cap)
 
 #define MLX5_CAP_ATOMIC(mdev, cap) \
-       MLX5_GET(atomic_caps, mdev->caps.hca[MLX5_CAP_ATOMIC].cur, cap)
+       MLX5_GET(atomic_caps, mdev->caps.hca[MLX5_CAP_ATOMIC]->cur, cap)
 
 #define MLX5_CAP_ATOMIC_MAX(mdev, cap) \
-       MLX5_GET(atomic_caps, mdev->caps.hca[MLX5_CAP_ATOMIC].max, cap)
+       MLX5_GET(atomic_caps, mdev->caps.hca[MLX5_CAP_ATOMIC]->max, cap)
 
 #define MLX5_CAP_FLOWTABLE(mdev, cap) \
-       MLX5_GET(flow_table_nic_cap, mdev->caps.hca[MLX5_CAP_FLOW_TABLE].cur, cap)
+       MLX5_GET(flow_table_nic_cap, mdev->caps.hca[MLX5_CAP_FLOW_TABLE]->cur, cap)
 
 #define MLX5_CAP64_FLOWTABLE(mdev, cap) \
-       MLX5_GET64(flow_table_nic_cap, (mdev)->caps.hca[MLX5_CAP_FLOW_TABLE].cur, cap)
+       MLX5_GET64(flow_table_nic_cap, (mdev)->caps.hca[MLX5_CAP_FLOW_TABLE]->cur, cap)
 
 #define MLX5_CAP_FLOWTABLE_MAX(mdev, cap) \
-       MLX5_GET(flow_table_nic_cap, mdev->caps.hca[MLX5_CAP_FLOW_TABLE].max, cap)
+       MLX5_GET(flow_table_nic_cap, mdev->caps.hca[MLX5_CAP_FLOW_TABLE]->max, cap)
 
 #define MLX5_CAP_FLOWTABLE_NIC_RX(mdev, cap) \
        MLX5_CAP_FLOWTABLE(mdev, flow_table_properties_nic_receive.cap)
 
 #define MLX5_CAP_ESW_FLOWTABLE(mdev, cap) \
        MLX5_GET(flow_table_eswitch_cap, \
-                mdev->caps.hca[MLX5_CAP_ESWITCH_FLOW_TABLE].cur, cap)
+                mdev->caps.hca[MLX5_CAP_ESWITCH_FLOW_TABLE]->cur, cap)
 
 #define MLX5_CAP_ESW_FLOWTABLE_MAX(mdev, cap) \
        MLX5_GET(flow_table_eswitch_cap, \
-                mdev->caps.hca[MLX5_CAP_ESWITCH_FLOW_TABLE].max, cap)
+                mdev->caps.hca[MLX5_CAP_ESWITCH_FLOW_TABLE]->max, cap)
 
 #define MLX5_CAP_ESW_FLOWTABLE_FDB(mdev, cap) \
        MLX5_CAP_ESW_FLOWTABLE(mdev, flow_table_properties_nic_esw_fdb.cap)
 
 #define MLX5_CAP_ESW(mdev, cap) \
        MLX5_GET(e_switch_cap, \
-                mdev->caps.hca[MLX5_CAP_ESWITCH].cur, cap)
+                mdev->caps.hca[MLX5_CAP_ESWITCH]->cur, cap)
 
 #define MLX5_CAP64_ESW_FLOWTABLE(mdev, cap) \
        MLX5_GET64(flow_table_eswitch_cap, \
-               (mdev)->caps.hca[MLX5_CAP_ESWITCH_FLOW_TABLE].cur, cap)
+               (mdev)->caps.hca[MLX5_CAP_ESWITCH_FLOW_TABLE]->cur, cap)
 
 #define MLX5_CAP_ESW_MAX(mdev, cap) \
        MLX5_GET(e_switch_cap, \
-                mdev->caps.hca[MLX5_CAP_ESWITCH].max, cap)
+                mdev->caps.hca[MLX5_CAP_ESWITCH]->max, cap)
 
 #define MLX5_CAP_ODP(mdev, cap)\
-       MLX5_GET(odp_cap, mdev->caps.hca[MLX5_CAP_ODP].cur, cap)
+       MLX5_GET(odp_cap, mdev->caps.hca[MLX5_CAP_ODP]->cur, cap)
 
 #define MLX5_CAP_ODP_MAX(mdev, cap)\
-       MLX5_GET(odp_cap, mdev->caps.hca[MLX5_CAP_ODP].max, cap)
+       MLX5_GET(odp_cap, mdev->caps.hca[MLX5_CAP_ODP]->max, cap)
 
 #define MLX5_CAP_VECTOR_CALC(mdev, cap) \
        MLX5_GET(vector_calc_cap, \
-                mdev->caps.hca[MLX5_CAP_VECTOR_CALC].cur, cap)
+                mdev->caps.hca[MLX5_CAP_VECTOR_CALC]->cur, cap)
 
 #define MLX5_CAP_QOS(mdev, cap)\
-       MLX5_GET(qos_cap, mdev->caps.hca[MLX5_CAP_QOS].cur, cap)
+       MLX5_GET(qos_cap, mdev->caps.hca[MLX5_CAP_QOS]->cur, cap)
 
 #define MLX5_CAP_DEBUG(mdev, cap)\
-       MLX5_GET(debug_cap, mdev->caps.hca[MLX5_CAP_DEBUG].cur, cap)
+       MLX5_GET(debug_cap, mdev->caps.hca[MLX5_CAP_DEBUG]->cur, cap)
 
 #define MLX5_CAP_PCAM_FEATURE(mdev, fld) \
        MLX5_GET(pcam_reg, (mdev)->caps.pcam, feature_cap_mask.enhanced_features.fld)
        MLX5_GET64(fpga_cap, (mdev)->caps.fpga, cap)
 
 #define MLX5_CAP_DEV_MEM(mdev, cap)\
-       MLX5_GET(device_mem_cap, mdev->caps.hca[MLX5_CAP_DEV_MEM].cur, cap)
+       MLX5_GET(device_mem_cap, mdev->caps.hca[MLX5_CAP_DEV_MEM]->cur, cap)
 
 #define MLX5_CAP64_DEV_MEM(mdev, cap)\
-       MLX5_GET64(device_mem_cap, mdev->caps.hca[MLX5_CAP_DEV_MEM].cur, cap)
+       MLX5_GET64(device_mem_cap, mdev->caps.hca[MLX5_CAP_DEV_MEM]->cur, cap)
 
 #define MLX5_CAP_TLS(mdev, cap) \
-       MLX5_GET(tls_cap, (mdev)->caps.hca[MLX5_CAP_TLS].cur, cap)
+       MLX5_GET(tls_cap, (mdev)->caps.hca[MLX5_CAP_TLS]->cur, cap)
 
 #define MLX5_CAP_DEV_EVENT(mdev, cap)\
-       MLX5_ADDR_OF(device_event_cap, (mdev)->caps.hca[MLX5_CAP_DEV_EVENT].cur, cap)
+       MLX5_ADDR_OF(device_event_cap, (mdev)->caps.hca[MLX5_CAP_DEV_EVENT]->cur, cap)
 
 #define MLX5_CAP_DEV_VDPA_EMULATION(mdev, cap)\
        MLX5_GET(virtio_emulation_cap, \
-               (mdev)->caps.hca[MLX5_CAP_VDPA_EMULATION].cur, cap)
+               (mdev)->caps.hca[MLX5_CAP_VDPA_EMULATION]->cur, cap)
 
 #define MLX5_CAP64_DEV_VDPA_EMULATION(mdev, cap)\
        MLX5_GET64(virtio_emulation_cap, \
-               (mdev)->caps.hca[MLX5_CAP_VDPA_EMULATION].cur, cap)
+               (mdev)->caps.hca[MLX5_CAP_VDPA_EMULATION]->cur, cap)
 
 #define MLX5_CAP_IPSEC(mdev, cap)\
-       MLX5_GET(ipsec_cap, (mdev)->caps.hca[MLX5_CAP_IPSEC].cur, cap)
+       MLX5_GET(ipsec_cap, (mdev)->caps.hca[MLX5_CAP_IPSEC]->cur, cap)
 
 enum {
        MLX5_CMD_STAT_OK                        = 0x0,