3 AR9331硬件架构
系统框图
功能框图
AR9331支持4个集成PHY的LAN口,及1个集成PHY的WAN口。4个LAN口通过GMII与CPU连接,WAN口可以配置使用指定的MII接口与CPU连接。
地址映射
交换控制器
AR9331以太网交换控制器包含5个10/100M FE端口。
AR9331集成2个GE MAC。交换芯片的phy4 WAN口通过GEO的MII接口与CPU连接。
PHY0 ~ PHY4支持桥接模式相连,在桥接模式下,GE0必须处于复位模式,所有5个口都 作为LAN口,并通过CPU的GE1与MAC0连接。如果GE0单独连接到PHY,MAC5必须处于复位模式。
4 platform设备与驱动
内核初始化
通过宏MIPS_MACHINE()
定义了struct mips_machine machine_ATH79_MACH_TL_WR741ND_V4_type
结构体,挂接了配置函数tl_wr741ndv4_setup()
。宏MIPS_MACHINE()
的作用是把定义的结构体置于.mips.machines.init
段中。
当用户配置用Kernel command line的参数board=TL-WR741ND-v4
,内核函数__setup("machtype=", mips_machtype_setup)
设置设备类型mips_machtype = TL-WR741ND-v4
。
内核初始化时,根据vmlinux.lds的段安排,内核初始化函数mips_machine_setup()
会遍历.mips.machines.init
段中的所有struct mips_machine
结构体成员,找出设备类型为“TL-WR741ND-v4”的成员,并设置设备名称mips_machine_name = "machine_name_ATH79_MACH_TL_WR741ND_V4"
,最后调用tl_wr741ndv4_setup()
对设备进行初始化配置。
MIPS_MACHINE(ATH79_MACH_TL_WR741ND_V4, "TL-WR741ND-v4",
"TP-LINK TL-WR741ND v4", tl_wr741ndv4_setup);
#define MIPS_MACHINE(_type, _id, _name, _setup) \
static const char machine_name_##_type[] __initconst \
__aligned(1) = _name; \
static const char machine_id_##_type[] __initconst \
__aligned(1) = _id; \
static struct mips_machine machine_##_type \
__used __section(.mips.machines.init) = \
{ \
.mach_type = _type, \
.mach_id = machine_id_##_type, \
.mach_name = machine_name_##_type, \
.mach_setup = _setup, \
};
/* vmlinux.lds */
.mips.machines.init : AT(ADDR(.mips.machines.init) - 0) {
__mips_machines_start = .;
*(.mips.machines.init)
__mips_machines_end = .;
注册platform设备
platform设备注册的接口是platform_device_register()
。
AR9331芯片寄存器描述:
#define AR71XX_APB_BASE 0x18000000
#define AR933X_GMAC_BASE (AR71XX_APB_BASE + 0x00070000)
/*
* AR933X GMAC interface
*/
#define AR933X_GMAC_REG_ETH_CFG 0x00
#define AR933X_ETH_CFG_SW_PHY_SWAP BIT(7)
#define AR933X_ETH_CFG_SW_PHY_ADDR_SWAP BIT(8)
static void __init tl_wr741ndv4_setup(void)
{
u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00);
u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
/* 寄存器ETH_CFG的第7、第8位,置位 */
ath79_setup_ar933x_phy4_switch(true, true);
/* 清除寄存器GPIO_FUNCTION_1的第3~7位 */
ath79_gpio_function_disable(AR933X_GPIO_FUNC_ETH_SWITCH_LED0_EN |
AR933X_GPIO_FUNC_ETH_SWITCH_LED1_EN |
AR933X_GPIO_FUNC_ETH_SWITCH_LED2_EN |
AR933X_GPIO_FUNC_ETH_SWITCH_LED3_EN |
AR933X_GPIO_FUNC_ETH_SWITCH_LED4_EN);
ath79_register_leds_gpio(-1, ARRAY_SIZE(tl_wr741ndv4_leds_gpio),
tl_wr741ndv4_leds_gpio);
ath79_register_gpio_keys_polled(1, TL_WR741NDV4_KEYS_POLL_INTERVAL,
ARRAY_SIZE(tl_wr741ndv4_gpio_keys),
tl_wr741ndv4_gpio_keys);
ath79_register_m25p80(&tl_wr741ndv4_flash_data);
/* 设置eth0与eth1的mac地址,分别是mac+1与mac-1 */
ath79_init_mac(ath79_eth0_data.mac_addr, mac, 1);
ath79_init_mac(ath79_eth1_data.mac_addr, mac, -1);
/* 挂接mdio驱动,注册mdio设备。
mdio_dev = &ath79_mdio1_device;
mdio_data = &ath79_mdio1_data; 且mdio_data->builtin_switch置位 */
ath79_register_mdio(0, 0x0);
/* 注册eth设备 */
ath79_register_eth(1);
ath79_register_eth(0);
/* 注册wmac设备 */
ath79_register_wmac(ee, mac);
}
/* ath79_setup_ar933x_phy4_switch()`设置`ETH_CFG`寄存器的第7、第8位 */
void __init ath79_setup_ar933x_phy4_switch(bool mac, bool mdio)
{
void __iomem *base;
u32 t;
base = ioremap(AR933X_GMAC_BASE, AR933X_GMAC_SIZE);
t = __raw_readl(base + AR933X_GMAC_REG_ETH_CFG);
t &= ~(AR933X_ETH_CFG_SW_PHY_SWAP | AR933X_ETH_CFG_SW_PHY_ADDR_SWAP);
if (mac)
t |= AR933X_ETH_CFG_SW_PHY_SWAP;
if (mdio)
t |= AR933X_ETH_CFG_SW_PHY_ADDR_SWAP;
__raw_writel(t, base + AR933X_GMAC_REG_ETH_CFG);
iounmap(base);
}
ath79_register_wmac()
注册wmac设备。
void __init ath79_register_wmac(u8 *cal_data, u8 *mac_addr)
{
ar933x_wmac_setup();
if (cal_data)
memcpy(ath79_wmac_data.eeprom_data, cal_data,
sizeof(ath79_wmac_data.eeprom_data));
if (mac_addr) {
memcpy(ath79_wmac_mac, mac_addr, sizeof(ath79_wmac_mac));
ath79_wmac_data.macaddr = ath79_wmac_mac;
}
/* 注册platform设备ath79_wmac_device */
platform_device_register(&ath79_wmac_device);
}
static void __init ar933x_wmac_setup(void)
{
u32 t;
/* 设置寄存器RST_RESET.WLAN_RESET,使WLAN重启 */
ar933x_wmac_reset();
ath79_wmac_device.name = "ar933x_wmac";
/* 设置wmac的IORESOURCE_MEM为0x18100000 ~ 0x1811ffff
MAC_PCU – 1810_8000
RTC – 1810_7000
Host Interface – 1810_4000
DCU – 1810_1000
QCU – 1810_0800
DMA – 1810_0000
wmac的IORESOURCE_IRQ = 2 */
ath79_wmac_resources[0].start = AR933X_WMAC_BASE;
ath79_wmac_resources[0].end = AR933X_WMAC_BASE + AR933X_WMAC_SIZE - 1;
ath79_wmac_resources[1].start = ATH79_CPU_IRQ_IP2;
ath79_wmac_resources[1].end = ATH79_CPU_IRQ_IP2;
t = ath79_reset_rr(AR933X_RESET_REG_BOOTSTRAP);
if (t & AR933X_BOOTSTRAP_REF_CLK_40)
ath79_wmac_data.is_clk_25mhz = false;
else
ath79_wmac_data.is_clk_25mhz = true;
if (ath79_soc_rev == 1)
ath79_wmac_data.get_mac_revision = ar933x_r1_get_wmac_revision;
ath79_wmac_data.external_reset = ar933x_wmac_reset;
}
注册platform驱动
platform驱动注册的接口是platform_driver_register()
。
static struct platform_driver ag71xx_driver = {
.probe = ag71xx_probe,
.remove = __exit_p(ag71xx_remove),
.driver = {
.name = "ag71xx",
}
};
static int __init ag71xx_module_init(void)
{
platform_driver_register(&ag71xx_driver);
}
#define platform_driver_register(drv) \
__platform_driver_register(drv, THIS_MODULE)
int __platform_driver_register(struct platform_driver *drv,
struct module *owner)
{
drv->driver.owner = owner;
drv->driver.bus = &platform_bus_type;
/* 如果驱动对象存在probe()等函数,则设置驱动对象的驱动成员
(struct platform_driver.driver)的probe等指针。
这样包装的目的:当内核设备驱动框架进行驱动挂接时,先调用platform_drv_probe()等
函数,这些函数会做一些额外的检查与保护,然后调用到实际的驱动probe()函数 */
if (drv->probe)
drv->driver.probe = platform_drv_probe;
if (drv->remove)
drv->driver.remove = platform_drv_remove;
if (drv->shutdown)
drv->driver.shutdown = platform_drv_shutdown;
driver_register(&drv->driver);
}
int driver_register(struct device_driver *drv)
{
/* 查找驱动是否已注册 */
driver_find(drv->name, drv->bus);
/* */
bus_add_driver(drv);
driver_add_groups(drv, drv->groups);
kobject_uevent(&drv->p->kobj, KOBJ_ADD);
}
/* 从platform总线框架里查找驱动名称是否已经注册。查找方式是查找priv.drivers_kset
保存的已注册驱动链表 */
struct device_driver *driver_find(const char *name, struct bus_type *bus)
{
struct kobject *k = kset_find_obj(bus->p->drivers_kset, name);
struct driver_private *priv;
if (k) {
/* Drop reference added by kset_find_obj() */
kobject_put(k);
priv = to_driver(k);
return priv->driver;
}
return NULL;
}
int bus_add_driver(struct device_driver *drv)
{
struct bus_type *bus;
struct driver_private *priv;
int error = 0;
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
klist_init(&priv->klist_devices, NULL, NULL);
/* 关联私有数据结构体 */
priv->driver = drv;
drv->p = priv;
priv->kobj.kset = bus->p->drivers_kset;
/* 设置priv.kobj.name */
kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
"%s", drv->name);
/* 把新的驱动节点添加到总线的驱动维护链表里 */
klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
/* 如果设置了自动探测标志,则进行设备的探测与驱动的挂接加载。如果设备在驱动之前注册
的,那么就可以探测到;反之亦然,在注册设备时,也会执行这样的类似操作,进行驱动的
探测。所以,不管是先注册设备,还是先注册驱动,在注册时部是会进行探测匹配 */
if (drv->bus->p->drivers_autoprobe) {
driver_attach(drv);
}
module_add_driver(drv->owner, drv);
error = driver_create_file(drv, &driver_attr_uevent);
if (error) {
printk(KERN_ERR "%s: uevent attr (%s) failed\n",
__func__, drv->name);
}
error = driver_add_groups(drv, bus->drv_groups);
if (error) {
/* How the hell do we get out of this pickle? Give up */
printk(KERN_ERR "%s: driver_create_groups(%s) failed\n",
__func__, drv->name);
}
if (!drv->suppress_bind_attrs) {
error = add_bind_files(drv);
if (error) {
/* Ditto */
printk(KERN_ERR "%s: add_bind_files(%s) failed\n",
__func__, drv->name);
}
}
return 0;
out_unregister:
kobject_put(&priv->kobj);
kfree(drv->p);
drv->p = NULL;
out_put_bus:
bus_put(bus);
return error;
}
/* 探测设备,挂接驱动 */
int driver_attach(struct device_driver *drv)
{
return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
}
int bus_for_each_dev(struct bus_type *bus, struct device *start,
void *data, int (*fn)(struct device *, void *))
{
struct klist_iter i;
struct device *dev;
/* 把i->i_klist指向总线的设备维护链表klist_devices */
klist_iter_init_node(&bus->p->klist_devices, &i,
(start ? &start->p->knode_bus : NULL));
/* 迭代链表klist_devices里的所有节点,执行__driver_attach()函数。
dev指向结构体struct platform_device.dev,本例中是设备ath79_eth0_device.dev。
data指向结构体struct platform_driver.device_driver,本例子中是
驱动ag71xx_driver.driver。 */
while ((dev = next_device(&i)) && !error)
error = fn(dev, data);
klist_iter_exit(&i);
}
static int __driver_attach(struct device *dev, void *data)
{
struct device_driver *drv = data;
/* 执行platform_bus_type.match() */
if (!driver_match_device(drv, dev))
return 0;
if (dev->parent) /* Needed for USB */
device_lock(dev->parent);
device_lock(dev);
/* 如果设备还未挂接过驱动,现在挂接驱动 */
if (!dev->driver)
driver_probe_device(drv, dev);
device_unlock(dev);
if (dev->parent)
device_unlock(dev->parent);
return 0;
}
static int platform_match(struct device *dev, struct device_driver *drv)
{
struct platform_device *pdev = to_platform_device(dev);
struct platform_driver *pdrv = to_platform_driver(drv);
/* When driver_override is set, only bind to the matching driver */
if (pdev->driver_override)
return !strcmp(pdev->driver_override, drv->name);
/* Attempt an OF style match first */
if (of_driver_match_device(dev, drv))
return 1;
/* Then try ACPI style match */
if (acpi_driver_match_device(dev, drv))
return 1;
/* Then try to match against the id table */
if (pdrv->id_table)
return platform_match_id(pdrv->id_table, pdev) != NULL;
/* 对于本例,以上匹配规则都不会被执行。
设备名与驱动名都是"ag71xx",因此返回匹配。这里的设备名不是指在/sys/下看到的设备
名,/sys/下的设备名称是"ag71xx.0" */
return (strcmp(pdev->name, drv->name) == 0);
}
int driver_probe_device(struct device_driver *drv, struct device *dev)
{
int ret = 0;
/* 判断设备是否已经注册。state_in_sysfs标志 */
if (!device_is_registered(dev))
return -ENODEV;
pm_runtime_barrier(dev);
/* 执行探测函数 */
really_probe(dev, drv);
pm_request_idle(dev);
}
static int really_probe(struct device *dev, struct device_driver *drv)
{
/* 挂接驱动,ath79_eth0_device.dev.driver = &ag71xx_driver.driver */
dev->driver = drv;
/* 设置用户空间sysfs的驱动与设备的挂接软链接 */
driver_sysfs_add(dev);
if (dev->bus->probe) {
dev->bus->probe(dev);
} else if (drv->probe) { /* 执行这里 */
/* 执行ag71xx_driver.driver.probe(),即platform_drv_probe()。
platform_drv_probe()会做一些检查与保护,并调用到真正的驱动probe()函数,
ag71xx_driver.probe(),即ag71xx_probe() */
drv->probe(dev);
}
driver_bound(dev);
ret = 1;
pr_debug("bus: '%s': %s: bound device %s to driver %s\n",
drv->bus->name, __func__, dev_name(dev), drv->name);
goto done;
done:
atomic_dec(&probe_count);
wake_up(&probe_waitqueue);
return ret;
}
/* 创建软链接。sysfs是分层结构组织的,设备放在设备目录下,驱动放在驱动目录下,那么在用户
空间设备目录与驱动目录是如何挂接呢?技巧就是使用软链接,在设备目录软链接指向对应的驱动
,在驱动目录下软链接指向对应的设备。 */
static int driver_sysfs_add(struct device *dev)
{
int ret;
/* 这个是在创建软件链接,在dev->driver->p->kobj(即设备所挂接的驱动的私有数据结构
体的kobj)对象下创建以设备名称(即ath79_eth0_device.dev.kobj.name)命名的软链
接,指向设备的sysfs目录:
/sys/bus/platform/drivers/ag71xx/ag71xx.0 ->
/sys/devices/platform/ag71xx.0 */
ret = sysfs_create_link(&dev->driver->p->kobj, &dev->kobj,
kobject_name(&dev->kobj));
if (ret == 0) {
/* 创建软链接: /sys/devices/platform/ag71xx.0/driver ->
/sys/bus/platform/drivers/ag71xx/ */
sysfs_create_link(&dev->kobj, &dev->driver->p->kobj,
"driver");
}
}
struct net
linux每个进程有自己的命名空间,在clone进程时,为新进程分配命名空间。命名空间由全局变量init_nsproxy
定义,按功能模块进行独立管理,内核可配置选择是否使用网络命名空间用来管理所有的网络设备与驱动,初始化入口是net_dev_init()
。如果不使用命名空间,则每个新进程分配的命名空间都是使用父进程的命名空间,即所有进程都属于同一命名空间,网络命名空间是全局变量init_net
;如果使用命名空间,则每个新进程分配的命名空间是重新创建的命名空间,由链表net_namespace_list
管理所有的网络命名空间,第一个进程的网络命名空间仍然是init_net
。
static int __init net_dev_init(void)
{
dev_proc_init(); /* 在procfs下创建管理节点 */
netdev_kobject_init(); /* 赋值kobj_ns_ops_tbl[KOBJ_NS_TYPE_NET] =
&net_ns_type_operations。
创建/sys/class/net/。 */
INIT_LIST_HEAD(&ptype_all);
for (i = 0; i < PTYPE_HASH_SIZE; i++)
INIT_LIST_HEAD(&ptype_base[i]);
INIT_LIST_HEAD(&offload_base);
if (register_pernet_subsys(&netdev_net_ops))
goto out;
dev_boot_phase = 0;
/* 把first_device指针指向loopback_net_ops.list */
register_pernet_device(&loopback_net_ops); /* loopback_net_ops(&init_net) */
register_pernet_device(&default_device_ops);
/* 设置软中断softirq_vec[].action */
open_softirq(NET_TX_SOFTIRQ, net_tx_action);
open_softirq(NET_RX_SOFTIRQ, net_rx_action);
hotcpu_notifier(dev_cpu_callback, 0);
dst_init(); /* 注册网络通告br_init */
}
static int __net_init netdev_init(struct net *net)
{
/* init_net->dev_base_head在定义变量时就已经初始化了。
dev_base_head用来把所有设备的struct net_device链接起来。 */
if (net != &init_net)
INIT_LIST_HEAD(&net->dev_base_head);
/* 分配256个struct hlist_node大小的空间 */
net->dev_name_head = netdev_create_hash();
/* 分配256个struct hlist_node大小的空间 */
net->dev_index_head = netdev_create_hash();
}
static struct pernet_operations __net_initdata netdev_net_ops = {
.init = netdev_init,
.exit = netdev_exit,
};
int register_pernet_subsys(struct pernet_operations *ops)
{
register_pernet_operations(first_device, ops);
}
static int register_pernet_operations(struct list_head *list,
struct pernet_operations *ops)
{
__register_pernet_operations(list, ops);
}
/* 没有网络命名空间的情况下 */
static int __register_pernet_operations(struct list_head *list,
struct pernet_operations *ops)
{
return ops_init(ops, &init_net);
}
static int ops_init(const struct pernet_operations *ops, struct net *net)
{
ops->init(net);
}
static struct pernet_operations __net_initdata dev_proc_ops = {
.init = dev_proc_net_init,
.exit = dev_proc_net_exit,
};
static struct pernet_operations __net_initdata dev_mc_net_ops = {
.init = dev_mc_net_init,
.exit = dev_mc_net_exit,
};
int __init dev_proc_init(void)
{
register_pernet_subsys(&dev_proc_ops); /* 执行dev_proc_net_init(&init_net) */
register_pernet_subsys(&dev_mc_net_ops); /* 执行dev_mc_net_init(&init_net) */
}
int __init netdev_kobject_init(void)
{
/* 赋值kobj_ns_ops_tbl[KOBJ_NS_TYPE_NET] = &net_ns_type_operations */
kobj_ns_type_register(&net_ns_type_operations);
/* 创建/sys/class/net/ */
return class_register(&net_class);
}
```c
**驱动探测**
```c
static int __devinit ag71xx_probe(struct platform_device *pdev)
{
struct net_device *dev;
struct resource *res;
struct ag71xx *ag;
struct ag71xx_platform_data *pdata;
int err;
/* ath79_eth0_data */
pdata = pdev->dev.platform_data;
/* 设备注册时已经初始化,pdata->mii_bus_dev = &ath79_mdio1_device.dev */
if (pdata->mii_bus_dev == NULL) {
dev_err(&pdev->dev, "no MII bus device specified\n");
err = -EINVAL;
goto err_out;
}
/* 创建eth设备的net_device */
dev = alloc_etherdev(sizeof(*ag));
SET_NETDEV_DEV(dev, &pdev->dev);
ag = netdev_priv(dev);
ag->pdev = pdev;
ag->dev = dev;
ag->msg_enable = netif_msg_init(ag71xx_msg_level,
AG71XX_DEFAULT_MSG_ENABLE);
spin_lock_init(&ag->lock);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mac_base");
ag->mac_base = ioremap_nocache(res->start, res->end - res->start + 1);
dev->irq = platform_get_irq(pdev, 0);
err = request_irq(dev->irq, ag71xx_interrupt,
IRQF_DISABLED,
dev->name, dev);
dev->base_addr = (unsigned long)ag->mac_base;
dev->netdev_ops = &ag71xx_netdev_ops;
dev->ethtool_ops = &ag71xx_ethtool_ops;
INIT_WORK(&ag->restart_work, ag71xx_restart_work_func);
init_timer(&ag->oom_timer);
ag->oom_timer.data = (unsigned long) dev;
ag->oom_timer.function = ag71xx_oom_timer_handler;
ag->tx_ring.size = AG71XX_TX_RING_SIZE_DEFAULT;
ag->rx_ring.size = AG71XX_RX_RING_SIZE_DEFAULT;
ag->stop_desc = dma_alloc_coherent(NULL,
sizeof(struct ag71xx_desc), &ag->stop_desc_dma, GFP_KERNEL);
if (!ag->stop_desc)
goto err_free_irq;
ag->stop_desc->data = 0;
ag->stop_desc->ctrl = 0;
ag->stop_desc->next = (u32) ag->stop_desc_dma;
memcpy(dev->dev_addr, pdata->mac_addr, ETH_ALEN);
netif_napi_add(dev, &ag->napi, ag71xx_poll, AG71XX_NAPI_WEIGHT);
register_netdev(dev);
/* 打印Ethernet寄存器信息 */
ag71xx_dump_regs(ag);
ag71xx_hw_init(ag);
ag71xx_dump_regs(ag);
ag71xx_phy_connect(ag);
ag71xx_debugfs_init(ag);
platform_set_drvdata(pdev, dev);
return 0;
}
分配网络设备实例并注册
#define alloc_etherdev(sizeof_priv) alloc_etherdev_mq(sizeof_priv, 1)
#define alloc_etherdev_mq(sizeof_priv, count) alloc_etherdev_mqs(sizeof_priv,
count, count)
struct net_device *alloc_etherdev_mqs(int sizeof_priv, unsigned int txqs,
unsigned int rxqs)
{
return alloc_netdev_mqs(sizeof_priv, "eth%d", NET_NAME_UNKNOWN,
ether_setup, txqs, rxqs);
}
/* @sizeof_priv:私有数据,比如设备的特征信息等,用户可根据需要添加任意的结构体。
@setup():初始化设备的回调函数ether_setup()
@txqs:TX队列的个数
@rxqs:RX队列的个数
*/
struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
unsigned char name_assign_type,
void (*setup)(struct net_device *),
unsigned int txqs, unsigned int rxqs)
{
struct net_device *dev;
size_t alloc_size;
struct net_device *p;
/* 在连续内存空间分配两个结构体,net_device与struct ag71xx */
alloc_size = sizeof(struct net_device);
if (sizeof_priv) {
alloc_size += sizeof_priv;
}
dev = kzalloc(alloc_size, GFP_KERNEL | __GFP_NOWARN | __GFP_REPEAT);
dev->pcpu_refcnt = alloc_percpu(int);
dev_addr_init(dev); /* 初始化设备mac的mac地址链表 */
dev_mc_init(dev); /* 初始化多播转发mac地址链表 */
dev_uc_init(dev); /* 初始化单播转发mac地址链表 */
/* 关联命名空间,dev->nd_net = &init_net */
dev_net_set(dev, &init_net);
/* 设置GSO */
dev->gso_max_size = GSO_MAX_SIZE;
dev->gso_max_segs = GSO_MAX_SEGS;
dev->gso_min_segs = 0;
INIT_LIST_HEAD(&dev->napi_list);
INIT_LIST_HEAD(&dev->unreg_list);
INIT_LIST_HEAD(&dev->close_list);
INIT_LIST_HEAD(&dev->link_watch_list);
INIT_LIST_HEAD(&dev->adj_list.upper);
INIT_LIST_HEAD(&dev->adj_list.lower);
INIT_LIST_HEAD(&dev->all_adj_list.upper);
INIT_LIST_HEAD(&dev->all_adj_list.lower);
INIT_LIST_HEAD(&dev->ptype_all);
INIT_LIST_HEAD(&dev->ptype_specific);
dev->priv_flags = IFF_XMIT_DST_RELEASE | IFF_XMIT_DST_RELEASE_PERM;
setup(dev); /* 执行ether_setup() */
dev->num_tx_queues = txqs; /* =1 */
dev->real_num_tx_queues = txqs; /* =1 */
/* netif_alloc_netdev_queues()创建并初始化发包队列,并把队列挂接到`dev`设备上 */
netif_alloc_netdev_queues(dev);
#ifdef CONFIG_SYSFS
dev->num_rx_queues = rxqs; /* =1 */
dev->real_num_rx_queues = rxqs; /* =1 */
/* netif_alloc_rx_queues()创建并初始化收包队列,并把队列挂接到`dev`设备上 */
netif_alloc_rx_queues(dev);
#endif
strcpy(dev->name, name);
dev->name_assign_type = name_assign_type;
dev->group = INIT_NETDEV_GROUP;
if (!dev->ethtool_ops)
dev->ethtool_ops = &default_ethtool_ops;
return dev;
}
void ether_setup(struct net_device *dev)
{
dev->header_ops = ð_header_ops;
dev->type = ARPHRD_ETHER;
dev->hard_header_len = ETH_HLEN;
dev->mtu = ETH_DATA_LEN;
dev->addr_len = ETH_ALEN;
dev->tx_queue_len = 1000; /* Ethernet wants good queues */
dev->flags = IFF_BROADCAST|IFF_MULTICAST;
dev->priv_flags |= IFF_TX_SKB_SHARING;
memset(dev->broadcast, 0xFF, ETH_ALEN);
}
/* 注册net_device设备 */
int register_netdev(struct net_device *dev)
{
rtnl_lock();
err = register_netdevice(dev);
rtnl_unlock();
}
int register_netdevice(struct net_device *dev)
{
int ret;
struct net *net = dev_net(dev);
BUG_ON(dev_boot_phase); /* net_dev_init()设置dev_boot_phase = 0 */
/* When net_device's are persistent, this will be fatal. */
BUG_ON(dev->reg_state != NETREG_UNINITIALIZED);
BUG_ON(!net);
spin_lock_init(&dev->addr_list_lock);
netdev_set_addr_lockdep_class(dev);
dev->iflink = -1;
/* 如果名称是eth%d这种带有未决字符的,搜索未使用的索引进行赋值。
搜索方式:从命名空间的设备名链表struct net.dev_base_head里从0开始搜索
还未使用的最小索引值。 */
dev_get_valid_name(net, dev, dev->name);
/* dev->netdev_ops = &ag71xx_netdev_ops */
if (dev->netdev_ops->ndo_init) { /* NULL,不执行 */
dev->netdev_ops->ndo_init(dev);
}
if (((dev->hw_features | dev->features) &
NETIF_F_HW_VLAN_CTAG_FILTER) &&
(!dev->netdev_ops->ndo_vlan_rx_add_vid ||
!dev->netdev_ops->ndo_vlan_rx_kill_vid)) {
netdev_WARN(dev, "Buggy VLAN acceleration in driver!\n");
ret = -EINVAL;
goto err_uninit;
}
ret = -EBUSY;
if (!dev->ifindex)
dev->ifindex = dev_new_index(net); /* 分配一个ifindex,取net->ifindex的值
作为基值,与dev->index_hlist链表进行比较,如果已存在,则
把基值+1递增继续比较,直到找出未使用的ifindex则返回。
ifindex的值最小为1。 */
else if (__dev_get_by_index(net, dev->ifindex))
goto err_uninit;
if (dev->iflink == -1)
dev->iflink = dev->ifindex;
/* Transfer changeable features to wanted_features and enable
* software offloads (GSO and GRO).
*/
dev->hw_features |= NETIF_F_SOFT_FEATURES;
dev->features |= NETIF_F_SOFT_FEATURES;
dev->wanted_features = dev->features & dev->hw_features;
if (!(dev->flags & IFF_LOOPBACK)) {
dev->hw_features |= NETIF_F_NOCACHE_COPY;
}
/* Make NETIF_F_HIGHDMA inheritable to VLAN devices.
*/
dev->vlan_features |= NETIF_F_HIGHDMA;
/* Make NETIF_F_SG inheritable to tunnel devices.
*/
dev->hw_enc_features |= NETIF_F_SG;
/* Make NETIF_F_SG inheritable to MPLS.
*/
dev->mpls_features |= NETIF_F_SG;
ret = call_netdevice_notifiers(NETDEV_POST_INIT, dev);
notifier_to_errno(ret);
/* 初始化设备模型实例,并添加到/sys/devices/virtual/net/。
如果(!dev->parent && dev->class),则在virtual目录下创建class对应的目录,再
把设备加入到该目录下 */
netdev_register_kobject(dev);
dev->reg_state = NETREG_REGISTERED;
__netdev_update_features(dev);
set_bit(__LINK_STATE_PRESENT, &dev->state);
linkwatch_init_dev(dev);
dev_init_scheduler(dev);
dev_hold(dev);
/* 把dev->name_hlist添加到net->dev_name_head,
把dev->ifindex添加到net->dev_index_head,
把dev->dev_list添加到net->dev_base_head */
list_netdevice(dev);
add_device_randomness(dev->dev_addr, dev->addr_len);
/* If the device has permanent device address, driver should
* set dev_addr and also addr_assign_type should be set to
* NET_ADDR_PERM (default value).
*/
if (dev->addr_assign_type == NET_ADDR_PERM)
memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
/* Notify protocols, that a new device appeared. */
ret = call_netdevice_notifiers(NETDEV_REGISTER, dev);
ret = notifier_to_errno(ret);
if (ret) {
rollback_registered(dev);
dev->reg_state = NETREG_UNREGISTERED;
}
/*
* Prevent userspace races by waiting until the network
* device is fully setup before sending notifications.
*/
if (!dev->rtnl_link_ops ||
dev->rtnl_link_state == RTNL_LINK_INITIALIZED)
rtmsg_ifinfo(RTM_NEWLINK, dev, ~0U, GFP_KERNEL);
out:
return ret;
err_uninit:
if (dev->netdev_ops->ndo_uninit)
dev->netdev_ops->ndo_uninit(dev);
goto out;
}
硬件初始化
static void ag71xx_hw_init(struct ag71xx *ag)
{
struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
u32 reset_mask = pdata->reset_bit;
/* 关闭DMA中断与传输 */
ag71xx_hw_stop(ag);
if (pdata->is_ar724x) {
u32 reset_phy = reset_mask;
reset_phy &= AR71XX_RESET_GE0_PHY | AR71XX_RESET_GE1_PHY;
reset_mask &= ~(AR71XX_RESET_GE0_PHY | AR71XX_RESET_GE1_PHY);
/* 复位phy */
ath79_device_reset_set(reset_phy);
mdelay(50);
/* 解复位phy */
ath79_device_reset_clear(reset_phy);
mdelay(200);
}
/* 重启MAC所有模块 */
ag71xx_sb(ag, AG71XX_REG_MAC_CFG1, MAC_CFG1_SR);
udelay(20);
/* 复位PHY之外的所有模块 */
ath79_device_reset_set(reset_mask);
mdelay(100);
/* 解复位PHY之外的所有模块 */
ath79_device_reset_clear(reset_mask);
mdelay(200);
/* 使能MAC帧接收与转发功能、设置MTU */
ag71xx_hw_setup(ag);
/* 配置并使能DMA */
ag71xx_dma_reset(ag);
}
网友评论