Merge branch 'parisc-5.1-1' of git://git.kernel.org/pub/scm/linux/kernel/git/deller...
[sfrench/cifs-2.6.git] / drivers / net / ethernet / mellanox / mlxsw / spectrum_buffers.c
index 80066f437a65e8a91c63ea7000189c62a7a4565e..9a79b5e1159743a9b619407cd3b9b9af065c97ca 100644 (file)
@@ -37,13 +37,19 @@ struct mlxsw_sp_sb_pm {
        struct mlxsw_cp_sb_occ occ;
 };
 
+struct mlxsw_sp_sb_mm {
+       u32 min_buff;
+       u32 max_buff;
+       u16 pool_index;
+};
+
 struct mlxsw_sp_sb_pool_des {
        enum mlxsw_reg_sbxx_dir dir;
        u8 pool;
 };
 
 /* Order ingress pools before egress pools. */
-static const struct mlxsw_sp_sb_pool_des mlxsw_sp_sb_pool_dess[] = {
+static const struct mlxsw_sp_sb_pool_des mlxsw_sp1_sb_pool_dess[] = {
        {MLXSW_REG_SBXX_DIR_INGRESS, 0},
        {MLXSW_REG_SBXX_DIR_INGRESS, 1},
        {MLXSW_REG_SBXX_DIR_INGRESS, 2},
@@ -55,7 +61,16 @@ static const struct mlxsw_sp_sb_pool_des mlxsw_sp_sb_pool_dess[] = {
        {MLXSW_REG_SBXX_DIR_EGRESS, 15},
 };
 
-#define MLXSW_SP_SB_POOL_DESS_LEN ARRAY_SIZE(mlxsw_sp_sb_pool_dess)
+static const struct mlxsw_sp_sb_pool_des mlxsw_sp2_sb_pool_dess[] = {
+       {MLXSW_REG_SBXX_DIR_INGRESS, 0},
+       {MLXSW_REG_SBXX_DIR_INGRESS, 1},
+       {MLXSW_REG_SBXX_DIR_INGRESS, 2},
+       {MLXSW_REG_SBXX_DIR_INGRESS, 3},
+       {MLXSW_REG_SBXX_DIR_EGRESS, 0},
+       {MLXSW_REG_SBXX_DIR_EGRESS, 1},
+       {MLXSW_REG_SBXX_DIR_EGRESS, 2},
+       {MLXSW_REG_SBXX_DIR_EGRESS, 3},
+};
 
 #define MLXSW_SP_SB_ING_TC_COUNT 8
 #define MLXSW_SP_SB_EG_TC_COUNT 16
@@ -63,16 +78,32 @@ static const struct mlxsw_sp_sb_pool_des mlxsw_sp_sb_pool_dess[] = {
 struct mlxsw_sp_sb_port {
        struct mlxsw_sp_sb_cm ing_cms[MLXSW_SP_SB_ING_TC_COUNT];
        struct mlxsw_sp_sb_cm eg_cms[MLXSW_SP_SB_EG_TC_COUNT];
-       struct mlxsw_sp_sb_pm pms[MLXSW_SP_SB_POOL_DESS_LEN];
+       struct mlxsw_sp_sb_pm *pms;
 };
 
 struct mlxsw_sp_sb {
-       struct mlxsw_sp_sb_pr prs[MLXSW_SP_SB_POOL_DESS_LEN];
+       struct mlxsw_sp_sb_pr *prs;
        struct mlxsw_sp_sb_port *ports;
        u32 cell_size;
+       u32 max_headroom_cells;
        u64 sb_size;
 };
 
+struct mlxsw_sp_sb_vals {
+       unsigned int pool_count;
+       const struct mlxsw_sp_sb_pool_des *pool_dess;
+       const struct mlxsw_sp_sb_pm *pms;
+       const struct mlxsw_sp_sb_pr *prs;
+       const struct mlxsw_sp_sb_mm *mms;
+       const struct mlxsw_sp_sb_cm *cms_ingress;
+       const struct mlxsw_sp_sb_cm *cms_egress;
+       const struct mlxsw_sp_sb_cm *cms_cpu;
+       unsigned int mms_count;
+       unsigned int cms_ingress_count;
+       unsigned int cms_egress_count;
+       unsigned int cms_cpu_count;
+};
+
 u32 mlxsw_sp_cells_bytes(const struct mlxsw_sp *mlxsw_sp, u32 cells)
 {
        return mlxsw_sp->sb->cell_size * cells;
@@ -83,6 +114,11 @@ u32 mlxsw_sp_bytes_cells(const struct mlxsw_sp *mlxsw_sp, u32 bytes)
        return DIV_ROUND_UP(bytes, mlxsw_sp->sb->cell_size);
 }
 
+u32 mlxsw_sp_sb_max_headroom_cells(const struct mlxsw_sp *mlxsw_sp)
+{
+       return mlxsw_sp->sb->max_headroom_cells;
+}
+
 static struct mlxsw_sp_sb_pr *mlxsw_sp_sb_pr_get(struct mlxsw_sp *mlxsw_sp,
                                                 u16 pool_index)
 {
@@ -121,7 +157,7 @@ static int mlxsw_sp_sb_pr_write(struct mlxsw_sp *mlxsw_sp, u16 pool_index,
                                u32 size, bool infi_size)
 {
        const struct mlxsw_sp_sb_pool_des *des =
-               &mlxsw_sp_sb_pool_dess[pool_index];
+               &mlxsw_sp->sb_vals->pool_dess[pool_index];
        char sbpr_pl[MLXSW_REG_SBPR_LEN];
        struct mlxsw_sp_sb_pr *pr;
        int err;
@@ -145,7 +181,7 @@ static int mlxsw_sp_sb_cm_write(struct mlxsw_sp *mlxsw_sp, u8 local_port,
                                bool infi_max, u16 pool_index)
 {
        const struct mlxsw_sp_sb_pool_des *des =
-               &mlxsw_sp_sb_pool_dess[pool_index];
+               &mlxsw_sp->sb_vals->pool_dess[pool_index];
        char sbcm_pl[MLXSW_REG_SBCM_LEN];
        struct mlxsw_sp_sb_cm *cm;
        int err;
@@ -174,7 +210,7 @@ static int mlxsw_sp_sb_pm_write(struct mlxsw_sp *mlxsw_sp, u8 local_port,
                                u16 pool_index, u32 min_buff, u32 max_buff)
 {
        const struct mlxsw_sp_sb_pool_des *des =
-               &mlxsw_sp_sb_pool_dess[pool_index];
+               &mlxsw_sp->sb_vals->pool_dess[pool_index];
        char sbpm_pl[MLXSW_REG_SBPM_LEN];
        struct mlxsw_sp_sb_pm *pm;
        int err;
@@ -195,7 +231,7 @@ static int mlxsw_sp_sb_pm_occ_clear(struct mlxsw_sp *mlxsw_sp, u8 local_port,
                                    u16 pool_index, struct list_head *bulk_list)
 {
        const struct mlxsw_sp_sb_pool_des *des =
-               &mlxsw_sp_sb_pool_dess[pool_index];
+               &mlxsw_sp->sb_vals->pool_dess[pool_index];
        char sbpm_pl[MLXSW_REG_SBPM_LEN];
 
        mlxsw_reg_sbpm_pack(sbpm_pl, local_port, des->pool, des->dir,
@@ -217,7 +253,7 @@ static int mlxsw_sp_sb_pm_occ_query(struct mlxsw_sp *mlxsw_sp, u8 local_port,
                                    u16 pool_index, struct list_head *bulk_list)
 {
        const struct mlxsw_sp_sb_pool_des *des =
-               &mlxsw_sp_sb_pool_dess[pool_index];
+               &mlxsw_sp->sb_vals->pool_dess[pool_index];
        char sbpm_pl[MLXSW_REG_SBPM_LEN];
        struct mlxsw_sp_sb_pm *pm;
 
@@ -230,24 +266,24 @@ static int mlxsw_sp_sb_pm_occ_query(struct mlxsw_sp *mlxsw_sp, u8 local_port,
                                     (unsigned long) pm);
 }
 
-static const u16 mlxsw_sp_pbs[] = {
-       [0] = 2 * ETH_FRAME_LEN,
-       [9] = 2 * MLXSW_PORT_MAX_MTU,
-};
-
-#define MLXSW_SP_PBS_LEN ARRAY_SIZE(mlxsw_sp_pbs)
+/* 1/4 of a headroom necessary for 100Gbps port and 100m cable. */
+#define MLXSW_SP_PB_HEADROOM 25632
 #define MLXSW_SP_PB_UNUSED 8
 
 static int mlxsw_sp_port_pb_init(struct mlxsw_sp_port *mlxsw_sp_port)
 {
+       const u32 pbs[] = {
+               [0] = MLXSW_SP_PB_HEADROOM * mlxsw_sp_port->mapping.width,
+               [9] = 2 * MLXSW_PORT_MAX_MTU,
+       };
        struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
        char pbmc_pl[MLXSW_REG_PBMC_LEN];
        int i;
 
        mlxsw_reg_pbmc_pack(pbmc_pl, mlxsw_sp_port->local_port,
                            0xffff, 0xffff / 2);
-       for (i = 0; i < MLXSW_SP_PBS_LEN; i++) {
-               u16 size = mlxsw_sp_bytes_cells(mlxsw_sp, mlxsw_sp_pbs[i]);
+       for (i = 0; i < ARRAY_SIZE(pbs); i++) {
+               u16 size = mlxsw_sp_bytes_cells(mlxsw_sp, pbs[i]);
 
                if (i == MLXSW_SP_PB_UNUSED)
                        continue;
@@ -280,50 +316,119 @@ static int mlxsw_sp_port_headroom_init(struct mlxsw_sp_port *mlxsw_sp_port)
        return mlxsw_sp_port_pb_prio_init(mlxsw_sp_port);
 }
 
+static int mlxsw_sp_sb_port_init(struct mlxsw_sp *mlxsw_sp,
+                                struct mlxsw_sp_sb_port *sb_port)
+{
+       struct mlxsw_sp_sb_pm *pms;
+
+       pms = kcalloc(mlxsw_sp->sb_vals->pool_count, sizeof(*pms),
+                     GFP_KERNEL);
+       if (!pms)
+               return -ENOMEM;
+       sb_port->pms = pms;
+       return 0;
+}
+
+static void mlxsw_sp_sb_port_fini(struct mlxsw_sp_sb_port *sb_port)
+{
+       kfree(sb_port->pms);
+}
+
 static int mlxsw_sp_sb_ports_init(struct mlxsw_sp *mlxsw_sp)
 {
        unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sp->core);
+       struct mlxsw_sp_sb_pr *prs;
+       int i;
+       int err;
 
        mlxsw_sp->sb->ports = kcalloc(max_ports,
                                      sizeof(struct mlxsw_sp_sb_port),
                                      GFP_KERNEL);
        if (!mlxsw_sp->sb->ports)
                return -ENOMEM;
+
+       prs = kcalloc(mlxsw_sp->sb_vals->pool_count, sizeof(*prs),
+                     GFP_KERNEL);
+       if (!prs) {
+               err = -ENOMEM;
+               goto err_alloc_prs;
+       }
+       mlxsw_sp->sb->prs = prs;
+
+       for (i = 0; i < max_ports; i++) {
+               err = mlxsw_sp_sb_port_init(mlxsw_sp, &mlxsw_sp->sb->ports[i]);
+               if (err)
+                       goto err_sb_port_init;
+       }
+
        return 0;
+
+err_sb_port_init:
+       for (i--; i >= 0; i--)
+               mlxsw_sp_sb_port_fini(&mlxsw_sp->sb->ports[i]);
+       kfree(mlxsw_sp->sb->prs);
+err_alloc_prs:
+       kfree(mlxsw_sp->sb->ports);
+       return err;
 }
 
 static void mlxsw_sp_sb_ports_fini(struct mlxsw_sp *mlxsw_sp)
 {
+       int max_ports = mlxsw_core_max_ports(mlxsw_sp->core);
+       int i;
+
+       for (i = max_ports - 1; i >= 0; i--)
+               mlxsw_sp_sb_port_fini(&mlxsw_sp->sb->ports[i]);
+       kfree(mlxsw_sp->sb->prs);
        kfree(mlxsw_sp->sb->ports);
 }
 
-#define MLXSW_SP_SB_PR_INGRESS_SIZE    12440000
-#define MLXSW_SP_SB_PR_INGRESS_MNG_SIZE (200 * 1000)
-#define MLXSW_SP_SB_PR_EGRESS_SIZE     13232000
-
 #define MLXSW_SP_SB_PR(_mode, _size)   \
        {                               \
                .mode = _mode,          \
                .size = _size,          \
        }
 
-static const struct mlxsw_sp_sb_pr mlxsw_sp_sb_prs[] = {
+#define MLXSW_SP1_SB_PR_INGRESS_SIZE   12440000
+#define MLXSW_SP1_SB_PR_INGRESS_MNG_SIZE (200 * 1000)
+#define MLXSW_SP1_SB_PR_EGRESS_SIZE    13232000
+
+static const struct mlxsw_sp_sb_pr mlxsw_sp1_sb_prs[] = {
        /* Ingress pools. */
        MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC,
-                      MLXSW_SP_SB_PR_INGRESS_SIZE),
+                      MLXSW_SP1_SB_PR_INGRESS_SIZE),
        MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0),
        MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0),
        MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC,
-                      MLXSW_SP_SB_PR_INGRESS_MNG_SIZE),
+                      MLXSW_SP1_SB_PR_INGRESS_MNG_SIZE),
        /* Egress pools. */
-       MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, MLXSW_SP_SB_PR_EGRESS_SIZE),
+       MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC,
+                      MLXSW_SP1_SB_PR_EGRESS_SIZE),
        MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0),
        MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0),
        MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0),
        MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_STATIC, MLXSW_SP_SB_INFI),
 };
 
-#define MLXSW_SP_SB_PRS_LEN ARRAY_SIZE(mlxsw_sp_sb_prs)
+#define MLXSW_SP2_SB_PR_INGRESS_SIZE   40960000
+#define MLXSW_SP2_SB_PR_INGRESS_MNG_SIZE (200 * 1000)
+#define MLXSW_SP2_SB_PR_EGRESS_SIZE    40960000
+
+static const struct mlxsw_sp_sb_pr mlxsw_sp2_sb_prs[] = {
+       /* Ingress pools. */
+       MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC,
+                      MLXSW_SP2_SB_PR_INGRESS_SIZE),
+       MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_STATIC, 0),
+       MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_STATIC, 0),
+       MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC,
+                      MLXSW_SP2_SB_PR_INGRESS_MNG_SIZE),
+       /* Egress pools. */
+       MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC,
+                      MLXSW_SP2_SB_PR_EGRESS_SIZE),
+       MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_STATIC, 0),
+       MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_STATIC, 0),
+       MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_STATIC, 0),
+};
 
 static int mlxsw_sp_sb_prs_init(struct mlxsw_sp *mlxsw_sp,
                                const struct mlxsw_sp_sb_pr *prs,
@@ -357,7 +462,7 @@ static int mlxsw_sp_sb_prs_init(struct mlxsw_sp *mlxsw_sp,
                .pool_index = _pool,                    \
        }
 
-static const struct mlxsw_sp_sb_cm mlxsw_sp_sb_cms_ingress[] = {
+static const struct mlxsw_sp_sb_cm mlxsw_sp1_sb_cms_ingress[] = {
        MLXSW_SP_SB_CM(10000, 8, 0),
        MLXSW_SP_SB_CM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN, 0),
        MLXSW_SP_SB_CM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN, 0),
@@ -370,9 +475,20 @@ static const struct mlxsw_sp_sb_cm mlxsw_sp_sb_cms_ingress[] = {
        MLXSW_SP_SB_CM(20000, 1, 3),
 };
 
-#define MLXSW_SP_SB_CMS_INGRESS_LEN ARRAY_SIZE(mlxsw_sp_sb_cms_ingress)
+static const struct mlxsw_sp_sb_cm mlxsw_sp2_sb_cms_ingress[] = {
+       MLXSW_SP_SB_CM(0, 7, 0),
+       MLXSW_SP_SB_CM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN, 0),
+       MLXSW_SP_SB_CM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN, 0),
+       MLXSW_SP_SB_CM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN, 0),
+       MLXSW_SP_SB_CM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN, 0),
+       MLXSW_SP_SB_CM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN, 0),
+       MLXSW_SP_SB_CM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN, 0),
+       MLXSW_SP_SB_CM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN, 0),
+       MLXSW_SP_SB_CM(0, 0, 0), /* dummy, this PG does not exist */
+       MLXSW_SP_SB_CM(20000, 1, 3),
+};
 
-static const struct mlxsw_sp_sb_cm mlxsw_sp_sb_cms_egress[] = {
+static const struct mlxsw_sp_sb_cm mlxsw_sp1_sb_cms_egress[] = {
        MLXSW_SP_SB_CM(1500, 9, 4),
        MLXSW_SP_SB_CM(1500, 9, 4),
        MLXSW_SP_SB_CM(1500, 9, 4),
@@ -392,7 +508,25 @@ static const struct mlxsw_sp_sb_cm mlxsw_sp_sb_cms_egress[] = {
        MLXSW_SP_SB_CM(1, 0xff, 4),
 };
 
-#define MLXSW_SP_SB_CMS_EGRESS_LEN ARRAY_SIZE(mlxsw_sp_sb_cms_egress)
+static const struct mlxsw_sp_sb_cm mlxsw_sp2_sb_cms_egress[] = {
+       MLXSW_SP_SB_CM(0, 7, 4),
+       MLXSW_SP_SB_CM(0, 7, 4),
+       MLXSW_SP_SB_CM(0, 7, 4),
+       MLXSW_SP_SB_CM(0, 7, 4),
+       MLXSW_SP_SB_CM(0, 7, 4),
+       MLXSW_SP_SB_CM(0, 7, 4),
+       MLXSW_SP_SB_CM(0, 7, 4),
+       MLXSW_SP_SB_CM(0, 7, 4),
+       MLXSW_SP_SB_CM(0, 7, 4),
+       MLXSW_SP_SB_CM(0, 7, 4),
+       MLXSW_SP_SB_CM(0, 7, 4),
+       MLXSW_SP_SB_CM(0, 7, 4),
+       MLXSW_SP_SB_CM(0, 7, 4),
+       MLXSW_SP_SB_CM(0, 7, 4),
+       MLXSW_SP_SB_CM(0, 7, 4),
+       MLXSW_SP_SB_CM(0, 7, 4),
+       MLXSW_SP_SB_CM(1, 0xff, 4),
+};
 
 #define MLXSW_SP_CPU_PORT_SB_CM MLXSW_SP_SB_CM(0, 0, 4)
 
@@ -431,9 +565,6 @@ static const struct mlxsw_sp_sb_cm mlxsw_sp_cpu_port_sb_cms[] = {
        MLXSW_SP_CPU_PORT_SB_CM,
 };
 
-#define MLXSW_SP_CPU_PORT_SB_MCS_LEN \
-       ARRAY_SIZE(mlxsw_sp_cpu_port_sb_cms)
-
 static bool
 mlxsw_sp_sb_pool_is_static(struct mlxsw_sp *mlxsw_sp, u16 pool_index)
 {
@@ -447,6 +578,7 @@ static int __mlxsw_sp_sb_cms_init(struct mlxsw_sp *mlxsw_sp, u8 local_port,
                                  const struct mlxsw_sp_sb_cm *cms,
                                  size_t cms_len)
 {
+       const struct mlxsw_sp_sb_vals *sb_vals = mlxsw_sp->sb_vals;
        int i;
        int err;
 
@@ -458,7 +590,7 @@ static int __mlxsw_sp_sb_cms_init(struct mlxsw_sp *mlxsw_sp, u8 local_port,
                if (i == 8 && dir == MLXSW_REG_SBXX_DIR_INGRESS)
                        continue; /* PG number 8 does not exist, skip it */
                cm = &cms[i];
-               if (WARN_ON(mlxsw_sp_sb_pool_dess[cm->pool_index].dir != dir))
+               if (WARN_ON(sb_vals->pool_dess[cm->pool_index].dir != dir))
                        continue;
 
                min_buff = mlxsw_sp_bytes_cells(mlxsw_sp, cm->min_buff);
@@ -484,27 +616,28 @@ static int __mlxsw_sp_sb_cms_init(struct mlxsw_sp *mlxsw_sp, u8 local_port,
 
 static int mlxsw_sp_port_sb_cms_init(struct mlxsw_sp_port *mlxsw_sp_port)
 {
+       struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
        int err;
 
-       err = __mlxsw_sp_sb_cms_init(mlxsw_sp_port->mlxsw_sp,
+       err = __mlxsw_sp_sb_cms_init(mlxsw_sp,
                                     mlxsw_sp_port->local_port,
                                     MLXSW_REG_SBXX_DIR_INGRESS,
-                                    mlxsw_sp_sb_cms_ingress,
-                                    MLXSW_SP_SB_CMS_INGRESS_LEN);
+                                    mlxsw_sp->sb_vals->cms_ingress,
+                                    mlxsw_sp->sb_vals->cms_ingress_count);
        if (err)
                return err;
        return __mlxsw_sp_sb_cms_init(mlxsw_sp_port->mlxsw_sp,
                                      mlxsw_sp_port->local_port,
                                      MLXSW_REG_SBXX_DIR_EGRESS,
-                                     mlxsw_sp_sb_cms_egress,
-                                     MLXSW_SP_SB_CMS_EGRESS_LEN);
+                                     mlxsw_sp->sb_vals->cms_egress,
+                                     mlxsw_sp->sb_vals->cms_egress_count);
 }
 
 static int mlxsw_sp_cpu_port_sb_cms_init(struct mlxsw_sp *mlxsw_sp)
 {
        return __mlxsw_sp_sb_cms_init(mlxsw_sp, 0, MLXSW_REG_SBXX_DIR_EGRESS,
-                                     mlxsw_sp_cpu_port_sb_cms,
-                                     MLXSW_SP_CPU_PORT_SB_MCS_LEN);
+                                     mlxsw_sp->sb_vals->cms_cpu,
+                                     mlxsw_sp->sb_vals->cms_cpu_count);
 }
 
 #define MLXSW_SP_SB_PM(_min_buff, _max_buff)   \
@@ -513,7 +646,7 @@ static int mlxsw_sp_cpu_port_sb_cms_init(struct mlxsw_sp *mlxsw_sp)
                .max_buff = _max_buff,          \
        }
 
-static const struct mlxsw_sp_sb_pm mlxsw_sp_sb_pms[] = {
+static const struct mlxsw_sp_sb_pm mlxsw_sp1_sb_pms[] = {
        /* Ingress pools. */
        MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MAX),
        MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN),
@@ -527,7 +660,18 @@ static const struct mlxsw_sp_sb_pm mlxsw_sp_sb_pms[] = {
        MLXSW_SP_SB_PM(10000, 90000),
 };
 
-#define MLXSW_SP_SB_PMS_LEN ARRAY_SIZE(mlxsw_sp_sb_pms)
+static const struct mlxsw_sp_sb_pm mlxsw_sp2_sb_pms[] = {
+       /* Ingress pools. */
+       MLXSW_SP_SB_PM(0, 7),
+       MLXSW_SP_SB_PM(0, 0),
+       MLXSW_SP_SB_PM(0, 0),
+       MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MAX),
+       /* Egress pools. */
+       MLXSW_SP_SB_PM(0, 7),
+       MLXSW_SP_SB_PM(0, 0),
+       MLXSW_SP_SB_PM(0, 0),
+       MLXSW_SP_SB_PM(0, 0),
+};
 
 static int mlxsw_sp_port_sb_pms_init(struct mlxsw_sp_port *mlxsw_sp_port)
 {
@@ -535,8 +679,8 @@ static int mlxsw_sp_port_sb_pms_init(struct mlxsw_sp_port *mlxsw_sp_port)
        int i;
        int err;
 
-       for (i = 0; i < MLXSW_SP_SB_PMS_LEN; i++) {
-               const struct mlxsw_sp_sb_pm *pm = &mlxsw_sp_sb_pms[i];
+       for (i = 0; i < mlxsw_sp->sb_vals->pool_count; i++) {
+               const struct mlxsw_sp_sb_pm *pm = &mlxsw_sp->sb_vals->pms[i];
                u32 max_buff;
                u32 min_buff;
 
@@ -552,12 +696,6 @@ static int mlxsw_sp_port_sb_pms_init(struct mlxsw_sp_port *mlxsw_sp_port)
        return 0;
 }
 
-struct mlxsw_sp_sb_mm {
-       u32 min_buff;
-       u32 max_buff;
-       u16 pool_index;
-};
-
 #define MLXSW_SP_SB_MM(_min_buff, _max_buff, _pool)    \
        {                                               \
                .min_buff = _min_buff,                  \
@@ -583,21 +721,19 @@ static const struct mlxsw_sp_sb_mm mlxsw_sp_sb_mms[] = {
        MLXSW_SP_SB_MM(0, 6, 4),
 };
 
-#define MLXSW_SP_SB_MMS_LEN ARRAY_SIZE(mlxsw_sp_sb_mms)
-
 static int mlxsw_sp_sb_mms_init(struct mlxsw_sp *mlxsw_sp)
 {
        char sbmm_pl[MLXSW_REG_SBMM_LEN];
        int i;
        int err;
 
-       for (i = 0; i < MLXSW_SP_SB_MMS_LEN; i++) {
+       for (i = 0; i < mlxsw_sp->sb_vals->mms_count; i++) {
                const struct mlxsw_sp_sb_pool_des *des;
                const struct mlxsw_sp_sb_mm *mc;
                u32 min_buff;
 
-               mc = &mlxsw_sp_sb_mms[i];
-               des = &mlxsw_sp_sb_pool_dess[mc->pool_index];
+               mc = &mlxsw_sp->sb_vals->mms[i];
+               des = &mlxsw_sp->sb_vals->pool_dess[mc->pool_index];
                /* All pools used by sb_mm's are initialized using dynamic
                 * thresholds, therefore 'max_buff' isn't specified in cells.
                 */
@@ -611,22 +747,55 @@ static int mlxsw_sp_sb_mms_init(struct mlxsw_sp *mlxsw_sp)
        return 0;
 }
 
-static void mlxsw_sp_pool_count(u16 *p_ingress_len, u16 *p_egress_len)
+static void mlxsw_sp_pool_count(struct mlxsw_sp *mlxsw_sp,
+                               u16 *p_ingress_len, u16 *p_egress_len)
 {
        int i;
 
-       for (i = 0; i < MLXSW_SP_SB_POOL_DESS_LEN; ++i)
-               if (mlxsw_sp_sb_pool_dess[i].dir == MLXSW_REG_SBXX_DIR_EGRESS)
+       for (i = 0; i < mlxsw_sp->sb_vals->pool_count; ++i)
+               if (mlxsw_sp->sb_vals->pool_dess[i].dir ==
+                   MLXSW_REG_SBXX_DIR_EGRESS)
                        goto out;
        WARN(1, "No egress pools\n");
 
 out:
        *p_ingress_len = i;
-       *p_egress_len = MLXSW_SP_SB_POOL_DESS_LEN - i;
+       *p_egress_len = mlxsw_sp->sb_vals->pool_count - i;
 }
 
+const struct mlxsw_sp_sb_vals mlxsw_sp1_sb_vals = {
+       .pool_count = ARRAY_SIZE(mlxsw_sp1_sb_pool_dess),
+       .pool_dess = mlxsw_sp1_sb_pool_dess,
+       .pms = mlxsw_sp1_sb_pms,
+       .prs = mlxsw_sp1_sb_prs,
+       .mms = mlxsw_sp_sb_mms,
+       .cms_ingress = mlxsw_sp1_sb_cms_ingress,
+       .cms_egress = mlxsw_sp1_sb_cms_egress,
+       .cms_cpu = mlxsw_sp_cpu_port_sb_cms,
+       .mms_count = ARRAY_SIZE(mlxsw_sp_sb_mms),
+       .cms_ingress_count = ARRAY_SIZE(mlxsw_sp1_sb_cms_ingress),
+       .cms_egress_count = ARRAY_SIZE(mlxsw_sp1_sb_cms_egress),
+       .cms_cpu_count = ARRAY_SIZE(mlxsw_sp_cpu_port_sb_cms),
+};
+
+const struct mlxsw_sp_sb_vals mlxsw_sp2_sb_vals = {
+       .pool_count = ARRAY_SIZE(mlxsw_sp2_sb_pool_dess),
+       .pool_dess = mlxsw_sp2_sb_pool_dess,
+       .pms = mlxsw_sp2_sb_pms,
+       .prs = mlxsw_sp2_sb_prs,
+       .mms = mlxsw_sp_sb_mms,
+       .cms_ingress = mlxsw_sp2_sb_cms_ingress,
+       .cms_egress = mlxsw_sp2_sb_cms_egress,
+       .cms_cpu = mlxsw_sp_cpu_port_sb_cms,
+       .mms_count = ARRAY_SIZE(mlxsw_sp_sb_mms),
+       .cms_ingress_count = ARRAY_SIZE(mlxsw_sp2_sb_cms_ingress),
+       .cms_egress_count = ARRAY_SIZE(mlxsw_sp2_sb_cms_egress),
+       .cms_cpu_count = ARRAY_SIZE(mlxsw_sp_cpu_port_sb_cms),
+};
+
 int mlxsw_sp_buffers_init(struct mlxsw_sp *mlxsw_sp)
 {
+       u32 max_headroom_size;
        u16 ing_pool_count;
        u16 eg_pool_count;
        int err;
@@ -637,18 +806,26 @@ int mlxsw_sp_buffers_init(struct mlxsw_sp *mlxsw_sp)
        if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_BUFFER_SIZE))
                return -EIO;
 
+       if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_HEADROOM_SIZE))
+               return -EIO;
+
        mlxsw_sp->sb = kzalloc(sizeof(*mlxsw_sp->sb), GFP_KERNEL);
        if (!mlxsw_sp->sb)
                return -ENOMEM;
        mlxsw_sp->sb->cell_size = MLXSW_CORE_RES_GET(mlxsw_sp->core, CELL_SIZE);
        mlxsw_sp->sb->sb_size = MLXSW_CORE_RES_GET(mlxsw_sp->core,
                                                   MAX_BUFFER_SIZE);
+       max_headroom_size = MLXSW_CORE_RES_GET(mlxsw_sp->core,
+                                              MAX_HEADROOM_SIZE);
+       /* Round down, because this limit must not be overstepped. */
+       mlxsw_sp->sb->max_headroom_cells = max_headroom_size /
+                                               mlxsw_sp->sb->cell_size;
 
        err = mlxsw_sp_sb_ports_init(mlxsw_sp);
        if (err)
                goto err_sb_ports_init;
-       err = mlxsw_sp_sb_prs_init(mlxsw_sp, mlxsw_sp_sb_prs,
-                                  MLXSW_SP_SB_PRS_LEN);
+       err = mlxsw_sp_sb_prs_init(mlxsw_sp, mlxsw_sp->sb_vals->prs,
+                                  mlxsw_sp->sb_vals->pool_count);
        if (err)
                goto err_sb_prs_init;
        err = mlxsw_sp_cpu_port_sb_cms_init(mlxsw_sp);
@@ -657,7 +834,7 @@ int mlxsw_sp_buffers_init(struct mlxsw_sp *mlxsw_sp)
        err = mlxsw_sp_sb_mms_init(mlxsw_sp);
        if (err)
                goto err_sb_mms_init;
-       mlxsw_sp_pool_count(&ing_pool_count, &eg_pool_count);
+       mlxsw_sp_pool_count(mlxsw_sp, &ing_pool_count, &eg_pool_count);
        err = devlink_sb_register(priv_to_devlink(mlxsw_sp->core), 0,
                                  mlxsw_sp->sb->sb_size,
                                  ing_pool_count,
@@ -705,10 +882,11 @@ int mlxsw_sp_sb_pool_get(struct mlxsw_core *mlxsw_core,
                         unsigned int sb_index, u16 pool_index,
                         struct devlink_sb_pool_info *pool_info)
 {
-       enum mlxsw_reg_sbxx_dir dir = mlxsw_sp_sb_pool_dess[pool_index].dir;
        struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
+       enum mlxsw_reg_sbxx_dir dir;
        struct mlxsw_sp_sb_pr *pr;
 
+       dir = mlxsw_sp->sb_vals->pool_dess[pool_index].dir;
        pr = mlxsw_sp_sb_pr_get(mlxsw_sp, pool_index);
        pool_info->pool_type = (enum devlink_sb_pool_type) dir;
        pool_info->size = mlxsw_sp_cells_bytes(mlxsw_sp, pr->size);
@@ -834,7 +1012,7 @@ int mlxsw_sp_sb_tc_pool_bind_set(struct mlxsw_core_port *mlxsw_core_port,
        u32 max_buff;
        int err;
 
-       if (dir != mlxsw_sp_sb_pool_dess[pool_index].dir)
+       if (dir != mlxsw_sp->sb_vals->pool_dess[pool_index].dir)
                return -EINVAL;
 
        err = mlxsw_sp_sb_threshold_in(mlxsw_sp, pool_index,
@@ -932,7 +1110,7 @@ next_batch:
                        continue;
                mlxsw_reg_sbsr_ingress_port_mask_set(sbsr_pl, local_port, 1);
                mlxsw_reg_sbsr_egress_port_mask_set(sbsr_pl, local_port, 1);
-               for (i = 0; i < MLXSW_SP_SB_POOL_DESS_LEN; i++) {
+               for (i = 0; i < mlxsw_sp->sb_vals->pool_count; i++) {
                        err = mlxsw_sp_sb_pm_occ_query(mlxsw_sp, local_port, i,
                                                       &bulk_list);
                        if (err)
@@ -991,7 +1169,7 @@ next_batch:
                        continue;
                mlxsw_reg_sbsr_ingress_port_mask_set(sbsr_pl, local_port, 1);
                mlxsw_reg_sbsr_egress_port_mask_set(sbsr_pl, local_port, 1);
-               for (i = 0; i < MLXSW_SP_SB_POOL_DESS_LEN; i++) {
+               for (i = 0; i < mlxsw_sp->sb_vals->pool_count; i++) {
                        err = mlxsw_sp_sb_pm_occ_clear(mlxsw_sp, local_port, i,
                                                       &bulk_list);
                        if (err)