先日に公開したカーネル差分である linux-6.15.4-shmin-1.patch は、LANは正常動作するものの起動時にエラーが発生します。

エラー対策をしたカーネル差分は linux-6.15.4-shmin-2.patchです。
Linuxカーネル本体のソースアーカイブは linux-6.15.4.tar.xzです。

実は、Linux5.17以降に、ネットワークデバイス構造体のMACアドレスを格納する6バイトの変数にMACアドレスを格納する際に専用の関数を使うように仕様変更されました。

もし、専用の関数を使わない場合、LAN起動時に以下のようなエラーが発生します。

~ # udhcpc

udhcpc: started, v1.37.0
ax88796b ax88796b eth0: Current addr: 00 18 5f 00 60 a8 00 00 00 00 00 00 00 00 00 00 00 00 00 0
ax88796b ax88796b eth0: Expected addr: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0
————[ cut here ]————
netdevice: eth0: Incorrect netdev->dev_addr
WARNING: CPU: 0 PID: 684 at net/core/dev_addr_lists.c:520 dev_addr_check+0x74/0xd8
Modules linked in:

CPU: 0 UID: 0 PID: 684 Comm: ifconfig Not tainted 6.15.4 #1 PREEMPT
PC is at dev_addr_check+0x74/0xd8
PR is at dev_addr_check+0x74/0xd8
PC : 8c2b2c64 SP : 8d435d50 SR : 40000101 TEA : 004d59fc
R0 : 09000000 R1 : 00000000 R2 : 00000000 R3 : 00000000
R4 : 00000001 R5 : ff07b407 R6 : 00000008 R7 : 00000089
R8 : 8ca40000 R9 : 8ca400bc R10 : 8c01419c R11 : 8ca4023c
R12 : 8ca40040 R13 : 8c3b0320 R14 : 00001002
MACH: 0000d6c9 MACL: 0000afa8 GBR : 005314f0 PR : 8c2b2c64

Call trace:
[<8c2aec80>] __dev_open+0x48/0x158
[<8c2a5f4c>] netif_device_present+0x0/0xc
[<8c2af05e>] __dev_change_flags+0x122/0x184
[<8c2aec00>] dev_set_rx_mode+0x0/0x38
[<8c2aec00>] dev_set_rx_mode+0x0/0x38
[<8c2bfe60>] __rtnl_unlock+0x24/0x50
[<8c2af0e4>] netif_change_flags+0x24/0x64
[<8c2b19f4>] dev_change_flags+0x1c/0x3c
[<8c325fb8>] devinet_ioctl+0x120/0x428
[<8c327b3c>] inet_ioctl+0x130/0x1b8
[<8c370c30>] memset+0x0/0x48
[<8c28ff5e>] sock_ioctl+0x10e/0x334
[<8c0daf1a>] vfs_ioctl+0x16/0x22
[<8c0dbcca>] sys_ioctl+0x596/0x7f0
[<8c38cc38>] do_page_fault+0x1bc/0x218
[<8c00c25a>] syscall_call+0x18/0x1e
[<8c0db734>] sys_ioctl+0x0/0x7f0

—[ end trace 0000000000000000 ]—
AX88796B: The media mode is autosense.
udhcpc: broadcasting discover
eth0: link up, 100Mbps, Full-duplex
udhcpc: broadcasting discover
udhcpc: broadcasting select for 192.168.0.4, server 192.168.0.1
udhcpc: lease of 192.168.0.4 obtained from 192.168.0.1, lease time 86400
deleting routers
route: SIOCDELRT: No such process
adding dns 192.168.0.1
~ #

従来は、下記のようにネットワークデバイス構造体であるndevのMACアドレスを格納する6バイト変数dev_addrに直接、MACアドレスを格納していました。

static void ax88796b_load_macaddr (struct net_device *ndev)
{
	struct ax_device *ax_local = ax_get_priv (ndev);
	void *ax_base = ax_local->membase;
	int i;
	unsigned char *pMac;
	struct ax88796b_regset
	{
		unsigned char value, offset;
	};
	struct ax88796b_regset program_seq[] =
	{
		{E8390_NODMA | E8390_PAGE0 | E8390_STOP, E8390_CMD},
		{ax_local->bus_width, EN0_DCFG},
		{0x00, EN0_RCNTLO},
		{0x00, EN0_RCNTHI},
		{0x00, EN0_IMR},
		{0xFF, EN0_ISR},
		{E8390_RXOFF, EN0_RXCR},
		{E8390_TXOFF, EN0_TXCR},
		{0x0C, EN0_RCNTLO},
		{0x00, EN0_RCNTHI},
		{0x00, EN0_RSARLO},
		{0x00, EN0_RSARHI},
		{E8390_RREAD | E8390_START, E8390_CMD},
	};

	pMac = (unsigned char *)(ndev->dev_addr);
	/* Read the 12 bytes of station address PROM. */
	for (i = 0; i < sizeof (program_seq)/sizeof (program_seq[0]); i++)
		writeb (program_seq[i].value, ax_base + program_seq[i].offset);

	while (( readb (ax_base + EN0_SR) & 0x20) == 0);

	for (i = 0; i < 6; i++)
		pMac[i] = (unsigned char) READ_FIFO (ax_base + EN0_DATAPORT);

	writeb (ENISR_RDC, ax_base + EN0_ISR);	/* Ack intr. */

	/* Support for No EEPROM */
	if (!is_valid_ether_addr (pMac)) {
		PRINTK (DRIVER_MSG, "Use random MAC address\n");
		eth_random_addr(pMac);
	}
}

下記のようにMACアドレスはローカル変数であるmac_addrに格納するようにして、最後に専用の関数であるeth_hw_addr_setでネットワークデバイス構造体にMACアドレスを格納するようにしました。

static void ax88796b_load_macaddr (struct net_device *ndev) {
	struct ax_device *ax_local = ax_get_priv (ndev);
	void *ax_base = ax_local->membase;
	int i;
	unsigned char mac_addr[ETH_ALEN];
	struct ax88796b_regset
	{
		unsigned char value, offset;
	};
	struct ax88796b_regset program_seq[] =
	{
		{E8390_NODMA | E8390_PAGE0 | E8390_STOP, E8390_CMD},
		{ax_local->bus_width, EN0_DCFG},
		{0x00, EN0_RCNTLO},
		{0x00, EN0_RCNTHI},
		{0x00, EN0_IMR},
		{0xFF, EN0_ISR},
		{E8390_RXOFF, EN0_RXCR},
		{E8390_TXOFF, EN0_TXCR},
		{0x0C, EN0_RCNTLO},
		{0x00, EN0_RCNTHI},
		{0x00, EN0_RSARLO},
		{0x00, EN0_RSARHI},
		{E8390_RREAD | E8390_START, E8390_CMD},
	};

	/* Read the 12 bytes of station address PROM. */
	for (i = 0; i < sizeof (program_seq)/sizeof (program_seq[0]); i++)
		writeb (program_seq[i].value, ax_base + program_seq[i].offset);

	while (( readb (ax_base + EN0_SR) & 0x20) == 0);

	for (i = 0; i < 6; i++)
		mac_addr[i] = (unsigned char) READ_FIFO (ax_base + EN0_DATAPORT);

	writeb (ENISR_RDC, ax_base + EN0_ISR);	/* Ack intr. */

	/* Support for No EEPROM */
	if (!is_valid_ether_addr (mac_addr)) {
		PRINTK (DRIVER_MSG, "Use random MAC address\n");
		eth_random_addr(mac_addr);
	}
	eth_hw_addr_set(ndev, mac_addr);
}

そうすると以下のようにLAN起動時にエラーが発生しなくなりました。

~ # udhcpc
udhcpc: started, v1.37.0
AX88796B: The media mode is autosense.
udhcpc: broadcasting discover
eth0: link up, 100Mbps, Full-duplex
udhcpc: broadcasting discover
udhcpc: broadcasting select for 192.168.0.4, server 192.168.0.1
udhcpc: lease of 192.168.0.4 obtained from 192.168.0.1, lease time 86400
deleting routers
route: SIOCDELRT: No such process
adding dns 192.168.0.1
~ #