在同专栏的mdio访问phy的三种方式篇,我们着重介绍了通过ioctrl的方式将mdio总线与网卡绑定进行访问,但是实时上数据接口和管理接口可以独立去控制,很不幸,作者现在必须把mdio与网卡解除绑定并独立操控,因此接下来将详细介绍通过devmem的访问方式。
dev/mem
dev/mem是linux下的一个设备节点,看名字能够猜测到大概和内存有关,如果你的系统下没有该节点,可以通过内核的如下配置使能该功能。
dev/mem本身的功能是用来映射物理寄存器到应用层的,通常我们会在内核驱动当中将物理寄存器映射后进行操作,但不会将寄存器暴漏至应用层,但是在系统调试时,我们又希望通过什么接口去监测寄存器状态,或是有不得已的需求需要将某些寄存器交给应用去控制,这种情况下就可以通过/dev/mem节点,将物理地址mmap到dev/mem中,然后去读写访问/dev/mem。
应用程序参考如下,以下例程将寄存器0x1e110004映射到应用层,并打印出该寄存器的值。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#define MAP_SIZE 0x1
#define base 0x1e110004
int main(int argc, char **argv)
{
int fd = open("/dev/mem",O_RDWR|O_NDELAY);
if (fd < 0)
{
printf("open /dev/mem error!\n");
return -1;
}
void *map_base = mmap(NULL,MAP_SIZE,PROT_READ|PROT_WRITE,MAP_SHARED,fd,base);
if (map_base == MAP_FAILED)
return -1;
printf("%x \n",*(volatile unsigned int*)(map_base));
close(fd);
munmap(map_base,MAP_SIZE);
return 0;
}
devmem
有的时候,我们只是想看某一寄存器的值,不会去写,仅作为调试使用。那此时可以使用命令devmem,该命令同样依赖于/dev/mem节点,并且该命令在busybox中包含,命令如下:
$devmem
BusyBox v1.34.0 (2023-01-16 15:32:42 CST) multi-call binary.
Usage: devmem ADDRESS [WIDTH [VALUE]]
Read/write from physical address
ADDRESS Address to act upon
WIDTH Width (8/16/...)
VALUE Data to be written
以32位读地址0x1e110004:
devmem 0x1e110004 32
向0x1e110004以32位写入数据0x80590000
devmem 0x1e110004 32 0x80590000
MT7621 MDIO 控制
前面介绍了/dev/mem的使用,但是最终要落到实际使用中,MT7621的mdio总线在驱动中是与mac相绑定的,如果mac作为fixed-link使用时,phy就不能进行访问,因此我们要将mdio寄存器单独拎出来去控制,但很不幸,MT7621并没有在手册中开放MDIO寄存器的定义,甚至我们连寄存器在哪都不知道,不过通过分析7621驱动源码,我们找到了mdio寄存器的物理地址0x1e110004。并且通过驱动我们反推出了7621 mdio寄存器的定义以及访问方式:
我们来使用devmem命令进行访问测试,我的phy_addr是0x5,那么我们要访问寄存器0则需要写入0x80590000:
依次访问寄存器0,1,2,3,4,5,6:
接下来就可以通过应用程序来封装读写接口啦!