<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁 > PCI設(shè)備初始化編程的過程

          PCI設(shè)備初始化編程的過程

          ——
          作者: 時(shí)間:2007-03-06 來源:電子產(chǎn)品世界 收藏

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

          PowerPC的PCI控制器符合PCI2.2標(biāo)準(zhǔn),以下使我解讀的VxWorks系統(tǒng)程序代碼分析

          主要執(zhí)行過程

          1.PCI設(shè)備

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

          syslib.c

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

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

          //和網(wǎng)絡(luò),PCI有關(guān)的函數(shù)

          #ifdef INCLUDE_EMAC_NETWORK


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

          malReset();

          #endif

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

          #ifdef INCLUDE_NETWORK
          sysNetHwInit(); //初始化網(wǎng)絡(luò)接口
          #endif

          }

           

          //該函數(shù)初始化PCI

          PCI的地址轉(zhuǎn)換形式:

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

          void pciInit()
          {

          unsigned short temp_short;

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

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

          /*

          解釋:

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

          在PLB上共有三個(gè)ranges, PMM1MA代表區(qū)域rang1, PMM2MA代表區(qū)域range2.

          PMM_UNUSED: 0x00000000

          range的定義

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

          PPBridge(PLB和PCI設(shè)備間的接口)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存儲(chǔ)空間的大小.這里清零

          sysPciOutLong(PTM2MS, PTM_UNUSED);

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


          //解釋: 從PCI寄存器PCI_CFG_BRIDGE_OPT2中讀出數(shù)值

          其中 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); /* 延時(shí)1ms kernel may not be up yet!! */

          //再放一次

          pciConfigOut(PPC405GP_PCI_BUSDEVFUNC, PCI_CFG_BRIDGE_OPT2, temp_short, 2);


          /*
          * 設(shè)置PCI Master(PMM),這是從本地存儲(chǔ)地址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);


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


          //PTM1LA 0xEF400034, PTM1_LOCAL_ADRS 0x00000000

          sysPciOutLong(PTM1LA, PTM1_LOCAL_ADRS);

          //PTM1MS 0xEF400030,

          sysPciOutLong(PTM1MS, PTM1_SIZE_ATTRIB);

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

          /*
          * 寫 405GP PCI 設(shè)置寄存器.
          * 使能 405GP,使其成為PCI總線的一個(gè)master (PMM).
          * 使能 405GP 作為一個(gè)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的主機(jī)host掃描PCI總線,查找PCI設(shè)備. 并為每個(gè)設(shè)備分配唯一的PCI或I/O地址* 空間
          */

          pciScan(0);
          return;
          }

           

          //pciScan() - 掃描PCI總線,根據(jù)PCI ID和 vender ID查找設(shè)置現(xiàn)有的PCI設(shè)備

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


          /*
          * 從device 1開始,查找每個(gè)Slot,如有PCI設(shè)備,分配內(nèi)存和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

          //調(diào)用pciConfigDevice(BusDevFunc, 6)對(duì)PCI設(shè)備進(jìn)行設(shè)置


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

          //pciConfigDevice - 為PCI設(shè)備配置內(nèi)存和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)讀出數(shù)據(jù)
          AddrDesc = pciConfigIn(BusDevFunc,
          PCI_CFG_BASE_ADDRESS_0 + (4*AddrSlot),
          4);


          // 如果數(shù)據(jù)是0,沒有PCI設(shè)備,繼續(xù)循環(huán)搜索
          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網(wǎng)卡驅(qū)動(dòng)調(diào)用過程

          sysNet.c用于初始化系統(tǒng)的網(wǎng)絡(luò)

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

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

          #ifdef INCLUDE_PCI_NETWORK
          STATUS sysIn97xEndBldLoadStr() // 生成網(wǎng)絡(luò)初始化的字符串


          函數(shù)sysIn97xEndBldLoadStr()調(diào)用pciFindDevice()

          STATUS pciFindDevice //用Vendor ID和Device ID查找PCI網(wǎng)卡
          (
          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以太網(wǎng)卡,得到PCI網(wǎng)卡的基地址,根據(jù)PCI插槽Slot選擇正確的中斷向量,讀網(wǎng)卡的MAC地址,然后調(diào)用ln97xEndLoad

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


          /*
          * 在PCI總線上查找設(shè)置第一個(gè)AMD設(shè)備.
          * 如果發(fā)現(xiàn)存在,函數(shù)pciFindDevice 為busDevFunc賦值
          */

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

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

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

          /*
          * 每個(gè)PCI插槽連接到中斷控制器的管腳不一樣,中斷取決于網(wǎng)卡插在哪一個(gè)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);

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

          /*
          * 生成初始化字符串,如一下形式:
          *
          * <devMemAddr>:<devIoAddr>:<pciMemBase>:<vecNum>:<intLvl>:<memAdrs>:
          * <memSize>:<memWidth>:<csr3b>:<offset>:<flags>
          *
          * 這個(gè)字符串將在函數(shù)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);

          }



          關(guān)鍵詞: PCI設(shè)備 初始化

          評(píng)論


          相關(guān)推薦

          技術(shù)專區(qū)

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();