diff options
author | William A. Kennington III <wak@google.com> | 2021-10-16 01:55:39 +0300 |
---|---|---|
committer | William A. Kennington III <wak@google.com> | 2021-10-20 02:35:08 +0300 |
commit | a7532a6b3629e7b8e1690769f70d4d9dcc3f7056 (patch) | |
tree | 4f00ddab52eb4cc9aa56d6435a8dbae47439e83a /meta-google | |
parent | dc7e42efcf59bc5b0afbdc09465247a2877661bd (diff) | |
download | openbmc-a7532a6b3629e7b8e1690769f70d4d9dcc3f7056.tar.xz |
meta-google: ipmi-fru: Direct read support
We can't dynamically bind to the at24 driver if the eeprom is not in
the kernel's device tree. Since this support was intended to be used
for dynamic FRUs, it is broken when the kernel has the entries removed.
Change-Id: I99c774191c22d67e518fe9435b1446b80efb5600
Signed-off-by: William A. Kennington III <wak@google.com>
Diffstat (limited to 'meta-google')
-rw-r--r-- | meta-google/recipes-google/ipmi/ipmi-fru-sh/lib.sh | 72 |
1 files changed, 52 insertions, 20 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 940be7fb0..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,10 +56,14 @@ 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_to_file() { +ipmi_fru_device_alloc() { local fdn="$1" + local idx="$2" local json json="$(busctl -j call xyz.openbmc_project.FruDevice \ @@ -54,20 +72,21 @@ ipmi_fru_device_to_file() { local jqq='.data[0] | (.BUS.data | tostring) + " " + (.ADDRESS.data | tostring)' local busaddr - busaddr="$(echo "$json" | jq -r "$jqq")" || return + 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' ]; then - echo "/etc/fru/baseboard.fru.bin" + if (( busaddr[0] == 0 && busaddr[1] == 0 )); then + IPMI_FRU_EEPROM_FILE["$idx"]=/etc/fru/baseboard.fru.bin else - local dev="$(printf '%d-%04x' $busaddr)" - local efile="/sys/bus/i2c/devices/$dev/eeprom" - # The at24 eeprom driver is not guaranteed to be bound - if [ ! -e "$efile" ]; then - echo "$dev" >/sys/bus/i2c/drivers/at24/bind || return + 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 - echo "$efile" + IPMI_FRU_EEPROM_BUSADDR["$idx"]="${busaddr[*]} $offset_bw" fi } @@ -77,7 +96,8 @@ ipmi_fru_alloc() { # 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}" ] || break + [ -n "${IPMI_FRU_EEPROM_FILE[@]+1}" ] || \ + [ -n "${IPMI_FRU_EEPROM_BUSADDR[@]+1}" ]|| break done if [[ "$name" =~ ^of-name:(.*)$ || "$name" =~ ^([^:]*)$ ]]; then @@ -91,13 +111,12 @@ ipmi_fru_alloc() { local file while (( SECONDS - start < 60 )); do local rc=0 - file="$(ipmi_fru_device_to_file "$fdn")" || rc=$? + 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 - IPMI_FRU_EEPROM_FILE["$ret"]="$file" else echo "Invalid IPMI FRU eeprom specification: $name" >&2 return 1 @@ -106,6 +125,7 @@ ipmi_fru_alloc() { ipmi_fru_free() { unset 'IPMI_FRU_EEPROM_FILE[$1]' + unset 'IPMI_FRU_EEPROM_BUSADDR[$1]' } checksum() { @@ -127,24 +147,36 @@ fix_checksum() { } read_bytes() { + 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 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() { |