diff --git a/evga-card.c b/evga-card.c index 88102b3..b256a12 100644 --- a/evga-card.c +++ b/evga-card.c @@ -62,7 +62,8 @@ int find_evga_gpu_i2cs(struct card_info *infos, int max_gpus) /* Matched all PCI IDs, check for good firmware read */ strcpy(dev_file, "/dev/"); strcat(dev_file, ent->d_name); - if (check_for_icx3(dev_file)) { + infos[num_gpus].i2c_dev_path = dev_file; + if (icx3_init(&infos[num_gpus]) > 0) { /* Write our card info into the provided struct array */ infos[num_gpus].card_name = evga_pci_ids[i].card_name; infos[num_gpus].pci_id = pci_addr; diff --git a/evga-card.h b/evga-card.h index f8a10d3..9347457 100644 --- a/evga-card.h +++ b/evga-card.h @@ -1,3 +1,6 @@ +#ifndef EVGA_CARD_H +#define EVGA_CARD_H + #define NVIDIA_VEN 0x10DE #define NVIDIA_RTX3060_DEV 0x2503 @@ -85,6 +88,7 @@ struct card_info { char *pci_id; char *i2c_dev_path; int i2c_fd; + int product_id; }; struct gpu_pci_info { @@ -159,3 +163,5 @@ static struct gpu_pci_info evga_pci_ids[] = int find_evga_gpu_i2cs(struct card_info *infos, int max_gpus); unsigned short read_pci_id(char *device_path, char *field); char *read_nvidia_pci_address(char *device_path); + +#endif diff --git a/evga-icx.c b/evga-icx.c index b6d7b32..d60ce62 100644 --- a/evga-icx.c +++ b/evga-icx.c @@ -85,7 +85,7 @@ int main (int argc, char **argv) } gpu_count = find_evga_gpu_i2cs(gpus, MAX_GPUS); - + if (gpu_count == -1) { printf("Error scanning I2C devices\n"); return -1; @@ -105,15 +105,13 @@ int main (int argc, char **argv) for (int i = 0; i < gpu_count; i++){ for (int j = 0; j < ICX3_MAX_FANS; j++) { if (fan_speed[j] != NULL) - set_fan(j, fan_speed[j], gpus[i].i2c_dev_path); - /* printf("gpu %d fan %d : %s\n", i, j, fan_speed[j]); */ + set_fan(j, fan_speed[j], &gpus[i]); } } } else if (gpu_num <= gpu_count - 1) { for (int j = 0; j < ICX3_MAX_FANS; j++) { if (fan_speed[j] != NULL) - set_fan(gpu_num, fan_speed[j], gpus[gpu_num].i2c_dev_path); - /* printf("gpu %d fan %d : %s\n", gpu_num, j, fan_speed[j]);*/ + set_fan(gpu_num, fan_speed[j], &gpus[gpu_num]); } } @@ -133,13 +131,13 @@ int main (int argc, char **argv) void print_gpu_info(int gpu_num, struct card_info gpus[], int compact) { if (compact) { printf("#%d ", gpu_num); - print_icx3_fans_oneline(gpus[gpu_num].i2c_dev_path); - print_icx3_temps_oneline(gpus[gpu_num].i2c_dev_path); + print_icx3_fans_oneline(&gpus[gpu_num]); + print_icx3_temps_oneline(&gpus[gpu_num]); printf("\n"); } else { printf("#%d: %s (%s) @ %s\n", gpu_num, gpus[gpu_num].card_name, gpus[gpu_num].i2c_dev_path, gpus[gpu_num].pci_id); - print_icx3_fans(gpus[gpu_num].i2c_dev_path); - print_icx3_temps(gpus[gpu_num].i2c_dev_path); + print_icx3_fans(&gpus[gpu_num]); + print_icx3_temps(&gpus[gpu_num]); printf("\n"); } diff --git a/icx3.c b/icx3.c index 17f5d4b..7c460d1 100644 --- a/icx3.c +++ b/icx3.c @@ -9,32 +9,42 @@ #include "icx3.h" -/* Check an I2C device file for an ICX3 controller, returns the product id, or ICX3_PRODUCT_NONE on bad read. */ -enum icx3_product_id check_for_icx3(char *i2c_dev_path) +int icx3_init(struct card_info *card) { char data[I2C_SMBUS_BLOCK_MAX] = {}; - int fd, read_result; + int read_result; struct icx3_info *temp_info; - fd = open_i2c_dev(i2c_dev_path); + int fd = open(card->i2c_dev_path, O_RDONLY); + if (fd == -1) - return ICX3_PRODUCT_NONE; + return -1; + + if (ioctl(fd, I2C_SLAVE, ICX3_I2C_ADDR) < 0) { + close(fd); + return -1; + } read_result = i2c_smbus_read_i2c_block_data(fd, ICX3_REG_READINFORMATION, ICX3_READINFORMATION_SIZE, data); - close(fd); if (read_result == ICX3_READINFORMATION_SIZE) { temp_info = (struct icx3_info*)&data; - if (temp_info->slave_address == ICX3_I2C_ADDR) - return temp_info->product_id; + if (temp_info->slave_address == ICX3_I2C_ADDR) { + card->product_id = temp_info->product_id; + card->i2c_fd = fd; + return fd; + } else { + close(fd); + return -1; + } } - - return ICX3_PRODUCT_NONE; + + return -1; } -void print_icx3_fans(char *i2c_dev_path) +void print_icx3_fans(struct card_info *card) { struct icx3_fan_control fans[ICX3_MAX_FANS]; - get_fan_status(fans, i2c_dev_path); + get_fan_status(fans, card); for (int i=0; i < ICX3_MAX_FANS; i++) { printf("%s: %d RPM (%d/%d%%, %s)\n", @@ -47,10 +57,10 @@ void print_icx3_fans(char *i2c_dev_path) } } -void print_icx3_fans_oneline(char *i2c_dev_path) +void print_icx3_fans_oneline(struct card_info *card) { struct icx3_fan_control fans[ICX3_MAX_FANS]; - get_fan_status(fans, i2c_dev_path); + get_fan_status(fans, card); printf("FAN"); for (int i=0; i < ICX3_MAX_FANS; i++) { @@ -59,11 +69,11 @@ void print_icx3_fans_oneline(char *i2c_dev_path) printf("%%"); } -void print_icx3_temps(char *i2c_dev_path) +void print_icx3_temps(struct card_info *card) { float temps[ICX3_NUM_TEMP_SENSORS]; - get_temp_sensors(temps, i2c_dev_path); + get_temp_sensors(temps, card); for (int i=0; iproduct_id; /* From ICX3TotalFanCtrl.cs */ switch(product_id) { @@ -142,47 +152,34 @@ void get_available_fans(char *i2c_dev_path, char *fans_avail) } } -void get_fan_status(struct icx3_fan_control *fans, char *i2c_dev_path) +void get_fan_status(struct icx3_fan_control *fans, struct card_info *card) { char data[I2C_SMBUS_BLOCK_MAX] = {}; - int fd, read_result; + int read_result; - /* First thing is to check for the product ID to figure out how many fans we have */ char fans_avail[ICX3_MAX_FANS] = {0}; - get_available_fans(i2c_dev_path, fans_avail); - - fd = open_i2c_dev(i2c_dev_path); - if (fd == -1) - return; - + get_available_fans(fans_avail, card); + for (int i=0; i < ICX3_MAX_FANS; i++) { if (!fans_avail[i]) { continue; } - read_result = i2c_smbus_read_i2c_block_data(fd, ICX3_REG_FANCONTROL + i, ICX3_FANCONTROL_SIZE, data); + read_result = i2c_smbus_read_i2c_block_data(card->i2c_fd, ICX3_REG_FANCONTROL + i, ICX3_FANCONTROL_SIZE, data); if (read_result != ICX3_FANCONTROL_SIZE) { - close(fd); return; } memcpy(&fans[i], &data, sizeof(struct icx3_fan_control)); } - - close(fd); } -void get_temp_sensors(float *temps, char *i2c_dev_path) +void get_temp_sensors(float *temps, struct card_info *card) { char data[I2C_SMBUS_BLOCK_MAX] = {}; - int fd, read_result; + int read_result; struct icx3_temp_sensors *temp_sensors; - - fd = open_i2c_dev(i2c_dev_path); - if (fd == -1) - return; - - read_result = i2c_smbus_read_i2c_block_data(fd, ICX3_REG_TEMPSENSOR, ICX3_TEMPSENSOR_SIZE, data); - close(fd); + + read_result = i2c_smbus_read_i2c_block_data(card->i2c_fd, ICX3_REG_TEMPSENSOR, ICX3_TEMPSENSOR_SIZE, data); if (read_result != ICX3_TEMPSENSOR_SIZE) return; temp_sensors = (struct icx3_temp_sensors*) &data; @@ -198,54 +195,34 @@ void get_temp_sensors(float *temps, char *i2c_dev_path) } } -int open_i2c_dev(char *i2c_dev_path) -{ - int fd = open(i2c_dev_path, O_RDONLY); - - /* Error silently here because we should have already checked we can read the i2c in check_for_icx3() */ - if (fd == -1) - return -1; - - if (ioctl(fd, I2C_SLAVE, ICX3_I2C_ADDR) < 0) { - close(fd); - return -1; - } - return fd; -} - -void enable_write(int enable, char *i2c_dev_path) -{ - int fd = open_i2c_dev(i2c_dev_path); - if (fd == -1) - return; - +void enable_write(int enable, struct card_info *card) +{ unsigned char *data; if (enable) data = icx3_write_enable; else data = icx3_write_disable; /* Enable or disable write */ - i2c_smbus_write_i2c_block_data(fd, ICX3_REG_ENABLEWRITE, ICX3_ENABLEWRITE_SIZE, data); + i2c_smbus_write_i2c_block_data(card->i2c_fd, ICX3_REG_ENABLEWRITE, ICX3_ENABLEWRITE_SIZE, data); /* Read back the result to verify */ unsigned char read_result[ICX3_ENABLEWRITE_SIZE]; int write_ok = 0; - i2c_smbus_read_i2c_block_data(fd, ICX3_REG_ENABLEWRITE, ICX3_ENABLEWRITE_SIZE, read_result); + i2c_smbus_read_i2c_block_data(card->i2c_fd, ICX3_REG_ENABLEWRITE, ICX3_ENABLEWRITE_SIZE, read_result); if (enable) write_ok = (read_result[1] == 0xFC); else write_ok = (read_result[1] == 0xFE); if (!write_ok) - printf("Unable to enable/disable write on %s\n", i2c_dev_path); - + printf("Unable to enable/disable write on %s\n", card->i2c_dev_path); } /* Sets a given fan on the GPU according to a string setting 'auto' resets the fan to default (fans 1-2 go to GPU control, 3-4 to +0 RPM offset from GPU control) A number without a sign (e.g. 50) manually sets the fan to a given % duty cycle A number with a sign (e.g. +500) sets the fan to run at an RPM offset from GPU control */ -void set_fan(int fan, char *setting, char *i2c_dev_path) +void set_fan(int fan, char *setting, struct card_info *card) { char fans_avail[ICX3_MAX_FANS] = {0}; @@ -256,15 +233,11 @@ void set_fan(int fan, char *setting, char *i2c_dev_path) int write_result; /* Check to make sure we're setting a valid fan */ - get_available_fans(i2c_dev_path, fans_avail); + get_available_fans(fans_avail, card); if (fans_avail[fan] == 0) { printf("Fan %d does not exist on this card \n", fan); return; } - - int fp = open_i2c_dev(i2c_dev_path); - if (fp == -1) - return; fan_control.length = ICX3_FANCONTROL_SIZE - 1; if (strcmp(setting, "auto") == 0) { @@ -283,16 +256,15 @@ void set_fan(int fan, char *setting, char *i2c_dev_path) fan_control.duty = atoi(setting); } - enable_write(1, i2c_dev_path); + enable_write(1, card); - i2c_smbus_write_i2c_block_data(fp, reg, ICX3_FANCONTROL_SIZE, (char *)&fan_control); + i2c_smbus_write_i2c_block_data(card->i2c_fd, reg, ICX3_FANCONTROL_SIZE, (char *)&fan_control); /* Read back data and verify we set the fan properly */ - i2c_smbus_read_i2c_block_data(fp, reg, ICX3_FANCONTROL_SIZE, (char *)&fan_readback); + i2c_smbus_read_i2c_block_data(card->i2c_fd, reg, ICX3_FANCONTROL_SIZE, (char *)&fan_readback); if (fan_readback.fanmode != fan_control.fanmode || fan_readback.rpm_offset != fan_control.rpm_offset || fan_readback.duty != fan_control.duty) - printf("Error setting fan %d on %s\n", fan, i2c_dev_path); - close(fp); + printf("Error setting fan %d on %s\n", fan, card->i2c_fd); } diff --git a/icx3.h b/icx3.h index 08c3e60..d3e21ae 100644 --- a/icx3.h +++ b/icx3.h @@ -1,3 +1,8 @@ +#ifndef ICX3_H +#define ICX3_H + +#include "evga-card.h" + #define ICX3_I2C_ADDR 0x2D #define ICX3_REG_FANCONTROL 80 @@ -111,14 +116,15 @@ static char *icx3_temp_sensor_names[] = { "PWR5", }; -enum icx3_product_id check_for_icx3(char *i2c_dev_path); -void print_icx3_fans(char *i2c_dev_path); -void print_icx3_fans_oneline(char *i2c_dev_path); -void print_icx3_temps(char *i2c_dev_path); -void print_icx3_temps_oneline(char *i2c_dev_path); -void get_available_fans(char *i2c_dev_path, char *fans_avail); -void get_fan_status(struct icx3_fan_control *fans, char *i2c_dev_path); -void get_temp_sensors(float *temps, char *i2c_dev_path); -int open_i2c_dev(char *i2c_dev_path); -void enable_write(int enable, char *i2c_dev_path); -void set_fan(int fan, char *setting, char *i2c_dev_path); +int icx3_init(struct card_info *card); +void print_icx3_fans(struct card_info *card); +void print_icx3_fans_oneline(struct card_info *card); +void print_icx3_temps(struct card_info *card); +void print_icx3_temps_oneline(struct card_info *card); +void get_available_fans(char *fans_avail, struct card_info *card); +void get_fan_status(struct icx3_fan_control *fans, struct card_info *card); +void get_temp_sensors(float *temps, struct card_info *card); +void enable_write(int enable, struct card_info *card); +void set_fan(int fan, char *setting, struct card_info *card); + +#endif