// Copyright(c) 2018-2020, Intel Corporation // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // * Neither the name of Intel Corporation nor the names of its contributors // may be used to endorse or promote products derived from this software // without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. #include #include "bmc.h" #include "bmcdata.h" #include #include #ifndef _WIN32 #include #include #else #include #endif #include #include #include "bmc_ioctl.h" #include #define NULL_CHECK(x) \ do { \ if (NULL == (x)) { \ return FPGA_INVALID_PARAM; \ } \ } while (0) fpga_result rawFromDouble(Values *details, double dbl, uint8_t *raw) { fpga_result res = FPGA_OK; NULL_CHECK(details); NULL_CHECK(raw); int32_t R_exp = -(details->result_exp); int32_t i; for (i = 0; i < abs(R_exp); i++) { if (R_exp < 0) { dbl /= 10.0; } else { dbl *= 10.0; } } dbl = (dbl - details->B) / details->M; *raw = dbl > (double)0xff ? (uint8_t)0xff : (uint8_t)dbl; return res; } void fill_set_request(Values *vals, threshold_list *thresh, bmc_set_thresh_request *req) { fpga_result res = FPGA_OK; uint8_t mask = 0; if (thresh->upper_nr_thresh.is_valid) { mask |= UNR_thresh; res += rawFromDouble(vals, thresh->upper_nr_thresh.value, &req->UNR); } else { mask &= ~UNR_thresh; } if (thresh->upper_c_thresh.is_valid) { mask |= UC_thresh; res += rawFromDouble(vals, thresh->upper_c_thresh.value, &req->UC); } else { mask &= ~UC_thresh; } if (thresh->upper_nc_thresh.is_valid) { mask |= UNC_thresh; res += rawFromDouble(vals, thresh->upper_nc_thresh.value, &req->UNC); } else { mask &= ~UNC_thresh; } if (thresh->lower_nr_thresh.is_valid) { mask |= LNR_thresh; res += rawFromDouble(vals, thresh->lower_nr_thresh.value, &req->LNR); } else { mask &= ~LNR_thresh; } if (thresh->lower_c_thresh.is_valid) { mask |= LC_thresh; res += rawFromDouble(vals, thresh->lower_c_thresh.value, &req->LC); } else { mask &= ~LC_thresh; } if (thresh->lower_nc_thresh.is_valid) { mask |= LNC_thresh; res += rawFromDouble(vals, thresh->lower_nc_thresh.value, &req->LNC); } else { mask &= ~LNC_thresh; } if (FPGA_OK == res) { req->mask = mask; } } fpga_result _bmcSetThreshold(int fd, uint32_t sensor, bmc_set_thresh_request *req) { bmc_xact xact = {0}; bmc_set_thresh_response resp; fpga_result res = FPGA_OK; xact.argsz = sizeof(xact); xact.txlen = sizeof(bmc_set_thresh_request); xact.rxlen = sizeof(bmc_set_thresh_response); xact.txbuf = (uint64_t)req; xact.rxbuf = (uint64_t)&resp; req->sens_num = sensor; req->header[0] = BMC_THRESH_HEADER_0; req->header[1] = BMC_THRESH_HEADER_1; req->header[2] = BMC_SET_THRESH_CMD; if (ioctl(fd, _IOWR(AVMMI_BMC_MAGIC, 0, struct avmmi_bmc_xact), &xact) != 0) { res = FPGA_INVALID_PARAM; goto out_close; } if (resp.cc) { res = FPGA_EXCEPTION; } out_close: return res; } fpga_result _bmcGetThreshold(int fd, uint32_t sensor, bmc_get_thresh_response *resp) { bmc_xact xact = {0}; bmc_get_thresh_request req; fpga_result res = FPGA_OK; xact.argsz = sizeof(xact); xact.txlen = sizeof(bmc_get_thresh_request); xact.rxlen = sizeof(bmc_get_thresh_response); xact.txbuf = (uint64_t)&req; xact.rxbuf = (uint64_t)resp; req.sens_num = sensor; req.header[0] = BMC_THRESH_HEADER_0; req.header[1] = BMC_THRESH_HEADER_1; req.header[2] = BMC_GET_THRESH_CMD; if (ioctl(fd, _IOWR(AVMMI_BMC_MAGIC, 0, struct avmmi_bmc_xact), &xact) != 0) { res = FPGA_INVALID_PARAM; goto out_close; } if (resp->cc) { res = FPGA_EXCEPTION; } out_close: return res; } fpga_result bmcSetHWThresholds(bmc_sdr_handle sdr_h, uint32_t sensor, threshold_list *thresh) { fpga_result res = FPGA_OK; char sysfspath[SYSFS_PATH_MAX] = { 0, }; int fd = 0; bmc_set_thresh_request req; Values *vals; sensor_reading read; bmc_get_thresh_response resp; size_t len; NULL_CHECK(sdr_h); NULL_CHECK(thresh); struct _sdr_rec *sdr = (struct _sdr_rec *)sdr_h; if (BMC_SDR_MAGIC != sdr->magic) { return FPGA_INVALID_PARAM; } if (sensor >= sdr->num_records) { return FPGA_INVALID_PARAM; } if (snprintf(sysfspath, sizeof(sysfspath), "%s/" SYSFS_AVMMI_DIR, sdr->sysfs_path) < 0) { OPAE_ERR("snprintf buffer overflow"); return FPGA_EXCEPTION; } glob_t pglob; int gres = glob(sysfspath, GLOB_NOSORT, NULL, &pglob); if ((gres) || (1 != pglob.gl_pathc)) { globfree(&pglob); return FPGA_NOT_FOUND; } char *avmmi = strrchr(pglob.gl_pathv[0], '/'); if (NULL == avmmi) { globfree(&pglob); return FPGA_NOT_FOUND; } strncpy(sysfspath, "/dev/", 6); len = strnlen(&avmmi[1], sizeof(sysfspath) - 6); strncat(sysfspath, &avmmi[1], len + 1); fd = open(sysfspath, O_RDWR); globfree(&pglob); if (fd < 0) { return FPGA_NOT_FOUND; } memset(&req, 0, sizeof(req)); memset(&read, 0, sizeof(read)); vals = bmc_build_values(&read, &sdr->contents[sensor].header, &sdr->contents[sensor].key, &sdr->contents[sensor].body); if (NULL == vals) { close(fd); return FPGA_NO_MEMORY; } res = _bmcGetThreshold(fd, sensor, &resp); if (FPGA_OK != res) { fprintf(stderr, "Error returned from _bmcGetThreshold\n"); } lseek(fd, 0, SEEK_SET); req.mask = resp.mask; req.LNC = resp.LNC; req.LC = resp.LC; req.LNR = resp.LNR; req.UNC = resp.UNC; req.UC = resp.UC; req.UNR = resp.UNR; fill_set_request(vals, thresh, &req); if (vals->name) free(vals->name); if (vals) free(vals); res = _bmcSetThreshold(fd, sensor, &req); close(fd); return res; }