PHY设备驱动综合分析

PHY设备驱动分析

声明:

使用其他作者原创资料较多就不一一列举,冒犯之处望海涵。我原创也不少咯。

MAC和PHY可能是集成在CPU中可能独立,下图介绍典型的MAC集成,PHY独立。两者搭配实现网卡功能。

在这里插入图片描述


struct phy_device {
	struct phy_driver *drv;	//PHY设备驱动
	struct mii_bus *bus;	//对应的MII总线
	struct device dev;	//设备文件
	u32 phy_id;	//PHY ID
	enum phy_state state;	//PHY状态
	u32 dev_flags;
	phy_interface_t interface;	//PHY接口
	int addr;	//PHY 总线地址(0~31)
	int speed;	//速度
	int duplex;	//双工模式
	int pause;	//停止
	int asym_pause;	//
	int link;	
	u32 interrupts;	//中断使能标志
	u32 supported;	
	u32 advertising;
	int autoneg;
	int link_timeout;	//026
	int irq;	//中断号
	void *priv;	//私有数据
	struct work_struct phy_queue;	//PHY工作队列
	struct delayed_work state_queue;	//PHY延时工作队列
	atomic_t irq_disable;	
	struct mutex lock;
	struct net_device *attached_dev;	//网络设备
	void (*adjust_link)(struct net_device *dev);
	void (*adjust_state)(struct net_device *dev);
};
struct phy_driver {
	u32 phy_id;		//PHY ID
	char *name;		//PHY名
	unsigned int phy_id_mask;
	u32 features;	//特性
	u32 flags;	//标记
	int (*config_init)(struct phy_device *phydev);	//配置初始化
	int (*probe)(struct phy_device *phydev);	//探测到 probe方法
	int (*suspend)(struct phy_device *phydev);	//唤醒
	int (*resume)(struct phy_device *phydev);	//挂起
	int (*config_aneg)(struct phy_device *phydev);	//支援(Auto-negotiation)配置
	int (*read_status)(struct phy_device *phydev);	//读支援(Auto-negotiation)状态
	int (*ack_interrupt)(struct phy_device *phydev);	//清中断
	int (*config_intr)(struct phy_device *phydev);	//使能/禁用 中断
	int (*did_interrupt)(struct phy_device *phydev);	//判断是否由中断
	void (*remove)(struct phy_device *phydev);	//移除
	int  (*hwtstamp)(struct phy_device *phydev, struct ifreq *ifr);	//时间戳处理
	bool (*rxtstamp)(struct phy_device *dev, struct sk_buff *skb, int type);	//接收时间戳
	void (*txtstamp)(struct phy_device *dev, struct sk_buff *skb, int type);	//发送时间戳
	struct device_driver driver;	//设备驱动文件
};
enum phy_state {
	PHY_DOWN = 0, // PHY芯片和驱动没准备好,一般情况下少发生
	PHY_STARTING, // PHY芯片OK了,但驱动还没有准备好
	PHY_READY,    // 准备好了,在probe中赋值,接下来会切到PHY_UP
	PHY_PENDING,
	PHY_UP,       // phy启动了,可以工作了,接下来会到PHY_AN
	PHY_AN,       // 自动协商
	PHY_RUNNING,  // 正在运行中,在网络连接(插上网线)时会到这个状态
	PHY_NOLINK,   // 断网了
	PHY_FORCING,  // 强制,当自动协商不使能时,就会进行此状态(实际上会读PHY寄存器进行设置速率、双工,等)
	PHY_CHANGELINK, // 变化,这个状态很重要,当连接时,会换到PHY_RUNNING,当断网时,会切到PHY_NOLINK
	PHY_HALTED,
	PHY_RESUMING
};

Mdio设备注册到总线

文件路径:drivers\net\ethernet\ti\davinci_mdio.c
device_initcall(davinci_mdio_init);
–> davinci_mdio_init
–>platform_driver_register(&davinci_mdio_driver);
davinci_mdio_probe
–> mdiobus_regist

Phy设备初始化:

Linux内核通过mdio总线访问、控制PHY , phy_device的注册不依靠设备树(根据上面驱动的名字在设备树中搜不到),该设备的注册在MDIO驱动中调用mdiobus_register中会注册phy_device
文件路径:drivers\net\phy\mdio_bus.c
–> mdiobus_register /* register the mii bus */
–> device_register
–> mdiobus_scan /这个过程就是根据phy id通过mdio的mdiobus_read去读phy芯片的寄存器来检测改id下的phy设备是否存在,如果存在就把该设备使用phy_device_register注册/
–> get_phy_device
–> get_phy_id // 读寄存器
–> phy_device_create // 创建phy设备,创建phy设备时会设置phy的接口,例如PHY_INTERFACE_MODE_GMII,以及从总线上扫描到的设备的信息赋值给phy设备
–> INIT_DELAYED_WORK(&dev->state_queue, phy_state_machine); // !!!初始化状态机函数
–> phy_device_register

在phy_device_create 时会使用mdio_bus_type这个结构体,里面有个匹配函数具体如下


/**
 * mdio_bus_match - determine if given PHY driver supports the given PHY device
 * @dev: target PHY device
 * @drv: given PHY driver
 *
 * Description: Given a PHY device, and a PHY driver, return 1 if
 *   the driver supports the device.  Otherwise, return 0.
 */
static int mdio_bus_match(struct device *dev, struct device_driver *drv)
{
	struct phy_device *phydev = to_phy_device(dev);
	struct phy_driver *phydrv = to_phy_driver(drv);
	return ((phydrv->phy_id & phydrv->phy_id_mask) ==
		(phydev->phy_id & phydrv->phy_id_mask));
}

Phy驱动注册:

nt phy_driver_register(struct phy_driver *new_driver)
{
	int retval;
	new_driver->driver.name = new_driver->name;
	new_driver->driver.bus = &a
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值