pci设备的初始化

    xiaoxiao2021-12-14  19

    pci设备的初始化

    这里讨论系统上电时的情况, 热插拔的情况应该差不多. 首先是从根总线开始, 然后就是扫描这个根总线上的每一条子BUS, 如下: unsigned int pci_scan_child_bus(struct pci_bus *bus) {     unsigned int devfn, pass, max = bus->secondary;     struct pci_dev *dev;     pr_debug("PCI: Scanning bus x:x\n", pci_domain_nr(bus), bus->number);         这里循环256(0x100)/8 = 32次的意思是, 每个总线可能有32个设备,     而每个设备可能是多功能的, 且最多有8个功能.     for (devfn = 0; devfn < 0x100; devfn += 8)         pci_scan_slot(bus, devfn);     //下面在递归扫描PCI桥,不是我们要关心的.         pr_debug("PCI: Fixups for bus x:x\n", pci_domain_nr(bus), bus->number);     pcibios_fixup_bus(bus);     for (pass=0; pass < 2; pass++)         list_for_each_entry(dev, &bus->devices, bus_list) {             if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||                 dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)                 max = pci_scan_bridge(bus, dev, max, pass);         }         pr_debug("PCI: Bus scan for x:x returning with max=x\n",         pci_domain_nr(bus), bus->number, max);     return max; } int pci_scan_slot(struct pci_bus *bus, int devfn) {     int func, nr = 0;     int scan_all_fns;     //空函数     scan_all_fns = pcibios_scan_all_fns(bus, devfn);     //每个设备可能有8个功能     for (func = 0; func < 8; func++, devfn++) {         struct pci_dev *dev;         //分配并初始化找到的设备         dev = pci_scan_single_device(bus, devfn);         if (dev) {             nr++;                         if (!dev->multifunction) {                 if (func > 0) {                     dev->multifunction = 1;                 } else {                      break;                 }             }         } else {             if (func == 0 && !scan_all_fns)                 break;         }     }     return nr; } struct pci_dev *pci_scan_single_device(struct pci_bus *bus, int devfn) {     struct pci_dev *dev;     //扫描设备, 如果存在, 分配一个结构,     //并读取这个设备的寄存器信息将其初始化     dev = pci_scan_device(bus, devfn);     if (!dev)         return NULL;     //将设备加入的bus总线     pci_device_add(dev, bus);     return dev; } 这个函数的功能上面的注释已经说明白了 static struct pci_dev * __devinit pci_scan_device(struct pci_bus *bus, int devfn) {     struct pci_dev *dev;     u32 l;     u8 hdr_type;     int delay = 1;     //两个检查     if (pci_bus_read_config_dword(bus, devfn, PCI_VENDOR_ID, &l))         return NULL;         if (l == 0xffffffff || l == 0x00000000 ||         l == 0x0000ffff || l == 0xffff0000)         return NULL;         while (l == 0xffff0001) {         msleep(delay);         delay *= 2;         if (pci_bus_read_config_dword(bus, devfn, PCI_VENDOR_ID, &l))             return NULL;                 if (delay > 60 * 1000) {             printk(KERN_WARNING "Device x:x:x.%d not "                     "responding\n", pci_domain_nr(bus),                     bus->number, PCI_SLOT(devfn),                     PCI_FUNC(devfn));             return NULL;         }     }     //读PCI类型信息, PCI_HEADER_TYPE是在这个寄存器中的偏移值     //可能的类型信息如下: #define PCI_HEADER_TYPE        0x0e    #define PCI_HEADER_TYPE_NORMAL        0 #define PCI_HEADER_TYPE_BRIDGE        1 #define PCI_HEADER_TYPE_CARDBUS    2     if (pci_bus_read_config_byte(bus, devfn, PCI_HEADER_TYPE, &hdr_type))         return NULL;     //如果上面的成功了, 则为设备分配一个pci_dev结构,     //我们在写驱动的时候看到, 在调用probe函数是, 参数传入的就是这里得到的结构.     //这个结构在这个函数里面已经初始化好了.     dev = alloc_pci_dev();     if (!dev)         return NULL;     //初步初始化一些域     dev->bus = bus;     dev->sysdata = bus->sysdata;     dev->dev.parent = bus->bridge;     dev->dev.bus = &pci_bus_type;     dev->devfn = devfn;     dev->hdr_type = hdr_type & 0x7f;     dev->multifunction = !!(hdr_type & 0x80);     dev->vendor = l & 0xffff;     dev->device = (l >> 16) & 0xffff;     dev->cfg_size = pci_cfg_space_size(dev); // 用于PCI-X     dev->error_state = pci_channel_io_normal;         dev->dma_mask = 0xffffffff; //32为DMA     //进一步初始化, 数据来自于寄存器     if (pci_setup_device(dev) < 0) {         kfree(dev);         return NULL;     }     return dev; } //分配一个结构并初始化两个队列 struct pci_dev *alloc_pci_dev(void) {     struct pci_dev *dev;     dev = kzalloc(sizeof(struct pci_dev), GFP_KERNEL);     if (!dev)         return NULL;     INIT_LIST_HEAD(&dev->global_list);     INIT_LIST_HEAD(&dev->bus_list);     pci_msi_init_pci_dev(dev);     return dev; } struct bus_type pci_bus_type = {     .name        = "pci",     .match        = pci_bus_match,     .uevent        = pci_uevent,     .probe        = pci_device_probe,     .remove        = pci_device_remove,     .suspend    = pci_device_suspend,     .suspend_late    = pci_device_suspend_late,     .resume_early    = pci_device_resume_early,     .resume        = pci_device_resume,     .shutdown    = pci_device_shutdown,     .dev_attrs    = pci_dev_attrs, }; 这个函数比较简单, 可以看注释,就不说了 static int pci_setup_device(struct pci_dev * dev) {     u32 class;     sprintf(pci_name(dev), "x:x:x.%d", pci_domain_nr(dev->bus),         dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));     pci_read_config_dword(dev, PCI_CLASS_REVISION, &class);     class >>= 8;                        dev->class = class;     class >>= 8;     pr_debug("PCI: Found %s [x/x] x x\n", pci_name(dev),         dev->vendor, dev->device, class, dev->hdr_type);         dev->current_state = PCI_UNKNOWN;         pci_fixup_device(pci_fixup_early, dev);     class = dev->class >> 8;     switch (dev->hdr_type) {                case PCI_HEADER_TYPE_NORMAL:                    if (class == PCI_CLASS_BRIDGE_PCI)             goto bad;         pci_read_irq(dev);         pci_read_bases(dev, 6, PCI_ROM_ADDRESS);         pci_read_config_word(dev, PCI_SUBSYSTEM_VENDOR_ID, &dev->subsystem_vendor);         pci_read_config_word(dev, PCI_SUBSYSTEM_ID, &dev->subsystem_device);                 if (class == PCI_CLASS_STORAGE_IDE) {             u8 progif;             pci_read_config_byte(dev, PCI_CLASS_PROG, &progif);             if ((progif & 1) == 0) {                 dev->resource[0].start = 0x1F0;                 dev->resource[0].end = 0x1F7;                 dev->resource[0].flags = LEGACY_IO_RESOURCE;                 dev->resource[1].start = 0x3F6;                 dev->resource[1].end = 0x3F6;                 dev->resource[1].flags = LEGACY_IO_RESOURCE;             }             if ((progif & 4) == 0) {                 dev->resource[2].start = 0x170;                 dev->resource[2].end = 0x177;                 dev->resource[2].flags = LEGACY_IO_RESOURCE;                 dev->resource[3].start = 0x376;                 dev->resource[3].end = 0x376;                 dev->resource[3].flags = LEGACY_IO_RESOURCE;             }         }         break;     case PCI_HEADER_TYPE_BRIDGE:                    if (class != PCI_CLASS_BRIDGE_PCI)             goto bad;                 pci_read_irq(dev);         dev->transparent = ((dev->class & 0xff) == 1);         pci_read_bases(dev, 2, PCI_ROM_ADDRESS1);         break;     case PCI_HEADER_TYPE_CARDBUS:                    if (class != PCI_CLASS_BRIDGE_CARDBUS)             goto bad;         pci_read_irq(dev);         pci_read_bases(dev, 1, 0);         pci_read_config_word(dev, PCI_CB_SUBSYSTEM_VENDOR_ID, &dev->subsystem_vendor);         pci_read_config_word(dev, PCI_CB_SUBSYSTEM_ID, &dev->subsystem_device);         break;     default:                            printk(KERN_ERR "PCI: device %s has unknown header type x, ignoring.\n",             pci_name(dev), dev->hdr_type);         return -1;     bad:         printk(KERN_ERR "PCI: %s: class %x doesn't match header type x. Ignoring class.\n",                pci_name(dev), class, dev->hdr_type);         dev->class = PCI_CLASS_NOT_DEFINED;     }         return 0; } 设备初始化完成后, 我们就回到了pci_scan_single_device()这个函数, 下一步就是将这个分配好的设备加入的bus队列中去了. void pci_device_add(struct pci_dev *dev, struct pci_bus *bus) {     device_initialize(&dev->dev);     dev->dev.release = pci_release_dev;     pci_dev_get(dev);     set_dev_node(&dev->dev, pcibus_to_node(bus));     dev->dev.dma_mask = &dev->dma_mask;     dev->dev.coherent_dma_mask = 0xffffffffull;         pci_fixup_device(pci_fixup_header, dev);         INIT_LIST_HEAD(&dev->global_list);     down_write(&pci_bus_sem);     list_add_tail(&dev->bus_list, &bus->devices); //加入到bus的device队列     up_write(&pci_bus_sem); } void device_initialize(struct device *dev) {     //属于devices_subsys子系统     kobj_set_kset_s(dev, devices_subsys);     //以下是初始化一下队列, 如等待队列     kobject_init(&dev->kobj);     klist_init(&dev->klist_children, klist_children_get,            klist_children_put);     INIT_LIST_HEAD(&dev->dma_pools);     INIT_LIST_HEAD(&dev->node);     init_MUTEX(&dev->sem);     spin_lock_init(&dev->devres_lock);     INIT_LIST_HEAD(&dev->devres_head);     device_init_wakeup(dev, 0);     set_dev_node(dev, -1); }

    转载请注明原文地址: https://ju.6miu.com/read-964578.html

    最新回复(0)