Commit 8127224c authored by Ivan Khoronzhuk's avatar Ivan Khoronzhuk Committed by David S. Miller

ethernet: ti: am65-cpsw-qos: add TAPRIO offload support

AM65 CPSW h/w supports Enhanced Scheduled Traffic (EST – defined
in P802.1Qbv/D2.2 that later got included in IEEE 802.1Q-2018)
configuration. EST allows express queue traffic to be scheduled
(placed) on the wire at specific repeatable time intervals. In
Linux kernel, EST configuration is done through tc command and
the taprio scheduler in the net core implements a software only
scheduler (SCH_TAPRIO). If the NIC is capable of EST configuration,
user indicate "flag 2" in the command which is then parsed by
taprio scheduler in net core and indicate that the command is to
be offloaded to h/w. taprio then offloads the command to the
driver by calling ndo_setup_tc() ndo ops. This patch implements
ndo_setup_tc() to offload EST configuration to CPSW h/w.

Currently driver supports only SetGateStates operation. EST
operates on a repeating time interval generated by the CPTS EST
function generator. Each Ethernet port has a global EST fetch
RAM that can be configured as 2 buffers, each of 64 locations
or one large buffer of 128 locations. In 2 buffer configuration,
a ping pong mechanism is used to hold the active schedule (oper)
in one buffer and new (admin) command in the other. Each 22-bit
fetch command consists of a 14-bit fetch count (14 MSB’s) and an
8-bit priority fetch allow (8 LSB’s) that will be applied for the
fetch count time in wireside clocks. Driver process each of the
sched-entry in the offload command and update the fetch RAM.
Driver configures duration in sched-entry into the fetch count
and Gate mask into the priority fetch bits of the RAM. Then
configures the CPTS EST function generator to activate the
schedule. Currently driver supports only 2 buffer configuration
which means driver supports a max cycle time of ~8 msec.

CPSW supports a configurable number of priority queues (up to 8)
and needs to be switched to this mode from the default round
robin mode before EST can be offloaded. User configures
these through ethtool commands (-L for changing number of
queues and --set-priv-flags to disable round robin mode).
Driver doesn't enable EST if pf_p0_rx_ptype_rrobin privat flag
is set. The flag is common for all ports, and so can't be just
overridden by taprio configuration w/o user involvement.
Command fails if pf_p0_rx_ptype_rrobin is already set in the
driver.

Scheds (commands) configuration depends on interface speed so
driver translates the duration to the fetch count based on
link speed. Each schedule can be constructed with several
command entries in fetch RAM  depending on interval. For example
if each sched has timer interval < ~130us on 1000 Mb link then
each sched consumes one command and have 1:1 mapping. When
Ethernet link goes down, driver purge the configuration if link
is down for more than 1 second.

The patch allows to update the timer and scheds memory only if it's
really needed, and skip cases required the user to stop timer by
configuring only shceds memory.
Signed-off-by: default avatarIvan Khoronzhuk <ivan.khoronzhuk@linaro.org>
Signed-off-by: default avatarMurali Karicheri <m-karicheri2@ti.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent ec008fa2
...@@ -123,6 +123,15 @@ config TI_K3_AM65_CPTS ...@@ -123,6 +123,15 @@ config TI_K3_AM65_CPTS
protocol, Ethernet Enhanced Scheduled Traffic Operations (CPTS_ESTFn) protocol, Ethernet Enhanced Scheduled Traffic Operations (CPTS_ESTFn)
and PCIe Subsystem Precision Time Measurement (PTM). and PCIe Subsystem Precision Time Measurement (PTM).
config TI_AM65_CPSW_TAS
bool "Enable TAS offload in AM65 CPSW"
depends on TI_K3_AM65_CPSW_NUSS && NET_SCH_TAPRIO && TI_K3_AM65_CPTS
help
Say y here to support Time Aware Shaper(TAS) offload in AM65 CPSW.
AM65 CPSW hardware supports Enhanced Scheduled Traffic (EST)
defined in IEEE 802.1Q 2018. The EST scheduler runs on CPTS and the
TAS/EST schedule is updated in the Fetch RAM memory of the CPSW.
config TI_KEYSTONE_NETCP config TI_KEYSTONE_NETCP
tristate "TI Keystone NETCP Core Support" tristate "TI Keystone NETCP Core Support"
select TI_DAVINCI_MDIO select TI_DAVINCI_MDIO
......
...@@ -25,5 +25,5 @@ obj-$(CONFIG_TI_KEYSTONE_NETCP_ETHSS) += keystone_netcp_ethss.o ...@@ -25,5 +25,5 @@ obj-$(CONFIG_TI_KEYSTONE_NETCP_ETHSS) += keystone_netcp_ethss.o
keystone_netcp_ethss-y := netcp_ethss.o netcp_sgmii.o netcp_xgbepcsr.o cpsw_ale.o keystone_netcp_ethss-y := netcp_ethss.o netcp_sgmii.o netcp_xgbepcsr.o cpsw_ale.o
obj-$(CONFIG_TI_K3_AM65_CPSW_NUSS) += ti-am65-cpsw-nuss.o obj-$(CONFIG_TI_K3_AM65_CPSW_NUSS) += ti-am65-cpsw-nuss.o
ti-am65-cpsw-nuss-y := am65-cpsw-nuss.o cpsw_sl.o am65-cpsw-ethtool.o cpsw_ale.o k3-cppi-desc-pool.o ti-am65-cpsw-nuss-y := am65-cpsw-nuss.o cpsw_sl.o am65-cpsw-ethtool.o cpsw_ale.o k3-cppi-desc-pool.o am65-cpsw-qos.o
obj-$(CONFIG_TI_K3_AM65_CPTS) += am65-cpts.o obj-$(CONFIG_TI_K3_AM65_CPTS) += am65-cpts.o
...@@ -730,9 +730,17 @@ static u32 am65_cpsw_get_ethtool_priv_flags(struct net_device *ndev) ...@@ -730,9 +730,17 @@ static u32 am65_cpsw_get_ethtool_priv_flags(struct net_device *ndev)
static int am65_cpsw_set_ethtool_priv_flags(struct net_device *ndev, u32 flags) static int am65_cpsw_set_ethtool_priv_flags(struct net_device *ndev, u32 flags)
{ {
struct am65_cpsw_common *common = am65_ndev_to_common(ndev); struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
int rrobin;
common->pf_p0_rx_ptype_rrobin = rrobin = !!(flags & AM65_CPSW_PRIV_P0_RX_PTYPE_RROBIN);
!!(flags & AM65_CPSW_PRIV_P0_RX_PTYPE_RROBIN);
if (common->est_enabled && rrobin) {
netdev_err(ndev,
"p0-rx-ptype-rrobin flag conflicts with QOS\n");
return -EINVAL;
}
common->pf_p0_rx_ptype_rrobin = rrobin;
am65_cpsw_nuss_set_p0_ptype(common); am65_cpsw_nuss_set_p0_ptype(common);
return 0; return 0;
......
...@@ -37,12 +37,14 @@ ...@@ -37,12 +37,14 @@
#define AM65_CPSW_XGMII_BASE 0x2100 #define AM65_CPSW_XGMII_BASE 0x2100
#define AM65_CPSW_CPSW_NU_BASE 0x20000 #define AM65_CPSW_CPSW_NU_BASE 0x20000
#define AM65_CPSW_NU_PORTS_BASE 0x1000 #define AM65_CPSW_NU_PORTS_BASE 0x1000
#define AM65_CPSW_NU_FRAM_BASE 0x12000
#define AM65_CPSW_NU_STATS_BASE 0x1a000 #define AM65_CPSW_NU_STATS_BASE 0x1a000
#define AM65_CPSW_NU_ALE_BASE 0x1e000 #define AM65_CPSW_NU_ALE_BASE 0x1e000
#define AM65_CPSW_NU_CPTS_BASE 0x1d000 #define AM65_CPSW_NU_CPTS_BASE 0x1d000
#define AM65_CPSW_NU_PORTS_OFFSET 0x1000 #define AM65_CPSW_NU_PORTS_OFFSET 0x1000
#define AM65_CPSW_NU_STATS_PORT_OFFSET 0x200 #define AM65_CPSW_NU_STATS_PORT_OFFSET 0x200
#define AM65_CPSW_NU_FRAM_PORT_OFFSET 0x200
#define AM65_CPSW_MAX_PORTS 8 #define AM65_CPSW_MAX_PORTS 8
...@@ -188,9 +190,11 @@ void am65_cpsw_nuss_adjust_link(struct net_device *ndev) ...@@ -188,9 +190,11 @@ void am65_cpsw_nuss_adjust_link(struct net_device *ndev)
cpsw_ale_control_set(common->ale, port->port_id, cpsw_ale_control_set(common->ale, port->port_id,
ALE_PORT_STATE, ALE_PORT_STATE_FORWARD); ALE_PORT_STATE, ALE_PORT_STATE_FORWARD);
am65_cpsw_qos_link_up(ndev, phy->speed);
netif_tx_wake_all_queues(ndev); netif_tx_wake_all_queues(ndev);
} else { } else {
int tmo; int tmo;
/* disable forwarding */ /* disable forwarding */
cpsw_ale_control_set(common->ale, port->port_id, cpsw_ale_control_set(common->ale, port->port_id,
ALE_PORT_STATE, ALE_PORT_STATE_DISABLE); ALE_PORT_STATE, ALE_PORT_STATE_DISABLE);
...@@ -204,6 +208,7 @@ void am65_cpsw_nuss_adjust_link(struct net_device *ndev) ...@@ -204,6 +208,7 @@ void am65_cpsw_nuss_adjust_link(struct net_device *ndev)
cpsw_sl_ctl_reset(port->slave.mac_sl); cpsw_sl_ctl_reset(port->slave.mac_sl);
am65_cpsw_qos_link_down(ndev);
netif_tx_stop_all_queues(ndev); netif_tx_stop_all_queues(ndev);
} }
...@@ -1378,6 +1383,7 @@ static const struct net_device_ops am65_cpsw_nuss_netdev_ops_2g = { ...@@ -1378,6 +1383,7 @@ static const struct net_device_ops am65_cpsw_nuss_netdev_ops_2g = {
.ndo_vlan_rx_kill_vid = am65_cpsw_nuss_ndo_slave_kill_vid, .ndo_vlan_rx_kill_vid = am65_cpsw_nuss_ndo_slave_kill_vid,
.ndo_do_ioctl = am65_cpsw_nuss_ndo_slave_ioctl, .ndo_do_ioctl = am65_cpsw_nuss_ndo_slave_ioctl,
.ndo_set_features = am65_cpsw_nuss_ndo_slave_set_features, .ndo_set_features = am65_cpsw_nuss_ndo_slave_set_features,
.ndo_setup_tc = am65_cpsw_qos_ndo_setup_tc,
}; };
static void am65_cpsw_nuss_slave_disable_unused(struct am65_cpsw_port *port) static void am65_cpsw_nuss_slave_disable_unused(struct am65_cpsw_port *port)
...@@ -1739,6 +1745,9 @@ static int am65_cpsw_nuss_init_slave_ports(struct am65_cpsw_common *common) ...@@ -1739,6 +1745,9 @@ static int am65_cpsw_nuss_init_slave_ports(struct am65_cpsw_common *common)
port->stat_base = common->cpsw_base + AM65_CPSW_NU_STATS_BASE + port->stat_base = common->cpsw_base + AM65_CPSW_NU_STATS_BASE +
(AM65_CPSW_NU_STATS_PORT_OFFSET * port_id); (AM65_CPSW_NU_STATS_PORT_OFFSET * port_id);
port->name = of_get_property(port_np, "label", NULL); port->name = of_get_property(port_np, "label", NULL);
port->fetch_ram_base =
common->cpsw_base + AM65_CPSW_NU_FRAM_BASE +
(AM65_CPSW_NU_FRAM_PORT_OFFSET * (port_id - 1));
port->disabled = !of_device_is_available(port_np); port->disabled = !of_device_is_available(port_np);
if (port->disabled) if (port->disabled)
......
...@@ -9,7 +9,9 @@ ...@@ -9,7 +9,9 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/phy.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include "am65-cpsw-qos.h"
struct am65_cpts; struct am65_cpts;
...@@ -38,10 +40,12 @@ struct am65_cpsw_port { ...@@ -38,10 +40,12 @@ struct am65_cpsw_port {
u32 port_id; u32 port_id;
void __iomem *port_base; void __iomem *port_base;
void __iomem *stat_base; void __iomem *stat_base;
void __iomem *fetch_ram_base;
bool disabled; bool disabled;
struct am65_cpsw_slave_data slave; struct am65_cpsw_slave_data slave;
bool tx_ts_enabled; bool tx_ts_enabled;
bool rx_ts_enabled; bool rx_ts_enabled;
struct am65_cpsw_qos qos;
}; };
struct am65_cpsw_host { struct am65_cpsw_host {
...@@ -104,6 +108,7 @@ struct am65_cpsw_common { ...@@ -104,6 +108,7 @@ struct am65_cpsw_common {
u32 cpsw_ver; u32 cpsw_ver;
bool pf_p0_rx_ptype_rrobin; bool pf_p0_rx_ptype_rrobin;
struct am65_cpts *cpts; struct am65_cpts *cpts;
int est_enabled;
}; };
struct am65_cpsw_ndev_stats { struct am65_cpsw_ndev_stats {
......
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com/
*/
#ifndef AM65_CPSW_QOS_H_
#define AM65_CPSW_QOS_H_
#include <linux/netdevice.h>
#include <net/pkt_sched.h>
struct am65_cpsw_est {
int buf;
/* has to be the last one */
struct tc_taprio_qopt_offload taprio;
};
struct am65_cpsw_qos {
struct am65_cpsw_est *est_admin;
struct am65_cpsw_est *est_oper;
ktime_t link_down_time;
int link_speed;
};
int am65_cpsw_qos_ndo_setup_tc(struct net_device *ndev, enum tc_setup_type type,
void *type_data);
void am65_cpsw_qos_link_up(struct net_device *ndev, int link_speed);
void am65_cpsw_qos_link_down(struct net_device *ndev);
#endif /* AM65_CPSW_QOS_H_ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment