192 lines
5.4 KiB
C
192 lines
5.4 KiB
C
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <dirent.h>
|
|
#include <stdint.h>
|
|
#include <math.h>
|
|
|
|
#include "blackwell-sensors.h"
|
|
|
|
/* Number of die sensors, 4 for Blackwell */
|
|
#define BLACKWELL_NUM_DIE_SENSORS 4
|
|
/* Memory spacing between DRAM FBPA blocks */
|
|
#define BLACKWELL_FBPA_STRIDE 0x4000
|
|
/* Maximum count of FBPA blocks, technically up to 18 but no consumer card has more than 8 */
|
|
#define BLACKWELL_MAX_NUM_FBPA 9
|
|
|
|
/* Yeah I know this is duplicated */
|
|
#define HEADER_COLOR_START "\x1b[36m"
|
|
#define HEADER_COLOR_END "\x1b[39m"
|
|
|
|
static float read_temp_sensor(void *addr);
|
|
static int read_dram_temp_sensor(void *addr);
|
|
|
|
struct blackwell_card_info {
|
|
char *card_name;
|
|
unsigned short vendor_id;
|
|
unsigned short device_id;
|
|
int die_temp_offset[BLACKWELL_NUM_DIE_SENSORS];
|
|
int sys_temp_offset;
|
|
int dram_temp_offset_start;
|
|
int clamshell; /* If the card has dual-side ram, if not then half the DRAM temps are repeated */
|
|
};
|
|
|
|
static struct blackwell_card_info blackwell_card_list[] =
|
|
{
|
|
{"NVIDIA RTX PRO 6000 Blackwell Workstation Edition", NVIDIA_VEN, NVIDIA_RTXPRO6000_WORKSTATION_DEV, {0xAD0A90, 0xAD0A94, 0xAD0A98, 0xAD0A9C}, 0xAD06EC, 0x9024C0, true}
|
|
};
|
|
|
|
|
|
/* Search all i2c device files for ones are on a PCI device of a supported GPU,
|
|
and respond with the correct iCX3 version information */
|
|
int find_blackwell_gpus(struct card_info *infos, int num_gpus, int max_gpus)
|
|
{
|
|
char pci_devices_path[PATH_MAX];
|
|
char device_path[PATH_MAX];
|
|
char dev_file[PATH_MAX];
|
|
char pci_path[PATH_MAX];
|
|
char *pci_addr;
|
|
|
|
DIR *dir;
|
|
struct dirent *ent;
|
|
|
|
unsigned short pci_vendor, pci_device = 0;
|
|
|
|
/* Start looking for PCI */
|
|
strcpy(pci_devices_path, "/sys/bus/pci/devices/");
|
|
dir = opendir(pci_devices_path);
|
|
|
|
/* make sure we can open the PCI device */
|
|
if(dir == NULL)
|
|
return num_gpus;
|
|
|
|
/* loop over all PCI devices */
|
|
while((ent = readdir(dir)) != NULL)
|
|
{
|
|
strcpy(device_path, pci_devices_path);
|
|
strcat(device_path, ent->d_name);
|
|
|
|
pci_vendor = read_pci_id(device_path, "/vendor");
|
|
pci_device = read_pci_id(device_path, "/device");
|
|
|
|
/* See if it's a supported Blackwell card*/
|
|
for (int i = 0; i < (sizeof(blackwell_card_list) / sizeof(struct blackwell_card_info)); i++) {
|
|
|
|
if (pci_vendor == blackwell_card_list[i].vendor_id &&
|
|
pci_device == blackwell_card_list[i].device_id) {
|
|
|
|
infos[num_gpus].card_name = blackwell_card_list[i].card_name;
|
|
infos[num_gpus].pci_id = strdup(ent->d_name);
|
|
infos[num_gpus].pci_dev_path = strdup(device_path);
|
|
infos[num_gpus].pci_device_id = pci_device;
|
|
infos[num_gpus].i2c_dev_path = NULL;
|
|
infos[num_gpus].i2c_fd = -1;
|
|
|
|
mmap_bar0(&infos[num_gpus]);
|
|
num_gpus++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (num_gpus == max_gpus)
|
|
break;
|
|
}
|
|
|
|
return num_gpus;
|
|
}
|
|
|
|
void print_blackwell_info(int compact, int overwrite, struct card_info *gpu)
|
|
{
|
|
if (gpu->bar0_mmap == NULL)
|
|
return;
|
|
|
|
for (int i = 0; i < (sizeof(blackwell_card_list) / sizeof(struct blackwell_card_info)); i++) {
|
|
if (!compact)
|
|
printf("%s @ %s\n", gpu->card_name, gpu->pci_id);
|
|
float temp;
|
|
|
|
if (blackwell_card_list[i].device_id == gpu->pci_device_id) {
|
|
/* Print die sensors */
|
|
if (compact)
|
|
printf("%sDIE%s", HEADER_COLOR_START, HEADER_COLOR_END);
|
|
for (int die_sens_num = 0; die_sens_num < BLACKWELL_NUM_DIE_SENSORS; die_sens_num++) {
|
|
temp = read_temp_sensor(gpu->bar0_mmap + blackwell_card_list[i].die_temp_offset[die_sens_num]);
|
|
if (compact)
|
|
printf(" %3.0f", temp);
|
|
else
|
|
printf("Die %d: %+.1f°C\n", die_sens_num, temp);
|
|
}
|
|
|
|
/* Sys temp */
|
|
temp = read_temp_sensor(gpu->bar0_mmap + blackwell_card_list[i].sys_temp_offset);
|
|
if (compact)
|
|
printf(" %sSYS%s %3.0f", HEADER_COLOR_START, temp, HEADER_COLOR_END);
|
|
else
|
|
printf("System: %+.1f°C\n", temp);
|
|
|
|
/* DRAM temps */
|
|
int dram_num = 0;
|
|
int num_channels = blackwell_card_list[i].clamshell ? 4 : 2;
|
|
int dram_max = 0;
|
|
int dram_min = 120;
|
|
int dram_total = 0.0;
|
|
for (int fbpa_num = 0; fbpa_num < BLACKWELL_MAX_NUM_FBPA; fbpa_num++) {
|
|
for (int chan_num = 0; chan_num < num_channels; chan_num++) {
|
|
temp = read_dram_temp_sensor(gpu->bar0_mmap +
|
|
blackwell_card_list[i].dram_temp_offset_start +
|
|
BLACKWELL_FBPA_STRIDE * fbpa_num +
|
|
0x4 * chan_num +
|
|
2);
|
|
|
|
if (temp == 0.0)
|
|
break;
|
|
|
|
dram_max = (temp > dram_max) ? temp : dram_max;
|
|
dram_min = (temp < dram_min) ? temp : dram_min;
|
|
dram_total += temp;
|
|
|
|
if (!compact)
|
|
printf("DRAM %i: %+.0f°C\n", dram_num, temp);
|
|
dram_num++;
|
|
}
|
|
}
|
|
if (compact) {
|
|
printf(" %sDRAM HI%s %3.0f %sAVG%s %5.1f %sLO%s %3.0f",
|
|
HEADER_COLOR_START,
|
|
HEADER_COLOR_END,
|
|
(float)dram_max,
|
|
HEADER_COLOR_START,
|
|
HEADER_COLOR_END,
|
|
(float)dram_total/dram_num,
|
|
HEADER_COLOR_START,
|
|
HEADER_COLOR_END,
|
|
(float)dram_min);
|
|
} else {
|
|
printf("DRAM average: %+.1f°C\n", (float)dram_total/dram_num);
|
|
printf("DRAM min: %+.0f°C\n", (float)dram_min);
|
|
printf("DRAM max: %+.0f°C\n", (float)dram_max);
|
|
}
|
|
if (overwrite)
|
|
printf("\x1b[1G");
|
|
else
|
|
printf("\n");
|
|
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
float read_temp_sensor(void *addr)
|
|
{
|
|
return (*(uint16_t *)addr) / (float)0x100;
|
|
}
|
|
|
|
int read_dram_temp_sensor(void *addr)
|
|
{
|
|
uint16_t raw = *(uint16_t *)addr;
|
|
if (raw == 0xBADF)
|
|
return 0.0;
|
|
|
|
int code = (raw >> 8) & 0xFF;
|
|
if (code > 80) code = 80;
|
|
return (code > 19) ? (code - 20) * 2 : -(40 - code * 2);
|
|
} |