基于linux-4.20-rc3源码分析

1 .扫描所有PCI设备并检测,填充设备结构体

static struct pci_dev *pci_scan_device(struct pci_bus *bus, int devfn)
{
struct pci_dev *dev;
u32 l; //查询PCI设备厂商号和设备号,以判断设备是否发生异常
if (!pci_bus_read_dev_vendor_id(bus, devfn, &l, 60*1000))
return NULL; //分配设备结构体
dev = pci_alloc_dev(bus);
if (!dev)
return NULL; dev->devfn = devfn;
dev->vendor = l & 0xffff; //获取厂商号
dev->device = (l >> 16) & 0xffff; //获取设备号 //设置链表节点
pci_set_of_node(dev); //扫描所有设备并设置,和获取信息
if (pci_setup_device(dev)) {
pci_bus_put(dev->bus);
kfree(dev);
return NULL;
} return dev;
}

其中pci_setup_device(dev)函数对挂载在该总线上所有的设备进行检测并获取相关数据,并设备信息进行填充。对于有些需特殊处理的设备也进行了特殊处理,达到尽量兼容新老设备的目的。

1.1查询设备厂商号和设备号

pci_bus_read_dev_vendor_id()

#ifdef CONFIG_PCI_QUIRKS
struct pci_dev *bridge = bus->self; /*
* Certain IDT switches have an issue where they improperly trigger
* ACS Source Validation errors on completions for config reads.
*/
//某些IDT交换机有一个问题,即它们在完成配置读取时错误地触发ACS源验证错误。
if (bridge && bridge->vendor == PCI_VENDOR_ID_IDT &&
bridge->device == 0x80b5)
return pci_idt_bus_quirk(bus, devfn, l, timeout);
#endif return pci_bus_generic_read_dev_vendor_id(bus, devfn, l, timeout);

该函数主要读取PCI设备的厂商号和设备号,如果读取出来包含全0,全1之类数据,这判断为PCI设备异常不再进行下一步操作。

对于某些IDT交换机设备,可能存在在读取设备信息时触发ACS验证错误,此时需要进行特殊操作,如果代码允许在IDT交换机上请一定配置PCI_QUIRKS选项。

ACS:安全接入控制器,接入服务器(Access Server)又称网络接入服务器NAS或远程接入服务器RAS,它是位于公用电话网(PSTN/ISDN)与IP网之间的一种远程访问接入设备。

  • pci_bus_generic_read_dev_vendor_id()

    该函数用于获取设备厂商号,并对错误的状态进行识别,对需重试获取的设备进行重试获取信息,并通过超时加以限制。
 if (pci_bus_read_config_dword(bus, devfn, PCI_VENDOR_ID, l))
return false; /* Some broken boards return 0 or ~0 if a slot is empty: */
//如果槽为空时会返回0或者~0
if (*l == 0xffffffff || *l == 0x00000000 ||
*l == 0x0000ffff || *l == 0xffff0000)
return false; //具有配置重试机制的设备进行重试读取厂商号
if (pci_bus_crs_vendor_id(*l))
return pci_bus_wait_crs(bus, devfn, l, timeout); return true;

1.2获取设备信息并设置

1.2.1获取设备头信息

pci_hdr_type()

 pci_read_config_byte(dev, PCI_HEADER_TYPE, &hdr_type);

1.2.2 判断是否为pcie设备

//判断是否为pcie设备
pos = pci_find_capability(pdev, PCI_CAP_ID_EXP);
if (!pos)
return; pdev->pcie_cap = pos;
pci_read_config_word(pdev, pos + PCI_EXP_FLAGS, &reg16);
pdev->pcie_flags_reg = reg16;
pci_read_config_word(pdev, pos + PCI_EXP_DEVCAP, &reg16);
pdev->pcie_mpss = reg16 & PCI_EXP_DEVCAP_PAYLOAD;

通过state寄存器获取capability的有效性,并通过capability首地址顺势查找是否有PCIE capatility结构体存在,从而判断该设备是否时pcie设备

1.2.2.1 查找设备的capability,判断其是否为pcie设备

pci_find_capability()

//判断capability有效性,有效则获取capability表起始地址
pos = __pci_bus_find_cap_start(dev->bus, dev->devfn, dev->hdr_type); //获取ID为cap的capability的偏移
if (pos)
pos = __pci_find_next_cap(dev->bus, dev->devfn, pos, cap);
  • __pci_bus_find_cap_start()
 //判断capabilityPointer寄存器中的值是否有效
pci_bus_read_config_word(bus, devfn, PCI_STATUS, &status);
if (!(status & PCI_STATUS_CAP_LIST))
return 0; switch (hdr_type) {
case PCI_HEADER_TYPE_NORMAL:
case PCI_HEADER_TYPE_BRIDGE:
return PCI_CAPABILITY_LIST; //普通设备偏移
case PCI_HEADER_TYPE_CARDBUS:
return PCI_CB_CAPABILITY_LIST; //桥设备偏移
}
  • __pci_find_next_cap()
//pos为capatibility结构首地址
pci_bus_read_config_byte(bus, devfn, pos, &pos); //目前ttl = PCI_FIND_CAP_TTL = 48;
while ((*ttl)--) {
if (pos < 0x40)
break;
pos &= ~3;
pci_bus_read_config_word(bus, devfn, pos, &ent); id = ent & 0xff;
if (id == 0xff)
break;
if (id == cap) //获取ID为PCI_CAP_ID_EXP的capatility结构体偏移
return pos;
pos = (ent >> 8);
}

1.2.3 添加槽结构体到链表

pci_dev_assign_slot()

 struct pci_slot *slot;

 mutex_lock(&pci_slot_mutex);
list_for_each_entry(slot, &dev->bus->slots, list)
if (PCI_SLOT(dev->devfn) == slot->number)
dev->slot = slot;
mutex_unlock(&pci_slot_mutex);

1.2.4设置驱动名称

 dev_set_name(&dev->dev, "%04x:%02x:%02x.%d", pci_domain_nr(dev->bus),
dev->bus->number, PCI_SLOT(dev->devfn),
PCI_FUNC(dev->devfn));

1.2.5获取设备类别等信息

//获取设备类别
class = pci_class(dev); //读取PCI空间偏移0x8处数据。 dev->revision = class & 0xff; //版本号
dev->class = class >> 8; /* upper 3 bytes */ //设备类型

1.2.6 boot阶段打印PCI信息

if (pci_early_dump)

early_dump_pci_device(dev);

boot阶段用于打印pci设备所有配置空间信息

1.2.7 获取pci配置空间大小

pci_cfg_space_size()

通过判断设备类型从而获取配置空间大小。

pci和pxi模式1的设备的配置空间大小为256byte,PXI模式2和pcie设备的配置空间大小为4096byte

pci枚举初始化部分(1)的更多相关文章

  1. pci枚举初始化部分(2)

    1.2.8判断pcie设备是否支持雷电技术 Intel具有一种基于Thunderbolt技术的PCIE变体,它结合了DisplayPort和PCIe协议,与Mini DisplayPort兼容. Th ...

  2. linux PCI设备初始化过程

    linux PCI设备初始化过程 start_kernel->rest_init 这个函数会启动一个核心线程0, 核心线程然后调用init -> do_basic_setup. 然后我们开 ...

  3. 【转】PCI学习笔记

    1.PCI设备编号    每一个PCI device都有其unique PFA(PCI Fcntion Address)    PFA由 bus number.device number.functi ...

  4. 【原创】Linux PCI驱动框架分析(二)

    背 景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本 ...

  5. Swift中如何化简标准库中冗长的类实例初始化代码

    可能有些童鞋并不知道,在Swift中缩写点符号对于任何类型的任何static成员都有效. 我们实际写一个例子看一下: import UIKit class CFoo{ static let share ...

  6. Kotlin 枚举类

    枚举类最基本的用法是实现一个类型安全的枚举. 枚举常量用逗号分隔,每个枚举常量都是一个对象. enum class Color{ RED,BLACK,BLUE,GREEN,WHITE } 枚举初始化 ...

  7. [知乎]老狼:深入PCI与PCIe之二:软件篇

    深入PCI与PCIe之二:软件篇 https://zhuanlan.zhihu.com/p/26244141 我们前一篇文章(深入PCI与PCIe之一:硬件篇 - 知乎专栏)介绍了PCI和PCIe的硬 ...

  8. Swift_初始化

    #Swift_初始化 点击查看源码 初始化结构体 //初始化结构体 func testInitStruct() { //结构体 类中默认方法 struct Size { //宽 var width = ...

  9. java编程思想第五章初始化与清理

    5.1使用构造器确保初始化: 构造器与一般方法一样,但是没有返回值,且其方法名与类名完全相同. 不接受任何参数的构造器成为默认构造器,也叫无参构造器. 5.2 方法重载: 为什么会有方法重载? 构造器 ...

随机推荐

  1. vmware centos 安装

    一.分区 一块硬盘主分区+扩展分区最多只能有4个,其中扩展分区最多只能有1个.扩展分区不能写入数据,只能包含逻辑分区.这些都不是linux的限制,而是硬盘结构的限制. 分区号 第一种分区法: |--- ...

  2. web 应用响应乱码问题

    非西欧语系乱码原因 在没有设置任何内容类型或编码之前,HttpServletResponse使用的字符编码默认是ISO-8859-1.也就是说,如果直接输出中文,在浏览器上就会看到乱码. 有两种方式可 ...

  3. TestNG 判断文件下载成功

    用WatchService写一个方法放在onTestStart()方法里监听文件夹的变化. 但是判断下载成功还需要写一个方法, 用来判断什么时候文件从.xlsx.rcdownload改成.xlsx才行 ...

  4. hdfs操作手册

    hdfscli 命令行 # hdfscli --help HdfsCLI: a command line interface for HDFS. Usage: hdfscli [interactive ...

  5. [翻译] NMBottomTabBarController

    NMBottomTabBarController A customisable tab bar controller for iOS written in Objective C. It uses a ...

  6. umount nfs文件系统 显示 umount.nfs: device is busy

    网上的方法一般都是 fuser -m  /nfs 查出进程号,然后杀死进程号,或者fuser -km /nfs直接杀死,我试了下都不行 解决方法: 对于nfs文件系统来说,umount -l /nfs ...

  7. The Master of Science degree in Computer Scienc

    Computer Science MS Degree MS Degree or Depth       45.00 Hours Required   http://scpd.stanford.edu/ ...

  8. 清除右键菜单CMD入口

    批处理代码 reg add "HKEY_CLASSES_ROOT\Directory\Background\shell\cmd" /v Extended /t REG_SZ

  9. asp.net Core 使用过滤器判断请求客户端是否为移动端,并实现PC端和移动端请求映射和自动跳转

    很多时候我们做网站时单纯的用bootstrap等前端框架实现的前端自适应带给用户的体验并不太好,所以为了提高用户体验会专门针对PC端网页重新设计一套移动端网页,但是怎么才能做到在移动端访问PC页面的时 ...

  10. 线性规划 Matlab

    线性规划的 Matlab 解法 形式 s.t.( subject to) c和 x为n 维列向量, A. Aeq 为适当维数的矩阵,b .beq为适当维数的列向 量. 函数: linprog(c,A, ...