Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

578 lines
16 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name:
  4. pcienum.c
  5. Abstract:
  6. This module contains support routines for the Pci bus enumeration.
  7. Author:
  8. Bassam Tabbara (bassamt) 05-Aug-2001
  9. Environment:
  10. Real mode
  11. --*/
  12. #include "hwdetect.h"
  13. typedef VOID (*PINTERFACE_REFERENCE)(PVOID Context);
  14. typedef VOID (*PINTERFACE_DEREFERENCE)(PVOID Context);
  15. typedef PVOID PDEVICE_OBJECT;
  16. #include "pci.h"
  17. #include "pcienum.h"
  18. #include <string.h>
  19. #define PCI_FIXED_HDR_LENGTH 16 // Through BIST
  20. #define UnusedParameter(x) (void)x
  21. #define X86_FLAG_IF 0x0200
  22. #define TURN_INTERRUPTS_OFF(_s_) \
  23. __asm { \
  24. __asm pushf \
  25. __asm pop ax \
  26. __asm mov _s_,ax \
  27. __asm cli \
  28. }
  29. #define RESTORE_INTERRUPTS(_s_) \
  30. do { \
  31. if ((_s_) & X86_FLAG_IF) { \
  32. __asm sti \
  33. } \
  34. } while (0)
  35. //////////////////////////////////////////////////////////// PCI Mechanism #0.
  36. //
  37. static ULONG PciReadInt32_0(
  38. UCHAR nBus,
  39. UCHAR nDev,
  40. UCHAR nFun,
  41. UCHAR nReg)
  42. {
  43. UnusedParameter(nBus);
  44. UnusedParameter(nDev);
  45. UnusedParameter(nFun);
  46. UnusedParameter(nReg);
  47. return ~0u;
  48. }
  49. static VOID PciWriteInt32_0(
  50. UCHAR nBus,
  51. UCHAR nDev,
  52. UCHAR nFun,
  53. UCHAR nReg,
  54. ULONG Data)
  55. {
  56. UnusedParameter(nBus);
  57. UnusedParameter(nDev);
  58. UnusedParameter(nFun);
  59. UnusedParameter(nReg);
  60. UnusedParameter(Data);
  61. return;
  62. }
  63. //////////////////////////////////////////////////////////// PCI Mechanism #1.
  64. //
  65. static ULONG PciReadInt32_1(
  66. UCHAR nBus,
  67. UCHAR nDev,
  68. UCHAR nFun,
  69. UCHAR nReg)
  70. {
  71. USHORT fl;
  72. ULONG data = 0;
  73. PCI_TYPE1_CFG_BITS cfg;
  74. cfg.u.bits.Reserved1 = 0;
  75. cfg.u.bits.RegisterNumber = nReg >> 2;
  76. cfg.u.bits.FunctionNumber = nFun;
  77. cfg.u.bits.DeviceNumber = nDev;
  78. cfg.u.bits.BusNumber = nBus;
  79. cfg.u.bits.Reserved2 = 0;
  80. cfg.u.bits.Enable = 1;
  81. TURN_INTERRUPTS_OFF(fl);
  82. WRITE_PORT_ULONG((PUSHORT)PCI_TYPE1_ADDR_PORT, (ULONG)cfg.u.AsULONG); // Select
  83. data = READ_PORT_ULONG((PUSHORT)PCI_TYPE1_DATA_PORT); // Fetch
  84. RESTORE_INTERRUPTS(fl);
  85. return data;
  86. }
  87. static VOID PciWriteInt32_1(
  88. UCHAR nBus,
  89. UCHAR nDev,
  90. UCHAR nFun,
  91. UCHAR nReg,
  92. ULONG Data)
  93. {
  94. USHORT fl;
  95. PCI_TYPE1_CFG_BITS cfg;
  96. cfg.u.bits.Reserved1 = 0;
  97. cfg.u.bits.RegisterNumber = nReg >> 2;
  98. cfg.u.bits.FunctionNumber = nFun;
  99. cfg.u.bits.DeviceNumber = nDev;
  100. cfg.u.bits.BusNumber = nBus;
  101. cfg.u.bits.Reserved2 = 0;
  102. cfg.u.bits.Enable = 1;
  103. TURN_INTERRUPTS_OFF(fl);
  104. WRITE_PORT_ULONG((PUSHORT)PCI_TYPE1_ADDR_PORT, cfg.u.AsULONG); // Select
  105. WRITE_PORT_ULONG((PUSHORT)PCI_TYPE1_DATA_PORT, Data); // Write
  106. RESTORE_INTERRUPTS(fl);
  107. }
  108. //////////////////////////////////////////////////////////// PCI Mechanism #2.
  109. //
  110. static ULONG PciReadInt32_2(
  111. UCHAR nBus,
  112. UCHAR nDev,
  113. UCHAR nFun,
  114. UCHAR nReg)
  115. {
  116. USHORT fl;
  117. ULONG data = 0;
  118. PCI_TYPE2_CSE_BITS cse;
  119. PCI_TYPE2_ADDRESS_BITS adr;
  120. cse.u.bits.Enable = 1;
  121. cse.u.bits.FunctionNumber = nFun;
  122. cse.u.bits.Key = 0xf;
  123. adr.u.bits.RegisterNumber = nReg;
  124. adr.u.bits.Agent = nDev;
  125. adr.u.bits.AddressBase = PCI_TYPE2_ADDRESS_BASE;
  126. TURN_INTERRUPTS_OFF(fl);
  127. WRITE_PORT_UCHAR((PUCHAR)PCI_TYPE2_FORWARD_PORT, nBus); // Select bus
  128. WRITE_PORT_UCHAR((PUCHAR)PCI_TYPE2_CSE_PORT, cse.u.AsUCHAR); // Select function & mapping
  129. data = READ_PORT_ULONG((PUSHORT)adr.u.AsUSHORT); // Fetch
  130. WRITE_PORT_UCHAR((PUCHAR)PCI_TYPE2_CSE_PORT, 0); // Disable mapping.
  131. RESTORE_INTERRUPTS(fl);
  132. return data;
  133. }
  134. static VOID PciWriteInt32_2(
  135. UCHAR nBus,
  136. UCHAR nDev,
  137. UCHAR nFun,
  138. UCHAR nReg,
  139. ULONG Data)
  140. {
  141. USHORT fl;
  142. PCI_TYPE2_CSE_BITS cse;
  143. PCI_TYPE2_ADDRESS_BITS adr;
  144. cse.u.bits.Enable = 1;
  145. cse.u.bits.FunctionNumber = nFun;
  146. cse.u.bits.Key = 0xf;
  147. adr.u.bits.RegisterNumber = nReg;
  148. adr.u.bits.Agent = nDev;
  149. adr.u.bits.AddressBase = PCI_TYPE2_ADDRESS_BASE;
  150. TURN_INTERRUPTS_OFF(fl);
  151. WRITE_PORT_UCHAR((PUCHAR)PCI_TYPE2_FORWARD_PORT, nBus); // Select bus
  152. WRITE_PORT_UCHAR((PUCHAR)PCI_TYPE2_CSE_PORT, cse.u.AsUCHAR); // Select function & mapping
  153. WRITE_PORT_ULONG((PUSHORT)adr.u.AsUSHORT, Data); // Write
  154. WRITE_PORT_UCHAR((PUCHAR)PCI_TYPE2_CSE_PORT, 0); // Disable mapping.
  155. RESTORE_INTERRUPTS(fl);
  156. }
  157. /////////////////////////////////////////////////////////// PCI Configuration.
  158. //
  159. typedef ULONG (*PF_PCI_READ)(UCHAR nBus,
  160. UCHAR nDev,
  161. UCHAR nFun,
  162. UCHAR nReg);
  163. typedef VOID (*PF_PCI_WRITE)(UCHAR nBus,
  164. UCHAR nDev,
  165. UCHAR nFun,
  166. UCHAR nReg,
  167. ULONG Data);
  168. static UCHAR s_nPciMajorRevision = 0;
  169. static UCHAR s_nPciMinorRevision = 0;
  170. static UCHAR s_nPciNumberOfBuses = 0;
  171. static PF_PCI_READ s_pPciRead = PciReadInt32_0;
  172. static PF_PCI_WRITE s_pPciWrite = PciWriteInt32_0;
  173. //////////////////////////////////////////////////////////////////////////////
  174. //
  175. ULONG PciReadConfig(ULONG nDevIt, ULONG cbOffset, UCHAR *pbData, ULONG cbData)
  176. {
  177. ULONG cbDone;
  178. UCHAR nBus = PCI_ITERATOR_TO_BUS(nDevIt);
  179. UCHAR nDev = PCI_ITERATOR_TO_DEVICE(nDevIt);
  180. UCHAR nFun = PCI_ITERATOR_TO_FUNCTION(nDevIt);
  181. // CONFIG space is a space of aligned DWORDs, according to specs.
  182. // Therefore, if Offset is not aligned the caller is confused.
  183. //
  184. if ((cbOffset & 0x3) || (cbData & 0x3)) {
  185. #if DBG
  186. BlPrint("CPci::ReadConfig() called with Offset=x%x, Length=x%x\n", cbOffset, cbData);
  187. #endif
  188. return 0;
  189. }
  190. for (cbDone = 0; cbDone < cbData; cbDone += sizeof(ULONG)) {
  191. *((ULONG*)pbData)++ = s_pPciRead(nBus, nDev, nFun,
  192. (UCHAR)(cbOffset + cbDone));
  193. }
  194. return cbDone;
  195. }
  196. ULONG PciWriteConfig(ULONG nDevIt, ULONG cbOffset, UCHAR *pbData, ULONG cbData)
  197. {
  198. ULONG cbDone;
  199. UCHAR nBus = PCI_ITERATOR_TO_BUS(nDevIt);
  200. UCHAR nDev = PCI_ITERATOR_TO_DEVICE(nDevIt);
  201. UCHAR nFun = PCI_ITERATOR_TO_FUNCTION(nDevIt);
  202. // CONFIG space is a space of aligned DWORDs, according to specs.
  203. // Therefore, if Offset is not aligned the caller is confused.
  204. //
  205. if ((cbOffset & 0x3) || (cbData & 0x3)) {
  206. #if DBG
  207. BlPrint("CPci::ReadConfig() called with Offset=x%x, Length=x%x\n", cbOffset, cbData);
  208. #endif
  209. return 0;
  210. }
  211. for (cbDone = 0; cbDone < cbData; cbDone += sizeof(ULONG)) {
  212. s_pPciWrite(nBus, nDev, nFun, (UCHAR)(cbOffset + cbDone),
  213. *((ULONG*)pbData)++);
  214. }
  215. return cbDone;
  216. }
  217. ULONG PciFindDevice(USHORT VendorId, USHORT DeviceId, ULONG nBegDevIt)
  218. {
  219. ULONG nDevIt;
  220. UCHAR nBus = 0;
  221. UCHAR nDev = 0;
  222. UCHAR nFun = 0;
  223. if (nBegDevIt != 0) {
  224. nBus = (UCHAR)PCI_ITERATOR_TO_BUS(nBegDevIt);
  225. nDev = (UCHAR)PCI_ITERATOR_TO_DEVICE(nBegDevIt);
  226. nFun = (UCHAR)(PCI_ITERATOR_TO_FUNCTION(nBegDevIt) + 1);
  227. }
  228. //
  229. // for each PCI bus
  230. //
  231. for (; nBus < s_nPciNumberOfBuses; nBus++) {
  232. //
  233. // for each PCI Device on the bus
  234. //
  235. for (; nDev < PCI_MAX_DEVICES; nDev++) {
  236. BOOLEAN bIsMultiFunction;
  237. PCI_COMMON_CONFIG config;
  238. //
  239. // Check if we have a device on function 0
  240. //
  241. config.VendorID = PCI_INVALID_VENDORID;
  242. PciReadConfig( PCI_TO_ITERATOR(nBus, nDev, 0),
  243. 0,
  244. (UCHAR*)&config,
  245. PCI_FIXED_HDR_LENGTH );
  246. // No device on function 0, skip to next device
  247. if (config.VendorID == PCI_INVALID_VENDORID) {
  248. continue;
  249. }
  250. // check if the device is a multifunction device
  251. bIsMultiFunction = config.HeaderType & PCI_MULTIFUNCTION;
  252. for (; nFun < PCI_MAX_FUNCTION; nFun++) {
  253. // function numbers greater than zero
  254. // are only allowed on multifunction devices.
  255. if (nFun > 0 && !bIsMultiFunction) {
  256. break;
  257. }
  258. // Read configuration header.
  259. //
  260. nDevIt = PCI_TO_ITERATOR(nBus, nDev, nFun);
  261. config.VendorID = PCI_INVALID_VENDORID;
  262. PciReadConfig(nDevIt, 0, (UCHAR*)&config, PCI_FIXED_HDR_LENGTH);
  263. // No function found, skip to next function
  264. if (config.VendorID == PCI_INVALID_VENDORID) {
  265. continue;
  266. }
  267. if (VendorId == 0 ||
  268. (VendorId == config.VendorID &&
  269. (DeviceId == 0 || DeviceId == config.DeviceID))) {
  270. return nDevIt;
  271. }
  272. }
  273. nFun = 0;
  274. }
  275. nDev = 0;
  276. }
  277. return 0;
  278. }
  279. BOOLEAN PciInit(PCI_REGISTRY_INFO *pPCIReg)
  280. {
  281. s_nPciMajorRevision = pPCIReg->MajorRevision;
  282. s_nPciMinorRevision = pPCIReg->MinorRevision;
  283. s_nPciNumberOfBuses = pPCIReg->NoBuses;
  284. if ((pPCIReg->HardwareMechanism & 0x0F) == 1) {
  285. s_pPciRead = PciReadInt32_1;
  286. s_pPciWrite = PciWriteInt32_1;
  287. }
  288. else if ((pPCIReg->HardwareMechanism & 0x0F) == 2) {
  289. s_pPciRead = PciReadInt32_2;
  290. s_pPciWrite = PciWriteInt32_2;
  291. }
  292. else {
  293. #if DBG
  294. BlPrint("Unknown PCI HW Mechanism!\n");
  295. #endif
  296. return FALSE;
  297. }
  298. return TRUE;
  299. }
  300. #if DBG
  301. #define PCI_SUCCESSFUL 0x00
  302. #define PCI_BAD_REGISTER_NUMBER 0x87
  303. UCHAR PciBiosReadConfig(ULONG nDevIt, UCHAR cbOffset, UCHAR * pbData, ULONG cbData)
  304. {
  305. UCHAR returnCode = 0;
  306. UCHAR nBus = (UCHAR)PCI_ITERATOR_TO_BUS(nDevIt);
  307. UCHAR nDev = (UCHAR)PCI_ITERATOR_TO_DEVICE(nDevIt);
  308. UCHAR nFun = (UCHAR)PCI_ITERATOR_TO_FUNCTION(nDevIt);
  309. // CONFIG space is a space of aligned DWORDs, according to specs.
  310. // Therefore, if Offset is not aligned the caller is confused.
  311. //
  312. if ((cbOffset & 0x3) || (cbData & 0x3)) {
  313. #if DBG
  314. BlPrint("PciNewReadConfig() called with Offset=x%x, Length=x%x\n",
  315. cbOffset, cbData);
  316. #endif
  317. return 0;
  318. }
  319. for (cbData += cbOffset; cbOffset < cbData;
  320. cbOffset += sizeof(ULONG), ((ULONG *)pbData)++) {
  321. returnCode = HwGetPciConfigurationDword(nBus, nDev, nFun,
  322. cbOffset, (ULONG *)pbData);
  323. if (returnCode == PCI_BAD_REGISTER_NUMBER) {
  324. #if DBG
  325. BlPrint("PciNewReadConfig() failed with returncode=x%x, Bus=x%x\n\tDevice=x%x, Function=x%x, Offset=x%x\n",
  326. returnCode, nBus, nDev, nFun, cbOffset);
  327. #endif
  328. break;
  329. }
  330. }
  331. return returnCode;
  332. }
  333. ULONG PciBiosFindDevice(USHORT VendorId, USHORT DeviceId, ULONG nBegDevIt)
  334. {
  335. ULONG nDevIt;
  336. UCHAR nBus = 0;
  337. UCHAR nDev = 0;
  338. UCHAR nFun = 0;
  339. UCHAR resultCode;
  340. if (nBegDevIt != 0) {
  341. nBus = (UCHAR)PCI_ITERATOR_TO_BUS(nBegDevIt);
  342. nDev = (UCHAR)PCI_ITERATOR_TO_DEVICE(nBegDevIt);
  343. nFun = (UCHAR)(PCI_ITERATOR_TO_FUNCTION(nBegDevIt) + 1);
  344. }
  345. //
  346. // for each PCI bus
  347. //
  348. for (; nBus < s_nPciNumberOfBuses; nBus++) {
  349. //
  350. // for each PCI Device on the bus
  351. //
  352. for (; nDev < PCI_MAX_DEVICES; nDev++) {
  353. BOOLEAN bIsMultiFunction;
  354. PCI_COMMON_CONFIG config;
  355. //
  356. // Check if we have a device on function 0
  357. //
  358. config.VendorID = PCI_INVALID_VENDORID;
  359. resultCode = PciBiosReadConfig( PCI_TO_ITERATOR(nBus, nDev, 0),
  360. 0,
  361. (UCHAR*)&config,
  362. PCI_FIXED_HDR_LENGTH );
  363. if (resultCode != PCI_SUCCESSFUL) {
  364. #if DBG
  365. BlPrint("PciBiosReadConfig() failed reading config, result: %x, Bus: %x, Device: %x, Function: %x\n",
  366. resultCode, nBus, nDev, 0);
  367. #endif
  368. return 0;
  369. }
  370. // No device on function 0, skip to next device
  371. if (config.VendorID == PCI_INVALID_VENDORID) {
  372. continue;
  373. }
  374. // check if the device is a multifunction device
  375. bIsMultiFunction = config.HeaderType & PCI_MULTIFUNCTION;
  376. for (; nFun < PCI_MAX_FUNCTION; nFun++) {
  377. // function numbers greater than zero
  378. // are only allowed on multifunction devices.
  379. if (nFun > 0 && !bIsMultiFunction) {
  380. break;
  381. }
  382. // Read configuration header.
  383. //
  384. nDevIt = PCI_TO_ITERATOR(nBus, nDev, nFun);
  385. config.VendorID = PCI_INVALID_VENDORID;
  386. resultCode = PciBiosReadConfig( nDevIt,
  387. 0,
  388. (UCHAR*)&config,
  389. PCI_FIXED_HDR_LENGTH );
  390. if (resultCode != PCI_SUCCESSFUL) {
  391. #if DBG
  392. BlPrint("PciBiosReadConfig() failed reading config, result: %x, Bus: %x, Device: %x, Function: %x\n",
  393. resultCode, nBus, nDev, nFun);
  394. #endif
  395. return 0;
  396. }
  397. // No function found, skip to next function
  398. if (config.VendorID == PCI_INVALID_VENDORID) {
  399. continue;
  400. }
  401. if (VendorId == 0 ||
  402. (VendorId == config.VendorID &&
  403. (DeviceId == 0 || DeviceId == config.DeviceID))) {
  404. return nDevIt;
  405. }
  406. }
  407. nFun = 0;
  408. }
  409. nDev = 0;
  410. }
  411. return 0;
  412. }
  413. VOID
  414. ScanPCIViaBIOS(
  415. PPCI_REGISTRY_INFO pPciEntry
  416. )
  417. {
  418. ULONG nDevIt;
  419. USHORT PCIDeviceCount = 0;
  420. UCHAR ResultCode;
  421. #if DBG
  422. clrscrn ();
  423. BlPrint("\nEnumerating PCI Devices via the BIOS...\n");
  424. #endif // DBG
  425. PciInit(pPciEntry);
  426. //
  427. // Count the devices
  428. //
  429. PCIDeviceCount = 0;
  430. for (nDevIt = 0; (nDevIt = PciBiosFindDevice(0, 0, nDevIt)) != 0;) {
  431. PCIDeviceCount++;
  432. }
  433. BlPrint("Found %d PCI devices\n", PCIDeviceCount );
  434. //
  435. // Fill in Device Information
  436. //
  437. PCIDeviceCount = 0;
  438. for (nDevIt = 0; (nDevIt = PciBiosFindDevice(0, 0, nDevIt)) != 0;) {
  439. PCI_COMMON_CONFIG config;
  440. _fmemset(&config, 0, (USHORT)PCI_COMMON_HDR_LENGTH);
  441. ResultCode = PciBiosReadConfig(nDevIt, 0, (UCHAR*)&config, PCI_COMMON_HDR_LENGTH);
  442. if (ResultCode != 0) {
  443. BlPrint("PciBiosReadConfig() failed reading config, result: %x, BusDevFn: %x\n",
  444. ResultCode, nDevIt);
  445. break;
  446. }
  447. {
  448. USHORT x = (config.BaseClass << 8) + config.SubClass;
  449. BlPrint("%d: %d.%d.%d: PCI\\VEN_%x&DEV_%x&SUBSYS_%x%x&REV_%x&CC_%x",
  450. PCIDeviceCount,
  451. PCI_ITERATOR_TO_BUS(nDevIt),
  452. PCI_ITERATOR_TO_DEVICE(nDevIt),
  453. PCI_ITERATOR_TO_FUNCTION(nDevIt),
  454. config.VendorID,
  455. config.DeviceID,
  456. config.u.type0.SubVendorID,
  457. config.u.type0.SubSystemID,
  458. config.RevisionID,
  459. x );
  460. if ( (config.HeaderType & (~PCI_MULTIFUNCTION) ) == PCI_BRIDGE_TYPE) {
  461. BlPrint(" Brdg %d->%d\n",
  462. config.u.type1.PrimaryBus,
  463. config.u.type1.SecondaryBus );
  464. } else {
  465. BlPrint("\n");
  466. }
  467. }
  468. PCIDeviceCount++;
  469. }
  470. BlPrint("Enumerating PCI devices via BIOS complete...\n");
  471. while ( ! HwGetKey ());
  472. clrscrn();
  473. return;
  474. }
  475. #endif