ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_etha.c
Go to the documentation of this file.
1
46
47#include "ra8_etha.h"
48
49#include <stdint.h>
50
51#include "ra8_attributes.h"
52#include "ra8_check.h"
53#include "ra8_err.h"
54#include "ra8_etha_internal.h"
55#include "ra8_etha_regs.h"
56#include "ra8_ether_regs.h"
57#include "ra8_hw_err.h"
58#include "ra8_log.h"
59#include "ra8_mstp.h"
60#include "ra8_mstp_regs.h"
61
72static const char* s_tag = "ETHA";
73
86volatile uint32_t g_ra8_etha_diag_last_eams[2] = {0U, 0U};
87
89typedef enum : uint32_t {
92
107
118
138static inline bool internal_tc_ok(ra8_etha_tc_t tc)
139{
140 return (uint8_t)tc < k_ra8_etha_tc_count;
141}
142
163{
164 return (uint8_t)block < k_ra8_etha_irq_class_count;
165}
166
168{
169 RA8_CHECK_NULL_PTR(cfg, s_tag, "etha_init: cfg must not be nullptr");
170 if (!internal_port_ok(port)) {
171 ra8_log_error(s_tag, "etha_init: port out of range");
173 }
174
175 /* HUM Ch 11.2.8 "MSTPCRC : Module Stop Control Register C" p 446 */
177 RA8_RETURN_ON_ERROR(mst_err, s_tag, "etha_init: mstp enable");
178
179 volatile r_etha_regs_t* reg = ra8_etha(port);
180
181 /* HUM Ch 32.3.1.1 "EAMC : Mode Configuration Register" p 1630 */
182 reg->EAMC = (uint32_t)cfg->initial_mode & k_ra8_etha_mask_opc;
183 /* HUM Ch 32.3.7.1.3 "EAEID0 : Error Interrupt Disable Register 0" p 1662 */
185 /* HUM Ch 32.3.7.1.6 "EAEID1 : Error Interrupt Disable Register 1" p 1665 */
187 /* HUM Ch 32.3.7.1.9 "EAEID2 : Error Interrupt Disable Register 2" p 1668 */
189 /* HUM Ch 32.3.7.1.2 "EAEIE0 : Error Interrupt Enable Register 0" p 1661 */
190 reg->EAEIE0 = cfg->eaeie0_mask;
191 /* HUM Ch 32.3.7.1.5 "EAEIE1 : Error Interrupt Enable Register 1" p 1664 */
192 reg->EAEIE1 = cfg->eaeie1_mask;
193 /* HUM Ch 32.3.7.1.8 "EAEIE2 : Error Interrupt Enable Register 2" p 1667 */
194 reg->EAEIE2 = cfg->eaeie2_mask;
195
196 s_etha_slots[(uint8_t)port].cb = nullptr;
197 s_etha_slots[(uint8_t)port].ctx = nullptr;
198 s_etha_slots[(uint8_t)port].stats = (ra8_etha_port_stats_t){};
199 ra8_log_info(s_tag, "etha_init");
200 return k_ra8_ok;
201}
202
204{
205 if (!internal_port_ok(port)) {
206 ra8_log_error(s_tag, "etha_deinit: port out of range");
208 }
209
210 volatile r_etha_regs_t* reg = ra8_etha(port);
211 /* HUM Ch 32.3.1.1 "EAMC : Mode Configuration Register" p 1630 */
212 reg->EAMC = (uint32_t)k_ra8_etha_opc_reset;
213 /* HUM Ch 32.3.7.1.2 "EAEIE0 : Error Interrupt Enable Register 0" p 1661 */
214 reg->EAEIE0 = 0U;
215 /* HUM Ch 32.3.7.1.5 "EAEIE1 : Error Interrupt Enable Register 1" p 1664 */
216 reg->EAEIE1 = 0U;
217 /* HUM Ch 32.3.7.1.8 "EAEIE2 : Error Interrupt Enable Register 2" p 1667 */
218 reg->EAEIE2 = 0U;
219
220 s_etha_slots[(uint8_t)port].cb = nullptr;
221 s_etha_slots[(uint8_t)port].ctx = nullptr;
222 s_etha_slots[(uint8_t)port].stats = (ra8_etha_port_stats_t){};
223 /* MSTP gate is shared with the rest of the Ethernet subsystem; do
224 * NOT drop it here. ra8_eth_deinit owns the final reference. */
225 return k_ra8_ok;
226}
227
229{
230 RA8_CHECK_NULL_PTR(out, s_tag, "etha_get_status: out must not be nullptr");
231 if (!internal_port_ok(port)) {
232 ra8_log_error(s_tag, "etha_get_status: port out of range");
234 }
235
236 volatile const r_etha_regs_t* reg = ra8_etha(port);
237 /* HUM Ch 32.3.1.2 "EAMS : Mode Status Register" p 1631 */
238 const uint32_t ops = reg->EAMS & k_ra8_etha_mask_ops;
239 /* HUM Ch 32.3.7.1.1 "EAEIS0 : Error Interrupt Status Register 0" p 1659 */
240 const uint32_t eaeis0 = reg->EAEIS0;
241 /* HUM Ch 32.3.7.1.4 "EAEIS1 : Error Interrupt Status Register 1" p 1662 */
242 const uint32_t eaeis1 = reg->EAEIS1;
243 /* HUM Ch 32.3.7.1.7 "EAEIS2 : Error Interrupt Status Register 2" p 1665 */
244 const uint32_t eaeis2 = reg->EAEIS2;
245 /* HUM Ch 32.3.5.12 "EATASCTM : TAS Cycle Time Monitoring Register" p 1651 */
246 const uint32_t tasctm = reg->EATASCTM;
247 out->ops = (ra8_etha_ops_t)(uint8_t)ops;
248 out->eaeis0 = eaeis0;
249 out->eaeis1 = eaeis1;
250 out->eaeis2 = eaeis2;
251 out->tas_cycle = tasctm;
252 return k_ra8_ok;
253}
254
256{
257 if (!internal_port_ok(port) || !internal_irq_block_ok(block)) {
258 ra8_log_error(s_tag, "etha_clear_status: port/block out of range");
260 }
261
262 volatile r_etha_regs_t* reg = ra8_etha(port);
263 switch (block) {
265 /* HUM Ch 32.3.7.1.3 "EAEID0 : Error Interrupt Disable Register 0" p 1662 */
266 reg->EAEID0 = mask;
267 /* HUM Ch 32.3.7.1.1 "EAEIS0 : Error Interrupt Status Register 0" p 1659 */
268 reg->EAEIS0 = reg->EAEIS0 & ~mask;
269 break;
271 /* HUM Ch 32.3.7.1.6 "EAEID1 : Error Interrupt Disable Register 1" p 1665 */
272 reg->EAEID1 = mask;
273 /* HUM Ch 32.3.7.1.4 "EAEIS1 : Error Interrupt Status Register 1" p 1662 */
274 reg->EAEIS1 = reg->EAEIS1 & ~mask;
275 break;
277 /* HUM Ch 32.3.7.1.9 "EAEID2 : Error Interrupt Disable Register 2" p 1668 */
278 reg->EAEID2 = mask;
279 /* HUM Ch 32.3.7.1.7 "EAEIS2 : Error Interrupt Status Register 2" p 1665 */
280 reg->EAEIS2 = reg->EAEIS2 & ~mask;
281 break;
283 default:
285 }
286 return k_ra8_ok;
287}
288
290{
291 if (!internal_port_ok(port) || !internal_irq_block_ok(block)) {
292 ra8_log_error(s_tag, "etha_enable_irq: bad arg");
294 }
295 volatile r_etha_regs_t* reg = ra8_etha(port);
296 switch (block) {
298 /* HUM Ch 32.3.7.1.2 "EAEIE0 : Error Interrupt Enable Register 0" p 1661 */
299 reg->EAEIE0 = reg->EAEIE0 | mask;
300 break;
302 /* HUM Ch 32.3.7.1.5 "EAEIE1 : Error Interrupt Enable Register 1" p 1664 */
303 reg->EAEIE1 = reg->EAEIE1 | mask;
304 break;
306 /* HUM Ch 32.3.7.1.8 "EAEIE2 : Error Interrupt Enable Register 2" p 1667 */
307 reg->EAEIE2 = reg->EAEIE2 | mask;
308 break;
310 default:
312 }
313 return k_ra8_ok;
314}
315
317{
318 if (!internal_port_ok(port) || !internal_irq_block_ok(block)) {
319 ra8_log_error(s_tag, "etha_disable_irq: bad arg");
321 }
322 volatile r_etha_regs_t* reg = ra8_etha(port);
323 switch (block) {
325 /* HUM Ch 32.3.7.1.2 "EAEIE0 : Error Interrupt Enable Register 0" p 1661 */
326 reg->EAEIE0 = reg->EAEIE0 & ~mask;
327 break;
329 /* HUM Ch 32.3.7.1.5 "EAEIE1 : Error Interrupt Enable Register 1" p 1664 */
330 reg->EAEIE1 = reg->EAEIE1 & ~mask;
331 break;
333 /* HUM Ch 32.3.7.1.8 "EAEIE2 : Error Interrupt Enable Register 2" p 1667 */
334 reg->EAEIE2 = reg->EAEIE2 & ~mask;
335 break;
337 default:
339 }
340 return k_ra8_ok;
341}
342
344{
345 if (!internal_port_ok(port)) {
346 ra8_log_error(s_tag, "etha_attach_handler: port out of range");
348 }
349 s_etha_slots[(uint8_t)port].cb = cb;
350 s_etha_slots[(uint8_t)port].ctx = ctx;
351 return k_ra8_ok;
352}
353
356{
357 if (!internal_port_ok(port)) {
358 return;
359 }
360
361 volatile r_etha_regs_t* reg = ra8_etha(port);
362 /* HUM Ch 32.3.7.1.1 "EAEIS0 : Error Interrupt Status Register 0" p 1659 */
363 const uint32_t s0 = reg->EAEIS0;
364 /* HUM Ch 32.3.7.1.4 "EAEIS1 : Error Interrupt Status Register 1" p 1662 */
365 const uint32_t s1 = reg->EAEIS1;
366 /* HUM Ch 32.3.7.1.7 "EAEIS2 : Error Interrupt Status Register 2" p 1665 */
367 const uint32_t s2 = reg->EAEIS2;
368
369 const ra8_etha_event_fn_t fn = s_etha_slots[(uint8_t)port].cb;
370 void* const ctx = s_etha_slots[(uint8_t)port].ctx;
371
372 /* HUM Ch 32.3.7.1.3 "EAEID0 : Error Interrupt Disable Register 0" p 1662 */
373 reg->EAEID0 = s0;
374 /* HUM Ch 32.3.7.1.6 "EAEID1 : Error Interrupt Disable Register 1" p 1665 */
375 reg->EAEID1 = s1;
376 /* HUM Ch 32.3.7.1.9 "EAEID2 : Error Interrupt Disable Register 2" p 1668 */
377 reg->EAEID2 = s2;
378 /* HUM Ch 32.3.7.1.1 "EAEIS0 : Error Interrupt Status Register 0" p 1659 */
379 reg->EAEIS0 = 0U;
380 /* HUM Ch 32.3.7.1.4 "EAEIS1 : Error Interrupt Status Register 1" p 1662 */
381 reg->EAEIS1 = 0U;
382 /* HUM Ch 32.3.7.1.7 "EAEIS2 : Error Interrupt Status Register 2" p 1665 */
383 reg->EAEIS2 = 0U;
384
385 if (fn != nullptr) {
386 fn(ctx, port, s0, s1, s2);
387 }
388}
389
391{
392 if (!internal_port_ok(port)) {
393 ra8_log_error(s_tag, "etha_enter_stop: port out of range");
395 }
396 /* HUM Ch 32.3.1.1 "EAMC : Mode Configuration Register" p 1630 */
397 ra8_etha(port)->EAMC = (uint32_t)k_ra8_etha_opc_disable;
398 return k_ra8_ok;
399}
400
402{
403 if (!internal_port_ok(port)) {
404 ra8_log_error(s_tag, "etha_exit_stop: port out of range");
406 }
407 /* HUM Ch 32.3.1.1 "EAMC : Mode Configuration Register" p 1630 */
408 ra8_etha(port)->EAMC = (uint32_t)k_ra8_etha_opc_operation;
409 return k_ra8_ok;
410}
411
413{
414 if (!internal_port_ok(port)) {
415 ra8_log_error(s_tag, "etha_reset: port out of range");
417 }
418 volatile r_etha_regs_t* reg = ra8_etha(port);
419 /* HUM Ch 32.3.1.1 "EAMC : Mode Configuration Register" p 1630 */
420 reg->EAMC = (uint32_t)k_ra8_etha_opc_reset;
421 /* HUM Ch 32.3.1.1 "EAMC : Mode Configuration Register" p 1630 */
422 reg->EAMC = (uint32_t)k_ra8_etha_opc_config;
423 return k_ra8_ok;
424}
425
455static ra8_err_t
457{
458 /* Only CONFIG and DISABLE are load-bearing: writes to MRMAC require
459 * the port to actually be in CONFIG, and the OPERATION -> DISABLE
460 * step has to land before the next CONFIG attempt. RESET and
461 * OPERATION transitions are fire-and-forget on this silicon -- the
462 * bench's eth_loopback test exercises OPERATION on the unwired
463 * ETHA0 port where EAMS never advances past CONFIG (no PHY, no
464 * media); polling there hangs the test. */
465 if (mode != k_ra8_etha_opc_config) {
466 if (mode != k_ra8_etha_opc_disable) {
467 return k_ra8_ok;
468 }
469 }
470 enum : uint32_t {
471 k_ms_budget = 500U,
472 k_inner = 200000U,
473 };
474 const uint32_t target = (uint32_t)mode & k_ra8_etha_mask_ops;
475 for (uint32_t ms = 0U; ms < (uint32_t)k_ms_budget; ++ms) {
476 for (uint32_t i = 0U; i < (uint32_t)k_inner; ++i) {
477 const uint32_t eams = reg->EAMS & k_ra8_etha_mask_ops;
478 g_ra8_etha_diag_last_eams[(uint32_t)port & 1U] = eams;
479#if defined(RA8_OFF_TARGET) && defined(UNIT_TEST)
480 if (ra8_fake_mmio_wait_eval(&reg->EAMS, i, (eams == target))) {
481 return k_ra8_ok;
482 }
483#else
484 if (eams == target) {
485 return k_ra8_ok;
486 }
487#endif
488 }
489 }
490 ra8_log_error(s_tag, "etha_set_mode: EAMS.OPS never reached requested mode");
492}
493
495{
496 if (!internal_port_ok(port) || (uint32_t)mode > k_ra8_etha_mask_opc) {
497 ra8_log_error(s_tag, "etha_set_mode: bad arg");
499 }
500 volatile r_etha_regs_t* reg = ra8_etha(port);
501 /* HUM Ch 32.3.1.1 "EAMC : Mode Configuration Register" p 1630 */
502 reg->EAMC = (uint32_t)mode & k_ra8_etha_mask_opc;
503 return internal_etha_wait_for_mode(port, reg, mode);
504}
505
507{
508 if (!internal_port_ok(port) || !internal_tc_ok(tc) || (uint32_t)arb > k_ra8_etha_mask_tdqa) {
509 ra8_log_error(s_tag, "etha_set_queue_arb: bad arg");
511 }
512
513 volatile r_etha_regs_t* reg = ra8_etha(port);
514 /* HUM Ch 32.3.2.4 "EATDQAC : TX Descriptor Queue Arbitration Configuration Register" p 1634 */
515 const uint32_t shift = (uint32_t)((uint8_t)tc * 4U);
516 /* HUM Ch 32.3.2.4 "EATDQAC : TX Descriptor Queue Arbitration Configuration Register" p 1634 */
517 const uint32_t mask = k_ra8_etha_mask_tdqa << shift;
518 /* HUM Ch 32.3.2.4 "EATDQAC : TX Descriptor Queue Arbitration Configuration Register" p 1634 */
519 reg->EATDQAC = (reg->EATDQAC & ~mask) | (((uint32_t)arb & k_ra8_etha_mask_tdqa) << shift);
520 return k_ra8_ok;
521}
522
524{
525 if (!internal_port_ok(port) || !internal_tc_ok(tc) || (uint32_t)depth > k_ra8_etha_mask_dqd) {
526 ra8_log_error(s_tag, "etha_set_queue_depth: bad arg");
528 }
529 /* HUM Ch 32.3.2.7 "EATDQDCq" p 1636 */
530 ra8_etha(port)->EATDQDC[(uint8_t)tc] = (uint32_t)depth & k_ra8_etha_mask_dqd;
531 return k_ra8_ok;
532}
533
535 ra8_etha_tc_t tc,
536 uint16_t* cur_level,
537 uint16_t* peak)
538{
539 RA8_CHECK_NULL_PTR(cur_level, s_tag, "etha_get_queue_level: cur_level null");
540 RA8_CHECK_NULL_PTR(peak, s_tag, "etha_get_queue_level: peak null");
541 if (!internal_port_ok(port) || !internal_tc_ok(tc)) {
542 ra8_log_error(s_tag, "etha_get_queue_level: bad arg");
544 }
545
546 volatile r_etha_regs_t* reg = ra8_etha(port);
547 /* HUM Ch 32.3.2.8 "EATDQMq : Transmission Descriptor Queue q Monitoring (q = 0 to 7)" p 1636 */
548 *cur_level = (uint16_t)(reg->EATDQM[(uint8_t)tc] & k_ra8_etha_mask_dnq);
549 /* HUM Ch 32.3.2.9 "EATDQMLMq : Transmission Descriptor Queue q Max Level Monitoring" p 1637 */
550 *peak = (uint16_t)(reg->EATDQMLM[(uint8_t)tc] & k_ra8_etha_mask_dnq);
551 return k_ra8_ok;
552}
553
555ra8_etha_set_preemption(ra8_etha_port_t port, uint8_t preempt, uint8_t cut_thru, ra8_etha_afs_t afs)
556{
557 if (!internal_port_ok(port)) {
558 ra8_log_error(s_tag, "etha_set_preemption: port out of range");
560 }
561 /* HUM Ch 32.3.2.5 "EATPEC : TX Preemption Configuration Register" p 1635 */
562 uint32_t v = (uint32_t)preempt & k_ra8_etha_local_byte_mask;
563 if (cut_thru != 0U) {
564 v |= (1U << 8); /* TTQ8 cut-through preemptable */
565 }
566 v |= ((uint32_t)afs & 0x3U) << (uint32_t)k_ra8_etha_eatpec_afs_pos;
567 /* HUM Ch 32.3.2.5 "EATPEC : TX Preemption Configuration Register" p 1635 */
568 ra8_etha(port)->EATPEC = v;
569 return k_ra8_ok;
570}
571
573{
574 if (!internal_port_ok(port) || !internal_tc_ok(tc)) {
575 ra8_log_error(s_tag, "etha_set_max_frame_size: bad arg");
577 }
578 /* HUM Ch 32.3.2.6 "EATMFSCq" p 1635 */
579 ra8_etha(port)->EATMFSC[(uint8_t)tc] = (uint32_t)max_bytes & k_ra8_etha_mask_mfs;
580 return k_ra8_ok;
581}
582
584{
585 RA8_CHECK_NULL_PTR(map, s_tag, "etha_set_ipv_remap: map null");
586 if (!internal_port_ok(port)) {
587 ra8_log_error(s_tag, "etha_set_ipv_remap: port out of range");
589 }
590 /* Validate every entry first so we never write a partial value. */
591 for (uint8_t i = 0U; i < k_ra8_etha_tc_count; ++i) {
592 if ((uint32_t)map[i] > k_ra8_etha_mask_ipv) {
593 ra8_log_error(s_tag, "etha_set_ipv_remap: entry > 7");
595 }
596 }
597 /* HUM Ch 32.3.2.1 "EAIRC : IPV Remapping Configuration Register [802.1Q]" p 1631 */
598 uint32_t packed = 0U;
599 for (uint8_t i = 0U; i < k_ra8_etha_tc_count; ++i) {
600 /* HUM Ch 32.3.2.1 "EAIRC : IPV Remapping Configuration Register [802.1Q]" p 1631 */
601 const uint32_t shift = (uint32_t)i * 4U;
602 packed |= ((uint32_t)map[i] & k_ra8_etha_mask_ipv) << shift;
603 }
604 /* HUM Ch 32.3.2.1 "EAIRC : IPV Remapping Configuration Register [802.1Q]" p 1631 */
605 ra8_etha(port)->EAIRC = packed;
606 return k_ra8_ok;
607}
608
610{
611 if (!internal_port_ok(port)) {
612 ra8_log_error(s_tag, "etha_set_vlan_mode: port out of range");
614 }
615 /* HUM Ch 32.3.3.1 "EAVCC : VLAN Control Configuration Register" p 1639 */
616 const uint32_t v = ((uint32_t)vim & 0x1U) |
617 (((uint32_t)vem & k_etha_vem_mask) << (uint32_t)k_ra8_etha_eavcc_vem_pos);
618 /* HUM Ch 32.3.3.1 "EAVCC : VLAN Control Configuration Register" p 1639 */
619 ra8_etha(port)->EAVCC = v;
620 return k_ra8_ok;
621}
622
624 const ra8_etha_vlan_tag_t* c_tag,
625 const ra8_etha_vlan_tag_t* s_tag_in)
626{
627 RA8_CHECK_NULL_PTR(c_tag, s_tag, "etha_set_vlan_tag: c_tag null");
628 RA8_CHECK_NULL_PTR(s_tag_in, s_tag, "etha_set_vlan_tag: s_tag null");
629 if (!internal_port_ok(port)) {
630 ra8_log_error(s_tag, "etha_set_vlan_tag: port out of range");
632 }
633 if ((uint32_t)c_tag->vid > k_ra8_etha_mask_vlan_vid ||
634 (uint32_t)s_tag_in->vid > k_ra8_etha_mask_vlan_vid ||
635 (uint32_t)c_tag->pcp > k_ra8_etha_mask_vlan_pcp ||
636 (uint32_t)s_tag_in->pcp > k_ra8_etha_mask_vlan_pcp ||
637 (uint32_t)c_tag->dei > k_ra8_etha_mask_vlan_dei ||
638 (uint32_t)s_tag_in->dei > k_ra8_etha_mask_vlan_dei) {
639 ra8_log_error(s_tag, "etha_set_vlan_tag: tag fields out of range");
641 }
642
643 const uint32_t v =
644 (((uint32_t)c_tag->vid & k_ra8_etha_mask_vlan_vid) << (uint32_t)k_ra8_etha_eavtc_ctv_pos) |
645 (((uint32_t)c_tag->pcp & k_ra8_etha_mask_vlan_pcp) << (uint32_t)k_ra8_etha_eavtc_ctp_pos) |
646 (((uint32_t)c_tag->dei & k_ra8_etha_mask_vlan_dei) << (uint32_t)k_ra8_etha_eavtc_ctd_pos) |
647 (((uint32_t)s_tag_in->vid & k_ra8_etha_mask_vlan_vid) << (uint32_t)k_ra8_etha_eavtc_stv_pos) |
648 (((uint32_t)s_tag_in->pcp & k_ra8_etha_mask_vlan_pcp) << (uint32_t)k_ra8_etha_eavtc_stp_pos) |
649 (((uint32_t)s_tag_in->dei & k_ra8_etha_mask_vlan_dei) << (uint32_t)k_ra8_etha_eavtc_std_pos);
650 /* HUM Ch 32.3.3.2 "EAVTC : VLAN TAG Configuration Register" p 1640 */
651 ra8_etha(port)->EAVTC = v;
652 return k_ra8_ok;
653}
654
656{
657 if (!internal_port_ok(port)) {
658 ra8_log_error(s_tag, "etha_set_rx_tag_filter: port out of range");
660 }
661 /* HUM Ch 32.3.3.3 "EARTFC : Reception TAG Filtering Configuration Register" p 1641 */
663 return k_ra8_ok;
664}
665
667{
668 if (!internal_port_ok(port) || (uint32_t)dqd > k_ra8_etha_mask_ctdqd) {
669 ra8_log_error(s_tag, "etha_configure_cut_through: bad arg");
671 }
672 volatile r_etha_regs_t* reg = ra8_etha(port);
673 /* HUM Ch 32.3.2.10 "EACTQC : Cut-Through Queue Configuration Register" p 1637 */
674 reg->EACTQC = (uint32_t)qd & k_ra8_etha_mask_ctqd;
675 /* HUM Ch 32.3.2.11 "EACTDQDC : Cut-Through Descriptor Queue Depth Configuration" p 1638 */
676 reg->EACTDQDC = (uint32_t)dqd & k_ra8_etha_mask_ctdqd;
677 return k_ra8_ok;
678}
679
681 ra8_etha_tc_t tc,
682 uint8_t enable,
683 const ra8_etha_cbs_param_t* param)
684{
685 if (!internal_port_ok(port) || !internal_tc_ok(tc)) {
686 ra8_log_error(s_tag, "etha_configure_cbs: bad arg");
688 }
689 if (enable != 0U) {
690 RA8_CHECK_NULL_PTR(param, s_tag, "etha_configure_cbs: param null");
692 ra8_log_error(s_tag, "etha_configure_cbs: param range");
694 }
695 }
696
697 volatile r_etha_regs_t* reg = ra8_etha(port);
698 if (enable != 0U) {
699 /* HUM Ch 32.3.4.3 "EACAIVCq : CBS Admin Increment Value Configuration q (q = 0 to 7)" p 1643 */
700 reg->EACAIVC[(uint8_t)tc] = param->increment & k_ra8_etha_mask_civ;
701 /* HUM Ch 32.3.4.4 "EACAULCq : CBS Admin Upper Limit Configuration q (q = 0 to 7)" p 1643 */
702 reg->EACAULC[(uint8_t)tc] = param->upper_lim & k_ra8_etha_mask_cul;
703 }
704 /* HUM Ch 32.3.4.1 "EACAEC : CBS Admin Enable Configuration Register" p 1642 */
705 const uint32_t bit = 1U << (uint8_t)tc;
706 if (enable != 0U) {
707 reg->EACAEC = reg->EACAEC | bit;
708 /* HUM Ch 32.3.4.2 "EACC : CBS Configuration Register" p 1642 */
709 reg->EACC = reg->EACC | bit;
710 } else {
711 reg->EACAEC = reg->EACAEC & ~bit;
712 /* HUM Ch 32.3.4.2 "EACC : CBS Configuration Register" p 1642 */
713 reg->EACC = reg->EACC & ~bit;
714 }
715 return k_ra8_ok;
716}
717
719 ra8_etha_tc_t tc,
720 uint8_t* enabled,
721 uint8_t* gate_open,
722 ra8_etha_cbs_param_t* oper_param)
723{
724 RA8_CHECK_NULL_PTR(enabled, s_tag, "etha_get_cbs_state: enabled null");
725 RA8_CHECK_NULL_PTR(gate_open, s_tag, "etha_get_cbs_state: gate_open null");
726 RA8_CHECK_NULL_PTR(oper_param, s_tag, "etha_get_cbs_state: oper_param null");
727 if (!internal_port_ok(port) || !internal_tc_ok(tc)) {
728 ra8_log_error(s_tag, "etha_get_cbs_state: bad arg");
730 }
731
732 volatile r_etha_regs_t* reg = ra8_etha(port);
733 const uint32_t bit = 1U << (uint8_t)tc;
734 /* HUM Ch 32.3.4.5 "EACOEM : CBS Oper Enable Monitoring Register" p 1644 */
735 *enabled = (uint8_t)((reg->EACOEM & bit) != 0U ? 1U : 0U);
736 /* HUM Ch 32.3.4.8 "EACGSM : CBS Gate State Monitoring Register" p 1645 */
737 *gate_open = (uint8_t)((reg->EACGSM & bit) != 0U ? 1U : 0U);
738 /* HUM Ch 32.3.4.6 "EACOIVMq : CBS Oper Increment Value Monitoring q (q = 0 to 7)" p 1644 */
739 oper_param->increment = reg->EACOIVM[(uint8_t)tc] & k_ra8_etha_mask_civ;
740 /* HUM Ch 32.3.4.7 "EACOULMq : CBS Oper Upper Limit Monitoring Register q (q = 0 to 7)" p 1645 */
741 oper_param->upper_lim = reg->EACOULM[(uint8_t)tc] & k_ra8_etha_mask_cul;
742 return k_ra8_ok;
743}
744
746{
747 RA8_CHECK_NULL_PTR(out, s_tag, "etha_read_stats: out null");
748 if (!internal_port_ok(port)) {
749 ra8_log_error(s_tag, "etha_read_stats: port out of range");
751 }
752
753 volatile const r_etha_regs_t* reg = ra8_etha(port);
754 /* HUM Ch 32.3.6.1 "EAUSMFSECN : Under Minimum Frame Size Error Counter Register" p 1656 */
755 out->switch_min_frame_err = (uint16_t)(reg->EAUSMFSECN & k_ra8_etha_mask_mfs);
756 /* HUM Ch 32.3.6.2 "EATFECN : TAG Filtering Error Counter Register" p 1657 */
757 out->tag_filter_err = (uint16_t)(reg->EATFECN & k_ra8_etha_mask_mfs);
758 /* HUM Ch 32.3.6.3 "EAFSECN : Frame Size Error Counter Register" p 1658 */
759 out->frame_size_err = (uint16_t)(reg->EAFSECN & k_ra8_etha_mask_mfs);
760 /* HUM Ch 32.3.6.4 "EADQOECN : Descriptor Queue Overflow Error Counter Register" p 1658 */
761 out->queue_overflow_err = (uint16_t)(reg->EADQOECN & k_ra8_etha_mask_mfs);
762 /* HUM Ch 32.3.6.5 "EADQSECN : Descriptor Queue Security Error Counter Register" p 1659 */
763 out->queue_security_err = (uint16_t)(reg->EADQSECN & k_ra8_etha_mask_mfs);
764 return k_ra8_ok;
765}
766
768{
769 if (!internal_port_ok(port)) {
770 ra8_log_error(s_tag, "etha_clear_stats: port out of range");
772 }
773 volatile r_etha_regs_t* reg = ra8_etha(port);
774 /* HUM Ch 32.3.6.1 "EAUSMFSECN : Under Minimum Frame Size Error Counter Register" p 1656 */
775 reg->EAUSMFSECN = 0U;
776 /* HUM Ch 32.3.6.2 "EATFECN : TAG Filtering Error Counter Register" p 1657 */
777 reg->EATFECN = 0U;
778 /* HUM Ch 32.3.6.3 "EAFSECN : Frame Size Error Counter Register" p 1658 */
779 reg->EAFSECN = 0U;
780 /* HUM Ch 32.3.6.4 "EADQOECN : Descriptor Queue Overflow Error Counter Register" p 1658 */
781 reg->EADQOECN = 0U;
782 /* HUM Ch 32.3.6.5 "EADQSECN : Descriptor Queue Security Error Counter Register" p 1659 */
783 reg->EADQSECN = 0U;
784 return k_ra8_ok;
785}
static const char * s_tag
Logging / check tag.
Definition ra8_app.c:17
Annotation-attribute framework macros for ra8-firmware.
#define RA8_ISR_SAFE
The function is callable from interrupt context.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
Validation and Error-Checking Macros for ra8-firmware.
#define RA8_RETURN_ON_ERROR(err, tag, message)
Early return on error, propagating the code upward.
Definition ra8_check.h:184
#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_invalid_arg
Invalid function argument.
Definition ra8_err.h:152
@ k_ra8_err_hw_timeout
Hardware timed out waiting for a flag or handshake.
Definition ra8_err.h:304
@ 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
ra8_err_t ra8_etha_read_stats(ra8_etha_port_t port, ra8_etha_stats_t *out)
Read the per-port MIB error counters.
Definition ra8_etha.c:745
static ra8_err_t internal_etha_wait_for_mode(ra8_etha_port_t port, volatile r_etha_regs_t *reg, ra8_etha_opc_t mode)
Busy-wait until EAMS.OPS catches up to the requested EAMC.OPC.
Definition ra8_etha.c:456
ra8_err_t ra8_etha_set_ipv_remap(ra8_etha_port_t port, const uint8_t *map)
Programme the IPV (PCP-to-internal-priority) remap table.
Definition ra8_etha.c:583
ra8_err_t ra8_etha_clear_stats(ra8_etha_port_t port)
Clear the per-port MIB error counters in hardware.
Definition ra8_etha.c:767
ra8_err_t ra8_etha_deinit(ra8_etha_port_t port)
Tear down an ETHA port (drop into RESET, mask all IRQs).
Definition ra8_etha.c:203
ra8_err_t ra8_etha_set_mode(ra8_etha_port_t port, ra8_etha_opc_t mode)
Issue an explicit EAMC mode-change command.
Definition ra8_etha.c:494
ra8_err_t ra8_etha_set_vlan_mode(ra8_etha_port_t port, ra8_etha_vim_t vim, ra8_etha_vem_t vem)
Configure VLAN tag insertion / extraction for the port.
Definition ra8_etha.c:609
volatile uint32_t g_ra8_etha_diag_last_eams[2]
Last EAMS.OPS value observed during the CONFIG-mode poll.
Definition ra8_etha.c:86
ra8_err_t ra8_etha_disable_irq(ra8_etha_port_t port, ra8_etha_irq_class_t block, uint32_t mask)
Atomically disable specific error IRQ bits in one of the three blocks.
Definition ra8_etha.c:316
ra8_err_t ra8_etha_enter_stop(ra8_etha_port_t port)
Drop an ETHA port into low-power stop (DISABLE mode).
Definition ra8_etha.c:390
ra8_err_t ra8_etha_clear_status(ra8_etha_port_t port, ra8_etha_irq_class_t block, uint32_t mask)
Clear bits in EAEIS0 / EAEIS1 / EAEIS2 via EAEIDx.
Definition ra8_etha.c:255
ra8_etha_slot_t s_etha_slots[k_ra8_etha_port_count]
Per-port handler table; index = ra8_etha_port_t.
Definition ra8_etha.c:117
ra8_err_t ra8_etha_set_queue_depth(ra8_etha_port_t port, ra8_etha_tc_t tc, uint16_t depth)
Set the TX descriptor queue depth for one traffic class.
Definition ra8_etha.c:523
ra8_err_t ra8_etha_enable_irq(ra8_etha_port_t port, ra8_etha_irq_class_t block, uint32_t mask)
Atomically enable specific error IRQ bits in one of the three blocks.
Definition ra8_etha.c:289
ra8_err_t ra8_etha_set_rx_tag_filter(ra8_etha_port_t port, uint32_t mask)
Configure the RX tag filter (multicast group + VLAN-tag filter).
Definition ra8_etha.c:655
void ra8_etha_dispatch(ra8_etha_port_t port)
Snapshot all three EAEISx, clear them, then fire the per-port handler.
Definition ra8_etha.c:355
ra8_err_t ra8_etha_attach_handler(ra8_etha_port_t port, ra8_etha_event_fn_t cb, void *ctx)
Attach a per-port event handler.
Definition ra8_etha.c:343
ra8_err_t ra8_etha_get_status(ra8_etha_port_t port, ra8_etha_status_t *out)
Read a port's status snapshot (mode + 3x error IRQ status + TAS).
Definition ra8_etha.c:228
ra8_err_t ra8_etha_configure_cut_through(ra8_etha_port_t port, uint16_t qd, uint8_t dqd)
Configure the cut-through TX queue (low-latency forwarding).
Definition ra8_etha.c:666
ra8_err_t ra8_etha_set_preemption(ra8_etha_port_t port, uint8_t preempt, uint8_t cut_thru, ra8_etha_afs_t afs)
Configure 802.3br TX preemption: which classes are pre-emptable.
Definition ra8_etha.c:555
ra8_err_t ra8_etha_reset(ra8_etha_port_t port)
Software-reset the port: drop to RESET, then re-enter CONFIG.
Definition ra8_etha.c:412
static bool internal_irq_block_ok(ra8_etha_irq_class_t block)
Range-check an error-IRQ block index.
Definition ra8_etha.c:162
ra8_err_t ra8_etha_configure_cbs(ra8_etha_port_t port, ra8_etha_tc_t tc, uint8_t enable, const ra8_etha_cbs_param_t *param)
Configure the credit-based shaper (CBS) for one traffic class.
Definition ra8_etha.c:680
ra8_err_t ra8_etha_exit_stop(ra8_etha_port_t port)
Bring an ETHA port back from low-power stop (OPERATION mode).
Definition ra8_etha.c:401
ra8_err_t ra8_etha_get_cbs_state(ra8_etha_port_t port, ra8_etha_tc_t tc, uint8_t *enabled, uint8_t *gate_open, ra8_etha_cbs_param_t *oper_param)
Read the operational CBS gate-state vector + per-class oper params.
Definition ra8_etha.c:718
static bool internal_tc_ok(ra8_etha_tc_t tc)
Range-check a traffic-class argument.
Definition ra8_etha.c:138
ra8_etha_local_mask_t
Local mask helpers used inside this driver.
Definition ra8_etha.c:102
@ k_ra8_etha_local_9bit_mask
9-bit field mask.
Definition ra8_etha.c:105
@ k_ra8_etha_local_byte_mask
8-bit field mask.
Definition ra8_etha.c:104
@ k_ra8_etha_local_all_bits_set
W1C-all helper.
Definition ra8_etha.c:103
ra8_err_t ra8_etha_set_max_frame_size(ra8_etha_port_t port, ra8_etha_tc_t tc, uint16_t max_bytes)
Set the maximum frame size for one traffic class (jumbo OK).
Definition ra8_etha.c:572
ra8_err_t ra8_etha_set_queue_arb(ra8_etha_port_t port, ra8_etha_tc_t tc, uint8_t arb)
Configure the per-traffic-class TX queue arbitration weight.
Definition ra8_etha.c:506
etha_field_t
EAVCC field constants.
Definition ra8_etha.c:89
@ k_etha_vem_mask
3-bit VLAN egress mode field.
Definition ra8_etha.c:90
ra8_err_t ra8_etha_init(ra8_etha_port_t port, const ra8_etha_config_t *cfg)
Initialise an ETHA port (MSTP gate + reset registers + initial mode).
Definition ra8_etha.c:167
ra8_err_t ra8_etha_get_queue_level(ra8_etha_port_t port, ra8_etha_tc_t tc, uint16_t *cur_level, uint16_t *peak)
Read the current and high-water-mark queue level for one class.
Definition ra8_etha.c:534
ra8_err_t ra8_etha_set_vlan_tag(ra8_etha_port_t port, const ra8_etha_vlan_tag_t *c_tag, const ra8_etha_vlan_tag_t *s_tag_in)
Programme the C-VLAN and S-VLAN tag values used on TX insertion.
Definition ra8_etha.c:623
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_port_count
Number of ETHA ports.
ra8_etha_afs_t
EATPEC.AFS[1:0] additional fragment size policy for 802.3br.
ra8_etha_tc_t
Traffic-class index (q = 0..7) used by every per-class array.
@ k_ra8_etha_tc_count
Number of traffic classes per port.
ra8_etha_opc_t
ETHA EAMC.OPC[1:0] operating mode commands.
@ k_ra8_etha_opc_operation
Enter OPERATION mode.
@ k_ra8_etha_opc_config
Enter CONFIG mode.
@ k_ra8_etha_opc_reset
Enter RESET mode.
@ k_ra8_etha_opc_disable
Enter DISABLE mode.
ra8_etha_ops_t
ETHA EAMS.OPS[1:0] operating-mode status flag values.
ra8_etha_irq_class_t
Identifier for one of the three error-interrupt blocks.
@ k_ra8_etha_irq_class_1
Block 1: CBS overflow + TAS gate-states.
@ k_ra8_etha_irq_class_2
Block 2: descriptor queue overflow + security.
@ k_ra8_etha_irq_class_0
Block 0: ECC + frame errors + TAS gate-events.
@ k_ra8_etha_irq_class_count
RA8 etha IRQ class count.
static volatile r_etha_regs_t * ra8_etha(ra8_etha_port_t port)
Compile-time offset and size insurance for r_etha_regs_t.
ra8_etha_vim_t
EAVCC.VIM VLAN insertion mode for TX.
@ k_ra8_etha_eavtc_stv_pos
EAVTC.STV[27:16] S-VLAN VID.
@ k_ra8_etha_eavtc_std_pos
EAVTC.STD[31] S-VLAN DEI.
@ k_ra8_etha_eavtc_ctp_pos
EAVTC.CTP[14:12] C-VLAN PCP.
@ k_ra8_etha_eavtc_ctd_pos
EAVTC.CTD[15] C-VLAN DEI.
@ k_ra8_etha_eavtc_stp_pos
EAVTC.STP[30:28] S-VLAN PCP.
@ k_ra8_etha_eavtc_ctv_pos
EAVTC.CTV[11:0] C-VLAN VID.
@ k_ra8_etha_eatpec_afs_pos
EATPEC.AFS[17:16].
@ k_ra8_etha_eavcc_vem_pos
EAVCC.VEM[18:16].
@ k_ra8_etha_mask_civ
EACAIVCq.CIV[19:0].
@ k_ra8_etha_mask_cul
EACAULCq.CUL[30:0].
@ k_ra8_etha_mask_vlan_dei
EAVTC DEI 1-bit field.
@ k_ra8_etha_mask_ctqd
EACTQC.CTQD[15:0].
@ k_ra8_etha_mask_ctdqd
EACTDQDC.CTDQD[3:0].
@ k_ra8_etha_mask_vlan_vid
EAVTC VID 12-bit field.
@ k_ra8_etha_mask_vlan_pcp
EAVTC PCP 3-bit field.
@ k_ra8_etha_mask_opc
EAMC.OPC[1:0].
@ k_ra8_etha_mask_dqd
EATDQDCq.DQD[10:0].
@ k_ra8_etha_mask_mfs
EATMFSCq.MFS[15:0].
@ k_ra8_etha_mask_ops
EAMS.OPS[1:0].
@ k_ra8_etha_mask_ipv
EAIRC.IPVRq[2:0].
@ k_ra8_etha_mask_dnq
EATDQMq.DNQ[10:0].
@ k_ra8_etha_mask_tdqa
EATDQAC.TDQAq[3:0].
ra8_etha_vem_t
EAVCC.VEM[2:0] VLAN extraction mode.
void(* ra8_etha_event_fn_t)(void *ctx, ra8_etha_port_t port, uint32_t eaeis0, uint32_t eaeis1, uint32_t eaeis2)
ETHA per-port event callback.
Ethernet controller base addresses for the Renesas RA8D2.
Bounded wait-flag primitives for RA8D2 HAL drivers.
Lightweight Logging Interface for ra8-firmware.
#define ra8_log_info(tag, message)
RA8 log info.
Definition ra8_log.h:364
#define ra8_log_error(tag, message)
RA8 log error.
Definition ra8_log.h:335
Ref-counted Module Stop Control wrapper for the RA8D2.
ra8_err_t ra8_mstp_enable(ra8_mstp_t id)
Reference-counted "ungate this peripheral" request.
Definition ra8_mstp.c:343
Module Stop Control (MSTP) register layout for the Renesas RA8D2.
@ k_ra8_mstp_eswm
MSTPC30 ESWM.
Full ETHA per-port register window (HUM Ch 32, FSP R_ETHA0_Type).
volatile uint32_t EARTFC
+0x0138 RX tag filter configuration.
volatile uint32_t EAMC
+0x0000 Mode command.
volatile uint32_t EACTQC
+0x0100 Cut-through queue config.
volatile uint32_t EACAULC[8]
+0x0240..0x025F CBS admin upper lim.
volatile uint32_t EACC
+0x0204 CBS configuration.
volatile uint32_t EAFSECN
+0x0408 Frame size error counter.
volatile uint32_t EACGSM
+0x02C0 CBS gate state monitor.
volatile uint32_t EATDQAC
+0x001C TX desc queue arbitration.
volatile uint32_t EAIRC
+0x0010 IPV remap (8x 3-bit fields).
volatile uint32_t EATDQM[8]
+0x0080..0x009F Per-class queue mon.
volatile uint32_t EAUSMFSECN
+0x0400 Switch min frame size err cnt.
volatile uint32_t EADQSECN
+0x0410 Queue security error counter.
volatile uint32_t EAEID1
+0x0518 Error interrupt disable 1.
volatile uint32_t EAEIE0
+0x0504 Error interrupt enable 0.
volatile uint32_t EACTDQDC
+0x0104 Cut-through queue depth.
volatile uint32_t EATDQMLM[8]
+0x00A0..0x00BF Per-class peak level.
volatile uint32_t EADQOECN
+0x040C Queue overflow error counter.
volatile uint32_t EAEIE2
+0x0524 Error interrupt enable 2.
volatile uint32_t EAVTC
+0x0134 VLAN tag (C+S) configuration.
volatile uint32_t EAVCC
+0x0130 VLAN control configuration.
volatile uint32_t EATASCTM
+0x03B4 TAS cycle time monitor.
volatile uint32_t EATPEC
+0x0020 TX preemption config (802.3br).
volatile uint32_t EACAEC
+0x0200 CBS admin enable.
volatile uint32_t EAEIS0
+0x0500 Error interrupt status 0.
volatile uint32_t EATDQDC[8]
+0x0060..0x007F Per-class queue depth.
volatile uint32_t EATFECN
+0x0404 Tag filter error counter.
volatile uint32_t EAEID0
+0x0508 Error interrupt disable 0.
volatile uint32_t EACOULM[8]
+0x02A0..0x02BF CBS oper upper limit.
volatile uint32_t EATMFSC[8]
+0x0040..0x005F Per-class max frame.
volatile uint32_t EACOIVM[8]
+0x0280..0x029F CBS oper increment mon.
volatile uint32_t EAEIS2
+0x0520 Error interrupt status 2.
volatile uint32_t EACAIVC[8]
+0x0220..0x023F CBS admin increment.
volatile uint32_t EACOEM
+0x0260 CBS oper enable monitor.
volatile uint32_t EAMS
+0x0004 Mode status.
volatile uint32_t EAEID2
+0x0528 Error interrupt disable 2.
volatile uint32_t EAEIS1
+0x0510 Error interrupt status 1.
volatile uint32_t EAEIE1
+0x0514 Error interrupt enable 1.
Credit-based shaper parameters per traffic class.
uint32_t increment
CIV credit-add per byte (20 bits).
uint32_t upper_lim
CUL upper credit limit (31 bits).
Per-port ETHA configuration knobs.
uint32_t eaeie2_mask
Bits to OR into EAEIE2 on init.
uint32_t eaeie0_mask
Bits to OR into EAEIE0 on init.
uint32_t eaeie1_mask
Bits to OR into EAEIE1 on init.
ra8_etha_opc_t initial_mode
Mode to enter after init.
Per-port runtime traffic counters maintained by ra8_etha.
Per-port runtime state.
Per-port MIB counter snapshot.
uint16_t frame_size_err
EAFSECN.FSEN[15:0].
uint16_t tag_filter_err
EATFECN.TFEN[15:0].
uint16_t switch_min_frame_err
EAUSMFSECN.USMFSEN[15:0].
uint16_t queue_security_err
EADQSECN.DQSEN[15:0].
uint16_t queue_overflow_err
EADQOECN.DQOEN[15:0].
Snapshot of an ETHA port's runtime state.
uint32_t tas_cycle
EATASCTM TAS cycle-time monitor.
uint32_t eaeis0
Raw EAEIS0 (ECC + frame errors).
uint32_t eaeis1
Raw EAEIS1 (CBS + TAS gate).
ra8_etha_ops_t ops
Current operating-mode flag.
uint32_t eaeis2
Raw EAEIS2 (queue overflow).
802.1Q VLAN tag descriptor (used by::ra8_etha_set_vlan_tag).
uint8_t pcp
Priority code point (3 bits).
uint16_t vid
VLAN identifier (12 bits).
uint8_t dei
Drop eligible indicator (1 bit).