/* * Compile-out HW debug timeline (bench only). * * make HW_DEBUG=1 → -DPOG422_HW_DEBUG=1 * make → all macros compile to nothing (prod) * * No runtime is_debug checks on hot paths. */ #ifndef POG422_HW_DEBUG_H #define POG422_HW_DEBUG_H #include #include #include #ifndef POG422_HW_DEBUG #define POG422_HW_DEBUG 0 #endif /* Event types (userspace ring + IPC). GPIO5_* only from driver USB-INT drain. */ enum { POG422_HWDBG_HS_RISE = 1, POG422_HWDBG_HS_FALL = 2, POG422_HWDBG_RX_CHUNK = 3, POG422_HWDBG_TX_BULK_START = 4, POG422_HWDBG_TX_BULK_DONE = 5, POG422_HWDBG_DE_ON = 6, POG422_HWDBG_DE_OFF = 7, POG422_HWDBG_TEMT = 8, POG422_HWDBG_GPIO1_EDGE = 9, POG422_HWDBG_GPIO5_EDGE = 10, POG422_HWDBG_MARK = 11, POG422_HWDBG_COPPER = 12, }; #ifndef POG422_HWDBG_RING_MAX #define POG422_HWDBG_RING_MAX 512u #endif typedef struct __attribute__((packed)) { uint64_t t_mono_ns; uint8_t type; uint8_t _pad; uint16_t a; /* first byte / gpio flags / phase */ uint32_t b; /* len / gpio_stat / fifo */ } pog422_hwdbg_sample_t; typedef struct __attribute__((packed)) { uint32_t n; uint32_t dropped; /* n × pog422_hwdbg_sample_t follows in IPC */ } pog422_ipc_hwdbg_hdr_t; #if POG422_HW_DEBUG #define HWDBG_ENABLED 1 typedef struct { pog422_hwdbg_sample_t samples[POG422_HWDBG_RING_MAX]; uint32_t head; /* next write */ uint32_t count; uint32_t dropped; } pog422_hwdbg_ring_t; static inline uint64_t pog422_hwdbg_mono_ns(void) { struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); return (uint64_t)ts.tv_sec * 1000000000ull + (uint64_t)ts.tv_nsec; } static inline void pog422_hwdbg_ring_init(pog422_hwdbg_ring_t *r) { if (!r) { return; } memset(r, 0, sizeof(*r)); } static inline void pog422_hwdbg_emit( pog422_hwdbg_ring_t *r, uint8_t type, uint16_t a, uint32_t b, uint64_t t_mono_ns ) { pog422_hwdbg_sample_t *s; if (!r) { return; } s = &r->samples[r->head]; s->t_mono_ns = t_mono_ns ? t_mono_ns : pog422_hwdbg_mono_ns(); s->type = type; s->_pad = 0; s->a = a; s->b = b; r->head = (r->head + 1u) % POG422_HWDBG_RING_MAX; if (r->count < POG422_HWDBG_RING_MAX) { r->count++; } else { r->dropped++; } } /* Copy chronological samples into out[]; returns n written. Clears ring. */ static inline uint32_t pog422_hwdbg_ring_drain( pog422_hwdbg_ring_t *r, pog422_hwdbg_sample_t *out, uint32_t max_out, uint32_t *dropped_out ) { uint32_t n; uint32_t start; uint32_t i; if (!r || !out || max_out == 0u) { if (dropped_out) { *dropped_out = r ? r->dropped : 0u; } return 0u; } n = r->count; if (n > max_out) { n = max_out; } start = (r->head + POG422_HWDBG_RING_MAX - r->count) % POG422_HWDBG_RING_MAX; for (i = 0; i < n; i++) { out[i] = r->samples[(start + i) % POG422_HWDBG_RING_MAX]; } if (dropped_out) { *dropped_out = r->dropped; } r->head = 0; r->count = 0; r->dropped = 0; return n; } #define HWDBG_EMIT(ring, type, a, b) \ pog422_hwdbg_emit((ring), (uint8_t)(type), (uint16_t)(a), (uint32_t)(b), 0ull) #define HWDBG_EMIT_AT(ring, type, a, b, tns) \ pog422_hwdbg_emit((ring), (uint8_t)(type), (uint16_t)(a), (uint32_t)(b), (uint64_t)(tns)) #else /* !POG422_HW_DEBUG */ #define HWDBG_ENABLED 0 typedef struct { uint8_t _unused; } pog422_hwdbg_ring_t; static inline void pog422_hwdbg_ring_init(pog422_hwdbg_ring_t *r) { (void)r; } static inline void pog422_hwdbg_emit( pog422_hwdbg_ring_t *r, uint8_t type, uint16_t a, uint32_t b, uint64_t t_mono_ns ) { (void)r; (void)type; (void)a; (void)b; (void)t_mono_ns; } #define HWDBG_EMIT(ring, type, a, b) ((void)0) #define HWDBG_EMIT_AT(ring, type, a, b, tns) ((void)0) static inline uint32_t pog422_hwdbg_ring_drain( pog422_hwdbg_ring_t *r, pog422_hwdbg_sample_t *out, uint32_t max_out, uint32_t *dropped_out ) { (void)r; (void)out; (void)max_out; if (dropped_out) { *dropped_out = 0u; } return 0u; } #endif /* POG422_HW_DEBUG */ #endif /* POG422_HW_DEBUG_H */