ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_eth_gwca_queue.c
Go to the documentation of this file.
1
20
21#include <stdint.h>
22#include <string.h>
23
24#include "ra8_attributes.h"
25#include "ra8_check.h"
26#include "ra8_err.h"
27#include "ra8_eth_gwca.h"
29#include "ra8_ether_regs.h"
30#include "ra8_hw_err.h"
31#include "ra8_log.h"
32
33static const char* s_tag = "ETHGWC";
34
61{
62 /* GWDCC value: DQT + DCP[18:16] + SL + EDE. SM[1:0] stays 00b
63 * (Normal mode -- full descriptor write-back). ETS stays 0, BALR
64 * stays 0 (default AXI burst), OSID 0. EDE = 1 when the queue uses
65 * 16-byte extended descriptors (the TX path). */
66 uint32_t value = 0U;
67 if (cfg->is_tx) {
68 value |= (uint32_t)k_ra8_gwdcc_dqt;
69 }
70 if (cfg->stop_on_last) {
71 value |= (uint32_t)k_ra8_gwdcc_sl;
72 }
73 if (cfg->extended) {
74 value |= (uint32_t)k_ra8_gwdcc_ede;
75 }
76 value |= (((uint32_t)cfg->priority << k_ra8_gwdcc_dcp_shift) & k_ra8_gwdcc_dcp_mask);
77 return value;
78}
79
81{
82 enum : uintptr_t {
83 k_ra8_linkfix_ptr_upper_shift = 32U,
84 k_ra8_linkfix_ptr_upper_mask = 0xFFULL,
85 k_ra8_linkfix_ptr_lower_mask = 0xFFFFFFFFULL,
86 };
87 const uintptr_t head_addr = (uintptr_t)chain_head;
88 entry->dt = (uint8_t)k_ra8_gwdcc_dt_linkfix;
89 entry->ptr_h =
90 (uint8_t)((uint64_t)head_addr >> k_ra8_linkfix_ptr_upper_shift) & k_ra8_linkfix_ptr_upper_mask;
91 entry->ptr_l = (uint32_t)head_addr & k_ra8_linkfix_ptr_lower_mask;
92}
93
121 uint32_t queue_index,
122 const ra8_eth_gwca_queue_cfg_t* cfg)
123{
124 RA8_CHECK_NULL_PTR(linkfix_table, s_tag, "configure_queue: table null");
125 RA8_CHECK_NULL_PTR(cfg, s_tag, "configure_queue: cfg null");
126 RA8_CHECK_NULL_PTR(cfg->chain_head, s_tag, "configure_queue: chain_head null");
127 enum : uint8_t {
128 k_ra8_gwdcc_dcp_max = 7U,
129 };
130 if (cfg->priority > k_ra8_gwdcc_dcp_max) {
132 }
133 volatile uint32_t* const gwdcc = ra8_gwca_gwdcc(queue_index);
134 if (gwdcc == nullptr) {
136 }
137 *gwdcc = internal_compose_gwdcc(cfg);
138 priv_ra8_eth_gwca_set_linkfix_entry(&linkfix_table[queue_index], cfg->chain_head);
139 return k_ra8_ok;
140}
141
171{
172 volatile uint32_t* const gwdcc = ra8_gwca_gwdcc(queue_index);
173 if (gwdcc == nullptr) {
175 }
176 /* HUM Ch 34.3 "GWDCCi" p 1811: BALR self-clears once the GWCA has
177 * reset the AXI address RAM current_address pointer. */
178 *gwdcc |= (uint32_t)k_ra8_gwdcc_balr;
179 const ra8_err_t err =
181 if (err != k_ra8_ok) {
182 ra8_log_error(s_tag, "reload_queue: GWDCC BALR never cleared");
183 }
184 return err;
185}
186
212ra8_eth_gwca_init_ring(ra8_gwca_basic_descriptor_t* chain, uint32_t ring_depth, uint32_t slot_bytes)
213{
214 RA8_CHECK_NULL_PTR(chain, s_tag, "init_ring: chain null");
215 enum : uint32_t {
216 k_ra8_gwca_ring_min_depth = 2U,
217 k_ra8_gwca_ring_max_bytes = 2048U,
218 };
219 if (ring_depth < k_ra8_gwca_ring_min_depth || slot_bytes > k_ra8_gwca_ring_max_bytes) {
221 }
222
223 /* FEMPTY data slots: ds carries the buffer size, dt = FEMPTY. */
224 enum : uint32_t {
225 k_ra8_ds_byte_mask = 0xFFU,
226 k_ra8_ds_high_shift = 8U,
227 k_ra8_ds_high_mask = 0xFU,
228 };
229 for (uint32_t i = 0U; i < (ring_depth - 1U); ++i) {
230 (void)memset(&chain[i], 0, sizeof(ra8_gwca_basic_descriptor_t));
231 chain[i].dt = (uint8_t)k_ra8_gwdcc_dt_fempty;
232 chain[i].ds_l = (uint8_t)(slot_bytes & k_ra8_ds_byte_mask);
233 chain[i].ds_h = (uint8_t)((slot_bytes >> k_ra8_ds_high_shift) & k_ra8_ds_high_mask);
234 /* ptr_l left at 0 -- caller fills in the per-slot buffer address. */
235 }
236
237 /* Last entry: LINK back to chain[0] so the chip wraps. */
238 priv_ra8_eth_gwca_set_linkfix_entry(&chain[ring_depth - 1U], &chain[0]);
239 /* Override dt: priv_ra8_eth_gwca_set_linkfix_entry writes LINKFIX, but for
240 * mid-chain wrap we want LINK (interchangeable per HUM Ch
241 * 34.5.1.3.2; LINK is the standard chain-continuation type). */
242 chain[ring_depth - 1U].dt = (uint8_t)k_ra8_gwdcc_dt_link;
243 return k_ra8_ok;
244}
245
268{
269 RA8_CHECK_NULL_PTR(desc, s_tag, "set_descriptor_buffer: desc null");
270 enum : uintptr_t {
271 k_ra8_buf_ptr_upper_shift = 32U,
272 k_ra8_buf_ptr_upper_mask = 0xFFULL,
273 k_ra8_buf_ptr_lower_mask = 0xFFFFFFFFULL,
274 };
275 const uintptr_t addr = (uintptr_t)buffer;
276 desc->ptr_h = (uint8_t)((uint64_t)addr >> k_ra8_buf_ptr_upper_shift) & k_ra8_buf_ptr_upper_mask;
277 desc->ptr_l = (uint32_t)addr & k_ra8_buf_ptr_lower_mask;
278 return k_ra8_ok;
279}
280
308 uint32_t ring_depth,
309 uint32_t slot_bytes,
310 uint8_t* pool)
311{
312 RA8_CHECK_NULL_PTR(chain, s_tag, "attach_buffers: chain null");
313 RA8_CHECK_NULL_PTR(pool, s_tag, "attach_buffers: pool null");
314 if (ring_depth < 2U || slot_bytes == 0U) {
316 }
317 for (uint32_t i = 0U; i < (ring_depth - 1U); ++i) {
318 const size_t slot_offset = (size_t)i * (size_t)slot_bytes;
319 const ra8_err_t err = ra8_eth_gwca_set_descriptor_buffer(&chain[i], &pool[slot_offset]);
320 if (err != k_ra8_ok) {
321 return err;
322 }
323 }
324 return k_ra8_ok;
325}
326
349ra8_err_t ra8_eth_gwca_kick_tx(uint32_t queue_index)
350{
351 enum : uint32_t {
352 k_ra8_gwca_max_tx_queues = 64U,
353 k_ra8_gwca_queues_per_reg = 32U,
354 };
355 if (queue_index >= k_ra8_gwca_max_tx_queues) {
357 }
358 const uintptr_t offset = (queue_index < k_ra8_gwca_queues_per_reg)
359 ? (uintptr_t)k_ra8_gwca_off_gwtrc0
360 : (uintptr_t)k_ra8_gwca_off_gwtrc1;
361 volatile uint32_t* const gwtrc = (volatile uint32_t*)(k_ra8_gwca0_base_addr + offset);
362 const uint32_t bit = 1U << (queue_index % k_ra8_gwca_queues_per_reg);
363 *gwtrc = *gwtrc | bit;
364 return k_ra8_ok;
365}
366
396 uint32_t ring_depth,
397 ra8_gwdcc_dt_t match_dt,
398 uint32_t start_idx,
399 uint32_t* out_index)
400{
401 RA8_CHECK_NULL_PTR(chain, s_tag, "find_slot: chain null");
402 RA8_CHECK_NULL_PTR(out_index, s_tag, "find_slot: out_index null");
403 if (ring_depth < 2U) {
405 }
406 const uint32_t data_slot_count = ring_depth - 1U;
407 if (start_idx >= data_slot_count) {
409 }
410 /* Walk from start_idx forward, wrapping once if needed. */
411 for (uint32_t i = 0U; i < data_slot_count; ++i) {
412 const uint32_t slot = (start_idx + i) % data_slot_count;
413 if (chain[slot].dt == (uint8_t)match_dt) {
414 *out_index = slot;
415 return k_ra8_ok;
416 }
417 }
418 return k_ra8_err_no_data;
419}
420
422{
423 if (desc == nullptr) {
424 return nullptr;
425 }
426 /* PTR is 40 bits across ptr_h (high 8) + ptr_l (low 32). On a
427 * 32-bit target uintptr_t is 32 bits, so shifting by 32 is UB --
428 * promote to uint64_t for the recompose, then back to uintptr_t.
429 * On 32-bit chips ptr_h is always zero so the upper byte is
430 * harmlessly truncated when we cast back. */
431 enum : uint64_t {
432 k_ra8_ptr_upper_shift = 32ULL,
433 k_ra8_ptr_low_mask = 0xFFFFFFFFULL,
434 };
435 const uint64_t addr64 =
436 ((uint64_t)desc->ptr_h << k_ra8_ptr_upper_shift) | ((uint64_t)desc->ptr_l & k_ra8_ptr_low_mask);
437 return (uint8_t*)(uintptr_t)addr64;
438}
439
470 uint32_t ring_depth,
471 uint32_t* tail_idx,
472 const uint8_t* frame,
473 uint32_t frame_len,
474 uint32_t slot_bytes)
475{
476 RA8_CHECK_NULL_PTR(chain, s_tag, "tx_frame: chain null");
477 RA8_CHECK_NULL_PTR(tail_idx, s_tag, "tx_frame: tail_idx null");
478 RA8_CHECK_NULL_PTR(frame, s_tag, "tx_frame: frame null");
479 if (frame_len == 0U || frame_len > slot_bytes) {
481 }
482 uint32_t slot = 0U;
483 const ra8_err_t err = ra8_eth_gwca_find_slot(chain,
484 ring_depth,
486 *tail_idx % (ring_depth - 1U),
487 &slot);
488 if (err != k_ra8_ok) {
489 return err;
490 }
491 uint8_t* const buf = priv_ra8_eth_gwca_decode_ptr(&chain[slot]);
492 if (buf == nullptr) {
494 }
495 (void)memcpy(buf, frame, (size_t)frame_len);
496 enum : uint32_t {
497 k_ra8_ds_low_byte_mask = 0xFFU,
498 k_ra8_ds_high_shift = 8U,
499 k_ra8_ds_high_nibble = 0xFU,
500 };
501 chain[slot].ds_l = (uint8_t)(frame_len & k_ra8_ds_low_byte_mask);
502 chain[slot].ds_h = (uint8_t)((frame_len >> k_ra8_ds_high_shift) & k_ra8_ds_high_nibble);
503 chain[slot].dt = (uint8_t)k_ra8_gwdcc_dt_fsingle;
504 *tail_idx = (slot + 1U) % (ring_depth - 1U);
505 return k_ra8_ok;
506}
static const char * s_tag
Logging / check tag.
Definition ra8_app.c:17
Annotation-attribute framework macros for ra8-firmware.
#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_no_data
No application data available (e.g.
Definition ra8_err.h:202
@ 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
Ethernet CPU Agent (GWCA) driver.
Cross-TU shared surface for the ra8_eth_gwca driver split.
@ k_ra8_eth_gwca_balr_spin
GWDCCi.BALR self-clear poll budget.
uint8_t * priv_ra8_eth_gwca_decode_ptr(const ra8_gwca_basic_descriptor_t *desc)
Decode a descriptor's 40-bit PTR back to a host pointer.
ra8_err_t ra8_eth_gwca_kick_tx(uint32_t queue_index)
Kick a TX queue via GWTRC.
ra8_err_t ra8_eth_gwca_init_ring(ra8_gwca_basic_descriptor_t *chain, uint32_t ring_depth, uint32_t slot_bytes)
Initialise a descriptor chain as a ring of FEMPTY slots.
ra8_err_t ra8_eth_gwca_tx_frame(ra8_gwca_basic_descriptor_t *chain, uint32_t ring_depth, uint32_t *tail_idx, const uint8_t *frame, uint32_t frame_len, uint32_t slot_bytes)
Enqueue one frame on a TX queue's descriptor ring.
void priv_ra8_eth_gwca_set_linkfix_entry(ra8_gwca_basic_descriptor_t *entry, const void *chain_head)
Promote a LINKFIX entry from LEMPTY to LINKFIX with chain-head PTR.
static uint32_t internal_compose_gwdcc(const ra8_eth_gwca_queue_cfg_t *cfg)
Compose the GWDCC[i] 32-bit value from a queue config.
ra8_err_t ra8_eth_gwca_find_slot(const ra8_gwca_basic_descriptor_t *chain, uint32_t ring_depth, ra8_gwdcc_dt_t match_dt, uint32_t start_idx, uint32_t *out_index)
Find the next slot in a ring matching a target descriptor type.
ra8_err_t ra8_eth_gwca_reload_queue(uint32_t queue_index)
Reload a descriptor queue: pulse GWDCC[i].BALR, wait for clear.
ra8_err_t ra8_eth_gwca_configure_queue(ra8_gwca_basic_descriptor_t *linkfix_table, uint32_t queue_index, const ra8_eth_gwca_queue_cfg_t *cfg)
Wire a per-queue config into GWDCC[i] + LINKFIX[i].
ra8_err_t ra8_eth_gwca_set_descriptor_buffer(ra8_gwca_basic_descriptor_t *desc, void *buffer)
Set a descriptor's data-buffer pointer.
ra8_err_t ra8_eth_gwca_attach_buffers(ra8_gwca_basic_descriptor_t *chain, uint32_t ring_depth, uint32_t slot_bytes, uint8_t *pool)
Walk a ring and attach per-slot buffers from a static pool.
Ethernet controller base addresses for the Renesas RA8D2.
@ k_ra8_gwca_off_gwtrc0
TX Request Cfg, queues 0..31.
@ k_ra8_gwca_off_gwtrc1
TX Request Cfg, queues 32..63.
ra8_gwdcc_dt_t
Descriptor type field values (HUM Ch 34.5.1.2.2 "Descriptor Types").
@ k_ra8_gwdcc_dt_fsingle
FSINGLE – single-fragment frame.
@ k_ra8_gwdcc_dt_link
LINK – chain continuation.
@ k_ra8_gwdcc_dt_fempty
FEMPTY – empty, full frame slot.
@ k_ra8_gwdcc_dt_linkfix
LINKFIX – chain head pointer.
@ k_ra8_gwca0_base_addr
RA8 gwca0 base address.
@ k_ra8_gwdcc_dcp_shift
RA8 gwdcc dcp shift.
@ k_ra8_gwdcc_balr
RA8 gwdcc balr.
@ k_ra8_gwdcc_dqt
0 = RX queue, 1 = TX queue.
@ k_ra8_gwdcc_ede
RA8 gwdcc ede.
@ k_ra8_gwdcc_sl
RA8 gwdcc sl.
@ k_ra8_gwdcc_dcp_mask
RA8 gwdcc dcp mask.
static volatile uint32_t * ra8_gwca_gwdcc(uint32_t queue_index)
Get pointer to GWDCC[queue_index] (per-queue descriptor chain cfg).
void * memset(void *dst, int value, size_t n)
Fill memory with a constant byte value.
void * memcpy(void *dst, const void *src, size_t n)
Copy memory area between non-overlapping regions.
Bounded wait-flag primitives for RA8D2 HAL drivers.
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
Per-queue configuration descriptor for ra8_eth_gwca_configure_queue.
bool stop_on_last
SL: stop processing on last.
bool extended
EDE: true = 16-byte extended descriptors.
bool is_tx
DQT: true = TX, false = RX.
void * chain_head
First descriptor in the queue (basic or extended).
uint8_t priority
DCP[2:0]: class priority (0..7).
8-byte basic descriptor (HUM Ch 34.5.1.2 "General Formats").
volatile uint8_t dt
20..23 Descriptor type (ra8_gwdcc_dt_t).
volatile uint8_t ds_h
8..11 Descriptor size (high nibble).
volatile uint32_t ptr_l
32..63 Pointer low 32 bits.
volatile uint8_t ds_l
0..7 Descriptor size (low byte).
volatile uint8_t ptr_h
24..31 Pointer high byte (PTR[39:32]).