网络控制器驱动——海思 + switch 第一部分 驱动加载

网络子系统目录架构:
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

猜你喜欢

转载自www.cnblogs.com/pokerface/p/9079165.html