194 lines
6.7 KiB
C
194 lines
6.7 KiB
C
/* SPDX-License-Identifier: AGPL-3.0-or-later */
|
|
/* Copyright (C) 2026 David (Corey) Herrera */
|
|
/**
|
|
* @file gpu_owner_util.h
|
|
* @brief Shared helpers for the multi-die GPU resource owner: GK210 sysfs
|
|
* enumeration + driver_override blocking, nvidia load-once, a dlopen'd CUDA
|
|
* driver-API table, and the slow_add die-pattern compute helpers.
|
|
*
|
|
* These are de-static'd, collected copies of helpers that previously lived as
|
|
* file-private statics inside barswap/tests/worker_switch.c and
|
|
* barswap/tests/compute_persist.c. On a host with no nvidia/libcuda (e.g. the
|
|
* Mac), gou_cuda_load_symbols() returns NULL — callers treat that as the SKIP
|
|
* path ("not on a K80 host").
|
|
*
|
|
* @status None
|
|
* @issues None
|
|
* @todo None
|
|
*/
|
|
|
|
#ifndef FOUNDRY_GPU_OWNER_UTIL_H
|
|
#define FOUNDRY_GPU_OWNER_UTIL_H
|
|
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
|
|
/* Max GK210 dies addressable on an 8-card K80 host (8 cards x 2 dies). */
|
|
#define GOU_MAX_DIES 16
|
|
|
|
/* ================================================================
|
|
* CUDA driver API types (no cuda.h dependency) + dlopen'd symbol table.
|
|
* ================================================================ */
|
|
|
|
typedef int CUresult;
|
|
typedef int CUdevice;
|
|
typedef void *CUcontext;
|
|
typedef void *CUmodule;
|
|
typedef void *CUfunction;
|
|
typedef void *CUstream;
|
|
typedef unsigned long long CUdeviceptr;
|
|
|
|
/*
|
|
* Resolved CUDA driver-API entry points. Function-pointer members mirror the
|
|
* subset of libcuda the owner needs; _v2 ABI variants are loaded for the calls
|
|
* that have them (see gou_cuda_load_symbols).
|
|
*/
|
|
typedef struct gou_cuda {
|
|
CUresult (*cuInit)(unsigned);
|
|
CUresult (*cuDeviceGetCount)(int*);
|
|
CUresult (*cuDeviceGet)(CUdevice*,int);
|
|
CUresult (*cuCtxCreate)(CUcontext*,unsigned,CUdevice);
|
|
CUresult (*cuCtxDestroy)(CUcontext);
|
|
CUresult (*cuCtxSetCurrent)(CUcontext);
|
|
CUresult (*cuCtxGetCurrent)(CUcontext*);
|
|
CUresult (*cuCtxSynchronize)(void);
|
|
CUresult (*cuMemAlloc)(CUdeviceptr*,size_t);
|
|
CUresult (*cuMemFree)(CUdeviceptr);
|
|
CUresult (*cuMemcpyHtoD)(CUdeviceptr,const void*,size_t);
|
|
CUresult (*cuMemcpyDtoH)(void*,CUdeviceptr,size_t);
|
|
CUresult (*cuMemGetInfo)(size_t*,size_t*);
|
|
CUresult (*cuModuleLoadData)(CUmodule*,const void*);
|
|
CUresult (*cuModuleGetFunction)(CUfunction*,CUmodule,const char*);
|
|
CUresult (*cuLaunchKernel)(CUfunction,unsigned,unsigned,unsigned,unsigned,unsigned,unsigned,unsigned,CUstream,void**,void**);
|
|
} gou_cuda;
|
|
|
|
/**
|
|
* Resolve the CUDA driver API by dlopen'ing libcuda and dlsym'ing every entry
|
|
* point into a file-static gou_cuda table (resolved once, idempotent).
|
|
*
|
|
* Tries libcuda.so.1 then libcuda.so. If neither opens (e.g. on the Mac) the
|
|
* function returns NULL — the SKIP path callers treat as "not on a K80 host".
|
|
* If any required symbol fails to resolve it also returns NULL.
|
|
*
|
|
* @return Pointer to the resolved table, or NULL if libcuda is unavailable
|
|
* or a required symbol is missing. The table is owned by this module.
|
|
*
|
|
* Thread-safe: no (lazy init of a shared static)
|
|
* Reentrant: no
|
|
* Signal-safe: no
|
|
*/
|
|
const gou_cuda *gou_cuda_load_symbols(void);
|
|
|
|
/* ================================================================
|
|
* GK210 enumeration + driver_override protocol (sysfs).
|
|
* ================================================================ */
|
|
|
|
/**
|
|
* Discover GK210 device BDFs from sysfs (vendor 0x10de, device 0x102d), sort
|
|
* them by BDF string, and cache them file-statically.
|
|
*
|
|
* @return Number of GK210 devices found (also queryable via gou_num_gk210).
|
|
*/
|
|
int gou_discover_gk210s(void);
|
|
|
|
/**
|
|
* @return Number of GK210 devices cached by the last gou_discover_gk210s().
|
|
*/
|
|
int gou_num_gk210(void);
|
|
|
|
/**
|
|
* @param index Index into the cached GK210 BDF table.
|
|
* @return The BDF string at index, or NULL if index is out of range.
|
|
*/
|
|
const char *gou_gk210_bdf(int index);
|
|
|
|
/**
|
|
* Read BAR 0 start address from a PCI device's sysfs `resource` file.
|
|
*
|
|
* @param bdf PCI BDF string (e.g. "0000:03:00.0").
|
|
* @return BAR 0 start address, or 0 if unreadable/unmapped.
|
|
*/
|
|
uint64_t gou_read_bar0(const char *bdf);
|
|
|
|
/**
|
|
* Find which cached GK210 currently has BARs programmed into the MMIO slot.
|
|
* Only the acquired die has a non-zero BAR 0 (the rest are zeroed on release).
|
|
*
|
|
* @return Index into the cached BDF table, or -1 if none found.
|
|
*/
|
|
int gou_find_acquired_bdf(void);
|
|
|
|
/**
|
|
* Write a NUL-terminated string to a sysfs attribute (O_WRONLY, write, close).
|
|
* The caller must include any trailing newline the attribute expects.
|
|
*
|
|
* @param path Absolute sysfs attribute path.
|
|
* @param str NUL-terminated string to write.
|
|
* @return 0 on success, -1 on error.
|
|
*/
|
|
int gou_sysfs_write(const char *path, const char *str);
|
|
|
|
/**
|
|
* Set (or clear) a device's driver_override. Pass "" to clear the override
|
|
* (allow nvidia to bind), or "none" to block binding.
|
|
*
|
|
* @param bdf PCI BDF string of the device.
|
|
* @param value Override value; "" clears it.
|
|
*/
|
|
void gou_set_driver_override(const char *bdf, const char *value);
|
|
|
|
/**
|
|
* Block every cached GK210 except the one at bdf_index, so nvidia only binds
|
|
* the acquired die.
|
|
*
|
|
* @param bdf_index Index of the die to leave bindable.
|
|
*/
|
|
void gou_block_all_except(int bdf_index);
|
|
|
|
/**
|
|
* Clear the driver_override on every cached GK210.
|
|
*/
|
|
void gou_unblock_all(void);
|
|
|
|
/**
|
|
* Load the nvidia and nvidia_uvm modules ONCE for the whole run (via modprobe
|
|
* --ignore-install). After this returns the modules stay resident.
|
|
*
|
|
* @return 0 on success, -1 if a modprobe fails.
|
|
*/
|
|
int gou_load_nvidia_once(void);
|
|
|
|
/* ================================================================
|
|
* Compute payload — slow_add PTX + die-pattern helpers.
|
|
* ================================================================ */
|
|
|
|
/*
|
|
* Embedded PTX kernel (entry "slow_add", .target sm_37): out[i] = in[i] + iters,
|
|
* exact in float32 while values stay under 2^24.
|
|
*/
|
|
extern const char *const gou_slow_add_ptx;
|
|
|
|
/**
|
|
* Fill a host buffer with a distinct per-die input pattern. Values are kept in
|
|
* 0..4095 so out = in + iters stays exact in float32.
|
|
*
|
|
* @param buf Destination buffer (n floats).
|
|
* @param n Element count.
|
|
* @param seed Per-die seed selecting the pattern.
|
|
*/
|
|
void gou_fill_die_pattern(float *buf, int n, uint32_t seed);
|
|
|
|
/**
|
|
* Verify a buffer holds the slow_add result for a seed: every element must
|
|
* equal gou_fill_die_pattern(seed)'s value + iters.
|
|
*
|
|
* @param buf Buffer to check (n floats).
|
|
* @param n Element count.
|
|
* @param seed Per-die seed the pattern was generated from.
|
|
* @param iters Number of +1.0 adds the kernel applied.
|
|
* @return 1 if every element matches in[i] + iters, else 0.
|
|
*/
|
|
int gou_verify_die_pattern(const float *buf, int n, uint32_t seed, int iters);
|
|
|
|
#endif /* FOUNDRY_GPU_OWNER_UTIL_H */
|