DM9000网卡驱动源码分析系列08 - 整理补充

/*
 *      Davicom DM9000 Fast Ethernet driver for Linux.
 * 	Copyright (C) 1997  Sten Wang
 *
 * 	This program is free software; you can redistribute it and/or
 * 	modify it under the terms of the GNU General Public License
 * 	as published by the Free Software Foundation; either version 2
 * 	of the License, or (at your option) any later version.
 *
 * 	This program is distributed in the hope that it will be useful,
 * 	but WITHOUT ANY WARRANTY; without even the implied warranty of
 * 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * 	GNU General Public License for more details.
 *
 * (C) Copyright 1997-1998 DAVICOM Semiconductor,Inc. All Rights Reserved.
 *
 * Additional updates, Copyright:
 *	Ben Dooks <ben@simtec.co.uk>
 *	Sascha Hauer <s.hauer@pengutronix.de>
 */

#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/interrupt.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <linux/crc32.h>
#include <linux/mii.h>
#include <linux/of.h>
#include <linux/of_net.h>
#include <linux/ethtool.h>
#include <linux/dm9000.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/irq.h>
#include <linux/slab.h>

#include <asm/delay.h>
#include <asm/irq.h>
#include <asm/io.h>

#include "dm9000.h"

/* Board/System/Debug information/definition ---------------- */

#define DM9000_PHY	0x40	/* PHY address 0x01 */

#define CARDNAME	"dm9000"
#define DRV_VERSION	"1.31"

/*
 * Transmit timeout, default 5 seconds.
 */
static int watchdog = 5000;
module_param(watchdog, int, 0400);
MODULE_PARM_DESC(watchdog, "transmit timeout in milliseconds");

/*
 * Debug messages level
 */
static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "dm9000 debug level (0-4)");

/* DM9000 register address locking.
 *
 * The DM9000 uses an address register to control where data written
 * to the data register goes. This means that the address register
 * must be preserved over interrupts or similar calls.
 *
 * During interrupt and other critical calls, a spinlock is used to
 * protect the system, but the calls themselves save the address
 * in the address register in case they are interrupting another
 * access to the device.
 *
 * For general accesses a lock is provided so that calls which are
 * allowed to sleep are serialised so that the address register does
 * not need to be saved. This lock also serves to serialise access
 * to the EEPROM and PHY access registers which are shared between
 * these two devices.
 */

/* The driver supports the original DM9000E, and now the two newer
 * devices, DM9000A and DM9000B.
 */

enum dm9000_type {
	TYPE_DM9000E,	/* original DM9000 */
	TYPE_DM9000A,
	TYPE_DM9000B
};

/* debug code */

#define dm9000_dbg(db, lev, msg...) do {        \
    if ((lev) < debug) {                \
        dev_dbg(db->dev, msg);            \
    }                        \
} while (0)

static inline struct board_info *to_dm9000_board(struct net_device *dev)
{
    return netdev_priv(dev);
}


/* Structure/enum declaration ------------------------------- */
struct board_info {
	struct resource	*addr_res;	/* resources found */
	struct resource *data_res;
	struct resource *irq_res;

	struct resource	*addr_req;	/* resources requested */
	struct resource *data_req;
	u16		 irq;		/* IRQ */

	void __iomem	*io_addr;	/* Register I/O base address */
	void __iomem	*io_data;	/* Data I/O address */
/**
 *  addr_res/data_res/irq_res 是在probe中通过调用platform_get_resource获取到的板级信息
 *  addr_req/data_req 是在probe中通过调用request_mem_region申请到的资源
 *  irq的值从irq_res->start中获取
 *  io_addr/io_data 申请到资源后,要通过ioremap映射到虚拟地址上才能操作,最后通过iounmap释放
 */

	void (*inblk)(void __iomem *port, void *data, int length);
	void (*outblk)(void __iomem *port, void *data, int length);
	void (*dumpblk)(void __iomem *port, int length);
/**
 *  有了可操作的虚拟内存地址以后,封装一系列函数对内存区域进行读写操作
 *  inblk从网卡读数据到驱动程序
 *  outblk把数据从驱动程序写入到网卡
 *  dumpblk把垃圾数据从网卡中取出,丢弃
 */

	enum dm9000_type type;
	struct device	*dev;		/* parent device */
	struct mutex	addr_lock;	/* phy and eeprom access lock */
	spinlock_t	lock;
	struct net_device	*ndev;
	struct delayed_work	phy_poll;
	struct mii_if_info	mii;
	u32		msg_enable;
/**
 *  type: 网卡类型 dm9000a/dm9000b/dm9000e
 *  dev: 赋值为(struct platform_device)->dev, 注释是parent device,这是什么意思?
 *		这个值我理解为触发这个驱动执行probe函数的设备的结构体指针
 *  addr_lock: 读写eeprom和phy时需要用到这个锁
 *  lock: 读写寄存器时用的锁,避免同时读写同一个寄存器
 *  ndev: 绑定的网卡设备
 *  phy_poll: delay_work,绑定dm9000_poll_work,进行硬件载波检查
 *  mii: (Medium Independent Interface), ethtool/ioctl功能的支持
 *  msg_enable: ethtool eth0打印出来的,Current message level的值
 */

	int		irq_wake;
	u32		wake_state;
/**
 *  irq_wake: 赋值为platform_get_irq(pdev, 1), dm9000会产生两类中断,一类是正常的收发包中断
 *		另一类是这个wakeup中断,以支持wol功能, dm9000_wol_interrupt中断处理函数打印唤醒的原因,应该是系统起来后再执行
 *  wol就是Wake-up On LAN, 现在许多新的PC机(尤其是主板集成网卡的机器)都支持远程唤醒功能
 *  通过远程唤醒,可以方便管理员实现计算机的自动开启。当然被远程唤醒的主机需要具备以下条件:
 *	主板(和网卡)支持WOL功能,有些机器还需要在BIOS中设置开启该功能;
 *	主机在关闭状态时需要是插电的,即计算机的主板和网卡为通电状态(此时整个计算机的用电量很小),才能够监听到网络中对自己的“唤醒数据包”;
 *	管理员需要记下被唤醒主机网卡的MAC地址(物理地址),这样才能够通过相应的方法唤醒该主机
 *  wake_state: ethtool eth0打印出来的:	Supports Wake-on: pumbg
 *					Wake-on: g
 */

	unsigned int	flags;
	unsigned int	in_timeout:1;
	unsigned int	in_suspend:1;
	unsigned int	wake_supported:1;
/**
 *  in_timeout: 标记位,标记是否发包超时
 *  in_suspend: 标记位,标记是否处于休眠状态
 *  wake_supported: 标记位,标记是否支持wol
 *  flags: 设备的flags,比如是否处于混杂模式(IFF_PROMISC),是否有eeprom(DM9000_PLATF_NO_EEPROM),可见flag可以是通用的,也可以是设备独有的
 */
	u16		tx_pkt_cnt;
	u16		queue_pkt_len;
	u16		queue_start_addr;
	u16		queue_ip_summed;
	int		ip_summed;
	u16		dbug_cnt;
	u8		io_mode;		/* 0:word, 2:byte */
	u8		phy_addr;
	u8		imr_all;
/**
 *  tx_pkt_cnt: 当前有几个包待发送,dm9000最多缓存两个包
 *  queue_pkt_len: 放在队列里的那个待发送包的长度(skb->len)
 *  queue_start_addr: 预留字段,暂时没用
 *  queue_ip_summed: 放在队列里的那个待发送包的ip_summed值
 *  ip_summed: 上一次发送的包的ip_summed值, 与当前要发送的包的ip_summed值对比,检测是不是同一个包的不同分片
 *  dbug_cnt: 预留字段,暂时没用
 *  io_mode: I/O mode, see DM9000 Application Notes V1.22 Jun 11, 2004 page 9
 *	The interrupt status register ISR (REG_FE) can help us to check the I/O mode setting
 *	0 0 16-bit mode
 *	1 0 8-bit mode
 *  phy_addr: 预留字段,暂时没用
 *  imr_all: 在恢复中断中使用,
 */
};


delay work流程如下:
1: probe函数
    INIT_DELAYED_WORK(&db->phy_poll, dm9000_poll_work);
    设置(struct board_info)->phy_poll.work.work_func_t = dm9000_poll_work
    类似schedule_delayed_work(&db->phy_poll, 1);设置的时间到期后,dm9000_poll_work函数会被执行
2: open函数
    schedule_delayed_work(&db->phy_poll, 1);
3: dm9000_poll_work函数
    if (netif_running(ndev))
        dm9000_schedule_poll(db);
4: dm9000_schedule_poll(struct board_info *db)
    if (db->type == TYPE_DM9000E)
        schedule_delayed_work(&db->phy_poll, HZ * 2);

如果设备是dm9000e,且设备在运行, 那么每两秒跳到第三步执行

如果设备不是dm9000e,那么只有在中断发生时, 在dm9000_interrupt函数
    if (db->type != TYPE_DM9000E) {
        if (int_status & ISR_LNKCHNG) {
            /* fire a link-change request */
            schedule_delayed_work(&db->phy_poll, 1);
        }
    }
然后跳到第三步执行


最后附一张我理解的dm9000流程图



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值