《Linux那些事儿之我是PCI》笔记

内核版本:2.6.22

1. PCI access mode: BIOS, direct, mmconfig, any。
    BIOS mode:有的BIOS程序提供了针对PCI总线的操作,这些操作包括总线枚举,此种BIOS称为PCI BIOS;此种方式直接使用BIOS程序枚举的结果。(64位平台没有该选项) 。
    Direct mode: 内核进行PCI总线枚举过程。
    MMConfig: PCIE才用的上,PCI用不上。
    ANY: 首先尝试MMConfig、然后Direct、都失败后再尝试BIOS。

2. PCI设备配置寄存器的内容是谁写入的?
    总线枚举。
    芯片组:
        北桥+南桥。
        北桥中包含host bridge, 即RC(root complex)。
    部分信息(如vendor id、device id)固化在设备中;其他信息在总线枚举阶段,有内核酌情设置。

3. 中断
    过程:设备产生中断信号(电信号)->中断控制器->CPU->内核->中断处理程序(事先注册,与指定中断关联)。
    PIC: 只能用于一个处理器的系统;每个PIC提供8个中断线。
    APIC:
        能够处理CPU之间的中断。
        中断线数量增多至255。
        Local APIC + IO APIC。
        可通过/proc/interrupts查看系统有没有使用IO APIC。
    MSI:
        往预定义的内存地址写入预定义的消息来提出中断请求。
        PCI设备->TLP消息-> Host Bridge -> CPU-> 内核->中断处理程序。
        依赖于CONFIG_X86_LOCAL_APIC。

4. kconfig语法:Documentation/kbuild/kconfig-language.txt。

5. 源码:
    drivers/pci/Makefile; arch/x86/pci/Makefile。
    include/linux/init.h (page 902): 各个入口宏的定义。将不同的函数指针存放在.initcall.init的指定子节中。

6. 参数类型:
    内核参数和模块参数:
        内核参数说明:Documentation/kernel-parameters.txt。
        查看模块参数:modinfo -p 模块名。
    内核函数parse_args(): 参数解析。
        内核启动时调用一次,解析内核参数。
        模块加载时调用,解析模块参数。
    early_param宏声明特权参数;module_param宏声明普通参数。
    参数解析完之后,会调用xxx_initcall()入口函数。

7. 内核参数解析
    drivers/pci/pci.c: pci_setup()函数解析内核参数中PCI相关的参数。
        arch/x86/pci/common.c: pcibios_setup()。
    off: 不进行PCI总线枚举。
    bfsort和nobfsort:广度优先和深度优先。
    bios: 使用PCI BIOS的枚举结果;建议在make menuconfig时PCI access mode选项使用any,由内核判断使用哪种方式。
    nobios: 不使用PCI BIOS的枚举结果。
    biosirq: 告诉内核通过PCI BIOS获取中断路由表。仅用于PIC,APIC不适用。
    pirqaddr: 默认情况下,内核可以在0xf0000~0xfffff这段地址查找中断路由表。而pirqaddr告诉内核中断路由表的确切地址。
    nommconfig: 告诉内核不要使用MMConfig方式访问设备;
    noacpi: 禁止使用ACPI处理PCI总线枚举和PCI设备的中断路由。
    noearly: 在内核启动过程的开始阶段,禁用对PCI设备的早期扫描(使用type1方式尝试访问每个可能存在的PCI设备的配置空间)。
    assign-busses: 内核将无视PCI BIOS分配的总线号,自己重新分配;枚举包括总线号分配和其他地址空间的分配。此处仅指总线号重新分配。
    routeirq: 内核为PCI设备分配中断路由。PCI驱动可能漏调用pci_enable_device()。
        pci_enable_device(): 驱动程序访问PCI设备的任何资源前都要先调用pci_enable_device(),为设备完成中断路由,也就是分配中断请求线等工作。
    realloc: 作用?看看代码。
    
8. 初始化(一)
    1. 初始化函数执行顺序的判断依据
        入口函数:init/main.c: do_initcalls()。
        依次执行.initcall.init节中的函数指针。
        .initcall.init节中有7个子节,优先执行.initcall1.init子节中的函数指针。
        相同子节中的函数指针的执行顺序,根据Makefile中各个c文件的链接顺序确定。
    2. 初始化流程
        在driver/pci/和arch/x86/pci/目录下找出所有用xxx_initcall()声明的初始化函数,然后按照顺序执行。
        .initcall2.init:
            pcibus_class_init():
                源文件:driver/pci/probe.c。
                设备模型;注册一个名称pci_bus的struct class。
                体现在sysfs上,是在/sys/class/目录下创建了一个pci_bus目录;用来存储各个pci总线。
            pci_driver_init():
                源文件:driver/pci/pci-driver.c。
                注册pci总线(struct bus_type类型的结构);只有总线存在了,才会有设备链表和驱动链表,才会有设备和驱动的match。

9. 初始化(二)
    .initcall3.init:
        不同目录下的两个文件,哪个文件先链接:
            位于同一子目录下,被同一Makefile编译的两个文件,可以很方便的分辨出哪个文件是先链接的。
            而位于两个目录下被两个Makefile编译的两个文件,需要分辨哪个Makefile首先被上级Makefile调用。
            内核构建顺序:根Makefile -> arch/*/Makefile -> driver/等其他子目录Makefile。
        pci_access_init():
            源文件:arch/i386/pci/init.c。
            根据make menucofig时"PCI access mode"的配置,进行初始化。
            Linux内核大量使用GNU C扩展,以至于GNU C成为能够编译内核的唯一编译器。
                GNU C扩展:代码优化、目标代码布局、安全检查等。
            pci_direct_probe():
                源文件:arch/i386/pci/direct.c。
                direct方式分为conf1和conf2,conf2主要为兼容老主板。
                struct resource:
                    源文件:include/linux/ioport.h。
                    作用: 描述IO资源(IO端口或IO内存)。
                    flags字段:描述资源的种类和属性。
                        IORESOURCE_IO     对应/proc/ioports
                        IORESOURCE_MEM    对应/proc/iomem
                        IORESOURCE_IRQ    对应/proc/interrupt
                        IORESOURCE_DMA    对应/proc/dma
                    申请IO资源:
                        申请IO端口:request_region()。
                        申请IO内存request_mem_region()。
                    地址种类:
                        用户虚拟地址:用户空间进程使用的地址。
                        物理地址:cpu和内存简的地址。
                        总线地址:主桥和设备简的地址。
                        内核逻辑地址:在多多数体系结构中,与物理地址仅差一个固定的偏移量。
                        内核虚拟地址。
                    为设备申请的IO资源,得到的是总线地址,需要通过ioremap映射后,通过专用API访问。
                    include/linux/pci_regs.h:定义了PCI配置空间寄存器偏移量的宏。
                pci_check_type1()
                    首先写0x0cf8地址,然后读;如果读写内容一致,则0x0cf8可能是主桥的地址端口。
                    pci_sanify_check(struct pci_raw_ops *o)
                        struct pci_raw_ops
                            源文件:include/linux/pci.h。
                            作用:包含指定BDF指定寄存器的读写API。
                            PCI设备的访问方式有BIOS、Direct的conf1和conf2、MMConfig,均对应一个struct pci_raw_ops结构的全局变量。
                        for循环中根据CLASS_ID和DENDOR_ID的值判断主桥是否存在。
                        DMI: Desktop Management Interface
                            SMBIOS: System Management BIOS,是主板厂商显示序列号、电池型号、网卡型号等系统管理信息时所必须遵守的规范。
                            DMI是用来访问和收集这些信息的接口。
                            DMI信息存储在BIOS ROM的一段数据区里,启动时,由BIOS拷贝至内存
                            dmidecode:显示dmi信息。
        acpi_pci_init():
            源文件:driver/pci/pci_acpi.c。

            
   

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值