Add ENST (Enhanced Network Scheduling and Timing) register definitions to support IEEE 802.1Qbv time-gated transmission. Register architecture: - Per-queue timing registers: ENST_START_TIME, ENST_ON_TIME, ENST_OFF_TIME - Centralized control of the ENST_CONTROL register for enabling or disabling queue gates. - Time intervals programmed in hardware byte units - Hardware-level queue scheduling infrastructure. Signed-off-by: Vineeth Karumanchi --- drivers/net/ethernet/cadence/macb.h | 43 +++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h index c9a5c8beb2fa..e456ac65d6c6 100644 --- a/drivers/net/ethernet/cadence/macb.h +++ b/drivers/net/ethernet/cadence/macb.h @@ -184,6 +184,13 @@ #define GEM_DCFG8 0x029C /* Design Config 8 */ #define GEM_DCFG10 0x02A4 /* Design Config 10 */ #define GEM_DCFG12 0x02AC /* Design Config 12 */ +#define GEM_ENST_START_TIME_Q0 0x0800 /* ENST Q0 start time */ +#define GEM_ENST_START_TIME_Q1 0x0804 /* ENST Q1 start time */ +#define GEM_ENST_ON_TIME_Q0 0x0820 /* ENST Q0 on time */ +#define GEM_ENST_ON_TIME_Q1 0x0824 /* ENST Q1 on time */ +#define GEM_ENST_OFF_TIME_Q0 0x0840 /* ENST Q0 off time */ +#define GEM_ENST_OFF_TIME_Q1 0x0844 /* ENST Q1 off time */ +#define GEM_ENST_CONTROL 0x0880 /* ENST control register */ #define GEM_USX_CONTROL 0x0A80 /* High speed PCS control register */ #define GEM_USX_STATUS 0x0A88 /* High speed PCS status register */ @@ -221,6 +228,15 @@ #define GEM_IDR(hw_q) (0x0620 + ((hw_q) << 2)) #define GEM_IMR(hw_q) (0x0640 + ((hw_q) << 2)) +#define GEM_ENST_START_TIME(hw_q) (0x0800 + ((hw_q) << 2)) +#define GEM_ENST_ON_TIME(hw_q) (0x0820 + ((hw_q) << 2)) +#define GEM_ENST_OFF_TIME(hw_q) (0x0840 + ((hw_q) << 2)) + +/* Bitfields in ENST_CONTROL. */ +#define GEM_ENST_DISABLE_QUEUE(hw_q) BIT((hw_q) + 16) /* q0 disable is 16'b */ +#define GEM_ENST_DISABLE_QUEUE_OFFSET 16 +#define GEM_ENST_ENABLE_QUEUE(hw_q) BIT(hw_q) /* q0 enable is 0'b */ + /* Bitfields in NCR */ #define MACB_LB_OFFSET 0 /* reserved */ #define MACB_LB_SIZE 1 @@ -554,6 +570,33 @@ #define GEM_HIGH_SPEED_OFFSET 26 #define GEM_HIGH_SPEED_SIZE 1 +/* Bitfields in ENST_START_TIME_Q0, Q1. */ +#define GEM_START_TIME_SEC_OFFSET 30 +#define GEM_START_TIME_SEC_SIZE 2 +#define GEM_START_TIME_NSEC_OFFSET 0 +#define GEM_START_TIME_NSEC_SIZE 30 + +/* Bitfields in ENST_ON_TIME_Q0, Q1. */ +#define GEM_ON_TIME_OFFSET 0 +#define GEM_ON_TIME_SIZE 17 + +/* Bitfields in ENST_OFF_TIME_Q0, Q1. */ +#define GEM_OFF_TIME_OFFSET 0 +#define GEM_OFF_TIME_SIZE 17 + +/* Hardware ENST timing registers granularity */ +#define ENST_TIME_GRANULARITY_NS 8 + +/* Bitfields in ENST_CONTROL. */ +#define GEM_DISABLE_Q1_OFFSET 17 +#define GEM_DISABLE_Q1_SIZE 1 +#define GEM_DISABLE_Q0_OFFSET 16 +#define GEM_DISABLE_Q0_SIZE 1 +#define GEM_ENABLE_Q1_OFFSET 1 +#define GEM_ENABLE_Q1_SIZE 1 +#define GEM_ENABLE_Q0_OFFSET 0 +#define GEM_ENABLE_Q0_SIZE 1 + /* Bitfields in USX_CONTROL. */ #define GEM_USX_CTRL_SPEED_OFFSET 14 #define GEM_USX_CTRL_SPEED_SIZE 3 -- 2.34.1 Add Enhanced Network Scheduling and Timing (ENST) support to queue infrastructure with speed-dependent timing calculations for precise gate control. Hardware timing unit conversion: - Timing values programmed as hardware units based on link speed - Conversion formula: time_bytes = time_ns / divisor - Speed-specific divisors: * 1 Gbps: divisor = 8 * 100 Mbps: divisor = 80 * 10 Mbps: divisor = 800 Infrastructure changes: - Extend macb_queue structure with ENST timing control registers - Add queue_enst_configs structure for per-entry TC configuration storage - Map ENST register offsets into existing queue management framework - Define ENST_NS_TO_HW_UNITS() macro for automatic speed-based conversion This enables hardware-native timing programming while abstracting the speed-dependent conversions Signed-off-by: Vineeth Karumanchi --- drivers/net/ethernet/cadence/macb.h | 32 ++++++++++++++++++++++++ drivers/net/ethernet/cadence/macb_main.c | 6 +++++ 2 files changed, 38 insertions(+) diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h index e456ac65d6c6..ef3995564c5c 100644 --- a/drivers/net/ethernet/cadence/macb.h +++ b/drivers/net/ethernet/cadence/macb.h @@ -857,6 +857,16 @@ #define MACB_READ_NSR(bp) macb_readl(bp, NSR) +/* ENST macros*/ +#define ENST_NS_TO_HW_UNITS(ns, speed_mbps) \ + DIV_ROUND_UP((ns) * (speed_mbps), (ENST_TIME_GRANULARITY_NS * 1000)) + +#define ENST_MAX_HW_INTERVAL(speed_mbps) \ + DIV_ROUND_UP(GENMASK(GEM_ON_TIME_SIZE - 1, 0) * ENST_TIME_GRANULARITY_NS * 1000,\ + (speed_mbps)) + +#define ENST_MAX_START_TIME_SEC GENMASK(GEM_START_TIME_SEC_SIZE - 1, 0) + /* struct macb_dma_desc - Hardware DMA descriptor * @addr: DMA address of data buffer * @ctrl: Control and status bits @@ -1262,6 +1272,11 @@ struct macb_queue { unsigned int RBQP; unsigned int RBQPH; + /* ENST register offsets for this queue */ + unsigned int ENST_START_TIME; + unsigned int ENST_ON_TIME; + unsigned int ENST_OFF_TIME; + /* Lock to protect tx_head and tx_tail */ spinlock_t tx_ptr_lock; unsigned int tx_head, tx_tail; @@ -1450,4 +1465,21 @@ struct macb_platform_data { struct clk *hclk; }; +/** + * struct queue_enst_configs - Configuration for Enhanced Scheduled Traffic (ENST) queue + * @queue_id: Identifier for the queue + * @start_time_mask: Bitmask representing the start time for the queue + * @on_time_bytes: "on" time nsec expressed in bytes + * @off_time_bytes: "off" time nsec expressed in bytes + * + * This structure holds the configuration parameters for an ENST queue, + * used to control time-based transmission scheduling in the MACB driver. + */ +struct queue_enst_configs { + u8 queue_id; + u32 start_time_mask; + u32 on_time_bytes; + u32 off_time_bytes; +}; + #endif /* _MACB_H */ diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index ce95fad8cedd..ff87d3e1d8a0 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -4305,6 +4305,9 @@ static int macb_init(struct platform_device *pdev) queue->TBQP = GEM_TBQP(hw_q - 1); queue->RBQP = GEM_RBQP(hw_q - 1); queue->RBQS = GEM_RBQS(hw_q - 1); + queue->ENST_START_TIME = GEM_ENST_START_TIME(hw_q); + queue->ENST_ON_TIME = GEM_ENST_ON_TIME(hw_q); + queue->ENST_OFF_TIME = GEM_ENST_OFF_TIME(hw_q); #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT if (bp->hw_dma_cap & HW_DMA_CAP_64B) { queue->TBQPH = GEM_TBQPH(hw_q - 1); @@ -4319,6 +4322,9 @@ static int macb_init(struct platform_device *pdev) queue->IMR = MACB_IMR; queue->TBQP = MACB_TBQP; queue->RBQP = MACB_RBQP; + queue->ENST_START_TIME = GEM_ENST_START_TIME(0); + queue->ENST_ON_TIME = GEM_ENST_ON_TIME(0); + queue->ENST_OFF_TIME = GEM_ENST_OFF_TIME(0); #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT if (bp->hw_dma_cap & HW_DMA_CAP_64B) { queue->TBQPH = MACB_TBQPH; -- 2.34.1 Implement Time-Aware Traffic Scheduling (TAPRIO) hardware offload for "tc qdisc replace" operations, enabling IEEE 802.1Qbv compliant gate scheduling on Cadence MACB/GEM controllers. Parameter validation checks performed: - Queue count bounds checking (1 < queues <= MACB_MAX_QUEUES) - TC entry limit validation against available hardware queues - Base time non-negativity enforcement - Speed-adaptive timing constraint verification - Cycle time vs. total gate time consistency checks - Single-queue gate mask enforcement per scheduling entry Hardware programming sequence: - GEM doesn't support changing register values if ENST is running, hence disable ENST before programming - Atomic timing register configuration (START_TIME, ON_TIME, OFF_TIME) - Enable the configured queues via ENST_CONTROL register This implementation ensures deterministic gate scheduling while preventing invalid configurations. Signed-off-by: Vineeth Karumanchi --- drivers/net/ethernet/cadence/macb_main.c | 155 +++++++++++++++++++++++ 1 file changed, 155 insertions(+) diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index ff87d3e1d8a0..4518b59168d5 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -36,6 +36,7 @@ #include #include #include +#include #include "macb.h" /* This structure is only used for MACB on SiFive FU540 devices */ @@ -4084,6 +4085,160 @@ static void macb_restore_features(struct macb *bp) macb_set_rxflow_feature(bp, features); } +static int macb_taprio_setup_replace(struct net_device *ndev, + struct tc_taprio_qopt_offload *conf) +{ + u64 total_on_time = 0, start_time_sec = 0, start_time = conf->base_time; + struct queue_enst_configs *enst_queue; + u32 configured_queues = 0, speed = 0; + struct tc_taprio_sched_entry *entry; + struct macb *bp = netdev_priv(ndev); + struct ethtool_link_ksettings kset; + struct macb_queue *queue; + unsigned long flags; + int err = 0, i; + + /* Validate queue configuration */ + if (bp->num_queues < 1 || bp->num_queues > MACB_MAX_QUEUES) { + netdev_err(ndev, "Invalid number of queues: %d\n", bp->num_queues); + return -EINVAL; + } + + if (conf->num_entries > bp->num_queues) { + netdev_err(ndev, "Too many TAPRIO entries: %lu > %d queues\n", + conf->num_entries, bp->num_queues); + return -EINVAL; + } + + if (start_time < 0) { + netdev_err(ndev, "Invalid base_time: must be 0 or positive, got %lld\n", + conf->base_time); + return -ERANGE; + } + + /* Get the current link speed */ + err = phylink_ethtool_ksettings_get(bp->phylink, &kset); + if (unlikely(err)) { + netdev_err(ndev, "Failed to get link settings: %d\n", err); + return err; + } + + speed = kset.base.speed; + if (unlikely(speed <= 0)) { + netdev_err(ndev, "Invalid speed: %d\n", speed); + return -EINVAL; + } + + enst_queue = kcalloc(conf->num_entries, sizeof(*enst_queue), GFP_KERNEL); + if (!enst_queue) + return -ENOMEM; + + /* Pre-validate all entries before making any hardware changes */ + for (i = 0; i < conf->num_entries; i++) { + entry = &conf->entries[i]; + + if (entry->command != TC_TAPRIO_CMD_SET_GATES) { + netdev_err(ndev, "Entry %d: unsupported command %d\n", + i, entry->command); + err = -EOPNOTSUPP; + goto cleanup; + } + + /* Validate gate_mask: must be nonzero, single queue, and within range */ + if (!is_power_of_2(entry->gate_mask)) { + netdev_err(ndev, "Entry %d: gate_mask 0x%x is not a power of 2 (only one queue per entry allowed)\n", + i, entry->gate_mask); + err = -EINVAL; + goto cleanup; + } + + /* gate_mask must not select queues outside the valid queue_mask */ + if (entry->gate_mask & ~bp->queue_mask) { + netdev_err(ndev, "Entry %d: gate_mask 0x%x exceeds queue range (max_queues=%d)\n", + i, entry->gate_mask, bp->num_queues); + err = -EINVAL; + goto cleanup; + } + + /* Check for start time limits */ + start_time_sec = div_u64(start_time, NSEC_PER_SEC); + if (start_time_sec > ENST_MAX_START_TIME_SEC) { + netdev_err(ndev, "Entry %d: Start time %llu s exceeds hardware limit\n", + i, start_time_sec); + err = -ERANGE; + goto cleanup; + } + + /* Check for on time limit*/ + if (entry->interval > ENST_MAX_HW_INTERVAL(speed)) { + netdev_err(ndev, "Entry %d: interval %u ns exceeds hardware limit %lu ns\n", + i, entry->interval, ENST_MAX_HW_INTERVAL(speed)); + err = -ERANGE; + goto cleanup; + } + + /* Check for off time limit*/ + if ((conf->cycle_time - entry->interval) > ENST_MAX_HW_INTERVAL(speed)) { + netdev_err(ndev, "Entry %d: off_time %llu ns exceeds hardware limit %lu ns\n", + i, conf->cycle_time - entry->interval, + ENST_MAX_HW_INTERVAL(speed)); + err = -ERANGE; + goto cleanup; + } + + enst_queue[i].queue_id = order_base_2(entry->gate_mask); + enst_queue[i].start_time_mask = + (start_time_sec << GEM_START_TIME_SEC_OFFSET) | + (start_time % NSEC_PER_SEC); + enst_queue[i].on_time_bytes = + ENST_NS_TO_HW_UNITS(entry->interval, speed); + enst_queue[i].off_time_bytes = + ENST_NS_TO_HW_UNITS(conf->cycle_time - entry->interval, speed); + + configured_queues |= entry->gate_mask; + total_on_time += entry->interval; + start_time += entry->interval; + } + + /* Check total interval doesn't exceed cycle time */ + if (total_on_time > conf->cycle_time) { + netdev_err(ndev, "Total ON %llu ns exceeds cycle time %llu ns\n", + total_on_time, conf->cycle_time); + err = -EINVAL; + goto cleanup; + } + + netdev_dbg(ndev, "TAPRIO setup: %lu entries, base_time=%lld ns, cycle_time=%llu ns\n", + conf->num_entries, conf->base_time, conf->cycle_time); + + /* All validations passed - proceed with hardware configuration */ + spin_lock_irqsave(&bp->lock, flags); + + /* Disable ENST queues if running before configuring */ + if (gem_readl(bp, ENST_CONTROL)) + gem_writel(bp, ENST_CONTROL, + GENMASK(bp->num_queues - 1, 0) << GEM_ENST_DISABLE_QUEUE_OFFSET); + + for (i = 0; i < conf->num_entries; i++) { + queue = &bp->queues[enst_queue[i].queue_id]; + /* Configure queue timing registers */ + queue_writel(queue, ENST_START_TIME, enst_queue[i].start_time_mask); + queue_writel(queue, ENST_ON_TIME, enst_queue[i].on_time_bytes); + queue_writel(queue, ENST_OFF_TIME, enst_queue[i].off_time_bytes); + } + + /* Enable ENST for all configured queues in one write */ + gem_writel(bp, ENST_CONTROL, configured_queues); + spin_unlock_irqrestore(&bp->lock, flags); + + netdev_info(ndev, "TAPRIO configuration completed successfully: %lu entries, %d queues configured\n", + conf->num_entries, hweight32(configured_queues)); + +cleanup: + kfree(enst_queue); + return err; +} + static const struct net_device_ops macb_netdev_ops = { .ndo_open = macb_open, .ndo_stop = macb_close, -- 2.34.1 Add hardware offload support for "tc qdisc destroy" operations to safely remove IEEE 802.1Qbv time-gated scheduling configuration and restore default queue behavior. Cleanup sequence: - Reset network device TC configuration state - Disable Enhanced Network Scheduling and Timing for all queues - Clear all ENST timing control registers (START_TIME, ON_TIME, OFF_TIME) - Atomic register programming with proper synchronization This ensures complete removal of time-aware scheduling state, returning the controller to standard FIFO queue operation without residual timing constraints Signed-off-by: Vineeth Karumanchi --- drivers/net/ethernet/cadence/macb_main.c | 28 ++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index 4518b59168d5..6b3eff28a842 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -4239,6 +4239,34 @@ static int macb_taprio_setup_replace(struct net_device *ndev, return err; } +static void macb_taprio_destroy(struct net_device *ndev) +{ + struct macb *bp = netdev_priv(ndev); + struct macb_queue *queue; + unsigned long flags; + u32 enst_disable_mask; + u8 i; + + netdev_reset_tc(ndev); + enst_disable_mask = GENMASK(bp->num_queues - 1, 0) << GEM_ENST_DISABLE_QUEUE_OFFSET; + netdev_dbg(ndev, "TAPRIO destroy: disabling all gates\n"); + + spin_lock_irqsave(&bp->lock, flags); + + /* Single disable command for all queues */ + gem_writel(bp, ENST_CONTROL, enst_disable_mask); + + /* Clear all queue ENST registers in batch */ + for (i = 0; i < bp->num_queues; i++) { + queue = &bp->queues[i]; + queue_writel(queue, ENST_START_TIME, 0); + queue_writel(queue, ENST_ON_TIME, 0); + queue_writel(queue, ENST_OFF_TIME, 0); + } + + spin_unlock_irqrestore(&bp->lock, flags); +} + static const struct net_device_ops macb_netdev_ops = { .ndo_open = macb_open, .ndo_stop = macb_close, -- 2.34.1 Add Traffic Control offload infrastructure with command routing for TAPRIO qdisc operations: - macb_setup_taprio(): TAPRIO command dispatcher - macb_setup_tc(): TC_SETUP_QDISC_TAPRIO entry point - Support for REPLACE/DESTROY command mapping Provides standardized TC interface for time-gated scheduling control. Signed-off-by: Vineeth Karumanchi --- drivers/net/ethernet/cadence/macb_main.c | 33 ++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index 6b3eff28a842..cc33491930e3 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -4267,6 +4267,38 @@ static void macb_taprio_destroy(struct net_device *ndev) spin_unlock_irqrestore(&bp->lock, flags); } +static int macb_setup_taprio(struct net_device *ndev, + struct tc_taprio_qopt_offload *taprio) +{ + int err = 0; + + switch (taprio->cmd) { + case TAPRIO_CMD_REPLACE: + err = macb_taprio_setup_replace(ndev, taprio); + break; + case TAPRIO_CMD_DESTROY: + macb_taprio_destroy(ndev); + break; + default: + err = -EOPNOTSUPP; + } + + return err; +} + +static int macb_setup_tc(struct net_device *dev, enum tc_setup_type type, void *type_data) +{ + if (!dev || !type_data) + return -EINVAL; + + switch (type) { + case TC_SETUP_QDISC_TAPRIO: + return macb_setup_taprio(dev, type_data); + default: + return -EOPNOTSUPP; + } +} + static const struct net_device_ops macb_netdev_ops = { .ndo_open = macb_open, .ndo_stop = macb_close, @@ -4284,6 +4316,7 @@ static const struct net_device_ops macb_netdev_ops = { .ndo_features_check = macb_features_check, .ndo_hwtstamp_set = macb_hwtstamp_set, .ndo_hwtstamp_get = macb_hwtstamp_get, + .ndo_setup_tc = macb_setup_tc, }; /* Configure peripheral capabilities according to device tree -- 2.34.1 The "exclude_qbv" bit in designcfg_debug1 register varies between MACB/GEM IP revisions, making direct register probing unreliable for feature detection. A capability-based approach provides consistent QBV support identification across the IP family Platform support: - Enable MACB_CAPS_QBV for Xilinx Versal platform configuration - Foundation for QBV feature detection in TAPRIO implementation Signed-off-by: Vineeth Karumanchi --- drivers/net/ethernet/cadence/macb.h | 1 + drivers/net/ethernet/cadence/macb_main.c | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h index ef3995564c5c..4e8d5dcc814e 100644 --- a/drivers/net/ethernet/cadence/macb.h +++ b/drivers/net/ethernet/cadence/macb.h @@ -782,6 +782,7 @@ #define MACB_CAPS_MIIONRGMII 0x00000200 #define MACB_CAPS_NEED_TSUCLK 0x00000400 #define MACB_CAPS_QUEUE_DISABLE 0x00000800 +#define MACB_CAPS_QBV 0x00001000 #define MACB_CAPS_PCS 0x01000000 #define MACB_CAPS_HIGH_SPEED 0x02000000 #define MACB_CAPS_CLK_HW_CHG 0x04000000 diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index cc33491930e3..98e56697661c 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -4601,6 +4601,10 @@ static int macb_init(struct platform_device *pdev) dev->hw_features |= NETIF_F_HW_CSUM | NETIF_F_RXCSUM; if (bp->caps & MACB_CAPS_SG_DISABLED) dev->hw_features &= ~NETIF_F_SG; + /* Enable HW_TC if hardware supports QBV */ + if (bp->caps & MACB_CAPS_QBV) + dev->hw_features |= NETIF_F_HW_TC; + dev->features = dev->hw_features; /* Check RX Flow Filters support. @@ -5345,7 +5349,7 @@ static const struct macb_config sama7g5_emac_config = { static const struct macb_config versal_config = { .caps = MACB_CAPS_GIGABIT_MODE_AVAILABLE | MACB_CAPS_JUMBO | MACB_CAPS_GEM_HAS_PTP | MACB_CAPS_BD_RD_PREFETCH | MACB_CAPS_NEED_TSUCLK | - MACB_CAPS_QUEUE_DISABLE, + MACB_CAPS_QUEUE_DISABLE, MACB_CAPS_QBV, .dma_burst_length = 16, .clk_init = macb_clk_init, .init = init_reset_optional, -- 2.34.1