3.14.43 cpsw网卡驱动部分分析

arch/arm/boot/dts/am33xx.dtsi

/ {

ocp {

mac: ethernet@4a100000 {

compatible = "ti,cpsw"; //属性,与驱动函数的匹配字符串是一致的

ti,hwmods = "cpgmac0"; //可选属性:对硬件模块配置,为了跟驱动匹配

//指定时钟,定义在am33xx-clocks.dtsi文件中

clocks = <&cpsw_125mhz_gclk>, <&cpsw_cpts_rft_clk>;

clock-names = "fck", "cpts";

//cpma(common platformdma)的通道数

cpdma_channels = <8>;

//指定ale条目

ale_entries = <1024>;

bd_ram_size = <0x2000>;

//设置HW descriptor是否在内部bd ram 0 or 1

no_bd_ram = <0>;

//指定RX描述符个数

rx_descs = <64>;

//mac 控制器

mac_control = <0x20>;

//从站数量

slaves = <2>;

//默认是从站0

active_slave = <0>;

cpts_clock_mult = <0x80000000>;

cpts_clock_shift = <29>;

//cpsw寄存器映射地址

reg = <0x4a100000 0x800

0x4a101200 0x100>;

#address-cells = <1>;

#size-cells = <1>;

//父中断控制器

interrupt-parent = <&intc>;

/*

* c0_rx_thresh_pend

* c0_rx_pend

* c0_tx_pend

* c0_misc_pend

*/

//中断号

interrupts = <40 41 42 43>;

ranges;

 

davinci_mdio: mdio@4a101000 {

compatible = "ti,davinci_mdio";

#address-cells = <1>;

#size-cells = <0>;

ti,hwmods = "davinci_mdio";

bus_freq = <1000000>;

reg = <0x4a101000 0x100>;

};

//以太网控制器

cpsw_emac0: slave@4a100200 {

/* Filled in by U-Boot */

mac-address = [ 00 00 00 00 00 00 ];

};

 

cpsw_emac1: slave@4a100300 {

/* Filled in by U-Boot */

mac-address = [ 00 00 00 00 00 00 ];

};

//phy寄存器基地址和寄存器的值

phy_sel: cpsw-phy-sel@44e10650 {

compatible = "ti,am3352-cpsw-phy-sel";

reg= <0x44e10650 0x3a>; //见TRM第9章gmii_sel Register的内容

reg-names = "gmii-sel";

};

};

};

};

 

 

drivers/net/ethernet/ti/cpsw.c

static const struct of_device_id cpsw_of_mtable[] = {

{ .compatible = "ti,cpsw", },

{ /* sentinel */ },

};

MODULE_DEVICE_TABLE(of, cpsw_of_mtable);

 

static struct platform_driver cpsw_driver = {

.driver = {

.name = "cpsw",

.owner = THIS_MODULE,

.pm = &cpsw_pm_ops,

.of_match_table = cpsw_of_mtable,

},

.probe = cpsw_probe,

.remove = cpsw_remove,

};

当cpsw_of_mtable与设备树中的匹配,就执行probe函数。如果在设备树中找不到,就判断平台设备中是否存在"cpsw",存在就执行probe函数

static int cpsw_probe(struct platform_device *pdev)

{

//分配网络设备空间

ndev = alloc_etherdev(sizeof(struct cpsw_priv));

一些平台数据、资源、DMA初始化、赋值netdev_ops、ethtool_ops

//获取设备树中的信息

if (cpsw_probe_dt(&priv->data, pdev)) {

........

//注册net_device_ops结构体

ndev->netdev_ops = &cpsw_netdev_ops;

//注册网络设备

ret = register_netdev(ndev);

//注册第2个从设备

if (priv->data.dual_emac) {

ret = cpsw_probe_dual_emac(pdev, priv);

}

 

static const struct net_device_ops cpsw_netdev_ops = {

.ndo_open = cpsw_ndo_open,

.ndo_stop = cpsw_ndo_stop,

.ndo_start_xmit = cpsw_ndo_start_xmit,

.ndo_set_mac_address = cpsw_ndo_set_mac_address,

.ndo_do_ioctl = cpsw_ndo_ioctl,

.ndo_validate_addr = eth_validate_addr,

.ndo_change_mtu = eth_change_mtu,

.ndo_tx_timeout = cpsw_ndo_tx_timeout,

.ndo_set_rx_mode = cpsw_ndo_set_rx_mode,

#ifdef CONFIG_NET_POLL_CONTROLLER

.ndo_poll_controller = cpsw_ndo_poll_controller,

#endif

.ndo_vlan_rx_add_vid = cpsw_ndo_vlan_rx_add_vid,

.ndo_vlan_rx_kill_vid = cpsw_ndo_vlan_rx_kill_vid,

};

 

static int cpsw_ndo_open(struct net_device *ndev)

{

//初始化,执行ifconfig up会打印这个信息

dev_info(priv->dev, "initializing cpsw version %d.%d (%d)\n",

CPSW_MAJOR_VERSION(reg), CPSW_MINOR_VERSION(reg),

CPSW_RTL_VERSION(reg));

for_each_slave(priv, cpsw_slave_open, priv);

}

static void cpsw_slave_open(struct cpsw_slave *slave, struct cpsw_priv *priv)

{

slave->phy = phy_connect(priv->ndev, slave->data->phy_id,

&cpsw_adjust_link, slave->data->phy_if);

if (IS_ERR(slave->phy)) {

dev_err(priv->dev, "phy %s not found on slave %d\n",

slave->data->phy_id, slave->slave_num); //检测到网络从设备

slave->phy = NULL;

} else {

dev_info(priv->dev, "phy found : id is : 0x%x\n",

slave->phy->phy_id); //检测到phy_id

phy_start(slave->phy); //PHY_READY变为PHY_UP

 

/* Configure GMII_SEL register */

cpsw_phy_sel(&priv->pdev->dev, slave->phy->interface,

slave->slave_num);

}

}

struct phy_device *phy_connect(struct net_device *dev, const char *bus_id,

void (*handler)(struct net_device *),

phy_interface_t interface)

{

rc = phy_connect_direct(dev, phydev, handler, interface);

}

int phy_connect_direct(struct net_device *dev, struct phy_device *phydev,

void (*handler)(struct net_device *),

phy_interface_t interface)

{

rc = phy_attach_direct(dev, phydev, phydev->dev_flags, interface);

phy_prepare_link(phydev, handler);

//启动phy状态机

phy_start_machine(phydev);

if (phydev->irq > 0)

phy_start_interrupts(phydev);

return 0;

}

int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,

u32 flags, phy_interface_t interface)

{

if (NULL == d->driver) {

if (phydev->is_c45)

//通用驱动赋值,支持1G、10G

d->driver = &genphy_driver[GENPHY_DRV_10G].driver;

else

d->driver = &genphy_driver[GENPHY_DRV_1G].driver;

//调用到genphy_driver的检测函数

err = d->driver->probe(d);

if (err >= 0)

//绑定驱动到设备

err = device_bind_driver(d);

if (err)

return err;

}

//指向dev

phydev->attached_dev = dev;

dev->phydev = phydev;

phydev->dev_flags = flags;

phydev->interface = interface;

//将phy的状态标记为PHY_READY

phydev->state = PHY_READY;

//硬件级的初始化,最后会调用config_init

err = phy_init_hw(phydev);

if (err)

phy_detach(phydev);

else

phy_resume(phydev);

}

 

drivers/net/phy/phy_device.c

static int __init phy_init(void)

rc = phy_drivers_register(genphy_driver,ARRAY_SIZE(genphy_driver));

for (i = 0; i < n; i++) {

ret = phy_driver_register(new_driver + i);

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;

 

static int phy_probe(struct device *dev)

{

//从device结构体得到phy_device指针

struct phy_device *phydev = to_phy_device(dev);

//赋值device_driver指针

struct device_driver *drv = phydev->dev.driver;

//从drv得到phy_driver指针

struct phy_driver *phydrv = to_phy_driver(drv);

phydev->supported = phydrv->features;

phydev->advertising = phydrv->features;

phydev->state = PHY_READY;

if (phydev->drv->probe)

err = phydev->drv->probe(phydev);

}

 

 

上电过程中调用的主要函数,默认是自动协商的

--> tixxx_cpsw_init

--> phy_init

--> mdio_bus_init

--> phy_drivers_register

-->phy_driver_register

--> davinci_mdio_probe

--> cpsw_probe

--> cpsw_ndo_open

--> cpsw_slave_open

--> phy_probe

--> PHY_READY->PHY_UP

--> phy_state_machine状态机函数

--> phy_start_aneg

--> genphy_config_aneg

--> genphy_config_advert

--> genphy_restart_aneg

--> PHY_AN

--> PHY_AN->HY_RUNNING

--> _cpsw_adjust_link

--> phy_print_status

--> "Link is Up - xxxx"

--> PHY_RUNNING->PHY_CHANGELINK->PHY_RUNNING(循环)

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值