网络子系统目录架构:
net->
->core
->各类协议
->过滤
->通讯方式
driver->
->net
->各类协议
->ethernet
->以太网下各厂商驱动
->hieth-gmac
->higmac.c higmac.h
->ctrl.c ctrl.h
->forward.c forward.h
->mdio.c mdio.h
->mv88e6320.c mv88e6320.h
->phy_fix.c phy_fix.h
以太网驱动以海思以太网gmac驱动为例
higmac.c为驱动本体:
一、驱动初始化
static int __init higmac_init(void)
{
int ret = 0, i;
ret = platform_device_register(&higmac_platform_device);
if (ret) {
pr_err("register netdevice device failed!");
goto _error_register_device;
}
ret = platform_driver_register(&higmac_dev_driver);
if (ret) {
pr_err("register netdevice driver failed!");
goto _error_register_driver;
}
ret = misc_register(&gmac_dev);
if (ret) {
pr_err("register misc device failed!");
goto _error_register_misc_dev;
} else
miscdev_registered = 1;
higmac_proc_create();
for (i = 0; i < CONFIG_GMAC_NUMS; i++) {
pr_info("ETH%d: %s, phy_addr=%d, mii_name=%s\n", i,
mii_to_str[higmac_board_info[i].phy_intf],
higmac_board_info[i].phy_addr,
higmac_board_info[i].mii_name);
}
return ret;
_error_register_misc_dev:
platform_driver_unregister(&higmac_dev_driver);
_error_register_driver:
platform_device_unregister(&higmac_platform_device);
_error_register_device:
return -1;
}
解析:
#define __init __section(.init.text) __cold notrace
函数所在位置初始化代码段
对于存储位置,可以见图
平台注册分为平台设备信息和平台驱动:
1.1平台设备信息:
static struct platform_device higmac_platform_device = {
.name = HIGMAC_DRIVER_NAME,
.id = 0,
.dev = {
.dma_mask = &higmac_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32),
.release = higmac_platform_dev_release,
},
.num_resources = ARRAY_SIZE(higmac_resources),
.resource = higmac_resources,
};
其中:
#define HIGMAC_DRIVER_NAME "hi_gmac_v200"
设备信息与驱动的匹配字符串
static u64 higmac_dmamask = DMA_BIT_MASK(32);
dma的最大寻址能力,主要用于容错。
当申请一致性DMA缓冲区时(采用64bit),则用
u64 coherent_dma_mask;
释放平台设备信息时,用
higmac_platform_dev_release
实际上这个函数为空
资源信息个数:
.num_resources = ARRAY_SIZE(higmac_resources),
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
资源信息higmac_resources实际为
static struct resource higmac_resources[] = {
[0] = {/* eth0 io space */
.start = CONFIG_HIGMAC_IOBASE,
.end = CONFIG_HIGMAC_IOBASE + HIGMAC_IOSIZE - 1,
.flags = IORESOURCE_MEM,
},
[1] = {/* eth1 io space */
.start = CONFIG_HIGMAC_IOBASE + HIGMAC_OFFSET,
.end = CONFIG_HIGMAC_IOBASE + HIGMAC_OFFSET
+ HIGMAC_IOSIZE - 1,
.flags = IORESOURCE_MEM,
},
[2] = {/* gmac0 irq */
.start = CONFIG_HIGMAC_IRQNUM,
.end = CONFIG_HIGMAC_IRQNUM,
.flags = IORESOURCE_IRQ,
},
[3] = {/* gmac1 irq */
.start = CONFIG_HIGMAC_IRQNUM + 1,
.end = CONFIG_HIGMAC_IRQNUM + 1,
.flags = IORESOURCE_IRQ,
}
};
资源信息为芯片控制寄存器地址:
#define CONFIG_HIGMAC_IOBASE 0x10090000
#define HIGMAC_IOSIZE (0x1000)
最后一个寄存器地址
#define HIGMAC_IOSIZE (0x1000)
#define HIGMAC_OFFSET (HIGMAC_IOSIZE)
根据芯片手册得知,设备并没有第二个网卡,这里可能是海思预留
#define CONFIG_HIGMAC_IRQNUM 57
中断源分配表
除了flag
#define IORESOURCE_MEM 0x00000200
#define IORESOURCE_IRQ 0x00000400
1.2平台驱动
static struct platform_driver higmac_dev_driver = {
.probe = higmac_dev_probe,
.remove = higmac_dev_remove,
.suspend = higmac_dev_suspend,
.resume = higmac_dev_resume,
.driver = {
.owner = THIS_MODULE,
.name = HIGMAC_DRIVER_NAME,
},
};
higmac_dev_probe为探针函数,驱动加载且匹配设备信息成功后,会回调probe函数,主要功能初始化
higmac_dev_remove为卸载函数,驱动执行rmmod卸载后会执行,主要功能清理注册
higmac_dev_suspend为挂起函数,驱动进入电源管理睡眠后会执行,主要功能低功耗处理
higmac_dev_resume为唤醒函数,驱动退出电源管理睡眠后会执行,主要功能低功耗恢复
THIS_MODULE为device_driver的指向本设备驱动的模块指针
HIGMAC_DRIVER_NAME为设备信息与驱动的匹配字符串
设备信息和平台驱动注册完后,需要实现设备驱动,完成ioctl等文件操作
1.3杂项设备驱动注册
static struct miscdevice gmac_dev = {
MISC_DYNAMIC_MINOR,
"gmac",
&gmac_fops
};
杂项设备驱动的次设备号统一为
#define MISC_DYNAMIC_MINOR 255
/dev/下的设别名字为 gmac
文件操作函数为gmac_fops
static const struct file_operations gmac_fops = {
.open = gmacdev_open,
.release = gmacdev_release,
.compat_ioctl = gmacdev_ioctl,
.unlocked_ioctl = gmacdev_ioctl,
};
gmacdev_open为设备文件打开函数
gmacdev_release为设备文件关闭函数
gmacdev_ioctl为compat_ioctl和unlocked_ioctl的ioctl
其中,两种ioctl的区别在于:
unlocked_ioctl作为替换ioctl的新调用,替换的原因在于,ioctl操作前需要执行大内核锁进行上锁,操作后进行解锁。
对于大内核锁:
大内核锁本身作为处理SMP的多核同时访问资源引起的竞争问题的锁机制,但是会导致多处理器的性能虽然在用户态是并行处理,在内核态还是单线执行,无法挖掘SMP的性能。
而且内核大部分代码是多处理器安全的,只有少数全局资源具有互斥性,所以所有处理器都可以随时进入内核态执行,关键在于需要把具有排他性的资源找出,并在访问这些资源时加以保护。
因此,大内核锁在2.6版本以后改为零散保护内核态的关键数据。
替换后,unlocked_ioctl的代码需要用自己的锁保护。此外,去掉了inode参数,可以从
filp->f_dentry->d_inode获得
compat_ioctl用于进程为32位,系统为64位时所用的ioctl。
1.4创建proc路径及文件
void higmac_proc_create(void)
{
struct proc_dir_entry *entry;
int i;
higmac_proc_root = proc_mkdir("higmac", NULL);
if (!higmac_proc_root)
return;
for (i = 0; i < ARRAY_SIZE(proc_file); i++) {
entry = create_proc_entry(proc_file[i].name, 0,
higmac_proc_root);
if (entry) {
entry->read_proc = proc_file[i].read;
entry->write_proc = proc_file[i].write;
entry->data = NULL;
} else
pr_err("Cann't create proc file:%s!\n",
proc_file[i].name);
}
}
创建路径
higmac
创建文件
static struct proc_file {
char *name;
read_proc_t *read;
write_proc_t *write;
} proc_file[] = {
{
.name = "hw_stats",
.read = hw_states_read,
}, {
.name = "hw_fwd_mac_tbl",
.read = hw_fwd_mac_tbl_read,
}, {
.name = "work_mode",
.read = work_mode_proc_read,
.write = work_mode_proc_write,
}, {
.name = "force_forwarding",
.read = fwd_proc_read,
.write = fwd_proc_write,
}, {
.name = "debug_info",
.read = debug_level_proc_read,
.write = debug_level_proc_write,
}
};
最终创建的效果为
/proc/higmac/
|---hw_stats
|---hw_fwd_mac_tbl
|---work_mode
|---force_forwarding
|---debug_level
|---skb_pools