Index | Thread | Search

From:
Kirill A. Korinsky <kirill@korins.ky>
Subject:
sys/ure: use and load firmware
To:
kevlo@openbsd.org
Cc:
OpenBSD tech <tech@openbsd.org>
Date:
Wed, 04 Nov 2026 09:39:41 +0100

Download raw body.

Thread
  • Kirill A. Korinsky:

    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