net: dsa: microchip: add support for credit based shaper
authorArun Ramadoss <arun.ramadoss@microchip.com>
Fri, 20 Jan 2023 05:21:35 +0000 (10:51 +0530)
committerJakub Kicinski <kuba@kernel.org>
Tue, 24 Jan 2023 06:12:35 +0000 (22:12 -0800)
KSZ9477, KSZ9567, KSZ9563, KSZ8563 and LAN937x supports Credit based
shaper. To differentiate the chip supporting cbs, tc_cbs_supported
flag is introduced in ksz_chip_data.
And KSZ series has 16bit Credit increment registers whereas LAN937x has
24bit register. The value to be programmed in the credit increment is
determined using the successive multiplication method to convert decimal
fraction to hexadecimal fraction.
For example: if idleslope is 10000 and sendslope is -90000, then
bandwidth is 10000 - (-90000) = 100000.
The 10% bandwidth of 100Mbps means 10/100 = 0.1(decimal). This value has
to be converted to hexa.
1) 0.1 * 16 = 1.6  --> fraction 0.6 Carry = 1 (MSB)
2) 0.6 * 16 = 9.6  --> fraction 0.6 Carry = 9
3) 0.6 * 16 = 9.6  --> fraction 0.6 Carry = 9
4) 0.6 * 16 = 9.6  --> fraction 0.6 Carry = 9
5) 0.6 * 16 = 9.6  --> fraction 0.6 Carry = 9
6) 0.6 * 16 = 9.6  --> fraction 0.6 Carry = 9 (LSB)
Now 0.1(decimal) becomes 0.199999(Hex).
If it is LAN937x, 24 bit value will be programmed to Credit Inc
register, 0x199999. For others 16 bit value will be prgrammed, 0x1999.

Signed-off-by: Arun Ramadoss <arun.ramadoss@microchip.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/dsa/microchip/ksz9477.c
drivers/net/dsa/microchip/ksz9477.h
drivers/net/dsa/microchip/ksz9477_reg.h
drivers/net/dsa/microchip/ksz_common.c
drivers/net/dsa/microchip/ksz_common.h
drivers/net/dsa/microchip/lan937x.h
drivers/net/dsa/microchip/lan937x_main.c
drivers/net/dsa/microchip/lan937x_reg.h

index 1b4bb2f..bf13d47 100644 (file)
@@ -1184,6 +1184,13 @@ u32 ksz9477_get_port_addr(int port, int offset)
        return PORT_CTRL_ADDR(port, offset);
 }
 
+int ksz9477_tc_cbs_set_cinc(struct ksz_device *dev, int port, u32 val)
+{
+       val = val >> 8;
+
+       return ksz_pwrite16(dev, port, REG_PORT_MTI_CREDIT_INCREMENT, val);
+}
+
 int ksz9477_switch_init(struct ksz_device *dev)
 {
        u8 data8;
index 2554cb6..b6f7e3c 100644 (file)
@@ -51,6 +51,7 @@ int ksz9477_mdb_del(struct ksz_device *dev, int port,
                    const struct switchdev_obj_port_mdb *mdb, struct dsa_db db);
 int ksz9477_change_mtu(struct ksz_device *dev, int port, int mtu);
 void ksz9477_config_cpu_port(struct dsa_switch *ds);
+int ksz9477_tc_cbs_set_cinc(struct ksz_device *dev, int port, u32 val);
 int ksz9477_enable_stp_addr(struct ksz_device *dev);
 int ksz9477_reset_switch(struct ksz_device *dev);
 int ksz9477_dsa_init(struct ksz_device *dev);
index b433a52..cba3dba 100644 (file)
 
 /* 9 - Shaping */
 
-#define REG_PORT_MTI_QUEUE_INDEX__4    0x0900
+#define REG_PORT_MTI_QUEUE_CTRL_0__4   0x0904
 
-#define REG_PORT_MTI_QUEUE_CTRL_0__4   0x0904
+#define MTI_PVID_REPLACE               BIT(0)
 
-#define MTI_PVID_REPLACE               BIT(0)
-
-#define REG_PORT_MTI_QUEUE_CTRL_0      0x0914
-
-#define MTI_SCHEDULE_MODE_M            0x3
-#define MTI_SCHEDULE_MODE_S            6
-#define MTI_SCHEDULE_STRICT_PRIO       0
-#define MTI_SCHEDULE_WRR               2
-#define MTI_SHAPING_M                  0x3
-#define MTI_SHAPING_S                  4
-#define MTI_SHAPING_OFF                        0
-#define MTI_SHAPING_SRP                        1
-#define MTI_SHAPING_TIME_AWARE         2
-
-#define REG_PORT_MTI_QUEUE_CTRL_1      0x0915
-
-#define MTI_TX_RATIO_M                 (BIT(7) - 1)
-
-#define REG_PORT_MTI_QUEUE_CTRL_2__2   0x0916
-#define REG_PORT_MTI_HI_WATER_MARK     0x0916
-#define REG_PORT_MTI_QUEUE_CTRL_3__2   0x0918
-#define REG_PORT_MTI_LO_WATER_MARK     0x0918
-#define REG_PORT_MTI_QUEUE_CTRL_4__2   0x091A
 #define REG_PORT_MTI_CREDIT_INCREMENT  0x091A
 
 /* A - QM */
index 9d4dcbe..46becc0 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/of_net.h>
 #include <linux/micrel_phy.h>
 #include <net/dsa.h>
+#include <net/pkt_cls.h>
 #include <net/switchdev.h>
 
 #include "ksz_common.h"
 #include "ksz9477.h"
 #include "lan937x.h"
 
+#define KSZ_CBS_ENABLE ((MTI_SCHEDULE_STRICT_PRIO << MTI_SCHEDULE_MODE_S) | \
+                       (MTI_SHAPING_SRP << MTI_SHAPING_S))
+#define KSZ_CBS_DISABLE ((MTI_SCHEDULE_WRR << MTI_SCHEDULE_MODE_S) |\
+                        (MTI_SHAPING_OFF << MTI_SHAPING_S))
 #define MIB_COUNTER_NUM 0x20
 
 struct ksz_stats_raw {
@@ -250,6 +255,7 @@ static const struct ksz_dev_ops ksz9477_dev_ops = {
        .change_mtu = ksz9477_change_mtu,
        .phylink_mac_link_up = ksz9477_phylink_mac_link_up,
        .config_cpu_port = ksz9477_config_cpu_port,
+       .tc_cbs_set_cinc = ksz9477_tc_cbs_set_cinc,
        .enable_stp_addr = ksz9477_enable_stp_addr,
        .reset = ksz9477_reset_switch,
        .init = ksz9477_switch_init,
@@ -286,6 +292,7 @@ static const struct ksz_dev_ops lan937x_dev_ops = {
        .change_mtu = lan937x_change_mtu,
        .phylink_mac_link_up = ksz9477_phylink_mac_link_up,
        .config_cpu_port = lan937x_config_cpu_port,
+       .tc_cbs_set_cinc = lan937x_tc_cbs_set_cinc,
        .enable_stp_addr = ksz9477_enable_stp_addr,
        .reset = lan937x_reset_switch,
        .init = lan937x_switch_init,
@@ -1081,6 +1088,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
                .port_cnt = 3,          /* total port count */
                .port_nirqs = 3,
                .num_tx_queues = 4,
+               .tc_cbs_supported = true,
                .ops = &ksz9477_dev_ops,
                .mib_names = ksz9477_mib_names,
                .mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
@@ -1219,6 +1227,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
                .port_cnt = 7,          /* total physical port count */
                .port_nirqs = 4,
                .num_tx_queues = 4,
+               .tc_cbs_supported = true,
                .ops = &ksz9477_dev_ops,
                .phy_errata_9477 = true,
                .mib_names = ksz9477_mib_names,
@@ -1342,6 +1351,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
                .port_cnt = 3,          /* total port count */
                .port_nirqs = 3,
                .num_tx_queues = 4,
+               .tc_cbs_supported = true,
                .ops = &ksz9477_dev_ops,
                .mib_names = ksz9477_mib_names,
                .mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
@@ -1368,6 +1378,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
                .port_cnt = 7,          /* total physical port count */
                .port_nirqs = 3,
                .num_tx_queues = 4,
+               .tc_cbs_supported = true,
                .ops = &ksz9477_dev_ops,
                .phy_errata_9477 = true,
                .mib_names = ksz9477_mib_names,
@@ -1399,6 +1410,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
                .port_cnt = 5,          /* total physical port count */
                .port_nirqs = 6,
                .num_tx_queues = 8,
+               .tc_cbs_supported = true,
                .ops = &lan937x_dev_ops,
                .mib_names = ksz9477_mib_names,
                .mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
@@ -1424,6 +1436,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
                .port_cnt = 6,          /* total physical port count */
                .port_nirqs = 6,
                .num_tx_queues = 8,
+               .tc_cbs_supported = true,
                .ops = &lan937x_dev_ops,
                .mib_names = ksz9477_mib_names,
                .mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
@@ -1449,6 +1462,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
                .port_cnt = 8,          /* total physical port count */
                .port_nirqs = 6,
                .num_tx_queues = 8,
+               .tc_cbs_supported = true,
                .ops = &lan937x_dev_ops,
                .mib_names = ksz9477_mib_names,
                .mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
@@ -1478,6 +1492,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
                .port_cnt = 5,          /* total physical port count */
                .port_nirqs = 6,
                .num_tx_queues = 8,
+               .tc_cbs_supported = true,
                .ops = &lan937x_dev_ops,
                .mib_names = ksz9477_mib_names,
                .mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
@@ -1507,6 +1522,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
                .port_cnt = 8,          /* total physical port count */
                .port_nirqs = 6,
                .num_tx_queues = 8,
+               .tc_cbs_supported = true,
                .ops = &lan937x_dev_ops,
                .mib_names = ksz9477_mib_names,
                .mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
@@ -2976,6 +2992,101 @@ static int ksz_switch_detect(struct ksz_device *dev)
        return 0;
 }
 
+/* Bandwidth is calculated by idle slope/transmission speed. Then the Bandwidth
+ * is converted to Hex-decimal using the successive multiplication method. On
+ * every step, integer part is taken and decimal part is carry forwarded.
+ */
+static int cinc_cal(s32 idle_slope, s32 send_slope, u32 *bw)
+{
+       u32 cinc = 0;
+       u32 txrate;
+       u32 rate;
+       u8 temp;
+       u8 i;
+
+       txrate = idle_slope - send_slope;
+
+       if (!txrate)
+               return -EINVAL;
+
+       rate = idle_slope;
+
+       /* 24 bit register */
+       for (i = 0; i < 6; i++) {
+               rate = rate * 16;
+
+               temp = rate / txrate;
+
+               rate %= txrate;
+
+               cinc = ((cinc << 4) | temp);
+       }
+
+       *bw = cinc;
+
+       return 0;
+}
+
+static int ksz_setup_tc_cbs(struct dsa_switch *ds, int port,
+                           struct tc_cbs_qopt_offload *qopt)
+{
+       struct ksz_device *dev = ds->priv;
+       int ret;
+       u32 bw;
+
+       if (!dev->info->tc_cbs_supported)
+               return -EOPNOTSUPP;
+
+       if (qopt->queue > dev->info->num_tx_queues)
+               return -EINVAL;
+
+       /* Queue Selection */
+       ret = ksz_pwrite32(dev, port, REG_PORT_MTI_QUEUE_INDEX__4, qopt->queue);
+       if (ret)
+               return ret;
+
+       if (!qopt->enable)
+               return ksz_pwrite8(dev, port, REG_PORT_MTI_QUEUE_CTRL_0,
+                                  KSZ_CBS_DISABLE);
+
+       /* High Credit */
+       ret = ksz_pwrite16(dev, port, REG_PORT_MTI_HI_WATER_MARK,
+                          qopt->hicredit);
+       if (ret)
+               return ret;
+
+       /* Low Credit */
+       ret = ksz_pwrite16(dev, port, REG_PORT_MTI_LO_WATER_MARK,
+                          qopt->locredit);
+       if (ret)
+               return ret;
+
+       /* Credit Increment Register */
+       ret = cinc_cal(qopt->idleslope, qopt->sendslope, &bw);
+       if (ret)
+               return ret;
+
+       if (dev->dev_ops->tc_cbs_set_cinc) {
+               ret = dev->dev_ops->tc_cbs_set_cinc(dev, port, bw);
+               if (ret)
+                       return ret;
+       }
+
+       return ksz_pwrite8(dev, port, REG_PORT_MTI_QUEUE_CTRL_0,
+                          KSZ_CBS_ENABLE);
+}
+
+static int ksz_setup_tc(struct dsa_switch *ds, int port,
+                       enum tc_setup_type type, void *type_data)
+{
+       switch (type) {
+       case TC_SETUP_QDISC_CBS:
+               return ksz_setup_tc_cbs(ds, port, type_data);
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
 static const struct dsa_switch_ops ksz_switch_ops = {
        .get_tag_protocol       = ksz_get_tag_protocol,
        .connect_tag_protocol   = ksz_connect_tag_protocol,
@@ -3018,6 +3129,7 @@ static const struct dsa_switch_ops ksz_switch_ops = {
        .port_hwtstamp_set      = ksz_hwtstamp_set,
        .port_txtstamp          = ksz_port_txtstamp,
        .port_rxtstamp          = ksz_port_rxtstamp,
+       .port_setup_tc          = ksz_setup_tc,
 };
 
 struct ksz_device *ksz_switch_alloc(struct device *base, void *priv)
index 1a00143..d2d5761 100644 (file)
@@ -50,6 +50,7 @@ struct ksz_chip_data {
        int port_cnt;
        u8 port_nirqs;
        u8 num_tx_queues;
+       bool tc_cbs_supported;
        const struct ksz_dev_ops *ops;
        bool phy_errata_9477;
        bool ksz87xx_eee_link_erratum;
@@ -354,6 +355,7 @@ struct ksz_dev_ops {
                                    struct phy_device *phydev, int speed,
                                    int duplex, bool tx_pause, bool rx_pause);
        void (*setup_rgmii_delay)(struct ksz_device *dev, int port);
+       int (*tc_cbs_set_cinc)(struct ksz_device *dev, int port, u32 val);
        void (*config_cpu_port)(struct dsa_switch *ds);
        int (*enable_stp_addr)(struct ksz_device *dev);
        int (*reset)(struct ksz_device *dev);
@@ -647,6 +649,24 @@ static inline int is_lan937x(struct ksz_device *dev)
 #define KSZ8_LEGAL_PACKET_SIZE         1518
 #define KSZ9477_MAX_FRAME_SIZE         9000
 
+/* CBS related registers */
+#define REG_PORT_MTI_QUEUE_INDEX__4    0x0900
+
+#define REG_PORT_MTI_QUEUE_CTRL_0      0x0914
+
+#define MTI_SCHEDULE_MODE_M            0x3
+#define MTI_SCHEDULE_MODE_S            6
+#define MTI_SCHEDULE_STRICT_PRIO       0
+#define MTI_SCHEDULE_WRR               2
+#define MTI_SHAPING_M                  0x3
+#define MTI_SHAPING_S                  4
+#define MTI_SHAPING_OFF                        0
+#define MTI_SHAPING_SRP                        1
+#define MTI_SHAPING_TIME_AWARE         2
+
+#define REG_PORT_MTI_HI_WATER_MARK     0x0916
+#define REG_PORT_MTI_LO_WATER_MARK     0x0918
+
 /* Regmap tables generation */
 #define KSZ_SPI_OP_RD          3
 #define KSZ_SPI_OP_WR          2
index 8e9e66d..3388d91 100644 (file)
@@ -20,4 +20,5 @@ void lan937x_phylink_get_caps(struct ksz_device *dev, int port,
                              struct phylink_config *config);
 void lan937x_setup_rgmii_delay(struct ksz_device *dev, int port);
 int lan937x_set_ageing_time(struct ksz_device *dev, unsigned int msecs);
+int lan937x_tc_cbs_set_cinc(struct ksz_device *dev, int port, u32 val);
 #endif
index 923388f..399a390 100644 (file)
@@ -340,6 +340,11 @@ void lan937x_setup_rgmii_delay(struct ksz_device *dev, int port)
        }
 }
 
+int lan937x_tc_cbs_set_cinc(struct ksz_device *dev, int port, u32 val)
+{
+       return ksz_pwrite32(dev, port, REG_PORT_MTI_CREDIT_INCREMENT, val);
+}
+
 int lan937x_switch_init(struct ksz_device *dev)
 {
        dev->port_mask = (1 << dev->info->port_cnt) - 1;
index 5bc16a4..45b606b 100644 (file)
 
 #define P_PRIO_CTRL                    REG_PORT_MRI_PRIO_CTRL
 
+/* 9 - Shaping */
+#define REG_PORT_MTI_CREDIT_INCREMENT  0x091C
+
 /* The port number as per the datasheet */
 #define RGMII_2_PORT_NUM               5
 #define RGMII_1_PORT_NUM               6