PCI SYSFS
我们在调试时最长在PCI SYSFS目录下进行调试,这个目录是怎么生成的?
/sys/bus/pci/devices/0000:26:00.0$ lsaer_dev_correctable broken_parity_status current_link_speed dma_mask_bits iommu_group max_link_speed numa_node reset revision sriov_offset subsystem vendoraer_dev_fatal class current_link_width driver_override irq max_link_width power resource rom sriov_stride subsystem_deviceaer_dev_nonfatal config d3cold_allowed enable local_cpulist modalias remove resource0 sriov_drivers_autoprobe sriov_totalvfs subsystem_vendorari_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 生成并注册
相关宏
// linux-5.7.14/include/linux/device/bus.h#define BUS_ATTR_RW(_name) \struct bus_attribute bus_attr_##_name = __ATTR_RW(_name)#define BUS_ATTR_RO(_name) \struct bus_attribute bus_attr_##_name = __ATTR_RO(_name)#define BUS_ATTR_WO(_name) \struct bus_attribute bus_attr_##_name = __ATTR_WO(_name)// linux-5.7.14/include/linux/device.h#define DEVICE_ATTR(_name, _mode, _show, _store) \struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)#define DEVICE_ATTR_PREALLOC(_name, _mode, _show, _store) \struct device_attribute dev_attr_##_name = \__ATTR_PREALLOC(_name, _mode, _show, _store)#define DEVICE_ATTR_RW(_name) \struct device_attribute dev_attr_##_name = __ATTR_RW(_name)#define DEVICE_ATTR_RO(_name) \struct device_attribute dev_attr_##_name = __ATTR_RO(_name)#define DEVICE_ATTR_WO(_name) \struct device_attribute dev_attr_##_name = __ATTR_WO(_name)#define DEVICE_ULONG_ATTR(_name, _mode, _var) \struct dev_ext_attribute dev_attr_##_name = \{ __ATTR(_name, _mode, device_show_ulong, device_store_ulong), &(_var) }#define DEVICE_INT_ATTR(_name, _mode, _var) \struct dev_ext_attribute dev_attr_##_name = \{ __ATTR(_name, _mode, device_show_int, device_store_int), &(_var) }#define DEVICE_BOOL_ATTR(_name, _mode, _var) \struct dev_ext_attribute dev_attr_##_name = \{ __ATTR(_name, _mode, device_show_bool, device_store_bool), &(_var) }#define DEVICE_ATTR_IGNORE_LOCKDEP(_name, _mode, _show, _store) \struct device_attribute dev_attr_##_name = \__ATTR_IGNORE_LOCKDEP(_name, _mode, _show, _store)// linux-5.7.14/include/linux/sysfs.h#define __ATTR(_name, _mode, _show, _store) { \.attr = {.name = __stringify(_name), \.mode = VERIFY_OCTAL_PERMISSIONS(_mode) }, \.show = _show, \.store = _store, \}#define __ATTR_PREALLOC(_name, _mode, _show, _store) { \.attr = {.name = __stringify(_name), \.mode = SYSFS_PREALLOC | VERIFY_OCTAL_PERMISSIONS(_mode) },\.show = _show, \.store = _store, \}#define __ATTR_RO(_name) { \.attr = { .name = __stringify(_name), .mode = 0444 }, \.show = _name##_show, \}#define __ATTR_RO_MODE(_name, _mode) { \.attr = { .name = __stringify(_name), \.mode = VERIFY_OCTAL_PERMISSIONS(_mode) }, \.show = _name##_show, \}#define __ATTR_WO(_name) { \.attr = { .name = __stringify(_name), .mode = 0200 }, \.store = _name##_store, \}#define __ATTR_RW(_name) __ATTR(_name, 0644, _name##_show, _name##_store)#define __ATTR_NULL { .attr = { .name = NULL } }
// linux-5.7.14/drivers/pci/pci-driver.cstruct bus_type pci_bus_type = {.name = "pci",.......dev_groups = pci_dev_groups,.bus_groups = pci_bus_groups,.drv_groups = pci_drv_groups,.....};pci_driver_initbus_register(&pcie_port_bus_type);priv->devices_kset = kset_create_and_add("devices", NULL,&priv->subsys.kobj);kset_create_and_add("drivers", NULL,&priv->subsys.kobj);bus_add_groups(bus, bus->bus_groups);sysfs_create_groups(&bus->p->subsys.kobj, groups); // 参考bus操作接口// linux-5.7.14/drivers/pci/pci-sysfs.cpci_bus_add_devicepci_create_sysfs_dev_files(dev);sysfs_create_bin_file(&pdev->dev.kobj, &pci_config_attr); // config接口sysfs_create_bin_file(&pdev->dev.kobj, attr); // if (rom_size) ;option Rom接口
bus操作接口
rescan 重新扫描所有PCI设备
// linux-5.7.14/drivers/pci/pci-sysfs.crecan属性:WO,ssize_t rescan_store(struct bus_type *bus, const char *buf, size_t count);static BUS_ATTR_WO(rescan); ===>struct bus_attribute bus_attr_rescan = {.attr = { .rescan = __stringify(rescan), .mode = 0200 }, \.store = rescan_store,};static struct attribute *pci_bus_attrs[] = {&bus_attr_rescan.attr,NULL,};static const struct attribute_group pci_bus_group = {.attrs = pci_bus_attrs,};const struct attribute_group *pci_bus_groups[] = {&pci_bus_group,NULL,};
device接口
提供了一大波device的操作接口,太多,不一一列举。
/* show configuration fields */#define pci_config_attr(field, format_string) \static ssize_t \field##_show(struct device *dev, struct device_attribute *attr, char *buf) \{ \struct pci_dev *pdev; \\pdev = to_pci_dev(dev); \return sprintf(buf, format_string, pdev->field); \} \static DEVICE_ATTR_RO(field)pci_config_attr(vendor, "0x%04x\n"); // 一大波show接口pci_config_attr(device, "0x%04x\n");pci_config_attr(subsystem_vendor, "0x%04x\n");pci_config_attr(subsystem_device, "0x%04x\n");pci_config_attr(revision, "0x%02x\n");pci_config_attr(class, "0x%06x\n");pci_config_attr(irq, "%u\n");static DEVICE_ATTR_RW(enable); // enable接口static ssize_t enable_show(struct device *dev, struct device_attribute *attr,char *buf)static ssize_t enable_store(struct device *dev, struct device_attribute *attr,const char *buf, size_t count)static struct attribute *pci_dev_attrs[] = {&dev_attr_resource.attr,&dev_attr_vendor.attr,&dev_attr_device.attr,&dev_attr_subsystem_vendor.attr,&dev_attr_subsystem_device.attr,&dev_attr_revision.attr,&dev_attr_class.attr,&dev_attr_irq.attr,&dev_attr_local_cpus.attr,&dev_attr_local_cpulist.attr,&dev_attr_modalias.attr,#ifdef CONFIG_NUMA&dev_attr_numa_node.attr,#endif&dev_attr_dma_mask_bits.attr,&dev_attr_consistent_dma_mask_bits.attr,&dev_attr_enable.attr,&dev_attr_broken_parity_status.attr,&dev_attr_msi_bus.attr,#if defined(CONFIG_PM) && defined(CONFIG_ACPI)&dev_attr_d3cold_allowed.attr,#endif#ifdef CONFIG_OF&dev_attr_devspec.attr,#endif&dev_attr_driver_override.attr,&dev_attr_ari_enabled.attr,NULL,};static const struct attribute_group pci_dev_group = {.attrs = pci_dev_attrs,};const struct attribute_group *pci_dev_groups[] = {&pci_dev_group,NULL,};
pci_setup_device(pci设备初始化)
PCI是怎么获取配置空间大小的 ???pdev->cfg_size 在什么地方填充?
pci_scan_devicepci_setup_devicepci_setup_devicehdr_type = pci_hdr_type(dev); // 读取头部信息set_pcie_port_typepos = pci_find_capability(pdev, PCI_CAP_ID_EXP); // PCIE一定有0x10的ID配置__pci_bus_find_cap_start// 读取pci配置空间的状态位,判断是否capabilities list位是否使能pci_bus_read_config_word(bus, devfn, PCI_STATUS, &status);// 如果没使能,那配置空间也就0x00-0x3f// 如果使能,返回PCI_CAPABILITY_LIST 0x34,也就是capability指针位置__pci_find_next_cap //pci_bus_read_config_byte(bus, devfn, pos, &pos); // 读取指针,寻找next....// 开始遍历capability,寻找ID符合的。也就是PCI_CAP_ID_EXPpci_cfg_space_size // 获取配置空间大小// 桥设备暂时不考虑if (pci_is_pcie(dev)) // 根据前边获取到的信息,判断是否是pcie设备return pci_cfg_space_size_ext(dev); // 这里边就是尝试读取下0x100以后的数据,
