Chinaunix首页 | 论坛 | 博客
  • 博客访问: 502129
  • 博文数量: 157
  • 博客积分: 3010
  • 博客等级: 中校
  • 技术积分: 1608
  • 用 户 组: 普通用户
  • 注册时间: 2008-08-16 09:30
文章存档

2010年(155)

2008年(2)

我的朋友

分类: LINUX

2010-03-12 19:37:16

这里讨论系统上电时的情况, 热插拔的情况应该差不多.

首先是从根总线开始, 然后就是扫描这个根总线上的每一条子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 %04x:%02x\n", pci_domain_nr(bus), bus->number);

    /* Go find them, Rover! */
    这里循环256(0x100)/8 = 32次的意思是, 每个总线可能有32个设备,
    而每个设备可能是多功能的, 且最多有8个功能.
    for (devfn = 0; devfn < 0x100; devfn += 8)
        pci_scan_slot(bus, devfn);

    //下面在递归扫描PCI桥,不是我们要关心的.
    /*
    * After performing arch-dependent fixup of the bus, look behind
    * all PCI-to-PCI bridges on this bus.
    */
    pr_debug("PCI: Fixups for bus %04x:%02x\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);
        }

    /*
    * We've scanned the bus and so we know all about what's on
    * the other side of any bridges that may be on this bus plus
    * any devices.
    *
    * Return how far we've got finding sub-buses.
    */
    pr_debug("PCI: Bus scan for %04x:%02x returning with max=%02x\n",
        pci_domain_nr(bus), bus->number, max);
    return max;
}



/**
* pci_scan_slot - scan a PCI slot on a bus for devices.
* @bus: PCI bus to scan
* @devfn: slot number to scan (must have zero function.)
*
* Scan a PCI slot on the specified PCI bus for devices, adding
* discovered devices to the @bus->devices list. New devices
* will have an empty dev->global_list head.
*/
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 this is a single function device,
             * don't scan past the first function.
             */
            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;
}



/*
* Read the config data for a PCI device, sanity-check it
* and fill in the dev structure...
*/

这个函数的功能上面的注释已经说明白了
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;

    /* some broken boards return 0 or ~0 if a slot is empty: */
    if (l == 0xffffffff || l == 0x00000000 ||
        l == 0x0000ffff || l == 0xffff0000)
        return NULL;



    /* Configuration request Retry Status */
    while (l == 0xffff0001) {
        msleep(delay);
        delay *= 2;
        if (pci_bus_read_config_dword(bus, devfn, PCI_VENDOR_ID, &l))
            return NULL;
        /* Card hasn't responded in 60 seconds? Must be stuck. */
        if (delay > 60 * 1000) {
            printk(KERN_WARNING "Device %04x:%02x:%02x.%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    /* 8 bits */
#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;

    /* Assume 32-bit PCI; let 64-bit PCI cards (which are far rarer)
       set this higher, assuming the system even supports it. */
    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,
};




/**
* pci_setup_device - fill in class and map information of a device
* @dev: the device structure to fill
*
* Initialize the device structure with information about the device's
* vendor,class,memory and IO-space addresses,IRQ lines etc.
* Called at initialisation of the PCI subsystem and by CardBus services.
* Returns 0 on success and -1 if unknown type of device (not normal, bridge
* or CardBus).
*/

这个函数比较简单, 可以看注释,就不说了

static int pci_setup_device(struct pci_dev * dev)
{
    u32 class;

    sprintf(pci_name(dev), "%04x:%02x:%02x.%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;                    /* upper 3 bytes */
    dev->class = class;
    class >>= 8;

    pr_debug("PCI: Found %s [%04x/%04x] %06x %02x\n", pci_name(dev),
        dev->vendor, dev->device, class, dev->hdr_type);

    /* "Unknown power state" */
    dev->current_state = PCI_UNKNOWN;

    /* Early fixups, before probing the BARs */
    pci_fixup_device(pci_fixup_early, dev);
    class = dev->class >> 8;

    switch (dev->hdr_type) {            /* header type */
    case PCI_HEADER_TYPE_NORMAL:            /* standard header */
        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);

        /*
        *    Do the ugly legacy mode stuff here rather than broken chip
        *    quirk code. Legacy mode ATA controllers have fixed
        *    addresses. These are not always echoed in BAR0-3, and
        *    BAR0-3 in a few cases contain junk!
        */
        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:            /* bridge header */
        if (class != PCI_CLASS_BRIDGE_PCI)
            goto bad;
        /* The PCI-to-PCI bridge spec requires that subtractive
           decoding (i.e. transparent) bridge must have programming
           interface code of 0x01. */
        pci_read_irq(dev);
        dev->transparent = ((dev->class & 0xff) == 1);
        pci_read_bases(dev, 2, PCI_ROM_ADDRESS1);
        break;

    case PCI_HEADER_TYPE_CARDBUS:            /* CardBus bridge header */
        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:                    /* unknown header */
        printk(KERN_ERR "PCI: device %s has unknown header type %02x, ignoring.\n",
            pci_name(dev), dev->hdr_type);
        return -1;

    bad:
        printk(KERN_ERR "PCI: %s: class %x doesn't match header type %02x. Ignoring

class.\n",
               pci_name(dev), class, dev->hdr_type);
        dev->class = PCI_CLASS_NOT_DEFINED;
    }

    /* We found a fine healthy device, go go go... */
    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;

    /* Fix up broken headers */
    pci_fixup_device(pci_fixup_header, dev);

    /*
    * Add the device to our list of discovered devices
    * and the bus list for fixup functions, etc.
    */
    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);
}


/**
*    device_initialize - init device structure.
*    @dev:    device.
*
*    This prepares the device for use by other layers,
*    including adding it to the device hierarchy.
*    It is the first half of device_register(), if called by
*    that, though it can also be called separately, so one
*    may use @dev's fields (e.g. the refcount).
*/

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);
}
阅读(2254) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~