Foundry/tt/ft_tt_kmd.h

248 lines
9.6 KiB
C

/* SPDX-License-Identifier: AGPL-3.0-or-later */
/**
* @file ft_tt_kmd.h
* @brief Foundry's boundary to the Tenstorrent kernel driver's character device
* (/dev/tenstorrent/N): open a card, read what it is, claim / map / aim / release TLB
* windows, and the two driver side-requests Foundry uses (AI clock, close-time NoC write).
*
* Every entry point returns 0 or a NEGATIVE errno unless its comment says otherwise. Each one
* issues exactly the syscalls its comment lists, once, with no retries — a differential
* harness compares the syscall sequence and argument bytes, so nothing here may add one.
*
* THE NOC FENCE. Aiming a window (CONFIGURE_WINDOW) is the only operation here that issues a
* NoC transaction, and a wrong one hangs the chip. It exists only in a build that defines
* FT_TT_PHASE1B_NOC_ENABLED; otherwise ft_tt_kmd_window_aim() returns -EPERM and touches
* nothing, so a default build cannot reach the NoC at all.
*
* @status Complete against the driver ABI in ft_tt_kmd_abi.h. Unit-tested off-device against
* fake syscalls (tests/test_kmd.c).
* @issues None
* @todo None
*/
#ifndef FT_TT_KMD_H
#define FT_TT_KMD_H
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "ft_tt_kmd_abi.h"
/* ================================================================
* Enums — the VALUES are relied on elsewhere (ft_tt_arch tables, callers' logs)
* ================================================================ */
/** Chip architecture, as decoded from the PCI device id. */
enum ft_tt_kmd_arch {
FT_TT_KMD_ARCH_UNKNOWN = 0,
FT_TT_KMD_ARCH_WORMHOLE = 1,
FT_TT_KMD_ARCH_BLACKHOLE = 2
};
/** Which mapping of a window's aperture to use: uncached for registers, write-combined for
* bulk data. */
enum ft_tt_kmd_cache_mode {
FT_TT_KMD_CACHE_UC = 0,
FT_TT_KMD_CACHE_WC = 1
};
/** What ft_tt_kmd_driver_attr() reports. */
enum ft_tt_kmd_driver_attr {
FT_TT_KMD_DRIVER_API_VERSION = 0,
FT_TT_KMD_DRIVER_VERSION_MAJOR = 1,
FT_TT_KMD_DRIVER_VERSION_MINOR = 2,
FT_TT_KMD_DRIVER_VERSION_PATCH = 3
};
/** NoC ordering of a window's transactions. */
enum ft_tt_kmd_window_ordering {
FT_TT_KMD_ORDERING_RELAXED = 0,
FT_TT_KMD_ORDERING_STRICT = 1,
FT_TT_KMD_ORDERING_POSTED = 2,
FT_TT_KMD_ORDERING_POSTED_STRICT = 3
};
/* ================================================================
* Window sizes
* ================================================================ */
#define FT_TT_KMD_WINDOW_SIZE_1M (1ull << 20)
#define FT_TT_KMD_WINDOW_SIZE_2M (2ull << 20)
#define FT_TT_KMD_WINDOW_SIZE_16M (16ull << 20)
#define FT_TT_KMD_WINDOW_SIZE_4G (4ull << 30)
/** The most 2 MiB windows a Blackhole reports, however large BAR0 is. */
#define FT_TT_KMD_BLACKHOLE_2M_WINDOW_LIMIT 202u
/* ================================================================
* Types
* ================================================================ */
/** One open chardev: its fd and the BAR resources cached at open. Opaque. */
typedef struct ft_tt_kmd_device ft_tt_kmd_device;
/** One claimed TLB window: driver id, size and the mapped aperture. Opaque. */
typedef struct ft_tt_kmd_window ft_tt_kmd_window;
/** What the card is (GET_DEVICE_INFO), plus window counts derived from the BAR lengths. */
typedef struct ft_tt_kmd_device_attrs {
uint64_t pci_domain;
uint64_t pci_bus;
uint64_t pci_device;
uint64_t pci_function;
uint64_t pci_vendor_id;
uint64_t pci_device_id;
uint64_t pci_subsystem_vendor_id;
uint64_t pci_subsystem_id;
uint64_t chip_arch; /**< enum ft_tt_kmd_arch */
uint64_t window_count_1m;
uint64_t window_count_2m;
uint64_t window_count_16m;
uint64_t window_count_4g; /**< 0 on a board with no BAR4 */
} ft_tt_kmd_device_attrs;
/** mmap offsets and lengths of the three BARs. A length of 0 means the BAR is absent. */
typedef struct ft_tt_kmd_resources {
uint64_t bar0_uc_offset;
uint64_t bar0_wc_offset;
uint64_t bar0_len;
uint64_t bar2_uc_offset;
uint64_t bar2_wc_offset;
uint64_t bar2_len;
uint64_t bar4_uc_offset;
uint64_t bar4_wc_offset;
uint64_t bar4_len;
} ft_tt_kmd_resources;
/** Where to aim a window. A unicast target has x_end/y_end set and the starts zero. */
typedef struct ft_tt_kmd_window_target {
uint64_t addr; /**< tile-local address; a multiple of the window size */
uint16_t x_end;
uint16_t y_end;
uint16_t x_start;
uint16_t y_start;
uint8_t noc;
uint8_t mcast;
uint8_t ordering; /**< enum ft_tt_kmd_window_ordering */
uint8_t static_vc;
} ft_tt_kmd_window_target;
/* ================================================================
* Device
* ================================================================ */
/**
* Open the chardev and cache its BAR resources.
*
* Syscalls: open(path, O_RDWR | O_CLOEXEC | extra_flags), then one QUERY_MAPPINGS asking for
* six records. On an ioctl failure the fd is closed.
*
* @param path e.g. "/dev/tenstorrent/0"
* @param out_device receives the handle on success; release with ft_tt_kmd_close()
* @param extra_flags added to the open flags (O_APPEND marks a power-aware client)
* @return 0, -EINVAL (NULL argument), -ENOMEM, or the failing call's -errno
*
* Thread-safe: yes Reentrant: yes Signal-safe: no
*/
int ft_tt_kmd_open(const char *path, ft_tt_kmd_device **out_device, int extra_flags);
/**
* Close the fd and free the handle. NULL is a no-op returning 0. The handle is freed even
* when close() fails.
* @return 0 or close()'s -errno
*/
int ft_tt_kmd_close(ft_tt_kmd_device *device);
/**
* Read the card's identity with one GET_DEVICE_INFO. Window counts are nonzero only on a
* Blackhole: 2 MiB = BAR0 length / 2 MiB capped at 202, 4 GiB = BAR4 length / 4 GiB.
* @return 0, -EINVAL, or the ioctl's -errno
*/
int ft_tt_kmd_get_attrs(ft_tt_kmd_device *device, ft_tt_kmd_device_attrs *out_attrs);
/** Copy the BAR resources cached at open. No syscall. @return 0 or -EINVAL */
int ft_tt_kmd_get_resources(const ft_tt_kmd_device *device, ft_tt_kmd_resources *out_resources);
/** The chardev fd, or -1 for NULL. */
int ft_tt_kmd_fd(const ft_tt_kmd_device *device);
/**
* Ask for the maximum (or minimum) AI clock: one SET_POWER_STATE with every flag valid and
* the word FT_TT_KMD_POWER_FLAGS_ALL, minus MAX_AI_CLOCK when `want_max` is false.
* @return 0, -EINVAL, or the ioctl's -errno
*/
int ft_tt_kmd_request_max_ai_clock(ft_tt_kmd_device *device, bool want_max);
/**
* Register a NoC write the driver performs when this fd closes — including when the process
* dies. One NOC_CLEANUP ioctl.
* @param noc NoC index
* @param x, y target tile
* @param addr tile-local address
* @param value data written there
* @return 0, -EINVAL, or the ioctl's -errno
*/
int ft_tt_kmd_set_noc_cleanup(ft_tt_kmd_device *device, uint8_t noc, uint8_t x, uint8_t y,
uint64_t addr, uint64_t value);
/** Cancel the close-time write: one NOC_CLEANUP with enabled = 0. @return as above */
int ft_tt_kmd_clear_noc_cleanup(ft_tt_kmd_device *device);
/**
* Report a driver attribute. With a device, one GET_DRIVER_INFO is issued first.
* FT_TT_KMD_DRIVER_API_VERSION is the compiled-in FT_TT_KMD_ABI_VERSION, answerable with a
* NULL device. The semver parts come from the driver's reply; with a NULL device they write 0
* and return -ENODEV.
* @return 0, -EINVAL (NULL out or unknown attribute), -ENODEV, or the ioctl's -errno
*/
int ft_tt_kmd_driver_attr(ft_tt_kmd_device *device, enum ft_tt_kmd_driver_attr attr,
uint64_t *out_value);
/* ================================================================
* Windows
* ================================================================ */
/**
* Claim a window (ALLOCATE_WINDOW) and mmap its aperture with `protection`. If the mmap
* fails the claim is released with one FREE_WINDOW before returning.
* @param cache which of the driver's two aperture offsets to map
* @return 0, -EINVAL, -ENOMEM, or the failing call's -errno
*/
int ft_tt_kmd_window_alloc(ft_tt_kmd_device *device, size_t size,
enum ft_tt_kmd_cache_mode cache, int protection,
ft_tt_kmd_window **out_window);
/**
* munmap the aperture, THEN release the claim (FREE_WINDOW), then free the handle. The order
* is required: the driver may hand the window to another client the moment it is freed. A
* failing step is reported but does not stop the later ones.
* @return 0, -EINVAL, or the last failing call's -errno
*/
int ft_tt_kmd_window_free(ft_tt_kmd_device *device, ft_tt_kmd_window *window);
/** The mapped aperture. @return 0 or -EINVAL */
int ft_tt_kmd_window_aperture(const ft_tt_kmd_window *window, void **out_aperture);
/** The driver-assigned window id. @return 0 or -EINVAL */
int ft_tt_kmd_window_id(const ft_tt_kmd_window *window, uint32_t *out_id);
/** The window size in bytes. @return 0 or -EINVAL */
int ft_tt_kmd_window_size(const ft_tt_kmd_window *window, size_t *out_size);
/**
* Aim a window (CONFIGURE_WINDOW). FENCED: without FT_TT_PHASE1B_NOC_ENABLED this returns
* -EPERM and touches nothing.
* @return 0, -EPERM (fence), -EINVAL (NULL argument, or addr not a multiple of the window
* size), or the ioctl's -errno
*/
int ft_tt_kmd_window_aim(ft_tt_kmd_device *device, ft_tt_kmd_window *window,
const ft_tt_kmd_window_target *target);
/** Aim a window at one tile: a zeroed target with addr, x_end = x, y_end = y. Fenced the
* same way as ft_tt_kmd_window_aim(). */
int ft_tt_kmd_window_aim_unicast(ft_tt_kmd_device *device, ft_tt_kmd_window *window,
uint16_t x, uint16_t y, uint64_t addr);
#endif /* FT_TT_KMD_H */