Skip to content

Instantly share code, notes, and snippets.

@fdx90
Forked from ixs/intel_x520_patcher.py
Last active May 16, 2024 23:29
Show Gist options
  • Select an option

  • Save fdx90/2ba2b73d8faa2e15fa2c3b4bf83ff2dd to your computer and use it in GitHub Desktop.

Select an option

Save fdx90/2ba2b73d8faa2e15fa2c3b4bf83ff2dd to your computer and use it in GitHub Desktop.
Intel x520 EEPROM Patcher allows to unlock the x520 network card to work with non-intel branded SFP modules.
#!/usr/bin/env python3
#
# Simple Intel x520 EEPROM patcher
# Modifies the EEPROM to unlock the card for non-intel branded SFP modules.
#
# Copyright 2020,2021,2022 Andreas Thienemann <[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.
#
# Changes made:
# 1. Modularized the code into separate functions for better readability and maintainability.
# 2. Improved error handling with more user-friendly messages.
# 3. Utilized f-strings for clearer and more concise string formatting.
# 4. Added docstrings to functions for better documentation and understanding of their purposes.
#
import subprocess
import sys
VENDOR_ID = '0x8086'
DEVICE_IDS = {'0x10fb', '0x154d'}
EEPROM_OFFSET = '0x58'
EEPROM_LENGTH = '1'
def read_file(filepath):
"""Reads the content of a file and returns it as a string."""
try:
with open(filepath) as f:
return f.read().strip()
except IOError:
return None
def check_interface(intf):
"""Checks if the interface is a recognized Intel x520 card."""
vdr_id = read_file(f"/sys/class/net/{intf}/device/vendor")
dev_id = read_file(f"/sys/class/net/{intf}/device/device")
if vdr_id != VENDOR_ID or dev_id not in DEVICE_IDS:
return None, None
return vdr_id, dev_id
def read_eeprom(intf):
"""Reads the EEPROM value at the specified offset."""
try:
output = subprocess.check_output(['ethtool', '-e', intf, 'offset', EEPROM_OFFSET, 'length', EEPROM_LENGTH])
val = output.strip().split(b'\n')[-1].split()[-1]
return int(val, 16)
except subprocess.CalledProcessError:
return None
def patch_eeprom(intf, dev_id, vdr_id, val_bin):
"""Patches the EEPROM if it is locked to Intel only SFP modules."""
if val_bin & 0b00000001:
print("Card is already unlocked for all SFP modules. Nothing to do.")
return
new_val = val_bin | 0b00000001
print(f"New EEPROM Value at {EEPROM_OFFSET} will be {hex(new_val)} ({bin(new_val)})")
magic = f"{dev_id}{vdr_id[2:]}"
cmd = ['ethtool', '-E', intf, 'magic', magic, 'offset', EEPROM_OFFSET, 'value', hex(new_val), 'length', EEPROM_LENGTH]
print(f"Running {' '.join(cmd)}")
subprocess.call(cmd)
print("Reboot the machine for changes to take effect...")
def main():
if len(sys.argv) != 2:
print(f"Usage: {sys.argv[0]} <interface>")
sys.exit(255)
intf = sys.argv[1]
vdr_id, dev_id = check_interface(intf)
if not vdr_id or not dev_id:
print("Not a recognized Intel x520 card.")
sys.exit(3)
val_bin = read_eeprom(intf)
if val_bin is None:
print("Can't read EEPROM value.")
sys.exit(2)
print(f"EEPROM Value at {EEPROM_OFFSET} is {hex(val_bin)} ({bin(val_bin)})")
patch_eeprom(intf, dev_id, vdr_id, val_bin)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment