Compare commits
No commits in common. "4cb9ef42a6431056b541a804007ecab6ce3b5adc" and "73f7038eaa43bb3f60b2991791e5cac4ed455477" have entirely different histories.
4cb9ef42a6
...
73f7038eaa
@ -39,7 +39,6 @@ Available options:
|
|||||||
--reset : Reset all fans to their default mode
|
--reset : Reset all fans to their default mode
|
||||||
--sensors : Print sensor readings even if setting a fan speed
|
--sensors : Print sensor readings even if setting a fan speed
|
||||||
--compact : Print sensor reading in a compact one-line per card format
|
--compact : Print sensor reading in a compact one-line per card format
|
||||||
--watch N : Keep printing output every N seconds
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Examples:
|
### Examples:
|
||||||
|
21
evga-card.c
21
evga-card.c
@ -13,7 +13,6 @@ int find_evga_gpu_i2cs(struct card_info *infos, int max_gpus)
|
|||||||
char i2c_devices_path[NAME_MAX];
|
char i2c_devices_path[NAME_MAX];
|
||||||
char device_path[NAME_MAX];
|
char device_path[NAME_MAX];
|
||||||
char dev_file[NAME_MAX];
|
char dev_file[NAME_MAX];
|
||||||
char *pci_addr;
|
|
||||||
|
|
||||||
FILE *test_fd;
|
FILE *test_fd;
|
||||||
DIR *dir;
|
DIR *dir;
|
||||||
@ -40,11 +39,6 @@ int find_evga_gpu_i2cs(struct card_info *infos, int max_gpus)
|
|||||||
strcpy(device_path, i2c_devices_path);
|
strcpy(device_path, i2c_devices_path);
|
||||||
strcat(device_path, ent->d_name);
|
strcat(device_path, ent->d_name);
|
||||||
|
|
||||||
/* Only check Nvidia devices */
|
|
||||||
pci_addr = read_nvidia_pci_address(device_path);
|
|
||||||
if (pci_addr == NULL)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* Read the PCI info for the underlying device */
|
/* Read the PCI info for the underlying device */
|
||||||
pci_vendor = read_pci_id(device_path, "/device/vendor");
|
pci_vendor = read_pci_id(device_path, "/device/vendor");
|
||||||
pci_device = read_pci_id(device_path, "/device/device");
|
pci_device = read_pci_id(device_path, "/device/device");
|
||||||
@ -62,11 +56,10 @@ int find_evga_gpu_i2cs(struct card_info *infos, int max_gpus)
|
|||||||
/* Matched all PCI IDs, check for good firmware read */
|
/* Matched all PCI IDs, check for good firmware read */
|
||||||
strcpy(dev_file, "/dev/");
|
strcpy(dev_file, "/dev/");
|
||||||
strcat(dev_file, ent->d_name);
|
strcat(dev_file, ent->d_name);
|
||||||
infos[num_gpus].i2c_dev_path = dev_file;
|
if (check_for_icx3(dev_file)) {
|
||||||
if (icx3_init(&infos[num_gpus]) > 0) {
|
|
||||||
/* Write our card info into the provided struct array */
|
/* Write our card info into the provided struct array */
|
||||||
infos[num_gpus].card_name = evga_pci_ids[i].card_name;
|
infos[num_gpus].card_name = evga_pci_ids[i].card_name;
|
||||||
infos[num_gpus].pci_id = pci_addr;
|
infos[num_gpus].pci_id = read_nvidia_pci_address(device_path);
|
||||||
infos[num_gpus].i2c_dev_path = calloc(strlen(dev_file) + 1, sizeof(char));
|
infos[num_gpus].i2c_dev_path = calloc(strlen(dev_file) + 1, sizeof(char));
|
||||||
strcpy(infos[num_gpus].i2c_dev_path, dev_file);
|
strcpy(infos[num_gpus].i2c_dev_path, dev_file);
|
||||||
num_gpus++;
|
num_gpus++;
|
||||||
@ -118,18 +111,12 @@ char *read_nvidia_pci_address(char *device_path)
|
|||||||
|
|
||||||
FILE *fp = fopen(file_path, "r");
|
FILE *fp = fopen(file_path, "r");
|
||||||
|
|
||||||
if (fp == NULL) {
|
if (fp == NULL)
|
||||||
free(ret);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
|
||||||
|
|
||||||
fscanf(fp, "NVIDIA i2c adapter %*u at %16s", ret);
|
fscanf(fp, "NVIDIA i2c adapter %*u at %16s", ret);
|
||||||
fclose(fp);
|
|
||||||
|
|
||||||
if (strlen(ret) == 0) {
|
fclose(fp);
|
||||||
free(ret);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,3 @@
|
|||||||
#ifndef EVGA_CARD_H
|
|
||||||
#define EVGA_CARD_H
|
|
||||||
|
|
||||||
#define NVIDIA_VEN 0x10DE
|
#define NVIDIA_VEN 0x10DE
|
||||||
|
|
||||||
#define NVIDIA_RTX3060_DEV 0x2503
|
#define NVIDIA_RTX3060_DEV 0x2503
|
||||||
@ -87,8 +84,7 @@ struct card_info {
|
|||||||
char *card_name;
|
char *card_name;
|
||||||
char *pci_id;
|
char *pci_id;
|
||||||
char *i2c_dev_path;
|
char *i2c_dev_path;
|
||||||
int i2c_fd;
|
int fd;
|
||||||
int product_id;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct gpu_pci_info {
|
struct gpu_pci_info {
|
||||||
@ -163,5 +159,3 @@ static struct gpu_pci_info evga_pci_ids[] =
|
|||||||
int find_evga_gpu_i2cs(struct card_info *infos, int max_gpus);
|
int find_evga_gpu_i2cs(struct card_info *infos, int max_gpus);
|
||||||
unsigned short read_pci_id(char *device_path, char *field);
|
unsigned short read_pci_id(char *device_path, char *field);
|
||||||
char *read_nvidia_pci_address(char *device_path);
|
char *read_nvidia_pci_address(char *device_path);
|
||||||
|
|
||||||
#endif
|
|
||||||
|
34
evga-icx.c
34
evga-icx.c
@ -20,8 +20,7 @@ static const char helpstring[] = "Available options:\n"
|
|||||||
" [+/-]N to set that fan to an RPM offset from the GPU-controlled speed\n"
|
" [+/-]N to set that fan to an RPM offset from the GPU-controlled speed\n"
|
||||||
"--reset : Reset all fans to their default mode\n"
|
"--reset : Reset all fans to their default mode\n"
|
||||||
"--sensors : Print sensor readings even if setting a fan speed \n"
|
"--sensors : Print sensor readings even if setting a fan speed \n"
|
||||||
"--compact : Print sensor reading in a compact one-line per card format\n"
|
"--compact : Print sensor reading in a compact one-line per card format\n";
|
||||||
"--watch N : Keep printing output every N seconds\n";
|
|
||||||
|
|
||||||
void print_gpu_info(int gpu_num, struct card_info gpus[], int compact);
|
void print_gpu_info(int gpu_num, struct card_info gpus[], int compact);
|
||||||
|
|
||||||
@ -32,7 +31,6 @@ int main (int argc, char **argv)
|
|||||||
int print_info = 0;
|
int print_info = 0;
|
||||||
int compact = 0;
|
int compact = 0;
|
||||||
int gpu_num = -1; /* Card to control */
|
int gpu_num = -1; /* Card to control */
|
||||||
int watch = -1;
|
|
||||||
char *fan_speed[ICX3_MAX_FANS] = {NULL};
|
char *fan_speed[ICX3_MAX_FANS] = {NULL};
|
||||||
|
|
||||||
/* Input parsing */
|
/* Input parsing */
|
||||||
@ -71,14 +69,6 @@ int main (int argc, char **argv)
|
|||||||
print_info = 1;
|
print_info = 1;
|
||||||
} else if (strcmp(argv[i], "--compact") == 0) {
|
} else if (strcmp(argv[i], "--compact") == 0) {
|
||||||
compact = 1;
|
compact = 1;
|
||||||
} else if (strcmp(argv[i], "--watch") == 0) {
|
|
||||||
i++;
|
|
||||||
if (i < argc) {
|
|
||||||
watch = atoi(argv[i]);
|
|
||||||
} else {
|
|
||||||
printf(helpstring);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
printf(helpstring);
|
printf(helpstring);
|
||||||
return 0;
|
return 0;
|
||||||
@ -95,7 +85,7 @@ int main (int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
gpu_count = find_evga_gpu_i2cs(gpus, MAX_GPUS);
|
gpu_count = find_evga_gpu_i2cs(gpus, MAX_GPUS);
|
||||||
|
|
||||||
if (gpu_count == -1) {
|
if (gpu_count == -1) {
|
||||||
printf("Error scanning I2C devices\n");
|
printf("Error scanning I2C devices\n");
|
||||||
return -1;
|
return -1;
|
||||||
@ -115,18 +105,19 @@ int main (int argc, char **argv)
|
|||||||
for (int i = 0; i < gpu_count; i++){
|
for (int i = 0; i < gpu_count; i++){
|
||||||
for (int j = 0; j < ICX3_MAX_FANS; j++) {
|
for (int j = 0; j < ICX3_MAX_FANS; j++) {
|
||||||
if (fan_speed[j] != NULL)
|
if (fan_speed[j] != NULL)
|
||||||
set_fan(j, fan_speed[j], &gpus[i]);
|
set_fan(j, fan_speed[j], gpus[i].i2c_dev_path);
|
||||||
|
/* printf("gpu %d fan %d : %s\n", i, j, fan_speed[j]); */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (gpu_num <= gpu_count - 1) {
|
} else if (gpu_num <= gpu_count - 1) {
|
||||||
for (int j = 0; j < ICX3_MAX_FANS; j++) {
|
for (int j = 0; j < ICX3_MAX_FANS; j++) {
|
||||||
if (fan_speed[j] != NULL)
|
if (fan_speed[j] != NULL)
|
||||||
set_fan(gpu_num, fan_speed[j], &gpus[gpu_num]);
|
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]);*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* print sensor info */
|
/* print sensor info */
|
||||||
print:
|
|
||||||
if (print_info) {
|
if (print_info) {
|
||||||
if (gpu_num == -1) {
|
if (gpu_num == -1) {
|
||||||
for (int i = 0; i < gpu_count; i++){
|
for (int i = 0; i < gpu_count; i++){
|
||||||
@ -136,22 +127,19 @@ print:
|
|||||||
print_gpu_info(gpu_num, gpus, compact);
|
print_gpu_info(gpu_num, gpus, compact);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (watch > 0) {
|
|
||||||
sleep(watch);
|
|
||||||
goto print;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_gpu_info(int gpu_num, struct card_info gpus[], int compact) {
|
void print_gpu_info(int gpu_num, struct card_info gpus[], int compact) {
|
||||||
if (compact) {
|
if (compact) {
|
||||||
printf("#%d ", gpu_num);
|
printf("#%d ", gpu_num);
|
||||||
print_icx3_fans_oneline(&gpus[gpu_num]);
|
print_icx3_fans_oneline(gpus[gpu_num].i2c_dev_path);
|
||||||
print_icx3_temps_oneline(&gpus[gpu_num]);
|
print_icx3_temps_oneline(gpus[gpu_num].i2c_dev_path);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
} else {
|
} 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);
|
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]);
|
print_icx3_fans(gpus[gpu_num].i2c_dev_path);
|
||||||
print_icx3_temps(&gpus[gpu_num]);
|
print_icx3_temps(gpus[gpu_num].i2c_dev_path);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
128
icx3.c
128
icx3.c
@ -9,42 +9,32 @@
|
|||||||
|
|
||||||
#include "icx3.h"
|
#include "icx3.h"
|
||||||
|
|
||||||
int icx3_init(struct card_info *card)
|
/* 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)
|
||||||
{
|
{
|
||||||
char data[I2C_SMBUS_BLOCK_MAX] = {};
|
char data[I2C_SMBUS_BLOCK_MAX] = {};
|
||||||
int read_result;
|
int fd, read_result;
|
||||||
struct icx3_info *temp_info;
|
struct icx3_info *temp_info;
|
||||||
|
|
||||||
int fd = open(card->i2c_dev_path, O_RDONLY);
|
fd = open_i2c_dev(i2c_dev_path);
|
||||||
|
|
||||||
if (fd == -1)
|
if (fd == -1)
|
||||||
return -1;
|
return ICX3_PRODUCT_NONE;
|
||||||
|
|
||||||
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);
|
read_result = i2c_smbus_read_i2c_block_data(fd, ICX3_REG_READINFORMATION, ICX3_READINFORMATION_SIZE, data);
|
||||||
|
close(fd);
|
||||||
if (read_result == ICX3_READINFORMATION_SIZE) {
|
if (read_result == ICX3_READINFORMATION_SIZE) {
|
||||||
temp_info = (struct icx3_info*)&data;
|
temp_info = (struct icx3_info*)&data;
|
||||||
if (temp_info->slave_address == ICX3_I2C_ADDR) {
|
if (temp_info->slave_address == ICX3_I2C_ADDR)
|
||||||
card->product_id = temp_info->product_id;
|
return temp_info->product_id;
|
||||||
card->i2c_fd = fd;
|
|
||||||
return fd;
|
|
||||||
} else {
|
|
||||||
close(fd);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return ICX3_PRODUCT_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_icx3_fans(struct card_info *card)
|
void print_icx3_fans(char *i2c_dev_path)
|
||||||
{
|
{
|
||||||
struct icx3_fan_control fans[ICX3_MAX_FANS];
|
struct icx3_fan_control fans[ICX3_MAX_FANS];
|
||||||
get_fan_status(fans, card);
|
get_fan_status(fans, i2c_dev_path);
|
||||||
|
|
||||||
for (int i=0; i < ICX3_MAX_FANS; i++) {
|
for (int i=0; i < ICX3_MAX_FANS; i++) {
|
||||||
printf("%s: %d RPM (%d/%d%%, %s)\n",
|
printf("%s: %d RPM (%d/%d%%, %s)\n",
|
||||||
@ -57,10 +47,10 @@ void print_icx3_fans(struct card_info *card)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_icx3_fans_oneline(struct card_info *card)
|
void print_icx3_fans_oneline(char *i2c_dev_path)
|
||||||
{
|
{
|
||||||
struct icx3_fan_control fans[ICX3_MAX_FANS];
|
struct icx3_fan_control fans[ICX3_MAX_FANS];
|
||||||
get_fan_status(fans, card);
|
get_fan_status(fans, i2c_dev_path);
|
||||||
|
|
||||||
printf("FAN");
|
printf("FAN");
|
||||||
for (int i=0; i < ICX3_MAX_FANS; i++) {
|
for (int i=0; i < ICX3_MAX_FANS; i++) {
|
||||||
@ -69,11 +59,11 @@ void print_icx3_fans_oneline(struct card_info *card)
|
|||||||
printf("%%");
|
printf("%%");
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_icx3_temps(struct card_info *card)
|
void print_icx3_temps(char *i2c_dev_path)
|
||||||
{
|
{
|
||||||
float temps[ICX3_NUM_TEMP_SENSORS];
|
float temps[ICX3_NUM_TEMP_SENSORS];
|
||||||
|
|
||||||
get_temp_sensors(temps, card);
|
get_temp_sensors(temps, i2c_dev_path);
|
||||||
|
|
||||||
for (int i=0; i<ICX3_NUM_TEMP_SENSORS; i++) {
|
for (int i=0; i<ICX3_NUM_TEMP_SENSORS; i++) {
|
||||||
printf("%s: %+.1f°C\n",
|
printf("%s: %+.1f°C\n",
|
||||||
@ -82,11 +72,11 @@ void print_icx3_temps(struct card_info *card)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_icx3_temps_oneline(struct card_info *card)
|
void print_icx3_temps_oneline(char *i2c_dev_path)
|
||||||
{
|
{
|
||||||
float temps[ICX3_NUM_TEMP_SENSORS];
|
float temps[ICX3_NUM_TEMP_SENSORS];
|
||||||
|
|
||||||
get_temp_sensors(temps, card);
|
get_temp_sensors(temps, i2c_dev_path);
|
||||||
|
|
||||||
for (int i=0; i<ICX3_NUM_TEMP_SENSORS; i++) {
|
for (int i=0; i<ICX3_NUM_TEMP_SENSORS; i++) {
|
||||||
if (i == 0 || strncmp(icx3_temp_sensor_names[i], icx3_temp_sensor_names[i-1], 3))
|
if (i == 0 || strncmp(icx3_temp_sensor_names[i], icx3_temp_sensor_names[i-1], 3))
|
||||||
@ -96,9 +86,9 @@ void print_icx3_temps_oneline(struct card_info *card)
|
|||||||
printf("°C");
|
printf("°C");
|
||||||
}
|
}
|
||||||
|
|
||||||
void get_available_fans(char *fans_avail, struct card_info *card)
|
void get_available_fans(char *i2c_dev_path, char *fans_avail)
|
||||||
{
|
{
|
||||||
int product_id = card->product_id;
|
int product_id = check_for_icx3(i2c_dev_path);
|
||||||
|
|
||||||
/* From ICX3TotalFanCtrl.cs */
|
/* From ICX3TotalFanCtrl.cs */
|
||||||
switch(product_id) {
|
switch(product_id) {
|
||||||
@ -152,34 +142,47 @@ 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_fan_status(struct icx3_fan_control *fans, char *i2c_dev_path)
|
||||||
{
|
{
|
||||||
char data[I2C_SMBUS_BLOCK_MAX] = {};
|
char data[I2C_SMBUS_BLOCK_MAX] = {};
|
||||||
int read_result;
|
int fd, 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};
|
char fans_avail[ICX3_MAX_FANS] = {0};
|
||||||
get_available_fans(fans_avail, card);
|
get_available_fans(i2c_dev_path, fans_avail);
|
||||||
|
|
||||||
|
fd = open_i2c_dev(i2c_dev_path);
|
||||||
|
if (fd == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
for (int i=0; i < ICX3_MAX_FANS; i++) {
|
for (int i=0; i < ICX3_MAX_FANS; i++) {
|
||||||
if (!fans_avail[i]) {
|
if (!fans_avail[i]) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
read_result = i2c_smbus_read_i2c_block_data(card->i2c_fd, ICX3_REG_FANCONTROL + i, ICX3_FANCONTROL_SIZE, data);
|
read_result = i2c_smbus_read_i2c_block_data(fd, ICX3_REG_FANCONTROL + i, ICX3_FANCONTROL_SIZE, data);
|
||||||
if (read_result != ICX3_FANCONTROL_SIZE) {
|
if (read_result != ICX3_FANCONTROL_SIZE) {
|
||||||
|
close(fd);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
memcpy(&fans[i], &data, sizeof(struct icx3_fan_control));
|
memcpy(&fans[i], &data, sizeof(struct icx3_fan_control));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void get_temp_sensors(float *temps, struct card_info *card)
|
void get_temp_sensors(float *temps, char *i2c_dev_path)
|
||||||
{
|
{
|
||||||
char data[I2C_SMBUS_BLOCK_MAX] = {};
|
char data[I2C_SMBUS_BLOCK_MAX] = {};
|
||||||
int read_result;
|
int fd, read_result;
|
||||||
struct icx3_temp_sensors *temp_sensors;
|
struct icx3_temp_sensors *temp_sensors;
|
||||||
|
|
||||||
read_result = i2c_smbus_read_i2c_block_data(card->i2c_fd, ICX3_REG_TEMPSENSOR, ICX3_TEMPSENSOR_SIZE, data);
|
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);
|
||||||
if (read_result != ICX3_TEMPSENSOR_SIZE)
|
if (read_result != ICX3_TEMPSENSOR_SIZE)
|
||||||
return;
|
return;
|
||||||
temp_sensors = (struct icx3_temp_sensors*) &data;
|
temp_sensors = (struct icx3_temp_sensors*) &data;
|
||||||
@ -195,34 +198,54 @@ void get_temp_sensors(float *temps, struct card_info *card)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void enable_write(int enable, struct card_info *card)
|
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;
|
||||||
|
|
||||||
unsigned char *data;
|
unsigned char *data;
|
||||||
if (enable)
|
if (enable)
|
||||||
data = icx3_write_enable;
|
data = icx3_write_enable;
|
||||||
else
|
else
|
||||||
data = icx3_write_disable;
|
data = icx3_write_disable;
|
||||||
/* Enable or disable write */
|
/* Enable or disable write */
|
||||||
i2c_smbus_write_i2c_block_data(card->i2c_fd, ICX3_REG_ENABLEWRITE, ICX3_ENABLEWRITE_SIZE, data);
|
i2c_smbus_write_i2c_block_data(fd, ICX3_REG_ENABLEWRITE, ICX3_ENABLEWRITE_SIZE, data);
|
||||||
|
|
||||||
/* Read back the result to verify */
|
/* Read back the result to verify */
|
||||||
unsigned char read_result[ICX3_ENABLEWRITE_SIZE];
|
unsigned char read_result[ICX3_ENABLEWRITE_SIZE];
|
||||||
int write_ok = 0;
|
int write_ok = 0;
|
||||||
i2c_smbus_read_i2c_block_data(card->i2c_fd, ICX3_REG_ENABLEWRITE, ICX3_ENABLEWRITE_SIZE, read_result);
|
i2c_smbus_read_i2c_block_data(fd, ICX3_REG_ENABLEWRITE, ICX3_ENABLEWRITE_SIZE, read_result);
|
||||||
if (enable)
|
if (enable)
|
||||||
write_ok = (read_result[1] == 0xFC);
|
write_ok = (read_result[1] == 0xFC);
|
||||||
else
|
else
|
||||||
write_ok = (read_result[1] == 0xFE);
|
write_ok = (read_result[1] == 0xFE);
|
||||||
|
|
||||||
if (!write_ok)
|
if (!write_ok)
|
||||||
printf("Unable to enable/disable write on %s\n", card->i2c_dev_path);
|
printf("Unable to enable/disable write on %s\n", i2c_dev_path);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sets a given fan on the GPU according to a string setting
|
/* 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)
|
'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 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 */
|
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, struct card_info *card)
|
void set_fan(int fan, char *setting, char *i2c_dev_path)
|
||||||
{
|
{
|
||||||
char fans_avail[ICX3_MAX_FANS] = {0};
|
char fans_avail[ICX3_MAX_FANS] = {0};
|
||||||
|
|
||||||
@ -233,11 +256,15 @@ void set_fan(int fan, char *setting, struct card_info *card)
|
|||||||
int write_result;
|
int write_result;
|
||||||
|
|
||||||
/* Check to make sure we're setting a valid fan */
|
/* Check to make sure we're setting a valid fan */
|
||||||
get_available_fans(fans_avail, card);
|
get_available_fans(i2c_dev_path, fans_avail);
|
||||||
if (fans_avail[fan] == 0) {
|
if (fans_avail[fan] == 0) {
|
||||||
printf("Fan %d does not exist on this card \n", fan);
|
printf("Fan %d does not exist on this card \n", fan);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int fp = open_i2c_dev(i2c_dev_path);
|
||||||
|
if (fp == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
fan_control.length = ICX3_FANCONTROL_SIZE - 1;
|
fan_control.length = ICX3_FANCONTROL_SIZE - 1;
|
||||||
if (strcmp(setting, "auto") == 0) {
|
if (strcmp(setting, "auto") == 0) {
|
||||||
@ -256,15 +283,16 @@ void set_fan(int fan, char *setting, struct card_info *card)
|
|||||||
fan_control.duty = atoi(setting);
|
fan_control.duty = atoi(setting);
|
||||||
}
|
}
|
||||||
|
|
||||||
enable_write(1, card);
|
enable_write(1, i2c_dev_path);
|
||||||
|
|
||||||
i2c_smbus_write_i2c_block_data(card->i2c_fd, reg, ICX3_FANCONTROL_SIZE, (char *)&fan_control);
|
i2c_smbus_write_i2c_block_data(fp, reg, ICX3_FANCONTROL_SIZE, (char *)&fan_control);
|
||||||
|
|
||||||
/* Read back data and verify we set the fan properly */
|
/* Read back data and verify we set the fan properly */
|
||||||
i2c_smbus_read_i2c_block_data(card->i2c_fd, reg, ICX3_FANCONTROL_SIZE, (char *)&fan_readback);
|
i2c_smbus_read_i2c_block_data(fp, reg, ICX3_FANCONTROL_SIZE, (char *)&fan_readback);
|
||||||
if (fan_readback.fanmode != fan_control.fanmode ||
|
if (fan_readback.fanmode != fan_control.fanmode ||
|
||||||
fan_readback.rpm_offset != fan_control.rpm_offset ||
|
fan_readback.rpm_offset != fan_control.rpm_offset ||
|
||||||
fan_readback.duty != fan_control.duty)
|
fan_readback.duty != fan_control.duty)
|
||||||
printf("Error setting fan %d on %s\n", fan, card->i2c_fd);
|
printf("Error setting fan %d on %s\n", fan, i2c_dev_path);
|
||||||
|
close(fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
28
icx3.h
28
icx3.h
@ -1,8 +1,3 @@
|
|||||||
#ifndef ICX3_H
|
|
||||||
#define ICX3_H
|
|
||||||
|
|
||||||
#include "evga-card.h"
|
|
||||||
|
|
||||||
#define ICX3_I2C_ADDR 0x2D
|
#define ICX3_I2C_ADDR 0x2D
|
||||||
|
|
||||||
#define ICX3_REG_FANCONTROL 80
|
#define ICX3_REG_FANCONTROL 80
|
||||||
@ -116,15 +111,14 @@ static char *icx3_temp_sensor_names[] = {
|
|||||||
"PWR5",
|
"PWR5",
|
||||||
};
|
};
|
||||||
|
|
||||||
int icx3_init(struct card_info *card);
|
enum icx3_product_id check_for_icx3(char *i2c_dev_path);
|
||||||
void print_icx3_fans(struct card_info *card);
|
void print_icx3_fans(char *i2c_dev_path);
|
||||||
void print_icx3_fans_oneline(struct card_info *card);
|
void print_icx3_fans_oneline(char *i2c_dev_path);
|
||||||
void print_icx3_temps(struct card_info *card);
|
void print_icx3_temps(char *i2c_dev_path);
|
||||||
void print_icx3_temps_oneline(struct card_info *card);
|
void print_icx3_temps_oneline(char *i2c_dev_path);
|
||||||
void get_available_fans(char *fans_avail, struct card_info *card);
|
void get_available_fans(char *i2c_dev_path, char *fans_avail);
|
||||||
void get_fan_status(struct icx3_fan_control *fans, struct card_info *card);
|
void get_fan_status(struct icx3_fan_control *fans, char *i2c_dev_path);
|
||||||
void get_temp_sensors(float *temps, struct card_info *card);
|
void get_temp_sensors(float *temps, char *i2c_dev_path);
|
||||||
void enable_write(int enable, struct card_info *card);
|
int open_i2c_dev(char *i2c_dev_path);
|
||||||
void set_fan(int fan, char *setting, struct card_info *card);
|
void enable_write(int enable, char *i2c_dev_path);
|
||||||
|
void set_fan(int fan, char *setting, char *i2c_dev_path);
|
||||||
#endif
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user