Source code of Windows XP (NT5)
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.

366 lines
9.6 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. #define PCI_FIXED_HDR_LENGTH 16 // Through BIST
  19. #define UnusedParameter(x) (void)x
  20. #define X86_FLAG_IF 0x0200
  21. #define TURN_INTERRUPTS_OFF(_s_) \
  22. __asm { \
  23. __asm pushf \
  24. __asm pop ax \
  25. __asm mov _s_,ax \
  26. __asm cli \
  27. }
  28. #define RESTORE_INTERRUPTS(_s_) \
  29. do { \
  30. if ((_s_) & X86_FLAG_IF) { \
  31. __asm sti \
  32. } \
  33. } while (0)
  34. //////////////////////////////////////////////////////////// PCI Mechanism #0.
  35. //
  36. static ULONG PciReadInt32_0(
  37. UCHAR nBus,
  38. UCHAR nDev,
  39. UCHAR nFun,
  40. UCHAR nReg)
  41. {
  42. UnusedParameter(nBus);
  43. UnusedParameter(nDev);
  44. UnusedParameter(nFun);
  45. UnusedParameter(nReg);
  46. return ~0u;
  47. }
  48. static VOID PciWriteInt32_0(
  49. UCHAR nBus,
  50. UCHAR nDev,
  51. UCHAR nFun,
  52. UCHAR nReg,
  53. ULONG Data)
  54. {
  55. UnusedParameter(nBus);
  56. UnusedParameter(nDev);
  57. UnusedParameter(nFun);
  58. UnusedParameter(nReg);
  59. UnusedParameter(Data);
  60. return;
  61. }
  62. //////////////////////////////////////////////////////////// PCI Mechanism #1.
  63. //
  64. static ULONG PciReadInt32_1(
  65. UCHAR nBus,
  66. UCHAR nDev,
  67. UCHAR nFun,
  68. UCHAR nReg)
  69. {
  70. USHORT fl;
  71. ULONG data = 0;
  72. PCI_TYPE1_CFG_BITS cfg;
  73. cfg.u.bits.Reserved1 = 0;
  74. cfg.u.bits.RegisterNumber = nReg >> 2;
  75. cfg.u.bits.FunctionNumber = nFun;
  76. cfg.u.bits.DeviceNumber = nDev;
  77. cfg.u.bits.BusNumber = nBus;
  78. cfg.u.bits.Reserved2 = 0;
  79. cfg.u.bits.Enable = 1;
  80. TURN_INTERRUPTS_OFF(fl);
  81. WRITE_PORT_ULONG((PUSHORT)PCI_TYPE1_ADDR_PORT, (ULONG)cfg.u.AsULONG); // Select
  82. data = READ_PORT_ULONG((PUSHORT)PCI_TYPE1_DATA_PORT); // Fetch
  83. RESTORE_INTERRUPTS(fl);
  84. return data;
  85. }
  86. static VOID PciWriteInt32_1(
  87. UCHAR nBus,
  88. UCHAR nDev,
  89. UCHAR nFun,
  90. UCHAR nReg,
  91. ULONG Data)
  92. {
  93. USHORT fl;
  94. PCI_TYPE1_CFG_BITS cfg;
  95. cfg.u.bits.Reserved1 = 0;
  96. cfg.u.bits.RegisterNumber = nReg >> 2;
  97. cfg.u.bits.FunctionNumber = nFun;
  98. cfg.u.bits.DeviceNumber = nDev;
  99. cfg.u.bits.BusNumber = nBus;
  100. cfg.u.bits.Reserved2 = 0;
  101. cfg.u.bits.Enable = 1;
  102. TURN_INTERRUPTS_OFF(fl);
  103. WRITE_PORT_ULONG((PUSHORT)PCI_TYPE1_ADDR_PORT, cfg.u.AsULONG); // Select
  104. WRITE_PORT_ULONG((PUSHORT)PCI_TYPE1_DATA_PORT, Data); // Write
  105. RESTORE_INTERRUPTS(fl);
  106. }
  107. //////////////////////////////////////////////////////////// PCI Mechanism #2.
  108. //
  109. static ULONG PciReadInt32_2(
  110. UCHAR nBus,
  111. UCHAR nDev,
  112. UCHAR nFun,
  113. UCHAR nReg)
  114. {
  115. USHORT fl;
  116. ULONG data = 0;
  117. PCI_TYPE2_CSE_BITS cse;
  118. PCI_TYPE2_ADDRESS_BITS adr;
  119. cse.u.bits.Enable = 1;
  120. cse.u.bits.FunctionNumber = nFun;
  121. cse.u.bits.Key = 0xf;
  122. adr.u.bits.RegisterNumber = nReg;
  123. adr.u.bits.Agent = nDev;
  124. adr.u.bits.AddressBase = PCI_TYPE2_ADDRESS_BASE;
  125. TURN_INTERRUPTS_OFF(fl);
  126. WRITE_PORT_UCHAR((PUCHAR)PCI_TYPE2_FORWARD_PORT, nBus); // Select bus
  127. WRITE_PORT_UCHAR((PUCHAR)PCI_TYPE2_CSE_PORT, cse.u.AsUCHAR); // Select function & mapping
  128. data = READ_PORT_ULONG((PUSHORT)adr.u.AsUSHORT); // Fetch
  129. WRITE_PORT_UCHAR((PUCHAR)PCI_TYPE2_CSE_PORT, 0); // Disable mapping.
  130. RESTORE_INTERRUPTS(fl);
  131. return data;
  132. }
  133. static VOID PciWriteInt32_2(
  134. UCHAR nBus,
  135. UCHAR nDev,
  136. UCHAR nFun,
  137. UCHAR nReg,
  138. ULONG Data)
  139. {
  140. USHORT fl;
  141. PCI_TYPE2_CSE_BITS cse;
  142. PCI_TYPE2_ADDRESS_BITS adr;
  143. cse.u.bits.Enable = 1;
  144. cse.u.bits.FunctionNumber = nFun;
  145. cse.u.bits.Key = 0xf;
  146. adr.u.bits.RegisterNumber = nReg;
  147. adr.u.bits.Agent = nDev;
  148. adr.u.bits.AddressBase = PCI_TYPE2_ADDRESS_BASE;
  149. TURN_INTERRUPTS_OFF(fl);
  150. WRITE_PORT_UCHAR((PUCHAR)PCI_TYPE2_FORWARD_PORT, nBus); // Select bus
  151. WRITE_PORT_UCHAR((PUCHAR)PCI_TYPE2_CSE_PORT, cse.u.AsUCHAR); // Select function & mapping
  152. WRITE_PORT_ULONG((PUSHORT)adr.u.AsUSHORT, Data); // Write
  153. WRITE_PORT_UCHAR((PUCHAR)PCI_TYPE2_CSE_PORT, 0); // Disable mapping.
  154. RESTORE_INTERRUPTS(fl);
  155. }
  156. /////////////////////////////////////////////////////////// PCI Configuration.
  157. //
  158. typedef ULONG (*PF_PCI_READ)(UCHAR nBus,
  159. UCHAR nDev,
  160. UCHAR nFun,
  161. UCHAR nReg);
  162. typedef VOID (*PF_PCI_WRITE)(UCHAR nBus,
  163. UCHAR nDev,
  164. UCHAR nFun,
  165. UCHAR nReg,
  166. ULONG Data);
  167. static UCHAR s_nPciMajorRevision = 0;
  168. static UCHAR s_nPciMinorRevision = 0;
  169. static UCHAR s_nPciNumberOfBuses = 0;
  170. static PF_PCI_READ s_pPciRead = PciReadInt32_0;
  171. static PF_PCI_WRITE s_pPciWrite = PciWriteInt32_0;
  172. //////////////////////////////////////////////////////////////////////////////
  173. //
  174. ULONG PciReadConfig(USHORT nDevIt, ULONG cbOffset, UCHAR *pbData, ULONG cbData)
  175. {
  176. ULONG cbDone;
  177. UCHAR nBus = (UCHAR)PCI_ITERATOR_TO_BUS(nDevIt);
  178. UCHAR nDev = (UCHAR)PCI_ITERATOR_TO_DEVICE(nDevIt);
  179. UCHAR nFun = (UCHAR)PCI_ITERATOR_TO_FUNCTION(nDevIt);
  180. // CONFIG space is a space of aligned DWORDs, according to specs.
  181. // Therefore, if Offset is not aligned the caller is confused.
  182. //
  183. if ((cbOffset & 0x3) || (cbData & 0x3)) {
  184. #if DBG
  185. BlPrint("CPci::ReadConfig() called with Offset=x%x, Length=x%x\n", cbOffset, cbData);
  186. #endif
  187. return 0;
  188. }
  189. for (cbDone = 0; cbDone < cbData; cbDone += sizeof(ULONG)) {
  190. *((ULONG*)pbData)++ = s_pPciRead(nBus, nDev, nFun,
  191. (UCHAR)(cbOffset + cbDone));
  192. }
  193. return cbDone;
  194. }
  195. ULONG PciWriteConfig(USHORT nDevIt, ULONG cbOffset, UCHAR *pbData, ULONG cbData)
  196. {
  197. ULONG cbDone;
  198. UCHAR nBus = (UCHAR)PCI_ITERATOR_TO_BUS(nDevIt);
  199. UCHAR nDev = (UCHAR)PCI_ITERATOR_TO_DEVICE(nDevIt);
  200. UCHAR nFun = (UCHAR)PCI_ITERATOR_TO_FUNCTION(nDevIt);
  201. // CONFIG space is a space of aligned DWORDs, according to specs.
  202. // Therefore, if Offset is not aligned the caller is confused.
  203. //
  204. if ((cbOffset & 0x3) || (cbData & 0x3)) {
  205. #if DBG
  206. BlPrint("CPci::ReadConfig() called with Offset=x%x, Length=x%x\n", cbOffset, cbData);
  207. #endif
  208. return 0;
  209. }
  210. for (cbDone = 0; cbDone < cbData; cbDone += sizeof(ULONG)) {
  211. s_pPciWrite(nBus, nDev, nFun, (UCHAR)(cbOffset + cbDone),
  212. *((ULONG*)pbData)++);
  213. }
  214. return cbDone;
  215. }
  216. USHORT PciFindDevice(USHORT VendorId, USHORT DeviceId, USHORT nBegDevIt)
  217. {
  218. USHORT nDevIt;
  219. UCHAR nBus = 0;
  220. UCHAR nDev = 0;
  221. UCHAR nFun = 0;
  222. if (nBegDevIt != 0) {
  223. nBus = (UCHAR)PCI_ITERATOR_TO_BUS(nBegDevIt);
  224. nDev = (UCHAR)PCI_ITERATOR_TO_DEVICE(nBegDevIt);
  225. nFun = (UCHAR)(PCI_ITERATOR_TO_FUNCTION(nBegDevIt) + 1);
  226. }
  227. //
  228. // for each PCI bus
  229. //
  230. for (; nBus < s_nPciNumberOfBuses; nBus++) {
  231. //
  232. // for each PCI Device on the bus
  233. //
  234. for (; nDev < PCI_MAX_DEVICES; nDev++) {
  235. BOOLEAN bIsMultiFunction;
  236. PCI_COMMON_CONFIG config;
  237. //
  238. // Check if we have a device on function 0
  239. //
  240. config.VendorID = PCI_INVALID_VENDORID;
  241. PciReadConfig( PCI_TO_ITERATOR(nBus, nDev, 0),
  242. 0,
  243. (UCHAR*)&config,
  244. PCI_FIXED_HDR_LENGTH );
  245. // No device on function 0, skip to next device
  246. if (config.VendorID == PCI_INVALID_VENDORID) {
  247. continue;
  248. }
  249. // check if the device is a multifunction device
  250. bIsMultiFunction = config.HeaderType & PCI_MULTIFUNCTION;
  251. for (; nFun < PCI_MAX_FUNCTION; nFun++) {
  252. // function numbers greater than zero
  253. // are only allowed on multifunction devices.
  254. if (nFun > 0 && !bIsMultiFunction) {
  255. break;
  256. }
  257. // Read configuration header.
  258. //
  259. nDevIt = PCI_TO_ITERATOR(nBus, nDev, nFun);
  260. config.VendorID = PCI_INVALID_VENDORID;
  261. PciReadConfig(nDevIt, 0, (UCHAR*)&config, PCI_FIXED_HDR_LENGTH);
  262. // No function found, skip to next function
  263. if (config.VendorID == PCI_INVALID_VENDORID) {
  264. continue;
  265. }
  266. if (VendorId == 0 ||
  267. (VendorId == config.VendorID &&
  268. (DeviceId == 0 || DeviceId == config.DeviceID))) {
  269. return nDevIt;
  270. }
  271. }
  272. nFun = 0;
  273. }
  274. nDev = 0;
  275. }
  276. return 0;
  277. }
  278. BOOLEAN PciInit(PCI_REGISTRY_INFO *pPCIReg)
  279. {
  280. s_nPciMajorRevision = pPCIReg->MajorRevision;
  281. s_nPciMinorRevision = pPCIReg->MinorRevision;
  282. s_nPciNumberOfBuses = pPCIReg->NoBuses;
  283. if ((pPCIReg->HardwareMechanism & 0x0F) == 1) {
  284. s_pPciRead = PciReadInt32_1;
  285. s_pPciWrite = PciWriteInt32_1;
  286. }
  287. else if ((pPCIReg->HardwareMechanism & 0x0F) == 2) {
  288. s_pPciRead = PciReadInt32_2;
  289. s_pPciWrite = PciWriteInt32_2;
  290. }
  291. else {
  292. #if DBG
  293. BlPrint("Unknown PCI HW Mechanism!\n");
  294. #endif
  295. return FALSE;
  296. }
  297. return TRUE;
  298. }