mirror of
https://github.com/torvalds/linux
synced 2024-10-16 16:29:20 +00:00
Merge branch 'dsa-microchip-tc-ets'
Oleksij Rempel says: ==================== net: dsa: microchip: tc-ets support changes v3: - add tc_ets_supported to match supported devices - dynamically regenerated default TC to queue map. - add Acked-by to the first patch changes v2: - run egress limit configuration on all queue separately. Otherwise configuration may not apply correctly. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
c0a274151d
|
@ -32,10 +32,6 @@
|
|||
#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 {
|
||||
|
@ -1089,6 +1085,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
|
|||
.port_nirqs = 3,
|
||||
.num_tx_queues = 4,
|
||||
.tc_cbs_supported = true,
|
||||
.tc_ets_supported = true,
|
||||
.ops = &ksz9477_dev_ops,
|
||||
.mib_names = ksz9477_mib_names,
|
||||
.mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
|
||||
|
@ -1228,6 +1225,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
|
|||
.port_nirqs = 4,
|
||||
.num_tx_queues = 4,
|
||||
.tc_cbs_supported = true,
|
||||
.tc_ets_supported = true,
|
||||
.ops = &ksz9477_dev_ops,
|
||||
.phy_errata_9477 = true,
|
||||
.mib_names = ksz9477_mib_names,
|
||||
|
@ -1352,6 +1350,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
|
|||
.port_nirqs = 3,
|
||||
.num_tx_queues = 4,
|
||||
.tc_cbs_supported = true,
|
||||
.tc_ets_supported = true,
|
||||
.ops = &ksz9477_dev_ops,
|
||||
.mib_names = ksz9477_mib_names,
|
||||
.mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
|
||||
|
@ -1379,6 +1378,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
|
|||
.port_nirqs = 3,
|
||||
.num_tx_queues = 4,
|
||||
.tc_cbs_supported = true,
|
||||
.tc_ets_supported = true,
|
||||
.ops = &ksz9477_dev_ops,
|
||||
.phy_errata_9477 = true,
|
||||
.mib_names = ksz9477_mib_names,
|
||||
|
@ -1411,6 +1411,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
|
|||
.port_nirqs = 6,
|
||||
.num_tx_queues = 8,
|
||||
.tc_cbs_supported = true,
|
||||
.tc_ets_supported = true,
|
||||
.ops = &lan937x_dev_ops,
|
||||
.mib_names = ksz9477_mib_names,
|
||||
.mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
|
||||
|
@ -1437,6 +1438,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
|
|||
.port_nirqs = 6,
|
||||
.num_tx_queues = 8,
|
||||
.tc_cbs_supported = true,
|
||||
.tc_ets_supported = true,
|
||||
.ops = &lan937x_dev_ops,
|
||||
.mib_names = ksz9477_mib_names,
|
||||
.mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
|
||||
|
@ -1463,6 +1465,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
|
|||
.port_nirqs = 6,
|
||||
.num_tx_queues = 8,
|
||||
.tc_cbs_supported = true,
|
||||
.tc_ets_supported = true,
|
||||
.ops = &lan937x_dev_ops,
|
||||
.mib_names = ksz9477_mib_names,
|
||||
.mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
|
||||
|
@ -1493,6 +1496,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
|
|||
.port_nirqs = 6,
|
||||
.num_tx_queues = 8,
|
||||
.tc_cbs_supported = true,
|
||||
.tc_ets_supported = true,
|
||||
.ops = &lan937x_dev_ops,
|
||||
.mib_names = ksz9477_mib_names,
|
||||
.mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
|
||||
|
@ -1523,6 +1527,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
|
|||
.port_nirqs = 6,
|
||||
.num_tx_queues = 8,
|
||||
.tc_cbs_supported = true,
|
||||
.tc_ets_supported = true,
|
||||
.ops = &lan937x_dev_ops,
|
||||
.mib_names = ksz9477_mib_names,
|
||||
.mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
|
||||
|
@ -3091,6 +3096,14 @@ static int cinc_cal(s32 idle_slope, s32 send_slope, u32 *bw)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ksz_setup_tc_mode(struct ksz_device *dev, int port, u8 scheduler,
|
||||
u8 shaper)
|
||||
{
|
||||
return ksz_pwrite8(dev, port, REG_PORT_MTI_QUEUE_CTRL_0,
|
||||
FIELD_PREP(MTI_SCHEDULE_MODE_M, scheduler) |
|
||||
FIELD_PREP(MTI_SHAPING_M, shaper));
|
||||
}
|
||||
|
||||
static int ksz_setup_tc_cbs(struct dsa_switch *ds, int port,
|
||||
struct tc_cbs_qopt_offload *qopt)
|
||||
{
|
||||
|
@ -3110,8 +3123,8 @@ static int ksz_setup_tc_cbs(struct dsa_switch *ds, int port,
|
|||
return ret;
|
||||
|
||||
if (!qopt->enable)
|
||||
return ksz_pwrite8(dev, port, REG_PORT_MTI_QUEUE_CTRL_0,
|
||||
KSZ_CBS_DISABLE);
|
||||
return ksz_setup_tc_mode(dev, port, MTI_SCHEDULE_WRR,
|
||||
MTI_SHAPING_OFF);
|
||||
|
||||
/* High Credit */
|
||||
ret = ksz_pwrite16(dev, port, REG_PORT_MTI_HI_WATER_MARK,
|
||||
|
@ -3136,8 +3149,215 @@ static int ksz_setup_tc_cbs(struct dsa_switch *ds, int port,
|
|||
return ret;
|
||||
}
|
||||
|
||||
return ksz_pwrite8(dev, port, REG_PORT_MTI_QUEUE_CTRL_0,
|
||||
KSZ_CBS_ENABLE);
|
||||
return ksz_setup_tc_mode(dev, port, MTI_SCHEDULE_STRICT_PRIO,
|
||||
MTI_SHAPING_SRP);
|
||||
}
|
||||
|
||||
static int ksz_disable_egress_rate_limit(struct ksz_device *dev, int port)
|
||||
{
|
||||
int queue, ret;
|
||||
|
||||
/* Configuration will not take effect until the last Port Queue X
|
||||
* Egress Limit Control Register is written.
|
||||
*/
|
||||
for (queue = 0; queue < dev->info->num_tx_queues; queue++) {
|
||||
ret = ksz_pwrite8(dev, port, KSZ9477_REG_PORT_OUT_RATE_0 + queue,
|
||||
KSZ9477_OUT_RATE_NO_LIMIT);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ksz_ets_band_to_queue(struct tc_ets_qopt_offload_replace_params *p,
|
||||
int band)
|
||||
{
|
||||
/* Compared to queues, bands prioritize packets differently. In strict
|
||||
* priority mode, the lowest priority is assigned to Queue 0 while the
|
||||
* highest priority is given to Band 0.
|
||||
*/
|
||||
return p->bands - 1 - band;
|
||||
}
|
||||
|
||||
static int ksz_queue_set_strict(struct ksz_device *dev, int port, int queue)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = ksz_pwrite32(dev, port, REG_PORT_MTI_QUEUE_INDEX__4, queue);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return ksz_setup_tc_mode(dev, port, MTI_SCHEDULE_STRICT_PRIO,
|
||||
MTI_SHAPING_OFF);
|
||||
}
|
||||
|
||||
static int ksz_queue_set_wrr(struct ksz_device *dev, int port, int queue,
|
||||
int weight)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = ksz_pwrite32(dev, port, REG_PORT_MTI_QUEUE_INDEX__4, queue);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ksz_setup_tc_mode(dev, port, MTI_SCHEDULE_WRR,
|
||||
MTI_SHAPING_OFF);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return ksz_pwrite8(dev, port, KSZ9477_PORT_MTI_QUEUE_CTRL_1, weight);
|
||||
}
|
||||
|
||||
static int ksz_tc_ets_add(struct ksz_device *dev, int port,
|
||||
struct tc_ets_qopt_offload_replace_params *p)
|
||||
{
|
||||
int ret, band, tc_prio;
|
||||
u32 queue_map = 0;
|
||||
|
||||
/* In order to ensure proper prioritization, it is necessary to set the
|
||||
* rate limit for the related queue to zero. Otherwise strict priority
|
||||
* or WRR mode will not work. This is a hardware limitation.
|
||||
*/
|
||||
ret = ksz_disable_egress_rate_limit(dev, port);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Configure queue scheduling mode for all bands. Currently only strict
|
||||
* prio mode is supported.
|
||||
*/
|
||||
for (band = 0; band < p->bands; band++) {
|
||||
int queue = ksz_ets_band_to_queue(p, band);
|
||||
|
||||
ret = ksz_queue_set_strict(dev, port, queue);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Configure the mapping between traffic classes and queues. Note:
|
||||
* priomap variable support 16 traffic classes, but the chip can handle
|
||||
* only 8 classes.
|
||||
*/
|
||||
for (tc_prio = 0; tc_prio < ARRAY_SIZE(p->priomap); tc_prio++) {
|
||||
int queue;
|
||||
|
||||
if (tc_prio > KSZ9477_MAX_TC_PRIO)
|
||||
break;
|
||||
|
||||
queue = ksz_ets_band_to_queue(p, p->priomap[tc_prio]);
|
||||
queue_map |= queue << (tc_prio * KSZ9477_PORT_TC_MAP_S);
|
||||
}
|
||||
|
||||
return ksz_pwrite32(dev, port, KSZ9477_PORT_MRI_TC_MAP__4, queue_map);
|
||||
}
|
||||
|
||||
static int ksz_tc_ets_del(struct ksz_device *dev, int port)
|
||||
{
|
||||
int ret, queue, tc_prio, s;
|
||||
u32 queue_map = 0;
|
||||
|
||||
/* To restore the default chip configuration, set all queues to use the
|
||||
* WRR scheduler with a weight of 1.
|
||||
*/
|
||||
for (queue = 0; queue < dev->info->num_tx_queues; queue++) {
|
||||
ret = ksz_queue_set_wrr(dev, port, queue,
|
||||
KSZ9477_DEFAULT_WRR_WEIGHT);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
switch (dev->info->num_tx_queues) {
|
||||
case 2:
|
||||
s = 2;
|
||||
break;
|
||||
case 4:
|
||||
s = 1;
|
||||
break;
|
||||
case 8:
|
||||
s = 0;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Revert the queue mapping for TC-priority to its default setting on
|
||||
* the chip.
|
||||
*/
|
||||
for (tc_prio = 0; tc_prio <= KSZ9477_MAX_TC_PRIO; tc_prio++) {
|
||||
int queue;
|
||||
|
||||
queue = tc_prio >> s;
|
||||
queue_map |= queue << (tc_prio * KSZ9477_PORT_TC_MAP_S);
|
||||
}
|
||||
|
||||
return ksz_pwrite32(dev, port, KSZ9477_PORT_MRI_TC_MAP__4, queue_map);
|
||||
}
|
||||
|
||||
static int ksz_tc_ets_validate(struct ksz_device *dev, int port,
|
||||
struct tc_ets_qopt_offload_replace_params *p)
|
||||
{
|
||||
int band;
|
||||
|
||||
/* Since it is not feasible to share one port among multiple qdisc,
|
||||
* the user must configure all available queues appropriately.
|
||||
*/
|
||||
if (p->bands != dev->info->num_tx_queues) {
|
||||
dev_err(dev->dev, "Not supported amount of bands. It should be %d\n",
|
||||
dev->info->num_tx_queues);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
for (band = 0; band < p->bands; ++band) {
|
||||
/* The KSZ switches utilize a weighted round robin configuration
|
||||
* where a certain number of packets can be transmitted from a
|
||||
* queue before the next queue is serviced. For more information
|
||||
* on this, refer to section 5.2.8.4 of the KSZ8565R
|
||||
* documentation on the Port Transmit Queue Control 1 Register.
|
||||
* However, the current ETS Qdisc implementation (as of February
|
||||
* 2023) assigns a weight to each queue based on the number of
|
||||
* bytes or extrapolated bandwidth in percentages. Since this
|
||||
* differs from the KSZ switches' method and we don't want to
|
||||
* fake support by converting bytes to packets, it is better to
|
||||
* return an error instead.
|
||||
*/
|
||||
if (p->quanta[band]) {
|
||||
dev_err(dev->dev, "Quanta/weights configuration is not supported.\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ksz_tc_setup_qdisc_ets(struct dsa_switch *ds, int port,
|
||||
struct tc_ets_qopt_offload *qopt)
|
||||
{
|
||||
struct ksz_device *dev = ds->priv;
|
||||
int ret;
|
||||
|
||||
if (!dev->info->tc_ets_supported)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (qopt->parent != TC_H_ROOT) {
|
||||
dev_err(dev->dev, "Parent should be \"root\"\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
switch (qopt->command) {
|
||||
case TC_ETS_REPLACE:
|
||||
ret = ksz_tc_ets_validate(dev, port, &qopt->replace_params);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return ksz_tc_ets_add(dev, port, &qopt->replace_params);
|
||||
case TC_ETS_DESTROY:
|
||||
return ksz_tc_ets_del(dev, port);
|
||||
case TC_ETS_STATS:
|
||||
case TC_ETS_GRAFT:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int ksz_setup_tc(struct dsa_switch *ds, int port,
|
||||
|
@ -3146,6 +3366,8 @@ static int ksz_setup_tc(struct dsa_switch *ds, int port,
|
|||
switch (type) {
|
||||
case TC_SETUP_QDISC_CBS:
|
||||
return ksz_setup_tc_cbs(ds, port, type_data);
|
||||
case TC_SETUP_QDISC_ETS:
|
||||
return ksz_tc_setup_qdisc_ets(ds, port, type_data);
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
|
|
@ -51,6 +51,7 @@ struct ksz_chip_data {
|
|||
u8 port_nirqs;
|
||||
u8 num_tx_queues;
|
||||
bool tc_cbs_supported;
|
||||
bool tc_ets_supported;
|
||||
const struct ksz_dev_ops *ops;
|
||||
bool phy_errata_9477;
|
||||
bool ksz87xx_eee_link_erratum;
|
||||
|
@ -649,21 +650,30 @@ static inline int is_lan937x(struct ksz_device *dev)
|
|||
#define KSZ8_LEGAL_PACKET_SIZE 1518
|
||||
#define KSZ9477_MAX_FRAME_SIZE 9000
|
||||
|
||||
#define KSZ9477_REG_PORT_OUT_RATE_0 0x0420
|
||||
#define KSZ9477_OUT_RATE_NO_LIMIT 0
|
||||
|
||||
#define KSZ9477_PORT_MRI_TC_MAP__4 0x0808
|
||||
|
||||
#define KSZ9477_PORT_TC_MAP_S 4
|
||||
#define KSZ9477_MAX_TC_PRIO 7
|
||||
|
||||
/* 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_MODE_M GENMASK(7, 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_M GENMASK(5, 4)
|
||||
#define MTI_SHAPING_OFF 0
|
||||
#define MTI_SHAPING_SRP 1
|
||||
#define MTI_SHAPING_TIME_AWARE 2
|
||||
|
||||
#define KSZ9477_PORT_MTI_QUEUE_CTRL_1 0x0915
|
||||
#define KSZ9477_DEFAULT_WRR_WEIGHT 1
|
||||
|
||||
#define REG_PORT_MTI_HI_WATER_MARK 0x0916
|
||||
#define REG_PORT_MTI_LO_WATER_MARK 0x0918
|
||||
|
||||
|
|
Loading…
Reference in a new issue