AM335X+AR8031网卡驱动(三)
AM335X自带了MAC层,MAC层和AR8031之间通过MDIO总线进行管理配置,AM335X的PHY采用CPSW方式,接下来是对其驱动的分析:
首先是网卡驱动probe函数static int __devinit cpsw_probe(struct platform_device *pdev),此函数可以对接入的网络设备进行及时响应,进行如下一系列操作
1.CPSW平台数据、资源、DMA初始化、赋值netdev_ops、ethtool_ops,
2.注册网络设备register_netdev
3.添加net_device_ops操作集cpsw_netdev_ops
在最新的内核中可以通过设备树来完成这一系列的工作
4.在操作集合中通过cpsw_ndo_open来打开设备,调用for_each_slave(priv, cpsw_slave_open, priv)来遍历所有连接,AM335X支持双网卡
5.cpsw_slave_open中调用phy_connect实现网卡连接,返回值即为phy_device的结构体,连接的实现主要是通过mdio总线实现bus_find_device_by_name,在总线上寻找设备
6.调用phy_connect_direct函数,phy_attach_direct函数
static int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
u32 flags, phy_interface_t interface)
{
struct device d = &phydev->dev;
int err;
/ Assume that if there is no driver, that it doesn’t
* exist, and we should use the genphy driver. /
if (NULL == d->driver) {
d->driver = &genphy_driver.driver;//通用驱动赋值
err = d->driver->probe(d);//phy_probe函数
if (err >= 0)
err = device_bind_driver(d);//绑定驱动到设备
if (err)
return err;
}
if (phydev->attached_dev) {
dev_err(&dev->dev, “PHY already attached\n”);
return -EBUSY;
}
phydev->attached_dev = dev;
dev->phydev = phydev;
phydev->dev_flags = flags;
phydev->interface = interface;
phydev->state = PHY_READY;//标记为PHY_READY
/ Do initial configuration here, now that
* we have certain key parameters
* (dev_flags and interface) */
err = phy_init_hw(phydev);
if (err)
phy_detach(phydev);
return err;
}
phy驱动的genphy_driver结构体:
static struct phy_driver genphy_driver = {
.phy_id = 0xffffffff,
.phy_id_mask = 0xffffffff,
.name = “Generic PHY”,
.config_init = genphy_config_init,
.features = 0,
.config_aneg = genphy_config_aneg, 自动协商,当自动协商使能时,配置advertising,并重新自动协商。如不是,则强制设置(写寄存器0)
.read_status = genphy_read_status,读取状态,是否连接上,当前速率、能力,等等,在phy状态机中,此函数经常被调用
.suspend = genphy_suspend,
.resume = genphy_resume,
.driver = {.owner= THIS_MODULE, },
};
完成一些初始化和配置工作
phy_probe函数
static int phy_probe(struct device *dev)
{
struct phy_device *phydev;
struct phy_driver *phydrv;
struct device_driver drv;
int err = 0;
phydev = to_phy_device(dev);//得到设备结构体
/ Make sure the driver is held.
* XXX – Is this correct? /
drv = get_driver(phydev->dev.driver);//赋值device_driver指针
phydrv = to_phy_driver(drv);//从drv得到phy_driver指针
phydev->drv = phydrv;
/ Disable the interrupt if the PHY doesn’t support it /
if (!(phydrv->flags & PHY_HAS_INTERRUPT))
phydev->irq = PHY_POLL;
mutex_lock(&phydev->lock);
/ Start out supporting everything. Eventually,
* a controller will attach, and may modify one
* or both of these values /
phydev->supported = phydrv->features;
phydev->advertising = phydrv->features;
/ Set the state to READY by default */
phydev->state = PHY_READY;
if (phydev->drv->probe)
err = phydev->drv->probe(phydev);
mutex_unlock(&phydev->lock);
return err;
}
7.传递cpsw_adjust_link函数
8.phy_start_machine 启动PHY状态机
9.开启phy_start_interrupts中断
10.phy_start(slave->phy)网卡状态变为PHY_UP
AM335X+AR8031网卡驱动(三)
最新推荐文章于 2021-05-12 13:46:21 发布