// SPDX-License-Identifier: BSD-2-Clause-Views /* * Copyright (c) 2021-2023 The Regents of the University of California */ #include #include #include #include static void usage(char *name) { fprintf(stderr, "usage: %s [options]\n" " -d name device to open (/dev/mqnic0)\n" " -i number interface\n" " -P number port\n", name); } uint32_t mqnic_alveo_bmc_reg_read(struct mqnic_reg_block *rb, uint32_t reg) { mqnic_reg_write32(rb->regs, MQNIC_RB_ALVEO_BMC_REG_ADDR, reg); mqnic_reg_read32(rb->regs, MQNIC_RB_ALVEO_BMC_REG_DATA); // dummy read return mqnic_reg_read32(rb->regs, MQNIC_RB_ALVEO_BMC_REG_DATA); } void mqnic_alveo_bmc_reg_write(struct mqnic_reg_block *rb, uint32_t reg, uint32_t val) { mqnic_reg_write32(rb->regs, MQNIC_RB_ALVEO_BMC_REG_ADDR, reg); mqnic_reg_write32(rb->regs, MQNIC_RB_ALVEO_BMC_REG_DATA, val); mqnic_reg_read32(rb->regs, MQNIC_RB_ALVEO_BMC_REG_DATA); // dummy read } struct sensor_channel { uint32_t reg; char name[32]; char unit[8]; }; struct sensor_channel alveo_bmc_sensors[] = { {0x0020, "12V_PEX", "mV"}, {0x002C, "3V3_PEX", "mV"}, {0x0038, "3V3_AUX", "mV"}, {0x0044, "12V_AUX", "mV"}, {0x0050, "DDR4_VPP_BTM", "mV"}, {0x005C, "SYS_5V5", "mV"}, {0x0068, "VCC1V2_TOP", "mV"}, {0x0074, "VCC1V8", "mV"}, {0x0080, "VCC0V85", "mV"}, {0x008C, "DDR4_VPP_TOP", "mV"}, {0x0098, "MGT0V9AVCC", "mV"}, {0x00A4, "12VSW", "mV"}, {0x00B0, "MGTAVTT", "mV"}, {0x00BC, "VCC1V2_BTM", "mV"}, {0x00C8, "12VPEX_I_IN", "mA"}, {0x00D4, "12V_AUX_I_IN", "mA"}, {0x00E0, "VCCINT", "mV"}, {0x00EC, "VCCINT_I", "mA"}, {0x00F8, "FPGA_TEMP", "C"}, {0x0104, "FAN_TEMP", "C"}, {0x0110, "DIMM_TEMP0", "C"}, {0x011C, "DIMM_TEMP1", "C"}, {0x0128, "DIMM_TEMP2", "C"}, {0x0134, "DIMM_TEMP3", "C"}, {0x0140, "SE98_TEMP0", "C"}, {0x014C, "SE98_TEMP1", "C"}, {0x0158, "SE98_TEMP2", "C"}, {0x0164, "FAN_SPEED", "RPM"}, {0x0170, "CAGE_TEMP0", "C"}, {0x017C, "CAGE_TEMP1", "C"}, {0x0188, "CAGE_TEMP2", "C"}, {0x0194, "CAGE_TEMP3", "C"}, {0x0260, "HBM_TEMP1", "C"}, {0x026C, "VCC3V3", "mV"}, {0x0278, "3V3_PEX_I_IN", "mA"}, {0x0284, "VCC0V85_I", "mA"}, {0x0290, "HBM_1V2", "mV"}, {0x029C, "VPP2V5", "mV"}, {0x02A8, "VCCINT_BRAM", "mV"}, {0x02B4, "HBM_TEMP2", "C"}, {0x02C0, "12V_AUX1", "mV"}, {0x02CC, "VCCINT_TEMP", "C"}, {0x02D8, "PEX_12V_POWER", "mW"}, {0x02E4, "PEX_3V3_POWER", "mW"}, {0x02F0, "AUX_3V3_I", "mA"}, {0x0314, "VCC1V2_I", "mA"}, {0x0320, "V12_IN_I", "mA"}, {0x032C, "V12_IN_AUX0_I", "mA"}, {0x0338, "V12_IN_AUX1_I", "mA"}, {0x0344, "VCCAUX", "mV"}, {0x0350, "VCCAUX_PMC", "mV"}, {0x035C, "VCCRAM", "mV"}, {0, "", ""} }; int mqnic_gecko_bmc_read(struct mqnic_reg_block *rb) { uint32_t val; int timeout = 20000; while (1) { val = mqnic_reg_read32(rb->regs, MQNIC_RB_GECKO_BMC_REG_STATUS); if (val & (1 << 19)) { if (val & (1 << 18)) { // timed out printf("Timed out waiting for BMC\n"); usleep(10000); return -2; } return val & 0xffff; } else { timeout--; if (timeout == 0) { printf("Timed out waiting for operation\n"); return -1; } usleep(10); } } return -1; } int mqnic_gecko_bmc_write(struct mqnic_reg_block *rb, uint16_t cmd, uint32_t data) { int ret; ret = mqnic_gecko_bmc_read(rb); if (ret == -1) return ret; mqnic_reg_write32(rb->regs, MQNIC_RB_GECKO_BMC_REG_DATA, data); mqnic_reg_write32(rb->regs, MQNIC_RB_GECKO_BMC_REG_CMD, cmd << 16); return 0; } int mqnic_gecko_bmc_query(struct mqnic_reg_block *rb, uint16_t cmd, uint32_t data) { int ret; ret = mqnic_gecko_bmc_write(rb, cmd, data); if (ret) return ret; return mqnic_gecko_bmc_read(rb); } int main(int argc, char *argv[]) { char *name; int opt; int ret = 0; char *device = NULL; struct mqnic *dev; struct mqnic_reg_block *bmc_rb; name = strrchr(argv[0], '/'); name = name ? 1+name : argv[0]; while ((opt = getopt(argc, argv, "d:h?")) != EOF) { switch (opt) { case 'd': device = optarg; break; case 'h': case '?': usage(name); return 0; default: usage(name); return -1; } } if (!device) { fprintf(stderr, "Device not specified\n"); usage(name); return -1; } dev = mqnic_open(device); if (!dev) { fprintf(stderr, "Failed to open device\n"); return -1; } if (dev->pci_device_path[0]) { char *ptr = strrchr(dev->pci_device_path, '/'); if (ptr) printf("PCIe ID: %s\n", ptr+1); } mqnic_print_fw_id(dev); if ((bmc_rb = mqnic_find_reg_block(dev->rb_list, MQNIC_RB_ALVEO_BMC_TYPE, MQNIC_RB_ALVEO_BMC_VER, 0))) { printf("Detected Xilinx Alveo board with MSP430 BMC\n"); printf("Attempt to communicate with CMS microblaze...\n"); if (mqnic_alveo_bmc_reg_read(bmc_rb, 0x020000) == 0 || mqnic_alveo_bmc_reg_read(bmc_rb, 0x028000) == 0) { printf("Resetting CMS...\n"); // reset CMS mqnic_alveo_bmc_reg_write(bmc_rb, 0x020000, 0); mqnic_alveo_bmc_reg_write(bmc_rb, 0x020000, 1); usleep(200000); } if (mqnic_alveo_bmc_reg_read(bmc_rb, 0x028000) != 0x74736574) { fprintf(stderr, "CMS not responding\n"); ret = -1; goto err; } // read sensor channels printf("Sensor values:\n"); for (const struct sensor_channel *ptr = alveo_bmc_sensors; ptr->reg; ptr++) { uint32_t reg = 0x028000 + ptr->reg; uint32_t val_max = mqnic_alveo_bmc_reg_read(bmc_rb, reg); uint32_t val_avg = mqnic_alveo_bmc_reg_read(bmc_rb, reg+4); uint32_t val_ins = mqnic_alveo_bmc_reg_read(bmc_rb, reg+8); printf("%s: %d %s (%d %s avg, %d %s max)\n", ptr->name, val_ins, ptr->unit, val_avg, ptr->unit, val_max, ptr->unit); } // read MAC addresses printf("MAC addresses:\n"); for (int k = 0; k < 8; k++) { uint8_t mac[6]; uint32_t reg = 0x0281a0 + k*8; uint32_t val = mqnic_alveo_bmc_reg_read(bmc_rb, reg); mac[0] = (val >> 8) & 0xff; mac[1] = val & 0xff; val = mqnic_alveo_bmc_reg_read(bmc_rb, reg+4); mac[2] = (val >> 24) & 0xff; mac[3] = (val >> 16) & 0xff; mac[4] = (val >> 8) & 0xff; mac[5] = val & 0xff; printf("MAC %d: ", k); for (int i = 0; i < 6; i++) { if (i != 0) printf(":"); printf("%02x", mac[i]); } printf("\n"); } } else if ((bmc_rb = mqnic_find_reg_block(dev->rb_list, MQNIC_RB_GECKO_BMC_TYPE, MQNIC_RB_GECKO_BMC_VER, 0))) { printf("Detected Silicom board with Gecko BMC\n"); if (mqnic_gecko_bmc_query(bmc_rb, 0x7006, 0) <= 0) { fprintf(stderr, "Failed to communicate with BMC\n"); ret = -1; goto err; } uint16_t v_l = mqnic_gecko_bmc_query(bmc_rb, 0x7005, 0); uint16_t v_h = mqnic_gecko_bmc_query(bmc_rb, 0x7006, 0); printf("Gecko BMC version %d.%d.%d.%d\n", (v_h >> 8) & 0xff, v_h & 0xff, (v_l >> 8) & 0xff, v_l & 0xff); // read MAC addresses printf("MAC addresses:\n"); for (int k = 0; k < 8; k++) { uint8_t mac[6]; for (int i = 0; i < 6; i += 2) { uint16_t val = mqnic_gecko_bmc_query(bmc_rb, 0x2003, 0+k*6+i); mac[i] = val & 0xff; mac[i+1] = (val >> 8) & 0xff; } printf("MAC %d: ", k); for (int i = 0; i < 6; i++) { if (i != 0) printf(":"); printf("%02x", mac[i]); } printf("\n"); } } else { fprintf(stderr, "Board does not have BMC or BMC not currently supported\n"); ret = -1; goto err; } err: mqnic_close(dev); return ret; }