xilinx emaclite 网卡驱动分析

Emac lite芯片驱动

drivers/net/ethernet/xilinx/xilinx_emaclite.c
MODULE_DESCRIPTION(“Xilinx Ethernet MAC Lite driver”);

xemaclite_of_driver

module_platform_driver(xemaclite_of_driver);

static struct platform_driver xemaclite_of_driver = {
.driver = {
.name = DRIVER_NAME,
.of_match_table = xemaclite_of_match,
},
.probe = xemaclite_of_probe,
.remove = xemaclite_of_remove,
};

xemaclite_of_match

static const struct of_device_id xemaclite_of_match[] = {
{ .compatible = “xlnx,opb-ethernetlite-1.01.a”, },
{ .compatible = “xlnx,opb-ethernetlite-1.01.b”, },
{ .compatible = “xlnx,xps-ethernetlite-1.00.a”, },
{ .compatible = “xlnx,xps-ethernetlite-2.00.a”, },
{ .compatible = “xlnx,xps-ethernetlite-2.01.a”, },
{ .compatible = “xlnx,xps-ethernetlite-3.00.a”, },
{ /* end of list */ },
};

DTS设备树信息

axi_ethernetlite: ethernet@62000000 {
compatible = “xlnx,xps-ethernetlite-3.00.a”;
device_type = “network”;
local-mac-address = [00 00 5E 00 FA CE];
interrupts = <0 97 IRQ_TYPE_EDGE_RISING>;
phy-handle = <&phy0>;
reg = <0x62000000 0x10000>;
xlnx,duplex = <0x1>;
xlnx,include-global-buffers = <0x1>;
xlnx,include-internal-loopback = <0x0>;
xlnx,include-mdio = <0x1>;
xlnx,instance = “axi_ethernetlite_inst”;
xlnx,rx-ping-pong = <0x1>;
xlnx,s-axi-id-width = <0x1>;
xlnx,tx-ping-pong = <0x1>;
xlnx,use-internal = <0x0>;
#include <dt-bindings/net/ti-dp83867.h>
mdio {
#address-cells = <1>;
#size-cells = <0>;
phy0: phy@1 {
device_type = “ethernet-phy”;
reg = <0>;
tx-fifo-depth = <DP83867_PHYCR_FIFO_DEPTH_4_B_NIB>;
rx-fifo-depth = <DP83867_PHYCR_FIFO_DEPTH_4_B_NIB>;
ti,max-output-impedance;
ti,clk-output-sel = <DP83867_CLK_O_SEL_CHN_A_RCLK>;
ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_25_NS>;
ti,tx-internal-delay = <DP83867_RGMIIDCTL_2_75_NS>;
};
};
};

xemaclite_of_probe

xemaclite_of_probe //Xilinx emac lite网卡初始化函数
->ndev = alloc_etherdev(sizeof(struct net_local))
->alloc_etherdev_mqs
->alloc_netdev_mqs(sizeof_priv, “eth%d”, NET_NAME_UNKNOWN, ether_setup, txqs, rxqs)
->platform_get_resource(ofdev, IORESOURCE_IRQ, 0)
->platform_get_resource(ofdev, IORESOURCE_MEM, 0)
->xemaclite_update_address(lp, ndev->dev_addr)
->lp->phy_node = of_parse_phandle(ofdev->dev.of_node, “phy-handle”, 0);
->xemaclite_mdio_setup(lp, &ofdev->dev); //这里面,会调用phy driver进行初始化
->xemaclite_writel(XEL_MDIOCTRL_MDIOEN_MASK, lp->base_addr + XEL_MDIOCTRL_OFFSET)
->struct mii_bus *bus = mdiobus_alloc()
->bus->name = “Xilinx Emaclite MDIO”;
->bus->read = xemaclite_mdio_read
->bus->write = xemaclite_mdio_write
->bus->parent = dev;
->of_mdiobus_register(bus, np)
-> mdio->phy_mask = ~0 //bus->phy_mask=0xFFFFFFFF,这样, mdiobus_scan就不自动扫描所有的phy
->mdiobus_register(mdio)
->__mdiobus_register(bus, THIS_MODULE)
->device_register(&bus->dev) //注册mii bus的设备
->devm_gpiod_get_optional(&bus->dev, “reset”, GPIOD_OUT_LOW) //???
->mdiobus_scan(bus, i) //这里不会调到,因为phy mask为0xffffffff, 所以条件不满足
->of_mdio_parse_addr(&mdio->dev, child) //查找reg属性,从而获取phy器件的地址
->of_property_read_u32(np, “reg”, &addr)
->of_mdiobus_register_phy(mdio, child, addr)
->of_get_phy_id(child, &phy_id) //返回NULL
->get_phy_device(mdio, addr, is_c45)
->get_phy_c22_id(bus, addr, &phy_id) //读MII_PHYSID1/MII_PHYSID2寄存器,获取PHY芯片的硬件ID
->phy_device_create(bus, addr, phy_id, is_c45, &c45_ids)
->struct phy_device *dev= kzalloc(sizeof(*dev), GFP_KERNEL) //创建phy device 设备
->mdiodev = &dev->mdio
->mdiodev->bus_match = phy_bus_match
->dev->interface = PHY_INTERFACE_MODE_GMII
->dev->phy_id = phy_id
->device_initialize(&mdiodev->dev)
->INIT_DELAYED_WORK(&dev->state_queue, phy_state_machine) //phy的状态机
->of_mdiobus_phy_device_register(mdio, phy, child, addr)
->phy_device_register(phy) //注册phy device,最终会与phy driver匹配,成功后,调用到phy driver的probe()函数
->mdiobus_register_device(&phydev->mdio)
->mdiodev->bus->mdio_map[mdiodev->addr] = mdiodev
->phy_device_reset(phydev, 0);
->phy_scan_fixups(phydev);
->device_add(&phydev->mdio.dev)
-> bus_probe_device(dev)
-> device_initial_probe(dev)
-> __device_attach(dev, true)
-> bus_for_each_drv(dev->bus, NULL, &data, __device_attach_driver) //device尝试去匹配driver
->dev_info(dev, “MAC address is now %pM\n”, ndev->dev_addr);
->ndev->netdev_ops = &xemaclite_netdev_ops;
->ndev->ethtool_ops = &xemaclite_ethtool_ops;
->ndev->flags &= ~IFF_MULTICAST;
->ndev->watchdog_timeo = TX_TIMEOUT;
->register_netdevice //注册一个网络设备

关于devm_gpiod_get_optional(&bus->dev, “reset”, GPIOD_OUT_LOW) //???
这里有一个例子,如下:
&davinci_mdio {
pinctrl-names = “default”, “sleep”;
pinctrl-0 = <&davinci_mdio_default>;
pinctrl-1 = <&davinci_mdio_sleep>;
status = “okay”;
reset-gpios = <&gpio2 5 GPIO_ACTIVE_LOW>;
reset-delay-us = <2>; /* PHY datasheet states 1uS min */

ethphy0: ethernet-phy@1 {
	reg = <1>;
};

ethphy1: ethernet-phy@3 {
	reg = <3>;
};

};

xemaclite_netdev_ops

static const struct net_device_ops xemaclite_netdev_ops = {
.ndo_open = xemaclite_open,
.ndo_stop = xemaclite_close,
.ndo_start_xmit = xemaclite_send,
.ndo_set_mac_address = xemaclite_set_mac_address,
.ndo_tx_timeout = xemaclite_tx_timeout,
.ndo_do_ioctl = xemaclite_ioctl,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = xemaclite_poll_controller,
#endif
};

xemaclite_open打开网卡

xemaclite_open
->xemaclite_disable_interrupts(lp); //关闭中断
->lp->phy_dev = of_phy_connect(lp->ndev, lp->phy_node, //这里,会调用 dp83867的reset()和config_init()函数
xemaclite_adjust_link, 0,
PHY_INTERFACE_MODE_MII);
->phy_set_max_speed(lp->phy_dev, SPEED_100); //设置为100M,因为不支持1000M
->phy_write(lp->phy_dev, MII_CTRL1000, 0);
->phy_write(lp->phy_dev, MII_ADVERTISE, ADVERTISE_ALL |ADVERTISE_CSMA);
->bmcr = phy_read(lp->phy_dev, MII_BMCR);
->bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
->phy_write(lp->phy_dev, MII_BMCR, bmcr);
->phy_start(lp->phy_dev); //启动phy,本质是,设置状态为PHY_UP,同时启动phy的状态机
->xemaclite_update_address(lp, dev->dev_addr); //更新mac地址
->request_irq(dev->irq, xemaclite_interrupt, 0, dev->name, dev); //注册中断函数
->xemaclite_enable_interrupts(lp); //打开中断
->netif_start_queue(dev) //开始调度队列

xemaclite_send发送数据

xemaclite_send
->struct net_local *lp = netdev_priv(dev)
->struct sk_buff *new_skb

  • 9
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值