一. 简介
前面一篇文章说明了有线网络的网络硬件方案。常用到的一种方案是:内部集成了MAC网络外设的SOC芯片(处理器),外接一个 PHY网络芯片。
注意:Linux内核中的 PHY子系统,就是针对 PHY网络芯片的驱动实现而提供的。
本文开始就来简单了解一下 PHY 子系统。PHY 子系统就是用于 PHY 设备相关内容的,分为 PHY 设备和 PHY 驱动,和 platform 总线一样,PHY 子系统也是一个设备、总线和驱动模型。
本文具体来学习一下PHY子系统中的 PHY设备相关的驱动代码。
二. Linux 内核中PHY子系统(网络):PHY设备
1. phy_device 结构体
首先看一下
PHY
设备,
Linux
内核使用
phy_device
结构体来表示
PHY
设备,结构体定义在
include/linux/phy.h
,结构体内容如下:
struct phy_device {
/* Information about the PHY type */
/* And management functions */
struct phy_driver *drv;
struct mii_bus *bus;
struct device dev;
u32 phy_id;
struct phy_c45_device_ids c45_ids;
bool is_c45;
bool is_internal;
bool has_fixups;
bool suspended;
enum phy_state state;
u32 dev_flags;
phy_interface_t interface;
/* Bus address of the PHY (0-31) */
int addr;
/*
* forced speed & duplex (no autoneg)
* partner speed & duplex & pause (autoneg)
*/
int speed;
int duplex;
int pause;
int asym_pause;
/* The most recently read link state */
int link;
/* Enabled Interrupts */
u32 interrupts;
/* Union of PHY and Attached devices' supported modes */
/* See mii.h for more info */
u32 supported;
u32 advertising;
u32 lp_advertising;
int autoneg;
int link_timeout;
/*
* Interrupt number for this PHY
* -1 means no interrupt
*/
int irq;
/* private data pointer */
/* For use by PHYs to maintain extra state */
void *priv;
/* Interrupt and Polling infrastructure */
struct work_struct phy_queue;
struct delayed_work state_queue;
atomic_t irq_disable;
struct mutex lock;
struct net_device *attached_dev;
void (*adjust_link)(struct net_device *dev);
};
2. 向 Linux 内核注册 PHY设备
一个
PHY
设备对应一个
phy_device
实例,然后需要向
Linux
内核注册这个实例。使用phy_device_register
函数完成
PHY
设备的注册,函数原型如下:
int phy_device_register(struct phy_device *phy)
函数参数和返回值含义如下:
phy
:
需要注册的
PHY
设备。
返回值:
0
成功,负值 失败。
PHY 设备的注册过程一般是先调用 get_phy_device 函数获取 PHY 设备,此函数内容如下:
struct phy_device *get_phy_device(struct mii_bus *bus, int addr, bool is_c45)
{
struct phy_c45_device_ids c45_ids = {0};
u32 phy_id = 0;
int r;
r = get_phy_id(bus, addr, &phy_id, is_c45, &c45_ids);
if (r)
return ERR_PTR(r);
/* If the phy_id is mostly Fs, there is no device there */
if ((phy_id & 0x1fffffff) == 0x1fffffff)
return NULL;
return phy_device_create(bus, addr, phy_id, is_c45, &c45_ids);
}
第
7
行,调用
get_phy_id
函数获取
PHY ID
,也就是读取
PHY
芯片的那两个
ID
寄存器,
得到
PHY
芯片
ID
信息。
第
15
行,调用
phy_device_create
函数创建
phy_device
,此函数先申请
phy_device
内存,然后初始化
phy_device
的各个结构体成员,最终返回创建好的
phy_device
。
phy_device_register
函
数注册的就是这个创建好的
phy_device
。