ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_etha_tas.c
Go to the documentation of this file.
1
40
41#include <stdint.h>
42
43#include "ra8_attributes.h"
44#include "ra8_check.h"
45#include "ra8_err.h"
46#include "ra8_etha.h"
47#include "ra8_etha_internal.h"
48#include "ra8_etha_regs.h"
49#include "ra8_hw_err.h"
50#include "ra8_log.h"
51
62static const char* s_tag = "ETHA";
63
76typedef enum : uint32_t {
80
91typedef enum : uint32_t {
92 k_ra8_etha_tas_word_mask = 0xFFFFFFFFUL,
94
122 uint8_t address,
123 const ra8_etha_tas_entry_t* entry)
124{
125 /* HUM Ch 32.3.5.13 "EATASGL0 : TAS Gate Learn Register 0" p 1652 */
126 reg->EATASGL0 = (uint32_t)address & k_ra8_etha_mask_tas_gal;
127
128 uint32_t gl1 = entry->gate_time_ns & k_ra8_etha_mask_tas_gtl;
129 if (entry->gate_open) {
130 gl1 |= (uint32_t)1U << (uint32_t)k_ra8_etha_eatasgl1_tasgsl_pos;
131 }
132 /* HUM Ch 32.3.5.14 "EATASGL1 : TAS Gate Learn Register 1" p 1652 */
133 reg->EATASGL1 = gl1;
134
135 /* HUM Ch 32.3.5.15 "EATASGLR : TAS Gate Learn Result Register" p 1653 */
136 const ra8_err_t err =
138 (uint32_t)1U << (uint32_t)k_ra8_etha_eatasglr_gl_pos,
140 if (err != k_ra8_ok) {
141 ra8_log_error(s_tag, "etha_tas: EATASGLR.GL never cleared");
142 }
143 return err;
144}
145
173{
174 uint32_t total = 0U;
176 for (uint8_t queue = 0U; queue < (uint8_t)k_ra8_etha_tc_count; ++queue) {
177 const uint16_t count = queues[queue].count;
178 if (count == 0U) {
179 continue;
180 }
181 RA8_CHECK_NULL_PTR(queues[queue].entries, s_tag, "etha_tas: queue entries null");
183 for (uint16_t index = 0U; index < count; ++index) {
184 if (queues[queue].entries[index].gate_time_ns > k_ra8_etha_mask_tas_gtl) {
185 ra8_log_error(s_tag, "etha_tas: gate time exceeds TASGTL[27:0]");
187 }
188 }
189 total += (uint32_t)count;
190 }
191 if (total > (uint32_t)k_ra8_etha_tas_entries_max) {
192 ra8_log_error(s_tag, "etha_tas: total entries exceed TAS RAM capacity");
194 }
195 return k_ra8_ok;
196}
197
224 const ra8_etha_tas_queue_t* queues,
225 uint8_t base)
226{
227 uint32_t address = (uint32_t)base;
229 for (uint8_t queue = 0U; queue < (uint8_t)k_ra8_etha_tc_count; ++queue) {
231 for (uint16_t index = 0U; index < queues[queue].count; ++index) {
232 const ra8_err_t err = internal_tas_learn_entry(reg,
233 (uint8_t)(address & k_ra8_etha_mask_tas_gal),
234 &queues[queue].entries[index]);
235 if (err != k_ra8_ok) {
236 return err;
237 }
238 ++address;
239 }
240 }
241 return k_ra8_ok;
242}
243
245{
246 if (!internal_port_ok(port)) {
247 ra8_log_error(s_tag, "etha_tas_ram_reset: port out of range");
249 }
250 volatile r_etha_regs_t* reg = ra8_etha(port);
251
252 /* HUM Ch 32.3.5.19 "EATASRIRM : TAS RAM Initialization Register Monitoring" p 1655 */
253 reg->EATASRIRM = (uint32_t)1U << (uint32_t)k_ra8_etha_eatasrirm_tasriog_pos;
254
255 /* HUM Ch 32.3.5.19 "EATASRIRM : TAS RAM Initialization Register Monitoring" p 1655 */
256 const ra8_err_t err =
258 (uint32_t)1U << (uint32_t)k_ra8_etha_eatasrirm_tasrr_pos,
259 (uint32_t)k_ra8_etha_tas_ram_spins);
260 if (err != k_ra8_ok) {
261 ra8_log_error(s_tag, "etha_tas_ram_reset: EATASRIRM.TASRR never asserted");
262 }
263 return err;
264}
265
293 const ra8_etha_tas_queue_t* queues,
294 uint8_t initial_gate_states,
295 uint32_t cycle_time_ns,
296 uint64_t start_time)
297{
298 /* HUM Ch 32.3.5.2 "EATASIGSC : TAS Initial Gate State Configuration Register" p 1647 */
299 reg->EATASIGSC = (uint32_t)initial_gate_states & k_ra8_etha_mask_tas_igs;
301 for (uint8_t queue = 0U; queue < (uint8_t)k_ra8_etha_tc_count; ++queue) {
302 /* HUM Ch 32.3.5.3 "EATASENCi : TAS Entry Number Configuration Register i" p 1647 */
303 reg->EATASENC[queue] = (uint32_t)queues[queue].count & k_ra8_etha_mask_aen;
304 }
305 /* HUM Ch 32.3.5.7 "EATASCSTC0 : TAS Cycle Start Time Configuration Register 0" p 1649 */
306 reg->EATASCSTC0 = (uint32_t)(start_time & (uint64_t)k_ra8_etha_tas_word_mask);
307 /* HUM Ch 32.3.5.8 "EATASCSTC1 : TAS Cycle Start Time Configuration Register 1" p 1650 */
308 reg->EATASCSTC1 = (uint32_t)((start_time >> 32U) & (uint64_t)k_ra8_etha_tas_word_mask);
309 /* HUM Ch 32.3.5.11 "EATASCTC : TAS Cycle Time Configuration Register" p 1651 */
310 reg->EATASCTC = cycle_time_ns;
311}
312
314 const ra8_etha_tas_queue_t* queues,
315 uint8_t initial_gate_states,
316 uint32_t cycle_time_ns,
317 uint64_t start_time)
318{
319 RA8_CHECK_NULL_PTR(queues, s_tag, "etha_set_tas_schedule: queues null");
320 if (!internal_port_ok(port)) {
321 ra8_log_error(s_tag, "etha_set_tas_schedule: port out of range");
323 }
324 const ra8_err_t valid_err = internal_tas_validate(queues);
325 if (valid_err != k_ra8_ok) {
326 return valid_err;
327 }
328
329 volatile r_etha_regs_t* reg = ra8_etha(port);
330 /* HUM Ch 32.3.5.1 "EATASC : TAS Configuration Register" p 1646 */
331 const uint32_t tasc = reg->EATASC;
332 if ((tasc & ((uint32_t)1U << (uint32_t)k_ra8_etha_eatasc_tasci_pos)) != 0U) {
333 ra8_log_error(s_tag, "etha_set_tas_schedule: EATASC.TASCI set");
334 return k_ra8_err_busy;
335 }
336 const uint8_t base =
337 (uint8_t)((tasc >> (uint32_t)k_ra8_etha_eatasc_tasca_pos) & k_ra8_etha_mask_tas_gal);
338 const bool already_enabled =
339 (tasc & ((uint32_t)1U << (uint32_t)k_ra8_etha_eatasc_tase_pos)) != 0U;
340
341 internal_tas_program_timing(reg, queues, initial_gate_states, cycle_time_ns, start_time);
342
343 const ra8_err_t learn_err = internal_tas_learn_all(reg, queues, base);
344 if (learn_err != k_ra8_ok) {
345 return learn_err;
346 }
347
348 /* Commit: TASE always, TASCC only when this replaces a running schedule
349 * (HUM Figure 32.11's two terminal boxes). */
350 uint32_t commit = tasc | ((uint32_t)1U << (uint32_t)k_ra8_etha_eatasc_tase_pos);
351 if (already_enabled) {
352 commit |= (uint32_t)1U << (uint32_t)k_ra8_etha_eatasc_tascc_pos;
353 } else {
354 commit &= ~((uint32_t)1U << (uint32_t)k_ra8_etha_eatasc_tascc_pos);
355 }
356 /* HUM Ch 32.3.5.1 "EATASC : TAS Configuration Register" p 1646 */
357 reg->EATASC = commit;
358 return k_ra8_ok;
359}
360
362{
363 RA8_CHECK_NULL_PTR(out, s_tag, "etha_read_tas_entry: out null");
364 if (!internal_port_ok(port)) {
365 ra8_log_error(s_tag, "etha_read_tas_entry: port out of range");
367 }
368 volatile r_etha_regs_t* reg = ra8_etha(port);
369
370 /* HUM Ch 32.3.5.16 "EATASGR : TAS Gate Read Register" p 1653 */
371 reg->EATASGR = (uint32_t)address & k_ra8_etha_mask_tas_gal;
372
373 /* HUM Ch 32.3.5.17 "EATASGRR : TAS Gate Read Result Register" p 1654 */
374 const ra8_err_t err =
376 (uint32_t)1U << (uint32_t)k_ra8_etha_eatasgrr_gr_pos,
378 if (err != k_ra8_ok) {
379 ra8_log_error(s_tag, "etha_read_tas_entry: EATASGRR.GR never cleared");
380 return err;
381 }
382 /* HUM Ch 32.3.5.17 "EATASGRR : TAS Gate Read Result Register" p 1654 */
383 const uint32_t grr = reg->EATASGRR;
385 out->gate_open = (grr & ((uint32_t)1U << (uint32_t)k_ra8_etha_eatasgrr_tasgsr_pos)) != 0U;
386 return k_ra8_ok;
387}
388
390{
391 if (!internal_port_ok(port)) {
392 ra8_log_error(s_tag, "etha_enable_tas: port out of range");
394 }
395 volatile r_etha_regs_t* reg = ra8_etha(port);
396 /* HUM Ch 32.3.5.1 "EATASC : TAS Configuration Register" p 1646 */
397 const uint32_t tasc = reg->EATASC;
398 const uint32_t bit = (uint32_t)1U << (uint32_t)k_ra8_etha_eatasc_tase_pos;
399 /* HUM Ch 32.3.5.1 "EATASC : TAS Configuration Register" p 1646 */
400 reg->EATASC = (enable != 0U) ? (tasc | bit) : (tasc & ~bit);
401 return k_ra8_ok;
402}
static const char * s_tag
Logging / check tag.
Definition ra8_app.c:17
Annotation-attribute framework macros for ra8-firmware.
#define RA8_LOOP_BOUND(ceiling)
NASA Power-of-10 Rule 2: bind ONE loop to a compile-time ceiling.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
Validation and Error-Checking Macros for ra8-firmware.
#define RA8_CHECK_NULL_PTR(ptr, tag, message)
Reject nullptr pointer, returning k_ra8_err_null_ptr.
Definition ra8_check.h:243
Error Code Definitions for ra8-firmware.
@ k_ra8_err_busy
Resource busy – blocking operation cannot proceed.
Definition ra8_err.h:195
@ k_ra8_err_invalid_arg
Invalid function argument.
Definition ra8_err.h:152
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
Per-port Ethernet Agent (ETHA) driver – HUM Ch 32 (p 1627-1702).
Cross-TU shared surface for the ra8_etha driver split.
static bool internal_port_ok(ra8_etha_port_t port)
Range-check a port argument.
Ethernet Agent (ETHA) per-port register layout for the RA8D2.
ra8_etha_port_t
ETHA port index (m = 0, 1).
@ k_ra8_etha_tc_count
Number of traffic classes per port.
@ k_ra8_etha_tas_entries_max
Max total entries across all queues.
static volatile r_etha_regs_t * ra8_etha(ra8_etha_port_t port)
Compile-time offset and size insurance for r_etha_regs_t.
@ k_ra8_etha_eatasc_tasca_pos
EATASC.TASCA[23:16].
@ k_ra8_etha_eatasc_tase_pos
EATASC.TASE.
@ k_ra8_etha_eatasc_tasci_pos
EATASC.TASCI.
@ k_ra8_etha_eatasc_tascc_pos
EATASC.TASCC.
@ k_ra8_etha_eatasglr_gl_pos
EATASGLR.GL: learn in progress.
@ k_ra8_etha_eatasrirm_tasriog_pos
EATASRIRM.TASRIOG: init ongoing.
@ k_ra8_etha_eatasgl1_tasgsl_pos
EATASGL1.TASGSL: entry gate state.
@ k_ra8_etha_eatasrirm_tasrr_pos
EATASRIRM.TASRR: TAS RAM ready.
@ k_ra8_etha_eatasgrr_gr_pos
EATASGRR.GR: read in progress.
@ k_ra8_etha_eatasgrr_tasgsr_pos
EATASGRR.TASGSR: read gate state.
@ k_ra8_etha_mask_tas_gal
EATASGL0.TASGAL[7:0].
@ k_ra8_etha_mask_tas_igs
EATASIGSC.TASIGS7..0.
@ k_ra8_etha_mask_tas_gtl
EATASGL1.TASGTL[27:0].
@ k_ra8_etha_mask_aen
EATASENC.TASAEN[8:0].
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_enable_tas(ra8_etha_port_t port, uint8_t enable)
Enable or disable the TAS scheduler (main switch).
ra8_err_t ra8_etha_tas_ram_reset(ra8_etha_port_t port)
Reset the TAS RAM and wait for it to report ready.
ra8_etha_tas_word_t
Word-width mask used when splitting the 64-bit cycle start time.
@ k_ra8_etha_tas_word_mask
All 32 bits of one register.
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_etha_tas_poll_t
Spin budgets for the two TAS flows that wait on hardware.
@ k_ra8_etha_tas_learn_spins
EATASGLR.GL / EATASGRR.GR budget.
@ k_ra8_etha_tas_ram_spins
EATASRIRM.TASRR budget.
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.
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.
Bounded wait-flag primitives for RA8D2 HAL drivers.
static ra8_err_t ra8_hw_wait_flag_set32(volatile const uint32_t *reg, uint32_t mask, uint32_t budget)
Spin until (*reg & mask) != 0 or budget runs out.
Definition ra8_hw_err.h:309
static ra8_err_t ra8_hw_wait_flag_clear32(volatile const uint32_t *reg, uint32_t mask, uint32_t budget)
Spin until (*reg & mask) == 0 or budget runs out.
Definition ra8_hw_err.h:351
Lightweight Logging Interface for ra8-firmware.
#define ra8_log_error(tag, message)
RA8 log error.
Definition ra8_log.h:335
Full ETHA per-port register window (HUM Ch 32, FSP R_ETHA0_Type).
volatile uint32_t EATASENC[8]
+0x0320..0x033F TAS entry-num cfg.
volatile uint32_t EATASGLR
+0x03C8 TAS gate learn result.
volatile uint32_t EATASGR
+0x03D0 TAS gate read.
volatile uint32_t EATASCTC
+0x03B0 TAS cycle time configuration.
volatile uint32_t EATASIGSC
+0x0304 TAS initial gate state cfg.
volatile uint32_t EATASGL0
+0x03C0 TAS gate learn 0.
volatile uint32_t EATASCSTC0
+0x03A0 TAS cycle start time cfg lo.
volatile uint32_t EATASGL1
+0x03C4 TAS gate learn 1.
volatile uint32_t EATASRIRM
+0x03E4 TAS RAM-init register monitor.
volatile uint32_t EATASC
+0x0300 TAS configuration.
volatile uint32_t EATASGRR
+0x03D4 TAS gate read result.
volatile uint32_t EATASCSTC1
+0x03A4 TAS cycle start time cfg hi.
One TAS (802.1Qbv) RAM entry, exactly as HUM Table 32.6 defines it.
bool gate_open
TAS.GS – true opens this queue's gate.
uint32_t gate_time_ns
TAS.GT – entry duration in ns, 28 bits.
The gate-control list of one descriptor queue.
uint16_t count
Entries for this queue (EATASENCi).