乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      PCI驅(qū)動框架簡單分析

       chi_Andy 2017-06-24

      一、PCI 概念介紹

          PCI是CPU和外圍設(shè)備通信的高速傳輸總線。PCI規(guī)范能夠?qū)崿F(xiàn)32位并行數(shù)據(jù)傳輸,工作頻率為 33MHz 或 66MHz ,最大吞吐率高達(dá)266MB/s,PCI的衍生物包括 CardBus、mini-PCI、PCI-Express、cPCI等。

          PCI總線體系結(jié)構(gòu)是一種層次式的體系結(jié)構(gòu)。在這種層次體系結(jié)構(gòu)中,PCI橋設(shè)備占據(jù)著重要的地位,它將父總線與子總線連接在一起,從而使整個系統(tǒng)看起來像一個倒置的樹狀結(jié)構(gòu),樹的頂端是CPU,它通過一個較為特殊的CPI橋設(shè)備-Host/PCI橋設(shè)備與根PCI總線連接起來。

          作為特殊的PCI設(shè)備,PCI橋包括以下幾種:

          HOST/PCI橋,用于連接CPU與PCI根總線,第一個根總線的編號為0。在PC中,內(nèi)存控制器也通常被集成到Host/PCI橋設(shè)備芯片中,因此,Host/PCI橋也通常被稱為“北橋”芯片組。

          PCI/ISA橋,用作連接舊的ISA總線,通常,PCI中的類似的i8359A中斷控制器這樣的設(shè)備也會被集成到PCI/ISA橋設(shè)備中,因此,PCI/ISA橋通常也被稱作“南橋”芯片組。

          PCI-to-PCI橋,用于連接PCI主總線與次總線,PCI橋所處的總線被稱作“主總線”(父總線),PCI橋設(shè)備所連接的總線為“次總線”(子總線)。

          

      二、PCI設(shè)備與配置空間

          在i386系統(tǒng)結(jié)構(gòu)中,對內(nèi)存的訪問和對輸入/輸出寄存器的訪問通過兩套不同的指令完成,所有的存儲器和IO兩個不同的地址空間。一般而言,內(nèi)存的物理地址以及輸入/輸出寄存器的地址是由硬件決定的,不過對于內(nèi)存的物理地址還可以通過地址映射機(jī)制來一次轉(zhuǎn)換(I/O也可以映射)。可是,怎樣處理外設(shè)的存儲空間呢?理想的辦法是系統(tǒng)軟件自動設(shè)置,思路是:

          1、外設(shè)通過某種途徑告訴系統(tǒng),它有幾個存儲區(qū)間以及I/O地址空間,每個區(qū)間是多大,以及各自在本地的地址,顯然這些地址都是局部的內(nèi)部的,都從0開始算起。

          2、系統(tǒng)軟件在知道了一共有多少外設(shè),各自又有什么樣的存儲區(qū)間以后,就可以為這些區(qū)間分配“物理地址”,并且建立起這些區(qū)間與總線之間的連接,以后就可以通過這些地址來訪問。顯然,這里所謂的“物理地址”與真正的物理地址還是有些區(qū)別的,它實際上也是一種邏輯地址,所以常成為“總線地址”,因為這是CPU在總線上所看到的地址??上攵?,外設(shè)上一定有著某種地址映射機(jī)制。所謂的“為外設(shè)分配地址”,就是為其分配總線地址,并建立起映射。

          PCI設(shè)備上存在許多完成上述工作的寄存器(配置空間),那么系統(tǒng)初始化的時候如何訪問這些寄存器該何如?對于i386結(jié)構(gòu)的處理器,PCI總線的設(shè)計者在I/O地址空間保留了8個字節(jié)用于這個目的,那就是0xCF8~0xCFF,這8個字節(jié)的地址空間構(gòu)成了兩個32位的寄存器,第一個是“地址寄存器”0xCF8,第二個是“數(shù)據(jù)寄存器”0xCFC,要訪問配置空間的寄存器時,CPU先向地址寄存器寫入目標(biāo)地址,然后通過數(shù)據(jù)寄存器進(jìn)行讀寫數(shù)據(jù)不過,寫入地址寄存器的目標(biāo)地址是一種包括總線號、設(shè)備號、功能號以及配置寄存器地址的綜合地址。每個PCI設(shè)備最多有8個功能,所以設(shè)備號和功能號組合在一起又被稱作“邏輯設(shè)備”號。


          如上圖所示,PCI標(biāo)準(zhǔn)規(guī)定每個設(shè)備的配置寄存器組最多可以有256字節(jié)的連續(xù)空間,其中開頭的64字節(jié)的用途和格式是標(biāo)準(zhǔn)的,成為配置寄存器組的“頭部”,這樣的頭部又有兩種,“0型”頭部用于一般的PCI設(shè)備,“1型”頭部用于PCI橋無論是“0型”還是“1型”,其開頭的16個字節(jié)的用途和格式是共同的


      三、PCI驅(qū)動框架分析

          在內(nèi)核中與PCI相關(guān)的結(jié)構(gòu)體大概有pci_driver 、pci_bus_type 、pci_dev 、pci_bus ,我們前邊所說的所有的PCI總線都是指的 pci_bus 。

        3.1 pci_bus

      1. struct pci_bus {  
      2.     struct list_head node;      /* node in list of buses */  
      3.     struct pci_bus  *parent;    /* parent bus this bridge is on */  
      4.     struct list_head children;  /* list of child buses */  
      5.     struct list_head devices;   /* list of devices on this bus */  
      6.     struct pci_dev  *self;      /* bridge device as seen by parent */  
      7.     struct list_head slots;     /* list of slots on this bus */  
      8.     struct resource *resource[PCI_BUS_NUM_RESOURCES];  
      9.                     /* address space routed to this bus */  
      10.   
      11.     struct pci_ops  *ops;       /* configuration access functions */  
      12.     void        *sysdata;   /* hook for sys-specific extension */  
      13.     struct proc_dir_entry *procdir; /* directory entry in /proc/bus/pci */  
      14.   
      15.     unsigned char   number;     /* bus number */  
      16.     unsigned char   primary;    /* number of primary bridge */  
      17.     unsigned char   secondary;  /* number of secondary bridge */  
      18.     unsigned char   subordinate;    /* max number of subordinate buses */  
      19.   
      20.     char        name[48];  
      21.   
      22.     unsigned short  bridge_ctl; /* manage NO_ISA/FBB/et al behaviors */  
      23.     pci_bus_flags_t bus_flags;  /* Inherited by child busses */  
      24.     struct device       *bridge;  
      25.     struct device       dev;  
      26.     struct bin_attribute    *legacy_io; /* legacy I/O for this bus */  
      27.     struct bin_attribute    *legacy_mem; /* legacy mem */  
      28.     unsigned int        is_added:1;  
      29. };  
          幾個重要的成員:

          children:  PCI橋可以使當(dāng)前總線得到擴(kuò)展,當(dāng)前總線上有幾個PCI橋,那么當(dāng)前總線就會擁有幾個子總線,子總線會連接到父總線的children鏈表中。

          device: 連接在這條總線上的設(shè)備鏈表。

          ops: 當(dāng)前總線訪問總線上設(shè)備配置空間的 read、write 方法。

          在內(nèi)核啟動的過程中,首先會創(chuàng)建0級總線,然后枚舉探測0級總線上的設(shè)備,如果是PCI橋,那么還要進(jìn)入下一級子總線,最終所有的連接的PCI設(shè)備都將被探測到,詳細(xì)的探測過程,我們在后邊分析。


        3.2 pci_bus_type

          看到 bus_type 顯然這是個設(shè)備總線驅(qū)動模型里的“總線”,與前邊提到的 pci_bus ,完全是兩碼事,那么pci_driver 和 pci_dev 就是注冊到 pci_bus_type 的驅(qū)動和設(shè)備。分析總線設(shè)備驅(qū)動模型的時候,總要分析一下它的 match 函數(shù)(匹配規(guī)則)。

      1. static int pci_bus_match(struct device *dev, struct device_driver *drv)  
      2. {  
      3.     struct pci_dev *pci_dev = to_pci_dev(dev);  
      4.     struct pci_driver *pci_drv = to_pci_driver(drv);  
      5.     const struct pci_device_id *found_id;  
      6.   
      7.     found_id = pci_match_device(pci_drv, pci_dev);  
      8.     if (found_id)  
      9.         return 1;  
      10.   
      11.     return 0;  
      12. }  
      1. static const struct pci_device_id *pci_match_device(struct pci_driver *drv,  
      2.                             struct pci_dev *dev)  
      3. {  
      4.     struct pci_dynid *dynid;  
      5.   
      6.     /* Look at the dynamic ids first, before the static ones */  
      7.     spin_lock(&drv->dynids.lock);  
      8.     list_for_each_entry(dynid, &drv->dynids.list, node) {  
      9.         if (pci_match_one_device(&dynid->id, dev)) {  
      10.             spin_unlock(&drv->dynids.lock);  
      11.             return &dynid->id;  
      12.         }  
      13.     }  
      14.     spin_unlock(&drv->dynids.lock);  
      15.   
      16.     return pci_match_id(drv->id_table, dev);  
      17. }  
      1. static inline const struct pci_device_id *  
      2. pci_match_one_device(const struct pci_device_id *id, const struct pci_dev *dev)  
      3. {  
      4.     if ((id->vendor == PCI_ANY_ID || id->vendor == dev->vendor) &&  
      5.         (id->device == PCI_ANY_ID || id->device == dev->device) &&  
      6.         (id->subvendor == PCI_ANY_ID || id->subvendor == dev->subsystem_vendor) &&  
      7.         (id->subdevice == PCI_ANY_ID || id->subdevice == dev->subsystem_device) &&  
      8.         !((id->class ^ dev->class) & id->class_mask))  
      9.         return id;  
      10.     return NULL;  
      11. }  
      1. const struct pci_device_id *pci_match_id(const struct pci_device_id *ids,  
      2.                      struct pci_dev *dev)  
      3. {  
      4.     if (ids) {  
      5.         while (ids->vendor || ids->subvendor || ids->class_mask) {  
      6.             if (pci_match_one_device(ids, dev))  
      7.                 return ids;  
      8.             ids++;  
      9.         }  
      10.     }  
      11.     return NULL;  
      12. }  
          通過分析代碼,PCI設(shè)備與驅(qū)動的匹配方式有兩種,一種是通過 pci_driver->dynids ,另一種是通過 pci_driver->idtable 。使用idtable 是總線設(shè)備驅(qū)動模型中常用的匹配方法,一般都是通過設(shè)備名來匹配,但是PCI比較特殊,它是通過設(shè)備的 vendor 、subvendor 、device 、subdevice 來匹配(這些都是在配置空間里可以讀取到的)。

          至于 pci_driver->dynids ,它是通過用戶空間給驅(qū)動增加匹配條件的一種方法(還記得I2C可以在用戶空間創(chuàng)建設(shè)備嗎,一樣的)。

      1. error = pci_create_newid_file(drv);  
      2. static int  
      3. pci_create_newid_file(struct pci_driver *drv)  
      4. {  
      5.     int error = 0;  
      6.     if (drv->probe != NULL)  
      7.         error = driver_create_file(&drv->driver, &driver_attr_new_id);  
      8.     return error;  
      9. }  
          在 pci_register_driver 函數(shù)中會調(diào)用到一個 pci_create_newid_file 函數(shù),它在 sysfs 文件系統(tǒng)中會創(chuàng)建一個 new_id 的屬性文件,通過這個屬性文件,我們就可以來為該驅(qū)動增加匹配條件。

          內(nèi)核幫助文檔有說明:

          New PCI IDs may be added to a device driver pci_ids table at runtime as shown below:
          echo "vendor device subvendor subdevice class class_mask driver_data" > \
      /sys/bus/pci/drivers/{driver}/new_id

          對于這種方法不在詳細(xì)分析。

          分析完設(shè)備總線驅(qū)動模型,我想整個PCI驅(qū)動的框架就非常清楚了,內(nèi)核啟動時,通過pci_bus之間的關(guān)系枚舉出所有的 PCI 設(shè)備,并為每一個 PCI 設(shè)備創(chuàng)建一個 pci_dev ,根據(jù)配置空間的信息填充 pci_dev 之后,注冊到pci_bus_type 。而,我們寫的 pci_driver 在 idtable 里指定它所支持的設(shè)備信息,同樣也注冊到 pci_bus_type中去,信息一致匹配成功則調(diào)用 driver->probe 函數(shù),然后你可以注冊字符設(shè)備、塊設(shè)備等等。


      四、PCI設(shè)備的枚舉探測過程

          在內(nèi)核啟動過程中,PCI設(shè)備的探測過程是完全自動的,內(nèi)核已經(jīng)集成好了方法,我們無需更改,在這里還是分析一邊代碼作為了解。

          分析之前,先看一下全部的函數(shù)調(diào)用關(guān)系,大致了解一下

      1. <span style="font-size:10px;">pci_arch_init /* 判斷host/pci橋的類型 */  
      2.     pci_direct_probe  
      3.         pci_check_type1  
      4.             pci_sanity_check  
      5.       
      6.     pci_direct_init  
      7.         raw_pci_ops = &pci_direct_conf1;  
      8.         raw_pci_ext_ops = &pci_direct_conf1;    
      9.   
      10. /* 第二個過程,枚舉各級總線上的設(shè)備 */  
      11. pci_subsys_init  
      12.     pci_legacy_init  
      13.         pcibios_scan_root  
      14.             pci_scan_bus_parented(NULL, busnum, &pci_root_ops, sd);    
      15.                 pci_create_bus(parent, bus, ops, sysdata);  // 創(chuàng)建 0 級總線  
      16.                 pci_scan_child_bus(b); // 探測當(dāng)前總線設(shè)備以及子總線、子總線設(shè)備  
      17.                     pci_scan_slot(bus, devfn);  // 探測當(dāng)前總線的設(shè)備  
      18.                         pci_scan_single_device(bus, devfn); // 探測單功能設(shè)備  
      19.                         pci_scan_single_device(bus, devfn + fn); //探測多功能設(shè)備  
      20.                             pci_scan_device(bus, devfn);    //通過配置空間 枚舉設(shè)備  
      21.                                 pci_setup_device    //根據(jù)配置空間信息,設(shè)置pci_dev  
      22.                             pci_device_add(dev, bus);                         
      23.                                 list_add_tail(&dev->bus_list, &bus->devices); // 將探測到的設(shè)備加入到當(dāng)前總線的設(shè)備鏈表   
      24.                     pci_scan_bridge  //此時已經(jīng)完成當(dāng)前總線設(shè)備的探測,如果這些設(shè)備里有PCI橋,那么進(jìn)入下一級,探測橋下的設(shè)備  
      25.                         child = pci_add_new_bus(bus, dev, busnr);  
      26.                         pci_scan_child_bus(child);  // 進(jìn)入下一級探測  
      27.         pci_bus_add_devices // 全部設(shè)備探測完畢,注冊設(shè)備。  
      28.             pci_bus_add_device(dev);   
      29.                 device_add  // 將設(shè)備注冊到 pci_bus_type  
      30.             pci_bus_add_devices(child); //它最終也會調(diào)用到 device_add 將各個子總線上的設(shè)備注冊到 pci_bus_type  
          下面來看具體的探測過程。

      1. static __init int pci_arch_init(void)  
      2. {  
      3. #ifdef CONFIG_PCI_DIRECT  
      4.     int type = 0;  
      5.     type = pci_direct_probe();  
      6. #endif  
      7.   
      8. #ifdef CONFIG_PCI_BIOS  
      9.     pci_pcbios_init();  
      10. #endif  
      11.   
      12. #ifdef CONFIG_PCI_DIRECT  
      13.     pci_direct_init(type);  
      14. #endif  
      15.   
      16.     dmi_check_pciprobe();  
      17.   
      18.     dmi_check_skip_isa_align();  
      19.   
      20.     return 0;  
      21. }  
      22. arch_initcall(pci_arch_init);  
          這個函數(shù)是放在 init 段中,內(nèi)核啟動時會調(diào)用。
      1. int __init pci_direct_probe(void)  
      2. {  
      3.     struct resource *region, *region2;  
      4.     /* 申請IO資源 */  
      5.     region = request_region(0xCF8, 8, "PCI conf1");  
      6.       
      7.     /* 探測那種類型 ,0型(PCI設(shè)備)和1型(PCI橋) */  
      8.     if (pci_check_type1()) {  
      9.         raw_pci_ops = &pci_direct_conf1;  
      10.         port_cf9_safe = true;  
      11.         return 1;  
      12.     }  
      13.     release_resource(region);  
      14.   
      15.     return 0;  
      16. }  
          這里,我們以“1型”也就是PCI橋為例,看看是如何判斷類型的。

      1. static int __init pci_check_type1(void)  
      2. {  
      3.     unsigned long flags;  
      4.     unsigned int tmp;  
      5.     int works = 0;  
      6.   
      7.     local_irq_save(flags);  
      8.       
      9.     /* i386 pci地址寄存器 0xcfb 寫 0x01 */  
      10.     outb(0x01, 0xCFB);  
      11.     tmp = inl(0xCF8);  
      12.     outl(0x80000000, 0xCF8);  
      13.     /* 判斷設(shè)備類型 */  
      14.     if (inl(0xCF8) == 0x80000000 && pci_sanity_check(&pci_direct_conf1)) {  
      15.         works = 1;  
      16.     }  
      17.     outl(tmp, 0xCF8);  
      18.     local_irq_restore(flags);  
      19.   
      20.     return works;  
      21. }  
      1. static int __init pci_sanity_check(struct pci_raw_ops *o)  
      2. {  
      3.     u32 x = 0;  
      4.     int year, devfn;  
      5.   
      6.     /* Assume Type 1 works for newer systems. 
      7.        This handles machines that don't have anything on PCI Bus 0. */  
      8.     dmi_get_date(DMI_BIOS_DATE, &year, NULL, NULL);  
      9.     if (year >= 2001)  
      10.         return 1;  
      11.   
      12.     for (devfn = 0; devfn < 0x100; devfn++) {  
      13.         /* 讀  CLASS_DEVICE ,PCI_CLASS_DEVICE 是片內(nèi)偏移地址 */  
      14.         if (o->read(0, 0, devfn, PCI_CLASS_DEVICE, 2, &x))  
      15.             continue;  
      16.         /* 如果 CLASS_DEVICE 為 HOST-PCI橋(北橋),PCI-PCI橋,PCI-ISA橋(南橋)正確返回 */  
      17.         if (x == PCI_CLASS_BRIDGE_HOST || x == PCI_CLASS_DISPLAY_VGA)  
      18.             return 1;  
      19.         /* 讀  VENDOR_ID 制造商ID */  
      20.         if (o->read(0, 0, devfn, PCI_VENDOR_ID, 2, &x))  
      21.             continue;  
      22.         /* 如果 VENDOR_ID 為  INTEL 或 COMPAQ 正常返回 */  
      23.         if (x == PCI_VENDOR_ID_INTEL || x == PCI_VENDOR_ID_COMPAQ)  
      24.             return 1;  
      25.     }  
      26.   
      27.     DBG(KERN_WARNING "PCI: Sanity check failed\n");  
      28.     return 0;  
      29. }  
          檢測完是“0型”還是“1型”設(shè)備之后,在 raw_pci_ops 中指定對應(yīng)的讀寫配置空間的方法。

      1. /* 地址是由 總線編號、設(shè)備號、片內(nèi)陸址 組成 */  
      2. #define PCI_CONF1_ADDRESS(bus, devfn, reg) \  
      3.     (0x80000000 | ((reg & 0xF00) << 16) | (bus << 16) \  
      4.     | (devfn << 8) | (reg & 0xFC))  
      5.   
      6. static int pci_conf1_read(unsigned int seg, unsigned int bus,  
      7.               unsigned int devfn, int reg, int len, u32 *value)  
      8. {  
      9.     unsigned long flags;  
      10.     /* 最多256個總線 ,256個設(shè)備 片內(nèi)寄存器范圍 0~4095 */  
      11.     if ((bus > 255) || (devfn > 255) || (reg > 4095)) {  
      12.         *value = -1;  
      13.         return -EINVAL;  
      14.     }  
      15.   
      16.     spin_lock_irqsave(&pci_config_lock, flags);  
      17.       
      18.     /* 向地址寄存器 寫要讀取的地址 */  
      19.     outl(PCI_CONF1_ADDRESS(bus, devfn, reg), 0xCF8);  
      20.       
      21.     /* 從數(shù)據(jù)寄存器讀取數(shù)據(jù) */  
      22.     switch (len) {  
      23.     case 1:  
      24.         *value = inb(0xCFC + (reg & 3));  
      25.         break;  
      26.     case 2:  
      27.         *value = inw(0xCFC + (reg & 2));  
      28.         break;  
      29.     case 4:  
      30.         *value = inl(0xCFC);  
      31.         break;  
      32.     }  
      33.   
      34.     spin_unlock_irqrestore(&pci_config_lock, flags);  
      35.   
      36.     return 0;  
      37. }  
      38.   
      39. struct pci_raw_ops {  
      40.     int (*read)(unsigned int domain, unsigned int bus, unsigned int devfn,  
      41.                         int reg, int len, u32 *val);  
      42.     int (*write)(unsigned int domain, unsigned int bus, unsigned int devfn,  
      43.                         int reg, int len, u32 val);  
      44. };  
      45. struct pci_raw_ops *raw_pci_ops;  
      1. /* 設(shè)置全局的 配置空間讀寫函數(shù) */  
      2. void __init pci_direct_init(int type)  
      3. {  
      4.     if (type == 1) {  
      5.         raw_pci_ops = &pci_direct_conf1;  
      6.   
      7.         raw_pci_ext_ops = &pci_direct_conf1;  
      8.         return;  
      9.     }  
      10. }  
          在內(nèi)核啟動過程中,還有一個PCI相關(guān)的函數(shù)會被調(diào)用
      1. int __init pci_subsys_init(void)  
      2. {  
      3. #ifdef CONFIG_X86_NUMAQ  
      4.     pci_numaq_init();  
      5. #endif  
      6. #ifdef CONFIG_ACPI  
      7.     pci_acpi_init();  
      8. #endif  
      9. #ifdef CONFIG_X86_VISWS  
      10.     pci_visws_init();  
      11. #endif  
      12.     pci_legacy_init();  
      13.     pcibios_fixup_peer_bridges();  
      14.     pcibios_irq_init();  
      15.     pcibios_init();  
      16.   
      17.     return 0;  
      18. }  
      19. subsys_initcall(pci_subsys_init);  
      1. struct pci_bus *pci_root_bus;  
      2. static int __init pci_legacy_init(void)  
      3. {  
      4.     pci_root_bus = pcibios_scan_root(0);//創(chuàng)建0級總線  
      5.     if (pci_root_bus)  
      6.         pci_bus_add_devices(pci_root_bus);  
      7.   
      8.     return 0;  
      9. }  
      1. extern struct list_head pci_root_buses; /* list of all known PCI buses */  
      2. struct pci_bus * __devinit pcibios_scan_root(int busnum)  
      3. {  
      4.     struct pci_bus *bus = NULL;  
      5.     struct pci_sysdata *sd;  
      6.     /* 在全局 pci_root_buses 鏈表尋找 總線編號為 busnum 的總線 */  
      7.     while ((bus = pci_find_next_bus(bus)) != NULL) {  
      8.         if (bus->number == busnum) {  
      9.             /* 如果已經(jīng)存在,返回它 */  
      10.             return bus;  
      11.         }  
      12.     }  
      13.   
      14.     /* 如果這個總線編號不存在, 那么創(chuàng)建這個Bus */  
      15.     sd = kzalloc(sizeof(*sd), GFP_KERNEL);  
      16.     sd->node = get_mp_bus_to_node(busnum);  
      17.   
      18.     bus = pci_scan_bus_parented(NULL, busnum, &pci_root_ops, sd);  
      19.   
      20.     return bus;  
      21. }  
      1. struct pci_bus * __devinit pci_scan_bus_parented(struct device *parent,  
      2.         int bus, struct pci_ops *ops, void *sysdata)  
      3. {  
      4.     struct pci_bus *b;  
      5.     /* 創(chuàng)建 Bus */  
      6.     b = pci_create_bus(parent, bus, ops, sysdata);  
      7.     if (b)  
      8.         b->subordinate = pci_scan_child_bus(b);  
      9.     return b;  
      10. }  
      1. unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus)  
      2. {  
      3.     unsigned int devfn, pass, max = bus->secondary;  
      4.     struct pci_dev *dev;  
      5.   
      6.     /* 探測總線上的設(shè)備 */  
      7.     for (devfn = 0; devfn < 0x100; devfn += 8)  
      8.         pci_scan_slot(bus, devfn);  
      9.   
      10.     /* Reserve buses for SR-IOV capability. */  
      11.     max += pci_iov_bus_range(bus);  
      12.   
      13.     /* 
      14.      * After performing arch-dependent fixup of the bus, look behind 
      15.      * all PCI-to-PCI bridges on this bus. 
      16.      */  
      17.     if (!bus->is_added) {  
      18.         pr_debug("PCI: Fixups for bus %04x:%02x\n",  
      19.              pci_domain_nr(bus), bus->number);  
      20.         pcibios_fixup_bus(bus);  
      21.         if (pci_is_root_bus(bus))  
      22.             bus->is_added = 1;  
      23.     }  
      24.     /* 探測 pci 橋上的設(shè)備,創(chuàng)建子Bus,掛到父 bus->child */  
      25.     for (pass=0; pass < 2; pass++)  
      26.         list_for_each_entry(dev, &bus->devices, bus_list) {  
      27.             if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||  
      28.                 dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)  
      29.                 max = pci_scan_bridge(bus, dev, max, pass);  
      30.         }  
      31.   
      32.     /* 
      33.      * We've scanned the bus and so we know all about what's on 
      34.      * the other side of any bridges that may be on this bus plus 
      35.      * any devices. 
      36.      * 
      37.      * Return how far we've got finding sub-buses. 
      38.      */  
      39.     pr_debug("PCI: Bus scan for %04x:%02x returning with max=%02x\n",  
      40.         pci_domain_nr(bus), bus->number, max);  
      41.     return max;  
      42. }  
      1. int pci_scan_slot(struct pci_bus *bus, int devfn)  
      2. {  
      3.     int fn, nr = 0;  
      4.     struct pci_dev *dev;  
      5.       
      6.     dev = pci_scan_single_device(bus, devfn);  
      7.       
      8.     /* 如果是多功能設(shè)備 */  
      9.     if (dev && dev->multifunction) {  
      10.         for (fn = 1; fn < 8; fn++) {  
      11.             dev = pci_scan_single_device(bus, devfn + fn);  
      12.             if (dev) {  
      13.                 if (!dev->is_added)  
      14.                     nr++;  
      15.                 dev->multifunction = 1;  
      16.             }  
      17.         }  
      18.     }  
      19.   
      20.     return nr;  
      21. }  
      1. struct pci_dev *__ref pci_scan_single_device(struct pci_bus *bus, int devfn)  
      2. {  
      3.     struct pci_dev *dev;  
      4.     /* 遍歷 bus->devices 設(shè)備鏈表,查找是否有 devfn 號設(shè)備存在 */  
      5.     dev = pci_get_slot(bus, devfn);  
      6.     /* 如果已經(jīng)存在,返回它 */  
      7.     if (dev) {  
      8.         pci_dev_put(dev);  
      9.         return dev;  
      10.     }  
      11.     /* 通過訪問配置空間,探測設(shè)備 */  
      12.     dev = pci_scan_device(bus, devfn);  
      13.     /* 探測失敗 返回Null */  
      14.     if (!dev)  
      15.         return NULL;  
      16.     /* 探測成功 */  
      17.     pci_device_add(dev, bus);  
      18.   
      19.     return dev;  
      20. }  
      1. static struct pci_dev *pci_scan_device(struct pci_bus *bus, int devfn)  
      2. {  
      3.     struct pci_dev *dev;  
      4.     u32 l;  
      5.     int delay = 1;  
      6.       
      7.     /* 讀  PCI_VENDOR_ID 制造商ID */  
      8.     if (pci_bus_read_config_dword(bus, devfn, PCI_VENDOR_ID, &l))  
      9.         return NULL;  
      10.       
      11.     /* id 等于這些值,認(rèn)為探測失敗 ,返回 */  
      12.     if (l == 0xffffffff || l == 0x00000000 ||  
      13.         l == 0x0000ffff || l == 0xffff0000)  
      14.         return NULL;  
      15.     ....  
      16.       
      17.     /* 探測成功,分配一個 pci_dev 結(jié)構(gòu) */  
      18.     dev = alloc_pci_dev();  
      19.   
      20.     dev->bus = bus;  
      21.     dev->devfn = devfn;  
      22.     dev->vendor = l & 0xffff;  
      23.     dev->device = (l >> 16) & 0xffff;  
      24.     /* 讀取配置空間,更詳細(xì)的設(shè)置,指定 dev->bus 等 */  
      25.     if (pci_setup_device(dev)) {  
      26.         kfree(dev);  
      27.         return NULL;  
      28.     }  
      29.   
      30.     return dev;  
      31. }  
      1. int pci_setup_device(struct pci_dev *dev)  
      2. {  
      3.     u32 class;  
      4.     u8 hdr_type;  
      5.     struct pci_slot *slot;  
      6.   
      7.   
      8.     dev->sysdata = dev->bus->sysdata;  
      9.     dev->dev.parent = dev->bus->bridge;  
      10.       
      11.     /* 設(shè)置 dev 所屬的總線 */  
      12.     dev->dev.bus = &pci_bus_type;  
      13.     dev->hdr_type = hdr_type & 0x7f;  
      14.     dev->multifunction = !!(hdr_type & 0x80);  
      15.     dev->error_state = pci_channel_io_normal;  
      16.     set_pcie_port_type(dev);  
      17.   
      18.   
      19.     list_for_each_entry(slot, &dev->bus->slots, list)  
      20.         if (PCI_SLOT(dev->devfn) == slot->number)  
      21.             dev->slot = slot;  
      22.   
      23.   
      24.     dev->dma_mask = 0xffffffff;  
      25.     /* 設(shè)備名 */  
      26.     dev_set_name(&dev->dev, "%04x:%02x:%02x.%d", pci_domain_nr(dev->bus),  
      27.              dev->bus->number, PCI_SLOT(dev->devfn),  
      28.              PCI_FUNC(dev->devfn));  
      29.     /* 設(shè)備類型 */  
      30.     pci_read_config_dword(dev, PCI_CLASS_REVISION, &class);  
      31.     dev->revision = class & 0xff;  
      32.     class >>= 8;                  /* upper 3 bytes */  
      33.     dev->class = class;  
      34.     class >>= 8;  
      35.   
      36.   
      37.     /* need to have dev->class ready */  
      38.     dev->cfg_size = pci_cfg_space_size(dev);  
      39.   
      40.   
      41.     /* "Unknown power state" */  
      42.     dev->current_state = PCI_UNKNOWN;  
      43.   
      44.   
      45.     /* Early fixups, before probing the BARs */  
      46.     pci_fixup_device(pci_fixup_early, dev);  
      47.     /* device class may be changed after fixup */  
      48.     class = dev->class >> 8;  
      49.   
      50.   
      51.     switch (dev->hdr_type) {         /* header type */  
      52.     case PCI_HEADER_TYPE_NORMAL:            /* standard header */  
      53.         ...  
      54.     case PCI_HEADER_TYPE_BRIDGE:            /* bridge header */  
      55.         /* 設(shè)置 dev->irq  */  
      56.         pci_read_irq(dev);  
      57.         dev->transparent = ((dev->class & 0xff) == 1);  
      58.         /* 設(shè)置 dev->rom_base_reg */  
      59.         pci_read_bases(dev, 2, PCI_ROM_ADDRESS1);  
      60.         set_pcie_hotplug_bridge(dev);  
      61.         break;  
      62.   
      63.   
      64.     case PCI_HEADER_TYPE_CARDBUS:           /* CardBus bridge header */  
      65.         ...  
      66.         break;  
      67.           
      68.     return 0;  
      69. }  
      1. void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)  
      2. {  
      3.     device_initialize(&dev->dev);  
      4.     dev->dev.release = pci_release_dev;  
      5.     pci_dev_get(dev);  
      6.   
      7.     dev->dev.dma_mask = &dev->dma_mask;  
      8.     dev->dev.dma_parms = &dev->dma_parms;  
      9.     dev->dev.coherent_dma_mask = 0xffffffffull;  
      10.   
      11.     pci_set_dma_max_seg_size(dev, 65536);  
      12.     pci_set_dma_seg_boundary(dev, 0xffffffff);  
      13.   
      14.     /* Fix up broken headers */  
      15.     pci_fixup_device(pci_fixup_header, dev);  
      16.   
      17.     /* Clear the state_saved flag. */  
      18.     dev->state_saved = false;  
      19.   
      20.     /* Initialize various capabilities */  
      21.     pci_init_capabilities(dev);  
      22.   
      23.     /* 將設(shè)備掛入 bus->devices鏈表 */  
      24.     down_write(&pci_bus_sem);  
      25.     list_add_tail(&dev->bus_list, &bus->devices);  
      26.     up_write(&pci_bus_sem);  
      27. }  
      1. void pci_bus_add_devices(const struct pci_bus *bus)  
      2. {  
      3.     struct pci_dev *dev;  
      4.     struct pci_bus *child;  
      5.     int retval;  
      6.     /* 遍歷當(dāng)前總線的 dev ,注冊設(shè)備 */  
      7.     list_for_each_entry(dev, &bus->devices, bus_list) {  
      8.         /* Skip already-added devices */  
      9.         if (dev->is_added)  
      10.             continue;  
      11.         retval = pci_bus_add_device(dev);  
      12.         if (retval)  
      13.             dev_err(&dev->dev, "Error adding device, continuing\n");  
      14.     }  
      15.     /* 遍歷子總線的dev,注冊設(shè)備 */  
      16.     list_for_each_entry(dev, &bus->devices, bus_list) {  
      17.         BUG_ON(!dev->is_added);  
      18.   
      19.         child = dev->subordinate;  
      20.         /* 
      21.          * If there is an unattached subordinate bus, attach 
      22.          * it and then scan for unattached PCI devices. 
      23.          */  
      24.         if (!child)  
      25.             continue;  
      26.         if (list_empty(&child->node)) {  
      27.             down_write(&pci_bus_sem);  
      28.             list_add_tail(&child->node, &dev->bus->children);  
      29.             up_write(&pci_bus_sem);  
      30.         }  
      31.         pci_bus_add_devices(child);  
      32.   
      33.         /* 
      34.          * register the bus with sysfs as the parent is now 
      35.          * properly registered. 
      36.          */  
      37.         if (child->is_added)  
      38.             continue;  
      39.         retval = pci_bus_add_child(child);  
      40.         if (retval)  
      41.             dev_err(&dev->dev, "Error adding bus, continuing\n");  
      42.     }  
      43. }  
      1. int pci_bus_add_device(struct pci_dev *dev)  
      2. {  
      3.     int retval;  
      4.       
      5.     /* 將設(shè)備注冊到 pci_bus_type */  
      6.     retval = device_add(&dev->dev);  
      7.     if (retval)  
      8.         return retval;  
      9.   
      10.     dev->is_added = 1;  
      11.     pci_proc_attach_device(dev);  
      12.     pci_create_sysfs_dev_files(dev);  
      13.     return 0;  
      14. }  


















       






        本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多