4 Commits
Author SHA1 Message Date
moosecrap b7d22ed9ac Reduced number of NVML function calls 2025-02-21 10:59:31 -08:00
moosecrap 46eb773820 Readme update 2025-02-17 04:33:35 -08:00
moosecrap dc63b57bbe Cleanup for non-overwrite mode 2025-02-17 04:25:10 -08:00
moosecrap 7cd23384f6 Added --i2c command line option 2025-02-16 22:28:16 -08:00
6 changed files with 44 additions and 22 deletions
+4 -1
View File
@@ -3,7 +3,7 @@
This program allows you to read temperature sensors off of supported EVGA 30-series iCX3 video cards, as well as control the fans individually.
## Prerequisites
A supported EVGA 30-series iCX3 card. I have not done extensive testing but belive this is every model of their:
A supported EVGA 30-series card with iCX3. This includes:
* RTX 3060 Ti
* RTX 3070
* RTX 3070 Ti
@@ -14,6 +14,8 @@ A supported EVGA 30-series iCX3 card. I have not done extensive testing but bel
The number of fans supported depends, of course, on your particular model.
You must have the `i2c-dev` kernel module loaded with `modprobe i2c-dev`
Access to the `/dev/i2c` device files, which means either:
* Run as root, or
* Install udev rules to allow user access. If you have the OpenRGB udev rules installed to control the LEDs you already have this set up.
@@ -39,6 +41,7 @@ Note that when controlling fans directly through iCX3 they will fall offline fro
```text
Available options:
--i2c N : Only probe I2C bus N instead of all (may help with stuttering or freezing when probing I2C devices)
--gpu N : Control only GPU N instead of all supported cards
--fan SPEED : Set all fans at once to SPEED (see below)
--fanN SPEED : Set fan N (0-3) to SPEED
+10 -1
View File
@@ -8,7 +8,7 @@
/* 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_evga_gpu_i2cs(struct card_info *infos, int max_gpus)
int find_evga_gpu_i2cs(struct card_info *infos, int max_gpus, int i2c_bus)
{
char i2c_devices_path[NAME_MAX];
char device_path[NAME_MAX];
@@ -20,6 +20,7 @@ int find_evga_gpu_i2cs(struct card_info *infos, int max_gpus)
struct dirent *ent;
int num_gpus = 0;
int current_i2c_bus = -1;
unsigned short pci_vendor, pci_device, pci_subsystem_vendor, pci_subsystem_device = 0;
/* Start looking for I2C adapters in /sys/bus/i2c/devices/ */
@@ -37,6 +38,14 @@ int find_evga_gpu_i2cs(struct card_info *infos, int max_gpus)
if(strncmp(ent->d_name, "i2c-", 4) != 0)
continue;
/* Only probe the specific device given (if provided) */
if (i2c_bus >= 0) {
sscanf(ent->d_name, "i2c-%i", &current_i2c_bus);
if (current_i2c_bus != i2c_bus)
continue;
}
strcpy(device_path, i2c_devices_path);
strcat(device_path, ent->d_name);
+2 -1
View File
@@ -91,6 +91,7 @@ struct card_info {
int i2c_fd; /* File descriptor for the i2c device file, for re-use */
int product_id; /* EVGA internal product ID, as reported by the iCX3 controller */
unsigned int bar0; /* Address of the card's PCI base address register */
void *nvml_device; /* Pointer to nvmlDevice_t for use in NVML calls */
};
struct gpu_pci_info {
@@ -162,7 +163,7 @@ static struct gpu_pci_info evga_pci_ids[] =
{"EVGA GeForce RTX 3090 Ti FTW3 Ultra Gaming" , NVIDIA_VEN, NVIDIA_RTX3090TI_DEV, EVGA_SUB_VEN, EVGA_RTX3090TI_FTW3_ULTRA_GAMING_SUB_DEV }
};
int find_evga_gpu_i2cs(struct card_info *infos, int max_gpus);
int find_evga_gpu_i2cs(struct card_info *infos, int max_gpus, int i2c_bus);
unsigned short read_pci_id(char *device_path, char *field);
char *read_nvidia_pci_address(char *device_path);
+16 -3
View File
@@ -24,6 +24,7 @@ char *header_start = "";
char *header_end = "";
static const char helpstring[] = "Available options:\n"
"--i2c N : Only probe I2C bus N instead of all (may help with stuttering or freezing when probing I2C devices)\n"
"--gpu N : Control only GPU N instead of all supported cards\n"
"--fan SPEED : Set all fans at once to SPEED (see below)\n"
"--fanN SPEED : Set fan N (0-3) to SPEED\n"
@@ -47,13 +48,22 @@ int main (int argc, char **argv)
int print_info = 0;
int compact = 0;
int gpu_num = -1; /* Card to control */
int i2c_bus = -1;
int overwrite = 0;
unsigned int watch = 0;
char *fan_speed[ICX3_MAX_FANS] = {NULL};
/* Input parsing */
for (int i = 1; i < argc; i++){
if (strcmp(argv[i], "--gpu") == 0) {
if (strcmp(argv[i], "--i2c") == 0) {
i++;
if (i < argc) {
i2c_bus = atoi(argv[i]);
} else {
printf(helpstring);
return -1;
}
} else if (strcmp(argv[i], "--gpu") == 0) {
i++;
if (i < argc) {
gpu_num = atoi(argv[i]);
@@ -119,7 +129,7 @@ int main (int argc, char **argv)
if (overwrite && !compact)
overwrite = 0;
gpu_count = find_evga_gpu_i2cs(gpus, MAX_GPUS);
gpu_count = find_evga_gpu_i2cs(gpus, MAX_GPUS, i2c_bus);
if (gpu_count == -1) {
printf("Error scanning I2C devices\n");
@@ -153,6 +163,8 @@ int main (int argc, char **argv)
/* NVML init */
#ifdef USE_NVML
init_nvml();
for (int i = 0; i < gpu_count; i++)
get_nvml_handle(&gpus[i]);
#endif
/* PCI init for VRAM/hotspot temps */
@@ -164,7 +176,8 @@ int main (int argc, char **argv)
/* print sensor info */
if (print_info) {
do {
printf("\x1b[K"); /* Clear current console line (really just for overwrite mode) */
if (overwrite)
printf("\x1b[K"); /* Clear current console line */
if (gpu_num == -1) {
/* No GPU specified on command line, loop over all supported GPUs */
+10 -14
View File
@@ -10,15 +10,14 @@ void init_nvml()
printf("Could not init NVML: %s\n", nvmlErrorString(result));
}
int get_nvml_handle(nvmlDevice_t *device, struct card_info *card)
void get_nvml_handle(struct card_info *card)
{
nvmlReturn_t result;
result = nvmlDeviceGetHandleByPciBusId_v2(card->pci_id, device);
result = nvmlDeviceGetHandleByPciBusId_v2(card->pci_id, card->nvml_device);
if (result != NVML_SUCCESS) {
printf("Failed to get device handle for card at %s: %s\n", card->pci_id, nvmlErrorString(result));
return 0;
printf("Failed to get NVML device handle for card at %s: %s\n", card->pci_id, nvmlErrorString(result));
card->nvml_device = NULL;
}
return 1;
}
void print_nvml_clock_reason(int compact, struct card_info *card)
@@ -52,12 +51,11 @@ void print_nvml_clock_reason(int compact, struct card_info *card)
unsigned int get_nvml_temp(struct card_info *card)
{
nvmlDevice_t nvml_device;
if (!get_nvml_handle(&nvml_device, card))
if (card->nvml_device == NULL)
return 0;
unsigned int temp;
nvmlReturn_t result = nvmlDeviceGetTemperature(nvml_device, NVML_TEMPERATURE_GPU, &temp);
nvmlReturn_t result = nvmlDeviceGetTemperature(*(nvmlDevice_t*)(card->nvml_device), NVML_TEMPERATURE_GPU, &temp);
if (result != NVML_SUCCESS) {
printf("Failed to get temperature for card at %s: %s\n", card->pci_id, nvmlErrorString(result));
return 0;
@@ -67,12 +65,11 @@ unsigned int get_nvml_temp(struct card_info *card)
unsigned long long get_nvml_clock_reasons(struct card_info *card)
{
nvmlDevice_t nvml_device;
if (!get_nvml_handle(&nvml_device, card))
if (card->nvml_device == NULL)
return 0;
unsigned long long reasons;
nvmlReturn_t result = nvmlDeviceGetCurrentClocksEventReasons(nvml_device, &reasons) ;
nvmlReturn_t result = nvmlDeviceGetCurrentClocksEventReasons(*(nvmlDevice_t*)(card->nvml_device), &reasons) ;
if (result != NVML_SUCCESS) {
printf("Failed to get clock reasons for card at %s: %s\n", card->pci_id, nvmlErrorString(result));
return 0;
@@ -83,12 +80,11 @@ unsigned long long get_nvml_clock_reasons(struct card_info *card)
unsigned int get_nvml_mem_util(struct card_info *card)
{
nvmlDevice_t nvml_device;
if (!get_nvml_handle(&nvml_device, card))
if (card->nvml_device == NULL)
return 0;
nvmlUtilization_t util;
nvmlReturn_t result = nvmlDeviceGetUtilizationRates(nvml_device, &util);
nvmlReturn_t result = nvmlDeviceGetUtilizationRates(*(nvmlDevice_t*)(card->nvml_device), &util);
if (result != NVML_SUCCESS) {
printf("Failed to get clock reasons for card at %s: %s\n", card->pci_id, nvmlErrorString(result));
return 0;
+1 -1
View File
@@ -22,7 +22,7 @@ static struct clock_reason clock_reason_names[] =
};
void init_nvml();
int get_nvml_handle(nvmlDevice_t *device, struct card_info *card);
void get_nvml_handle(struct card_info *card);
void print_nvml_clock_reason(int compact, struct card_info *card);
unsigned int get_nvml_temp(struct card_info *card);
unsigned long long get_nvml_clock_reasons(struct card_info *card);