diff options
Diffstat (limited to 'meta-facebook/meta-yosemite/recipes-yosemite')
115 files changed, 13948 insertions, 0 deletions
diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/bic-cached/bic-cached_0.1.bb b/meta-facebook/meta-yosemite/recipes-yosemite/bic-cached/bic-cached_0.1.bb new file mode 100644 index 0000000..ef7a15c --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/bic-cached/bic-cached_0.1.bb @@ -0,0 +1,44 @@ +# Copyright 2015-present Facebook. All Rights Reserved. + +SUMMARY = "Bridge IC Cache Daemon" +DESCRIPTION = "Daemon to provide Bridge IC Cache information." +SECTION = "base" +PR = "r1" +LICENSE = "GPLv2" +LIC_FILES_CHKSUM = "file://bic-cached.c;beginline=5;endline=17;md5=da35978751a9d71b73679307c4d296ec" + + +DEPENDS_append = "libbic update-rc.d-native" + +SRC_URI = "file://Makefile \ + file://setup-bic-cached.sh \ + file://bic-cached.c \ + " + +S = "${WORKDIR}" + +binfiles = "bic-cached" + +pkgdir = "bic-cached" + +do_install() { + dst="${D}/usr/local/fbpackages/${pkgdir}" + bin="${D}/usr/local/bin" + install -d $dst + install -d $bin + install -m 755 bic-cached ${dst}/bic-cached + ln -snf ../fbpackages/${pkgdir}/bic-cached ${bin}/bic-cached + install -d ${D}${sysconfdir}/init.d + install -d ${D}${sysconfdir}/rcS.d + install -m 755 setup-bic-cached.sh ${D}${sysconfdir}/init.d/setup-bic-cached.sh + update-rc.d -r ${D} setup-bic-cached.sh start 66 S . +} + +FBPACKAGEDIR = "${prefix}/local/fbpackages" + +FILES_${PN} = "${FBPACKAGEDIR}/bic-cached ${prefix}/local/bin ${sysconfdir} " + +# Inhibit complaints about .debug directories: + +INHIBIT_PACKAGE_DEBUG_SPLIT = "1" +INHIBIT_PACKAGE_STRIP = "1" diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/bic-cached/files/Makefile b/meta-facebook/meta-yosemite/recipes-yosemite/bic-cached/files/Makefile new file mode 100644 index 0000000..478b25e --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/bic-cached/files/Makefile @@ -0,0 +1,10 @@ +# Copyright 2015-present Facebook. All Rights Reserved. +all: bic-cached + +bic-cached: bic-cached.c + $(CC) -pthread -lbic -std=c99 -o $@ $^ $(LDFLAGS) + +.PHONY: clean + +clean: + rm -rf *.o bic-cached diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/bic-cached/files/bic-cached.c b/meta-facebook/meta-yosemite/recipes-yosemite/bic-cached/files/bic-cached.c new file mode 100644 index 0000000..3a2dd28 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/bic-cached/files/bic-cached.c @@ -0,0 +1,133 @@ +/* + * + * 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. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <syslog.h> +#include <string.h> +#include <pthread.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <openbmc/ipmi.h> +#include <openbmc/ipmb.h> +#include <facebook/bic.h> + +#define LAST_RECORD_ID 0xFFFF +#define MAX_SENSOR_NUM 0xFF +#define BYTES_ENTIRE_RECORD 0xFF + +void +fruid_cache_init(uint8_t slot_id) { + // Initialize Slot0's fruid + int ret; + int i; + char fruid_temp_path[64] = {0}; + char fruid_path[64] = {0}; + + sprintf(fruid_temp_path, "/tmp/tfruid_slot%d.bin", slot_id); + sprintf(fruid_path, "/tmp/fruid_slot%d.bin", slot_id); + + ret = bic_read_fruid(slot_id, 0, fruid_temp_path); + if (ret) { + syslog(LOG_ALERT, "fruid_cache_init: bic_read_fruid returns %d\n", ret); + } + + rename(fruid_temp_path, fruid_path); + + return; +} + +void +sdr_cache_init(uint8_t slot_id) { + int ret; + int fd; + uint8_t rlen; + uint8_t rbuf[MAX_IPMB_RES_LEN] = {0}; + char *path = NULL; + char sdr_temp_path[64] = {0}; + char sdr_path[64] = {0}; + + sprintf(sdr_temp_path, "/tmp/tsdr_slot%d.bin", slot_id); + sprintf(sdr_path, "/tmp/sdr_slot%d.bin", slot_id); + + ipmi_sel_sdr_req_t req; + ipmi_sel_sdr_res_t *res = (ipmi_sel_sdr_res_t *) rbuf; + + req.rsv_id = 0; + req.rec_id = 0; + req.offset = 0; + req.nbytes = BYTES_ENTIRE_RECORD; + + // Read Slot0's SDR records and store + path = sdr_temp_path; + unlink(path); + fd = open(path, O_WRONLY | O_CREAT | O_EXCL, 0666); + if (fd < 0) { + syslog(LOG_ALERT, "sdr_cache_init: open fails for path: %s\n", path); + return; + } + + while (1) { + ret = bic_get_sdr(slot_id, &req, res, &rlen); + if (ret) { + syslog(LOG_ALERT, "sdr_cache_init:bic_get_sdr returns %d\n", ret); + continue; + } + + sdr_full_t *sdr = res->data; + + write(fd, sdr, sizeof(sdr_full_t)); + + req.rec_id = res->next_rec_id; + if (req.rec_id == LAST_RECORD_ID) { + // syslog(LOG_INFO, "This record is LAST record\n"); + break; + } + } + + rename(sdr_temp_path, sdr_path); +} + +int +main (int argc, char * const argv[]) +{ + int ret; + ipmi_dev_id_t id = {0}; + uint8_t slot_id; + + if (argc != 2) { + return -1; + } + + slot_id = atoi(argv[1]); + + do { + ret = bic_get_dev_id(slot_id, &id); + sleep(5); + } while (ret != 0); + + fruid_cache_init(slot_id); + sdr_cache_init(slot_id); + + return 0; +} diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/bic-cached/files/setup-bic-cached.sh b/meta-facebook/meta-yosemite/recipes-yosemite/bic-cached/files/setup-bic-cached.sh new file mode 100644 index 0000000..45eb1e3 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/bic-cached/files/setup-bic-cached.sh @@ -0,0 +1,33 @@ +#!/bin/sh +# +# Copyright 2015-present Facebook. All Rights Reserved. +# +### BEGIN INIT INFO +# Provides: setup-bic-cached +# Required-Start: +# Required-Stop: +# Default-Start: S +# Default-Stop: +# Short-Description: Set Cachcing for Bridge IC info +### END INIT INFO + +. /usr/local/fbpackages/utils/ast-functions + +echo -n "Setup Caching for Bridge IC info.." +if [ $(is_server_prsnt 1) == "1" ]; then + /usr/local/bin/bic-cached 1 > /dev/null 2>&1 & +fi + +if [ $(is_server_prsnt 2) == "1" ]; then +/usr/local/bin/bic-cached 2 > /dev/null 2>&1 & +fi + +if [ $(is_server_prsnt 3) == "1" ]; then +/usr/local/bin/bic-cached 3 > /dev/null 2>&1 & +fi + +if [ $(is_server_prsnt 4) == "1" ]; then +/usr/local/bin/bic-cached 4 > /dev/null 2>&1 & +fi + +echo "done." diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/consoled/consoled_0.1.bbappend b/meta-facebook/meta-yosemite/recipes-yosemite/consoled/consoled_0.1.bbappend new file mode 100644 index 0000000..12a1d17 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/consoled/consoled_0.1.bbappend @@ -0,0 +1,53 @@ +# Copyright 2015-present Facebook. All Rights Reserved. +# +# This program file 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; version 2 of the License. +# +# 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 in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA + +FILESEXTRAPATHS_prepend := "${THISDIR}/files:" + +SRC_URI += "file://setup-consoled.sh \ + " + +S = "${WORKDIR}" + + +pkgdir = "consoled" + +do_install() { + dst="${D}/usr/local/fbpackages/${pkgdir}" + bin="${D}/usr/local/bin" + install -d $dst + install -d $bin + for f in ${binfiles}; do + install -m 755 $f ${dst}/$f + ln -snf ../fbpackages/${pkgdir}/$f ${bin}/$f + done + for f in ${otherfiles}; do + install -m 644 $f ${dst}/$f + done + install -d ${D}${sysconfdir}/init.d + install -d ${D}${sysconfdir}/rcS.d + install -m 755 setup-consoled.sh ${D}${sysconfdir}/init.d/setup-consoled.sh + update-rc.d -r ${D} setup-consoled.sh start 91 S . +} + +FBPACKAGEDIR = "${prefix}/local/fbpackages" + +FILES_${PN} = "${FBPACKAGEDIR}/consoled ${prefix}/local/bin ${sysconfdir} " + +# Inhibit complaints about .debug directories for the sensord binary: + +INHIBIT_PACKAGE_DEBUG_SPLIT = "1" +INHIBIT_PACKAGE_STRIP = "1" diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/consoled/files/setup-consoled.sh b/meta-facebook/meta-yosemite/recipes-yosemite/consoled/files/setup-consoled.sh new file mode 100644 index 0000000..8c50e49 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/consoled/files/setup-consoled.sh @@ -0,0 +1,51 @@ +#!/bin/sh +# +# Copyright 2015-present Facebook. All Rights Reserved. +# +# This program file 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; version 2 of the License. +# +# 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 in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +# + +### BEGIN INIT INFO +# Provides: setup-consoled +# Required-Start: +# Required-Stop: +# Default-Start: S +# Default-Stop: +# Short-Description: Setup console history buffering +### END INIT INFO + +. /usr/local/fbpackages/utils/ast-functions + +# TODO: check for the if slot/server is present before starting the daemon +echo -n "Setup console buffering..." + + if [ $(is_server_prsnt 1) == "1" ] ; then + /usr/local/bin/consoled slot1 --buffer + fi + + if [ $(is_server_prsnt 2) == "1" ] ; then + /usr/local/bin/consoled slot2 --buffer + fi + + if [ $(is_server_prsnt 3) == "1" ] ; then + /usr/local/bin/consoled slot3 --buffer + fi + + if [ $(is_server_prsnt 4) == "1" ] ; then + /usr/local/bin/consoled slot4 --buffer + fi + +echo "done." diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fan-ctrl/fan-ctrl/get_fan_speed.sh b/meta-facebook/meta-yosemite/recipes-yosemite/fan-ctrl/fan-ctrl/get_fan_speed.sh new file mode 100755 index 0000000..c77c6f0 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fan-ctrl/fan-ctrl/get_fan_speed.sh @@ -0,0 +1,53 @@ +#!/bin/sh +# +# Copyright 2015-present Facebook. All Rights Reserved. +# +# This program file 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; version 2 of the License. +# +# 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 in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +# +usage() { + echo "Usage: $0 [Fan Unit (0..1)]" >&2 +} + +PWM_DIR=/sys/devices/platform/ast_pwm_tacho.0 +set -e + +# refer to the comments in init_pwn.sh regarding +# the fan unit and tacho mapping +if [ "$#" -eq 0 ]; then + TACHOS="0:0 1:1" +elif [ "$#" -eq 1 ]; then + case "$1" in + "0") + TACHOS="0:0" + ;; + "1") + TACHOS="1:1" + ;; + *) + usage + exit 1 + ;; + esac +else + usage + exit 1 +fi + +for fan_tacho in $TACHOS; do + fan=${fan_tacho%%:*} + tacho=${fan_tacho##*:} + echo "Fan $fan RPM: $(cat $PWM_DIR/tacho${tacho}_rpm)" +done diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fan-ctrl/fan-ctrl/init_pwm.sh b/meta-facebook/meta-yosemite/recipes-yosemite/fan-ctrl/fan-ctrl/init_pwm.sh new file mode 100755 index 0000000..8c8adc6 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fan-ctrl/fan-ctrl/init_pwm.sh @@ -0,0 +1,64 @@ +#!/bin/sh +# +# Copyright 2015-present Facebook. All Rights Reserved. +# +# This program file 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; version 2 of the License. +# +# 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 in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +# +PWM_DIR=/sys/devices/platform/ast_pwm_tacho.0 + +set -e + +# The PWM frequency is + +# clk_source / ((2 ^ division_) * (2 * division_l) * (unit + 1)) +# +# Our clk_source is 24Mhz. 4-pin fans are generally supposed to be driven with +# a 25Khz PWM control signal. Therefore we want the divisor to equal 960. +# +# We also want the unit to be as large as possible, since this controls the +# granularity with which we can modulate the PWM signal. The following +# settings allow us to set the fan from 0 to 100% in increments of 1/96th. +# +# The AST chip supports 3 different PWM clock configurations, but we only use +# type M for now. +echo 0 > $PWM_DIR/pwm_type_m_division_h +echo 5 > $PWM_DIR/pwm_type_m_division_l +echo 95 > $PWM_DIR/pwm_type_m_unit + +# On Yosemite, there are 2 fans connected. +# Each fan uses same PWM input and provide one tacho output. +# Here is the mapping between the fan and PWN/Tacho, +# staring from the one from the edge +# Fan 0: PWM 0, Tacho0 +# Fan 1: PWM 0, Tacho1 + +# For each fan, setting the type, and 100% initially +for pwm in 0 1; do + echo 0 > $PWM_DIR/pwm${pwm}_type + echo 0 > $PWM_DIR/pwm${pwm}_rising + echo 0 > $PWM_DIR/pwm${pwm}_falling + echo 1 > $PWM_DIR/pwm${pwm}_en +done + +# Enable Tach 0..1 +echo 0 > $PWM_DIR/tacho0_source +echo 1 > $PWM_DIR/tacho1_source + +t=0 +while [ $t -le 1 ]; do + echo 1 > $PWM_DIR/tacho${t}_en + t=$((t+1)) +done diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fan-ctrl/fan-ctrl/set_fan_speed.sh b/meta-facebook/meta-yosemite/recipes-yosemite/fan-ctrl/fan-ctrl/set_fan_speed.sh new file mode 100755 index 0000000..49ef55b --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fan-ctrl/fan-ctrl/set_fan_speed.sh @@ -0,0 +1,79 @@ +#!/bin/sh +# +# Copyright 2004-present Facebook. All Rights Reserved. +# +# This program file 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; version 2 of the License. +# +# 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 in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +# +usage() { + echo "Usage: $0 <PERCENT (0..100)> <Fan Unit (0..1)> " >&2 +} + +PWM_DIR=/sys/devices/platform/ast_pwm_tacho.0 + +# The maximum unit setting. +# This should be the value in pwm_type_m_unit plus 1 +PWM_UNIT_MAX=96 + +set -e + +if [ "$#" -ne 2 ] && [ "$#" -ne 1 ]; then + usage + exit 1 +fi + +# refer to the comments in init_pwn.sh regarding +# the fan unit and PWM mapping +if [ "$#" -eq 1 ]; then + PWMS="0:0 1:0" +else + case "$2" in + "0") + PWMS="0:0" + ;; + "1") + PWMS="1:0" + ;; + *) + usage + exit 1 + ;; + esac +fi + +# Convert the percentage to our 1/96th unit. +unit=$(( ( $1 * $PWM_UNIT_MAX ) / 100 )) + +for FAN_PWM in $PWMS; do + FAN_N=${FAN_PWM%%:*} + PWM_N=${FAN_PWM##*:} + if [ "$unit" -eq 0 ]; then + # For 0%, turn off the PWM entirely + echo 0 > $PWM_DIR/pwm${PWM_N}_en + else + if [ "$unit" -eq $PWM_UNIT_MAX ]; then + # For 100%, set falling and rising to the same value + unit=0 + fi + + # always use type M. refer to the comments in init_pwm.sh + echo 0 > $PWM_DIR/pwm${PWM_N}_type + echo 0 > $PWM_DIR/pwm${PWM_N}_rising + echo "$unit" > $PWM_DIR/pwm${PWM_N}_falling + echo 1 > $PWM_DIR/pwm${PWM_N}_en + fi + + echo "Successfully set fan ${FAN_N} (PWM: $PWM_N) speed to $1%" +done diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fan-ctrl/fan-ctrl/setup-fan.sh b/meta-facebook/meta-yosemite/recipes-yosemite/fan-ctrl/fan-ctrl/setup-fan.sh new file mode 100644 index 0000000..72016d0 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fan-ctrl/fan-ctrl/setup-fan.sh @@ -0,0 +1,36 @@ +#!/bin/sh +# +# Copyright 2015-present Facebook. All Rights Reserved. +# +# This program file 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; version 2 of the License. +# +# 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 in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +# + +### BEGIN INIT INFO +# Provides: setup-fan +# Required-Start: board-id +# Required-Stop: +# Default-Start: S +# Default-Stop: +# Short-Description: Set fan speed +### END INIT INFO + +. /usr/local/fbpackages/utils/ast-functions + +echo -n "Setup fan speed... " +/usr/local/bin/init_pwm.sh +/usr/local/bin/set_fan_speed.sh 50 +/usr/local/bin/fand +echo "done." diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fan-ctrl/fan-ctrl_0.1.bbappend b/meta-facebook/meta-yosemite/recipes-yosemite/fan-ctrl/fan-ctrl_0.1.bbappend new file mode 100644 index 0000000..d5659ae --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fan-ctrl/fan-ctrl_0.1.bbappend @@ -0,0 +1,64 @@ +# Copyright 2014-present Facebook. All Rights Reserved. +# +# This program file 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; version 2 of the License. +# +# 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 in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA + +DEPENDS_append = "update-rc.d-native libyosemite-sensor" + +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" +SRC_URI += "file://get_fan_speed.sh \ + file://init_pwm.sh \ + file://set_fan_speed.sh \ + file://setup-fan.sh \ + " + +S = "${WORKDIR}" + +binfiles += "get_fan_speed.sh \ + init_pwm.sh \ + set_fan_speed.sh \ + " + +CXXFLAGS_prepend = "-DCONFIG_YOSEMITE " +LDFLAGS_append = " -lyosemite_sensor" + +pkgdir = "fan_ctrl" + +do_install() { + dst="${D}/usr/local/fbpackages/${pkgdir}" + bin="${D}/usr/local/bin" + install -d $dst + install -d $bin + for f in ${binfiles}; do + install -m 755 $f ${dst}/$f + ln -snf ../fbpackages/${pkgdir}/$f ${bin}/$f + done + for f in ${otherfiles}; do + install -m 644 $f ${dst}/$f + done + install -d ${D}${sysconfdir}/init.d + install -d ${D}${sysconfdir}/rcS.d + install -m 755 setup-fan.sh ${D}${sysconfdir}/init.d/setup-fan.sh + update-rc.d -r ${D} setup-fan.sh start 91 S . +} + +FBPACKAGEDIR = "${prefix}/local/fbpackages" + +FILES_${PN} = "${FBPACKAGEDIR}/fan_ctrl ${prefix}/local/bin ${sysconfdir} " + +# Inhibit complaints about .debug directories for the fand binary: + +INHIBIT_PACKAGE_DEBUG_SPLIT = "1" +INHIBIT_PACKAGE_STRIP = "1" 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__ */ diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/pal/Makefile b/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/pal/Makefile new file mode 100644 index 0000000..bab4007 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/pal/Makefile @@ -0,0 +1,11 @@ +# Copyright 2015-present Facebook. All Rights Reserved. +lib: libpal.so + +libpal.so: pal.c + $(CC) $(CFLAGS) -fPIC -c -o pal.o pal.c + $(CC) -lbic -lyosemite_common -lyosemite_fruid -lyosemite_sensor -shared -o libpal.so pal.o -lc + +.PHONY: clean + +clean: + rm -rf *.o libpal.so diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/pal/pal.c b/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/pal/pal.c new file mode 100644 index 0000000..93a5fbf --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/pal/pal.c @@ -0,0 +1,1151 @@ +/* + * + * 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 <stdbool.h> +#include <fcntl.h> +#include <errno.h> +#include <syslog.h> +#include <sys/mman.h> +#include <string.h> +#include "pal.h" + +#define BIT(value, index) ((value >> index) & 1) + +#define YOSEMITE_PLATFORM_NAME "Yosemite" +#define LAST_KEY "last_key" +#define YOSEMITE_MAX_NUM_SLOTS 4 +#define GPIO_VAL "/sys/class/gpio/gpio%d/value" +#define GPIO_DIR "/sys/class/gpio/gpio%d/direction" + +#define GPIO_HAND_SW_ID1 138 +#define GPIO_HAND_SW_ID2 139 +#define GPIO_HAND_SW_ID4 140 +#define GPIO_HAND_SW_ID8 141 + +#define GPIO_RST_BTN 144 +#define GPIO_PWR_BTN 24 + +#define GPIO_USB_SW0 36 +#define GPIO_USB_SW1 37 + +#define GPIO_UART_SEL0 32 +#define GPIO_UART_SEL1 33 +#define GPIO_UART_SEL2 34 +#define GPIO_UART_RX 35 + +#define GPIO_POSTCODE_0 48 +#define GPIO_POSTCODE_1 49 +#define GPIO_POSTCODE_2 50 +#define GPIO_POSTCODE_3 51 +#define GPIO_POSTCODE_4 124 +#define GPIO_POSTCODE_5 125 +#define GPIO_POSTCODE_6 126 +#define GPIO_POSTCODE_7 127 + +#define GPIO_DBG_CARD_PRSNT 137 + +#define PAGE_SIZE 0x1000 +#define AST_SCU_BASE 0x1e6e2000 +#define PIN_CTRL1_OFFSET 0x80 +#define PIN_CTRL2_OFFSET 0x84 + +#define UART1_TXD (1 << 22) +#define UART2_TXD (1 << 30) +#define UART3_TXD (1 << 22) +#define UART4_TXD (1 << 30) + +#define BIT(v, i) ((v >> i) & 1) +#define DELAY_GRACEFUL_SHUTDOWN 1 +#define DELAY_POWER_OFF 5 + +static uint8_t gpio_rst_btn[5] = { 0, 57, 56, 59, 58 }; +static uint8_t gpio_led[5] = { 0, 97, 96, 99, 98 }; +static uint8_t gpio_prsnt[5] = { 0, 61, 60, 63, 62 }; +static uint8_t gpio_power[5] = { 0, 27, 25, 31, 29 }; +const char pal_fru_list[] = "all, slot1, slot2, slot3, slot4, spb, nic"; +const char pal_server_list[] = "slot1, slot2, slot3, slot4"; + +char * key_list[] = { +"pwr_server1_last_state", +"pwr_server2_last_state", +"pwr_server3_last_state", +"pwr_server4_last_state", +"slot1_por_cfg", +"slot2_por_cfg", +"slot3_por_cfg", +"slot4_por_cfg", +/* Add more Keys here */ +LAST_KEY /* This is the last key of the list */ +}; + +// Helper Functions +static int +read_device(const char *device, int *value) { + FILE *fp; + int rc; + + fp = fopen(device, "r"); + if (!fp) { + int err = errno; + + syslog(LOG_INFO, "failed to open device %s", device); + return err; + } + + rc = fscanf(fp, "%d", value); + fclose(fp); + if (rc != 1) { + syslog(LOG_INFO, "failed to read device %s", device); + return ENOENT; + } else { + return 0; + } +} + +static int +write_device(const char *device, const char *value) { + FILE *fp; + int rc; + + fp = fopen(device, "w"); + if (!fp) { + int err = errno; + + syslog(LOG_INFO, "failed to open device for write %s", device); + return err; + } + + rc = fputs(value, fp); + fclose(fp); + + if (rc < 0) { + syslog(LOG_INFO, "failed to write device %s", device); + return ENOENT; + } else { + return 0; + } +} + +// Power On the server in a given slot +static int +server_power_on(uint8_t slot_id) { + char vpath[64] = {0}; + + sprintf(vpath, GPIO_VAL, gpio_power[slot_id]); + + if (write_device(vpath, "1")) { + return -1; + } + + if (write_device(vpath, "0")) { + return -1; + } + + sleep(1); + + if (write_device(vpath, "1")) { + return -1; + } + + return 0; +} + +// Power Off the server in given slot +static int +server_power_off(uint8_t slot_id, bool gs_flag) { + char vpath[64] = {0}; + + if (slot_id < 1 || slot_id > 4) { + return -1; + } + + sprintf(vpath, GPIO_VAL, gpio_power[slot_id]); + + if (write_device(vpath, "1")) { + return -1; + } + + sleep(1); + + if (write_device(vpath, "0")) { + return -1; + } + + if (gs_flag) { + sleep(DELAY_GRACEFUL_SHUTDOWN); + } else { + sleep(DELAY_POWER_OFF); + } + + if (write_device(vpath, "1")) { + return -1; + } + + return 0; +} + +// Debug Card's UART and BMC/SoL port share UART port and need to enable only +// one TXD i.e. either BMC's TXD or Debug Port's TXD. +static int +control_sol_txd(uint8_t slot) { + uint32_t scu_fd; + uint32_t ctrl; + void *scu_reg; + void *scu_pin_ctrl1; + void *scu_pin_ctrl2; + + scu_fd = open("/dev/mem", O_RDWR | O_SYNC ); + if (scu_fd < 0) { + syslog(LOG_ALERT, "control_sol_txd: open fails\n"); + return -1; + } + + scu_reg = mmap(NULL, PAGE_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, scu_fd, + AST_SCU_BASE); + scu_pin_ctrl1 = (char*)scu_reg + PIN_CTRL1_OFFSET; + scu_pin_ctrl2 = (char*)scu_reg + PIN_CTRL2_OFFSET; + + switch(slot) { + case 1: + // Disable UART2's TXD and enable others + ctrl = *(volatile uint32_t*) scu_pin_ctrl2; + ctrl |= UART1_TXD; + ctrl &= (~UART2_TXD); //Disable + *(volatile uint32_t*) scu_pin_ctrl2 = ctrl; + + ctrl = *(volatile uint32_t*) scu_pin_ctrl1; + ctrl |= UART3_TXD | UART4_TXD; + *(volatile uint32_t*) scu_pin_ctrl1 = ctrl; + break; + case 2: + // Disable UART1's TXD and enable others + ctrl = *(volatile uint32_t*) scu_pin_ctrl2; + ctrl &= (~UART1_TXD); // Disable + ctrl |= UART2_TXD; + *(volatile uint32_t*) scu_pin_ctrl2 = ctrl; + + ctrl = *(volatile uint32_t*) scu_pin_ctrl1; + ctrl |= UART3_TXD | UART4_TXD; + *(volatile uint32_t*) scu_pin_ctrl1 = ctrl; + break; + case 3: + // Disable UART4's TXD and enable others + ctrl = *(volatile uint32_t*) scu_pin_ctrl2; + ctrl |= UART1_TXD | UART2_TXD; + *(volatile uint32_t*) scu_pin_ctrl2 = ctrl; + + ctrl = *(volatile uint32_t*) scu_pin_ctrl1; + ctrl |= UART3_TXD; + ctrl &= (~UART4_TXD); // Disable + *(volatile uint32_t*) scu_pin_ctrl1 = ctrl; + break; + case 4: + // Disable UART3's TXD and enable others + ctrl = *(volatile uint32_t*) scu_pin_ctrl2; + ctrl |= UART1_TXD | UART2_TXD; + *(volatile uint32_t*) scu_pin_ctrl2 = ctrl; + + ctrl = *(volatile uint32_t*) scu_pin_ctrl1; + ctrl &= (~UART3_TXD); // Disable + ctrl |= UART4_TXD; + *(volatile uint32_t*) scu_pin_ctrl1 = ctrl; + break; + default: + // Any other slots we need to enable all TXDs + ctrl = *(volatile uint32_t*) scu_pin_ctrl2; + ctrl |= UART1_TXD | UART2_TXD; + *(volatile uint32_t*) scu_pin_ctrl2 = ctrl; + + ctrl = *(volatile uint32_t*) scu_pin_ctrl1; + ctrl |= UART3_TXD | UART4_TXD; + *(volatile uint32_t*) scu_pin_ctrl1 = ctrl; + break; + } + + munmap(scu_reg, PAGE_SIZE); + close(scu_fd); + + return 0; +} + +// Display the given POST code using GPIO port +static int +pal_post_display(uint8_t status) { + char path[64] = {0}; + int ret; + char *val; + + syslog(LOG_ALERT, "pal_post_display: status is %d\n", status); + + sprintf(path, GPIO_VAL, GPIO_POSTCODE_0); + + if (BIT(status, 0)) { + val = "1"; + } else { + val = "0"; + } + + ret = write_device(path, val); + if (ret) { + goto post_exit; + } + + sprintf(path, GPIO_VAL, GPIO_POSTCODE_1); + if (BIT(status, 1)) { + val = "1"; + } else { + val = "0"; + } + + ret = write_device(path, val); + if (ret) { + goto post_exit; + } + + sprintf(path, GPIO_VAL, GPIO_POSTCODE_2); + if (BIT(status, 2)) { + val = "1"; + } else { + val = "0"; + } + + ret = write_device(path, val); + if (ret) { + goto post_exit; + } + + sprintf(path, GPIO_VAL, GPIO_POSTCODE_3); + if (BIT(status, 3)) { + val = "1"; + } else { + val = "0"; + } + + ret = write_device(path, val); + if (ret) { + goto post_exit; + } + + sprintf(path, GPIO_VAL, GPIO_POSTCODE_4); + if (BIT(status, 4)) { + val = "1"; + } else { + val = "0"; + } + + ret = write_device(path, val); + if (ret) { + goto post_exit; + } + + sprintf(path, GPIO_VAL, GPIO_POSTCODE_5); + if (BIT(status, 5)) { + val = "1"; + } else { + val = "0"; + } + + ret = write_device(path, val); + if (ret) { + goto post_exit; + } + + sprintf(path, GPIO_VAL, GPIO_POSTCODE_6); + if (BIT(status, 6)) { + val = "1"; + } else { + val = "0"; + } + + ret = write_device(path, val); + if (ret) { + goto post_exit; + } + + sprintf(path, GPIO_VAL, GPIO_POSTCODE_7); + if (BIT(status, 7)) { + val = "1"; + } else { + val = "0"; + } + + ret = write_device(path, val); + if (ret) { + goto post_exit; + } + +post_exit: + if (ret) { + syslog(LOG_ALERT, "write_device failed for %s\n", path); + return -1; + } else { + return 0; + } +} + +// Platform Abstraction Layer (PAL) Functions +int +pal_get_platform_name(char *name) { + strcpy(name, YOSEMITE_PLATFORM_NAME); + + return 0; +} + +int +pal_get_num_slots(uint8_t *num) { + *num = YOSEMITE_MAX_NUM_SLOTS; + + return 0; +} + +int +pal_is_server_prsnt(uint8_t slot_id, uint8_t *status) { + int val; + char path[64] = {0}; + + if (slot_id < 1 || slot_id > 4) { + return -1; + } + + sprintf(path, GPIO_VAL, gpio_prsnt[slot_id]); + + if (read_device(path, &val)) { + return -1; + } + + if (val == 0x0) { + *status = 1; + } else { + *status = 0; + } + + return 0; +} + +int +pal_is_debug_card_prsnt(uint8_t *status) { + int val; + char path[64] = {0}; + + sprintf(path, GPIO_VAL, GPIO_DBG_CARD_PRSNT); + + if (read_device(path, &val)) { + return -1; + } + + // TODO: Logic is reversed until DVT board with h/w fix + if (val == 0x0) { + *status = 0; + } else { + *status = 1; + } + + return 0; +} + +int +pal_get_server_power(uint8_t slot_id, uint8_t *status) { + int ret; + bic_gpio_t gpio; + + ret = bic_get_gpio(slot_id, &gpio); + if (ret) { + return ret; + } + + if (gpio.pwrgood_cpu) { + *status = SERVER_POWER_ON; + } else { + *status = SERVER_POWER_OFF; + } + + return 0; +} + +// Power Off, Power On, or Power Reset the server in given slot +int +pal_set_server_power(uint8_t slot_id, uint8_t cmd) { + uint8_t status; + bool gs_flag = false; + + if (slot_id < 1 || slot_id > 4) { + return -1; + } + + if (pal_get_server_power(slot_id, &status) < 0) { + return -1; + } + + switch(cmd) { + case SERVER_POWER_ON: + if (status == SERVER_POWER_ON) + return 1; + else + return server_power_on(slot_id); + break; + + case SERVER_POWER_OFF: + if (status == SERVER_POWER_OFF) + return 1; + else + return server_power_off(slot_id, gs_flag); + break; + + case SERVER_POWER_CYCLE: + if (status == SERVER_POWER_ON) + return (server_power_off(slot_id, gs_flag) || server_power_on(slot_id)); + else if (status == SERVER_POWER_OFF) + return (server_power_on(slot_id)); + break; + + case SERVER_GRACEFUL_SHUTDOWN: + if (status == SERVER_POWER_OFF) + return 1; + else + gs_flag = true; + return server_power_off(slot_id, gs_flag); + break; + default: + return -1; + } + + return 0; +} + +int +pal_sled_cycle(void) { + // Remove the adm1275 module as the HSC device is busy + system("rmmod adm1275"); + + // Send command to HSC power cycle + system("i2cset -y 10 0x40 0xd9 c"); + + return 0; +} + +// Read the Front Panel Hand Switch and return the position +int +pal_get_hand_sw(uint8_t *pos) { + char path[64] = {0}; + int id1, id2, id4, id8; + uint8_t loc; + // Read 4 GPIOs to read the current position + // id1: GPIOR2(138) + // id2: GPIOR3(139) + // id4: GPIOR4(140) + // id8: GPIOR5(141) + + // Read ID1 + sprintf(path, GPIO_VAL, GPIO_HAND_SW_ID1); + if (read_device(path, &id1)) { + return -1; + } + + // Read ID2 + sprintf(path, GPIO_VAL, GPIO_HAND_SW_ID2); + if (read_device(path, &id2)) { + return -1; + } + + // Read ID4 + sprintf(path, GPIO_VAL, GPIO_HAND_SW_ID4); + if (read_device(path, &id4)) { + return -1; + } + + // Read ID8 + sprintf(path, GPIO_VAL, GPIO_HAND_SW_ID8); + if (read_device(path, &id8)) { + return -1; + } + + loc = ((id8 << 3) | (id4 << 2) | (id2 << 1) | (id1)); + + switch(loc) { + case 1: + case 6: + *pos = HAND_SW_SERVER1; + break; + case 2: + case 7: + *pos = HAND_SW_SERVER2; + break; + case 3: + case 8: + *pos = HAND_SW_SERVER3; + break; + case 4: + case 9: + *pos = HAND_SW_SERVER4; + break; + default: + *pos = HAND_SW_BMC; + break; + } + + return 0; +} + +// Return the Front panel Power Button +int +pal_get_pwr_btn(uint8_t *status) { + char path[64] = {0}; + int val; + + sprintf(path, GPIO_VAL, GPIO_PWR_BTN); + if (read_device(path, &val)) { + return -1; + } + + if (val) { + *status = 0x0; + } else { + *status = 0x1; + } + + return 0; +} + +// Return the front panel's Reset Button status +int +pal_get_rst_btn(uint8_t *status) { + char path[64] = {0}; + int val; + + sprintf(path, GPIO_VAL, GPIO_RST_BTN); + if (read_device(path, &val)) { + return -1; + } + + if (val) { + *status = 0x0; + } else { + *status = 0x1; + } + + return 0; +} + +// Update the Reset button input to the server at given slot +int +pal_set_rst_btn(uint8_t slot, uint8_t status) { + char path[64] = {0}; + char *val; + + if (slot < 1 || slot > 4) { + return -1; + } + + if (status) { + val = "0"; + } else { + val = "1"; + } + + sprintf(path, GPIO_VAL, gpio_rst_btn[slot]); + if (write_device(path, val)) { + return -1; + } + + return 0; +} + +// Update the LED for the given slot with the status +int +pal_set_led(uint8_t slot, uint8_t status) { + char path[64] = {0}; + char *val; + + if (slot < 1 || slot > 4) { + return -1; + } + + if (status) { + val = "1"; + } else { + val = "0"; + } + + sprintf(path, GPIO_VAL, gpio_led[slot]); + if (write_device(path, val)) { + return -1; + } + + return 0; +} + +// Update the USB Mux to the server at given slot +int +pal_switch_usb_mux(uint8_t slot) { + char *gpio_sw0, *gpio_sw1; + char path[64] = {0}; + + // Based on the USB mux table in Schematics + switch(slot) { + case 1: + gpio_sw0 = "1"; + gpio_sw1 = "0"; + break; + case 2: + gpio_sw0 = "0"; + gpio_sw1 = "0"; + break; + case 3: + gpio_sw0 = "1"; + gpio_sw1 = "1"; + break; + case 4: + gpio_sw0 = "0"; + gpio_sw1 = "1"; + break; + default: + // Default is for BMC itself + return 0; + } + + sprintf(path, GPIO_VAL, GPIO_USB_SW0); + if (write_device(path, gpio_sw0) < 0) { + syslog(LOG_ALERT, "write_device failed for %s\n", path); + return -1; + } + + sprintf(path, GPIO_VAL, GPIO_USB_SW1); + if (write_device(path, gpio_sw1) < 0) { + syslog(LOG_ALERT, "write_device failed for %s\n", path); + return -1; + } + + return 0; +} + +// Switch the UART mux to the given slot +int +pal_switch_uart_mux(uint8_t slot) { + char * gpio_uart_sel0; + char * gpio_uart_sel1; + char * gpio_uart_sel2; + char * gpio_uart_rx; + char path[64] = {0}; + int ret; + + // Refer the UART select table in schematic + switch(slot) { + case 1: + gpio_uart_sel2 = "0"; + gpio_uart_sel1 = "0"; + gpio_uart_sel0 = "1"; + gpio_uart_rx = "0"; + break; + case 2: + gpio_uart_sel2 = "0"; + gpio_uart_sel1 = "0"; + gpio_uart_sel0 = "0"; + gpio_uart_rx = "0"; + break; + case 3: + gpio_uart_sel2 = "0"; + gpio_uart_sel1 = "1"; + gpio_uart_sel0 = "1"; + gpio_uart_rx = "0"; + break; + case 4: + gpio_uart_sel2 = "0"; + gpio_uart_sel1 = "1"; + gpio_uart_sel0 = "0"; + gpio_uart_rx = "0"; + break; + default: + // for all other cases, assume BMC + gpio_uart_sel2 = "1"; + gpio_uart_sel1 = "0"; + gpio_uart_sel0 = "0"; + gpio_uart_rx = "1"; + break; + } + + // Diable TXD path from BMC to avoid conflict with SoL + ret = control_sol_txd(slot); + if (ret) { + goto uart_exit; + } + + // Enable Debug card path + sprintf(path, GPIO_VAL, GPIO_UART_SEL2); + ret = write_device(path, gpio_uart_sel2); + if (ret) { + goto uart_exit; + } + + sprintf(path, GPIO_VAL, GPIO_UART_SEL1); + ret = write_device(path, gpio_uart_sel1); + if (ret) { + goto uart_exit; + } + + sprintf(path, GPIO_VAL, GPIO_UART_SEL0); + ret = write_device(path, gpio_uart_sel0); + if (ret) { + goto uart_exit; + } + + sprintf(path, GPIO_VAL, GPIO_UART_RX); + ret = write_device(path, gpio_uart_rx); + if (ret) { + goto uart_exit; + } + +uart_exit: + if (ret) { + syslog(LOG_ALERT, "pal_switch_uart_mux: write_device failed: %s\n", path); + return ret; + } else { + return 0; + } +} + +// Enable POST buffer for the server in given slot +int +pal_post_enable(uint8_t slot) { + int ret; + int i; + bic_config_t config = {0}; + bic_config_u *t = (bic_config_u *) &config; + + ret = bic_get_config(slot, &config); + if (ret) { + syslog(LOG_ALERT, "post_enable: bic_get_config failed\n"); + return ret; + } + + t->bits.post = 1; + + ret = bic_set_config(slot, &config); + if (ret) { + syslog(LOG_ALERT, "post_enable: bic_set_config failed\n"); + return ret; + } + + return 0; +} + +// Disable POST buffer for the server in given slot +int +pal_post_disable(uint8_t slot) { + int ret; + int i; + bic_config_t config = {0}; + bic_config_u *t = (bic_config_u *) &config; + + ret = bic_get_config(slot, &config); + if (ret) { + return ret; + } + + t->bits.post = 0; + + ret = bic_set_config(slot, &config); + if (ret) { + return ret; + } + + return 0; +} + +// Get the last post code of the given slot +int +pal_post_get_last(uint8_t slot, uint8_t *status) { + int ret; + uint8_t buf[MAX_IPMB_RES_LEN] = {0x0}; + uint8_t len; + int i; + + ret = bic_get_post_buf(slot, buf, &len); + if (ret) { + return ret; + } + + // The post buffer is LIFO and the first byte gives the latest post code + *status = buf[0]; + + return 0; +} + +// Handle the received post code, for now display it on debug card +int +pal_post_handle(uint8_t slot, uint8_t status) { + uint8_t prsnt, pos; + int ret; + + // Check for debug card presence + ret = pal_is_debug_card_prsnt(&prsnt); + if (ret) { + return ret; + } + + // No debug card present, return + if (!prsnt) { + return 0; + } + + // Get the hand switch position + ret = pal_get_hand_sw(&pos); + if (ret) { + return ret; + } + + // If the give server is not selected, return + if (pos != slot) { + return 0; + } + + // Display the post code in the debug card + ret = pal_post_display(status); + if (ret) { + return ret; + } + + return 0; +} + + +static int +read_kv(char *key, char *value) { + + FILE *fp; + int rc; + + fp = fopen(key, "r"); + if (!fp) { + int err = errno; + syslog(LOG_ALERT, "read_kv: failed to open %s", key); + return err; + } + + rc = (int) fread(value, 1, MAX_VALUE_LEN, fp); + fclose(fp); + if (rc <= 0) { + syslog(LOG_INFO, "read_kv: failed to read %s", key); + return ENOENT; + } else { + return 0; + } +} + +static int +write_kv(char *key, char *value) { + + FILE *fp; + int rc; + + fp = fopen(key, "w"); + if (!fp) { + int err = errno; + syslog(LOG_ALERT, "write_kv: failed to open %s", key); + return err; + } + + rc = fwrite(value, 1, strlen(value), fp); + fclose(fp); + + if (rc < 0) { + syslog(LOG_ALERT, "write_kv: failed to write to %s", key); + return ENOENT; + } else { + return 0; + } +} + +int +pal_get_fru_id(char *str, uint8_t *fru) { + + return yosemite_common_fru_id(str, fru); +} + +int +pal_get_fru_sensor_list(uint8_t fru, uint8_t **sensor_list, int *cnt) { + + switch(fru) { + case FRU_SLOT1: + case FRU_SLOT2: + case FRU_SLOT3: + case FRU_SLOT4: + *sensor_list = (uint8_t *) bic_sensor_list; + *cnt = bic_sensor_cnt; + break; + case FRU_SPB: + *sensor_list = (uint8_t *) spb_sensor_list; + *cnt = spb_sensor_cnt; + break; + case FRU_NIC: + *sensor_list = NULL; // (uint8_t *) nic_sensor_list; + *cnt = 0; //nic_sensor_cnt; + break; + default: + syslog(LOG_ALERT, "pal_get_fru_sensor_list: Wrong fru id %u", fru); + return -1; + } + return 0; +} + +int +pal_sensor_read(uint8_t fru, uint8_t sensor_num, void *value) { + return yosemite_sensor_read(fru, sensor_num, value); +} + +int +pal_get_sensor_name(uint8_t fru, uint8_t sensor_num, char *name) { + return yosemite_sensor_name(fru, sensor_num, name); +} + +int +pal_get_sensor_units(uint8_t fru, uint8_t sensor_num, char *units) { + return yosemite_sensor_units(fru, sensor_num, units); +} + +int +pal_get_fruid_path(uint8_t fru, char *path) { + return yosemite_get_fruid_path(fru, path); +} + +int +pal_get_fruid_name(uint8_t fru, char *name) { + return yosemite_get_fruid_name(fru, name); +} + + +static int +get_key_value(char* key, char *value) { + + char kpath[64] = {0}; + + sprintf(kpath, KV_STORE, key); + + if (access(KV_STORE_PATH, F_OK) == -1) { + mkdir(KV_STORE_PATH, 0777); + } + + return read_kv(kpath, value); +} + +static int +set_key_value(char *key, char *value) { + + char kpath[64] = {0}; + + sprintf(kpath, KV_STORE, key); + + if (access(KV_STORE_PATH, F_OK) == -1) { + mkdir(KV_STORE_PATH, 0777); + } + + return write_kv(kpath, value); +} + +int +pal_get_key_value(char *key, char *value) { + + int ret; + int i; + + i = 0; + while(strcmp(key_list[i], LAST_KEY)) { + + if (!strcmp(key, key_list[i])) { + // Key is valid + if ((ret = get_key_value(key, value)) < 0 ) { + syslog(LOG_ALERT, "pal_get_key_value: get_key_value failed. %d", ret); + return ret; + } + return ret; + } + i++; + } + + return -1; +} + +int +pal_set_key_value(char *key, char *value) { + + int ret; + int i; + + i = 0; + while(strcmp(key_list[i], LAST_KEY)) { + + if (!strcmp(key, key_list[i])) { + // Key is valid + if ((ret = set_key_value(key, value)) < 0) { + syslog(LOG_ALERT, "pal_set_key_value: set_key_value failed. %d", ret); + printf("pal_set_key_value: ret = %d\n", ret); + return ret; + } + return ret; + } + i++; + } + + return -1; +} + +int +pal_get_fru_devtty(uint8_t fru, char *devtty) { + + switch(fru) { + case FRU_SLOT1: + sprintf(devtty, "/dev/ttyS2"); + break; + case FRU_SLOT2: + sprintf(devtty, "/dev/ttyS1"); + break; + case FRU_SLOT3: + sprintf(devtty, "/dev/ttyS4"); + break; + case FRU_SLOT4: + sprintf(devtty, "/dev/ttyS3"); + break; + default: + syslog(LOG_ALERT, "pal_get_fru_devtty: Wrong fru id %u", fru); + return -1; + } + return 0; +} + +void +pal_dump_key_value(void) { + int i; + int ret; + + char value[MAX_VALUE_LEN] = {0x0}; + + while (strcmp(key_list[i], LAST_KEY)) { + printf("%s:", key_list[i]); + if (ret = get_key_value(key_list[i], value) < 0) { + printf("\n"); + } else { + printf("%s\n", value); + } + i++; + memset(value, 0, MAX_VALUE_LEN); + } +} diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/pal/pal.h b/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/pal/pal.h new file mode 100644 index 0000000..1d9f3b9 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/pal/pal.h @@ -0,0 +1,98 @@ +/* + * + * 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 __PAL_H__ +#define __PAL_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <facebook/bic.h> +#include <facebook/yosemite_common.h> +#include <facebook/yosemite_fruid.h> +#include <facebook/yosemite_sensor.h> + +#define MAX_NUM_FRUS 6 +#define MAX_KEY_LEN 64 +#define MAX_VALUE_LEN 64 + +#define KV_STORE "/mnt/data/kv_store/%s" +#define KV_STORE_PATH "/mnt/data/kv_store" + +extern char * key_list[]; +extern const char pal_fru_list[]; +extern const char pal_server_list[]; + +enum { + LED_STATE_OFF, + LED_STATE_ON, +}; + +enum { + SERVER_POWER_OFF, + SERVER_POWER_ON, + SERVER_POWER_CYCLE, + SERVER_GRACEFUL_SHUTDOWN, +}; + +enum { + HAND_SW_SERVER1 = 1, + HAND_SW_SERVER2, + HAND_SW_SERVER3, + HAND_SW_SERVER4, + HAND_SW_BMC +}; + +int pal_get_platform_name(char *name); +int pal_get_num_slots(uint8_t *num); +int pal_is_server_prsnt(uint8_t slot_id, uint8_t *status); +int pal_get_server_power(uint8_t slot_id, uint8_t *status); +int pal_set_server_power(uint8_t slot_id, uint8_t cmd); +int pal_sled_cycle(void); +int pal_is_debug_card_prsnt(uint8_t *status); +int pal_get_hand_sw(uint8_t *pos); +int pal_switch_usb_mux(uint8_t slot); +int pal_switch_uart_mux(uint8_t slot); +int pal_post_enable(uint8_t slot); +int pal_post_disable(uint8_t slot); +int pal_post_get_last(uint8_t slot, uint8_t *post); +int pal_post_handle(uint8_t slot, uint8_t status); +int pal_get_pwr_btn(uint8_t *status); +int pal_get_rst_btn(uint8_t *status); +int pal_set_rst_btn(uint8_t slot, uint8_t status); +int pal_set_led(uint8_t slot, uint8_t status); +int pal_get_fru_id(char *fru_str, uint8_t *fru); +int pal_get_fruid_path(uint8_t fru, char *path); +int pal_get_fruid_name(uint8_t fru, char *name); +int pal_get_sensor_units(uint8_t fru, uint8_t sensor_num, char *units); +int pal_get_fru_sensor_list(uint8_t fru, uint8_t **sensor_list, int *cnt); +int pal_sensor_read(uint8_t fru, uint8_t sensor_num, void *value); +int pal_get_sensor_name(uint8_t fru, uint8_t sensor_num, char *name); +int pal_get_key_value(char *key, char *value); +int pal_set_key_value(char *key, char *value); +void pal_dump_key_value(void); +int pal_get_fru_devtty(uint8_t fru, char *devtty); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif /* __PAL_H__ */ diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/yosemite_common/Makefile b/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/yosemite_common/Makefile new file mode 100644 index 0000000..76bf61f --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/yosemite_common/Makefile @@ -0,0 +1,11 @@ +# Copyright 2015-present Facebook. All Rights Reserved. +lib: libyosemite_common.so + +libyosemite_common.so: yosemite_common.c + $(CC) $(CFLAGS) -fPIC -c -o yosemite_common.o yosemite_common.c + $(CC) -shared -o libyosemite_common.so yosemite_common.o -lc + +.PHONY: clean + +clean: + rm -rf *.o libyosemite_common.so diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/yosemite_common/yosemite_common.c b/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/yosemite_common/yosemite_common.c new file mode 100644 index 0000000..e41690f --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/yosemite_common/yosemite_common.c @@ -0,0 +1,55 @@ +/* + * + * 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 <stdlib.h> +#include <stdint.h> +#include <stdbool.h> +#include <math.h> +#include <fcntl.h> +#include <errno.h> +#include <syslog.h> +#include "yosemite_common.h" + +int +yosemite_common_fru_id(char *str, uint8_t *fru) { + + if (!strcmp(str, "all")) { + *fru = FRU_ALL; + } else if (!strcmp(str, "slot1")) { + *fru = FRU_SLOT1; + } else if (!strcmp(str, "slot2")) { + *fru = FRU_SLOT2; + } else if (!strcmp(str, "slot3")) { + *fru = FRU_SLOT3; + } else if (!strcmp(str, "slot4")) { + *fru = FRU_SLOT4; + } else if (!strcmp(str, "spb")) { + *fru = FRU_SPB; + } else if (!strcmp(str, "nic")) { + *fru = FRU_NIC; + } else { + syslog(LOG_ALERT, "yosemite_common_fru_id: Wrong fru id"); + return -1; + } + + return 0; +} diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/yosemite_common/yosemite_common.h b/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/yosemite_common/yosemite_common.h new file mode 100644 index 0000000..85d8638 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/yosemite_common/yosemite_common.h @@ -0,0 +1,44 @@ +/* + * + * 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 __YOSEMITE_COMMON_H__ +#define __YOSEMITE_COMMON_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + FRU_ALL = 0, + FRU_SLOT1 = 1, + FRU_SLOT2 = 2, + FRU_SLOT3 = 3, + FRU_SLOT4 = 4, + FRU_SPB = 5, + FRU_NIC = 6, +}; + +int yosemite_common_fru_id(char *str, uint8_t *fru); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif /* __YOSEMITE_COMMON_H__ */ diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/yosemite_fruid/Makefile b/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/yosemite_fruid/Makefile new file mode 100644 index 0000000..eda01dc --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/yosemite_fruid/Makefile @@ -0,0 +1,27 @@ +# Copyright 2015-present Facebook. All Rights Reserved. +# +# This program file 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; version 2 of the License. +# +# 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 in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA + +lib: libyosemite_fruid.so + +libyosemite_fruid.so: yosemite_fruid.c + $(CC) $(CFLAGS) -fPIC -c -o yosemite_fruid.o yosemite_fruid.c + $(CC) -lyosemite_common -shared -o libyosemite_fruid.so yosemite_fruid.o -lc + +.PHONY: clean + +clean: + rm -rf *.o libyosemite_fruid.so diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/yosemite_fruid/yosemite_fruid.c b/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/yosemite_fruid/yosemite_fruid.c new file mode 100644 index 0000000..226f2f8 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/yosemite_fruid/yosemite_fruid.c @@ -0,0 +1,86 @@ +/* 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 <stdlib.h> +#include <stdint.h> +#include <syslog.h> +#include "yosemite_fruid.h" + +/* Populate char path[] with the path to the fru's fruid binary dump */ +int +yosemite_get_fruid_path(uint8_t fru, char *path) { + char fname[16] = {0}; + + switch(fru) { + case FRU_SLOT1: + sprintf(fname, "slot1"); + break; + case FRU_SLOT2: + sprintf(fname, "slot2"); + break; + case FRU_SLOT3: + sprintf(fname, "slot3"); + break; + case FRU_SLOT4: + sprintf(fname, "slot4"); + break; + case FRU_SPB: + sprintf(fname, "spb"); + break; + case FRU_NIC: + sprintf(fname, "nic"); + break; + default: + syslog(LOG_ALERT, "yosemite_get_fruid_path: wrong fruid"); + return -1; + } + + sprintf(path, YOSEMITE_FRU_PATH, fname); + return 0; +} +/* Populate char name[] with the path to the fru's name */ +int +yosemite_get_fruid_name(uint8_t fru, char *name) { + + switch(fru) { + case FRU_SLOT1: + sprintf(name, "MonoLake Board 1"); + break; + case FRU_SLOT2: + sprintf(name, "MonoLake Board 2"); + break; + case FRU_SLOT3: + sprintf(name, "MonoLake Board 3"); + break; + case FRU_SLOT4: + sprintf(name, "MonoLake Board 4"); + break; + case FRU_SPB: + sprintf(name, "Side Plane Board"); + break; + case FRU_NIC: + sprintf(name, "CX4 NIC"); + break; + default: + syslog(LOG_ALERT, "yosemite_get_fruid_name: wrong fruid"); + return -1; + } + return 0; +} diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/yosemite_fruid/yosemite_fruid.h b/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/yosemite_fruid/yosemite_fruid.h new file mode 100644 index 0000000..5c01267 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/yosemite_fruid/yosemite_fruid.h @@ -0,0 +1,37 @@ +/* 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 __YOSEMITE_FRUID_H__ +#define __YOSEMITE_FRUID_H__ + +#include <facebook/yosemite_common.h> + +#define YOSEMITE_FRU_PATH "/tmp/fruid_%s.bin" + +#ifdef __cplusplus +extern "C" { +#endif + +int yosemite_get_fruid_path(uint8_t fru, char *path); +int yosemite_get_fruid_name(uint8_t fru, char *name); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif /* __YOSEMITE_FRUID_H__ */ diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/yosemite_gpio/Makefile b/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/yosemite_gpio/Makefile new file mode 100644 index 0000000..66c0005 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/yosemite_gpio/Makefile @@ -0,0 +1,27 @@ +# Copyright 2015-present Facebook. All Rights Reserved. +# +# This program file 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; version 2 of the License. +# +# 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 in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA + +lib: libyosemite_gpio.so + +libyosemite_gpio.so: yosemite_gpio.c + $(CC) $(CFLAGS) -fPIC -c -o yosemite_gpio.o yosemite_gpio.c + $(CC) -shared -o libyosemite_gpio.so yosemite_gpio.o -lc + +.PHONY: clean + +clean: + rm -rf *.o libyosemite_gpio.so diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/yosemite_gpio/yosemite_gpio.c b/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/yosemite_gpio/yosemite_gpio.c new file mode 100644 index 0000000..ac2c820 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/yosemite_gpio/yosemite_gpio.c @@ -0,0 +1,116 @@ +/* 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 <stdlib.h> +#include <stdint.h> +#include <syslog.h> +#include "yosemite_gpio.h" + +// List of GPIO pins to be monitored +const uint8_t gpio_pin_list[] = { + PWRGOOD_CPU, + 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, +}; + +size_t gpio_pin_cnt = sizeof(gpio_pin_list)/sizeof(uint8_t); +const uint32_t gpio_ass_val = 0x0 | (1 << FM_CPLD_FIVR_FAULT); + +const char *gpio_pin_name[] = { + "PWRGOOD_CPU", + "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" +}; + +int +yosemite_get_gpio_name(uint8_t fru, uint8_t gpio, char *name) { + + //TODO: Add support for BMC GPIO pins + if (fru < 1 || fru > 4) { + syslog(LOG_ALERT, "yosemite_get_gpio_name: Wrong fru %u", fru); + return -1; + } + + if (gpio < 0 || gpio > MAX_GPIO_PINS) { + syslog(LOG_ALERT, "yosemite_get_gpio_name: Wrong gpio pin %u", gpio); + return -1; + } + + sprintf(name, "%s", gpio_pin_name[gpio]); + return 0; +} diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/yosemite_gpio/yosemite_gpio.h b/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/yosemite_gpio/yosemite_gpio.h new file mode 100644 index 0000000..77808a8 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/yosemite_gpio/yosemite_gpio.h @@ -0,0 +1,39 @@ +/* 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 __YOSEMITE_GPIO_H__ +#define __YOSEMITE_GPIO_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <facebook/bic.h> + +extern const uint8_t gpio_pin_list[]; +extern const char *gpio_pin_name[]; +extern const uint32_t gpio_ass_val; +extern size_t gpio_pin_cnt; + +int yosemite_get_gpio_name(uint8_t fru, uint8_t gpio, char *name); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif /* __YOSEMITE_GPIO_H__ */ diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/yosemite_sensor/Makefile b/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/yosemite_sensor/Makefile new file mode 100644 index 0000000..63b334c --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/yosemite_sensor/Makefile @@ -0,0 +1,11 @@ +# Copyright 2015-present Facebook. All Rights Reserved. +lib: libyosemite_sensor.so + +libyosemite_sensor.so: yosemite_sensor.c + $(CC) $(CFLAGS) -fPIC -c -o yosemite_sensor.o yosemite_sensor.c + $(CC) -lm -lbic -lsdr -lipmi -lipmb -lyosemite_common -shared -o libyosemite_sensor.so yosemite_sensor.o -lc + +.PHONY: clean + +clean: + rm -rf *.o libyosemite_sensor.so diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/yosemite_sensor/yosemite_sensor.c b/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/yosemite_sensor/yosemite_sensor.c new file mode 100644 index 0000000..0f25e54 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/yosemite_sensor/yosemite_sensor.c @@ -0,0 +1,778 @@ +/* + * + * 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 <stdlib.h> +#include <stdint.h> +#include <stdbool.h> +#include <math.h> +#include <fcntl.h> +#include <errno.h> +#include <syslog.h> +#include "yosemite_sensor.h" + +#define LARGEST_DEVICE_NAME 120 + +#define GPIO_VAL "/sys/class/gpio/gpio%d/value" + +#define I2C_BUS_9_DIR "/sys/class/i2c-adapter/i2c-9/" +#define I2C_BUS_10_DIR "/sys/class/i2c-adapter/i2c-10/" + +#define TACH_DIR "/sys/devices/platform/ast_pwm_tacho.0" +#define ADC_DIR "/sys/devices/platform/ast_adc.0" + +#define SP_INLET_TEMP_DEVICE I2C_BUS_9_DIR "9-004e" +#define SP_OUTLET_TEMP_DEVICE I2C_BUS_9_DIR "9-004f" +#define HSC_DEVICE I2C_BUS_10_DIR "10-0040" + +#define FAN_TACH_RPM "tacho%d_rpm" +#define ADC_VALUE "adc%d_value" +#define HSC_IN_VOLT "in1_input" +#define HSC_OUT_CURR "curr1_input" +#define HSC_TEMP "temp1_input" + +#define UNIT_DIV 1000 + +#define BIC_SENSOR_READ_NA 0x20 + +#define MAX_SENSOR_NUM 0xFF +#define ALL_BYTES 0xFF +#define LAST_REC_ID 0xFFFF + +#define YOSEMITE_SDR_PATH "/tmp/sdr_%s.bin" + +// List of BIC sensors to be monitored +const uint8_t bic_sensor_list[] = { + /* Threshold sensors */ + BIC_SENSOR_MB_OUTLET_TEMP, + BIC_SENSOR_VCCIN_VR_TEMP, + BIC_SENSOR_VCC_GBE_VR_TEMP, + BIC_SENSOR_1V05PCH_VR_TEMP, + BIC_SENSOR_SOC_TEMP, + BIC_SENSOR_MB_INLET_TEMP, + BIC_SENSOR_PCH_TEMP, + BIC_SENSOR_SOC_THERM_MARGIN, + BIC_SENSOR_VDDR_VR_TEMP, + BIC_SENSOR_VCC_GBE_VR_CURR, + BIC_SENSOR_1V05_PCH_VR_CURR, + BIC_SENSOR_VCCIN_VR_POUT, + BIC_SENSOR_VCCIN_VR_CURR, + BIC_SENSOR_VCCIN_VR_VOL, + BIC_SENSOR_INA230_POWER, + BIC_SENSOR_SOC_PACKAGE_PWR, + BIC_SENSOR_SOC_TJMAX, + BIC_SENSOR_VDDR_VR_POUT, + BIC_SENSOR_VDDR_VR_CURR, + BIC_SENSOR_VDDR_VR_VOL, + BIC_SENSOR_VCC_SCSUS_VR_CURR, + BIC_SENSOR_VCC_SCSUS_VR_VOL, + BIC_SENSOR_VCC_SCSUS_VR_TEMP, + BIC_SENSOR_VCC_SCSUS_VR_POUT, + BIC_SENSOR_VCC_GBE_VR_POUT, + BIC_SENSOR_VCC_GBE_VR_VOL, + BIC_SENSOR_1V05_PCH_VR_VOL, + BIC_SENSOR_SOC_DIMMA0_TEMP, + BIC_SENSOR_SOC_DIMMA1_TEMP, + BIC_SENSOR_SOC_DIMMB0_TEMP, + BIC_SENSOR_SOC_DIMMB1_TEMP, + BIC_SENSOR_P3V3_MB, + BIC_SENSOR_P12V_MB, + BIC_SENSOR_P1V05_PCH, + BIC_SENSOR_P3V3_STBY_MB, + BIC_SENSOR_P5V_STBY_MB, + BIC_SENSOR_PV_BAT, + BIC_SENSOR_PVDDR, + BIC_SENSOR_PVCC_GBE, + /* Discrete sensors */ + //BIC_SENSOR_SYSTEM_STATUS, + //BIC_SENSOR_SYS_BOOT_STAT, + //BIC_SENSOR_CPU_DIMM_HOT, + //BIC_SENSOR_PROC_FAIL, + //BIC_SENSOR_VR_HOT, + /* Event-only sensors */ + //BIC_SENSOR_POST_ERR, + //BIC_SENSOR_SPS_FW_HLTH, + //BIC_SENSOR_POWER_THRESH_EVENT, + //BIC_SENSOR_MACHINE_CHK_ERR, + //BIC_SENSOR_PCIE_ERR, + //BIC_SENSOR_OTHER_IIO_ERR, + //BIC_SENSOR_PROC_HOT_EXT, + //BIC_SENSOR_POWER_ERR, + //BIC_SENSOR_CAT_ERR, +}; + +// List of SPB sensors to be monitored +const uint8_t spb_sensor_list[] = { + SP_SENSOR_INLET_TEMP, + SP_SENSOR_OUTLET_TEMP, + //SP_SENSOR_MEZZ_TEMP + SP_SENSOR_FAN0_TACH, + SP_SENSOR_FAN1_TACH, + //SP_SENSOR_AIR_FLOW, + SP_SENSOR_P5V, + SP_SENSOR_P12V, + SP_SENSOR_P3V3_STBY, + SP_SENSOR_P12V_SLOT0, + SP_SENSOR_P12V_SLOT1, + SP_SENSOR_P12V_SLOT2, + SP_SENSOR_P12V_SLOT3, + SP_SENSOR_P3V3, + SP_SENSOR_HSC_IN_VOLT, + SP_SENSOR_HSC_OUT_CURR, + SP_SENSOR_HSC_TEMP, + SP_SENSOR_HSC_IN_POWER, +}; + +size_t bic_sensor_cnt = sizeof(bic_sensor_list)/sizeof(uint8_t); + +size_t spb_sensor_cnt = sizeof(spb_sensor_list)/sizeof(uint8_t); + +enum { + FAN0 = 0, + FAN1, +}; + +enum { + ADC_PIN0 = 0, + ADC_PIN1, + ADC_PIN2, + ADC_PIN3, + ADC_PIN4, + ADC_PIN5, + ADC_PIN6, + ADC_PIN7, +}; + +static sensor_info_t g_sinfo1[MAX_SENSOR_NUM] = {0}; +static sensor_info_t g_sinfo2[MAX_SENSOR_NUM] = {0}; +static sensor_info_t g_sinfo3[MAX_SENSOR_NUM] = {0}; +static sensor_info_t g_sinfo4[MAX_SENSOR_NUM] = {0}; +static sensor_info_t g_sinfo_spb[MAX_SENSOR_NUM] = {0}; +static sensor_info_t g_sinfo_nic[MAX_SENSOR_NUM] = {0}; + +static int +read_device(const char *device, int *value) { + FILE *fp; + int rc; + + fp = fopen(device, "r"); + if (!fp) { + int err = errno; + + syslog(LOG_INFO, "failed to open device %s", device); + return err; + } + + rc = fscanf(fp, "%d", value); + fclose(fp); + + if (rc != 1) { + syslog(LOG_INFO, "failed to read device %s", device); + return ENOENT; + } else { + return 0; + } +} + +static int +read_device_float(const char *device, float *value) { + FILE *fp; + int rc; + char tmp[10]; + + fp = fopen(device, "r"); + if (!fp) { + int err = errno; + + syslog(LOG_INFO, "failed to open device %s", device); + return err; + } + + rc = fscanf(fp, "%s", tmp); + fclose(fp); + + if (rc != 1) { + syslog(LOG_INFO, "failed to read device %s", device); + return ENOENT; + } + + *value = atof(tmp); + + return 0; +} + +static int +read_temp(const char *device, float *value) { + char full_name[LARGEST_DEVICE_NAME + 1]; + int tmp; + + snprintf( + full_name, LARGEST_DEVICE_NAME, "%s/temp1_input", device); + if (read_device(full_name, &tmp)) { + return -1; + } + + *value = ((float)tmp)/UNIT_DIV; + + return 0; +} + +static int +read_fan_value(const int fan, const char *device, float *value) { + char device_name[LARGEST_DEVICE_NAME]; + char full_name[LARGEST_DEVICE_NAME]; + + snprintf(device_name, LARGEST_DEVICE_NAME, device, fan); + snprintf(full_name, LARGEST_DEVICE_NAME, "%s/%s", TACH_DIR, device_name); + return read_device_float(full_name, value); +} + +static int +read_adc_value(const int pin, const char *device, float *value) { + char device_name[LARGEST_DEVICE_NAME]; + char full_name[LARGEST_DEVICE_NAME]; + + snprintf(device_name, LARGEST_DEVICE_NAME, device, pin); + snprintf(full_name, LARGEST_DEVICE_NAME, "%s/%s", ADC_DIR, device_name); + return read_device_float(full_name, value); +} + +static int +read_hsc_value(const char *device, float *value) { + char full_name[LARGEST_DEVICE_NAME]; + int tmp; + + snprintf(full_name, LARGEST_DEVICE_NAME, "%s/%s", HSC_DEVICE, device); + if(read_device(full_name, &tmp)) { + return -1; + } + + *value = ((float) tmp)/UNIT_DIV; + + return 0; +} + +static int +bic_read_sensor_wrapper(uint8_t slot_id, uint8_t sensor_num, void *value) { + int ret; + ipmi_sensor_reading_t sensor; + + ret = bic_read_sensor(slot_id, sensor_num, &sensor); + if (ret) { + return ret; + } + + if (sensor.flags & BIC_SENSOR_READ_NA) { + syslog(LOG_ERR, "bic_read_sensor_wrapper: Reading Not Available"); + syslog(LOG_ERR, "bic_read_sensor_wrapper: sensor_num: 0x%X, flag: 0x%X", + sensor_num, sensor.flags); + return -1; + } + + if (sensor.status) { + //printf("bic_read_sensor_wrapper: Status Asserted: 0x%X\n", sensor.status); + } + + // Check SDR to convert raw value to actual + sdr_full_t *sdr; + + switch (slot_id) { + case 1: + sdr = &g_sinfo1[sensor_num].sdr; + break; + case 2: + sdr = &g_sinfo2[sensor_num].sdr; + break; + case 3: + sdr = &g_sinfo3[sensor_num].sdr; + break; + case 4: + sdr = &g_sinfo4[sensor_num].sdr; + break; + default: + syslog(LOG_ALERT, "bic_read_sensor_wrapper: Wrong Slot ID\n"); + return -1; + } + + // If the SDR is not type1, no need for conversion + if (sdr->type !=1) { + *(float *) value = sensor.value; + return 0; + } + + // y = (mx + b * 10^b_exp) * 10^r_exp + uint8_t x; + uint8_t m_lsb, m_msb, m; + uint8_t b_lsb, b_msb, b; + int8_t b_exp, r_exp; + + x = sensor.value; + + m_lsb = sdr->m_val; + m_msb = sdr->m_tolerance >> 6; + m = (m_msb << 8) | m_lsb; + + b_lsb = sdr->b_val; + b_msb = sdr->b_accuracy >> 6; + b = (b_msb << 8) | b_lsb; + + // exponents are 2's complement 4-bit number + b_exp = sdr->rb_exp & 0xF; + if (b_exp > 7) { + b_exp = (~b_exp + 1) & 0xF; + b_exp = -b_exp; + } + r_exp = (sdr->rb_exp >> 4) & 0xF; + if (r_exp > 7) { + r_exp = (~r_exp + 1) & 0xF; + r_exp = -r_exp; + } + + //printf("m:%d, x:%d, b:%d, b_exp:%d, r_exp:%d\n", m, x, b, b_exp, r_exp); + + * (float *) value = ((m * x) + (b * pow(10, b_exp))) * (pow(10, r_exp)); + + return 0; +} + +/* Returns the all the SDRs for the particular fru# */ +static sensor_info_t * +get_struct_sensor_info(uint8_t fru) { + sensor_info_t *sinfo; + switch(fru) { + case FRU_SLOT1: + sinfo = g_sinfo1; + break; + case FRU_SLOT2: + sinfo = g_sinfo2; + break; + case FRU_SLOT3: + sinfo = g_sinfo3; + break; + case FRU_SLOT4: + sinfo = g_sinfo4; + break; + case FRU_SPB: + sinfo = g_sinfo_spb; + break; + case FRU_NIC: + sinfo = g_sinfo_nic; + break; + default: + syslog(LOG_ALERT, "yosemite_sdr_init: Wrong Slot ID\n"); + return NULL; + } + return sinfo; +} + +int +get_fru_sdr_path(uint8_t fru, char *path) { + + char fru_name[16] = {0}; + + switch(fru) { + case FRU_SLOT1: + sprintf(fru_name, "%s", "slot1"); + break; + case FRU_SLOT2: + sprintf(fru_name, "%s", "slot2"); + break; + case FRU_SLOT3: + sprintf(fru_name, "%s", "slot3"); + break; + case FRU_SLOT4: + sprintf(fru_name, "%s", "slot4"); + break; + case FRU_SPB: + sprintf(fru_name, "%s", "spb"); + break; + case FRU_NIC: + sprintf(fru_name, "%s", "nic"); + break; + default: + syslog(LOG_ALERT, "yosemite_sdr_init: Wrong Slot ID\n"); + return -1; + } + + sprintf(path, YOSEMITE_SDR_PATH, fru_name); + + return 0; +} + +static int +yosemite_sdr_init(uint8_t fru) { + int fd; + uint8_t buf[MAX_SDR_LEN] = {0}; + uint8_t bytes_rd = 0; + uint8_t sn = 0; + char path[64] = {0}; + sensor_info_t *sinfo; + + if (get_fru_sdr_path(fru, path) < 0) { + syslog(LOG_ALERT, "yosemite_sdr_init: get_fru_sdr_path failed\n"); + return -1; + } + sinfo = get_struct_sensor_info(fru); + if (sinfo == NULL) { + syslog(LOG_ALERT, "yosemite_sdr_init: get_struct_sensor_info failed\n"); + return -1; + } + + if (sdr_init(path, sinfo) < 0) { + syslog(LOG_ERR, "yosemite_sdr_init: sdr_init failed for FRU %d", fru); + } + + return 0; +} + +static bool +is_server_prsnt(uint8_t slot_id) { + uint8_t gpio; + int val; + char path[64] = {0}; + + switch(slot_id) { + case 1: + gpio = 61; + break; + case 2: + gpio = 60; + break; + case 3: + gpio = 63; + break; + case 4: + gpio = 62; + break; + default: + return 0; + } + + sprintf(path, GPIO_VAL, gpio); + + if (read_device(path, &val)) { + return -1; + } + + if (val == 0x0) { + return 1; + } else { + return 0; + } +} + +/* Get the units for the sensor */ +int +yosemite_sensor_units(uint8_t fru, uint8_t sensor_num, char *units) { + static bool init_done = false; + uint8_t op, modifier; + sensor_info_t *sinfo; + + if (!init_done) { + + if (is_server_prsnt(1) && (yosemite_sdr_init(FRU_SLOT1) != 0)) { + return -1; + } + if (is_server_prsnt(2) && (yosemite_sdr_init(FRU_SLOT2) != 0)) { + return -1; + } + if (is_server_prsnt(3) && (yosemite_sdr_init(FRU_SLOT3) != 0)) { + return -1; + } + if (is_server_prsnt(4) && (yosemite_sdr_init(FRU_SLOT4) != 0)) { + return -1; + } + init_done = true; + } + + switch(fru) { + case FRU_SLOT1: + case FRU_SLOT2: + case FRU_SLOT3: + case FRU_SLOT4: + sinfo = get_struct_sensor_info(fru); + if (sinfo == NULL) { + syslog(LOG_ALERT, "yosemite_sensor_units: get_struct_sensor_info failed\n"); + return -1; + } + + if (sdr_get_sensor_units(&sinfo[sensor_num].sdr, &op, &modifier, units)) { + syslog(LOG_ALERT, "yosemite_sensor_units: FRU %d: num 0x%2X: reading units" + " from SDR failed.", fru, sensor_num); + return -1; + } + break; + case FRU_SPB: + switch(sensor_num) { + case SP_SENSOR_INLET_TEMP: + sprintf(units, "C"); + break; + case SP_SENSOR_OUTLET_TEMP: + sprintf(units, "C"); + break; + case SP_SENSOR_MEZZ_TEMP: + sprintf(units, "C"); + break; + case SP_SENSOR_FAN0_TACH: + sprintf(units, "RPM"); + break; + case SP_SENSOR_FAN1_TACH: + sprintf(units, "RPM"); + break; + case SP_SENSOR_AIR_FLOW: + sprintf(units, ""); + break; + case SP_SENSOR_P5V: + sprintf(units, "Volts"); + break; + case SP_SENSOR_P12V: + sprintf(units, "Volts"); + break; + case SP_SENSOR_P3V3_STBY: + sprintf(units, "Volts"); + break; + case SP_SENSOR_P12V_SLOT0: + sprintf(units, "Volts"); + break; + case SP_SENSOR_P12V_SLOT1: + sprintf(units, "Volts"); + break; + case SP_SENSOR_P12V_SLOT2: + sprintf(units, "Volts"); + break; + case SP_SENSOR_P12V_SLOT3: + sprintf(units, "Volts"); + break; + case SP_SENSOR_P3V3: + sprintf(units, "Volts"); + break; + case SP_SENSOR_HSC_IN_VOLT: + sprintf(units, "Volts"); + break; + case SP_SENSOR_HSC_OUT_CURR: + sprintf(units, "Amps"); + break; + case SP_SENSOR_HSC_TEMP: + sprintf(units, "C"); + break; + case SP_SENSOR_HSC_IN_POWER: + sprintf(units, "Watts"); + break; + } + break; + case FRU_NIC: + sprintf(units, ""); + break; + } + return 0; +} + +/* Get the name for the sensor */ +int +yosemite_sensor_name(uint8_t fru, uint8_t sensor_num, char *name) { + static bool init_done = false; + uint8_t op, modifier; + sensor_info_t *sinfo; + + if (!init_done) { + + if (is_server_prsnt(1) && (yosemite_sdr_init(FRU_SLOT1) != 0)) { + return -1; + } + if (is_server_prsnt(2) && (yosemite_sdr_init(FRU_SLOT2) != 0)) { + return -1; + } + if (is_server_prsnt(3) && (yosemite_sdr_init(FRU_SLOT3) != 0)) { + return -1; + } + if (is_server_prsnt(4) && (yosemite_sdr_init(FRU_SLOT4) != 0)) { + return -1; + } + init_done = true; + } + + switch(fru) { + case FRU_SLOT1: + case FRU_SLOT2: + case FRU_SLOT3: + case FRU_SLOT4: + sinfo = get_struct_sensor_info(fru); + if (sinfo == NULL) { + syslog(LOG_ALERT, "yosemite_sensor_name: get_struct_sensor_info failed\n"); + return -1; + } + + if (sdr_get_sensor_name(&sinfo[sensor_num].sdr, name)) { + syslog(LOG_ALERT, "yosemite_sensor_name: FRU %d: num 0x%2X: reading units" + " from SDR failed.", fru, sensor_num); + return -1; + } + + break; + case FRU_SPB: + switch(sensor_num) { + case SP_SENSOR_INLET_TEMP: + sprintf(name, "SP_SENSOR_INLET_TEMP"); + break; + case SP_SENSOR_OUTLET_TEMP: + sprintf(name, "SP_SENSOR_OUTLET_TEMP"); + break; + case SP_SENSOR_MEZZ_TEMP: + sprintf(name, "SP_SENSOR_MEZZ_TEMP"); + break; + case SP_SENSOR_FAN0_TACH: + sprintf(name, "SP_SENSOR_FAN0_TACH"); + break; + case SP_SENSOR_FAN1_TACH: + sprintf(name, "SP_SENSOR_FAN1_TACH"); + break; + case SP_SENSOR_AIR_FLOW: + sprintf(name, "SP_SENSOR_AIR_FLOW"); + break; + case SP_SENSOR_P5V: + sprintf(name, "SP_SENSOR_P5V"); + break; + case SP_SENSOR_P12V: + sprintf(name, "SP_SENSOR_P12V"); + break; + case SP_SENSOR_P3V3_STBY: + sprintf(name, "SP_SENSOR_P3V3_STBY"); + break; + case SP_SENSOR_P12V_SLOT0: + sprintf(name, "SP_SENSOR_P12V_SLOT0"); + break; + case SP_SENSOR_P12V_SLOT1: + sprintf(name, "SP_SENSOR_P12V_SLOT1"); + break; + case SP_SENSOR_P12V_SLOT2: + sprintf(name, "SP_SENSOR_P12V_SLOT2"); + break; + case SP_SENSOR_P12V_SLOT3: + sprintf(name, "SP_SENSOR_P12V_SLOT3"); + break; + case SP_SENSOR_P3V3: + sprintf(name, "SP_SENSOR_P3V3"); + break; + case SP_SENSOR_HSC_IN_VOLT: + sprintf(name, "SP_SENSOR_HSC_IN_VOLT"); + break; + case SP_SENSOR_HSC_OUT_CURR: + sprintf(name, "SP_SENSOR_HSC_OUT_CURR"); + break; + case SP_SENSOR_HSC_TEMP: + sprintf(name, "SP_SENSOR_HSC_TEMP"); + break; + case SP_SENSOR_HSC_IN_POWER: + sprintf(name, "SP_SENSOR_HSC_IN_POWER"); + break; + } + break; + case FRU_NIC: + sprintf(name, ""); + break; + } + return 0; +} + + +int +yosemite_sensor_read(uint8_t slot_id, uint8_t sensor_num, void *value) { + static bool init_done = false; + float volt; + float curr; + + if (!init_done) { + + if (is_server_prsnt(1) && (yosemite_sdr_init(FRU_SLOT1) != 0)) { + return -1; + } + + if (is_server_prsnt(2) && (yosemite_sdr_init(FRU_SLOT2) != 0)) { + return -1; + } + + if (is_server_prsnt(3) && (yosemite_sdr_init(FRU_SLOT3) != 0)) { + return -1; + } + + if (is_server_prsnt(4) && (yosemite_sdr_init(FRU_SLOT4) != 0)) { + return -1; + } + + init_done = true; + } + + switch(sensor_num) { + // Inlet, Outlet Temp + + case SP_SENSOR_INLET_TEMP: + return read_temp(SP_INLET_TEMP_DEVICE, (float*) value); + case SP_SENSOR_OUTLET_TEMP: + return read_temp(SP_OUTLET_TEMP_DEVICE, (float*) value); + + // Fan Tach Values + case SP_SENSOR_FAN0_TACH: + return read_fan_value(FAN0, FAN_TACH_RPM, (float*) value); + case SP_SENSOR_FAN1_TACH: + return read_fan_value(FAN1, FAN_TACH_RPM, (float*) value); + + // Various Voltages + case SP_SENSOR_P5V: + return read_adc_value(ADC_PIN0, ADC_VALUE, (float*) value); + case SP_SENSOR_P12V: + return read_adc_value(ADC_PIN1, ADC_VALUE, (float*) value); + case SP_SENSOR_P3V3_STBY: + return read_adc_value(ADC_PIN2, ADC_VALUE, (float*) value); + case SP_SENSOR_P12V_SLOT0: + return read_adc_value(ADC_PIN3, ADC_VALUE, (float*) value); + case SP_SENSOR_P12V_SLOT1: + return read_adc_value(ADC_PIN4, ADC_VALUE, (float*) value); + case SP_SENSOR_P12V_SLOT2: + return read_adc_value(ADC_PIN5, ADC_VALUE, (float*) value); + case SP_SENSOR_P12V_SLOT3: + return read_adc_value(ADC_PIN6, ADC_VALUE, (float*) value); + case SP_SENSOR_P3V3: + return read_adc_value(ADC_PIN7, ADC_VALUE, (float*) value); + + // Hot Swap Controller + case SP_SENSOR_HSC_IN_VOLT: + return read_hsc_value(HSC_IN_VOLT, (float*) value); + case SP_SENSOR_HSC_OUT_CURR: + return read_hsc_value(HSC_OUT_CURR, (float*) value); + case SP_SENSOR_HSC_TEMP: + return read_hsc_value(HSC_TEMP, (float*) value); + case SP_SENSOR_HSC_IN_POWER: + if (read_hsc_value(HSC_IN_VOLT, &volt)) { + return -1; + } + + if (read_hsc_value(HSC_OUT_CURR, &curr)) { + return -1; + } + + * (float*) value = volt * curr; + return 0; + default: + // For all others we assume the sensors are on Monolake + return bic_read_sensor_wrapper(slot_id, sensor_num, value); + } +} + diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/yosemite_sensor/yosemite_sensor.h b/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/yosemite_sensor/yosemite_sensor.h new file mode 100644 index 0000000..0a33173 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/yosemite_sensor/yosemite_sensor.h @@ -0,0 +1,133 @@ +/* + * + * 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 __YOSEMITE_SENSOR_H__ +#define __YOSEMITE_SENSOR_H__ + +#include <stdbool.h> +#include <openbmc/ipmi.h> +#include <openbmc/ipmb.h> +#include <openbmc/sdr.h> +#include <facebook/bic.h> +#include <facebook/yosemite_common.h> + +#ifdef __cplusplus +extern "C" { +#endif + +// Sensors under Bridge IC +enum { + BIC_SENSOR_MB_OUTLET_TEMP = 0x01, + BIC_SENSOR_VCCIN_VR_TEMP = 0x02, + BIC_SENSOR_VCC_GBE_VR_TEMP = 0x03, + BIC_SENSOR_1V05PCH_VR_TEMP = 0x04, + BIC_SENSOR_SOC_TEMP = 0x05, + BIC_SENSOR_MB_INLET_TEMP = 0x07, + BIC_SENSOR_PCH_TEMP = 0x08, + BIC_SENSOR_SOC_THERM_MARGIN = 0x09, + BIC_SENSOR_VDDR_VR_TEMP = 0x0B, + BIC_SENSOR_SYSTEM_STATUS = 0x10, //Discrete + BIC_SENSOR_SPS_FW_HLTH = 0x17, //Event-only + BIC_SENSOR_VCC_GBE_VR_CURR = 0x20, + BIC_SENSOR_1V05_PCH_VR_CURR = 0x21, + BIC_SENSOR_VCCIN_VR_POUT = 0x22, + BIC_SENSOR_VCCIN_VR_CURR = 0x23, + BIC_SENSOR_VCCIN_VR_VOL = 0x24, + BIC_SENSOR_INA230_POWER = 0x29, + BIC_SENSOR_POST_ERR = 0x2B, //Event-only + BIC_SENSOR_SOC_PACKAGE_PWR = 0x2C, + BIC_SENSOR_SOC_TJMAX = 0x30, + BIC_SENSOR_VDDR_VR_POUT = 0x32, + BIC_SENSOR_VDDR_VR_CURR = 0x33, + BIC_SENSOR_VDDR_VR_VOL = 0x34, + BIC_SENSOR_VCC_SCSUS_VR_CURR = 0x35, + BIC_SENSOR_VCC_SCSUS_VR_VOL = 0x36, + BIC_SENSOR_VCC_SCSUS_VR_TEMP = 0x37, + BIC_SENSOR_VCC_SCSUS_VR_POUT = 0x38, + BIC_SENSOR_VCC_GBE_VR_POUT = 0x39, + BIC_SENSOR_POWER_THRESH_EVENT = 0x3B, //Event-only + //BIC_SENSOR_1V05_PCH_VR_POUT = 0x40, + BIC_SENSOR_MACHINE_CHK_ERR = 0x40, //Event-only + BIC_SENSOR_PCIE_ERR = 0x41, //Event-only + BIC_SENSOR_OTHER_IIO_ERR = 0x43, //Event-only + BIC_SENSOR_PROC_HOT_EXT = 0x51, //Event-only + BIC_SENSOR_VCC_GBE_VR_VOL = 0x54, + BIC_SENSOR_1V05_PCH_VR_VOL = 0x55, + BIC_SENSOR_POWER_ERR = 0x56, //Event-only + BIC_SENSOR_MEM_ECC_ERR = 0x63, //Event-only + BIC_SENSOR_PROC_FAIL = 0x65, //Discrete + BIC_SENSOR_SYS_BOOT_STAT = 0x7E, //Discrete + BIC_SENSOR_VR_HOT = 0xB2, //Discrete + BIC_SENSOR_CPU_DIMM_HOT = 0xB3, //Discrete + BIC_SENSOR_SOC_DIMMA0_TEMP = 0xB4, + BIC_SENSOR_SOC_DIMMA1_TEMP = 0xB5, + BIC_SENSOR_SOC_DIMMB0_TEMP = 0xB6, + BIC_SENSOR_SOC_DIMMB1_TEMP = 0xB7, + BIC_SENSOR_P3V3_MB = 0xD0, + BIC_SENSOR_P12V_MB = 0xD2, + BIC_SENSOR_P1V05_PCH = 0xD3, + BIC_SENSOR_P3V3_STBY_MB = 0xD5, + BIC_SENSOR_P5V_STBY_MB = 0xD6, + BIC_SENSOR_PV_BAT = 0xD7, + BIC_SENSOR_PVDDR = 0xD8, + BIC_SENSOR_PVCC_GBE = 0xD9, + BIC_SENSOR_CAT_ERR = 0xEB, //Event-only +}; + +// Sensors Under Side Plane +enum { + SP_SENSOR_INLET_TEMP = 0x81, + SP_SENSOR_OUTLET_TEMP = 0x80, + SP_SENSOR_MEZZ_TEMP = 0x82, + SP_SENSOR_FAN0_TACH = 0x46, + SP_SENSOR_FAN1_TACH = 0x47, + SP_SENSOR_AIR_FLOW = 0x4A, + SP_SENSOR_P5V = 0xE0, + SP_SENSOR_P12V = 0xE1, + SP_SENSOR_P3V3_STBY = 0xE2, + SP_SENSOR_P12V_SLOT0 = 0xE3, + SP_SENSOR_P12V_SLOT1 = 0xE4, + SP_SENSOR_P12V_SLOT2 = 0xE5, + SP_SENSOR_P12V_SLOT3 = 0xE6, + SP_SENSOR_P3V3 = 0xE7, + SP_SENSOR_HSC_IN_VOLT = 0xC0, + SP_SENSOR_HSC_OUT_CURR = 0xC1, + SP_SENSOR_HSC_TEMP = 0xC2, + SP_SENSOR_HSC_IN_POWER = 0xC3, +}; + +extern const uint8_t bic_sensor_list[]; + +extern const uint8_t spb_sensor_list[]; + +extern size_t bic_sensor_cnt; + +extern size_t spb_sensor_cnt; + +int yosemite_sensor_read(uint8_t slot_id, uint8_t sensor_num, void *value); +int yosemite_sensor_name(uint8_t fru, uint8_t sensor_num, char *name); +int yosemite_sensor_units(uint8_t fru, uint8_t sensor_num, char *units); +int get_fru_sdr_path(uint8_t fru, char *path); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif /* __YOSEMITE_SENSOR_H__ */ diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/libbic_0.1.bb b/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/libbic_0.1.bb new file mode 100644 index 0000000..6b22366 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/libbic_0.1.bb @@ -0,0 +1,25 @@ +# Copyright 2015-present Facebook. All Rights Reserved. +SUMMARY = "Bridge IC Library" +DESCRIPTION = "library for communicating with Bridge IC" +SECTION = "base" +PR = "r1" +LICENSE = "GPLv2" +LIC_FILES_CHKSUM = "file://bic.c;beginline=8;endline=20;md5=da35978751a9d71b73679307c4d296ec" + + +SRC_URI = "file://bic \ + " +DEPENDS += "libipmi libipmb" + +S = "${WORKDIR}/bic" + +do_install() { + install -d ${D}${libdir} + install -m 0644 libbic.so ${D}${libdir}/libbic.so + + install -d ${D}${includedir}/facebook + install -m 0644 bic.h ${D}${includedir}/facebook/bic.h +} + +FILES_${PN} = "${libdir}/libbic.so" +FILES_${PN}-dev = "${includedir}/facebook/bic.h" diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/libpal_0.1.bb b/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/libpal_0.1.bb new file mode 100644 index 0000000..bcdd420 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/libpal_0.1.bb @@ -0,0 +1,28 @@ +# Copyright 2015-present Facebook. All Rights Reserved. +SUMMARY = "Platform Abstraction Library" +DESCRIPTION = "library for communicating with Platform" +SECTION = "base" +PR = "r1" +LICENSE = "GPLv2" +LIC_FILES_CHKSUM = "file://pal.c;beginline=8;endline=20;md5=da35978751a9d71b73679307c4d296ec" + + +SRC_URI = "file://pal \ + " + +DEPENDS += "libbic libyosemite-common libyosemite-fruid libyosemite-sensor " + +S = "${WORKDIR}/pal" + +do_install() { + install -d ${D}${libdir} + install -m 0644 libpal.so ${D}${libdir}/libpal.so + + install -d ${D}${includedir}/openbmc + install -m 0644 pal.h ${D}${includedir}/openbmc/pal.h +} + +FILES_${PN} = "${libdir}/libpal.so" +FILES_${PN}-dev = "${includedir}/openbmc/pal.h" + +RDEPENDS_${PN} += " libyosemite-common" diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/libyosemite-common_0.1.bb b/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/libyosemite-common_0.1.bb new file mode 100644 index 0000000..bdf8192 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/libyosemite-common_0.1.bb @@ -0,0 +1,25 @@ +# Copyright 2015-present Facebook. All Rights Reserved. +SUMMARY = "Yosemite Common Library" +DESCRIPTION = "library for common Yosemite information" +SECTION = "base" +PR = "r1" +LICENSE = "GPLv2" +LIC_FILES_CHKSUM = "file://yosemite_common.c;beginline=8;endline=20;md5=da35978751a9d71b73679307c4d296ec" + + +SRC_URI = "file://yosemite_common \ + " + +S = "${WORKDIR}/yosemite_common" + +do_install() { + install -d ${D}${libdir} + install -m 0644 libyosemite_common.so ${D}${libdir}/libyosemite_common.so + + install -d ${D}${includedir} + install -d ${D}${includedir}/facebook + install -m 0644 yosemite_common.h ${D}${includedir}/facebook/yosemite_common.h +} + +FILES_${PN} = "${libdir}/libyosemite_common.so" +FILES_${PN}-dev = "${includedir}/facebook/yosemite_common.h" diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/libyosemite-fruid_0.1.bb b/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/libyosemite-fruid_0.1.bb new file mode 100644 index 0000000..ce9fe7f --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/libyosemite-fruid_0.1.bb @@ -0,0 +1,43 @@ +# Copyright 2015-present Facebook. All Rights Reserved. +# +# This program file 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; version 2 of the License. +# +# 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 in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA + +SUMMARY = "Yosemite Fruid Library" +DESCRIPTION = "library for reading all yosemite fruids" +SECTION = "base" +PR = "r1" +LICENSE = "GPLv2" +LIC_FILES_CHKSUM = "file://yosemite_fruid.c;beginline=6;endline=18;md5=da35978751a9d71b73679307c4d296ec" + + +SRC_URI = "file://yosemite_fruid \ + " + +DEPENDS += " libyosemite-common " + +S = "${WORKDIR}/yosemite_fruid" + +do_install() { + install -d ${D}${libdir} + install -m 0644 libyosemite_fruid.so ${D}${libdir}/libyosemite_fruid.so + + install -d ${D}${includedir} + install -d ${D}${includedir}/facebook + install -m 0644 yosemite_fruid.h ${D}${includedir}/facebook/yosemite_fruid.h +} + +FILES_${PN} = "${libdir}/libyosemite_fruid.so" +FILES_${PN}-dev = "${includedir}/facebook/yosemite_fruid.h" diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/libyosemite-gpio_0.1.bb b/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/libyosemite-gpio_0.1.bb new file mode 100644 index 0000000..39993d0 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/libyosemite-gpio_0.1.bb @@ -0,0 +1,43 @@ +# Copyright 2015-present Facebook. All Rights Reserved. +# +# This program file 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; version 2 of the License. +# +# 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 in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA + +SUMMARY = "Yosemite GPIO Pin Library" +DESCRIPTION = "library for all gpio pins in yosemite" +SECTION = "base" +PR = "r1" +LICENSE = "GPLv2" +LIC_FILES_CHKSUM = "file://yosemite_gpio.c;beginline=6;endline=18;md5=da35978751a9d71b73679307c4d296ec" + + +SRC_URI = "file://yosemite_gpio \ + " + +DEPENDS += "libbic " + +S = "${WORKDIR}/yosemite_gpio" + +do_install() { + install -d ${D}${libdir} + install -m 0644 libyosemite_gpio.so ${D}${libdir}/libyosemite_gpio.so + + install -d ${D}${includedir} + install -d ${D}${includedir}/facebook + install -m 0644 yosemite_gpio.h ${D}${includedir}/facebook/yosemite_gpio.h +} + +FILES_${PN} = "${libdir}/libyosemite_gpio.so" +FILES_${PN}-dev = "${includedir}/facebook/yosemite_gpio.h" diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/libyosemite-sensor_0.1.bb b/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/libyosemite-sensor_0.1.bb new file mode 100644 index 0000000..fbb4a15 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fblibs/libyosemite-sensor_0.1.bb @@ -0,0 +1,25 @@ +# Copyright 2015-present Facebook. All Rights Reserved. +SUMMARY = "Yosemite Sensor Library" +DESCRIPTION = "library for reading various sensors" +SECTION = "base" +PR = "r1" +LICENSE = "GPLv2" +LIC_FILES_CHKSUM = "file://yosemite_sensor.c;beginline=8;endline=20;md5=da35978751a9d71b73679307c4d296ec" + + +SRC_URI = "file://yosemite_sensor \ + " +DEPENDS =+ " libipmi libipmb libbic libsdr libyosemite-common " + +S = "${WORKDIR}/yosemite_sensor" + +do_install() { + install -d ${D}${libdir} + install -m 0644 libyosemite_sensor.so ${D}${libdir}/libyosemite_sensor.so + + install -d ${D}${includedir}/facebook + install -m 0644 yosemite_sensor.h ${D}${includedir}/facebook/yosemite_sensor.h +} + +FILES_${PN} = "${libdir}/libyosemite_sensor.so" +FILES_${PN}-dev = "${includedir}/facebook/yosemite_sensor.h" diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/bic-util_0.1.bb b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/bic-util_0.1.bb new file mode 100644 index 0000000..86679d6 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/bic-util_0.1.bb @@ -0,0 +1,21 @@ +# Copyright 2015-present Facebook. All Rights Reserved. +SUMMARY = "Bridge IC Utility" +DESCRIPTION = "Util for checking with Bridge IC on Yosemite" +SECTION = "base" +PR = "r1" +LICENSE = "GPLv2" +LIC_FILES_CHKSUM = "file://bic-util.c;beginline=4;endline=16;md5=b395943ba8a0717a83e62ca123a8d238" + +SRC_URI = "file://bic-util \ + " + +S = "${WORKDIR}/bic-util" + +do_install() { + install -d ${D}${bindir} + install -m 0755 bic-util ${D}${bindir}/bic-util +} + +DEPENDS += "libbic" + +FILES_${PN} = "${bindir}" diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/fbutils_0.1.bb b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/fbutils_0.1.bb new file mode 100644 index 0000000..9a9f5fe --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/fbutils_0.1.bb @@ -0,0 +1,102 @@ +# Copyright 2014-present Facebook. All Rights Reserved. +# +# This program file 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; version 2 of the License. +# +# 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 in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +SUMMARY = "Utilities" +DESCRIPTION = "Various utilities" +SECTION = "base" +PR = "r1" +LICENSE = "GPLv2" +LIC_FILES_CHKSUM = "file://COPYING;md5=eb723b61539feef013de476e68b5c50a" + +SRC_URI = "file://ast-functions \ + file://us_console.sh \ + file://sol-util \ + file://power_led.sh \ + file://power_util.py \ + file://post_led.sh \ + file://reset_usb.sh \ + file://setup-gpio.sh \ + file://setup_rov.sh \ + file://mdio.py \ + file://bcm5396.py \ + file://bcm5396_util.py \ + file://mount_data0.sh \ + file://eth0_mac_fixup.sh \ + file://yosemite_power.sh \ + file://power-on.sh \ + file://wedge_us_mac.sh \ + file://setup_switch.py \ + file://create_vlan_intf \ + file://watch-fc.sh \ + file://fcswitcher.sh \ + file://rc.early \ + file://rc.local \ + file://src \ + file://COPYING \ + " + +pkgdir = "utils" + +S = "${WORKDIR}" + +binfiles = "us_console.sh sol-util power_led.sh post_led.sh \ + reset_usb.sh mdio.py setup_rov.sh yosemite_power.sh wedge_us_mac.sh \ + bcm5396.py bcm5396_util.py setup_switch.py watch-fc.sh power_util.py" + +DEPENDS_append = "update-rc.d-native" + +do_install() { + dst="${D}/usr/local/fbpackages/${pkgdir}" + install -d $dst + install -m 644 ast-functions ${dst}/ast-functions + localbindir="${D}/usr/local/bin" + install -d ${localbindir} + for f in ${binfiles}; do + install -m 755 $f ${dst}/${f} + ln -s ../fbpackages/${pkgdir}/${f} ${localbindir}/${f} + done + + # common lib and include files + install -d ${D}${includedir}/facebook + install -m 0644 src/include/log.h ${D}${includedir}/facebook/log.h + install -m 0644 src/include/i2c-dev.h ${D}${includedir}/facebook/i2c-dev.h + + # init + install -d ${D}${sysconfdir}/init.d + install -d ${D}${sysconfdir}/rcS.d + # the script to mount /mnt/data + install -m 0755 ${WORKDIR}/mount_data0.sh ${D}${sysconfdir}/init.d/mount_data0.sh + update-rc.d -r ${D} mount_data0.sh start 03 S . + install -m 0755 ${WORKDIR}/rc.early ${D}${sysconfdir}/init.d/rc.early + update-rc.d -r ${D} rc.early start 04 S . + install -m 755 setup-gpio.sh ${D}${sysconfdir}/init.d/setup-gpio.sh + update-rc.d -r ${D} setup-gpio.sh start 59 S . + # create VLAN intf automatically + #install -d ${D}/${sysconfdir}/network/if-up.d + #install -m 755 create_vlan_intf ${D}${sysconfdir}/network/if-up.d/create_vlan_intf + # networking is done after rcS, any start level within rcS + # for mac fixup should work + #install -m 755 eth0_mac_fixup.sh ${D}${sysconfdir}/init.d/eth0_mac_fixup.sh + #update-rc.d -r ${D} eth0_mac_fixup.sh start 70 S . + install -m 755 power-on.sh ${D}${sysconfdir}/init.d/power-on.sh + update-rc.d -r ${D} power-on.sh start 85 S . + #install -m 755 fcswitcher.sh ${D}${sysconfdir}/init.d/fcswitcher.sh + #update-rc.d -r ${D} fcswitcher.sh start 90 S . + install -m 0755 ${WORKDIR}/rc.local ${D}${sysconfdir}/init.d/rc.local + update-rc.d -r ${D} rc.local start 99 2 3 4 5 . +} + +FILES_${PN} += "/usr/local ${sysconfdir}" diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/COPYING b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/COPYING new file mode 100644 index 0000000..3912109 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/ast-functions b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/ast-functions new file mode 100644 index 0000000..f29514f --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/ast-functions @@ -0,0 +1,147 @@ +# Copyright 2014-present Facebook. All Rights Reserved. +DEVMEM=/sbin/devmem + +devmem_set_bit() { + local addr + local val + addr=$1 + val=$($DEVMEM $addr) + val=$((val | (0x1 << $2))) + $DEVMEM $addr 32 $val +} + +devmem_clear_bit() { + local addr + local val + addr=$1 + val=$($DEVMEM $addr) + val=$((val & ~(0x1 << $2))) + $DEVMEM $addr 32 $val +} + +scu_addr() { + echo $((0x1E6E2000 + 0x$1)) +} + +GPIODIR="/sys/class/gpio" +GPIOEXPORT="$GPIODIR/export" + +gpio_dir() { + echo "$GPIODIR/gpio$1" +} + +gpio_name2value() { + local first remaining base val + remaining=$1 + val=0 + while [ -n "$remaining" ]; do + first=${remaining:0:1} + case "$first" in + [[:lower:]]) + base=$(printf "%d" "'$first'") + base=$((base - 96)) + val=$((val * 26 + base)) + ;; + [[:upper:]]) + base=$(printf "%d" "'$first'") + base=$((base - 64)) + val=$((val * 26 + base)) + ;; + *) + if [ $val -gt 0 ]; then + val=$((val-1)) + fi + val=$((val * 8 + $remaining)) + break + ;; + esac + remaining=${remaining:1} + done + echo "$val" +} + +gpio_export() { + local gpio + gpio=$(gpio_name2value $1) + dir=$(gpio_dir $gpio) + if [ ! -d ${dir} ]; then + echo $gpio > $GPIOEXPORT + fi +} + +gpio_set() { + local gpio + local val + gpio=$(gpio_name2value $1) + val=$2 + dir=$(gpio_dir $gpio) + if [ ! -d ${dir} ]; then + echo $gpio > $GPIOEXPORT + fi + echo out > ${dir}/direction + echo $val > ${dir}/value +} + +gpio_get() { + local gpio + local val + gpio=$(gpio_name2value $1) + dir=$(gpio_dir $gpio) + if [ ! -d ${dir} ]; then + echo $gpio > $GPIOEXPORT + fi + echo in > ${dir}/direction + cat ${dir}/value +} + +# Check to see if BMC power-on-reset +is_bmc_por() { + local val + # Read the Watch Dog Counter + val=$(devmem 0x1e785010 2>/dev/null) + if [ "$((val & 0xff00))" == "0" ]; then + # Power ON Reset + echo 1 + else + echo 0 + fi +} + +# Check to see if server is present in given slot or not +is_server_prsnt() { + local prsnt + + case $1 in + 1) + prsnt=$(gpio_get H5) + ;; + 2) + prsnt=$(gpio_get H4) + ;; + 3) + prsnt=$(gpio_get H7) + ;; + 4) + prsnt=$(gpio_get H6) + ;; + *) + prsnt=$(gpio_get H4) + ;; + esac + + if [ $prsnt == "0" ]; then + echo 1 + else + echo 0 + fi +} + +yosemite_is_server_on() { + local curr_pwr_cpu + curr_pwr_cpu=$(python -c 'import sys; sys.path.append("/usr/local/fbpackages/utils"); import power_util; print power_util.get_pwr_cpu()') + if [ $curr_pwr_cpu == "1" ]; then + echo 1 + else + echo 0 + fi +} diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/at93c46.py b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/at93c46.py new file mode 100644 index 0000000..9fa9f05 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/at93c46.py @@ -0,0 +1,276 @@ +# Copyright 2004-present Facebook. All rights reserved. +# +# This program file 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; version 2 of the License. +# +# 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 in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +# + +import subprocess +import struct +import sys + +class VerboseLogger: + def __init__(self, verbose=False): + self.verbose = verbose + + def _verbose_print(self, caption, bytestream=None): + ''' + Print a bytestream to stdout if verbose is enabled. + ''' + if self.verbose: + if bytestream is not None: + sys.stderr.write("{}: {}\n".format(caption, " ".join(['{:02X}'.format(ord(x)) for x in bytestream]))) + else: + sys.stderr.write("{}\n".format(caption)) + +class AT93C46SPI(VerboseLogger): + '''The class to access AT93C46 through SPI intf''' + SPI_CMD = 'spi-bb' + + def __init__(self, bus_width, gpio_cs, gpio_ck, gpio_do, gpio_di, + verbose=False): + if bus_width != 8 and bus_width != 16: + raise Exception("Invalid bus width for AT93C46!") + + self.bus_width = bus_width + self.gpio_cs = gpio_cs + self.gpio_ck = gpio_ck + self.gpio_do = gpio_do + self.gpio_di = gpio_di + self.verbose = verbose + + self.addr_bits = 6 if self.bus_width == 16 else 7 + self.addr_mask = 0x3F if self.bus_width == 16 else 0x7F + + def __shift(self, bytestream, value): + ''' + Shift an entire byte stream by value bits. + ''' + binary = "".join(['{:08b}'.format(ord(x)) for x in bytestream]) + if value > 0: + binary = binary[value:] + '0' * value + else: + binary = '0' * (-value) + binary[:value] + return "".join([chr(int(binary[x:x+8],2)) for x in range(0, len(binary), 8)]) + + def __io(self, op, addr, data=None): + ''' + Perform an IO operation against the EEPROM + ''' + write_bits = self.addr_bits + 3 + if data is not None: + # If giving data, we are doing a write command so + # no need to read any data. + write_bits = write_bits + self.bus_width + read_bits = 0 + else: + # If not giving data, we are doing either a read + # command or a set command, so read the result. + # We pad with an extra bit due to a dummy bit introduced + # by a delay for address decoding on chip. + read_bits = self.addr_bits + 4 + self.bus_width + + # Format the command itself + cmd_loc = 6 if self.bus_width == 16 else 7 + instruction = addr & self.addr_mask + instruction = instruction | ((0x4 | (op & 0x3)) << cmd_loc) + if data is not None: + if self.bus_width == 16: + write_data = struct.pack(">HH", instruction, data & 0xFFFF) + else: + write_data = struct.pack(">HB", instruction, data & 0xFF) + else: + write_data = struct.pack(">H", instruction) + write_data = self.__shift(write_data, 16 - (cmd_loc + 3)) + + self._verbose_print("Write data", write_data) + + # Run the command with the bitbang driver + if read_bits > 0: + data_portion = "-r {} -w {}".format(read_bits, write_bits) + else: + data_portion = "-w {}".format(write_bits) + + cmd = "{} -s {} -c {} -o {} -i {} -b {}".format( + self.SPI_CMD, self.gpio_cs, self.gpio_ck, self.gpio_do, + self.gpio_di, data_portion + ) + + self._verbose_print("Command: {}".format(cmd)) + + out = subprocess.Popen(cmd.split(), + stdout=subprocess.PIPE, + stdin = subprocess.PIPE)\ + .communicate(input=write_data) + + # Format the response + read_data = self.__shift(out[0], cmd_loc + 4) + if self.bus_width == 16: + read_data = read_data[:2] + self._verbose_print("Read data", read_data) + return struct.unpack(">H", read_data)[0] + else: + read_data = read_data[:1] + self._verbose_print("Read data", read_data) + return struct.unpack(">B", read_data)[0] + + def read(self, addr): + return self.__io(0x2, addr) + + def ewen(self): + self.__io(0x0, 0x3 << (self.addr_bits - 2)) + + def erase(self, addr): + self.__io(0x3, addr) + + def write(self, addr, data): + self.__io(0x1, addr, data) + + def eral(self): + self.__io(0x0, 0x2 << (self.addr_bits - 2)) + + def wral(self, data): + self.__io(0x0, 0x1 << (self.addr_bits - 2), data) + + def ewds(self): + self.__io(0x0, 0x0) + +class AT93C46(VerboseLogger): + ''' + The class which handles accessing memory on the AT93C46 chip. + ''' + AT93C46_MEMORY_SIZE = 128 + + def __init__(self, bus_width, gpio_cs, gpio_ck, gpio_do, gpio_di, + byte_swap, verbose=False): + self.bus_width = bus_width + self.verbose = verbose + self.byte_swap = byte_swap + + self.spi = AT93C46SPI(bus_width=bus_width, gpio_cs=gpio_cs, + gpio_ck=gpio_ck, gpio_do=gpio_do, + gpio_di=gpio_di, verbose=verbose) + + def __swap(self, value): + ''' + Swap bytes for a 16-bit integer if instructed to do so. + ''' + if self.bus_width == 16: + if self.byte_swap: + return ((value >> 8) & 0xFF) | ((value << 8) & 0xFF00) + else: + return value + else: + return value + + def erase(self, offset=None, limit=None): + ''' + Erase the chip. + ''' + if offset is None: + offset = 0 + if limit is None: + limit = self.AT93C46_MEMORY_SIZE + + if offset < 0 or offset + limit > self.AT93C46_MEMORY_SIZE: + raise Exception("Erase would be out of bounds!") + if self.bus_width == 16 and \ + ((offset & 1) != 0 or ((offset + limit) & 1) != 0): + raise Exception("Erase can't start or end on odd boundary in 16-bit mode!") + + if offset == 0 and limit == self.AT93C46_MEMORY_SIZE: + # Special case when we are erasing the entire chip + self.spi.ewen() + self.spi.eral() + self.spi.ewds() + + self._verbose_print("Erased entire chip") + else: + # Regular case + if self.bus_width == 16: + real_offset = offset / 2 + real_limit = limit / 2 + else: + real_offset = offset + real_limit = limit + + self.spi.ewen() + for addr in range(real_offset, real_offset + real_limit): + self.spi.erase(addr) + self.spi.ewds() + + self._verbose_print("Erased {} bytes from offset {}".format(limit, offset)) + + def read(self, offset=None, limit=None): + ''' + Read the chip into a memory buffer. + ''' + if offset is None: + offset = 0 + if limit is None: + limit = self.AT93C46_MEMORY_SIZE + + if offset < 0 or offset + limit > self.AT93C46_MEMORY_SIZE: + raise Exception("Read would be out of bounds!") + if self.bus_width == 16 and \ + ((offset & 1) != 0 or ((offset + limit) & 1) != 0): + raise Exception("Read can't start or end on odd boundary in 16-bit mode!") + + output = "" + if self.bus_width == 16: + real_offset = offset / 2 + real_limit = limit / 2 + pack_instruction = "=H" + else: + real_offset = offset + real_offset + pack_instruction = "=B" + + for addr in range(real_offset, real_offset + real_limit): + output = output + struct.pack(pack_instruction, self.__swap(self.spi.read(addr))) + + self._verbose_print("Read {} bytes from offset {}".format(limit, offset), output) + + return output + + def write(self, data, offset=None): + ''' + Write a memory buffer to the chip. + ''' + if offset is None: + offset = 0 + + if offset < 0 or offset + len(data) > self.AT93C46_MEMORY_SIZE: + raise Exception("Write would be out of bounds!") + if self.bus_width == 16 and \ + ((offset & 1) != 0 or ((offset + len(data)) & 1) != 0): + raise Exception("Write can't start or end on odd boundary in 16-bit mode!") + + if self.bus_width == 16: + offset_divisor = 2 + pack_instruction = "=H" + else: + offset_divisor = 1 + pack_instruction = "=B" + + self.spi.ewen() + for addr in range(offset, offset + len(data), offset_divisor): + actual_addr = addr / offset_divisor + value = self.__swap(struct.unpack(pack_instruction, data[(addr - offset):(addr - offset) + offset_divisor])[0]) + + self.spi.erase(actual_addr) + self.spi.write(actual_addr, value) + self.spi.ewds() + + self._verbose_print("Wrote {} bytes from offset {}".format(len(data), offset), data) diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/at93c46_util.py b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/at93c46_util.py new file mode 100755 index 0000000..c10f879 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/at93c46_util.py @@ -0,0 +1,194 @@ +#!/usr/bin/python -S +# Copyright 2004-present Facebook. All rights reserved. +# +# This program file 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; version 2 of the License. +# +# 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 in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +# + +from argparse import ArgumentParser +from at93c46 import AT93C46, AT93C46SPI +import sys + +def get_raw(args): + return AT93C46SPI(args.bus_width, args.cs, args.clk, args.mosi, args.miso, + args.verbose) + +def get_chip(args): + return AT93C46(args.bus_width, args.cs, args.clk, args.mosi, args.miso, + args.byte_swap, args.verbose) + +def access_parser(ap): + # Default, based on currenct HW configuration + SPI_CS_DEFAULT = 68 + SPI_CLK_DEFAULT = 69 + SPI_MOSI_DEFAULT = 70 + SPI_MISO_DEFAULT = 71 + + spi_group = ap.add_argument_group('SPI Access') + spi_group.add_argument('--cs', type=int, default=SPI_CS_DEFAULT, + help='The GPIO number for SPI CS pin (default: %s)' + % SPI_CS_DEFAULT) + spi_group.add_argument('--clk', type=int, default=SPI_CLK_DEFAULT, + help='The GPIO number for SPI CLK pin (default: %s)' + % SPI_CLK_DEFAULT) + spi_group.add_argument('--mosi', type=int, default=SPI_MOSI_DEFAULT, + help='The GPIO number for SPI MOSI pin (default: %s)' + % SPI_MOSI_DEFAULT) + spi_group.add_argument('--miso', type=int, default=SPI_MISO_DEFAULT, + help='The GPIO number for SPI MISO pin (default: %s)' + % SPI_MISO_DEFAULT) + +def bus_width_parser(ap): + # Default, based on currenct HW configuration + AT83C46_BUS_WIDTH = 16 + + bus_group = ap.add_argument_group('Bus Width') + bus_group.add_argument('--bus-width', type=int, default=AT83C46_BUS_WIDTH, + help='The configured bus width (default: %s)' + % AT83C46_BUS_WIDTH) + +def read_raw(args): + raw = get_raw(args) + val = raw.read(args.address) + + if args.int: + print "{}".format(val) + else: + if args.bus_width == 16: + print "0x{:04X}".format(val) + else: + print "0x{:02X}".format(val) + +def write_raw(args): + if args.value[:2] == "0x": + value = int(args.value, 16) + else: + value = int(args.value) + + raw = get_raw(args) + raw.ewen() + raw.erase(args.address) + raw.write(args.address, value) + raw.ewds() + +def erase_raw(args): + raw = get_raw(args) + raw.ewen() + raw.erase(args.address) + raw.ewds() + +def raw_subparser(subparsers): + raw_parser = subparsers.add_parser('raw', help='Raw memory access') + raw_sub = raw_parser.add_subparsers() + + read_parser = raw_sub.add_parser('read', help='Read a single memory address') + read_parser.add_argument('address', type=int, help='The memory address') + read_parser.add_argument('--int', action='store_true', + help='Display output as an integer') + read_parser.set_defaults(func=read_raw) + + write_parser = raw_sub.add_parser('write', help='Write a single memory address') + write_parser.add_argument('address', type=int, help='The memory address') + write_parser.add_argument('value', type=str, help='The value to write, either integer or hex') + write_parser.set_defaults(func=write_raw) + + erase_parser = raw_sub.add_parser('erase', help='Erase a single memory address') + erase_parser.add_argument('address', type=int, help='The memory address') + erase_parser.set_defaults(func=erase_raw) + +def read_chip(args): + chip = get_chip(args) + data = chip.read(args.start, args.length) + + if args.file is None: + sys.stdout.write(data) + else: + fp = open(args.file, "wb") + fp.write(data) + +def write_chip(args): + chip = get_chip(args) + + # Either way, limit reads to the size of the chip + if args.file is None: + data = sys.stdin.read(AT93C46.AT93C46_MEMORY_SIZE) + else: + fp = open(args.file, "rb") + data = fp.read(AT93C46.AT93C46_MEMORY_SIZE) + + if args.length is not None: + # Make sure length is correct + if len(data) < args.length: + data = data + '\x00' * (args.length - len(data)) + if len(data) > args.length: + data = data[:args.length] + + chip.write(data, args.start) + +def erase_chip(args): + chip = get_chip(args) + chip.erase(args.start, args.length) + +def chip_subparser(subparsers): + chip_parser = subparsers.add_parser('chip', help='Chip-level access') + chip_sub = chip_parser.add_subparsers() + + read_parser = chip_sub.add_parser('read', help='Read from the chip') + read_parser.add_argument('--start', type=int, + help='The memory address to start at (default: 0)') + read_parser.add_argument('--length', type=int, + help='The number of bytes to read (default: whole chip)') + read_parser.add_argument('--file', type=str, + help='File to operate on (default: stdout)') + read_parser.add_argument('--byte-swap', action='store_true', + help='Byte swap values for 16-bit reads/writes') + read_parser.set_defaults(func=read_chip) + + write_parser = chip_sub.add_parser('write', help='Write to the chip') + write_parser.add_argument('--start', type=int, + help='The memory address to start at (default: 0)') + write_parser.add_argument('--length', type=int, + help='The number of bytes to write (default: file length)') + write_parser.add_argument('--file', type=str, + help='File to operate on (default: stdin)') + write_parser.add_argument('--byte-swap', action='store_true', + help='Byte swap values for 16-bit reads/writes') + write_parser.set_defaults(func=write_chip) + + erase_parser = chip_sub.add_parser('erase', help='Erase the chip') + erase_parser.add_argument('--start', type=int, + help='The memory address to start at (default: 0)') + erase_parser.add_argument('--length', type=int, + help='The number of bytes to erase (default: whole chip)') + erase_parser.set_defaults(func=erase_chip) + +if __name__ == "__main__": + # General arguments + ap = ArgumentParser() + ap.add_argument('--verbose', action='store_true', + help='Print verbose debugging information') + + # SPI and bus width arguments + access_parser(ap) + bus_width_parser(ap) + + # Functionality + subparsers = ap.add_subparsers() + raw_subparser(subparsers) + chip_subparser(subparsers) + + # Command runner + args = ap.parse_args() + args.func(args) diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/bcm5396.py b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/bcm5396.py new file mode 100644 index 0000000..e1aba47 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/bcm5396.py @@ -0,0 +1,452 @@ +# +# Copyright 2004-present Facebook. All rights reserved. +# +# This program file 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; version 2 of the License. +# +# 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 in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +# + +import subprocess +import time + +class Bcm5396MDIO: + '''The class to access BCM5396 through MDIO intf''' + MDIO_CMD = 'mdio-bb' + + PHYADDR = 0x1E + + ACCESS_CTRL_REG = 16 + IO_CTRL_REG = 17 + STATUS_REG = 18 + DATA0_REG = 24 + DATA1_REG = 25 + DATA2_REG = 26 + DATA3_REG = 27 + + def __init__(self, mdc, mdio): + self.mdc = mdc + self.mdio = mdio + self.page = -1 + + def __io(self, op, reg, val=0): + cmd = '%s -p -c %s -d %s %s %s %s' \ + % (self.MDIO_CMD, self.mdc, self.mdio, op, str(self.PHYADDR), + str(reg)) + if op == 'write': + cmd += ' %s' % val + out = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE)\ + .communicate()[0] + if op == 'write': + return val + # need to parse the result for read + rc = 0 + for line in out.split('\n'): + if not line.startswith('Read:'): + continue + rc = int(line.split(':')[1], 0) + return rc + + def __read_mdio(self, reg): + return self.__io('read', reg) + + def __write_mdio(self, reg, val): + return self.__io('write', reg, val) + + def __set_page(self, page): + if self.page == page: + return + # Write MII register ACCESS_CTRL_REG: + # set bit 0 as "1" to enable MDIO access + # set "page number to bit 15:8 + val = 0x1 | ((page & 0xff) << 8) + self.__write_mdio(self.ACCESS_CTRL_REG, val) + self.page = page + + def __wait_for_done(self): + # Read MII register IO_CTRL_REG: + # Check op_code = "00" + while (self.__read_mdio(self.IO_CTRL_REG) & 0x3): + time.sleep(0.010) # 10ms + + def read(self, page, reg, n_bytes): + self.__set_page(page) + # Write MII register IO_CTRL_REG: + # set "Operation Code as "00" + # set "Register Address" to bit 15:8 + val = 0x00 | ((reg & 0xff) << 8) + self.__write_mdio(self.IO_CTRL_REG, val) + # Write MII register IO_CTRL_REG: + # set "Operation Code as "10" + # set "Register Address" to bit 15:8 + val = 0x2 | ((reg & 0xff) << 8) + self.__write_mdio(self.IO_CTRL_REG, val) + self.__wait_for_done() + # Read MII register DATA0_REG for bit 15:0 + val = long(self.__read_mdio(self.DATA0_REG)) + # Read MII register DATA1_REG for bit 31:16 + val |= self.__read_mdio(self.DATA1_REG) << 16 + # Read MII register DATA2_REG for bit 47:32 + val |= self.__read_mdio(self.DATA2_REG) << 32 + # Read MII register DATA3_REG for bit 63:48 + val |= self.__read_mdio(self.DATA3_REG) << 48 + return val + + def write(self, page, reg, val, n_bytes): + self.__set_page(page) + # Write MII register DATA0_REG for bit 15:0 + self.__write_mdio(self.DATA0_REG, val & 0xFFFF) + # Write MII register DATA1_REG for bit 31:16 + self.__write_mdio(self.DATA1_REG, (val >> 16) & 0xFFFF) + # Write MII register DATA2_REG for bit 47:32 + self.__write_mdio(self.DATA2_REG, (val >> 32) & 0xFFFF) + # Write MII register DATA3_REG for bit 63:48 + self.__write_mdio(self.DATA3_REG, (val >> 48) & 0xFFFF) + # Write MII register IO_CTRL_REG: + # set "Operation Code as "00" + # set "Register Address" to bit 15:8 + val = 0x00 | ((reg & 0xff) << 8) + self.__write_mdio(self.IO_CTRL_REG, val) + # Write MII register IO_CTRL_REG: + # set "Operation Code as "01" + # set "Register Address" to bit 15:8 + val = 0x1 | ((reg & 0xff) << 8) + self.__write_mdio(self.IO_CTRL_REG, val) + self.__wait_for_done() + + +class Bcm5396SPI: + '''The class to access BCM5396 through SPI interface''' + SPI_CMD = 'spi-bb' + + READ_CMD = 0x60 + WRITE_CMD = 0x61 + + SPI_STS_DIO = 0xF0 + SPI_STS_REG = 0xFE + SPI_STS_REG_RACK = 0x1 << 5 + SPI_STS_REG_SPIF = 0x1 << 7 + PAGE_REG = 0xFF + + def __init__(self, cs, clk, mosi, miso): + self.cs = cs + self.clk = clk + self.mosi = mosi + self.miso = miso + self.page = -1 + + def __bytes2val(self, values): + # LSB first, MSB last + pos = 0 + result = 0L + for byte in values: + if type(byte) is str: + byte = int(byte, 16) + if byte > 255: + raise Exception('%s is not a byte in the list %s'\ + % (byte, values)) + result |= byte << pos + pos += 8 + return result + + def __val2bytes(self, value, n): + result = [] + for _ in range(n): + result.append(value & 0xFF) + value >>= 8 + if value > 0: + raise Exception('Value, %s, is too large for %s bytes' + % (value, n)) + return result + + def __io(self, bytes_to_write, to_read=0): + # TODO: check parameters + cmd = '%s -s %s -S low -c %s -o %s -i %s '\ + % (self.SPI_CMD, self.cs, self.clk, self.mosi, self.miso) + if len(bytes_to_write): + write_cmd = '-w %s %s '\ + % (len(bytes_to_write) * 8, + ' '.join([str(byte) for byte in bytes_to_write])) + else: + write_cmd = '' + if to_read: + # spi-bb will first return the exact number of bits used for + # writing. So, total number of bits to read should also include + # the number of bits written. + cmd += '-r %s ' % str((len(bytes_to_write) + to_read) * 8) + cmd += write_cmd + rc = 0L + out = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE)\ + .communicate()[0] + if to_read: + # need to parse the result + for line in out.split('\n'): + if not line.startswith('Read'): + continue + res = line.split(':')[1] + rc = self.__bytes2val(res.split()[len(bytes_to_write):]) + break + return rc + + def __set_page(self, page): + page &= 0xff + if self.page == page: + return + self.__io([self.WRITE_CMD, self.PAGE_REG, page]) + self.page = page + + def __read_spi_reg(self, reg): + reg &= 0xFF + return self.__io([self.READ_CMD, reg], 1) + + def __read_spi_sts(self): + return self.__read_spi_reg(self.SPI_STS_REG) + + def __read_spi_dio(self): + return self.__read_spi_reg(self.SPI_STS_DIO) + + def read(self, page, reg, n_bytes): + '''Read a register value from a page.''' + if n_bytes > 8: + print('TODO to support reading more than 8 bytes') + return 0 + if page > 0xff or reg > 0xff: + print('Page and register must be <= 255') + return 0 + try: + self.__set_page(page) + self.__io([self.READ_CMD, reg], 1) + while True: + # check sts + sts = self.__read_spi_sts() + if sts & self.SPI_STS_REG_RACK: + break + bytes = [] + for _ in range(n_bytes): + bytes.append(self.__read_spi_dio()) + except Exception as e: + print(e) + return self.__bytes2val(bytes) + + def write(self, page, reg, val, n_bytes): + '''Write a value as n bytes to a register on a page.''' + if page > 0xff or reg > 0xff: + print('Page and register must be <= 255') + return + bytes = self.__val2bytes(val, n_bytes) + if len(bytes) > 8: + print('TODO to support writing more than 8 bytes') + return + bytes = [self.WRITE_CMD, reg] + bytes + try: + self.__set_page(page) + self.__io(bytes) + except Exception as e: + print(e) + +class Bcm5396: + '''The class for BCM5396 Switch''' + + MDIO_ACCESS = 0 + SPI_ACCESS = 1 + + def __init__(self, access, **kwargs): + if access == self.MDIO_ACCESS: + self.access = Bcm5396MDIO(**kwargs) + else: + self.access = Bcm5396SPI(**kwargs) + + def write(self, page, reg, value, n_bytes): + return self.access.write(page, reg, value, n_bytes) + + def read(self, page, reg, n_bytes): + return self.access.read(page, reg, n_bytes) + + def __add_remove_vlan(self, add, vid, untag, fwd, spt): + VLAN_PAGE = 0x5 + CTRL_ADDR = 0x60 + CTRL_START_DONE = (0x1 << 7) + VID_ADDR = 0x61 + ENTRY_ADDR = 0x63 + + fwd_map = self.__ports2portmap(fwd) + untag_map = self.__ports2portmap(untag) + + # mark it as write and stop the previous action + ctrl = 0 + self.write(VLAN_PAGE, CTRL_ADDR, ctrl, 1) + # write entry + if (add): + entry = 0x1L | ((spt & 0x1F) << 1) \ + | (fwd_map << 6) | (untag_map << 23) + else: + entry = 0x0L + self.write(VLAN_PAGE, ENTRY_ADDR, entry, 8) + # write vid as the index + self.write(VLAN_PAGE, VID_ADDR, vid & 0xFFF, 2) + # start the write + ctrl = CTRL_START_DONE + self.write(VLAN_PAGE, CTRL_ADDR, ctrl, 1) + while True: + ctrl = self.read(VLAN_PAGE, CTRL_ADDR, 1) + if not (ctrl & CTRL_START_DONE): + # done + break + time.sleep(0.010) # 10ms + + def add_vlan(self, vid, untag, fwd, spt=0): + return self.__add_remove_vlan(True, vid, untag, fwd, spt) + + def remove_vlan(self, vid): + return self.__add_remove_vlan(False, vid, [], [], 0) + + def get_vlan(self, vid): + VLAN_PAGE = 0x5 + CTRL_ADDR = 0x60 + CTRL_START_DONE = (0x1 << 7) + CTRL_READ = 0x1 + VID_ADDR = 0x61 + ENTRY_ADDR = 0x63 + + # mark it as read and stop the previous action + ctrl = CTRL_READ + self.write(VLAN_PAGE, CTRL_ADDR, ctrl, 1) + # write the vid as the index + self.write(VLAN_PAGE, VID_ADDR, vid & 0xFFF, 2) + # start the read + ctrl = CTRL_READ|CTRL_START_DONE + self.write(VLAN_PAGE, CTRL_ADDR, ctrl, 1) + while True: + ctrl = self.read(VLAN_PAGE, CTRL_ADDR, 1) + if not (ctrl & CTRL_START_DONE): + # done + break + time.sleep(0.010) # 10ms + entry = self.read(VLAN_PAGE, ENTRY_ADDR, 8) + res = {} + res['valid'] = True if entry & 0x1 else False + res['spt'] = (entry >> 1) & 0x1f + res['fwd'] = self.__portmap2ports((entry >> 6) & 0x1ffff) + res['untag'] = self.__portmap2ports((entry >> 23) & 0x1ffff) + return res + + def __portmap2ports(self, port_map): + return list(set([port if port_map & (0x1 << port) else None + for port in range (0, 17)]) + - set([None])) + + def __ports2portmap(self, ports): + port_map = 0 + for port in ports: + port_map |= (0x1 << port) + return port_map & 0x1FFFF + + def __parse_arl_result(self, vid, result): + is_bitset = lambda bit: True if result & (0x1 << bit) else False + if not is_bitset(3): + return None + res = {} + # parse vid first + res['vid'] = (vid >> 48) & 0xfff + mac_val = vid & 0xffffffffffffL + mac_list = [] + for pos in range(5, -1, -1): + mac_list.append('{:02x}'.format((mac_val >> (pos * 8)) & 0xff)) + res['mac'] = ':'.join(mac_list) + if mac_val & (0x1 << 40): + res['ports'] = self.__portmap2ports((result >> 6) & 0xffff) + else: + res['ports'] = [(result >> 6) & 0xf] + res['static'] = is_bitset(5) + res['age'] = is_bitset(4) + res['valid'] = is_bitset(3) + res['priority'] = result & 0x7 + return res + + def get_all_arls(self): + ARL_PAGE = 0x5 + SEARCH_CTRL_ADDR = 0x30 + SEARCH_CTRL_START_DONE = (0x1 << 7) + SEARCH_CTRL_SR_VALID = (0x1) + + VID0_ADDR = 0x33 + RESULT0_ADDR = 0x3B + VID1_ADDR = 0x40 + RESULT1_ADDR = 0x48 + + all = [] + # write START to search control + ctrl = SEARCH_CTRL_START_DONE + self.write(ARL_PAGE, SEARCH_CTRL_ADDR, ctrl, 1) + while True: + ctrl = self.read(ARL_PAGE, SEARCH_CTRL_ADDR, 1) + if not (ctrl & SEARCH_CTRL_START_DONE): + # Done + break + if not (ctrl & SEARCH_CTRL_SR_VALID): + # result is not ready, sleep and retry + time.sleep(0.010) # 10ms + continue + for vid_addr, result_addr in [[VID1_ADDR, RESULT1_ADDR], + [VID0_ADDR, RESULT0_ADDR]]: + vid = self.read(ARL_PAGE, vid_addr, 8) + result = self.read(ARL_PAGE, result_addr, 4) + one = self.__parse_arl_result(vid, result) + if one: + all.append(one) + return all + + def vlan_ctrl(self, enable): + VLAN_CTRL_PAGE = 0x34 + VLAN_CTRL0_REG = 0x0 + VLAN_CTRL0_B_EN_1QVLAN = 0x1 << 7 + + ctrl = self.read(VLAN_CTRL_PAGE, VLAN_CTRL0_REG, 1) + need_write = False + if enable: + if not ctrl & VLAN_CTRL0_B_EN_1QVLAN: + need_write = True; + ctrl |= VLAN_CTRL0_B_EN_1QVLAN + else: + if ctrl & VLAN_CTRL0_B_EN_1QVLAN: + need_write = True; + ctrl &= (~VLAN_CTRL0_B_EN_1QVLAN) & 0xFF + if need_write: + self.write(VLAN_CTRL_PAGE, VLAN_CTRL0_REG, ctrl, 1) + + def vlan_set_port_default(self, port, vid, pri=0): + VLAN_PORT_PAGE = 0x34 + VLAN_PORT_REG_BASE = 0x10 + + if port < 0 or port > 16: + raise Exception('Invalid port number %s' % port) + if pri < 0 or pri > 7: + raise Exception('Invalid priority %s' % pri) + if vid < 0 or vid > 0xFFF: + raise Exception('Invalid VLAN %s' % vid) + reg = VLAN_PORT_REG_BASE + port * 2 + ctrl = (pri << 13) | vid + self.write(VLAN_PORT_PAGE, reg, ctrl, 2) + + def vlan_get_port_default(self, port): + VLAN_PORT_PAGE = 0x34 + VLAN_PORT_REG_BASE = 0x10 + + if port < 0 or port > 16: + raise Exception('Invalid port number %s' % port) + reg = VLAN_PORT_REG_BASE + port * 2 + val = self.read(VLAN_PORT_PAGE, reg, 2) + res = {} + res['priority'] = (val >> 13) & 0x7 + res['vid'] = val & 0xFFF + return res diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/bcm5396_util.py b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/bcm5396_util.py new file mode 100644 index 0000000..1496412 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/bcm5396_util.py @@ -0,0 +1,260 @@ +#!/usr/bin/python +# Copyright 2004-present Facebook. All rights reserved. +# +# This program file 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; version 2 of the License. +# +# 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 in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +# + +from argparse import ArgumentParser +from bcm5396 import Bcm5396 + +def auto_long(x): + return long(x, 0) + +def auto_int(x): + return int(x, 0) + +def get_bcm(args): + if args.spi: + return Bcm5396(Bcm5396.SPI_ACCESS, cs=args.cs, clk=args.clk, + mosi=args.mosi, miso=args.miso) + else: + return Bcm5396(Bcm5396.MDIO_ACCESS, mdc=args.mdc, mdio=args.mdio) + + +def read_register(args): + bcm = get_bcm(args) + val = bcm.read(args.page, args.register, args.size) + print('Read from BCM5396 ({}:{}.{}): {}' + .format(hex(args.page), hex(args.register), args.size, hex(val))) + +def write_register(args): + bcm = get_bcm(args) + val = bcm.write(args.page, args.register, args.value, args.size) + print('Write to BCM5396 ({}.{}): {}' + .format(hex(args.page), hex(args.register), hex(args.value))) + +def register_parser(subparser): + reg_parser = subparser.add_parser('register', help='Register IO') + reg_sub = reg_parser.add_subparsers() + + read_parser = reg_sub.add_parser('read', help='read switch register') + read_parser.set_defaults(func=read_register) + read_parser.add_argument('page', type=auto_int, + help='The page of the register') + read_parser.add_argument('register', type=auto_int, + help='The register to read from') + read_parser.add_argument('size', type=auto_int, + help='Number of bytes', + choices=range(1, 9)) + + write_parser = reg_sub.add_parser('write', help='write switch register') + write_parser.set_defaults(func=write_register) + write_parser.add_argument('page', type=auto_int, + help='The page oof the register') + write_parser.add_argument('register', type=auto_int, + help='The register to write to') + write_parser.add_argument('value', type=auto_long, + help='The value to write') + write_parser.add_argument('size', type=auto_int, + help='Number of bytes', + choices=range(1, 9)) + + +def dump_arl(args): + bcm = get_bcm(args) + arls = bcm.get_all_arls() + print('All ARLs are:') + for entry in arls: + print(entry) + +def arl_parser(subparser): + dump_parser = subparser.add_parser('arl', help='dump all ARL entries') + dump_parser.set_defaults(func=dump_arl) + + +def __parse_port_list(parm): + '''Parse the port numbers to a list''' + if len(parm) == 0: + return [] + ports=[] + for port in parm.split(','): + idx = port.find('-') + if idx == -1: + p = int(port) + if p < 0 or p > 15: + raise Exception('Invalid port number %s' % p) + # just one port + ports.append(p) + else: + start = int(port[:idx]) + end = int(port[idx+1:]) + if start > end or start < 0 or end > 15: + raise Exception('Invalid port range %s-%s' % (start, end)) + ports.extend(range(start, end + 1)) + return ports + +def enable_vlan(args): + bcm = get_bcm(args) + bcm.vlan_ctrl(True) + print('VLAN function is enabled.') + +def disable_vlan(args): + bcm = get_bcm(args) + bcm.vlan_ctrl(False) + print('VLAN function is disabled.') + +def add_vlan(args): + bcm = get_bcm(args) + vid = args.vid + fwd = sorted(__parse_port_list(args.fwd)) + untag = sorted(__parse_port_list(args.untag)) + spt = args.spt + # make sure untag is subset of fwd + if not set(untag).issubset(set(fwd)): + raise Exception('Some untagged ports, %s, are not part of forward ports' + % (set(untag) - set(fwd))) + bcm.add_vlan(vid, untag, fwd, spt) + print('Added VLAN: %s' % vid) + print('Ports in VLAN: %s' % sorted(fwd)) + print('Ports without VLAN tag: %s' % sorted(untag)) + +def remove_vlan(args): + bcm = get_bcm(args) + vid = args.vid + bcm.remove_vlan(vid) + print('Removed VLAN: %s' % vid) + +def show_vlan(args): + bcm = get_bcm(args) + vid = args.vid + vlan = bcm.get_vlan(vid) + if not vlan['valid']: + print('VLAN %s does not exist' % vid) + else: + print('VLAN: %s' % vid) + print('Spanning tree index: %s' % vlan['spt']) + print('Ports in VLAN: %s' % sorted(vlan['fwd'])) + print('Untagged ports in VLAN: %s' % sorted(vlan['untag'])) + +def set_port_vlan(args): + bcm = get_bcm(args) + bcm.vlan_set_port_default(args.port, args.vid, args.pri) + print('Set VLAN default for port: %s' % args.port) + print('Default VLAN: %s' % args.vid) + print('Default priority %s' % args.pri) + +def get_port_vlan(args): + bcm = get_bcm(args) + port = bcm.vlan_get_port_default(args.port) + print('Get VLAN default for port: %s' % args.port) + print('Default VLAN: %s' % port['vid']) + print('Default priority: %s' % port['priority']) + +def vlan_parser(subparser): + UNTAG_DEFAULT = '' + SPT_DEFAULT = 0 + PRI_DEFAULT = 0 + + vlan_parser = subparser.add_parser('vlan', help='Manage vlan function') + vlan_sub = vlan_parser.add_subparsers() + + add_parser = vlan_sub.add_parser('add', help='Add or modify a VLAN entry') + add_parser.add_argument('vid', type=int, help='The VLAN ID') + add_parser.add_argument('fwd', type=str, + help='Ports belonging to this VLAN. i.e. 1,4,5-8') + add_parser.add_argument('untag', type=str, default=UNTAG_DEFAULT, nargs='?', + help='Ports that do not add VLAN tag. i.e. 1,4,5-8' + ' (default: all ports are tagged)') + add_parser.add_argument('spt', type=int, default=SPT_DEFAULT, nargs='?', + help='Spanning tree index (default: %s)' + % SPT_DEFAULT) + add_parser.set_defaults(func=add_vlan) + + remove_parser = vlan_sub.add_parser('remove', help='Remove a VLAN entry') + remove_parser.add_argument('vid', type=int, help='The VLAN ID') + remove_parser.set_defaults(func=remove_vlan) + + show_parser = vlan_sub.add_parser('show', help='Show a VLAN entry') + show_parser.add_argument('vid', type=int, help='The VLAN ID') + show_parser.set_defaults(func=show_vlan) + + enable_parser = vlan_sub.add_parser('enable', help='Enable VLAN function') + enable_parser.set_defaults(func=enable_vlan) + + disable_parser = vlan_sub.add_parser('disable', help='Enable VLAN function') + disable_parser.set_defaults(func=disable_vlan) + + port_parser = vlan_sub.add_parser('port', + help='Set/Get VLAN default for a port') + port_sub = port_parser.add_subparsers() + set_port = port_sub.add_parser('set', help='Set VLAN default for a port') + set_port.add_argument('port', type=int, help='The port number (0..16)') + set_port.add_argument('vid', type=int, + help='The default VLAN for this port') + set_port.add_argument('pri', type=int, default=PRI_DEFAULT, nargs='?', + help='The default priority for this port ' + '(default: %s)' % PRI_DEFAULT) + set_port.set_defaults(func=set_port_vlan) + + get_port = port_sub.add_parser('get', help='Get VLAN default for a port') + get_port.add_argument('port', type=int, help='The port number (0..16)') + get_port.set_defaults(func=get_port_vlan) + +def access_parser(ap): + SPI_CS_DEFAULT = 68 + SPI_CLK_DEFAULT = 69 + SPI_MOSI_DEFAULT = 70 + SPI_MISO_DEFAULT = 71 + + MDIO_MDC_DEFAULT = 6 + MDIO_MDIO_DEFAULT = 7 + + spi_group = ap.add_argument_group('SPI Access') + spi_group.add_argument('--spi', action='store_true', + help='Access through SPI.') + spi_group.add_argument('--cs', type=int, default=SPI_CS_DEFAULT, + help='The GPIO number for SPI CS pin (default: %s)' + % SPI_CS_DEFAULT) + spi_group.add_argument('--clk', type=int, default=SPI_CLK_DEFAULT, + help='The GPIO number for SPI CLK pin (default: %s)' + % SPI_CLK_DEFAULT) + spi_group.add_argument('--mosi', type=int, default=SPI_MOSI_DEFAULT, + help='The GPIO number for SPI MOSI pin (default: %s)' + % SPI_MOSI_DEFAULT) + spi_group.add_argument('--miso', type=int, default=SPI_MISO_DEFAULT, + help='The GPIO number for SPI MISO pin (default: %s)' + % SPI_MISO_DEFAULT) + mdio_group = ap.add_argument_group('MDIO Access (default)') + mdio_group.add_argument('--mdc', type=int, default=MDIO_MDC_DEFAULT, + help='The GPIO number for MDC pin (default: %s)' + % MDIO_MDC_DEFAULT) + mdio_group.add_argument('--mdio', type=int, default=MDIO_MDIO_DEFAULT, + help='The GPIO number for MDIO pin (default: %s)' + % MDIO_MDIO_DEFAULT) + return ap + + +if __name__ == '__main__': + ap = ArgumentParser() + access_parser(ap) + + subparsers = ap.add_subparsers() + register_parser(subparsers) + arl_parser(subparsers) + vlan_parser(subparsers) + args = ap.parse_args() + + args.func(args) diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/bic-util/Makefile b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/bic-util/Makefile new file mode 100644 index 0000000..9c046be --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/bic-util/Makefile @@ -0,0 +1,10 @@ +# Copyright 2015-present Facebook. All Rights Reserved. +all: bic-util + +bic-util: bic-util.c + $(CC) -pthread -lipmi -lipmb -lbic -std=c99 -o $@ $^ $(LDFLAGS) + +.PHONY: clean + +clean: + rm -rf *.o bic-util diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/bic-util/bic-util.c b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/bic-util/bic-util.c new file mode 100644 index 0000000..4a8966d --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/bic-util/bic-util.c @@ -0,0 +1,384 @@ +/* + * bic-util + * + * 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. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <syslog.h> +#include <stdint.h> +#include <pthread.h> +#include <facebook/bic.h> +#include <openbmc/ipmi.h> + +#define LAST_RECORD_ID 0xFFFF +#define MAX_SENSOR_NUM 0xFF +#define BYTES_ENTIRE_RECORD 0xFF + +// Test to Get device ID +static void +util_get_device_id(uint8_t slot_id) { + int ret; + ipmi_dev_id_t id = {0}; + + ret = bic_get_dev_id(slot_id, &id); + if (ret) { + printf("util_get_device_id: bic_get_dev_id returns %d\n", ret); + return; + } + + // Print response + printf("Device ID: 0x%X\n", id.dev_id); + printf("Device Revision: 0x%X\n", id.dev_rev); + printf("Firmware Revision: 0x%X:0x%X\n", id.fw_rev1, id.fw_rev2); + printf("IPMI Version: 0x%X\n", id.ipmi_ver); + printf("Device Support: 0x%X\n", id.dev_support); + printf("Manufacturer ID: 0x%X:0x%X:0x%X\n", id.mfg_id[2], id.mfg_id[1], id.mfg_id[0]); + printf("Product ID: 0x%X:0x%X\n", id.prod_id[1], id.prod_id[0]); + printf("Aux. FW Rev: 0x%X:0x%X:0x%X:0x%X\n", id.aux_fw_rev[0], id.aux_fw_rev[1],id.aux_fw_rev[2],id.aux_fw_rev[3]); +} + +// Tests for reading GPIO values and configuration +static void +util_get_gpio(uint8_t slot_id) { + int ret; + bic_gpio_t gpio = {0}; + + ret = bic_get_gpio(slot_id, &gpio); + if (ret) { + printf("util_get_gpio: bic_get_gpio returns %d\n", ret); + return; + } + + bic_gpio_u *t = (bic_gpio_u*) &gpio; + + // Print response + printf("PWRGOOD_CPU: %d\n", t->bits.pwrgood_cpu); + printf("PWRGOOD_PCH_PWROK: %d\n", t->bits.pwrgd_pch_pwrok); + printf("PVDDR_VRHOT_N: %d\n", t->bits.pvddr_vrhot_n); + printf("PVCCIN_VRHOT_N: %d\n", t->bits.pvccin_vrhot_n); + printf("FM_FAST_PROCHOT_N: %d\n", t->bits.fm_fast_prochot_n); + printf("PCHHOT_CPU_N: %d\n", t->bits.pchhot_cpu_n); + printf("FM_CPLD_CPU_DIMM_EVENT_C0_N: %d\n", t->bits.fm_cpld_cpu_dimm_event_c0_n); + printf("FM_CPLD_BDXDE_THERMTRIP_N: %d\n", t->bits.fm_cpld_bdxde_thermtrip_n); + printf("THERMTRIP_PCH_N: %d\n", t->bits.thermtrip_pch_n); + printf("FM_CPLD_FIVR_FAULT: %d\n", t->bits.fm_cpld_fivr_fault); + printf("FM_BDXDE_CATERR_LVT3_N: %d\n", t->bits.fm_bdxde_caterr_lvt3_n); + printf("FM_BDXDE_ERR_LVT3_N: %d\n", t->bits.fm_bdxde_err_lvt3_n); + printf("SLP_S4_N: %d\n", t->bits.slp_s4_n); + printf("FM_NMI_EVENT_BMC_N: %d\n", t->bits.fm_nmi_event_bmc_n); + printf("FM_SMI_BMC_N: %d\n", t->bits.fm_smi_bmc_n); + printf("RST_PLTRST_BMC_N: %d\n", t->bits.rst_pltrst_bmc_n); + printf("FP_RST_BTN_BUF_N: %d\n", t->bits.fp_rst_btn_buf_n); + printf("BMC_RST_BTN_OUT_N: %d\n", t->bits.bmc_rst_btn_out_n); + printf("FM_BDE_POST_CMPLT_N: %d\n", t->bits.fm_bde_post_cmplt_n); + printf("FM_BDXDE_SLP3_N: %d\n", t->bits.fm_bdxde_slp3_n); + printf("FM_PWR_LED_N: %d\n", t->bits.fm_pwr_led_n); + printf("PWRGD_PVCCIN: %d\n", t->bits.pwrgd_pvccin); + printf("SVR_ID: %d\n", t->bits.svr_id); + printf("BMC_READY_N: %d\n", t->bits.bmc_ready_n); + printf("BMC_COM_SW_N: %d\n", t->bits.bmc_com_sw_n); + printf("rsvd: %d\n", t->bits.rsvd); +} + +static void +util_get_gpio_config(uint8_t slot_id) { + int ret; + int i; + bic_gpio_config_t gpio_config = {0}; + bic_gpio_config_u *t = (bic_gpio_config_u *) &gpio_config; + + // Read configuration of all bits + for (i = 0; i < MAX_GPIO_PINS; i++) { + ret = bic_get_gpio_config(slot_id, i, &gpio_config); + if (ret == -1) { + continue; + } + + printf("gpio_config for pin#%d:\n", i); + printf("Direction: %s", t->bits.dir?"Output":"Input"); + printf("Interrupt Enabled?: %s", t->bits.ie?"Enabled":"Disabled"); + printf("Trigger Type: %s", t->bits.edge?"Level":"Edge"); + if (t->bits.trig == 0x0) { + printf("Trigger Edge: %s\n", "Falling Edge"); + } else if (t->bits.trig == 0x1) { + printf("Trigger Edge: %s\n", "Falling Edge"); + } else if (t->bits.trig == 0x2) { + printf("Trigger Edge: %s\n", "Both Edges"); + } else { + printf("Trigger Edge: %s\n", "Reserved"); + } + } +} + +static void +util_get_config(uint8_t slot_id) { + int ret; + int i; + bic_config_t config = {0}; + bic_config_u *t = (bic_config_u *) &config; + + ret = bic_get_config(slot_id, &config); + if (ret) { + printf("util_get_config: bic_get_config failed\n"); + return; + } + + printf("SoL Enabled?: %s", t->bits.sol? "Enabled" : "Disabled"); + printf("POST Enabled?: %s", t->bits.post? "Enabled" : "Disabled"); + printf("KCS Enabled?: %s", t->bits.kcs? "Enabled" : "Disabled"); + printf("IPMB Enabled?: %s", t->bits.ipmb? "Enabled" : "Disabled"); +} + +static void +util_set_config(uint8_t slot_id, uint8_t status) { + +} + +// Test to get the POST buffer +static void +util_get_post_buf(uint8_t slot_id) { + int ret; + uint8_t buf[MAX_IPMB_RES_LEN] = {0x0}; + uint8_t len; + int i; + + ret = bic_get_post_buf(slot_id, buf, &len); + if (ret) { + printf("util_get_post_buf: bic_get_post_buf returns %d\n", ret); + return; + } + + printf("util_get_post_buf: returns %d bytes\n", len); + for (i = 0; i < len; i++) { + printf("0x%X:", buf[i]); + } + printf("\n"); +} + +// Tests to read FRUID of Monolake Server +static void +util_get_fruid_info(uint8_t slot_id) { + int ret; + int i; + + ipmi_fruid_info_t info = {0}; + + ret = bic_get_fruid_info(slot_id, 0, &info); + if (ret) { + printf("util_get_fruid_info: bic_get_fruid_info returns %d\n", ret); + return; + } + + printf("FRUID info for 1S Slot..\n"); + + printf("FRUID Size: %d\n", (info.size_msb << 8) + (info.size_lsb)); + printf("Accessed as : %s\n", (info.bytes_words)?"Words":"Bytes"); +} + +static void +util_read_fruid(uint8_t slot_id) { + int ret; + int i; + + char path[64] = {0}; + sprintf(path, "/tmp/fruid_slot%d.bin", slot_id); + + ret = bic_read_fruid(slot_id, 0, path); + if (ret) { + printf("util_read_fruid: bic_read_fruid returns %d\n", ret); + return; + } +} + +// Tests to read SEL from Monolake Server +static void +util_get_sel_info(uint8_t slot_id) { + int ret; + + ipmi_sel_sdr_info_t info; + + ret = bic_get_sel_info(slot_id, &info); + if (ret) { + printf("util_get_sel_info:bic_get_sel_info returns %d\n", ret); + return; + } + + printf("SEL info for 1S Slot is..\n"); + + printf("version: 0x%X\n", info.ver); + printf("Record Count: 0x%X\n", info.rec_count); + printf("Free Space: 0x%X\n", info.free_space); + printf("Recent Add TS: 0x%X:0x%X:0x%X:0x%X\n", info.add_ts[3], info.add_ts[2], info.add_ts[1], info.add_ts[0]); + printf("Recent Erase TS: 0x%X:0x%X:0x%X:0x%X\n", info.erase_ts[3], info.erase_ts[2], info.erase_ts[1], info.erase_ts[0]); + printf("Operation Support: 0x%X\n", info.oper); +} + +static void +util_get_sel(uint8_t slot_id) { + int ret; + int i; + uint16_t rsv; + uint8_t rlen; + uint8_t rbuf[MAX_IPMB_RES_LEN] = {0}; + + ipmi_sel_sdr_req_t req; + ipmi_sel_sdr_res_t *res = (ipmi_sel_sdr_res_t *) rbuf; + + req.rsv_id = 0; + req.rec_id = 0; + req.offset = 0; + req.nbytes = BYTES_ENTIRE_RECORD; + + while (1) { + ret = bic_get_sel(slot_id, &req, res, &rlen); + if (ret) { + printf("util_get_sel:bic_get_sel returns %d\n", ret); + continue; + } + + printf("SEL for rec_id %d\n", req.rec_id); + printf("Next Record ID is %d\n", res->next_rec_id); + printf("Record contents are..\n"); + for (i = 0; i < rlen-2; i++) { // First 2 bytes are next_rec_id + printf("0x%X:", res->data[i]); + } + printf("\n"); + + req.rec_id = res->next_rec_id; + if (req.rec_id == LAST_RECORD_ID) { + printf("This record is LAST record\n"); + break; + } + } +} + +// Tests to read SDR records from Monolake Servers +static void +util_get_sdr_info(uint8_t slot_id) { + int ret; + + ipmi_sel_sdr_info_t info; + + ret = bic_get_sdr_info(slot_id, &info); + if (ret) { + printf("util_get_sdr_info:bic_get_sdr_info returns %d\n", ret); + return; + } + + printf("SDR info for 1S Slot is..\n"); + + printf("version: 0x%X\n", info.ver); + printf("Record Count: 0x%X\n", info.rec_count); + printf("Free Space: 0x%X\n", info.free_space); + printf("Recent Add TS: 0x%X:0x%X:0x%X:0x%X\n", info.add_ts[3], info.add_ts[2], info.add_ts[1], info.add_ts[0]); + printf("Recent Erase TS: 0x%X:0x%X:0x%X:0x%X\n", info.erase_ts[3], info.erase_ts[2], info.erase_ts[1], info.erase_ts[0]); + printf("Operation Support: 0x%X\n", info.oper); +} + +static void +util_get_sdr(uint8_t slot_id) { + int ret; + int i; + uint16_t rsv; + uint8_t rlen; + uint8_t rbuf[MAX_IPMB_RES_LEN] = {0}; + + ipmi_sel_sdr_req_t req; + ipmi_sel_sdr_res_t *res = (ipmi_sel_sdr_res_t *) rbuf; + + req.rsv_id = 0; + req.rec_id = 0; + req.offset = 0; + req.nbytes = BYTES_ENTIRE_RECORD; + + while (1) { + ret = bic_get_sdr(slot_id, &req, res, &rlen); + if (ret) { + printf("util_get_sdr:bic_get_sdr returns %d\n", ret); + continue; + } + + sdr_full_t *sdr = res->data; + + printf("type: %d, ", sdr->type); + printf("sensor_num: %d, ", sdr->sensor_num); + printf("sensor_type: %d, ", sdr->sensor_type); + printf("evt_read_type: %d, ", sdr->evt_read_type); + printf("m_val: %d, ", sdr->m_val); + printf("m_tolerance: %d, ", sdr->m_tolerance); + printf("b_val: %d, ", sdr->b_val); + printf("b_accuracy: %d, ", sdr->b_accuracy); + printf("accuracy_dir: %d, ", sdr->accuracy_dir); + printf("rb_exp: %d,\n", sdr->rb_exp); + + req.rec_id = res->next_rec_id; + if (req.rec_id == LAST_RECORD_ID) { + printf("This record is LAST record\n"); + break; + } + } +} + +// Test to read all Sensors from Monolake Server +static void +util_read_sensor(uint8_t slot_id) { + int ret; + int i; + ipmi_sensor_reading_t sensor; + + for (i = 0; i < MAX_SENSOR_NUM; i++) { + ret = bic_read_sensor(slot_id, i, &sensor); + if (ret) { + continue; + } + + printf("sensor#%d: value: 0x%X, flags: 0x%X, status: 0x%X, ext_status: 0x%X\n", + i, sensor.value, sensor.flags, sensor.status, sensor.ext_status); + } +} + +// TODO: Make it as User selectable tests to run +int +main(int argc, char **argv) { + + uint8_t slot_id; + + slot_id = atoi(argv[1]); + + util_get_device_id(slot_id); + + util_get_gpio(slot_id); + util_get_gpio_config(slot_id); + + util_get_config(slot_id); + + util_get_post_buf(slot_id); + + util_get_fruid_info(slot_id); + util_read_fruid(slot_id); + + util_get_sel_info(slot_id); + util_get_sel(slot_id); + + util_get_sdr_info(slot_id); + util_get_sdr(slot_id); + util_read_sensor(slot_id); +} diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/create_vlan_intf b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/create_vlan_intf new file mode 100644 index 0000000..2cf7a9a --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/create_vlan_intf @@ -0,0 +1,37 @@ +#!/bin/bash +# +# Copyright 2014-present Facebook. All Rights Reserved. +# +# This program file 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; version 2 of the License. +# +# 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 in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +# + +# only care about 'eth0' and 'oob' intf +[ "$IFACE" != "eth0" ] && [ "$IFACE" != "oob" ] && exit 0 + +. /usr/local/fbpackages/utils/ast-functions + +board=$(wedge_board_type) + +[ "$board" = "WEDGE" ] && exit 0 + +vlan=4088 +intf="${IFACE}.${vlan}" +slot=$(wedge_slot_id $board) + +vconfig add $IFACE $vlan +ifconfig $intf up "fe80::$(printf "%x" $slot):1/64" + +exit 0 diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/eth0_mac_fixup.sh b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/eth0_mac_fixup.sh new file mode 100644 index 0000000..1cdbcb6 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/eth0_mac_fixup.sh @@ -0,0 +1,41 @@ +#!/bin/bash +# +# Copyright 2014-present Facebook. All Rights Reserved. +# +# This program file 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; version 2 of the License. +# +# 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 in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +# + +### BEGIN INIT INFO +# Provides: eth0_mac_fixup.sh +# Required-Start: +# Required-Stop: +# Default-Start: S +# Default-Stop: +# Short-Description: Fixup the MAC address for eth0 based on wedge EEPROM +### END INIT INFO + +PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin + +mac=$(weutil 2>/dev/null | grep '^Local MAC' 2>/dev/null | cut -d' ' -f3 2>/dev/null) + +if [ -n "$mac" ]; then + ifconfig eth0 hw ether $mac + # compare the 'ethaddr' from u-boot env + ethaddr=$(fw_printenv ethaddr 2>/dev/null | cut -d'=' -f2 2>/dev/null) + if [ "$ethaddr" != "$mac" ]; then + fw_setenv "ethaddr" "$mac" + fi +fi diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/fcswitcher.sh b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/fcswitcher.sh new file mode 100755 index 0000000..53e24f3 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/fcswitcher.sh @@ -0,0 +1,83 @@ +#! /bin/sh +# +# Copyright 2014-present Facebook. All Rights Reserved. +# +# This program file 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; version 2 of the License. +# +# 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 in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +# + +### BEGIN INIT INFO +# Provides: usbcons +# Required-Start: +# Required-Stop: +# Default-Start: S +# Default-Stop: 0 6 +# Short-Description: Creates a virtual USB serial device and starts a console +# on it. +# +### END INIT INFO + +PATH=/sbin:/bin:/usr/sbin:/usr/bin +NAME="FC Switcher" +DESC="FC Failover Daemon" + +# source function library +. /etc/init.d/functions + +. /usr/local/fbpackages/utils/ast-functions + +STOPPER= +ACTION="$1" + +case "$ACTION" in + start) + if [ "$(wedge_board_type)" = "LC" ]; then + # Ability to prevent this from starting by editing cmdline in u-boot. + # Keeping this here until I get gadget switching working properly. (t4906522) + /usr/local/bin/watch-fc.sh > /dev/null 2>&1 & + echo "$NAME." + else + echo 'skipping watch-fc.sh: only necessary on six-pack line cards.' + fi + ;; + stop) + echo -n "Stopping $DESC: " + killall watch-fc.sh + echo "$NAME." + ;; + restart|force-reload) + echo -n "Restarting $DESC: " + killall watch-fc.sh + if [ "$(wedge_board_type)" = "LC" ]; then + sleep 1 + /usr/local/bin/watch-fc.sh > /dev/null 2>&1 & + echo "$NAME." + else + echo 'skipping watch-fc.sh: only necessary on six-pack line cards.' + fi + ;; + status) + status watch-fc.sh + exit $? + ;; + *) + N=${0##*/} + N=${N#[SK]??} + echo "Usage: $N {start|stop|status|restart|force-reload}" >&2 + exit 1 + ;; +esac + +exit 0 diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/mdio.py b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/mdio.py new file mode 100755 index 0000000..aa7d4bf --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/mdio.py @@ -0,0 +1,124 @@ +#!/usr/bin/python +# +# Copyright 2014-present Facebook. All Rights Reserved. +# +# This program file 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; version 2 of the License. +# +# 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 in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +# + +from argparse import ArgumentParser +import subprocess +import time + +IO_BASE = [ 0x1e660000, 0x1e680000 ] +PHYCR_REG_OFFSET = 0x60 +PHYCR_READ_BIT = 0x1 << 26 +PHYCR_WRITE_BIT = 0x1 << 27 +phycr_reg = lambda mac: IO_BASE[mac - 1] + PHYCR_REG_OFFSET +PHYDATA_REG_OFFSET = 0x64 +phydata_reg = lambda mac: IO_BASE[mac - 1] + PHYDATA_REG_OFFSET + + +devmem_read_cmd = lambda reg: [ 'devmem', hex(reg) ] +devmem_write_cmd = lambda reg, val: [ 'devmem', hex(reg), '32', hex(val)] + + +def devmem_read(reg): + cmd = devmem_read_cmd(reg) + #print('Cmd: {}'.format(cmd)) + out = subprocess.Popen(cmd, stdout=subprocess.PIPE).communicate()[0] + return int(out, 0) + + +def devmem_write(reg, val): + cmd = devmem_write_cmd(reg, val) + #print('Cmd: {}'.format(cmd)) + subprocess.Popen(cmd, stdout=subprocess.PIPE).communicate()[0] + + +def wait_for_mdio_done(args): + reg = phycr_reg(args.mac) + while devmem_read(reg) & (PHYCR_READ_BIT|PHYCR_WRITE_BIT): + time.sleep(0.010) # 10ms + + +def read_mdio(args): + reg = phycr_reg(args.mac) + ctrl = devmem_read(reg) + ctrl &= 0x3000003f + ctrl |= (args.phy & 0x1F) << 16 + ctrl |= (args.register & 0x1F) << 21 + ctrl |= PHYCR_READ_BIT + devmem_write(reg, ctrl) + wait_for_mdio_done(args) + val = devmem_read(phydata_reg(args.mac)) >> 16 + print('Read from PHY ({}.{}): {}' + .format(hex(args.phy), hex(args.register), hex(val))) + + +def write_mdio(args): + ctrl_reg = phycr_reg(args.mac) + ctrl = devmem_read(ctrl_reg) + ctrl &= 0x3000003f + ctrl |= (args.phy & 0x1F) << 16 + ctrl |= (args.register & 0x1F) << 21 + ctrl |= PHYCR_WRITE_BIT + data_reg = phydata_reg(args.mac) + # write data first + devmem_write(data_reg, args.value) + # then ctrl + devmem_write(ctrl_reg, ctrl) + wait_for_mdio_done(args) + print('Write to PHY ({}.{}): {}' + .format(hex(args.phy), hex(args.register), hex(args.value))) + + +def auto_int(x): + return int(x, 0) + +if __name__ == '__main__': + ap = ArgumentParser() + ap.add_argument('--mac', '-m', type=int, default=2, + help='The MAC') + ap.add_argument('--phy', '-p', type=auto_int, default=0x1f, + help='The PHY address') + + subparsers = ap.add_subparsers() + + read_parser = subparsers.add_parser('read', + help='read MDIO') + read_parser.set_defaults(func=read_mdio) + read_parser.add_argument('register', type=auto_int, + help='The register to read from') + + write_parser = subparsers.add_parser('write', + help='write MDIO') + write_parser.set_defaults(func=write_mdio) + write_parser.add_argument('register', type=auto_int, + help='The register to write to') + write_parser.add_argument('value', type=auto_int, + help='The value to write to') + + args = ap.parse_args() + + if args.mac != 2 and args.mac != 1: + print("MAC can only be either 1 or 2.") + exit(-1) + + if args.phy > 0x1f: + printf("PHY address must be smaller than 0x1f.") + exit(-2) + + args.func(args) diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/mount_data0.sh b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/mount_data0.sh new file mode 100755 index 0000000..6986be5 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/mount_data0.sh @@ -0,0 +1,61 @@ +#!/bin/sh +# +# Copyright 2014-present Facebook. All Rights Reserved. +# +# This program file 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; version 2 of the License. +# +# 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 in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +# + +### BEGIN INIT INFO +# Provides: mount_data0 +# Required-Start: mountvirtfs +# Required-Stop: +# Default-Start: S +# Default-Stop: +# Short-Description: Mount data0 partition from flash chip. +# Description: +### END INIT INFO + +. /etc/default/rcS + +# Find out which device maps to 'data0' on mtd +# Note: /proc/mtd lists partitions using mtdX, where X is a number, +# but we mount using /dev/mtdblockX. We'll do some magic here +# to get the mtdX (char device) and mtdblockX (block device) +# names. +MOUNT_POINT="/mnt/data" +DATA_CHAR_DEV=$(cat /proc/mtd | awk '{ if ($4 == "\"data0\"") print $1 }' | + cut -d ':' -f 1 | awk '{ print "/dev/" $1 }') +if [ -z "$DATA_CHAR_DEV" ] +then + echo "No data0 partition found. Not mounting anything to $MOUNT_POINT." +else + DEVICE_ID=$(echo $DATA_CHAR_DEV | tail -c 2) + DATA_BLOCK_DEV=${DATA_CHAR_DEV/mtd/mtdblock} + + echo "data0 partition found on $DATA_BLOCK_DEV; mounting to $MOUNT_POINT." + mount -t jffs2 $DATA_BLOCK_DEV $MOUNT_POINT + + # if the mount failed, format the partition and remount + if [ $? -ne 0 ] + then + echo "Mount failed; formatting $DATA_BLOCK_DEV and remounting." + flash_eraseall $DATA_CHAR_DEV + mount -t jffs2 $DATA_BLOCK_DEV $MOUNT_POINT + fi +fi + +: exit 0 + diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/post_led.sh b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/post_led.sh new file mode 100644 index 0000000..c23349f --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/post_led.sh @@ -0,0 +1,105 @@ +#!/bin/sh +# +# Copyright 2004-present Facebook. All rights reserved. +# +# This program file 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; version 2 of the License. +# +# 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 in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +# + +usage() { + echo "Displays values onto the debug header LEDs." + echo "Hex and decimal accepted." + echo "Usage: $0 <value>" +} + +. /usr/local/fbpackages/utils/ast-functions + +# Function to set the less significant hex digit +display_lower() { + local bit0=$(expr $1 % 2) + local bit1=$(expr $1 / 2 % 2) + local bit2=$(expr $1 / 4 % 2) + local bit3=$(expr $1 / 8 % 2) + + # Set the pins to the correct operating mode. + # The relevant pins are GPIOG[0...3]. + # For GPIO bank G, SCU84[0..3] must be 0. + devmem_clear_bit $(scu_addr 84) 0 + devmem_clear_bit $(scu_addr 84) 1 + devmem_clear_bit $(scu_addr 84) 2 + devmem_clear_bit $(scu_addr 84) 3 + + # Now set the GPIOs to the right binary values + gpio_set 48 $bit0 + gpio_set 49 $bit1 + gpio_set 50 $bit2 + gpio_set 51 $bit3 +} + +# Function to set the more significant hex digit +display_upper() { + local bit0=$(expr $1 % 2) + local bit1=$(expr $1 / 2 % 2) + local bit2=$(expr $1 / 4 % 2) + local bit3=$(expr $1 / 8 % 2) + + # Set the pins to the correct operating mode. + # The relevant pins are GPIOB[4...7]. + # GPIOB4: SCU80[12] = 0 and Strap[14] = 0 + # GPIOB5: SCU80[13] = 0 + # GPIOB6: SCU80[14] = 0 + # GPIOB7: SCU80[15] = 0 + devmem_clear_bit $(scu_addr 70) 14 + devmem_clear_bit $(scu_addr 80) 12 + devmem_clear_bit $(scu_addr 80) 13 + devmem_clear_bit $(scu_addr 80) 14 + devmem_clear_bit $(scu_addr 80) 15 + + gpio_set 12 $bit0 + gpio_set 13 $bit1 + gpio_set 14 $bit2 + gpio_set 15 $bit3 +} + +# Check number of parameters +if [ $# -ne 1 ] +then + usage + exit 1 +fi + +# Make sure input is actually numeric +DEC_VALUE=$(printf "%d" $1 2>/dev/null) +if [ $? -eq 1 ] +then + echo "Unable to parse input as numeric value." + exit 1 +fi + +# Make sure input is within proper range +if [ $DEC_VALUE -lt 0 ] || [ $DEC_VALUE -gt 255 ] +then + echo "Value $DEC_VALUE is outside of displayable range 0 - 0xff (255)." + exit 1 +fi + +# Get upper/lower decimal values +LOWER_DEC_VALUE=$(expr $DEC_VALUE % 16) +UPPER_DEC_VALUE=$(expr $DEC_VALUE / 16) + +# Display the results +display_lower $LOWER_DEC_VALUE +display_upper $UPPER_DEC_VALUE + diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/power-on.sh b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/power-on.sh new file mode 100644 index 0000000..3a9ce06 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/power-on.sh @@ -0,0 +1,99 @@ +#!/bin/sh +# +# Copyright 2014-present Facebook. All Rights Reserved. +# +# This program file 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; version 2 of the License. +# +# 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 in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA + +### BEGIN INIT INFO +# Provides: power-on +# Required-Start: +# Required-Stop: +# Default-Start: S +# Default-Stop: +# Short-Description: Power on Server +### END INIT INFO +. /usr/local/fbpackages/utils/ast-functions + +PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin + +# Disable Watch Dog Timer +/usr/local/bin/watchdog_ctrl.sh off + + +KEYDIR=/mnt/data/kv_store +DEF_PWR_ON=1 +TO_PWR_ON= + +check_por_config() +{ + + TO_PWR_ON=-1 + + # Check if the file/key doesn't exist + if [ ! -f "${KEYDIR}/slot${1}_por_cfg" ]; then + TO_PWR_ON=$DEF_PWR_ON + else + POR=`cat ${KEYDIR}/slot${1}_por_cfg` + + # Case ON + if [ $POR == "on" ]; then + TO_PWR_ON=1; + + # Case OFF + elif [ $POR == "off" ]; then + TO_PWR_ON=0; + + # Case LPS + elif [ $POR == "lps" ]; then + + # Check if the file/key doesn't exist + if [ ! -f "${KEYDIR}/pwr_server${1}_last_state" ]; then + TO_PWR_ON=$DEF_PWR_ON + else + LS=`cat ${KEYDIR}/pwr_server${1}_last_state` + if [ $LS == "on" ]; then + TO_PWR_ON=1; + elif [ $LS == "off" ]; then + TO_PWR_ON=0; + fi + fi + fi + fi +} + +# Check whether it is fresh power on reset +if [ $(is_bmc_por) -eq 1 ]; then + + check_por_config 1 + if [ $TO_PWR_ON -eq 1 ] && [ $(is_server_prsnt 1) == "1" ] ; then + power-util slot1 on + fi + + check_por_config 2 + if [ $TO_PWR_ON -eq 1 ] && [ $(is_server_prsnt 2) == "1" ] ; then + power-util slot2 on + fi + + check_por_config 3 + if [ $TO_PWR_ON -eq 1 ] && [ $(is_server_prsnt 3) == "1" ] ; then + power-util slot3 on + fi + + check_por_config 4 + if [ $TO_PWR_ON -eq 1 ] && [ $(is_server_prsnt 4) == "1" ] ; then + power-util slot4 on + fi +fi diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/power_led.sh b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/power_led.sh new file mode 100755 index 0000000..2f9bb6a --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/power_led.sh @@ -0,0 +1,58 @@ +#!/bin/bash +# +# Copyright 2014-present Facebook. All Rights Reserved. +# +# This program file 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; version 2 of the License. +# +# 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 in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +# + +usage() { + echo "Usage: $1 <slot#> <on | off>" + exit -1 +} + +. /usr/local/fbpackages/utils/ast-functions + +PATH=/sbin:/bin:/usr/sbin:/usr/bin + +set -e + +if [ $# != 2 ]; then + usage $0 +fi + +# Slot#1: GPIOM1(97),Slot#2: GPIOM0(96),Slot#3: GPIOM3(99),Slot#4: GPIOM2(98) +if [ $1 = "1" ]; then + gpio=M1 +elif [ $1 = "2" ]; then + gpio=M0 +elif [ $1 = "3" ]; then + gpio=M3 +elif [ $1 = "4" ]; then + gpio=M2 +else + usage $0 +fi + + +if [ $2 = "on" ]; then + val=1 +elif [ $2 = "off" ]; then + val=0 +else + usage $0 +fi + +gpio_set $gpio $val diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/power_util.py b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/power_util.py new file mode 100644 index 0000000..d1cc60e --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/power_util.py @@ -0,0 +1,151 @@ +#!/usr/bin/env python +# +# Copyright 2015-present Facebook. All Rights Reserved. +# +# This program file 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; version 2 of the License. +# +# 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 in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +# + +import os +import re +import time +import logging +from ctypes import * + +POR_DIR = '/mnt/data/power/por' +POR_CONFIG = '%s/config' % POR_DIR +POR_LPS = '%s/last_state' % POR_DIR + +logging.basicConfig(level=logging.INFO) +log = logging.getLogger(__name__) + +class PORConfig(): + on = "1" # Default ON + off = "2" # Default OFF + lps = "3" # Default is to use the Last Power State + +# Handler for Bridge IC libraries +bic = CDLL("libbic.so") + +class BIC_GPIO(Structure): + _fields_ = [ ("bic_gpio_data", c_char * 4) ] + +# Get 32-bit GPIO data +def get_bic_gpio(): + gpio = BIC_GPIO() + p_gpio = pointer(gpio) + bic.bic_get_gpio(p_gpio) + return gpio + +# Get the CPU power status +def get_pwr_cpu(): + gpio = get_bic_gpio() + pwrgood_cpu = (ord(gpio.bic_gpio_data[0]) & 0x01) + return pwrgood_cpu + +# Initilize the POR configuration files in /mnt/data +def init_por(): + + por = PORConfig() + + # For the Power On Reset Config + if not os.path.isfile(POR_CONFIG): + try: + os.makedirs(POR_DIR) + except OSERROR as err: + pass + + por_cnfg = open(POR_CONFIG, 'w') + por_cnfg.write('%s\n' % por.on) + por_cnfg.close() + + # For the Last Power State info + if not os.path.isfile(POR_LPS): + curr_time = int(time.time()) + lps = 'on %s' % str(curr_time) + + f_lps = open(POR_LPS, 'w') + f_lps.write('%s\n' % lps) + f_lps.close() + +# Get the POR config [ ON | OFF | LPS ] +def get_por_config(): + + por = PORConfig() + + if os.path.isfile(POR_CONFIG): + por_cnfg = open(POR_CONFIG, 'r') + cnfg = por_cnfg.read(1) + + if cnfg in [por.on, por.off, por.lps]: + return cnfg + else: + return 0 + else: + return -1 + +# To check whether the last power state was on or off +def get_por_lps(): + + if os.path.isfile(POR_LPS): + f_lps = open(POR_LPS, 'r') + lps = f_lps.readline() + if re.search(r'on', lps): + return 1 + elif re.search(r'off', lps): + return 0 + else: + return -1 + +# This tells whether to Power ON or not on POR +# 1 - Power ON +# 0 - Do not Power ON +def por_policy(): + + por = PORConfig() + cnfg = get_por_config() + if cnfg < 1: + log.error("power_util: Error getting the POR config.") + exit(-1) + + if (cnfg == por.on): + # cpu power ON + log.debug('ON: Powering ON') + return 1 + + elif (cnfg == por.off): + # cpu power OFF + log.debug('OFF: Powering OFF') + return 0 + + elif (cnfg == por.lps): + lps = get_por_lps() + if lps < 0: + log.error("power_util: Error getting the POR Last State.") + exit(-1) + + if lps == 1: + # cpu power ON + log.debug('LPS: Powering ON') + return 1 + + elif lps == 0: + # cpu power OFF + log.debug('LPS: Powering OFF') + return 0 + + +if __name__ == "__main__": + main() diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/rc.early b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/rc.early new file mode 100644 index 0000000..0f47c72 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/rc.early @@ -0,0 +1,25 @@ +#!/bin/sh +# +# Copyright 2014-present Facebook. All Rights Reserved. +# +# This program file 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; version 2 of the License. +# +# 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 in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +# +# This script will be executed at rcS S04 level, which is right after mount /mnt/data +# and before almost anything else. + +if [ -x /mnt/data/etc/rc.early ]; then + /mnt/data/etc/rc.early +fi diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/rc.local b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/rc.local new file mode 100644 index 0000000..36fa0f1 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/rc.local @@ -0,0 +1,26 @@ +#!/bin/sh +# +# Copyright 2014-present Facebook. All Rights Reserved. +# +# This program file 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; version 2 of the License. +# +# 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 in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +# + +# +# This script will be executed *after* all the other init scripts. + +if [ -x /mnt/data/etc/rc.local ]; then + /mnt/data/etc/rc.local +fi diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/reset_usb.sh b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/reset_usb.sh new file mode 100644 index 0000000..a7936b1 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/reset_usb.sh @@ -0,0 +1,55 @@ +#!/bin/sh +# +# Copyright 2014-present Facebook. All Rights Reserved. +# +# This program file 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; version 2 of the License. +# +# 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 in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +# + +. /usr/local/fbpackages/utils/ast-functions + +#TODO: Add logic to control mux based on front panel switch +echo -n "Set USB Mux to given slot ... " + +# USB_MUX_SEL signals: GPIOE4(36), GPIOE5(37) +slot=$1 + +case $slot in + 1) + gpio_set E4 1 + gpio_set E5 0 + ;; + 2) + gpio_set E4 0 + gpio_set E5 0 + ;; + 3) + gpio_set E4 1 + gpio_set E5 1 + ;; + 4) + gpio_set E4 0 + gpio_set E5 1 + ;; + *) + gpio_set E4 0 + gpio_set E5 0 + ;; +esac + +# Enable the USB MUX GPIOS3(147) +gpio_set S3 0 + +echo "Done" diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/setup-gpio.sh b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/setup-gpio.sh new file mode 100755 index 0000000..91797c5 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/setup-gpio.sh @@ -0,0 +1,307 @@ +#!/bin/bash +# +# Copyright 2014-present Facebook. All Rights Reserved. +# +# This program file 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; version 2 of the License. +# +# 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 in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +# + +### BEGIN INIT INFO +# Provides: gpio-setup +# Required-Start: +# Required-Stop: +# Default-Start: S +# Default-Stop: +# Short-Description: Set up GPIO pins as appropriate +### END INIT INFO + +# This file contains definitions for the GPIO pins that were not otherwise +# defined in other files. We should probably move some more of the +# definitions to this file at some point. + +# The commented-out sections are generally already defined elsewhere, +# and defining them twice generates errors. + +# The exception to this is the definition of the GPIO H0, H1, and H2 +# pins, which seem to adversely affect the rebooting of the system. +# When defined, the system doesn't reboot cleanly. We're still +# investigating this. + +. /usr/local/fbpackages/utils/ast-functions + +# Set up to read the board revision pins, Y0, Y1, Y2 +devmem_set_bit $(scu_addr 70) 19 +devmem_clear_bit $(scu_addr a4) 8 +devmem_clear_bit $(scu_addr a4) 9 +devmem_clear_bit $(scu_addr a4) 10 + +gpio_export Y0 +gpio_export Y1 +gpio_export Y2 + +# SLOT1_PRSNT_N, GPIOH5 (61) +# GPIOH5(61): SCU90[6], SCU90[7] shall be 0 +devmem_clear_bit $(scu_addr 90) 6 +devmem_clear_bit $(scu_addr 90) 7 + +gpio_export H5 + +# SLOT2_PRSNT_N, GPIOH4 (60) +# GPIOH4(60): SCU90[6], SCU90[7] shall be 0 +gpio_export H4 + +# SLOT3_PRSNT_N, GPIOH7 (63) +# GPIOH7(63): SCU90[6], SCU90[7] shall be 0 +gpio_export H7 + +# SLOT4_PRSNT_N, GPIOH6 (62) +# GPIOH6(62): SCU90[6], SCU90[7] shall be 0 +gpio_export H6 + +# BMC_PWR_BTN_IN_N, uServer power button in, on GPIO D0(24) +gpio_export D0 + +# PWR_SLOT1_BTN_N, 1S Server power out, on GPIO D3 +# GPIOD3(27): SCU90[1], SCU8C[9], and SCU70[21] shall be 0 +devmem_clear_bit $(scu_addr 90) 1 +devmem_clear_bit $(scu_addr 8c) 9 +devmem_clear_bit $(scu_addr 70) 21 + +gpio_set D3 1 + +# PWR_SLOT2_BTN_N, 1S Server power out, on GPIO D1 +# Make sure the Power Control Pin is Set properly +# GPIOD1(25): SCU90[1], SCU8C[8], and SCU70[21] shall be 0 + +devmem_clear_bit $(scu_addr 8c) 8 + +gpio_set D1 1 + +# PWR_SLOT3_BTN_N, 1S Server power out, on GPIO D7 +# GPIOD7(31): SCU90[1], SCU8C[11], and SCU70[21] shall be 0 +devmem_clear_bit $(scu_addr 8c) 11 + +gpio_set D7 1 + +# PWR_SLOT4_BTN_N, 1S Server power out, on GPIO D5 +# GPIOD5(29): SCU90[1], SCU8C[10], and SCU70[21] shall be 0 +devmem_clear_bit $(scu_addr 8c) 10 + +gpio_set D5 1 + +# SMB_SLOT0_NIC_ALERT_N, alert for 1S Server NIC I2C, GPIO B0 +devmem_clear_bit $(scu_addr 80) 8 + +gpio_export B0 + +# Setup GPIOs to Mux Enable: GPIOS3(147), Channel Select: GPIOE4(36), GPIOE5(37) + +# To use GPIOS3 (147), SCU8C[3], SCU94[0], and SCU94[1] must be 0 +devmem_clear_bit $(scu_addr 8C) 3 +devmem_clear_bit $(scu_addr 94) 0 +devmem_clear_bit $(scu_addr 94) 1 + +# To use GPIOE4 (36), SCU80[20], SCU8C[14], and SCU70[22] must be 0 +devmem_clear_bit $(scu_addr 80) 20 +devmem_clear_bit $(scu_addr 8C) 14 +devmem_clear_bit $(scu_addr 70) 22 + +# To use GPIOE5 (37), SCU80[21], SCU8C[14], and SCU70[22] must be 0 +devmem_clear_bit $(scu_addr 80) 21 +devmem_clear_bit $(scu_addr 8C) 14 +devmem_clear_bit $(scu_addr 70) 22 + +gpio_export S3 +gpio_export E4 +gpio_export E5 + +# BMC_HEARTBEAT_N, heartbeat LED, GPIO Q7 +devmem_clear_bit $(scu_addr 90) 28 + +gpio_export Q7 + +# USB_OC_N, resettable fuse tripped, GPIO Q6 +devmem_clear_bit $(scu_addr 90) 28 + +gpio_export Q6 + +# System SPI +# Strap 12 must be 0 and Strape 13 must be 1 +devmem_clear_bit $(scu_addr 70) 12 +devmem_set_bit $(scu_addr 70) 13 + +# DEBUG_PORT_UART_SEL_BMC_N: GPIOR1(137) +# To use GPIOR1, SCU88[25] must be 0 +devmem_clear_bit $(scu_addr 88) 25 + +gpio_export R1 + +# DEBUG UART Controls +# 4 signals: DEBUG_UART_SEL_0/1/2 and DEBUG_UART_RX_SEL_N +# GPIOE0 (32), GPIOE1 (33), GPIOE2 (34) and GPIOE3 (35) + +# To enable GPIOE0, SCU80[16], SCU8C[12], and SCU70[22] must be 0 +devmem_clear_bit $(scu_addr 80) 16 +devmem_clear_bit $(scu_addr 8C) 12 +devmem_clear_bit $(scu_addr 70) 22 + +gpio_set E0 0 + +# To enable GPIOE1, SCU80[17], SCU8C[12], and SCU70[22] must be 0 +devmem_clear_bit $(scu_addr 80) 17 + +gpio_set E1 0 + +# To enable GPIOE2, SCU80[18], SCU8C[13], and SCU70[22] must be 0 +devmem_clear_bit $(scu_addr 80) 18 +devmem_clear_bit $(scu_addr 8C) 13 + +gpio_set E2 1 + +# To enable GPIOE3, SCU80[19], SCU8C[13], and SCU70[22] must be 0 +devmem_clear_bit $(scu_addr 80) 19 + +gpio_set E3 1 + +# Enable GPIOY3: BoardId(Yosemite or Test system) +devmem_clear_bit $(scu_addr a4) 11 + +# Power LED for Slot#2: +# To use GPIOM0 (96), SCU90[4], SCU90[5], and SCU84[24] must be 0 +devmem_clear_bit $(scu_addr 90) 4 +devmem_clear_bit $(scu_addr 90) 5 +devmem_clear_bit $(scu_addr 84) 24 + +gpio_set M0 1 + +# Power LED for Slot#1: +# To use GPIOM1 (97), SCU90[4], SCU90[5], and SCU84[25] must be 0 +devmem_clear_bit $(scu_addr 84) 25 + +gpio_set M1 1 + +# Power LED for Slot#4: +# To use GPIOM2 (98), SCU90[4], SCU90[5], and SCU84[26] must be 0 +devmem_clear_bit $(scu_addr 84) 26 + +gpio_set M2 1 + +# Power LED for Slot#3: +# To use GPIOM3 (99), SCU90[4], SCU90[5], and SCU84[27] must be 0 +devmem_clear_bit $(scu_addr 84) 27 + +gpio_set M3 1 + +# Front Panel Hand Switch GPIO setup +# HAND_SW_ID1: GPIOR2(138) +# To use GPIOR2, SCU88[26] must be 0 +devmem_clear_bit $(scu_addr 88) 26 + +gpio_export R2 + +# HAND_SW_ID2: GPIOR3(139) +# To use GPIOR3, SCU88[27] must be 0 +devmem_clear_bit $(scu_addr 88) 27 + +gpio_export R3 + +# HAND_SW_ID4: GPIOR4(140) +# To use GPIOR4, SCU88[28] must be 0 +devmem_clear_bit $(scu_addr 88) 28 + +gpio_export R4 + + +# HAND_SW_ID8: GPIOR5(141) +# To use GPIOR5, SCU88[29] must be 0 +devmem_clear_bit $(scu_addr 88) 29 + +gpio_export R5 + +# LED POST CODES: 8 GPIO signals + +# LED_POSTCODE_0: GPIOG0 (48) +# To use GPIOG0, SCU84[0] must be 0 +devmem_clear_bit $(scu_addr 84) 0 + +gpio_set G0 0 + +# LED_POSTCODE_1: GPIOG1 (49) +# To use GPIOG1, SCU84[1] must be 0 +devmem_clear_bit $(scu_addr 84) 1 + +gpio_set G1 0 + +# LED_POSTCODE_2: GPIOG2 (50) +# To use GPIOG2, SCU84[2] must be 0 +devmem_clear_bit $(scu_addr 84) 2 + +gpio_set G2 0 + +# LED_POSTCODE_3: GPIOG3 (51) +# To use GPIOG3, SCU84[3] must be 0 +devmem_clear_bit $(scu_addr 84) 3 + +gpio_set G3 0 + +# LED_POSTCODE_4: GPIOP4 (124) +gpio_set P4 0 + +# LED_POSTCODE_5: GPIOP5 (125) +gpio_set P5 0 + +# LED_POSTCODE_6: GPIOP6 (126) +# To use GPIOP6, SCU88[22] must be 0 +devmem_clear_bit $(scu_addr 88) 22 + +gpio_set P6 0 + +# LED_POSTCODE_7: GPIOP7 (127) +# To use GPIOP7, SCU88[23] must be 0 +devmem_clear_bit $(scu_addr 88) 23 + +gpio_set P7 0 + +# BMC_READY_N: GPIOG6 (54) +# To use GPIOG6, SCU84[6] must be 0 +devmem_clear_bit $(scu_addr 84) 6 + +gpio_set G6 0 + +# BMC_RST_BTN_IN_N: GPIOS0 (144) +# To use GPIOS0, SCU8C[0] +devmem_clear_bit $(scu_addr 8c) 0 + +gpio_export S0 + +# RESET for all Slots +# RST_SLOT1_SYS_RESET_N: GPIOH1 (57) +# To use GPIOH1, SCU90[6], SCU90[7] must be 0 +devmem_clear_bit $(scu_addr 90) 6 +devmem_clear_bit $(scu_addr 90) 7 + +gpio_set H1 1 + +# RST_SLOT2_SYS_RESET_N: GPIOH0 (56) +# To use GPIOH0, SCU90[6], SCU90[7] must be 0 +gpio_set H0 1 + +# RST_SLOT3_SYS_RESET_N: GPIOH3 (59) +# To use GPIOH3, SCU90[6], SCU90[7] must be 0 +gpio_set H3 1 + +# RST_SLOT4_SYS_RESET_N: GPIOH2 (58) +# To use GPIOH2, SCU90[6], SCU90[7] must be 0 +gpio_set H2 1 diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/setup_rov.sh b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/setup_rov.sh new file mode 100755 index 0000000..749fe65 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/setup_rov.sh @@ -0,0 +1,99 @@ +#!/bin/bash +# +# Copyright 2014-present Facebook. All Rights Reserved. +# +# This program file 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; version 2 of the License. +# +# 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 in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +# + +# The T2 chip can prefer different input voltages, depending, presumably +# of manufacturing variations. We need to determine whether it wants +# 0.95V or 1.025V, reset the T2 to reduce total power usage, set the +# outgoing voltage on the first buck converter, and bring T2 up out of +# reset. + +. /usr/local/fbpackages/utils/ast-functions + +# read the T2 ROV after the GPIOs are enabled +t2_rov() { + local val0 val1 val2 + # Note that the values are *not* read in order. + val0=$(cat /sys/class/gpio/gpio58/value 2>/dev/null) + val1=$(cat /sys/class/gpio/gpio56/value 2>/dev/null) + val2=$(cat /sys/class/gpio/gpio57/value 2>/dev/null) + echo $((val0 | (val1 << 1) | (val2 << 2))) +} + +rov=$(t2_rov) + +# target_volts come from the data sheet and 18mV of loss and +# some fudging based on actual measurements to get either 1.025V +# or 0.95V at T2 +if [ $rov -eq 1 ]; then + target_volts=0x5a +elif [ $rov -eq 2 ]; then + target_volts=0x65 +else + echo "Unrecognized T2 ROV value $rov, setting failed." + exit 1 +fi +target_volts=$(( $target_volts * 1 )) # normalize to decimal + +# We shouldn't have to rmmod pmbus, because it hasn't been loaded yet, +# but if the script is rerun after the system is up, it may be necessary. +rmmod pmbus +reload=$? + +# Get current voltage value +cur_volts=$(i2cget -y 1 0x60 0x8b w) +cur_volts=$(( $cur_volts * 1 )) # normalize to decimal + +# Only bounce the T2 if we actually need to modify the voltage +if [ $cur_volts -ne $target_volts ]; then + # Set values before turning out output; we're using "PCIE, then MCS" + echo 1 > /sys/class/gpio/gpio42/value + echo 1 > /sys/class/gpio/gpio43/value + echo out > /sys/class/gpio/gpio42/direction + echo out > /sys/class/gpio/gpio43/direction + echo 0 > /sys/class/gpio/gpio16/value + echo out > /sys/class/gpio/gpio16/direction + # T2 is in reset; note that this may cause NMI messages on the uServer, + # which shouldn't be up anyway when this is first run. + + # Set the requested value to the current value to avoid rapid shifts + i2cset -y 1 0x60 0x21 $cur_volts w + # Enable the requested voltage + i2cset -y 1 0x60 0xd2 0x5a + i2cset -y 1 0x60 0xd3 0x5a + sleep 1 + + # Set the target voltage + i2cset -y 1 0x60 0x21 $target_volts w + + sleep 1 + + # Let T2 come out of reset + echo 1 > /sys/class/gpio/gpio16/value + echo "T2 ROV value set based on $rov." + sleep 2 + echo 0 > /sys/class/gpio/gpio42/value + echo 0 > /sys/class/gpio/gpio43/value +else + echo "T2 ROV already correctly set." +fi +# Bring back pmbus if necessary +if [ $reload -eq 0 ]; then + modprobe pmbus +fi diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/setup_switch.py b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/setup_switch.py new file mode 100644 index 0000000..995cec8 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/setup_switch.py @@ -0,0 +1,49 @@ +#!/usr/bin/python +# +# Copyright 2004-present Facebook. All rights reserved. +# +# This program file 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; version 2 of the License. +# +# 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 in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +# +# This script combines multiple switch configuration into one python script. +# All such configuration can be done directly through bcm5396_util.py. +# But, it turns out it took several seconds to just start the python script. +# Involking the script 16 times (2 to create vlan, 13 to set port vlan default, +# and 1 to enable vlan function) contributes 1 minute delay. + +from bcm5396 import Bcm5396 + +MDC_GPIO = 6 +MDIO_GPIO = 7 + +INTERNAL_VLAN = 4088 +DEFAULT_VLAN=4090 + +INTERNAL_PORTS = [3, 10, 1, 11, 0, 8, 2, 9, 4, 12, 14, 13] +FRONT_PORT=5 + +if __name__ == '__main__': + bcm = Bcm5396(Bcm5396.MDIO_ACCESS, mdc=MDC_GPIO, mdio=MDIO_GPIO) + # create default VLAN including internal ports and front panel + # port (un-tagged) + bcm.add_vlan(DEFAULT_VLAN, INTERNAL_PORTS + [FRONT_PORT], + INTERNAL_PORTS + [FRONT_PORT], 0) + # set ingress vlan for internal ports and front panel port to default vlan + for port in INTERNAL_PORTS + [FRONT_PORT]: + bcm.vlan_set_port_default(port, DEFAULT_VLAN, 0) + # create internal vlan including internal ports only (tagged) + bcm.add_vlan(INTERNAL_VLAN, [], INTERNAL_PORTS, 0) + # enable vlan + bcm.vlan_ctrl(True) diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/sol-util b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/sol-util new file mode 100755 index 0000000..3769a5b --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/sol-util @@ -0,0 +1,74 @@ +#!/bin/sh +# +# Copyright 2014-present Facebook. All Rights Reserved. +# +# This program file 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; version 2 of the License. +# +# 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 in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +# + +BIN_CONSOLED="/usr/local/bin/consoled" +LOGFILE1="/tmp/consoled_$1_log-old" +LOGFILE2="/tmp/consoled_$1_log" + + +if [ "$1" == "slot1" ] || [ "$1" == "slot2" ] || [ "$1" == "slot3" ] || [ "$1" == "slot4" ] +then + SLOT=$1 +else + echo "Usage: sol-util [ slot1 | slot2 | slot3 | slot4 ]" + echo " sol-util [ slot1 | slot2 | slot3 | slot4 ] --force" + echo " sol-util [ slot1 | slot2 | slot3 | slot4 ] --history" + exit -1 +fi + +if [ $# -gt 1 ]; then + if [[ "$2" == "--history" ]]; then + cat $LOGFILE1 2>/dev/null + cat $LOGFILE2 2>/dev/null + exit 0 + fi +fi + +PS=$(ps | grep -e $BIN_CONSOLED | grep -e $SLOT) + +PID=$(ps | grep -e $BIN_CONSOLED | grep -e $SLOT | awk '{print $1}') + + +if [[ $PS =~ "term" ]] && [[ "$2" != "--force" ]]; then + echo "Another SOL session is running." + echo "Please use the \"--force\" option" + exit -1 +fi + +echo "You are in SOL session." +echo "Use ctrl-x to quit." +echo "-----------------------" +echo + +kill -9 -s TERM $PID 2>/dev/null + +if [[ "$2" == "--force" ]]; then + PID=$(ps | grep -e $BIN_CONSOLED | grep -e $SLOT | awk '{print $1}') + kill -9 -s TERM $PID 2>/dev/null +fi + +$BIN_CONSOLED $SLOT --term + +$BIN_CONSOLED $SLOT --buffer + +echo +echo +echo "-----------------------" +echo "Exit from SOL session." diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/src/include/i2c-dev.h b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/src/include/i2c-dev.h new file mode 100644 index 0000000..3b67afc --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/src/include/i2c-dev.h @@ -0,0 +1,364 @@ +/* + i2c-dev.h - i2c-bus driver, char device interface + + Copyright (C) 1995-97 Simon G. Vogl + Copyright (C) 1998-99 Frodo Looijaard <frodol@dds.nl> + + 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., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301 USA. +*/ + +#ifndef _LINUX_I2C_DEV_H +#define _LINUX_I2C_DEV_H + +#include <linux/types.h> +#include <sys/ioctl.h> +#include <stddef.h> +#include <string.h> + + +/* -- i2c.h -- */ + +#define _I2C_MIN(a, b) (((a) <= (b)) ? (a) : (b)) + +/* + * I2C Message - used for pure i2c transaction, also from /dev interface + */ +struct i2c_msg { + __u16 addr; /* slave address */ + unsigned short flags; +#define I2C_CLIENT_PEC 0x04 /* Use Packet Error Checking */ +#define I2C_M_TEN 0x0010 /* this is a ten bit chip address */ +#define I2C_M_RD 0x0001 /* read data, from slave to master */ +#define I2C_S_EN 0x0002 /* read data, from slave to master */ +#define I2C_M_NOSTART 0x4000 /* if I2C_FUNC_PROTOCOL_MANGLING */ +#define I2C_M_REV_DIR_ADDR 0x2000 /* if I2C_FUNC_PROTOCOL_MANGLING */ +#define I2C_M_IGNORE_NAK 0x1000 /* if I2C_FUNC_PROTOCOL_MANGLING */ +#define I2C_M_NO_RD_ACK 0x0800 /* if I2C_FUNC_PROTOCOL_MANGLING */ +#define I2C_M_RECV_LEN 0x0400 /* length will be first received byte */ + short len; /* msg length */ + char *buf; /* pointer to msg data */ +}; + +/* To determine what functionality is present */ + +#define I2C_FUNC_I2C 0x00000001 +#define I2C_FUNC_10BIT_ADDR 0x00000002 +#define I2C_FUNC_PROTOCOL_MANGLING 0x00000004 /* I2C_M_{REV_DIR_ADDR,NOSTART,..} */ +#define I2C_FUNC_SMBUS_PEC 0x00000008 +#define I2C_FUNC_SMBUS_BLOCK_PROC_CALL 0x00008000 /* SMBus 2.0 */ +#define I2C_FUNC_SMBUS_QUICK 0x00010000 +#define I2C_FUNC_SMBUS_READ_BYTE 0x00020000 +#define I2C_FUNC_SMBUS_WRITE_BYTE 0x00040000 +#define I2C_FUNC_SMBUS_READ_BYTE_DATA 0x00080000 +#define I2C_FUNC_SMBUS_WRITE_BYTE_DATA 0x00100000 +#define I2C_FUNC_SMBUS_READ_WORD_DATA 0x00200000 +#define I2C_FUNC_SMBUS_WRITE_WORD_DATA 0x00400000 +#define I2C_FUNC_SMBUS_PROC_CALL 0x00800000 +#define I2C_FUNC_SMBUS_READ_BLOCK_DATA 0x01000000 +#define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA 0x02000000 +#define I2C_FUNC_SMBUS_READ_I2C_BLOCK 0x04000000 /* I2C-like block xfer */ +#define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK 0x08000000 /* w/ 1-byte reg. addr. */ + +#define I2C_FUNC_SMBUS_BYTE (I2C_FUNC_SMBUS_READ_BYTE | \ + I2C_FUNC_SMBUS_WRITE_BYTE) +#define I2C_FUNC_SMBUS_BYTE_DATA (I2C_FUNC_SMBUS_READ_BYTE_DATA | \ + I2C_FUNC_SMBUS_WRITE_BYTE_DATA) +#define I2C_FUNC_SMBUS_WORD_DATA (I2C_FUNC_SMBUS_READ_WORD_DATA | \ + I2C_FUNC_SMBUS_WRITE_WORD_DATA) +#define I2C_FUNC_SMBUS_BLOCK_DATA (I2C_FUNC_SMBUS_READ_BLOCK_DATA | \ + I2C_FUNC_SMBUS_WRITE_BLOCK_DATA) +#define I2C_FUNC_SMBUS_I2C_BLOCK (I2C_FUNC_SMBUS_READ_I2C_BLOCK | \ + I2C_FUNC_SMBUS_WRITE_I2C_BLOCK) + +/* Old name, for compatibility */ +#define I2C_FUNC_SMBUS_HWPEC_CALC I2C_FUNC_SMBUS_PEC + +/* + * Data for SMBus Messages + */ +#define I2C_SMBUS_BLOCK_MAX 32 /* As specified in SMBus standard */ +#define I2C_SMBUS_I2C_BLOCK_MAX 32 /* Not specified but we use same structure */ +union i2c_smbus_data { + __u8 byte; + __u16 word; + __u8 block[I2C_SMBUS_BLOCK_MAX + 2]; /* block[0] is used for length */ + /* and one more for PEC */ +}; + +#define I2C_SMBUS_BLOCK_LARGE_MAX 240 +union i2c_smbus_large_data { + union i2c_smbus_data data; + __u8 block[I2C_SMBUS_BLOCK_LARGE_MAX + 2]; /* block[0] is used for length */ + /* and one more for PEC */ +}; + +/* smbus_access read or write markers */ +#define I2C_SMBUS_READ 1 +#define I2C_SMBUS_WRITE 0 + +/* SMBus transaction types (size parameter in the above functions) + Note: these no longer correspond to the (arbitrary) PIIX4 internal codes! */ +#define I2C_SMBUS_QUICK 0 +#define I2C_SMBUS_BYTE 1 +#define I2C_SMBUS_BYTE_DATA 2 +#define I2C_SMBUS_WORD_DATA 3 +#define I2C_SMBUS_PROC_CALL 4 +#define I2C_SMBUS_BLOCK_DATA 5 +#define I2C_SMBUS_I2C_BLOCK_BROKEN 6 +#define I2C_SMBUS_BLOCK_PROC_CALL 7 /* SMBus 2.0 */ +#define I2C_SMBUS_I2C_BLOCK_DATA 8 +#define I2C_SMBUS_BLOCK_LARGE_DATA 9 + + +/* /dev/i2c-X ioctl commands. The ioctl's parameter is always an + * unsigned long, except for: + * - I2C_FUNCS, takes pointer to an unsigned long + * - I2C_RDWR, takes pointer to struct i2c_rdwr_ioctl_data + * - I2C_SMBUS, takes pointer to struct i2c_smbus_ioctl_data + */ +#define I2C_RETRIES 0x0701 /* number of times a device address should + be polled when not acknowledging */ +#define I2C_TIMEOUT 0x0702 /* set timeout in units of 10 ms */ + +/* NOTE: Slave address is 7 or 10 bits, but 10-bit addresses + * are NOT supported! (due to code brokenness) + */ +#define I2C_SLAVE 0x0703 /* Use this slave address */ +#define I2C_SLAVE_FORCE 0x0706 /* Use this slave address, even if it + is already in use by a driver! */ +#define I2C_TENBIT 0x0704 /* 0 for 7 bit addrs, != 0 for 10 bit */ + +#define I2C_FUNCS 0x0705 /* Get the adapter functionality mask */ + +#define I2C_RDWR 0x0707 /* Combined R/W transfer (one STOP only) */ +#define I2C_SLAVE_RDWR 0x0709 /* Slave Read/Write */ + +#define I2C_PEC 0x0708 /* != 0 to use PEC with SMBus */ +#define I2C_SMBUS 0x0720 /* SMBus transfer */ + + +/* This is the structure as used in the I2C_SMBUS ioctl call */ +struct i2c_smbus_ioctl_data { + __u8 read_write; + __u8 command; + __u32 size; + union i2c_smbus_data *data; +}; + +/* This is the structure as used in the I2C_RDWR ioctl call */ +struct i2c_rdwr_ioctl_data { + struct i2c_msg *msgs; /* pointers to i2c_msgs */ + __u32 nmsgs; /* number of i2c_msgs */ +}; + +#define I2C_RDRW_IOCTL_MAX_MSGS 42 + + +static inline __s32 i2c_smbus_access(int file, char read_write, __u8 command, + int size, union i2c_smbus_data *data) +{ + struct i2c_smbus_ioctl_data args; + + args.read_write = read_write; + args.command = command; + args.size = size; + args.data = data; + return ioctl(file,I2C_SMBUS,&args); +} + + +static inline __s32 i2c_smbus_write_quick(int file, __u8 value) +{ + return i2c_smbus_access(file,value,0,I2C_SMBUS_QUICK,NULL); +} + +static inline __s32 i2c_smbus_read_byte(int file) +{ + union i2c_smbus_data data; + if (i2c_smbus_access(file,I2C_SMBUS_READ,0,I2C_SMBUS_BYTE,&data)) + return -1; + else + return 0x0FF & data.byte; +} + +static inline __s32 i2c_smbus_write_byte(int file, __u8 value) +{ + return i2c_smbus_access(file,I2C_SMBUS_WRITE,value, + I2C_SMBUS_BYTE,NULL); +} + +static inline __s32 i2c_smbus_read_byte_data(int file, __u8 command) +{ + union i2c_smbus_data data; + if (i2c_smbus_access(file,I2C_SMBUS_READ,command, + I2C_SMBUS_BYTE_DATA,&data)) + return -1; + else + return 0x0FF & data.byte; +} + +static inline __s32 i2c_smbus_write_byte_data(int file, __u8 command, + __u8 value) +{ + union i2c_smbus_data data; + data.byte = value; + return i2c_smbus_access(file,I2C_SMBUS_WRITE,command, + I2C_SMBUS_BYTE_DATA, &data); +} + +static inline __s32 i2c_smbus_read_word_data(int file, __u8 command) +{ + union i2c_smbus_data data; + if (i2c_smbus_access(file,I2C_SMBUS_READ,command, + I2C_SMBUS_WORD_DATA,&data)) + return -1; + else + return 0x0FFFF & data.word; +} + +static inline __s32 i2c_smbus_write_word_data(int file, __u8 command, + __u16 value) +{ + union i2c_smbus_data data; + data.word = value; + return i2c_smbus_access(file,I2C_SMBUS_WRITE,command, + I2C_SMBUS_WORD_DATA, &data); +} + +static inline __s32 i2c_smbus_process_call(int file, __u8 command, __u16 value) +{ + union i2c_smbus_data data; + data.word = value; + if (i2c_smbus_access(file,I2C_SMBUS_WRITE,command, + I2C_SMBUS_PROC_CALL,&data)) + return -1; + else + return 0x0FFFF & data.word; +} + + +/* Returns the number of read bytes */ +static inline __s32 i2c_smbus_read_block_data(int file, __u8 command, + __u8 *values) +{ + union i2c_smbus_data data; + if (i2c_smbus_access(file,I2C_SMBUS_READ,command, + I2C_SMBUS_BLOCK_DATA,&data)) + return -1; + else { + memcpy(values, &data.block[1], _I2C_MIN(data.block[0], I2C_SMBUS_BLOCK_MAX)); + return data.block[0]; + } +} + +static inline __s32 i2c_smbus_write_block_data(int file, __u8 command, + __u8 length, const __u8 *values) +{ + union i2c_smbus_data data; + if (length > 32) + length = 32; + memcpy(&data.block[1], values, length); + data.block[0] = length; + return i2c_smbus_access(file,I2C_SMBUS_WRITE,command, + I2C_SMBUS_BLOCK_DATA, &data); +} + +static inline __s32 i2c_smbus_read_block_large_data(int file, __u8 command, + __u8 *values) +{ + union i2c_smbus_large_data data; + if (i2c_smbus_access(file, I2C_SMBUS_READ, command, + I2C_SMBUS_BLOCK_LARGE_DATA, + (union i2c_smbus_data *)&data)) { + return -1; + } else { + /* the first byte is the length which is not copied */ + memcpy(values, &data.block[1], _I2C_MIN(data.block[0], I2C_SMBUS_BLOCK_LARGE_MAX)); + return data.block[0]; + } +} + +static inline __s32 i2c_smbus_write_block_large_data(int file, __u8 command, + __u8 length, + const __u8 *values) +{ + union i2c_smbus_large_data data; + if (length > I2C_SMBUS_BLOCK_LARGE_MAX) { + length = I2C_SMBUS_BLOCK_LARGE_MAX; + } + data.block[0] = length; + memcpy(&data.block[1], values, length); + return i2c_smbus_access(file, I2C_SMBUS_WRITE, command, + I2C_SMBUS_BLOCK_LARGE_DATA, + (union i2c_smbus_data *)&data); +} + +/* Returns the number of read bytes */ +/* Until kernel 2.6.22, the length is hardcoded to 32 bytes. If you + ask for less than 32 bytes, your code will only work with kernels + 2.6.23 and later. */ +static inline __s32 i2c_smbus_read_i2c_block_data(int file, __u8 command, + __u8 length, __u8 *values) +{ + union i2c_smbus_data data; + + if (length > 32) + length = 32; + data.block[0] = length; + if (i2c_smbus_access(file,I2C_SMBUS_READ,command, + length == 32 ? I2C_SMBUS_I2C_BLOCK_BROKEN : + I2C_SMBUS_I2C_BLOCK_DATA,&data)) + return -1; + else { + memcpy(values, &data.block[1], _I2C_MIN(data.block[0], I2C_SMBUS_BLOCK_MAX)); + return data.block[0]; + } +} + +static inline __s32 i2c_smbus_write_i2c_block_data(int file, __u8 command, + __u8 length, + const __u8 *values) +{ + union i2c_smbus_data data; + if (length > 32) + length = 32; + memcpy(&data.block[1], values, length); + data.block[0] = length; + return i2c_smbus_access(file,I2C_SMBUS_WRITE,command, + I2C_SMBUS_I2C_BLOCK_BROKEN, &data); +} + +/* Returns the number of read bytes */ +static inline __s32 i2c_smbus_block_process_call(int file, __u8 command, + __u8 length, __u8 *values) +{ + union i2c_smbus_data data; + if (length > 32) + length = 32; + memcpy(&data.block[1], values, length); + data.block[0] = length; + if (i2c_smbus_access(file,I2C_SMBUS_WRITE,command, + I2C_SMBUS_BLOCK_PROC_CALL,&data)) + return -1; + else { + memcpy(values, &data.block[1], _I2C_MIN(data.block[0], I2C_SMBUS_BLOCK_MAX)); + return data.block[0]; + } +} + +#undef _I2C_MIN + +#endif /* _LINUX_I2C_DEV_H */ diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/src/include/log.h b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/src/include/log.h new file mode 100644 index 0000000..a69d69e --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/src/include/log.h @@ -0,0 +1,59 @@ +/* + * Copyright 2014-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 LOG_H +#define LOG_H + +#include <stdio.h> +#include <string.h> + +//#define DEBUG +//#define VERBOSE + +#define _LOG(dst, fmt, ...) do { \ + fprintf(dst, "%s:%d " fmt "\n", \ + __FUNCTION__, __LINE__, ##__VA_ARGS__); \ + fflush(dst); \ +} while(0) + +#define LOG_ERR(err, fmt, ...) do { \ + char buf[128]; \ + strerror_r(err, buf, sizeof(buf)); \ + _LOG(stderr, "ERROR " fmt ": %s", ##__VA_ARGS__, buf); \ +} while(0) + +#define LOG_INFO(fmt, ...) do { \ + _LOG(stdout, fmt, ##__VA_ARGS__); \ +} while(0) + +#ifdef DEBUG +#define LOG_DBG(fmt, ...) do { \ + _LOG(stdout, fmt, ##__VA_ARGS__); \ +} while(0) +#else +#define LOG_DBG(fmt, ...) +#endif + +#ifdef VERBOSE +#define LOG_VER(fmt, ...) do { \ + _LOG(stdout, fmt, ##__VA_ARGS__); \ +} while(0) +#else +#define LOG_VER(fmt, ...) +#endif + +#endif diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/us_console.sh b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/us_console.sh new file mode 100755 index 0000000..1672acd --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/us_console.sh @@ -0,0 +1,41 @@ +#!/bin/sh +# +# Copyright 2014-present Facebook. All Rights Reserved. +# +# This program file 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; version 2 of the License. +# +# 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 in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +# + +usage() { + echo "$0 <connect | disconnect>" +} + +. /usr/local/fbpackages/utils/ast-functions + +if [ $# -ne 1 ]; then + usage + exit 1 +fi + +if [ "$1" == "connect" ]; then + VALUE=1 +elif [ "$1" == "disconnect" ]; then + VALUE=0 +else + usage + exit 1 +fi + +gpio_set 32 $VALUE diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/watch-fc.sh b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/watch-fc.sh new file mode 100755 index 0000000..d04b7cd --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/watch-fc.sh @@ -0,0 +1,34 @@ +#!/bin/bash +# +# Copyright 2014-present Facebook. All Rights Reserved. +# +# This program file 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; version 2 of the License. +# +# 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 in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +# + +. /usr/local/fbpackages/utils/ast-functions + +MAC1LINK=0 # GPIOA0 +FAB0_PRES=20 # GPIOC4 +FAB1_PRES=21 # GPIOC5 +while true; do + # fabN_pres: active low. + if [ $(gpio_get $FAB0_PRES) = 0 ]; then + gpio_set $MAC1LINK 0 + elif [ $(gpio_get $FAB1_PRES) = 0 ]; then + gpio_set $MAC1LINK 1 + fi + sleep 1 +done diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/wedge_us_mac.sh b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/wedge_us_mac.sh new file mode 100644 index 0000000..34b8e59 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/wedge_us_mac.sh @@ -0,0 +1,29 @@ +#!/bin/bash +# +# Copyright 2014-present Facebook. All Rights Reserved. +# +# This program file 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; version 2 of the License. +# +# 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 in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +# + +PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin + +mac=$(i2cdump -y 0x0 0x49 s 0xd4 | grep '^00: d4'| awk '{ print $3":"$4":"$5":"$6":"$7":"$8 }') 2>/dev/null + +if [ -n "$mac" ]; then + echo $mac +else + echo "Cannot find out the microserver MAC" 1>&2 +fi diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/yosemite-sensors/Makefile b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/yosemite-sensors/Makefile new file mode 100644 index 0000000..2bc9721 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/yosemite-sensors/Makefile @@ -0,0 +1,10 @@ +# Copyright 2015-present Facebook. All Rights Reserved. +all: yosemite-sensors + +yosemite-sensors: yosemite-sensors.c + $(CC) -lyosemite_sensor -std=c99 -o $@ $^ $(LDFLAGS) + +.PHONY: clean + +clean: + rm -rf *.o yosemite-sensors diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/yosemite-sensors/yosemite-sensors.c b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/yosemite-sensors/yosemite-sensors.c new file mode 100644 index 0000000..aa921db --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/yosemite-sensors/yosemite-sensors.c @@ -0,0 +1,405 @@ +/* + * yosemite-sensors + * + * 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. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <syslog.h> +#include <stdint.h> +#include <pthread.h> +#include <facebook/bic.h> +#include <openbmc/ipmi.h> +#include <facebook/yosemite_sensor.h> + +int +main(int argc, char **argv) { + int value; + float fvalue; + uint8_t slot_id; + + slot_id = atoi(argv[1]); + + if (yosemite_sensor_read(slot_id, SP_SENSOR_INLET_TEMP, &fvalue)) { + printf("yosemite_sensor_read failed: SP_SENSOR_INLET_TEMP\n"); + } else { + printf("SP_SENSOR_INLET_TEMP: %.2f C\n", fvalue); + } + + if (yosemite_sensor_read(slot_id, SP_SENSOR_OUTLET_TEMP, &fvalue)) { + printf("yosemite_sensor_read failed: SP_SENSOR_OUTLET_TEMP\n"); + } else { + printf("SP_SENSOR_OUTLET_TEMP: %.2f C\n", fvalue); + } + + if (yosemite_sensor_read(slot_id, SP_SENSOR_FAN0_TACH, &value)) { + printf("yosemite_sensor_read failed: SP_SENSOR_FAN0_TACH\n"); + } else { + printf("SP_SENSOR_FAN0_TACH: %d rpm\n", value); + } + + if (yosemite_sensor_read(slot_id, SP_SENSOR_FAN1_TACH, &value)) { + printf("yosemite_sensor_read failed: SP_SENSOR_FAN1_TACH\n"); + } else { + printf("SP_SENSOR_FAN1_TACH: %d rpm\n", value); + } + + if (yosemite_sensor_read(slot_id, SP_SENSOR_P5V, &fvalue)) { + printf("yosemite_sensor_read failed: SP_SENSOR_P5V\n"); + } else { + printf("SP_SENSOR_P5V: %.2f Volts\n", fvalue); + } + + if (yosemite_sensor_read(slot_id, SP_SENSOR_P12V, &fvalue)) { + printf("yosemite_sensor_read failed: SP_SENSOR_P12V\n"); + } else { + printf("SP_SENSOR_P12V: %.2f Volts\n", fvalue); + } + + if (yosemite_sensor_read(slot_id, SP_SENSOR_P3V3_STBY, &fvalue)) { + printf("yosemite_sensor_read failed: SP_SENSOR_P3V3_STBY\n"); + } else { + printf("SP_SENSOR_P3V3_STBY: %.2f Volts\n", fvalue); + } + + if (yosemite_sensor_read(slot_id, SP_SENSOR_P12V_SLOT0, &fvalue)) { + printf("yosemite_sensor_read failed: SP_SENSOR_P12V_SLOT0\n"); + } else { + printf("SP_SENSOR_P12V_SLOT0: %.2f Volts\n", fvalue); + } + + if (yosemite_sensor_read(slot_id, SP_SENSOR_P12V_SLOT1, &fvalue)) { + printf("yosemite_sensor_read failed: SP_SENSOR_P12V_SLOT1\n"); + } else { + printf("SP_SENSOR_P12V_SLOT1: %.2f Volts\n", fvalue); + } + + if (yosemite_sensor_read(slot_id, SP_SENSOR_P12V_SLOT2, &fvalue)) { + printf("yosemite_sensor_read failed: SP_SENSOR_P12V_SLOT2\n"); + } else { + printf("SP_SENSOR_P12V_SLOT2: %.2f Volts\n", fvalue); + } + + if (yosemite_sensor_read(slot_id, SP_SENSOR_P12V_SLOT3, &fvalue)) { + printf("yosemite_sensor_read failed: SP_SENSOR_P12V_SLOT3\n"); + } else { + printf("SP_SENSOR_P12V_SLOT3: %.2f Volts\n", fvalue); + } + + if (yosemite_sensor_read(slot_id, SP_SENSOR_P3V3, &fvalue)) { + printf("yosemite_sensor_read failed: SP_SENSOR_P3V3\n"); + } else { + printf("SP_SENSOR_P3V3: %.2f Volts\n", fvalue); + } + + if (yosemite_sensor_read(slot_id, SP_SENSOR_HSC_IN_VOLT, &fvalue)) { + printf("yosemite_sensor_read failed: SP_SENSOR_HSC_IN_VOLT\n"); + } else { + printf("SP_SENSOR_HSC_IN_VOLT: %.2f Volts\n", fvalue); + } + + if (yosemite_sensor_read(slot_id, SP_SENSOR_HSC_OUT_CURR, &fvalue)) { + printf("yosemite_sensor_read failed: SP_SENSOR_HSC_OUT_CURR\n"); + } else { + printf("SP_SENSOR_HSC_OUT_CURR: %.2f Amps\n", fvalue); + } + + if (yosemite_sensor_read(slot_id, SP_SENSOR_HSC_TEMP, &fvalue)) { + printf("yosemite_sensor_read failed: SP_SENSOR_HSC_TEMP\n"); + } else { + printf("SP_SENSOR_P3V3: %.2f C\n", fvalue); + } + + if (yosemite_sensor_read(slot_id, SP_SENSOR_HSC_IN_POWER, &fvalue)) { + printf("yosemite_sensor_read failed: SP_SENSOR_HSC_IN_POWER\n"); + } else { + printf("SP_SENSOR_HSC_IN_POWER: %.2f Watts\n", fvalue); + } + + if (yosemite_sensor_read(slot_id, BIC_SENSOR_MB_OUTLET_TEMP, &fvalue)) { + printf("yosemite_sensor_read failed: BIC_SENSOR_MB_OUTLET_TEMP\n"); + } else { + printf("BIC_SENSOR_MB_OUTLET_TEMP: %.2f C\n", fvalue); + } + + if (yosemite_sensor_read(slot_id, BIC_SENSOR_VCCIN_VR_TEMP, &fvalue)) { + printf("yosemite_sensor_read failed: BIC_SENSOR_VCCIN_VR_TEMP\n"); + } else { + printf("BIC_SENSOR_VCCIN_VR_TEMP: %.2f C\n", fvalue); + } + + if (yosemite_sensor_read(slot_id, BIC_SENSOR_VCC_GBE_VR_TEMP, &fvalue)) { + printf("yosemite_sensor_read failed: BIC_SENSOR_VCC_GBE_VR_TEMP\n"); + } else { + printf("BIC_SENSOR_VCC_GBE_VR_TEMP: %.2f C\n", fvalue); + } + + if (yosemite_sensor_read(slot_id, BIC_SENSOR_1V05PCH_VR_TEMP, &fvalue)) { + printf("yosemite_sensor_read failed: BIC_SENSOR_1V05PCH_VR_TEMP\n"); + } else { + printf("BIC_SENSOR_1V05PCH_VR_TEMP: %.2f C\n", fvalue); + } + + if (yosemite_sensor_read(slot_id, BIC_SENSOR_SOC_TEMP, &fvalue)) { + printf("yosemite_sensor_read failed: BIC_SENSOR_SOC_TEMP\n"); + } else { + printf("BIC_SENSOR_SOC_TEMP: %.2f C\n", fvalue); + } + + if (yosemite_sensor_read(slot_id, BIC_SENSOR_MB_INLET_TEMP, &fvalue)) { + printf("yosemite_sensor_read failed: BIC_SENSOR_MB_INLET_TEMP\n"); + } else { + printf("BIC_SENSOR_MB_INLET_TEMP: %.2f C\n", fvalue); + } + + if (yosemite_sensor_read(slot_id, BIC_SENSOR_PCH_TEMP, &fvalue)) { + printf("yosemite_sensor_read failed: BIC_SENSOR_PCH_TEMP\n"); + } else { + printf("BIC_SENSOR_PCH_TEMP: %.2f C\n", fvalue); + } + + if (yosemite_sensor_read(slot_id, BIC_SENSOR_SOC_THERM_MARGIN, &fvalue)) { + printf("yosemite_sensor_read failed: BIC_SENSOR_SOC_THERM_MARGIN\n"); + } else { + printf("BIC_SENSOR_SOC_THERM_MARGIN: %.2f C\n", fvalue); + } + + if (yosemite_sensor_read(slot_id, BIC_SENSOR_VDDR_VR_TEMP, &fvalue)) { + printf("yosemite_sensor_read failed: BIC_SENSOR_VDDR_VR_TEMP\n"); + } else { + printf("BIC_SENSOR_VDDR_VR_TEMP: %.2f C\n", fvalue); + } + + if (yosemite_sensor_read(slot_id, BIC_SENSOR_SOC_TJMAX, &fvalue)) { + printf("yosemite_sensor_read failed: BIC_SENSOR_SOC_TJMAX\n"); + } else { + printf("BIC_SENSOR_SOC_TJMAX: %.2f C\n", fvalue); + } + + if (yosemite_sensor_read(slot_id, BIC_SENSOR_VCC_SCSUS_VR_TEMP, &fvalue)) { + printf("yosemite_sensor_read failed: BIC_SENSOR_VCC_SCSUS_VR_TEMP\n"); + } else { + printf("BIC_SENSOR_VCC_SCSUS_VR_TEMP: %.2f C\n", fvalue); + } + + if (yosemite_sensor_read(slot_id, BIC_SENSOR_SOC_DIMMA0_TEMP, &fvalue)) { + printf("yosemite_sensor_read failed: BIC_SENSOR_SOC_DIMMA0_TEMP\n"); + } else { + printf("BIC_SENSOR_SOC_DIMMA0_TEMP: %.2f C\n", fvalue); + } + + if (yosemite_sensor_read(slot_id, BIC_SENSOR_SOC_DIMMA1_TEMP, &fvalue)) { + printf("yosemite_sensor_read failed: BIC_SENSOR_SOC_DIMMA1_TEMP\n"); + } else { + printf("BIC_SENSOR_SOC_DIMMA1_TEMP: %.2f C\n", fvalue); + } + + if (yosemite_sensor_read(slot_id, BIC_SENSOR_SOC_DIMMB0_TEMP, &fvalue)) { + printf("yosemite_sensor_read failed: BIC_SENSOR_SOC_DIMMB0_TEMP\n"); + } else { + printf("BIC_SENSOR_SOC_DIMMB0_TEMP: %.2f C\n", fvalue); + } + + if (yosemite_sensor_read(slot_id, BIC_SENSOR_SOC_DIMMB1_TEMP, &fvalue)) { + printf("yosemite_sensor_read failed: BIC_SENSOR_SOC_DIMMB1_TEMP\n"); + } else { + printf("BIC_SENSOR_SOC_DIMMB1_TEMP: %.2f C\n", fvalue); + } + + // Monolake Current Sensors + if (yosemite_sensor_read(slot_id, BIC_SENSOR_VCC_GBE_VR_CURR, &fvalue)) { + printf("yosemite_sensor_read failed: BIC_SENSOR_VCC_GBE_VR_CURR\n"); + } else { + printf("BIC_SENSOR_VCC_GBE_VR_CURR: %.2f Amps\n", fvalue); + } + + if (yosemite_sensor_read(slot_id, BIC_SENSOR_1V05_PCH_VR_CURR, &fvalue)) { + printf("yosemite_sensor_read failed: BIC_SENSOR_1V05_PCH_VR_CURR\n"); + } else { + printf("BIC_SENSOR_1V05_PCH_VR_CURR: %.2f Amps\n", fvalue); + } + + if (yosemite_sensor_read(slot_id, BIC_SENSOR_VCCIN_VR_CURR, &fvalue)) { + printf("yosemite_sensor_read failed: BIC_SENSOR_VCCIN_VR_CURR\n"); + } else { + printf("BIC_SENSOR_VCCIN_VR_CURR: %.2f Amps\n", fvalue); + } + + if (yosemite_sensor_read(slot_id, BIC_SENSOR_VDDR_VR_CURR, &fvalue)) { + printf("yosemite_sensor_read failed: BIC_SENSOR_VDDR_VR_CURR\n"); + } else { + printf("BIC_SENSOR_VDDR_VR_CURR: %.2f Amps\n", fvalue); + } + + if (yosemite_sensor_read(slot_id, BIC_SENSOR_VCC_SCSUS_VR_CURR, &fvalue)) { + printf("yosemite_sensor_read failed: BIC_SENSOR_VCC_SCSUS_VR_CURR\n"); + } else { + printf("BIC_SENSOR_VCC_SCSUS_VR_CURR: %.2f Amps\n", fvalue); + } + + // Monolake Voltage Sensors + if (yosemite_sensor_read(slot_id, BIC_SENSOR_VCCIN_VR_VOL, &fvalue)) { + printf("yosemite_sensor_read failed: BIC_SENSOR_VCCIN_VR_VOL\n"); + } else { + printf("BIC_SENSOR_VCCIN_VR_VOL: %.2f Volts\n", fvalue); + } + + if (yosemite_sensor_read(slot_id, BIC_SENSOR_VDDR_VR_VOL, &fvalue)) { + printf("yosemite_sensor_read failed: BIC_SENSOR_VDDR_VR_VOL\n"); + } else { + printf("BIC_SENSOR_VDDR_VR_VOL: %.2f Volts\n", fvalue); + } + + if (yosemite_sensor_read(slot_id, BIC_SENSOR_VCC_SCSUS_VR_VOL, &fvalue)) { + printf("yosemite_sensor_read failed: BIC_SENSOR_VCC_SCSUS_VR_VOL\n"); + } else { + printf("BIC_SENSOR_VCC_SCSUS_VR_VOL: %.2f Volts\n", fvalue); + } + + if (yosemite_sensor_read(slot_id, BIC_SENSOR_VCC_GBE_VR_VOL, &fvalue)) { + printf("yosemite_sensor_read failed: BIC_SENSOR_VCC_GBE_VR_VOL\n"); + } else { + printf("BIC_SENSOR_VCC_GBE_VR_VOL: %.2f Volts\n", fvalue); + } + + if (yosemite_sensor_read(slot_id, BIC_SENSOR_1V05_PCH_VR_VOL, &fvalue)) { + printf("yosemite_sensor_read failed: BIC_SENSOR_1V05_PCH_VR_VOL\n"); + } else { + printf("BIC_SENSOR_1V05_PCH_VR_VOL: %.2f Volts\n", fvalue); + } + + if (yosemite_sensor_read(slot_id, BIC_SENSOR_P3V3_MB, &fvalue)) { + printf("yosemite_sensor_read failed: BIC_SENSOR_P3V3_MB\n"); + } else { + printf("BIC_SENSOR_P3V3_MB: %.2f Volts\n", fvalue); + } + + if (yosemite_sensor_read(slot_id, BIC_SENSOR_P12V_MB, &fvalue)) { + printf("yosemite_sensor_read failed: BIC_SENSOR_P12V_MB\n"); + } else { + printf("BIC_SENSOR_P12V_MB: %.2f Volts\n", fvalue); + } + + if (yosemite_sensor_read(slot_id, BIC_SENSOR_P1V05_PCH, &fvalue)) { + printf("yosemite_sensor_read failed: BIC_SENSOR_P1V05_PCH\n"); + } else { + printf("BIC_SENSOR_P1V05_PCH: %.2f Volts\n", fvalue); + } + + if (yosemite_sensor_read(slot_id, BIC_SENSOR_P3V3_STBY_MB, &fvalue)) { + printf("yosemite_sensor_read failed: BIC_SENSOR_P3V3_STBY_MB\n"); + } else { + printf("BIC_SENSOR_P3V3_STBY_MB: %.2f Volts\n", fvalue); + } + + if (yosemite_sensor_read(slot_id, BIC_SENSOR_P5V_STBY_MB, &fvalue)) { + printf("yosemite_sensor_read failed: BIC_SENSOR_P5V_STBY_MB\n"); + } else { + printf("BIC_SENSOR_P5V_STBY_MB: %.2f Volts\n", fvalue); + } + + if (yosemite_sensor_read(slot_id, BIC_SENSOR_PV_BAT, &fvalue)) { + printf("yosemite_sensor_read failed: BIC_SENSOR_PV_BAT\n"); + } else { + printf("BIC_SENSOR_PV_BAT: %.2f Volts\n", fvalue); + } + + if (yosemite_sensor_read(slot_id, BIC_SENSOR_PVDDR, &fvalue)) { + printf("yosemite_sensor_read failed: BIC_SENSOR_PVDDR\n"); + } else { + printf("BIC_SENSOR_PVDDR: %.2f Volts\n", fvalue); + } + + if (yosemite_sensor_read(slot_id, BIC_SENSOR_PVCC_GBE, &fvalue)) { + printf("yosemite_sensor_read failed: BIC_SENSOR_PVCC_GBE\n"); + } else { + printf("BIC_SENSOR_PVCC_GBE: %.2f Volts\n", fvalue); + } + + // Monolake Power Sensors + if (yosemite_sensor_read(slot_id, BIC_SENSOR_VCCIN_VR_POUT, &fvalue)) { + printf("yosemite_sensor_read failed: BIC_SENSOR_VCCIN_VR_POUT\n"); + } else { + printf("BIC_SENSOR_VCCIN_VR_POUT: %.2f Watts\n", fvalue); + } + + if (yosemite_sensor_read(slot_id, BIC_SENSOR_INA230_POWER, &fvalue)) { + printf("yosemite_sensor_read failed: BIC_SENSOR_INA230_POWER\n"); + } else { + printf("BIC_SENSOR_INA230_POWER: %.2f Watts\n", fvalue); + } + + if (yosemite_sensor_read(slot_id, BIC_SENSOR_SOC_PACKAGE_PWR, &fvalue)) { + printf("yosemite_sensor_read failed: BIC_SENSOR_SOC_PACKAGE_PWR\n"); + } else { + printf("BIC_SENSOR_SOC_PACKAGE_PWR: %.2f Watts\n", fvalue); + } + + if (yosemite_sensor_read(slot_id, BIC_SENSOR_VDDR_VR_POUT, &fvalue)) { + printf("yosemite_sensor_read failed: BIC_SENSOR_VDDR_VR_POUT\n"); + } else { + printf("BIC_SENSOR_VDDR_VR_POUT: %.2f Watts\n", fvalue); + } + + if (yosemite_sensor_read(slot_id, BIC_SENSOR_VCC_SCSUS_VR_POUT, &fvalue)) { + printf("yosemite_sensor_read failed: BIC_SENSOR_VCC_SCSUS_VR_POUT\n"); + } else { + printf("BIC_SENSOR_VCC_SCSUS_VR_POUT: %.2f Watts\n", fvalue); + } + + if (yosemite_sensor_read(slot_id, BIC_SENSOR_VCC_GBE_VR_POUT, &fvalue)) { + printf("yosemite_sensor_read failed: BIC_SENSOR_VCC_GBE_VR_POUT\n"); + } else { + printf("BIC_SENSOR_VCC_GBE_VR_POUT: %.2f Watts\n", fvalue); + } + + // Discrete Sensors + if (yosemite_sensor_read(slot_id, BIC_SENSOR_SYSTEM_STATUS, &value)) { + printf("yosemite_sensor_read failed: BIC_SENSOR_SYSTEM_STATUS\n"); + } else { + printf("BIC_SENSOR_SYSTEM_STATUS: 0x%X\n", value); + } + + if (yosemite_sensor_read(slot_id, BIC_SENSOR_PROC_FAIL, &value)) { + printf("yosemite_sensor_read failed: BIC_SENSOR_PROC_FAIL\n"); + } else { + printf("BIC_SENSOR_PROC_FAIL: 0x%X\n", value); + } + + if (yosemite_sensor_read(slot_id, BIC_SENSOR_SYS_BOOT_STAT, &value)) { + printf("yosemite_sensor_read failed: BIC_SENSOR_SYS_BOOT_STAT\n"); + } else { + printf("BIC_SENSOR_SYS_BOOT_STAT: 0x%X\n", value); + } + + if (yosemite_sensor_read(slot_id, BIC_SENSOR_VR_HOT, &value)) { + printf("yosemite_sensor_read failed: BIC_SENSOR_VR_HOT\n"); + } else { + printf("BIC_SENSOR_VR_HOT: 0x%X\n", value); + } + + if (yosemite_sensor_read(slot_id, BIC_SENSOR_CPU_DIMM_HOT, &value)) { + printf("yosemite_sensor_read failed: BIC_SENSOR_CPU_DIMM_HOT\n"); + } else { + printf("BIC_SENSOR_CPU_DIMM_HOT: 0x%X\n", value); + } + + return 0; +} diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/yosemite_power.sh b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/yosemite_power.sh new file mode 100644 index 0000000..3a2aaf7 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/yosemite_power.sh @@ -0,0 +1,169 @@ +#!/bin/bash +# +# Copyright 2015-present Facebook. All Rights Reserved. +# +# This program file 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; version 2 of the License. +# +# 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 in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +# + +. /usr/local/fbpackages/utils/ast-functions + +PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin + +LPS_PATH=/mnt/data/power/por/last_state + +prog="$0" + +usage() { + echo "Usage: $prog <slot#> <command> [command options]" + echo + echo "Commands:" + echo " status: Get the current 1S server power status" + echo + echo " on: Power on 1S server if not powered on already" + echo " options:" + echo " -f: Re-do power on sequence no matter if 1S server has " + echo " been powered on or not." + echo + echo " off: Power off 1S server ungracefully" + echo + echo +} + +do_status() { + if [ $(is_server_prsnt $slot) == "0" ]; then + echo "The given slot is Empty" + return 0 + fi + + echo -n "1S Server power for slot#$slot is " + if [ $(yosemite_is_server_on $slot) -eq 1 ] ; then + echo "on" + else + echo "off" + fi + return 0 +} + +do_on() { + + if [ $(is_server_prsnt $slot) == "0" ]; then + echo "The given slot is Empty" + return 0 + fi + + local force opt + force=0 + while getopts "f" opt; do + case $opt in + f) + force=1 + ;; + *) + usage + exit -1 + ;; + + esac + done + echo -n "Power on slot#$slot server ..." + if [ $force -eq 0 ]; then + # need to check if 1S Server is on or not + if [ $(yosemite_is_server_on $slot) -eq 1 ]; then + echo " Already on. Skip!" + return 1 + fi + fi + + # TODO: State the power state change + echo "on $(date +%s)" > $LPS_PATH + + # first make sure, GPIO is high + gpio_set $gpio 1 + # generate the power on pulse + gpio_set $gpio 0 + sleep 1 + gpio_set $gpio 1 + sleep 1 + # Turn on the power LED + /usr/local/bin/power_led.sh $slot on + echo " Done" + return 0 +} + +do_off() { + if [ $(is_server_prsnt $slot) == "0" ]; then + echo "The given slot is Empty" + return 0 + fi + echo -n "Power off slot#$slot server ..." + + #TODO: State the power state change + echo "off $(date +%s)" > $LPS_PATH + + # first make sure, GPIO is high + gpio_set $gpio 1 + sleep 1 + gpio_set $gpio 0 + sleep 5 + gpio_set $gpio 1 + # Turn off the power LED + /usr/local/bin/power_led.sh $slot off + echo " Done" + return 0 +} + +# Slot1: GPIOD3(27), Slot2: GPIOD1(25), Slot3: GPIOD7(31), Slot4: GPIOD5(29) +slot=$1 + +case $slot in + 1) + gpio=D3 + ;; + 2) + gpio=D1 + ;; + 3) + gpio=D7 + ;; + 4) + gpio=D5 + ;; + *) + gpio=D3 + ;; +esac + +command="$2" +shift +shift + +case "$command" in + status) + do_status $@ + ;; + on) + do_on $@ + ;; + off) + do_off $@ + ;; + *) + usage + exit -1 + ;; +esac + +exit $? diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/yosemite-sensors_0.1.bb b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/yosemite-sensors_0.1.bb new file mode 100644 index 0000000..245f05d --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fbutils/yosemite-sensors_0.1.bb @@ -0,0 +1,21 @@ +# Copyright 2015-present Facebook. All Rights Reserved. +SUMMARY = "Yosemite Sensor Utility" +DESCRIPTION = "Util for reading various sensors on Yosemite" +SECTION = "base" +PR = "r1" +LICENSE = "GPLv2" +LIC_FILES_CHKSUM = "file://yosemite-sensors.c;beginline=4;endline=16;md5=b395943ba8a0717a83e62ca123a8d238" + +SRC_URI = "file://yosemite-sensors \ + " + +S = "${WORKDIR}/yosemite-sensors" + +do_install() { + install -d ${D}${bindir} + install -m 0755 yosemite-sensors ${D}${bindir}/yosemite-sensors +} + +DEPENDS += "libyosemite-sensor" + +FILES_${PN} = "${bindir}" diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/front-paneld/files/Makefile b/meta-facebook/meta-yosemite/recipes-yosemite/front-paneld/files/Makefile new file mode 100644 index 0000000..c542230 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/front-paneld/files/Makefile @@ -0,0 +1,10 @@ +# Copyright 2015-present Facebook. All Rights Reserved. +all: front-paneld + +front-paneld: front-paneld.c + $(CC) -pthread -lpal -lbic -std=c99 -o $@ $^ $(LDFLAGS) + +.PHONY: clean + +clean: + rm -rf *.o front-paneld diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/front-paneld/files/front-paneld.c b/meta-facebook/meta-yosemite/recipes-yosemite/front-paneld/files/front-paneld.c new file mode 100644 index 0000000..03849cd --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/front-paneld/files/front-paneld.c @@ -0,0 +1,460 @@ +/* + * + * 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. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <syslog.h> +#include <string.h> +#include <pthread.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <time.h> +#include <openbmc/ipmi.h> +#include <openbmc/ipmb.h> +#include <openbmc/pal.h> + +#define BTN_MAX_SAMPLES 200 +#define MAX_NUM_SLOTS 4 + +// Helper function for msleep +void +msleep(int msec) { + struct timespec req; + + req.tv_sec = 0; + req.tv_nsec = msec * 1000 * 1000; + + while(nanosleep(&req, &req) == -1 && errno == EINTR) { + continue; + } +} + +// Thread for monitoring debug card hotswap +static void * +debug_card_handler() { + int curr = -1; + int prev = -1; + uint8_t prsnt; + uint8_t pos; + uint8_t lpc; + int i, ret; + + while (1) { + // Check if debug card present or not + ret = pal_is_debug_card_prsnt(&prsnt); + if (ret) { + goto debug_card_out; + } + + curr = prsnt; + if (curr == prev) { + // No state change, continue + goto debug_card_out; + } + + if (curr) { + syslog(LOG_ALERT, "Debug Card Insertion\n"); + // Get current position of hand switch + ret = pal_get_hand_sw(&pos); + if (ret) { + goto debug_card_out; + } + + // Switch USB mux based on hand switch + ret = pal_switch_usb_mux(pos); + if (ret) { + goto debug_card_out; + } + // Switch UART mux based on hand switch + ret = pal_switch_uart_mux(pos); + if (ret) { + goto debug_card_out; + } + + // Enable POST code based on hand switch + if (pos == HAND_SW_BMC) { + // For BMC, there is no need to have POST specific code + goto debug_card_done; + } + + // Make sure the server at selected position is present + ret = pal_is_server_prsnt(pos, &prsnt); + if (ret || !prsnt) { + goto debug_card_done; + } + + // Enable POST codes for all slots + ret = pal_post_enable(pos); + if (ret) { + goto debug_card_out; + } + + // Get last post code and display it + ret = pal_post_get_last(pos, &lpc); + if (ret) { + goto debug_card_out; + } + + ret = pal_post_handle(pos, lpc); + if (ret) { + goto debug_card_out; + } + } else { + syslog(LOG_ALERT, "Debug Card Extraction\n"); + // Switch UART mux to BMC + ret = pal_switch_uart_mux(HAND_SW_BMC); + if (ret) { + goto debug_card_out; + } + } +debug_card_done: + prev = curr; +debug_card_out: + sleep(1); + } +} + +// Thread to monitor the hand switch +static void * +hand_sw_handler() { + int curr = -1; + int prev = -1; + int ret; + uint8_t pos; + uint8_t prsnt; + uint8_t lpc; + + while (1) { + // Get the current hand switch position + ret = pal_get_hand_sw(&pos); + if (ret) { + goto hand_sw_out; + } + curr = pos; + if (curr == prev) { + // No state change, continue; + goto hand_sw_out; + } + + // Switch USB Mux to selected server + ret = pal_switch_usb_mux(pos); + if (ret) { + goto hand_sw_out; + } + + // If Debug Card is present, update UART MUX + ret = pal_is_debug_card_prsnt(&prsnt); + if (ret) { + goto hand_sw_out; + } + + if (prsnt) { + // Switch UART mux based on position + ret = pal_switch_uart_mux(pos); + if (ret) { + goto hand_sw_out; + } + + if (pos == HAND_SW_BMC) { + // For BMC, there is no need for POST enable/disable code + goto hand_sw_done; + } + + ret = pal_is_server_prsnt(pos, &prsnt); + if (ret || !prsnt) { + // Server at chosen position is not present + goto hand_sw_done; + } + + // Enable post for the chosen server + ret = pal_post_enable(pos); + if (ret) { + goto hand_sw_out; + } + + // Get last post code and display it + ret = pal_post_get_last(pos, &lpc); + if (ret) { + goto hand_sw_out; + } + + ret = pal_post_handle(pos, lpc); + if (ret) { + goto hand_sw_out; + } + } +hand_sw_done: + prev = curr; +hand_sw_out: + sleep(1); + continue; + } +} + +// Thread to monitor Reset Button and propagate to selected server +static void * +rst_btn_handler() { + int ret; + uint8_t pos; + int i; + uint8_t btn; + + while (1) { + // Check the position of hand switch + ret = pal_get_hand_sw(&pos); + if (ret || pos == HAND_SW_BMC) { + // For BMC, no need to handle Reset Button + sleep (1); + continue; + } + + // Check if reset button is pressed + ret = pal_get_rst_btn(&btn); + if (ret || !btn) { + goto rst_btn_out; + } + + // Pass the reset button to the selected slot + syslog(LOG_ALERT, "reset button pressed\n"); + ret = pal_set_rst_btn(pos, 0); + if (ret) { + goto rst_btn_out; + } + + // Wait for the button to be released + for (i = 0; i < BTN_MAX_SAMPLES; i++) { + ret = pal_get_rst_btn(&btn); + if (ret || btn) { + msleep(100); + continue; + } + syslog(LOG_ALERT, "Reset button released\n"); + ret = pal_set_rst_btn(pos, 1); + goto rst_btn_out; + } + + // handle error case + if (i == BTN_MAX_SAMPLES) { + syslog(LOG_ALERT, "Reset button seems to stuck for long time\n"); + goto rst_btn_out; + } +rst_btn_out: + msleep(100); + } +} + +// Thread to handle Power Button and power on/off the selected server +static void * +pwr_btn_handler() { + int ret; + uint8_t pos, btn; + int i; + uint8_t power; + + while (1) { + // Check the position of hand switch + ret = pal_get_hand_sw(&pos); + if (ret || pos == HAND_SW_BMC) { + sleep(1); + continue; + } + + // Check if power button is pressed + ret = pal_get_pwr_btn(&btn); + if (ret || !btn) { + goto pwr_btn_out; + } + + syslog(LOG_ALERT, "power button pressed\n"); + + // Wait for the button to be released + for (i = 0; i < BTN_MAX_SAMPLES; i++) { + ret = pal_get_pwr_btn(&btn); + if (ret || btn ) { + msleep(100); + continue; + } + syslog(LOG_ALERT, "power button released\n"); + break; + } + + // handle error case + if (i == BTN_MAX_SAMPLES) { + syslog(LOG_ALERT, "Power button seems to stuck for long time\n"); + goto pwr_btn_out; + } + + // Get the current power state (power on vs. power off) + ret = pal_get_server_power(pos, &power); + if (ret) { + goto pwr_btn_out; + } + + // Reverse the power state of the given server + ret = pal_set_server_power(pos, !power); +pwr_btn_out: + msleep(100); + } +} + +// Thread to handle LED state of the server at given slot +static void * +led_handler(void *num) { + int ret; + uint8_t prsnt; + uint8_t power; + uint8_t pos; + uint8_t ident; + uint8_t led_blink; + int led_on_time, led_off_time; + + uint8_t slot = (*(int*) num) + 1; + + syslog(LOG_INFO, "led_handler for slot %d\n", slot); + + ret = pal_is_server_prsnt(slot, &prsnt); + if (ret || !prsnt) { + // Turn off led and exit + ret = pal_set_led(slot, 0); + goto led_handler_exit; + } + + while (1) { + // Get power status for this slot + ret = pal_get_server_power(slot, &power); + if (ret) { + sleep(1); + continue; + } + + // Get hand switch position to see if this is selected server + ret = pal_get_hand_sw(&pos); + if (ret) { + sleep(1); + continue; + } + + if (pos == slot) { + // This server is selcted one, set ident flag + ident = 1; + } else { + ident = 0; + } + + // Update LED based on current state + if (ident) { + // If this is selected server the blink flag is one + led_blink = 1; + // update the blink rate based on power state + if (power) { + led_on_time = 900; + led_off_time = 100; + } else { + led_on_time = 100; + led_off_time = 900; + } + } else { + // This server is not selected one + led_blink = 0; + } + + if (!led_blink) { + // Set the led state based on power state + ret = pal_set_led(slot, power); + goto led_handler_out; + } + + // Since this is selected slot, start blinking the LED + ret = pal_set_led(slot, 1); + if (ret) { + goto led_handler_out; + } + + msleep(led_on_time); + + ret = pal_set_led(slot, 0); + if (ret) { + goto led_handler_out; + } + + msleep(led_off_time); +led_handler_out: + msleep(100); + } + +led_handler_exit: + free(num); +} + +int +main (int argc, char * const argv[]) { + pthread_t tid_hand_sw; + pthread_t tid_debug_card; + pthread_t tid_rst_btn; + pthread_t tid_pwr_btn; + pthread_t tid_leds[MAX_NUM_SLOTS]; + int i; + int *ip; + + daemon(1, 0); + openlog("front-paneld", LOG_CONS, LOG_DAEMON); + + if (pthread_create(&tid_debug_card, NULL, debug_card_handler, NULL) < 0) { + syslog(LOG_ALERT, "pthread_create for debug card error\n"); + exit(1); + } + + if (pthread_create(&tid_hand_sw, NULL, hand_sw_handler, NULL) < 0) { + syslog(LOG_ALERT, "pthread_create for hand switch error\n"); + exit(1); + } + + if (pthread_create(&tid_rst_btn, NULL, rst_btn_handler, NULL) < 0) { + syslog(LOG_ALERT, "pthread_create for reset button error\n"); + exit(1); + } + + if (pthread_create(&tid_pwr_btn, NULL, pwr_btn_handler, NULL) < 0) { + syslog(LOG_ALERT, "pthread_create for power button error\n"); + exit(1); + } + + for (i = 0; i < MAX_NUM_SLOTS; i++) { + ip = malloc(sizeof(int)); + *ip = i; + if (pthread_create(&tid_leds[i], NULL, led_handler, (void*)ip) < 0) { + syslog(LOG_ALERT, "pthread_create for hand switch error\n"); + exit(1); + } + } + + pthread_join(tid_debug_card, NULL); + pthread_join(tid_hand_sw, NULL); + pthread_join(tid_rst_btn, NULL); + pthread_join(tid_pwr_btn, NULL); + for (i = 0; i < MAX_NUM_SLOTS; i++) { + pthread_join(tid_leds[i], NULL); + } + + return 0; +} diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/front-paneld/files/setup-front-paneld.sh b/meta-facebook/meta-yosemite/recipes-yosemite/front-paneld/files/setup-front-paneld.sh new file mode 100644 index 0000000..7055cc0 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/front-paneld/files/setup-front-paneld.sh @@ -0,0 +1,16 @@ +#!/bin/sh +# +# Copyright 2015-present Facebook. All Rights Reserved. +# +### BEGIN INIT INFO +# Provides: setup-front-paneld +# Required-Start: +# Required-Stop: +# Default-Start: S +# Default-Stop: +# Short-Description: Start front panel control daemon +### END INIT INFO + +echo -n "Setup Front Panel Daemon.." + /usr/local/bin/front-paneld > /dev/null 2>&1 & +echo "done." diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/front-paneld/front-paneld_0.1.bb b/meta-facebook/meta-yosemite/recipes-yosemite/front-paneld/front-paneld_0.1.bb new file mode 100644 index 0000000..26db659 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/front-paneld/front-paneld_0.1.bb @@ -0,0 +1,44 @@ +# Copyright 2015-present Facebook. All Rights Reserved. + +SUMMARY = "Front Panel Control Daemon" +DESCRIPTION = "Daemon to monitor and control the front panel " +SECTION = "base" +PR = "r1" +LICENSE = "GPLv2" +LIC_FILES_CHKSUM = "file://front-paneld.c;beginline=5;endline=17;md5=da35978751a9d71b73679307c4d296ec" + + +DEPENDS_append = "libpal libbic update-rc.d-native" + +SRC_URI = "file://Makefile \ + file://setup-front-paneld.sh \ + file://front-paneld.c \ + " + +S = "${WORKDIR}" + +binfiles = "front-paneld" + +pkgdir = "front-paneld" + +do_install() { + dst="${D}/usr/local/fbpackages/${pkgdir}" + bin="${D}/usr/local/bin" + install -d $dst + install -d $bin + install -m 755 front-paneld ${dst}/front-paneld + ln -snf ../fbpackages/${pkgdir}/front-paneld ${bin}/front-paneld + install -d ${D}${sysconfdir}/init.d + install -d ${D}${sysconfdir}/rcS.d + install -m 755 setup-front-paneld.sh ${D}${sysconfdir}/init.d/setup-front-paneld.sh + update-rc.d -r ${D} setup-front-paneld.sh start 67 S . +} + +FBPACKAGEDIR = "${prefix}/local/fbpackages" + +FILES_${PN} = "${FBPACKAGEDIR}/front-paneld ${prefix}/local/bin ${sysconfdir} " + +# Inhibit complaints about .debug directories: + +INHIBIT_PACKAGE_DEBUG_SPLIT = "1" +INHIBIT_PACKAGE_STRIP = "1" diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/fruid/fruid_0.1.bbappend b/meta-facebook/meta-yosemite/recipes-yosemite/fruid/fruid_0.1.bbappend new file mode 100644 index 0000000..c87f2a7 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/fruid/fruid_0.1.bbappend @@ -0,0 +1,24 @@ +# Copyright 2015-present Facebook. All Rights Reserved. +# +# This program file 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; version 2 of the License. +# +# 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 in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA + + +S = "${WORKDIR}" + +CFLAGS_prepend = " -DCONFIG_YOSEMITE" +LDFLAGS_append = " -lyosemite_fruid" + +DEPENDS_prepend = "libyosemite-fruid" diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/gpiod/files/Makefile b/meta-facebook/meta-yosemite/recipes-yosemite/gpiod/files/Makefile new file mode 100644 index 0000000..68e9453 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/gpiod/files/Makefile @@ -0,0 +1,26 @@ +# Copyright 2015-present Facebook. All Rights Reserved. +# +# This program file 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; version 2 of the License. +# +# 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 in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA + +all: gpiod + +sensord: gpiod.c + $(CC) $(CFLAGS) -D _XOPEN_SOURCE -pthread -lm -std=c99 -o $@ $^ $(LDFLAGS) + +.PHONY: clean + +clean: + rm -rf *.o gpiod diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/gpiod/files/gpiod.c b/meta-facebook/meta-yosemite/recipes-yosemite/gpiod/files/gpiod.c new file mode 100644 index 0000000..9282e00 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/gpiod/files/gpiod.c @@ -0,0 +1,353 @@ +/* + * sensord + * + * 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. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> +#include <unistd.h> +#include <errno.h> +#include <syslog.h> +#include <stdint.h> +#include <math.h> +#include <string.h> +#include <pthread.h> +#include <sys/un.h> +#include <sys/file.h> +#include <openbmc/ipmi.h> +#include <openbmc/pal.h> +#include <facebook/bic.h> +#include <facebook/yosemite_gpio.h> + +#define SETBIT(x, y) (x | (1 << y)) +#define GETBIT(x, y) ((x & (1 << y)) > y) +#define CLEARBIT(x, y) (x & (~(1 << y))) +#define GETMASK(y) (1 << y) + +#define MAX_NUM_SLOTS 4 +#define GPIOD_READ_DELAY 1 +#define SOCK_PATH_GPIO "/tmp/gpio_socket" + +/* To hold the gpio info and status */ +typedef struct { + uint8_t flag; + uint8_t status; + uint8_t ass_val; + char name[32]; +} gpio_pin_t; + +static gpio_pin_t gpio_slot1[MAX_GPIO_PINS] = {0}; +static gpio_pin_t gpio_slot2[MAX_GPIO_PINS] = {0}; +static gpio_pin_t gpio_slot3[MAX_GPIO_PINS] = {0}; +static gpio_pin_t gpio_slot4[MAX_GPIO_PINS] = {0}; + +/* Returns the pointer to the struct holding all gpio info for the fru#. */ +static gpio_pin_t * +get_struct_gpio_pin(uint8_t fru) { + + gpio_pin_t *gpios; + + switch (fru) { + case FRU_SLOT1: + gpios = gpio_slot1; + break; + case FRU_SLOT2: + gpios = gpio_slot2; + break; + case FRU_SLOT3: + gpios = gpio_slot3; + break; + case FRU_SLOT4: + gpios = gpio_slot4; + break; + default: + syslog(LOG_ALERT, "get_struct_gpio_pin: Wrong SLOT ID %d\n", fru); + return NULL; + } + + return gpios; +} + +int +enable_gpio_intr_config(uint8_t fru, uint8_t gpio) { + int ret; + + bic_gpio_config_t cfg = {0}; + bic_gpio_config_t verify_cfg = {0}; + + + ret = bic_get_gpio_config(fru, gpio, &cfg); + if (ret < 0) { + syslog(LOG_ERR, "enable_gpio_intr_config: bic_get_gpio_config failed" + "for slot_id: %u, gpio pin: %u", fru, gpio); + return -1; + } + + cfg.ie = 1; + + ret = bic_set_gpio_config(fru, gpio, &cfg); + if (ret < 0) { + syslog(LOG_ERR, "enable_gpio_intr_config: bic_set_gpio_config failed" + "for slot_id: %u, gpio pin: %u", fru, gpio); + return -1; + } + + ret = bic_get_gpio_config(fru, gpio, &verify_cfg); + if (ret < 0) { + syslog(LOG_ERR, "enable_gpio_intr_config: verification bic_get_gpio_config" + "for slot_id: %u, gpio pin: %u", fru, gpio); + return -1; + } + + if (verify_cfg.ie != cfg.ie) { + syslog(LOG_ALERT, "Slot_id: %u,Interrupt enabling FAILED for GPIO pin# %d", + fru, gpio); + return -1; + } + + return 0; +} + +/* Enable the interrupt mode for all the gpio sensors */ +static void +enable_gpio_intr(uint8_t fru) { + + int i, ret; + gpio_pin_t *gpios; + + gpios = get_struct_gpio_pin(fru); + if (gpios == NULL) { + syslog(LOG_ALERT, "enable_gpio_intr: get_struct_gpio_pin failed."); + return; + } + + for (i = 0; i < gpio_pin_cnt; i++) { + ret = enable_gpio_intr_config(fru, gpio_pin_list[i]); + if (ret < 0) { + gpios[i].flag = 0; + syslog(LOG_ALERT, "enable_gpio_intr: Slot: %d, Pin %d interrupt enabling" + " failed", fru, gpio_pin_list[i]); + syslog(LOG_ALERT, "enable_gpio_intr: Disable check for Slot %d, Pin %d", + fru, gpio_pin_list[i]); + } else { + gpios[i].flag = 1; +#ifdef DEBUG + syslog(LOG_ALERT, "enable_gpio_intr: Enabled check for Slot: %d, Pin %d", + fru, gpio_pin_list[i]); +#endif /* DEBUG */ + } + } +} + +static void +populate_gpio_pins(uint8_t fru) { + + int i, ret; + + gpio_pin_t *gpios; + + gpios = get_struct_gpio_pin(fru); + if (gpios == NULL) { + syslog(LOG_ALERT, "populate_gpio_pins: get_struct_gpio_pin failed."); + return; + } + + for(i = 0; i < gpio_pin_cnt; i++) { + gpios[gpio_pin_list[i]].flag = 1; + } + + + for(i = 0; i < MAX_GPIO_PINS; i++) { + if (gpios[i].flag) { + gpios[i].ass_val = GETBIT(gpio_ass_val, i); + ret = yosemite_get_gpio_name(fru, i, gpios[i].name); + if (ret < 0) + continue; + } + } +} + +/* Wrapper function to configure and get all gpio info */ +static void +init_gpio_pins() { + int fru; + + for (fru = FRU_SLOT1; fru < (FRU_SLOT1 + MAX_NUM_SLOTS); fru++) { + populate_gpio_pins(fru); + } +} + +/* Monitor the gpio pins */ +static int +gpio_monitor_poll(uint8_t fru_flag) { + int i, ret; + uint8_t fru; + uint32_t revised_pins, n_pin_val, o_pin_val[MAX_NUM_SLOTS + 1] = {0}; + gpio_pin_t *gpios; + + uint32_t status; + bic_gpio_t gpio = {0}; + + /* Check for initial Asserts */ + for (fru = 1; fru <= MAX_NUM_SLOTS; fru++) { + if (GETBIT(fru_flag, fru) == 0) + continue; + + ret = bic_get_gpio(fru, &gpio); + if (ret) { + syslog(LOG_ALERT, "populate_gpio_pins: bic_get_gpio failed for " + " fru %u", fru); + continue; + } + + gpios = get_struct_gpio_pin(fru); + if (gpios == NULL) { + syslog(LOG_ALERT, "gpio_monitor_poll: get_struct_gpio_pin failed for" + " fru %u", fru); + continue; + } + + memcpy(&status, (uint8_t *) &gpio, sizeof(status)); + + o_pin_val[fru] = 0; + + for (i = 0; i <= MAX_GPIO_PINS; i++) { + + if (gpios[i].flag == 0) + continue; + + gpios[i].status = GETBIT(status, i); + + if (gpios[i].status) + o_pin_val[fru] = SETBIT(o_pin_val[fru], i); + + if (gpios[i].status == gpios[i].ass_val) { + syslog(LOG_CRIT, "ASSERT: fru: %u, gpio pin: %-20s, num: %d", + fru, gpios[i].name, i); + } + } + } + + /* Keep monitoring each fru's gpio pins every 4 * GPIOD_READ_DELAY seconds */ + while(1) { + for (fru = 1; fru <= MAX_NUM_SLOTS; fru++) { + if (!(GETBIT(fru_flag, fru))) { + sleep(GPIOD_READ_DELAY); + continue; + } + + gpios = get_struct_gpio_pin(fru); + if (gpios == NULL) { + syslog(LOG_ALERT, "gpio_monitor_poll: get_struct_gpio_pin failed for" + " fru %u", fru); + continue; + } + + if ((ret = bic_get_gpio(fru, (bic_gpio_t *) &n_pin_val)) < 0) { + syslog(LOG_ALERT, "gpio_monitor_poll: bic_get_gpio failed for " + " fru %u", fru); + continue; + } + + if (o_pin_val[fru] == n_pin_val) { + o_pin_val[fru] = n_pin_val; + sleep(GPIOD_READ_DELAY); + continue; + } + + revised_pins = (n_pin_val ^ o_pin_val[fru]); + + for (i = 0; i < MAX_GPIO_PINS; i++) { + if (GETBIT(revised_pins, i) & gpios[i].flag) { + gpios[i].status = GETBIT(n_pin_val, i); + + // Check if the new GPIO val is ASSERT + if (gpios[i].status == gpios[i].ass_val) { + syslog(LOG_CRIT, "ASSERT: fru: %u, gpio pin: %-20s, num: %d", + fru, gpios[i].name, i); + } else { + syslog(LOG_CRIT, "DEASSERT: fru: %u, gpio pin: %-20s, num: %d", + fru, gpios[i].name, i); + } + } + } + + o_pin_val[fru] = n_pin_val; + sleep(GPIOD_READ_DELAY); + + } /* For Loop for each fru */ + } /* while loop */ +} /* function definition*/ + +static void +print_usage() { + printf("Usage: gpiod [ %s ]\n", "slot1, slot2, slot3, slot4"); +} + +/* Spawns a pthread for each fru to monitor all the sensors on it */ +static void +run_gpiod(int argc, void **argv) { + + //gpio_monitor(); + + int i, ret; + uint8_t fru_flag, fru; + + /* Check for which fru do we need to monitor the gpio pins */ + fru_flag = 0; + for (i = 1; i < argc; i++) { + ret = pal_get_fru_id(argv[i], &fru); + if (ret < 0) { + print_usage(); + exit(-1); + } + fru_flag = SETBIT(fru_flag, fru); + } + + gpio_monitor_poll(fru_flag); +} + +int +main(int argc, void **argv) { + int dev, rc, pid_file; + + if (argc < 2) { + print_usage(); + exit(-1); + } + + pid_file = open("/var/run/gpiod.pid", O_CREAT | O_RDWR, 0666); + rc = flock(pid_file, LOCK_EX | LOCK_NB); + if(rc) { + if(EWOULDBLOCK == errno) { + printf("Another gpiod instance is running...\n"); + exit(-1); + } + } else { + + init_gpio_pins(); + + daemon(0,1); + openlog("gpiod", LOG_CONS, LOG_DAEMON); + syslog(LOG_INFO, "gpiod: daemon started"); + run_gpiod(argc, argv); + } + + return 0; +} diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/gpiod/files/setup-gpiod.sh b/meta-facebook/meta-yosemite/recipes-yosemite/gpiod/files/setup-gpiod.sh new file mode 100644 index 0000000..9e532f2 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/gpiod/files/setup-gpiod.sh @@ -0,0 +1,33 @@ +#!/bin/sh +# +# Copyright 2015-present Facebook. All Rights Reserved. +# +# This program file 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; version 2 of the License. +# +# 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 in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +# + +### BEGIN INIT INFO +# Provides: setup-sensord +# Required-Start: +# Required-Stop: +# Default-Start: S +# Default-Stop: +# Short-Description: Setup sensor monitoring +### END INIT INFO + +# TODO: check for the if slot/server is present before starting the daemon +echo -n "Setup gpio monitoring for yosemite... " +/usr/local/bin/gpiod slot1 slot2 slot3 slot4 +echo "done." diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/gpiod/gpiod_0.1.bb b/meta-facebook/meta-yosemite/recipes-yosemite/gpiod/gpiod_0.1.bb new file mode 100644 index 0000000..2193a92 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/gpiod/gpiod_0.1.bb @@ -0,0 +1,62 @@ +# Copyright 2015-present Facebook. All Rights Reserved. +# +# This program file 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; version 2 of the License. +# +# 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 in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA + +SUMMARY = "GPIO Sensor Monitoring Daemon" +DESCRIPTION = "Daemon for monitoring the gpio sensors" +SECTION = "base" +PR = "r1" +LICENSE = "GPLv2" +LIC_FILES_CHKSUM = "file://gpiod.c;beginline=4;endline=16;md5=b395943ba8a0717a83e62ca123a8d238" + +SRC_URI = "file://Makefile \ + file://gpiod.c \ + file://setup-gpiod.sh \ + " + +S = "${WORKDIR}" + +binfiles = "gpiod \ + " + +CFLAGS += " -lbic -lyosemite_gpio -lpal " + +DEPENDS += " libbic libyosemite-gpio libpal " + +pkgdir = "gpiod" + +do_install() { + dst="${D}/usr/local/fbpackages/${pkgdir}" + bin="${D}/usr/local/bin" + install -d $dst + install -d $bin + for f in ${binfiles}; do + install -m 755 $f ${dst}/$f + ln -snf ../fbpackages/${pkgdir}/$f ${bin}/$f + done + install -d ${D}${sysconfdir}/init.d + install -d ${D}${sysconfdir}/rcS.d + install -m 755 setup-gpiod.sh ${D}${sysconfdir}/init.d/setup-gpiod.sh + update-rc.d -r ${D} setup-gpiod.sh start 91 S . +} + +FBPACKAGEDIR = "${prefix}/local/fbpackages" + +FILES_${PN} = "${FBPACKAGEDIR}/gpiod ${prefix}/local/bin ${sysconfdir} " + + +INHIBIT_PACKAGE_DEBUG_SPLIT = "1" +INHIBIT_PACKAGE_STRIP = "1" diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/ipmbd/files/setup-ipmbd.sh b/meta-facebook/meta-yosemite/recipes-yosemite/ipmbd/files/setup-ipmbd.sh new file mode 100644 index 0000000..b37d8fa --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/ipmbd/files/setup-ipmbd.sh @@ -0,0 +1,104 @@ +#! /bin/sh +# +# Copyright 2015-present Facebook. All Rights Reserved. +# +# This program file 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; version 2 of the License. +# +# 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 in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +# + +### BEGIN INIT INFO +# Provides: ipmbd +# Required-Start: +# Required-Stop: +# Default-Start: S +# Default-Stop: 0 6 +# Short-Description: Provides ipmb message tx/rx service +# +### END INIT INFO + +. /usr/local/fbpackages/utils/ast-functions + +PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin +DAEMON=/usr/local/bin/ipmbd +NAME=ipmbd +DESC="IPMB Rx/Tx Daemon" + +test -f $DAEMON || exit 0 + +STOPPER= +ACTION="$1" + +case "$ACTION" in + start) + echo -n "Starting $DESC: " + + if [ $(is_server_prsnt 1) == "1" ]; then + $DAEMON 3 > /dev/null 2>&1 & + fi + + if [ $(is_server_prsnt 2) == "1" ]; then + $DAEMON 1 > /dev/null 2>&1 & + fi + + if [ $(is_server_prsnt 3) == "1" ]; then + $DAEMON 7 > /dev/null 2>&1 & + fi + + if [ $(is_server_prsnt 4) == "1" ]; then + $DAEMON 5 > /dev/null 2>&1 & + fi + + echo "$NAME." + ;; + stop) + echo -n "Stopping $DESC: " + start-stop-daemon --stop --quiet --exec $DAEMON + echo "$NAME." + ;; + restart|force-reload) + echo -n "Restarting $DESC: " + start-stop-daemon --stop --quiet --exec $DAEMON + sleep 1 + if [ $(is_server_prsnt 1) == "1" ]; then + $DAEMON 3 > /dev/null 2>&1 & + fi + + if [ $(is_server_prsnt 2) == "1" ]; then + $DAEMON 1 > /dev/null 2>&1 & + fi + + if [ $(is_server_prsnt 3) == "1" ]; then + $DAEMON 7 > /dev/null 2>&1 & + fi + + if [ $(is_server_prsnt 4) == "1" ]; then + $DAEMON 5 > /dev/null 2>&1 & + fi + + echo "$NAME." + ;; + status) + status $DAEMON + exit $? + ;; + *) + N=${0##*/} + N=${N#[SK]??} + echo "Usage: $N {start|stop|status|restart|force-reload}" >&2 + exit 1 + ;; +esac + +exit 0 diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/ipmbd/ipmbd_0.1.bbappend b/meta-facebook/meta-yosemite/recipes-yosemite/ipmbd/ipmbd_0.1.bbappend new file mode 100644 index 0000000..bf2af1e --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/ipmbd/ipmbd_0.1.bbappend @@ -0,0 +1,27 @@ +# Copyright 2015-present Facebook. All Rights Reserved. + +FILESEXTRAPATHS_prepend := "${THISDIR}/files:" +SRC_URI += " file://setup-ipmbd.sh \ + " + +CFLAGS_prepend = " -DCONFIG_YOSEMITE" + +do_install() { + dst="${D}/usr/local/fbpackages/${pkgdir}" + bin="${D}/usr/local/bin" + install -d $dst + install -d $bin + install -m 755 ipmbd ${dst}/ipmbd + ln -snf ../fbpackages/${pkgdir}/ipmbd ${bin}/ipmbd + install -d ${D}${sysconfdir}/init.d + install -d ${D}${sysconfdir}/rcS.d + install -m 755 setup-ipmbd.sh ${D}${sysconfdir}/init.d/setup-ipmbd.sh + update-rc.d -r ${D} setup-ipmbd.sh start 65 S . +} + +FBPACKAGEDIR = "${prefix}/local/fbpackages" + +FILES_${PN} = "${FBPACKAGEDIR}/ipmbd ${prefix}/local/bin ${sysconfdir} " + +INHIBIT_PACKAGE_DEBUG_SPLIT = "1" +INHIBIT_PACKAGE_STRIP = "1" diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/ipmid/files/bic.c b/meta-facebook/meta-yosemite/recipes-yosemite/ipmid/files/bic.c new file mode 100644 index 0000000..5af03ce --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/ipmid/files/bic.c @@ -0,0 +1,78 @@ +/* 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 <stdlib.h> +#include <errno.h> +#include <string.h> +#include <syslog.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <openbmc/ipmi.h> + +#define MAX_IPMI_RES_LEN 100 + +/* + * Function to handle GPIO interrupt + */ +void +lib_gpio_intr_handle(unsigned char *request, unsigned char req_len, + unsigned char *response, unsigned char *res_len) { + + int sockfd, t, len; + struct sockaddr_un remote; + + // TODO: Need to update to reuse the socket instead of creating new + if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { + syslog(LOG_ALERT, "lib_gpio_intr_handle: socket() failed\n"); + return; + } + + remote.sun_family = AF_UNIX; + strcpy(remote.sun_path, SOCK_PATH_GPIO); + len = strlen(remote.sun_path) + sizeof(remote.sun_family); + + if (connect(sockfd, (struct sockaddr *)&remote, len) == -1) { + syslog(LOG_ALERT, "lib_gpio_intr_handle: connect() failed\n"); + return; + } + + if (send(sockfd, request, req_len, 0) == -1) { + syslog(LOG_ALERT, "lib_gpio_intr_handle: send() failed\n"); + return; + } + + if ((t=recv(sockfd, response, MAX_IPMI_RES_LEN, 0)) > 0) { + *res_len = t; + } else { + if (t < 0) { + syslog(LOG_ALERT, "lib_gpio_intr_handle: recv() failed\n"); + } else { + printf("Server closed connection"); + } + + return; + } + + close(sockfd); + + return; +} diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/ipmid/files/bic.h b/meta-facebook/meta-yosemite/recipes-yosemite/ipmid/files/bic.h new file mode 100644 index 0000000..c0fcfbb --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/ipmid/files/bic.h @@ -0,0 +1,29 @@ +/* + * + * 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__ + +#define SOCK_PATH_GPIO "/tmp/gpio_socket" + +void lib_gpio_intr_handle(unsigned char *request, unsigned char req_len, + unsigned char *response, unsigned char *res_len); + +#endif /* __BIC_H__ */ diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/ipmid/files/fruid.c b/meta-facebook/meta-yosemite/recipes-yosemite/ipmid/files/fruid.c new file mode 100644 index 0000000..04772d7 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/ipmid/files/fruid.c @@ -0,0 +1,111 @@ +/* + * + * Copyright 2015-present Facebook. All Rights Reserved. + * + * This file provides platform specific implementation of FRUID information + * + * FRUID specification can be found at + * www.intel.com/content/dam/www/public/us/en/documents/product-briefs/platform-management-fru-document-rev-1-2-feb-2013.pdf + * + * + * 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 <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <syslog.h> +#include <string.h> +#include <stdint.h> +#include "fruid.h" + +#define EEPROM_SPB "/sys/class/i2c-adapter/i2c-8/8-0051/eeprom" + +#define BIN_SPB "/tmp/fruid_spb.bin" + +#define NAME_SPB "Side Plane Board" + +#define BUF_SIZE 1024 + +/* + * copy_eeprom_to_bin - copy the eeprom to binary file im /tmp directory + * + * @eeprom_file : path for the eeprom of the device + * @bin_file : path for the binary file + * + * returns 0 on successful copy + * returns non-zero on file operation errors + */ +int copy_eeprom_to_bin(const char * eeprom_file, const char * bin_file) { + + int eeprom; + int bin; + uint64_t tmp[BUF_SIZE]; + ssize_t bytes_rd, bytes_wr; + + errno = 0; + + if (access(eeprom_file, F_OK) != -1) { + + eeprom = open(eeprom_file, O_RDONLY); + if (eeprom == -1) { + syslog(LOG_ERR, "copy_eeprom_to_bin: unable to open the %s file: %s", + eeprom_file, strerror(errno)); + return errno; + } + + bin = open(bin_file, O_WRONLY | O_CREAT, 0644); + if (bin == -1) { + syslog(LOG_ERR, "copy_eeprom_to_bin: unable to create %s file: %s", + bin_file, strerror(errno)); + return errno; + } + + while ((bytes_rd = read(eeprom, tmp, BUF_SIZE)) > 0) { + bytes_wr = write(bin, tmp, bytes_rd); + if (bytes_wr != bytes_rd) { + syslog(LOG_ERR, "copy_eeprom_to_bin: write to %s file failed: %s", + bin_file, strerror(errno)); + return errno; + } + } + + close(bin); + close(eeprom); + } + + return 0; +} + +/* Populate the platform specific eeprom for fruid info */ +int plat_fruid_init(void) { + + int ret; + + ret = copy_eeprom_to_bin(EEPROM_SPB, BIN_SPB); + + return ret; +} + +int plat_fruid_size(void) { + /* TODO: Not supported yet */ + return 0; +} +int plat_fruid_data(int offset, int count, unsigned char *data) { + /* TODO: Not supported yet */ + return 0; +} diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/ipmid/files/sensor.c b/meta-facebook/meta-yosemite/recipes-yosemite/ipmid/files/sensor.c new file mode 100644 index 0000000..16cf98e --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/ipmid/files/sensor.c @@ -0,0 +1,371 @@ +/* + * + * Copyright 2014-present Facebook. All Rights Reserved. + * + * This file provides platform specific implementation of sensor information + * + * + * 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 "sensor.h" +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <syslog.h> +#include <string.h> + +#define SENSOR_MGMT_MAX 1 +#define SENSOR_DISC_MAX 8 +#define SENSOR_THRESH_MAX 1 +#define SENSOR_OEM_MAX 1 + +#define BMC_SLAVE_ADDR 0x20 + +typedef struct { + unsigned char num; + sensor_mgmt_t sensor[SENSOR_MGMT_MAX]; +} sensor_mgmt_info_t; + +typedef struct { + unsigned char num; + sensor_disc_t sensor[SENSOR_DISC_MAX]; +} sensor_disc_info_t; + +typedef struct { + unsigned char num; + sensor_thresh_t sensor[SENSOR_THRESH_MAX]; +} sensor_thresh_info_t; + +typedef struct { + unsigned char num; + sensor_oem_t sensor[SENSOR_OEM_MAX]; +} sensor_oem_info_t; + +// Global structures +static sensor_mgmt_info_t g_sensor_mgmt = {0}; +static sensor_disc_info_t g_sensor_disc = {0}; +static sensor_thresh_info_t g_sensor_thresh = {0}; +static sensor_oem_info_t g_sensor_oem = {0}; + +static void +populate_mgmt_sensors(void) { + sensor_mgmt_t sensor = {0}; + + // Add record for the AST2100 BMC + sensor.slave_addr = BMC_SLAVE_ADDR; + sensor.chan_no = 0x0; // Primary BMC controller + + // Init Agent = false + sensor.pwr_state_init = 0x00; + + // FRUID = true, SEL = true, SDR = true, Sensor = true + sensor.dev_caps = 0x0F; + + // Device ID string + // Type - 0xC0: ASCII, Length - 0x09 + sensor.str_type_len = 0xC0 + 0x09; + strncpy(sensor.str, "Yosemite-BMC", 0x09); + + // Add this sensor to the global table + if (g_sensor_mgmt.num >= SENSOR_MGMT_MAX) { + syslog(LOG_ALERT, "populate_mgmt_sensors: num exceeded\n"); + return; + } + + memcpy(&g_sensor_mgmt.sensor[g_sensor_mgmt.num], &sensor, sizeof(sensor_mgmt_t)); + + g_sensor_mgmt.num++; + + return; +} + +static void +populate_disc_sensors(void) { + + sensor_disc_t sensor = {0}; + + // Sensor uS Status + // Sensor# 0x10 + // EntitiyId# 0xD0, EntityInst# 0x00 + // Sensor Type# Chassis 0x18 + // Event Read/Type# OEM 0x70 + sensor.owner= BMC_SLAVE_ADDR; + sensor.lun = 0x00; + sensor.sensor_num = 0x10; + + sensor.ent_id = 0xD0; + sensor.ent_inst = 0x00; + // Enable Scanning, Enable Events + sensor.sensor_init = 0x63; + // Supports Auto Re-Arm + sensor.sensor_caps = 0x40; + sensor.sensor_type = 0x18; + sensor.evt_read_type = 0x70; + // 1-bit for CPU0 Thermal Trip + sensor.assert_evt_mask[0] = 0x04; + sensor.deassert_evt_mask[0] = 0x00; + sensor.read_evt_mask[0] = 0x04; + + // Device ID string + // Type - 0xC0: ASCII, Length - 12 + sensor.str_type_len = 0xC0 + 9; + strncpy(sensor.str, "uS-Status", 9); + + // Add this sensor to the global table + if (g_sensor_disc.num >= SENSOR_DISC_MAX) { + syslog(LOG_ALERT, "populate_disc_sensors: num exceeded\n"); + return; + } + + memcpy(&g_sensor_disc.sensor[g_sensor_disc.num], &sensor, sizeof(sensor_disc_t)); + + g_sensor_disc.num++; + + // Sensor SEL Status + // Sensor# 0x5F + // EntitiyId# 0xD0, EntityInst# 0x02 + // Sensor Type# OEM: 0xC0 + // Event Read/Type# Sensor Specific: 0x6F + sensor.owner= BMC_SLAVE_ADDR; + sensor.lun = 0x00; + sensor.sensor_num = 0x5F; + + sensor.ent_id = 0xD0; + sensor.ent_inst = 0x02; + // Enable Scanning, Enable Events + sensor.sensor_init = 0x63; + // Supports Auto Re-Arm + sensor.sensor_caps = 0x40; + sensor.sensor_type = 0xC0; + sensor.evt_read_type = 0x6F; + // SEL Clear(bit1), SEL Rollover(bit8) + sensor.assert_evt_mask[0] = 0x02; + sensor.assert_evt_mask[1] = 0x01; + sensor.deassert_evt_mask[0] = 0x00; + sensor.deassert_evt_mask[1] = 0x00; + sensor.read_evt_mask[0] = 0x02; + sensor.read_evt_mask[1] = 0x01; + + // Device ID string + // Type - 0xC0: ASCII, Length - 12 + sensor.str_type_len = 0xC0 + 10; + strncpy(sensor.str, "SEL-Status", 10); + + // Add this sensor to the global table + if (g_sensor_disc.num >= SENSOR_DISC_MAX) { + syslog(LOG_ALERT, "populate_disc_sensors: num exceeded\n"); + return; + } + + memcpy(&g_sensor_disc.sensor[g_sensor_disc.num], &sensor, sizeof(sensor_disc_t)); + + g_sensor_disc.num++; + + + // Sensor WDT + // Sensor# 0x60 + // EntitiyId# 0xD0, EntityInst# 0x03 + // Sensor Type# WDT2: 0x23 + // Event Read/Type# Sensor Specific: 0x6F + sensor.owner= BMC_SLAVE_ADDR; + sensor.lun = 0x00; + sensor.sensor_num = 0x60; + + sensor.ent_id = 0xD0; + sensor.ent_inst = 0x03; + // Enable Scanning, Enable Events + sensor.sensor_init = 0x63; + // Supports Auto Re-Arm + sensor.sensor_caps = 0x40; + sensor.sensor_type = 0x23; + sensor.evt_read_type = 0x6F; + // 5 bits for expiry, reset, pwrdown, pwrcycle, timer + sensor.assert_evt_mask[0] = 0x0F; + sensor.assert_evt_mask[1] = 0x01; + sensor.deassert_evt_mask[0] = 0x00; + sensor.deassert_evt_mask[1] = 0x00; + sensor.read_evt_mask[0] = 0x0F; + sensor.read_evt_mask[1] = 0x01; + + // Device ID string + // Type - 0xC0: ASCII, Length - 12 + sensor.str_type_len = 0xC0 + 3; + strncpy(sensor.str, "WDT", 3); + + // Add this sensor to the global table + if (g_sensor_disc.num >= SENSOR_DISC_MAX) { + syslog(LOG_ALERT, "populate_disc_sensors: num exceeded\n"); + return; + } + + memcpy(&g_sensor_disc.sensor[g_sensor_disc.num], &sensor, sizeof(sensor_disc_t)); + + g_sensor_disc.num++; + + + // Sensor Chassis Pwr Sts + // Sensor# 0x70 + // EntitiyId# 0x15, EntityInst# 0x00 + // Sensor Type# OEM: 0xC8 + // Event Read/Type# Sensor Specific: 0x6F + sensor.owner= BMC_SLAVE_ADDR; + sensor.lun = 0x00; + sensor.sensor_num = 0x70; + + sensor.ent_id = 0x15; + sensor.ent_inst = 0x00; + // Enable Scanning, Enable Events + sensor.sensor_init = 0x63; + // Supports Auto Re-Arm + sensor.sensor_caps = 0x40; + sensor.sensor_type = 0xC8; + sensor.evt_read_type = 0x6F; + // 6 bits for pwroff, pwrcycle, pwron, softdown, ac-lost, hard-reset + sensor.assert_evt_mask[0] = 0x3F; + sensor.deassert_evt_mask[0] = 0x00; + sensor.read_evt_mask[0] = 0x3F; + + // Device ID string + // Type - 0xC0: ASCII, Length - 12 + sensor.str_type_len = 0xC0 + 13; + strncpy(sensor.str, "CH-Pwr-Status", 13); + + // Add this sensor to the global table + if (g_sensor_disc.num >= SENSOR_DISC_MAX) { + syslog(LOG_ALERT, "populate_disc_sensors: num exceeded\n"); + return; + } + + memcpy(&g_sensor_disc.sensor[g_sensor_disc.num], &sensor, sizeof(sensor_disc_t)); + + g_sensor_disc.num++; + + // Sensor CPU DIMM Hot + // Sensor# 0xB3 + // EntitiyId# 0xD0, EntityInst# 0x05 + // Sensor Type# OEM 0xC6 + // Event Read/Type# Sensor Specific 6Fh + sensor.owner= BMC_SLAVE_ADDR; + sensor.lun = 0x00; + sensor.sensor_num = 0xB3; + + sensor.ent_id = 0xD0; + sensor.ent_inst = 0x05; + // Enable Scanning, Enable Events + sensor.sensor_init = 0x63; + // Supports Auto Re-Arm + sensor.sensor_caps = 0x40; + sensor.sensor_type = 0xC6; + sensor.evt_read_type = 0x6F; + // Two bits for CPU Hot, DIMM Hot + sensor.assert_evt_mask[0] = 0x05; + sensor.deassert_evt_mask[0] = 0x05; + sensor.read_evt_mask[0] = 0x05; + + // Device ID string + // Type - 0xC0: ASCII, Length - 12 + sensor.str_type_len = 0xC0 + 12; + strncpy(sensor.str, "CPU_DIMM_HOT", 12); + + // Add this sensor to the global table + if (g_sensor_disc.num >= SENSOR_DISC_MAX) { + syslog(LOG_ALERT, "populate_disc_sensors: num exceeded\n"); + return; + } + + memcpy(&g_sensor_disc.sensor[g_sensor_disc.num], &sensor, sizeof(sensor_disc_t)); + + g_sensor_disc.num++; + + // Sensor PMBus Status Word Low + // Sensor PMBus Status Word High + // Sensor PMBus Status MFR + // Sensor PMBus Status Input + // Sensor NTP Status + // Sensor# 0xED + // EntitiyId# 0x35, EntityInst# 0x00 + // Sensor Type# OEM 0xC7 + // Event Read/Type# Sensor Specific 6Fh + sensor.owner= BMC_SLAVE_ADDR; + sensor.lun = 0x00; + sensor.sensor_num = 0xED; + + sensor.ent_id = 0x35; + sensor.ent_inst = 0x00; + // Enable Scanning, Enable Events + sensor.sensor_init = 0x63; + // Supports Auto Re-Arm + sensor.sensor_caps = 0x40; + sensor.sensor_type = 0xC7; + sensor.evt_read_type = 0x6F; + // 1-bit for date/time sync failed + sensor.assert_evt_mask[0] = 0x01; + sensor.deassert_evt_mask[0] = 0x00; + sensor.read_evt_mask[0] = 0x01; + + // Device ID string + // Type - 0xC0: ASCII, Length - 10 + sensor.str_type_len = 0xC0 + 12; + strncpy(sensor.str, "NTP-Status", 10); + + // Add this sensor to the global table + if (g_sensor_disc.num >= SENSOR_DISC_MAX) { + syslog(LOG_ALERT, "populate_disc_sensors: num exceeded\n"); + return; + } + + memcpy(&g_sensor_disc.sensor[g_sensor_disc.num], &sensor, sizeof(sensor_disc_t)); + + g_sensor_disc.num++; + + return; +} + +// Access functions for Sensor Table +void +plat_sensor_mgmt_info(int *p_num, sensor_mgmt_t **p_sensor) { + *p_num = g_sensor_mgmt.num; + *p_sensor = g_sensor_mgmt.sensor; +} + +void +plat_sensor_disc_info(int *p_num, sensor_disc_t **p_sensor) { + *p_num = g_sensor_disc.num; + *p_sensor = g_sensor_disc.sensor; +} + +void +plat_sensor_thresh_info(int *p_num, sensor_thresh_t **p_sensor) { + *p_num = g_sensor_thresh.num; + *p_sensor = g_sensor_thresh.sensor; +} + +void +plat_sensor_oem_info(int *p_num, sensor_oem_t **p_sensor) { + *p_num = g_sensor_oem.num; + *p_sensor = g_sensor_oem.sensor; +} + +// Initialize Sensor Table +int +plat_sensor_init(void) { + + // Populate all Sensors + populate_mgmt_sensors(); + populate_disc_sensors(); + + return 0; +} diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/ipmid/files/setup-ipmid.sh b/meta-facebook/meta-yosemite/recipes-yosemite/ipmid/files/setup-ipmid.sh new file mode 100644 index 0000000..b724d70 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/ipmid/files/setup-ipmid.sh @@ -0,0 +1,32 @@ +#!/bin/sh +# +# Copyright 2014-present Facebook. All Rights Reserved. +# +# This program file 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; version 2 of the License. +# +# 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 in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +# + +### BEGIN INIT INFO +# Provides: setup-ipmid +# Required-Start: +# Required-Stop: +# Default-Start: S +# Default-Stop: +# Short-Description: Set IPMI Message handler +### END INIT INFO + +echo -n "Setup IPMI message handler... " +/usr/local/bin/ipmid +echo "done." diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/ipmid/ipmid_0.2.bbappend b/meta-facebook/meta-yosemite/recipes-yosemite/ipmid/ipmid_0.2.bbappend new file mode 100644 index 0000000..4a92e78 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/ipmid/ipmid_0.2.bbappend @@ -0,0 +1,46 @@ +# Copyright 2014-present Facebook. All Rights Reserved. +# +# This program file 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; version 2 of the License. +# +# 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 in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA + +DEPENDS_append = "libipmi libfruid update-rc.d-native" + +FILESEXTRAPATHS_prepend := "${THISDIR}/files:" +SRC_URI += "file://setup-ipmid.sh \ + file://sensor.c \ + file://fruid.c \ + " + +S = "${WORKDIR}" + +do_install() { + dst="${D}/usr/local/fbpackages/${pkgdir}" + bin="${D}/usr/local/bin" + install -d $dst + install -d $bin + install -m 755 ipmid ${dst}/ipmid + ln -snf ../fbpackages/${pkgdir}/ipmid ${bin}/ipmid + install -d ${D}${sysconfdir}/init.d + install -d ${D}${sysconfdir}/rcS.d + install -m 755 setup-ipmid.sh ${D}${sysconfdir}/init.d/setup-ipmid.sh + update-rc.d -r ${D} setup-ipmid.sh start 64 S . +} + +FBPACKAGEDIR = "${prefix}/local/fbpackages" + +FILES_${PN} = "${FBPACKAGEDIR}/ipmid ${prefix}/local/bin ${sysconfdir} " + +INHIBIT_PACKAGE_DEBUG_SPLIT = "1" +INHIBIT_PACKAGE_STRIP = "1" diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/lm_sensors/files/yosemite.conf b/meta-facebook/meta-yosemite/recipes-yosemite/lm_sensors/files/yosemite.conf new file mode 100644 index 0000000..b05ec3a --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/lm_sensors/files/yosemite.conf @@ -0,0 +1,44 @@ + +bus "i2c-9" "ast_i2c.9" + +chip "tmp75-i2c-9-4e" + label temp1 "Inlet Temp" + +chip "tmp75-i2c-9-4f" + label temp1 "Outlet Temp" + +chip "ast_pwm-*" + label fan1 "Fan 1" + label fan2 "Fan 2" + ignore fan3 + ignore fan4 + ignore fan5 + ignore fan6 + ignore fan7 + ignore fan8 + ignore fan9 + ignore fan10 + ignore fan11 + ignore fan12 + ignore fan13 + ignore fan14 + ignore fan15 + ignore fan16 + +chip "ast_adc-isa-0000" + label in0 "P5V_STBY Voltage" + label in1 "P12V_STBY Voltage" + label in2 "P3V3_STBY Voltage" + label in3 "P12V_STBY_SLOT0 Voltage" + label in4 "P12V_STBY_SLOT1 Voltage" + label in5 "P12V_STBY_SLOT2 Voltage" + label in6 "P12V_STBY_SLOT3 Voltage" + label in7 "P3V3 Voltage" + ignore in8 + ignore in9 + ignore in10 + ignore in11 + ignore in12 + ignore in13 + ignore in14 + ignore in15 diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/lm_sensors/lmsensors_%.bbappend b/meta-facebook/meta-yosemite/recipes-yosemite/lm_sensors/lmsensors_%.bbappend new file mode 100644 index 0000000..c33761e --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/lm_sensors/lmsensors_%.bbappend @@ -0,0 +1,10 @@ + +FILESEXTRAPATHS_prepend := "${THISDIR}/files:" + +SRC_URI += "file://yosemite.conf \ + " + +do_install_append() { + install -d ${D}${sysconfdir}/sensors.d + install -m 644 ../yosemite.conf ${D}${sysconfdir}/sensors.d/yosemite.conf +} diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/Makefile b/meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/Makefile new file mode 100644 index 0000000..00464e5 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/Makefile @@ -0,0 +1,29 @@ +# Copyright 2014-present Facebook. All Rights Reserved. +# +# This program file 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; version 2 of the License. +# +# 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 in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA + +all: oob-nic i2craw + +oob-nic: main.o nic.o intf.o ll_map.o libnetlink.o + $(CC) -o $@ $^ $(LDFLAGS) -lwedge_eeprom + +i2craw: i2craw.o + $(CC) -o $@ $^ $(LDFLAGS) + +.PHONY: clean + +clean: + rm -rf *.o oob-nic i2craw diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/README b/meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/README new file mode 100644 index 0000000..f46971f --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/README @@ -0,0 +1,10 @@ + +TODO: + +1. Currently, we poll the SMbus instead of rely on the ALERT. The kernel does not handle the ALERT either other than just a print out. + +2. Maximum fragment is 32 + +3. We use libnetlink for bring interface up and setting MAC. That increases the binary by about 50k and also we copied about 5 files from iproute2 here for that. We might be able to get away this by using some non-iproute2 API + +4. The dependency in the Makefile does not consider .h diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/etc/oob-nic.sh b/meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/etc/oob-nic.sh new file mode 100644 index 0000000..71ee0fa --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/etc/oob-nic.sh @@ -0,0 +1,93 @@ +#! /bin/sh +# +# Copyright 2014-present Facebook. All Rights Reserved. +# +# This program file 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; version 2 of the License. +# +# 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 in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +# + +### BEGIN INIT INFO +# Provides: oob-nic +# Required-Start: +# Required-Stop: +# Default-Start: S +# Default-Stop: 0 6 +# Short-Description: One of the first scripts to be executed. Starts or stops +# the OOB NIC. +# +### END INIT INFO + +PATH=/sbin:/bin:/usr/sbin:/usr/bin +DAEMON=/usr/sbin/oob-nic +NAME=oob-nic +DESC="OOB NIC Driver" + +# source function library +. /etc/init.d/functions + +test -f $DAEMON || exit 0 + +. /usr/local/fbpackages/utils/ast-functions + +fix_etc_interfaces() { + local intf_conf rev + intf_conf="/etc/network/interfaces" +} + +STOPPER= +ACTION="$1" + +case "$ACTION" in + start) + echo -n "Starting $DESC: " + if [ ! -d /dev/net ] + then + mkdir /dev/net + fi + if [ ! -f /dev/net/tun ] + then + mknod /dev/net/tun c 10 200 + chmod 666 /dev/net/tun + fi + fix_etc_interfaces + $DAEMON > /dev/null 2>&1 & + echo "$NAME." + ;; + stop) + echo -n "Stopping $DESC: " + start-stop-daemon --stop --quiet --exec $DAEMON + echo "$NAME." + ;; + restart|force-reload) + echo -n "Restarting $DESC: " + start-stop-daemon --stop --quiet --exec $DAEMON + sleep 1 + fix_etc_interfaces + $DAEMON > /dev/null 2>&1 & + echo "$NAME." + ;; + status) + status $DAEMON + exit $? + ;; + *) + N=${0##*/} + N=${N#[SK]??} + echo "Usage: $N {start|stop|status|restart|force-reload}" >&2 + exit 1 + ;; +esac + +exit 0 diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/hlist.h b/meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/hlist.h new file mode 100644 index 0000000..5e89765 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/hlist.h @@ -0,0 +1,73 @@ +/* + * Note: Original file from iproute2 package + * + * 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 __HLIST_H__ +#define __HLIST_H__ 1 +/* Hash list stuff from kernel */ + +#include <stddef.h> + +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + +struct hlist_head { + struct hlist_node *first; +}; + +struct hlist_node { + struct hlist_node *next, **pprev; +}; + +static inline void hlist_del(struct hlist_node *n) +{ + struct hlist_node *next = n->next; + struct hlist_node **pprev = n->pprev; + *pprev = next; + if (next) + next->pprev = pprev; +} + +static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) +{ + struct hlist_node *first = h->first; + n->next = first; + if (first) + first->pprev = &n->next; + h->first = n; + n->pprev = &h->first; +} + +#define hlist_for_each(pos, head) \ + for (pos = (head)->first; pos ; pos = pos->next) + + +#define hlist_for_each_safe(pos, n, head) \ + for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \ + pos = n) + +#define hlist_entry_safe(ptr, type, member) \ + ({ typeof(ptr) ____ptr = (ptr); \ + ____ptr ? hlist_entry(____ptr, type, member) : NULL; \ + }) + +#define hlist_for_each_entry(pos, head, member) \ + for (pos = hlist_entry_safe((head)->first, typeof(*(pos)), member);\ + pos; \ + pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member)) + +#endif /* __HLIST_H__ */ diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/i2craw.c b/meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/i2craw.c new file mode 100644 index 0000000..f9d499b --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/i2craw.c @@ -0,0 +1,245 @@ +/* + * Copyright 2004-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 <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> +#include <stdint.h> + +#include "facebook/i2c-dev.h" +#include "facebook/log.h" + +void usage(const char *prog) { + printf("Usage: %s [options] <bus number> <slave address>\n", prog); + printf("\n Options:\n" + "\n\t-w 'bytes to write':\n" + "\t\t i2c write\n" + "\n\t-r <number of bytes to read>:\n" + "\t\t if 0 is provided, the first byte of read is used to determine\n" + "\t\t how many bytes more to read\n" + "\n\t-p:\n" + "\t\t Use PEC\n" + "\n\t-h:\n" + "\t\t Print this help\n" + "\n Note: if both '-w' and '-r' are specified, write will be" + "\n performed first, followed by read\n"); +} + +#define MAX_BYTES 255 + +int g_use_pec = 0; +int g_has_write = 0; +int g_n_write = 0; +uint8_t g_write_bytes[MAX_BYTES]; +int g_has_read = 0; +int g_n_read = -1; +uint8_t g_read_bytes[MAX_BYTES]; +uint8_t g_bus = -1; +uint8_t g_slave_addr = 0xff; + +static int parse_byte_string(const char *str) { + const char *startptr = str; + char *endptr; + int total = 0; + unsigned long val; + + do { + val = strtoul(startptr, &endptr, 0); + if (startptr == endptr) { + printf("'%s' is invalid\n", str); + return -1; + } + if (val > MAX_BYTES) { + printf("'%s' is invalid\n", str); + return -1; + } + g_write_bytes[total++] = val; + if (*endptr == '\0') { + break; + } + if (total >= MAX_BYTES) { + printf("'%s' is invalid\n", str); + return -1; + } + startptr = endptr; + } while(1); + + return total; +} + +static int i2c_open() { + int fd; + char fn[32]; + int rc; + + snprintf(fn, sizeof(fn), "/dev/i2c-%d", g_bus); + fd = open(fn, O_RDWR); + if (fd == -1) { + LOG_ERR(errno, "Failed to open i2c device %s", fn); + return -1; + } + + rc = ioctl(fd, I2C_SLAVE, g_slave_addr); + if (rc < 0) { + LOG_ERR(errno, "Failed to open slave @ address 0x%x", g_slave_addr); + close(fd); + } + + return fd; +} + +static int i2c_io(int fd) { + struct i2c_rdwr_ioctl_data data; + struct i2c_msg msg[2]; + int n_msg = 0; + int rc; + + memset(&msg, 0, sizeof(msg)); + + if (g_has_write) { + msg[n_msg].addr = g_slave_addr; + msg[n_msg].flags = (g_use_pec) ? I2C_CLIENT_PEC : 0; + msg[n_msg].len = g_n_write; + msg[n_msg].buf = g_write_bytes; + n_msg++; + } + + if (g_has_read) { + msg[n_msg].addr = g_slave_addr; + msg[n_msg].flags = I2C_M_RD + | ((g_use_pec) ? I2C_CLIENT_PEC : 0) + | ((g_n_read == 0) ? I2C_M_RECV_LEN : 0); + /* + * In case of g_n_read is 0, block length will be added by + * the underlying bus driver. + */ + msg[n_msg].len = (g_n_read) ? g_n_read : 256; + msg[n_msg].buf = g_read_bytes; + if (g_n_read == 0) { + /* If we're using variable length block reads, we have to set the + * first byte of the buffer to at least one or the kernel complains. + */ + g_read_bytes[0] = 1; + } + n_msg++; + } + + data.msgs = msg; + data.nmsgs = n_msg; + + rc = ioctl(fd, I2C_RDWR, &data); + if (rc < 0) { + LOG_ERR(errno, "Failed to do raw io"); + return -1; + } + + return 0; +} + +int main(int argc, char * const argv[]) { + int i; + int fd; + int opt; + while ((opt = getopt(argc, argv, "hpw:r:")) != -1) { + switch (opt) { + case 'h': + usage(argv[0]); + return 0; + case 'p': + g_use_pec = 1; + break; + case 'w': + g_has_write = 1; + if ((g_n_write = parse_byte_string(optarg)) <= 0) { + usage(argv[0]); + return -1; + } + break; + case 'r': + g_has_read = 1; + g_n_read = atoi(optarg); + break; + default: + usage(argv[0]); + return -1; + } + } + + /* make sure we still have arguments for bus and slave address */ + if (optind + 2 != argc) { + printf("Bus or slave address is missing\n"); + usage(argv[0]); + return -1; + } + + g_bus = atoi(argv[optind]); + g_slave_addr = strtoul(argv[optind + 1], NULL, 0); + if ((g_slave_addr & 0x80)) { + printf("Slave address must be 7-bit\n"); + return -1; + } + + if (!g_has_write && !g_has_read) { + /* by default, read, first byte read is the length */ + g_has_read = 1; + g_n_read = 0; + } + + printf("Bus: %d\nDevice address: 0x%x\n", g_bus, g_slave_addr); + if (g_has_write) { + printf("To write %d bytes:", g_n_write); + for (i = 0; i < g_n_write; i++) { + printf(" 0x%x", g_write_bytes[i]); + } + printf("\n"); + } + if (g_has_read) { + if (g_n_read) { + printf("To read %d bytes.\n", g_n_read); + } else { + printf("To read data.\n"); + } + } + + fd = i2c_open(); + if (fd < 0) { + return -1; + } + + if (i2c_io(fd) < 0) { + return -1; + } + + if (g_has_read) { + printf("Received:\n "); + if (g_n_read == 0) { + g_n_read = g_read_bytes[0] + 1; + } + for (i = 0; i < g_n_read; i++) { + printf(" 0x%x", g_read_bytes[i]); + } + printf("\n"); + } + + return 0; +} diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/intf.c b/meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/intf.c new file mode 100644 index 0000000..5bf8480 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/intf.c @@ -0,0 +1,254 @@ +/* + * Copyright 2014-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 "intf.h" + +#include <errno.h> +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <linux/rtnetlink.h> +#include <linux/if.h> +#include <linux/if_tun.h> +#include <linux/fib_rules.h> + +#include "facebook/log.h" +#include "libnetlink.h" +#include "ll_map.h" + +struct oob_intf_t { + char oi_name[32]; + int oi_fd; + int oi_ifidx; + uint8_t oi_mac[6]; + struct rtnl_handle oi_rth; +}; + +#define TUN_DEVICE "/dev/net/tun" + +static int oob_intf_set_mac(oob_intf *intf, const uint8_t mac[6]) { + int rc; + struct { + struct nlmsghdr n; + struct ifinfomsg ifi; + char buf[256]; + } req; + + memset(&req, 0, sizeof(req)); + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); + req.n.nlmsg_type = RTM_NEWLINK; + req.n.nlmsg_flags = NLM_F_REQUEST; + req.ifi.ifi_family = AF_UNSPEC; + req.ifi.ifi_index = intf->oi_ifidx; + memcpy(intf->oi_mac, mac, sizeof(intf->oi_mac)); + addattr_l(&req.n, sizeof(req), IFLA_ADDRESS, + intf->oi_mac, sizeof(intf->oi_mac)); + rc = rtnl_talk(&intf->oi_rth, &req.n, 0, 0, NULL); + if (rc < 0) { + rc = errno; + LOG_ERR(rc, "Failed to set mac to interface %s @ index %d", + intf->oi_name, intf->oi_ifidx); + return -rc; + } + + LOG_INFO("Set interface %s @ index %d mac to %x:%x:%x:%x:%x:%x", + intf->oi_name, intf->oi_ifidx, + intf->oi_mac[0], intf->oi_mac[1], intf->oi_mac[2], + intf->oi_mac[3], intf->oi_mac[4], intf->oi_mac[5]); + + return 0; +} + +static int oob_intf_bring_up(oob_intf *intf) { + int rc; + struct { + struct nlmsghdr n; + struct ifinfomsg ifi; + char buf[256]; + } req; + + memset(&req, 0, sizeof(req)); + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); + req.n.nlmsg_type = RTM_NEWLINK; + req.n.nlmsg_flags = NLM_F_REQUEST; + req.ifi.ifi_family = AF_UNSPEC; + req.ifi.ifi_change |= IFF_UP; + req.ifi.ifi_flags |= IFF_UP; + req.ifi.ifi_index = intf->oi_ifidx; + rc = rtnl_talk(&intf->oi_rth, &req.n, 0, 0, NULL); + if (rc < 0) { + rc = errno; + LOG_ERR(rc, "Failed to bring up interface %s @ index %d", + intf->oi_name, intf->oi_ifidx); + return -rc; + } + + LOG_INFO("Brought up interface %s @ index %d", intf->oi_name, intf->oi_ifidx); + + return 0; +} + +oob_intf* oob_intf_create(const char *name, const uint8_t mac[6]) { + + int rc; + int flags; + struct ifreq ifr; + oob_intf *intf = NULL; + +#define _CHECK_RC(fmt, ...) do { \ + if (rc < 0) { \ + rc = errno; \ + LOG_ERR(rc, fmt, ##__VA_ARGS__); \ + goto err_out; \ + } \ +} while(0) + + intf = malloc(sizeof(*intf)); + if (!intf) { + rc = ENOMEM; + LOG_ERR(rc, "Failed to allocate memory for interface"); + goto err_out; + } + memset(intf, 0, sizeof(*intf)); + strncpy(intf->oi_name, name, sizeof(intf->oi_name)); + intf->oi_name[sizeof(intf->oi_name) - 1] = '\0'; + intf->oi_fd = -1; + + rc = rtnl_open(&intf->oi_rth, 0); + _CHECK_RC("Failed to open rth_handler"); + + rc = open(TUN_DEVICE, O_RDWR); + _CHECK_RC("Failed to open %s", TUN_DEVICE); + intf->oi_fd = rc; + + memset(&ifr, 0, sizeof(ifr)); + /* + * IFF_TAP: TAP interface + * IFF_NO_PI: Do not provide pracket information + */ + ifr.ifr_flags = IFF_TAP|IFF_NO_PI; + strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0'; + + rc = ioctl(intf->oi_fd, TUNSETIFF, (void *) &ifr); + _CHECK_RC("Failed to create tap interface %s", ifr.ifr_name); + + /* make fd non-blocking */ + rc = fcntl(intf->oi_fd, F_GETFL); + _CHECK_RC("Failed to get flags from fd ", intf->oi_fd); + flags = rc | O_NONBLOCK; + rc = fcntl(intf->oi_fd, F_SETFL, rc); + _CHECK_RC("Failed to set non-blocking flags ", flags, + " to fd ", intf->oi_fd); + + /* set CLOEXEC */ + rc = fcntl(intf->oi_fd, F_GETFD); + _CHECK_RC("Failed to get flags from fd ", intf->oi_fd); + flags = rc | FD_CLOEXEC; + rc = fcntl(intf->oi_fd, F_SETFD, flags); + _CHECK_RC("Failed to set close-on-exec flags ", flags, + " to fd ", intf->oi_fd); + + // TODO: if needed, we can adjust send buffer size, TUNSETSNDBUF + intf->oi_ifidx = ll_name_to_index(intf->oi_name); + + /* now set the mac address */ + oob_intf_set_mac(intf, mac); + +#if 0 + /* make it persistent */ + rc = ioctl(intf->oi_fd, TUNSETPERSIST, 0); + _CHECK_RC("Failed to make the tap interface %s persistent", intf->oi_name); +#endif + + LOG_INFO("Create/attach to tap interface %s @ fd %d, index %d", + intf->oi_name, intf->oi_fd, intf->oi_ifidx); + + //oob_intf_bring_up(intf); + + return intf; + + err_out: + if (intf) { + rtnl_close(&intf->oi_rth); + if (intf->oi_fd != -1) { + close(intf->oi_fd); + } + free(intf); + } + + return NULL; +} + +int oob_intf_get_fd(const oob_intf *intf) { + return intf->oi_fd; +} + +int oob_intf_receive(const oob_intf *intf, char *buf, int len) { + int rc; + do { + rc = read(intf->oi_fd, buf, len); + } while (rc == -1 && errno == EINTR); + if (rc < 0) { + rc = errno; + if (rc != EAGAIN) { + LOG_ERR(rc, "Failed to read on interface fd %d", intf->oi_fd); + return -rc; + } else { + /* nothing is available */ + return 0; + } + } else if (rc == 0) { + // Nothing to read. It shall not happen as the fd is non-blocking. + // Just add this case to be safe. + return 0; + } else if (rc > len) { + // The pkt is larger than the buffer. We don't have complete packet. + // It shall not happen unless the MTU is mis-match. Drop the packet. + LOG_ERR(ENOSPC, "Received a too large packet (%d bytes > %d) from the " + "tap interface. Drop it...", rc, len); + return -ENOSPC; + } else { + LOG_VER("Recv a packet of %d bytes from %s", rc, intf->oi_name); + return rc; + } +} + +int oob_intf_send(const oob_intf *intf, const char *buf, int len) { + int rc; + do { + rc = write(intf->oi_fd, buf, len); + } while (rc == -1 && errno == EINTR); + if (rc < 0) { + rc = errno; + LOG_ERR(rc, "Failed to send on interface fd %d", intf->oi_fd); + return -rc; + } else if (rc < len) { + LOG_ERR(EIO, "Failed to send the full packet (%d bytes > %d) for fd %d", + len, rc, intf->oi_fd); + return -EIO; + } else { + LOG_VER("Sent a packet of %d bytes to %s", rc, intf->oi_name); + return rc; + } +} diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/intf.h b/meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/intf.h new file mode 100644 index 0000000..6ea7af1 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/intf.h @@ -0,0 +1,31 @@ +/* + * Copyright 2014-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 INTF_H +#define INTF_H + +#include <stdint.h> + +typedef struct oob_intf_t oob_intf; + +oob_intf* oob_intf_create(const char *name, const uint8_t mac[6]); +int oob_intf_get_fd(const oob_intf *intf); + +int oob_intf_receive(const oob_intf *intf, char *buf, int len); +int oob_intf_send(const oob_intf *intf, const char *buf, int len); + +#endif diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/libnetlink.c b/meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/libnetlink.c new file mode 100644 index 0000000..019e2c8 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/libnetlink.c @@ -0,0 +1,717 @@ +/* + * Note: Original file from iproute2 package + * + * libnetlink.c RTnetlink service routines. + * + * 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. + * + * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <syslog.h> +#include <fcntl.h> +#include <net/if_arp.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <string.h> +#include <errno.h> +#include <time.h> +#include <sys/uio.h> + +#include "libnetlink.h" + +int rcvbuf = 1024 * 1024; + +void rtnl_close(struct rtnl_handle *rth) +{ + if (rth->fd >= 0) { + close(rth->fd); + rth->fd = -1; + } +} + +int rtnl_open_byproto(struct rtnl_handle *rth, unsigned subscriptions, + int protocol) +{ + socklen_t addr_len; + int sndbuf = 32768; + + memset(rth, 0, sizeof(*rth)); + + rth->fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, protocol); + if (rth->fd < 0) { + perror("Cannot open netlink socket"); + return -1; + } + + if (setsockopt(rth->fd,SOL_SOCKET,SO_SNDBUF,&sndbuf,sizeof(sndbuf)) < 0) { + perror("SO_SNDBUF"); + return -1; + } + + if (setsockopt(rth->fd,SOL_SOCKET,SO_RCVBUF,&rcvbuf,sizeof(rcvbuf)) < 0) { + perror("SO_RCVBUF"); + return -1; + } + + memset(&rth->local, 0, sizeof(rth->local)); + rth->local.nl_family = AF_NETLINK; + rth->local.nl_groups = subscriptions; + + if (bind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local)) < 0) { + perror("Cannot bind netlink socket"); + return -1; + } + addr_len = sizeof(rth->local); + if (getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len) < 0) { + perror("Cannot getsockname"); + return -1; + } + if (addr_len != sizeof(rth->local)) { + fprintf(stderr, "Wrong address length %d\n", addr_len); + return -1; + } + if (rth->local.nl_family != AF_NETLINK) { + fprintf(stderr, "Wrong address family %d\n", rth->local.nl_family); + return -1; + } + rth->seq = time(NULL); + return 0; +} + +int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions) +{ + return rtnl_open_byproto(rth, subscriptions, NETLINK_ROUTE); +} + +int rtnl_wilddump_request(struct rtnl_handle *rth, int family, int type) +{ + return rtnl_wilddump_req_filter(rth, family, type, RTEXT_FILTER_VF); +} + +int rtnl_wilddump_req_filter(struct rtnl_handle *rth, int family, int type, + __u32 filt_mask) +{ + struct { + struct nlmsghdr nlh; + struct ifinfomsg ifm; + /* attribute has to be NLMSG aligned */ + struct rtattr ext_req __attribute__ ((aligned(NLMSG_ALIGNTO))); + __u32 ext_filter_mask; + } req; + + memset(&req, 0, sizeof(req)); + req.nlh.nlmsg_len = sizeof(req); + req.nlh.nlmsg_type = type; + req.nlh.nlmsg_flags = NLM_F_DUMP|NLM_F_REQUEST; + req.nlh.nlmsg_pid = 0; + req.nlh.nlmsg_seq = rth->dump = ++rth->seq; + req.ifm.ifi_family = family; + + req.ext_req.rta_type = IFLA_EXT_MASK; + req.ext_req.rta_len = RTA_LENGTH(sizeof(__u32)); + req.ext_filter_mask = filt_mask; + + return send(rth->fd, (void*)&req, sizeof(req), 0); +} + +int rtnl_send(struct rtnl_handle *rth, const void *buf, int len) +{ + return send(rth->fd, buf, len, 0); +} + +int rtnl_send_check(struct rtnl_handle *rth, const void *buf, int len) +{ + struct nlmsghdr *h; + int status; + char resp[1024]; + + status = send(rth->fd, buf, len, 0); + if (status < 0) + return status; + + /* Check for immediate errors */ + status = recv(rth->fd, resp, sizeof(resp), MSG_DONTWAIT|MSG_PEEK); + if (status < 0) { + if (errno == EAGAIN) + return 0; + return -1; + } + + for (h = (struct nlmsghdr *)resp; NLMSG_OK(h, status); + h = NLMSG_NEXT(h, status)) { + if (h->nlmsg_type == NLMSG_ERROR) { + struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h); + if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) + fprintf(stderr, "ERROR truncated\n"); + else + errno = -err->error; + return -1; + } + } + + return 0; +} + +int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len) +{ + struct nlmsghdr nlh; + struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK }; + struct iovec iov[2] = { + { .iov_base = &nlh, .iov_len = sizeof(nlh) }, + { .iov_base = req, .iov_len = len } + }; + struct msghdr msg = { + .msg_name = &nladdr, + .msg_namelen = sizeof(nladdr), + .msg_iov = iov, + .msg_iovlen = 2, + }; + + nlh.nlmsg_len = NLMSG_LENGTH(len); + nlh.nlmsg_type = type; + nlh.nlmsg_flags = NLM_F_DUMP|NLM_F_REQUEST; + nlh.nlmsg_pid = 0; + nlh.nlmsg_seq = rth->dump = ++rth->seq; + + return sendmsg(rth->fd, &msg, 0); +} + +int rtnl_dump_filter_l(struct rtnl_handle *rth, + const struct rtnl_dump_filter_arg *arg) +{ + struct sockaddr_nl nladdr; + struct iovec iov; + struct msghdr msg = { + .msg_name = &nladdr, + .msg_namelen = sizeof(nladdr), + .msg_iov = &iov, + .msg_iovlen = 1, + }; + char buf[16384]; + int dump_intr = 0; + + iov.iov_base = buf; + while (1) { + int status; + const struct rtnl_dump_filter_arg *a; + int found_done = 0; + int msglen = 0; + + iov.iov_len = sizeof(buf); + status = recvmsg(rth->fd, &msg, 0); + + if (status < 0) { + if (errno == EINTR || errno == EAGAIN) + continue; + fprintf(stderr, "netlink receive error %s (%d)\n", + strerror(errno), errno); + return -1; + } + + if (status == 0) { + fprintf(stderr, "EOF on netlink\n"); + return -1; + } + + for (a = arg; a->filter; a++) { + struct nlmsghdr *h = (struct nlmsghdr*)buf; + msglen = status; + + while (NLMSG_OK(h, msglen)) { + int err; + + if (nladdr.nl_pid != 0 || + h->nlmsg_pid != rth->local.nl_pid || + h->nlmsg_seq != rth->dump) + goto skip_it; + + if (h->nlmsg_flags & NLM_F_DUMP_INTR) + dump_intr = 1; + + if (h->nlmsg_type == NLMSG_DONE) { + found_done = 1; + break; /* process next filter */ + } + if (h->nlmsg_type == NLMSG_ERROR) { + struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h); + if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) { + fprintf(stderr, + "ERROR truncated\n"); + } else { + errno = -err->error; + perror("RTNETLINK answers"); + } + return -1; + } + err = a->filter(&nladdr, h, a->arg1); + if (err < 0) + return err; + +skip_it: + h = NLMSG_NEXT(h, msglen); + } + } + + if (found_done) { + if (dump_intr) + fprintf(stderr, + "Dump was interrupted and may be inconsistent.\n"); + return 0; + } + + if (msg.msg_flags & MSG_TRUNC) { + fprintf(stderr, "Message truncated\n"); + continue; + } + if (msglen) { + fprintf(stderr, "!!!Remnant of size %d\n", msglen); + exit(1); + } + } +} + +int rtnl_dump_filter(struct rtnl_handle *rth, + rtnl_filter_t filter, + void *arg1) +{ + const struct rtnl_dump_filter_arg a[2] = { + { .filter = filter, .arg1 = arg1, }, + { .filter = NULL, .arg1 = NULL, }, + }; + + return rtnl_dump_filter_l(rth, a); +} + +int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer, + unsigned groups, struct nlmsghdr *answer) +{ + int status; + unsigned seq; + struct nlmsghdr *h; + struct sockaddr_nl nladdr; + struct iovec iov = { + .iov_base = (void*) n, + .iov_len = n->nlmsg_len + }; + struct msghdr msg = { + .msg_name = &nladdr, + .msg_namelen = sizeof(nladdr), + .msg_iov = &iov, + .msg_iovlen = 1, + }; + char buf[16384]; + + memset(&nladdr, 0, sizeof(nladdr)); + nladdr.nl_family = AF_NETLINK; + nladdr.nl_pid = peer; + nladdr.nl_groups = groups; + + n->nlmsg_seq = seq = ++rtnl->seq; + + if (answer == NULL) + n->nlmsg_flags |= NLM_F_ACK; + + status = sendmsg(rtnl->fd, &msg, 0); + + if (status < 0) { + perror("Cannot talk to rtnetlink"); + return -1; + } + + memset(buf,0,sizeof(buf)); + + iov.iov_base = buf; + + while (1) { + iov.iov_len = sizeof(buf); + status = recvmsg(rtnl->fd, &msg, 0); + + if (status < 0) { + if (errno == EINTR || errno == EAGAIN) + continue; + fprintf(stderr, "netlink receive error %s (%d)\n", + strerror(errno), errno); + return -1; + } + if (status == 0) { + fprintf(stderr, "EOF on netlink\n"); + return -1; + } + if (msg.msg_namelen != sizeof(nladdr)) { + fprintf(stderr, "sender address length == %d\n", msg.msg_namelen); + exit(1); + } + for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) { + int len = h->nlmsg_len; + int l = len - sizeof(*h); + + if (l < 0 || len>status) { + if (msg.msg_flags & MSG_TRUNC) { + fprintf(stderr, "Truncated message\n"); + return -1; + } + fprintf(stderr, "!!!malformed message: len=%d\n", len); + exit(1); + } + + if (nladdr.nl_pid != peer || + h->nlmsg_pid != rtnl->local.nl_pid || + h->nlmsg_seq != seq) { + /* Don't forget to skip that message. */ + status -= NLMSG_ALIGN(len); + h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len)); + continue; + } + + if (h->nlmsg_type == NLMSG_ERROR) { + struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h); + if (l < sizeof(struct nlmsgerr)) { + fprintf(stderr, "ERROR truncated\n"); + } else { + if (!err->error) { + if (answer) + memcpy(answer, h, h->nlmsg_len); + return 0; + } + + fprintf(stderr, "RTNETLINK answers: %s\n", strerror(-err->error)); + errno = -err->error; + } + return -1; + } + if (answer) { + memcpy(answer, h, h->nlmsg_len); + return 0; + } + + fprintf(stderr, "Unexpected reply!!!\n"); + + status -= NLMSG_ALIGN(len); + h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len)); + } + if (msg.msg_flags & MSG_TRUNC) { + fprintf(stderr, "Message truncated\n"); + continue; + } + if (status) { + fprintf(stderr, "!!!Remnant of size %d\n", status); + exit(1); + } + } +} + +int rtnl_listen(struct rtnl_handle *rtnl, + rtnl_filter_t handler, + void *jarg) +{ + int status; + struct nlmsghdr *h; + struct sockaddr_nl nladdr; + struct iovec iov; + struct msghdr msg = { + .msg_name = &nladdr, + .msg_namelen = sizeof(nladdr), + .msg_iov = &iov, + .msg_iovlen = 1, + }; + char buf[8192]; + + memset(&nladdr, 0, sizeof(nladdr)); + nladdr.nl_family = AF_NETLINK; + nladdr.nl_pid = 0; + nladdr.nl_groups = 0; + + iov.iov_base = buf; + while (1) { + iov.iov_len = sizeof(buf); + status = recvmsg(rtnl->fd, &msg, 0); + + if (status < 0) { + if (errno == EINTR || errno == EAGAIN) + continue; + fprintf(stderr, "netlink receive error %s (%d)\n", + strerror(errno), errno); + if (errno == ENOBUFS) + continue; + return -1; + } + if (status == 0) { + fprintf(stderr, "EOF on netlink\n"); + return -1; + } + if (msg.msg_namelen != sizeof(nladdr)) { + fprintf(stderr, "Sender address length == %d\n", msg.msg_namelen); + exit(1); + } + for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) { + int err; + int len = h->nlmsg_len; + int l = len - sizeof(*h); + + if (l<0 || len>status) { + if (msg.msg_flags & MSG_TRUNC) { + fprintf(stderr, "Truncated message\n"); + return -1; + } + fprintf(stderr, "!!!malformed message: len=%d\n", len); + exit(1); + } + + err = handler(&nladdr, h, jarg); + if (err < 0) + return err; + + status -= NLMSG_ALIGN(len); + h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len)); + } + if (msg.msg_flags & MSG_TRUNC) { + fprintf(stderr, "Message truncated\n"); + continue; + } + if (status) { + fprintf(stderr, "!!!Remnant of size %d\n", status); + exit(1); + } + } +} + +int rtnl_from_file(FILE *rtnl, rtnl_filter_t handler, + void *jarg) +{ + int status; + struct sockaddr_nl nladdr; + char buf[8192]; + struct nlmsghdr *h = (void*)buf; + + memset(&nladdr, 0, sizeof(nladdr)); + nladdr.nl_family = AF_NETLINK; + nladdr.nl_pid = 0; + nladdr.nl_groups = 0; + + while (1) { + int err, len; + int l; + + status = fread(&buf, 1, sizeof(*h), rtnl); + + if (status < 0) { + if (errno == EINTR) + continue; + perror("rtnl_from_file: fread"); + return -1; + } + if (status == 0) + return 0; + + len = h->nlmsg_len; + l = len - sizeof(*h); + + if (l<0 || len>sizeof(buf)) { + fprintf(stderr, "!!!malformed message: len=%d @%lu\n", + len, ftell(rtnl)); + return -1; + } + + status = fread(NLMSG_DATA(h), 1, NLMSG_ALIGN(l), rtnl); + + if (status < 0) { + perror("rtnl_from_file: fread"); + return -1; + } + if (status < l) { + fprintf(stderr, "rtnl-from_file: truncated message\n"); + return -1; + } + + err = handler(&nladdr, h, jarg); + if (err < 0) + return err; + } +} + +int addattr(struct nlmsghdr *n, int maxlen, int type) +{ + return addattr_l(n, maxlen, type, NULL, 0); +} + +int addattr8(struct nlmsghdr *n, int maxlen, int type, __u8 data) +{ + return addattr_l(n, maxlen, type, &data, sizeof(__u8)); +} + +int addattr16(struct nlmsghdr *n, int maxlen, int type, __u16 data) +{ + return addattr_l(n, maxlen, type, &data, sizeof(__u16)); +} + +int addattr32(struct nlmsghdr *n, int maxlen, int type, __u32 data) +{ + return addattr_l(n, maxlen, type, &data, sizeof(__u32)); +} + +int addattr64(struct nlmsghdr *n, int maxlen, int type, __u64 data) +{ + return addattr_l(n, maxlen, type, &data, sizeof(__u64)); +} + +int addattrstrz(struct nlmsghdr *n, int maxlen, int type, const char *str) +{ + return addattr_l(n, maxlen, type, str, strlen(str)+1); +} + +int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data, + int alen) +{ + int len = RTA_LENGTH(alen); + struct rtattr *rta; + + if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) { + fprintf(stderr, "addattr_l ERROR: message exceeded bound of %d\n",maxlen); + return -1; + } + rta = NLMSG_TAIL(n); + rta->rta_type = type; + rta->rta_len = len; + memcpy(RTA_DATA(rta), data, alen); + n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len); + return 0; +} + +int addraw_l(struct nlmsghdr *n, int maxlen, const void *data, int len) +{ + if (NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len) > maxlen) { + fprintf(stderr, "addraw_l ERROR: message exceeded bound of %d\n",maxlen); + return -1; + } + + memcpy(NLMSG_TAIL(n), data, len); + memset((void *) NLMSG_TAIL(n) + len, 0, NLMSG_ALIGN(len) - len); + n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len); + return 0; +} + +struct rtattr *addattr_nest(struct nlmsghdr *n, int maxlen, int type) +{ + struct rtattr *nest = NLMSG_TAIL(n); + + addattr_l(n, maxlen, type, NULL, 0); + return nest; +} + +int addattr_nest_end(struct nlmsghdr *n, struct rtattr *nest) +{ + nest->rta_len = (void *)NLMSG_TAIL(n) - (void *)nest; + return n->nlmsg_len; +} + +struct rtattr *addattr_nest_compat(struct nlmsghdr *n, int maxlen, int type, + const void *data, int len) +{ + struct rtattr *start = NLMSG_TAIL(n); + + addattr_l(n, maxlen, type, data, len); + addattr_nest(n, maxlen, type); + return start; +} + +int addattr_nest_compat_end(struct nlmsghdr *n, struct rtattr *start) +{ + struct rtattr *nest = (void *)start + NLMSG_ALIGN(start->rta_len); + + start->rta_len = (void *)NLMSG_TAIL(n) - (void *)start; + addattr_nest_end(n, nest); + return n->nlmsg_len; +} + +int rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data) +{ + int len = RTA_LENGTH(4); + struct rtattr *subrta; + + if (RTA_ALIGN(rta->rta_len) + len > maxlen) { + fprintf(stderr,"rta_addattr32: Error! max allowed bound %d exceeded\n",maxlen); + return -1; + } + subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len)); + subrta->rta_type = type; + subrta->rta_len = len; + memcpy(RTA_DATA(subrta), &data, 4); + rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len; + return 0; +} + +int rta_addattr_l(struct rtattr *rta, int maxlen, int type, + const void *data, int alen) +{ + struct rtattr *subrta; + int len = RTA_LENGTH(alen); + + if (RTA_ALIGN(rta->rta_len) + RTA_ALIGN(len) > maxlen) { + fprintf(stderr,"rta_addattr_l: Error! max allowed bound %d exceeded\n",maxlen); + return -1; + } + subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len)); + subrta->rta_type = type; + subrta->rta_len = len; + memcpy(RTA_DATA(subrta), data, alen); + rta->rta_len = NLMSG_ALIGN(rta->rta_len) + RTA_ALIGN(len); + return 0; +} + +int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len) +{ + return parse_rtattr_flags(tb, max, rta, len, 0); +} + +int parse_rtattr_flags(struct rtattr *tb[], int max, struct rtattr *rta, + int len, unsigned short flags) +{ + unsigned short type; + + memset(tb, 0, sizeof(struct rtattr *) * (max + 1)); + while (RTA_OK(rta, len)) { + type = rta->rta_type & ~flags; + if ((type <= max) && (!tb[type])) + tb[type] = rta; + rta = RTA_NEXT(rta,len); + } + if (len) + fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len); + return 0; +} + +int parse_rtattr_byindex(struct rtattr *tb[], int max, struct rtattr *rta, int len) +{ + int i = 0; + + memset(tb, 0, sizeof(struct rtattr *) * max); + while (RTA_OK(rta, len)) { + if (rta->rta_type <= max && i < max) + tb[i++] = rta; + rta = RTA_NEXT(rta,len); + } + if (len) + fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len); + return i; +} + +int __parse_rtattr_nested_compat(struct rtattr *tb[], int max, struct rtattr *rta, + int len) +{ + if (RTA_PAYLOAD(rta) < len) + return -1; + if (RTA_PAYLOAD(rta) >= RTA_ALIGN(len) + sizeof(struct rtattr)) { + rta = RTA_DATA(rta) + RTA_ALIGN(len); + return parse_rtattr_nested(tb, max, rta); + } + memset(tb, 0, sizeof(struct rtattr *) * (max + 1)); + return 0; +} diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/libnetlink.h b/meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/libnetlink.h new file mode 100644 index 0000000..9e72692 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/libnetlink.h @@ -0,0 +1,161 @@ +/* + * Note: Original file from iproute2 package + * + * 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 __LIBNETLINK_H__ +#define __LIBNETLINK_H__ 1 + +#include <stdio.h> +#include <string.h> +#include <asm/types.h> +#include <linux/netlink.h> +#include <linux/rtnetlink.h> +#include <linux/if_link.h> +#include <linux/if_addr.h> +#include <linux/neighbour.h> +#include <linux/netconf.h> + +struct rtnl_handle +{ + int fd; + struct sockaddr_nl local; + struct sockaddr_nl peer; + __u32 seq; + __u32 dump; +}; + +extern int rcvbuf; + +extern int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions); +extern int rtnl_open_byproto(struct rtnl_handle *rth, unsigned subscriptions, int protocol); +extern void rtnl_close(struct rtnl_handle *rth); +extern int rtnl_wilddump_request(struct rtnl_handle *rth, int fam, int type); +extern int rtnl_wilddump_req_filter(struct rtnl_handle *rth, int fam, int type, + __u32 filt_mask); +extern int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len); + +typedef int (*rtnl_filter_t)(const struct sockaddr_nl *, + struct nlmsghdr *n, void *); + +struct rtnl_dump_filter_arg +{ + rtnl_filter_t filter; + void *arg1; +}; + +extern int rtnl_dump_filter_l(struct rtnl_handle *rth, + const struct rtnl_dump_filter_arg *arg); +extern int rtnl_dump_filter(struct rtnl_handle *rth, rtnl_filter_t filter, + void *arg); +extern int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer, + unsigned groups, struct nlmsghdr *answer); +extern int rtnl_send(struct rtnl_handle *rth, const void *buf, int); +extern int rtnl_send_check(struct rtnl_handle *rth, const void *buf, int); + +extern int addattr(struct nlmsghdr *n, int maxlen, int type); +extern int addattr8(struct nlmsghdr *n, int maxlen, int type, __u8 data); +extern int addattr16(struct nlmsghdr *n, int maxlen, int type, __u16 data); +extern int addattr32(struct nlmsghdr *n, int maxlen, int type, __u32 data); +extern int addattr64(struct nlmsghdr *n, int maxlen, int type, __u64 data); +extern int addattrstrz(struct nlmsghdr *n, int maxlen, int type, const char *data); + +extern int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data, int alen); +extern int addraw_l(struct nlmsghdr *n, int maxlen, const void *data, int len); +extern struct rtattr *addattr_nest(struct nlmsghdr *n, int maxlen, int type); +extern int addattr_nest_end(struct nlmsghdr *n, struct rtattr *nest); +extern struct rtattr *addattr_nest_compat(struct nlmsghdr *n, int maxlen, int type, const void *data, int len); +extern int addattr_nest_compat_end(struct nlmsghdr *n, struct rtattr *nest); +extern int rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data); +extern int rta_addattr_l(struct rtattr *rta, int maxlen, int type, const void *data, int alen); + +extern int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len); +extern int parse_rtattr_flags(struct rtattr *tb[], int max, struct rtattr *rta, + int len, unsigned short flags); +extern int parse_rtattr_byindex(struct rtattr *tb[], int max, struct rtattr *rta, int len); +extern int __parse_rtattr_nested_compat(struct rtattr *tb[], int max, struct rtattr *rta, int len); + +#define parse_rtattr_nested(tb, max, rta) \ + (parse_rtattr((tb), (max), RTA_DATA(rta), RTA_PAYLOAD(rta))) + +#define parse_rtattr_nested_compat(tb, max, rta, data, len) \ + ({ data = RTA_PAYLOAD(rta) >= len ? RTA_DATA(rta) : NULL; \ + __parse_rtattr_nested_compat(tb, max, rta, len); }) + +static inline __u8 rta_getattr_u8(const struct rtattr *rta) +{ + return *(__u8 *)RTA_DATA(rta); +} +static inline __u16 rta_getattr_u16(const struct rtattr *rta) +{ + return *(__u16 *)RTA_DATA(rta); +} +static inline __u32 rta_getattr_u32(const struct rtattr *rta) +{ + return *(__u32 *)RTA_DATA(rta); +} +static inline __u64 rta_getattr_u64(const struct rtattr *rta) +{ + __u64 tmp; + memcpy(&tmp, RTA_DATA(rta), sizeof(__u64)); + return tmp; +} +static inline const char *rta_getattr_str(const struct rtattr *rta) +{ + return (const char *)RTA_DATA(rta); +} + +extern int rtnl_listen(struct rtnl_handle *, rtnl_filter_t handler, + void *jarg); +extern int rtnl_from_file(FILE *, rtnl_filter_t handler, + void *jarg); + +#define NLMSG_TAIL(nmsg) \ + ((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len))) + +#ifndef IFA_RTA +#define IFA_RTA(r) \ + ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrmsg)))) +#endif +#ifndef IFA_PAYLOAD +#define IFA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifaddrmsg)) +#endif + +#ifndef IFLA_RTA +#define IFLA_RTA(r) \ + ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifinfomsg)))) +#endif +#ifndef IFLA_PAYLOAD +#define IFLA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifinfomsg)) +#endif + +#ifndef NDA_RTA +#define NDA_RTA(r) \ + ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg)))) +#endif +#ifndef NDA_PAYLOAD +#define NDA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ndmsg)) +#endif + +#ifndef NDTA_RTA +#define NDTA_RTA(r) \ + ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndtmsg)))) +#endif +#ifndef NDTA_PAYLOAD +#define NDTA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ndtmsg)) +#endif + +#endif /* __LIBNETLINK_H__ */ + diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/ll_map.c b/meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/ll_map.c new file mode 100644 index 0000000..64e5069 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/ll_map.c @@ -0,0 +1,225 @@ +/* + * Note: Original file from iproute2 package + * + * ll_map.c + * + * 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. + * + * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <syslog.h> +#include <fcntl.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <string.h> +#include <net/if.h> + +#include "libnetlink.h" +#include "ll_map.h" +#include "hlist.h" + +struct ll_cache { + struct hlist_node idx_hash; + struct hlist_node name_hash; + unsigned flags; + int index; + unsigned short type; + char name[IFNAMSIZ]; +}; + +#define IDXMAP_SIZE 1024 +static struct hlist_head idx_head[IDXMAP_SIZE]; +static struct hlist_head name_head[IDXMAP_SIZE]; + +static struct ll_cache *ll_get_by_index(unsigned index) +{ + struct hlist_node *n; + unsigned h = index & (IDXMAP_SIZE - 1); + + hlist_for_each(n, &idx_head[h]) { + struct ll_cache *im + = container_of(n, struct ll_cache, idx_hash); + if (im->index == index) + return im; + } + + return NULL; +} + +static unsigned namehash(const char *str) +{ + unsigned hash = 5381; + + while (*str) + hash = ((hash << 5) + hash) + *str++; /* hash * 33 + c */ + + return hash; +} + +static struct ll_cache *ll_get_by_name(const char *name) +{ + struct hlist_node *n; + unsigned h = namehash(name) & (IDXMAP_SIZE - 1); + + hlist_for_each(n, &name_head[h]) { + struct ll_cache *im + = container_of(n, struct ll_cache, name_hash); + + if (strncmp(im->name, name, IFNAMSIZ) == 0) + return im; + } + + return NULL; +} + +int ll_remember_index(const struct sockaddr_nl *who, + struct nlmsghdr *n, void *arg) +{ + unsigned int h; + const char *ifname; + struct ifinfomsg *ifi = NLMSG_DATA(n); + struct ll_cache *im; + struct rtattr *tb[IFLA_MAX+1]; + + if (n->nlmsg_type != RTM_NEWLINK && n->nlmsg_type != RTM_DELLINK) + return 0; + + if (n->nlmsg_len < NLMSG_LENGTH(sizeof(ifi))) + return -1; + + im = ll_get_by_index(ifi->ifi_index); + if (n->nlmsg_type == RTM_DELLINK) { + if (im) { + hlist_del(&im->name_hash); + hlist_del(&im->idx_hash); + free(im); + } + return 0; + } + + memset(tb, 0, sizeof(tb)); + parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), IFLA_PAYLOAD(n)); + ifname = rta_getattr_str(tb[IFLA_IFNAME]); + if (ifname == NULL) + return 0; + + if (im) { + /* change to existing entry */ + if (strcmp(im->name, ifname) != 0) { + hlist_del(&im->name_hash); + h = namehash(ifname) & (IDXMAP_SIZE - 1); + hlist_add_head(&im->name_hash, &name_head[h]); + } + + im->flags = ifi->ifi_flags; + return 0; + } + + im = malloc(sizeof(*im)); + if (im == NULL) + return 0; + im->index = ifi->ifi_index; + strcpy(im->name, ifname); + im->type = ifi->ifi_type; + im->flags = ifi->ifi_flags; + + h = ifi->ifi_index & (IDXMAP_SIZE - 1); + hlist_add_head(&im->idx_hash, &idx_head[h]); + + h = namehash(ifname) & (IDXMAP_SIZE - 1); + hlist_add_head(&im->name_hash, &name_head[h]); + + return 0; +} + +const char *ll_idx_n2a(unsigned idx, char *buf) +{ + const struct ll_cache *im; + + if (idx == 0) + return "*"; + + im = ll_get_by_index(idx); + if (im) + return im->name; + + if (if_indextoname(idx, buf) == NULL) + snprintf(buf, IFNAMSIZ, "if%d", idx); + + return buf; +} + +const char *ll_index_to_name(unsigned idx) +{ + static char nbuf[IFNAMSIZ]; + + return ll_idx_n2a(idx, nbuf); +} + +int ll_index_to_type(unsigned idx) +{ + const struct ll_cache *im; + + if (idx == 0) + return -1; + + im = ll_get_by_index(idx); + return im ? im->type : -1; +} + +unsigned ll_index_to_flags(unsigned idx) +{ + const struct ll_cache *im; + + if (idx == 0) + return 0; + + im = ll_get_by_index(idx); + return im ? im->flags : -1; +} + +unsigned ll_name_to_index(const char *name) +{ + const struct ll_cache *im; + unsigned idx; + + if (name == NULL) + return 0; + + im = ll_get_by_name(name); + if (im) + return im->index; + + idx = if_nametoindex(name); + if (idx == 0) + sscanf(name, "if%u", &idx); + return idx; +} + +void ll_init_map(struct rtnl_handle *rth) +{ + static int initialized; + + if (initialized) + return; + + if (rtnl_wilddump_request(rth, AF_UNSPEC, RTM_GETLINK) < 0) { + perror("Cannot send dump request"); + exit(1); + } + + if (rtnl_dump_filter(rth, ll_remember_index, NULL) < 0) { + fprintf(stderr, "Dump terminated\n"); + exit(1); + } + + initialized = 1; +} diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/ll_map.h b/meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/ll_map.h new file mode 100644 index 0000000..d74a46f --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/ll_map.h @@ -0,0 +1,32 @@ +/* + * Note: Original file from iproute2 package + * + * 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 __LL_MAP_H__ +#define __LL_MAP_H__ 1 + +extern int ll_remember_index(const struct sockaddr_nl *who, + struct nlmsghdr *n, void *arg); + +extern void ll_init_map(struct rtnl_handle *rth); +extern unsigned ll_name_to_index(const char *name); +extern const char *ll_index_to_name(unsigned idx); +extern const char *ll_idx_n2a(unsigned idx, char *buf); +extern int ll_index_to_type(unsigned idx); +extern unsigned ll_index_to_flags(unsigned idx); + +#endif /* __LL_MAP_H__ */ diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/main.c b/meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/main.c new file mode 100644 index 0000000..4312402 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/main.c @@ -0,0 +1,192 @@ +/* + * Copyright 2014-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 <unistd.h> +#include <sys/select.h> +#include <sys/time.h> +#include <sys/errno.h> + +#include "nic.h" +#include "intf.h" + +#include "facebook/log.h" +#include "facebook/wedge_eeprom.h" + +#define WAIT4PACKET_TIMEOUT 10000 /* 10ms */ +#define NO_RCV_CHECK_THRESHOLD 100 /* if not receiving pkt for 100 times (1s), + * check the NIC status + */ + +static void io_loop(oob_nic *nic, oob_intf *intf, const uint8_t mac[6]) { + + fd_set rfds; + int fd = oob_intf_get_fd(intf); + struct timeval timeout; + int rc; + int n_fds; + int n_io; + char buf[NIC_PKT_SIZE_MAX]; + int no_rcv = 0; + struct oob_nic_status_t sts; + + while (1) { + memset(&timeout, 0, sizeof(timeout)); + timeout.tv_sec = 0; + timeout.tv_usec = WAIT4PACKET_TIMEOUT; + + FD_ZERO(&rfds); + FD_SET(fd, &rfds); + + n_fds = select(fd + 1, &rfds, NULL, NULL, &timeout); + if (n_fds < 0) { + rc = errno; + LOG_ERR(rc, "Failed to select"); + continue; + } + + /* + * no matter what, receive packet from nic first, as the nic + * has small amount of memory. Without read, the sending could + * fail due to OOM. + * + * TODO: We might want to do something smart here to prevent attack or + * just rx flooding. Disable the Receive Enable first, drain the buffer + * with oob_nic_receive(), then Tx, and enable Receive Enable after. + */ + for (n_io = 0; n_io < 16; n_io++) { + rc = oob_nic_receive(nic, buf, sizeof(buf)); + if (rc <= 0) { + no_rcv++; + break; + } + oob_intf_send(intf, buf, rc); + no_rcv = 0; + } + + /* + * if we didn't receive any packet for NO_RCV_CHECK_THRESHOLD times, + * check the nic status + */ + if (no_rcv >= NO_RCV_CHECK_THRESHOLD) { + while(oob_nic_get_status(nic, &sts)) { + usleep(1000); + } + LOG_INFO("Failed to receive packets for %d times. NIC status is " + "%x.%x", NO_RCV_CHECK_THRESHOLD, sts.ons_byte1, sts.ons_byte2); + /* + * if the NIC went through initialization, or not set force up, need to + * re-program the filters by calling oob_nic_start(). + */ + if ((sts.ons_byte1 & NIC_STATUS_D1_INIT) + || !(sts.ons_byte1 & NIC_STATUS_D1_FORCE_UP)) { + while(oob_nic_start(nic, mac)) { + usleep(1000); + } + } + no_rcv = 0; + } + + if (n_fds > 0 && FD_ISSET(fd, &rfds)) { + for (n_io = 0; n_io < 1; n_io++) { + rc = oob_intf_receive(intf, buf, sizeof(buf)); + if (rc <= 0) { + break; + } + oob_nic_send(nic, buf, rc); + } + } + } +} + +int main(int argc, const char **argv) { + + uint8_t mac[6]; + oob_nic *nic; + oob_intf *intf; + struct wedge_eeprom_st eeprom; + int rc; + int from_eeprom = 0; + + nic = oob_nic_open(0, 0x49); + if (!nic) { + return -1; + } + + /* read EEPROM for the MAC */ + if (wedge_eeprom_parse(NULL, &eeprom) == 0) { + if (eeprom.fbw_mac_size <= 0) { + LOG_ERR(EFAULT, "Invalid extended MAC size: %d", eeprom.fbw_mac_size); + } else { + uint16_t carry; + int pos; + /* use the last MAC address from the extended MAC range */ + memcpy(mac, eeprom.fbw_mac_base, sizeof(mac)); + if (eeprom.fbw_mac_size > 128) { + LOG_ERR(EFAULT, "Extended MAC size (%d) is too large.", + eeprom.fbw_mac_size); + carry = 127; + } else { + /* + * hack around bug device which have the same MAC address on + * left and right. + */ + if (strncmp(eeprom.fbw_location, "LEFT", FBW_EEPROM_F_LOCATION) == 0) { + carry = eeprom.fbw_mac_size - 2; + } else { + carry = eeprom.fbw_mac_size - 1; + } + } + for (pos = sizeof(mac) - 1; pos >= 0 && carry; pos--) { + uint16_t tmp = mac[pos] + carry; + mac[pos] = tmp & 0xFF; + carry = tmp >> 8; + } + from_eeprom = 1; + } + } + + if (!from_eeprom) { + while (oob_nic_get_mac(nic, mac)) { + usleep(1000); + } + /* + * increase the last byte of the mac by 1 and turn on the + * local administered bit to use it as the oob nic mac + */ + mac[0] |= 0x2; + mac[5]++; + } + + LOG_INFO("Retrieve MAC %x:%x:%x:%x:%x:%x from %s", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], + (from_eeprom) ? "EEPROM" : "NIC"); + + /* create the tap interface */ + intf = oob_intf_create("oob", mac); + if (!intf) { + return -1; + } + + while (oob_nic_start(nic, mac)) { + usleep(1000); + } + + io_loop(nic, intf, mac); + + return 0; +} diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/nic.c b/meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/nic.c new file mode 100644 index 0000000..a4dc071 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/nic.c @@ -0,0 +1,487 @@ +/* + * Copyright 2014-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 "nic.h" + +#include <errno.h> +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <sys/types.h> + +#include "facebook/i2c-dev.h" +#include "facebook/log.h" + +struct oob_nic_t { + int on_bus; + uint8_t on_addr; + int on_file; /* the file descriptor */ + uint8_t on_mac[6]; /* the mac address assigned to this NIC */ +}; + +oob_nic* oob_nic_open(int bus, uint8_t addr) { + oob_nic *dev = NULL; + char fn[32]; + int rc; + + /* address must be 7 bits maximum */ + if ((addr & 0x80)) { + LOG_ERR(EINVAL, "Address 0x%x has the 8th bit", addr); + return NULL; + } + + dev = calloc(1, sizeof(*dev)); + if (!dev) { + return NULL; + } + dev->on_bus = bus; + dev->on_addr = addr; + + /* construct the device file name */ + snprintf(fn, sizeof(fn), "/dev/i2c-%d", bus); + dev->on_file = open(fn, O_RDWR); + if (dev->on_file == -1) { + LOG_ERR(errno, "Failed to open i2c device %s", fn); + goto err_out; + } + + /* assign the device address */ + rc = ioctl(dev->on_file, I2C_SLAVE, dev->on_addr); + if (rc < 0) { + LOG_ERR(errno, "Failed to open slave @ address 0x%x", dev->on_addr); + goto err_out; + } + + return dev; + + err_out: + oob_nic_close(dev); + return NULL; +} + +void oob_nic_close(oob_nic *dev) { + if (!dev) { + return; + } + if (dev->on_file != -1) { + close(dev->on_file); + } + free(dev); +} + +int oob_nic_get_mac(oob_nic *dev, uint8_t mac[6]) { + int rc; + uint8_t buf[64]; + + rc = i2c_smbus_read_block_data(dev->on_file, NIC_READ_MAC_CMD, buf); + if (rc < 0) { + rc = errno; + LOG_ERR(rc, "Failed to get MAC on %d-%x", + dev->on_bus, dev->on_addr); + return -rc; + } + + if (rc != NIC_READ_MAC_RES_LEN) { + LOG_ERR(EFAULT, "Unexpected response len (%d) for get MAC on %d-%x", + rc, dev->on_bus, dev->on_addr); + return -EFAULT; + } + + if (buf[0] != NIC_READ_MAC_RES_OPT) { + LOG_ERR(EFAULT, "Unexpected response opt code (0x%x) get MAC on %d-%x", + buf[0], dev->on_bus, dev->on_addr); + return -EFAULT; + } + + memcpy(mac, &buf[1], 6); + + LOG_DBG("Get MAC on %d-%x: %x:%x:%x:%x:%x:%x", dev->on_bus, dev->on_addr, + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + return 0; +} + +int oob_nic_get_status(oob_nic *dev, oob_nic_status *status) { + int rc; + uint8_t buf[64]; + + rc = i2c_smbus_read_block_data(dev->on_file, NIC_READ_STATUS_CMD, buf); + if (rc < 0) { + rc = errno; + LOG_ERR(rc, "Failed to get status on %d-%x", + dev->on_bus, dev->on_addr); + return -rc; + } + + if (rc != NIC_READ_STATUS_RES_LEN) { + LOG_ERR(EFAULT, "Unexpected response len (%d) for get status on %d-%x", + rc, dev->on_bus, dev->on_addr); + return -EFAULT; + } + + if (buf[0] != NIC_READ_STATUS_RES_OPT) { + LOG_ERR(EFAULT, "Unexpected response opt code (0x%x) get status on %d-%x", + buf[0], dev->on_bus, dev->on_addr); + return -EFAULT; + } + + memset(status, 0, sizeof(*status)); + status->ons_byte1 = buf[1]; + status->ons_byte2 = buf[2]; + + LOG_VER("Get status on %d-%x: byte1:0x%x byte2:0x%x", + dev->on_bus, dev->on_addr, + status->ons_byte1, status->ons_byte2); + return 0; +} + +int oob_nic_receive(oob_nic *dev, uint8_t *buf, int len) { + + int rc = 0; + uint8_t pkt[I2C_SMBUS_BLOCK_LARGE_MAX]; + uint8_t opt; + int copied = 0; + int to_copy; + int expect_first = 1; + int n_frags = 0; + +#define _COPY_DATA(n, data) do { \ + int to_copy; \ + if (copied >= len) { \ + break; \ + } \ + to_copy = (n < len - copied) ? n : len - copied; \ + if (to_copy) { \ + memcpy(buf + copied, data, to_copy); \ + } \ + copied += to_copy; \ +} while(0) + + do { + rc = i2c_smbus_read_block_large_data(dev->on_file, NIC_READ_PKT_CMD, pkt); + if (rc < 0) { + rc = errno; + LOG_ERR(rc, "Failed to get packet on %d-%x", + dev->on_bus, dev->on_addr); + goto err_out; + } + if (rc > I2C_SMBUS_BLOCK_LARGE_MAX) { + LOG_ERR(EFAULT, "Too large i2c block (%d) received on %d-%x", + rc, dev->on_bus, dev->on_addr); + rc = EFAULT; + goto err_out; + } + opt = pkt[0]; + switch (opt) { + case NIC_READ_PKT_RES_FIRST_OPT: + if (!expect_first) { + rc = EFAULT; + LOG_ERR(rc, "Received more than one buffer with FIRST set"); + goto err_out; + } + expect_first = 0; + n_frags++; + _COPY_DATA(rc - 1, &pkt[1]); + break; + case NIC_READ_PKT_RES_MIDDLE_OPT: + if (expect_first) { + rc = EFAULT; + LOG_ERR(rc, "Received MIDDLE before getting FIRST"); + goto err_out; + } + _COPY_DATA(rc - 1, &pkt[1]); + n_frags++; + break; + case NIC_READ_PKT_RES_LAST_OPT: + if (expect_first) { + rc = EFAULT; + LOG_ERR(rc, "Received LAST before getting FIRST"); + goto err_out; + } + if (rc != NIC_READ_PKT_RES_LAST_LEN) { + LOG_ERR(EFAULT, "Expect %d bytes (got %d) for LAST segement", + NIC_READ_PKT_RES_LAST_LEN, rc); + rc = EFAULT; + goto err_out; + } + /* TODO: pkt status???? */ + break; + case NIC_READ_STATUS_RES_OPT: + /* that means no pkt available */ + if (!expect_first) { + rc = EFAULT; + LOG_ERR(rc, "Received STATUS in the middle of packet"); + goto err_out; + } + //LOG_VER("Received STATUS when receiving the packet"); + return 0; + default: + rc = EFAULT; + LOG_ERR(rc, "Unexpected opt code 0x%x", opt); + goto err_out; + } + } while (opt != NIC_READ_PKT_RES_LAST_OPT); + + LOG_VER("Received a packet with %d bytes in %d fragments", copied, n_frags); + return copied; + + err_out: + return -rc; +#undef _COPY_DATA +} + +int oob_nic_send(oob_nic *dev, const uint8_t *data, int len) { + + int rc; + uint8_t to_send; + int has_sent = 0; + int is_first = 1; + uint8_t cmd; + int n_frags = 0; + + if (len <= 0 || len > NIC_PKT_SIZE_MAX) { + rc = EINVAL; + LOG_ERR(rc, "Invalid packet length %d", len); + return -rc; + } + + while (len) { + to_send = (len < OOB_NIC_PKT_FRAGMENT_SIZE) + ? len : OOB_NIC_PKT_FRAGMENT_SIZE; + + if (is_first) { + if (to_send >= len) { + /* this is the last pkt also */ + cmd = NIC_WRITE_PKT_SINGLE_CMD; + } else { + cmd = NIC_WRITE_PKT_FIRST_CMD; + } + is_first = 0; + } else { + if (to_send >= len) { + /* this is the last pkt */ + cmd = NIC_WRITE_PKT_LAST_CMD; + } else { + cmd = NIC_WRITE_PKT_MIDDLE_CMD; + } + } + + rc = i2c_smbus_write_block_large_data(dev->on_file, cmd, + to_send, data + has_sent); + if (rc < 0) { + rc = errno; + LOG_ERR(rc, "Failed to sent packet with cmd 0x%x, has_sent=%d " + "to_send=%d", cmd, has_sent, to_send); + return -rc; + } + + has_sent += to_send; + len -= to_send; + n_frags++; + } + + LOG_VER("Sent a packet with %d bytes in %d fragments", has_sent, n_frags); + + return has_sent; +} + +static int oob_nic_set_mng_ctrl(oob_nic *dev, const uint8_t *data, int len) { + int rc; + + if (len <= 0) { + rc = EINVAL; + LOG_ERR(rc, "Invalid data length: %d", len); + return -rc; + } + + rc = i2c_smbus_write_block_data(dev->on_file, NIC_WRITE_MNG_CTRL_CMD, + len, data); + if (rc < 0) { + rc = errno; + LOG_ERR(rc, "Failed to send management control command for parameter # %d", + data[0]); + return -rc; + } + + return 0; +} + +static int oob_nic_set_force_up(oob_nic *dev, int enable) { + uint8_t cmd[2]; + + cmd[0] = NIC_MNG_CTRL_KEEP_LINK_UP_NUM; + cmd[1] = enable + ? NIC_MNG_CTRL_KEEP_LINK_UP_ENABLE : NIC_MNG_CTRL_KEEP_LINK_UP_DISABLE; + + LOG_DBG("Turn %s link force up", enable ? "on" : "off"); + return oob_nic_set_mng_ctrl(dev, cmd, sizeof(cmd)); +} + +static int oob_nic_setup_filters(oob_nic *dev, const uint8_t mac[6]) { + int rc; + int i; + uint32_t cmd32; + uint8_t buf[32]; + uint8_t *cmd; + + /* + * Command to set MAC filter + * Seven bytes are required to load the MAC address filters. + * Data 2—MAC address filters pair number (3:0). + * Data 3—MSB of MAC address. + * ... + * Data 8: LSB of MAC address. + */ + /* set MAC filter to pair 0 */ + cmd = buf; + *cmd++ = NIC_FILTER_MAC_NUM; + *cmd++ = NIC_FILTER_MAC_PAIR0; /* pair 0 */ + for (i = 0; i < 6; i++) { + *cmd++ = mac[i]; + } + rc = i2c_smbus_write_block_data(dev->on_file, NIC_WRITE_FILTER_CMD, + cmd - buf, buf); + if (rc < 0) { + rc = errno; + LOG_ERR(rc, "Failed to set MAC filter"); + return -rc; + } + + /* + * Command to enable filter + * + * 9 bytes to load the extended decision filters (MDEF_EXT & MDEF) + * Data 2—MDEF filter index (valid values are 0...6) + * Data 3—MSB of MDEF_EXT (DecisionFilter0) + * .... + * Data 6—LSB of MDEF_EXT (DecisionFilter0) + * Data 7—MSB of MDEF (DecisionFilter0) + * .... + * Data 10—LSB of MDEF (DecisionFilter0) + */ + + /* enable MAC filter pair 0 on filter 0 */ + cmd = buf; + *cmd++ = NIC_FILTER_DECISION_EXT_NUM; + *cmd++ = NIC_FILTER_MDEF0; + /* enable filter for traffic from network and host */ + cmd32 = NIC_FILTER_MDEF_BIT(NIC_FILTER_MDEF_EXT_NET_EN_OFFSET) + | NIC_FILTER_MDEF_BIT(NIC_FILTER_MDEF_EXT_HOST_EN_OFFSET); + for (i = 0; i < sizeof(cmd32); i++) { + *cmd++ = (cmd32 >> (24 - 8 * i)) & 0xFF; + } + /* enable mac pair 0 */ + cmd32 = NIC_FILTER_MDEF_BIT_VAL(NIC_FILTER_MDEF_MAC_AND_OFFSET, + NIC_FILTER_MAC_PAIR0); + for (i = 0; i < sizeof(cmd32); i++) { + *cmd++ = (cmd32 >> (24 - 8 * i)) & 0xFF; + } + rc = i2c_smbus_write_block_data(dev->on_file, NIC_WRITE_FILTER_CMD, + cmd - buf, buf); + if (rc < 0) { + rc = errno; + LOG_ERR(rc, "Failed to set MAC filter to MDEF 0"); + return -rc; + } + /* enable ARP and ND on filter 1*/ + cmd = buf; + *cmd++ = NIC_FILTER_DECISION_EXT_NUM; + *cmd++ = NIC_FILTER_MDEF1; + /* enable filter for traffic from network and host */ + cmd32 = NIC_FILTER_MDEF_BIT(NIC_FILTER_MDEF_EXT_NET_EN_OFFSET) + | NIC_FILTER_MDEF_BIT(NIC_FILTER_MDEF_EXT_HOST_EN_OFFSET); + for (i = 0; i < sizeof(cmd32); i++) { + *cmd++ = (cmd32 >> (24 - 8 * i)) & 0xFF; + } + /* enable ARP and ND */ + cmd32 = NIC_FILTER_MDEF_BIT(NIC_FILTER_MDEF_ARP_REQ_OR_OFFSET) + | NIC_FILTER_MDEF_BIT(NIC_FILTER_MDEF_ARP_RES_OR_OFFSET) + | NIC_FILTER_MDEF_BIT(NIC_FILTER_MDEF_NBG_OR_OFFSET); + for (i = 0; i < sizeof(cmd32); i++) { + *cmd++ = (cmd32 >> (24 - 8 * i)) & 0xFF; + } + rc = i2c_smbus_write_block_data(dev->on_file, NIC_WRITE_FILTER_CMD, + cmd - buf, buf); + if (rc < 0) { + rc = errno; + LOG_ERR(rc, "Failed to set ARP and ND filter to MDEF 1"); + return -rc; + } + + /* make filter 0, matching MAC, to be mng only */ + cmd = buf; + *cmd++ = NIC_FILTER_MNG_ONLY_NUM; + cmd32 = NIC_FILTER_MNG_ONLY_FILTER0; + for (i = 0; i < sizeof(cmd32); i++) { + *cmd++ = (cmd32 >> (24 - 8 * i)) & 0xFF; + } + rc = i2c_smbus_write_block_data(dev->on_file, NIC_WRITE_FILTER_CMD, + cmd - buf, buf); + if (rc < 0) { + rc = errno; + LOG_ERR(rc, "Failed to enabled management only filter"); + return -rc; + } + + return 0; +} + +int oob_nic_start(oob_nic *dev, const uint8_t mac[6]) { + int rc; + uint8_t cmd; + + /* force the link up, no matter what the status of the main link */ + rc = oob_nic_set_force_up(dev, 1); + if (rc != 0) { + return rc; + } + + oob_nic_setup_filters(dev, mac); + + /* first byte is the control */ + cmd = NIC_WRITE_RECV_ENABLE_EN + | NIC_WRITE_RECV_ENABLE_STA + | NIC_WRITE_RECV_ENABLE_NM_UNSUPP /* TODO, to support ALERT */ + | NIC_WRITE_RECV_ENABLE_RESERVED; + + rc = i2c_smbus_write_block_data(dev->on_file, NIC_WRITE_RECV_ENABLE_CMD, + 1, &cmd); + if (rc < 0) { + rc = errno; + LOG_ERR(rc, "Failed to start receive function"); + return -rc; + } + LOG_DBG("Started receive function"); + return 0; +} + +int oob_nic_stop(oob_nic *dev) { + int rc; + uint8_t ctrl; + /* don't set any enable bits, which turns off the receive func */ + ctrl = NIC_WRITE_RECV_ENABLE_RESERVED; + rc = i2c_smbus_write_block_data(dev->on_file, NIC_WRITE_RECV_ENABLE_CMD, + 1, &ctrl); + if (rc < 0) { + rc = errno; + LOG_ERR(rc, "Failed to stop receive function"); + return -rc; + } + LOG_DBG("Stopped receive function"); + return 0; +} diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/nic.h b/meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/nic.h new file mode 100644 index 0000000..1ac7ff8 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/nic.h @@ -0,0 +1,44 @@ +/* + * Copyright 2014-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 NIC_H +#define NIC_H + +#include <stdint.h> + +#include "nic_defs.h" + +typedef struct oob_nic_t oob_nic; + +oob_nic* oob_nic_open(int bus, uint8_t addr); +void oob_nic_close(oob_nic* dev); + +/* MAC */ +int oob_nic_get_mac(oob_nic *dev, uint8_t mac[6]); + +/* Status */ +typedef struct oob_nic_status_t oob_nic_status; +int oob_nic_get_status(oob_nic *dev, oob_nic_status *status); + +int oob_nic_start(oob_nic *dev, const uint8_t mac[6]); +int oob_nic_stop(oob_nic *dev); + +int oob_nic_send(oob_nic *dev, const uint8_t *data, int len); + +int oob_nic_receive(oob_nic *dev, uint8_t *buf, int len); + +#endif diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/nic_defs.h b/meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/nic_defs.h new file mode 100644 index 0000000..1ae8721 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/nic_defs.h @@ -0,0 +1,143 @@ +/* + * Copyright 2014-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 NIC_DEFS_H +#define NIC_DEFS_H + +#include <stdint.h> + +#define OOB_NIC_PKT_FRAGMENT_SIZE 240 +#define NIC_PKT_SIZE_MAX 1536 + +/** Get System MAC Address */ +#define NIC_READ_MAC_CMD 0xD4 +#define NIC_READ_MAC_RES_OPT 0xD4 +#define NIC_READ_MAC_RES_LEN 7 + +/** Read Status */ +#define NIC_READ_STATUS_CMD 0xDE +#define NIC_READ_STATUS_RES_OPT 0xDD +#define NIC_READ_STATUS_RES_LEN 3 + +struct oob_nic_status_t { + uint8_t ons_byte1; + uint8_t ons_byte2; +}; + +#define NIC_STATUS_D1_POWER_DR 0x00 +#define NIC_STATUS_D1_POWER_D0U 0x01 +#define NIC_STATUS_D1_POWER_D0 0x10 +#define NIC_STATUS_D1_POWER_D3 0x11 +#define NIC_STATUS_D1_PORT_MSB (0x1 << 2) +#define NIC_STATUS_D1_INIT (0x1 << 3) +#define NIC_STATUS_D1_FORCE_UP (0x1 << 4) +#define NIC_STATUS_D1_LINK (0x1 << 5) +#define NIC_STATUS_D1_TCO_CMD_ABORT (0x1 << 6) +#define NIC_STATUS_D1_PORT_LSB (0x1 << 7) + +#define NIC_STATUS_D2_ICR (0x1 << 1) +#define NIC_STATUS_D2_IPI (0x1 << 2) +#define NIC_STATUS_D2_DRV_VALID (0x1 << 3) + +/** Receive TCO Packet */ +#define NIC_READ_PKT_CMD 0xC0 +#define NIC_READ_PKT_RES_FIRST_OPT 0x90 +#define NIC_READ_PKT_RES_MIDDLE_OPT 0x10 +#define NIC_READ_PKT_RES_LAST_OPT 0x50 +#define NIC_READ_PKT_RES_LAST_LEN 17 + +/** Transmit Packet */ +#define NIC_WRITE_PKT_SINGLE_CMD 0xC4 +#define NIC_WRITE_PKT_FIRST_CMD 0x84 +#define NIC_WRITE_PKT_MIDDLE_CMD 0x04 +#define NIC_WRITE_PKT_LAST_CMD 0x44 + +/** Management Control */ +#define NIC_WRITE_MNG_CTRL_CMD 0xC1 + +#define NIC_MNG_CTRL_KEEP_LINK_UP_NUM 0x00 +#define NIC_MNG_CTRL_KEEP_LINK_UP_ENABLE 0x01 +#define NIC_MNG_CTRL_KEEP_LINK_UP_DISABLE 0x00 + +/** Update MNG RCV Filter Parameters */ +#define NIC_WRITE_FILTER_CMD 0xCC + +#define NIC_FILTER_MAC_NUM 0x66 +#define NIC_FILTER_MAC_PAIR0 0 +#define NIC_FILTER_MAC_PAIR1 1 +#define NIC_FILTER_MAC_PAIR2 2 +#define NIC_FILTER_MAC_PAIR3 3 + +#define NIC_FILTER_MNG_ONLY_NUM 0xF +#define NIC_FILTER_MNG_ONLY_FILTER0 (0x1) +#define NIC_FILTER_MNG_ONLY_FILTER1 (0x1 << 1) +#define NIC_FILTER_MNG_ONLY_FILTER2 (0x1 << 2) +#define NIC_FILTER_MNG_ONLY_FILTER3 (0x1 << 3) +#define NIC_FILTER_MNG_ONLY_FILTER4 (0x1 << 4) + +#define NIC_FILTER_DECISION_EXT_NUM 0x68 +#define NIC_FILTER_MDEF0 0 /* index 0 */ +#define NIC_FILTER_MDEF1 1 /* index 1 */ +#define NIC_FILTER_MDEF2 2 /* index 2 */ +#define NIC_FILTER_MDEF3 3 /* index 3 */ +#define NIC_FILTER_MDEF4 4 /* index 4 */ +#define NIC_FILTER_MDEF5 5 /* index 5 */ +#define NIC_FILTER_MDEF6 6 /* index 6 */ +#define NIC_FILTER_MDEF7 7 /* index 7 */ + +#define NIC_FILTER_MDEF_MAC_AND_OFFSET 0 +#define NIC_FILTER_MDEF_BCAST_AND_OFFSET 4 +#define NIC_FILTER_MDEF_VLAN_AND_OFFSET 5 +#define NIC_FILTER_MDEF_IPV4_AND_OFFSET 13 +#define NIC_FILTER_MDEF_IPV6_AND_OFFSET 17 +#define NIC_FILTER_MDEF_MAC_OR_OFFSET 21 +#define NIC_FILTER_MDEF_BCAST_OR_OFFSET 25 +#define NIC_FILTER_MDEF_MCAST_AND_OFFSET 26 +#define NIC_FILTER_MDEF_ARP_REQ_OR_OFFSET 27 +#define NIC_FILTER_MDEF_ARP_RES_OR_OFFSET 28 +#define NIC_FILTER_MDEF_NBG_OR_OFFSET 29 +#define NIC_FILTER_MDEF_PORT298_OR_OFFSET 30 +#define NIC_FILTER_MDEF_PORT26F_OR_OFFSET 31 + +#define NIC_FILTER_MDEF_EXT_ETHTYPE_AND_OFFSET 0 +#define NIC_FILTER_MDEF_EXT_ETHTYPE_OR_OFFSET 8 +#define NIC_FILTER_MDEF_EXT_FLEX_PORT_OR_OFFSET 16 +#define NIC_FILTER_MDEF_EXT_FLEX_TCO_OR_OFFSET 24 +#define NIC_FILTER_MDEF_EXT_NCSI_DISABLE_OFFSET 28 +#define NIC_FILTER_MDEF_EXT_FLOW_CONTROL_DISCARD_OFFSET 29 +#define NIC_FILTER_MDEF_EXT_NET_EN_OFFSET 30 +#define NIC_FILTER_MDEF_EXT_HOST_EN_OFFSET 31 + +#define NIC_FILTER_MDEF_BIT(offset) ((0x1) << (offset)) +#define NIC_FILTER_MDEF_BIT_VAL(offset, val) ((0x1) << ((offset) + (val))) + +/** Receive Enable */ +#define NIC_WRITE_RECV_ENABLE_CMD 0xCA +#define NIC_WRITE_RECV_ENABLE_LEN_MAX 14 + +#define NIC_WRITE_RECV_ENABLE_EN 0x1 +#define NIC_WRITE_RECV_ENABLE_ALL (0x1 << 1) +#define NIC_WRITE_RECV_ENABLE_STA (0x1 << 2) +#define NIC_WRITE_RECV_ENABLE_ARP_RES (0x1 << 3) +#define NIC_WRITE_RECV_ENABLE_NM_ALERT (0x00 << 4) +#define NIC_WRITE_RECV_ENABLE_NM_ASYNC (0x01 << 4) +#define NIC_WRITE_RECV_ENABLE_NM_DIRECT (0x02 << 4) +#define NIC_WRITE_RECV_ENABLE_NM_UNSUPP (0x03 << 4) +#define NIC_WRITE_RECV_ENABLE_RESERVED (0x1 << 6) +#define NIC_WRITE_RECV_ENABLE_CBDM (0x1 << 7) + +#endif diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic_0.1.bb b/meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic_0.1.bb new file mode 100644 index 0000000..30f167f --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic_0.1.bb @@ -0,0 +1,44 @@ +# Copyright 2014-present Facebook. All Rights Reserved. +# +# This program file 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; version 2 of the License. +# +# 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 in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA + +SUMMARY = "OOB Shared NIC driver" +DESCRIPTION = "The shared-nic driver" +SECTION = "base" +PR = "r2" +LICENSE = "GPLv2" +LIC_FILES_CHKSUM = "file://main.c;beginline=4;endline=16;md5=da35978751a9d71b73679307c4d296ec" + +SRC_URI = "file://src \ + " + +S = "${WORKDIR}/src" + +DEPENDS += "fbutils libwedge-eeprom" + +RDEPENDS_${PN} += "libwedge-eeprom" + +do_install() { + install -d ${D}${sbindir} + install -m 755 oob-nic ${D}${sbindir}/oob-nic + install -m 755 i2craw ${D}${sbindir}/i2craw + install -d ${D}${sysconfdir}/init.d + install -d ${D}${sysconfdir}/rcS.d + install -m 755 etc/oob-nic.sh ${D}${sysconfdir}/init.d/oob-nic.sh + update-rc.d -r ${D} oob-nic.sh start 80 S . +} + +FILES_${PN} = " ${sbindir} ${sysconfdir} " diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/rest-api/files/plat_tree.py b/meta-facebook/meta-yosemite/recipes-yosemite/rest-api/files/plat_tree.py new file mode 100644 index 0000000..b93e98e --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/rest-api/files/plat_tree.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python +# +# Copyright 2014-present Facebook. All Rights Reserved. +# +# This program file 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; version 2 of the License. +# +# 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 in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +# + +from ctypes import * +import json +import ssl +import socket +import os +from node_api import get_node_api +from node_spb import get_node_spb +from node_bmc import get_node_bmc +from node_server import get_node_server +from node_fruid import get_node_fruid +from node_sensors import get_node_sensors +from node_config import get_node_config +from tree import tree +from pal import * + +def populate_server_node(num): + prsnt = pal_is_server_prsnt(num) + if prsnt == None or prsnt == 0: + return None + + r_server = tree("server" + repr(num), data = get_node_server(num)) + + r_fruid = tree("fruid", data = get_node_fruid("slot" + repr(num))) + + r_sensors = tree("sensors", data = get_node_sensors("slot" + repr(num))) + + r_config = tree("config", data = get_node_config("slot" + repr(num))) + + r_server.addChildren([r_fruid, r_sensors, r_config]) + + return r_server + +# Initialize Platform specific Resource Tree +def init_plat_tree(): + + # Create /api end point as root node + r_api = tree("api", data = get_node_api()) + + # Add /api/spb to represent side plane board + r_spb = tree("spb", data = get_node_spb()) + r_api.addChild(r_spb) + + # Add servers /api/server[1-max] + num = pal_get_num_slots() + for i in range(1, num+1): + r_server = populate_server_node(i) + if r_server: + r_api.addChild(r_server) + + # TODO: Need to add /api/nic to represent NIC Mezz Card + + # Add /api/spb/fruid end point + r_temp = tree("fruid", data = get_node_fruid("spb")) + r_spb.addChild(r_temp) + + # /api/spb/bmc end point + r_temp = tree("bmc", data = get_node_bmc()) + r_spb.addChild(r_temp) + + # /api/spb/sensors end point + r_temp = tree("sensors", data = get_node_sensors("spb")) + r_spb.addChild(r_temp) + + return r_api diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/rest-api/files/setup-rest-api.sh b/meta-facebook/meta-yosemite/recipes-yosemite/rest-api/files/setup-rest-api.sh new file mode 100644 index 0000000..bdd79b6 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/rest-api/files/setup-rest-api.sh @@ -0,0 +1,32 @@ +#!/bin/sh +# +# Copyright 2014-present Facebook. All Rights Reserved. +# +# This program file 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; version 2 of the License. +# +# 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 in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +# + +### BEGIN INIT INFO +# Provides: setup-rest-api +# Required-Start: +# Required-Stop: +# Default-Start: S +# Default-Stop: +# Short-Description: Set REST API handler +### END INIT INFO + +echo -n "Setup REST API handler... " +/usr/local/bin/rest.py > /tmp/rest.log 2>&1 & +echo "done." diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/rest-api/rest-api_0.2.bbappend b/meta-facebook/meta-yosemite/recipes-yosemite/rest-api/rest-api_0.2.bbappend new file mode 100644 index 0000000..ce33bba --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/rest-api/rest-api_0.2.bbappend @@ -0,0 +1,62 @@ +# Copyright 2015-present Facebook. All Rights Reserved. +# +# This program file 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; version 2 of the License. +# +# 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 in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +SUMMARY = "Rest API Daemon" +DESCRIPTION = "Daemon to handle RESTful interface." +SECTION = "base" +PR = "r1" +LICENSE = "GPLv2" +LIC_FILES_CHKSUM = "file://rest.py;beginline=5;endline=18;md5=0b1ee7d6f844d472fa306b2fee2167e0" + +DEPENDS_append = " update-rc.d-native" + +S = "${WORKDIR}" + +FILESEXTRAPATHS_prepend := "${THISDIR}/files:" +SRC_URI += "file://setup-rest-api.sh \ + file://plat_tree.py \ + file://node_api.py \ + file://node_spb.py \ + file://node_bmc.py \ + file://node_server.py \ + file://node_fruid.py \ + file://node_sensors.py \ + file://node_config.py \ + " + +binfiles += "setup-rest-api.sh plat_tree.py node_api.py node_spb.py node_bmc.py node_server.py node_fruid.py node_sensors.py node_config.py" + +do_install() { + dst="${D}/usr/local/fbpackages/${pkgdir}" + bin="${D}/usr/local/bin" + install -d $dst + install -d $bin + for f in ${binfiles}; do + install -m 755 $f ${dst}/$f + ln -snf ../fbpackages/${pkgdir}/$f ${bin}/$f + done + for f in ${otherfiles}; do + install -m 644 $f ${dst}/$f + done + install -d ${D}${sysconfdir}/init.d + install -d ${D}${sysconfdir}/rcS.d + install -m 755 setup-rest-api.sh ${D}${sysconfdir}/init.d/setup-rest-api.sh + update-rc.d -r ${D} setup-rest-api.sh start 95 2 3 4 5 . +} + +FBPACKAGEDIR = "${prefix}/local/fbpackages" + +FILES_${PN} = "${FBPACKAGEDIR}/rest-api ${prefix}/local/bin ${sysconfdir} " diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/sensor-mon/files/setup-sensord.sh b/meta-facebook/meta-yosemite/recipes-yosemite/sensor-mon/files/setup-sensord.sh new file mode 100644 index 0000000..3f4b38e --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/sensor-mon/files/setup-sensord.sh @@ -0,0 +1,35 @@ +#!/bin/sh +# +# Copyright 2015-present Facebook. All Rights Reserved. +# +# This program file 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; version 2 of the License. +# +# 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 in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +# + +### BEGIN INIT INFO +# Provides: setup-sensord +# Required-Start: +# Required-Stop: +# Default-Start: S +# Default-Stop: +# Short-Description: Setup sensor monitoring +### END INIT INFO + +. /usr/local/fbpackages/utils/ast-functions + +# TODO: check for the if slot/server is present before starting the daemon +echo -n "Setup sensor monitoring for yosemite... " +/usr/local/bin/sensord slot1 slot2 slot3 slot4 +echo "done." diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/sensor-mon/sensor-mon_0.1.bbappend b/meta-facebook/meta-yosemite/recipes-yosemite/sensor-mon/sensor-mon_0.1.bbappend new file mode 100644 index 0000000..687a599 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/sensor-mon/sensor-mon_0.1.bbappend @@ -0,0 +1,58 @@ +# Copyright 2015-present Facebook. All Rights Reserved. +# +# This program file 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; version 2 of the License. +# +# 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 in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA + +FILESEXTRAPATHS_prepend := "${THISDIR}/files:" + +SRC_URI += "file://setup-sensord.sh \ + " + +S = "${WORKDIR}" + +CFLAGS_prepend = " -DCONFIG_YOSEMITE " + +LDFLAGS_append = " -lyosemite_sensor " + +DEPENDS_append = "libyosemite-sensor update-rc.d-native" + +pkgdir = "sensor-mon" + +do_install() { + dst="${D}/usr/local/fbpackages/${pkgdir}" + bin="${D}/usr/local/bin" + install -d $dst + install -d $bin + for f in ${binfiles}; do + install -m 755 $f ${dst}/$f + ln -snf ../fbpackages/${pkgdir}/$f ${bin}/$f + done + for f in ${otherfiles}; do + install -m 644 $f ${dst}/$f + done + install -d ${D}${sysconfdir}/init.d + install -d ${D}${sysconfdir}/rcS.d + install -m 755 setup-sensord.sh ${D}${sysconfdir}/init.d/setup-sensord.sh + update-rc.d -r ${D} setup-sensord.sh start 91 S . +} + +FBPACKAGEDIR = "${prefix}/local/fbpackages" + +FILES_${PN} = "${FBPACKAGEDIR}/sensor-mon ${prefix}/local/bin ${sysconfdir} " + +# Inhibit complaints about .debug directories for the sensord binary: + +INHIBIT_PACKAGE_DEBUG_SPLIT = "1" +INHIBIT_PACKAGE_STRIP = "1" diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/sensor-setup/files/sensor-setup.sh b/meta-facebook/meta-yosemite/recipes-yosemite/sensor-setup/files/sensor-setup.sh new file mode 100644 index 0000000..a53b316 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/sensor-setup/files/sensor-setup.sh @@ -0,0 +1,54 @@ +#!/bin/sh +# +# Copyright 2014-present Facebook. All Rights Reserved. +# +# This program file 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; version 2 of the License. +# +# 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 in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +# + +### BEGIN INIT INFO +# Provides: sensor-setup +# Required-Start: power-on +# Required-Stop: +# Default-Start: S +# Default-Stop: +# Short-Description: Power on micro-server +### END INIT INFO + +# Eventually, this will be used to configure the various (mostly +# i2c-based) sensors, once we have a kernel version that supports +# doing this more dynamically. +# +# For now, we're using it to install the lm75 and pmbus module so that it +# can detect the fourth temperature sensor, which is located +# on the uServer, which doesn't get power until power-on executes. +# +# Similarly, the pmbus sensor seems to have an easier time of +# detecting the NCP4200 buck converters after poweron. This has not +# been carefully explored. + +modprobe lm75 +modprobe pmbus + +# Enable the ADC inputs; adc0 - adc7 are connected to various voltage sensors + +echo 1 > /sys/devices/platform/ast_adc.0/adc0_en +echo 1 > /sys/devices/platform/ast_adc.0/adc1_en +echo 1 > /sys/devices/platform/ast_adc.0/adc2_en +echo 1 > /sys/devices/platform/ast_adc.0/adc3_en +echo 1 > /sys/devices/platform/ast_adc.0/adc4_en +echo 1 > /sys/devices/platform/ast_adc.0/adc5_en +echo 1 > /sys/devices/platform/ast_adc.0/adc6_en +echo 1 > /sys/devices/platform/ast_adc.0/adc7_en diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/sensor-setup/sensor-setup_0.1.bb b/meta-facebook/meta-yosemite/recipes-yosemite/sensor-setup/sensor-setup_0.1.bb new file mode 100644 index 0000000..1b0f937 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/sensor-setup/sensor-setup_0.1.bb @@ -0,0 +1,38 @@ +# Copyright 2014-present Facebook. All Rights Reserved. +# +# This program file 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; version 2 of the License. +# +# 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 in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +SUMMARY = "Configure the sensors" +DESCRIPTION = "The script configure sensors" +SECTION = "base" +PR = "r1" +LICENSE = "GPLv2" +LIC_FILES_CHKSUM = "file://sensor-setup.sh;beginline=5;endline=18;md5=0b1ee7d6f844d472fa306b2fee2167e0" + +DEPENDS_append = " update-rc.d-native" + +SRC_URI = "file://sensor-setup.sh \ + " + +S = "${WORKDIR}" + +do_install() { + install -d ${D}${sysconfdir}/init.d + install -d ${D}${sysconfdir}/rcS.d + install -m 755 sensor-setup.sh ${D}${sysconfdir}/init.d/sensor-setup.sh + update-rc.d -r ${D} sensor-setup.sh start 90 S . +} + +FILES_${PN} = " ${sysconfdir} " diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/usb-console/files/usbcons.sh b/meta-facebook/meta-yosemite/recipes-yosemite/usb-console/files/usbcons.sh new file mode 100755 index 0000000..de284bb --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/usb-console/files/usbcons.sh @@ -0,0 +1,80 @@ +#! /bin/sh +# +# Copyright 2014-present Facebook. All Rights Reserved. +# +# This program file 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; version 2 of the License. +# +# 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 in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +# + +### BEGIN INIT INFO +# Provides: usbcons +# Required-Start: +# Required-Stop: +# Default-Start: S +# Default-Stop: 0 6 +# Short-Description: Creates a virtual USB serial device and starts a console +# on it. +# +### END INIT INFO + +PATH=/sbin:/bin:/usr/sbin:/usr/bin +NAME=usbcons +PIDFILE=/run/usbcons.pid +DESC="USB Serial Console" + +# source function library +. /etc/init.d/functions + +STOPPER= +ACTION="$1" + +case "$ACTION" in + start) + # Ability to prevent this from starting by editing cmdline in u-boot. + # Keeping this here until I get gadget switching working properly. (t4906522) + if grep "nousbcons" /proc/cmdline > /dev/null 2>&1 + then + echo "USB Console Disabled." + exit 0 + fi + echo -n "Starting $DESC: " + /usr/local/bin/usbmon.sh > /dev/null 2>&1 & + echo "$NAME." + ;; + stop) + echo -n "Stopping $DESC: " + killall usbmon.sh + echo "$NAME." + ;; + restart|force-reload) + echo -n "Restarting $DESC: " + killall usbmon.sh + sleep 1 + /usr/local/bin/usbmon.sh > /dev/null 2>&1 & + echo "$NAME." + ;; + status) + status $DAEMON + exit $? + ;; + *) + N=${0##*/} + N=${N#[SK]??} + echo "Usage: $N {start|stop|status|restart|force-reload}" >&2 + exit 1 + ;; +esac + +exit 0 diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/usb-console/files/usbmon.sh b/meta-facebook/meta-yosemite/recipes-yosemite/usb-console/files/usbmon.sh new file mode 100755 index 0000000..0030775 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/usb-console/files/usbmon.sh @@ -0,0 +1,25 @@ +#!/bin/sh +# +# Copyright 2014-present Facebook. All Rights Reserved. +# +# This program file 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; version 2 of the License. +# +# 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 in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +# + +modprobe g_cdc host_addr=02:00:00:00:00:02 dev_addr=02:00:00:00:00:01 +while true; do + getty /dev/ttyGS0 57600 + sleep 1 +done diff --git a/meta-facebook/meta-yosemite/recipes-yosemite/usb-console/usb-console_0.1.bb b/meta-facebook/meta-yosemite/recipes-yosemite/usb-console/usb-console_0.1.bb new file mode 100644 index 0000000..c934f46 --- /dev/null +++ b/meta-facebook/meta-yosemite/recipes-yosemite/usb-console/usb-console_0.1.bb @@ -0,0 +1,42 @@ +# Copyright 2014-present Facebook. All Rights Reserved. +# +# This program file 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; version 2 of the License. +# +# 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 in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +SUMMARY = "Set up a USB serial console" +DESCRIPTION = "Sets up a USB serial console" +SECTION = "base" +PR = "r1" +LICENSE = "GPLv2" +LIC_FILES_CHKSUM = "file://usbcons.sh;beginline=5;endline=18;md5=0b1ee7d6f844d472fa306b2fee2167e0" + +DEPENDS_append = " update-rc.d-native" + +SRC_URI = "file://usbcons.sh \ + file://usbmon.sh \ + " + +S = "${WORKDIR}" + +do_install() { + install -d ${D}${sysconfdir}/init.d + install -d ${D}${sysconfdir}/rcS.d + install -m 755 usbcons.sh ${D}${sysconfdir}/init.d/usbcons.sh + update-rc.d -r ${D} usbcons.sh start 90 S . + localbindir="${D}/usr/local/bin" + install -d ${localbindir} + install -m 755 usbmon.sh ${localbindir}/usbmon.sh +} + +FILES_${PN} = " ${sysconfdir} /usr/local" |