Skip to content

Instantly share code, notes, and snippets.

@jeffangelion
Last active March 10, 2025 13:48
Show Gist options
  • Save jeffangelion/e7736a0802d4782d5e3d4d2e08e8306b to your computer and use it in GitHub Desktop.
Save jeffangelion/e7736a0802d4782d5e3d4d2e08e8306b to your computer and use it in GitHub Desktop.
#!/usr/bin/env bash
#
# Simple Intel x520 EEPROM patcher
# Modifies the EEPROM to unlock the card for non-intel branded SFP modules.
#
# Copyright 2024 Ivan Vatlin <[email protected]>
#
# Licensed under the GPLv3
#
# Based on research described at https://forums.servethehome.com/index.php?threads/patching-intel-x520-eeprom-to-unlock-all-sfp-transceivers.24634/
#
# Quick explanation of what's going on:
# Looking at the Intel driver at e.g. https://elixir.bootlin.com/linux/v5.8/source/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h#L2140 we can see
# that the bit 0x1 at Address 0x58 contains a configuration setting whether the card allows any SFP modules or if Intel specific ones are enforced
# by the driver.
#
# Addr Bitstring
# 0x58 xxxxxxx0 means Intel specific SFPs
# 0x58 xxxxxxx1 means any SFP is allowed.
#
# Using the parameter allow_unsupported_sfp for the kernel module we can tell the driver to accept any SFPs.
# But this tool will flip the right bit 1 to make that change permanent in the configuration bits in the EEPROM,
# thus making kernel module parameters unnecessary.
#
# export YOLO=1 for auto usage if you are brave enough
yolo=${YOLO:-0}
intel="0x8086"
declare -A x520_card_ids=( ["0x10fb"]="82599ES 10-Gigabit SFI/SFP+ Network Connection" ["0x154d"]="Ethernet 10G 2P X520 Adapter" )
# declare -A x710_card_ids=( ["0x1572"]="Ethernet Controller X710 for 10GbE SFP+" )
function verify_interface {
local interface=$1
local vendor_id="$(cat /sys/class/net/$interface/device/vendor)"
local device_id="$(cat /sys/class/net/$interface/device/device)"
if [[ -z $vendor_id || -z $device_id ]]; then
printf "%s: can't read interface data, skipping...\n" "$interface"
return
fi
if [[ $vendor_id == "$intel" ]]; then
printf "%s: recognized an Intel manufactured card\n" "$interface"
else
printf "%s: not an Intel manufactured card, skipping...\n" "$interface"
return
fi
if [[ "${!x520_card_ids[*]}" =~ $device_id ]]; then
printf "%s: recognized the %s card\n" "$interface" "${x520_card_ids[$device_id]}"
unlock_x520 "$interface" "$vendor_id" "$device_id"
# elif [[ "${!x710_card_ids[*]}" =~ $device_id ]]; then
# printf "%s: recognized the %s card\n" "$interface" "${x710_card_ids[$device_id]}"
# unlock_x710 $interface
else
printf "%s: not a supported card, skipping...\n" "$interface"
return
fi
return
}
function unlock_x520 {
local interface=$1
local vendor_id=$2
local device_id=$3
local magic="${device_id}${vendor_id:2}"
# get current bit
local current_eeprom_value_hex="$(ethtool -e $interface offset 0x58 length 1 raw on | hexdump -e '"%2x"')"
local current_eeprom_value="$((16#$current_eeprom_value_hex))"
if [[ -z $current_eeprom_value_hex ]]; then
printf "%s: failed to get EEPROM value, is ethtool installed?\n" "$interface"
return
elif (( ($current_eeprom_value & 0x1) == 0x1 )); then
printf "%s: card is already unlocked, skipping...\n" "$interface"
return
else
local new_eeprom_value=$((current_eeprom_value | 1))
local new_eeprom_value_hex=$( (printf '%x' $new_eeprom_value) )
local unlock_cmd=("ethtool" "-E" "${interface}" "magic" "${magic}" "offset" "0x58" "value" "0x${new_eeprom_value_hex}" "length" "1")
if [[ $yolo -eq 0 ]]; then
printf "%s: about to run %s\n" "$interface" "${unlock_cmd[*]}"
printf "%s: this operation will write data to your ethernet card eeprom. Type 'yes' to confirm: \n" "$interface"
read -r answer
if [[ ${answer,,} != "yes" ]]; then
printf "%s: operation aborted, skipping...\n" "$interface"
return
else
"${unlock_cmd[@]}"
fi
else
printf "%s: running %s" "$interface" "${unlock_cmd[*]}"
"${unlock_cmd[@]}"
fi
fi
# check if bit is actually set
if [[ "$(ethtool -e $interface offset 0x58 length 1 raw on | hexdump -e '"%2x"')" == $new_eeprom_value_hex ]]; then
printf "%s: successfully unlocked, reboot for changes to take effect\n" "$interface"
fi
}
# function unlock_x710 {}
if [[ -z $1 ]]; then
printf "%s <interfaces>\n" "$0"
exit 255
fi
while [[ $# -gt 0 ]]; do
verify_interface "$1"
shift
done
@jeffangelion
Copy link
Author

new version allows batch unlocks via YOLO=1 ./intel_x520_patcher.sh eth{0..255}

@melonhaus
Copy link

Hi,

Complete and utter guide follower here. How does one run this to unlock an x520? Im on windows but will booting into an Ubuntu Desktop live environment work? Any other prerequisites? Many thanks in advance!

@bykaj
Copy link

bykaj commented Feb 19, 2025

Thanks @jeffangelion!

@jeffangelion
Copy link
Author

jeffangelion commented Feb 20, 2025

How does one run this to unlock an x520?

@melonhaus you can use any Linux distribution with root shell or sudo and recent version of ethtool but I highly recommend to use Clonezilla as live environment (it has an option to enter shell and using old interface name convention ethX) and run something like:
$ ./intel_x520_patcher.sh your_interface_here
You can get interface name by invoking a command:
$ ip -c a
Or, you can use a very brute approach:

$ sudo -i
# YOLO=1 ./intel_x520_patcher.sh eth{0..255}

While I can confirm its results in my environment, I can't confirm it'll work for you (thus it's your own responsibility)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment