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.

586 lines
17 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. ixpcisup.c
  5. Abstract:
  6. Support functions for doing PCI the bus-handler
  7. way.
  8. Author:
  9. Ken Reneris (kenr) 14-June-1994
  10. Environment:
  11. Kernel mode
  12. Revision History:
  13. Moved code into this file so that it would be
  14. easier to build a non-bus-handler HAL. This
  15. file will only be compiled into HALs that
  16. use bus handlers. -- Jake Oshins 2-Dec-1997
  17. --*/
  18. #include "halp.h"
  19. #include "pci.h"
  20. #include "pcip.h"
  21. #include "chiphacks.h"
  22. BOOLEAN
  23. HalpIsIdeDevice(
  24. IN PPCI_COMMON_CONFIG PciData
  25. );
  26. VOID
  27. HalpGetNMICrashFlag (
  28. VOID
  29. );
  30. extern BOOLEAN HalpDisableHibernate;
  31. #ifdef ALLOC_PRAGMA
  32. #pragma alloc_text(INIT,HalpInitializePciBus)
  33. #pragma alloc_text(INIT,HalpIsIdeDevice)
  34. #pragma alloc_text(INIT,HalpAllocateAndInitPciBusHandler)
  35. #endif
  36. VOID
  37. HalpInitializePciBus (
  38. VOID
  39. )
  40. {
  41. PPCI_REGISTRY_INFO_INTERNAL PCIRegInfo;
  42. ULONG i, d, HwType, BusNo, f;
  43. PBUS_HANDLER BusHandler;
  44. PCI_SLOT_NUMBER SlotNumber;
  45. PPCI_COMMON_CONFIG PciData;
  46. UCHAR iBuffer[PCI_COMMON_HDR_LENGTH + sizeof(TYPE2EXTRAS)];
  47. ULONG OPBNumber;
  48. BOOLEAN OPBA2B0Found, COPBInbPostingEnabled;
  49. UCHAR buffer [4];
  50. BOOLEAN fullDecodeChipset = FALSE;
  51. NTSTATUS Status;
  52. ULONG flags;
  53. PCIRegInfo = HalpQueryPciRegistryInfo();
  54. if (!PCIRegInfo) {
  55. return;
  56. }
  57. //
  58. // Initialize spinlock for synchronizing access to PCI space
  59. //
  60. KeInitializeSpinLock (&HalpPCIConfigLock);
  61. PciData = (PPCI_COMMON_CONFIG) iBuffer;
  62. //
  63. // PCIRegInfo describes the system's PCI support as indicated by the BIOS.
  64. //
  65. HwType = PCIRegInfo->HardwareMechanism & 0xf;
  66. //
  67. // Some AMI bioses claim machines are Type2 configuration when they
  68. // are really type1. If this is a Type2 with at least one bus,
  69. // try to verify it's not really a type1 bus
  70. //
  71. if (PCIRegInfo->NoBuses && HwType == 2) {
  72. //
  73. // Check each slot for a valid device. Which every style configuration
  74. // space shows a valid device first will be used
  75. //
  76. SlotNumber.u.bits.Reserved = 0;
  77. SlotNumber.u.bits.FunctionNumber = 0;
  78. for (d = 0; d < PCI_MAX_DEVICES; d++) {
  79. SlotNumber.u.bits.DeviceNumber = d;
  80. //
  81. // First try what the BIOS claims - type 2. Allocate type2
  82. // test handle for PCI bus 0.
  83. //
  84. HwType = 2;
  85. BusHandler = HalpAllocateAndInitPciBusHandler (HwType, 0, TRUE);
  86. if (HalpIsValidPCIDevice (BusHandler, SlotNumber)) {
  87. break;
  88. }
  89. //
  90. // Valid device not found on Type2 access for this slot.
  91. // Reallocate the bus handler are Type1 and take a look.
  92. //
  93. HwType = 1;
  94. BusHandler = HalpAllocateAndInitPciBusHandler (HwType, 0, TRUE);
  95. if (HalpIsValidPCIDevice (BusHandler, SlotNumber)) {
  96. break;
  97. }
  98. HwType = 2;
  99. }
  100. //
  101. // Reset handler for PCI bus 0 to whatever style config space
  102. // was finally decided.
  103. //
  104. HalpAllocateAndInitPciBusHandler (HwType, 0, FALSE);
  105. }
  106. //
  107. // For each PCI bus present, allocate a handler structure and
  108. // fill in the dispatch functions
  109. //
  110. do {
  111. for (i=0; i < PCIRegInfo->NoBuses; i++) {
  112. //
  113. // If handler not already built, do it now
  114. //
  115. if (!HalpHandlerForBus (PCIBus, i)) {
  116. HalpAllocateAndInitPciBusHandler (HwType, i, FALSE);
  117. }
  118. }
  119. //
  120. // Bus handlers for all PCI buses have been allocated, go collect
  121. // pci bridge information.
  122. //
  123. } while (HalpGetPciBridgeConfig (HwType, &PCIRegInfo->NoBuses)) ;
  124. //
  125. // Fixup SUPPORTED_RANGES
  126. //
  127. HalpFixupPciSupportedRanges (PCIRegInfo->NoBuses);
  128. //
  129. // Look for PCI controllers which have known work-arounds, and make
  130. // sure they are applied.
  131. //
  132. // In addition, fill in the bitmask HalpPciIrqMask with all the
  133. // interrupts that PCI devices might use.
  134. //
  135. OPBNumber = 0;
  136. OPBA2B0Found = FALSE;
  137. COPBInbPostingEnabled = FALSE;
  138. SlotNumber.u.bits.Reserved = 0;
  139. for (BusNo=0; BusNo < PCIRegInfo->NoBuses; BusNo++) {
  140. BusHandler = HalpHandlerForBus (PCIBus, BusNo);
  141. for (d = 0; d < PCI_MAX_DEVICES; d++) {
  142. SlotNumber.u.bits.DeviceNumber = d;
  143. for (f = 0; f < PCI_MAX_FUNCTION; f++) {
  144. SlotNumber.u.bits.FunctionNumber = f;
  145. //
  146. // Read PCI configuration information
  147. //
  148. HalpReadPCIConfig (BusHandler, SlotNumber, PciData, 0, PCI_COMMON_HDR_LENGTH);
  149. if (*((PULONG)(PciData)) == 0xffffffff) {
  150. continue;
  151. }
  152. if (PCI_CONFIGURATION_TYPE(PciData) == PCI_CARDBUS_BRIDGE_TYPE) {
  153. HalpReadPCIConfig(
  154. BusHandler,
  155. SlotNumber,
  156. PciData+1,
  157. FIELD_OFFSET(PCI_COMMON_CONFIG, DeviceSpecific),
  158. sizeof(TYPE2EXTRAS)
  159. );
  160. }
  161. #ifndef SUBCLASSPCI
  162. //
  163. // Look at interrupt line register and fill in HalpPciIrqMask,
  164. // but not for an IDE controller, as IDE controllers really
  165. // trigger interrupts like ISA devices.
  166. //
  167. if (PCI_CONFIGURATION_TYPE(PciData) != 1) {
  168. if ((PciData->u.type0.InterruptPin != 0) &&
  169. (PciData->u.type0.InterruptLine != 0) &&
  170. (PciData->u.type0.InterruptLine < PIC_VECTORS) &&
  171. !HalpIsIdeDevice(PciData)) {
  172. HalpPciIrqMask |= 1 << PciData->u.type0.InterruptLine;
  173. }
  174. }
  175. #endif
  176. //
  177. // Check for chips with known work-arounds to apply
  178. //
  179. if (PciData->VendorID == 0x8086 &&
  180. PciData->DeviceID == 0x04A3 &&
  181. PciData->RevisionID < 0x11) {
  182. //
  183. // 82430 PCMC controller
  184. //
  185. HalpReadPCIConfig (BusHandler, SlotNumber, buffer, 0x53, 2);
  186. buffer[0] &= ~0x08; // turn off bit 3 register 0x53
  187. if (PciData->RevisionID == 0x10) { // on rev 0x10, also turn
  188. buffer[1] &= ~0x01; // bit 0 register 0x54
  189. }
  190. HalpWritePCIConfig (BusHandler, SlotNumber, buffer, 0x53, 2);
  191. }
  192. if (PciData->VendorID == 0x8086 &&
  193. PciData->DeviceID == 0x0484 &&
  194. PciData->RevisionID <= 3) {
  195. //
  196. // 82378 ISA bridge & SIO
  197. //
  198. HalpReadPCIConfig (BusHandler, SlotNumber, buffer, 0x41, 1);
  199. buffer[0] &= ~0x1; // turn off bit 0 register 0x41
  200. HalpWritePCIConfig (BusHandler, SlotNumber, buffer, 0x41, 1);
  201. }
  202. //
  203. // Look for Orion PCI Bridge
  204. //
  205. if (PciData->VendorID == 0x8086 &&
  206. PciData->DeviceID == 0x84c4 ) {
  207. //
  208. // 82450 Orion PCI Bridge Workaround
  209. // Need a workaround if following conditions are true:
  210. // i) 2 OPBs present
  211. // ii)There is an A2/B0 step OPB present.
  212. // iii) Inbound posting on the compatibility OPB is
  213. // enabled.
  214. // NOTE: Inbound Posting on the non-compatibility OPB
  215. // MUST BE disabled by BIOS
  216. //
  217. OPBNumber += 1;
  218. if (PciData->RevisionID <= 4) {
  219. OPBA2B0Found = TRUE;
  220. }
  221. if (SlotNumber.u.bits.DeviceNumber == (0xc8>>3)) {
  222. // Found compatibility OPB. Determine if the compatibility
  223. // OPB has inbound posting enabled by testing bit 0 of reg 54
  224. HalpReadPCIConfig (BusHandler, SlotNumber, buffer, 0x54, 2);
  225. COPBInbPostingEnabled = (buffer[0] & 0x1) ? TRUE : FALSE;
  226. } else {
  227. // The compatibility OPB ALWAYS has a device
  228. // number 0xc8. Save the ncOPB slot number
  229. // and BusHandler
  230. HalpOrionOPB.Slot = SlotNumber;
  231. HalpOrionOPB.Handler = BusHandler;
  232. }
  233. }
  234. //
  235. // Check the list for host bridges who's existance will mark a
  236. // chipset as 16bit decode. We use this to cover for BIOS
  237. // writers who list "fixed" PnPBIOS resources without noticing
  238. // that such a descriptor implies their device is 10bit decode.
  239. //
  240. if ((!fullDecodeChipset) &&
  241. HalpIsRecognizedCard(PCIRegInfo, PciData,
  242. PCIFT_FULLDECODE_HOSTBRIDGE)) {
  243. fullDecodeChipset = TRUE;
  244. }
  245. //
  246. // Look for ICH, or any other Intel or VIA UHCI USB controller.
  247. //
  248. if ((PciData->BaseClass == PCI_CLASS_SERIAL_BUS_CTLR) &&
  249. (PciData->SubClass == PCI_SUBCLASS_SB_USB) &&
  250. (PciData->ProgIf == 0x00)) {
  251. if (PciData->VendorID == 0x8086) {
  252. HalpStopUhciInterrupt(BusNo,
  253. SlotNumber,
  254. TRUE);
  255. } else if (PciData->VendorID == 0x1106) {
  256. HalpStopUhciInterrupt(BusNo,
  257. SlotNumber,
  258. FALSE);
  259. }
  260. }
  261. //
  262. // Look for an OHCI-compliant USB controller.
  263. //
  264. if ((PciData->BaseClass == PCI_CLASS_SERIAL_BUS_CTLR) &&
  265. (PciData->SubClass == PCI_SUBCLASS_SB_USB) &&
  266. (PciData->ProgIf == 0x10)) {
  267. HalpStopOhciInterrupt(BusNo,
  268. SlotNumber);
  269. }
  270. Status = HalpGetChipHacks(PciData->VendorID,
  271. PciData->DeviceID,
  272. 0,
  273. &flags);
  274. if (NT_SUCCESS(Status)) {
  275. if (flags & DISABLE_HIBERNATE_HACK_FLAG) {
  276. HalpDisableHibernate = TRUE;
  277. }
  278. if (flags & WHACK_ICH_USB_SMI_HACK_FLAG) {
  279. HalpWhackICHUsbSmi(BusNo, SlotNumber);
  280. }
  281. }
  282. } // next function
  283. } // next device
  284. } // next bus
  285. //
  286. // Is Orion B0 workaround needed?
  287. //
  288. if (OPBNumber >= 2 && OPBA2B0Found && COPBInbPostingEnabled) {
  289. //
  290. // Replace synchronization functions with Orion specific functions
  291. //
  292. ASSERT (PCIConfigHandler.Synchronize == HalpPCISynchronizeType1);
  293. MmLockPagableCodeSection (&HalpPCISynchronizeOrionB0);
  294. PCIConfigHandler.Synchronize = HalpPCISynchronizeOrionB0;
  295. PCIConfigHandler.ReleaseSynchronzation = HalpPCIReleaseSynchronzationOrionB0;
  296. }
  297. //
  298. // Check if we should crashdump on NMI.
  299. //
  300. HalpGetNMICrashFlag();
  301. #if DBG
  302. HalpTestPci (0);
  303. #endif
  304. //
  305. // Mark the chipset appropriately.
  306. //
  307. HalpMarkChipsetDecode(fullDecodeChipset);
  308. ExFreePool(PCIRegInfo);
  309. }
  310. PBUS_HANDLER
  311. HalpAllocateAndInitPciBusHandler (
  312. IN ULONG HwType,
  313. IN ULONG BusNo,
  314. IN BOOLEAN TestAllocation
  315. )
  316. {
  317. PBUS_HANDLER Bus;
  318. PPCIPBUSDATA BusData;
  319. Bus = HalpAllocateBusHandler (
  320. PCIBus, // Interface type
  321. PCIConfiguration, // Has this configuration space
  322. BusNo, // bus #
  323. Internal, // child of this bus
  324. 0, // and number
  325. sizeof (PCIPBUSDATA) // sizeof bus specific buffer
  326. );
  327. if (!Bus) {
  328. return NULL;
  329. }
  330. //
  331. // Fill in PCI handlers
  332. //
  333. Bus->GetBusData = (PGETSETBUSDATA) HalpGetPCIData;
  334. Bus->SetBusData = (PGETSETBUSDATA) HalpSetPCIData;
  335. Bus->GetInterruptVector = (PGETINTERRUPTVECTOR) HalpGetPCIIntOnISABus;
  336. Bus->AdjustResourceList = (PADJUSTRESOURCELIST) HalpAdjustPCIResourceList;
  337. Bus->AssignSlotResources = (PASSIGNSLOTRESOURCES) HalpAssignPCISlotResources;
  338. Bus->BusAddresses->Dma.Limit = 0;
  339. BusData = (PPCIPBUSDATA) Bus->BusData;
  340. //
  341. // Fill in common PCI data
  342. //
  343. BusData->CommonData.Tag = PCI_DATA_TAG;
  344. BusData->CommonData.Version = PCI_DATA_VERSION;
  345. BusData->CommonData.ReadConfig = (PciReadWriteConfig) HalpReadPCIConfig;
  346. BusData->CommonData.WriteConfig = (PciReadWriteConfig) HalpWritePCIConfig;
  347. BusData->CommonData.Pin2Line = (PciPin2Line) HalpPCIPin2ISALine;
  348. BusData->CommonData.Line2Pin = (PciLine2Pin) HalpPCIISALine2Pin;
  349. //
  350. // Set defaults
  351. //
  352. BusData->MaxDevice = PCI_MAX_DEVICES;
  353. BusData->GetIrqRange = (PciIrqRange) HalpGetISAFixedPCIIrq;
  354. RtlInitializeBitMap (&BusData->DeviceConfigured,
  355. BusData->ConfiguredBits, 256);
  356. switch (HwType) {
  357. case 1:
  358. //
  359. // Initialize access port information for Type1 handlers
  360. //
  361. RtlCopyMemory (&PCIConfigHandler,
  362. &PCIConfigHandlerType1,
  363. sizeof (PCIConfigHandler));
  364. BusData->Config.Type1.Address = PCI_TYPE1_ADDR_PORT;
  365. BusData->Config.Type1.Data = PCI_TYPE1_DATA_PORT;
  366. break;
  367. case 2:
  368. //
  369. // Initialize access port information for Type2 handlers
  370. //
  371. RtlCopyMemory (&PCIConfigHandler,
  372. &PCIConfigHandlerType2,
  373. sizeof (PCIConfigHandler));
  374. BusData->Config.Type2.CSE = PCI_TYPE2_CSE_PORT;
  375. BusData->Config.Type2.Forward = PCI_TYPE2_FORWARD_PORT;
  376. BusData->Config.Type2.Base = PCI_TYPE2_ADDRESS_BASE;
  377. //
  378. // Early PCI machines didn't decode the last bit of
  379. // the device id. Shrink type 2 support max device.
  380. //
  381. BusData->MaxDevice = 0x10;
  382. break;
  383. default:
  384. // unsupport type
  385. DBGMSG ("HAL: Unkown PCI type\n");
  386. }
  387. if (!TestAllocation) {
  388. #ifdef SUBCLASSPCI
  389. HalpSubclassPCISupport (Bus, HwType);
  390. #endif
  391. }
  392. return Bus;
  393. }
  394. BOOLEAN
  395. HalpIsIdeDevice(
  396. IN PPCI_COMMON_CONFIG PciData
  397. )
  398. {
  399. if ((PciData->BaseClass == PCI_CLASS_MASS_STORAGE_CTLR) &&
  400. (PciData->SubClass == PCI_SUBCLASS_MSC_IDE_CTLR)) {
  401. return TRUE;
  402. }
  403. //
  404. // Now look for old, hard to recognize controllers.
  405. //
  406. if (PciData->VendorID == 0x1c1c) { // Old Symphony controller
  407. return TRUE;
  408. }
  409. if ((PciData->VendorID == 0x10B9) &&
  410. ((PciData->DeviceID == 0x5215) ||
  411. (PciData->DeviceID == 0x5219))) { // ALI controllers
  412. return TRUE;
  413. }
  414. if ((PciData->VendorID == 0x1097) &&
  415. (PciData->DeviceID == 0x0038)) { // Appian controller
  416. return TRUE;
  417. }
  418. if ((PciData->VendorID == 0x0E11) &&
  419. (PciData->DeviceID == 0xAE33)) { // Compaq controller
  420. return TRUE;
  421. }
  422. if ((PciData->VendorID == 0x1042) &&
  423. (PciData->DeviceID == 0x1000)) { // PCTECH controller
  424. return TRUE;
  425. }
  426. if ((PciData->VendorID == 0x1039) &&
  427. ((PciData->DeviceID == 0x0601) ||
  428. (PciData->DeviceID == 0x5513))) { // SIS controllers
  429. return TRUE;
  430. }
  431. if ((PciData->VendorID == 0x10AD) &&
  432. ((PciData->DeviceID == 0x0001) ||
  433. (PciData->DeviceID == 0x0150))) { // Newer Symphony controllers
  434. return TRUE;
  435. }
  436. if ((PciData->VendorID == 0x1060) &&
  437. (PciData->DeviceID == 0x0101)) { // United Microelectronics controller
  438. return TRUE;
  439. }
  440. return FALSE;
  441. }