RK3566设置以太网MAC地址

1.遇到的问题

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

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

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

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

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

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

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

 

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_BOOTboot_from_udisk();
#endif
#ifdef CONFIG_DM_CHARGE_DISPLAYcharge_display();
#endif
#ifdef CONFIG_DRM_ROCKCHIProckchip_show_logo();
#endif
#ifdef CONFIG_ROCKCHIP_EINK_DISPLAYrockchip_eink_show_uboot_logo();
#endifenv_fixup();soc_clk_dump();cmdline_handle();
#ifdef CONFIG_AMPamp_cpus_on();
#endifreturn rk_board_late_init();
}

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

#define MAX_ETHERNET	0x2static int rockchip_set_ethaddr(void)
{
#ifdef CONFIG_ROCKCHIP_VENDOR_PARTITIONchar 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"));elsesprintf(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);}
#endifreturn 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失败!!!",如下所示:

目前想到的解决方案是给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_PARTITIONchar 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"));elsesprintf(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);}
#endifreturn 0;
}

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

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

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

 填写内容后再写入,前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:1RX packets:0 errors:0 dropped:0 overruns:0 frame:0TX packets:0 errors:0 dropped:0 overruns:0 carrier:0collisions:0 txqueuelen:1000 RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)Interrupt:35 

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


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部