概述
ethtool
dummy.c
添加一个dummy的网络设备
关键函数及结构体
module_init
linux内核的模块机制,向linux内核提供本模块的初始化函数
rtnl_link_ops(dummy_link_ops)
为rtnl机制(???)提供setup和validate方法,在module_init函数中注册
net_device_ops (dummy_netdev_ops)
net_device的方法,在rtnl_link_ops的setup函数中注册
初始化流程
module_init(dummy_init_module)
__rtnl_link_register(&dummy_link_ops);
dev_dummy = alloc_netdev(0, "dummy%d", NET_NAME_UNKNOWN, dummy_setup);
dev_dummy->rtnl_link_ops= &dummy_link_ops;
register_netdevice(dev_dummy);
staticstruct rtnl_link_ops dummy_link_ops__read_mostly = {
.kind = DRV_NAME,
.setup = dummy_setup,
ether_setup(dev);
dev->netdev_ops= &dummy_netdev_ops;
dev->ethtool_ops= &dummy_ethtool_ops;
.validate = dummy_validate,
};
staticconst struct net_device_ops dummy_netdev_ops= {
.ndo_init = dummy_dev_init,
.ndo_uninit = dummy_dev_uninit,
.ndo_start_xmit = dummy_xmit,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_rx_mode = set_multicast_list,
.ndo_set_mac_address = eth_mac_addr,
.ndo_get_stats64 = dummy_get_stats64,
.ndo_change_carrier = dummy_change_carrier,
};
mdio.c
mdio接口定义,通过关键参数mdio_if_info*进行mdio操作。
mdio_if_info *mdio在哪里初始化?
mii.c
mii接口定义,通过关键参数mii_if_info*进行mii操作(mdioread/write、net_device操作)。
phy
phy.c
phy接口定义,通过关键参数phy_device *(可调用phy_driver)进行phy操作。
phy_device.c
phy_init
通过subsys_initcall(phy_init)向系统注册。
mdio_bus_init
phy_drivers_register( (phy_driver[])genphy_driver, ARRAY_SIZE(genphy_driver));
phy_drivers_register
(struct phy_driver *new_driver)
设置device_driver的probe和remove,通过driver_register注册device_driver。
new_driver->driver.bus =&mdio_bus_type;
new_driver->driver.probe = phy_probe;
new_driver->driver.remove =phy_remove;
driver_register( &(device_driver*) new_driver->driver );
phy_device_register
(struct phy_device *phydev)
什么时候被调用?
phydev->bus->phy_map[phydev->addr] = phydev;
phy_scan_fixups(phydev);
device_add(&phydev->dev);
struct phy_device*phy_connect
(net_device *dev, char*bus_id, void (*handler)(structnet_device *), phy_interface_tinterface)
phy_device*phydev = bus_find_device_by_name(&mdio_bus_type,NULL, bus_id);
phy_connect_direct(dev, phydev,handler, interface);
phy_attach_direct(dev, phydev, phydev->dev_flags,interface);
phy_prepare_link(phydev, handler);
phy_attach
(struct net_device *dev, const char *bus_id, phy_interface_t interface)
什么时候被调用
(phy_device *)phydev = bus_find_device_by_name(bus,NULL, bus_id);
phy_attach_direct(dev, phydev, phydev->dev_flags, interface);
d(=phydev->dev.driver)= &genphy_driver[GENPHY_DRV_1G].driver;
d->driver->probe(d);
device_bind_driver(d);
phy_init_hw(phydev);
phydev->drv->soft_reset(phydev);
phy_scan_fixups(phydev);
phydev->drv->config_init(phydev);
phy_scan_fixups
(struct phy_device*phydev)
检查phy_fixup_list中各个节点的bus_id和uid,如果不匹配,则调用run进行fixup。
phy_register_fixup提供对phy_fixup进行注册的接口(bus_id、uid、run赋值)。
probe(remove)
(struct device *dev)
服务于device_driver,(match之后)为phy_device设置phy_driver。
phydev->drv = to_phy_driver (phydev->dev.driver);
phydev->drv->probe(phydev);
一般phy操作接口
(struct phy_device *phydev)
genphy_resume、genphy_suspend、genphy_config_init、genphy_soft_reset、genphy_read_status、genphy_update_link、genphy_aneg_done、genphy_config_aneg、genphy_restart_aneg、genphy_setup_forced
直接调用phy_read、phy_write方法(mdiobus_read、mdiobus_write)
phy_driver接口
(struct phy_device *phydev)
phy_resume、phy_suspend
通过to_phy_driver(phydev->dev.driver)调用phy_driver的对应方法。
phy_driver genphy_driver[] = {
{
.phy_id = 0xffffffff,
.phy_id_mask = 0xffffffff,
.name = "Generic PHY",
.soft_reset = genphy_soft_reset,
.config_init = genphy_config_init,
.features = PHY_GBIT_FEATURES |SUPPORTED_MII |
SUPPORTED_AUI | SUPPORTED_FIBRE |
SUPPORTED_BNC,
.config_aneg = genphy_config_aneg,
.aneg_done = genphy_aneg_done,
.read_status = genphy_read_status,
.suspend = genphy_suspend,
.resume = genphy_resume,
.driver = { .owner = THIS_MODULE, },
}, };
mdio_bus.c
接口
为mii_bus分配内存的接口
设备树匹配接口
操作接口,通过mii_bus*操作mdio
mdio_bus_init
class_register(&mdio_bus_class);
bus_register(&mdio_bus_type);
mdiobus_register
device_register(&bus->dev);
mdiobus_scan(bus,i);
get_phy_device(bus,addr, false);
of_mdiobus_link_phydev(bus,phydev);
phy_device_register(phydev);
class mdio_bus_class= {
.name = "mdio_bus",
.dev_release = mdiobus_release,
};
bus_type mdio_bus_type = {
.name = "mdio_bus",
.match = mdio_bus_match,
.pm = MDIO_BUS_PM_OPS = {
.suspend= mdio_bus_suspend,
.resume= mdio_bus_resume,
.freeze= mdio_bus_suspend,
.thaw= mdio_bus_resume,
.restore= mdio_bus_restore,
},
.dev_groups = mdio_dev_groups,
};
结构体genphy_driver定义phy的操作接口,这些接口的关键参数为device*或net_device*、phy_device*;
phy_drivers_register注册genphy_driver的device_driver成员;
static int __init phy_init(void)
mdio_bus_init();
phy_drivers_register(new_driver, ARRAY_SIZE(genphy_driver));
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);
ethernet/ti
cpmac.c
cpmac_init
注册platform_driver
(mii_bus *)cpmac_mii初始化
cpmac_mii->priv = ioremap(AR7_REGS_MDIO, 256);
mdiobus_register(cpmac_mii);
platform_driver_register(&cpmac_driver);
static struct platform_driver cpmac_driver = {
.driver= {.name ="cpmac",},
.probe = cpmac_probe,
.remove= cpmac_remove,
};
cpmac_probe
(struct platform_device*pdev)
注册net_device
从pdev收集mdio_bus/phy_id信息
创建net_device - dev = alloc_etherdev_mq(sizeof(*priv),CPMAC_QUEUES);
关联platform_device和net_device - platform_set_drvdata(pdev, dev);
platform_get_resource_byname(pdev, IORESOURCE_MEM,"regs");
dev->irq = platform_get_irq_byname(pdev, "irq");
dev->netdev_ops= &cpmac_netdev_ops;
dev->ethtool_ops= &cpmac_ethtool_ops;
netif_napi_add(dev, &priv->napi,cpmac_poll, 64);
netif_msg_init(debug_level, 0xff);
priv->phy= phy_connect(dev,priv->phy_name, cpmac_adjust_link,PHY_INTERFACE_MODE_MII);
register_netdev(dev);
netif_msg_probe(priv)
net_device_ops cpmac_netdev_ops = {
.ndo_open = cpmac_open,
.ndo_stop = cpmac_stop,
.ndo_start_xmit =cpmac_start_xmit,
.ndo_tx_timeout = cpmac_tx_timeout,
.ndo_set_rx_mode = cpmac_set_multicast_list,
.ndo_do_ioctl = cpmac_ioctl,
.ndo_change_mtu = eth_change_mtu,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = eth_mac_addr,
};
net_device_ops在什么地方被调用?
cpsw.c
大致结构与cpsw_phy_sel一致
module_platform_driver(cpsw_driver);
platform_driver cpsw_driver ={
.driver= {
.name = "cpsw", //与DTS中的compatible匹配
.pm = &cpsw_pm_ops, //电源管理,非必需
.of_match_table= cpsw_of_mtable, //私有数据
},
.probe= cpsw_probe,
.remove= cpsw_remove,
};
cpsw_probe
(struct platform_device *pdev)
创建net_device
alloc_etherdev(sizeof(struct cpsw_priv));
初始化net_device->cpsw_priv,关联platform_device/ net_device / cpsw_priv
引脚设置
pinctrl_pm_select_default_state(&pdev->dev);
根据dts文件设置cpsw_priv结构体
cpsw_probe_dt(&priv->data, pdev)
MAC地址初始化,slave分配空间
申请资源(地址空间)
platform_get_resource(pdev,IORESOURCE_MEM, 0);
request_mem_region(priv->cpsw_res->start,
resource_size(priv->cpsw_res),ndev->name)
ioremap(priv->cpsw_res->start,resource_size(priv->cpsw_res));
cpsw_slave_init
DMA初始化
priv->dma= cpdma_ctlr_create(&dma_params);
priv->txch= cpdma_chan_create(priv->dma,tx_chan_num(0), cpsw_tx_handler);
priv->rxch= cpdma_chan_create(priv->dma,rx_chan_num(0), cpsw_rx_handler);
ALE初始化
priv->ale = cpsw_ale_create(&ale_params);
IRQ初始化
irq = platform_get_irq(pdev, 1);
devm_request_irq(&pdev->dev, irq, cpsw_rx_interrupt, 0, dev_name(&pdev->dev), priv);
irq =platform_get_irq(pdev, 2);
devm_request_irq(&pdev->dev, irq, cpsw_rx_interrupt, 0, dev_name(&pdev->dev), priv);
操作注册
ndev->netdev_ops = &cpsw_netdev_ops;
ndev->ethtool_ops = &cpsw_ethtool_ops;
netif_napi_add(ndev,&priv->napi_rx, cpsw_rx_poll,CPSW_POLL_WEIGHT);
netif_napi_add(ndev,&priv->napi_tx, cpsw_tx_poll,CPSW_POLL_WEIGHT);
register_netdev(ndev);
发包
初始化
.ndo_start_xmit =cpsw_ndo_start_xmit,
devm_request_irq(&pdev->dev,irq, cpsw_tx_interrupt,0, dev_name(&pdev->dev), priv);
netif_napi_add(ndev,&priv->napi_tx, cpsw_tx_poll, CPSW_POLL_WEIGHT);
priv->txch = cpdma_chan_create(priv->dma,tx_chan_num(0), cpsw_tx_handler);
cpsw_ndo_start_xmit
cpsw_tx_packet_submit(ndev,priv, skb);
cpdma_chan_submit
cpsw_tx_interrupt 发送完成中断触发
napi_schedule(&priv->napi_tx);
cpsw_tx_poll napi调用
cpdma_chan_process (priv->txch,budget);
napi_complete(napi_tx);
enable_irq(priv->irqs_table[1]);
cpsw_tx_handler dma结束后调用
dev_kfree_skb_any(skb);
收包
在cpsw_probe中注册irq处理函数,napi处理函数
devm_request_irq(&pdev->dev,irq, cpsw_rx_interrupt, 0,dev_name(&pdev->dev), priv);
netif_napi_add(ndev,&priv->napi_rx, cpsw_rx_poll, CPSW_POLL_WEIGHT);
cpdma_chan_create(priv->dma,rx_chan_num(0), cpsw_rx_handler);
cpsw_rx_interrupt 接收中断触发
cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_RX);
writel(0, &priv->wr_regs->rx_en);
napi_schedule(&priv->napi_rx);
cpsw_rx_poll 由napi调用
cpdma_chan_process(priv->rxch, budget);
napi_complete(napi_rx);
writel(0xff, &priv->wr_regs->rx_en);
cpsw_rx_handler dma结束后调用
netif_receive_skb(skb);
cpdma_chan_submit(priv->rxch, new_skb, new_skb->data,skb_tailroom(new_skb), 0);
IOCTL
关键结构体
structcpsw_priv
structcpsw_slave *slaves;
struct cpsw_slave_data *data;
structphy_device *phy;
structnet_device *ndev;
cpsw_probe
priv->slaves分配空间
priv->slaves[0].ndev= ndev; //指向新建的net_device
cpsw_slave_init // cpsw_slave_data内容(寄存器地址空间)赋值
cpsw_probe_dt
of_property_read_u32(node,"slaves", &prop) // slaves = <2>;
of_property_read_u32(node,"active_slave", &prop) // active_slave = <0>;
for_each_child_of_node(node,slave_node) //遍历slave node
// phy_id = <&davinci_mdio>, <0>;
__be32*parp = of_get_property(slave_node,"phy_id", &lenp)
device_node *mdio_node = of_find_node_by_phandle(be32_to_cpup(parp))
platform_device *mdio = of_find_device_by_node(mdio_node); //找到davinci_mdio[0]
of_node_put(mdio_node);
snprintf(slave_data->phy_id,sizeof(slave_data->phy_id), PHY_ID_FMT, mdio->name, phyid);
slave_data->phy_if =of_get_phy_mode(slave_node); // phy-mode = "mii";
cpsw_slave_open ---------->cpsw_ndo_open
寄存器赋值
slave->phy= phy_connect(priv->ndev,slave->data->phy_id,&cpsw_adjust_link,
slave->data->phy_if); //查找mdio_bus_type上的phy_device
phy_start(slave->phy);
cpsw_phy_sel(&priv->pdev->dev,
slave->phy->interface,slave->slave_num);
mdio
davinci_mdio_probe
devm_mdiobus_alloc
davinci_mdio_probe_dt
data->bus->read = davinci_mdio_read,
data->bus->write = davinci_mdio_write,
mdiobus_register(data->bus) // mdio_bus_class
device_register(&bus->dev);
get_phy_device(bus,addr, false);
phy_device_register(phydev);
phy-sel //仅仅为了设置phy的mode?
cpsw_phy_sel_probe
NAPI机制说明
1 禁止网卡中断
2napi_schedule把自己的napi_struct挂到softnet_data的poll_list中,然后就结束了中断处理
3softirq的处理调到napi_struct中的poll函数不断从网卡中读取数据转发到协议栈,直到没有数据可读了,或者quota到。
4通过napi_complete将自身从poll_list中拿出来,然后开启网卡中断
DMA
cpsw_probe
priv->dma = cpdma_ctlr_create((structcpdma_params *)&dma_params);
cpdma_desc_pool_create
dma_alloc_coherent(dev, size,&pool->phys, GFP_KERNEL); 或者
ioremap(phys,size);
cpdma_chan_create(priv->dma,tx_chan_num(0), cpsw_tx_handler);
cpdma_chan_create(priv->dma,rx_chan_num(0), cpsw_rx_handler);
devm_request_irq(&pdev->dev,irq, cpsw_rx_interrupt, 0, dev_name(&pdev->dev), priv);
devm_request_irq(&pdev->dev,irq, cpsw_tx_interrupt, 0, dev_name(&pdev->dev), priv);
netif_napi_add(ndev, &priv->napi_rx,cpsw_rx_poll, CPSW_POLL_WEIGHT);
netif_napi_add(ndev,&priv->napi_tx, cpsw_tx_poll, CPSW_POLL_WEIGHT);
cpsw_tx_packet_submit
开始dma发送
cpdma_chan_submit(priv->txch, skb, skb->data, skb->len, 0);
desc= cpdma_desc_alloc(ctlr->pool, 1, is_rx_chan(chan));
dma_map_single(ctlr->dev, data, len,chan->dir);
desc赋值
__cpdma_chan_submit(chan,desc);
cpsw_tx_interrupt
napi_schedule(&priv->napi_tx);
cpsw_tx_poll
num_tx =cpdma_chan_process(priv->txch, budget);
napi_complete(napi_tx);
cpsw_tx_handler
发送完一个包
dev_kfree_skb_any(skb);
cpsw_rx_interrupt 报文接收完以后调用?
napi_schedule(&priv->napi_rx);
cpsw_rx_poll
cpdma_chan_process(priv->rxch,budget);
napi_complete(napi_rx);
cpsw_rx_handler dmachannel free时调用
报文处理:重新接收或者转发给协议栈
cpdma_chan_submit(priv->rxch,new_skb, new_skb->data, skb_tailroom(new_skb), 0);
或者 netif_receive_skb(skb);
davinci_mdio.c
davinci_mdio_driver
platform_driver = {
.driver= {
.name = "davinci_mdio",
.pm = &davinci_mdio_pm_ops,
.of_match_table= of_match_ptr(davinci_mdio_of_mtable),
},
.probe= davinci_mdio_probe,
.remove= davinci_mdio_remove,
};
davinci_mdio_probe
(struct platform_device *pdev)
(mii_bus*)devm_mdiobus_alloc(dev);
of_mdiobus_register(data->bus,dev->of_node);
cpsw_phy_sel.c
module_platform_driver(cpsw_phy_sel_driver);
platform_driver cpsw_phy_sel_driver = {
.probe = cpsw_phy_sel_probe,
.driver = {
.name = "cpsw-phy-sel",
.of_match_table= cpsw_phy_sel_id_table,
},
};
of_device_id cpsw_phy_sel_id_table[]= {
{
.compatible = "ti,am3352-cpsw-phy-sel",
.data = &cpsw_gmii_sel_am3352,
},
{}
};
cpsw_phy_sel_probe
(struct platform_device*pdev)
匹配dts的设备描述和本地of_device_id
of_device_id *of_id = of_match_node(cpsw_phy_sel_id_table, pdev->dev.of_node);
使用本地of_device_id数据设置device的私有数据
priv->cpsw_phy_sel = of_id->data;
dev_set_drvdata(&pdev->dev,priv); 私有数据初始化
cpsw_phy_sel
(struct device *dev, phy_interface_t phy_mode, int slave)
device_node*node = of_get_child_by_name(dev->of_node, "cpsw-phy-sel");
dev = bus_find_device(&platform_bus_type,NULL, node, match);
dev_get_drvdata(dev)->cpsw_phy_sel(priv, phy_mode,slave);
cpsw_ale.c
ale接口
cpts.c
davinci_cpdma.c
davinci_emac.c
late_initcall(davinci_emac_init);
platform_driver_register(&davinci_emac_driver);
davinci_emac_driver
(platform_driver) = {
.driver= {
.name = "davinci_emac",
.pm = &davinci_emac_pm_ops,
.of_match_table= of_match_ptr(davinci_emac_of_match),
},
.probe= davinci_emac_probe,
.remove= davinci_emac_remove,
};
davinci_emac_of_match[]
(of_device_id) = {
{.compatible= "ti,davinci-dm6467-emac", },
{.compatible= "ti,am3517-emac", .data = &am3517_emac_data, },
{.compatible= "ti,dm816-emac", .data = &dm816_emac_data, },
{},
};
davinci_emac_probe
(struct platform_device *pdev)
netcp_core.c
最后
以上就是完美黄豆为你收集整理的摘要:2 网络驱动ethtooldummy.cmdio.cmii.cphyethernet/ti的全部内容,希望文章能够帮你解决摘要:2 网络驱动ethtooldummy.cmdio.cmii.cphyethernet/ti所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复