summaryrefslogtreecommitdiffstats
path: root/meta-facebook
diff options
context:
space:
mode:
Diffstat (limited to 'meta-facebook')
-rw-r--r--meta-facebook/meta-wedge/conf/machine/wedge.conf5
-rw-r--r--meta-facebook/meta-wedge/recipes-core/images/wedge-image.inc6
-rw-r--r--meta-facebook/meta-wedge/recipes-core/init-ifupdown/files/dhcpv6_down27
-rw-r--r--meta-facebook/meta-wedge/recipes-core/init-ifupdown/files/dhcpv6_up28
-rw-r--r--meta-facebook/meta-wedge/recipes-core/init-ifupdown/init-ifupdown_%.bbappend16
-rw-r--r--meta-facebook/meta-wedge/recipes-kernel/linux/linux-aspeed_2.6%.bbappend2
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/bmc-log/bmc-log_0.1.bb50
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/bmc-log/files/Makefile24
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/bmc-log/files/bmc-log-config16
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/bmc-log/files/bmc-log.c559
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/bmc-log/files/bmc-log.h46
-rwxr-xr-xmeta-facebook/meta-wedge/recipes-wedge/bmc-log/files/bmc-log.sh77
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/fan-ctrl/fan-ctrl/setup-fan.sh18
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/fan-ctrl/fan-ctrl_0.1.bbappend64
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/fblibs/files/alert_control/Makefile18
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/fblibs/files/ipmi/Makefile18
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/fblibs/libalert-control_0.1.bb16
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/fblibs/libipmi_0.1.bb16
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/fbutils/files/at93cx6.py318
-rwxr-xr-xmeta-facebook/meta-wedge/recipes-wedge/fbutils/files/at93cx6_util.py223
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/fbutils/files/bcm5396.py19
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/fbutils/files/bcm5396_util.py12
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/fbutils/files/board-utils.sh163
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/fbutils/files/create_vlan_intf2
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/fbutils/files/eth0_mac_fixup.sh24
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/fbutils/files/post_led.sh2
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/fbutils/files/power-on.sh2
-rwxr-xr-xmeta-facebook/meta-wedge/recipes-wedge/fbutils/files/power_led.sh2
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/fbutils/files/reset_usb.sh2
-rwxr-xr-xmeta-facebook/meta-wedge/recipes-wedge/fbutils/files/setup-gpio.sh168
-rwxr-xr-xmeta-facebook/meta-wedge/recipes-wedge/fbutils/files/setup_rov.sh2
-rwxr-xr-xmeta-facebook/meta-wedge/recipes-wedge/fbutils/files/sol.sh11
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/fbutils/files/start_us_monitor.sh73
-rwxr-xr-xmeta-facebook/meta-wedge/recipes-wedge/fbutils/files/us_console.sh2
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/fbutils/files/us_monitor.sh56
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/fbutils/files/wedge_power.sh61
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/fbutils/openbmc-utils_%.bbappend95
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/ipmid/files/Makefile16
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/ipmid/files/setup-ipmid.sh16
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/ipmid/ipmid_0.1.bb15
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/lm_sensors/lmsensors_%.bbappend6
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/Makefile16
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/etc/oob-nic.sh10
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/i2craw.c2
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/intf.c2
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/main.c52
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/nic.c94
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/nic_defs.h18
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic_0.1.bb17
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/po-eeprom/files/Makefile16
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/po-eeprom/po-eeprom_0.1.bb17
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/Makefile34
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/hexfile.py174
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/modbus.c181
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/modbus.h47
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/modbuscmd.c152
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/modbussim.c2
-rwxr-xr-xmeta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/psu-update-delta.py269
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/rackmon-config.py93
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/rackmond.c637
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/rackmond.h46
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/rackmondata.c58
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/setup-rackmond.sh20
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon_0.1.bb33
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/rest-api/files/rest.py88
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/rest-api/files/rest_bmc.py10
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/rest-api/files/rest_modbus.py28
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/rest-api/files/rest_sensors.py4
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/rest-api/files/rest_slotid.py33
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/rest-api/files/setup-rest-api.sh16
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/rest-api/rest-api_0.1.bb19
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/sensor-setup/sensor-setup_0.1.bb15
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/sms-kcsd/sms-kcsd/Makefile16
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/sms-kcsd/sms-kcsd/setup-sms-kcs.sh16
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/sms-kcsd/sms-kcsd_0.1.bb15
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/usb-console/usb-console_0.1.bb15
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/files/lib/Makefile18
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/files/lib/wedge_eeprom.c4
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/files/utils/Makefile16
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/files/utils/weutil.c2
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/libwedge-eeprom_0.1.bb18
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/wedge-eeprom_0.1.bb15
-rw-r--r--meta-facebook/meta-yosemite/conf/bblayers.conf.sample21
-rw-r--r--meta-facebook/meta-yosemite/conf/conf-notes.txt2
-rw-r--r--meta-facebook/meta-yosemite/conf/layer.conf10
-rw-r--r--meta-facebook/meta-yosemite/conf/local.conf.sample140
-rw-r--r--meta-facebook/meta-yosemite/conf/machine/yosemite.conf7
-rw-r--r--meta-facebook/meta-yosemite/recipes-core/busybox/busybox/busybox.cfg18
-rw-r--r--meta-facebook/meta-yosemite/recipes-core/busybox/busybox_%.bbappend5
-rw-r--r--meta-facebook/meta-yosemite/recipes-core/images/yosemite-image.bb1
-rw-r--r--meta-facebook/meta-yosemite/recipes-core/images/yosemite-image.inc82
-rw-r--r--meta-facebook/meta-yosemite/recipes-core/init-ifupdown/files/interfaces11
-rw-r--r--meta-facebook/meta-yosemite/recipes-core/init-ifupdown/init-ifupdown_%.bbappend2
-rw-r--r--meta-facebook/meta-yosemite/recipes-core/sysvinit/sysvinit-inittab_%.bbappend2
-rw-r--r--meta-facebook/meta-yosemite/recipes-kernel/linux/linux-aspeed_2.6%.bbappend5
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/bic-cached/bic-cached_0.1.bb44
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/bic-cached/files/Makefile10
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/bic-cached/files/bic-cached.c133
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/bic-cached/files/setup-bic-cached.sh33
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/consoled/consoled_0.1.bbappend53
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/consoled/files/setup-consoled.sh51
-rwxr-xr-xmeta-facebook/meta-yosemite/recipes-yosemite/fan-ctrl/fan-ctrl/get_fan_speed.sh53
-rwxr-xr-xmeta-facebook/meta-yosemite/recipes-yosemite/fan-ctrl/fan-ctrl/init_pwm.sh64
-rwxr-xr-xmeta-facebook/meta-yosemite/recipes-yosemite/fan-ctrl/fan-ctrl/set_fan_speed.sh79
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/fan-ctrl/fan-ctrl/setup-fan.sh36
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/fan-ctrl/fan-ctrl_0.1.bbappend64
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/bic/Makefile11
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/bic/bic.c466
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/bic/bic.h156
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/pal/Makefile11
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/pal/pal.c1151
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/pal/pal.h98
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/yosemite_common/Makefile11
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/yosemite_common/yosemite_common.c55
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/yosemite_common/yosemite_common.h44
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/yosemite_fruid/Makefile27
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/yosemite_fruid/yosemite_fruid.c86
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/yosemite_fruid/yosemite_fruid.h37
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/yosemite_gpio/Makefile27
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/yosemite_gpio/yosemite_gpio.c116
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/yosemite_gpio/yosemite_gpio.h39
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/yosemite_sensor/Makefile11
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/yosemite_sensor/yosemite_sensor.c778
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/fblibs/files/yosemite_sensor/yosemite_sensor.h133
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/fblibs/libbic_0.1.bb25
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/fblibs/libpal_0.1.bb28
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/fblibs/libyosemite-common_0.1.bb25
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/fblibs/libyosemite-fruid_0.1.bb43
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/fblibs/libyosemite-gpio_0.1.bb43
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/fblibs/libyosemite-sensor_0.1.bb25
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/fbutils/bic-util_0.1.bb21
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/fbutils/fbutils_0.1.bb102
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/COPYING340
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/ast-functions147
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/at93c46.py276
-rwxr-xr-xmeta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/at93c46_util.py194
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/bcm5396.py452
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/bcm5396_util.py260
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/bic-util/Makefile10
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/bic-util/bic-util.c384
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/create_vlan_intf37
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/eth0_mac_fixup.sh41
-rwxr-xr-xmeta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/fcswitcher.sh83
-rwxr-xr-xmeta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/mdio.py124
-rwxr-xr-xmeta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/mount_data0.sh61
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/post_led.sh105
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/power-on.sh99
-rwxr-xr-xmeta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/power_led.sh58
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/power_util.py151
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/rc.early25
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/rc.local26
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/reset_usb.sh55
-rwxr-xr-xmeta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/setup-gpio.sh307
-rwxr-xr-xmeta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/setup_rov.sh99
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/setup_switch.py49
-rwxr-xr-xmeta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/sol-util74
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/src/include/i2c-dev.h364
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/src/include/log.h59
-rwxr-xr-xmeta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/us_console.sh41
-rwxr-xr-xmeta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/watch-fc.sh34
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/wedge_us_mac.sh29
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/yosemite-sensors/Makefile10
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/yosemite-sensors/yosemite-sensors.c405
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/fbutils/files/yosemite_power.sh169
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/fbutils/yosemite-sensors_0.1.bb21
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/front-paneld/files/Makefile10
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/front-paneld/files/front-paneld.c460
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/front-paneld/files/setup-front-paneld.sh16
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/front-paneld/front-paneld_0.1.bb44
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/fruid/fruid_0.1.bbappend24
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/gpiod/files/Makefile26
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/gpiod/files/gpiod.c353
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/gpiod/files/setup-gpiod.sh33
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/gpiod/gpiod_0.1.bb62
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/ipmbd/files/setup-ipmbd.sh104
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/ipmbd/ipmbd_0.1.bbappend27
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/ipmid/files/bic.c78
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/ipmid/files/bic.h29
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/ipmid/files/fruid.c111
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/ipmid/files/sensor.c371
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/ipmid/files/setup-ipmid.sh32
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/ipmid/ipmid_0.2.bbappend46
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/lm_sensors/files/yosemite.conf44
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/lm_sensors/lmsensors_%.bbappend10
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/Makefile29
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/README10
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/etc/oob-nic.sh93
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/hlist.h73
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/i2craw.c245
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/intf.c254
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/intf.h31
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/libnetlink.c717
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/libnetlink.h161
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/ll_map.c225
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/ll_map.h32
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/main.c192
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/nic.c487
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/nic.h44
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic/src/nic_defs.h143
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/oob-nic/oob-nic_0.1.bb44
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/rest-api/files/plat_tree.py84
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/rest-api/files/setup-rest-api.sh32
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/rest-api/rest-api_0.2.bbappend62
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/sensor-mon/files/setup-sensord.sh35
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/sensor-mon/sensor-mon_0.1.bbappend58
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/sensor-setup/files/sensor-setup.sh54
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/sensor-setup/sensor-setup_0.1.bb38
-rwxr-xr-xmeta-facebook/meta-yosemite/recipes-yosemite/usb-console/files/usbcons.sh80
-rwxr-xr-xmeta-facebook/meta-yosemite/recipes-yosemite/usb-console/files/usbmon.sh25
-rw-r--r--meta-facebook/meta-yosemite/recipes-yosemite/usb-console/usb-console_0.1.bb42
210 files changed, 18589 insertions, 299 deletions
diff --git a/meta-facebook/meta-wedge/conf/machine/wedge.conf b/meta-facebook/meta-wedge/conf/machine/wedge.conf
index 69f3a90..3ed8ec1 100644
--- a/meta-facebook/meta-wedge/conf/machine/wedge.conf
+++ b/meta-facebook/meta-wedge/conf/machine/wedge.conf
@@ -5,3 +5,8 @@
UBOOT_MACHINE_wedge = "wedge_config"
require conf/machine/include/ast1250.inc
+
+# configuration for preferred version of packages
+PREFERRED_VERSION_libipmi = "0.1"
+PREFERRED_VERSION_ipmid = "0.1"
+PREFERRED_VERSION_rest-api = "0.1"
diff --git a/meta-facebook/meta-wedge/recipes-core/images/wedge-image.inc b/meta-facebook/meta-wedge/recipes-core/images/wedge-image.inc
index 15a4252..7cd89de 100644
--- a/meta-facebook/meta-wedge/recipes-core/images/wedge-image.inc
+++ b/meta-facebook/meta-wedge/recipes-core/images/wedge-image.inc
@@ -39,9 +39,8 @@ NTP_PKGS = " \
# Include modules in rootfs
IMAGE_INSTALL += " \
kernel-modules \
- u-boot \
u-boot-fw-utils \
- fbutils \
+ openbmc-utils \
fan-ctrl \
rackmon \
watchdog-ctrl \
@@ -49,6 +48,8 @@ IMAGE_INSTALL += " \
sensor-setup \
usb-console \
oob-nic \
+ lldp-util \
+ bmc-log \
lmsensors-sensors \
wedge-eeprom \
sms-kcsd \
@@ -61,6 +62,7 @@ IMAGE_INSTALL += " \
${NTP_PKGS} \
iproute2 \
dhcp-client \
+ spatula \
"
IMAGE_FEATURES += " \
diff --git a/meta-facebook/meta-wedge/recipes-core/init-ifupdown/files/dhcpv6_down b/meta-facebook/meta-wedge/recipes-core/init-ifupdown/files/dhcpv6_down
new file mode 100644
index 0000000..a44deb4
--- /dev/null
+++ b/meta-facebook/meta-wedge/recipes-core/init-ifupdown/files/dhcpv6_down
@@ -0,0 +1,27 @@
+#!/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
+#
+
+pid="/var/run/dhclient6.${IFACE}.pid"
+
+if [ -f "${pid}" ]; then
+ kill -9 `cat ${pid}` 2>/dev/null
+fi
+
+exit 0
diff --git a/meta-facebook/meta-wedge/recipes-core/init-ifupdown/files/dhcpv6_up b/meta-facebook/meta-wedge/recipes-core/init-ifupdown/files/dhcpv6_up
new file mode 100644
index 0000000..6469b9f
--- /dev/null
+++ b/meta-facebook/meta-wedge/recipes-core/init-ifupdown/files/dhcpv6_up
@@ -0,0 +1,28 @@
+#!/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
+#
+
+# only care about 'eth0' and 'oob' intf
+[ "$IFACE" != "eth0" ] && [ "$IFACE" != "oob" ] && exit 0
+
+pid="/var/run/dhclient6.${IFACE}.pid"
+
+dhclient -6 -nw -pf ${pid} ${IFACE}
+
+exit 0
diff --git a/meta-facebook/meta-wedge/recipes-core/init-ifupdown/init-ifupdown_%.bbappend b/meta-facebook/meta-wedge/recipes-core/init-ifupdown/init-ifupdown_%.bbappend
index 7d74521..e715c27 100644
--- a/meta-facebook/meta-wedge/recipes-core/init-ifupdown/init-ifupdown_%.bbappend
+++ b/meta-facebook/meta-wedge/recipes-core/init-ifupdown/init-ifupdown_%.bbappend
@@ -1,2 +1,18 @@
FILESEXTRAPATHS_prepend := "${THISDIR}/files:"
+
+SRC_URI += "file://dhcpv6_up \
+ file://dhcpv6_down \
+ "
+
+do_install_append() {
+ # rules to request dhcpv6
+ install -d ${D}/${sysconfdir}/network/if-up.d
+ install -m 755 ${WORKDIR}/dhcpv6_up ${D}${sysconfdir}/network/if-up.d/dhcpv6_up
+ install -d ${D}/${sysconfdir}/network/if-down.d
+ install -m 755 ${WORKDIR}/dhcpv6_down ${D}${sysconfdir}/network/if-down.d/dhcpv6_down
+}
+
+FILES_${PN} += "${sysconfdir}/network/if-up.d/dhcpv6_up \
+ ${sysconfdir}/network/if-down.d/dhcpv6_down \
+ "
diff --git a/meta-facebook/meta-wedge/recipes-kernel/linux/linux-aspeed_2.6%.bbappend b/meta-facebook/meta-wedge/recipes-kernel/linux/linux-aspeed_2.6%.bbappend
index 6bf04da..3c5b71c 100644
--- a/meta-facebook/meta-wedge/recipes-kernel/linux/linux-aspeed_2.6%.bbappend
+++ b/meta-facebook/meta-wedge/recipes-kernel/linux/linux-aspeed_2.6%.bbappend
@@ -2,4 +2,4 @@ LINUX_VERSION_EXTENSION = "-wedge"
COMPATIBLE_MACHINE = "wedge"
-KERNEL_DEFCONFIG_aspeed = "wedge_defconfig"
+KERNEL_CONFIG_COMMAND = "oe_runmake wedge_defconfig && oe_runmake oldconfig"
diff --git a/meta-facebook/meta-wedge/recipes-wedge/bmc-log/bmc-log_0.1.bb b/meta-facebook/meta-wedge/recipes-wedge/bmc-log/bmc-log_0.1.bb
new file mode 100644
index 0000000..2788a36
--- /dev/null
+++ b/meta-facebook/meta-wedge/recipes-wedge/bmc-log/bmc-log_0.1.bb
@@ -0,0 +1,50 @@
+# 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 = "Logging Utility"
+DESCRIPTION = "Util for logging"
+SECTION = "base"
+PR = "r1"
+LICENSE = "GPLv2"
+LIC_FILES_CHKSUM = "file://bmc-log.c;beginline=4;endline=16;md5=da35978751a9d71b73679307c4d296ec"
+
+SRC_URI = "file://bmc-log.c \
+ file://bmc-log.h \
+ file://Makefile \
+ file://bmc-log-config \
+ file://bmc-log.sh \
+ "
+
+S = "${WORKDIR}"
+
+do_install() {
+ install -d ${D}${sbindir}
+ install -m 755 bmc-log ${D}${sbindir}/bmc-log
+ install -d ${D}${sysconfdir}/default
+ install -m 755 bmc-log-config ${D}${sysconfdir}/default/bmc-log
+ install -d ${D}${sysconfdir}/init.d
+ install -m 755 bmc-log.sh ${D}${sysconfdir}/init.d/bmc-log.sh
+ update-rc.d -r ${D} bmc-log.sh start 92 S .
+}
+
+FILES_${PN} = "${sbindir} ${sysconfdir} "
+
+# Inhibit complaints about .debug directories
+
+INHIBIT_PACKAGE_DEBUG_SPLIT = "1"
+INHIBIT_PACKAGE_STRIP = "1"
diff --git a/meta-facebook/meta-wedge/recipes-wedge/bmc-log/files/Makefile b/meta-facebook/meta-wedge/recipes-wedge/bmc-log/files/Makefile
new file mode 100644
index 0000000..5004556
--- /dev/null
+++ b/meta-facebook/meta-wedge/recipes-wedge/bmc-log/files/Makefile
@@ -0,0 +1,24 @@
+# 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
+
+LIBS = -lutil
+
+all:
+ ${CC} ${CFLAGS} -o bmc-log bmc-log.c ${LIBS}
+
+clean:
+ rm -rf *.o bmc-log
diff --git a/meta-facebook/meta-wedge/recipes-wedge/bmc-log/files/bmc-log-config b/meta-facebook/meta-wedge/recipes-wedge/bmc-log/files/bmc-log-config
new file mode 100644
index 0000000..529adf2
--- /dev/null
+++ b/meta-facebook/meta-wedge/recipes-wedge/bmc-log/files/bmc-log-config
@@ -0,0 +1,16 @@
+# Configuration used by bmc-log script
+
+#Serial port connected to the micro-server
+US_TTY=""
+
+#IP version of the log collecting server
+LOG_SERVER_IP_VERSION=""
+
+#Host name of the log collecting server
+LOG_SERVER_NAME=""
+
+#Port number of the log collecting server
+LOG_SERVER_PORT=""
+
+#Baud rate to set for the US_TTY
+TTY_BAUD_RATE=""
diff --git a/meta-facebook/meta-wedge/recipes-wedge/bmc-log/files/bmc-log.c b/meta-facebook/meta-wedge/recipes-wedge/bmc-log/files/bmc-log.c
new file mode 100644
index 0000000..078db7b
--- /dev/null
+++ b/meta-facebook/meta-wedge/recipes-wedge/bmc-log/files/bmc-log.c
@@ -0,0 +1,559 @@
+/*
+ * 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 <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <string.h>
+#include <linux/serial.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <time.h>
+#include <arpa/inet.h>
+#include <sys/stat.h>
+#include <pty.h>
+#include <errno.h>
+#include <signal.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include "bmc-log.h"
+
+FILE *error_file = NULL;
+
+bool kill_received = false; // To check if a killing interrupt is received
+
+speed_t baud_rate = B57600; // Default baud rate - change if user inputs a different one
+
+int fd_tty = -1, fd_soc = -1;
+
+/* Hostname and port of the server */
+char *hostname;
+int port;
+
+struct termios orig_tty_state;
+
+char *get_time()
+{
+ static char mytime[TIME_FORMAT_SIZE];
+ memset(mytime, 0, sizeof(mytime));
+ time_t this_time;
+ struct tm *this_tm;
+ this_time = time(NULL);
+ this_tm = localtime(&this_time);
+
+ snprintf(mytime, sizeof(mytime), "%04d-%02d-%02d %02d:%02d:%02d",
+ 1900 + this_tm->tm_year, this_tm->tm_mon + 1,
+ this_tm->tm_mday, this_tm->tm_hour,
+ this_tm->tm_min, this_tm->tm_sec);
+ return mytime;
+}
+
+void errlog(char *frmt, ...)
+{
+ va_list args;
+ va_start(args, frmt);
+ struct stat st;
+
+ char *time_now = get_time();
+
+ fprintf(stderr, "[%s] ", time_now);
+ vfprintf(stderr, frmt, args);
+
+ if (error_file) {
+ stat(error_log_file, &st);
+ if (st.st_size >= MAX_LOG_FILE_SIZE) {
+ truncate(error_log_file, 0);
+ }
+ fprintf(error_file, "[%s] ", time_now);
+ vfprintf(error_file, frmt, args);
+ fflush(error_file);
+ }
+}
+
+/* Get the address info of netcons server */
+struct addrinfo *get_addr_info(int ip_version)
+{
+ int ip_family = (ip_version == IPV4) ? AF_INET : AF_INET6;
+ struct addrinfo hints;
+
+ struct addrinfo *result;
+ result = malloc(sizeof(*result));
+ if (!result) {
+ errlog("Error: Unable to allocate memory - %m\n");
+ return NULL;
+ }
+
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_family = ip_family; /* Allow IPv4 or IPv6 */
+ hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */
+ hints.ai_flags = AI_PASSIVE; /* For wildcard IP address */
+ hints.ai_protocol = 0; /* Any protocol */
+ hints.ai_canonname = NULL;
+ hints.ai_addr = NULL;
+ hints.ai_next = NULL;
+
+ if (getaddrinfo(hostname, NULL, &hints, &result)) {
+ errlog("Error: getaddrinfo failed - %m\n");
+ return NULL;
+ }
+
+ return result;
+}
+
+/* Prepare Ipv4 Socket */
+bool prepare_sock(struct sockaddr_in * tgt_addr)
+{
+ struct addrinfo *addr_info;
+ memset(tgt_addr, 0, sizeof(*tgt_addr));
+
+ if ((addr_info = get_addr_info(IPV4)) == NULL) {
+ errlog("Error: Unable to get address info\n");
+ return false;
+ }
+
+ tgt_addr->sin_addr = ((struct sockaddr_in *)addr_info->ai_addr)->sin_addr;
+ tgt_addr->sin_port = htons(port);
+ tgt_addr->sin_family = AF_INET;
+
+ return true;
+}
+
+/* Prepare Ipv6 Socket */
+bool prepare_sock6(struct sockaddr_in6 * tgt_addr6)
+{
+ struct addrinfo *addr_info;
+ memset(tgt_addr6, 0, sizeof(*tgt_addr6));
+
+ if ((addr_info = get_addr_info(IPV6)) == NULL) {
+ errlog("Erorr: Unable to get address info\n");
+ return false;
+ }
+
+ tgt_addr6->sin6_addr = ((struct sockaddr_in6 *)addr_info->ai_addr)->sin6_addr;
+ tgt_addr6->sin6_port = htons(port);
+ tgt_addr6->sin6_family = AF_INET6;
+
+ return true;
+}
+
+/* Set TTY to raw mode */
+bool set_tty(int fd)
+{
+ struct termios tty_state;
+
+ if (tcgetattr(fd, &tty_state) < 0) {
+ return false;
+ }
+
+ if (tcgetattr(fd, &orig_tty_state) < 0) // Save original settings
+ {
+ return false;
+ }
+
+ if (cfsetspeed(&tty_state, baud_rate) == -1) {
+ errlog("Error: Baud Rate not set - %m\n");
+ return false;
+ }
+
+ tty_state.c_lflag &= ~(ICANON | IEXTEN | ISIG | ECHO);
+ tty_state.c_iflag &= ~(IGNCR | ICRNL | INPCK | ISTRIP | IXON | BRKINT);
+ tty_state.c_iflag |= (IGNCR | ICRNL);
+ tty_state.c_oflag &= ~OPOST;
+ tty_state.c_cflag |= CS8;
+
+ tty_state.c_cc[VMIN] = 1;
+ tty_state.c_cc[VTIME] = 0;
+
+ if (tcsetattr(fd, TCSAFLUSH, &tty_state) < 0) {
+ return false;
+ }
+
+ return true;
+}
+
+/* Create a pseudo terminal for other process to use (as this program is using up the actual TTY) */
+int create_pseudo_tty()
+{
+ int amaster, aslave;
+ int flags;
+
+ if (openpty(&amaster, &aslave, NULL, NULL, NULL) == -1) {
+ errlog("Error: Openpty failed - %m\n");
+ return -1;
+ }
+
+ /* Set to non blocking mode */
+ flags = fcntl(amaster, F_GETFL);
+ flags |= O_NONBLOCK;
+ fcntl(amaster, F_SETFL, flags);
+
+ FILE *pseudo_save_file = fopen(pseudo_tty_save_file, "w+");
+ if (!pseudo_save_file) {
+ errlog("Error: Unable to open the pseudo info file - %m\n");
+ return -1;
+ }
+ /* Save the name of the created pseudo tty in a text file for other processes to use */
+ if (fprintf(pseudo_save_file, "%s\n", ttyname(aslave)) == -1) {
+ errlog("Error writing to the pseudo info file\n");
+ fclose(pseudo_save_file);
+ return -1;
+ }
+ fclose(pseudo_save_file);
+
+ if (set_tty(aslave) == -1) {
+ errlog("Error: Slave TTY not set properly\n");
+ return -1;
+ }
+
+ return amaster;
+}
+
+/* Prepare logs from the read_buf and send them to the server */
+bool prepare_log_send(char *read_buf, int max_read, int fd_socket)
+{
+ size_t buff_index = 0; // Index for the read_buf string
+
+ static char line[LINE_LEN] = { 0 };
+ static size_t line_index = 0; // Index for the line string
+
+ char msg[MSG_LEN] = { 0 }; // Message to be sent to the server
+
+ /* Kernel Version */
+ static char kernel_version[KERNEL_VERSION_LEN] = "dummy_kernel";
+ static int kernel_search_pos = 0;
+
+ while (buff_index < max_read && read_buf[buff_index] != '\0') {
+ if (read_buf[buff_index] == 'L') // Check if there is a possibility of new kernel version
+ {
+ kernel_search_pos = line_index;
+ }
+
+ /* Send the log when a line is read */
+ if (read_buf[buff_index] == '\n') {
+ if (kernel_search_pos > 0) {
+ if (strncmp(line + kernel_search_pos, "Linux version ", kernel_search_len) == 0) {
+ sscanf(line + kernel_search_pos + kernel_search_len, "%s", kernel_version);
+ }
+ kernel_search_pos = 0;
+ }
+
+ /* Prepare the message */
+ memset(msg, 0, sizeof(msg));
+ if (snprintf(msg, sizeof(msg), "%s %s %s %s", "kernel:", kernel_version, "- msg", line) < 0) {
+ errlog("Error copying the message - %m\n");
+ return false;
+ }
+
+ /* Send message to the server */
+ if (write(fd_socket, msg, strlen(msg)) < 0) {
+ errlog("Error: Write to socket failed - %m\n");
+ return false;
+ }
+
+ /* Reset the line buffer */
+ line_index = 0;
+ memset(line, 0, sizeof(line));
+
+ buff_index++;
+ continue;
+ }
+
+ /* If line is too big, send only the first few bytes and discard others. */
+ if (line_index >= sizeof(line)) {
+ line[line_index - 1] = 0;
+ buff_index++;
+ continue;
+ }
+
+ line[line_index++] = read_buf[buff_index++];
+ }
+
+ return true;
+}
+
+/* Read text from the TTY and send to send as logs */
+bool read_send(int fd_tty, int fd_socket)
+{
+ char read_buf[LINE_LEN] = { 0 }; // Buffer to be read into.
+ int read_size = 0;
+ fd_set readset;
+ int sel;
+ int fdmax;
+
+ int pseudo_tty = create_pseudo_tty();
+
+ if (pseudo_tty == -1) {
+ errlog("Error: Cannot create a psuedo terminal\n");
+ return false;
+ }
+
+ fdmax = MAX(fd_tty, pseudo_tty);
+
+ while (!kill_received) {
+ do {
+ FD_ZERO(&readset);
+ FD_SET(fd_tty, &readset);
+ FD_SET(pseudo_tty, &readset);
+
+ sel = select(fdmax + 1, &readset, NULL, NULL, NULL);
+ }
+ while (sel == -1 && errno == EINTR && !kill_received);
+
+ memset(read_buf, 0, sizeof(read_buf));
+ if (FD_ISSET(fd_tty, &readset)) {
+ read_size = read(fd_tty, read_buf, sizeof(read_buf) - 1);
+
+ if (read_size == 0) {
+ continue;
+ }
+ if (read_size < 0) {
+ if (errno == EAGAIN) {
+ continue;
+ }
+ errlog("Error: Read from tty failed - %m\n");
+ return false;
+ }
+
+ /* Send the read data to the pseudo terminal */
+ if (write(pseudo_tty, read_buf, read_size) < 0) {
+ if (errno == EAGAIN) // Output buffer full - flush it.
+ {
+ tcflush(pseudo_tty, TCIOFLUSH);
+ continue;
+ }
+
+ errlog("Error: Write to pseudo tty failed - %m\n");
+ return false;
+ }
+
+ /* Prepare log message and send to the server */
+ if (!prepare_log_send(read_buf, sizeof(read_buf), fd_socket)) {
+ errlog("Error: Sending log failed - %m\n");
+ return false;
+ }
+ }
+ /*if (FD_ISSET(fd_tty, &readset)) */
+ if (kill_received) {
+ break;
+ }
+
+ /* Check if there is an data in the pseudo terminal's buffer */
+ if (FD_ISSET(pseudo_tty, &readset)) {
+ read_size = read(pseudo_tty, read_buf, sizeof(read_buf) - 1);
+
+ if (read_size == 0) {
+ continue;
+ }
+ if (read_size < 0) {
+ if (errno == EAGAIN) {
+ continue;
+ }
+ errlog("Error: Read from pseudo tty failed - %m\n");
+ return false;
+ }
+
+ if (write(fd_tty, read_buf, read_size) < 0) {
+ if (errno == EAGAIN) // Output buffer full - flush it.
+ {
+ tcflush(fd_tty, TCIOFLUSH);
+ continue;
+ }
+
+ errlog("Error: Write to tty failed - %m\n");
+ return false;
+ }
+ } /*if (FD_ISSET(pseudo_tty,&readset)) */
+ } /*while (!kill_received) */
+
+ return true;
+}
+
+void cleanup()
+{
+ remove(pseudo_tty_save_file);
+ tcsetattr(fd_tty, TCSAFLUSH, &orig_tty_state); //Restore original settings
+ close(fd_tty);
+ close(fd_soc);
+ fclose(error_file);
+}
+
+void sig_kill(int signum)
+{
+ kill_received = true;
+}
+
+void register_kill()
+{
+ struct sigaction sigact;
+ sigset_t sigset;
+
+ sigemptyset(&sigset);
+ memset(&sigact, 0, sizeof sigact);
+ sigact.sa_handler = sig_kill;
+ sigact.sa_mask = sigset;
+
+ sigaction(SIGHUP, &sigact, NULL);
+ sigaction(SIGINT, &sigact, NULL);
+ sigaction(SIGQUIT, &sigact, NULL);
+ sigaction(SIGPIPE, &sigact, NULL);
+ sigaction(SIGTERM, &sigact, NULL);
+ sigaction(SIGKILL, &sigact, NULL);
+ sigaction(SIGABRT, &sigact, NULL);
+}
+
+void usage(char *prog_name)
+{
+ printf("Usage:\n");
+ printf("\t%s TTY ip_version(4 or 6) hostname port [baud rate (like 57600)]\n", prog_name);
+ printf("\t%s -h : For this help\n", prog_name);
+ printf("Example:\n\t./bmc-log /dev/ttyS1 4 netcons.any.facebook.com 1514\n");
+ printf("\tOR\n\t./bmc-log /dev/ttyS1 6 netcons6.any.facebook.com 1514 57600\n");
+}
+
+bool parse_user_input(int nargs, char **args, char *read_tty, int read_tty_size, int *ip_version)
+{
+ if (nargs < 5) {
+ if ((nargs > 1) && ((strcmp(args[1], "-h") == 0) || (strcmp(args[1], "--help") == 0))) {
+ usage(args[0]);
+ return false; // Not an error but returning -1 for the main function to return
+ }
+ fprintf(stderr, "Error: Invalid number of arguments\n");
+ usage(args[0]);
+ return false;
+ }
+
+ if (strlen(args[1]) > read_tty_size) {
+ fprintf(stderr, "Error: TTY too long\n");
+ usage(args[0]);
+ return false;
+ }
+
+ /* TTT to read the logs from */
+ strncpy(read_tty, args[1], read_tty_size);
+
+ /* IP Version, IP Address and Port of the netcons server */
+ *ip_version = atoi(args[2]);
+ if (*ip_version != IPV4 && *ip_version != IPV6) {
+ fprintf(stderr, "Error: Invalid IP Version input\n");
+ usage(args[0]);
+ return false;
+ }
+
+ hostname = args[3];
+ port = atoi(args[4]);
+
+ baud_rate = B57600;
+ if (nargs == 6)
+ baud_rate = atoi(args[5]);
+
+ return true;
+}
+
+int main(int argc, char **argv)
+{
+ char read_tty[TTY_LEN] = { 0 };
+ int ip_version;
+ int socket_domain = AF_UNSPEC;
+ char cmd[COMMAND_LEN] = { 0 };
+
+ /* Open the error log file */
+ error_file = fopen(error_log_file, "a+");
+ if (!error_file) {
+ printf("Error: Unable to open log file - %m\n");
+ return 1;
+ }
+
+ /* Register actions upon interrupts */
+ register_kill();
+
+ /* Parse the user input */
+ if (!parse_user_input(argc, argv, read_tty, sizeof(read_tty), &ip_version)) {
+ return 2;
+ }
+
+ snprintf(cmd, sizeof(cmd), "%s %s", uS_console, "connect");
+ if (system(cmd) == -1) {
+ errlog("Error: Unable to connect to the micro-server\n");
+ return 3;
+ }
+
+ /* Create a socket to communicate with the netcons server */
+ socket_domain = (ip_version == IPV4) ? AF_INET : AF_INET6;
+ fd_soc = socket(socket_domain, SOCK_DGRAM, 0);
+ if (fd_soc == -1) {
+ errlog("Error: Socket creation failed - %m\n");
+ return 4;
+ }
+
+ if (ip_version == IPV4) { /* IPv4 */
+ struct sockaddr_in tgt_addr;
+ if (!prepare_sock(&tgt_addr)) {
+ close(fd_soc);
+ errlog("Error: Socket not valid\n");
+ return 5;
+ }
+
+ if (connect(fd_soc, (struct sockaddr *)&tgt_addr, sizeof(tgt_addr)) == -1) {
+ close(fd_soc);
+ errlog("Error: Socket connection failed - %m\n");
+ return 6;
+ }
+
+ } else { /* IPv6 */
+
+ struct sockaddr_in6 tgt_addr6;
+ if (!prepare_sock6(&tgt_addr6)) {
+ close(fd_soc);
+ errlog("Error: Socket not valid\n");
+ return 5;
+ }
+
+ if (connect(fd_soc, (struct sockaddr *)&tgt_addr6, sizeof(tgt_addr6)) == -1) {
+ close(fd_soc);
+ errlog("Error: Socket connection failed - %m\n");
+ return 6;
+ }
+ }
+
+ /* TTY Operations */
+ if ((fd_tty = open(read_tty, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK)) == -1) {
+ close(fd_soc);
+ errlog("Error: Serial Port %s open failed - %m\n", read_tty);
+ return 7;
+ }
+
+ if (!set_tty(fd_tty)) {
+ errlog("Error: tty not set properly\n");
+ cleanup();
+ return 8;
+ }
+
+ /* Read, prepare and send the logs */
+ if (!read_send(fd_tty, fd_soc)) {
+ errlog("Error: Sending logs failed\n");
+ cleanup();
+ return 9;
+ }
+
+ cleanup();
+ return 0;
+}
diff --git a/meta-facebook/meta-wedge/recipes-wedge/bmc-log/files/bmc-log.h b/meta-facebook/meta-wedge/recipes-wedge/bmc-log/files/bmc-log.h
new file mode 100644
index 0000000..5795e6a
--- /dev/null
+++ b/meta-facebook/meta-wedge/recipes-wedge/bmc-log/files/bmc-log.h
@@ -0,0 +1,46 @@
+/*
+ * 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 BMC_LOG_H_
+#define BMC_LOG_H_
+
+/* IP Version */
+#define IPV4 (4)
+#define IPV6 (6)
+
+/* Search string for the kernel version */
+#define KERNEL_SEARCH_STR "Linux version "
+
+/* Size constants */
+#define TIME_FORMAT_SIZE (100)
+#define MAX_LOG_FILE_SIZE (1024*1024*5) //5MB
+#define TTY_LEN (50)
+#define LINE_LEN (257)
+#define MSG_LEN (1025)
+#define COMMAND_LEN (100)
+#define KERNEL_VERSION_LEN (100)
+
+static char *uS_console = "/usr/local/fbpackages/utils/us_console.sh";
+
+static char *error_log_file = "/var/log/bmc-log";
+
+static char *pseudo_tty_save_file = "/etc/us_pseudo_tty";
+
+static int kernel_search_len = sizeof(KERNEL_SEARCH_STR) - 1;
+
+#endif
diff --git a/meta-facebook/meta-wedge/recipes-wedge/bmc-log/files/bmc-log.sh b/meta-facebook/meta-wedge/recipes-wedge/bmc-log/files/bmc-log.sh
new file mode 100755
index 0000000..00bf63c
--- /dev/null
+++ b/meta-facebook/meta-wedge/recipes-wedge/bmc-log/files/bmc-log.sh
@@ -0,0 +1,77 @@
+#!/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: bmc-log
+# Required-Start:
+# Required-Stop:
+# Default-Start: S
+# Default-Stop:
+# Short-Description: Collect micro-server kernel logs through serial port
+### END INIT INFO
+
+. /etc/default/bmc-log
+. /etc/init.d/functions
+
+DAEMON=/usr/sbin/bmc-log
+NAME=bmc-log
+DESC="Micro-Server log collection"
+
+TTY=${US_TTY:-/dev/ttyS1}
+IP=${LOG_SERVER_IP_VERSION:-4}
+LOG_SERVER=${LOG_SERVER_NAME:-}
+PORT=${LOG_SERVER_PORT:-}
+BAUD_RATE=${TTY_BAUD_RATE:-}
+
+if [ -z "$LOG_SERVER" ] || [ -z "$PORT" ]
+then
+ echo "Error: Server and/or port not set"
+ exit 0
+fi
+
+
+ACTION="$1"
+
+case "$ACTION" in
+ start)
+ echo -e "Starting $DESC"
+ $DAEMON $TTY $IP $LOG_SERVER $PORT $BAUD_RATE
+ ;;
+ stop)
+ echo -e "Stopping $DESC: "
+ start-stop-daemon --stop --quiet --exec $DAEMON
+ ;;
+ restart|force-reload)
+ echo -e "Restarting $DESC: "
+ start-stop-daemon --stop --quiet --exec $DAEMON
+ sleep 1
+ $DAEMON $TTY $IP $LOG_SERVER $PORT $BAUD_RATE
+ ;;
+ status)
+ stat $DAEMON
+ exit $?
+ ;;
+ *)
+ N=${0##*/}
+ N=${N#[SK]??}
+ echo "Usage: $N {start|stop|status|restart|force-reload}" >&2
+ exit 1
+ ;;
+esac
diff --git a/meta-facebook/meta-wedge/recipes-wedge/fan-ctrl/fan-ctrl/setup-fan.sh b/meta-facebook/meta-wedge/recipes-wedge/fan-ctrl/fan-ctrl/setup-fan.sh
index 0cbdb24..146a787 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/fan-ctrl/fan-ctrl/setup-fan.sh
+++ b/meta-facebook/meta-wedge/recipes-wedge/fan-ctrl/fan-ctrl/setup-fan.sh
@@ -2,6 +2,22 @@
#
# 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-fan
# Required-Start: board-id
@@ -11,7 +27,7 @@
# Short-Description: Set fan speed
### END INIT INFO
-. /usr/local/fbpackages/utils/ast-functions
+. /usr/local/bin/openbmc-utils.sh
# Enable the isolation buffer
wedge_iso_buf_enable
diff --git a/meta-facebook/meta-wedge/recipes-wedge/fan-ctrl/fan-ctrl_0.1.bbappend b/meta-facebook/meta-wedge/recipes-wedge/fan-ctrl/fan-ctrl_0.1.bbappend
new file mode 100644
index 0000000..ef2932e
--- /dev/null
+++ b/meta-facebook/meta-wedge/recipes-wedge/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 = "libwedge-eeprom update-rc.d-native"
+
+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 \
+ "
+
+LDFLAGS_append = " -lwedge_eeprom"
+CXXFLAGS_prepend = "-DCONFIG_WEDGE "
+
+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-wedge/recipes-wedge/fblibs/files/alert_control/Makefile b/meta-facebook/meta-wedge/recipes-wedge/fblibs/files/alert_control/Makefile
index 74ce8f3..2f27a8c 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/fblibs/files/alert_control/Makefile
+++ b/meta-facebook/meta-wedge/recipes-wedge/fblibs/files/alert_control/Makefile
@@ -1,8 +1,24 @@
# 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
+
lib: libalert_control.so
libalert_control.so: alert_control.c
- $(CC) $(CCFLAGS) -fPIC -c -o alert_control.o alert_control.c
+ $(CC) $(CFLAGS) -fPIC -c -o alert_control.o alert_control.c
$(CC) -shared -o libalert_control.so alert_control.o -lc
.PHONY: clean
diff --git a/meta-facebook/meta-wedge/recipes-wedge/fblibs/files/ipmi/Makefile b/meta-facebook/meta-wedge/recipes-wedge/fblibs/files/ipmi/Makefile
index 8cb69e7..369819c 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/fblibs/files/ipmi/Makefile
+++ b/meta-facebook/meta-wedge/recipes-wedge/fblibs/files/ipmi/Makefile
@@ -1,8 +1,24 @@
# 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
+
lib: libipmi.so
libipmi.so: ipmi.c
- $(CC) $(CCFLAGS) -fPIC -c -o ipmi.o ipmi.c
+ $(CC) $(CFLAGS) -fPIC -c -o ipmi.o ipmi.c
$(CC) -shared -o libipmi.so ipmi.o -lc
.PHONY: clean
diff --git a/meta-facebook/meta-wedge/recipes-wedge/fblibs/libalert-control_0.1.bb b/meta-facebook/meta-wedge/recipes-wedge/fblibs/libalert-control_0.1.bb
index 2ae4ea7..ec02d04 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/fblibs/libalert-control_0.1.bb
+++ b/meta-facebook/meta-wedge/recipes-wedge/fblibs/libalert-control_0.1.bb
@@ -1,4 +1,19 @@
# 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 = "Wedge Alert Control Library"
DESCRIPTION = "library for Wedge Alert Control"
SECTION = "base"
@@ -20,5 +35,4 @@ do_install() {
}
FILES_${PN} = "${libdir}/libalert_control.so"
-FILES_${PN}-dbg = "${libdir}/.debug"
FILES_${PN}-dev = "${includedir}/facebook/alert_control.h"
diff --git a/meta-facebook/meta-wedge/recipes-wedge/fblibs/libipmi_0.1.bb b/meta-facebook/meta-wedge/recipes-wedge/fblibs/libipmi_0.1.bb
index 0b6f3d3..83292be 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/fblibs/libipmi_0.1.bb
+++ b/meta-facebook/meta-wedge/recipes-wedge/fblibs/libipmi_0.1.bb
@@ -1,4 +1,19 @@
# 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 = "Wedge IPMI Client Library"
DESCRIPTION = "library for Wedge IPMI Client"
SECTION = "base"
@@ -21,5 +36,4 @@ do_install() {
}
FILES_${PN} = "${libdir}/libipmi.so"
-FILES_${PN}-dbg = "${libdir}/.debug"
FILES_${PN}-dev = "${includedir}/facebook/ipmi.h"
diff --git a/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/at93cx6.py b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/at93cx6.py
new file mode 100644
index 0000000..514a06b
--- /dev/null
+++ b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/at93cx6.py
@@ -0,0 +1,318 @@
+# 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
+
+
+AT93C46 = 'at93c46'
+AT93C56 = 'at93c56'
+AT93C66 = 'at93c66'
+AT93C86 = 'at93c86'
+
+
+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 AT93CX6SPI(VerboseLogger):
+ '''The class to access AT93CX6 through SPI intf'''
+ SPI_CMD = 'spi-bb'
+
+ def __init__(self, bus_width, gpio_cs, gpio_ck, gpio_do, gpio_di,
+ model, verbose=False):
+ addr_bits_map = {
+ AT93C46 : 6,
+ AT93C56 : 8,
+ AT93C66 : 8,
+ AT93C86 : 10,
+ }
+ if bus_width != 8 and bus_width != 16:
+ raise Exception("Invalid bus width for AT93CX6!")
+ if model not in addr_bits_map:
+ raise Exception("Invalid model '%s'" % model)
+
+ 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 = addr_bits_map[model] \
+ + (0 if self.bus_width == 16 else 1)
+ self.addr_mask = (1 << self.addr_bits) - 1
+
+ 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
+ instruction = addr & self.addr_mask
+ instruction = instruction | ((0x4 | (op & 0x3)) << self.addr_bits)
+ 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 - (self.addr_bits + 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], self.addr_bits + 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 AT93CX6(VerboseLogger):
+ '''
+ The class which handles accessing memory on the AT93CX6 chip.
+ '''
+
+ def __init__(self, bus_width, gpio_cs, gpio_ck, gpio_do, gpio_di,
+ byte_swap, model=AT93C46, verbose=False):
+ mem_size_map = {
+ # in bytes
+ AT93C46 : 128,
+ AT93C56 : 256,
+ AT93C66 : 512,
+ AT93C86 : 2048,
+ }
+ self.bus_width = bus_width
+ self.verbose = verbose
+ self.byte_swap = byte_swap
+ self.model = model
+ self.memory_size = mem_size_map[model]
+
+ self.spi = AT93CX6SPI(bus_width=bus_width, gpio_cs=gpio_cs,
+ gpio_ck=gpio_ck, gpio_do=gpio_do,
+ gpio_di=gpio_di, model=model,
+ 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 get_memory_size(self):
+ return self.memory_size
+
+ def erase(self, offset=None, limit=None):
+ '''
+ Erase the chip.
+ '''
+ if offset is None:
+ offset = 0
+ if limit is None:
+ limit = self.memory_size
+
+ if offset < 0 or offset + limit > self.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.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.memory_size
+
+ if offset < 0 or offset + limit > self.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.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-wedge/recipes-wedge/fbutils/files/at93cx6_util.py b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/at93cx6_util.py
new file mode 100755
index 0000000..8ae7664
--- /dev/null
+++ b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/at93cx6_util.py
@@ -0,0 +1,223 @@
+#!/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
+import at93cx6
+import sys
+
+
+def get_raw(args):
+ return at93cx6.AT93CX6SPI(
+ args.bus_width, args.cs, args.clk, args.mosi, args.miso,
+ args.model, args.verbose)
+
+def get_chip(args):
+ return at93cx6.AT93CX6(
+ args.bus_width, args.cs, args.clk, args.mosi, args.miso,
+ args.byte_swap if hasattr(args, 'byte_swap') else None,
+ args.model, args.verbose)
+
+def model_parser(ap):
+ # Default, based on currenct HW configuration
+ MODEL_DEFAULT = at93cx6.AT93C46
+
+ ap.add_argument('--model', default=at93cx6.AT93C46,
+ choices=[at93cx6.AT93C46, at93cx6.AT93C56,
+ at93cx6.AT93C66, at93cx6.AT93C86],
+ help='The chip model (default: %(default)s)')
+
+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: %(default)s)')
+ spi_group.add_argument('--clk', type=int, default=SPI_CLK_DEFAULT,
+ help='The GPIO number for SPI CLK pin '
+ '(default: %(default)s)')
+ spi_group.add_argument('--mosi', type=int, default=SPI_MOSI_DEFAULT,
+ help='The GPIO number for SPI MOSI pin '
+ '(default: %(default)s)')
+ spi_group.add_argument('--miso', type=int, default=SPI_MISO_DEFAULT,
+ help='The GPIO number for SPI MISO pin '
+ '(default: %(default)s)')
+
+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: %(default)s)')
+
+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:
+ with open(args.file, "wb") as fp:
+ 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(chip.get_memory_size())
+ else:
+ with open(args.file, "rb") as fp:
+ data = fp.read(chip.get_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', default=False, action='store_true',
+ help='Byte swap values for 16-bit reads/writes '
+ '(default: %(default)s)')
+ 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', default=False, action='store_true',
+ help='Byte swap values for 16-bit reads/writes '
+ '(default: %(default)s)')
+ 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')
+
+ # Model, SPI, and bus width arguments
+ model_parser(ap)
+ 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-wedge/recipes-wedge/fbutils/files/bcm5396.py b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/bcm5396.py
index e1aba47..91d9a85 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/bcm5396.py
+++ b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/bcm5396.py
@@ -16,10 +16,13 @@
# 51 Franklin Street, Fifth Floor,
# Boston, MA 02110-1301 USA
#
+from __future__ import print_function
+
import subprocess
import time
+
class Bcm5396MDIO:
'''The class to access BCM5396 through MDIO intf'''
MDIO_CMD = 'mdio-bb'
@@ -254,23 +257,35 @@ class Bcm5396SPI:
except Exception as e:
print(e)
+
class Bcm5396:
'''The class for BCM5396 Switch'''
MDIO_ACCESS = 0
SPI_ACCESS = 1
- def __init__(self, access, **kwargs):
+ def __init__(self, access, verbose=False, **kwargs):
+ self.verbose = verbose
if access == self.MDIO_ACCESS:
self.access = Bcm5396MDIO(**kwargs)
else:
self.access = Bcm5396SPI(**kwargs)
def write(self, page, reg, value, n_bytes):
+ if self.verbose:
+ print('WRITE {:2x} {:2x} {:2x} '.format(page, reg, n_bytes), end='')
+ bytes = '{:2x}'.format(value)
+ print([bytes[i:i+2] for i in range(0, len(bytes), 2)][-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)
+ if self.verbose:
+ print('READ {:2x} {:2x} {:2x} '.format(page, reg, n_bytes), end='')
+ result = self.access.read(page, reg, n_bytes)
+ if self.verbose:
+ bytes = '{:2x}'.format(result)
+ print([bytes[i:i+2] for i in range(0, len(bytes), 2)][-n_bytes:])
+ return result
def __add_remove_vlan(self, add, vid, untag, fwd, spt):
VLAN_PAGE = 0x5
diff --git a/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/bcm5396_util.py b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/bcm5396_util.py
index 1496412..0759b08 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/bcm5396_util.py
+++ b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/bcm5396_util.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/python -tt
# Copyright 2004-present Facebook. All rights reserved.
#
# This program file is free software; you can redistribute it and/or modify it
@@ -29,9 +29,11 @@ def auto_int(x):
def get_bcm(args):
if args.spi:
return Bcm5396(Bcm5396.SPI_ACCESS, cs=args.cs, clk=args.clk,
- mosi=args.mosi, miso=args.miso)
+ mosi=args.mosi, miso=args.miso,
+ verbose=args.verbose)
else:
- return Bcm5396(Bcm5396.MDIO_ACCESS, mdc=args.mdc, mdio=args.mdio)
+ return Bcm5396(Bcm5396.MDIO_ACCESS, mdc=args.mdc, mdio=args.mdio,
+ verbose=args.verbose)
def read_register(args):
@@ -249,6 +251,10 @@ def access_parser(ap):
if __name__ == '__main__':
ap = ArgumentParser()
+ ap.add_argument('-v', '--verbose', action='store_true',
+ help='Dump the switch page, register, and value '
+ 'for each operation')
+
access_parser(ap)
subparsers = ap.add_subparsers()
diff --git a/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/board-utils.sh b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/board-utils.sh
new file mode 100644
index 0000000..e4d34aa
--- /dev/null
+++ b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/board-utils.sh
@@ -0,0 +1,163 @@
+# Copyright 2014-present Facebook. All Rights Reserved.
+wedge_iso_buf_enable() {
+ # GPIOC2 (18) to low, SCU90[0] and SCU90[24] must be 0
+ devmem_clear_bit $(scu_addr 90) 0
+ devmem_clear_bit $(scu_addr 90) 24
+ gpio_set 18 0
+}
+
+wedge_iso_buf_disable() {
+ # GPIOC2 (18) to low, SCU90[0] and SCU90[24] must be 0
+ devmem_clear_bit $(scu_addr 90) 0
+ devmem_clear_bit $(scu_addr 90) 24
+ gpio_set 18 1
+}
+
+wedge_is_us_on() {
+ local val n retries prog
+ if [ $# -gt 0 ]; then
+ retries="$1"
+ else
+ retries=1
+ fi
+ if [ $# -gt 1 ]; then
+ prog="$2"
+ else
+ prog=""
+ fi
+ if [ $# -gt 2 ]; then
+ default=$3 # value 0 means defaul is 'ON'
+ else
+ default=1
+ fi
+ n=1
+ while true; do
+ val=$(cat /sys/class/i2c-adapter/i2c-4/4-0040/gpio_inputs 2>/dev/null)
+ if [ -n "$val" ]; then
+ break
+ fi
+ n=$((n+1))
+ if [ $n -gt $retries ]; then
+ echo -n " failed to read GPIO. "
+ return $default
+ break
+ fi
+ echo -n "$prog"
+ sleep 1
+ done
+ if [ "$((val & (0x1 << 14)))" != "0" ]; then
+ # powered on already
+ return 0
+ else
+ return 1
+ fi
+}
+
+
+# Return the board type, 'LC', 'FC-LEFT', 'FC-RIGHT', or, 'WEDGE'
+wedge_board_type() {
+ local pn
+ pn=$(/usr/bin/weutil 2> /dev/null | grep -i '^Location on Fabric:')
+ case "$pn" in
+ *LEFT*)
+ echo 'FC-LEFT'
+ ;;
+ *RIGHT*)
+ echo 'FC-RIGHT'
+ ;;
+ *LC*)
+ echo 'LC'
+ ;;
+ *)
+ echo 'WEDGE'
+ ;;
+ esac
+}
+
+# On FC,
+# board rev < 2:
+# FAB_SLOT_ID (GPIOU0), low == FC0; high == FC1
+# else:
+# FAB_SLOT_ID (GPIOU6), low == FC0; high == FC1
+## On LC, Wedge,
+# board rev < 3:
+# GPIOU0(ID0), GPIOU1(ID1), GPIOU2(ID2), GPIOU3(ID3)
+# else:
+# GPIOU6(ID0), GPIOU7(ID1), GPIOV0(ID2), GPIOV1(ID3)
+#
+# ID[2:0] ID3 Slot#
+# 000 0 1
+# 000 1 2
+# 001 0 3
+# 001 1 4
+# 010 0 5
+# 010 1 6
+# 011 0 7
+# 011 1 8
+
+wedge_slot_id() {
+ local type slot id3 id2 id1 id0 FC_CARD_BASE board_rev
+ FC_CARD_BASE=65
+ # need to check the board rev
+ board_rev=$(wedge_board_rev)
+ case "$1" in
+ FC-LEFT|FC-RIGHT)
+ # On FC
+ if [ $board_rev -lt 2 ]; then
+ slot=$(gpio_get U0)
+ else
+ slot=$(gpio_get U6)
+ fi
+ if [ "$1" = "FC-LEFT" ]; then
+ # fabric card left
+ slot=$((FC_CARD_BASE + slot * 2))
+ else
+ # fabric card right
+ slot=$((FC_CARD_BASE + slot * 2 + 1))
+ fi
+ ;;
+ *)
+ # either edge or LC
+ if [ $board_rev -lt 3 ]; then
+ id0=$(gpio_get U0)
+ id1=$(gpio_get U1)
+ id2=$(gpio_get U2)
+ id3=$(gpio_get U3)
+ else
+ id0=$(gpio_get U6)
+ id1=$(gpio_get U7)
+ id2=$(gpio_get V0)
+ id3=$(gpio_get V1)
+ fi
+ slot=$(((id2 * 4 + id1 * 2 + id0) * 2 + id3 + 1))
+ esac
+ echo "$slot"
+}
+
+# wedge_board_rev() is only valid after GPIO Y0, Y1, and Y2 are enabled
+wedge_board_rev() {
+ local val0 val1 val2
+ val0=$(cat /sys/class/gpio/gpio192/value 2>/dev/null)
+ val1=$(cat /sys/class/gpio/gpio193/value 2>/dev/null)
+ val2=$(cat /sys/class/gpio/gpio194/value 2>/dev/null)
+ echo $((val0 | (val1 << 1) | (val2 << 2)))
+}
+
+# Should we enable OOB interface or not
+wedge_should_enable_oob() {
+ board_rev=$(wedge_board_rev)
+ board_type=$(wedge_board_type)
+ case "$board_type" in
+ FC-LEFT|FC-RIGHT)
+ if [ $board_rev -lt 2 ]; then
+ return 0
+ fi
+ ;;
+ *)
+ if [ $board_rev -lt 3 ]; then
+ return 0
+ fi
+ ;;
+ esac
+ return -1
+}
diff --git a/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/create_vlan_intf b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/create_vlan_intf
index 2cf7a9a..8c7e74b 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/create_vlan_intf
+++ b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/create_vlan_intf
@@ -21,7 +21,7 @@
# only care about 'eth0' and 'oob' intf
[ "$IFACE" != "eth0" ] && [ "$IFACE" != "oob" ] && exit 0
-. /usr/local/fbpackages/utils/ast-functions
+. /usr/local/bin/openbmc-utils.sh
board=$(wedge_board_type)
diff --git a/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/eth0_mac_fixup.sh b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/eth0_mac_fixup.sh
index 1cdbcb6..f244bd0 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/eth0_mac_fixup.sh
+++ b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/eth0_mac_fixup.sh
@@ -29,13 +29,27 @@
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin
+# get the MAC from EEPROM
mac=$(weutil 2>/dev/null | grep '^Local MAC' 2>/dev/null | cut -d' ' -f3 2>/dev/null)
+# get the MAC from u-boot environment
+ethaddr=$(fw_printenv ethaddr 2>/dev/null | cut -d'=' -f2 2>/dev/null)
+
+if [ -z "$mac" ] && [ -n "$ethaddr" ]; then
+ # no MAC from EEPROM, use the one from u-boot environment
+ mac="$ethaddr"
+fi
+
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
+else
+ # no MAC from either EEPROM or u-boot environment
+ mac=$(ifconfig eth0 2>/dev/null |grep HWaddr 2>/dev/null |awk '{ print $5 }')
+
+fi
+
+if [ "$ethaddr" != "$mac" ]; then
+ # set the MAC from EEPROM or ifconfig back to u-boot environment so that u-boot
+ # can use it
+ fw_setenv "ethaddr" "$mac"
fi
diff --git a/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/post_led.sh b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/post_led.sh
index c23349f..b653cb3 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/post_led.sh
+++ b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/post_led.sh
@@ -24,7 +24,7 @@ usage() {
echo "Usage: $0 <value>"
}
-. /usr/local/fbpackages/utils/ast-functions
+. /usr/local/bin/openbmc-utils.sh
# Function to set the less significant hex digit
display_lower() {
diff --git a/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/power-on.sh b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/power-on.sh
index 843b79a..ace3c6a 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/power-on.sh
+++ b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/power-on.sh
@@ -25,7 +25,7 @@
# Default-Stop:
# Short-Description: Power on micro-server
### END INIT INFO
-. /usr/local/fbpackages/utils/ast-functions
+. /usr/local/bin/openbmc-utils.sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin
diff --git a/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/power_led.sh b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/power_led.sh
index 20206a1..066646e 100755
--- a/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/power_led.sh
+++ b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/power_led.sh
@@ -23,7 +23,7 @@ usage() {
exit -1
}
-. /usr/local/fbpackages/utils/ast-functions
+. /usr/local/bin/openbmc-utils.sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin
diff --git a/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/reset_usb.sh b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/reset_usb.sh
index 7d1c2c6..c63ed10 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/reset_usb.sh
+++ b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/reset_usb.sh
@@ -18,7 +18,7 @@
# Boston, MA 02110-1301 USA
#
-. /usr/local/fbpackages/utils/ast-functions
+. /usr/local/bin/openbmc-utils.sh
echo -n "Reset USB Switch ... "
diff --git a/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/setup-gpio.sh b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/setup-gpio.sh
index 9f0b543..717bcd8 100755
--- a/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/setup-gpio.sh
+++ b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/setup-gpio.sh
@@ -39,7 +39,7 @@
# When defined, the system doesn't reboot cleanly. We're still
# investigating this.
-. /usr/local/fbpackages/utils/ast-functions
+. /usr/local/bin/openbmc-utils.sh
# Set up to read the board revision pins, Y0, Y1, Y2
devmem_set_bit $(scu_addr 70) 19
@@ -182,8 +182,8 @@ devmem_set_bit $(scu_addr 70) 13
# GPIOQ5 is ISO_FLASH_HOLD, must be 1 to be out of reset
# To use GPIOQ4 and GPIOQ5, SCU90[27] must be 0
devmem_clear_bit $(scu_addr 90) 27
-gpio_set 134 1
-gpio_set 135 1
+gpio_set Q4 1
+gpio_set Q5 1
# GPIOD6 is ISO_FL_PRG_SEL, set it to 0 so that BMC does not have control
# on the EEPROM by default.
# To use GPIOD6, SCU90[1] must be 0, SCU8C[21] must be 0, and Strap[21] must be 0
@@ -244,31 +244,139 @@ board_type=$(wedge_board_type)
case "$board_type" in
FC-LEFT|FC-RIGHT)
# On FC
- # FAB_SLOT_ID is GPIOU0
- # PEER_FAB_PRSNT is GPIOU1
- devmem_set_bit $(scu_addr a0) 8
- devmem_set_bit $(scu_addr a0) 9
- gpio_export U0
- gpio_export U1
- # T2_POWER_UP is GPIOT6
- devmem_set_bit $(scu_addr a0) 6
- gpio_export T6
- # HS_FAULT_N is GPIOT7
- devmem_set_bit $(scu_addr a0) 7
- gpio_export T7
- if [ "$board_type" = "FC-LEFT" ]; then
- # GPIOE2 is CPU_EEPROM_SEL, on FC-LEFT
- devmem_clear_bit $(scu_addr 80) 18
- devmem_clear_bit $(scu_addr 8c) 13
- devmem_clear_bit $(scu_addr 70) 22
- gpio_export E2
- # GPIOA6 and GPIOA7 are MAC2 MDIO pins, we use them as
- # GPIO for bitbang driver
- devmem_clear_bit $(scu_addr 90) 2
- devmem_clear_bit $(scu_addr 80) 6
- devmem_clear_bit $(scu_addr 80) 7
- gpio_export A6
- gpio_export A7
+ if [ $board_rev -lt 2 ]; then
+ # EVT board
+ # FAB_SLOT_ID is GPIOU0
+ # PEER_FAB_PRSNT is GPIOU1
+ devmem_set_bit $(scu_addr a0) 8
+ devmem_set_bit $(scu_addr a0) 9
+ gpio_export U0
+ gpio_export U1
+ # T2_POWER_UP is GPIOT6
+ devmem_set_bit $(scu_addr a0) 6
+ gpio_export T6 T2_POWER_UP
+ # HS_FAULT_N is GPIOT7
+ devmem_set_bit $(scu_addr a0) 7
+ gpio_export T7
+ if [ "$board_type" = "FC-LEFT" ]; then
+ # GPIOE2 is CPU_EEPROM_SEL, on FC-LEFT
+ devmem_clear_bit $(scu_addr 80) 18
+ devmem_clear_bit $(scu_addr 8c) 13
+ devmem_clear_bit $(scu_addr 70) 22
+ gpio_export E2
+ # GPIOA6 and GPIOA7 are MAC2 MDIO pins, we use them as
+ # GPIO for bitbang driver
+ devmem_clear_bit $(scu_addr 90) 2
+ devmem_clear_bit $(scu_addr 80) 6
+ devmem_clear_bit $(scu_addr 80) 7
+ gpio_export A6
+ gpio_export A7
+ fi
+ else
+ # DVT board
+ if [ "$board_type" = "FC-LEFT" ]; then # Left FC
+ # BMC_SW_RST is GPIOL0, 16p switch
+ # SCU84[16] must be 0
+ devmem_clear_bit $(scu_addr 84) 16
+ gpio_set L0 1
+
+ # MDC|MDIO_CONT are GPIOR6 and GPIOR7, 16p switch
+ # SCU88[30:31] must be 0
+ devmem_clear_bit $(scu_addr 88) 30
+ devmem_clear_bit $(scu_addr 88) 31
+ gpio_set R6 1
+ gpio_set R7 1
+
+ # SWITCH_EEPROM1_WRT is GPIOE2, 16p switch EEPROM (U61)
+ # SCU80[18], SCU8C[13], and SCU70[22] must be 0
+ devmem_clear_bit $(scu_addr 80) 18
+ devmem_clear_bit $(scu_addr 8C) 13
+ devmem_clear_bit $(scu_addr 70) 22
+ gpio_export E2
+
+ # SPI bus to 16p switch EEPROM
+ # GPIOI4 <--> BMC_EEPROM1_SPI_SS
+ # GPIOI5 <--> BMC_EEPROM1_SPI_SCK
+ # GPIOI6 <--> BMC_EEPROM1_SPI_MOSI
+ # GPIOI7 <--> BMC_EEPROM1_SPI_MISO
+ # The EEPROM SPI clk does not match with the BMC SPI master.
+ # Have to configure these pins as GPIO to use with
+ # SPI bitbang driver.
+ # SCU70[13:12,5] must be 0
+ devmem_clear_bit $(scu_addr 70) 5
+ devmem_clear_bit $(scu_addr 70) 12
+ devmem_clear_bit $(scu_addr 70) 13
+ gpio_export I4
+ gpio_export I5
+ gpio_export I6
+ gpio_export I7
+
+ # BMC_PHY_RST is GPIOT0, Front Panel Port PHY on the 16p switch
+ # SCUA0[0] must be 1
+ devmem_set_bit $(scu_addr a0) 0
+ gpio_set T0 1
+
+ # BMC_5PORTSW_RST is GPIOT1, 5p switch
+ # SCUA0[1] must be 1
+ devmem_set_bit $(scu_addr a0) 1
+ gpio_set T1 1
+
+ # ISO_SWITCH1_MDC|MDIO are GPIOT4 and GPIOT5, 5p switch
+ # SCUA0[4:5] must be 1
+ devmem_set_bit $(scu_addr a0) 4
+ devmem_set_bit $(scu_addr a0) 5
+ gpio_set T4 1
+ gpio_set T5 1
+
+ # ISO_SWITCH_EEPROM2_WRT is GPIOV0, 5p switch EEPROM (U114)
+ # SCUA0[16] must be 1
+ devmem_set_bit $(scu_addr a0) 16
+ gpio_export V0
+
+ # SPI bus to 5p switch EEPROM (U114)
+ # GPIOI0 <--> ISO_BMC_EEPROM2_SPI_SS
+ # GPIOI1 <--> ISO_BMC_EEPROM2_SPI_SCK
+ # GPIOI2 <--> ISO_BMC_EEPROM2_SPI_MOSI
+ # GPIOI3 <--> ISO_BMC_EEPROM2_SPI_MISO
+ # The EEPROM SPI clk does not match with the BMC SPI master.
+ # Have to configure these pins as GPIO to use with
+ # SPI bitbang driver.
+ # SCU70[13] must be 0, has already been set when
+ # preparing for GPIOI4-GPIOI7
+ gpio_export I0
+ gpio_export I1
+ gpio_export I2
+ gpio_export I3
+
+ # BMC_PHYL_RST is GPIOF0, Left BMC PHY
+ # SCU80[24] must be 0
+ devmem_clear_bit $(scu_addr 80) 24
+ gpio_set F0 1
+ else # Right FC
+ # BMC_PHYR_RST is GPIOL1, Right BMC PHY
+ # SCU84[17] must be 0
+ devmem_clear_bit $(scu_addr 84) 17
+ gpio_set L1 1
+ fi
+ # T2_POWER_UP is GPIOU4
+ # SCUA0[12] must be 1
+ devmem_set_bit $(scu_addr a0) 12
+ gpio_export U4 T2_POWER_UP
+
+ # HS_FAULT_N is GPIOU5
+ # SCUA0[13] must be 1
+ devmem_set_bit $(scu_addr a0) 13
+ gpio_export U5
+
+ # FAB_SLOT_ID is GPIOU6
+ # SCUA0[14] must be 1
+ devmem_set_bit $(scu_addr a0) 14
+ gpio_export U6
+
+ # PEER_FAB_PRSNT is GPIOU7
+ # SCUA0[15] must be 1
+ devmem_set_bit $(scu_addr a0) 15
+ gpio_export U7
fi
;;
*)
@@ -289,7 +397,7 @@ case "$board_type" in
gpio_export U3
# T2_POWER_UP is GPIOT6
devmem_set_bit $(scu_addr a0) 6
- gpio_export T6
+ gpio_export T6 T2_POWER_UP
# HS_FAULT_N is GPIOT7
devmem_set_bit $(scu_addr a0) 7
gpio_export T7
@@ -307,7 +415,7 @@ case "$board_type" in
gpio_export V1
# T2_POWER_UP is GPIOU4
devmem_set_bit $(scu_addr a0) 12
- gpio_export U4
+ gpio_export U4 T2_POWER_UP
# HS_FAULT_N is GPIOU5
devmem_set_bit $(scu_addr a0) 13
gpio_export U5
diff --git a/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/setup_rov.sh b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/setup_rov.sh
index 749fe65..1400464 100755
--- a/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/setup_rov.sh
+++ b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/setup_rov.sh
@@ -24,7 +24,7 @@
# outgoing voltage on the first buck converter, and bring T2 up out of
# reset.
-. /usr/local/fbpackages/utils/ast-functions
+. /usr/local/bin/openbmc-utils.sh
# read the T2 ROV after the GPIOs are enabled
t2_rov() {
diff --git a/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/sol.sh b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/sol.sh
index ccbdc61..2998c81 100755
--- a/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/sol.sh
+++ b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/sol.sh
@@ -18,7 +18,14 @@
# Boston, MA 02110-1301 USA
#
-CONSOLE_SH=/usr/local/fbpackages/utils/us_console.sh
+CONSOLE_SH=/usr/local/bin/us_console.sh
+FILE=/etc/us_pseudo_tty
+TTY=/dev/ttyS1
+
+if [ -a $FILE ]
+ then
+ read -r TTY<$FILE
+fi
$CONSOLE_SH connect
@@ -29,7 +36,7 @@ echo
trap '"$CONSOLE_SH" disconnect' INT TERM QUIT EXIT
-/usr/bin/microcom -s 57600 /dev/ttyS1
+/usr/bin/microcom -s 57600 $TTY
echo
echo
diff --git a/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/start_us_monitor.sh b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/start_us_monitor.sh
new file mode 100644
index 0000000..19f3198
--- /dev/null
+++ b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/start_us_monitor.sh
@@ -0,0 +1,73 @@
+#! /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: us-monitor
+# Required-Start:
+# Required-Stop:
+# Default-Start: S
+# Default-Stop: 0 6
+# Short-Description: Start the microserver reset monitoring script
+#
+### END INIT INFO
+
+PATH=/sbin:/bin:/usr/sbin:/usr/bin
+NAME="us_monitor"
+DESC="monitoring microserver reset"
+DAEMON="us_monitor.sh"
+
+# source function library
+. /etc/init.d/functions
+
+. /usr/local/bin/openbmc-utils.sh
+
+STOPPER=
+ACTION="$1"
+
+case "$ACTION" in
+ start)
+ echo -n "Starting $DESC: "
+ /usr/local/bin/${DAEMON} > /dev/null 2>&1 &
+ echo "$NAME."
+ ;;
+ stop)
+ echo -n "Stopping $DESC: "
+ killall ${DAEMON}
+ echo "$NAME."
+ ;;
+ restart|force-reload)
+ echo -n "Restarting $DESC: "
+ killall ${DAEMON}
+ /usr/local/bin/${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-wedge/recipes-wedge/fbutils/files/us_console.sh b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/us_console.sh
index 6f445ee..75bbcea 100755
--- a/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/us_console.sh
+++ b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/us_console.sh
@@ -22,7 +22,7 @@ usage() {
echo "$0 <connect | disconnect>"
}
-. /usr/local/fbpackages/utils/ast-functions
+. /usr/local/bin/openbmc-utils.sh
if [ $# -ne 1 ]; then
usage
diff --git a/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/us_monitor.sh b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/us_monitor.sh
new file mode 100644
index 0000000..b7a9cb6
--- /dev/null
+++ b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/us_monitor.sh
@@ -0,0 +1,56 @@
+#!/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/bin/openbmc-utils.sh
+
+PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin
+
+# Because the voltage leak from uS COM pins could cause uS to struck when
+# transitting from S5 to S0, we will need to explicitely pull down uS COM
+# pins before powering off/reset and restoring COM pins after
+
+pull_down_us_com() {
+ # set GPIOL6 and GPIOL7 low
+ devmem_clear_bit $(scu_addr 84) 22
+ devmem_clear_bit $(scu_addr 84) 23
+ gpio_set 94 0
+ gpio_set 95 0
+ # now, connect uart from BMC to the uS
+ gpio_set 32 1
+}
+
+restore_us_com() {
+ devmem_set_bit $(scu_addr 84) 22
+ devmem_set_bit $(scu_addr 84) 23
+ # if sol.sh is running, keep uart from uS connected with BMC
+ if pidof -x sol.sh > /dev/null 2>&1; then
+ gpio_set 32 1
+ else
+ gpio_set 32 0
+ fi
+}
+
+while true; do
+ if ! wedge_is_us_on 1 '' 0 > /dev/null 2>&1; then
+ pull_down_us_com
+ else
+ restore_us_com
+ fi
+ usleep 400000 # 400ms
+done
diff --git a/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/wedge_power.sh b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/wedge_power.sh
index 5ba5311..ce734ef 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/wedge_power.sh
+++ b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/wedge_power.sh
@@ -18,7 +18,7 @@
# Boston, MA 02110-1301 USA
#
-. /usr/local/fbpackages/utils/ast-functions
+. /usr/local/bin/openbmc-utils.sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin
@@ -43,31 +43,6 @@ usage() {
echo
}
-# Because the voltage leak from uS COM pins could cause uS to struck when transitting
-# from S5 to S0, we will need to explicitely pull down uS COM pins before powering off/reset
-# and restoring COM pins after
-
-pull_down_us_com() {
- # set GPIOL6 and GPIOL7 low
- devmem_clear_bit $(scu_addr 84) 22
- devmem_clear_bit $(scu_addr 84) 23
- gpio_set 94 0
- gpio_set 95 0
- # now, connect uart from BMC to the uS
- gpio_set 32 1
-}
-
-restore_us_com() {
- devmem_set_bit $(scu_addr 84) 22
- devmem_set_bit $(scu_addr 84) 23
- # if sol.sh is running, keep uart from uS connected with BMC
- if ps | grep sol.sh > /dev/null 2>&1; then
- gpio_set 32 1
- else
- gpio_set 32 0
- fi
-}
-
do_status() {
echo -n "Microserver power is "
if wedge_is_us_on; then
@@ -79,7 +54,7 @@ do_status() {
}
do_on() {
- local force opt
+ local force opt pulse_us n retries
force=0
while getopts "f" opt; do
case $opt in
@@ -103,14 +78,31 @@ do_on() {
fi
# first make sure, GPIOD1 (25) is high
gpio_set 25 1
+ sleep 1
# then, put GPIOP7 (127) to low
gpio_set 127 0
- # generate the power on pulse
- gpio_set 25 0
- sleep 1
- gpio_set 25 1
- sleep 1
- restore_us_com
+ pulse_us=500000 # 500ms
+ retries=3
+ n=1
+ while true; do
+ # first make sure, GPIOD1 (25) is high
+ gpio_set 25 1
+ usleep $pulse_us
+ # generate the power on pulse
+ gpio_set 25 0
+ usleep $pulse_us
+ gpio_set 25 1
+ sleep 3
+ if wedge_is_us_on 1 '' 1; then
+ break
+ fi
+ n=$((n+1))
+ if [ $n -gt $retries ]; then
+ echo " Failed"
+ return 1
+ fi
+ echo -n "..."
+ done
# Turn on the power LED (GPIOE5)
/usr/local/bin/power_led.sh on
echo " Done"
@@ -119,7 +111,6 @@ do_on() {
do_off() {
echo -n "Power off microserver ..."
- pull_down_us_com
# first make sure, GPIOD1 (25) is high
gpio_set 25 1
# then, put GPIOP7 (127) to low
@@ -158,14 +149,12 @@ do_reset() {
return -1
fi
echo -n "Power reset microserver ..."
- pull_down_us_com
# then, put GPIOP7 (127) to low
gpio_set 127 0
gpio_set 17 0
sleep 1
gpio_set 17 1
sleep 1
- restore_us_com
fi
echo " Done"
return 0
diff --git a/meta-facebook/meta-wedge/recipes-wedge/fbutils/openbmc-utils_%.bbappend b/meta-facebook/meta-wedge/recipes-wedge/fbutils/openbmc-utils_%.bbappend
new file mode 100644
index 0000000..d6641c9
--- /dev/null
+++ b/meta-facebook/meta-wedge/recipes-wedge/fbutils/openbmc-utils_%.bbappend
@@ -0,0 +1,95 @@
+# 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
+
+FILESEXTRAPATHS_prepend := "${THISDIR}/files:"
+
+SRC_URI += "file://board-utils.sh \
+ file://us_console.sh \
+ file://sol.sh \
+ file://power_led.sh \
+ 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://at93cx6.py \
+ file://at93cx6_util.py \
+ file://mount_data0.sh \
+ file://eth0_mac_fixup.sh \
+ file://wedge_power.sh \
+ file://power-on.sh \
+ file://wedge_us_mac.sh \
+ file://setup_switch.py \
+ file://create_vlan_intf \
+ file://rc.early \
+ file://rc.local \
+ file://src \
+ file://start_us_monitor.sh \
+ file://us_monitor.sh \
+ "
+
+OPENBMC_UTILS_FILES += " \
+ board-utils.sh us_console.sh sol.sh power_led.sh post_led.sh \
+ reset_usb.sh mdio.py setup_rov.sh wedge_power.sh wedge_us_mac.sh \
+ bcm5396.py bcm5396_util.py setup_switch.py us_monitor.sh \
+ at93cx6.py at93cx6_util.py \
+ "
+
+DEPENDS_append = "update-rc.d-native"
+
+do_install_board() {
+ # for backward compatible, create /usr/local/fbpackages/utils/ast-functions
+ olddir="/usr/local/fbpackages/utils"
+ install -d ${D}${olddir}
+ ln -s "/usr/local/bin/openbmc-utils.sh" ${D}${olddir}/ast-functions
+
+ # common lib and include files
+ install -d ${D}${includedir}/facebook
+ 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 start_us_monitor.sh ${D}${sysconfdir}/init.d/start_us_monitor.sh
+ update-rc.d -r ${D} start_us_monitor.sh start 84 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 0755 ${WORKDIR}/rc.local ${D}${sysconfdir}/init.d/rc.local
+ update-rc.d -r ${D} rc.local start 99 2 3 4 5 .
+}
+
+do_install_append() {
+ do_install_board
+}
+
+FILES_${PN} += "${sysconfdir}"
diff --git a/meta-facebook/meta-wedge/recipes-wedge/ipmid/files/Makefile b/meta-facebook/meta-wedge/recipes-wedge/ipmid/files/Makefile
index 8282964..c21df07 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/ipmid/files/Makefile
+++ b/meta-facebook/meta-wedge/recipes-wedge/ipmid/files/Makefile
@@ -1,4 +1,20 @@
# 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: ipmid
ipmid: ipmid.c \
diff --git a/meta-facebook/meta-wedge/recipes-wedge/ipmid/files/setup-ipmid.sh b/meta-facebook/meta-wedge/recipes-wedge/ipmid/files/setup-ipmid.sh
index b1fbbb1..b724d70 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/ipmid/files/setup-ipmid.sh
+++ b/meta-facebook/meta-wedge/recipes-wedge/ipmid/files/setup-ipmid.sh
@@ -2,6 +2,22 @@
#
# 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:
diff --git a/meta-facebook/meta-wedge/recipes-wedge/ipmid/ipmid_0.1.bb b/meta-facebook/meta-wedge/recipes-wedge/ipmid/ipmid_0.1.bb
index 3f9c4a7..7d8fd37 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/ipmid/ipmid_0.1.bb
+++ b/meta-facebook/meta-wedge/recipes-wedge/ipmid/ipmid_0.1.bb
@@ -1,4 +1,19 @@
# 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 = "IPMI Daemon"
DESCRIPTION = "Daemon to handle IPMI Messages."
diff --git a/meta-facebook/meta-wedge/recipes-wedge/lm_sensors/lmsensors_%.bbappend b/meta-facebook/meta-wedge/recipes-wedge/lm_sensors/lmsensors_%.bbappend
index 35433ae..90a3954 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/lm_sensors/lmsensors_%.bbappend
+++ b/meta-facebook/meta-wedge/recipes-wedge/lm_sensors/lmsensors_%.bbappend
@@ -4,7 +4,11 @@ FILESEXTRAPATHS_prepend := "${THISDIR}/files:"
SRC_URI += "file://wedge.conf \
"
-do_install_append() {
+do_install_board_config() {
install -d ${D}${sysconfdir}/sensors.d
install -m 644 ../wedge.conf ${D}${sysconfdir}/sensors.d/wedge.conf
}
+
+do_install_append() {
+ do_install_board_config
+}
diff --git a/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/Makefile b/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/Makefile
index 0c9f49f..00464e5 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/Makefile
+++ b/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/Makefile
@@ -1,4 +1,20 @@
# 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
diff --git a/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/etc/oob-nic.sh b/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/etc/oob-nic.sh
index 35e1a2a..7eaf581 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/etc/oob-nic.sh
+++ b/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/etc/oob-nic.sh
@@ -40,14 +40,12 @@ DESC="OOB NIC Driver"
test -f $DAEMON || exit 0
# enable the isolation buffer
-. /usr/local/fbpackages/utils/ast-functions
-wedge_iso_buf_enable
+. /usr/local/bin/openbmc-utils.sh
fix_etc_interfaces() {
- local intf_conf rev
- intf_conf="/etc/network/interfaces"
- rev=$(wedge_board_rev)
- if [ $rev -lt 3 ]; then
+ local intf_conf board_rev board_type enable_oob
+ if wedge_should_enable_oob; then
+ intf_conf="/etc/network/interfaces"
if ! grep oob $intf_conf > /dev/null 2>&1; then
echo >> $intf_conf
echo "auto oob" >> $intf_conf
diff --git a/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/i2craw.c b/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/i2craw.c
index f9d499b..83f03b7 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/i2craw.c
+++ b/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/i2craw.c
@@ -27,7 +27,7 @@
#include <stdint.h>
#include "facebook/i2c-dev.h"
-#include "facebook/log.h"
+#include "openbmc/log.h"
void usage(const char *prog) {
printf("Usage: %s [options] <bus number> <slave address>\n", prog);
diff --git a/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/intf.c b/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/intf.c
index 5bf8480..81834b9 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/intf.c
+++ b/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/intf.c
@@ -32,7 +32,7 @@
#include <linux/if_tun.h>
#include <linux/fib_rules.h>
-#include "facebook/log.h"
+#include "openbmc/log.h"
#include "libnetlink.h"
#include "ll_map.h"
diff --git a/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/main.c b/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/main.c
index 4312402..2dc1917 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/main.c
+++ b/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/main.c
@@ -24,7 +24,7 @@
#include "nic.h"
#include "intf.h"
-#include "facebook/log.h"
+#include "openbmc/log.h"
#include "facebook/wedge_eeprom.h"
#define WAIT4PACKET_TIMEOUT 10000 /* 10ms */
@@ -129,28 +129,40 @@ int main(int argc, const char **argv) {
/* read EEPROM for the MAC */
if (wedge_eeprom_parse(NULL, &eeprom) == 0) {
- if (eeprom.fbw_mac_size <= 0) {
+ uint16_t carry;
+ int pos;
+ int adj;
+ /*
+ * OOB MAC comes from this range. We pick the last MAC from the range to
+ * use as OOB MAC.
+ */
+ if (eeprom.fbw_mac_size > 128) {
+ LOG_ERR(EFAULT, "Extended MAC size (%d) is too large.",
+ eeprom.fbw_mac_size);
+ carry = 128;
+ } else {
+ carry = eeprom.fbw_mac_size;
+ }
+
+ /*
+ * Due to various manufacture issues, some FC boards have MAC range overlap
+ * between LEFT and RIGHT sides. A SW workaround is done below to use the
+ * 8th (or 7th for right side FC) last MAC from the range for FC.
+ */
+ if (strncmp(eeprom.fbw_location, "LEFT", FBW_EEPROM_F_LOCATION) == 0) {
+ adj = 8;
+ } else if (strncmp(eeprom.fbw_location, "RIGHT", FBW_EEPROM_F_LOCATION)
+ == 0) {
+ adj = 7;
+ } else {
+ adj = 1;
+ }
+
+ if (carry < adj) {
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 */
+ carry -= adj;
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;
diff --git a/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/nic.c b/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/nic.c
index a4dc071..c5fa422 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/nic.c
+++ b/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/nic.c
@@ -17,6 +17,7 @@
*/
#include "nic.h"
+#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
@@ -26,7 +27,9 @@
#include <sys/types.h>
#include "facebook/i2c-dev.h"
-#include "facebook/log.h"
+#include "openbmc/log.h"
+
+#define ETHERTYPE_LLDP 0x88cc
struct oob_nic_t {
int on_bus;
@@ -334,12 +337,25 @@ static int oob_nic_set_force_up(oob_nic *dev, int enable) {
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;
/*
+ * There are 8 filters in total (MDEF0-MDEF7). Any filter that has a
+ * configuration will be applied. Any packet that matches any filter will
+ * be passed to OOB by the main NIC.
+ *
+ * Each filter has two sets of bits, MDEF and MDEF_EXT. Each bit in the
+ * filter represents a filter with its logical operation. For example,
+ * NIC_FILTER_MDEF_MAC_AND_OFFSET(0) represent MAC filter 0 using AND
+ * operation. So, in order to receive packets matching a specific MAC, MAC0
+ * filter (NIC_FILTER_MAC_NUM:NIC_FILTER_MAC_PAIR0) must be programmed
+ * with the specific MAC. Then set NIC_FILTER_MDEF_MAC_AND_OFFSET (for
+ * AND) or NIC_FILTER_MDEF_MAC_OR_OFFSET (for OR) in one of the filters.
+ */
+
+ /*
* Command to set MAC filter
* Seven bytes are required to load the MAC address filters.
* Data 2—MAC address filters pair number (3:0).
@@ -351,9 +367,8 @@ static int oob_nic_setup_filters(oob_nic *dev, const uint8_t mac[6]) {
cmd = buf;
*cmd++ = NIC_FILTER_MAC_NUM;
*cmd++ = NIC_FILTER_MAC_PAIR0; /* pair 0 */
- for (i = 0; i < 6; i++) {
- *cmd++ = mac[i];
- }
+ memcpy(cmd, mac, 6);
+ cmd += 6;
rc = i2c_smbus_write_block_data(dev->on_file, NIC_WRITE_FILTER_CMD,
cmd - buf, buf);
if (rc < 0) {
@@ -380,17 +395,15 @@ static int oob_nic_setup_filters(oob_nic *dev, const uint8_t mac[6]) {
*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;
- }
+ cmd32 = htonl(NIC_FILTER_MDEF_BIT(NIC_FILTER_MDEF_EXT_NET_EN_OFFSET)
+ | NIC_FILTER_MDEF_BIT(NIC_FILTER_MDEF_EXT_HOST_EN_OFFSET));
+ memcpy(cmd, &cmd32, sizeof(cmd32));
+ cmd += sizeof(cmd32);
/* 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;
- }
+ cmd32 = htonl(NIC_FILTER_MDEF_BIT_VAL(NIC_FILTER_MDEF_MAC_AND_OFFSET,
+ NIC_FILTER_MAC_PAIR0));
+ memcpy(cmd, &cmd32, sizeof(cmd32));
+ cmd += sizeof(cmd32);
rc = i2c_smbus_write_block_data(dev->on_file, NIC_WRITE_FILTER_CMD,
cmd - buf, buf);
if (rc < 0) {
@@ -398,23 +411,41 @@ static int oob_nic_setup_filters(oob_nic *dev, const uint8_t mac[6]) {
LOG_ERR(rc, "Failed to set MAC filter to MDEF 0");
return -rc;
}
- /* enable ARP and ND on filter 1*/
+
+ /* Program EtherType0 to match LLDP */
+ cmd = buf;
+ *cmd++ = NIC_FILTER_ETHERTYPE_NUM;
+ *cmd++ = NIC_FILTER_ETHERTYPE0;
+ cmd32 = htonl(ETHERTYPE_LLDP);
+ memcpy(cmd, &cmd32, sizeof(cmd32));
+ cmd += sizeof(cmd32);
+ 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 program EtherType0 to match LLDP");
+ return -rc;
+ }
+
+ /* enable ARP, ND, and EtheryType0 (OR) 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 filter for traffic from network and host, matching ethertype0 */
+ cmd32 = htonl(NIC_FILTER_MDEF_BIT(NIC_FILTER_MDEF_EXT_NET_EN_OFFSET)
+ | NIC_FILTER_MDEF_BIT(NIC_FILTER_MDEF_EXT_HOST_EN_OFFSET)
+ | NIC_FILTER_MDEF_BIT_VAL(
+ NIC_FILTER_MDEF_EXT_ETHTYPE_OR_OFFSET,
+ NIC_FILTER_ETHERTYPE0));
+ memcpy(cmd, &cmd32, sizeof(cmd32));
+ cmd += sizeof(cmd32);
+
/* 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;
- }
+ cmd32 = htonl(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));
+ memcpy(cmd, &cmd32, sizeof(cmd32));
+ cmd += sizeof(cmd32);
rc = i2c_smbus_write_block_data(dev->on_file, NIC_WRITE_FILTER_CMD,
cmd - buf, buf);
if (rc < 0) {
@@ -426,10 +457,9 @@ static int oob_nic_setup_filters(oob_nic *dev, const uint8_t mac[6]) {
/* 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;
- }
+ cmd32 = htonl(NIC_FILTER_MNG_ONLY_FILTER0);
+ memcpy(cmd, &cmd32, sizeof(cmd32));
+ cmd += sizeof(cmd32);
rc = i2c_smbus_write_block_data(dev->on_file, NIC_WRITE_FILTER_CMD,
cmd - buf, buf);
if (rc < 0) {
diff --git a/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/nic_defs.h b/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/nic_defs.h
index 1ae8721..87574f0 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/nic_defs.h
+++ b/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/nic_defs.h
@@ -76,12 +76,6 @@ struct oob_nic_status_t {
/** 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)
@@ -89,6 +83,18 @@ struct oob_nic_status_t {
#define NIC_FILTER_MNG_ONLY_FILTER3 (0x1 << 3)
#define NIC_FILTER_MNG_ONLY_FILTER4 (0x1 << 4)
+#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_ETHERTYPE_NUM 0x67
+#define NIC_FILTER_ETHERTYPE0 0
+#define NIC_FILTER_ETHERTYPE1 1
+#define NIC_FILTER_ETHERTYPE2 2
+#define NIC_FILTER_ETHERTYPE3 3
+
#define NIC_FILTER_DECISION_EXT_NUM 0x68
#define NIC_FILTER_MDEF0 0 /* index 0 */
#define NIC_FILTER_MDEF1 1 /* index 1 */
diff --git a/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic_0.1.bb b/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic_0.1.bb
index 1df83dc..82a5296 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic_0.1.bb
+++ b/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic_0.1.bb
@@ -1,4 +1,19 @@
# 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"
@@ -12,7 +27,7 @@ SRC_URI = "file://src \
S = "${WORKDIR}/src"
-DEPENDS += "fbutils libwedge-eeprom"
+DEPENDS += "openbmc-utils liblog libwedge-eeprom"
RDEPENDS_${PN} += "libwedge-eeprom"
diff --git a/meta-facebook/meta-wedge/recipes-wedge/po-eeprom/files/Makefile b/meta-facebook/meta-wedge/recipes-wedge/po-eeprom/files/Makefile
index 408de95..0b3fd71 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/po-eeprom/files/Makefile
+++ b/meta-facebook/meta-wedge/recipes-wedge/po-eeprom/files/Makefile
@@ -1,4 +1,20 @@
# 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: po-eeprom
po-eeprom: po-eeprom.o
diff --git a/meta-facebook/meta-wedge/recipes-wedge/po-eeprom/po-eeprom_0.1.bb b/meta-facebook/meta-wedge/recipes-wedge/po-eeprom/po-eeprom_0.1.bb
index e1d8b32..ad635dc 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/po-eeprom/po-eeprom_0.1.bb
+++ b/meta-facebook/meta-wedge/recipes-wedge/po-eeprom/po-eeprom_0.1.bb
@@ -1,4 +1,21 @@
# 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 = "PowerOne EEPROM Utilities"
DESCRIPTION = "Util for PowerOne eeprom"
SECTION = "base"
diff --git a/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/Makefile b/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/Makefile
index 4a3c25d..926bf52 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/Makefile
+++ b/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/Makefile
@@ -1,16 +1,40 @@
# Copyright 2014-present Facebook. All Rights Reserved.
-all: modbuscmd gpiowatch modbussim
+#
+# 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
+
+override CFLAGS+=-D_GNU_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=199309 -Wall -Werror -std=c99
+override LDFLAGS+=-pthread
+all: modbuscmd gpiowatch modbussim rackmond rackmondata
+
+rackmondata: rackmondata.c modbus.c
+ $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
+
+rackmond: rackmond.c modbus.c
+ $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
modbuscmd: modbuscmd.c modbus.c
- $(CC) -D_BSD_SOURCE -Wall -Werror -std=c99 -o $@ $^ $(LDFLAGS)
+ $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
modbussim: modbussim.c modbus.c
- $(CC) -D_BSD_SOURCE -Wall -Werror -std=c99 -o $@ $^ $(LDFLAGS)
+ $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
gpiowatch: gpiowatch.c
- $(CC) -D_BSD_SOURCE -Wall -Werror -std=c99 -o $@ $^ $(LDFLAGS)
+ $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
.PHONY: clean
clean:
- rm -rf *.o modbuscmd gpiowatch modbussim
+ rm -rf *.o modbuscmd gpiowatch modbussim rackmond rackmondata
diff --git a/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/hexfile.py b/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/hexfile.py
new file mode 100644
index 0000000..c484fdf
--- /dev/null
+++ b/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/hexfile.py
@@ -0,0 +1,174 @@
+# The MIT License (MIT)
+# =====================
+#
+# Copyright (c) 2014 Ryan Sturmer
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+# https://github.com/ryansturmer/hexfile/blob/master/hexfile/core.py
+
+import itertools
+
+def short(msb,lsb):
+ return (msb<<8) | lsb
+
+class HexFile(object):
+ def __init__(self, segments):
+ self.segments = segments
+
+ def __getitem__(self, val):
+ if isinstance(val, slice):
+ address = val.start
+ else:
+ address = val
+
+ for segment in self.segments:
+ if address in segment:
+ return segment[val]
+
+ raise IndexError('No segment contains address 0x%x' % address)
+
+ def __len__(self):
+ return sum(map(len, self.segments))
+
+ @property
+ def size(self):
+ return len(self)
+
+ def __iter__(self):
+ return itertools.chain(*self.segments)
+
+ @staticmethod
+ def load(filename):
+ segments = [Segment(0)]
+
+ with open(filename) as fp:
+ lines = fp.readlines()
+
+ extended_linear_address = 0
+ current_address = 0
+ end_of_file = False
+
+ lineno = 0
+ for line in lines:
+ lineno += 1
+ line = line.strip();
+ if not line.startswith(':'):
+ continue
+
+ if end_of_file:
+ raise Exception("Record found after end of file on line %d" % lineno)
+
+ bytes = [int(line[i:i+2], 16) for i in range(1,len(line), 2)]
+ byte_count = bytes[0]
+ address = short(*bytes[1:3])
+ record_type = bytes[3]
+ checksum = bytes[-1]
+ data = bytes[4:-1]
+ computed_checksum = ((1 << 8)-(sum(bytes[:-1]) & 0xff)) & 0xff
+
+ if(computed_checksum != checksum):
+ raise Exception("Record checksum doesn't match on line %d" % lineno)
+
+ if record_type == 0:
+ if byte_count == len(data):
+ current_address = (address | extended_linear_address)
+ have_segment = False
+ for segment in segments:
+ if segment.end_address == current_address:
+ segment.data.extend(data)
+ have_segment = True
+ break
+ if not have_segment:
+ segments.append(Segment(current_address, data))
+ else:
+ raise Exception("Data record reported size does not match actual size on line %d" % lineno)
+ elif record_type == 1:
+ end_of_file = True
+ elif record_type == 4:
+ if byte_count != 2 or len(data) != 2:
+ raise Exception("Byte count misreported in extended linear address record on line %d" % lineno)
+ extended_linear_address = short(*data) << 16
+
+ else:
+ raise Exception("Unknown record type: %s" % record_type)
+ return HexFile(segments)
+
+ def pretty_string(self, stride=16):
+ retval = []
+ for segment in self.segments:
+ retval.append('Segment @ 0x%08x (%d bytes)' % (segment.start_address, segment.size))
+ retval.append(segment.pretty_string(stride=stride))
+ retval.append('')
+ return '\n'.join(retval)
+
+def load(filename):
+ return HexFile.load(filename)
+
+class Segment(object):
+ def __init__(self, start_address, data = None):
+ self.start_address = start_address
+ self.data = data or []
+
+ def pretty_string(self, stride=16):
+ retval = []
+ addresses = self.addresses
+ ranges = [addresses[i:i+stride] for i in range(0, self.size, stride)]
+ for r in ranges:
+ retval.append('%08x ' % r[0] + ' '.join(['%02x' % self[addr] for addr in r]))
+ return '\n'.join(retval)
+
+ def __str__(self):
+ return '<%d byte segment @ 0x%08x>' % (self.size, self.start_address)
+ def __repr__(self):
+ return str(self)
+
+ @property
+ def end_address(self):
+ return self.start_address + len(self.data)
+
+ @property
+ def size(self):
+ return len(self.data)
+
+ def __contains__(self, address):
+ return address >= self.start_address and address < self.end_address
+
+ def __getitem__(self, address):
+ if isinstance(address, slice):
+ if address.start not in self or address.stop-1 not in self:
+ raise IndexError('Address out of range for this segment')
+ else:
+ d = self.data[address.start-self.start_address:address.stop-self.start_address:address.step]
+ start_address = address.start + self.start_address
+ return Segment(start_address, d)
+ else:
+ if not address in self:
+ raise IndexError("Address 0x%x is not in this segment" % address)
+ return self.data[address-self.start_address]
+
+ @property
+ def addresses(self):
+ return range(self.start_address, self.end_address)
+
+ def __len__(self):
+ return len(self.data)
+
+ def __iter__(self):
+ return iter(self.data)
diff --git a/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/modbus.c b/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/modbus.c
index 46618a9..8fb0835 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/modbus.c
+++ b/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/modbus.c
@@ -16,6 +16,7 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include <time.h>
#include "modbus.h"
#include <termios.h>
#include <unistd.h>
@@ -26,9 +27,15 @@
#include <string.h>
#include <errno.h>
#include <sys/ioctl.h>
+#include <sched.h>
+#include <pthread.h>
-static int loops = 0;
-void waitfd(int fd) {
+int verbose = 0;
+
+#define TIOCSERWAITTEMT 0x5499
+int waitfd(int fd) {
+ int loops = 0;
+ ioctl(fd, TIOCSERWAITTEMT, DEFAULT_GPIO);
while(1) {
int lsr;
int ret = ioctl(fd, TIOCSERGETLSR, &lsr);
@@ -37,8 +44,10 @@ void waitfd(int fd) {
break;
}
if(lsr & TIOCSER_TEMT) break;
+ // never should hit this with new ioctl
loops++;
}
+ return loops;
}
void gpio_on(int fd) {
@@ -60,8 +69,7 @@ void decode_hex_in_place(char* buf, size_t* len) {
void append_modbus_crc16(char* buf, size_t* len) {
uint16_t crc = modbus_crc16(buf, *len);
- if (verbose)
- fprintf(stderr, "[*] Append Modbus CRC16 %04x\n", crc);
+ dbg("[*] Append Modbus CRC16 %04x\n", crc);
buf[(*len)++] = crc >> 8;
buf[(*len)++] = crc & 0x00FF;
}
@@ -78,7 +86,7 @@ size_t read_wait(int fd, char* dst, size_t maxlen, int mdelay_us) {
size_t read_size = 0;
size_t pos = 0;
memset(dst, 0, maxlen);
- for(;;) {
+ while(pos < maxlen) {
FD_ZERO(&fdset);
FD_SET(fd, &fdset);
timeout.tv_sec = 0;
@@ -95,10 +103,11 @@ size_t read_wait(int fd, char* dst, size_t maxlen, int mdelay_us) {
fprintf(stderr, "read error: %s\n", strerror(errno));
exit(1);
}
- if((pos + read_size) < maxlen) {
+ if((pos + read_size) <= maxlen) {
memcpy(dst + pos, read_buf, read_size);
pos += read_size;
} else {
+ return pos;
fprintf(stderr, "Response buffer overflowed!\n");
}
}
@@ -181,3 +190,163 @@ uint16_t modbus_crc16(char* buffer, size_t buffer_length) {
return (crc_hi << 8 | crc_lo);
}
+
+
+double ts_diff (struct timespec* begin, struct timespec* end) {
+ return 1000.0 * (end->tv_sec) + (1e-6 * end->tv_nsec)
+ - (1000.0 * (begin->tv_sec) + (1e-6 * begin->tv_nsec));
+}
+
+static long success = 0;
+static long crcfail = 0;
+static long timeout = 0;
+static long stat_wait = 0;
+
+int modbuscmd(modbus_req *req) {
+ int error = 0;
+ struct termios tio;
+ char modbus_cmd[req->cmd_len + 2];
+ size_t cmd_len = req->cmd_len;
+
+ if (verbose)
+ fprintf(stderr, "[*] Setting TTY flags!\n");
+ memset(&tio, 0, sizeof(tio));
+ // CREAD should be left *off* until we've confirmed THRE
+ // to avoid catching false character starts
+ cfsetspeed(&tio,B19200);
+ tio.c_cflag |= PARENB;
+ tio.c_cflag |= CLOCAL;
+ tio.c_cflag |= CS8;
+ tio.c_iflag |= INPCK;
+ tio.c_cc[VMIN] = 1;
+ tio.c_cc[VTIME] = 0;
+ CHECK(tcsetattr(req->tty_fd,TCSANOW,&tio));
+
+ memcpy(modbus_cmd, req->modbus_cmd, cmd_len);
+ append_modbus_crc16(modbus_cmd, &cmd_len);
+
+ // print command as sent
+ if (verbose) {
+ fprintf(stderr, "Will send: ");
+ print_hex(stderr, modbus_cmd, cmd_len);
+ fprintf(stderr, "\n");
+ }
+
+ dbg("[*] Writing!\n");
+
+ // hoped adding the ioctl to do the switching would have alleviated the
+ // need to do SCHED_FIFO, but we still get preempted between the write and
+ // ioctl syscalls w/o it often enough to break f/w updates.
+ struct sched_param sp;
+ sp.sched_priority = 50;
+ int policy = SCHED_FIFO;
+ CHECKP(sched, pthread_setschedparam(pthread_self(), policy, &sp));
+ // gpio on, write, wait, gpio off
+ gpio_on(req->gpio_fd);
+ struct timespec write_begin;
+ struct timespec wait_begin;
+ struct timespec wait_end;
+ struct timespec read_end;
+ clock_gettime(CLOCK_MONOTONIC_RAW, &write_begin);
+ write(req->tty_fd, modbus_cmd, cmd_len);
+ clock_gettime(CLOCK_MONOTONIC_RAW, &wait_begin);
+ int waitloops = waitfd(req->tty_fd);
+ clock_gettime(CLOCK_MONOTONIC_RAW, &wait_end);
+ gpio_off(req->gpio_fd);
+ sp.sched_priority = 0;
+ // Enable UART read
+ tio.c_cflag |= CREAD;
+ CHECK(tcsetattr(req->tty_fd,TCSANOW,&tio));
+ policy = SCHED_OTHER;
+ CHECKP(sched, pthread_setschedparam(pthread_self(), policy, &sp));
+
+ dbg("[*] waitfd loops: %d\n", waitloops);
+ dbg("[*] reading any response...\n");
+ // Read back response
+ size_t mb_pos = 0;
+ memset(req->dest_buf, 0, req->dest_limit);
+ if(req->expected_len == 0) {
+ req->expected_len = req->dest_limit;
+ }
+ if(req->expected_len > req->dest_limit) {
+ return -1;
+ }
+ mb_pos = read_wait(req->tty_fd, req->dest_buf, req->expected_len, req->timeout);
+ clock_gettime(CLOCK_MONOTONIC_RAW, &read_end);
+ req->dest_len = mb_pos;
+ if(mb_pos >= 4) {
+ uint16_t crc = modbus_crc16(req->dest_buf, mb_pos - 2);
+ dbg("Modbus response CRC: %04X\n ", crc);
+ if((req->dest_buf[mb_pos - 2] == (crc >> 8)) &&
+ (req->dest_buf[mb_pos - 1] == (crc & 0x00FF))) {
+ dbg("CRC OK!\n");
+ } else {
+ dbg("BAD CRC :(\n");
+ fprintf(stderr, "bad crc timings:");
+ fprintf(stderr, " write: %.2f ms", ts_diff(&write_begin, &wait_begin));
+ fprintf(stderr, " wait: %.2f ms", ts_diff(&wait_begin, &wait_end));
+ fprintf(stderr, " read: %.2f ms\n", ts_diff(&wait_end, &read_end));
+ if(!req->scan) {
+ crcfail++;
+ }
+ if(verbose) {
+ print_hex(stderr, req->dest_buf, mb_pos);
+ }
+ return MODBUS_BAD_CRC;
+ }
+ } else {
+ fprintf(stderr, "timeout timings:");
+ fprintf(stderr, " write: %.2f ms", ts_diff(&write_begin, &wait_begin));
+ fprintf(stderr, " wait: %.2f ms", ts_diff(&wait_begin, &wait_end));
+ fprintf(stderr, " wait: %d iters", waitloops);
+ fprintf(stderr, " read: %.2f ms\n", ts_diff(&wait_end, &read_end));
+ dbg("No response :(\n");
+ if(!req->scan) {
+ timeout++;
+ }
+ return MODBUS_RESPONSE_TIMEOUT;
+ }
+
+cleanup:
+ if(error != 0) {
+ error = -1;
+ fprintf(stderr, "%s\n", strerror(errno));
+ } else {
+ //fprintf(stderr, "success, timings:");
+ //fprintf(stderr, " write: %.2f ms", ts_diff(&write_begin, &wait_begin));
+ //fprintf(stderr, " wait: %.2f ms", ts_diff(&wait_begin, &wait_end));
+ //fprintf(stderr, " read: %.2f ms -- ", ts_diff(&wait_end, &read_end));
+ if(stat_wait == 0 && !req->scan) {
+ fprintf(stderr, "success: %.2f%% crcfail %.2f%%, timeout %.2f%%\n",
+ ((double) 100.0 * success / (success + crcfail + timeout)),
+ ((double) 100.0 * crcfail / (success + crcfail + timeout)),
+ ((double) 100.0 * timeout / (success + crcfail + timeout)));
+ stat_wait = 1000;
+ fprintf(stderr, "success timings:");
+ fprintf(stderr, " write: %.2f ms", ts_diff(&write_begin, &wait_begin));
+ fprintf(stderr, " wait: %.2f ms", ts_diff(&wait_begin, &wait_end));
+ fprintf(stderr, " wait: %d iters", waitloops);
+ fprintf(stderr, " read: %.2f ms\n", ts_diff(&wait_end, &read_end));
+ } else if (!req->scan) {
+ stat_wait--;
+ }
+ if(!req->scan) {
+ success++;
+ }
+ }
+ return 0;
+}
+
+const char* modbus_strerror(int mb_err) {
+ if (mb_err < 0) {
+ mb_err = -mb_err;
+ }
+ switch(mb_err) {
+ case 4:
+ return "timed out";
+ case 5:
+ return "crc check failed";
+ default:
+ return "unknown";
+ }
+}
diff --git a/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/modbus.h b/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/modbus.h
index 435d518..1354feb 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/modbus.h
+++ b/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/modbus.h
@@ -26,12 +26,27 @@ uint16_t modbus_crc16(char* buffer, size_t length);
#define DEFAULT_TTY "/dev/ttyS3"
#define DEFAULT_GPIO 45
-#define CHECK(x) { if((x) < 0) { \
- error = x; \
+extern int verbose;
+#define dbg(...) if(verbose) { fprintf(stderr, __VA_ARGS__); }
+#define log(...) { fprintf(stderr, __VA_ARGS__); }
+
+#define CHECK(expr) { int _check = expr; if((_check) < 0) { \
+ error = _check; \
+ goto cleanup; \
+} }
+#define CHECKP(name, expr) { int _check = expr; if((_check) < 0) { \
+ error = _check; \
+ perror(#name); \
goto cleanup; \
} }
+#define BAIL(...) { \
+ fprintf(stderr, __VA_ARGS__); \
+ fflush(stderr); \
+ error = -1; \
+ goto cleanup; \
+}
-void waitfd(int fd);
+int waitfd(int fd);
void gpio_on(int fd);
void gpio_off(int fd);
void decode_hex_in_place(char* buf, size_t* len);
@@ -41,6 +56,30 @@ void print_hex(FILE* f, char* buf, size_t len);
// Read until maxlen bytes or no bytes in mdelay_us microseconds
size_t read_wait(int fd, char* dst, size_t maxlen, int mdelay_us);
-extern int verbose;
+
+typedef struct _modbus_req {
+ int tty_fd;
+ int gpio_fd;
+ const char *modbus_cmd;
+ size_t cmd_len;
+ int timeout;
+ size_t expected_len;
+ char *dest_buf;
+ size_t dest_limit;
+ size_t dest_len;
+ int scan;
+} modbus_req;
+
+int modbuscmd(modbus_req *req);
+// Modbus errors
+
+#define MODBUS_RESPONSE_TIMEOUT -4
+#define MODBUS_BAD_CRC -5
+
+const char* modbus_strerror(int mb_err);
+
+// Modbus constants
+#define MODBUS_READ_HOLDING_REGISTERS 3
+
#endif
diff --git a/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/modbuscmd.c b/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/modbuscmd.c
index 2d33039..78f62a1 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/modbuscmd.c
+++ b/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/modbuscmd.c
@@ -16,51 +16,54 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <termios.h>
-#include <unistd.h>
+#include <errno.h>
#include <fcntl.h>
-#include <stdlib.h>
+#include <getopt.h>
+#include <sched.h>
#include <stdint.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
-#include <errno.h>
+#include <unistd.h>
#include <sys/ioctl.h>
-#include <getopt.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
#include "modbus.h"
-
-int verbose;
+#include "rackmond.h"
void usage() {
fprintf(stderr,
- "modbuscmd [-v] [-t <tty>] [-g <gpio>] modbus_command\n"
- "\ttty defaults to %s\n"
- "\tgpio defaults to %d\n"
+ "modbuscmd [-v] [-t <timeout in ms>] [-x <expected response length>] modbus_command\n"
"\tmodbus command should be specified in hex\n"
- "\teg:\ta40300000008\n",
- DEFAULT_TTY, DEFAULT_GPIO);
+ "\teg:\ta40300000008\n"
+ "\tif an expected response length is provided, modbuscmd will stop receving and check crc immediately "
+ "after receiving that many bytes\n");
exit(1);
}
+
int main(int argc, char **argv) {
int error = 0;
- int fd;
- struct termios tio;
- char gpio_filename[255];
- int gpio_fd = 0;
- int gpio_n = DEFAULT_GPIO;
- char *tty = DEFAULT_TTY;
char *modbus_cmd = NULL;
size_t cmd_len = 0;
+ int expected = 0;
+ uint32_t timeout = 0;
verbose = 0;
+ rackmond_command *cmd = NULL;
+ char *response = NULL;
+ int clisock;
+ uint16_t response_len_actual;
+ struct sockaddr_un rackmond_addr;
int opt;
- while((opt = getopt(argc, argv, "t:g:v")) != -1) {
+ while((opt = getopt(argc, argv, "w:x:t:g:v")) != -1) {
switch (opt) {
- case 't':
- tty = optarg;
+ case 'x':
+ expected = atoi(optarg);
break;
- case 'g':
- gpio_n = atoi(optarg);
+ case 't':
+ timeout = atol(optarg);
break;
case 'v':
verbose = 1;
@@ -77,29 +80,6 @@ int main(int argc, char **argv) {
usage();
}
- if (verbose)
- fprintf(stderr, "[*] Opening TTY\n");
- fd = open(tty, O_RDWR | O_NOCTTY);
- CHECK(fd);
-
- if (verbose)
- fprintf(stderr, "[*] Opening GPIO %d\n", gpio_n);
- snprintf(gpio_filename, 255, "/sys/class/gpio/gpio%d/value", gpio_n);
- gpio_fd = open(gpio_filename, O_WRONLY | O_SYNC);
- CHECK(gpio_fd);
-
- if (verbose)
- fprintf(stderr, "[*] Setting TTY flags!\n");
- memset(&tio, 0, sizeof(tio));
- cfsetspeed(&tio,B19200);
- tio.c_cflag |= PARENB;
- tio.c_cflag |= CLOCAL;
- tio.c_cflag |= CS8;
- tio.c_iflag |= INPCK;
- tio.c_cc[VMIN] = 1;
- tio.c_cc[VTIME] = 0;
- CHECK(tcsetattr(fd,TCSANOW,&tio));
-
//convert hex to bytes
cmd_len = strlen(modbus_cmd);
if(cmd_len < 4) {
@@ -107,57 +87,45 @@ int main(int argc, char **argv) {
exit(1);
}
decode_hex_in_place(modbus_cmd, &cmd_len);
- append_modbus_crc16(modbus_cmd, &cmd_len);
- // print command as sent
- if (verbose) {
- fprintf(stderr, "Will send: ");
- print_hex(stderr, modbus_cmd, cmd_len);
- fprintf(stderr, "\n");
- }
-
- if (verbose)
- fprintf(stderr, "[*] Writing!\n");
-
- // gpio on, write, wait, gpio off
- gpio_on(gpio_fd);
- write(fd, modbus_cmd, cmd_len);
- waitfd(fd);
- gpio_off(gpio_fd);
+ cmd = malloc(sizeof(rackmond_command) + cmd_len);
+ cmd->type = COMMAND_TYPE_RAW_MODBUS;
+ cmd->raw_modbus.length = cmd_len;
+ cmd->raw_modbus.custom_timeout = timeout;
+ memcpy(cmd->raw_modbus.data, modbus_cmd, cmd_len);
+ cmd->raw_modbus.expected_response_length = expected;
+ response = malloc(expected ? expected : 1024);
+ uint16_t wire_cmd_len = sizeof(rackmond_command) + cmd_len;
- // Enable UART read
- tio.c_cflag |= CREAD;
- CHECK(tcsetattr(fd,TCSANOW,&tio));
-
- if(verbose)
- fprintf(stderr, "[*] reading any response...\n");
- // Read back response
- char modbus_buf[255];
- size_t mb_pos = 0;
- memset(modbus_buf, 0, sizeof(modbus_buf));
- mb_pos = read_wait(fd, modbus_buf, sizeof(modbus_buf), 90000);
- if(mb_pos >= 4) {
- uint16_t crc = modbus_crc16(modbus_buf, mb_pos - 2);
- if(verbose)
- fprintf(stderr, "Modbus response CRC: %04X\n ", crc);
- if((modbus_buf[mb_pos - 2] == (crc >> 8)) &&
- (modbus_buf[mb_pos - 1] == (crc & 0x00FF))) {
- if(verbose)
- fprintf(stderr, "CRC OK!\n");
- print_hex(stdout, modbus_buf, mb_pos);
- printf("\n");
- } else {
- fprintf(stderr, "BAD CRC :(\n");
- return 5;
- }
- } else {
- fprintf(stderr, "No response :(\n");
- return 4;
+ clisock = socket(AF_UNIX, SOCK_STREAM, 0);
+ CHECKP(socket, clisock);
+ rackmond_addr.sun_family = AF_UNIX;
+ strcpy(rackmond_addr.sun_path, "/var/run/rackmond.sock");
+ int addr_len = strlen(rackmond_addr.sun_path) + sizeof(rackmond_addr.sun_family);
+ CHECKP(connect, connect(clisock, (struct sockaddr*) &rackmond_addr, addr_len));
+ CHECKP(send, send(clisock, &wire_cmd_len, sizeof(wire_cmd_len), 0));
+ CHECKP(send, send(clisock, cmd, wire_cmd_len, 0));
+ CHECKP(recv, recv(clisock, &response_len_actual, sizeof(response_len_actual), 0));
+ if(response_len_actual == 0) {
+ uint16_t errcode = 0;
+ CHECKP(recv, recv(clisock, &errcode, sizeof(errcode), 0));
+ fprintf(stderr, "modbus error: %d (%s)\n", errcode, modbus_strerror(errcode));
+ error = 1;
+ goto cleanup;
+ }
+ CHECKP(recv, recv(clisock, response, response_len_actual, 0));
+ if(error == 0) {
+ printf("Response: ");
+ print_hex(stdout, response, response_len_actual);
+ printf("\n");
}
-
cleanup:
+ free(cmd);
+ free(response);
if(error != 0) {
+ if(errno != 0) {
+ fprintf(stderr, "errno err: %s\n", strerror(errno));
+ }
error = 1;
- fprintf(stderr, "%s\n", strerror(errno));
}
return error;
}
diff --git a/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/modbussim.c b/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/modbussim.c
index bf8c6c8..e276501 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/modbussim.c
+++ b/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/modbussim.c
@@ -28,8 +28,6 @@
#include <getopt.h>
#include "modbus.h"
-int verbose = 0;
-
void usage() {
fprintf(stderr,
"modbussim [-v] [-t <tty>] [-g <gpio>] modbus_request modbus_reply\n"
diff --git a/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/psu-update-delta.py b/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/psu-update-delta.py
new file mode 100755
index 0000000..a92cf8e
--- /dev/null
+++ b/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/psu-update-delta.py
@@ -0,0 +1,269 @@
+#!/usr/bin/env python
+from __future__ import print_function
+
+import os.path
+import socket
+import struct
+import sys
+import argparse
+import traceback
+
+import hexfile
+
+
+def auto_int(x):
+ return int(x, 0)
+
+
+parser = argparse.ArgumentParser()
+parser.add_argument('--addr', type=auto_int, required=True,
+ help="PSU Modbus Address")
+parser.add_argument('file', help="firmware file")
+
+
+class ModbusTimeout(Exception):
+ pass
+
+
+class ModbusCRCFail(Exception):
+ pass
+
+
+class ModbusUnknownError(Exception):
+ pass
+
+
+class BadMEIResponse(Exception):
+ pass
+
+
+def rackmon_command(cmd):
+ srvpath = "/var/run/rackmond.sock"
+ replydata = []
+ if os.path.exists(srvpath):
+ client = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+ client.connect(srvpath)
+ cmdlen = struct.pack("@H", len(cmd))
+ client.send(cmdlen)
+ client.send(cmd)
+ while True:
+ data = client.recv(1024)
+ if not data:
+ break
+ replydata.append(data)
+ client.close()
+ return ''.join(replydata)
+
+
+def pause_monitoring():
+ COMMAND_TYPE_PAUSE_MONITORING = 0x04
+ command = struct.pack("@Hxx", COMMAND_TYPE_PAUSE_MONITORING)
+ result = rackmon_command(command)
+ (res_n, ) = struct.unpack("@B", result)
+ if res_n == 1:
+ print("Monitoring was already paused when tried to pause")
+ elif res_n == 0:
+ print("Monitoring paused")
+ else:
+ print("Unknown response pausing monitoring: %d" % res_n)
+
+
+def resume_monitoring():
+ COMMAND_TYPE_START_MONITORING = 0x05
+ command = struct.pack("@Hxx", COMMAND_TYPE_START_MONITORING)
+ result = rackmon_command(command)
+ (res_n, ) = struct.unpack("@B", result)
+ if res_n == 1:
+ print("Monitoring was already running when tried to resume")
+ elif res_n == 0:
+ print("Monitoring resumed")
+ else:
+ print("Unknown response resuming monitoring: %d" % res_n)
+
+
+def modbuscmd(raw_cmd, expected=0, timeout=0):
+ COMMAND_TYPE_RAW_MODBUS = 1
+ send_command = struct.pack("@HxxHHL",
+ COMMAND_TYPE_RAW_MODBUS,
+ len(raw_cmd),
+ expected,
+ timeout) + raw_cmd
+ result = rackmon_command(send_command)
+ if len(result) == 0:
+ raise ModbusUnknownError()
+ (resp_len,) = struct.unpack("@H", result[:2])
+ if resp_len == 0:
+ (error, ) = struct.unpack("@H", result[2:4])
+ if error == 4:
+ raise ModbusTimeout()
+ if error == 5:
+ raise ModbusCRCFail()
+ print("Unknown modbus error: " + str(error))
+ raise ModbusUnknownError()
+ return result[2:resp_len]
+
+
+def mei_command(addr, func_code, mei_type=0x64, data=None, timeout=0):
+ i_data = data
+ if i_data is None:
+ i_data = ("\xFF" * 7)
+ if len(i_data) < 7:
+ i_data = i_data + ("\xFF" * (7 - len(i_data)))
+ assert len(i_data) == 7
+ command = struct.pack("BBBB", addr, 0x2b, mei_type, func_code) + i_data
+ return modbuscmd(command, expected=13, timeout=timeout)
+
+
+def enter_bootloader(addr):
+ try:
+ print("Entering bootloader...")
+ mei_command(addr, 0xFB, timeout=4000)
+ except ModbusTimeout:
+ print("Enter bootloader timed out (expected.)")
+ pass
+
+
+def mei_expect(response, addr, data_pfx, error, success_mei_type=0x71):
+ expected = struct.pack("BBB", addr, 0x2B, success_mei_type) + \
+ data_pfx + ("\xFF" * (8 - len(data_pfx)))
+ if response != expected:
+ print(error + ", response: " + response.encode('hex'))
+ raise BadMEIResponse()
+
+
+def start_programming(addr):
+ print("Send start programming...")
+ response = mei_command(addr, 0x70, timeout=10000)
+ mei_expect(response, addr, "\xB0", "Start programming failed")
+ print("Start programming succeeded.")
+
+
+def get_challenge(addr):
+ print("Send get seed")
+ response = mei_command(addr, 0x27, timeout=3000)
+ expected = struct.pack("BBBB", addr, 0x2B, 0x71, 0x67)
+ if response[:len(expected)] != expected:
+ print("Bad response to get seed: " + response.encode('hex'))
+ raise BadMEIResponse()
+ challenge = response[len(expected):len(expected) + 4]
+ print("Got seed: " + challenge.encode('hex'))
+ return challenge
+
+
+def send_key(addr, key):
+ print("Send key")
+ response = mei_command(addr, 0x28, data=key, timeout=3000)
+ mei_expect(response, addr, "\x68", "Start programming failed")
+ print("Send key successful.")
+
+
+def delta_seccalckey(challenge):
+ (seed, ) = struct.unpack(">L", challenge)
+ for i in range(32):
+ if seed & 1 != 0:
+ seed = seed ^ 0xc758a5b6
+ seed = (seed >> 1) & 0x7fffffff
+ seed = seed ^ 0x06854137
+ return struct.pack(">L", seed)
+
+
+def verify_flash(addr):
+ print("Verifying program...")
+ response = mei_command(addr, 0x76, timeout=60000)
+ mei_expect(response, addr, "\xB6", "Program verification failed")
+
+
+def set_write_address(psu_addr, flash_addr):
+ # print("Set write address to " + hex(flash_addr))
+ data = struct.pack(">LB", flash_addr, 0xEA)
+ response = mei_command(psu_addr, 0x61, data=data, timeout=3000)
+ mei_expect(response, psu_addr, "\xA1\xEA", "Set address failed")
+
+
+def write_data(addr, data):
+ assert(len(data) == 8)
+ command = struct.pack(">BBB", addr, 0x2b, 0x65) + data
+ response = modbuscmd(command, expected=13, timeout=3000)
+ expected = struct.pack(">B", addr) +\
+ "\x2b\x73\xf0\xaa\xff\xff\xff\xff\xff\xff"
+ if response != expected:
+ print("Bad response to writing data: " +
+ response.encode('hex'))
+ raise BadMEIResponse()
+
+
+def send_image(addr, fwimg):
+ total_chunks = sum([len(s) for s in fwimg.segments]) / 8
+ sent_chunks = 0
+ for s in fwimg.segments:
+ if len(s) == 0:
+ continue
+ print("Sending " + str(s))
+ set_write_address(addr, s.start_address)
+ for i in xrange(0, len(s), 8):
+ chunk = s.data[i:i+8]
+ if len(chunk) < 8:
+ chunk = chunk + ("\xFF" * (8 - len(chunk)))
+ sent_chunks += 1
+ print("\r[%.2f%%] Sending chunk %d of %d..." %
+ (sent_chunks * 100.0 / total_chunks,
+ sent_chunks, total_chunks), end="")
+ sys.stdout.flush()
+ write_data(addr, str(bytearray(chunk)))
+ print("")
+
+
+def reset_psu(addr):
+ print("Resetting PSU...")
+ try:
+ response = mei_command(addr, 0x72, timeout=10000)
+ except ModbusTimeout:
+ print("No reply from PSU reset (expected.)")
+ return
+ expected = struct.pack(">BBBB", addr, 0x2b, 0x71, 0xb2) +\
+ ("\xFF" * 7)
+ if response != expected:
+ print("Bad response to unit reset request: " +
+ response.encode('hex'))
+ raise BadMEIResponse()
+
+
+def erase_flash(addr):
+ print("Erasing flash... ")
+ sys.stdout.flush()
+ response = mei_command(addr, 0x65, timeout=30000)
+ expected = struct.pack(">BBBB", addr, 0x2b, 0x71, 0xa5) +\
+ ("\xFF" * 7)
+ if response != expected:
+ print("Bad response to erasing flash: " +
+ response.encode('hex'))
+ raise BadMEIResponse()
+
+
+def update_psu(addr, filename):
+ pause_monitoring()
+ fwimg = hexfile.load(filename)
+ enter_bootloader(addr)
+ start_programming(addr)
+ challenge = get_challenge(addr)
+ send_key(addr, delta_seccalckey(challenge))
+ erase_flash(addr)
+ send_image(addr, fwimg)
+ verify_flash(addr)
+ reset_psu(addr)
+
+
+def main():
+ args = parser.parse_args()
+ try:
+ update_psu(args.addr, args.file)
+ except:
+ traceback.print_exc()
+ print("Firmware update failed")
+ resume_monitoring()
+ sys.exit(1)
+ resume_monitoring()
+ sys.exit(0)
+
+if __name__ == "__main__":
+ main()
diff --git a/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/rackmon-config.py b/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/rackmon-config.py
new file mode 100644
index 0000000..e93dfae
--- /dev/null
+++ b/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/rackmon-config.py
@@ -0,0 +1,93 @@
+from __future__ import print_function
+import struct
+import socket
+import os, os.path
+
+reglist = [
+ {"begin": 0x0, #MFR_MODEL
+ "length": 8},
+ {"begin": 0x10, #MFR_DATE
+ "length": 8},
+ {"begin": 0x20, #FB Part #
+ "length": 8},
+ {"begin": 0x30, #HW Revision
+ "length": 4},
+ {"begin": 0x38, #FW Revision
+ "length": 4},
+ {"begin": 0x40, #MFR Serial #
+ "length": 16},
+ {"begin": 0x60, #Workorder #
+ "length": 4},
+ {"begin": 0x68, #PSU Status
+ "length": 1,
+ "keep": 10, # 10-sample ring buffer
+ "flags": 1},
+ {"begin": 0x69, #Battery Status
+ "length": 1,
+ "keep": 10, # 10-sample ring buffer
+ "flags": 1},
+ {"begin": 0x80, #Input VAC
+ "length": 1,
+ "keep": 10},
+ {"begin": 0x82, #Input Current AC
+ "length": 1,
+ "keep": 10},
+ {"begin": 0x84, #Battery Voltage
+ "length": 1,
+ "keep": 10},
+ {"begin": 0x86, #Battery Current Output
+ "length": 1},
+ {"begin": 0x88, #Battery Current Input
+ "length": 1},
+ {"begin": 0x8A, #Output Voltage (main converter)
+ "length": 1,
+ "keep": 10},
+ {"begin": 0x8C, #Output Current (main converter)
+ "length": 1,
+ "keep": 10},
+ {"begin": 0x8E, #IT Load Voltage Output
+ "length": 1},
+ {"begin": 0x90, #IT Load Current Output
+ "length": 1},
+ {"begin": 0x92, #Bulk Cap Voltage
+ "length": 1},
+ {"begin": 0x94, #Input Power
+ "length": 1,
+ "keep": 10},
+ {"begin": 0x96, #Output Power
+ "length": 1,
+ "keep": 10},
+ {"begin": 0x98, #RPM Fan 0
+ "length": 1},
+ {"begin": 0x9A, #RPM Fan 1
+ "length": 1},
+ {"begin": 0x9E, #Temp 0
+ "length": 1},
+ {"begin": 0xA0, #Temp 1
+ "length": 1},
+]
+
+def main():
+ COMMAND_TYPE_SET_CONFIG = 2
+ config_command = struct.pack("@HxxH",
+ COMMAND_TYPE_SET_CONFIG,
+ len(reglist))
+ for r in reglist:
+ keep = 1
+ if "keep" in r:
+ keep = r["keep"]
+ flags = 0
+ if "flags" in r:
+ flags = r["flags"]
+ monitor_interval = struct.pack("@HHHH", r["begin"], r["length"], keep, flags)
+ config_command += monitor_interval
+
+ config_packet = struct.pack("H", len(config_command)) + config_command
+ srvpath = "/var/run/rackmond.sock"
+ if os.path.exists(srvpath):
+ client = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+ client.connect(srvpath)
+ client.send(config_packet)
+
+if __name__ == "__main__":
+ main()
diff --git a/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/rackmond.c b/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/rackmond.c
new file mode 100644
index 0000000..cce3ba4
--- /dev/null
+++ b/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/rackmond.c
@@ -0,0 +1,637 @@
+#include "modbus.h"
+#include "rackmond.h"
+#include <string.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <poll.h>
+#include <time.h>
+#include <stdarg.h>
+#include <syslog.h>
+#include <signal.h>
+
+#define MAX_ACTIVE_ADDRS 12
+#define REGISTER_PSU_STATUS 0x68
+
+struct _lock_holder {
+ pthread_mutex_t *lock;
+ int held;
+};
+
+#define lock_holder(holder_name, lock_expr) \
+ struct _lock_holder holder_name; \
+ holder_name.lock = lock_expr; \
+ holder_name.held = 0;
+
+#define lock_take(holder_name) { \
+ pthread_mutex_lock(holder_name.lock); \
+ holder_name.held = 1; \
+}
+
+#define lock_release(holder_name) { \
+ if(holder_name.held) { \
+ pthread_mutex_unlock(holder_name.lock); \
+ holder_name.held = 0; \
+ } \
+}
+
+int scanning = 0;
+
+typedef struct _rs485_dev {
+ // hold this for the duration of a command
+ pthread_mutex_t lock;
+ int tty_fd;
+ int gpio_fd;
+} rs485_dev;
+
+typedef struct _register_req {
+ uint16_t begin;
+ int num;
+} register_req;
+
+typedef struct register_range_data {
+ monitor_interval* i;
+ void* mem_begin;
+ size_t mem_pos;
+} register_range_data;
+
+typedef struct monitoring_data {
+ uint8_t addr;
+ register_range_data range_data[1];
+} monitoring_data;
+
+typedef struct _rackmond_data {
+ // global rackmond lock
+ pthread_mutex_t lock;
+ // number of register read commands to send to each PSU
+ int num_reqs;
+ // register read commands (begin+length)
+ register_req *reqs;
+ monitoring_config *config;
+
+ uint8_t num_active_addrs;
+ uint8_t active_addrs[MAX_ACTIVE_ADDRS];
+ monitoring_data* stored_data[MAX_ACTIVE_ADDRS];
+ FILE *status_log;
+
+ // timeout in nanosecs
+ int modbus_timeout;
+
+ int paused;
+
+ rs485_dev rs485;
+} rackmond_data;
+
+rackmond_data world;
+
+char psu_address(int rack, int shelf, int psu) {
+ int rack_a = ((rack & 3) << 3);
+ int shelf_a = ((shelf & 1) << 2);
+ int psu_a = (psu & 3);
+ return 0xA0 | rack_a | shelf_a | psu_a;
+}
+
+int modbus_command(rs485_dev* dev, int timeout, char* command, size_t len, char* destbuf, size_t dest_limit, size_t expect) {
+ int error = 0;
+ lock_holder(devlock, &dev->lock);
+ modbus_req req;
+ req.tty_fd = dev->tty_fd;
+ req.gpio_fd = dev->gpio_fd;
+ req.modbus_cmd = command;
+ req.cmd_len = len;
+ req.dest_buf = destbuf;
+ req.dest_limit = dest_limit;
+ req.timeout = timeout;
+ req.expected_len = expect != 0 ? expect : dest_limit;
+ req.scan = scanning;
+ lock_take(devlock);
+ int cmd_error = modbuscmd(&req);
+ CHECK(cmd_error);
+cleanup:
+ lock_release(devlock);
+ if (error >= 0) {
+ return req.dest_len;
+ }
+
+ return error;
+}
+
+int read_registers(rs485_dev *dev, int timeout, uint8_t addr, uint16_t begin, uint16_t num, uint16_t* out) {
+ int error = 0;
+ // address, function, begin, length in # of regs
+ char command[sizeof(addr) + 1 + sizeof(begin) + sizeof(num)];
+ // address, function, length (1 byte), data (2 bytes per register), crc
+ // (VLA)
+ char response[sizeof(addr) + 1 + 1 + (2 * num) + 2];
+ command[0] = addr;
+ command[1] = MODBUS_READ_HOLDING_REGISTERS;
+ command[2] = begin << 8;
+ command[3] = begin & 0xFF;
+ command[4] = num << 8;
+ command[5] = num & 0xFF;
+
+ int dest_len =
+ modbus_command(
+ dev, timeout,
+ command, sizeof(addr) + 1 + sizeof(begin) + sizeof(num),
+ response, sizeof(addr) + 1 + 1 + (2 * num) + 2, 0);
+ CHECK(dest_len);
+
+ if (dest_len >= 5) {
+ memcpy(out, response + 3, num * 2);
+ } else {
+ log("Unexpected short but CRC correct response!\n");
+ error = -1;
+ goto cleanup;
+ }
+ if (response[0] != addr) {
+ log("Got response for addr %02x when expected %02x\n", response[0], addr);
+ error = -1;
+ goto cleanup;
+ }
+ if (response[2] != (num * 2)) {
+ log("Got %d register data bytes when expecting %d\n", response[2], (num * 2));
+ error = -1;
+ goto cleanup;
+ }
+cleanup:
+ return error;
+}
+
+int sub_uint8s(const void* a, const void* b) {
+ return (*(uint8_t*)a) - (*(uint8_t*)b);
+}
+
+int check_active_psus() {
+ int error = 0;
+ lock_holder(worldlock, &world.lock);
+ lock_take(worldlock);
+ if (world.paused == 1) {
+ usleep(1000);
+ goto cleanup;
+ }
+ if (world.config == NULL) {
+ lock_release(worldlock);
+ usleep(5000);
+ goto cleanup;
+ }
+ world.num_active_addrs = 0;
+
+ scanning = 1;
+ //fprintf(stderr, "Begin presence check: ");
+ for(int rack = 0; rack < 3; rack++) {
+ for(int shelf = 0; shelf < 2; shelf++) {
+ for(int psu = 0; psu < 3; psu++) {
+ char addr = psu_address(rack, shelf, psu);
+ uint16_t status = 0;
+ int err = read_registers(&world.rs485, world.modbus_timeout, addr, REGISTER_PSU_STATUS, 1, &status);
+ if (err == 0) {
+ world.active_addrs[world.num_active_addrs] = addr;
+ world.num_active_addrs++;
+ //fprintf(stderr, "%02x - active (%04x) ", addr, status);
+ } else {
+ dbg("%02x - %d; ", addr, err);
+ }
+ }
+ }
+ }
+ //its the only stdlib sort
+ qsort(world.active_addrs, world.num_active_addrs,
+ sizeof(uint8_t), sub_uint8s);
+cleanup:
+ scanning = 0;
+ lock_release(worldlock);
+ return error;
+}
+
+monitoring_data* alloc_monitoring_data(uint8_t addr) {
+ size_t size = sizeof(monitoring_data) +
+ sizeof(register_range_data) * world.config->num_intervals;
+ for(int i = 0; i < world.config->num_intervals; i++) {
+ monitor_interval *iv = &world.config->intervals[i];
+ int pitch = sizeof(uint32_t) + (sizeof(uint16_t) * iv->len);
+ int data_size = pitch * iv->keep;
+ size += data_size;
+ }
+ monitoring_data* d = calloc(1, size);
+ if (d == NULL) {
+ log("Failed to allocate memory for sensor data.\n");
+ return NULL;
+ }
+ d->addr = addr;
+ void* mem = d;
+ mem = mem + (sizeof(monitoring_data) +
+ sizeof(register_range_data) * world.config->num_intervals);
+ for(int i = 0; i < world.config->num_intervals; i++) {
+ monitor_interval *iv = &world.config->intervals[i];
+ int pitch = sizeof(uint32_t) + (sizeof(uint16_t) * iv->len);
+ int data_size = pitch * iv->keep;
+ d->range_data[i].i = iv;
+ d->range_data[i].mem_begin = mem;
+ d->range_data[i].mem_pos = 0;
+ mem = mem + data_size;
+ }
+ return d;
+}
+
+int sub_storeptrs(const void* va, const void *vb) {
+ //more *s than i like :/
+ monitoring_data* a = *(monitoring_data**)va;
+ monitoring_data* b = *(monitoring_data**)vb;
+ //nulls to the end
+ if (b == NULL && a == NULL) {
+ return 0;
+ }
+ if (b == NULL) {
+ return -1;
+ }
+ if (a == NULL) {
+ return 1;
+ }
+ return a->addr - b->addr;
+}
+
+int alloc_monitoring_datas() {
+ int error = 0;
+ if (world.config == NULL) {
+ goto cleanup;
+ }
+ qsort(world.stored_data, MAX_ACTIVE_ADDRS,
+ sizeof(monitoring_data*), sub_storeptrs);
+ int data_pos = 0;
+ for(int i = 0; i < world.num_active_addrs; i++) {
+ uint8_t addr = world.active_addrs[i];
+ while(world.stored_data[data_pos] != NULL &&
+ world.stored_data[data_pos]->addr != addr) {
+ data_pos++;
+ }
+ if (world.stored_data[data_pos] == NULL) {
+ log("Detected PSU at address 0x%02x\n", addr);
+ //syslog(LOG_INFO, "Detected PSU at address 0x%02x", addr);
+ world.stored_data[data_pos] = alloc_monitoring_data(addr);
+ if (world.stored_data[data_pos] == NULL) {
+ BAIL("allocation failed\n");
+ }
+ //reset search pos after alloc (post-sorted addrs may already be alloc'd, need to check again)
+ data_pos = 0;
+ continue;
+ }
+ if (world.stored_data[data_pos]->addr == addr) {
+ continue;
+ }
+ BAIL("shouldn't get here!\n");
+ }
+cleanup:
+ return error;
+}
+
+void record_data(register_range_data* rd, uint32_t time, uint16_t* regs) {
+ int n_regs = (rd->i->len);
+ int pitch = sizeof(time) + (sizeof(uint16_t) * n_regs);
+ int mem_size = pitch * rd->i->keep;
+
+ memcpy(rd->mem_begin + rd->mem_pos, &time, sizeof(time));
+ rd->mem_pos += sizeof(time);
+ memcpy(rd->mem_begin + rd->mem_pos, regs, n_regs * sizeof(uint16_t));
+ rd->mem_pos += n_regs * sizeof(uint16_t);
+ rd->mem_pos = rd->mem_pos % mem_size;
+}
+
+int fetch_monitored_data() {
+ int error = 0;
+ int data_pos = 0;
+ lock_holder(worldlock, &world.lock);
+ lock_take(worldlock);
+ if (world.paused == 1) {
+ usleep(1000);
+ goto cleanup;
+ }
+ if (world.config == NULL) {
+ goto cleanup;
+ }
+ lock_release(worldlock);
+
+ usleep(1000); // wait a sec btween PSUs to not overload RT scheduling
+ // threshold
+ while(world.stored_data[data_pos] != NULL && data_pos < MAX_ACTIVE_ADDRS) {
+ uint8_t addr = world.stored_data[data_pos]->addr;
+ //log("readpsu %02x\n", addr);
+ for(int r = 0; r < world.config->num_intervals; r++) {
+ register_range_data* rd = &world.stored_data[data_pos]->range_data[r];
+ monitor_interval* i = rd->i;
+ uint16_t regs[i->len];
+ int err = read_registers(&world.rs485,
+ world.modbus_timeout, addr, i->begin, i->len, regs);
+ if (err) {
+ log("Error %d reading %02x registers at %02x from %02x\n",
+ err, i->len, i->begin, addr);
+ continue;
+ }
+ struct timespec ts;
+ clock_gettime(CLOCK_REALTIME, &ts);
+ uint32_t timestamp = ts.tv_sec;
+ if (rd->i->flags & MONITOR_FLAG_ONLY_CHANGES) {
+ int pitch = sizeof(timestamp) + (sizeof(uint16_t) * i->len);
+ int lastpos = rd->mem_pos - pitch;
+ if (lastpos < 0) {
+ lastpos = (pitch * rd->i->keep) - pitch;
+ }
+ if (!memcmp(rd->mem_begin + lastpos + sizeof(timestamp),
+ regs, sizeof(uint16_t) * i->len) &&
+ memcmp(rd->mem_begin, "\x00\x00\x00\x00", 4)) {
+ continue;
+ }
+
+ if (world.status_log) {
+ time_t rawt;
+ struct tm* ti;
+ time(&rawt);
+ ti = localtime(&rawt);
+ char timestr[80];
+ strftime(timestr, sizeof(timestr), "%b %e %T", ti);
+ fprintf(world.status_log,
+ "%s: Change to status register %02x on address %02x. New value: %02x\n",
+ timestr, i->begin, addr, regs[0]);
+ fflush(world.status_log);
+ }
+
+ }
+ lock_take(worldlock);
+ record_data(rd, timestamp, regs);
+ lock_release(worldlock);
+ }
+ data_pos++;
+ }
+cleanup:
+ lock_release(worldlock);
+ return error;
+}
+
+// check for new psus every N rounds of sensor reads
+#define SEARCH_PSUS_EVERY 200
+void* monitoring_loop(void* arg) {
+ (void) arg;
+ int until_search = 0;
+ world.status_log = fopen("/var/log/psu-status.log", "a+");
+ while(1) {
+ if (until_search == 0) {
+ check_active_psus();
+ alloc_monitoring_datas();
+ until_search = SEARCH_PSUS_EVERY;
+ } else {
+ until_search--;
+ }
+ fetch_monitored_data();
+ }
+ return NULL;
+}
+
+int open_rs485_dev(const char* tty_filename, int gpio_num, rs485_dev *dev) {
+ int error = 0;
+ int tty_fd, gpio_fd;
+ char gpio_filename[128];
+ dbg("[*] Opening TTY\n");
+ tty_fd = open(tty_filename, O_RDWR | O_NOCTTY);
+ CHECK(tty_fd);
+
+ dbg("[*] Opening GPIO %d\n", gpio_num);
+ snprintf(gpio_filename, sizeof(gpio_filename), "/sys/class/gpio/gpio%d/value", gpio_num);
+ gpio_fd = open(gpio_filename, O_WRONLY | O_SYNC);
+ CHECK(gpio_fd);
+
+ dev->tty_fd = tty_fd;
+ dev->gpio_fd = gpio_fd;
+ pthread_mutex_init(&dev->lock, NULL);
+cleanup:
+ return error;
+}
+
+int do_command(int sock, rackmond_command* cmd) {
+ int error = 0;
+ lock_holder(worldlock, &world.lock);
+ switch(cmd->type) {
+ case COMMAND_TYPE_RAW_MODBUS:
+ {
+ uint16_t expected = cmd->raw_modbus.expected_response_length;
+ int timeout = world.modbus_timeout;
+ if (cmd->raw_modbus.custom_timeout) {
+ //ms to us
+ timeout = cmd->raw_modbus.custom_timeout * 1000;
+ }
+ if (expected == 0) {
+ expected = 1024;
+ }
+ char response[expected];
+ int response_len = modbus_command(
+ &world.rs485, timeout,
+ cmd->raw_modbus.data, cmd->raw_modbus.length,
+ response, expected, expected);
+ uint16_t response_len_wire = response_len;
+ if(response_len < 0) {
+ uint16_t error = -response_len;
+ response_len_wire = 0;
+ send(sock, &response_len_wire, sizeof(uint16_t), 0);
+ send(sock, &error, sizeof(uint16_t), 0);
+ break;
+ }
+ send(sock, &response_len_wire, sizeof(uint16_t), 0);
+ send(sock, response, response_len, 0);
+ break;
+ }
+ case COMMAND_TYPE_SET_CONFIG:
+ {
+ lock_take(worldlock);
+ if (world.config != NULL) {
+ BAIL("rackmond already configured\n");
+ }
+ size_t config_size = sizeof(monitoring_config) +
+ (sizeof(monitor_interval) * cmd->set_config.config.num_intervals);
+ world.config = calloc(1, config_size);
+ memcpy(world.config, &cmd->set_config.config, config_size);
+ syslog(LOG_INFO, "got configuration");
+ lock_release(worldlock);
+ break;
+ }
+ case COMMAND_TYPE_DUMP_DATA_JSON:
+ {
+ lock_take(worldlock);
+ if (world.config == NULL) {
+ send(sock, "[]", 2, 0);
+ } else {
+ struct timespec ts;
+ clock_gettime(CLOCK_REALTIME, &ts);
+ uint32_t now = ts.tv_sec;
+ send(sock, "[", 1, 0);
+ int data_pos = 0;
+ while(world.stored_data[data_pos] != NULL && data_pos < MAX_ACTIVE_ADDRS) {
+ dprintf(sock, "{\"addr\":%d,\"now\":%d,\"ranges\":[",
+ world.stored_data[data_pos]->addr, now);
+ for(int i = 0; i < world.config->num_intervals; i++) {
+ uint32_t time;
+ register_range_data *rd = &world.stored_data[data_pos]->range_data[i];
+ char* mem_pos = rd->mem_begin;
+ dprintf(sock,"{\"begin\":%d,\"readings\":[", rd->i->begin);
+ // want to cut the list off early just before
+ // the first entry with time == 0
+ memcpy(&time, mem_pos, sizeof(time));
+ for(int j = 0; j < rd->i->keep && time != 0; j++) {
+ mem_pos += sizeof(time);
+ dprintf(sock, "{\"time\":%d,\"data\":\"", time);
+ for(int c = 0; c < rd->i->len * 2; c++) {
+ dprintf(sock, "%02x", *mem_pos);
+ mem_pos++;
+ }
+ send(sock, "\"}", 2, 0);
+ memcpy(&time, mem_pos, sizeof(time));
+ if (time == 0) {
+ break;
+ }
+ if ((j+1) < rd->i->keep) {
+ send(sock, ",", 1, 0);
+ }
+ }
+ send(sock, "]}", 2, 0);
+ if ((i+1) < world.config->num_intervals) {
+ send(sock, ",", 1, 0);
+ }
+ }
+ data_pos++;
+ if (data_pos < MAX_ACTIVE_ADDRS && world.stored_data[data_pos] != NULL) {
+ send(sock, "]},", 3, 0);
+ } else {
+ send(sock, "]}", 2, 0);
+ }
+ }
+ send(sock, "]", 1, 0);
+ }
+ lock_release(worldlock);
+ break;
+ }
+ case COMMAND_TYPE_PAUSE_MONITORING:
+ {
+ lock_take(worldlock);
+ uint8_t was_paused = world.paused;
+ world.paused = 1;
+ send(sock, &was_paused, sizeof(was_paused), 0);
+ lock_release(worldlock);
+ break;
+ }
+ case COMMAND_TYPE_START_MONITORING:
+ {
+ lock_take(worldlock);
+ uint8_t was_started = !world.paused;
+ world.paused = 0;
+ send(sock, &was_started, sizeof(was_started), 0);
+ lock_release(worldlock);
+ break;
+ }
+ default:
+ CHECK(-1);
+ }
+cleanup:
+ lock_release(worldlock);
+ return error;
+}
+
+typedef enum {
+ CONN_WAITING_LENGTH,
+ CONN_WAITING_BODY
+} rackmond_connection_state;
+
+// receive the command as a length prefixed block
+// (uint16_t, followed by data)
+// this is all over a local socket, won't be doing
+// endian flipping, clients should only be local procs
+// compiled for the same arch
+int handle_connection(int sock) {
+ int error = 0;
+ rackmond_connection_state state = CONN_WAITING_LENGTH;
+ char bodybuf[1024];
+ uint16_t expected_len = 0;
+ struct pollfd pfd;
+ int recvret = 0;
+ pfd.fd = sock;
+ pfd.events = POLLIN | POLLERR | POLLHUP;
+ // if you don't do anything for a whole second we bail
+next:
+ CHECKP(poll, poll(&pfd, 1, 1000));
+ if (pfd.revents & (POLLERR | POLLHUP)) {
+ goto cleanup;
+ }
+ switch(state) {
+ case CONN_WAITING_LENGTH:
+ recvret = recv(sock, &expected_len, 2, MSG_DONTWAIT);
+ if (recvret == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
+ goto next;
+ }
+ if (expected_len == 0 || expected_len > sizeof(bodybuf)) {
+ // bad length; bail
+ goto cleanup;
+ }
+ state = CONN_WAITING_BODY;
+ goto next;
+ break;
+ case CONN_WAITING_BODY:
+ recvret = recv(sock, &bodybuf, expected_len, MSG_DONTWAIT);
+ if (recvret == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
+ goto next;
+ }
+ CHECK(do_command(sock, (rackmond_command*) bodybuf));
+ }
+cleanup:
+ close(sock);
+ if (error != 0) {
+ fprintf(stderr, "Warning: possible error handling user connection (%d)\n", error);
+ }
+ return 0;
+}
+
+int main(int argc, char** argv) {
+ if (getenv("RACKMOND_FOREGROUND") == NULL) {
+ daemon(0, 0);
+ }
+ signal(SIGPIPE, SIG_IGN);
+ int error = 0;
+ world.paused = 0;
+ world.modbus_timeout = 300000;
+ if (getenv("RACKMOND_TIMEOUT") != NULL) {
+ world.modbus_timeout = atoll(getenv("RACKMOND_TIMEOUT"));
+ fprintf(stderr, "Timeout from env: %dms\n",
+ (world.modbus_timeout / 1000));
+ }
+ world.config = NULL;
+ pthread_mutex_init(&world.lock, NULL);
+ verbose = getenv("RACKMOND_VERBOSE") != NULL ? 1 : 0;
+ openlog("rackmond", 0, LOG_USER);
+ syslog(LOG_INFO, "rackmon/modbus service starting");
+ CHECK(open_rs485_dev(DEFAULT_TTY, DEFAULT_GPIO, &world.rs485));
+ pthread_t monitoring_thread;
+ pthread_create(&monitoring_thread, NULL, monitoring_loop, NULL);
+ struct sockaddr_un local, client;
+ int sock = socket(AF_UNIX, SOCK_STREAM, 0);
+ strcpy(local.sun_path, "/var/run/rackmond.sock");
+ local.sun_family = AF_UNIX;
+ int socknamelen = sizeof(local.sun_family) + strlen(local.sun_path);
+ unlink(local.sun_path);
+ CHECKP(bind, bind(sock, (struct sockaddr *)&local, socknamelen));
+ CHECKP(listen, listen(sock, 5));
+ syslog(LOG_INFO, "rackmon/modbus service listening");
+ while(1) {
+ socklen_t clisocklen = sizeof(struct sockaddr_un);
+ int clisock = accept(sock, (struct sockaddr*) &client, &clisocklen);
+ CHECKP(accept, clisock);
+ CHECK(handle_connection(clisock));
+ }
+
+cleanup:
+ if (error != 0) {
+ error = 1;
+ }
+ return error;
+}
diff --git a/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/rackmond.h b/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/rackmond.h
new file mode 100644
index 0000000..2c0e8a0
--- /dev/null
+++ b/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/rackmond.h
@@ -0,0 +1,46 @@
+#include <stdint.h>
+
+//would've been nice to have thrift
+
+// Raw modbus command
+// Response is just the raw response data
+typedef struct raw_modbus_command {
+ uint16_t length;
+ uint16_t expected_response_length;
+ uint32_t custom_timeout; // 0 for default
+ char data[1];
+} raw_modbus_command;
+
+// only store new value if different from most recent
+// (for watching changes to status flags registers)
+#define MONITOR_FLAG_ONLY_CHANGES 0x1
+
+typedef struct monitor_interval {
+ uint16_t begin;
+ uint16_t len;
+ uint16_t keep; // How long of a history to keep?
+ uint16_t flags;
+} monitor_interval;
+
+typedef struct monitoring_config {
+ uint16_t num_intervals;
+ monitor_interval intervals[1];
+} monitoring_config;
+
+typedef struct set_config_command {
+ monitoring_config config;
+} set_config_command;
+
+#define COMMAND_TYPE_RAW_MODBUS 0x01
+#define COMMAND_TYPE_SET_CONFIG 0x02
+#define COMMAND_TYPE_DUMP_DATA_JSON 0x03
+#define COMMAND_TYPE_PAUSE_MONITORING 0x04
+#define COMMAND_TYPE_START_MONITORING 0x05
+
+typedef struct rackmond_command {
+ uint16_t type;
+ union {
+ raw_modbus_command raw_modbus;
+ set_config_command set_config;
+ };
+} rackmond_command;
diff --git a/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/rackmondata.c b/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/rackmondata.c
new file mode 100644
index 0000000..391b5be
--- /dev/null
+++ b/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/rackmondata.c
@@ -0,0 +1,58 @@
+/*
+ * 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 <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include "modbus.h"
+#include "rackmond.h"
+
+int main(int argc, char **argv) {
+ int error = 0;
+ rackmond_command cmd;
+ int clisock;
+ uint16_t wire_cmd_len = sizeof(cmd);
+ struct sockaddr_un rackmond_addr;
+ cmd.type = COMMAND_TYPE_DUMP_DATA_JSON;
+ clisock = socket(AF_UNIX, SOCK_STREAM, 0);
+ CHECKP(socket, clisock);
+ rackmond_addr.sun_family = AF_UNIX;
+ strcpy(rackmond_addr.sun_path, "/var/run/rackmond.sock");
+ int addr_len = strlen(rackmond_addr.sun_path) + sizeof(rackmond_addr.sun_family);
+ CHECKP(connect, connect(clisock, (struct sockaddr*) &rackmond_addr, addr_len));
+ CHECKP(send, send(clisock, &wire_cmd_len, sizeof(wire_cmd_len), 0));
+ CHECKP(send, send(clisock, &cmd, wire_cmd_len, 0));
+ char readbuf[256];
+ ssize_t n_read;
+ while((n_read = read(clisock, readbuf, sizeof(readbuf))) > 0) {
+ write(1, readbuf, n_read);
+ }
+cleanup:
+ if(error != 0) {
+ if(errno != 0) {
+ fprintf(stderr, "%s\n", strerror(errno));
+ }
+ error = 1;
+ }
+ return error;
+}
diff --git a/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/setup-rackmond.sh b/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/setup-rackmond.sh
new file mode 100644
index 0000000..85a1e22
--- /dev/null
+++ b/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/setup-rackmond.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+#
+# Copyright 2014-present Facebook. All Rights Reserved.
+#
+### BEGIN INIT INFO
+# Provides: setup-rackmond
+# Required-Start:
+# Required-Stop:
+# Default-Start: S
+# Default-Stop:
+# Short-Description: Start Rackmon service
+### END INIT INFO
+
+echo -n "Starting rackmon background service..."
+/usr/local/bin/rackmond
+echo "done."
+
+echo -n "Configuring rackmon service..."
+python /etc/rackmon-config.py
+echo "done."
diff --git a/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon_0.1.bb b/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon_0.1.bb
index d3e79e4..399f7c0 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon_0.1.bb
+++ b/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon_0.1.bb
@@ -1,4 +1,19 @@
# 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 = "Rackmon Functionality"
DESCRIPTION = "Rackmon Functionality"
SECTION = "base"
@@ -6,7 +21,7 @@ PR = "r1"
LICENSE = "GPLv2"
LIC_FILES_CHKSUM = "file://modbus.c;beginline=4;endline=16;md5=da35978751a9d71b73679307c4d296ec"
-#DEPENDS_append = " update-rc.d-native"
+DEPENDS_append = " update-rc.d-native"
SRC_URI = "file://Makefile \
file://modbuscmd.c \
@@ -14,6 +29,13 @@ SRC_URI = "file://Makefile \
file://modbus.c \
file://modbus.h \
file://gpiowatch.c \
+ file://rackmond.c \
+ file://rackmond.h \
+ file://rackmondata.c \
+ file://setup-rackmond.sh \
+ file://rackmon-config.py \
+ file://psu-update-delta.py \
+ file://hexfile.py \
"
S = "${WORKDIR}"
@@ -21,6 +43,10 @@ S = "${WORKDIR}"
binfiles = "modbuscmd \
modbussim \
gpiowatch \
+ rackmond \
+ rackmondata \
+ psu-update-delta.py \
+ hexfile.py \
"
#otherfiles = "README"
@@ -36,6 +62,11 @@ do_install() {
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-rackmond.sh ${D}${sysconfdir}/init.d/setup-rackmond.sh
+ install -m 755 rackmon-config.py ${D}${sysconfdir}/rackmon-config.py
+ update-rc.d -r ${D} setup-rackmond.sh start 95 2 3 4 5 .
}
FBPACKAGEDIR = "${prefix}/local/fbpackages"
diff --git a/meta-facebook/meta-wedge/recipes-wedge/rest-api/files/rest.py b/meta-facebook/meta-wedge/recipes-wedge/rest-api/files/rest.py
index 6d59fd6..52c98d9 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/rest-api/files/rest.py
+++ b/meta-facebook/meta-wedge/recipes-wedge/rest-api/files/rest.py
@@ -20,14 +20,24 @@
from ctypes import *
-from bottle import route, run, template, request, response
+from bottle import route, run, template, request, response, ServerAdapter
from bottle import abort
+from wsgiref.simple_server import make_server, WSGIRequestHandler, WSGIServer
import json
-from rest_fruid import *
-from rest_server import *
-from rest_sensors import *
-from rest_bmc import *
-from rest_gpios import *
+import ssl
+import socket
+import os
+import rest_fruid
+import rest_server
+import rest_sensors
+import rest_bmc
+import rest_gpios
+import rest_modbus
+import rest_slotid
+
+CONSTANTS = {
+ 'certificate': '/usr/lib/ssl/certs/rest_server.pem',
+}
# Handler for root resource endpoint
@route('/api')
@@ -50,7 +60,8 @@ def rest_sys():
"Description": "Wedge System",
},
"Actions": [],
- "Resources": [ "mb", "bmc", "server", "sensors", "gpios"],
+ "Resources": [ "mb", "bmc", "server", "sensors", "gpios",
+ "modbus_registers", "slotid"],
}
return result
@@ -70,33 +81,72 @@ def rest_sys():
# Handler for sys/mb/fruid resource endpoint
@route('/api/sys/mb/fruid')
-def rest_fruid():
- return get_fruid()
+def rest_fruid_hdl():
+ return rest_fruid.get_fruid()
# Handler for sys/bmc resource endpoint
@route('/api/sys/bmc')
-def rest_bmc():
- return get_bmc()
+def rest_bmc_hdl():
+ return rest_bmc.get_bmc()
# Handler for sys/server resource endpoint
@route('/api/sys/server')
-def rest_bmc():
- return get_server()
+def rest_server_hdl():
+ return rest_server.get_server()
# Handler for uServer resource endpoint
@route('/api/sys/server', method='POST')
-def rest_server():
+def rest_server_act_hdl():
data = json.load(request.body)
- return server_action(data)
+ return rest_server.server_action(data)
# Handler for sensors resource endpoint
@route('/api/sys/sensors')
-def rest_sensors():
- return get_sensors()
+def rest_sensors_hdl():
+ return rest_sensors.get_sensors()
# Handler for sensors resource endpoint
@route('/api/sys/gpios')
-def rest_gpios():
- return get_gpios()
+def rest_gpios_hdl():
+ return rest_gpios.get_gpios()
+
+@route('/api/sys/modbus_registers')
+def modbus_registers_hdl():
+ return rest_modbus.get_modbus_registers()
+
+# Handler for sensors resource endpoint
+@route('/api/sys/slotid')
+def rest_slotid_hdl():
+ return rest_slotid.get_slotid()
run(host = "::", port = 8080)
+
+# SSL Wrapper for Rest API
+class SSLWSGIRefServer(ServerAdapter):
+ def run(self, handler):
+ if self.quiet:
+ class QuietHandler(WSGIRequestHandler):
+ def log_request(*args, **kw): pass
+ self.options['handler_class'] = QuietHandler
+
+ # IPv6 Support
+ server_cls = self.options.get('server_class', WSGIServer)
+
+ if ':' in self.host:
+ if getattr(server_cls, 'address_family') == socket.AF_INET:
+ class server_cls(server_cls):
+ address_family = socket.AF_INET6
+
+ srv = make_server(self.host, self.port, handler,
+ server_class=server_cls, **self.options)
+ srv.socket = ssl.wrap_socket (
+ srv.socket,
+ certfile=CONSTANTS['certificate'],
+ server_side=True)
+ srv.serve_forever()
+
+# Use SSL if the certificate exists. Otherwise, run without SSL.
+if os.access(CONSTANTS['certificate'], os.R_OK):
+ run(server=SSLWSGIRefServer(host="::", port=8443))
+else:
+ run(host = "::", port = 8080)
diff --git a/meta-facebook/meta-wedge/recipes-wedge/rest-api/files/rest_bmc.py b/meta-facebook/meta-wedge/recipes-wedge/rest-api/files/rest_bmc.py
index d9600ae..c4f661e 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/rest-api/files/rest_bmc.py
+++ b/meta-facebook/meta-wedge/recipes-wedge/rest-api/files/rest_bmc.py
@@ -20,6 +20,7 @@
from subprocess import *
+import re
# Handler for FRUID resource endpoint
def get_bmc():
@@ -51,6 +52,14 @@ def get_bmc():
mem_usage = adata[0]
cpu_usage = adata[1]
+ # Get OpenBMC version
+ version = ""
+ data = Popen('cat /etc/issue', \
+ shell=True, stdout=PIPE).stdout.read()
+ ver = re.search(r'v([\w\d._-]*)\s', data)
+ if ver:
+ version = ver.group(1)
+
result = {
"Information": {
"Description": "Wedge BMC",
@@ -58,6 +67,7 @@ def get_bmc():
"Uptime": uptime,
"Memory Usage": mem_usage,
"CPU Usage": cpu_usage,
+ "OpenBMC Version": version,
},
"Actions": [],
"Resources": [],
diff --git a/meta-facebook/meta-wedge/recipes-wedge/rest-api/files/rest_modbus.py b/meta-facebook/meta-wedge/recipes-wedge/rest-api/files/rest_modbus.py
new file mode 100644
index 0000000..9d213fc
--- /dev/null
+++ b/meta-facebook/meta-wedge/recipes-wedge/rest-api/files/rest_modbus.py
@@ -0,0 +1,28 @@
+#!/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
+#
+
+import subprocess
+from subprocess import Popen
+
+# Handler for sensors resource endpoint
+def get_modbus_registers():
+ p = Popen('/usr/local/bin/rackmondata', stdout=subprocess.PIPE)
+ out, err = p.communicate()
+ return out
diff --git a/meta-facebook/meta-wedge/recipes-wedge/rest-api/files/rest_sensors.py b/meta-facebook/meta-wedge/recipes-wedge/rest-api/files/rest_sensors.py
index f4f83d3..fa65372 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/rest-api/files/rest_sensors.py
+++ b/meta-facebook/meta-wedge/recipes-wedge/rest-api/files/rest_sensors.py
@@ -39,12 +39,10 @@ def get_sensors():
if (len(tdata) < 2):
continue
sresult[tdata[0].strip()] = tdata[1].strip()
- result.append(sresult)
-
+ result.append(sresult)
fresult = {
"Information": result,
"Actions": [],
"Resources": [],
}
-
return fresult
diff --git a/meta-facebook/meta-wedge/recipes-wedge/rest-api/files/rest_slotid.py b/meta-facebook/meta-wedge/recipes-wedge/rest-api/files/rest_slotid.py
new file mode 100644
index 0000000..ee407ac
--- /dev/null
+++ b/meta-facebook/meta-wedge/recipes-wedge/rest-api/files/rest_slotid.py
@@ -0,0 +1,33 @@
+#!/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
+#
+
+import subprocess
+
+# Handler for sensors resource endpoint
+def get_slotid():
+ p = subprocess.Popen('source /usr/local/bin/openbmc-utils.sh;'
+ 'wedge_slot_id $(wedge_board_type)',
+ shell=True, stdout=subprocess.PIPE)
+ out, err = p.communicate()
+ try:
+ slot = int(out.strip('\n'))
+ except:
+ slot = 0
+ return { 'slotid' : slot }
diff --git a/meta-facebook/meta-wedge/recipes-wedge/rest-api/files/setup-rest-api.sh b/meta-facebook/meta-wedge/recipes-wedge/rest-api/files/setup-rest-api.sh
index fe01c23..bdd79b6 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/rest-api/files/setup-rest-api.sh
+++ b/meta-facebook/meta-wedge/recipes-wedge/rest-api/files/setup-rest-api.sh
@@ -2,6 +2,22 @@
#
# 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:
diff --git a/meta-facebook/meta-wedge/recipes-wedge/rest-api/rest-api_0.1.bb b/meta-facebook/meta-wedge/recipes-wedge/rest-api/rest-api_0.1.bb
index 2753f30..5dec4bf 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/rest-api/rest-api_0.1.bb
+++ b/meta-facebook/meta-wedge/recipes-wedge/rest-api/rest-api_0.1.bb
@@ -1,4 +1,19 @@
# 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 = "Rest API Daemon"
DESCRIPTION = "Daemon to handle RESTful interface."
SECTION = "base"
@@ -16,11 +31,13 @@ SRC_URI = "file://setup-rest-api.sh \
file://rest_gpios.py \
file://rest_server.py \
file://rest_sensors.py \
+ file://rest_modbus.py \
+ file://rest_slotid.py \
"
S = "${WORKDIR}"
-binfiles = "rest.py rest_bmc.py rest_fruid.py rest_gpios.py rest_server.py rest_sensors.py setup-rest-api.sh"
+binfiles = "rest.py rest_bmc.py rest_fruid.py rest_gpios.py rest_server.py rest_sensors.py rest_modbus.py rest_slotid.py setup-rest-api.sh"
pkgdir = "rest-api"
diff --git a/meta-facebook/meta-wedge/recipes-wedge/sensor-setup/sensor-setup_0.1.bb b/meta-facebook/meta-wedge/recipes-wedge/sensor-setup/sensor-setup_0.1.bb
index ad6bb0c..1b0f937 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/sensor-setup/sensor-setup_0.1.bb
+++ b/meta-facebook/meta-wedge/recipes-wedge/sensor-setup/sensor-setup_0.1.bb
@@ -1,4 +1,19 @@
# 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"
diff --git a/meta-facebook/meta-wedge/recipes-wedge/sms-kcsd/sms-kcsd/Makefile b/meta-facebook/meta-wedge/recipes-wedge/sms-kcsd/sms-kcsd/Makefile
index 6425261..dba9dbb 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/sms-kcsd/sms-kcsd/Makefile
+++ b/meta-facebook/meta-wedge/recipes-wedge/sms-kcsd/sms-kcsd/Makefile
@@ -1,4 +1,20 @@
# 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: sms-kcsd
sms-kcsd: sms-kcsd.c
diff --git a/meta-facebook/meta-wedge/recipes-wedge/sms-kcsd/sms-kcsd/setup-sms-kcs.sh b/meta-facebook/meta-wedge/recipes-wedge/sms-kcsd/sms-kcsd/setup-sms-kcs.sh
index d369f5c..b4234a4 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/sms-kcsd/sms-kcsd/setup-sms-kcs.sh
+++ b/meta-facebook/meta-wedge/recipes-wedge/sms-kcsd/sms-kcsd/setup-sms-kcs.sh
@@ -2,6 +2,22 @@
#
# 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-sms-kcs
# Required-Start:
diff --git a/meta-facebook/meta-wedge/recipes-wedge/sms-kcsd/sms-kcsd_0.1.bb b/meta-facebook/meta-wedge/recipes-wedge/sms-kcsd/sms-kcsd_0.1.bb
index 1f3ea08..812d815 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/sms-kcsd/sms-kcsd_0.1.bb
+++ b/meta-facebook/meta-wedge/recipes-wedge/sms-kcsd/sms-kcsd_0.1.bb
@@ -1,4 +1,19 @@
# 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 = "SMS KCS Daemon"
DESCRIPTION = "Daemon to handle SMS KCS interface."
SECTION = "base"
diff --git a/meta-facebook/meta-wedge/recipes-wedge/usb-console/usb-console_0.1.bb b/meta-facebook/meta-wedge/recipes-wedge/usb-console/usb-console_0.1.bb
index f92511c..c934f46 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/usb-console/usb-console_0.1.bb
+++ b/meta-facebook/meta-wedge/recipes-wedge/usb-console/usb-console_0.1.bb
@@ -1,4 +1,19 @@
# 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"
diff --git a/meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/files/lib/Makefile b/meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/files/lib/Makefile
index 0264efe..8c05686 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/files/lib/Makefile
+++ b/meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/files/lib/Makefile
@@ -1,8 +1,24 @@
# 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
+
lib: libwedge_eeprom.so
libwedge_eeprom.so: wedge_eeprom.c
- $(CC) $(CCFLAGS) -fPIC -c -o wedge_eeprom.o wedge_eeprom.c
+ $(CC) $(CFLAGS) -fPIC -c -o wedge_eeprom.o wedge_eeprom.c
$(CC) -shared -o libwedge_eeprom.so wedge_eeprom.o -lc
.PHONY: clean
diff --git a/meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/files/lib/wedge_eeprom.c b/meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/files/lib/wedge_eeprom.c
index 44f708d..e66941e 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/files/lib/wedge_eeprom.c
+++ b/meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/files/lib/wedge_eeprom.c
@@ -23,9 +23,11 @@
#include <stdio.h>
#include <string.h>
-#include <facebook/log.h>
+#include <openbmc/log.h>
+#ifndef FBW_EEPROM_FILE
#define FBW_EEPROM_FILE "/sys/class/i2c-adapter/i2c-6/6-0050/eeprom"
+#endif
#define FBW_EEPROM_VERSION 0
#define FBW_EEPROM_V0_SIZE 162
diff --git a/meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/files/utils/Makefile b/meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/files/utils/Makefile
index 30aac75..f2aeadc 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/files/utils/Makefile
+++ b/meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/files/utils/Makefile
@@ -1,4 +1,20 @@
# 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
+
utils: weutil
weutil: weutil.o
diff --git a/meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/files/utils/weutil.c b/meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/files/utils/weutil.c
index 9e932aa..90aca10 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/files/utils/weutil.c
+++ b/meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/files/utils/weutil.c
@@ -20,7 +20,7 @@
#include <stdio.h>
#include <facebook/wedge_eeprom.h>
-#include <facebook/log.h>
+#include <openbmc/log.h>
int main(int argc, const char *argv[])
{
diff --git a/meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/libwedge-eeprom_0.1.bb b/meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/libwedge-eeprom_0.1.bb
index 781cf76..6f62557 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/libwedge-eeprom_0.1.bb
+++ b/meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/libwedge-eeprom_0.1.bb
@@ -1,4 +1,19 @@
# 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 = "Wedge EEPROM Library"
DESCRIPTION = "library for wedge eeprom"
SECTION = "base"
@@ -9,7 +24,7 @@ LIC_FILES_CHKSUM = "file://wedge_eeprom.c;beginline=4;endline=16;md5=da35978751a
SRC_URI = "file://lib \
"
-DEPENDS += "fbutils"
+DEPENDS += "liblog"
S = "${WORKDIR}/lib"
@@ -22,5 +37,4 @@ do_install() {
}
FILES_${PN} = "${libdir}/libwedge_eeprom.so"
-FILES_${PN}-dbg = "${libdir}/.debug"
FILES_${PN}-dev = "${includedir}/facebook/wedge_eeprom.h"
diff --git a/meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/wedge-eeprom_0.1.bb b/meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/wedge-eeprom_0.1.bb
index 51bdbb9..3afbed1 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/wedge-eeprom_0.1.bb
+++ b/meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/wedge-eeprom_0.1.bb
@@ -1,4 +1,19 @@
# 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 = "Wedge EEPROM Utilities"
DESCRIPTION = "Util for wedge eeprom"
SECTION = "base"
diff --git a/meta-facebook/meta-yosemite/conf/bblayers.conf.sample b/meta-facebook/meta-yosemite/conf/bblayers.conf.sample
new file mode 100644
index 0000000..8827e9d
--- /dev/null
+++ b/meta-facebook/meta-yosemite/conf/bblayers.conf.sample
@@ -0,0 +1,21 @@
+# LAYER_CONF_VERSION is increased each time build/conf/bblayers.conf
+# changes incompatibly
+LCONF_VERSION = "6"
+
+BBPATH = "${TOPDIR}"
+BBFILES ?= ""
+
+BBLAYERS ?= " \
+ ##OEROOT##/meta \
+ ##OEROOT##/meta-yocto \
+ ##OEROOT##/meta-yocto-bsp \
+ ##OEROOT##/meta-openembedded/meta-oe \
+ ##OEROOT##/meta-openembedded/meta-networking \
+ ##OEROOT##/meta-openbmc \
+ ##OEROOT##/meta-openbmc/meta-aspeed \
+ ##OEROOT##/meta-openbmc/meta-facebook/meta-yosemite \
+ "
+BBLAYERS_NON_REMOVABLE ?= " \
+ ##OEROOT##/meta \
+ ##OEROOT##/meta-yocto \
+ "
diff --git a/meta-facebook/meta-yosemite/conf/conf-notes.txt b/meta-facebook/meta-yosemite/conf/conf-notes.txt
new file mode 100644
index 0000000..87ebd18
--- /dev/null
+++ b/meta-facebook/meta-yosemite/conf/conf-notes.txt
@@ -0,0 +1,2 @@
+Common targets are:
+ yosemite-image
diff --git a/meta-facebook/meta-yosemite/conf/layer.conf b/meta-facebook/meta-yosemite/conf/layer.conf
new file mode 100644
index 0000000..281d2cc
--- /dev/null
+++ b/meta-facebook/meta-yosemite/conf/layer.conf
@@ -0,0 +1,10 @@
+# We have a conf and classes directory, add to BBPATH
+BBPATH .= ":${LAYERDIR}"
+
+# We have recipes-* directories, add to BBFILES
+BBFILES += "${LAYERDIR}/recipes-*/*/*.bb \
+ ${LAYERDIR}/recipes-*/*/*.bbappend"
+
+BBFILE_COLLECTIONS += "yosemite"
+BBFILE_PATTERN_yosemite = "^${LAYERDIR}/"
+BBFILE_PRIORITY_yosemite = "8"
diff --git a/meta-facebook/meta-yosemite/conf/local.conf.sample b/meta-facebook/meta-yosemite/conf/local.conf.sample
new file mode 100644
index 0000000..9204236
--- /dev/null
+++ b/meta-facebook/meta-yosemite/conf/local.conf.sample
@@ -0,0 +1,140 @@
+#
+# Local configuration file for building the OpenBMC image.
+#
+
+# Always look for packages first in our own local package mirror
+SOURCE_MIRROR_URL ?= "file://${TOPDIR}/../meta-openbmc/source_mirror/"
+INHERIT += "own-mirrors"
+
+# Save local tarballs for all packages we download.
+# This can be used to update our mirror directory above.
+BB_GENERATE_MIRROR_TARBALLS = "1"
+
+# The following setting will prevent bitbake from downloading anything over the
+# network. This can be used to ensure that we get everything from a local
+# file:// mirror.
+#
+# Comment this out if you do need to download new packages from the internet.
+# However, once you have downloaded the package you should check them into our
+# mirror repository so that other developers will always get it from the mirror
+# repo.
+BB_NO_NETWORK = "fb-only"
+
+# Parallelism Options
+#
+# How many tasks bitbake should run in parallel:
+BB_NUMBER_THREADS ?= "${@oe.utils.cpu_count()}"
+# How many processes make should run in parallel:
+PARALLEL_MAKE ?= "-j ${@oe.utils.cpu_count()}"
+
+# Machine Selection
+MACHINE ??= "yosemite"
+
+# Build directory locationds.
+#
+#DL_DIR ?= "${TOPDIR}/downloads"
+#SSTATE_DIR ?= "${TOPDIR}/sstate-cache"
+#TMPDIR = "${TOPDIR}/tmp"
+
+#
+# Default policy config
+# We could eventually create our own distro config if desired,
+# but for now we use the standard poky distro settings.
+#
+DISTRO ?= "poky"
+
+# Use RPM packages
+PACKAGE_CLASSES ?= "package_rpm"
+
+# Extra image features.
+# Currently we do not enable anything extra here.
+#EXTRA_IMAGE_FEATURES = ""
+
+# We build on CentOS 6.3.
+# Don't complain about it, even though it isn't in poky's default
+# list of supported distros.
+SANITY_TESTED_DISTROS_append ?= " CentOS-6.3 \n "
+
+#
+# Additional image features
+#
+# The following is a list of additional classes to use when building images which
+# enable extra features. Some available options which can be included in this variable
+# are:
+# - 'buildstats' collect build statistics
+# - 'image-mklibs' to reduce shared library files size for an image
+# - 'image-prelink' in order to prelink the filesystem image
+# - 'image-swab' to perform host system intrusion detection
+# NOTE: if listing mklibs & prelink both, then make sure mklibs is before prelink
+# NOTE: mklibs also needs to be explicitly enabled for a given image, see local.conf.extended
+USER_CLASSES ?= "buildstats image-mklibs image-prelink"
+
+#
+# Interactive shell configuration
+#
+# Under certain circumstances the system may need input from you and to do this it
+# can launch an interactive shell. It needs to do this since the build is
+# multithreaded and needs to be able to handle the case where more than one parallel
+# process may require the user's attention. The default is iterate over the available
+# terminal types to find one that works.
+#
+# Examples of the occasions this may happen are when resolving patches which cannot
+# be applied, to use the devshell or the kernel menuconfig
+#
+# Supported values are auto, gnome, xfce, rxvt, screen, konsole (KDE 3.x only), none
+# Note: currently, Konsole support only works for KDE 3.x due to the way
+# newer Konsole versions behave
+#OE_TERMINAL = "auto"
+# By default disable interactive patch resolution (tasks will just fail instead):
+PATCHRESOLVE = "noop"
+
+#
+# Disk Space Monitoring during the build
+#
+# Monitor the disk space during the build. If there is less that 1GB of space or less
+# than 100K inodes in any key build location (TMPDIR, DL_DIR, SSTATE_DIR), gracefully
+# shutdown the build. If there is less that 100MB or 1K inodes, perform a hard abort
+# of the build. The reason for this is that running completely out of space can corrupt
+# files and damages the build in ways which may not be easily recoverable.
+BB_DISKMON_DIRS = "\
+ STOPTASKS,${TMPDIR},1G,100K \
+ STOPTASKS,${DL_DIR},1G,100K \
+ STOPTASKS,${SSTATE_DIR},1G,100K \
+ ABORT,${TMPDIR},100M,1K \
+ ABORT,${DL_DIR},100M,1K \
+ ABORT,${SSTATE_DIR},100M,1K"
+
+#
+# Shared-state files from other locations
+#
+# As mentioned above, shared state files are prebuilt cache data objects which can
+# used to accelerate build time. This variable can be used to configure the system
+# to search other mirror locations for these objects before it builds the data itself.
+#
+# This can be a filesystem directory, or a remote url such as http or ftp. These
+# would contain the sstate-cache results from previous builds (possibly from other
+# machines). This variable works like fetcher MIRRORS/PREMIRRORS and points to the
+# cache locations to check for the shared objects.
+# NOTE: if the mirror uses the same structure as SSTATE_DIR, you need to add PATH
+# at the end as shown in the examples below. This will be substituted with the
+# correct path within the directory structure.
+#SSTATE_MIRRORS ?= "\
+#file://.* http://someserver.tld/share/sstate/PATH;downloadfilename=PATH \n \
+#file://.* file:///some/local/dir/sstate/PATH"
+
+
+# CONF_VERSION is increased each time build/conf/ changes incompatibly and is used to
+# track the version of this file when it was generated. This can safely be ignored if
+# this doesn't mean anything to you.
+CONF_VERSION = "1"
+
+
+# Update root password to '0penBmc' and change the root shell back to bash.
+# This default root password is used at the ODM and system integrator. It will be
+# changed during provisioning at the datacenter.
+INHERIT += "extrausers"
+
+EXTRA_USERS_PARAMS = " \
+ usermod -s /bin/bash root; \
+ usermod -p '\$1\$UGMqyqdG\$FZiylVFmRRfl9Z0Ue8G7e/' root; \
+ "
diff --git a/meta-facebook/meta-yosemite/conf/machine/yosemite.conf b/meta-facebook/meta-yosemite/conf/machine/yosemite.conf
new file mode 100644
index 0000000..cd48ed6
--- /dev/null
+++ b/meta-facebook/meta-yosemite/conf/machine/yosemite.conf
@@ -0,0 +1,7 @@
+#@TYPE: Machine
+#@NAME: Yosemite
+#@DESCRIPTION: Machine configuration for Facebook Yosemite
+
+UBOOT_MACHINE_yosemite = "fbyosemite_config"
+
+require conf/machine/include/ast1250.inc
diff --git a/meta-facebook/meta-yosemite/recipes-core/busybox/busybox/busybox.cfg b/meta-facebook/meta-yosemite/recipes-core/busybox/busybox/busybox.cfg
new file mode 100644
index 0000000..66da117
--- /dev/null
+++ b/meta-facebook/meta-yosemite/recipes-core/busybox/busybox/busybox.cfg
@@ -0,0 +1,18 @@
+CONFIG_SH_MATH_SUPPORT_64=y
+CONFIG_DEVMEM=y
+CONFIG_LSUSB=y
+CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS=y
+CONFIG_RX=y
+CONFIG_FLASHCP=y
+CONFIG_FLASH_LOCK=y
+CONFIG_FLASH_UNLOCK=y
+CONFIG_FLASH_ERASEALL=y
+CONFIG_TRACEROUTE6=y
+CONFIG_VCONFIG=y
+# we use the standalone ip util
+CONFIG_IP=n
+# use dhclient, as udhcpc will flush all v6 link local addresses during renew
+CONFIG_FEATURE_IFUPDOWN_EXTERNAL_DHCP=y
+CONFIG_UDHCPD=n
+CONFIG_UDHCPC=n
+CONFIG_UDHCPC6=n
diff --git a/meta-facebook/meta-yosemite/recipes-core/busybox/busybox_%.bbappend b/meta-facebook/meta-yosemite/recipes-core/busybox/busybox_%.bbappend
new file mode 100644
index 0000000..b8641ee
--- /dev/null
+++ b/meta-facebook/meta-yosemite/recipes-core/busybox/busybox_%.bbappend
@@ -0,0 +1,5 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+
+SRC_URI += " \
+ file://busybox.cfg \
+ " \ No newline at end of file
diff --git a/meta-facebook/meta-yosemite/recipes-core/images/yosemite-image.bb b/meta-facebook/meta-yosemite/recipes-core/images/yosemite-image.bb
new file mode 100644
index 0000000..300f167
--- /dev/null
+++ b/meta-facebook/meta-yosemite/recipes-core/images/yosemite-image.bb
@@ -0,0 +1 @@
+include yosemite-image.inc
diff --git a/meta-facebook/meta-yosemite/recipes-core/images/yosemite-image.inc b/meta-facebook/meta-yosemite/recipes-core/images/yosemite-image.inc
new file mode 100644
index 0000000..5356c20
--- /dev/null
+++ b/meta-facebook/meta-yosemite/recipes-core/images/yosemite-image.inc
@@ -0,0 +1,82 @@
+inherit aspeed_uboot_image
+
+# /dev
+require recipes-core/images/aspeed-dev.inc
+
+# Base this image on core-image-minimal
+include recipes-core/images/core-image-minimal.bb
+
+# Changing the image compression from gz to lzma achieves 30% saving (~3M).
+# However, the current u-boot does not have lzma enabled. Stick to gz
+# until we generate a new u-boot image.
+IMAGE_FSTYPES += "cpio.lzma.u-boot"
+UBOOT_IMAGE_ENTRYPOINT = "0x40800000"
+
+PYTHON_PKGS = " \
+ python-core \
+ python-io \
+ python-json \
+ python-shell \
+ python-subprocess \
+ python-argparse \
+ python-ctypes \
+ python-datetime \
+ python-email \
+ python-threading \
+ python-mime \
+ python-pickle \
+ python-misc \
+ python-netserver \
+ "
+
+NTP_PKGS = " \
+ ntp \
+ ntp-utils \
+ sntp \
+ ntpdate \
+ "
+
+# Include modules in rootfs
+IMAGE_INSTALL += " \
+ kernel-modules \
+ u-boot-fw-utils \
+ fbutils \
+ fan-ctrl \
+ watchdog-ctrl \
+ i2c-tools \
+ sensor-setup \
+ usb-console \
+ lmsensors-sensors \
+ rest-api \
+ bottle \
+ ipmid \
+ ${PYTHON_PKGS} \
+ ${NTP_PKGS} \
+ iproute2 \
+ dhcp-client \
+ fruid \
+ ipmbd \
+ bic-cached \
+ bic-util \
+ yosemite-sensors \
+ sensor-util \
+ sensor-mon \
+ gpiod \
+ front-paneld \
+ power-util \
+ consoled \
+ cfg-util \
+ "
+
+IMAGE_FEATURES += " \
+ ssh-server-openssh \
+ tools-debug \
+ "
+
+DISTRO_FEATURES += " \
+ ext2 \
+ ipv6 \
+ nfs \
+ usbgadget \
+ usbhost \
+ "
diff --git a/meta-facebook/meta-yosemite/recipes-core/init-ifupdown/files/interfaces b/meta-facebook/meta-yosemite/recipes-core/init-ifupdown/files/interfaces
new file mode 100644
index 0000000..36e342e
--- /dev/null
+++ b/meta-facebook/meta-yosemite/recipes-core/init-ifupdown/files/interfaces
@@ -0,0 +1,11 @@
+# The loopback interface
+auto lo
+iface lo inet loopback
+
+auto eth0
+iface eth0 inet dhcp
+
+auto usb0
+iface usb0 inet6 static
+ address fe80::1
+ netmask 64
diff --git a/meta-facebook/meta-yosemite/recipes-core/init-ifupdown/init-ifupdown_%.bbappend b/meta-facebook/meta-yosemite/recipes-core/init-ifupdown/init-ifupdown_%.bbappend
new file mode 100644
index 0000000..7d74521
--- /dev/null
+++ b/meta-facebook/meta-yosemite/recipes-core/init-ifupdown/init-ifupdown_%.bbappend
@@ -0,0 +1,2 @@
+
+FILESEXTRAPATHS_prepend := "${THISDIR}/files:"
diff --git a/meta-facebook/meta-yosemite/recipes-core/sysvinit/sysvinit-inittab_%.bbappend b/meta-facebook/meta-yosemite/recipes-core/sysvinit/sysvinit-inittab_%.bbappend
new file mode 100644
index 0000000..9624d65
--- /dev/null
+++ b/meta-facebook/meta-yosemite/recipes-core/sysvinit/sysvinit-inittab_%.bbappend
@@ -0,0 +1,2 @@
+# ttyS0 is UART5, BMC's serial port
+SERIAL_CONSOLES += "57600;ttyS0"
diff --git a/meta-facebook/meta-yosemite/recipes-kernel/linux/linux-aspeed_2.6%.bbappend b/meta-facebook/meta-yosemite/recipes-kernel/linux/linux-aspeed_2.6%.bbappend
new file mode 100644
index 0000000..a317986
--- /dev/null
+++ b/meta-facebook/meta-yosemite/recipes-kernel/linux/linux-aspeed_2.6%.bbappend
@@ -0,0 +1,5 @@
+LINUX_VERSION_EXTENSION = "-yosemite"
+
+COMPATIBLE_MACHINE = "yosemite"
+
+KERNEL_CONFIG_COMMAND = "oe_runmake yosemite_defconfig && oe_runmake oldconfig"
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"
OpenPOWER on IntegriCloud