diff options
Diffstat (limited to 'meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/bic')
3 files changed, 633 insertions, 0 deletions
diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/bic/Makefile b/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/bic/Makefile new file mode 100644 index 0000000..12cb085 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/bic/Makefile @@ -0,0 +1,11 @@ +# Copyright 2015-present Facebook. All Rights Reserved. +lib: libbic.so + +libbic.so: bic.c + $(CC) $(CFLAGS) -fPIC -c -o bic.o bic.c + $(CC) -lipmb -shared -o libbic.so bic.o -lc + +.PHONY: clean + +clean: + rm -rf *.o libbic.so diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/bic/bic.c b/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/bic/bic.c new file mode 100644 index 0000000..55cd56b --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/bic/bic.c @@ -0,0 +1,466 @@ +/* + * + * Copyright 2015-present Facebook. All Rights Reserved. + * + * This file contains code to support IPMI2.0 Specificaton available @ + * http://www.intel.com/content/www/us/en/servers/ipmi/ipmi-specifications.html + * + * 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 <fcntl.h> +#include "bic.h" + +#define FRUID_READ_COUNT_MAX 0x30 +#define SDR_READ_COUNT_MAX 0x1A + +enum { + IPMB_BUS_SLOT1 = 3, + IPMB_BUS_SLOT2 = 1, + IPMB_BUS_SLOT3 = 7, + IPMB_BUS_SLOT4 = 5, +}; + +#pragma pack(push, 1) +typedef struct _sdr_rec_hdr_t { + uint16_t rec_id; + uint8_t ver; + uint8_t type; + uint8_t len; +} sdr_rec_hdr_t; +#pragma pack(pop) + +// Common IPMB Wrapper function + +static int +get_ipmb_bus_id(uint8_t slot_id) { + int bus_id; + + switch(slot_id) { + case 1: + bus_id = IPMB_BUS_SLOT1; + break; + case 2: + bus_id = IPMB_BUS_SLOT2; + break; + case 3: + bus_id = IPMB_BUS_SLOT3; + break; + case 4: + bus_id = IPMB_BUS_SLOT4; + break; + default: + bus_id = -1; + break; + } + + return bus_id; +} + +static int +bic_ipmb_wrapper(uint8_t slot_id, uint8_t netfn, uint8_t cmd, + uint8_t *txbuf, uint8_t txlen, + uint8_t *rxbuf, uint8_t *rxlen) { + ipmb_req_t *req; + ipmb_res_t *res; + uint8_t rbuf[MAX_IPMB_RES_LEN] = {0}; + uint8_t tbuf[MAX_IPMB_RES_LEN] = {0}; + uint8_t tlen = 0; + uint8_t rlen = 0; + int count = 0; + int i = 0; + int ret; + uint8_t bus_id; + + ret = get_ipmb_bus_id(slot_id); + if (ret < 0) { + printf("bic_ipmb_wrapper: Wrong Slot ID %d\n", slot_id); + return ret; + } + + bus_id = (uint8_t) ret; + + req = (ipmb_req_t*)tbuf; + + req->res_slave_addr = BRIDGE_SLAVE_ADDR << 1; + req->netfn_lun = netfn << LUN_OFFSET; + req->hdr_cksum = req->res_slave_addr + + req->netfn_lun; + req->hdr_cksum = ZERO_CKSUM_CONST - req->hdr_cksum; + + req->req_slave_addr = BMC_SLAVE_ADDR << 1; + req->seq_lun = 0x00; + req->cmd = cmd; + + //copy the data to be send + if (txlen) { + memcpy(req->data, txbuf, txlen); + } + + tlen = IPMB_HDR_SIZE + IPMI_REQ_HDR_SIZE + txlen; + + // Invoke IPMB library handler + lib_ipmb_handle(bus_id, tbuf, tlen, &rbuf, &rlen); + if (rlen == 0) { + printf("bic_ipmb_wrapper: Zero bytes received\n"); + return -1; + } + + // Handle IPMB response + res = (ipmb_res_t*) rbuf; + + if (res->cc) { + printf("bic_ipmb_wrapper: Completion Code: 0x%X\n", res->cc); + return -1; + } + + // copy the received data back to caller + *rxlen = rlen - IPMB_HDR_SIZE - IPMI_RESP_HDR_SIZE; + memcpy(rxbuf, res->data, *rxlen); + + return 0; +} + +// Get Device ID +int +bic_get_dev_id(uint8_t slot_id, ipmi_dev_id_t *dev_id) { + uint8_t rlen = 0; + int ret; + + ret = bic_ipmb_wrapper(slot_id, NETFN_APP_REQ, CMD_APP_GET_DEVICE_ID, NULL, 0, (uint8_t *) dev_id, &rlen); + + return ret; +} + +// Get GPIO value and configuration +int +bic_get_gpio(uint8_t slot_id, bic_gpio_t *gpio) { + uint8_t rlen = 0; + int ret; + + ret = bic_ipmb_wrapper(slot_id, NETFN_OEM_1S_REQ, CMD_OEM_1S_GET_GPIO, NULL, 0, (uint8_t*) gpio, &rlen); + + return ret; +} + +int +bic_get_gpio_config(uint8_t slot_id, uint8_t gpio, bic_gpio_config_t *gpio_config) { + uint8_t tbuf[4] = {0}; + uint8_t rlen = 0; + uint8_t tlen = 0; + uint32_t pin; + int ret; + + pin = 1 << gpio; + + tbuf[0] = pin & 0xFF; + tbuf[1] = (pin >> 8) & 0xFF; + tbuf[2] = (pin >> 16) & 0xFF; + tbuf[3] = (pin >> 24) & 0xFF; + + tlen = 4; + + ret = bic_ipmb_wrapper(slot_id, NETFN_OEM_1S_REQ, CMD_OEM_1S_GET_GPIO_CONFIG, tbuf, tlen, (uint8_t *) gpio_config, &rlen); + + return ret; +} + +int +bic_set_gpio_config(uint8_t slot_id, uint8_t gpio, bic_gpio_config_t *gpio_config) { + uint8_t tbuf[5] = {0}; + uint8_t rlen = 0; + uint8_t tlen = 0; + uint32_t pin; + uint8_t res; + int ret; + + pin = 1 << gpio; + + tbuf[0] = pin & 0xFF; + tbuf[1] = (pin >> 8) & 0xFF; + tbuf[2] = (pin >> 16) & 0xFF; + tbuf[3] = (pin >> 24) & 0xFF; + tbuf[4] = (*(uint8_t *) gpio_config) & 0x1F; + + tlen = 5; + + ret = bic_ipmb_wrapper(slot_id, NETFN_OEM_1S_REQ, CMD_OEM_1S_SET_GPIO_CONFIG, + tbuf, tlen, &res, &rlen); + return ret; +} + +// Get BIC Configuration +int +bic_get_config(uint8_t slot_id, bic_config_t *cfg) { + uint8_t rlen = 0; + int ret; + + ret = bic_ipmb_wrapper(slot_id, NETFN_OEM_1S_REQ, CMD_OEM_1S_GET_CONFIG, + NULL, 0x00, (uint8_t *) cfg, &rlen); + return ret; +} + +// Set BIC Configuration +int +bic_set_config(uint8_t slot_id, bic_config_t *cfg) { + uint8_t rlen = 0; + uint8_t rbuf[4] = {0}; + int ret; + + ret = bic_ipmb_wrapper(slot_id, NETFN_OEM_1S_REQ, CMD_OEM_1S_SET_CONFIG, + (uint8_t *) cfg, 1, rbuf, &rlen); + return ret; +} + +// Read POST Buffer +int +bic_get_post_buf(uint8_t slot_id, uint8_t *buf, uint8_t *len) { + int ret; + + ret = bic_ipmb_wrapper(slot_id, NETFN_OEM_1S_REQ, CMD_OEM_1S_GET_POST_BUF, NULL, 0, buf, len); + + return ret; +} + +// Read 1S server's FRUID +int +bic_get_fruid_info(uint8_t slot_id, uint8_t fru_id, ipmi_fruid_info_t *info) { + int ret; + uint8_t rlen = 0; + + ret = bic_ipmb_wrapper(slot_id, NETFN_STORAGE_REQ, CMD_STORAGE_GET_FRUID_INFO, &fru_id, 1, (uint8_t *) info, &rlen); + + return ret; +} + +static int +_read_fruid(uint8_t slot_id, uint8_t fru_id, uint32_t offset, uint8_t count, uint8_t *rbuf, uint8_t *rlen) { + int ret; + uint8_t tbuf[4] = {0}; + uint8_t tlen = 0; + + tbuf[0] = fru_id; + tbuf[1] = offset & 0xFF; + tbuf[2] = (offset >> 8) & 0xFF; + tbuf[3] = count; + + ret = bic_ipmb_wrapper(slot_id, NETFN_STORAGE_REQ, CMD_STORAGE_READ_FRUID_DATA, tbuf, 4, rbuf, rlen); + + return ret; +} + +int +bic_read_fruid(uint8_t slot_id, uint8_t fru_id, const char *path) { + int ret; + uint32_t nread; + uint32_t offset; + uint8_t count; + uint8_t rbuf[256] = {0}; + uint8_t rlen = 0; + int fd; + ipmi_fruid_info_t info; + + // Remove the file if exists already + unlink(path); + + // Open the file exclusively for write + fd = open(path, O_WRONLY | O_CREAT | O_EXCL, 0666); + if (fd < 0) { + printf("bic_read_fruid: open fails for path: %s\n", path); + goto error_exit; + } + + // Read the FRUID information + ret = bic_get_fruid_info(slot_id, fru_id, &info); + if (ret) { + printf("bic_read_fruid: bic_read_fruid_info returns %d\n", ret); + goto error_exit; + } + + // Indicates the size of the FRUID + nread = (info.size_msb << 8) + (info.size_lsb); + + // Read chunks of FRUID binary data in a loop + offset = 0; + while (nread > 0) { + if (nread > FRUID_READ_COUNT_MAX) { + count = FRUID_READ_COUNT_MAX; + } else { + count = nread; + } + + ret = _read_fruid(slot_id, fru_id, offset, count, rbuf, &rlen); + if (ret) { + printf("bic_read_fruid: ipmb_wrapper fails\n"); + goto error_exit; + } + + // Ignore the first byte as it indicates length of response + write(fd, &rbuf[1], rlen-1); + + // Update offset + offset += (rlen-1); + nread -= (rlen-1); + } + +error_exit: + if (fd > 0 ) { + close(fd); + } + + return ret; +} + +// Read System Event Log (SEL) +int +bic_get_sel_info(uint8_t slot_id, ipmi_sel_sdr_info_t *info) { + int ret; + uint8_t rlen = 0; + + ret = bic_ipmb_wrapper(slot_id, NETFN_STORAGE_REQ, CMD_STORAGE_GET_SEL_INFO, NULL, 0, (uint8_t *)info, &rlen); + + return ret; +} + +static int +_get_sel_rsv(uint8_t slot_id, uint16_t *rsv) { + int ret; + uint8_t rlen = 0; + + ret = bic_ipmb_wrapper(slot_id, NETFN_STORAGE_REQ, CMD_STORAGE_RSV_SEL, NULL, 0, (uint8_t *) rsv, &rlen); + return ret; +} + +int +bic_get_sel(uint8_t slot_id, ipmi_sel_sdr_req_t *req, ipmi_sel_sdr_res_t *res, uint8_t *rlen) { + + int ret; + + ret = bic_ipmb_wrapper(slot_id, NETFN_STORAGE_REQ, CMD_STORAGE_GET_SEL, (uint8_t *)req, sizeof(ipmi_sel_sdr_req_t), (uint8_t*)res, rlen); + + return ret; +} + +// Read Sensor Data Records (SDR) +int +bic_get_sdr_info(uint8_t slot_id, ipmi_sel_sdr_info_t *info) { + int ret; + uint8_t rlen = 0; + + ret = bic_ipmb_wrapper(slot_id, NETFN_STORAGE_REQ, CMD_STORAGE_GET_SDR_INFO, NULL, 0, (uint8_t *) info, &rlen); + + return ret; +} + +static int +_get_sdr_rsv(uint8_t slot_id, uint16_t *rsv) { + int ret; + uint8_t rlen = 0; + + ret = bic_ipmb_wrapper(slot_id, NETFN_STORAGE_REQ, CMD_STORAGE_RSV_SDR, NULL, 0, (uint8_t *) rsv, &rlen); + + return ret; +} + +static int +_get_sdr(uint8_t slot_id, ipmi_sel_sdr_req_t *req, ipmi_sel_sdr_res_t *res, uint8_t *rlen) { + int ret; + + ret = bic_ipmb_wrapper(slot_id, NETFN_STORAGE_REQ, CMD_STORAGE_GET_SDR, (uint8_t *)req, sizeof(ipmi_sel_sdr_req_t), (uint8_t*)res, rlen); + + return ret; +} + +int +bic_get_sdr(uint8_t slot_id, ipmi_sel_sdr_req_t *req, ipmi_sel_sdr_res_t *res, uint8_t *rlen) { + int ret; + uint8_t tbuf[MAX_IPMB_RES_LEN] = {0}; + uint8_t tlen; + uint8_t len; + ipmi_sel_sdr_res_t *tres; + sdr_rec_hdr_t *hdr; + + tres = (ipmi_sel_sdr_res_t *) tbuf; + + // Get SDR reservation ID for the given record + ret = _get_sdr_rsv(slot_id, &req->rsv_id); + if (ret) { + printf("bic_read_sdr: _get_sdr_rsv returns %d\n", ret); + return ret; + } + + // Initialize the response length to zero + *rlen = 0; + + // Read SDR Record Header + req->offset = 0; + req->nbytes = sizeof(sdr_rec_hdr_t); + + ret = _get_sdr(slot_id, req, tbuf, &tlen); + if (ret) { + printf("bic_read_sdr: _get_sdr returns %d\n", ret); + return ret; + } + + // Copy the next record id to response + res->next_rec_id = tres->next_rec_id; + + // Copy the header excluding first two bytes(next_rec_id) + memcpy(res->data, tres->data, tlen-2); + + // Update response length and offset for next request + *rlen += tlen-2; + req->offset = tlen-2; + + // Find length of data from header info + hdr = (sdr_rec_hdr_t *) tres->data; + len = hdr->len; + + // Keep reading chunks of SDR record in a loop + while (len > 0) { + if (len > SDR_READ_COUNT_MAX) { + req->nbytes = SDR_READ_COUNT_MAX; + } else { + req->nbytes = len; + } + + ret = _get_sdr(slot_id, req, tbuf, &tlen); + if (ret) { + printf("bic_read_sdr: _get_sdr returns %d\n", ret); + return ret; + } + + // Copy the data excluding the first two bytes(next_rec_id) + memcpy(&res->data[req->offset], tres->data, tlen-2); + + // Update response length, offset for next request, and remaining length + *rlen += tlen-2; + req->offset += tlen-2; + len -= tlen-2; + } + + return 0; +} + +int +bic_read_sensor(uint8_t slot_id, uint8_t sensor_num, ipmi_sensor_reading_t *sensor) { + int ret; + int rlen = 0; + + ret = bic_ipmb_wrapper(slot_id, NETFN_SENSOR_REQ, CMD_SENSOR_GET_SENSOR_READING, (uint8_t *)&sensor_num, 1, (uint8_t *)sensor, &rlen); + + return ret; +} diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/bic/bic.h b/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/bic/bic.h new file mode 100644 index 0000000..47b0baa --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/bic/bic.h @@ -0,0 +1,156 @@ +/* + * + * Copyright 2015-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. + */ + +#ifndef __BIC_H__ +#define __BIC_H__ + +#include <openbmc/ipmi.h> +#include <openbmc/ipmb.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define MAX_GPIO_PINS 32 + +// GPIO PINS +enum { + PWRGOOD_CPU = 0x0, + PWRGD_PCH_PWROK, + PVDDR_VRHOT_N, + PVCCIN_VRHOT_N, + FM_FAST_PROCHOT_N, + PCHHOT_CPU_N, + FM_CPLD_CPU_DIMM_EVENT_CO_N, + FM_CPLD_BDXDE_THERMTRIP_N, + THERMTRIP_PCH_N, + FM_CPLD_FIVR_FAULT, + FM_BDXDE_CATERR_LVT3_N, + FM_BDXDE_ERR2_LVT3_N, + FM_BDXDE_ERR1_LVT3_N, + FM_BDXDE_ERR0_LVT3_N, + SLP_S4_N, + FM_NMI_EVENT_BMC_N, + FM_SMI_BMC_N, + RST_PLTRST_BMC_N, + FP_RST_BTN_BUF_N, + BMC_RST_BTN_OUT_N, + FM_BDE_POST_CMPLT_N, + FM_BDXDE_SLP3_N, + FM_PWR_LED_N, + PWRGD_PVCCIN, + SVR_ID0, + SVR_ID1, + SVR_ID2, + SVR_ID3, + BMC_READY_N, + RESERVED_29, + RESERVED_30, + RESERVED_31, +}; + +// Bridge IC Spec +typedef struct _bic_gpio_t { + uint32_t pwrgood_cpu:1; + uint32_t pwrgd_pch_pwrok:1; + uint32_t pvddr_vrhot_n:1; + uint32_t pvccin_vrhot_n:1; + uint32_t fm_fast_prochot_n:1; + uint32_t pchhot_cpu_n:1; + uint32_t fm_cpld_cpu_dimm_event_c0_n:1; + uint32_t fm_cpld_bdxde_thermtrip_n:1; + uint32_t thermtrip_pch_n:1; + uint32_t fm_cpld_fivr_fault:1; + uint32_t fm_bdxde_caterr_lvt3_n:1; + uint32_t fm_bdxde_err_lvt3_n:3; + uint32_t slp_s4_n:1; + uint32_t fm_nmi_event_bmc_n:1; + uint32_t fm_smi_bmc_n:1; + uint32_t rst_pltrst_bmc_n:1; + uint32_t fp_rst_btn_buf_n:1; + uint32_t bmc_rst_btn_out_n:1; + uint32_t fm_bde_post_cmplt_n:1; + uint32_t fm_bdxde_slp3_n:1; + uint32_t fm_pwr_led_n:1; + uint32_t pwrgd_pvccin:1; + uint32_t svr_id:4; + uint32_t bmc_ready_n:1; + uint32_t bmc_com_sw_n:1; + uint32_t rsvd:2; +} bic_gpio_t; + +typedef union _bic_gpio_u { + uint8_t gpio[4]; + bic_gpio_t bits; +} bic_gpio_u; + +typedef struct _bic_gpio_config_t { + uint8_t dir:1; + uint8_t ie:1; + uint8_t edge:1; + uint8_t trig:2; +} bic_gpio_config_t; + +typedef union _bic_gpio_config_u { + uint8_t config; + bic_gpio_config_t bits; +} bic_gpio_config_u; + +typedef struct _bic_config_t { + uint8_t sol:1; + uint8_t post:1; + uint8_t kcs:1; + uint8_t ipmb:1; + uint8_t rsvd:4; +} bic_config_t; + +typedef union _bic_config_u { + uint8_t config; + bic_config_t bits; +} bic_config_u; + +int bic_get_dev_id(uint8_t slot_id, ipmi_dev_id_t *id); + +int bic_get_bic_config(uint8_t slot_id, bic_config_t *cfg); +int bic_set_bic_config(uint8_t slot_id, bic_config_t *cfg); + +int bic_get_gpio(uint8_t slot_id, bic_gpio_t *gpio); +int bic_get_gpio_config(uint8_t slot_id, uint8_t gpio, bic_gpio_config_t *gpio_config); +int bic_set_gpio_config(uint8_t slot_id, uint8_t gpio, bic_gpio_config_t *gpio_config); +int bic_get_post_buf(uint8_t slot_id, uint8_t *buf, uint8_t *len); + +int bic_get_fruid_info(uint8_t slot_id, uint8_t fru_id, ipmi_fruid_info_t *info); +int bic_read_fruid(uint8_t slot_id, uint8_t fru_id, const char *path); + +int bic_get_sel_info(uint8_t slot_id, ipmi_sel_sdr_info_t *info); +int bic_get_sel_rsv(uint8_t slot_id, uint16_t *rsv); +int bic_get_sel(uint8_t slot_id, ipmi_sel_sdr_req_t *req, ipmi_sel_sdr_res_t *res, uint8_t *rlen); + +int bic_get_sdr_info(uint8_t slot_id, ipmi_sel_sdr_info_t *info); +int bic_get_sdr_rsv(uint8_t slot_id, uint16_t *rsv); +int bic_get_sdr(uint8_t slot_id, ipmi_sel_sdr_req_t *req, ipmi_sel_sdr_res_t *res, uint8_t *rlen); + +int bic_read_sensor(uint8_t slot_id, uint8_t sensor_num, ipmi_sensor_reading_t *sensor); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif /* __BIC_H__ */ |