RK3566设置以太网MAC地址

1.遇到的问题

        此次购买了10块RK3566的核心板,收到后发现以太网的MAC地址全是一样的,然后尝试使用工具自行设置MAC地址。

使用RKDevInfoWriteTool工具(使用方法参照:RKDevInfoWriteTool使用指南 - V1.2.5.pdf)给主板设置LAN MAC地址,但是主板启动后读取的MAC地址不是设置的MAC地址:

RK3566设置以太网MAC地址_第1张图片

让主板进入Loader模式,启动RKDevInfoWriteTool工具,勾选LAN后面的复选框,勾选单次读取,点击读取,读取出的MAC地址是12个字节,猜想可能系统默认有两个gmac(RK3568有2个GMAC,RK3566只有1个GMAC,GMAC1。),前面6字节是gmac0的地址,后面6字节是gmac1的地址,所以加起来12字节。通过ifconfig指令获取eth0的mac地址为026E784A75A6,为后面6字节。

点击左上角的设置,进入设置页面:

RK3566设置以太网MAC地址_第2张图片

 将8CAE49610002作为MAC地址写入设备,如果选择“自增”的形式这里不能写入12字节,会提示MAC地址不符合规范。

写入之后再读取,LAN:的内容变为8CAE49610003,重启设备再次进入LOADER模式之后再读取,LAN:的内容变为了8CAE49610002A66AE16D2872。

RK3566设置以太网MAC地址_第3张图片

 重启正常进入系统之后通过ifconfig指令获取eth0 的mac地址为A66AE16D2872,如下所示:

RK3566设置以太网MAC地址_第4张图片

2.分析系统启动读取MAC地址的过程

系统启动时会在uboot过程中获取存储在vendor storage中的ETH MAC地址传给内核。

 uboot启动过程中执行..\x3566_linux_v1.2.0\u-boot\arch\arm\mach-rockchip\board.c中board_late_init()函数进行平台late初始化,函数实现如下:

int board_late_init(void)
{
    rockchip_set_ethaddr();
    rockchip_set_serialno();
    setup_download_mode();
#if (CONFIG_ROCKCHIP_BOOT_MODE_REG > 0)
    setup_boot_mode();
#endif
#ifdef CONFIG_ROCKCHIP_USB_BOOT
    boot_from_udisk();
#endif
#ifdef CONFIG_DM_CHARGE_DISPLAY
    charge_display();
#endif
#ifdef CONFIG_DRM_ROCKCHIP
    rockchip_show_logo();
#endif
#ifdef CONFIG_ROCKCHIP_EINK_DISPLAY
    rockchip_eink_show_uboot_logo();
#endif
    env_fixup();
    soc_clk_dump();
    cmdline_handle();
#ifdef CONFIG_AMP
    amp_cpus_on();
#endif
    return rk_board_late_init();
}

board_late_init()函数调用rockchip_set_ethaddr()进行eth mac地址的设置,函数实现如下:

#define MAX_ETHERNET	0x2

static int rockchip_set_ethaddr(void)
{
#ifdef CONFIG_ROCKCHIP_VENDOR_PARTITION
	char buf[ARP_HLEN_ASCII + 1], mac[16];
	u8 ethaddr[ARP_HLEN * MAX_ETHERNET] = {0};
	int ret, i;
	bool need_write = false, randomed = false;

	ret = vendor_storage_read(LAN_MAC_ID, ethaddr, sizeof(ethaddr));
	for (i = 0; i < MAX_ETHERNET; i++) {
		if (ret <= 0 || !is_valid_ethaddr(ðaddr[i * ARP_HLEN])) {
			if (!randomed) {
				net_random_ethaddr(ðaddr[i * ARP_HLEN]);
				randomed = true;
			} else {
				if (i > 0) {
					memcpy(ðaddr[i * ARP_HLEN],
					       ðaddr[(i - 1) * ARP_HLEN],
					       ARP_HLEN);
					ethaddr[i * ARP_HLEN] |= 0x02;
					ethaddr[i * ARP_HLEN] += (i << 2);
				}
			}

			need_write = true;
		}

		if (is_valid_ethaddr(ðaddr[i * ARP_HLEN])) {
			sprintf(buf, "%pM", ðaddr[i * ARP_HLEN]);
			if (i == 0)
				memcpy(mac, "ethaddr", sizeof("ethaddr"));
			else
				sprintf(mac, "eth%daddr", i);
			env_set(mac, buf);
		}
	}

	if (need_write) {
		ret = vendor_storage_write(LAN_MAC_ID,
					   ethaddr, sizeof(ethaddr));
		if (ret < 0)
			printf("%s: vendor_storage_write failed %d\n",
			       __func__, ret);
	}
#endif

	return 0;
}
  1. 定义MAX_ETHERNET为0x02,表示有两个ETH网卡。
  2. 从vendor storage区域LAN_MAC_ID处读取12字节的内容,接下来判断是否读取成功和依次判断前6字节和后6字节是否为合法的eth地址。
  3. 若读取失败或前6字节不是有效的eth地址,则随机生成一个mac地址。
  4. 若读取失败或后6字节不是有效的eth地址,则将前6字节的内容拷贝到后6字节区域,然后将后6字节的第0字节的内容与0x02想或,然后再加4,按照这个规则可以猜测第一次读取的LAN的内容FE6E784A75A6026E784A75A6的前6字节是由系统随机生成的,后6字节是按规则生成的。
  5. 若修改过ethaddr的内容,则将need_write赋值为true,在后面的执行中将ethaddr的内容重新写入vendor storage区域。
  6. 使用sprintf(buf, "%pM", ðaddr[i * ARP_HLEN]);语句将ethaddr[]中的内容格式化为冒号分割的MAC字符串存入buf,如8C:AE:49:61:00:02,把前6字节设置为ethaddr变量的内容,后6字节设置为eth1addr变量的内容。

3.自创的设置MAC地址的方法

RK3566虽然只有一个gmac,但是是gmac1,只写入6字节的MAC地址会被默认为gmac0,所以需要写入12字节的MAC,然后系统取后6字节作为gmac1的MAC地址,系统启动后通过ifconfig才能获取到正确的MAC地址。但是通过LAN无法写入12字节,会提示"获取LAN MAC失败!!!",如下所示:

RK3566设置以太网MAC地址_第5张图片

目前想到的解决方案是给Vendor storage区新增一个ID用来存储两个以太网的MAC地址,编号为18,因为从vendor.h文件中看到0~17已有定义:

#define RSV_ID				0
#define SN_ID				1
#define WIFI_MAC_ID			2
#define LAN_MAC_ID			3
#define BT_MAC_ID			4
#define HDCP_14_HDMI_ID			5
#define HDCP_14_DP_ID			6
#define HDCP_2X_ID			7
#define DRM_KEY_ID			8
#define PLAYREADY_CERT_ID		9
#define ATTENTION_KEY_ID		10
#define PLAYREADY_ROOT_KEY_0_ID		11
#define PLAYREADY_ROOT_KEY_1_ID		12
#define SENSOR_CALIBRATION_ID		13
#define IMEI_ID				15
#define LAN_RGMII_DL_ID			16
#define EINK_VCOM_ID			17

再修改下static int rockchip_set_ethaddr(void)函数,如下所示:

static int rockchip_set_ethaddr(void)
{
#ifdef CONFIG_ROCKCHIP_VENDOR_PARTITION
	char buf[ARP_HLEN_ASCII + 1], mac[16];
	u8 ethaddr[ARP_HLEN * MAX_ETHERNET] = {0};
	int ret, i;
	bool need_write = false, randomed = false;

//	ret = vendor_storage_read(LAN_MAC_ID, ethaddr, sizeof(ethaddr));
	ret = vendor_storage_read(18, ethaddr, sizeof(ethaddr));
	for (i = 0; i < MAX_ETHERNET; i++) {
		if (ret <= 0 || !is_valid_ethaddr(ðaddr[i * ARP_HLEN])) {
			if (!randomed) {
				net_random_ethaddr(ðaddr[i * ARP_HLEN]);
				randomed = true;
			} else {
				if (i > 0) {
					memcpy(ðaddr[i * ARP_HLEN],
					       ðaddr[(i - 1) * ARP_HLEN],
					       ARP_HLEN);
					ethaddr[i * ARP_HLEN] |= 0x02;
					ethaddr[i * ARP_HLEN] += (i << 2);
				}
			}

			need_write = true;
		}

		if (is_valid_ethaddr(ðaddr[i * ARP_HLEN])) {
			sprintf(buf, "%pM", ðaddr[i * ARP_HLEN]);
			if (i == 0)
				memcpy(mac, "ethaddr", sizeof("ethaddr"));
			else
				sprintf(mac, "eth%daddr", i);
			env_set(mac, buf);
		}
	}

	if (need_write) {
//		ret = vendor_storage_write(LAN_MAC_ID,
//					   ethaddr, sizeof(ethaddr));

		ret = vendor_storage_write(18,
					   ethaddr, sizeof(ethaddr));

		if (ret < 0)
			printf("%s: vendor_storage_write failed %d\n",
			       __func__, ret);
	}
#endif

	return 0;
}

修改完成之后,重新编译uboot,然后烧写到主板。

重启主板进入loader模式,使用RKDevInfoWriteTool工具向vendor storage ID为18的区域写入两个MAC地址,操作如下所示:

RK3566设置以太网MAC地址_第6张图片

 手动输入,ID为18,二进制,然后点保存回到主界面:

RK3566设置以太网MAC地址_第7张图片

 填写内容后再写入,前6字节可以填写任意内容,后6字节内容为MAC地址。

写入之后重启主板,正常启动之后,通过ifconfig命令查询到eth0的mac地址为:8C:AE:49:61:00:03

eth0      Link encap:Ethernet  HWaddr 8C:AE:49:61:00:03  
          UP BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
          Interrupt:35 

问题暂时解决,如有更好的方法,请不吝赐教!

4.正确的解决方法

之前使用的工具为RKDevInfoWriteTool_1.2.6,没有多MAC的选项,换为RKDevInfoWriteTool_Setup_V1.1.4工具后,LAN MAC设置界面可选择多LAN MAC,如下所示:

RK3566设置以太网MAC地址_第8张图片

虽然RK3566只有一个gmac,但是使用的gmac1,所以需要将MAC地址写入MAC1。

介绍手动写入的方法:

RK3566设置以太网MAC地址_第9张图片

单击读取可以获取两个MAC地址,第二个地址为gmac1的地址,也就是RK3566实际的eth0地址,将第二个地址改为需要写入的地址后单击写入。 

你可能感兴趣的:(linux系统及驱动开发,linux,eth,mac)