• <li id="00i08"><input id="00i08"></input></li>
  • <sup id="00i08"><tbody id="00i08"></tbody></sup>
    <abbr id="00i08"></abbr>
  • 新聞中心

    EEPW首頁 > PCI設備初始化編程的過程

    PCI設備初始化編程的過程

    ——
    作者: 時間:2007-03-06 來源:電子產品世界 收藏

    這里以PowerPC上的為例,介紹編程的過程,其他CPU的PCI基本框架是類似的.

    PowerPC的PCI控制器符合PCI2.2標準,以下使我解讀的VxWorks系統程序代碼分析

    主要執行過程

    1.PCI設備

    文件romInit.s中romInit()=======>文件bootInit.c中romStart()========>文件usrConfig.c中的usrInit()======>文件syslib.c中的sysHwInit()

    syslib.c

    void sysHwInit (void){ //用于系統硬件

    ......................

    //和網絡,PCI有關的函數

    #ifdef INCLUDE_EMAC_NETWORK


    //初始化媒介訪問層MAL(控制EMAC和Buffer Descriptor BD間的數據傳輸)

    malReset();

    #endif

    #ifdef INCLUDE_PCI
    pciInit(); //初始化PCI
    #endif

    #ifdef INCLUDE_NETWORK
    sysNetHwInit(); //初始化網絡接口
    #endif

    }

     

    //該函數初始化PCI

    PCI的地址轉換形式:

    CPU->PCI (master/initiator) 地址轉換
    PCI->CPU (slave/target) 地址轉換

    void pciInit()
    {

    unsigned short temp_short;

    /*
    * 初始化并 disable 所有的 PCI Master regions(三個),
    little endian,直接對寄存器R操作 */

    sysPciOutLong(PMM0MA, PMM_UNUSED);
    sysPciOutLong(PMM1MA, PMM_UNUSED);
    sysPciOutLong(PMM2MA, PMM_UNUSED);

    /*

    解釋:

    PMM0MA:地址 0xEE400004, 控制PLB上的映射到PCI存儲空間的range0大小和屬性.

    在PLB上共有三個ranges, PMM1MA代表區域rang1, PMM2MA代表區域range2.

    PMM_UNUSED: 0x00000000

    range的定義

    range: map PLB======>PCI 64-bit

    PPBridge(PLB和PCI設備間的接口)responds as a target on the PLB bus in servral address ranges.

    These ranges allow a PLB Master to configure the PPBridge and to cause PPBridge to generate Mem I/O,interrupt acknowledge and special cycles to PCI bus.

    */


    /*
    * Initially disable PCI Target region 2 to start. Region 1 is hardwired
    * to always be active.
    */

    //PTM2MS:地址 0xEF400038,定義PCI存儲空間的大小.這里清零

    sysPciOutLong(PTM2MS, PTM_UNUSED);

    /*
    * Drive PCI 重新置位. 用于熱啟動,置位必須保持1ms
    */


    //解釋: 從PCI寄存器PCI_CFG_BRIDGE_OPT2中讀出數值

    其中 PPC405GP_PCI_BUSDEVFUNC = 0x00000000;

    PCI_CFG_BRIDGE_OPT2 = 0x60

    temp_short = pciConfigIn(PPC405GP_PCI_BUSDEVFUNC, PCI_CFG_BRIDGE_OPT2, 2);

    //把讀出的值放回寄存器PCI_CFG_BRIDGE_OPT2中

    pciConfigOut(PPC405GP_PCI_BUSDEVFUNC, PCI_CFG_BRIDGE_OPT2,
    temp_short | 0x1000, 2);

    sysLocalDelay(1); /* 延時1ms kernel may not be up yet!! */

    //再放一次

    pciConfigOut(PPC405GP_PCI_BUSDEVFUNC, PCI_CFG_BRIDGE_OPT2, temp_short, 2);


    /*
    * 設置PCI Master(PMM),這是從本地存儲地址Local memory address到PCI空間的映射 * CPU->PCI,參見文件 See config.h中的定義,參考 BSP配置文件
    */{{分頁}}


    //說明sysPciOutLong(A,B);放B到A

    //PMM region 0

    //PMM0LA 0xEF400000, PMM0_LOCAL_ADRS 0x80000000

    sysPciOutLong(PMM0LA, PMM0_LOCAL_ADRS);

    //PMM0PCILA 0xEF400008, PMM0_PCI_LOW_ADRS 0x80000000

    sysPciOutLong(PMM0PCILA, PMM0_PCI_LOW_ADRS);

    //PMM0PCIHA 0xEF40000C, PMM0_PCI_HIGH_ADRS 0x00000000

    sysPciOutLong(PMM0PCIHA, PMM0_PCI_HIGH_ADRS);

    //PMM0MA 0xEF400004,

    //PMM0_PCI_MASK_ATTRIB PMM_MASK_512MB|PMM_ENABLE

    sysPciOutLong(PMM0MA, PMM0_PCI_MASK_ATTRIB);


    sysPciOutLong(PMM1LA, PMM1_LOCAL_ADRS); /* PMM region 1 */
    sysPciOutLong(PMM1PCILA, PMM1_PCI_LOW_ADRS);
    sysPciOutLong(PMM1PCIHA, PMM1_PCI_HIGH_ADRS);
    sysPciOutLong(PMM1MA, PMM1_PCI_MASK_ATTRIB);

    sysPciOutLong(PMM2LA, PMM2_LOCAL_ADRS); /* PMM region 2 */
    sysPciOutLong(PMM2PCILA, PMM2_PCI_LOW_ADRS);
    sysPciOutLong(PMM2PCIHA, PMM2_PCI_HIGH_ADRS);
    sysPciOutLong(PMM2MA, PMM2_PCI_MASK_ATTRIB);


    /*
    * 設置 PCI Target (PTM). 這是從PCI的地址到本地地址的映射
    * 參見文件 config.h中的定義
    * 如果不是用 region 2, 必須保證它的使能位關閉,region 1硬件連接使能.
    */


    //PTM1LA 0xEF400034, PTM1_LOCAL_ADRS 0x00000000

    sysPciOutLong(PTM1LA, PTM1_LOCAL_ADRS);

    //PTM1MS 0xEF400030,

    sysPciOutLong(PTM1MS, PTM1_SIZE_ATTRIB);

    ...................

    /*
    * 寫 405GP PCI 設置寄存器.
    * 使能 405GP,使其成為PCI總線的一個master (PMM).
    * 使能 405GP 作為一個PCI memory target (PTM).
    */

    temp_short = pciConfigIn(PPC405GP_PCI_BUSDEVFUNC, PCI_CFG_COMMAND, 2);
    temp_short = temp_short | PCI_CMD_MASTER_ENABLE | PCI_CMD_MEM_ENABLE;
    pciConfigOut(PPC405GP_PCI_BUSDEVFUNC, PCI_CFG_COMMAND, temp_short, 2);

    ..........................


    /*
    * 作為PCI的主機host掃描PCI總線,查找PCI設備. 并為每個設備分配唯一的PCI或I/O地址* 空間
    */

    pciScan(0);
    return;
    }

     

    //pciScan() - 掃描PCI總線,根據PCI ID和 vender ID查找設置現有的PCI設備

    void pciScan
    (
    int busNum
    )
    {
    int Device;
    int BusDevFunc;


    /*
    * 從device 1開始,查找每個Slot,如有PCI設備,分配內存和I/O, 405GP是 device 0.
    */


    for (Device = 1; Device <= WALNUT_NUM_PCI_SLOTS; Device++)
    {
    BusDevFunc = (busNum << 16) | (Device << 11);

    //如果Device存在
    if (pciConfigIn(BusDevFunc, PCI_CFG_VENDOR_ID,2) != 0xFFFF)
    {
    #ifdef PCIDEBUG
    printf("* * * * * * * * * * * * * * * * *n");
    printf("Device %d is presentn",Device);
    #endif
    switch( pciConfigIn(BusDevFunc, PCI_CFG_SUBCLASS, 2) )
    {

    case 0x0604: /* PCI-PCI Bridge */
    break;

    default:
    pciDumpDevice(BusDevFunc); //打印 Vendor ID, Device ID

    //調用pciConfigDevice(BusDevFunc, 6)對PCI設備進行設置


    pciConfigDevice(BusDevFunc, 6);
    }
    }
    else
    {
    #ifdef PCIDEBUG
    printf("Device %d not presentn",Device);
    #endif
    }
    }
    }

    //pciConfigDevice - 為PCI設備配置內存和I/O方式

    void pciConfigDevice(int BusDevFunc,int NumBaseAddr)
    {
    int AddrSlot;
    int i;
    unsigned long AddrDesc;
    unsigned long AddrProg;
    unsigned long Min_Gnt_Val;


    // NumBaseAddr = 6
    for (AddrSlot = 0; AddrSlot < NumBaseAddr; AddrSlot++)
    {

    // PCI_CFG_BASE_ADDRESS_0 = 0x10 將0xFFFFFFFF寫入 PCI_CFG_BASE_ADDRESS_0 + (4*AddrSlot)
    pciConfigOut(BusDevFunc, PCI_CFG_BASE_ADDRESS_0 + (4*AddrSlot),
    0xFFFFFFFF, 4);

    // 從PCI_CFG_BASE_ADDRESS_0 + (4*AddrSlot)讀出數據
    AddrDesc = pciConfigIn(BusDevFunc,
    PCI_CFG_BASE_ADDRESS_0 + (4*AddrSlot),
    4);


    // 如果數據是0,沒有PCI設備,繼續循環搜索
    if (AddrDesc == 0) /* unimplemented, stop looking */
    continue;

    #ifdef PCIDEBUG
    printf("Read Base Addr Reg %d = 0x%08xn",AddrSlot,AddrDesc);
    #endif
    /* 如果AddrDesc的位0是0,表示是Mem方式 */
    if ((AddrDesc & 1) == 0)
    {
    AddrDesc &= 0xFFFFFFF0;

    for (i = 0; (AddrDesc & 1) != 1; i++) //查詢Mem的大小
    AddrDesc = AddrDesc >> 1;

    AddrDesc = 1 << i;

    if ((unsigned long)AddrDesc < 4096)
    AddrDesc = 4096;
    #ifdef PCIDEBUG
    printf(" PCI Memory space = 0x%x bytes n",AddrDesc);
    #endif
    for (AddrProg = PCI_MEMORY_START;
    AddrProg < LowestMemAddr;
    AddrProg += AddrDesc);{{分頁}}

    pciConfigOut(BusDevFunc, PCI_CFG_BASE_ADDRESS_0 + (4*AddrSlot),
    AddrProg, 4);
    LowestMemAddr = AddrProg + AddrDesc;
    }
    else /* I/O 方式*/
    {
    AddrDesc &= 0xFFFFFFFC;

    for (i = 0; (AddrDesc & 1) != 1; i++) //查詢I/O空間的大小
    AddrDesc = AddrDesc >> 1;

    AddrDesc = 1 << i;
    #ifdef PCIDEBUG
    printf(" PCI I/O space = 0x%x bytes n",AddrDesc);
    #endif
    for (AddrProg = PCI_IO_REGION_1_START;
    AddrProg < LowestIOAddr;
    AddrProg += AddrDesc);

    pciConfigOut(BusDevFunc, PCI_CFG_BASE_ADDRESS_0 + (4*AddrSlot),
    AddrProg, 4);
    LowestIOAddr = AddrProg + AddrDesc;
    }

    }


    /*
    * Read Min_Gnt(0x3eh) register value and write it to
    * the Latency Timer(0xdh) register
    */
    Min_Gnt_Val = 0x80;
    pciConfigOut(BusDevFunc, PCI_CFG_LATENCY_TIMER, Min_Gnt_Val, 1);

    }

    2.PCI網卡驅動調用過程

    sysNet.c用于初始化系統的網絡

    文件sysNet.c中void sysNetHwInit(void)定義了,這里以AMD PCI網卡97x為例:

    #ifdef INCLUDE_PCI_NETWORK
    unsigned char sysEnetAddr [6]; /* 網卡的 MAC 地址 */
    char sys97xLoadString[100]; /* 需要為初始化加載的字符串 */
    #endif

    #ifdef INCLUDE_PCI_NETWORK
    STATUS sysIn97xEndBldLoadStr() // 生成網絡初始化的字符串


    函數sysIn97xEndBldLoadStr()調用pciFindDevice()

    STATUS pciFindDevice //用Vendor ID和Device ID查找PCI網卡
    (
    int VendorID,
    int DeviceID,
    int index,
    int *busDevFunc
    )
    {
    int Device;
    int tmpBusDevFunc;
    int tmpIndex;
    int busNum;

    tmpIndex = 0;
    for (busNum = MaxBusNum; busNum >= 0; busNum--) //查訊Slot
    {
    for (Device = 0; Device <= WALNUT_NUM_PCI_SLOTS; Device++)
    {
    tmpBusDevFunc = (busNum << 16) | (Device << 11);

    // 如果指定寄存器中Vendor ID和Device ID正確,賦值給*busDevFunc,返回

    if (pciConfigIn(tmpBusDevFunc, PCI_CFG_VENDOR_ID, 2) == VendorID
    && pciConfigIn(tmpBusDevFunc, PCI_CFG_DEVICE_ID, 2) == DeviceID)
    {
    if (tmpIndex == index)
    {
    *busDevFunc = tmpBusDevFunc;
    return (OK);
    }
    else /* have a match, but not correct index */
    {
    tmpIndex++;
    }
    } } }
    return (ERROR); }


    sysln97xEndBldLoadStr(..)查找PCI以太網卡,得到PCI網卡的基地址,根據PCI插槽Slot選擇正確的中斷向量,讀網卡的MAC地址,然后調用ln97xEndLoad

    STATUS sysln97xEndBldLoadStr ( void )
    {
    int i;
    int intvec;
    int intlvl;
    ULONG pciMemAddr;
    unsigned int busDevFunc;


    /*
    * 在PCI總線上查找設置第一個AMD設備.
    * 如果發現存在,函數pciFindDevice 為busDevFunc賦值
    */

    if (pciFindDevice(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_79C97X, 0, &busDevFunc))
    return(ERROR);

    /*
    * 97x的基地址 1 包含PCI存儲空間的基地址.
    */
    pciMemAddr = pciConfigIn(busDevFunc, PCI_CFG_BASE_ADDRESS_1, 4);
    pciMemAddr &= 0xFFFFFFF0;

    /*
    * 設置PCI定時器反應時間為50 Set latency timer to 50.
    */
    pciConfigOut(busDevFunc, PCI_LATENCY_TIMER, 50, 1);

    /*
    * 每個PCI插槽連接到中斷控制器的管腳不一樣,中斷取決于網卡插在哪一個PCI插槽上.
    */
    switch ((busDevFunc & 0x0000F800) >> 11) /* Strip off just the device */
    {
    case 1 : intvec = INT_VEC_PCI_SLOT3; /* 插槽 3 */
    intlvl = INT_LVL_PCI_SLOT3;
    break;
    case 2 : intvec = INT_VEC_PCI_SLOT2; /* 插槽 2 */
    intlvl = INT_LVL_PCI_SLOT2;
    break;
    case 3 : intvec = INT_VEC_PCI_SLOT1; /* 插槽 1 */
    intlvl = INT_LVL_PCI_SLOT1;
    break;
    case 4 : intvec = INT_VEC_PCI_SLOT0; /* 插槽 0 */
    intlvl = INT_LVL_PCI_SLOT0;
    break;
    default : return(ERROR); /* Not possible, error */

    }

    /*
    * 使能PCI Mem cycles 和 總線 Master 操作
    */
    pciConfigOut(busDevFunc, PCI_CFG_COMMAND,
    PCI_CMD_MEM_ENABLE | PCI_CMD_MASTER_ENABLE, 2);

    /*
    * 得到網卡的MAC地址
    */
    for (i=0; i<6; i++)
    sysEnetAddr = sysInByte(pciMemAddr+APROM01+i);

    /*
    * 生成初始化字符串,如一下形式:
    *
    * <devMemAddr>:<devIoAddr>:<pciMemBase>:<vecNum>:<intLvl>:<memAdrs>:
    * <memSize>:<memWidth>:<csr3b>:<offset>:<flags>
    *
    * 這個字符串將在函數muxEndLoad()中加載
    */

    sprintf(sys97xLoadString, "0x%x:0x%x:0:%d:%d:0x%x:0:0x%x:0:0:0",
    (unsigned int)pciMemAddr, NONE, intvec, intlvl,
    NONE,NONE);

    return(OK);

    }



    關鍵詞: PCI設備 初始化

    評論


    相關推薦

    技術專區

    關閉
    主站蜘蛛池模板: 抚州市| 牙克石市| 靖西县| 柞水县| 双流县| 邵阳市| 老河口市| 柳江县| 宣化县| 景东| 天津市| 邯郸县| 抚顺县| 宁德市| 莒南县| 泸州市| 韩城市| 彰化县| 雷山县| 双城市| 璧山县| 岳阳市| 泸水县| 北流市| 开鲁县| 黎川县| 蕲春县| 林州市| 五寨县| 拜城县| 广安市| 荣成市| 五峰| 镇康县| 左权县| 河南省| 财经| 高阳县| 祥云县| 息烽县| 财经|