3 AR9331硬件架構(gòu)
系統(tǒng)框圖
功能框圖
AR9331支持4個(gè)集成PHY的LAN口他炊,及1個(gè)集成PHY的WAN口争剿。4個(gè)LAN口通過GMII與CPU連接,WAN口可以配置使用指定的MII接口與CPU連接痊末。
地址映射
交換控制器
AR9331以太網(wǎng)交換控制器包含5個(gè)10/100M FE端口蚕苇。
AR9331集成2個(gè)GE MAC。交換芯片的phy4 WAN口通過GEO的MII接口與CPU連接凿叠。
PHY0 ~ PHY4支持橋接模式相連涩笤,在橋接模式下,GE0必須處于復(fù)位模式盒件,所有5個(gè)口都 作為LAN口蹬碧,并通過CPU的GE1與MAC0連接。如果GE0單獨(dú)連接到PHY炒刁,MAC5必須處于復(fù)位模式锰茉。
4 platform設(shè)備與驅(qū)動(dòng)
內(nèi)核初始化
通過宏MIPS_MACHINE()
定義了struct mips_machine machine_ATH79_MACH_TL_WR741ND_V4_type
結(jié)構(gòu)體,掛接了配置函數(shù)tl_wr741ndv4_setup()
切心。宏MIPS_MACHINE()
的作用是把定義的結(jié)構(gòu)體置于.mips.machines.init
段中飒筑。
當(dāng)用戶配置用Kernel command line的參數(shù)board=TL-WR741ND-v4
,內(nèi)核函數(shù)__setup("machtype=", mips_machtype_setup)
設(shè)置設(shè)備類型mips_machtype = TL-WR741ND-v4
绽昏。
內(nèi)核初始化時(shí)协屡,根據(jù)vmlinux.lds的段安排,內(nèi)核初始化函數(shù)mips_machine_setup()
會(huì)遍歷.mips.machines.init
段中的所有struct mips_machine
結(jié)構(gòu)體成員全谤,找出設(shè)備類型為“TL-WR741ND-v4”的成員肤晓,并設(shè)置設(shè)備名稱mips_machine_name = "machine_name_ATH79_MACH_TL_WR741ND_V4"
,最后調(diào)用tl_wr741ndv4_setup()
對設(shè)備進(jìn)行初始化配置认然。
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設(shè)備
platform設(shè)備注冊的接口是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);
/* 設(shè)置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驅(qū)動(dòng),注冊mdio設(shè)備毕骡。
mdio_dev = &ath79_mdio1_device;
mdio_data = &ath79_mdio1_data; 且mdio_data->builtin_switch置位 */
ath79_register_mdio(0, 0x0);
/* 注冊eth設(shè)備 */
ath79_register_eth(1);
ath79_register_eth(0);
/* 注冊wmac設(shè)備 */
ath79_register_wmac(ee, mac);
}
/* ath79_setup_ar933x_phy4_switch()`設(shè)置`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_init_mac()
設(shè)置mac地址。
void __init ath79_init_mac(unsigned char *dst, const unsigned char *src,
int offset)
{
int t;
if (!dst)
return;
if (!src || !is_valid_ether_addr(src)) {
memset(dst, '\0', ETH_ALEN);
return;
}
t = (((u32) src[3]) << 16) + (((u32) src[4]) << 8) + ((u32) src[5]);
t += offset;
dst[0] = src[0];
dst[1] = src[1];
dst[2] = src[2];
dst[3] = (t >> 16) & 0xff;
dst[4] = (t >> 8) & 0xff;
dst[5] = t & 0xff;
}
ath79_register_eth()
注冊eth設(shè)備未巫。
struct platform_device ath79_eth0_device = {
.name = "ag71xx",
.id = 0,
.resource = ath79_eth0_resources,
.num_resources = ARRAY_SIZE(ath79_eth0_resources),
.dev = {
.platform_data = &ath79_eth0_data,
},
};
void __init ath79_register_eth(unsigned int id)
{
struct platform_device *pdev;
struct ag71xx_platform_data *pdata;
int err;
if (id > 1) {
printk(KERN_ERR "ar71xx: invalid ethernet id %d\n", id);
return;
}
/* 初始化ath79_ethX_pll_data */
ath79_init_eth_pll_data(id);
if (id == 0)
pdev = &ath79_eth0_device;
else
pdev = &ath79_eth1_device;
/* 設(shè)置ath79_eth0_device.dev.platform_data.phy_if_mode =
PHY_INTERFACE_MODE_MII窿撬。
ath79_eth0_device.dev.platform_data.phy_if_mode =
PHY_INTERFACE_MODE_GMII */
pdata = pdev->dev.platform_data;
err = ath79_setup_phy_if_mode(id, pdata);
if (err) {
printk(KERN_ERR
"ar71xx: invalid PHY interface mode for GE%u\n", id);
return;
}
switch (ath79_soc) {
case ATH79_SOC_AR9331:
if (id == 0) {
pdata->reset_bit = AR933X_RESET_GE0_MAC |
AR933X_RESET_GE0_MDIO;
pdata->ddr_flush = ar933x_ddr_flush_ge0;
pdata->set_speed = ath79_set_speed_dummy;
pdata->phy_mask = BIT(4);
} else {
pdata->reset_bit = AR933X_RESET_GE1_MAC |
AR933X_RESET_GE1_MDIO;
pdata->ddr_flush = ar933x_ddr_flush_ge1;
pdata->set_speed = ath79_set_speed_dummy;
pdata->speed = SPEED_1000;
pdata->duplex = DUPLEX_FULL;
pdata->switch_data = &ath79_switch_data;
ath79_switch_data.phy_poll_mask |= BIT(4);
}
pdata->has_gbit = 1;
pdata->is_ar724x = 1;
if (!pdata->fifo_cfg1)
pdata->fifo_cfg1 = 0x0010ffff;
if (!pdata->fifo_cfg2)
pdata->fifo_cfg2 = 0x015500aa;
if (!pdata->fifo_cfg3)
pdata->fifo_cfg3 = 0x01f00140;
break;
}
switch (pdata->phy_if_mode) {
case PHY_INTERFACE_MODE_GMII:
case PHY_INTERFACE_MODE_RGMII:
if (!pdata->has_gbit) {
printk(KERN_ERR "ar71xx: no gbit available on eth%d\n",
id);
return;
}
/* fallthrough */
default:
break;
}
if (!is_valid_ether_addr(pdata->mac_addr)) {
random_ether_addr(pdata->mac_addr);
printk(KERN_DEBUG
"ar71xx: using random MAC address for eth%d\n",
ath79_eth_instance);
}
if (pdata->mii_bus_dev == NULL) {
switch (ath79_soc) {
case ATH79_SOC_AR9331:
pdata->mii_bus_dev = &ath79_mdio1_device.dev;
break;
}
}
/* 設(shè)置寄存器RST_RESET,重啟MAC與MDIO叙凡,寄存器進(jìn)入復(fù)位狀態(tài) */
ath79_device_reset_set(pdata->reset_bit);
mdelay(100);
/* 解除重啟劈伴,進(jìn)入正常工作 */
ath79_device_reset_clear(pdata->reset_bit);
mdelay(100);
/* 注冊platform設(shè)備dev */
platform_device_register(pdev);
ath79_eth_instance++;
}
int platform_device_register(struct platform_device *pdev)
{
/* pdev->dev->kobj.kset = devices_kset */
device_initialize(&pdev->dev);
arch_setup_pdev_archdata(pdev);
platform_device_add(pdev);
}
int platform_device_add(struct platform_device *pdev)
{
/* 關(guān)聯(lián)platform設(shè)備框架 */
if (!pdev->dev.parent)
pdev->dev.parent = &platform_bus;
/* 關(guān)聯(lián)platform總線框架 */
pdev->dev.bus = &platform_bus_type;
/* 設(shè)置pdev->dev.kobj.name = "pdev->name"."pdev->id" */
dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id);
device_add(&pdev->dev);
}
ath79_register_wmac()
注冊wmac設(shè)備。
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設(shè)備ath79_wmac_device */
platform_device_register(&ath79_wmac_device);
}
static void __init ar933x_wmac_setup(void)
{
u32 t;
/* 設(shè)置寄存器RST_RESET.WLAN_RESET握爷,使WLAN重啟 */
ar933x_wmac_reset();
ath79_wmac_device.name = "ar933x_wmac";
/* 設(shè)置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驅(qū)動(dòng)
platform驅(qū)動(dòng)注冊的接口是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;
/* 如果驅(qū)動(dòng)對象存在probe()等函數(shù)严里,則設(shè)置驅(qū)動(dòng)對象的驅(qū)動(dòng)成員
(struct platform_driver.driver)的probe等指針。
這樣包裝的目的:當(dāng)內(nèi)核設(shè)備驅(qū)動(dòng)框架進(jìn)行驅(qū)動(dòng)掛接時(shí)赡模,先調(diào)用platform_drv_probe()等
函數(shù)田炭,這些函數(shù)會(huì)做一些額外的檢查與保護(hù),然后調(diào)用到實(shí)際的驅(qū)動(dòng)probe()函數(shù) */
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)
{
/* 查找驅(qū)動(dòng)是否已注冊 */
driver_find(drv->name, drv->bus);
/* */
bus_add_driver(drv);
driver_add_groups(drv, drv->groups);
kobject_uevent(&drv->p->kobj, KOBJ_ADD);
}
/* 從platform總線框架里查找驅(qū)動(dòng)名稱是否已經(jīng)注冊漓柑。查找方式是查找priv.drivers_kset
保存的已注冊驅(qū)動(dòng)鏈表 */
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);
/* 關(guān)聯(lián)私有數(shù)據(jù)結(jié)構(gòu)體 */
priv->driver = drv;
drv->p = priv;
priv->kobj.kset = bus->p->drivers_kset;
/* 設(shè)置priv.kobj.name */
kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
"%s", drv->name);
/* 把新的驅(qū)動(dòng)節(jié)點(diǎn)添加到總線的驅(qū)動(dòng)維護(hù)鏈表里 */
klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
/* 如果設(shè)置了自動(dòng)探測標(biāo)志教硫,則進(jìn)行設(shè)備的探測與驅(qū)動(dòng)的掛接加載。如果設(shè)備在驅(qū)動(dòng)之前注冊
的辆布,那么就可以探測到瞬矩;反之亦然,在注冊設(shè)備時(shí)锋玲,也會(huì)執(zhí)行這樣的類似操作景用,進(jìn)行驅(qū)動(dòng)的
探測。所以惭蹂,不管是先注冊設(shè)備伞插,還是先注冊驅(qū)動(dòng),在注冊時(shí)部是會(huì)進(jìn)行探測匹配 */
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;
}
/* 探測設(shè)備盾碗,掛接驅(qū)動(dòng) */
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指向總線的設(shè)備維護(hù)鏈表klist_devices */
klist_iter_init_node(&bus->p->klist_devices, &i,
(start ? &start->p->knode_bus : NULL));
/* 迭代鏈表klist_devices里的所有節(jié)點(diǎn)媚污,執(zhí)行__driver_attach()函數(shù)。
dev指向結(jié)構(gòu)體struct platform_device.dev廷雅,本例中是設(shè)備ath79_eth0_device.dev耗美。
data指向結(jié)構(gòu)體struct platform_driver.device_driver,本例子中是
驅(qū)動(dòng)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;
/* 執(zhí)行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);
/* 如果設(shè)備還未掛接過驅(qū)動(dòng)商架,現(xiàn)在掛接驅(qū)動(dòng) */
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;
/* 對于本例,以上匹配規(guī)則都不會(huì)被執(zhí)行芥玉。
設(shè)備名與驅(qū)動(dòng)名都是"ag71xx"蛇摸,因此返回匹配。這里的設(shè)備名不是指在/sys/下看到的設(shè)備
名飞傀,/sys/下的設(shè)備名稱是"ag71xx.0" */
return (strcmp(pdev->name, drv->name) == 0);
}
int driver_probe_device(struct device_driver *drv, struct device *dev)
{
int ret = 0;
/* 判斷設(shè)備是否已經(jīng)注冊皇型。state_in_sysfs標(biāo)志 */
if (!device_is_registered(dev))
return -ENODEV;
pm_runtime_barrier(dev);
/* 執(zhí)行探測函數(shù) */
really_probe(dev, drv);
pm_request_idle(dev);
}
static int really_probe(struct device *dev, struct device_driver *drv)
{
/* 掛接驅(qū)動(dòng),ath79_eth0_device.dev.driver = &ag71xx_driver.driver */
dev->driver = drv;
/* 設(shè)置用戶空間sysfs的驅(qū)動(dòng)與設(shè)備的掛接軟鏈接 */
driver_sysfs_add(dev);
if (dev->bus->probe) {
dev->bus->probe(dev);
} else if (drv->probe) { /* 執(zhí)行這里 */
/* 執(zhí)行ag71xx_driver.driver.probe()砸烦,即platform_drv_probe()。
platform_drv_probe()會(huì)做一些檢查與保護(hù)绞吁,并調(diào)用到真正的驅(qū)動(dòng)probe()函數(shù)幢痘,
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;
}
/* 創(chuàng)建軟鏈接家破。sysfs是分層結(jié)構(gòu)組織的颜说,設(shè)備放在設(shè)備目錄下购岗,驅(qū)動(dòng)放在驅(qū)動(dòng)目錄下,那么在用戶
空間設(shè)備目錄與驅(qū)動(dòng)目錄是如何掛接呢门粪?技巧就是使用軟鏈接喊积,在設(shè)備目錄軟鏈接指向?qū)?yīng)的驅(qū)動(dòng)
,在驅(qū)動(dòng)目錄下軟鏈接指向?qū)?yīng)的設(shè)備玄妈。 */
static int driver_sysfs_add(struct device *dev)
{
int ret;
/* 這個(gè)是在創(chuàng)建軟件鏈接乾吻,在dev->driver->p->kobj(即設(shè)備所掛接的驅(qū)動(dòng)的私有數(shù)據(jù)結(jié)構(gòu)
體的kobj)對象下創(chuàng)建以設(shè)備名稱(即ath79_eth0_device.dev.kobj.name)命名的軟鏈
接,指向設(shè)備的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) {
/* 創(chuàng)建軟鏈接: /sys/devices/platform/ag71xx.0/driver ->
/sys/bus/platform/drivers/ag71xx/ */
sysfs_create_link(&dev->kobj, &dev->driver->p->kobj,
"driver");
}
}
struct net
linux每個(gè)進(jìn)程有自己的命名空間拟蜻,在clone進(jìn)程時(shí)绎签,為新進(jìn)程分配命名空間。命名空間由全局變量init_nsproxy
定義酝锅,按功能模塊進(jìn)行獨(dú)立管理诡必,內(nèi)核可配置選擇是否使用網(wǎng)絡(luò)命名空間用來管理所有的網(wǎng)絡(luò)設(shè)備與驅(qū)動(dòng),初始化入口是net_dev_init()
搔扁。如果不使用命名空間爸舒,則每個(gè)新進(jìn)程分配的命名空間都是使用父進(jìn)程的命名空間,即所有進(jìn)程都屬于同一命名空間稿蹲,網(wǎng)絡(luò)命名空間是全局變量init_net
扭勉;如果使用命名空間,則每個(gè)新進(jìn)程分配的命名空間是重新創(chuàng)建的命名空間场绿,由鏈表net_namespace_list
管理所有的網(wǎng)絡(luò)命名空間剖效,第一個(gè)進(jìn)程的網(wǎng)絡(luò)命名空間仍然是init_net
。
static int __init net_dev_init(void)
{
dev_proc_init(); /* 在procfs下創(chuàng)建管理節(jié)點(diǎn) */
netdev_kobject_init(); /* 賦值kobj_ns_ops_tbl[KOBJ_NS_TYPE_NET] =
&net_ns_type_operations焰盗。
創(chuàng)建/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);
/* 設(shè)置軟中斷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(); /* 注冊網(wǎng)絡(luò)通告br_init */
}
static int __net_init netdev_init(struct net *net)
{
/* init_net->dev_base_head在定義變量時(shí)就已經(jīng)初始化了。
dev_base_head用來把所有設(shè)備的struct net_device鏈接起來熬拒。 */
if (net != &init_net)
INIT_LIST_HEAD(&net->dev_base_head);
/* 分配256個(gè)struct hlist_node大小的空間 */
net->dev_name_head = netdev_create_hash();
/* 分配256個(gè)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);
}
/* 沒有網(wǎng)絡(luò)命名空間的情況下 */
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); /* 執(zhí)行dev_proc_net_init(&init_net) */
register_pernet_subsys(&dev_mc_net_ops); /* 執(zhí)行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);
/* 創(chuàng)建/sys/class/net/ */
return class_register(&net_class);
}
```c
**驅(qū)動(dòng)探測**
```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;
/* 設(shè)備注冊時(shí)已經(jīng)初始化爷光,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;
}
/* 創(chuàng)建eth設(shè)備的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;
}
分配網(wǎng)絡(luò)設(shè)備實(shí)例并注冊
#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:私有數(shù)據(jù),比如設(shè)備的特征信息等澎粟,用戶可根據(jù)需要添加任意的結(jié)構(gòu)體蛀序。
@setup():初始化設(shè)備的回調(diào)函數(shù)ether_setup()
@txqs:TX隊(duì)列的個(gè)數(shù)
@rxqs:RX隊(duì)列的個(gè)數(shù)
*/
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;
/* 在連續(xù)內(nèi)存空間分配兩個(gè)結(jié)構(gòu)體,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); /* 初始化設(shè)備mac的mac地址鏈表 */
dev_mc_init(dev); /* 初始化多播轉(zhuǎn)發(fā)mac地址鏈表 */
dev_uc_init(dev); /* 初始化單播轉(zhuǎn)發(fā)mac地址鏈表 */
/* 關(guān)聯(lián)命名空間活烙,dev->nd_net = &init_net */
dev_net_set(dev, &init_net);
/* 設(shè)置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); /* 執(zhí)行ether_setup() */
dev->num_tx_queues = txqs; /* =1 */
dev->real_num_tx_queues = txqs; /* =1 */
/* netif_alloc_netdev_queues()創(chuàng)建并初始化發(fā)包隊(duì)列徐裸,并把隊(duì)列掛接到`dev`設(shè)備上 */
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()創(chuàng)建并初始化收包隊(duì)列,并把隊(duì)列掛接到`dev`設(shè)備上 */
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設(shè)備 */
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()設(shè)置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這種帶有未決字符的啸盏,搜索未使用的索引進(jìn)行賦值重贺。
搜索方式:從命名空間的設(shè)備名鏈表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,不執(zhí)行 */
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); /* 分配一個(gè)ifindex气笙,取net->ifindex的值
作為基值次企,與dev->index_hlist鏈表進(jìn)行比較,如果已存在潜圃,則
把基值+1遞增繼續(xù)比較缸棵,直到找出未使用的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);
/* 初始化設(shè)備模型實(shí)例堵第,并添加到/sys/devices/virtual/net/。
如果(!dev->parent && dev->class)崇堵,則在virtual目錄下創(chuàng)建class對應(yīng)的目錄型诚,再
把設(shè)備加入到該目錄下 */
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;
/* 關(guān)閉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);
/* 復(fù)位phy */
ath79_device_reset_set(reset_phy);
mdelay(50);
/* 解復(fù)位phy */
ath79_device_reset_clear(reset_phy);
mdelay(200);
}
/* 重啟MAC所有模塊 */
ag71xx_sb(ag, AG71XX_REG_MAC_CFG1, MAC_CFG1_SR);
udelay(20);
/* 復(fù)位PHY之外的所有模塊 */
ath79_device_reset_set(reset_mask);
mdelay(100);
/* 解復(fù)位PHY之外的所有模塊 */
ath79_device_reset_clear(reset_mask);
mdelay(200);
/* 使能MAC幀接收與轉(zhuǎn)發(fā)功能狰贯、設(shè)置MTU */
ag71xx_hw_setup(ag);
/* 配置并使能DMA */
ag71xx_dma_reset(ag);
}