Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: (GPL-2.0 OR MIT)
0002 /* Copyright 2020-2021 NXP
0003  */
0004 #include <net/devlink.h>
0005 #include "ocelot.h"
0006 
0007 /* The queue system tracks four resource consumptions:
0008  * Resource 0: Memory tracked per source port
0009  * Resource 1: Frame references tracked per source port
0010  * Resource 2: Memory tracked per destination port
0011  * Resource 3: Frame references tracked per destination port
0012  */
0013 #define OCELOT_RESOURCE_SZ      256
0014 #define OCELOT_NUM_RESOURCES        4
0015 
0016 #define BUF_xxxx_I          (0 * OCELOT_RESOURCE_SZ)
0017 #define REF_xxxx_I          (1 * OCELOT_RESOURCE_SZ)
0018 #define BUF_xxxx_E          (2 * OCELOT_RESOURCE_SZ)
0019 #define REF_xxxx_E          (3 * OCELOT_RESOURCE_SZ)
0020 
0021 /* For each resource type there are 4 types of watermarks:
0022  * Q_RSRV: reservation per QoS class per port
0023  * PRIO_SHR: sharing watermark per QoS class across all ports
0024  * P_RSRV: reservation per port
0025  * COL_SHR: sharing watermark per color (drop precedence) across all ports
0026  */
0027 #define xxx_Q_RSRV_x            0
0028 #define xxx_PRIO_SHR_x          216
0029 #define xxx_P_RSRV_x            224
0030 #define xxx_COL_SHR_x           254
0031 
0032 /* Reservation Watermarks
0033  * ----------------------
0034  *
0035  * For setting up the reserved areas, egress watermarks exist per port and per
0036  * QoS class for both ingress and egress.
0037  */
0038 
0039 /*  Amount of packet buffer
0040  *  |  per QoS class
0041  *  |  |  reserved
0042  *  |  |  |   per egress port
0043  *  |  |  |   |
0044  *  V  V  v   v
0045  * BUF_Q_RSRV_E
0046  */
0047 #define BUF_Q_RSRV_E(port, prio) \
0048     (BUF_xxxx_E + xxx_Q_RSRV_x + OCELOT_NUM_TC * (port) + (prio))
0049 
0050 /*  Amount of packet buffer
0051  *  |  for all port's traffic classes
0052  *  |  |  reserved
0053  *  |  |  |   per egress port
0054  *  |  |  |   |
0055  *  V  V  v   v
0056  * BUF_P_RSRV_E
0057  */
0058 #define BUF_P_RSRV_E(port) \
0059     (BUF_xxxx_E + xxx_P_RSRV_x + (port))
0060 
0061 /*  Amount of packet buffer
0062  *  |  per QoS class
0063  *  |  |  reserved
0064  *  |  |  |   per ingress port
0065  *  |  |  |   |
0066  *  V  V  v   v
0067  * BUF_Q_RSRV_I
0068  */
0069 #define BUF_Q_RSRV_I(port, prio) \
0070     (BUF_xxxx_I + xxx_Q_RSRV_x + OCELOT_NUM_TC * (port) + (prio))
0071 
0072 /*  Amount of packet buffer
0073  *  |  for all port's traffic classes
0074  *  |  |  reserved
0075  *  |  |  |   per ingress port
0076  *  |  |  |   |
0077  *  V  V  v   v
0078  * BUF_P_RSRV_I
0079  */
0080 #define BUF_P_RSRV_I(port) \
0081     (BUF_xxxx_I + xxx_P_RSRV_x + (port))
0082 
0083 /*  Amount of frame references
0084  *  |  per QoS class
0085  *  |  |  reserved
0086  *  |  |  |   per egress port
0087  *  |  |  |   |
0088  *  V  V  v   v
0089  * REF_Q_RSRV_E
0090  */
0091 #define REF_Q_RSRV_E(port, prio) \
0092     (REF_xxxx_E + xxx_Q_RSRV_x + OCELOT_NUM_TC * (port) + (prio))
0093 
0094 /*  Amount of frame references
0095  *  |  for all port's traffic classes
0096  *  |  |  reserved
0097  *  |  |  |   per egress port
0098  *  |  |  |   |
0099  *  V  V  v   v
0100  * REF_P_RSRV_E
0101  */
0102 #define REF_P_RSRV_E(port) \
0103     (REF_xxxx_E + xxx_P_RSRV_x + (port))
0104 
0105 /*  Amount of frame references
0106  *  |  per QoS class
0107  *  |  |  reserved
0108  *  |  |  |   per ingress port
0109  *  |  |  |   |
0110  *  V  V  v   v
0111  * REF_Q_RSRV_I
0112  */
0113 #define REF_Q_RSRV_I(port, prio) \
0114     (REF_xxxx_I + xxx_Q_RSRV_x + OCELOT_NUM_TC * (port) + (prio))
0115 
0116 /*  Amount of frame references
0117  *  |  for all port's traffic classes
0118  *  |  |  reserved
0119  *  |  |  |   per ingress port
0120  *  |  |  |   |
0121  *  V  V  v   v
0122  * REF_P_RSRV_I
0123  */
0124 #define REF_P_RSRV_I(port) \
0125     (REF_xxxx_I + xxx_P_RSRV_x + (port))
0126 
0127 /* Sharing Watermarks
0128  * ------------------
0129  *
0130  * The shared memory area is shared between all ports.
0131  */
0132 
0133 /* Amount of buffer
0134  *  |   per QoS class
0135  *  |   |    from the shared memory area
0136  *  |   |    |  for egress traffic
0137  *  |   |    |  |
0138  *  V   V    v  v
0139  * BUF_PRIO_SHR_E
0140  */
0141 #define BUF_PRIO_SHR_E(prio) \
0142     (BUF_xxxx_E + xxx_PRIO_SHR_x + (prio))
0143 
0144 /* Amount of buffer
0145  *  |   per color (drop precedence level)
0146  *  |   |   from the shared memory area
0147  *  |   |   |  for egress traffic
0148  *  |   |   |  |
0149  *  V   V   v  v
0150  * BUF_COL_SHR_E
0151  */
0152 #define BUF_COL_SHR_E(dp) \
0153     (BUF_xxxx_E + xxx_COL_SHR_x + (1 - (dp)))
0154 
0155 /* Amount of buffer
0156  *  |   per QoS class
0157  *  |   |    from the shared memory area
0158  *  |   |    |  for ingress traffic
0159  *  |   |    |  |
0160  *  V   V    v  v
0161  * BUF_PRIO_SHR_I
0162  */
0163 #define BUF_PRIO_SHR_I(prio) \
0164     (BUF_xxxx_I + xxx_PRIO_SHR_x + (prio))
0165 
0166 /* Amount of buffer
0167  *  |   per color (drop precedence level)
0168  *  |   |   from the shared memory area
0169  *  |   |   |  for ingress traffic
0170  *  |   |   |  |
0171  *  V   V   v  v
0172  * BUF_COL_SHR_I
0173  */
0174 #define BUF_COL_SHR_I(dp) \
0175     (BUF_xxxx_I + xxx_COL_SHR_x + (1 - (dp)))
0176 
0177 /* Amount of frame references
0178  *  |   per QoS class
0179  *  |   |    from the shared area
0180  *  |   |    |  for egress traffic
0181  *  |   |    |  |
0182  *  V   V    v  v
0183  * REF_PRIO_SHR_E
0184  */
0185 #define REF_PRIO_SHR_E(prio) \
0186     (REF_xxxx_E + xxx_PRIO_SHR_x + (prio))
0187 
0188 /* Amount of frame references
0189  *  |   per color (drop precedence level)
0190  *  |   |   from the shared area
0191  *  |   |   |  for egress traffic
0192  *  |   |   |  |
0193  *  V   V   v  v
0194  * REF_COL_SHR_E
0195  */
0196 #define REF_COL_SHR_E(dp) \
0197     (REF_xxxx_E + xxx_COL_SHR_x + (1 - (dp)))
0198 
0199 /* Amount of frame references
0200  *  |   per QoS class
0201  *  |   |    from the shared area
0202  *  |   |    |  for ingress traffic
0203  *  |   |    |  |
0204  *  V   V    v  v
0205  * REF_PRIO_SHR_I
0206  */
0207 #define REF_PRIO_SHR_I(prio) \
0208     (REF_xxxx_I + xxx_PRIO_SHR_x + (prio))
0209 
0210 /* Amount of frame references
0211  *  |   per color (drop precedence level)
0212  *  |   |   from the shared area
0213  *  |   |   |  for ingress traffic
0214  *  |   |   |  |
0215  *  V   V   v  v
0216  * REF_COL_SHR_I
0217  */
0218 #define REF_COL_SHR_I(dp) \
0219     (REF_xxxx_I + xxx_COL_SHR_x + (1 - (dp)))
0220 
0221 static u32 ocelot_wm_read(struct ocelot *ocelot, int index)
0222 {
0223     int wm = ocelot_read_gix(ocelot, QSYS_RES_CFG, index);
0224 
0225     return ocelot->ops->wm_dec(wm);
0226 }
0227 
0228 static void ocelot_wm_write(struct ocelot *ocelot, int index, u32 val)
0229 {
0230     u32 wm = ocelot->ops->wm_enc(val);
0231 
0232     ocelot_write_gix(ocelot, wm, QSYS_RES_CFG, index);
0233 }
0234 
0235 static void ocelot_wm_status(struct ocelot *ocelot, int index, u32 *inuse,
0236                  u32 *maxuse)
0237 {
0238     int res_stat = ocelot_read_gix(ocelot, QSYS_RES_STAT, index);
0239 
0240     return ocelot->ops->wm_stat(res_stat, inuse, maxuse);
0241 }
0242 
0243 /* The hardware comes out of reset with strange defaults: the sum of all
0244  * reservations for frame memory is larger than the total buffer size.
0245  * One has to wonder how can the reservation watermarks still guarantee
0246  * anything under congestion.
0247  * Bring some sense into the hardware by changing the defaults to disable all
0248  * reservations and rely only on the sharing watermark for frames with drop
0249  * precedence 0. The user can still explicitly request reservations per port
0250  * and per port-tc through devlink-sb.
0251  */
0252 static void ocelot_disable_reservation_watermarks(struct ocelot *ocelot,
0253                           int port)
0254 {
0255     int prio;
0256 
0257     for (prio = 0; prio < OCELOT_NUM_TC; prio++) {
0258         ocelot_wm_write(ocelot, BUF_Q_RSRV_I(port, prio), 0);
0259         ocelot_wm_write(ocelot, BUF_Q_RSRV_E(port, prio), 0);
0260         ocelot_wm_write(ocelot, REF_Q_RSRV_I(port, prio), 0);
0261         ocelot_wm_write(ocelot, REF_Q_RSRV_E(port, prio), 0);
0262     }
0263 
0264     ocelot_wm_write(ocelot, BUF_P_RSRV_I(port), 0);
0265     ocelot_wm_write(ocelot, BUF_P_RSRV_E(port), 0);
0266     ocelot_wm_write(ocelot, REF_P_RSRV_I(port), 0);
0267     ocelot_wm_write(ocelot, REF_P_RSRV_E(port), 0);
0268 }
0269 
0270 /* We want the sharing watermarks to consume all nonreserved resources, for
0271  * efficient resource utilization (a single traffic flow should be able to use
0272  * up the entire buffer space and frame resources as long as there's no
0273  * interference).
0274  * The switch has 10 sharing watermarks per lookup: 8 per traffic class and 2
0275  * per color (drop precedence).
0276  * The trouble with configuring these sharing watermarks is that:
0277  * (1) There's a risk that we overcommit the resources if we configure
0278  *     (a) all 8 per-TC sharing watermarks to the max
0279  *     (b) all 2 per-color sharing watermarks to the max
0280  * (2) There's a risk that we undercommit the resources if we configure
0281  *     (a) all 8 per-TC sharing watermarks to "max / 8"
0282  *     (b) all 2 per-color sharing watermarks to "max / 2"
0283  * So for Linux, let's just disable the sharing watermarks per traffic class
0284  * (setting them to 0 will make them always exceeded), and rely only on the
0285  * sharing watermark for drop priority 0. So frames with drop priority set to 1
0286  * by QoS classification or policing will still be allowed, but only as long as
0287  * the port and port-TC reservations are not exceeded.
0288  */
0289 static void ocelot_disable_tc_sharing_watermarks(struct ocelot *ocelot)
0290 {
0291     int prio;
0292 
0293     for (prio = 0; prio < OCELOT_NUM_TC; prio++) {
0294         ocelot_wm_write(ocelot, BUF_PRIO_SHR_I(prio), 0);
0295         ocelot_wm_write(ocelot, BUF_PRIO_SHR_E(prio), 0);
0296         ocelot_wm_write(ocelot, REF_PRIO_SHR_I(prio), 0);
0297         ocelot_wm_write(ocelot, REF_PRIO_SHR_E(prio), 0);
0298     }
0299 }
0300 
0301 static void ocelot_get_buf_rsrv(struct ocelot *ocelot, u32 *buf_rsrv_i,
0302                 u32 *buf_rsrv_e)
0303 {
0304     int port, prio;
0305 
0306     *buf_rsrv_i = 0;
0307     *buf_rsrv_e = 0;
0308 
0309     for (port = 0; port <= ocelot->num_phys_ports; port++) {
0310         for (prio = 0; prio < OCELOT_NUM_TC; prio++) {
0311             *buf_rsrv_i += ocelot_wm_read(ocelot,
0312                               BUF_Q_RSRV_I(port, prio));
0313             *buf_rsrv_e += ocelot_wm_read(ocelot,
0314                               BUF_Q_RSRV_E(port, prio));
0315         }
0316 
0317         *buf_rsrv_i += ocelot_wm_read(ocelot, BUF_P_RSRV_I(port));
0318         *buf_rsrv_e += ocelot_wm_read(ocelot, BUF_P_RSRV_E(port));
0319     }
0320 
0321     *buf_rsrv_i *= OCELOT_BUFFER_CELL_SZ;
0322     *buf_rsrv_e *= OCELOT_BUFFER_CELL_SZ;
0323 }
0324 
0325 static void ocelot_get_ref_rsrv(struct ocelot *ocelot, u32 *ref_rsrv_i,
0326                 u32 *ref_rsrv_e)
0327 {
0328     int port, prio;
0329 
0330     *ref_rsrv_i = 0;
0331     *ref_rsrv_e = 0;
0332 
0333     for (port = 0; port <= ocelot->num_phys_ports; port++) {
0334         for (prio = 0; prio < OCELOT_NUM_TC; prio++) {
0335             *ref_rsrv_i += ocelot_wm_read(ocelot,
0336                               REF_Q_RSRV_I(port, prio));
0337             *ref_rsrv_e += ocelot_wm_read(ocelot,
0338                               REF_Q_RSRV_E(port, prio));
0339         }
0340 
0341         *ref_rsrv_i += ocelot_wm_read(ocelot, REF_P_RSRV_I(port));
0342         *ref_rsrv_e += ocelot_wm_read(ocelot, REF_P_RSRV_E(port));
0343     }
0344 }
0345 
0346 /* Calculate all reservations, then set up the sharing watermark for DP=0 to
0347  * consume the remaining resources up to the pool's configured size.
0348  */
0349 static void ocelot_setup_sharing_watermarks(struct ocelot *ocelot)
0350 {
0351     u32 buf_rsrv_i, buf_rsrv_e;
0352     u32 ref_rsrv_i, ref_rsrv_e;
0353     u32 buf_shr_i, buf_shr_e;
0354     u32 ref_shr_i, ref_shr_e;
0355 
0356     ocelot_get_buf_rsrv(ocelot, &buf_rsrv_i, &buf_rsrv_e);
0357     ocelot_get_ref_rsrv(ocelot, &ref_rsrv_i, &ref_rsrv_e);
0358 
0359     buf_shr_i = ocelot->pool_size[OCELOT_SB_BUF][OCELOT_SB_POOL_ING] -
0360             buf_rsrv_i;
0361     buf_shr_e = ocelot->pool_size[OCELOT_SB_BUF][OCELOT_SB_POOL_EGR] -
0362             buf_rsrv_e;
0363     ref_shr_i = ocelot->pool_size[OCELOT_SB_REF][OCELOT_SB_POOL_ING] -
0364             ref_rsrv_i;
0365     ref_shr_e = ocelot->pool_size[OCELOT_SB_REF][OCELOT_SB_POOL_EGR] -
0366             ref_rsrv_e;
0367 
0368     buf_shr_i /= OCELOT_BUFFER_CELL_SZ;
0369     buf_shr_e /= OCELOT_BUFFER_CELL_SZ;
0370 
0371     ocelot_wm_write(ocelot, BUF_COL_SHR_I(0), buf_shr_i);
0372     ocelot_wm_write(ocelot, BUF_COL_SHR_E(0), buf_shr_e);
0373     ocelot_wm_write(ocelot, REF_COL_SHR_E(0), ref_shr_e);
0374     ocelot_wm_write(ocelot, REF_COL_SHR_I(0), ref_shr_i);
0375     ocelot_wm_write(ocelot, BUF_COL_SHR_I(1), 0);
0376     ocelot_wm_write(ocelot, BUF_COL_SHR_E(1), 0);
0377     ocelot_wm_write(ocelot, REF_COL_SHR_E(1), 0);
0378     ocelot_wm_write(ocelot, REF_COL_SHR_I(1), 0);
0379 }
0380 
0381 /* Ensure that all reservations can be enforced */
0382 static int ocelot_watermark_validate(struct ocelot *ocelot,
0383                      struct netlink_ext_ack *extack)
0384 {
0385     u32 buf_rsrv_i, buf_rsrv_e;
0386     u32 ref_rsrv_i, ref_rsrv_e;
0387 
0388     ocelot_get_buf_rsrv(ocelot, &buf_rsrv_i, &buf_rsrv_e);
0389     ocelot_get_ref_rsrv(ocelot, &ref_rsrv_i, &ref_rsrv_e);
0390 
0391     if (buf_rsrv_i > ocelot->pool_size[OCELOT_SB_BUF][OCELOT_SB_POOL_ING]) {
0392         NL_SET_ERR_MSG_MOD(extack,
0393                    "Ingress frame reservations exceed pool size");
0394         return -ERANGE;
0395     }
0396     if (buf_rsrv_e > ocelot->pool_size[OCELOT_SB_BUF][OCELOT_SB_POOL_EGR]) {
0397         NL_SET_ERR_MSG_MOD(extack,
0398                    "Egress frame reservations exceed pool size");
0399         return -ERANGE;
0400     }
0401     if (ref_rsrv_i > ocelot->pool_size[OCELOT_SB_REF][OCELOT_SB_POOL_ING]) {
0402         NL_SET_ERR_MSG_MOD(extack,
0403                    "Ingress reference reservations exceed pool size");
0404         return -ERANGE;
0405     }
0406     if (ref_rsrv_e > ocelot->pool_size[OCELOT_SB_REF][OCELOT_SB_POOL_EGR]) {
0407         NL_SET_ERR_MSG_MOD(extack,
0408                    "Egress reference reservations exceed pool size");
0409         return -ERANGE;
0410     }
0411 
0412     return 0;
0413 }
0414 
0415 /* The hardware works like this:
0416  *
0417  *                         Frame forwarding decision taken
0418  *                                       |
0419  *                                       v
0420  *       +--------------------+--------------------+--------------------+
0421  *       |                    |                    |                    |
0422  *       v                    v                    v                    v
0423  * Ingress memory       Egress memory        Ingress frame        Egress frame
0424  *     check                check           reference check      reference check
0425  *       |                    |                    |                    |
0426  *       v                    v                    v                    v
0427  *  BUF_Q_RSRV_I   ok    BUF_Q_RSRV_E   ok    REF_Q_RSRV_I   ok     REF_Q_RSRV_E   ok
0428  *(src port, prio) -+  (dst port, prio) -+  (src port, prio) -+   (dst port, prio) -+
0429  *       |          |         |          |         |          |         |           |
0430  *       |exceeded  |         |exceeded  |         |exceeded  |         |exceeded   |
0431  *       v          |         v          |         v          |         v           |
0432  *  BUF_P_RSRV_I  ok|    BUF_P_RSRV_E  ok|    REF_P_RSRV_I  ok|    REF_P_RSRV_E   ok|
0433  *   (src port) ----+     (dst port) ----+     (src port) ----+     (dst port) -----+
0434  *       |          |         |          |         |          |         |           |
0435  *       |exceeded  |         |exceeded  |         |exceeded  |         |exceeded   |
0436  *       v          |         v          |         v          |         v           |
0437  * BUF_PRIO_SHR_I ok|   BUF_PRIO_SHR_E ok|   REF_PRIO_SHR_I ok|   REF_PRIO_SHR_E  ok|
0438  *     (prio) ------+       (prio) ------+       (prio) ------+       (prio) -------+
0439  *       |          |         |          |         |          |         |           |
0440  *       |exceeded  |         |exceeded  |         |exceeded  |         |exceeded   |
0441  *       v          |         v          |         v          |         v           |
0442  * BUF_COL_SHR_I  ok|   BUF_COL_SHR_E  ok|   REF_COL_SHR_I  ok|   REF_COL_SHR_E   ok|
0443  *      (dp) -------+        (dp) -------+        (dp) -------+        (dp) --------+
0444  *       |          |         |          |         |          |         |           |
0445  *       |exceeded  |         |exceeded  |         |exceeded  |         |exceeded   |
0446  *       v          v         v          v         v          v         v           v
0447  *      fail     success     fail     success     fail     success     fail      success
0448  *       |          |         |          |         |          |         |           |
0449  *       v          v         v          v         v          v         v           v
0450  *       +-----+----+         +-----+----+         +-----+----+         +-----+-----+
0451  *             |                    |                    |                    |
0452  *             +-------> OR <-------+                    +-------> OR <-------+
0453  *                        |                                        |
0454  *                        v                                        v
0455  *                        +----------------> AND <-----------------+
0456  *                                            |
0457  *                                            v
0458  *                                    FIFO drop / accept
0459  *
0460  * We are modeling each of the 4 parallel lookups as a devlink-sb pool.
0461  * At least one (ingress or egress) memory pool and one (ingress or egress)
0462  * frame reference pool need to have resources for frame acceptance to succeed.
0463  *
0464  * The following watermarks are controlled explicitly through devlink-sb:
0465  * BUF_Q_RSRV_I, BUF_Q_RSRV_E, REF_Q_RSRV_I, REF_Q_RSRV_E
0466  * BUF_P_RSRV_I, BUF_P_RSRV_E, REF_P_RSRV_I, REF_P_RSRV_E
0467  * The following watermarks are controlled implicitly through devlink-sb:
0468  * BUF_COL_SHR_I, BUF_COL_SHR_E, REF_COL_SHR_I, REF_COL_SHR_E
0469  * The following watermarks are unused and disabled:
0470  * BUF_PRIO_SHR_I, BUF_PRIO_SHR_E, REF_PRIO_SHR_I, REF_PRIO_SHR_E
0471  *
0472  * This function overrides the hardware defaults with more sane ones (no
0473  * reservations by default, let sharing use all resources) and disables the
0474  * unused watermarks.
0475  */
0476 static void ocelot_watermark_init(struct ocelot *ocelot)
0477 {
0478     int all_tcs = GENMASK(OCELOT_NUM_TC - 1, 0);
0479     int port;
0480 
0481     ocelot_write(ocelot, all_tcs, QSYS_RES_QOS_MODE);
0482 
0483     for (port = 0; port <= ocelot->num_phys_ports; port++)
0484         ocelot_disable_reservation_watermarks(ocelot, port);
0485 
0486     ocelot_disable_tc_sharing_watermarks(ocelot);
0487     ocelot_setup_sharing_watermarks(ocelot);
0488 }
0489 
0490 /* Pool size and type are fixed up at runtime. Keeping this structure to
0491  * look up the cell size multipliers.
0492  */
0493 static const struct devlink_sb_pool_info ocelot_sb_pool[] = {
0494     [OCELOT_SB_BUF] = {
0495         .cell_size = OCELOT_BUFFER_CELL_SZ,
0496         .threshold_type = DEVLINK_SB_THRESHOLD_TYPE_STATIC,
0497     },
0498     [OCELOT_SB_REF] = {
0499         .cell_size = 1,
0500         .threshold_type = DEVLINK_SB_THRESHOLD_TYPE_STATIC,
0501     },
0502 };
0503 
0504 /* Returns the pool size configured through ocelot_sb_pool_set */
0505 int ocelot_sb_pool_get(struct ocelot *ocelot, unsigned int sb_index,
0506                u16 pool_index,
0507                struct devlink_sb_pool_info *pool_info)
0508 {
0509     if (sb_index >= OCELOT_SB_NUM)
0510         return -ENODEV;
0511     if (pool_index >= OCELOT_SB_POOL_NUM)
0512         return -ENODEV;
0513 
0514     *pool_info = ocelot_sb_pool[sb_index];
0515     pool_info->size = ocelot->pool_size[sb_index][pool_index];
0516     if (pool_index)
0517         pool_info->pool_type = DEVLINK_SB_POOL_TYPE_INGRESS;
0518     else
0519         pool_info->pool_type = DEVLINK_SB_POOL_TYPE_EGRESS;
0520 
0521     return 0;
0522 }
0523 EXPORT_SYMBOL(ocelot_sb_pool_get);
0524 
0525 /* The pool size received here configures the total amount of resources used on
0526  * ingress (or on egress, depending upon the pool index). The pool size, minus
0527  * the values for the port and port-tc reservations, is written into the
0528  * COL_SHR(dp=0) sharing watermark.
0529  */
0530 int ocelot_sb_pool_set(struct ocelot *ocelot, unsigned int sb_index,
0531                u16 pool_index, u32 size,
0532                enum devlink_sb_threshold_type threshold_type,
0533                struct netlink_ext_ack *extack)
0534 {
0535     u32 old_pool_size;
0536     int err;
0537 
0538     if (sb_index >= OCELOT_SB_NUM) {
0539         NL_SET_ERR_MSG_MOD(extack,
0540                    "Invalid sb, use 0 for buffers and 1 for frame references");
0541         return -ENODEV;
0542     }
0543     if (pool_index >= OCELOT_SB_POOL_NUM) {
0544         NL_SET_ERR_MSG_MOD(extack,
0545                    "Invalid pool, use 0 for ingress and 1 for egress");
0546         return -ENODEV;
0547     }
0548     if (threshold_type != DEVLINK_SB_THRESHOLD_TYPE_STATIC) {
0549         NL_SET_ERR_MSG_MOD(extack,
0550                    "Only static threshold supported");
0551         return -EOPNOTSUPP;
0552     }
0553 
0554     old_pool_size = ocelot->pool_size[sb_index][pool_index];
0555     ocelot->pool_size[sb_index][pool_index] = size;
0556 
0557     err = ocelot_watermark_validate(ocelot, extack);
0558     if (err) {
0559         ocelot->pool_size[sb_index][pool_index] = old_pool_size;
0560         return err;
0561     }
0562 
0563     ocelot_setup_sharing_watermarks(ocelot);
0564 
0565     return 0;
0566 }
0567 EXPORT_SYMBOL(ocelot_sb_pool_set);
0568 
0569 /* This retrieves the configuration made with ocelot_sb_port_pool_set */
0570 int ocelot_sb_port_pool_get(struct ocelot *ocelot, int port,
0571                 unsigned int sb_index, u16 pool_index,
0572                 u32 *p_threshold)
0573 {
0574     int wm_index;
0575 
0576     switch (sb_index) {
0577     case OCELOT_SB_BUF:
0578         if (pool_index == OCELOT_SB_POOL_ING)
0579             wm_index = BUF_P_RSRV_I(port);
0580         else
0581             wm_index = BUF_P_RSRV_E(port);
0582         break;
0583     case OCELOT_SB_REF:
0584         if (pool_index == OCELOT_SB_POOL_ING)
0585             wm_index = REF_P_RSRV_I(port);
0586         else
0587             wm_index = REF_P_RSRV_E(port);
0588         break;
0589     default:
0590         return -ENODEV;
0591     }
0592 
0593     *p_threshold = ocelot_wm_read(ocelot, wm_index);
0594     *p_threshold *= ocelot_sb_pool[sb_index].cell_size;
0595 
0596     return 0;
0597 }
0598 EXPORT_SYMBOL(ocelot_sb_port_pool_get);
0599 
0600 /* This configures the P_RSRV per-port reserved resource watermark */
0601 int ocelot_sb_port_pool_set(struct ocelot *ocelot, int port,
0602                 unsigned int sb_index, u16 pool_index,
0603                 u32 threshold, struct netlink_ext_ack *extack)
0604 {
0605     int wm_index, err;
0606     u32 old_thr;
0607 
0608     switch (sb_index) {
0609     case OCELOT_SB_BUF:
0610         if (pool_index == OCELOT_SB_POOL_ING)
0611             wm_index = BUF_P_RSRV_I(port);
0612         else
0613             wm_index = BUF_P_RSRV_E(port);
0614         break;
0615     case OCELOT_SB_REF:
0616         if (pool_index == OCELOT_SB_POOL_ING)
0617             wm_index = REF_P_RSRV_I(port);
0618         else
0619             wm_index = REF_P_RSRV_E(port);
0620         break;
0621     default:
0622         NL_SET_ERR_MSG_MOD(extack, "Invalid shared buffer");
0623         return -ENODEV;
0624     }
0625 
0626     threshold /= ocelot_sb_pool[sb_index].cell_size;
0627 
0628     old_thr = ocelot_wm_read(ocelot, wm_index);
0629     ocelot_wm_write(ocelot, wm_index, threshold);
0630 
0631     err = ocelot_watermark_validate(ocelot, extack);
0632     if (err) {
0633         ocelot_wm_write(ocelot, wm_index, old_thr);
0634         return err;
0635     }
0636 
0637     ocelot_setup_sharing_watermarks(ocelot);
0638 
0639     return 0;
0640 }
0641 EXPORT_SYMBOL(ocelot_sb_port_pool_set);
0642 
0643 /* This retrieves the configuration done by ocelot_sb_tc_pool_bind_set */
0644 int ocelot_sb_tc_pool_bind_get(struct ocelot *ocelot, int port,
0645                    unsigned int sb_index, u16 tc_index,
0646                    enum devlink_sb_pool_type pool_type,
0647                    u16 *p_pool_index, u32 *p_threshold)
0648 {
0649     int wm_index;
0650 
0651     switch (sb_index) {
0652     case OCELOT_SB_BUF:
0653         if (pool_type == DEVLINK_SB_POOL_TYPE_INGRESS)
0654             wm_index = BUF_Q_RSRV_I(port, tc_index);
0655         else
0656             wm_index = BUF_Q_RSRV_E(port, tc_index);
0657         break;
0658     case OCELOT_SB_REF:
0659         if (pool_type == DEVLINK_SB_POOL_TYPE_INGRESS)
0660             wm_index = REF_Q_RSRV_I(port, tc_index);
0661         else
0662             wm_index = REF_Q_RSRV_E(port, tc_index);
0663         break;
0664     default:
0665         return -ENODEV;
0666     }
0667 
0668     *p_threshold = ocelot_wm_read(ocelot, wm_index);
0669     *p_threshold *= ocelot_sb_pool[sb_index].cell_size;
0670 
0671     if (pool_type == DEVLINK_SB_POOL_TYPE_INGRESS)
0672         *p_pool_index = 0;
0673     else
0674         *p_pool_index = 1;
0675 
0676     return 0;
0677 }
0678 EXPORT_SYMBOL(ocelot_sb_tc_pool_bind_get);
0679 
0680 /* This configures the Q_RSRV per-port-tc reserved resource watermark */
0681 int ocelot_sb_tc_pool_bind_set(struct ocelot *ocelot, int port,
0682                    unsigned int sb_index, u16 tc_index,
0683                    enum devlink_sb_pool_type pool_type,
0684                    u16 pool_index, u32 threshold,
0685                    struct netlink_ext_ack *extack)
0686 {
0687     int wm_index, err;
0688     u32 old_thr;
0689 
0690     /* Paranoid check? */
0691     if (pool_index == OCELOT_SB_POOL_ING &&
0692         pool_type != DEVLINK_SB_POOL_TYPE_INGRESS)
0693         return -EINVAL;
0694     if (pool_index == OCELOT_SB_POOL_EGR &&
0695         pool_type != DEVLINK_SB_POOL_TYPE_EGRESS)
0696         return -EINVAL;
0697 
0698     switch (sb_index) {
0699     case OCELOT_SB_BUF:
0700         if (pool_type == DEVLINK_SB_POOL_TYPE_INGRESS)
0701             wm_index = BUF_Q_RSRV_I(port, tc_index);
0702         else
0703             wm_index = BUF_Q_RSRV_E(port, tc_index);
0704         break;
0705     case OCELOT_SB_REF:
0706         if (pool_type == DEVLINK_SB_POOL_TYPE_INGRESS)
0707             wm_index = REF_Q_RSRV_I(port, tc_index);
0708         else
0709             wm_index = REF_Q_RSRV_E(port, tc_index);
0710         break;
0711     default:
0712         NL_SET_ERR_MSG_MOD(extack, "Invalid shared buffer");
0713         return -ENODEV;
0714     }
0715 
0716     threshold /= ocelot_sb_pool[sb_index].cell_size;
0717 
0718     old_thr = ocelot_wm_read(ocelot, wm_index);
0719     ocelot_wm_write(ocelot, wm_index, threshold);
0720     err = ocelot_watermark_validate(ocelot, extack);
0721     if (err) {
0722         ocelot_wm_write(ocelot, wm_index, old_thr);
0723         return err;
0724     }
0725 
0726     ocelot_setup_sharing_watermarks(ocelot);
0727 
0728     return 0;
0729 }
0730 EXPORT_SYMBOL(ocelot_sb_tc_pool_bind_set);
0731 
0732 /* The hardware does not support atomic snapshots, we'll read out the
0733  * occupancy registers individually and have this as just a stub.
0734  */
0735 int ocelot_sb_occ_snapshot(struct ocelot *ocelot, unsigned int sb_index)
0736 {
0737     return 0;
0738 }
0739 EXPORT_SYMBOL(ocelot_sb_occ_snapshot);
0740 
0741 /* The watermark occupancy registers are cleared upon read,
0742  * so let's read them.
0743  */
0744 int ocelot_sb_occ_max_clear(struct ocelot *ocelot, unsigned int sb_index)
0745 {
0746     u32 inuse, maxuse;
0747     int port, prio;
0748 
0749     switch (sb_index) {
0750     case OCELOT_SB_BUF:
0751         for (port = 0; port <= ocelot->num_phys_ports; port++) {
0752             for (prio = 0; prio < OCELOT_NUM_TC; prio++) {
0753                 ocelot_wm_status(ocelot, BUF_Q_RSRV_I(port, prio),
0754                          &inuse, &maxuse);
0755                 ocelot_wm_status(ocelot, BUF_Q_RSRV_E(port, prio),
0756                          &inuse, &maxuse);
0757             }
0758             ocelot_wm_status(ocelot, BUF_P_RSRV_I(port),
0759                      &inuse, &maxuse);
0760             ocelot_wm_status(ocelot, BUF_P_RSRV_E(port),
0761                      &inuse, &maxuse);
0762         }
0763         break;
0764     case OCELOT_SB_REF:
0765         for (port = 0; port <= ocelot->num_phys_ports; port++) {
0766             for (prio = 0; prio < OCELOT_NUM_TC; prio++) {
0767                 ocelot_wm_status(ocelot, REF_Q_RSRV_I(port, prio),
0768                          &inuse, &maxuse);
0769                 ocelot_wm_status(ocelot, REF_Q_RSRV_E(port, prio),
0770                          &inuse, &maxuse);
0771             }
0772             ocelot_wm_status(ocelot, REF_P_RSRV_I(port),
0773                      &inuse, &maxuse);
0774             ocelot_wm_status(ocelot, REF_P_RSRV_E(port),
0775                      &inuse, &maxuse);
0776         }
0777         break;
0778     default:
0779         return -ENODEV;
0780     }
0781 
0782     return 0;
0783 }
0784 EXPORT_SYMBOL(ocelot_sb_occ_max_clear);
0785 
0786 /* This retrieves the watermark occupancy for per-port P_RSRV watermarks */
0787 int ocelot_sb_occ_port_pool_get(struct ocelot *ocelot, int port,
0788                 unsigned int sb_index, u16 pool_index,
0789                 u32 *p_cur, u32 *p_max)
0790 {
0791     int wm_index;
0792 
0793     switch (sb_index) {
0794     case OCELOT_SB_BUF:
0795         if (pool_index == OCELOT_SB_POOL_ING)
0796             wm_index = BUF_P_RSRV_I(port);
0797         else
0798             wm_index = BUF_P_RSRV_E(port);
0799         break;
0800     case OCELOT_SB_REF:
0801         if (pool_index == OCELOT_SB_POOL_ING)
0802             wm_index = REF_P_RSRV_I(port);
0803         else
0804             wm_index = REF_P_RSRV_E(port);
0805         break;
0806     default:
0807         return -ENODEV;
0808     }
0809 
0810     ocelot_wm_status(ocelot, wm_index, p_cur, p_max);
0811     *p_cur *= ocelot_sb_pool[sb_index].cell_size;
0812     *p_max *= ocelot_sb_pool[sb_index].cell_size;
0813 
0814     return 0;
0815 }
0816 EXPORT_SYMBOL(ocelot_sb_occ_port_pool_get);
0817 
0818 /* This retrieves the watermark occupancy for per-port-tc Q_RSRV watermarks */
0819 int ocelot_sb_occ_tc_port_bind_get(struct ocelot *ocelot, int port,
0820                    unsigned int sb_index, u16 tc_index,
0821                    enum devlink_sb_pool_type pool_type,
0822                    u32 *p_cur, u32 *p_max)
0823 {
0824     int wm_index;
0825 
0826     switch (sb_index) {
0827     case OCELOT_SB_BUF:
0828         if (pool_type == DEVLINK_SB_POOL_TYPE_INGRESS)
0829             wm_index = BUF_Q_RSRV_I(port, tc_index);
0830         else
0831             wm_index = BUF_Q_RSRV_E(port, tc_index);
0832         break;
0833     case OCELOT_SB_REF:
0834         if (pool_type == DEVLINK_SB_POOL_TYPE_INGRESS)
0835             wm_index = REF_Q_RSRV_I(port, tc_index);
0836         else
0837             wm_index = REF_Q_RSRV_E(port, tc_index);
0838         break;
0839     default:
0840         return -ENODEV;
0841     }
0842 
0843     ocelot_wm_status(ocelot, wm_index, p_cur, p_max);
0844     *p_cur *= ocelot_sb_pool[sb_index].cell_size;
0845     *p_max *= ocelot_sb_pool[sb_index].cell_size;
0846 
0847     return 0;
0848 }
0849 EXPORT_SYMBOL(ocelot_sb_occ_tc_port_bind_get);
0850 
0851 int ocelot_devlink_sb_register(struct ocelot *ocelot)
0852 {
0853     int err;
0854 
0855     err = devlink_sb_register(ocelot->devlink, OCELOT_SB_BUF,
0856                   ocelot->packet_buffer_size, 1, 1,
0857                   OCELOT_NUM_TC, OCELOT_NUM_TC);
0858     if (err)
0859         return err;
0860 
0861     err = devlink_sb_register(ocelot->devlink, OCELOT_SB_REF,
0862                   ocelot->num_frame_refs, 1, 1,
0863                   OCELOT_NUM_TC, OCELOT_NUM_TC);
0864     if (err) {
0865         devlink_sb_unregister(ocelot->devlink, OCELOT_SB_BUF);
0866         return err;
0867     }
0868 
0869     ocelot->pool_size[OCELOT_SB_BUF][OCELOT_SB_POOL_ING] = ocelot->packet_buffer_size;
0870     ocelot->pool_size[OCELOT_SB_BUF][OCELOT_SB_POOL_EGR] = ocelot->packet_buffer_size;
0871     ocelot->pool_size[OCELOT_SB_REF][OCELOT_SB_POOL_ING] = ocelot->num_frame_refs;
0872     ocelot->pool_size[OCELOT_SB_REF][OCELOT_SB_POOL_EGR] = ocelot->num_frame_refs;
0873 
0874     ocelot_watermark_init(ocelot);
0875 
0876     return 0;
0877 }
0878 EXPORT_SYMBOL(ocelot_devlink_sb_register);
0879 
0880 void ocelot_devlink_sb_unregister(struct ocelot *ocelot)
0881 {
0882     devlink_sb_unregister(ocelot->devlink, OCELOT_SB_BUF);
0883     devlink_sb_unregister(ocelot->devlink, OCELOT_SB_REF);
0884 }
0885 EXPORT_SYMBOL(ocelot_devlink_sb_unregister);