-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/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