Download raw body.
sys/ure: use and load firmware
Kevin, tech@,
both RTL8157 and RTL8159 uses the same firmware from RTL8126-2 and
RTL8127, or at least I read it so by analyzing blob from
https://gitlab.com/koblitz-rtlnic/rtlnic_fw with some gule.
It allows me to reuse firmware which is already in base.
If firmware is not here, it continue to work like before.
Briefly tested by RTL8159 and it loads it and continue to work.
Ok?
Index: sys/dev/usb/if_ure.c
===================================================================
RCS file: /home/cvs/src/sys/dev/usb/if_ure.c,v
diff -u -p -r1.38 if_ure.c
--- sys/dev/usb/if_ure.c 7 Oct 2026 09:36:53 -0000 1.38
+++ sys/dev/usb/if_ure.c 4 Nov 2026 08:24:27 -0000
@@ -34,7 +34,9 @@
#include <sys/sockio.h>
#include <sys/rwlock.h>
#include <sys/mbuf.h>
+#include <sys/malloc.h>
#include <sys/device.h>
+#include <sys/endian.h>
#include <machine/bus.h>
@@ -132,6 +134,25 @@ const struct usb_devno ure_devs[] = {
{ USB_VENDOR_XIAOMI, USB_PRODUCT_XIAOMI_RTL8152B },
};
+#define URE_8157_FW "rge-rtl8126-2"
+#define URE_8159_FW "rge-rtl8127"
+
+struct ure_fw_hdr {
+ uint32_t maclen;
+ uint32_t phylen;
+} __packed;
+
+struct ure_fw_pair {
+ uint16_t reg;
+ uint16_t val;
+};
+
+struct ure_fw {
+ uint8_t buf[URE_FW_BUFSZ];
+ int len;
+ uint16_t page;
+};
+
int ure_match(struct device *, void *, void *);
void ure_attach(struct device *, struct device *, void *);
int ure_detach(struct device *, int);
@@ -205,6 +226,11 @@ void ure_rtl8152_init(struct ure_softc
int ure_rtl8153_init(struct ure_softc *);
int ure_rtl8153b_init(struct ure_softc *);
int ure_rtl8157_init(struct ure_softc *);
+void ure_loadfirmware(struct ure_softc *);
+int ure_fw_write(struct ure_softc *, struct ure_fw *, uint16_t,
+ uint16_t);
+int ure_fw_chunk(struct ure_softc *, struct ure_fw *);
+int ure_phy_patch_request(struct ure_softc *, int);
int ure_rtl8152_nic_reset(struct ure_softc *);
int ure_rtl8153_nic_reset(struct ure_softc *);
uint16_t ure_rtl8153_phy_status(struct ure_softc *, int);
@@ -1038,6 +1064,9 @@ ure_init(void *xsc)
/* Cancel pending I/O. */
ure_stop(sc);
+ if (sc->ure_flags & (URE_FLAG_8157 | URE_FLAG_8159))
+ ure_loadfirmware(sc);
+
if (sc->ure_flags & URE_FLAG_8152)
error = ure_rtl8152_nic_reset(sc);
else
@@ -1706,6 +1735,221 @@ ure_rtl8157_init(struct ure_softc *sc)
URE_SETBIT_2(sc, URE_PLA_RSTTALLY, URE_MCU_TYPE_PLA, URE_TALLY_RESET);
return (0);
+}
+
+void
+ure_loadfirmware(struct ure_softc *sc)
+{
+ struct ure_fw_hdr *hdr;
+ struct ure_fw_pair *phy;
+ struct ure_fw *ucode = NULL;
+ const char *fwname;
+ u_char *fw;
+ size_t fwlen, i, nphy, patchidx;
+ uint32_t maclen, phylen;
+ uint16_t reg, val, version;
+ int error, release_error;
+
+ if (sc->ure_flags & URE_FLAG_8159) {
+ fwname = URE_8159_FW;
+ version = URE_8159_FW_VER;
+ } else {
+ fwname = URE_8157_FW;
+ version = URE_8157_FW_VER;
+ }
+
+ if ((error = loadfirmware(fwname, &fw, &fwlen)) != 0) {
+ printf("%s: could not load firmware %s (%d)\n",
+ sc->ure_dev.dv_xname, fwname, error);
+ return;
+ }
+
+ error = EINVAL;
+ if (fwlen < sizeof(*hdr))
+ goto out;
+ hdr = (struct ure_fw_hdr *)fw;
+ maclen = letoh32(hdr->maclen);
+ phylen = letoh32(hdr->phylen);
+ if (maclen > fwlen - sizeof(*hdr) ||
+ phylen != fwlen - sizeof(*hdr) - maclen ||
+ maclen % sizeof(*phy) != 0 || phylen % sizeof(*phy) != 0 ||
+ phylen == 0)
+ goto out;
+
+ phy = (struct ure_fw_pair *)(fw + sizeof(*hdr) + maclen);
+ nphy = phylen / sizeof(*phy);
+ for (patchidx = 0; patchidx < nphy; patchidx++) {
+ if (letoh16(phy[patchidx].reg) == URE_OCP_PHY_PATCH_CMD &&
+ letoh16(phy[patchidx].val) == 0)
+ break;
+ }
+ if (patchidx == nphy)
+ goto out;
+
+ ure_phy_write(sc, URE_OCP_SRAM_ADDR, URE_SRAM_GPHY_FW_VER);
+ reg = ure_phy_read(sc, URE_OCP_SRAM_DATA);
+ if (reg == 0xffff) {
+ error = EIO;
+ goto out;
+ }
+ if (reg >= version) {
+ error = 0;
+ goto out;
+ }
+
+ ucode = malloc(sizeof(*ucode), M_DEVBUF, M_WAITOK | M_ZERO);
+ ucode->page = 0xffff;
+
+ if ((ure_read_2(sc, URE_PLA_GPHY_CTRL, URE_MCU_TYPE_PLA) &
+ URE_GPHY_FLASH) &&
+ !(ure_read_2(sc, URE_USB_GPHY_CTRL, URE_MCU_TYPE_USB) &
+ URE_BYPASS_FLASH)) {
+ if (URE_SETBIT_2(sc, URE_USB_GPHY_CTRL, URE_MCU_TYPE_USB,
+ URE_BYPASS_FLASH) != 0) {
+ error = EIO;
+ goto out;
+ }
+ }
+
+ error = ure_phy_patch_request(sc, 1);
+ if (error != 0)
+ goto release;
+
+ for (i = 0; i < nphy; i++) {
+ reg = letoh16(phy[i].reg);
+ val = letoh16(phy[i].val);
+ if (i == patchidx) {
+ error = ure_fw_write(sc, ucode, URE_OCP_SRAM_ADDR,
+ URE_SRAM_GPHY_FW_VER);
+ if (error != 0)
+ goto release;
+ error = ure_fw_write(sc, ucode, URE_OCP_SRAM_DATA,
+ version);
+ if (error != 0)
+ goto release;
+ if (sc->ure_flags & URE_FLAG_8159)
+ continue;
+ }
+ error = ure_fw_write(sc, ucode, reg, val);
+ if (error != 0)
+ goto release;
+ }
+ if (ucode->len != 0)
+ error = ure_fw_chunk(sc, ucode);
+
+release:
+ release_error = ure_phy_patch_request(sc, 0);
+ if (error == 0)
+ error = release_error;
+ if (error == 0) {
+ ure_phy_write(sc, URE_OCP_SRAM_ADDR, URE_SRAM_GPHY_FW_VER);
+ reg = ure_phy_read(sc, URE_OCP_SRAM_DATA);
+ if (reg == 0xffff || reg < version)
+ error = EIO;
+ }
+out:
+ if (error != 0)
+ printf("%s: loading firmware %s failed (%d)\n",
+ sc->ure_dev.dv_xname, fwname, error);
+ if (ucode != NULL)
+ free(ucode, M_DEVBUF, sizeof(*ucode));
+ free(fw, M_DEVBUF, fwlen);
+}
+
+int
+ure_fw_write(struct ure_softc *sc, struct ure_fw *ucode, uint16_t reg,
+ uint16_t val)
+{
+ uint16_t page = reg & 0xf000;
+ int error, page_select, len;
+
+ page_select = reg == URE_OCP_SRAM_ADDR &&
+ (val == 0xa016 || val == 0xb87c);
+ len = sizeof(struct ure_fw_pair);
+ if (page_select || ucode->page != page)
+ len += sizeof(struct ure_fw_pair);
+ if (ucode->len + len + sizeof(struct ure_fw_pair) > sizeof(ucode->buf)) {
+ error = ure_fw_chunk(sc, ucode);
+ if (error != 0)
+ return (error);
+ }
+
+ if (page_select || ucode->page != page) {
+ USETW(ucode->buf + ucode->len, URE_PLA_OCP_GPHY_BASE);
+ USETW(ucode->buf + ucode->len + 2, page);
+ ucode->len += sizeof(struct ure_fw_pair);
+ ucode->page = page;
+ }
+ USETW(ucode->buf + ucode->len, 0xb000 | (reg & 0x0fff));
+ USETW(ucode->buf + ucode->len + 2, val);
+ ucode->len += sizeof(struct ure_fw_pair);
+ return (0);
+}
+
+int
+ure_fw_chunk(struct ure_softc *sc, struct ure_fw *ucode)
+{
+ uint16_t reg;
+ int i;
+
+ if (usbd_is_dying(sc->ure_udev))
+ return (ENXIO);
+
+ memset(ucode->buf + ucode->len, 0xff, sizeof(struct ure_fw_pair));
+ ucode->len += sizeof(struct ure_fw_pair);
+ if (URE_SETBIT_2(sc, URE_USB_GPHY_CTRL, URE_MCU_TYPE_USB,
+ URE_GPHY_PATCH_DONE | URE_BACKUP_RESTORE) != 0 ||
+ ure_write_mem(sc, URE_FW_ADDR,
+ URE_MCU_TYPE_USB | URE_BYTE_EN_DWORD, ucode->buf, ucode->len) != 0 ||
+ URE_SETBIT_2(sc, URE_PLA_POL_GPIO_CTRL, URE_MCU_TYPE_PLA,
+ URE_POL_GPHY_PATCH) != 0)
+ return (EIO);
+
+ for (i = 0; i < URE_TIMEOUT; i++) {
+ if (usbd_is_dying(sc->ure_udev))
+ return (ENXIO);
+ reg = ure_read_2(sc, URE_PLA_POL_GPIO_CTRL, URE_MCU_TYPE_PLA);
+ if (reg == 0xffff)
+ return (EIO);
+ if (!(reg & URE_POL_GPHY_PATCH))
+ break;
+ }
+ if (i == URE_TIMEOUT)
+ return (ETIMEDOUT);
+
+ ucode->len = 0;
+ ucode->page = 0xffff;
+ return (0);
+}
+
+int
+ure_phy_patch_request(struct ure_softc *sc, int request)
+{
+ uint16_t reg;
+ int i;
+
+ if (usbd_is_dying(sc->ure_udev))
+ return (ENXIO);
+ reg = ure_phy_read(sc, URE_OCP_PHY_PATCH_CMD);
+ if (reg == 0xffff)
+ return (EIO);
+ if (request)
+ reg |= URE_PATCH_REQUEST;
+ else
+ reg &= ~URE_PATCH_REQUEST;
+ ure_phy_write(sc, URE_OCP_PHY_PATCH_CMD, reg);
+
+ for (i = 0; i < URE_PHY_PATCH_TIMEOUT; i++) {
+ usbd_delay_ms(sc->ure_udev, 1);
+ if (usbd_is_dying(sc->ure_udev))
+ return (ENXIO);
+ reg = ure_phy_read(sc, URE_OCP_PHY_PATCH_STAT);
+ if (reg == 0xffff)
+ return (EIO);
+ if (((reg & URE_PATCH_READY) != 0) == request)
+ return (0);
+ }
+ return (ETIMEDOUT);
}
int
Index: sys/dev/usb/if_urereg.h
===================================================================
RCS file: /home/cvs/src/sys/dev/usb/if_urereg.h,v
diff -u -p -r1.15 if_urereg.h
--- sys/dev/usb/if_urereg.h 7 Oct 2026 09:36:53 -0000 1.15
+++ sys/dev/usb/if_urereg.h 4 Nov 2026 08:24:27 -0000
@@ -34,6 +34,7 @@
#define URE_CTL_WRITE 0x02
#define URE_TIMEOUT 1000
+#define URE_PHY_PATCH_TIMEOUT 5000
#define URE_PHY_TIMEOUT 2000
#define URE_BYTE_EN_DWORD 0xff
@@ -176,10 +177,13 @@
#define URE_OCP_EEE_LPABLE 0xa5d2
#define URE_OCP_10GBT_CTRL 0xa5d4
#define URE_OCP_PHY_STATE 0xa708
+#define URE_OCP_PHY_PATCH_STAT 0xb800
+#define URE_OCP_PHY_PATCH_CMD 0xb820
#define URE_OCP_ADC_CFG 0xbc06
/* SRAM Register. */
#define URE_SRAM_LPF_CFG 0x8012
+#define URE_SRAM_GPHY_FW_VER 0x801e
#define URE_SRAM_10M_AMP1 0x8080
#define URE_SRAM_10M_AMP2 0x8082
#define URE_SRAM_IMPEDANCE 0x8084
@@ -361,6 +365,7 @@
#define URE_GPHY_FLASH 0x0002
/* URE_PLA_POL_GPIO_CTRL */
+#define URE_POL_GPHY_PATCH 0x0010
#define URE_DACK_DET_EN 0x8000
/* URE_PLA_PHYSTATUS */
@@ -411,6 +416,7 @@
/* URE_USB_GPHY_CTRL */
#define URE_GPHY_PATCH_DONE 0x0004
#define URE_BYPASS_FLASH 0x0020
+#define URE_BACKUP_RESTORE 0x0040
/* URE_USB_SPEED_OPTION */
#define URE_RG_PWRDN_EN 0x0100
@@ -544,6 +550,12 @@
/* URE_OCP_DOWN_SPEED */
#define URE_EN_10M_BGOFF 0x0080
+/* URE_OCP_PHY_PATCH_STAT */
+#define URE_PATCH_READY 0x0040
+
+/* URE_OCP_PHY_PATCH_CMD */
+#define URE_PATCH_REQUEST 0x0010
+
/* URE_OCP_PHY_STATE */
#define URE_TXDIS_STATE 0x01
#define URE_ABD_STATE 0x02
@@ -643,6 +655,11 @@ struct ure_txpkt_v2 {
#define URE_8156_TX_BUFSZ 32768
#define URE_8152_RX_BUFSZ 16384
#define URE_8153_RX_BUFSZ 32768
+
+#define URE_FW_BUFSZ 2048
+#define URE_FW_ADDR 0x9a00
+#define URE_8157_FW_VER 0x0014
+#define URE_8159_FW_VER 0x0020
#define URE_CMD_TYPE_BMU 0
#define URE_CMD_TYPE_IP 1
Index: share/man/man4/ure.4
===================================================================
RCS file: /home/cvs/src/share/man/man4/ure.4,v
diff -u -p -r1.12 ure.4
--- share/man/man4/ure.4 7 Oct 2026 09:39:37 -0000 1.12
+++ share/man/man4/ure.4 4 Nov 2026 08:24:27 -0000
@@ -57,6 +57,15 @@ Ethernet MAC.
.Pp
For more information on configuring this device, see
.Xr ifconfig 8 .
+.Sh FILES
+The following firmware files provide optional PHY updates and are loaded
+when the interface is brought up:
+.Bl -tag -width Ds -offset indent -compact
+.It Pa /etc/firmware/rge-rtl8126-2
+RTL8157 firmware.
+.It Pa /etc/firmware/rge-rtl8127
+RTL8159 firmware.
+.El
.Sh SEE ALSO
.Xr arp 4 ,
.Xr ifmedia 4 ,
@@ -78,8 +87,3 @@ The
.Nm
driver was written by
.An Kevin Lo Aq Mt kevlo@FreeBSD.org .
-.Sh CAVEATS
-RTL8159 adapters require firmware for 10Gb operation.
-The
-.Nm
-driver does not support loading this firmware.
--
wbr, Kirill
sys/ure: use and load firmware