设为首页 加入收藏

TOP

pci枚举初始化部分(1)(一)
2019-09-01 23:09:26 】 浏览:60
Tags:pci 枚举 初始 部分

基于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
首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇STM32的HAL库中的DMA_FLAG_TCIF3_.. 下一篇Linux分页机制之分页机制的演变--..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目