-
-
Save ixs/dbaac42730dea9bd124f26cbd439c58e to your computer and use it in GitHub Desktop.
| #!/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. | |
| # | |
| import subprocess | |
| import sys | |
| # Supported cards. If your card is supported but not listed here, please add a comment | |
| # with your PCI IDs at https://gist.github.com/ixs/dbaac42730dea9bd124f26cbd439c58e | |
| card_ids = { | |
| "0x10fb": "82599ES 10-Gigabit SFI/SFP+ Network Connection", | |
| "0x154d": "Ethernet 10G 2P X520 Adapter", | |
| "0x1557": "82599 10 Gigabit Network Connection", | |
| } | |
| try: | |
| intf = sys.argv[1] | |
| except IndexError: | |
| print("%s <interface>" % sys.argv[0]) | |
| exit(255) | |
| print("Verifying interface %s." % intf) | |
| try: | |
| with open("/sys/class/net/%s/device/vendor" % intf) as f: | |
| vdr_id = f.read().strip() | |
| with open("/sys/class/net/%s/device/device" % intf) as f: | |
| dev_id = f.read().strip() | |
| except IOError: | |
| print("Can't read interface data.") | |
| exit(2) | |
| if vdr_id in ("0x8086"): | |
| print("Recognized an Intel manufactured card.") | |
| else: | |
| print("No Intel manufactured card found.") | |
| exit(3) | |
| if dev_id in card_ids: | |
| print("Recognized the %s card." % card_ids[dev_id]) | |
| else: | |
| print("No recognized x520-based card found.") | |
| exit(3) | |
| # Read eeprom at offset 0x58 | |
| output = subprocess.check_output( | |
| ["ethtool", "-e", intf, "offset", "0x58", "length", "1"] | |
| ).decode("utf-8") | |
| # Parse ethtool output and convert the value into a binary string | |
| val = output.strip().split("\n")[-1].split()[-1] | |
| val_bin = int(val, 16) | |
| print("EEPROM Value at 0x58 is 0x%s (%s)." % (val, bin(val_bin))) | |
| if val_bin & 0b00000001 == 1: | |
| print("Card is already unlocked for all SFP modules. Nothing to do.") | |
| exit(1) | |
| if val_bin & 0b00000001 == 0: | |
| print("Card is locked to Intel only SFP modules. Patching EEPROM...") | |
| new_val = val_bin | 0b00000001 | |
| print("New EEPROM Value at 0x58 will be %s (%s)" % (hex(new_val), bin(new_val))) | |
| # The "magic" value we need in order to write to a intel card is "0x<device_id><vendor_id>" | |
| magic = "%s%s" % (dev_id, vdr_id[2:]) | |
| cmd = [ | |
| "ethtool", | |
| "-E", | |
| intf, | |
| "magic", | |
| str(magic), | |
| "offset", | |
| "0x58", | |
| "value", | |
| hex(new_val), | |
| "length", | |
| "1", | |
| ] | |
| print("About to run %s" % " ".join(cmd)) | |
| if ( | |
| input( | |
| "This operation will write data to your ethernet card eeprom. Type 'yes' to confirm: " | |
| ).lower() | |
| != "yes" | |
| ): | |
| print("Operation aborted.") | |
| exit(1) | |
| output = subprocess.check_output(cmd).decode("utf-8") | |
| if len(output) == 0: | |
| print("Sucess!") | |
| print("Reboot the machine for changes to take effect...") | |
| exit(0) | |
| else: | |
| print(output) |
@ixs, I've found another x520 card not listed that works with your script. I have verified the following additional card. Reword the description as you see fit.
"0x1557": "82599 10 Gigabit Network Connection (X520-DA1)",
I cleared the bit and saw the kernel message stating that the module wasn't supported. Upon flipping the bit back and rebooting, it started working again. I ordered 2 of these https://www.amazon.com/dp/B01N3YSBMY, and 1 card had it already set (0xfd) and the other card did not (0xfe). FYI, I was using these SFP+ modules, https://www.amazon.com/dp/B08NW1VBX6.
I was trying to reduce cost as much as was reasonable, which is why I'm mixing and matching these cheaper parts. They have been rock solid so far over ~50ft of CAT6. I'm getting the expected 9.4gpbs in iperf3 and even lower retr counts than I did over the previous gigabit connection with the same cables.
Thank you, it worked for us on the X520-DA2 with no issues
Wow this script helped me at work, here I rewrote it in pure Bash: https://gist.github.com/jeffangelion/e7736a0802d4782d5e3d4d2e08e8306b