ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_etha_tas.c File Reference

ETHA time-aware shaper (TAS / 802.1Qbv) flows – HUM Ch 32.4.2. More...

#include <stdint.h>
#include "ra8_attributes.h"
#include "ra8_check.h"
#include "ra8_err.h"
#include "ra8_etha.h"
#include "ra8_etha_internal.h"
#include "ra8_etha_regs.h"
#include "ra8_hw_err.h"
#include "ra8_log.h"
Include dependency graph for ra8_etha_tas.c:

Go to the source code of this file.

Enumerations

enum  ra8_etha_tas_poll_t : uint32_t {
  k_ra8_etha_tas_learn_spins = 100000U ,
  k_ra8_etha_tas_ram_spins = 100000U
}
 Spin budgets for the two TAS flows that wait on hardware. More...
enum  ra8_etha_tas_word_t : uint32_t { k_ra8_etha_tas_word_mask = 0xFFFFFFFFUL }
 Word-width mask used when splitting the 64-bit cycle start time. More...

Functions

static ra8_err_t internal_tas_learn_entry (volatile r_etha_regs_t *reg, uint8_t address, const ra8_etha_tas_entry_t *entry)
 Learn one entry into the TAS RAM and wait for it to land.
static ra8_err_t internal_tas_validate (const ra8_etha_tas_queue_t *queues)
 Reject a schedule hardware could not hold before any of it is written.
static ra8_err_t internal_tas_learn_all (volatile r_etha_regs_t *reg, const ra8_etha_tas_queue_t *queues, uint8_t base)
 Learn every queue's entries, laid out in queue order from base.
ra8_err_t ra8_etha_tas_ram_reset (ra8_etha_port_t port)
 Reset the TAS RAM and wait for it to report ready.
static void internal_tas_program_timing (volatile r_etha_regs_t *reg, const ra8_etha_tas_queue_t *queues, uint8_t initial_gate_states, uint32_t cycle_time_ns, uint64_t start_time)
 Write the schedule's sizing and timing registers.
ra8_err_t ra8_etha_set_tas_schedule (ra8_etha_port_t port, const ra8_etha_tas_queue_t *queues, uint8_t initial_gate_states, uint32_t cycle_time_ns, uint64_t start_time)
 Programme the time-aware shaper (TAS / 802.1Qbv) gate lists.
ra8_err_t ra8_etha_read_tas_entry (ra8_etha_port_t port, uint8_t address, ra8_etha_tas_entry_t *out)
 Read one TAS RAM entry back out of hardware.
ra8_err_t ra8_etha_enable_tas (ra8_etha_port_t port, uint8_t enable)
 Enable or disable the TAS scheduler (main switch).

Variables

static const char * s_tag = "ETHA"
 Logger tag used by every TAS call in this translation unit.

Detailed Description

ETHA time-aware shaper (TAS / 802.1Qbv) flows – HUM Ch 32.4.2.

Tag
[Ring 3 / HAL] {World: NS}

The TAS half of the ETHA driver, split out of ra8_etha.c because it is the only part of the block that is a multi-step hardware FLOW rather than a set of independent register writes. Three of the manual's flows are implemented here verbatim:

  • TAS RAM reset, HUM Figure 32.8 (Ch 32.4.2.6 p 1667);
  • TAS setting, HUM Figure 32.11 (Ch 32.4.2.9 p 1675-1676), which itself contains the per-entry learn flow of Figure 32.14 (Ch 32.4.2.12 p 1677);
  • TAS entry read, HUM Figure 32.15 (Ch 32.4.2.13 p 1678).

What was here before returned k_ra8_ok while programming the wrong things into the right registers (#539). EATASGL0.TASGAL[7:0] is the TAS RAM ENTRY ADDRESS – "Configures the address in which the TAS entry is learned" (HUM Ch 32.3.5.13 p 1652) – and it was receiving the gate state, so every learn iteration targeted an address derived from a gate bitmask and the entry index was never written at all. EATASGL1 bit 28 is TASGSL, the entry's gate state (Ch 32.3.5.14 p 1652), and it was receiving an unrelated "cut-through" flag. The mandatory per-queue entry counts (EATASENCi) were never written, and EATASGLR.GL – which hardware raises on every EATASGL1 write and lowers when the learn lands – was never polled, so the writes raced each other.

Nothing detected any of that, because all five shaper calls returned success from argument validation alone and no caller ever read hardware back. ra8_etha_read_tas_entry exists so that is no longer true.

Definition in file ra8_etha_tas.c.

Enumeration Type Documentation

◆ ra8_etha_tas_poll_t

enum ra8_etha_tas_poll_t : uint32_t

Spin budgets for the two TAS flows that wait on hardware.

Both waits are for an on-chip RAM operation that completes in a handful of ETHA clocks, so the budget only has to be large enough that a healthy part never reaches it and small enough that a wedged part is reported rather than hanging the caller forever.

Invariant
Every value is a loop-iteration count, not a time.
Enumerator
k_ra8_etha_tas_learn_spins 

EATASGLR.GL / EATASGRR.GR budget.

k_ra8_etha_tas_ram_spins 

EATASRIRM.TASRR budget.

Definition at line 76 of file ra8_etha_tas.c.

◆ ra8_etha_tas_word_t

enum ra8_etha_tas_word_t : uint32_t

Word-width mask used when splitting the 64-bit cycle start time.

EATASCSTC0 and EATASCSTC1 together hold one 64-bit start time as two 32-bit halves, so the split needs a named 32-bit mask rather than a bare literal.

Invariant
The value is exactly the width of one MMIO word.
Enumerator
k_ra8_etha_tas_word_mask 

All 32 bits of one register.

Definition at line 91 of file ra8_etha_tas.c.

Function Documentation

◆ internal_tas_learn_all()

ra8_err_t internal_tas_learn_all ( volatile r_etha_regs_t * reg,
const ra8_etha_tas_queue_t * queues,
uint8_t base )
static

Learn every queue's entries, laid out in queue order from base.

The per-queue blocks are contiguous and start at the address hardware nominated in EATASC.TASCA, so queue 0's block begins at base and each subsequent queue begins where the previous one ended.

Parameters
[in]regMMIO pointer to the port's ETHA window.
[in]queuesPer-queue gate lists, k_ra8_etha_tc_count of them.
[in]baseTAS RAM address the first entry is written to.
Returns
ra8_err_t Result code.
Return values
k_ra8_okEvery entry was learned.
k_ra8_err_hw_timeoutA learn never completed; nothing committed.
Precondition
queues passed internal_tas_validate.
reg points at a valid ETHA register window.
Postcondition
On success the TAS RAM holds every declared entry.
On failure the caller skips the commit.
Note
Not thread-safe; the caller serialises per port.
See also
internal_tas_learn_entry
Since
0.1.0

Definition at line 223 of file ra8_etha_tas.c.

References ra8_etha_tas_queue_t::count, internal_tas_learn_entry(), k_ra8_etha_mask_tas_gal, k_ra8_etha_tas_entries_max, k_ra8_etha_tc_count, k_ra8_ok, and RA8_LOOP_BOUND.

Referenced by ra8_etha_set_tas_schedule().

◆ internal_tas_learn_entry()

ra8_err_t internal_tas_learn_entry ( volatile r_etha_regs_t * reg,
uint8_t address,
const ra8_etha_tas_entry_t * entry )
static

Learn one entry into the TAS RAM and wait for it to land.

HUM Figure 32.14 (Ch 32.4.2.12 "TAS Entry i Learn Flow" p 1677): set EATASGL0 to the entry address, write EATASGL1, then read EATASGLR until GL is 0. Writing EATASGL1 is what raises GL, so the poll must follow that write and not precede it.

Parameters
[in]regMMIO pointer to the port's ETHA window.
[in]addressTAS RAM entry address for this entry.
[in]entryGate state and gate time to store.
Returns
ra8_err_t Result code.
Return values
k_ra8_okHardware lowered EATASGLR.GL.
k_ra8_err_hw_timeoutGL stayed high for the whole budget.
Precondition
reg points at a valid ETHA register window.
entry->gate_time_ns already checked against TASGTL[27:0].
Postcondition
On success the entry is resident at address in the TAS RAM.
On timeout no further entry is attempted by the caller.
Note
Not thread-safe; the caller serialises per port.
See also
ra8_etha_set_tas_schedule
Since
0.1.0

Definition at line 121 of file ra8_etha_tas.c.

References r_etha_regs_t::EATASGL0, r_etha_regs_t::EATASGL1, r_etha_regs_t::EATASGLR, ra8_etha_tas_entry_t::gate_open, ra8_etha_tas_entry_t::gate_time_ns, k_ra8_etha_eatasgl1_tasgsl_pos, k_ra8_etha_eatasglr_gl_pos, k_ra8_etha_mask_tas_gal, k_ra8_etha_mask_tas_gtl, k_ra8_etha_tas_learn_spins, k_ra8_ok, ra8_hw_wait_flag_clear32(), ra8_log_error, and s_tag.

Referenced by internal_tas_learn_all().

◆ internal_tas_program_timing()

void internal_tas_program_timing ( volatile r_etha_regs_t * reg,
const ra8_etha_tas_queue_t * queues,
uint8_t initial_gate_states,
uint32_t cycle_time_ns,
uint64_t start_time )
static

Write the schedule's sizing and timing registers.

Steps 3 and 4 of HUM Figure 32.11: each queue's entry count to its own EATASENCi, the per-queue initial gate states to EATASIGSC, and the cycle start / cycle time to EATASCSTC0, EATASCSTC1 and EATASCTC. Split out of ra8_etha_set_tas_schedule so that function stays inside the statement budget; it is one contiguous block of the manual's flow with no decisions of its own.

Parameters
[in]regMMIO pointer to the port's ETHA window.
[in]queuesPer-queue gate lists, one per traffic class.
[in]initial_gate_statesEATASIGSC bitmap, bit q per queue q.
[in]cycle_time_nsValue for EATASCTC.
[in]start_time64-bit cycle start, split across CSTC0/CSTC1.
Precondition
queues passed internal_tas_validate.
reg points at a valid ETHA register window.
Postcondition
Every EATASENCi, EATASIGSC, EATASCSTC0/1 and EATASCTC is written.
No entry has been learned yet and nothing is committed.
Note
Not thread-safe; the caller serialises per port.
See also
ra8_etha_set_tas_schedule
Since
0.1.0

Definition at line 292 of file ra8_etha_tas.c.

References r_etha_regs_t::EATASCSTC0, r_etha_regs_t::EATASCSTC1, r_etha_regs_t::EATASCTC, r_etha_regs_t::EATASENC, r_etha_regs_t::EATASIGSC, k_ra8_etha_mask_aen, k_ra8_etha_mask_tas_igs, k_ra8_etha_tas_word_mask, k_ra8_etha_tc_count, and RA8_LOOP_BOUND.

Referenced by ra8_etha_set_tas_schedule().

◆ internal_tas_validate()

ra8_err_t internal_tas_validate ( const ra8_etha_tas_queue_t * queues)
static

Reject a schedule hardware could not hold before any of it is written.

Validates the whole request up front so a rejected schedule leaves the previously active one running: once the first EATASENCi write lands there is no way back. Checks the per-queue pointer contract, the TASGTL[27:0] width of every gate time, and the TAS RAM capacity limit from HUM Ch 32.3.5.3 (p 1647).

Parameters
[in]queuesPer-queue gate lists, k_ra8_etha_tc_count of them.
Returns
ra8_err_t Result code.
Return values
k_ra8_okSchedule is programmable as given.
k_ra8_err_null_ptrA non-empty queue has a nullptr entry list.
k_ra8_err_invalid_argCapacity or gate-time width exceeded.
Precondition
queues is non-null and has k_ra8_etha_tc_count elements.
Every queue's count is its own entry-list length.
Postcondition
No hardware register is touched on any path.
The caller may program the schedule iff this returned k_ra8_ok.
Note
Pure; no side effects at all.
See also
ra8_etha_set_tas_schedule
Since
0.1.0

Definition at line 172 of file ra8_etha_tas.c.

References ra8_etha_tas_queue_t::count, k_ra8_err_invalid_arg, k_ra8_etha_mask_tas_gtl, k_ra8_etha_tas_entries_max, k_ra8_etha_tc_count, k_ra8_ok, RA8_CHECK_NULL_PTR, ra8_log_error, RA8_LOOP_BOUND, and s_tag.

Referenced by ra8_etha_set_tas_schedule().

◆ ra8_etha_enable_tas()

ra8_err_t ra8_etha_enable_tas ( ra8_etha_port_t port,
uint8_t enable )
nodiscard

Enable or disable the TAS scheduler (main switch).

Parameters
[in]portPort identifier.
[in]enableNon-zero -> set EATASC.TASE; zero -> clear.
Returns
ra8_err_t Error code.
Return values
k_ra8_okEATASC.TASE updated.
k_ra8_err_invalid_argport out of range.
Precondition
Port previously brought up via ra8_etha_init.
TAS schedule programmed via ra8_etha_set_tas_schedule.
Postcondition
EATASC.TASE = enable!=0.
Other EATASC bits unchanged.
Note
When disabled, all gates are forced open.
See also
ra8_etha_set_tas_schedule
Since
0.1.0

Definition at line 389 of file ra8_etha_tas.c.

References r_etha_regs_t::EATASC, internal_port_ok(), k_ra8_err_invalid_arg, k_ra8_etha_eatasc_tase_pos, k_ra8_ok, ra8_etha(), ra8_log_error, and s_tag.

Referenced by tsn_program_tas().

◆ ra8_etha_read_tas_entry()

ra8_err_t ra8_etha_read_tas_entry ( ra8_etha_port_t port,
uint8_t address,
ra8_etha_tas_entry_t * out )
nodiscard

Read one TAS RAM entry back out of hardware.

The TAS entry read flow of HUM Figure 32.15 (Ch 32.4.2.13 "TAS Entry i Read Flow" p 1678): write the address to EATASGR.TASGAR, poll until EATASGRR.GR clears, then take TASGSR and TASGTR[27:0].

This is the read-back that lets a caller assert something real. Without it, the only available evidence that a schedule was programmed is that the programming calls returned k_ra8_ok – which they also did while the driver was writing gate states into the entry-address register.

Parameters
[in]portPort identifier.
[in]addressTAS RAM entry address (0..k_ra8_etha_tas_addr_max).
[out]outEntry read back from that address.
Returns
ra8_err_t Error code.
Return values
k_ra8_ok*out holds the entry at address.
k_ra8_err_null_ptrout is nullptr.
k_ra8_err_invalid_argport out of range.
k_ra8_err_hw_timeoutEATASGRR.GR never cleared within budget.
Precondition
Port previously brought up via ra8_etha_init.
Port is not in RESET or DISABLE mode.
Postcondition
On success *out reflects TAS RAM contents at address.
Hardware state is unchanged apart from EATASGR.
Note
Not thread-safe; serialise per port.
See also
ra8_etha_set_tas_schedule
Since
0.1.0

Definition at line 361 of file ra8_etha_tas.c.

References r_etha_regs_t::EATASGR, r_etha_regs_t::EATASGRR, ra8_etha_tas_entry_t::gate_open, ra8_etha_tas_entry_t::gate_time_ns, internal_port_ok(), k_ra8_err_invalid_arg, k_ra8_etha_eatasgrr_gr_pos, k_ra8_etha_eatasgrr_tasgsr_pos, k_ra8_etha_mask_tas_gal, k_ra8_etha_mask_tas_gtl, k_ra8_etha_tas_learn_spins, k_ra8_ok, RA8_CHECK_NULL_PTR, ra8_etha(), ra8_hw_wait_flag_clear32(), ra8_log_error, and s_tag.

Referenced by tsn_tas_entry_matches().

◆ ra8_etha_set_tas_schedule()

ra8_err_t ra8_etha_set_tas_schedule ( ra8_etha_port_t port,
const ra8_etha_tas_queue_t * queues,
uint8_t initial_gate_states,
uint32_t cycle_time_ns,
uint64_t start_time )
nodiscard

Programme the time-aware shaper (TAS / 802.1Qbv) gate lists.

Implements the TAS setting flow of HUM Figure 32.11 (Ch 32.4.2.9 "TAS Setting Flow" p 1675-1676) exactly:

  1. read EATASC and abort when TASCI says a configuration change is impossible;
  2. take the base TAS RAM address from EATASC.TASCA[23:16];
  3. write each queue's entry count to EATASENCi;
  4. write the cycle start time to EATASCSTC0/1 and the cycle time to EATASCTC;
  5. learn every entry in turn – EATASGL0 takes the entry ADDRESS, EATASGL1 takes {TASGSL gate state, TASGTL gate time}, then EATASGLR.GL is polled until hardware clears it;
  6. commit by setting EATASC.TASE, with TASCC set only when TAS was already enabled (a live schedule change).

queues is indexed by descriptor queue because the TAS RAM is partitioned per queue rather than holding one interleaved list: the entry blocks are laid out in queue order from EATASC.TASCA upward, and an entry's single GS bit belongs to the queue whose block holds it.

Parameters
[in]portPort identifier.
[in]queuesPer-queue gate lists; k_ra8_etha_tc_count elements.
[in]initial_gate_statesEATASIGSC bitmap – bit q is queue q's gate state at schedule start (HUM Ch 32.3.5.2 p 1647).
[in]cycle_time_nsTotal cycle time, written verbatim to EATASCTC.
[in]start_timeAbsolute cycle-start time on the gPTP time base; low word to EATASCSTC0, high word to EATASCSTC1.
Returns
ra8_err_t Error code.
Return values
k_ra8_okTAS programmed and committed.
k_ra8_err_null_ptrqueues is nullptr, or a queue declares a non-zero count with a nullptr entry list.
k_ra8_err_invalid_argport out of range, the total entry count exceeds k_ra8_etha_tas_entries_max, or a gate time does not fit TASGTL[27:0].
k_ra8_err_busyEATASC.TASCI is set; the port cannot accept a configuration change right now.
k_ra8_err_hw_timeoutEATASGLR.GL never cleared after a learn.
Precondition
Port is in CONFIG or OPERATION mode – the flow is unusable in RESET and DISABLE, per the note on Figure 32.11.
The TAS RAM has been reset at least once via ra8_etha_tas_ram_reset.
Postcondition
On success every declared entry is resident in the TAS RAM and EATASC.TASE is set.
On any error return no commit is issued, so a previously active schedule keeps running.
Note
Not thread-safe; serialise per port.
Warning
Gate times are in NANOSECONDS, not bus clocks: HUM Table 32.6 (p 1691) defines TAS.GT that way.
Example:
static const ra8_etha_tas_entry_t ptp_window[2] = {
{.gate_time_ns = 125000U, .gate_open = true},
{.gate_time_ns = 875000U, .gate_open = false},
};
queues[k_ra8_etha_tc_7].entries = ptp_window;
queues[k_ra8_etha_tc_7].count = 2U;
(void)ra8_etha_set_tas_schedule(k_ra8_etha_port_0, queues, 0x80U, 1000000U, 0U);
@ k_ra8_etha_port_0
ETHA port 0 (base 0x403C_A000).
@ k_ra8_etha_tc_7
Highest priority / control / PTP.
@ k_ra8_etha_tc_count
Number of traffic classes per port.
ra8_err_t ra8_etha_set_tas_schedule(ra8_etha_port_t port, const ra8_etha_tas_queue_t *queues, uint8_t initial_gate_states, uint32_t cycle_time_ns, uint64_t start_time)
Programme the time-aware shaper (TAS / 802.1Qbv) gate lists.
One TAS (802.1Qbv) RAM entry, exactly as HUM Table 32.6 defines it.
The gate-control list of one descriptor queue.
const ra8_etha_tas_entry_t * entries
Gate list, or nullptr when count is 0.
uint16_t count
Entries for this queue (EATASENCi).
State Machine
See also
ra8_etha_tas_ram_reset
ra8_etha_read_tas_entry
Since
0.1.0

Definition at line 313 of file ra8_etha_tas.c.

References r_etha_regs_t::EATASC, internal_port_ok(), internal_tas_learn_all(), internal_tas_program_timing(), internal_tas_validate(), k_ra8_err_busy, k_ra8_err_invalid_arg, k_ra8_etha_eatasc_tasca_pos, k_ra8_etha_eatasc_tascc_pos, k_ra8_etha_eatasc_tasci_pos, k_ra8_etha_eatasc_tase_pos, k_ra8_etha_mask_tas_gal, k_ra8_ok, RA8_CHECK_NULL_PTR, ra8_etha(), ra8_log_error, and s_tag.

Referenced by tsn_program_tas().

◆ ra8_etha_tas_ram_reset()

ra8_err_t ra8_etha_tas_ram_reset ( ra8_etha_port_t port)
nodiscard

Reset the TAS RAM and wait for it to report ready.

The TAS RAM reset flow of HUM Figure 32.8 (Ch 32.4.2.6 "TAS RAM Reset Flow" p 1667): write 1 to EATASRIRM.TASRIOG, then poll until EATASRIRM.TASRR reads 1. Hardware clears TASRIOG itself when the initialisation completes. Entries learned before a reset do not survive it, so this runs once during bring-up, ahead of any schedule.

Parameters
[in]portPort identifier.
Returns
ra8_err_t Error code.
Return values
k_ra8_okTAS RAM initialised; EATASRIRM.TASRR reads 1.
k_ra8_err_invalid_argport out of range.
k_ra8_err_hw_timeoutTASRR never asserted within budget.
Precondition
Port previously brought up via ra8_etha_init.
Port is not in RESET or DISABLE mode; the flow is unusable there.
Postcondition
On success the TAS RAM holds no entries and TASRR reads 1.
On timeout no schedule is committed.
Note
Not thread-safe; serialise per port.
See also
ra8_etha_set_tas_schedule
Since
0.1.0

Definition at line 244 of file ra8_etha_tas.c.

References r_etha_regs_t::EATASRIRM, internal_port_ok(), k_ra8_err_invalid_arg, k_ra8_etha_eatasrirm_tasriog_pos, k_ra8_etha_eatasrirm_tasrr_pos, k_ra8_etha_tas_ram_spins, k_ra8_ok, ra8_etha(), ra8_hw_wait_flag_set32(), ra8_log_error, and s_tag.

Referenced by tsn_program_tas().

Variable Documentation

◆ s_tag

const char* s_tag = "ETHA"
static

Logger tag used by every TAS call in this translation unit.

TU-local read-only logger tag, matching the string the other two ETHA translation units use so a log reader sees one subsystem.

Note
Read-only after init; treat as immutable.
Warning
Not safe to mutate.
Since
0.1.0

Definition at line 62 of file ra8_etha_tas.c.