evga-icx/evga-card.c

146 lines
3.7 KiB
C
Raw Permalink Normal View History

2025-01-19 23:27:43 -08:00
#include <stdio.h>
#include <string.h>
#include <dirent.h>
#include <stdlib.h>
2025-01-19 23:27:43 -08:00
#include "evga-card.h"
#include "icx3.h"
/* Search all i2c device files for ones are on a PCI device of a supported GPU,
and respond with the correct iCX3 version information */
2025-02-16 22:28:16 -08:00
int find_evga_gpu_i2cs(struct card_info *infos, int max_gpus, int i2c_bus)
2025-01-19 23:27:43 -08:00
{
char i2c_devices_path[NAME_MAX];
char device_path[NAME_MAX];
char dev_file[NAME_MAX];
2025-02-01 00:29:48 -08:00
char *pci_addr;
2025-01-19 23:27:43 -08:00
FILE *test_fd;
DIR *dir;
struct dirent *ent;
2025-01-19 23:27:43 -08:00
int num_gpus = 0;
2025-02-16 22:28:16 -08:00
int current_i2c_bus = -1;
2025-01-19 23:27:43 -08:00
unsigned short pci_vendor, pci_device, pci_subsystem_vendor, pci_subsystem_device = 0;
/* Start looking for I2C adapters in /sys/bus/i2c/devices/ */
strcpy(i2c_devices_path, "/sys/bus/i2c/devices/");
dir = opendir(i2c_devices_path);
/* make sure we can open the i2c device */
if(dir == NULL)
return -1;
/* loop over all i2c devices */
while((ent = readdir(dir)) != NULL)
{
/* Don't check any non-i2c devices */
if(strncmp(ent->d_name, "i2c-", 4) != 0)
continue;
2025-02-16 22:28:16 -08:00
/* 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;
}
2025-01-19 23:27:43 -08:00
strcpy(device_path, i2c_devices_path);
strcat(device_path, ent->d_name);
2025-02-01 00:29:48 -08:00
/* Only check Nvidia devices */
pci_addr = read_nvidia_pci_address(device_path);
if (pci_addr == NULL)
continue;
2025-01-19 23:27:43 -08:00
/* Read the PCI info for the underlying device */
pci_vendor = read_pci_id(device_path, "/device/vendor");
pci_device = read_pci_id(device_path, "/device/device");
pci_subsystem_vendor = read_pci_id(device_path, "/device/subsystem_vendor");
pci_subsystem_device = read_pci_id(device_path, "/device/subsystem_device");
2025-01-19 23:27:43 -08:00
/* See if it's a matching device for a supported EVGA card */
for (int i = 0; i < (sizeof(evga_pci_ids) / sizeof(struct gpu_pci_info)); i++) {
2025-01-19 23:27:43 -08:00
2025-01-30 01:15:18 -08:00
if (pci_vendor == evga_pci_ids[i].vendor_id &&
pci_device == evga_pci_ids[i].device_id &&
pci_subsystem_vendor == evga_pci_ids[i].subvendor_id &&
pci_subsystem_device == evga_pci_ids[i].subdevice_id) {
2025-01-19 23:27:43 -08:00
/* Matched all PCI IDs, check for good firmware read */
strcpy(dev_file, "/dev/");
strcat(dev_file, ent->d_name);
2025-02-01 08:04:28 -08:00
infos[num_gpus].i2c_dev_path = dev_file;
if (icx3_init(&infos[num_gpus]) > 0) {
2025-01-19 23:27:43 -08:00
/* Write our card info into the provided struct array */
infos[num_gpus].card_name = evga_pci_ids[i].card_name;
2025-02-01 00:29:48 -08:00
infos[num_gpus].pci_id = pci_addr;
infos[num_gpus].pci_device_id = pci_device;
infos[num_gpus].i2c_dev_path = calloc(strlen(dev_file) + 1, sizeof(char));
strcpy(infos[num_gpus].i2c_dev_path, dev_file);
num_gpus++;
2025-01-19 23:27:43 -08:00
break;
}
}
}
if (num_gpus == max_gpus)
break;
2025-01-19 23:27:43 -08:00
}
return num_gpus;
2025-01-19 23:27:43 -08:00
}
/* Read a 16-bit unsigned int from a pci id file */
2025-01-19 23:27:43 -08:00
unsigned short read_pci_id(char *device_path, char *field)
{
char buf[16];
2025-01-19 23:27:43 -08:00
char file_path[NAME_MAX];
strcpy(file_path, device_path);
strcat(file_path, field);
FILE *fp = fopen(file_path, "r");
if (fp == NULL)
return 0;
if (fgets(buf, sizeof(buf), fp) == NULL) {
fclose(fp);
return 0;
}
fclose(fp);
return (unsigned short)strtoul(buf, NULL, 16);
}
char *read_nvidia_pci_address(char *device_path)
{
char file_path[NAME_MAX];
char *ret = calloc(16 + 1, sizeof(char)); /* assuming pci ids could look as large as 00000000:0C:00.0 */
strcpy(file_path, device_path);
strcat(file_path, "/name");
FILE *fp = fopen(file_path, "r");
2025-02-01 00:29:48 -08:00
if (fp == NULL) {
free(ret);
return NULL;
2025-02-01 00:29:48 -08:00
}
fscanf(fp, "NVIDIA i2c adapter %*u at %16s", ret);
fclose(fp);
2025-02-01 00:29:48 -08:00
if (strlen(ret) == 0) {
free(ret);
return NULL;
}
return ret;
}