From eba32ce8a542f3dce2d453faf200cb6d89a01421 Mon Sep 17 00:00:00 2001 From: Alex Forencich Date: Sat, 8 Jan 2022 15:32:50 -0800 Subject: [PATCH] Accept interface name and PCIe BDF when connecting to device --- utils/mqnic-fw.c | 87 +++++++++----------------- utils/mqnic.c | 160 ++++++++++++++++++++++++++++++++++++++--------- utils/mqnic.h | 4 ++ 3 files changed, 166 insertions(+), 85 deletions(-) diff --git a/utils/mqnic-fw.c b/utils/mqnic-fw.c index ba5ecf120..b53f0f3af 100644 --- a/utils/mqnic-fw.c +++ b/utils/mqnic-fw.c @@ -347,13 +347,13 @@ int file_type_from_ext(const char *file_name) return FILE_TYPE_BIN; } -int pcie_hot_reset(const char *pcie_port_path) +int pcie_hot_reset(const char *pci_port_path) { int fd; char path[PATH_MAX+32]; char buf[32]; - snprintf(path, sizeof(path), "%s/config", pcie_port_path); + snprintf(path, sizeof(path), "%s/config", pci_port_path); fd = open(path, O_RDWR); @@ -381,14 +381,14 @@ int pcie_hot_reset(const char *pcie_port_path) return 0; } -int pcie_disable_fatal_err(const char *pcie_port_path) +int pcie_disable_fatal_err(const char *pci_port_path) { int fd; char path[PATH_MAX+32]; char buf[32]; int offset; - snprintf(path, sizeof(path), "%s/config", pcie_port_path); + snprintf(path, sizeof(path), "%s/config", pci_port_path); fd = open(path, O_RDWR); @@ -451,8 +451,8 @@ int main(int argc, char *argv[]) FILE *write_file = NULL; char path[PATH_MAX+32]; - char device_path[PATH_MAX]; - char port_path[PATH_MAX]; + char pci_device_path[PATH_MAX]; + char pci_port_path[PATH_MAX]; char *ptr; int slot = -1; @@ -526,47 +526,24 @@ int main(int argc, char *argv[]) return -1; } - // determine sysfs path of PCIe device - // first, try to find via miscdevice - ptr = strrchr(device, '/'); - ptr = ptr ? ptr+1 : device; - - snprintf(path, sizeof(path), "/sys/class/misc/%s/device", ptr); - - if (!realpath(path, device_path)) + if (!dev->pci_device_path[0]) { - // that failed, perhaps it was a PCIe resource - strcpy(path, device); - ptr = strrchr(path, '/'); - if (ptr) - *ptr = 0; - - if (!realpath(path, device_path)) - { - perror("failed to determine device path"); - ret = -1; - goto err; - } - } - - // PCIe device will have a config space, so check for that - snprintf(path, sizeof(path), "%s/config", device_path); - - if (access(path, F_OK)) - { - perror("failed to determine device path"); + fprintf(stderr, "Failed to determine PCIe device path\n"); ret = -1; goto err; } + // snprintf(device_path, sizeof(device_path), dev->device_path) + snprintf(pci_device_path, sizeof(pci_device_path), "%s", dev->pci_device_path); + // determine sysfs path of upstream port - strcpy(port_path, device_path); - ptr = strrchr(port_path, '/'); + snprintf(pci_port_path, sizeof(pci_port_path), "%s", pci_device_path); + ptr = strrchr(pci_port_path, '/'); if (ptr) *ptr = 0; - printf("PCIe ID (device): %s\n", strrchr(device_path, '/')+1); - printf("PCIe ID (upstream port): %s\n", strrchr(port_path, '/')+1); + printf("PCIe ID (device): %s\n", strrchr(pci_device_path, '/')+1); + printf("PCIe ID (upstream port): %s\n", strrchr(pci_port_path, '/')+1); uint32_t flash_format = 0; const char *fpga_part = get_fpga_part(dev->fpga_id); @@ -1216,27 +1193,23 @@ skip_flash: // disable fatal error reporting on port (to prevent IPMI-triggered reboot) printf("Disabling PCIe fatal error reporting on port...\n"); - pcie_disable_fatal_err(port_path); + pcie_disable_fatal_err(pci_port_path); // disconnect from device mqnic_close(dev); dev = NULL; // attempt to disconnect driver - ptr = strrchr(device_path, '/'); - if (ptr) - { - snprintf(path, sizeof(path), "%s/driver/unbind", device_path); + snprintf(path, sizeof(path), "%s/driver/unbind", pci_device_path); - if (access(path, F_OK) == 0) - { - printf("Unbinding driver...\n"); - write_str_to_file(path, ptr+1); - } - else - { - printf("No driver bound\n"); - } + if (access(path, F_OK) == 0) + { + printf("Unbinding driver...\n"); + write_str_to_file(path, ptr+1); + } + else + { + printf("No driver bound\n"); } sleep(1); @@ -1245,7 +1218,7 @@ skip_flash: if (action_boot) { // reconnect directly to device - snprintf(path, sizeof(path), "%s/resource0", device_path); + snprintf(path, sizeof(path), "%s/resource0", pci_device_path); dev = mqnic_open(path); if (!dev) @@ -1269,7 +1242,7 @@ skip_flash: // remove PCIe device printf("Removing device...\n"); - snprintf(path, sizeof(path), "%s/remove", device_path); + snprintf(path, sizeof(path), "%s/remove", pci_device_path); if (write_1_to_file(path)) { @@ -1289,13 +1262,13 @@ skip_flash: for (int tries = 5; tries > 0; tries--) { printf("Performing hot reset on upstream port...\n"); - pcie_hot_reset(port_path); + pcie_hot_reset(pci_port_path); sleep(2); printf("Rescanning on upstream port...\n"); - snprintf(path, sizeof(path), "%s/rescan", port_path); + snprintf(path, sizeof(path), "%s/rescan", pci_port_path); if (write_1_to_file(path)) { @@ -1305,7 +1278,7 @@ skip_flash: } // PCIe device will have a config space, so check for that - snprintf(path, sizeof(path), "%s/config", device_path); + snprintf(path, sizeof(path), "%s/config", pci_device_path); if (access(path, F_OK) == 0) { diff --git a/utils/mqnic.c b/utils/mqnic.c index de73a76fc..737bf458d 100644 --- a/utils/mqnic.c +++ b/utils/mqnic.c @@ -33,8 +33,10 @@ either expressed or implied, of The Regents of the University of California. #include "mqnic.h" +#include #include #include +#include #include #include #include @@ -43,18 +45,29 @@ either expressed or implied, of The Regents of the University of California. #include #include -struct mqnic *mqnic_open(const char *dev_name) +static int mqnic_try_open(struct mqnic *dev, const char *fmt, ...) { - struct mqnic *dev = calloc(1, sizeof(struct mqnic)); + va_list ap; + char path[PATH_MAX+32]; struct stat st; + char *ptr; - if (!dev) - { - perror("memory allocation failed"); - goto fail_alloc; - } + va_start(ap, fmt); + vsnprintf(dev->device_path, sizeof(dev->device_path), fmt, ap); + va_end(ap); - dev->fd = open(dev_name, O_RDWR); + dev->pci_device_path[0] = 0; + + if (access(dev->device_path, W_OK)) + return -1; + + if (stat(dev->device_path, &st)) + return -1; + + if (S_ISDIR(st.st_mode)) + return -1; + + dev->fd = open(dev->device_path, O_RDWR); if (dev->fd < 0) { @@ -82,6 +95,35 @@ struct mqnic *mqnic_open(const char *dev_name) dev->regs_size = info.regs_size; } + // determine sysfs path of PCIe device + // first, try to find via miscdevice + ptr = strrchr(dev->device_path, '/'); + ptr = ptr ? ptr+1 : dev->device_path; + + snprintf(path, sizeof(path), "/sys/class/misc/%s/device", ptr); + + if (!realpath(path, dev->pci_device_path)) + { + // that failed, perhaps it was a PCIe resource + snprintf(path, sizeof(path), "%s", dev->device_path); + ptr = strrchr(path, '/'); + if (ptr) + *ptr = 0; + + if (!realpath(path, dev->pci_device_path)) + dev->pci_device_path[0] = 0; + } + + // PCIe device will have a config space, so check for that + if (dev->pci_device_path[0]) + { + snprintf(path, sizeof(path), "%s/config", dev->pci_device_path); + + if (access(path, F_OK)) + dev->pci_device_path[0] = 0; + } + + // map registers dev->regs = (volatile uint8_t *)mmap(NULL, dev->regs_size, PROT_READ | PROT_WRITE, MAP_SHARED, dev->fd, 0); if (dev->regs == MAP_FAILED) { @@ -89,20 +131,12 @@ struct mqnic *mqnic_open(const char *dev_name) goto fail_mmap_regs; } - if (mqnic_reg_read32(dev->regs, 4) == 0xffffffff) + if (dev->pci_device_path[0] && mqnic_reg_read32(dev->regs, 4) == 0xffffffff) { // if we were given a PCIe resource, then we may need to enable the device - char path[PATH_MAX+32]; - char *ptr; + snprintf(path, sizeof(path), "%s/enable", dev->pci_device_path); - strcpy(path, dev_name); - ptr = strrchr(path, '/'); - if (ptr) - { - strcpy(++ptr, "enable"); - } - - if (access(path, F_OK) == 0) + if (access(path, W_OK) == 0) { FILE *fp = fopen(path, "w"); @@ -137,6 +171,85 @@ struct mqnic *mqnic_open(const char *dev_name) goto fail_enum; } + return 0; + +fail_enum: + if (dev->rb_list) + free_reg_block_list(dev->rb_list); +fail_reset: + munmap((void *)dev->regs, dev->regs_size); +fail_mmap_regs: +fail_ioctl: +fail_fstat: + close(dev->fd); +fail_open: + return -1; +} + +static int mqnic_try_open_if_name(struct mqnic *dev, const char *if_name) +{ + DIR *folder; + struct dirent *entry; + char path[PATH_MAX]; + + snprintf(path, sizeof(path), "/sys/class/net/%s/device/misc/", if_name); + + folder = opendir(path); + if (!folder) + return -1; + + while ((entry = readdir(folder))) + { + if (entry->d_name[0] != '.') + break; + } + + if (!entry) + { + closedir(folder); + return -1; + } + + snprintf(path, sizeof(path), "/dev/%s", entry->d_name); + + closedir(folder); + + return mqnic_try_open(dev, "%s", path); +} + +struct mqnic *mqnic_open(const char *dev_name) +{ + struct mqnic *dev = calloc(1, sizeof(struct mqnic)); + + if (!dev) + { + perror("memory allocation failed"); + goto fail_alloc; + } + + // absolute path + if (mqnic_try_open(dev, "%s", dev_name) == 0) + goto open; + + // network interface + if (mqnic_try_open_if_name(dev, dev_name) == 0) + goto open; + + // PCIe sysfs path + if (mqnic_try_open(dev, "%s/resource0", dev_name) == 0) + goto open; + + // PCIe BDF (dddd:xx:yy.z) + if (mqnic_try_open(dev, "/sys/bus/pci/devices/%s/resource0", dev_name) == 0) + goto open; + + // PCIe BDF (xx:yy.z) + if (mqnic_try_open(dev, "/sys/bus/pci/devices/0000:%s/resource0", dev_name) == 0) + goto open; + + goto fail_open; + +open: dev->fpga_id = mqnic_reg_read32(dev->fw_id_rb->regs, MQNIC_RB_FW_ID_REG_FPGA_ID); dev->fw_id = mqnic_reg_read32(dev->fw_id_rb->regs, MQNIC_RB_FW_ID_REG_FW_ID); dev->fw_ver = mqnic_reg_read32(dev->fw_id_rb->regs, MQNIC_RB_FW_ID_REG_FW_VER); @@ -186,15 +299,6 @@ struct mqnic *mqnic_open(const char *dev_name) skip_interface: return dev; -fail: -fail_enum: -fail_reset: - mqnic_close(dev); - return NULL; -fail_mmap_regs: -fail_ioctl: -fail_fstat: - close(dev->fd); fail_open: free(dev); fail_alloc: diff --git a/utils/mqnic.h b/utils/mqnic.h index 03d0b6dd0..cbb47d9bb 100644 --- a/utils/mqnic.h +++ b/utils/mqnic.h @@ -34,6 +34,7 @@ either expressed or implied, of The Regents of the University of California. #ifndef MQNIC_H #define MQNIC_H +#include #include #include @@ -152,6 +153,9 @@ struct mqnic { char build_date_str[32]; struct mqnic_if *interfaces[MQNIC_MAX_IF]; + + char device_path[PATH_MAX]; + char pci_device_path[PATH_MAX]; }; struct mqnic *mqnic_open(const char *dev_name);