首先,向大家推荐一些文章。
http://blog.chinaunix.net/uid-24148050-id-131084.html
http://hi.baidu.com/lds102/item/eae3262c77b897de0f37f966
http://blog.csdn.net/zyboy2000/article/details/4525726
这上面说了MII、RMII、SMII、GMII等一系列的接口。
网口一般是这样
MacàPhyà网络变压器àRJ45口
但是只是从电路上不一定看得这么清楚,应为有些是集成的,例如DM9000就是mac+phy,还有很多网络变压器和RJ45口在一起。对于我们写驱动,要知道的是Mac和Pht之间的接口,其他的还是比较透明的。而它们的接口就是上面提的一些。
MII是(Medium Independent Interface)的意思,是指不用考虑媒体是铜轴、光纤、电缆等,因为这些媒体处理的相关工作都有PHY或者叫做MAC的芯片完成。 MII支持10兆和100兆的操作,不支持1000兆。
我们看一下MII的接口图(分别相对于mac和 phy)
前16位是数据传输,MDC和MDIO是SMI总线的东西,用于管理phy。这篇文章主要就是看linux内核对SMI总线的使用。
上面有篇文章是这么说的:
Mac对Phy的管理是使用SMI(SerialManagement Interface)总线通过读写PHY的寄存器来完成的。PHY里面的部分寄存器是IEEE定义的,这样PHY把自己的目前的状态反映到寄存器里面,MAC通过SMI总线不断的读取PHY的状态寄存器以得知目前PHY的状态,例如连接速度,双工的能力等。
上面让我在意的是PHY里面的部分寄存器是IEEE定义的。那我们看看内核里的定义吧.linux-3.0.8
include/linux/mii.h
/* Generic MII registers. */ #define MII_BMCR 0x00 /* Basic mode control register */ #define MII_BMSR 0x01 /* Basic mode status register */ #define MII_PHYSID1 0x02 /* PHYS ID 1 */ #define MII_PHYSID2 0x03 /* PHYS ID 2 */ #define MII_ADVERTISE 0x04 /* Advertisement control reg */ #define MII_LPA 0x05 /* Link partner ability reg */ #define MII_EXPANSION 0x06 /* Expansion register */ #define MII_CTRL1000 0x09 /* 1000BASE-T control */ #define MII_STAT1000 0x0a /* 1000BASE-T status */ #define MII_ESTATUS 0x0f /* Extended Status */ #define MII_DCOUNTER 0x12 /* Disconnect counter */ #define MII_FCSCOUNTER 0x13 /* False carrier counter */ #define MII_NWAYTEST 0x14 /* N-way auto-neg test reg */ #define MII_RERRCOUNTER 0x15 /* Receive error counter */ #define MII_SREVISION 0x16 /* Silicon revision */ #define MII_RESV1 0x17 /* Reserved... */ #define MII_LBRERROR 0x18 /* Lpback, rx, bypass error */ #define MII_PHYADDR 0x19 /* PHY address */ #define MII_RESV2 0x1a /* Reserved... */ #define MII_TPISTATUS 0x1b /* TPI status for 10mbps */ #define MII_NCONFIG 0x1c /* Network interface config */
我们在看看DM9000的定义:
不是所有都支持。
例如我们要启动自动协商机制,只要把control寄存器的的第12位置1就可以了。
现在摆在我们的面前有两个问题
1. DM9000如何操作去写或读。
2. linux提供了什么样的接口。
先看第一个问题:下面是DM9000的几个寄存器
EPCR: phy控制寄存器
EPAR: phy地址寄存器
EPDRL:phy数据寄存器低8位
EPDRH:phy数据寄存器高8位
读:
1. 先写入寄存器的地址(就是上面的MII Register Description上面的。你可以在mii.h中看到定义)到EPAR寄存器。
2. 把EPCR的ERPRR位(读命令)和EPOS(选择PHY)置位。
3. 读EEPROM用的是等待EPCR的ERRE变为0,为1表示正在进行。读PHY用的是延时1m秒。看一下uboot,都是用延时等待。
4. 清除EPCR的ERPRR位。
5. 读EPDRL和EPDRH。
写:
1. 先写入寄存器的地址到EPAR寄存器。
2. 写数据到ERDRL和EPDRH。
3. 把EPCR的ERPRW(写命令)和EPOS(选择PHY)置位。
4. 延时1m秒,等待完成。
5. 清除EPCR的ERPRR位。
下面我们看linux内核提供的接口。
struct mii_if_info { int phy_id; int advertising; int phy_id_mask; int reg_num_mask; unsigned int full_duplex : 1; /* is full duplex? */ unsigned int force_media : 1; /* is autoneg. disabled? */ unsigned int supports_gmii : 1; /* are GMII registers supported? */ struct net_device *dev; int (*mdio_read) (struct net_device *dev, int phy_id, int location); void (*mdio_write) (struct net_device *dev, int phy_id, int location, int val); };
看一下dm9000网卡的初始化:
db->mii.phy_id_mask = 0x1f;//这个给驱动用,dm9000没用,是考虑smi总线上有多个phy时。 db->mii.reg_num_mask = 0x1f;//寄存器mask db->mii.force_media = 0; db->mii.full_duplex = 0; db->mii.dev = ndev; db->mii.mdio_read = dm9000_phy_read; db->mii.mdio_write = dm9000_phy_write;
dm9000不支持gmii,所以没对它初始化
如果你提供了这些,对phy的操作就可以同drivers/net/mii.c中的函数去操作,不用再去看那些mii的寄存器了(当然有些非标准的要自己写)。我看看mii.c提供的
EXPORT_SYMBOL(mii_link_ok); EXPORT_SYMBOL(mii_nway_restart); EXPORT_SYMBOL(mii_ethtool_gset); EXPORT_SYMBOL(mii_ethtool_sset); EXPORT_SYMBOL(mii_check_link); EXPORT_SYMBOL(mii_check_media); EXPORT_SYMBOL(mii_check_gmii_support); EXPORT_SYMBOL(generic_mii_ioctl); 我们上次说的ethtool很多要依赖它们。 mii_link_ok:读链接状态 mii_nway_restart: 重启接口的自动协商机制 mii_ethtool_gset:获取接口设置。查看结构体struct ethtool_cmd有什么设置,上篇文章说过。 mii_ethtool_sset:设置接口设置。 mii_check_link:检测MII链接状态。这个会调用netif_carrier_on/off上报内核。 mii_check_media:检查双工改变。Full or Half mii_check_gmii_support:是否支持gmii,这个是1000M的支持 generic_mii_ioctl:ioctl接口。这个可以放在驱动的ioctl里面,用户可以通过socket的ioctl调用。
下次我们说一个千兆的网卡,对phy的控制。