meta-facebook/meta-fby35/recipes-fby35/dimm-util/files/me-functions.cpp (127 lines of code) (raw):

/* * * Copyright 2022-present Facebook. All Rights Reserved. * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <stdio.h> #include <stdint.h> #include <string.h> #include <facebook/bic_xfer.h> #include "dimm-util.h" #include "dimm-util-plat.h" #ifdef DEBUG_DIMM_UTIL #define DBG_PRINT(fmt, args...) printf(fmt, ##args) #else #define DBG_PRINT(fmt, args...) #endif static uint8_t dev_addr[MAX_DIMM_NUM_FBY35/2] = { DIMM0_SPD_ADDR, DIMM1_SPD_ADDR, DIMM2_SPD_ADDR, }; // dimm location constant strings, matching silk screen static char const *dimm_label[NUM_CPU_FBY35][MAX_DIMM_NUM_FBY35] = { { "A0", "A2", "A3", "A4", "A6", "A7" }, }; static uint8_t dimm_cache_id[NUM_CPU_FBY35][MAX_DIMM_NUM_FBY35] = { { 0, 4, 6, 8, 12, 14 }, }; static char const *fru_name_fby35[NUM_FRU_FBY35] = { "slot1", "slot2", "slot3", "slot4", "all", }; int plat_init() { num_frus = NUM_FRU_FBY35; num_dimms_per_cpu = MAX_DIMM_NUM_FBY35; num_cpus = NUM_CPU_FBY35; total_dimms = num_dimms_per_cpu * num_cpus; fru_name = fru_name_fby35; fru_id_min = FRU_ID_MIN_FBY35; fru_id_max = FRU_ID_MAX_FBY35; fru_id_all = FRU_ID_ALL_FBY35; read_block = true; return 0; } const char * get_dimm_label(uint8_t cpu, uint8_t dimm) { if ((cpu >= NUM_CPU_FBY35) || (dimm >= MAX_DIMM_NUM_FBY35)) { return "N/A"; } return dimm_label[cpu][dimm]; } uint8_t get_dimm_cache_id(uint8_t cpu, uint8_t dimm) { if ((cpu >= NUM_CPU_FBY35) || (dimm >= MAX_DIMM_NUM_FBY35)) { return 0xff; } return dimm_cache_id[cpu][dimm]; } int util_read_spd(uint8_t slot_id, uint8_t cpu, uint8_t dimm, uint16_t offset, uint8_t len, uint8_t *rxbuf) { #define MIN_RESP_LEN (1 /* ME CC */ + INTEL_ID_LEN) int ret; uint8_t tbuf[64] = {0}; uint8_t rbuf[64] = {0}; uint8_t tlen = 14; uint8_t rlen = sizeof(rbuf); uint8_t bus_id = 0; uint8_t addr = 0; // SPR CPU supports 2 SPD buses if (dimm >= (MAX_DIMM_NUM_FBY35/2)) { bus_id = 1; } addr = dev_addr[dimm % (MAX_DIMM_NUM_FBY35/2)]; tbuf[0] = NETFN_NM_REQ << 2; tbuf[1] = CMD_NM_READ_MEM_SM_BUS; tbuf[2] = MANU_INTEL_0; tbuf[3] = MANU_INTEL_1; tbuf[4] = MANU_INTEL_2; tbuf[5] = cpu; tbuf[6] = bus_id; tbuf[7] = addr; tbuf[8] = 2; // offset length tbuf[9] = (len > 0) ? len - 1 : 0; tbuf[10] = 0x80 | (offset & 0x7F); tbuf[11] = (offset & 0x780) >> 7; tbuf[12] = 0; tbuf[13] = 0; ret = bic_me_xmit(slot_id, tbuf, tlen, rbuf, &rlen); if (ret) { DBG_PRINT("ME no response!\n"); return -1; } if (rlen != (MIN_RESP_LEN + len)) { DBG_PRINT("return incomplete len=%d\n", rlen); return -1; } if (rbuf[0] != CC_SUCCESS) { DBG_PRINT("Completion Code: %02X\n", rbuf[0]); return -1; } memcpy(rxbuf, &rbuf[4], len); return len; } int util_check_me_status(uint8_t slot_id) { int ret; uint8_t tbuf[64] = {0x00}; uint8_t rbuf[64] = {0x00}; uint8_t tlen = 2; uint8_t rlen = sizeof(rbuf); tbuf[0] = NETFN_APP_REQ << 2; tbuf[1] = CMD_APP_GET_SELFTEST_RESULTS; ret = bic_me_xmit(slot_id, tbuf, tlen, rbuf, &rlen); if (ret) { DBG_PRINT("ME no response!\n"); return -1; } if (rlen < 3) { DBG_PRINT("return incomplete len=%d\n", rlen); return -1; } if (rbuf[0] != CC_SUCCESS) { DBG_PRINT("Completion Code: %02X\n", rbuf[0]); return -1; } if (rbuf[1] == 0x55) { return 0; } return -1; }