summaryrefslogtreecommitdiff
path: root/meta-google/recipes-google/ipmi/ipmi-fru-sh/lib.sh
diff options
context:
space:
mode:
Diffstat (limited to 'meta-google/recipes-google/ipmi/ipmi-fru-sh/lib.sh')
-rw-r--r--meta-google/recipes-google/ipmi/ipmi-fru-sh/lib.sh116
1 files changed, 107 insertions, 9 deletions
diff --git a/meta-google/recipes-google/ipmi/ipmi-fru-sh/lib.sh b/meta-google/recipes-google/ipmi/ipmi-fru-sh/lib.sh
index 335e0b21c..d02eeab47 100644
--- a/meta-google/recipes-google/ipmi/ipmi-fru-sh/lib.sh
+++ b/meta-google/recipes-google/ipmi/ipmi-fru-sh/lib.sh
@@ -23,6 +23,20 @@ IPMI_FRU_COMMON_HEADER_MULTI_RECORD_OFFSET_IDX=5
IPMI_FRU_AREA_HEADER_SIZE_IDX=1
IPMI_FRU_CHECKSUM_IDX=-1
+offset_1bw() {
+ local addr="$1"
+ local off="$2"
+ local extra="${3-0}"
+ echo w$((1+extra))@$addr $(( off & 0xff ))
+}
+
+offset_2bw() {
+ local addr="$1"
+ local off="$2"
+ local extra="${3-0}"
+ echo w$((2+extra))@$addr $(( (off >> 8) & 0xff )) $(( off & 0xff ))
+}
+
of_name_to_eeproms() {
local names
if ! names="$(grep -xl "$1" /sys/bus/i2c/devices/*/of_node/name)"; then
@@ -42,6 +56,78 @@ of_name_to_eeprom() {
echo "$eeproms"
}
+# Each element is a `filename`
+declare -A IPMI_FRU_EEPROM_FILE=()
+# Each element is a `bus` + `addr` + `offset_bytes_func`
+declare -A IPMI_FRU_EEPROM_BUSADDR=()
+
+ipmi_fru_device_alloc() {
+ local fdn="$1"
+ local idx="$2"
+
+ local json
+ json="$(busctl -j call xyz.openbmc_project.FruDevice \
+ /xyz/openbmc_project/FruDevice/"$fdn" org.freedesktop.DBus.Properties \
+ GetAll s xyz.openbmc_project.FruDevice)" || return 80
+
+ local jqq='.data[0] | (.BUS.data | tostring) + " " + (.ADDRESS.data | tostring)'
+ local busaddr
+ busaddr=($(echo "$json" | jq -r "$jqq")) || return
+
+ # FRU 0 is hardcoded and FruDevice does not report the correct bus for it
+ # Hardcode a workaround for this specifically known bus
+ if (( busaddr[0] == 0 && busaddr[1] == 0 )); then
+ IPMI_FRU_EEPROM_FILE["$idx"]=/etc/fru/baseboard.fru.bin
+ else
+ local offset_bw=offset_2bw
+ local rsp
+ rsp=$(i2ctransfer -f -y ${busaddr[0]} $(offset_1bw ${busaddr[1]} 0) r1) || return
+ # FRUs never start with 0xff bytes, so we can figure out addressing mode
+ if (( rsp != 0xff )); then
+ offset_bw=offset_1bw
+ fi
+ IPMI_FRU_EEPROM_BUSADDR["$idx"]="${busaddr[*]} $offset_bw"
+ fi
+}
+
+ipmi_fru_alloc() {
+ local name="$1"
+ local -n ret="$2"
+
+ # Pick the first free index to return as the allocated entry
+ for (( ret = 0; ret < "${#IPMI_FRU_EEPROM_FILE[@]}"; ++ret )); do
+ [ -n "${IPMI_FRU_EEPROM_FILE[@]+1}" ] || \
+ [ -n "${IPMI_FRU_EEPROM_BUSADDR[@]+1}" ]|| break
+ done
+
+ if [[ "$name" =~ ^of-name:(.*)$ || "$name" =~ ^([^:]*)$ ]]; then
+ local ofn="${BASH_REMATCH[1]}"
+ local file
+ file="$(of_name_to_eeprom "$ofn")" || return
+ IPMI_FRU_EEPROM_FILE["$ret"]="$file"
+ elif [[ "$name" =~ ^frudev-name:(.*)$ ]]; then
+ local fdn="${BASH_REMATCH[1]}"
+ local start=$SECONDS
+ local file
+ while (( SECONDS - start < 60 )); do
+ local rc=0
+ ipmi_fru_device_alloc "$fdn" "$ret" || rc=$?
+ (( rc == 0 )) && break
+ # Immediately return any errors, 80 is special to signify retry
+ (( rc != 80 )) && return $rc
+ sleep 1
+ done
+ else
+ echo "Invalid IPMI FRU eeprom specification: $name" >&2
+ return 1
+ fi
+}
+
+ipmi_fru_free() {
+ unset 'IPMI_FRU_EEPROM_FILE[$1]'
+ unset 'IPMI_FRU_EEPROM_BUSADDR[$1]'
+}
+
checksum() {
local -n checksum_arr="$1"
local checksum=0
@@ -61,24 +147,36 @@ fix_checksum() {
}
read_bytes() {
- local file="$1"
+ local busaddr=(${IPMI_FRU_EEPROM_BUSADDR["$1"]-})
+ local file="${IPMI_FRU_EEPROM_FILE["$1"]-$1}"
local offset="$2"
local size="$3"
- echo "Reading $file at $offset for $size" >&2
- dd if="$file" bs=1 count="$size" skip="$offset" 2>/dev/null | \
- hexdump -v -e '1/1 "%d "'
+ if (( "${#busaddr[@]}" > 0)); then
+ echo "Reading ${busaddr[*]} at $offset for $size" >&2
+ i2ctransfer -f -y ${busaddr[0]} $(${busaddr[2]} ${busaddr[1]} $offset) r$size
+ else
+ echo "Reading $file at $offset for $size" >&2
+ dd if="$file" bs=1 count="$size" skip="$offset" 2>/dev/null | \
+ hexdump -v -e '1/1 "%d "'
+ fi
}
write_bytes() {
- local file="$1"
+ local busaddr=(${IPMI_FRU_EEPROM_BUSADDR["$1"]-})
+ local file="${IPMI_FRU_EEPROM_FILE["$1"]-$1}"
local offset="$2"
local -n bytes_arr="$3"
- local hexstr
- hexstr="$(printf '\\x%x' "${bytes_arr[@]}")" || return
- echo "Writing $file at $offset for ${#bytes_arr[@]}" >&2
- printf "$hexstr" | dd of="$file" bs=1 seek=$offset 2>/dev/null
+ if (( "${#busaddr[@]}" > 0)); then
+ echo "Writing ${busaddr[*]} at $offset for ${#bytes_arr[@]}" >&2
+ i2ctransfer -f -y ${busaddr[0]} $(${busaddr[2]} ${busaddr[1]} $offset ${#bytes_arr[@]}) ${bytes_arr[@]}
+ else
+ local hexstr
+ hexstr="$(printf '\\x%x' "${bytes_arr[@]}")" || return
+ echo "Writing $file at $offset for ${#bytes_arr[@]}" >&2
+ printf "$hexstr" | dd of="$file" bs=1 seek=$offset 2>/dev/null
+ fi
}
read_header() {