PCI SYSFS

我们在调试时最长在PCI SYSFS目录下进行调试,这个目录是怎么生成的?

  1. /sys/bus/pci/devices/0000:26:00.0$ ls
  2. aer_dev_correctable broken_parity_status current_link_speed dma_mask_bits iommu_group max_link_speed numa_node reset revision sriov_offset subsystem vendor
  3. aer_dev_fatal class current_link_width driver_override irq max_link_width power resource rom sriov_stride subsystem_device
  4. aer_dev_nonfatal config d3cold_allowed enable local_cpulist modalias remove resource0 sriov_drivers_autoprobe sriov_totalvfs subsystem_vendor
  5. ari_enabled consistent_dma_mask_bits device iommu local_cpus msi_bus rescan resource2 sriov_numvfs sriov_vf_device uevent

/sys/bus/pci目录在 pci_driver_init 生成并注册

相关宏

  1. // linux-5.7.14/include/linux/device/bus.h
  2. #define BUS_ATTR_RW(_name) \
  3. struct bus_attribute bus_attr_##_name = __ATTR_RW(_name)
  4. #define BUS_ATTR_RO(_name) \
  5. struct bus_attribute bus_attr_##_name = __ATTR_RO(_name)
  6. #define BUS_ATTR_WO(_name) \
  7. struct bus_attribute bus_attr_##_name = __ATTR_WO(_name)
  8. // linux-5.7.14/include/linux/device.h
  9. #define DEVICE_ATTR(_name, _mode, _show, _store) \
  10. struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)
  11. #define DEVICE_ATTR_PREALLOC(_name, _mode, _show, _store) \
  12. struct device_attribute dev_attr_##_name = \
  13. __ATTR_PREALLOC(_name, _mode, _show, _store)
  14. #define DEVICE_ATTR_RW(_name) \
  15. struct device_attribute dev_attr_##_name = __ATTR_RW(_name)
  16. #define DEVICE_ATTR_RO(_name) \
  17. struct device_attribute dev_attr_##_name = __ATTR_RO(_name)
  18. #define DEVICE_ATTR_WO(_name) \
  19. struct device_attribute dev_attr_##_name = __ATTR_WO(_name)
  20. #define DEVICE_ULONG_ATTR(_name, _mode, _var) \
  21. struct dev_ext_attribute dev_attr_##_name = \
  22. { __ATTR(_name, _mode, device_show_ulong, device_store_ulong), &(_var) }
  23. #define DEVICE_INT_ATTR(_name, _mode, _var) \
  24. struct dev_ext_attribute dev_attr_##_name = \
  25. { __ATTR(_name, _mode, device_show_int, device_store_int), &(_var) }
  26. #define DEVICE_BOOL_ATTR(_name, _mode, _var) \
  27. struct dev_ext_attribute dev_attr_##_name = \
  28. { __ATTR(_name, _mode, device_show_bool, device_store_bool), &(_var) }
  29. #define DEVICE_ATTR_IGNORE_LOCKDEP(_name, _mode, _show, _store) \
  30. struct device_attribute dev_attr_##_name = \
  31. __ATTR_IGNORE_LOCKDEP(_name, _mode, _show, _store)
  32. // linux-5.7.14/include/linux/sysfs.h
  33. #define __ATTR(_name, _mode, _show, _store) { \
  34. .attr = {.name = __stringify(_name), \
  35. .mode = VERIFY_OCTAL_PERMISSIONS(_mode) }, \
  36. .show = _show, \
  37. .store = _store, \
  38. }
  39. #define __ATTR_PREALLOC(_name, _mode, _show, _store) { \
  40. .attr = {.name = __stringify(_name), \
  41. .mode = SYSFS_PREALLOC | VERIFY_OCTAL_PERMISSIONS(_mode) },\
  42. .show = _show, \
  43. .store = _store, \
  44. }
  45. #define __ATTR_RO(_name) { \
  46. .attr = { .name = __stringify(_name), .mode = 0444 }, \
  47. .show = _name##_show, \
  48. }
  49. #define __ATTR_RO_MODE(_name, _mode) { \
  50. .attr = { .name = __stringify(_name), \
  51. .mode = VERIFY_OCTAL_PERMISSIONS(_mode) }, \
  52. .show = _name##_show, \
  53. }
  54. #define __ATTR_WO(_name) { \
  55. .attr = { .name = __stringify(_name), .mode = 0200 }, \
  56. .store = _name##_store, \
  57. }
  58. #define __ATTR_RW(_name) __ATTR(_name, 0644, _name##_show, _name##_store)
  59. #define __ATTR_NULL { .attr = { .name = NULL } }
  1. // linux-5.7.14/drivers/pci/pci-driver.c
  2. struct bus_type pci_bus_type = {
  3. .name = "pci",
  4. ......
  5. .dev_groups = pci_dev_groups,
  6. .bus_groups = pci_bus_groups,
  7. .drv_groups = pci_drv_groups,
  8. .....
  9. };
  10. pci_driver_init
  11. bus_register(&pcie_port_bus_type);
  12. priv->devices_kset = kset_create_and_add("devices", NULL,
  13. &priv->subsys.kobj);
  14. kset_create_and_add("drivers", NULL,
  15. &priv->subsys.kobj);
  16. bus_add_groups(bus, bus->bus_groups);
  17. sysfs_create_groups(&bus->p->subsys.kobj, groups); // 参考bus操作接口
  18. // linux-5.7.14/drivers/pci/pci-sysfs.c
  19. pci_bus_add_device
  20. pci_create_sysfs_dev_files(dev);
  21. sysfs_create_bin_file(&pdev->dev.kobj, &pci_config_attr); // config接口
  22. sysfs_create_bin_file(&pdev->dev.kobj, attr); // if (rom_size) ;option Rom接口

bus操作接口

rescan 重新扫描所有PCI设备

  1. // linux-5.7.14/drivers/pci/pci-sysfs.c
  2. recan属性:WO,
  3. ssize_t rescan_store(struct bus_type *bus, const char *buf, size_t count);
  4. static BUS_ATTR_WO(rescan); ===>
  5. struct bus_attribute bus_attr_rescan = {
  6. .attr = { .rescan = __stringify(rescan), .mode = 0200 }, \
  7. .store = rescan_store,
  8. };
  9. static struct attribute *pci_bus_attrs[] = {
  10. &bus_attr_rescan.attr,
  11. NULL,
  12. };
  13. static const struct attribute_group pci_bus_group = {
  14. .attrs = pci_bus_attrs,
  15. };
  16. const struct attribute_group *pci_bus_groups[] = {
  17. &pci_bus_group,
  18. NULL,
  19. };

device接口

提供了一大波device的操作接口,太多,不一一列举。

  1. /* show configuration fields */
  2. #define pci_config_attr(field, format_string) \
  3. static ssize_t \
  4. field##_show(struct device *dev, struct device_attribute *attr, char *buf) \
  5. { \
  6. struct pci_dev *pdev; \
  7. \
  8. pdev = to_pci_dev(dev); \
  9. return sprintf(buf, format_string, pdev->field); \
  10. } \
  11. static DEVICE_ATTR_RO(field)
  12. pci_config_attr(vendor, "0x%04x\n"); // 一大波show接口
  13. pci_config_attr(device, "0x%04x\n");
  14. pci_config_attr(subsystem_vendor, "0x%04x\n");
  15. pci_config_attr(subsystem_device, "0x%04x\n");
  16. pci_config_attr(revision, "0x%02x\n");
  17. pci_config_attr(class, "0x%06x\n");
  18. pci_config_attr(irq, "%u\n");
  19. static DEVICE_ATTR_RW(enable); // enable接口
  20. static ssize_t enable_show(struct device *dev, struct device_attribute *attr,
  21. char *buf)
  22. static ssize_t enable_store(struct device *dev, struct device_attribute *attr,
  23. const char *buf, size_t count)
  24. static struct attribute *pci_dev_attrs[] = {
  25. &dev_attr_resource.attr,
  26. &dev_attr_vendor.attr,
  27. &dev_attr_device.attr,
  28. &dev_attr_subsystem_vendor.attr,
  29. &dev_attr_subsystem_device.attr,
  30. &dev_attr_revision.attr,
  31. &dev_attr_class.attr,
  32. &dev_attr_irq.attr,
  33. &dev_attr_local_cpus.attr,
  34. &dev_attr_local_cpulist.attr,
  35. &dev_attr_modalias.attr,
  36. #ifdef CONFIG_NUMA
  37. &dev_attr_numa_node.attr,
  38. #endif
  39. &dev_attr_dma_mask_bits.attr,
  40. &dev_attr_consistent_dma_mask_bits.attr,
  41. &dev_attr_enable.attr,
  42. &dev_attr_broken_parity_status.attr,
  43. &dev_attr_msi_bus.attr,
  44. #if defined(CONFIG_PM) && defined(CONFIG_ACPI)
  45. &dev_attr_d3cold_allowed.attr,
  46. #endif
  47. #ifdef CONFIG_OF
  48. &dev_attr_devspec.attr,
  49. #endif
  50. &dev_attr_driver_override.attr,
  51. &dev_attr_ari_enabled.attr,
  52. NULL,
  53. };
  54. static const struct attribute_group pci_dev_group = {
  55. .attrs = pci_dev_attrs,
  56. };
  57. const struct attribute_group *pci_dev_groups[] = {
  58. &pci_dev_group,
  59. NULL,
  60. };

pci_setup_device(pci设备初始化)

PCI是怎么获取配置空间大小的 ???pdev->cfg_size 在什么地方填充?

  1. pci_scan_device
  2. pci_setup_device
  3. pci_setup_device
  4. hdr_type = pci_hdr_type(dev); // 读取头部信息
  5. set_pcie_port_type
  6. pos = pci_find_capability(pdev, PCI_CAP_ID_EXP); // PCIE一定有0x10的ID配置
  7. __pci_bus_find_cap_start
  8. // 读取pci配置空间的状态位,判断是否capabilities list位是否使能
  9. pci_bus_read_config_word(bus, devfn, PCI_STATUS, &status);
  10. // 如果没使能,那配置空间也就0x00-0x3f
  11. // 如果使能,返回PCI_CAPABILITY_LIST 0x34,也就是capability指针位置
  12. __pci_find_next_cap //
  13. pci_bus_read_config_byte(bus, devfn, pos, &pos); // 读取指针,寻找next
  14. ....// 开始遍历capability,寻找ID符合的。也就是PCI_CAP_ID_EXP
  15. pci_cfg_space_size // 获取配置空间大小
  16. // 桥设备暂时不考虑
  17. if (pci_is_pcie(dev)) // 根据前边获取到的信息,判断是否是pcie设备
  18. return pci_cfg_space_size_ext(dev); // 这里边就是尝试读取下0x100以后的数据,