Foundry/tt/tests/test_phase1b_telemetry.c

101 lines
4.1 KiB
C

/* SPDX-License-Identifier: AGPL-3.0-or-later */
/* Copyright (C) 2026 David (Corey) Herrera */
/**
* test_phase1b_telemetry.c — the first NoC transaction this backend ever issues.
*
* Phase 1b's opening move is deliberately the safest one available: aim a TLB
* window at the endpoint tt-kmd itself is already aimed at, and only read.
*
* - The endpoint is ARC at NoC0 (8, 0), CSM base 0x10000000. That is not a
* guess and not a probe: it was decoded from the driver's own live window
* configuration through a read-only mapping of the TLB register file
* (docs/tt_bringup_log.md finding 3), and the driver's reads through it
* demonstrably work — sysfs is populated and tt_heartbeat ticks.
* - Nothing is written to the device. The sequence claims a window, aims it,
* reads, and releases it.
*
* This matters because a wrong endpoint does not fail a read, it hangs the NoC,
* and recovery is a physical power cycle (spec §7.3). One has already been spent.
*
* The result is checked against an independent oracle rather than merely
* printed: pyluwen read the same five values off this card before any of this C
* existed, so the expected numbers below are ground truth obtained by a
* completely separate path. Agreement is evidence; a print is not.
*
* Build (the fence must be opened explicitly):
* cc -std=c99 -Wall -Wextra -Werror -DFT_TT_PHASE1B_NOC_ENABLED -I.. \
* ../ft_tt_kmd.c ../ft_tt_device.c ../ft_tt_tlb.c \
* ../ft_tt_arc_telemetry.c test_phase1b_telemetry.c -o build/test_phase1b
*/
#include "ft_tt_arc_telemetry.h"
#include "ft_tt_device.h"
#include <stdio.h>
/* Ground truth read from this card via pyluwen, independently of this code. */
#define ORACLE_TENSIX_ENABLED_COL 16383u /* 0b11111111111111 — 14 columns */
#define ORACLE_ENABLED_ETH 16095u
#define ORACLE_ENABLED_GDDR 255u /* 8 banks */
#define ORACLE_ENABLED_L2CPU 15u /* 4 clusters */
#define ORACLE_TENSIX_COLUMNS 14u
#define ORACLE_DRAM_BANKS 8u
static int failures;
static void check_u32(const char *what, uint32_t got, uint32_t expected)
{
if (got == expected) {
printf(" ok %-34s = %u\n", what, got);
} else {
printf(" FAIL %-34s = %u (expected %u)\n", what, got, expected);
failures++;
}
}
int main(void)
{
ft_tt_ctx *ctx = ft_tt_init_device(0);
if (ctx == NULL) {
fprintf(stderr, "could not open device 0\n");
return 1;
}
printf("Phase 1b — first NoC read (ARC telemetry via NoC0 (8,0) CSM 0x10000000)\n");
ft_tt_grid_info grid;
int rc = ft_tt_arc_telemetry_read_grid(ctx, &grid);
if (rc != FT_TT_OK) {
fprintf(stderr, " ft_tt_arc_telemetry_read_grid failed: %d\n", rc);
fprintf(stderr, " (FT_TT_EPERM here means the Phase 1a fence is still closed —\n"
" rebuild with -DFT_TT_PHASE1B_NOC_ENABLED)\n");
ft_tt_ctx_free(ctx);
return 1;
}
check_u32("grid is valid", grid.valid ? 1u : 0u, 1u);
check_u32("tensix_enabled_col", grid.tensix_enabled_col, ORACLE_TENSIX_ENABLED_COL);
check_u32("enabled_eth", grid.enabled_eth, ORACLE_ENABLED_ETH);
check_u32("enabled_gddr", grid.enabled_gddr, ORACLE_ENABLED_GDDR);
check_u32("enabled_l2cpu", grid.enabled_l2cpu, ORACLE_ENABLED_L2CPU);
check_u32("noc_translation_enabled", grid.noc_translation_enabled, 1u);
check_u32("tensix_column_count", grid.tensix_column_count, ORACLE_TENSIX_COLUMNS);
check_u32("dram_bank_count", grid.dram_bank_count, ORACLE_DRAM_BANKS);
/* mem_info refused to guess in Phase 1a; with a grid it must now answer. */
size_t free_bytes = 0;
size_t total_bytes = 0;
rc = ft_tt_mem_info(ctx, &free_bytes, &total_bytes);
if (rc == FT_TT_OK) {
printf(" ok ft_tt_mem_info now answers = %.2f GiB total\n",
(double)total_bytes / (1024.0 * 1024.0 * 1024.0));
} else {
printf(" FAIL ft_tt_mem_info still refuses (rc=%d)\n", rc);
failures++;
}
printf("\n%d checks failed\n", failures);
ft_tt_ctx_free(ctx);
return failures == 0 ? 0 : 1;
}