|
ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
|
USBX device-controller-driver bridge to ra8_usb – IRQ pipe-walk. More...
#include <stdint.h>#include <string.h>#include "ra8_check.h"#include "ra8_elc_regs.h"#include "ra8_isr.h"#include "ra8_log.h"#include "ra8_usb_regs.h"#include "tx_api.h"#include "ux_api.h"#include "ux_dcd_ra8_usb.h"#include "ux_dcd_ra8_usb_internal.h"#include "ux_device_stack.h"#include "ux_system.h"#include "ux_utility.h"Go to the source code of this file.
Macros | |
| #define | UX_SOURCE_CODE |
Enumerations | |
| enum | ra8_usb_dcd_intsts0_hist_t : uint8_t { k_ra8_usb_dcd_intsts0_hist_n = 8U } |
| Sizing for the INTSTS0 / CTSQ history rings. More... | |
| enum | ux_dcd_ra8_usb_auto_echo_cfg_t : uint16_t { k_ux_dcd_ra8_usb_auto_echo_max = 512U } |
Functions | |
| static void | internal_irq_record_snapshot (uint16_t intsts0) |
| Record per-bit IRQ counters and the JLink-visible event ring. | |
| static void | internal_irq_auto_echo (uint8_t i) |
| No-waiter auto-echo drain on the configured OUT pipe. | |
| static bool | internal_irq_stage_next_in (UX_SLAVE_TRANSFER *tr, uint8_t i) |
| Stage the next IN chunk of a stashed transfer onto the pipe. | |
| static bool | internal_irq_recover_in_nak (UX_SLAVE_TRANSFER *tr, uint8_t i, volatile r_usb_regs_t *reg) |
| Recover a stashed IN transfer whose pipe fell to PID=NAK. | |
| static void | internal_irq_complete_in (UX_SLAVE_TRANSFER *tr, uint8_t i) |
| Complete a stashed IN-pipe transfer. | |
| static void | internal_irq_finish_out (UX_SLAVE_TRANSFER *tr, uint8_t i, uint16_t now) |
| Finish a completed OUT transfer: park, trace, wake the waiter. | |
| static void | internal_irq_complete_out (UX_SLAVE_TRANSFER *tr, uint8_t i) |
| Complete a stashed OUT-pipe transfer (or rearm on no-data). | |
| static void | internal_irq_drain_orphan_out (uint8_t i) |
| Capture a no-receiver bulk-OUT packet into the orphan buffer. | |
| static void | internal_irq_walk_pipe (uint8_t i) |
| Per-pipe finaliser for the BRDY/BEMP walk in ux_dcd_ra8_usb_irq. | |
| void | ux_dcd_ra8_usb_irq (ra8_usb_speed_t speed, uint16_t intsts0) |
| Ux dcd ra usb irq. | |
Variables | |
| volatile uint32_t | g_ctrt_irq_count = 0U |
| Counter of INTSTS0.CTRT events seen by the dispatcher. | |
| volatile uint16_t | g_intsts0_last_dispatch = 0U |
| Most-recent INTSTS0 snapshot fed to ux_dcd_ra8_usb_irq. | |
| volatile uint32_t | g_intsts0_valid_count = 0U |
| Number of dispatch ticks where INTSTS0.VALID was observed. | |
| volatile uint32_t | g_intsts0_ctrt_count = 0U |
| Number of dispatch ticks where INTSTS0.CTRT was observed. | |
| volatile uint16_t | g_intsts0_snapshot [(uint32_t) k_ra8_usb_dcd_intsts0_hist_n] = {} |
| Ring buffer of the last 8 INTSTS0 values seen by the worker on ticks where any of CTRT/VALID/DVST were set. | |
| volatile uint32_t | g_intsts0_snapshot_count = 0U |
| Total interesting INTSTS0 snapshots seen; modulo k_ra8_usb_dcd_intsts0_hist_n is the next write slot. | |
| volatile uint8_t | g_ctsq_history [(uint32_t) k_ra8_usb_dcd_intsts0_hist_n] = {} |
| Ring buffer of the last 8 INTSTS0.CTSQ[2:0] values observed with CTRT or VALID asserted. | |
| volatile uint16_t | g_intsts0_observed_or = 0U |
| Bitwise OR of every INTSTS0 value ever fed to ux_dcd_ra8_usb_irq. | |
| volatile uint8_t | g_dvsq_history [(uint32_t) k_ra8_usb_dcd_intsts0_hist_n] = {} |
| Per-snapshot DVSQ[2:0] field, pre-decoded for JLink readers. | |
| volatile uint32_t | g_dcd_auto_echo_drain_ok = 0U |
| volatile uint32_t | g_dcd_auto_echo_drain_skip = 0U |
| volatile uint32_t | g_dcd_auto_echo_tx_ok = 0U |
| volatile uint32_t | g_dcd_auto_echo_tx_err = 0U |
| volatile uint16_t | g_dcd_auto_echo_last_len = 0U |
| static uint8_t | s_dcd_auto_echo_buf [k_ux_dcd_ra8_usb_auto_echo_max] |
USBX device-controller-driver bridge to ra8_usb – IRQ pipe-walk.
The ISR bottom-half ux_dcd_ra8_usb_irq and its per-pipe BRDY / BEMP finalisers: IN streaming, OUT draining, auto-echo, and orphan-OUT capture.
Split out of ux_dcd_ra8_usb.c to keep each translation unit under the maintainability line cap; the cross-translation-unit contract lives in ux_dcd_ra8_usb_internal.h.
Definition in file ux_dcd_ra8_usb_irq.c.
| #define UX_SOURCE_CODE |
Definition at line 22 of file ux_dcd_ra8_usb_irq.c.
| enum ra8_usb_dcd_intsts0_hist_t : uint8_t |
Sizing for the INTSTS0 / CTSQ history rings.
| Enumerator | |
|---|---|
| k_ra8_usb_dcd_intsts0_hist_n | Slots in g_intsts0_snapshot/g_ctsq_history. |
Definition at line 70 of file ux_dcd_ra8_usb_irq.c.
| enum ux_dcd_ra8_usb_auto_echo_cfg_t : uint16_t |
| Enumerator | |
|---|---|
| k_ux_dcd_ra8_usb_auto_echo_max | Ux dcd RA8 USB auto echo maximum. |
Definition at line 175 of file ux_dcd_ra8_usb_irq.c.
|
static |
No-waiter auto-echo drain on the configured OUT pipe.
When the USBX-side waiter is absent (typically because the worker thread has not yet been dispatched) and the operator has enabled the in-ISR auto-echo path, drain the OUT pipe locally and re-queue the bytes back on the IN pipe. Workaround for ThreadX worker scheduling failure – keeps echo functional without any thread-mode involvement.
THROUGHPUT NOTE. On hardware this echo loop sustains ~2.66 MB/s one-way at HS and ~360 KB/s at FS (measured via scripts/hil/usb/stream_bench.py against Linux cdc_acm). That is ~66 % of the per-microframe scheduling ceiling for HS (4 MB/s at 1 packet/125 us microframe) and ~35 % of FS bulk wire. The bottleneck is NOT this code path – it is the host's cdc_acm URB-completion pipeline (MPS-sized read URBs, one completion per packet, callback latency limits URB recycling). To push past this ceiling needs either a libusb async client, a kernel cdc_acm patch with bigger URBs, or a vendor-specific interface.
| [in] | i | Pipe index that just signalled BRDY/BEMP with no waiter. |
Definition at line 271 of file ux_dcd_ra8_usb_irq.c.
References g_dcd, g_dcd_auto_echo_drain_ok, g_dcd_auto_echo_drain_skip, g_dcd_auto_echo_enable, g_dcd_auto_echo_in_pipe, g_dcd_auto_echo_last_len, g_dcd_auto_echo_out_pipe, g_dcd_auto_echo_tx_err, g_dcd_auto_echo_tx_ok, k_ra8_ok, k_ux_dcd_ra8_usb_auto_echo_max, RA8_INTERNAL, ra8_usb_queue_in(), ra8_usb_queue_out(), ra8_usb_rearm_out_pipe(), and s_dcd_auto_echo_buf.
Referenced by internal_irq_walk_pipe().
|
static |
Complete a stashed IN-pipe transfer.
IN: data was already pushed in TRANSFER_REQUEST. Mark complete on the BEMP that follows, and W0C-ack the per-pipe BEMPSTS bit so the global INTSTS0.BEMP flag can de-assert – without this BEMPSTS stays set forever, the global BEMP re-asserts after every dispatch ack, and the ISR storm prevents PendSV from delivering completions to the worker. HUM Ch 36.2.15 BEMPSTS (W0C, write ~pipe_bit to clear only this pipe).
| [in,out] | tr | Stashed transfer to complete. |
| [in] | i | Pipe index. |
Definition at line 413 of file ux_dcd_ra8_usb_irq.c.
References r_usb_regs_t::BEMPSTS, g_dcd, internal_irq_recover_in_nak(), internal_irq_stage_next_in(), k_dcd_trace_kind_in, k_dcd_trace_no_code, k_ra8_usb_speed_hs, priv_trace_event(), RA8_INTERNAL, ra8_usb_fs(), ra8_usb_hs(), and ra8_usb_queue_in().
Referenced by internal_irq_walk_pipe().
|
static |
Complete a stashed OUT-pipe transfer (or rearm on no-data).
Drain the OUT pipe into the stashed buffer. On success post UX_SUCCESS and wake the waiter; on k_ra8_err_no_data proactively W0C-ack NRDYSTS for this pipe and force PIPECTR.PID = BUF so the next host OUT is ACKed. HUM Ch 36.2.13 NRDYSTS + Ch 36.2.27 PIPECTR.
| [in,out] | tr | Stashed transfer to complete. |
| [in] | i | Pipe index. |
Definition at line 543 of file ux_dcd_ra8_usb_irq.c.
References g_dcd, g_diag, internal_irq_finish_out(), k_dcd_out_drain_max, k_ra8_ok, RA8_INTERNAL, ra8_usb_queue_out(), and ra8_usb_rearm_out_pipe().
Referenced by internal_irq_walk_pipe().
|
static |
Capture a no-receiver bulk-OUT packet into the orphan buffer.
Run from the IRQ pipe-walk for an OUT pipe that has no USBX transfer stashed. If a host packet has landed in the controller bank (BRDYSTS set), draining it via ra8_usb_queue_out both W0C-clears BRDYSTS – so the no-receiver BRDY interrupt cannot storm the CPU and starve thread mode (GitHub issue #6) – and preserves the packet in g_orphan_buf for internal_submit_pipe to hand to the next bulk-OUT transfer. The pipe is then parked at PID=NAK so no second packet can land. Skipped for IN pipes, unconfigured pipes, the CDC auto-echo pipe, and while the one-deep buffer is already occupied.
| [in] | i | Pipe index (1..max_pipes-1). |
Definition at line 619 of file ux_dcd_ra8_usb_irq.c.
References g_dcd, g_dcd_auto_echo_enable, g_dcd_auto_echo_out_pipe, g_orphan_buf, g_orphan_len, g_orphan_pipe, k_dcd_trace_kind_ocap, k_ra8_ok, k_ra8_usb_orphan_bytes, priv_trace_event(), RA8_INTERNAL, ra8_usb_park_out_pipe(), and ra8_usb_queue_out().
Referenced by internal_irq_walk_pipe().
|
static |
Finish a completed OUT transfer: park, trace, wake the waiter.
Parks the pipe at PID=NAK (a host OUT token landing before the class layer arms the next receiver is then NAK'd rather than ACK'd into a FIFO with no waiter – the latter latches BRDYSTS and storms the ISR, GitHub issue #6), records the transfer in the trace ring (with the SCSI opcode + CDB bytes 1..2 when it is a 31-byte CBW), posts UX_SUCCESS, and wakes the waiter.
| [in,out] | tr | Stashed transfer that just completed. |
| [in] | i | Pipe index. |
| [in] | now | Total bytes received for this transfer. |
Definition at line 493 of file ux_dcd_ra8_usb_irq.c.
References g_dcd, k_dcd_trace_byte_shift, k_dcd_trace_cbw_len, k_dcd_trace_cbw_op_off, k_dcd_trace_cdb_lba_hi, k_dcd_trace_cdb_lba_lo, k_dcd_trace_kind_out, k_dcd_trace_no_code, k_dcd_trace_op_read10, k_dcd_trace_op_write10, priv_trace_event(), RA8_INTERNAL, and ra8_usb_park_out_pipe().
Referenced by internal_irq_complete_out().
|
static |
Record per-bit IRQ counters and the JLink-visible event ring.
Bumps g_intsts0_valid_count / g_intsts0_ctrt_count / g_setup_token_observed then, when any event bit (CTRT / VALID / DVST) is set, snapshots the wire-format INTSTS0 along with the decoded CTSQ and DVSQ fields into the round-robin history ring (HUM Ch 36.2.14 / Ch 36.2.16). Folded out of ux_dcd_ra8_usb_irq so the outer ISR-side trampoline stays under the NASA P10 Rule 4 size cap.
| [in] | intsts0 | INTSTS0 snapshot forwarded by ra8_usb_dispatch. |
Definition at line 211 of file ux_dcd_ra8_usb_irq.c.
References g_ctsq_history, g_dvsq_history, g_intsts0_ctrt_count, g_intsts0_snapshot, g_intsts0_snapshot_count, g_intsts0_valid_count, g_setup_token_observed, k_ra8_int0_bit_ctrt, k_ra8_int0_bit_dvst, k_ra8_int0_dvsq_shift, k_ra8_intsts0_mask_ctsq, k_ra8_intsts0_mask_dvsq, k_ra8_intsts0_mask_valid, k_ra8_usb_dcd_intsts0_hist_n, and RA8_INTERNAL.
Referenced by ux_dcd_ra8_usb_irq().
|
static |
Recover a stashed IN transfer whose pipe fell to PID=NAK.
Strand recovery (seen against macOS hosts): a stashed IN transfer must never sit with PIPECTR.PID = NAK – the SIE then NAKs every IN token, the host eventually suspends the bus, and the class thread blocks on the semaphore forever. Two recoverable shapes:
| [in,out] | tr | Stashed transfer being streamed. |
| [in] | i | Pipe index. |
| [in] | reg | Controller register window. |
| false | The pipe is armed normally; continue the walk. |
Definition at line 367 of file ux_dcd_ra8_usb_irq.c.
References r_usb_regs_t::BEMPSTS, g_dcd, g_diag, internal_irq_stage_next_in(), k_ra8_pid_nak, k_ra8_pipectr_inbufm, k_ra8_pipectr_pid_mask, r_usb_regs_t::PIPECTR, and ra8_usb_rearm_out_pipe().
Referenced by internal_irq_complete_in().
|
static |
Stage the next IN chunk of a stashed transfer onto the pipe.
Pushes the next MPS-bounded chunk at the running actual_length offset via ra8_usb_queue_in and advances the offset on success. A failure (typically an FRDY timeout while the SIE holds the FIFO) is counted in g_diag.in_stage_fail and leaves actual_length unchanged so the caller can retry the same chunk on a later walk.
| [in,out] | tr | Stashed transfer being streamed. |
| [in] | i | Pipe index. |
| false | ra8_usb_queue_in failed; nothing was consumed. |
Definition at line 324 of file ux_dcd_ra8_usb_irq.c.
References g_dcd, g_diag, k_ra8_ok, RA8_INTERNAL, and ra8_usb_queue_in().
Referenced by internal_irq_complete_in(), and internal_irq_recover_in_nak().
|
static |
Per-pipe finaliser for the BRDY/BEMP walk in ux_dcd_ra8_usb_irq.
If no USBX-side waiter is stashed, dispatch to the in-ISR auto-echo path (workaround for ThreadX worker scheduling failure) and the no-receiver orphan-OUT capture. Otherwise dispatch to internal_irq_complete_in or internal_irq_complete_out depending on the pipe direction.
| [in] | i | Pipe index (1..max_pipes-1). |
Definition at line 673 of file ux_dcd_ra8_usb_irq.c.
References g_dcd, g_diag, internal_irq_auto_echo(), internal_irq_complete_in(), internal_irq_complete_out(), internal_irq_drain_orphan_out(), and RA8_INTERNAL.
Referenced by ux_dcd_ra8_usb_irq().
| void ux_dcd_ra8_usb_irq | ( | ra8_usb_speed_t | speed, |
| uint16_t | intsts0 ) |
Ux dcd ra usb irq.
ISR-context bottom-half.
See implementation for details.
| [in,out] | speed | See function signature for type and usage. |
| [in,out] | intsts0 | See function signature for type and usage. |
Definition at line 709 of file ux_dcd_ra8_usb_irq.c.
References g_ctrt_irq_count, g_dcd, g_intsts0_last_dispatch, g_intsts0_observed_or, internal_irq_record_snapshot(), internal_irq_walk_pipe(), k_ra8_int0_bit_ctrt, k_ra8_int0_bit_dvst, k_ra8_intsts0_mask_valid, k_ux_dcd_ra8_usb_max_pipes, k_ux_dcd_ra8_usb_state_uninit, priv_handle_ctrl_out_data(), priv_handle_ctrt(), and priv_irq_dvst_prelude().
Referenced by priv_event_cb().
| volatile uint32_t g_ctrt_irq_count = 0U |
Counter of INTSTS0.CTRT events seen by the dispatcher.
Bisect probe. Non-zero after host SETUP means the chip is reporting control-stage transitions; zero means SETUPs aren't being latched (HS chirp / termination problem). HUM Ch 36.2.14 p 1985.
Definition at line 51 of file ux_dcd_ra8_usb_irq.c.
Referenced by ux_dcd_ra8_usb_irq().
| volatile uint8_t g_ctsq_history[(uint32_t) k_ra8_usb_dcd_intsts0_hist_n] = {} |
Ring buffer of the last 8 INTSTS0.CTSQ[2:0] values observed with CTRT or VALID asserted.
Encoding (HUM Ch 36.2.14 p 1985 / ra8_usb_ctsq_t): 0=idle, 1=rdds, 2=rdss, 3=wrds, 4=wrss, 5=wrnd, 6=sqer.
Definition at line 138 of file ux_dcd_ra8_usb_irq.c.
Referenced by internal_irq_record_snapshot().
| volatile uint32_t g_dcd_auto_echo_drain_ok = 0U |
Definition at line 179 of file ux_dcd_ra8_usb_irq.c.
Referenced by internal_irq_auto_echo().
| volatile uint32_t g_dcd_auto_echo_drain_skip = 0U |
Definition at line 181 of file ux_dcd_ra8_usb_irq.c.
Referenced by internal_irq_auto_echo().
| volatile uint16_t g_dcd_auto_echo_last_len = 0U |
Definition at line 187 of file ux_dcd_ra8_usb_irq.c.
Referenced by internal_irq_auto_echo().
| volatile uint32_t g_dcd_auto_echo_tx_err = 0U |
Definition at line 185 of file ux_dcd_ra8_usb_irq.c.
Referenced by internal_irq_auto_echo().
| volatile uint32_t g_dcd_auto_echo_tx_ok = 0U |
Definition at line 183 of file ux_dcd_ra8_usb_irq.c.
Referenced by internal_irq_auto_echo().
| volatile uint8_t g_dvsq_history[(uint32_t) k_ra8_usb_dcd_intsts0_hist_n] = {} |
Per-snapshot DVSQ[2:0] field, pre-decoded for JLink readers.
Companion to g_intsts0_snapshot. Slot i holds (intsts0[i] >> 4) & 0x07, i.e. 0=Powered, 1=Default, 2=Address, 3=Configured, 4..7=Suspend (per HUM Ch 36.2.16 p 1986). Saves the human reader from mentally decoding the raw bits.
Definition at line 168 of file ux_dcd_ra8_usb_irq.c.
Referenced by internal_irq_record_snapshot().
| volatile uint32_t g_intsts0_ctrt_count = 0U |
Number of dispatch ticks where INTSTS0.CTRT was observed.
Bisect probe. Identical to g_ctrt_irq_count but bumped on the snapshot value before the CTRT branch decides whether to handle the SETUP – useful for detecting CTRT latches that hit a snapshot but failed the handler's CTSQ decode. HUM Ch 36.2.14 p 1985.
Definition at line 100 of file ux_dcd_ra8_usb_irq.c.
Referenced by internal_irq_record_snapshot().
| volatile uint16_t g_intsts0_last_dispatch = 0U |
Most-recent INTSTS0 snapshot fed to ux_dcd_ra8_usb_irq.
Live-debug probe. Read this from JLink to see the current pending interrupt mask + DVSQ/CTSQ field state without halting the polled worker. HUM Ch 36.2.14 p 1985.
Definition at line 64 of file ux_dcd_ra8_usb_irq.c.
Referenced by ux_dcd_ra8_usb_irq().
| volatile uint16_t g_intsts0_observed_or = 0U |
Bitwise OR of every INTSTS0 value ever fed to ux_dcd_ra8_usb_irq.
Definitive bisect probe. Read this once via JLink and check bit 3 (mask 0x0008 = VALID) – if it's clear, the controller has NEVER latched a SETUP token since power-on. Distinct from the snapshot ring (which can scroll edges out of view) because OR- accumulating bits is monotonic. HUM Ch 36.2.16 INTSTS0 p 1986 (VALID = bit 3, CTRT = bit 11, DVST = bit 12).
Definition at line 154 of file ux_dcd_ra8_usb_irq.c.
Referenced by ux_dcd_ra8_usb_irq().
| volatile uint16_t g_intsts0_snapshot[(uint32_t) k_ra8_usb_dcd_intsts0_hist_n] = {} |
Ring buffer of the last 8 INTSTS0 values seen by the worker on ticks where any of CTRT/VALID/DVST were set.
JLink-readable trace. Index of next write slot is g_intsts0_snapshot_count % k_ra8_usb_dcd_intsts0_hist_n. Only "interesting" ticks are recorded so a noisy idle loop doesn't scroll a real SETUP edge out of the ring. HUM Ch 36.2.14 p 1985.
Definition at line 115 of file ux_dcd_ra8_usb_irq.c.
Referenced by internal_irq_record_snapshot().
| volatile uint32_t g_intsts0_snapshot_count = 0U |
Total interesting INTSTS0 snapshots seen; modulo k_ra8_usb_dcd_intsts0_hist_n is the next write slot.
Definition at line 125 of file ux_dcd_ra8_usb_irq.c.
Referenced by internal_irq_record_snapshot().
| volatile uint32_t g_intsts0_valid_count = 0U |
Number of dispatch ticks where INTSTS0.VALID was observed.
Bisect probe. Distinguishes "controller never latched a SETUP" (count == 0) from "controller latched but our CTRT edge was lost" (count > 0 while g_ctrt_irq_count grows). HUM Ch 36.2.14 INTSTS0.VALID = bit 3, p 1985.
Definition at line 86 of file ux_dcd_ra8_usb_irq.c.
Referenced by internal_irq_record_snapshot().
|
static |
Definition at line 189 of file ux_dcd_ra8_usb_irq.c.
Referenced by internal_irq_auto_echo().