pci枚举初始化部分(1)
基于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, ®16);
pdev->pcie_flags_reg = reg16;
pci_read_config_word(pdev, pos + PCI_EXP_DEVCAP, ®16);
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)的更多相关文章
- pci枚举初始化部分(2)
1.2.8判断pcie设备是否支持雷电技术 Intel具有一种基于Thunderbolt技术的PCIE变体,它结合了DisplayPort和PCIe协议,与Mini DisplayPort兼容. Th ...
- linux PCI设备初始化过程
linux PCI设备初始化过程 start_kernel->rest_init 这个函数会启动一个核心线程0, 核心线程然后调用init -> do_basic_setup. 然后我们开 ...
- 【转】PCI学习笔记
1.PCI设备编号 每一个PCI device都有其unique PFA(PCI Fcntion Address) PFA由 bus number.device number.functi ...
- 【原创】Linux PCI驱动框架分析(二)
背 景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本 ...
- Swift中如何化简标准库中冗长的类实例初始化代码
可能有些童鞋并不知道,在Swift中缩写点符号对于任何类型的任何static成员都有效. 我们实际写一个例子看一下: import UIKit class CFoo{ static let share ...
- Kotlin 枚举类
枚举类最基本的用法是实现一个类型安全的枚举. 枚举常量用逗号分隔,每个枚举常量都是一个对象. enum class Color{ RED,BLACK,BLUE,GREEN,WHITE } 枚举初始化 ...
- [知乎]老狼:深入PCI与PCIe之二:软件篇
深入PCI与PCIe之二:软件篇 https://zhuanlan.zhihu.com/p/26244141 我们前一篇文章(深入PCI与PCIe之一:硬件篇 - 知乎专栏)介绍了PCI和PCIe的硬 ...
- Swift_初始化
#Swift_初始化 点击查看源码 初始化结构体 //初始化结构体 func testInitStruct() { //结构体 类中默认方法 struct Size { //宽 var width = ...
- java编程思想第五章初始化与清理
5.1使用构造器确保初始化: 构造器与一般方法一样,但是没有返回值,且其方法名与类名完全相同. 不接受任何参数的构造器成为默认构造器,也叫无参构造器. 5.2 方法重载: 为什么会有方法重载? 构造器 ...
随机推荐
- 【java8】慎用java8的foreach循环(作废)
+警告 这篇文章作废掉,是由一个错误的测试方法得到的一个错误结论,后续修正结果正在测试,将贴上. 准确测试已完成:http://www.cnblogs.com/yiwangzhibujian/p/69 ...
- python匿名函数 高阶函数 内置函数 文件操作
1.匿名函数 匿名就是没有名字 def func(x,y,z=1): return x+y+z 匿名 lambda x,y,z=1:x+y+z #与函数有相同的作用域,但是匿名意味着引用计数为0,使用 ...
- 【日常记录】【unity3d】 获取手柄轴的输入
参考 https://blogs.msdn.microsoft.com/nathalievangelist/2014/12/16/joystick-input-in-unity-using-xbox3 ...
- Java对于表达式中的自动类型提升
1 表达式中的自动类型提升: 表达式求值时,Java自动的隐含的将每个byte.short或char操作数提升为int类型,这些类型的包装类型也是可以的. 例如: short s1 = 1; s1 = ...
- LeetCode 之Find Minimum in Rotated Sorted Array
1.题目描述 2.题目分析 对该问题,要找最小元,可以从后向前遍历,只要前一个元素大于当前元素,说明当前元素就是最小元. 3.代码 int findMin(vector<int>& ...
- Oracle EBS AR 收款API收款方法标识无效
1.确认是不是没有收款方法 methods那个表的问题2.查看收款方法那个LOV的问题3.界面录入 是否会有问题 碰到的问题是 收款日期比较早时 找不到对应的收款方法 银行账户需要重新设置
- Mac .DS_Store 隐藏文件和清理.DS_Store的方法
1.清理.DS_Store的方法 输入命令: sudo find / -name ".DS_Store" -depth -exec rm {} \; 2.设置不产生.DS_Stor ...
- 使用CoreData [3]
使用CoreData [3] 此篇幅介绍CoreData如何升级版本防止崩溃 把你之前创建的实体文件全部删除掉,把沙盒中的数据库文件删除掉,实体只保持一个,然后重新创建出实体文件. - (BOOL)a ...
- September 21st 2017 Week 38th Thursday
What fire does not destroy, it hardens. 烈火摧毁不了的东西,只会变得更坚固. The true gold can stand the test of fire, ...
- 02-urllib库的get请求方式
对于urllib中的get请求方式,可以直接传入url的连接即可访问页面,但是对于要传入关键字的话,也可以用quote进行编码再传入. 案例如下: #get请求搜索参数如何添加 import urll ...