linux网络设备—PHY

一.结构体

1.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);

};

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

};

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

1.注册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);	//获取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

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;

}

2.注册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);

3.匹配

PHY设备和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);

匹配函数mdio_bus_match

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;

}

三.初始化过程

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设备驱动

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, },

};

初始化配置方法

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.状态分类

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函数中,开启了状态机

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命令的过程

进入分支状态机分支

case PHY_UP:	//开启(ifconfig eth0 up)

			needs_aneg = 1;

			phydev->link_timeout = PHY_AN_TIMEOUT;

			break;

相应处理

if (needs_aneg)	//需要自动协商机制(例如ifconfig eth0 up就会调用)

		err = phy_start_aneg(phydev);	//开始自动配置

调用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_config_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接口

void phy_print_status(struct phy_device *phydev);	//PHY打印状态


 

 

你可能感兴趣的:(linux)