PCI/PCIE之总线、设备枚举

先思考一个问题,系统配置PCI设备的时候,需要指明Bus Device Function Register构成的地址,但是系统如何知道主板上有多少总线,设备呢?整个系统的PCI拓扑需要系统去枚举遍历,使用的深度优先遍历算法,详见PCI的6.6.2章节。
下面以Linux内核代码分析来加深PCI配置的理解。按照参考3的描述,pci相关的初始化应该是如下顺序。
pcibus_class_init()
pci_driver_init()
pci_arch_init()
acpi_pci_init()
pci_acpi_init()
pci_legacy_init()
pcibios_assign_resources()
pci_init()
pci_proc_init()
pci_sysfs_init()

函数 作用
pcibus_class_init 就是向sys文件系统注册pci_bus class,完成后创建了/sys/class/pci_bus目录
pci_driver_init pci_driver_init向sys文件系统注册pci bus,此后创建了/sys/bus/pci 目录及文件
pci_arch_init 根据内核menuconfig配置,设置raw_pci_ops或者pci_bios_access,指定pci配置读写函数
acpi_pci_init 向sys文件系统注册acpi_pci_bus bus,设置pci_platform_pm为acpi_pci_platform_pm 电源管理相关的设置
pci_acpi_init pci acpi的一些中断函数指针设置,中断资源申请
pci_legacy_init 完成总线的枚举和设备的发现,完成PCI桥的配置等
pcibios_assign_resources
pci_proc_init proc目录下创建pci相关信息,呈现给用户态
pci_sysfs_init sys文件系统pci部分创建
static struct class pcibus_class = {
    .name       = "pci_bus",
    .dev_release    = &release_pcibus_dev,
    .dev_groups = pcibus_groups,
};

static int __init pcibus_class_init(void)
{
    return class_register(&pcibus_class);
}

pcibus_class_init就是向sys文件系统注册pci_bus class,完成后创建了/sys/class/pci_bus目录。

struct bus_type pci_bus_type = {
    .name       = "pci",
    .match      = pci_bus_match,
    .uevent     = pci_uevent,
    .probe      = pci_device_probe,
    .remove     = pci_device_remove,
    .shutdown   = pci_device_shutdown,
    .dev_groups = pci_dev_groups,
    .bus_groups = pci_bus_groups, 
    .drv_groups = pci_drv_groups,
    .pm     = PCI_PM_OPS_PTR,
};  
EXPORT_SYMBOL(pci_bus_type);

static int __init pci_driver_init(void)
{
    return bus_register(&pci_bus_type);//注册pci bus,创建/sys/bus/pci 目录及文件
}
postcore_initcall(pci_driver_init);
/**
 * bus_register - register a driver-core subsystem
 * @bus: bus to register
 *
 * Once we have that, we register the bus with the kobject
 * infrastructure, then register the children subsystems it has:
 * the devices and drivers that belong to the subsystem.
 */
int bus_register(struct bus_type *bus)
{
    int retval;
    struct subsys_private *priv;
    struct lock_class_key *key = &bus->lock_key;

    priv = kzalloc(sizeof(struct subsys_private), GFP_KERNEL);
    if (!priv)
        return -ENOMEM;

    priv->bus = bus; 
    bus->p = priv;

    BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);

    retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);
if (retval)
        goto out;

    priv->subsys.kobj.kset = bus_kset;
    priv->subsys.kobj.ktype = &bus_ktype;
    priv->drivers_autoprobe = 1;

    retval = kset_register(&priv->subsys);
    if (retval)
        goto out;

    retval = bus_create_file(bus, &bus_attr_uevent);
    if (retval)
        goto bus_uevent_fail;

    priv->devices_kset = kset_create_and_add("devices", NULL,
                         &priv->subsys.kobj);//创建/sys/bus/pci/devices
    if (!priv->devices_kset) {
        retval = -ENOMEM;
        goto bus_devices_fail;
    }

    priv->drivers_kset = kset_create_and_add("drivers", NULL,
                         &priv->subsys.kobj);//创建/sys/bus/pci/drivers
if (!priv->drivers_kset) {
        retval = -ENOMEM;
        goto bus_drivers_fail;
    }

    INIT_LIST_HEAD(&priv->interfaces);
    __mutex_init(&priv->mutex, "subsys mutex", key);
    klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);
    klist_init(&priv->klist_drivers, NULL, NULL);

    retval = add_probe_files(bus);
    if (retval)
        goto bus_probe_files_fail;

    retval = bus_add_groups(bus, bus->bus_groups);
    if (retval)
        goto bus_
  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值