linux网络设备—PHY

        linux网络设备—PHY       

分类:            linux设备驱动 2486人阅读 评论(3) 收藏 举报

一.结构体

1.PHY设备

  1. struct phy_device { 
  2.     struct phy_driver *drv; //PHY设备驱动 
  3.     struct mii_bus *bus;    //对应的MII总线 
  4.     struct device dev;  //设备文件 
  5.     u32 phy_id; //PHY ID 
  6.     enum phy_state state;   //PHY状态 
  7.     u32 dev_flags; 
  8.     phy_interface_t interface;  //PHY接口 
  9.     int addr;   //PHY 总线地址(0~31) 
  10.     int speed;  //速度 
  11.     int duplex; //双工模式 
  12.     int pause;  //停止 
  13.     int asym_pause; // 
  14.     int link;    
  15.     u32 interrupts; //中断使能标志 
  16.     u32 supported;   
  17.     u32 advertising; 
  18.     int autoneg; 
  19.     int link_timeout;   //026 
  20.     int irq;    //中断号 
  21.     void *priv; //私有数据 
  22.     struct work_struct phy_queue;   //PHY工作队列 
  23.     struct delayed_work state_queue;    //PHY延时工作队列 
  24.     atomic_t irq_disable;    
  25.     struct mutex lock; 
  26.     struct net_device *attached_dev;    //网络设备 
  27.     void (*adjust_link)(struct net_device *dev); 
  28.     void (*adjust_state)(struct net_device *dev); 
  29. }; 
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);
};

2.PHY驱动

  1. struct phy_driver { 
  2.     u32 phy_id;     //PHY ID 
  3.     char *name;     //PHY名 
  4.     unsigned int phy_id_mask; 
  5.     u32 features;   //特性 
  6.     u32 flags;  //标记 
  7.     int (*config_init)(struct phy_device *phydev);  //配置初始化 
  8.     int (*probe)(struct phy_device *phydev);    //探测到 probe方法 
  9.     int (*suspend)(struct phy_device *phydev);  //唤醒 
  10.     int (*resume)(struct phy_device *phydev);   //挂起 
  11.     int (*config_aneg)(struct phy_device *phydev);  //支援(Auto-negotiation)配置 
  12.     int (*read_status)(struct phy_device *phydev);  //读支援(Auto-negotiation)状态 
  13.     int (*ack_interrupt)(struct phy_device *phydev);    //清中断 
  14.     int (*config_intr)(struct phy_device *phydev);  //使能/禁用 中断 
  15.     int (*did_interrupt)(struct phy_device *phydev);    //判断是否由中断 
  16.     void (*remove)(struct phy_device *phydev);  //移除 
  17.     int  (*hwtstamp)(struct phy_device *phydev, struct ifreq *ifr); //时间戳处理 
  18.     bool (*rxtstamp)(struct phy_device *dev, struct sk_buff *skb, int type);    //接收时间戳 
  19.     void (*txtstamp)(struct phy_device *dev, struct sk_buff *skb, int type);    //发送时间戳 
  20.     struct device_driver driver;    //设备驱动文件 
  21. }; 
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;	//设备驱动文件
};

二.设备与驱动的注册函数

1.注册PHY设备

  1. int phy_device_register(struct phy_device *phydev) 
  2.     int err; 
  3.     if (phydev->bus->phy_map[phydev->addr])    //判断PHY是否已经给注册了 
  4.         return -EINVAL; 
  5.     phydev->bus->phy_map[phydev->addr] = phydev;   //添加PHY到总线的phy_map里 
  6.     phy_scan_fixups(phydev);    //执行匹配的fixups 
  7.     err = device_register(&phydev->dev); //注册设备 
  8.     if (err) { 
  9.         pr_err("phy %d failed to register\n", phydev->addr); 
  10.         goto out; 
  11.     } 
  12.     return 0; 
  13. out: 
  14.     phydev->bus->phy_map[phydev->addr] = NULL; 
  15.     return err; 
  16. EXPORT_SYMBOL(phy_device_register); 
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函数

  1. struct phy_device * get_phy_device(struct mii_bus *bus, int addr) 
  2.     struct phy_device *dev = NULL; 
  3.     u32 phy_id; 
  4.     int r; 
  5.     r = get_phy_id(bus, addr, &phy_id); //获取PHY ID 
  6.     if (r) 
  7.         return ERR_PTR(r); 
  8.     if ((phy_id & 0x1fffffff) == 0x1fffffff) 
  9.         return NULL; 
  10.     dev = phy_device_create(bus, addr, phy_id); //创建PHY设备 
  11.     return dev; 
  12. EXPORT_SYMBOL(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);	//获取PHY ID
	if (r)
		return ERR_PTR(r);
	if ((phy_id & 0x1fffffff) == 0x1fffffff)
		return NULL;
	dev = phy_device_create(bus, addr, phy_id);	//创建PHY设备
	return dev;
}
EXPORT_SYMBOL(get_phy_device);

获取PHY ID

  1. int get_phy_id(struct mii_bus *bus, int addr, u32 *phy_id) 
  2.     int phy_reg; 
  3.     //调用PHY的总线也就是mii总线的读方法获取PHY ID 
  4.     phy_reg = bus->read(bus, addr, MII_PHYSID1); //获取PHYS ID1命令 
  5.     if (phy_reg < 0) 
  6.         return -EIO; 
  7.     *phy_id = (phy_reg & 0xffff) << 16; 
  8.     phy_reg = bus->read(bus, addr, MII_PHYSID2); //获取PHYS ID1命令 
  9.     if (phy_reg < 0) 
  10.         return -EIO; 
  11.     *phy_id |= (phy_reg & 0xffff); 
  12.     return 0; 
  13. EXPORT_SYMBOL(get_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设备

  1. static struct phy_device* phy_device_create(struct mii_bus *bus,int addr, int phy_id) 
  2.     struct phy_device *dev; 
  3.     dev = kzalloc(sizeof(*dev), GFP_KERNEL);    //分配phy设备内存 
  4.     if (NULL == dev) 
  5.         return (struct phy_device*) PTR_ERR((void*)-ENOMEM); 
  6.     dev->dev.release = phy_device_release; 
  7.     dev->speed = 0;  //速度 
  8.     dev->duplex = -1;    //双工模式 
  9.     dev->pause = dev->asym_pause = 0; 
  10.     dev->link = 1;    
  11.     dev->interface = PHY_INTERFACE_MODE_GMII;    //接口模式GMII 
  12.     dev->autoneg = AUTONEG_ENABLE;   //自动使能 
  13.     dev->addr = addr; //地址 
  14.     dev->phy_id = phy_id; //PHY ID 
  15.     dev->bus = bus;  //mii总线 
  16.     dev->dev.parent = bus->parent;    //父设备 
  17.     dev->dev.bus = &mdio_bus_type;   //总线类型 
  18.     dev->irq = bus->irq != NULL ? bus->irq[addr] : PHY_POLL;   //中断/轮询 
  19.     dev_set_name(&dev->dev, PHY_ID_FMT, bus->id, addr);   //PHY 设备文件名 
  20.     dev->state = PHY_DOWN;   //状态DOWN 
  21.     mutex_init(&dev->lock); 
  22.     INIT_DELAYED_WORK(&dev->state_queue, phy_state_machine);    //初始化PHY状态机 
  23.     request_module(MDIO_MODULE_PREFIX MDIO_ID_FMT, MDIO_ID_ARGS(phy_id)); 
  24.     return dev; 
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;
}

2.注册PHY驱动

  1. int phy_driver_register(struct phy_driver *new_driver) 
  2.     int retval; 
  3.     new_driver->driver.name = new_driver->name;   //驱动名 
  4.     new_driver->driver.bus = &mdio_bus_type; //总线类型 
  5.     new_driver->driver.probe = phy_probe;    //探测函数 
  6.     new_driver->driver.remove = phy_remove;  //移除函数 
  7.     retval = driver_register(&new_driver->driver);   //注册设备驱动 
  8.     if (retval) { 
  9.         printk(KERN_ERR "%s: Error %d in registering driver\n",new_driver->name, retval); 
  10.         return retval; 
  11.     } 
  12.     pr_debug("%s: Registered new driver\n", new_driver->name); 
  13.     return 0; 
  14. EXPORT_SYMBOL(phy_driver_register); 
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);

3.匹配

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

  1. struct bus_type mdio_bus_type = { 
  2.     .name       = "mdio_bus"
  3.     .match      = mdio_bus_match,   //匹配方法 
  4.     .pm     = MDIO_BUS_PM_OPS, 
  5. }; 
  6. EXPORT_SYMBOL(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);

匹配函数mdio_bus_match

  1. static int mdio_bus_match(struct device *dev, struct device_driver *drv) 
  2.     struct phy_device *phydev = to_phy_device(dev); //获取PHY设备 
  3.     struct phy_driver *phydrv = to_phy_driver(drv); //获取PHY驱动 
  4.     return ((phydrv->phy_id & phydrv->phy_id_mask) ==(phydev->phy_id & phydrv->phy_id_mask));   //比较phy_id 
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

  1. static int phy_probe(struct device *dev) 
  2.     struct phy_device *phydev; 
  3.     struct phy_driver *phydrv; 
  4.     struct device_driver *drv; 
  5.     int err = 0; 
  6.     phydev = to_phy_device(dev);    //获取PHY设备 
  7.     drv = get_driver(phydev->dev.driver); 
  8.     phydrv = to_phy_driver(drv);    //获取PHY驱动 
  9.     phydev->drv = phydrv;    //捆绑一下 
  10.     if (!(phydrv->flags & PHY_HAS_INTERRUPT))    //设置中断方式 
  11.         phydev->irq = PHY_POLL; 
  12.     mutex_lock(&phydev->lock); 
  13.     phydev->supported = phydrv->features; //设置PHY设备特性 
  14.     phydev->advertising = phydrv->features;   //设置PHY设备特性 
  15.     phydev->state = PHY_READY;   //状态设置为"准备好" 
  16.     if (phydev->drv->probe)   //如果驱动有probe方法 
  17.         err = phydev->drv->probe(phydev); //则调用 
  18.     mutex_unlock(&phydev->lock); 
  19.     return err; 
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;
}

三.初始化过程

  1. static int __init phy_init(void
  2.     int rc; 
  3.     rc = mdio_bus_init();   //初始化mdio总线 
  4.     if (rc) 
  5.         return rc; 
  6.     rc = phy_driver_register(&genphy_driver);   //注册通用的PHY设备驱动 
  7.     if (rc) 
  8.         mdio_bus_exit(); 
  9.     return rc; 
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;
}

初始化过程主要是初始化mdio总线

接着注册通用的PHY设备驱动

  1. static struct phy_driver genphy_driver = { 
  2.     .phy_id = 0xffffffff, 
  3.     .phy_id_mask = 0xffffffff, 
  4.     .name   = "Generic PHY"
  5.     .config_init = genphy_config_init, //初始化函数 
  6.     .features   = 0, 
  7.     .config_aneg = genphy_config_aneg, //配置 支援(Auto-negotiation) 
  8.     .read_status = genphy_read_status, //读状态 
  9.     .suspend    = genphy_suspend, 
  10.     .resume = genphy_resume, 
  11.     .driver = {.owner= THIS_MODULE, }, 
  12. }; 
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, },
};

初始化配置方法

  1. static int genphy_config_init(struct phy_device *phydev) 
  2.     int val; 
  3.     u32 features; 
  4.     //默认支持特性 
  5.     features = (SUPPORTED_TP | SUPPORTED_MII| SUPPORTED_AUI | SUPPORTED_FIBRE |SUPPORTED_BNC); 
  6.     val = phy_read(phydev, MII_BMSR);   //读基础状态 
  7.     if (val < 0) 
  8.         return val; 
  9.     if (val & BMSR_ANEGCAPABLE) //支持(auto-negotiation) 
  10.         features |= SUPPORTED_Autoneg; 
  11.     if (val & BMSR_100FULL) //100兆全双工 
  12.         features |= SUPPORTED_100baseT_Full; 
  13.     if (val & BMSR_100HALF) //100兆半双工 
  14.         features |= SUPPORTED_100baseT_Half; 
  15.     if (val & BMSR_10FULL)  //10兆全双工 
  16.         features |= SUPPORTED_10baseT_Full; 
  17.     if (val & BMSR_10HALF)  //10兆半双工 
  18.         features |= SUPPORTED_10baseT_Half; 
  19.     if (val & BMSR_ESTATEN) { 
  20.         val = phy_read(phydev, MII_ESTATUS);    //读扩展状态 
  21.         if (val < 0) 
  22.             return val; 
  23.         if (val & ESTATUS_1000_TFULL)   //1000兆全双工 
  24.             features |= SUPPORTED_1000baseT_Full; 
  25.         if (val & ESTATUS_1000_THALF)   //1000兆半双工 
  26.             features |= SUPPORTED_1000baseT_Half; 
  27.     } 
  28.     phydev->supported = features;    //PHY特性 
  29.     phydev->advertising = features; 
  30.     return 0; 
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状态机

1.状态分类

  1. enum phy_state { 
  2.     PHY_DOWN=0, 
  3.     PHY_STARTING,   //开始 
  4.     PHY_READY,  //准备好 
  5.     PHY_PENDING,    //挂起 
  6.     PHY_UP,     //开启 
  7.     PHY_AN,     //判断连接状态中 negotiating 
  8.     PHY_RUNNING,    //运行 
  9.     PHY_NOLINK, //开启 未连接 
  10.     PHY_FORCING,    //设置中 
  11.     PHY_CHANGELINK, //连接状态改变 
  12.     PHY_HALTED, //停止 
  13.     PHY_RESUMING    //唤醒 
  14. }; 
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	//唤醒
};

2.状态机phy_state_machine

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

  1. void phy_state_machine(struct work_struct *work) 
  2.     struct delayed_work *dwork = to_delayed_work(work); 
  3.     struct phy_device *phydev = container_of(dwork, struct phy_device, state_queue); 
  4.     int needs_aneg = 0; 
  5.     int err = 0; 
  6.     mutex_lock(&phydev->lock); 
  7.     if (phydev->adjust_state) 
  8.         phydev->adjust_state(phydev->attached_dev); 
  9.     switch(phydev->state) { 
  10.         case PHY_DOWN:      //关闭((ifconfig eth0 down) 
  11.         case PHY_STARTING:  //开始 
  12.         case PHY_READY:     //准备好 
  13.         case PHY_PENDING:   //挂起 
  14.             break
  15.         case PHY_UP:    //开启(ifconfig eth0 up) 
  16.             needs_aneg = 1; 
  17.             phydev->link_timeout = PHY_AN_TIMEOUT; 
  18.             break
  19.         case PHY_AN:    //判断连接状态中 negotiating 
  20.             err = phy_read_status(phydev); 
  21.             if (err < 0) 
  22.                 break
  23.             if (!phydev->link) { 
  24.                 phydev->state = PHY_NOLINK; 
  25.                 netif_carrier_off(phydev->attached_dev); 
  26.                 phydev->adjust_link(phydev->attached_dev); 
  27.                 break
  28.             } 
  29.             err = phy_aneg_done(phydev); 
  30.             if (err < 0) 
  31.                 break
  32.             if (err > 0) { 
  33.                 phydev->state = PHY_RUNNING; 
  34.                 netif_carrier_on(phydev->attached_dev); 
  35.                 phydev->adjust_link(phydev->attached_dev); 
  36.  
  37.             }  
  38.             else if (0 == phydev->link_timeout--) { 
  39.                 int idx; 
  40.                 needs_aneg = 1; 
  41.                 if (phydev->drv->flags & PHY_HAS_MAGICANEG) 
  42.                     break
  43.                 idx = phy_find_valid(0, phydev->supported); 
  44.                 phydev->speed = settings[idx].speed; 
  45.                 phydev->duplex = settings[idx].duplex; 
  46.                 phydev->autoneg = AUTONEG_DISABLE; 
  47.                 pr_info("Trying %d/%s\n", phydev->speed,DUPLEX_FULL ==phydev->duplex ?"FULL" : "HALF"); 
  48.             } 
  49.             break
  50.         case PHY_NOLINK:    //开启 未连接 
  51.             err = phy_read_status(phydev); 
  52.             if (err) 
  53.                 break
  54.             if (phydev->link) { 
  55.                 phydev->state = PHY_RUNNING; 
  56.                 netif_carrier_on(phydev->attached_dev); 
  57.                 phydev->adjust_link(phydev->attached_dev); 
  58.             } 
  59.             break
  60.         case PHY_FORCING:   //设置中 
  61.             err = genphy_update_link(phydev); 
  62.             if (err) 
  63.                 break
  64.             if (phydev->link) { 
  65.                 phydev->state = PHY_RUNNING; 
  66.                 netif_carrier_on(phydev->attached_dev); 
  67.             }  
  68.             else
  69.                 if (0 == phydev->link_timeout--) { 
  70.                     phy_force_reduction(phydev); 
  71.                     needs_aneg = 1; 
  72.                 } 
  73.             } 
  74.             phydev->adjust_link(phydev->attached_dev); 
  75.             break
  76.         case PHY_RUNNING:   //运行 
  77.             if (PHY_POLL == phydev->irq) 
  78.                 phydev->state = PHY_CHANGELINK; 
  79.             break
  80.         case PHY_CHANGELINK:    //连接状态改变 
  81.             err = phy_read_status(phydev); 
  82.             if (err) 
  83.                 break
  84.             if (phydev->link) { 
  85.                 phydev->state = PHY_RUNNING; 
  86.                 netif_carrier_on(phydev->attached_dev); 
  87.             }  
  88.             else
  89.                 phydev->state = PHY_NOLINK; 
  90.                 netif_carrier_off(phydev->attached_dev); 
  91.             } 
  92.             phydev->adjust_link(phydev->attached_dev); 
  93.             if (PHY_POLL != phydev->irq) 
  94.                 err = phy_config_interrupt(phydev,PHY_INTERRUPT_ENABLED); 
  95.             break
  96.         case PHY_HALTED:    //停止 
  97.             if (phydev->link) { 
  98.                 phydev->link = 0; 
  99.                 netif_carrier_off(phydev->attached_dev); 
  100.                 phydev->adjust_link(phydev->attached_dev); 
  101.             } 
  102.             break
  103.         case PHY_RESUMING:  //唤醒 
  104.             err = phy_clear_interrupt(phydev); 
  105.             if (err) 
  106.                 break
  107.             err = phy_config_interrupt(phydev,PHY_INTERRUPT_ENABLED); 
  108.             if (err) 
  109.                 break
  110.             if (AUTONEG_ENABLE == phydev->autoneg) { 
  111.                 err = phy_aneg_done(phydev); 
  112.                 if (err < 0) 
  113.                     break
  114.                 if (err > 0) { 
  115.                     err = phy_read_status(phydev); 
  116.                     if (err) 
  117.                         break
  118.                     if (phydev->link) { 
  119.                         phydev->state = PHY_RUNNING; 
  120.                         netif_carrier_on(phydev->attached_dev); 
  121.                     }  
  122.                     else 
  123.                         phydev->state = PHY_NOLINK; 
  124.                     phydev->adjust_link(phydev->attached_dev); 
  125.                 }  
  126.                 else
  127.                     phydev->state = PHY_AN; 
  128.                     phydev->link_timeout = PHY_AN_TIMEOUT; 
  129.                 } 
  130.             } 
  131.             else
  132.                 err = phy_read_status(phydev); 
  133.                 if (err) 
  134.                     break
  135.                 if (phydev->link) { 
  136.                     phydev->state = PHY_RUNNING; 
  137.                     netif_carrier_on(phydev->attached_dev); 
  138.                 }  
  139.                 else 
  140.                     phydev->state = PHY_NOLINK; 
  141.                 phydev->adjust_link(phydev->attached_dev); 
  142.             } 
  143.             break
  144.     } 
  145.     mutex_unlock(&phydev->lock); 
  146.     if (needs_aneg) //需要自动配置(例如ifconfig eth0 up就会调用) 
  147.         err = phy_start_aneg(phydev);   //开始自动配置 
  148.     if (err < 0) 
  149.         phy_error(phydev); 
  150.     schedule_delayed_work(&phydev->state_queue, PHY_STATE_TIME * HZ); 
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);
}

3.运行ifconfig eth0 up命令的过程

进入分支状态机分支

  1. case PHY_UP:    //开启(ifconfig eth0 up) 
  2.             needs_aneg = 1; 
  3.             phydev->link_timeout = PHY_AN_TIMEOUT; 
  4.             break
case PHY_UP:	//开启(ifconfig eth0 up)
			needs_aneg = 1;
			phydev->link_timeout = PHY_AN_TIMEOUT;
			break;

相应处理

  1. if (needs_aneg) //需要自动协商机制(例如ifconfig eth0 up就会调用) 
  2.         err = phy_start_aneg(phydev);   //开始自动配置 
if (needs_aneg)	//需要自动协商机制(例如ifconfig eth0 up就会调用)
		err = phy_start_aneg(phydev);	//开始自动配置

调用phy_start_aneg函数

  1. int phy_start_aneg(struct phy_device *phydev) 
  2.     int err; 
  3.     mutex_lock(&phydev->lock); 
  4.     if (AUTONEG_DISABLE == phydev->autoneg) 
  5.         phy_sanitize_settings(phydev); 
  6.     err = phydev->drv->config_aneg(phydev);   //调用驱动的config_aneg方法,默认是genphy_config_aneg 
  7.     if (err < 0) 
  8.         goto out_unlock; 
  9.     if (phydev->state != PHY_HALTED) {   //调整修改PHY设备状态 
  10.         if (AUTONEG_ENABLE == phydev->autoneg) { 
  11.             phydev->state = PHY_AN; 
  12.             phydev->link_timeout = PHY_AN_TIMEOUT; 
  13.         }  
  14.         else
  15.             phydev->state = PHY_FORCING; 
  16.             phydev->link_timeout = PHY_FORCE_TIMEOUT; 
  17.         } 
  18.     } 
  19. out_unlock: 
  20.     mutex_unlock(&phydev->lock); 
  21.     return err; 
  22. EXPORT_SYMBOL(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

  1. int genphy_config_aneg(struct phy_device *phydev) 
  2.     int result; 
  3.     if (AUTONEG_ENABLE != phydev->autoneg) 
  4.         return genphy_setup_forced(phydev); 
  5.     result = genphy_config_advert(phydev); 
  6.     if (result < 0) /* error */ 
  7.         return result; 
  8.     if (result == 0) { 
  9.         int ctl = phy_read(phydev, MII_BMCR);   //获取状态 
  10.         if (ctl < 0) 
  11.             return ctl; 
  12.         if (!(ctl & BMCR_ANENABLE) || (ctl & BMCR_ISOLATE)) 
  13.             result = 1; /* do restart aneg */ 
  14.     } 
  15.     if (result > 0) 
  16.         result = genphy_restart_aneg(phydev);   //重新开启自动协商机制 
  17.     return result; 
  18. EXPORT_SYMBOL(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_config_aneg

  1. int genphy_restart_aneg(struct phy_device *phydev) 
  2.     int ctl; 
  3.     ctl = phy_read(phydev, MII_BMCR);   //获取基本状态 
  4.     if (ctl < 0) 
  5.         return ctl; 
  6.     ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);    //使能自动协商机制及支援重启 
  7.     /* Don't isolate the PHY if we're negotiating */ 
  8.     ctl &= ~(BMCR_ISOLATE); 
  9.     ctl = phy_write(phydev, MII_BMCR, ctl); //写命令 
  10.     return ctl; 
  11. EXPORT_SYMBOL(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

  1. static inline int phy_read(struct phy_device *phydev, u32 regnum);  //PHY读 
  2. static inline int phy_write(struct phy_device *phydev, u32 regnum, u16 val);    //PHY写 
  3. void phy_start(struct phy_device *phydev);  //PHY开始 
  4. void phy_stop(struct phy_device *phydev);   //PHY停止 
  5. int phy_init_hw(struct phy_device *phydev); //PHY初始化硬件 
  6. struct phy_device * phy_attach(struct net_device *dev,const char *bus_id, u32 flags, phy_interface_t interface);    //PHY接上 
  7. void phy_detach(struct phy_device *phydev); //PHY分离 
  8. struct phy_device *phy_find_first(struct mii_bus *bus); //查找mii_bus总线上第一个PHY 
  9. int phy_connect_direct(struct net_device *dev, struct phy_device *phydev,void (*handler)(struct net_device *), u32 flags,phy_interface_t interface);    //PHY直接连接网络设备 
  10. 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连接网络设备 
  11. void phy_disconnect(struct phy_device *phydev); //PHY断开与网络设备的连接 
  12. int phy_start_interrupts(struct phy_device *phydev);//PHY开始中断 
  13. int phy_stop_interrupts(struct phy_device *phydev); //PHY停止中断 
  14. int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd);   //ethtool工具sset功能 
  15. int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd);   //ethtool工具gset功能 
  16. int phy_mii_ioctl(struct phy_device *phydev,struct ifreq *ifr, int cmd);    //通用PHY/mii接口 
  17. void phy_print_status(struct phy_device *phydev);   //PHY打印状态 
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接口
void phy_print_status(struct phy_device *phydev);	//PHY打印状态

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值