理解系统内核linux phy驱动

PHY设备驱动是基于device、driver、bus的连接方式,驱动涉及如下几个重要部分: 总线 - sturct mii_bus (mii stand for media independent interface) 设备 - struct phy_device 驱动 - struct phy_driver。PHY驱动函数驱动功能:

函数名称    功能描述
soft_reset    执行 phy 的软件复位
config_init    在 phy 复位后将 phy 配置为一个既定的状态
probe    创建 phy->priv 并执行类似驱动绑定的过程
suspend/resume    电源管理挂起与恢复功能
config_aneq    修改速率双工模式自协商等配置
aneq_done    驱动自协商的结果
read_status    获取当前的速率双工与自协商配置状态
ack_interrupt    清楚挂起的中断
did_interrupt    检查是否 phy 触发了一个中断信号
config_intr    开启、关闭中断
remove    当驱动被移除时调用的接口
ts_info    请求查询 HW 时间戳状态
hwtstap    设置 phy 的 HW时间戳配置
rxtstamp    在 phy 这一层为 skb 请求一个接收时间戳
txtsamp    在 phy 这一层为 skd 请求一个发送时间戳
set_wol    使能 Wake-on-Lan
get_wol    获取 Wake-on-Lan 状态
read_mmd_indirect    读取 phy MMD 间接寄存器
write_mmd_indirect    写入 phy MMD 间接寄存器

理解系统内核linux phy驱动_第1张图片

一,PHY驱动中重要的有两个结构体

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);
};

PHY驱动

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;	//设备驱动文件
};

二,设备和驱动的注册函数

每个驱动都有独立的操作函数来对 phy 进行操作,也就是说网卡会直接调用类似 phy_ops 中的虚函数来使用 phy 的功能。而对于这种 phy 驱动而言,它与网卡驱动是独立的,将网卡驱动与 phy 驱动关联起来步骤:

PHY驱动的注册:在phy_init函数中不仅注册了mdio_bus总线,还注册了一个通用的PHY驱动作为缺省的内核PHY驱动,但是如果PHY芯片的内部寄存器和802.3定义的并不一样或者需要特殊的功能配置以实现更强的功能,这就需要专有的驱动。

注册PHY设备

int phy_device_register(struct phy_device *phydev)
{
	int err;
	if (phydev->bus->phy_map[phydev->addr])	//判断PHY是否已经给注册了
		return -EINVAL;
	phydev->bus->phy_map[phydev->addr] = phydev;	//添加PHY到总线的phy_map里
	phy_scan_fixups(phydev);	//执行匹配的fixups
	err = device_register(&phydev->dev);	//注册设备
	if (err) {
		pr_err("phy %d failed to register\n", phydev->addr);
		goto out;
	}
	return 0;
 out:
	phydev->bus->phy_map[phydev->addr] = NULL;
	return err;
}
EXPORT_SYMBOL(phy_device_register);

PHY设备一般是动态注册的,在注册之前一般会调用get_phy_device函数

struct phy_device * get_phy_device(struct mii_bus *bus, int addr)
{
	struct phy_device *dev = NULL;
	u32 phy_id;
	int r;
	r = get_phy_id(bus, addr, &phy_id);	//1 获取PHY ID
	if (r)
		return ERR_PTR(r);
	if ((phy_id & 0x1fffffff) == 0x1fffffff)
		return NULL;
	if ((phy_id & 0x1fffffff) == 0x0000ffff)//add by cyj, support marvel phy
		return NULL;
	dev = phy_device_create(bus, addr, phy_id);	//2 创建PHY设备
	return dev;
}
EXPORT_SYMBOL(get_phy_device);

获取PHY ID

int get_phy_id(struct mii_bus *bus, int addr, u32 *phy_id)
{
	int phy_reg;
	//调用PHY的总线也就是mii总线的读方法获取PHY ID
	phy_reg = bus->read(bus, addr, MII_PHYSID1);	//获取PHYS ID1命令
	if (phy_reg < 0)
		return -EIO;
	*phy_id = (phy_reg & 0xffff) << 16;
	phy_reg = bus->read(bus, addr, MII_PHYSID2);	//获取PHYS ID1命令
	if (phy_reg < 0)
		return -EIO;
	*phy_id |= (phy_reg & 0xffff);
	return 0;
}
EXPORT_SYMBOL(get_phy_id);

创建PHY设备

static struct phy_device* phy_device_create(struct mii_bus *bus,int addr, int phy_id)
{
	struct phy_device *dev;
	dev = kzalloc(sizeof(*dev), GFP_KERNEL);	//分配phy设备内存
	if (NULL == dev)
		return (struct phy_device*) PTR_ERR((void*)-ENOMEM);
	dev->dev.release = phy_device_release;
	dev->speed = 0;	//速度
	dev->duplex = -1;	//双工模式
	dev->pause = dev->asym_pause = 0;
	dev->link = 1;	
	dev->interface = PHY_INTERFACE_MODE_GMII;	//接口模式GMII
	dev->autoneg = AUTONEG_ENABLE;	//自动使能
	dev->addr = addr; //地址
	dev->phy_id = phy_id; //PHY ID
	dev->bus = bus;	//mii总线
	dev->dev.parent = bus->parent;	//父设备
	dev->dev.bus = &mdio_bus_type;	//总线类型
	dev->irq = bus->irq != NULL ? bus->irq[addr] : PHY_POLL;	//中断/轮询
	dev_set_name(&dev->dev, PHY_ID_FMT, bus->id, addr);	//PHY 设备文件名
	dev->state = PHY_DOWN;	//状态DOWN
	mutex_init(&dev->lock);
	INIT_DELAYED_WORK(&dev->state_queue, phy_state_machine);    //初始化PHY状态机
	request_module(MDIO_MODULE_PREFIX MDIO_ID_FMT, MDIO_ID_ARGS(phy_id));
	return dev;
}

注册PHY驱动

int phy_driver_register(struct phy_driver *new_driver)
{
	int retval;
	new_driver->driver.name = new_driver->name;	//驱动名
	new_driver->driver.bus = &mdio_bus_type;	//总线类型
	new_driver->driver.probe = phy_probe;	//探测函数
	new_driver->driver.remove = phy_remove;	//移除函数
	retval = driver_register(&new_driver->driver);	//注册设备驱动
	if (retval) {
		printk(KERN_ERR "%s: Error %d in registering driver\n",new_driver->name, retval);
		return retval;
	}
	pr_debug("%s: Registered new driver\n", new_driver->name);
	return 0;
}
EXPORT_SYMBOL(phy_driver_register);

通过MDIO总线匹配

phy设备和驱动的总线类型都是mdio_bus_type

struct bus_type mdio_bus_type = {
	.name		= "mdio_bus",
	.match		= mdio_bus_match,	//匹配方法
	.pm		= MDIO_BUS_PM_OPS,
};
EXPORT_SYMBOL(mdio_bus_type);
 
static int mdio_bus_match(struct device *dev, struct device_driver *drv)
{
	struct phy_device *phydev = to_phy_device(dev);	//获取PHY设备
	struct phy_driver *phydrv = to_phy_driver(drv);	//获取PHY驱动
	return ((phydrv->phy_id & phydrv->phy_id_mask) ==(phydev->phy_id & phydrv->phy_id_mask));	//比较phy_id
}

匹配成功就会调用phy驱动的probe方法,也即是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);	//获取PHY设备
	drv = get_driver(phydev->dev.driver);
	phydrv = to_phy_driver(drv);	//获取PHY驱动
	phydev->drv = phydrv;	//捆绑一下
	if (!(phydrv->flags & PHY_HAS_INTERRUPT))	//设置中断方式
		phydev->irq = PHY_POLL;
	mutex_lock(&phydev->lock);
	phydev->supported = phydrv->features;	//设置PHY设备特性
	phydev->advertising = phydrv->features;	//设置PHY设备特性
	phydev->state = PHY_READY;	//状态设置为"准备好"
	if (phydev->drv->probe)	//如果驱动有probe方法
		err = phydev->drv->probe(phydev);	//则调用
	mutex_unlock(&phydev->lock);
	return err;
}

三,初始化流程

主函数主要初始化mdio总线、注册通用的phy设备驱动

static int __init phy_init(void)
{
	int rc;
	rc = mdio_bus_init();	//初始化mdio总线
	if (rc)
		return rc;
	rc = phy_driver_register(&genphy_driver);	//注册通用的PHY设备驱动
	if (rc)
		mdio_bus_exit();
	return rc;
}
 
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, //配置自协商(Auto-negotiation)
	.read_status = genphy_read_status, //读状态
	.suspend	= genphy_suspend,
	.resume	= genphy_resume,
	.driver	= {.owner= THIS_MODULE, },
};

genphy_driver驱动中有初始化配置方法,配置速度、半双工/全双工、自协商模式等。

static int genphy_config_init(struct phy_device *phydev)
{
	int val;
	u32 features;
	//默认支持特性
	features = (SUPPORTED_TP | SUPPORTED_MII| SUPPORTED_AUI | SUPPORTED_FIBRE |SUPPORTED_BNC);
	val = phy_read(phydev, MII_BMSR);	//读基础状态
	if (val < 0)
		return val;
	if (val & BMSR_ANEGCAPABLE)	//支持(auto-negotiation)
		features |= SUPPORTED_Autoneg;
	if (val & BMSR_100FULL)	//100兆全双工
		features |= SUPPORTED_100baseT_Full;
	if (val & BMSR_100HALF)	//100兆半双工
		features |= SUPPORTED_100baseT_Half;
	if (val & BMSR_10FULL)	//10兆全双工
		features |= SUPPORTED_10baseT_Full;
	if (val & BMSR_10HALF)	//10兆半双工
		features |= SUPPORTED_10baseT_Half;
	if (val & BMSR_ESTATEN) {
		val = phy_read(phydev, MII_ESTATUS);	//读扩展状态
		if (val < 0)
			return val;
		if (val & ESTATUS_1000_TFULL)	//1000兆全双工
			features |= SUPPORTED_1000baseT_Full;
		if (val & ESTATUS_1000_THALF)	//1000兆半双工
			features |= SUPPORTED_1000baseT_Half;
	}
	phydev->supported = features;	//PHY特性
	phydev->advertising = features;
	return 0;
}

 *phy_start_aneg_priv-启动此phy设备的自动协商
*@phydev:phy_device结构
*@sync:表示是否等待工作队列取消
描述:对设置进行Sanitize(如果我们没有自动协商它们),然后调用驱动程序的config_aeg函数。如果PHYCONTROL层正在运行,我们会更改状态以反映自动协商或强制的开始

static int phy_start_aneg_priv(struct phy_device *phydev, bool sync)
{
	bool trigger = 0;
	int err;

	if (!phydev->drv)
		return -EIO;

	mutex_lock(&phydev->lock);
      printk("111111111111\n");
	if (AUTONEG_DISABLE == phydev->autoneg)
		phy_sanitize_settings(phydev);
    printk("~~phydev->autoneg~~~~~~~~~~\n",phydev->autoneg);
	/* Invalidate LP advertising flags */
	phydev->lp_advertising = 0;
    printk("222222222\n");
	
	err = phydev->drv->config_aneg(phydev);
	printk("err=%d\n",err );
	if (err < 0)
		goto out_unlock;

     printk("333333333\n");
	if (phydev->state != PHY_HALTED) {
		if (AUTONEG_ENABLE == phydev->autoneg) {
			phydev->state = PHY_AN;
			phydev->link_timeout = PHY_AN_TIMEOUT;
		} else {
			phydev->state = PHY_FORCING;
			phydev->link_timeout = PHY_FORCE_TIMEOUT;
		}
	}

	/* Re-schedule a PHY state machine to check PHY status because
	 * negotiation may already be done and aneg interrupt may not be
	 * generated.
	 */
	if (phy_interrupt_is_valid(phydev) && (phydev->state == PHY_AN)) {
		err = phy_aneg_done(phydev);
		if (err > 0) {
			trigger = true;
			err = 0;
		}
	}

out_unlock:
	mutex_unlock(&phydev->lock);

	if (trigger)
		phy_trigger_machine(phydev, sync);

	return err;
}

四,状态类型

enum phy_state {
	PHY_DOWN=0,
	PHY_STARTING,	//开始
	PHY_READY,	//准备好
	PHY_PENDING,	//挂起
	PHY_UP,		//开启
	PHY_AN,		//判断连接状态中 negotiating
	PHY_RUNNING,	//运行
	PHY_NOLINK,	//开启 未连接
	PHY_FORCING,	//设置中
	PHY_CHANGELINK,	//连接状态改变
	PHY_HALTED,	//停止
	PHY_RESUMING	//唤醒
};

状态机phy_state_machine

在phy_device_create函数中,开启了状态机

void phy_state_machine(struct work_struct *work)
{
	struct delayed_work *dwork = to_delayed_work(work);
	struct phy_device *phydev = container_of(dwork, struct phy_device, state_queue);
	int needs_aneg = 0;
	int err = 0;
	mutex_lock(&phydev->lock);
	if (phydev->adjust_state)
		phydev->adjust_state(phydev->attached_dev);
	switch(phydev->state) {
		case PHY_DOWN:		//关闭((ifconfig eth0 down)
		case PHY_STARTING:	//开始
		case PHY_READY:		//准备好
		case PHY_PENDING:	//挂起
			break;
		case PHY_UP:	//开启(ifconfig eth0 up)
			needs_aneg = 1;
			phydev->link_timeout = PHY_AN_TIMEOUT;
			break;
		case PHY_AN:	//判断连接状态中 negotiating
			err = phy_read_status(phydev);
			if (err < 0)
				break;
			if (!phydev->link) {
				phydev->state = PHY_NOLINK;
				netif_carrier_off(phydev->attached_dev);
				phydev->adjust_link(phydev->attached_dev);
				break;
			}
			err = phy_aneg_done(phydev);
			if (err < 0)
				break;
			if (err > 0) {
				phydev->state = PHY_RUNNING;
				netif_carrier_on(phydev->attached_dev);
				phydev->adjust_link(phydev->attached_dev);
 
			} 
			else if (0 == phydev->link_timeout--) {
				int idx;
				needs_aneg = 1;
				if (phydev->drv->flags & PHY_HAS_MAGICANEG)
					break;
				idx = phy_find_valid(0, phydev->supported);
				phydev->speed = settings[idx].speed;
				phydev->duplex = settings[idx].duplex;
				phydev->autoneg = AUTONEG_DISABLE;
				pr_info("Trying %d/%s\n", phydev->speed,DUPLEX_FULL ==phydev->duplex ?"FULL" : "HALF");
			}
			break;
		case PHY_NOLINK:	//开启 未连接
			err = phy_read_status(phydev);
			if (err)
				break;
			if (phydev->link) {
				phydev->state = PHY_RUNNING;
				netif_carrier_on(phydev->attached_dev);
				phydev->adjust_link(phydev->attached_dev);
			}
			break;
		case PHY_FORCING:	//设置中
			err = genphy_update_link(phydev);
			if (err)
				break;
			if (phydev->link) {
				phydev->state = PHY_RUNNING;
				netif_carrier_on(phydev->attached_dev);
			} 
			else {
				if (0 == phydev->link_timeout--) {
					phy_force_reduction(phydev);
					needs_aneg = 1;
				}
			}
			phydev->adjust_link(phydev->attached_dev);
			break;
		case PHY_RUNNING:	//运行
			if (PHY_POLL == phydev->irq)
				phydev->state = PHY_CHANGELINK;
			break;
		case PHY_CHANGELINK:	//连接状态改变
			err = phy_read_status(phydev);
			if (err)
				break;
			if (phydev->link) {
				phydev->state = PHY_RUNNING;
				netif_carrier_on(phydev->attached_dev);
			} 
			else {
				phydev->state = PHY_NOLINK;
				netif_carrier_off(phydev->attached_dev);
			}
			phydev->adjust_link(phydev->attached_dev);
			if (PHY_POLL != phydev->irq)
				err = phy_config_interrupt(phydev,PHY_INTERRUPT_ENABLED);
			break;
		case PHY_HALTED:	//停止
			if (phydev->link) {
				phydev->link = 0;
				netif_carrier_off(phydev->attached_dev);
				phydev->adjust_link(phydev->attached_dev);
			}
			break;
		case PHY_RESUMING:	//唤醒
			err = phy_clear_interrupt(phydev);
			if (err)
				break;
			err = phy_config_interrupt(phydev,PHY_INTERRUPT_ENABLED);
			if (err)
				break;
			if (AUTONEG_ENABLE == phydev->autoneg) {
				err = phy_aneg_done(phydev);
				if (err < 0)
					break;
				if (err > 0) {
					err = phy_read_status(phydev);
					if (err)
						break;
					if (phydev->link) {
						phydev->state = PHY_RUNNING;
						netif_carrier_on(phydev->attached_dev);
					} 
					else
						phydev->state = PHY_NOLINK;
					phydev->adjust_link(phydev->attached_dev);
				} 
				else {
					phydev->state = PHY_AN;
					phydev->link_timeout = PHY_AN_TIMEOUT;
				}
			}
			else {
				err = phy_read_status(phydev);
				if (err)
					break;
				if (phydev->link) {
					phydev->state = PHY_RUNNING;
					netif_carrier_on(phydev->attached_dev);
				} 
				else
					phydev->state = PHY_NOLINK;
				phydev->adjust_link(phydev->attached_dev);
			}
			break;
	}
	mutex_unlock(&phydev->lock);
	if (needs_aneg)	//需要自动配置(例如ifconfig eth0 up就会调用)
		err = phy_start_aneg(phydev);	//开始自动配置
	if (err < 0)
		phy_error(phydev);
	schedule_delayed_work(&phydev->state_queue, PHY_STATE_TIME * HZ);
}

理解系统内核linux phy驱动_第2张图片

调用phy_start_aneg自动配置函数

int phy_start_aneg(struct phy_device *phydev)
{
	int err;
	mutex_lock(&phydev->lock);
	if (AUTONEG_DISABLE == phydev->autoneg)
		phy_sanitize_settings(phydev);
	err = phydev->drv->config_aneg(phydev);	//调用驱动的config_aneg方法,默认是genphy_config_aneg
	if (err < 0)
		goto out_unlock;
	if (phydev->state != PHY_HALTED) {	//调整修改PHY设备状态
		if (AUTONEG_ENABLE == phydev->autoneg) {
			phydev->state = PHY_AN;
			phydev->link_timeout = PHY_AN_TIMEOUT;
		} 
		else {
			phydev->state = PHY_FORCING;
			phydev->link_timeout = PHY_FORCE_TIMEOUT;
		}
	}
out_unlock:
	mutex_unlock(&phydev->lock);
	return err;
}
EXPORT_SYMBOL(phy_start_aneg);

 调用默认的自动协商方法genphy_config_aneg

int genphy_config_aneg(struct phy_device *phydev)
{
	int result;
	if (AUTONEG_ENABLE != phydev->autoneg)
		return genphy_setup_forced(phydev);
	result = genphy_config_advert(phydev);
	if (result < 0) /* error */
		return result;
	if (result == 0) {
		int ctl = phy_read(phydev, MII_BMCR);	//获取状态
		if (ctl < 0)
			return ctl;
		if (!(ctl & BMCR_ANENABLE) || (ctl & BMCR_ISOLATE))
			result = 1; /* do restart aneg */
	}
	if (result > 0)
		result = genphy_restart_aneg(phydev);	//重新开启自动协商机制
	return result;
}
EXPORT_SYMBOL(genphy_config_aneg);

接着调用genphy_restart_aneg,重新开启自动协商机制

int genphy_restart_aneg(struct phy_device *phydev)
{
	int ctl;
	ctl = phy_read(phydev, MII_BMCR);	//获取基本状态
	if (ctl < 0)
		return ctl;
	ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);	//使能自动协商机制使能 重启
	/* Don't isolate the PHY if we're negotiating */
	ctl &= ~(BMCR_ISOLATE);
	ctl = phy_write(phydev, MII_BMCR, ctl);	//写命令
	return ctl;
}
EXPORT_SYMBOL(genphy_restart_aneg);

五,其它网口API函数调用

static inline int phy_read(struct phy_device *phydev, u32 regnum);    //PHY读
static inline int phy_write(struct phy_device *phydev, u32 regnum, u16 val);    //PHY写
void phy_start(struct phy_device *phydev);    //PHY开始
void phy_stop(struct phy_device *phydev);    //PHY停止
int phy_init_hw(struct phy_device *phydev);  //PHY初始化硬件
struct phy_device * phy_attach(struct net_device *dev,const char *bus_id, u32 flags, phy_interface_t interface);    //PHY接上
void phy_detach(struct phy_device *phydev);  //PHY分离
struct phy_device *phy_find_first(struct mii_bus *bus); //查找mii_bus总线上第一个PHY
int phy_connect_direct(struct net_device *dev, struct phy_device *phydev,void (*handler)(struct net_device *), u32 flags,phy_interface_t interface);    //PHY直接连接网络设备
struct phy_device * phy_connect(struct net_device *dev, const char *bus_id,void (*handler)(struct net_device *), u32 flags,phy_interface_t interface);    //PHY连接网络设备
void phy_disconnect(struct phy_device *phydev);    //PHY断开与网络设备的连接
int phy_start_interrupts(struct phy_device *phydev);//PHY开始中断
int phy_stop_interrupts(struct phy_device *phydev);    //PHY停止中断
int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd); //ethtool工具sset功能
int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd); //ethtool工具gset功能
int phy_mii_ioctl(struct phy_device *phydev,struct ifreq *ifr, int cmd);  //通用PHY/mii接口

你可能感兴趣的:(硬件接口_接口驱动开发,服务器)