文章目录
裸机操作
dm9000的裸机操作
这里 讲了如何对dm9000 访问
本文主要讲解dm9000 在linux下的驱动
文件解析
dm9000 linux 相关文件
drivers/net$ tree
.
├── ethernet
│ ├── davicom
│ │ ├── dm9000.c
│ │ ├── dm9000.h
│ │ ├── Kconfig
│ │ └── Makefile
│ ├── Kconfig
│ └── Makefile
├── Kconfig
├── loopback.c // 回环设备的驱动
├── Makefile
└── mii.c // mii 协议的代码描述,这里面EXPORT_SYMBOL出来的符号都被dm9000.c 用了
dm9000 mm.c 解析
- mii.c 中 EXPORT_SYMBOL 出来的符号
mii_link_ok
mii_nway_restart
mii_ethtool_gset
mii_ethtool_get_link_ksettings
mii_ethtool_sset
mii_ethtool_set_link_ksettings
mii_check_link
mii_check_media
mii_check_gmii_support
generic_mii_ioctl
dm9000 dm9000.c 解析
- dm9000.c 框架
dm9000.c 中 没有 EXPORT_SYMBOL 出来符号,且全部都是static 的
probe 做了一些 net_device_ops-> ndo_init 中需要做到的事情,所以把 ndo_init 直接留空了
dm9000.c 中 写了1795行
1413 - 1707 是probe
1429 - 1442 给dm9000 上电
1444 - 1460 给dm9000 复位
1462 - 1466 从设备树中获取信息,是不是用了ext phy,是不是no-eeprom,mac地址
1469 - 1683 行
申请 struct net_device , 并填充成员
申请 struct board_info , 并填充成员
1. dev.parent
2. struct board_info *db
2.1 lock
2.2 addr_lock
2.3 phy_poll
2.4 addr_res
2.5 data_res
2.6 addr_req
2.7 io_addr
2.8 data_req
2.9 io_data
2.10 dumpblk
2.11 outblk
2.12 inblk
2.13 flags
2.14 msg_enable
2.15 mii.phy_id_mask / mii.reg_num_mask/ mii.force_media/mii.full_duplex/mii.dev/
2.16 mii.mdio_read/mii.mdio_write
3. irq
4. irq_wake
5. base_addr
期间,reset 了 dm9000,读了id,知道dm9000的具体型号
6. hw_features
7. features
8. netdev_ops
9. watchdog_timeo
10.ethtool_ops
期间 读了 eeprom, 获取了 mac地址,并校验是否有效
期间,platform_set_drvdata(pdev, ndev);
register_netdev(ndev);
1760 - 1770 是 remove
unregister_netdev(ndev);
dm9000_release_board(pdev, netdev_priv(ndev));
free_netdev(ndev);
1710 - 1729 是 suspend
经过层层判断,然后dm9000_shutdown(包括 Power-Down PHY,Disable RX)
// 这个动作 也会在 dm9000_netdev_ops->ndo_open 即 dm9000_stop 中做
1732 - 1752 是 resume
对应suspend后 resume 的动作
做了 dm9000_init_dm9000 和 dm9000_unmask_interrupts
// 这2个动作 也会在 dm9000_netdev_ops->ndo_open 即 dm9000_open 中做
接口分析
实现了哪些ops
底层ops
对下,实现了这些ops
mdio_read
mdio_write
dm9000_get_eeprom
dm9000_set_eeprom
dm9000_get_link_ksettings
dm9000_set_link_ksettings
ior
iow
dumpblk
inblk
outblk
上层ops
对上,实现了这些ops
struct net_device_ops netdev_ops
struct ethtool_ops ethtool_ops
http://lnmp.ailinux.net/ethtool
https://zhuanlan.zhihu.com/p/55131870
1367 static const struct net_device_ops dm9000_netdev_ops = {
1368 .ndo_open = dm9000_open,
1369 .ndo_stop = dm9000_stop,
1370 .ndo_start_xmit = dm9000_start_xmit,
1371 .ndo_tx_timeout = dm9000_timeout,
1372 .ndo_set_rx_mode = dm9000_hash_table,
1373 .ndo_do_ioctl = dm9000_ioctl,
1374 .ndo_set_features = dm9000_set_features,
1375 .ndo_validate_addr = eth_validate_addr,
1376 .ndo_set_mac_address = eth_mac_addr,
1377 #ifdef CONFIG_NET_POLL_CONTROLLER
1378 .ndo_poll_controller = dm9000_poll_controller,
1379 #endif
1380 };
731 static const struct ethtool_ops dm9000_ethtool_ops = {
732 .get_drvinfo = dm9000_get_drvinfo,
733 .get_msglevel = dm9000_get_msglevel,
734 .set_msglevel = dm9000_set_msglevel,
735 .nway_reset = dm9000_nway_reset,
736 .get_link = dm9000_get_link,
737 .get_wol = dm9000_get_wol,
738 .set_wol = dm9000_set_wol,
739 .get_eeprom_len = dm9000_get_eeprom_len,
740 .get_eeprom = dm9000_get_eeprom,
741 .set_eeprom = dm9000_set_eeprom,
742 .get_link_ksettings = dm9000_get_link_ksettings,
743 .set_link_ksettings = dm9000_set_link_ksettings,
744 };
还有哪些接口
工作任务
INIT_DELAYED_WORK(&db->phy_poll, dm9000_poll_work);
dm9000_poll_work
...
注意,如果不是 TYPE_DM9000E , 则 不会 循环调用
dm9000_interrupt // 中断调用
schedule_delayed_work(&db->phy_poll, 1);
dm9000_open
schedule_delayed_work(&db->phy_poll, 1);
盲猜是中断或者ifconfig eth0 up开启了这个循环调用
中断
dm9000_interrupt
dm9000_wol_interrupt
dm9000 驱动的 接口层次划分
dev_queue_xmit
__dev_xmit_skb
sch_direct_xmit
dev_hard_start_xmit
xmit_one
netdev_start_xmit
__netdev_start_xmit
ops->ndo_start_xmit
static irqreturn_t dm9000_interrupt
dm9000_tx_done
static irqreturn_t dm9000_interrupt
dm9000_rx
netif_rx
接口调用流程
发送数据
接收数据
控制 TODO
其他ops接口什么时候会调用到 TODO
实例探索
用ftrace 抓取发送和接收过程
一个最少的网卡驱动要实现什么接口
- dm9000精简代码
- [arm vexpress code 中的 virt_net_card 驱动