加载中…
个人资料
散人
散人
  • 博客等级:
  • 博客积分:0
  • 博客访问:15,610
  • 关注人气:4
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
相关博文
推荐博文
谁看过这篇博文
加载中…
正文 字体大小:

3.1 PCI粉墨登场之一

(2011-01-13 09:48:10)
标签:

linux

还记得前几章提起过的initcall表吧,这一章重点分析devices硬件扫描(只包含上电部分不含hotplug部分)配置空间的读写流程.

 -------------------------------------------------------------------------

 function:    pci_subsys_init                                

 describtion:                                                             

 return:                                                                   

 -------------------------------------------------------------------------

int __init pci_subsys_init(void)
{
#ifdef CONFIG_X86_NUMAQ
    pci_numaq_init();
#endif
#ifdef CONFIG_ACPI
    pci_acpi_init();
#endif
#ifdef CONFIG_X86_VISWS
    pci_visws_init();
#endif
   
pci_legacy_init();->entry
    pcibios_irq_init();
    pcibios_init();

    return 0;
}

subsys_initcall(pci_subsys_init);//kernel自启动初始化模块

 -------------------------------------------------------------------------

 function:    pci_legacy_init                                

 describtion:                                                             

 return:                                                                   

 -------------------------------------------------------------------------

static int __init pci_legacy_init(void)
{
         if (!raw_pci_ops)
{//PCI support flag
                   printk("PCI: System does not support PCI ");
                   return 0;
         }
         if (pcibios_scanned++)//
只允许被执行一次,即初始化一次
                   return 0;
         printk("PCI: Probing PCI hardware ");
         pci_root_bus = pcibios_scan_root(0);//
PCI slot扫描entry点
         if (pci_root_bus)
                   pci_bus_add_devices(pci_root_bus);//
         pcibios_fixup_peer_bridges();
         return 0;
}

 -------------------------------------------------------------------------

 function:    pcibios_scan_root                               

 describtion:                                                             

 return:                                                                   

 -------------------------------------------------------------------------

struct pci_bus * __devinit pcibios_scan_root(int busnum)
{
    struct pci_bus *bus = NULL;
    struct pci_sysdata *sd;

    while ((bus = pci_find_next_bus(bus)) != NULL) {  //when first scan pci_find_next_bus always
        if (bus->number == busnum) {                  //return NULL
          
            return bus;
        }
    }
    sd = kzalloc(sizeof(*sd), GFP_KERNEL);
    if (!sd) {
        printk(KERN_ERR "PCI: OOM, not probing PCI bus x\n", busnum);
        return NULL;
    }

    sd->node = get_mp_bus_to_node(busnum);

    printk(KERN_DEBUG "PCI: Probing PCI hardware (bus x)\n", busnum);
    bus = pci_scan_bus_parented(NULL, busnum, &pci_root_ops, sd);//
扫描bus0下面的所有设备
    if (!bus)
    kfree(sd);

    return bus;
}

 -------------------------------------------------------------------------

 function:   pci_scan_bus_parented 

 describtion:                                                             

 return:                                                                   

 -------------------------------------------------------------------------

struct pci_bus * __devinit pci_scan_bus_parented(struct device *parent,
  int bus, struct pci_ops *ops, void *sysdata)
{
    struct pci_bus *b;
    b = pci_create_bus(parent, bus, ops, sysdata);//创建根总线bus pci_bus结构

    if (b)
        b->subordinate = pci_scan_child_bus(b);
    return b;
}

 -------------------------------------------------------------------------

 function:   pci_scan_child_bus

 describtion:                                                             

 return:                                                                   

 -------------------------------------------------------------------------

unsigned int __devinit 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);

   
    for (devfn = 0; devfn < 0x100; devfn += 8)//
从上一节了解到读配置空间需要总线号,设备号和功能号
         pci_scan_slot(bus, devfn);//busnum:0 devfn:0-255扫描所有的的slot插槽,功能号在下级函数提供

   
    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;
}

 -------------------------------------------------------------------------

 function:      pci_scan_slot

 describtion:   PCI 插槽 扫描                                           

 return:                                                                   

 -------------------------------------------------------------------------

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);

    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;
        }
    }

   
    if (bus->self && nr)
    pcie_aspm_init_link_state(bus->self);

    return nr;
}

 -------------------------------------------------------------------------

 function:      pci_scan_single_device

 describtion:   指定总线num 设备num 功能num下扫描设备,获取设备配置信息

 return:        返回NULL 设备不存在 或 返回existing's 设备的pci_dev指针        

 -------------------------------------------------------------------------

struct pci_dev *__ref pci_scan_single_device(struct pci_bus *bus, int devfn)
{
    struct pci_dev *dev;

    dev = pci_scan_device(bus, devfn);//获取设备信息
    if (!dev)
        return NULL;//指定位置设备不存在

    pci_device_add(dev, bus);//添加到全局devices list中

    return dev;
}

 -------------------------------------------------------------------------

 function:      pci_scan_device

 describtion:   给定总线num 设备num 下获取dev配置空间内容

 return:        返回设备指针                                 

 -------------------------------------------------------------------------

static struct pci_dev *pci_scan_device(struct pci_bus *bus, int devfn)
{
    struct pci_dev *dev;
    struct pci_slot *slot;
    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))//
retry again
            return NULL;
  
        if (delay > 60 * 1000) {//
读取次数限制一分钟之内读取失败 直接返回
            printk(KERN_WARNING "pci x:x:x.%d: not ""responding\n", pci_domain_nr(bus),
            bus->number, PCI_SLOT(devfn),
            PCI_FUNC(devfn));
            return NULL;
        }
    }

    if (pci_bus_read_config_byte(bus, devfn, PCI_HEADER_TYPE, &hdr_type))//获取头类型
        return NULL;

    dev = alloc_pci_dev();//为dev分配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;//
低4位(2字节厂商ID)
    dev->device = (l >> 16) & 0xffff;//
高4位(2字节设备ID)
    dev->cfg_size = pci_cfg_space_size(dev);//
获取配置空间大小 ??具体函数未分析
    dev->error_state = pci_channel_io_normal;
    set_pcie_port_type(dev);

    list_for_each_entry(slot, &bus->slots, list)//寻找指定(5bit)devfn的slot
    if (PCI_SLOT(devfn) == slot->number)//判断是哪个slot下的

        dev->slot = slot;//保存slot

 
    dev->dma_mask = 0xffffffff;
    if (pci_setup_device(dev) < 0) {
        kfree(dev);
        return NULL;
    }

    return dev;
}

 -------------------------------------------------------------------------

 function:      pci_setup_device

 describtion:   判断dev的class类型,获取版本号,中断line/pin,分配IO内存等

 return:        返回设备指针                                 

 -------------------------------------------------------------------------

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

    dev_set_name(&dev->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);//获取0x08-0x11 4字节内容
    dev->revision = class & 0xff;//
低字节为版本号
    class >>= 8;       
    dev->class = class;//
高3字节为版本号
    class >>= 8;//高2字节    

    dev_dbg(&dev->dev, "found [x:x] class x header type x\n",
            dev->vendor, dev->device, class, dev->hdr_type);

 
    dev->current_state = PCI_UNKNOWN;//未激活状态

 
    pci_fixup_device(pci_fixup_early, dev);
    class = dev->class >> 8;//高2字节 -> class  

    switch (dev->hdr_type) {       
        case PCI_HEADER_TYPE_NORMAL:     
            if (class == PCI_CLASS_BRIDGE_PCI)//
当前设备类属pci桥
                goto bad;
            pci_read_irq(dev);//
读中断line和中断pin
            pci_read_bases(dev, 6, PCI_ROM_ADDRESS);//
读PCI_ROM_ADDRESS(6字节)
            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: //CARDBUS CardBus是PCMCIA总线的一种类型,它是用

             if (class != PCI_CLASS_BRIDGE_CARDBUS)//于笔记本计算机的新的高性能PC卡

                 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:       
            dev_err(&dev->dev, "unknown header type x, ""ignoring device\n", dev->hdr_type);
            return -1;

        bad:
            dev_err(&dev->dev, "ignoring class x (doesn't match header "

                "type x)\n", class, dev->hdr_type);
            dev->class = PCI_CLASS_NOT_DEFINED;
    }

    return 0;
}


 

 

0

阅读 评论 收藏 转载 喜欢 打印举报/Report
  • 评论加载中,请稍候...
发评论

    发评论

    以上网友发言只代表其个人观点,不代表新浪网的观点或立场。

      

    新浪BLOG意见反馈留言板 欢迎批评指正

    新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 会员注册 | 产品答疑

    新浪公司 版权所有