摘要:2 网络驱动

来源:互联网 发布:163博客相册没有数据 编辑:程序博客网 时间:2024/06/06 08:31

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_datapoll_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

0 0
原创粉丝点击