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.

2711 lines
78 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. ixpcibus.c
  5. Abstract:
  6. Get/Set bus data routines for the PCI bus
  7. Author:
  8. Ken Reneris (kenr) 14-June-1994
  9. Environment:
  10. Kernel mode
  11. Revision History:
  12. --*/
  13. #include "halp.h"
  14. #include "pci.h"
  15. #include "pcip.h"
  16. extern const WCHAR rgzMultiFunctionAdapter[];
  17. extern const WCHAR rgzConfigurationData[];
  18. extern const WCHAR rgzIdentifier[];
  19. extern const WCHAR rgzPCIIdentifier[];
  20. extern const WCHAR rgzPCICardList[];
  21. //
  22. // Globals
  23. //
  24. KSPIN_LOCK HalpPCIConfigLock;
  25. PCI_CONFIG_HANDLER PCIConfigHandler;
  26. #ifdef ALLOC_DATA_PRAGMA
  27. #pragma const_seg("INITCONST")
  28. #endif // ALLOC_DATA_PRAGMA
  29. const PCI_CONFIG_HANDLER PCIConfigHandlerType1 = {
  30. HalpPCISynchronizeType1,
  31. HalpPCIReleaseSynchronzationType1,
  32. {
  33. HalpPCIReadUlongType1, // 0
  34. HalpPCIReadUcharType1, // 1
  35. HalpPCIReadUshortType1 // 2
  36. },
  37. {
  38. HalpPCIWriteUlongType1, // 0
  39. HalpPCIWriteUcharType1, // 1
  40. HalpPCIWriteUshortType1 // 2
  41. }
  42. };
  43. const PCI_CONFIG_HANDLER PCIConfigHandlerType2 = {
  44. HalpPCISynchronizeType2,
  45. HalpPCIReleaseSynchronzationType2,
  46. {
  47. HalpPCIReadUlongType2, // 0
  48. HalpPCIReadUcharType2, // 1
  49. HalpPCIReadUshortType2 // 2
  50. },
  51. {
  52. HalpPCIWriteUlongType2, // 0
  53. HalpPCIWriteUcharType2, // 1
  54. HalpPCIWriteUshortType2 // 2
  55. }
  56. };
  57. #ifdef ALLOC_DATA_PRAGMA
  58. #pragma const_seg()
  59. #endif // ALLOC_DATA_PRAGMA
  60. const UCHAR PCIDeref[4][4] = { {0,1,2,2},{1,1,1,1},{2,1,2,2},{1,1,1,1} };
  61. #define SIZEOF_PARTIAL_INFO_HEADER FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data)
  62. #if DBG
  63. ULONG HalpPCIIllegalBusScannerDetected;
  64. ULONG HalpPCIStopOnIllegalBusScannerDetected;
  65. #endif
  66. extern BOOLEAN HalpDoingCrashDump;
  67. VOID
  68. HalpPCIConfig (
  69. IN PBUS_HANDLER BusHandler,
  70. IN PCI_SLOT_NUMBER Slot,
  71. IN PUCHAR Buffer,
  72. IN ULONG Offset,
  73. IN ULONG Length,
  74. IN FncConfigIO *ConfigIO
  75. );
  76. VOID
  77. HalpGetNMICrashFlag (
  78. VOID
  79. );
  80. #ifdef ALLOC_PRAGMA
  81. #pragma alloc_text(INIT,HalpQueryPciRegistryInfo)
  82. #pragma alloc_text(INIT,HalpIsRecognizedCard)
  83. #pragma alloc_text(INIT,HalpIsValidPCIDevice)
  84. #pragma alloc_text(INIT,HalpGetNMICrashFlag)
  85. #pragma alloc_text(PAGE,HalpAssignPCISlotResources)
  86. #pragma alloc_text(PAGE,HalIrqTranslateRequirementsPciBridge)
  87. #pragma alloc_text(PAGE,HalIrqTranslateResourcesPciBridge)
  88. #pragma alloc_text(PAGELK,HalpPCISynchronizeOrionB0)
  89. #pragma alloc_text(PAGELK,HalpPCIReleaseSynchronzationOrionB0)
  90. #endif
  91. PPCI_REGISTRY_INFO_INTERNAL
  92. HalpQueryPciRegistryInfo (
  93. VOID
  94. )
  95. /*++
  96. Routine Description:
  97. Reads information from the registry concerning PCI, including the number
  98. of buses and the hardware access mechanism.
  99. Arguments:
  100. None.
  101. Returns:
  102. Buffer that must be freed by the caller, NULL if insufficient memory exists
  103. to complete the request, or the information cannot be located.
  104. --*/
  105. {
  106. PPCI_REGISTRY_INFO_INTERNAL PCIRegInfo = NULL;
  107. PPCI_REGISTRY_INFO PCIRegInfoHeader = NULL;
  108. UNICODE_STRING unicodeString, ConfigName, IdentName;
  109. HANDLE hMFunc, hBus, hCardList;
  110. OBJECT_ATTRIBUTES objectAttributes;
  111. NTSTATUS status;
  112. UCHAR buffer [sizeof(PPCI_REGISTRY_INFO) + 99];
  113. PWSTR p;
  114. WCHAR wstr[8];
  115. ULONG i, junk;
  116. ULONG cardListIndex, cardCount, cardMax;
  117. PKEY_VALUE_FULL_INFORMATION ValueInfo;
  118. PCM_FULL_RESOURCE_DESCRIPTOR Desc;
  119. PCM_PARTIAL_RESOURCE_DESCRIPTOR PDesc;
  120. UCHAR partialInfo[SIZEOF_PARTIAL_INFO_HEADER +
  121. sizeof(PCI_CARD_DESCRIPTOR)];
  122. PKEY_VALUE_PARTIAL_INFORMATION partialInfoHeader;
  123. KEY_FULL_INFORMATION keyFullInfo;
  124. //
  125. // Search the hardware description looking for any reported
  126. // PCI bus. The first ARC entry for a PCI bus will contain
  127. // the PCI_REGISTRY_INFO.
  128. RtlInitUnicodeString (&unicodeString, rgzMultiFunctionAdapter);
  129. InitializeObjectAttributes (
  130. &objectAttributes,
  131. &unicodeString,
  132. OBJ_CASE_INSENSITIVE,
  133. NULL, // handle
  134. NULL);
  135. status = ZwOpenKey (&hMFunc, KEY_READ, &objectAttributes);
  136. if (!NT_SUCCESS(status)) {
  137. return NULL;
  138. }
  139. unicodeString.Buffer = wstr;
  140. unicodeString.MaximumLength = sizeof (wstr);
  141. RtlInitUnicodeString (&ConfigName, rgzConfigurationData);
  142. RtlInitUnicodeString (&IdentName, rgzIdentifier);
  143. ValueInfo = (PKEY_VALUE_FULL_INFORMATION) buffer;
  144. for (i=0; TRUE; i++) {
  145. RtlIntegerToUnicodeString (i, 10, &unicodeString);
  146. InitializeObjectAttributes (
  147. &objectAttributes,
  148. &unicodeString,
  149. OBJ_CASE_INSENSITIVE,
  150. hMFunc,
  151. NULL);
  152. status = ZwOpenKey (&hBus, KEY_READ, &objectAttributes);
  153. if (!NT_SUCCESS(status)) {
  154. //
  155. // Out of Multifunction adapter entries...
  156. //
  157. ZwClose (hMFunc);
  158. return NULL;
  159. }
  160. //
  161. // Check the Identifier to see if this is a PCI entry
  162. //
  163. status = ZwQueryValueKey (
  164. hBus,
  165. &IdentName,
  166. KeyValueFullInformation,
  167. ValueInfo,
  168. sizeof (buffer),
  169. &junk
  170. );
  171. if (!NT_SUCCESS (status)) {
  172. ZwClose (hBus);
  173. continue;
  174. }
  175. p = (PWSTR) ((PUCHAR) ValueInfo + ValueInfo->DataOffset);
  176. if (p[0] != L'P' || p[1] != L'C' || p[2] != L'I' || p[3] != 0) {
  177. ZwClose (hBus);
  178. continue;
  179. }
  180. //
  181. // The first PCI entry has the PCI_REGISTRY_INFO structure
  182. // attached to it.
  183. //
  184. status = ZwQueryValueKey (
  185. hBus,
  186. &ConfigName,
  187. KeyValueFullInformation,
  188. ValueInfo,
  189. sizeof (buffer),
  190. &junk
  191. );
  192. ZwClose (hBus);
  193. if (!NT_SUCCESS(status)) {
  194. continue ;
  195. }
  196. Desc = (PCM_FULL_RESOURCE_DESCRIPTOR) ((PUCHAR)
  197. ValueInfo + ValueInfo->DataOffset);
  198. PDesc = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) ((PUCHAR)
  199. Desc->PartialResourceList.PartialDescriptors);
  200. if (PDesc->Type == CmResourceTypeDeviceSpecific) {
  201. // got it..
  202. PCIRegInfoHeader = (PPCI_REGISTRY_INFO) (PDesc+1);
  203. ZwClose (hMFunc);
  204. break;
  205. }
  206. }
  207. if (!PCIRegInfoHeader) {
  208. return NULL;
  209. }
  210. //
  211. // Retrieve the list of interesting cards.
  212. //
  213. RtlInitUnicodeString (&unicodeString, rgzPCICardList);
  214. InitializeObjectAttributes (
  215. &objectAttributes,
  216. &unicodeString,
  217. OBJ_CASE_INSENSITIVE,
  218. NULL, // handle
  219. NULL
  220. );
  221. status = ZwOpenKey (&hCardList, KEY_READ, &objectAttributes);
  222. if (NT_SUCCESS(status)) {
  223. status = ZwQueryKey( hCardList,
  224. KeyFullInformation,
  225. &keyFullInfo,
  226. sizeof(keyFullInfo),
  227. &junk );
  228. if ( NT_SUCCESS(status) ) {
  229. cardMax = keyFullInfo.Values;
  230. PCIRegInfo = (PPCI_REGISTRY_INFO_INTERNAL) ExAllocatePoolWithTag(
  231. NonPagedPool,
  232. sizeof(PCI_REGISTRY_INFO_INTERNAL) +
  233. cardMax * sizeof(PCI_CARD_DESCRIPTOR),
  234. HAL_POOL_TAG
  235. );
  236. if (PCIRegInfo) {
  237. //
  238. // Now that we've allocated enough room, enumerate again.
  239. //
  240. partialInfoHeader = (PKEY_VALUE_PARTIAL_INFORMATION) partialInfo;
  241. for(cardListIndex = cardCount = 0;
  242. cardListIndex < cardMax;
  243. cardListIndex++) {
  244. status = ZwEnumerateValueKey(
  245. hCardList,
  246. cardListIndex,
  247. KeyValuePartialInformation,
  248. partialInfo,
  249. sizeof(partialInfo),
  250. &junk
  251. );
  252. //
  253. // Note that STATUS_NO_MORE_ENTRIES is a failure code
  254. //
  255. if (!NT_SUCCESS( status )) {
  256. break;
  257. }
  258. if (partialInfoHeader->DataLength != sizeof(PCI_CARD_DESCRIPTOR)) {
  259. continue;
  260. }
  261. RtlCopyMemory(
  262. PCIRegInfo->CardList + cardCount,
  263. partialInfoHeader->Data,
  264. sizeof(PCI_CARD_DESCRIPTOR)
  265. );
  266. cardCount++;
  267. } // next cardListIndex
  268. }
  269. }
  270. ZwClose (hCardList);
  271. }
  272. if (!PCIRegInfo) {
  273. PCIRegInfo = (PPCI_REGISTRY_INFO_INTERNAL) ExAllocatePoolWithTag(
  274. NonPagedPool,
  275. sizeof(PCI_REGISTRY_INFO_INTERNAL),
  276. HAL_POOL_TAG
  277. );
  278. if (!PCIRegInfo) {
  279. return NULL;
  280. }
  281. cardCount = 0;
  282. }
  283. RtlCopyMemory(
  284. PCIRegInfo,
  285. PCIRegInfoHeader,
  286. sizeof(PCI_REGISTRY_INFO)
  287. );
  288. PCIRegInfo->ElementCount = cardCount;
  289. return PCIRegInfo;
  290. }
  291. BOOLEAN
  292. HalpIsRecognizedCard(
  293. IN PPCI_REGISTRY_INFO_INTERNAL PCIRegInfo,
  294. IN PPCI_COMMON_CONFIG PciData,
  295. IN ULONG FeatureMask
  296. )
  297. /*++
  298. Routine Description:
  299. Walks the internal registry info list to find any cards matching the passed
  300. in "feature" mask.
  301. Arguments:
  302. PCIRegInfo - Pointer to reg info with the list of "notable" devices.
  303. PciData - Config space (with subsystem info for cardbus bridges)
  304. FeatureMask - PCIFT flags to try to match
  305. Returns:
  306. Buffer that must be freed by the caller, NULL if insufficient memory exists
  307. to complete the request, or the information cannot be located.
  308. --*/
  309. {
  310. ULONG element;
  311. //
  312. // Detect if this has a h
  313. //
  314. for(element = 0; element < PCIRegInfo->ElementCount; element++) {
  315. if (FeatureMask & PCIRegInfo->CardList[element].Flags) {
  316. if (PCIRegInfo->CardList[element].VendorID != PciData->VendorID) {
  317. continue;
  318. }
  319. if (PCIRegInfo->CardList[element].DeviceID != PciData->DeviceID) {
  320. continue;
  321. }
  322. if (PCIRegInfo->CardList[element].Flags & PCICF_CHECK_REVISIONID) {
  323. if (PCIRegInfo->CardList[element].RevisionID != PciData->RevisionID) {
  324. continue;
  325. }
  326. }
  327. switch(PCI_CONFIGURATION_TYPE(PciData)) {
  328. case PCI_DEVICE_TYPE:
  329. if (PCIRegInfo->CardList[element].Flags & PCICF_CHECK_SSVID) {
  330. if (PCIRegInfo->CardList[element].SubsystemVendorID != PciData->u.type0.SubVendorID) {
  331. continue;
  332. }
  333. }
  334. if (PCIRegInfo->CardList[element].Flags & PCICF_CHECK_SSID) {
  335. if (PCIRegInfo->CardList[element].SubsystemID != PciData->u.type0.SubSystemID) {
  336. continue;
  337. }
  338. }
  339. break;
  340. case PCI_BRIDGE_TYPE:
  341. break;
  342. case PCI_CARDBUS_BRIDGE_TYPE:
  343. if (PCIRegInfo->CardList[element].Flags & PCICF_CHECK_SSVID) {
  344. if (PCIRegInfo->CardList[element].SubsystemVendorID !=
  345. ((TYPE2EXTRAS *)(PciData->DeviceSpecific))->SubVendorID) {
  346. continue;
  347. }
  348. }
  349. if (PCIRegInfo->CardList[element].Flags & PCICF_CHECK_SSID) {
  350. if (PCIRegInfo->CardList[element].SubsystemID !=
  351. ((TYPE2EXTRAS *)(PciData->DeviceSpecific))->SubSystemID) {
  352. continue;
  353. }
  354. }
  355. break;
  356. }
  357. //
  358. // We found the device matching one of the passed in feature bits.
  359. //
  360. return TRUE;
  361. }
  362. }
  363. return FALSE;
  364. }
  365. BOOLEAN
  366. HalpIsValidPCIDevice (
  367. IN PBUS_HANDLER BusHandler,
  368. IN PCI_SLOT_NUMBER Slot
  369. )
  370. /*++
  371. Routine Description:
  372. Reads the device configuration data for the given slot and
  373. returns TRUE if the configuration data appears to be valid for
  374. a PCI device; otherwise returns FALSE.
  375. Arguments:
  376. BusHandler - Bus to check
  377. Slot - Slot to check
  378. --*/
  379. {
  380. PPCI_COMMON_CONFIG PciData;
  381. UCHAR iBuffer[PCI_COMMON_HDR_LENGTH];
  382. ULONG i, j;
  383. PciData = (PPCI_COMMON_CONFIG) iBuffer;
  384. //
  385. // Read device common header
  386. //
  387. HalpReadPCIConfig (BusHandler, Slot, PciData, 0, PCI_COMMON_HDR_LENGTH);
  388. //
  389. // Valid device header?
  390. //
  391. if (PciData->VendorID == PCI_INVALID_VENDORID ||
  392. PCI_CONFIG_TYPE (PciData) != PCI_DEVICE_TYPE) {
  393. return FALSE;
  394. }
  395. //
  396. // Check fields for reasonable values
  397. //
  398. if ((PciData->u.type0.InterruptPin && PciData->u.type0.InterruptPin > 4) ||
  399. (PciData->u.type0.InterruptLine & 0x70)) {
  400. return FALSE;
  401. }
  402. for (i=0; i < PCI_TYPE0_ADDRESSES; i++) {
  403. j = PciData->u.type0.BaseAddresses[i];
  404. if (j & PCI_ADDRESS_IO_SPACE) {
  405. if (j > 0xffff) {
  406. // IO port > 64k?
  407. return FALSE;
  408. }
  409. } else {
  410. if (j > 0xf && j < 0x80000) {
  411. // Mem address < 0x8000h?
  412. return FALSE;
  413. }
  414. }
  415. if (Is64BitBaseAddress(j)) {
  416. i += 1;
  417. }
  418. }
  419. //
  420. // Guess it's a valid device..
  421. //
  422. return TRUE;
  423. }
  424. ULONG
  425. HalpGetPCIData (
  426. IN PBUS_HANDLER BusHandler,
  427. IN PBUS_HANDLER RootHandler,
  428. IN PCI_SLOT_NUMBER Slot,
  429. IN PUCHAR Buffer,
  430. IN ULONG Offset,
  431. IN ULONG Length
  432. )
  433. /*++
  434. Routine Description:
  435. The function returns the Pci bus data for a device.
  436. Arguments:
  437. BusNumber - Indicates which bus.
  438. VendorSpecificDevice - The VendorID (low Word) and DeviceID (High Word)
  439. Buffer - Supplies the space to store the data.
  440. Length - Supplies a count in bytes of the maximum amount to return.
  441. Return Value:
  442. Returns the amount of data stored into the buffer.
  443. If this PCI slot has never been set, then the configuration information
  444. returned is zeroed.
  445. --*/
  446. {
  447. PPCI_COMMON_CONFIG PciData;
  448. UCHAR iBuffer[PCI_COMMON_HDR_LENGTH];
  449. PPCIPBUSDATA BusData;
  450. ULONG Len;
  451. ULONG i, bit;
  452. if (Length > sizeof (PCI_COMMON_CONFIG)) {
  453. Length = sizeof (PCI_COMMON_CONFIG);
  454. }
  455. Len = 0;
  456. PciData = (PPCI_COMMON_CONFIG) iBuffer;
  457. if (Offset >= PCI_COMMON_HDR_LENGTH) {
  458. //
  459. // The user did not request any data from the common
  460. // header. Verify the PCI device exists, then continue
  461. // in the device specific area.
  462. //
  463. HalpReadPCIConfig (BusHandler, Slot, PciData, 0, sizeof(ULONG));
  464. if (PciData->VendorID == PCI_INVALID_VENDORID) {
  465. return 0;
  466. }
  467. } else {
  468. //
  469. // Caller requested at least some data within the
  470. // common header. Read the whole header, effect the
  471. // fields we need to and then copy the user's requested
  472. // bytes from the header
  473. //
  474. BusData = (PPCIPBUSDATA) BusHandler->BusData;
  475. //
  476. // Read this PCI devices slot data
  477. //
  478. Len = PCI_COMMON_HDR_LENGTH;
  479. HalpReadPCIConfig (BusHandler, Slot, PciData, 0, Len);
  480. if (PciData->VendorID == PCI_INVALID_VENDORID) {
  481. PciData->VendorID = PCI_INVALID_VENDORID;
  482. Len = 2; // only return invalid id
  483. #if DBG
  484. //
  485. // If this read would have accessed beyond the common header
  486. // then it is highly likely we have detected a device driver
  487. // doing a legacy scan of the bus but reading more than the
  488. // allowed configuration header. This can have catastrophic
  489. // side effects.
  490. //
  491. if ((Length + Offset) > PCI_COMMON_HDR_LENGTH) {
  492. if (++HalpPCIIllegalBusScannerDetected == 1) {
  493. DbgPrint("HAL Warning: PCI Configuration Access had detected an invalid bus scan.\n");
  494. }
  495. if (HalpPCIStopOnIllegalBusScannerDetected) {
  496. DbgBreakPoint();
  497. }
  498. }
  499. #endif
  500. } else {
  501. BusData->CommonData.Pin2Line (BusHandler, RootHandler, Slot, PciData);
  502. }
  503. //
  504. // Has this PCI device been configured?
  505. //
  506. #if 0
  507. //
  508. // On DBG build, if this PCI device has not yet been configured,
  509. // then don't report any current configuration the device may have.
  510. //
  511. bit = PciBitIndex(Slot.u.bits.DeviceNumber, Slot.u.bits.FunctionNumber);
  512. if (!RtlCheckBit(&BusData->DeviceConfigured, bit) &&
  513. PCI_CONFIG_TYPE (PciData) == PCI_DEVICE_TYPE) {
  514. for (i=0; i < PCI_TYPE0_ADDRESSES; i++) {
  515. PciData->u.type0.BaseAddresses[i] = 0;
  516. }
  517. PciData->u.type0.ROMBaseAddress = 0;
  518. PciData->Command &= ~(PCI_ENABLE_IO_SPACE | PCI_ENABLE_MEMORY_SPACE);
  519. }
  520. #endif
  521. //
  522. // Copy whatever data overlaps into the callers buffer
  523. //
  524. if (Len < Offset) {
  525. // no data at caller's buffer
  526. return 0;
  527. }
  528. Len -= Offset;
  529. if (Len > Length) {
  530. Len = Length;
  531. }
  532. RtlMoveMemory(Buffer, iBuffer + Offset, Len);
  533. Offset += Len;
  534. Buffer += Len;
  535. Length -= Len;
  536. }
  537. if (Length) {
  538. if (Offset >= PCI_COMMON_HDR_LENGTH) {
  539. //
  540. // The remaining Buffer comes from the Device Specific
  541. // area - put on the kitten gloves and read from it.
  542. //
  543. // Specific read/writes to the PCI device specific area
  544. // are guarenteed:
  545. //
  546. // Not to read/write any byte outside the area specified
  547. // by the caller. (this may cause WORD or BYTE references
  548. // to the area in order to read the non-dword aligned
  549. // ends of the request)
  550. //
  551. // To use a WORD access if the requested length is exactly
  552. // a WORD long.
  553. //
  554. // To use a BYTE access if the requested length is exactly
  555. // a BYTE long.
  556. //
  557. HalpReadPCIConfig (BusHandler, Slot, Buffer, Offset, Length);
  558. Len += Length;
  559. }
  560. }
  561. return Len;
  562. }
  563. ULONG
  564. HalpSetPCIData (
  565. IN PBUS_HANDLER BusHandler,
  566. IN PBUS_HANDLER RootHandler,
  567. IN PCI_SLOT_NUMBER Slot,
  568. IN PUCHAR Buffer,
  569. IN ULONG Offset,
  570. IN ULONG Length
  571. )
  572. /*++
  573. Routine Description:
  574. The function returns the Pci bus data for a device.
  575. Arguments:
  576. VendorSpecificDevice - The VendorID (low Word) and DeviceID (High Word)
  577. Buffer - Supplies the space to store the data.
  578. Length - Supplies a count in bytes of the maximum amount to return.
  579. Return Value:
  580. Returns the amount of data stored into the buffer.
  581. --*/
  582. {
  583. PPCI_COMMON_CONFIG PciData, PciData2;
  584. UCHAR iBuffer[PCI_COMMON_HDR_LENGTH];
  585. UCHAR iBuffer2[PCI_COMMON_HDR_LENGTH];
  586. PPCIPBUSDATA BusData;
  587. ULONG Len, cnt;
  588. if (Length > sizeof (PCI_COMMON_CONFIG)) {
  589. Length = sizeof (PCI_COMMON_CONFIG);
  590. }
  591. Len = 0;
  592. PciData = (PPCI_COMMON_CONFIG) iBuffer;
  593. PciData2 = (PPCI_COMMON_CONFIG) iBuffer2;
  594. if (Offset >= PCI_COMMON_HDR_LENGTH) {
  595. //
  596. // The user did not request any data from the common
  597. // header. Verify the PCI device exists, then continue in
  598. // the device specific area.
  599. //
  600. HalpReadPCIConfig (BusHandler, Slot, PciData, 0, sizeof(ULONG));
  601. if (PciData->VendorID == PCI_INVALID_VENDORID) {
  602. return 0;
  603. }
  604. } else {
  605. //
  606. // Caller requested to set at least some data within the
  607. // common header.
  608. //
  609. Len = PCI_COMMON_HDR_LENGTH;
  610. HalpReadPCIConfig (BusHandler, Slot, PciData, 0, Len);
  611. if (PciData->VendorID == PCI_INVALID_VENDORID ||
  612. PCI_CONFIG_TYPE (PciData) != PCI_DEVICE_TYPE) {
  613. // no device, or header type unkown
  614. return 0;
  615. }
  616. //
  617. // Set this device as configured
  618. //
  619. BusData = (PPCIPBUSDATA) BusHandler->BusData;
  620. #if DBG && !defined(ACPI_HAL)
  621. cnt = PciBitIndex(Slot.u.bits.DeviceNumber, Slot.u.bits.FunctionNumber);
  622. RtlSetBits (&BusData->DeviceConfigured, cnt, 1);
  623. #endif
  624. //
  625. // Copy COMMON_HDR values to buffer2, then overlay callers changes.
  626. //
  627. RtlMoveMemory (iBuffer2, iBuffer, Len);
  628. BusData->CommonData.Pin2Line (BusHandler, RootHandler, Slot, PciData2);
  629. Len -= Offset;
  630. if (Len > Length) {
  631. Len = Length;
  632. }
  633. RtlMoveMemory (iBuffer2+Offset, Buffer, Len);
  634. // in case interrupt line or pin was editted
  635. BusData->CommonData.Line2Pin (BusHandler, RootHandler, Slot, PciData2, PciData);
  636. #if DBG
  637. //
  638. // Verify R/O fields haven't changed
  639. //
  640. if (PciData2->VendorID != PciData->VendorID ||
  641. PciData2->DeviceID != PciData->DeviceID ||
  642. PciData2->RevisionID != PciData->RevisionID ||
  643. PciData2->ProgIf != PciData->ProgIf ||
  644. PciData2->SubClass != PciData->SubClass ||
  645. PciData2->BaseClass != PciData->BaseClass ||
  646. PciData2->HeaderType != PciData->HeaderType ||
  647. PciData2->BaseClass != PciData->BaseClass ||
  648. PciData2->u.type0.MinimumGrant != PciData->u.type0.MinimumGrant ||
  649. PciData2->u.type0.MaximumLatency != PciData->u.type0.MaximumLatency) {
  650. DbgPrint ("PCI SetBusData: Read-Only configuration value changed\n");
  651. }
  652. #endif
  653. //
  654. // Set new PCI configuration
  655. //
  656. HalpWritePCIConfig (BusHandler, Slot, iBuffer2+Offset, Offset, Len);
  657. Offset += Len;
  658. Buffer += Len;
  659. Length -= Len;
  660. }
  661. if (Length) {
  662. if (Offset >= PCI_COMMON_HDR_LENGTH) {
  663. //
  664. // The remaining Buffer comes from the Device Specific
  665. // area - put on the kitten gloves and write it
  666. //
  667. // Specific read/writes to the PCI device specific area
  668. // are guarenteed:
  669. //
  670. // Not to read/write any byte outside the area specified
  671. // by the caller. (this may cause WORD or BYTE references
  672. // to the area in order to read the non-dword aligned
  673. // ends of the request)
  674. //
  675. // To use a WORD access if the requested length is exactly
  676. // a WORD long.
  677. //
  678. // To use a BYTE access if the requested length is exactly
  679. // a BYTE long.
  680. //
  681. HalpWritePCIConfig (BusHandler, Slot, Buffer, Offset, Length);
  682. Len += Length;
  683. }
  684. }
  685. return Len;
  686. }
  687. VOID
  688. HalpReadPCIConfig (
  689. IN PBUS_HANDLER BusHandler,
  690. IN PCI_SLOT_NUMBER Slot,
  691. IN PVOID Buffer,
  692. IN ULONG Offset,
  693. IN ULONG Length
  694. )
  695. {
  696. if (!HalpValidPCISlot (BusHandler, Slot)) {
  697. //
  698. // Invalid SlotID return no data
  699. //
  700. RtlFillMemory (Buffer, Length, (UCHAR) -1);
  701. return ;
  702. }
  703. HalpPCIConfig (BusHandler, Slot, (PUCHAR) Buffer, Offset, Length,
  704. PCIConfigHandler.ConfigRead);
  705. }
  706. VOID
  707. HalpWritePCIConfig (
  708. IN PBUS_HANDLER BusHandler,
  709. IN PCI_SLOT_NUMBER Slot,
  710. IN PVOID Buffer,
  711. IN ULONG Offset,
  712. IN ULONG Length
  713. )
  714. {
  715. if (!HalpValidPCISlot (BusHandler, Slot)) {
  716. //
  717. // Invalid SlotID do nothing
  718. //
  719. return ;
  720. }
  721. HalpPCIConfig (BusHandler, Slot, (PUCHAR) Buffer, Offset, Length,
  722. PCIConfigHandler.ConfigWrite);
  723. }
  724. BOOLEAN
  725. HalpValidPCISlot (
  726. IN PBUS_HANDLER BusHandler,
  727. IN PCI_SLOT_NUMBER Slot
  728. )
  729. {
  730. PCI_SLOT_NUMBER Slot2;
  731. PPCIPBUSDATA BusData;
  732. ULONG i;
  733. UCHAR Header[FIELD_OFFSET(PCI_COMMON_CONFIG, u)];
  734. PPCI_COMMON_CONFIG PciConfig = (PPCI_COMMON_CONFIG)&Header;
  735. BusData = (PPCIPBUSDATA) BusHandler->BusData;
  736. if (Slot.u.bits.Reserved != 0) {
  737. return FALSE;
  738. }
  739. if (Slot.u.bits.DeviceNumber >= BusData->MaxDevice) {
  740. return FALSE;
  741. }
  742. if (Slot.u.bits.FunctionNumber == 0) {
  743. return TRUE;
  744. }
  745. //
  746. // Non zero function numbers are only supported if the
  747. // device has the PCI_MULTIFUNCTION bit set in it's header
  748. //
  749. i = Slot.u.bits.DeviceNumber;
  750. //
  751. // Read DeviceNumber, Function zero, to determine if the
  752. // PCI supports multifunction devices
  753. //
  754. Slot2 = Slot;
  755. Slot2.u.bits.FunctionNumber = 0;
  756. HalpReadPCIConfig (
  757. BusHandler,
  758. Slot2,
  759. &Header,
  760. 0,
  761. sizeof(Header)
  762. );
  763. if (PciConfig->VendorID == PCI_INVALID_VENDORID) {
  764. //
  765. // This device doesn't exist, therefore, this function
  766. // doesn't exist.
  767. //
  768. return FALSE;
  769. }
  770. if (PciConfig->HeaderType & PCI_MULTIFUNCTION) {
  771. //
  772. // It's a multifunction device. Slot is valid.
  773. //
  774. return TRUE;
  775. }
  776. //
  777. // Special cases, ie HACKs for broken hardware.
  778. //
  779. if ((PciConfig->VendorID == 0x8086) &&
  780. (PciConfig->DeviceID == 0x122e)) {
  781. //
  782. // This device lies, it really is multifunction.
  783. // It's also writable so write back the correct value
  784. // to avoid coming down this path in future.
  785. //
  786. PciConfig->HeaderType |= PCI_MULTIFUNCTION;
  787. HalpWritePCIConfig(
  788. BusHandler,
  789. Slot2,
  790. &PciConfig->HeaderType,
  791. FIELD_OFFSET(PCI_COMMON_CONFIG, HeaderType),
  792. sizeof(PciConfig->HeaderType)
  793. );
  794. return TRUE;
  795. }
  796. //
  797. // None of the above, must not be a multifunction device.
  798. //
  799. return FALSE;
  800. }
  801. VOID
  802. HalpPCIConfig (
  803. IN PBUS_HANDLER BusHandler,
  804. IN PCI_SLOT_NUMBER Slot,
  805. IN PUCHAR Buffer,
  806. IN ULONG Offset,
  807. IN ULONG Length,
  808. IN FncConfigIO *ConfigIO
  809. )
  810. {
  811. KIRQL OldIrql;
  812. ULONG i;
  813. UCHAR State[20];
  814. PPCIPBUSDATA BusData;
  815. BusData = (PPCIPBUSDATA) BusHandler->BusData;
  816. PCIConfigHandler.Synchronize (BusHandler, Slot, &OldIrql, State);
  817. while (Length) {
  818. i = PCIDeref[Offset % sizeof(ULONG)][Length % sizeof(ULONG)];
  819. i = ConfigIO[i] (BusData, State, Buffer, Offset);
  820. Offset += i;
  821. Buffer += i;
  822. Length -= i;
  823. }
  824. PCIConfigHandler.ReleaseSynchronzation (BusHandler, OldIrql);
  825. }
  826. VOID
  827. HalpPCISynchronizeType1 (
  828. IN PBUS_HANDLER BusHandler,
  829. IN PCI_SLOT_NUMBER Slot,
  830. IN PKIRQL Irql,
  831. IN PPCI_TYPE1_CFG_BITS PciCfg1
  832. )
  833. {
  834. //
  835. // Initialize PciCfg1
  836. //
  837. PciCfg1->u.AsULONG = 0;
  838. PciCfg1->u.bits.BusNumber = BusHandler->BusNumber;
  839. PciCfg1->u.bits.DeviceNumber = Slot.u.bits.DeviceNumber;
  840. PciCfg1->u.bits.FunctionNumber = Slot.u.bits.FunctionNumber;
  841. PciCfg1->u.bits.Enable = TRUE;
  842. //
  843. // Synchronize with PCI type1 config space
  844. //
  845. if (!HalpDoingCrashDump) {
  846. *Irql = KfRaiseIrql (HIGH_LEVEL);
  847. KiAcquireSpinLock (&HalpPCIConfigLock);
  848. } else {
  849. *Irql = HIGH_LEVEL;
  850. }
  851. }
  852. VOID
  853. HalpPCIReleaseSynchronzationType1 (
  854. IN PBUS_HANDLER BusHandler,
  855. IN KIRQL Irql
  856. )
  857. {
  858. PCI_TYPE1_CFG_BITS PciCfg1;
  859. PPCIPBUSDATA BusData;
  860. //
  861. // Disable PCI configuration space
  862. //
  863. PciCfg1.u.AsULONG = 0;
  864. BusData = (PPCIPBUSDATA) BusHandler->BusData;
  865. WRITE_PORT_ULONG (BusData->Config.Type1.Address, PciCfg1.u.AsULONG);
  866. //
  867. // Release spinlock
  868. //
  869. if (!HalpDoingCrashDump) {
  870. KiReleaseSpinLock (&HalpPCIConfigLock);
  871. KeLowerIrql (Irql);
  872. }
  873. }
  874. VOID
  875. HalpPCISynchronizeOrionB0 (
  876. IN PBUS_HANDLER BusHandler,
  877. IN PCI_SLOT_NUMBER Slot,
  878. IN PKIRQL Irql,
  879. IN PPCI_TYPE1_CFG_BITS PciCfg1
  880. )
  881. {
  882. PCI_TYPE1_CFG_BITS Cfg1;
  883. union {
  884. ULONG dword;
  885. USHORT word;
  886. UCHAR byte[4];
  887. } Buffer;
  888. //
  889. // First perform normal type 1 synchronization
  890. //
  891. HalpPCISynchronizeType1 (BusHandler, Slot, Irql, PciCfg1);
  892. //
  893. // Apply Orion B0 workaround
  894. //
  895. Cfg1.u.AsULONG=0;
  896. Cfg1.u.bits.BusNumber = HalpOrionOPB.Handler->BusNumber;
  897. Cfg1.u.bits.DeviceNumber = HalpOrionOPB.Slot.u.bits.DeviceNumber;
  898. Cfg1.u.bits.FunctionNumber = HalpOrionOPB.Slot.u.bits.FunctionNumber;
  899. Cfg1.u.bits.Enable = TRUE;
  900. //
  901. // Read OPB until we get back the expected Vendor ID and device ID
  902. //
  903. do {
  904. HalpPCIReadUlongType1 (HalpOrionOPB.Handler->BusData, &Cfg1, Buffer.byte, 0);
  905. } while (Buffer.dword != 0x84c48086);
  906. //
  907. // The bug is that the config read will return whatever value you
  908. // happened to read last. Read register 0x54 till we don't read the
  909. // last value read any more(Vendor ID/Device ID).
  910. //
  911. do {
  912. HalpPCIReadUshortType1 (HalpOrionOPB.Handler->BusData, &Cfg1, Buffer.byte, 0x54);
  913. } while (Buffer.word == 0x8086);
  914. //
  915. // Disable inbound posting by clearing bit 0 of register 0x54
  916. //
  917. Buffer.word &= ~0x1;
  918. HalpPCIWriteUshortType1 (HalpOrionOPB.Handler->BusData, &Cfg1, Buffer.byte, 0x54);
  919. }
  920. VOID
  921. HalpPCIReleaseSynchronzationOrionB0 (
  922. IN PBUS_HANDLER BusHandler,
  923. IN KIRQL Irql
  924. )
  925. {
  926. PCI_TYPE1_CFG_BITS PciCfg1;
  927. PPCIPBUSDATA BusData;
  928. union {
  929. ULONG dword;
  930. USHORT word;
  931. UCHAR byte[4];
  932. } Buffer;
  933. PciCfg1.u.AsULONG=0;
  934. PciCfg1.u.bits.BusNumber = HalpOrionOPB.Handler->BusNumber;
  935. PciCfg1.u.bits.DeviceNumber = HalpOrionOPB.Slot.u.bits.DeviceNumber;
  936. PciCfg1.u.bits.FunctionNumber = HalpOrionOPB.Slot.u.bits.FunctionNumber;
  937. PciCfg1.u.bits.Enable = TRUE;
  938. HalpPCIReadUshortType1 (HalpOrionOPB.Handler->BusData, &PciCfg1, Buffer.byte, 0x54);
  939. //
  940. // Enable Inbound posting by setting bit 0 of register 0x54 of ncOPB
  941. //
  942. Buffer.word |= 0x1;
  943. HalpPCIWriteUshortType1 (HalpOrionOPB.Handler->BusData, &PciCfg1, Buffer.byte, 0x54);
  944. //
  945. // Complete type 1 synchronization
  946. //
  947. HalpPCIReleaseSynchronzationType1 (BusHandler, Irql);
  948. }
  949. ULONG
  950. HalpPCIReadUcharType1 (
  951. IN PPCIPBUSDATA BusData,
  952. IN PPCI_TYPE1_CFG_BITS PciCfg1,
  953. IN PUCHAR Buffer,
  954. IN ULONG Offset
  955. )
  956. {
  957. ULONG i;
  958. i = Offset % sizeof(ULONG);
  959. PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG);
  960. WRITE_PORT_ULONG (BusData->Config.Type1.Address, PciCfg1->u.AsULONG);
  961. *Buffer = READ_PORT_UCHAR ((PUCHAR) (ULONG_PTR)(BusData->Config.Type1.Data + i));
  962. return sizeof (UCHAR);
  963. }
  964. ULONG
  965. HalpPCIReadUshortType1 (
  966. IN PPCIPBUSDATA BusData,
  967. IN PPCI_TYPE1_CFG_BITS PciCfg1,
  968. IN PUCHAR Buffer,
  969. IN ULONG Offset
  970. )
  971. {
  972. ULONG i;
  973. i = Offset % sizeof(ULONG);
  974. PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG);
  975. WRITE_PORT_ULONG (BusData->Config.Type1.Address, PciCfg1->u.AsULONG);
  976. *((PUSHORT) Buffer) = READ_PORT_USHORT ((PUSHORT) (ULONG_PTR)(BusData->Config.Type1.Data + i));
  977. return sizeof (USHORT);
  978. }
  979. ULONG
  980. HalpPCIReadUlongType1 (
  981. IN PPCIPBUSDATA BusData,
  982. IN PPCI_TYPE1_CFG_BITS PciCfg1,
  983. IN PUCHAR Buffer,
  984. IN ULONG Offset
  985. )
  986. {
  987. PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG);
  988. WRITE_PORT_ULONG (BusData->Config.Type1.Address, PciCfg1->u.AsULONG);
  989. *((PULONG) Buffer) = READ_PORT_ULONG ((PULONG) (ULONG_PTR)BusData->Config.Type1.Data);
  990. return sizeof (ULONG);
  991. }
  992. ULONG
  993. HalpPCIWriteUcharType1 (
  994. IN PPCIPBUSDATA BusData,
  995. IN PPCI_TYPE1_CFG_BITS PciCfg1,
  996. IN PUCHAR Buffer,
  997. IN ULONG Offset
  998. )
  999. {
  1000. ULONG i;
  1001. i = Offset % sizeof(ULONG);
  1002. PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG);
  1003. WRITE_PORT_ULONG (BusData->Config.Type1.Address, PciCfg1->u.AsULONG);
  1004. WRITE_PORT_UCHAR ((PUCHAR) (ULONG_PTR)(BusData->Config.Type1.Data + i), *Buffer);
  1005. return sizeof (UCHAR);
  1006. }
  1007. ULONG
  1008. HalpPCIWriteUshortType1 (
  1009. IN PPCIPBUSDATA BusData,
  1010. IN PPCI_TYPE1_CFG_BITS PciCfg1,
  1011. IN PUCHAR Buffer,
  1012. IN ULONG Offset
  1013. )
  1014. {
  1015. ULONG i;
  1016. i = Offset % sizeof(ULONG);
  1017. PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG);
  1018. WRITE_PORT_ULONG (BusData->Config.Type1.Address, PciCfg1->u.AsULONG);
  1019. WRITE_PORT_USHORT ((PUSHORT) (ULONG_PTR)(BusData->Config.Type1.Data + i), *((PUSHORT) Buffer));
  1020. return sizeof (USHORT);
  1021. }
  1022. ULONG
  1023. HalpPCIWriteUlongType1 (
  1024. IN PPCIPBUSDATA BusData,
  1025. IN PPCI_TYPE1_CFG_BITS PciCfg1,
  1026. IN PUCHAR Buffer,
  1027. IN ULONG Offset
  1028. )
  1029. {
  1030. PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG);
  1031. WRITE_PORT_ULONG (BusData->Config.Type1.Address, PciCfg1->u.AsULONG);
  1032. WRITE_PORT_ULONG ((PULONG) (ULONG_PTR)BusData->Config.Type1.Data, *((PULONG) Buffer));
  1033. return sizeof (ULONG);
  1034. }
  1035. VOID HalpPCISynchronizeType2 (
  1036. IN PBUS_HANDLER BusHandler,
  1037. IN PCI_SLOT_NUMBER Slot,
  1038. IN PKIRQL Irql,
  1039. IN PPCI_TYPE2_ADDRESS_BITS PciCfg2Addr
  1040. )
  1041. {
  1042. PCI_TYPE2_CSE_BITS PciCfg2Cse;
  1043. PPCIPBUSDATA BusData;
  1044. BusData = (PPCIPBUSDATA) BusHandler->BusData;
  1045. //
  1046. // Initialize Cfg2Addr
  1047. //
  1048. PciCfg2Addr->u.AsUSHORT = 0;
  1049. PciCfg2Addr->u.bits.Agent = (USHORT) Slot.u.bits.DeviceNumber;
  1050. PciCfg2Addr->u.bits.AddressBase = (USHORT) BusData->Config.Type2.Base;
  1051. //
  1052. // Synchronize with type2 config space - type2 config space
  1053. // remaps 4K of IO space, so we can not allow other I/Os to occur
  1054. // while using type2 config space.
  1055. //
  1056. HalpPCIAcquireType2Lock (&HalpPCIConfigLock, Irql);
  1057. PciCfg2Cse.u.AsUCHAR = 0;
  1058. PciCfg2Cse.u.bits.Enable = TRUE;
  1059. PciCfg2Cse.u.bits.FunctionNumber = (UCHAR) Slot.u.bits.FunctionNumber;
  1060. PciCfg2Cse.u.bits.Key = 0xff;
  1061. //
  1062. // Select bus & enable type 2 configuration space
  1063. //
  1064. WRITE_PORT_UCHAR (BusData->Config.Type2.Forward, (UCHAR) BusHandler->BusNumber);
  1065. WRITE_PORT_UCHAR (BusData->Config.Type2.CSE, PciCfg2Cse.u.AsUCHAR);
  1066. }
  1067. VOID HalpPCIReleaseSynchronzationType2 (
  1068. IN PBUS_HANDLER BusHandler,
  1069. IN KIRQL Irql
  1070. )
  1071. {
  1072. PCI_TYPE2_CSE_BITS PciCfg2Cse;
  1073. PPCIPBUSDATA BusData;
  1074. //
  1075. // disable PCI configuration space
  1076. //
  1077. BusData = (PPCIPBUSDATA) BusHandler->BusData;
  1078. PciCfg2Cse.u.AsUCHAR = 0;
  1079. WRITE_PORT_UCHAR (BusData->Config.Type2.CSE, PciCfg2Cse.u.AsUCHAR);
  1080. WRITE_PORT_UCHAR (BusData->Config.Type2.Forward, (UCHAR) 0);
  1081. //
  1082. // Restore interrupts, release spinlock
  1083. //
  1084. HalpPCIReleaseType2Lock (&HalpPCIConfigLock, Irql);
  1085. }
  1086. ULONG
  1087. HalpPCIReadUcharType2 (
  1088. IN PPCIPBUSDATA BusData,
  1089. IN PPCI_TYPE2_ADDRESS_BITS PciCfg2Addr,
  1090. IN PUCHAR Buffer,
  1091. IN ULONG Offset
  1092. )
  1093. {
  1094. PciCfg2Addr->u.bits.RegisterNumber = (USHORT) Offset;
  1095. *Buffer = READ_PORT_UCHAR ((PUCHAR) PciCfg2Addr->u.AsUSHORT);
  1096. return sizeof (UCHAR);
  1097. }
  1098. ULONG
  1099. HalpPCIReadUshortType2 (
  1100. IN PPCIPBUSDATA BusData,
  1101. IN PPCI_TYPE2_ADDRESS_BITS PciCfg2Addr,
  1102. IN PUCHAR Buffer,
  1103. IN ULONG Offset
  1104. )
  1105. {
  1106. PciCfg2Addr->u.bits.RegisterNumber = (USHORT) Offset;
  1107. *((PUSHORT) Buffer) = READ_PORT_USHORT ((PUSHORT) PciCfg2Addr->u.AsUSHORT);
  1108. return sizeof (USHORT);
  1109. }
  1110. ULONG
  1111. HalpPCIReadUlongType2 (
  1112. IN PPCIPBUSDATA BusData,
  1113. IN PPCI_TYPE2_ADDRESS_BITS PciCfg2Addr,
  1114. IN PUCHAR Buffer,
  1115. IN ULONG Offset
  1116. )
  1117. {
  1118. PciCfg2Addr->u.bits.RegisterNumber = (USHORT) Offset;
  1119. *((PULONG) Buffer) = READ_PORT_ULONG ((PULONG) PciCfg2Addr->u.AsUSHORT);
  1120. return sizeof(ULONG);
  1121. }
  1122. ULONG
  1123. HalpPCIWriteUcharType2 (
  1124. IN PPCIPBUSDATA BusData,
  1125. IN PPCI_TYPE2_ADDRESS_BITS PciCfg2Addr,
  1126. IN PUCHAR Buffer,
  1127. IN ULONG Offset
  1128. )
  1129. {
  1130. PciCfg2Addr->u.bits.RegisterNumber = (USHORT) Offset;
  1131. WRITE_PORT_UCHAR ((PUCHAR) PciCfg2Addr->u.AsUSHORT, *Buffer);
  1132. return sizeof (UCHAR);
  1133. }
  1134. ULONG
  1135. HalpPCIWriteUshortType2 (
  1136. IN PPCIPBUSDATA BusData,
  1137. IN PPCI_TYPE2_ADDRESS_BITS PciCfg2Addr,
  1138. IN PUCHAR Buffer,
  1139. IN ULONG Offset
  1140. )
  1141. {
  1142. PciCfg2Addr->u.bits.RegisterNumber = (USHORT) Offset;
  1143. WRITE_PORT_USHORT ((PUSHORT) PciCfg2Addr->u.AsUSHORT, *((PUSHORT) Buffer));
  1144. return sizeof (USHORT);
  1145. }
  1146. ULONG
  1147. HalpPCIWriteUlongType2 (
  1148. IN PPCIPBUSDATA BusData,
  1149. IN PPCI_TYPE2_ADDRESS_BITS PciCfg2Addr,
  1150. IN PUCHAR Buffer,
  1151. IN ULONG Offset
  1152. )
  1153. {
  1154. PciCfg2Addr->u.bits.RegisterNumber = (USHORT) Offset;
  1155. WRITE_PORT_ULONG ((PULONG) PciCfg2Addr->u.AsUSHORT, *((PULONG) Buffer));
  1156. return sizeof(ULONG);
  1157. }
  1158. NTSTATUS
  1159. HalpAssignPCISlotResources (
  1160. IN PBUS_HANDLER BusHandler,
  1161. IN PBUS_HANDLER RootHandler,
  1162. IN PUNICODE_STRING RegistryPath,
  1163. IN PUNICODE_STRING DriverClassName OPTIONAL,
  1164. IN PDRIVER_OBJECT DriverObject,
  1165. IN PDEVICE_OBJECT DeviceObject OPTIONAL,
  1166. IN ULONG Slot,
  1167. IN OUT PCM_RESOURCE_LIST *pAllocatedResources
  1168. )
  1169. /*++
  1170. Routine Description:
  1171. Reads the targeted device to determine it's required resources.
  1172. Calls IoAssignResources to allocate them.
  1173. Sets the targeted device with it's assigned resoruces
  1174. and returns the assignments to the caller.
  1175. Arguments:
  1176. Return Value:
  1177. STATUS_SUCCESS or error
  1178. --*/
  1179. {
  1180. NTSTATUS status;
  1181. PUCHAR WorkingPool;
  1182. PPCI_COMMON_CONFIG PciData, PciOrigData, PciData2;
  1183. PCI_SLOT_NUMBER PciSlot;
  1184. PPCIPBUSDATA BusData;
  1185. PIO_RESOURCE_REQUIREMENTS_LIST CompleteList;
  1186. PIO_RESOURCE_DESCRIPTOR Descriptor;
  1187. PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescriptor;
  1188. ULONG BusNumber;
  1189. ULONG i, j, m, length, memtype;
  1190. ULONG NoBaseAddress, RomIndex, Option;
  1191. PULONG BaseAddress[PCI_TYPE0_ADDRESSES + 1];
  1192. PULONG OrigAddress[PCI_TYPE0_ADDRESSES + 1];
  1193. BOOLEAN Match, EnableRomBase, RequestedInterrupt;
  1194. KIRQL Kirql;
  1195. KAFFINITY Kaffinity;
  1196. *pAllocatedResources = NULL;
  1197. PciSlot = *((PPCI_SLOT_NUMBER) &Slot);
  1198. BusNumber = BusHandler->BusNumber;
  1199. BusData = (PPCIPBUSDATA) BusHandler->BusData;
  1200. //
  1201. // Allocate some pool for working space
  1202. //
  1203. i = sizeof (IO_RESOURCE_REQUIREMENTS_LIST) +
  1204. sizeof (IO_RESOURCE_DESCRIPTOR) * (PCI_TYPE0_ADDRESSES + 2) * 2 +
  1205. PCI_COMMON_HDR_LENGTH * 3;
  1206. WorkingPool = (PUCHAR)ExAllocatePoolWithTag(PagedPool, i, HAL_POOL_TAG);
  1207. if (!WorkingPool) {
  1208. return STATUS_INSUFFICIENT_RESOURCES;
  1209. }
  1210. //
  1211. // Zero initialize pool, and get pointers into memory
  1212. //
  1213. RtlZeroMemory (WorkingPool, i);
  1214. CompleteList = (PIO_RESOURCE_REQUIREMENTS_LIST) WorkingPool;
  1215. PciData = (PPCI_COMMON_CONFIG) (WorkingPool + i - PCI_COMMON_HDR_LENGTH * 3);
  1216. PciData2 = (PPCI_COMMON_CONFIG) (WorkingPool + i - PCI_COMMON_HDR_LENGTH * 2);
  1217. PciOrigData = (PPCI_COMMON_CONFIG) (WorkingPool + i - PCI_COMMON_HDR_LENGTH * 1);
  1218. //
  1219. // Read the PCI device's configuration
  1220. //
  1221. HalpReadPCIConfig (BusHandler, PciSlot, PciData, 0, PCI_COMMON_HDR_LENGTH);
  1222. if (PciData->VendorID == PCI_INVALID_VENDORID) {
  1223. ExFreePool (WorkingPool);
  1224. return STATUS_NO_SUCH_DEVICE;
  1225. }
  1226. //
  1227. // For now since there's not PnP support in the OS, if the BIOS hasn't
  1228. // enable a VGA device don't allow it to get enabled via this interface.
  1229. //
  1230. if ( (PciData->BaseClass == 0 && PciData->SubClass == 1) ||
  1231. (PciData->BaseClass == 3 && PciData->SubClass == 0)) {
  1232. if ((PciData->Command & (PCI_ENABLE_IO_SPACE | PCI_ENABLE_MEMORY_SPACE)) == 0) {
  1233. ExFreePool (WorkingPool);
  1234. return STATUS_DEVICE_NOT_CONNECTED;
  1235. }
  1236. }
  1237. //
  1238. // Make a copy of the device's current settings
  1239. //
  1240. RtlMoveMemory (PciOrigData, PciData, PCI_COMMON_HDR_LENGTH);
  1241. //
  1242. // Initialize base addresses base on configuration data type
  1243. //
  1244. switch (PCI_CONFIG_TYPE(PciData)) {
  1245. case 0 :
  1246. NoBaseAddress = PCI_TYPE0_ADDRESSES+1;
  1247. for (j=0; j < PCI_TYPE0_ADDRESSES; j++) {
  1248. BaseAddress[j] = &PciData->u.type0.BaseAddresses[j];
  1249. OrigAddress[j] = &PciOrigData->u.type0.BaseAddresses[j];
  1250. }
  1251. BaseAddress[j] = &PciData->u.type0.ROMBaseAddress;
  1252. OrigAddress[j] = &PciOrigData->u.type0.ROMBaseAddress;
  1253. RomIndex = j;
  1254. break;
  1255. case 1:
  1256. NoBaseAddress = PCI_TYPE1_ADDRESSES+1;
  1257. for (j=0; j < PCI_TYPE1_ADDRESSES; j++) {
  1258. BaseAddress[j] = &PciData->u.type1.BaseAddresses[j];
  1259. OrigAddress[j] = &PciOrigData->u.type1.BaseAddresses[j];
  1260. }
  1261. BaseAddress[j] = &PciData->u.type1.ROMBaseAddress;
  1262. OrigAddress[j] = &PciOrigData->u.type1.ROMBaseAddress;
  1263. RomIndex = j;
  1264. break;
  1265. default:
  1266. ExFreePool (WorkingPool);
  1267. return STATUS_NO_SUCH_DEVICE;
  1268. }
  1269. //
  1270. // If the BIOS doesn't have the device's ROM enabled, then we won't
  1271. // enable it either. Remove it from the list.
  1272. //
  1273. EnableRomBase = TRUE;
  1274. if (!(*BaseAddress[RomIndex] & PCI_ROMADDRESS_ENABLED)) {
  1275. ASSERT (RomIndex+1 == NoBaseAddress);
  1276. EnableRomBase = FALSE;
  1277. NoBaseAddress -= 1;
  1278. }
  1279. //
  1280. // Set resources to all bits on to see what type of resources
  1281. // are required.
  1282. //
  1283. for (j=0; j < NoBaseAddress; j++) {
  1284. *BaseAddress[j] = 0xFFFFFFFF;
  1285. }
  1286. PciData->Command &= ~(PCI_ENABLE_IO_SPACE | PCI_ENABLE_MEMORY_SPACE);
  1287. *BaseAddress[RomIndex] &= ~PCI_ROMADDRESS_ENABLED;
  1288. HalpWritePCIConfig (BusHandler, PciSlot, PciData, 0, PCI_COMMON_HDR_LENGTH);
  1289. HalpReadPCIConfig (BusHandler, PciSlot, PciData, 0, PCI_COMMON_HDR_LENGTH);
  1290. // note type0 & type1 overlay ROMBaseAddress, InterruptPin, and InterruptLine
  1291. BusData->CommonData.Pin2Line (BusHandler, RootHandler, PciSlot, PciData);
  1292. //
  1293. // Build an IO_RESOURCE_REQUIREMENTS_LIST for the PCI device
  1294. //
  1295. CompleteList->InterfaceType = PCIBus;
  1296. CompleteList->BusNumber = BusNumber;
  1297. CompleteList->SlotNumber = Slot;
  1298. CompleteList->AlternativeLists = 1;
  1299. CompleteList->List[0].Version = 1;
  1300. CompleteList->List[0].Revision = 1;
  1301. Descriptor = CompleteList->List[0].Descriptors;
  1302. //
  1303. // If PCI device has an interrupt resource, add it
  1304. //
  1305. RequestedInterrupt = FALSE;
  1306. if (PciData->u.type0.InterruptPin &&
  1307. PciData->u.type0.InterruptLine != (0 ^ IRQXOR) &&
  1308. PciData->u.type0.InterruptLine != (0xFF ^ IRQXOR) &&
  1309. HalGetInterruptVector(PCIBus,
  1310. BusNumber,
  1311. PciData->u.type0.InterruptLine,
  1312. PciData->u.type0.InterruptLine,
  1313. &Kirql,
  1314. &Kaffinity)) {
  1315. RequestedInterrupt = TRUE;
  1316. CompleteList->List[0].Count++;
  1317. Descriptor->Option = 0;
  1318. Descriptor->Type = CmResourceTypeInterrupt;
  1319. Descriptor->ShareDisposition = CmResourceShareShared;
  1320. Descriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
  1321. if (ARGUMENT_PRESENT(DeviceObject)) {
  1322. //
  1323. // Let the arbiter pick any interrupt.
  1324. //
  1325. Descriptor->u.Interrupt.MinimumVector = 0;
  1326. Descriptor->u.Interrupt.MaximumVector = 0xff;
  1327. } else {
  1328. //
  1329. // Translation is going to fail, because we won't
  1330. // be able to identify this device by its device
  1331. // object. So trim the requested interrupt resources
  1332. // down to what's in the interrupt line register.
  1333. // The translator will punt and read this.
  1334. //
  1335. Descriptor->u.Interrupt.MinimumVector = PciData->u.type0.InterruptLine;
  1336. Descriptor->u.Interrupt.MaximumVector = PciData->u.type0.InterruptLine;
  1337. }
  1338. Descriptor++;
  1339. }
  1340. //
  1341. // Add a memory/port resoruce for each PCI resource
  1342. //
  1343. // Clear ROM reserved bits
  1344. *BaseAddress[RomIndex] &= ~0x7FF;
  1345. for (j=0; j < NoBaseAddress; j++) {
  1346. if (*BaseAddress[j]) {
  1347. i = *BaseAddress[j];
  1348. // scan for first set bit, that's the length & alignment
  1349. length = 1 << (i & PCI_ADDRESS_IO_SPACE ? 2 : 4);
  1350. while (!(i & length) && length) {
  1351. length <<= 1;
  1352. }
  1353. // scan for last set bit, that's the maxaddress + 1
  1354. for (m = length; i & m; m <<= 1) ;
  1355. m--;
  1356. // check for hosed PCI configuration requirements
  1357. if (length & ~m) {
  1358. #if DBG
  1359. DbgPrint ("PCI: defective device! Bus %d, Slot %d, Function %d\n",
  1360. BusNumber,
  1361. PciSlot.u.bits.DeviceNumber,
  1362. PciSlot.u.bits.FunctionNumber
  1363. );
  1364. DbgPrint ("PCI: BaseAddress[%d] = %08lx\n", j, i);
  1365. #endif
  1366. // the device is in error - punt. don't allow this
  1367. // resource any option - it either gets set to whatever
  1368. // bits it was able to return, or it doesn't get set.
  1369. if (i & PCI_ADDRESS_IO_SPACE) {
  1370. m = i & ~0x3;
  1371. Descriptor->u.Port.MinimumAddress.LowPart = m;
  1372. } else {
  1373. m = i & ~0xf;
  1374. Descriptor->u.Memory.MinimumAddress.LowPart = m;
  1375. }
  1376. m += length; // max address is min address + length
  1377. }
  1378. //
  1379. // Add requested resource
  1380. //
  1381. Descriptor->Option = 0;
  1382. if (i & PCI_ADDRESS_IO_SPACE) {
  1383. memtype = 0;
  1384. if (PciOrigData->Command & PCI_ENABLE_IO_SPACE) {
  1385. //
  1386. // The IO range is/was already enabled at some location, add that
  1387. // as it's preferred setting.
  1388. //
  1389. Descriptor->Type = CmResourceTypePort;
  1390. Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
  1391. Descriptor->Flags = CM_RESOURCE_PORT_IO;
  1392. Descriptor->Option = IO_RESOURCE_PREFERRED;
  1393. Descriptor->u.Port.Length = length;
  1394. Descriptor->u.Port.Alignment = length;
  1395. Descriptor->u.Port.MinimumAddress.LowPart = *OrigAddress[j] & ~0x3;
  1396. Descriptor->u.Port.MaximumAddress.LowPart =
  1397. Descriptor->u.Port.MinimumAddress.LowPart + length - 1;
  1398. CompleteList->List[0].Count++;
  1399. Descriptor++;
  1400. Descriptor->Option = IO_RESOURCE_ALTERNATIVE;
  1401. }
  1402. //
  1403. // Add this IO range
  1404. //
  1405. Descriptor->Type = CmResourceTypePort;
  1406. Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
  1407. Descriptor->Flags = CM_RESOURCE_PORT_IO;
  1408. Descriptor->u.Port.Length = length;
  1409. Descriptor->u.Port.Alignment = length;
  1410. Descriptor->u.Port.MaximumAddress.LowPart = m;
  1411. } else {
  1412. memtype = i & PCI_ADDRESS_MEMORY_TYPE_MASK;
  1413. Descriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
  1414. if (j == RomIndex) {
  1415. // this is a ROM address
  1416. Descriptor->Flags = CM_RESOURCE_MEMORY_READ_ONLY;
  1417. }
  1418. if (i & PCI_ADDRESS_MEMORY_PREFETCHABLE) {
  1419. Descriptor->Flags |= CM_RESOURCE_MEMORY_PREFETCHABLE;
  1420. }
  1421. if ((j == RomIndex) ||
  1422. ((PciOrigData->Command & PCI_ENABLE_MEMORY_SPACE) &&
  1423. ((!Is64BitBaseAddress(i)) || (*OrigAddress[j+1] == 0)))) {
  1424. //
  1425. // The memory range is/was already enabled at some location,
  1426. // add that as it's preferred setting.
  1427. //
  1428. Descriptor->Type = CmResourceTypeMemory;
  1429. Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
  1430. Descriptor->Option = IO_RESOURCE_PREFERRED;
  1431. Descriptor->u.Port.Length = length;
  1432. Descriptor->u.Port.Alignment = length;
  1433. Descriptor->u.Port.MinimumAddress.LowPart = *OrigAddress[j] & ~0xF;
  1434. Descriptor->u.Port.MaximumAddress.LowPart =
  1435. Descriptor->u.Port.MinimumAddress.LowPart + length - 1;
  1436. CompleteList->List[0].Count++;
  1437. Descriptor++;
  1438. Descriptor->Flags = Descriptor[-1].Flags;
  1439. Descriptor->Option = IO_RESOURCE_ALTERNATIVE;
  1440. }
  1441. //
  1442. // Add this memory range
  1443. //
  1444. Descriptor->Type = CmResourceTypeMemory;
  1445. Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
  1446. Descriptor->u.Memory.Length = length;
  1447. Descriptor->u.Memory.Alignment = length;
  1448. Descriptor->u.Memory.MaximumAddress.LowPart = m;
  1449. if (memtype == PCI_TYPE_20BIT && m > 0xFFFFF) {
  1450. // limit to 20 bit address
  1451. Descriptor->u.Memory.MaximumAddress.LowPart = 0xFFFFF;
  1452. }
  1453. }
  1454. CompleteList->List[0].Count++;
  1455. Descriptor++;
  1456. if (Is64BitBaseAddress(i)) {
  1457. // skip upper half of 64 bit address since this processor
  1458. // only supports 32 bits of address space
  1459. j++;
  1460. }
  1461. }
  1462. }
  1463. CompleteList->ListSize = (ULONG)
  1464. ((PUCHAR) Descriptor - (PUCHAR) CompleteList);
  1465. //
  1466. // Restore the device settings as we found them, enable memory
  1467. // and io decode after setting base addresses. This is done in
  1468. // case HalAdjustResourceList wants to read the current settings
  1469. // in the device.
  1470. //
  1471. HalpWritePCIConfig (
  1472. BusHandler,
  1473. PciSlot,
  1474. &PciOrigData->Status,
  1475. FIELD_OFFSET (PCI_COMMON_CONFIG, Status),
  1476. PCI_COMMON_HDR_LENGTH - FIELD_OFFSET (PCI_COMMON_CONFIG, Status)
  1477. );
  1478. HalpWritePCIConfig (
  1479. BusHandler,
  1480. PciSlot,
  1481. PciOrigData,
  1482. 0,
  1483. FIELD_OFFSET (PCI_COMMON_CONFIG, Status)
  1484. );
  1485. //
  1486. // Have the IO system allocate resource assignments
  1487. //
  1488. status = IoAssignResources (
  1489. RegistryPath,
  1490. DriverClassName,
  1491. DriverObject,
  1492. DeviceObject,
  1493. CompleteList,
  1494. pAllocatedResources
  1495. );
  1496. if (!NT_SUCCESS(status)) {
  1497. goto CleanUp;
  1498. }
  1499. //
  1500. // Slurp the assigments back into the PciData structure and
  1501. // perform them
  1502. //
  1503. CmDescriptor = (*pAllocatedResources)->List[0].PartialResourceList.PartialDescriptors;
  1504. //
  1505. // If PCI device has an interrupt resource then that was
  1506. // passed in as the first requested resource
  1507. //
  1508. if (RequestedInterrupt) {
  1509. PciData->u.type0.InterruptLine = (UCHAR) CmDescriptor->u.Interrupt.Vector;
  1510. BusData->CommonData.Line2Pin (BusHandler, RootHandler, PciSlot, PciData, PciOrigData);
  1511. CmDescriptor++;
  1512. }
  1513. //
  1514. // Pull out resources in the order they were passed to IoAssignResources
  1515. //
  1516. for (j=0; j < NoBaseAddress; j++) {
  1517. i = *BaseAddress[j];
  1518. if (i) {
  1519. if (i & PCI_ADDRESS_IO_SPACE) {
  1520. *BaseAddress[j] = CmDescriptor->u.Port.Start.LowPart;
  1521. } else {
  1522. *BaseAddress[j] = CmDescriptor->u.Memory.Start.LowPart;
  1523. if (Is64BitBaseAddress(i)) {
  1524. //
  1525. // 64 bit address occupies 2 BARs. Reset the
  1526. // upper 32 bits to zero (currently FFFFFFFF
  1527. // from above). Actually, set to upper 32 bits
  1528. // from assigned resource.
  1529. //
  1530. j++;
  1531. *BaseAddress[j] = CmDescriptor->u.Memory.Start.HighPart;
  1532. }
  1533. }
  1534. CmDescriptor++;
  1535. }
  1536. }
  1537. //
  1538. // Turn off decodes, then set new addresses
  1539. //
  1540. HalpWritePCIConfig (BusHandler, PciSlot, PciData, 0, PCI_COMMON_HDR_LENGTH);
  1541. //
  1542. // Read configuration back and verify address settings took
  1543. //
  1544. HalpReadPCIConfig(BusHandler, PciSlot, PciData2, 0, PCI_COMMON_HDR_LENGTH);
  1545. Match = TRUE;
  1546. if (PciData->u.type0.InterruptLine != PciData2->u.type0.InterruptLine ||
  1547. PciData->u.type0.InterruptPin != PciData2->u.type0.InterruptPin ||
  1548. PciData->u.type0.ROMBaseAddress != PciData2->u.type0.ROMBaseAddress) {
  1549. Match = FALSE;
  1550. }
  1551. for (j=0; j < NoBaseAddress; j++) {
  1552. if (*BaseAddress[j]) {
  1553. if (*BaseAddress[j] & PCI_ADDRESS_IO_SPACE) {
  1554. i = PCI_ADDRESS_IO_ADDRESS_MASK;
  1555. } else {
  1556. i = PCI_ADDRESS_MEMORY_ADDRESS_MASK;
  1557. }
  1558. if ((*BaseAddress[j] & i) !=
  1559. (*((PULONG) ((PUCHAR) BaseAddress[j] -
  1560. (PUCHAR) PciData +
  1561. (PUCHAR) PciData2)) & i)) {
  1562. Match = FALSE;
  1563. }
  1564. if (Is64BitBaseAddress(*BaseAddress[j])) {
  1565. // skip upper 32 bits
  1566. j++;
  1567. }
  1568. }
  1569. }
  1570. if (!Match) {
  1571. #if DBG
  1572. DbgPrint ("PCI: defective device! Bus %d, Slot %d, Function %d\n",
  1573. BusNumber,
  1574. PciSlot.u.bits.DeviceNumber,
  1575. PciSlot.u.bits.FunctionNumber
  1576. );
  1577. #endif
  1578. status = STATUS_DEVICE_PROTOCOL_ERROR;
  1579. goto CleanUp;
  1580. }
  1581. //
  1582. // Settings took - turn on the appropiate decodes
  1583. //
  1584. if (EnableRomBase && *BaseAddress[RomIndex]) {
  1585. // a rom address was allocated and should be enabled
  1586. *BaseAddress[RomIndex] |= PCI_ROMADDRESS_ENABLED;
  1587. HalpWritePCIConfig (
  1588. BusHandler,
  1589. PciSlot,
  1590. BaseAddress[RomIndex],
  1591. (ULONG) ((PUCHAR) BaseAddress[RomIndex] - (PUCHAR) PciData),
  1592. sizeof (ULONG)
  1593. );
  1594. }
  1595. //
  1596. // Enable IO, Memory, and BUS_MASTER decodes
  1597. // (use HalSetBusData since valid settings now set)
  1598. //
  1599. PciData->Command |= PCI_ENABLE_IO_SPACE |
  1600. PCI_ENABLE_MEMORY_SPACE |
  1601. PCI_ENABLE_BUS_MASTER;
  1602. HalSetBusDataByOffset (
  1603. PCIConfiguration,
  1604. BusHandler->BusNumber,
  1605. PciSlot.u.AsULONG,
  1606. &PciData->Command,
  1607. FIELD_OFFSET (PCI_COMMON_CONFIG, Command),
  1608. sizeof (PciData->Command)
  1609. );
  1610. CleanUp:
  1611. if (!NT_SUCCESS(status)) {
  1612. //
  1613. // Failure, if there are any allocated resources free them
  1614. //
  1615. if (*pAllocatedResources) {
  1616. IoAssignResources (
  1617. RegistryPath,
  1618. DriverClassName,
  1619. DriverObject,
  1620. DeviceObject,
  1621. NULL,
  1622. NULL
  1623. );
  1624. ExFreePool (*pAllocatedResources);
  1625. *pAllocatedResources = NULL;
  1626. }
  1627. //
  1628. // Restore the device settings as we found them, enable memory
  1629. // and io decode after setting base addresses
  1630. //
  1631. HalpWritePCIConfig (
  1632. BusHandler,
  1633. PciSlot,
  1634. &PciOrigData->Status,
  1635. FIELD_OFFSET (PCI_COMMON_CONFIG, Status),
  1636. PCI_COMMON_HDR_LENGTH - FIELD_OFFSET (PCI_COMMON_CONFIG, Status)
  1637. );
  1638. HalpWritePCIConfig (
  1639. BusHandler,
  1640. PciSlot,
  1641. PciOrigData,
  1642. 0,
  1643. FIELD_OFFSET (PCI_COMMON_CONFIG, Status)
  1644. );
  1645. }
  1646. ExFreePool (WorkingPool);
  1647. return status;
  1648. }
  1649. VOID
  1650. HalpGetNMICrashFlag (
  1651. VOID
  1652. )
  1653. {
  1654. UNICODE_STRING unicodeString, NMICrashDumpName;
  1655. OBJECT_ATTRIBUTES objectAttributes;
  1656. HANDLE hCrashControl;
  1657. UCHAR buffer [sizeof(PPCI_REGISTRY_INFO) + 99];
  1658. ULONG rsize;
  1659. NTSTATUS status;
  1660. extern BOOLEAN HalpNMIDumpFlag;
  1661. //
  1662. // Open Crash Control Registry Key
  1663. //
  1664. RtlInitUnicodeString (&unicodeString, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\CrashControl");
  1665. InitializeObjectAttributes (
  1666. &objectAttributes,
  1667. &unicodeString,
  1668. OBJ_CASE_INSENSITIVE,
  1669. NULL, // handle
  1670. NULL);
  1671. HalpNMIDumpFlag = FALSE;
  1672. status = ZwOpenKey (&hCrashControl, KEY_READ, &objectAttributes);
  1673. if (NT_SUCCESS(status)) {
  1674. //
  1675. // Look for NMICrashDump Value
  1676. //
  1677. RtlInitUnicodeString (&NMICrashDumpName, L"NMICrashDump");
  1678. status = ZwQueryValueKey (
  1679. hCrashControl,
  1680. &NMICrashDumpName,
  1681. KeyValuePartialInformation,
  1682. (PKEY_VALUE_PARTIAL_INFORMATION) buffer,
  1683. sizeof (buffer),
  1684. &rsize
  1685. );
  1686. if ((NT_SUCCESS (status)) && (rsize == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]) + sizeof(ULONG))) {
  1687. HalpNMIDumpFlag = (BOOLEAN)(((PKEY_VALUE_PARTIAL_INFORMATION)buffer)->Data[0]);
  1688. }
  1689. ZwClose (hCrashControl);
  1690. }
  1691. }
  1692. #ifndef ACPI_HAL
  1693. #define PciBridgeSwizzle(device, pin) \
  1694. ((((pin - 1) + device) % 4) + 1)
  1695. #define PCIPin2Int(Slot,Pin) \
  1696. ((((Slot.u.bits.DeviceNumber << 2) | (Pin-1)) != 0) ? \
  1697. (Slot.u.bits.DeviceNumber << 2) | (Pin-1) : 0x80);
  1698. #define PCIInt2Pin(interrupt) \
  1699. ((interrupt & 0x3) + 1)
  1700. #define PCIInt2Slot(interrupt) \
  1701. ((interrupt & 0x7f ) >> 2)
  1702. NTSTATUS
  1703. HalIrqTranslateRequirementsPciBridge(
  1704. IN PVOID Context,
  1705. IN PIO_RESOURCE_DESCRIPTOR Source,
  1706. IN PDEVICE_OBJECT PhysicalDeviceObject,
  1707. OUT PULONG TargetCount,
  1708. OUT PIO_RESOURCE_DESCRIPTOR *Target
  1709. )
  1710. /*++
  1711. Routine Description:
  1712. This function translates IRQ resource requirements to
  1713. the parent PCI bus. This is only to be used for devices
  1714. on a PCI bus created by a PCI to PCI bridge where there
  1715. is no other mechanism for determining the interrupt
  1716. routing exists. (i.e. this bus is generated by a
  1717. plug-in bridge.)
  1718. Arguments:
  1719. Context - must hold the slot number of the bridge
  1720. Return Value:
  1721. STATUS_SUCCESS, so long as we can allocate the necessary
  1722. memory
  1723. --*/
  1724. {
  1725. PIO_RESOURCE_DESCRIPTOR target;
  1726. PCI_SLOT_NUMBER bridgeSlot;
  1727. NTSTATUS status;
  1728. ULONG bridgePin;
  1729. ULONG pciBusNumber;
  1730. PCI_SLOT_NUMBER pciSlot;
  1731. UCHAR interruptLine;
  1732. UCHAR interruptPin;
  1733. UCHAR dummy;
  1734. PDEVICE_OBJECT parentPdo;
  1735. ROUTING_TOKEN routingToken;
  1736. PAGED_CODE();
  1737. ASSERT(Source->Type == CmResourceTypeInterrupt);
  1738. ASSERT(Source->u.Interrupt.MinimumVector == Source->u.Interrupt.MaximumVector);
  1739. target = ExAllocatePoolWithTag(PagedPool,
  1740. sizeof(IO_RESOURCE_DESCRIPTOR),
  1741. HAL_POOL_TAG);
  1742. if (!target) {
  1743. return STATUS_INSUFFICIENT_RESOURCES;
  1744. }
  1745. //
  1746. // Copy the source to fill in all the relevant fields.
  1747. //
  1748. *target = *Source;
  1749. status = PciIrqRoutingInterface.GetInterruptRouting(
  1750. PhysicalDeviceObject,
  1751. &pciBusNumber,
  1752. &pciSlot.u.AsULONG,
  1753. &interruptLine,
  1754. &interruptPin,
  1755. &dummy,
  1756. &dummy,
  1757. &parentPdo,
  1758. &routingToken,
  1759. &dummy
  1760. );
  1761. ASSERT(NT_SUCCESS(status));
  1762. //
  1763. // Find the translated IRQ.
  1764. //
  1765. bridgeSlot.u.AsULONG = 0;
  1766. bridgeSlot.u.bits.DeviceNumber = (ULONG)Context;
  1767. bridgePin = PciBridgeSwizzle(PCIInt2Slot(Source->u.Interrupt.MinimumVector),
  1768. PCIInt2Pin(Source->u.Interrupt.MinimumVector));
  1769. //
  1770. // The translated value is the the "PCI INT" of the pin
  1771. // on the bridge.
  1772. //
  1773. target->u.Interrupt.MinimumVector =
  1774. PCIPin2Int(bridgeSlot, bridgePin);
  1775. target->u.Interrupt.MaximumVector = target->u.Interrupt.MinimumVector;
  1776. *TargetCount = 1;
  1777. *Target = target;
  1778. return STATUS_SUCCESS;
  1779. }
  1780. NTSTATUS
  1781. HalIrqTranslateResourcesPciBridge(
  1782. IN PVOID Context,
  1783. IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Source,
  1784. IN RESOURCE_TRANSLATION_DIRECTION Direction,
  1785. IN ULONG AlternativesCount, OPTIONAL
  1786. IN IO_RESOURCE_DESCRIPTOR Alternatives[], OPTIONAL
  1787. IN PDEVICE_OBJECT PhysicalDeviceObject,
  1788. OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR Target
  1789. )
  1790. /*++
  1791. Routine Description:
  1792. This function translates IRQ resources to and from
  1793. the parent PCI bus. This is only to be used for devices
  1794. on a PCI bus created by a PCI to PCI bridge where there
  1795. is no other mechanism for determining the interrupt
  1796. routing exists. (i.e. this bus is generated by a
  1797. plug-in bridge.)
  1798. Arguments:
  1799. Context - must hold the slot number of the bridge
  1800. Return Value:
  1801. STATUS_SUCCESS
  1802. --*/
  1803. {
  1804. PCI_SLOT_NUMBER bridgeSlot, deviceSlot, childSlot;
  1805. ULONG bridgePin;
  1806. ULONG pciBusNumber, targetPciBusNumber, bridgeBusNumber;
  1807. UCHAR interruptPin;
  1808. UCHAR dummy;
  1809. PDEVICE_OBJECT parentPdo;
  1810. ROUTING_TOKEN routingToken;
  1811. NTSTATUS status;
  1812. UCHAR buffer[PCI_COMMON_HDR_LENGTH];
  1813. PPCI_COMMON_CONFIG pciData;
  1814. ULONG d, f;
  1815. PBUS_HANDLER busHandler;
  1816. PAGED_CODE();
  1817. ASSERT(Source->Type == CmResourceTypeInterrupt);
  1818. ASSERT(Source->u.Interrupt.Vector == Source->u.Interrupt.Level);
  1819. ASSERT(PciIrqRoutingInterface.GetInterruptRouting);
  1820. *Target = *Source;
  1821. status = PciIrqRoutingInterface.GetInterruptRouting(
  1822. PhysicalDeviceObject,
  1823. &pciBusNumber,
  1824. &deviceSlot.u.AsULONG,
  1825. &dummy,
  1826. &interruptPin,
  1827. &dummy,
  1828. &dummy,
  1829. &parentPdo,
  1830. &routingToken,
  1831. &dummy
  1832. );
  1833. ASSERT(NT_SUCCESS(status));
  1834. switch (Direction) {
  1835. case TranslateChildToParent:
  1836. //
  1837. // Find the translated IRQ.
  1838. //
  1839. bridgeSlot.u.AsULONG = 0;
  1840. bridgeSlot.u.bits.DeviceNumber = (ULONG_PTR)Context & 0xffff;
  1841. bridgePin = PciBridgeSwizzle(PCIInt2Slot(Source->u.Interrupt.Vector),
  1842. PCIInt2Pin(Source->u.Interrupt.Vector));
  1843. //
  1844. // The translated value is the the "PCI INT" of the pin
  1845. // on the bridge.
  1846. //
  1847. Target->u.Interrupt.Vector =
  1848. PCIPin2Int(bridgeSlot, bridgePin);
  1849. Target->u.Interrupt.Level = Target->u.Interrupt.Vector;
  1850. //
  1851. // The affinity should have been inherited from Source
  1852. // and it should be non-zero.
  1853. //
  1854. ASSERT(Target->u.Interrupt.Affinity != 0);
  1855. break;
  1856. case TranslateParentToChild:
  1857. //
  1858. // The child-relative representation of Vector and Level
  1859. // is from the MPS spec. And we need to know the device
  1860. // number and interrupt pin value.
  1861. //
  1862. //
  1863. // TEMPTEMP Use bushandlers until HALMPS is rid of them.
  1864. //
  1865. pciData = (PPCI_COMMON_CONFIG)&buffer;
  1866. bridgeBusNumber = ((ULONG_PTR)Context >> 16) & 0xffff;
  1867. busHandler = HaliHandlerForBus(PCIBus, bridgeBusNumber);
  1868. bridgeSlot.u.AsULONG = (ULONG_PTR)Context & 0xffff;
  1869. HalpReadPCIConfig(busHandler,
  1870. bridgeSlot,
  1871. pciData,
  1872. 0,
  1873. PCI_COMMON_HDR_LENGTH);
  1874. if (pciData->u.type1.SecondaryBus == pciBusNumber) {
  1875. //
  1876. // This device is sitting on the bus that we are translating
  1877. // into. So create a vector based on the address of this device.
  1878. // (Are we at the bottom of the translation?)
  1879. //
  1880. Target->u.Interrupt.Vector = PCIPin2Int(deviceSlot, interruptPin);
  1881. Target->u.Interrupt.Level = Target->u.Interrupt.Vector;
  1882. return STATUS_SUCCESS;
  1883. } else {
  1884. //
  1885. // This device is not sitting on the bus that we are translating
  1886. // into. This device must be a (grand) child of another bridge that
  1887. // sits on this bus. And that bridge will have our device's bus
  1888. // within its Subordinate bus register.
  1889. //
  1890. targetPciBusNumber = pciData->u.type1.SecondaryBus;
  1891. bridgeSlot.u.AsULONG = 0;
  1892. for (d = 0; d < PCI_MAX_DEVICES; d++) {
  1893. for (f = 0; f < PCI_MAX_FUNCTION; f++) {
  1894. bridgeSlot.u.bits.DeviceNumber = d;
  1895. bridgeSlot.u.bits.FunctionNumber = f;
  1896. busHandler = HaliHandlerForBus(PCIBus, targetPciBusNumber);
  1897. HalpReadPCIConfig(busHandler,
  1898. bridgeSlot,
  1899. pciData,
  1900. 0,
  1901. PCI_COMMON_HDR_LENGTH);
  1902. if ((PCI_CONFIGURATION_TYPE(pciData) == PCI_BRIDGE_TYPE) ||
  1903. (PCI_CONFIGURATION_TYPE(pciData) == PCI_CARDBUS_BRIDGE_TYPE)) {
  1904. //
  1905. // This is a bridge. Check the subordinate bus.
  1906. //
  1907. if (pciData->u.type1.SubordinateBus >= pciBusNumber) {
  1908. //
  1909. // Now we know the device number of the bridge on this
  1910. // bus that applies to this translation. We still need
  1911. // to know what pin will be triggered. To know that,
  1912. // we have to look one more bus down.
  1913. //
  1914. // There are two cases:
  1915. //
  1916. // 1) The next bus down contains the device.
  1917. //
  1918. // 2) The next bus down contains another bridge.
  1919. //
  1920. //
  1921. if (pciData->u.type1.SecondaryBus == pciBusNumber) {
  1922. //
  1923. // This is case 1).
  1924. //
  1925. interruptPin = (UCHAR)PciBridgeSwizzle(deviceSlot.u.bits.DeviceNumber,
  1926. interruptPin);
  1927. } else {
  1928. //
  1929. // This is case 2).
  1930. //
  1931. // Technically, to get the right answer, we would have to
  1932. // figure out which pin the bridge is going to trigger. But
  1933. // to do that, we would have to scan down busses until we found
  1934. // the device. And the information gathered on that little
  1935. // journey would never get used.
  1936. //
  1937. interruptPin = 1;
  1938. }
  1939. Target->u.Interrupt.Vector = PCIPin2Int(bridgeSlot, interruptPin);
  1940. Target->u.Interrupt.Level = Target->u.Interrupt.Vector;
  1941. return STATUS_SUCCESS;
  1942. }
  1943. }
  1944. }
  1945. }
  1946. }
  1947. return STATUS_NOT_FOUND;
  1948. }
  1949. return STATUS_SUCCESS;
  1950. }
  1951. #endif
  1952. #if DBG
  1953. VOID
  1954. HalpTestPci (ULONG flag2)
  1955. {
  1956. PCI_SLOT_NUMBER SlotNumber;
  1957. PCI_COMMON_CONFIG PciData, OrigData;
  1958. ULONG i, f, j, k, bus;
  1959. BOOLEAN flag;
  1960. if (!flag2) {
  1961. return ;
  1962. }
  1963. DbgBreakPoint ();
  1964. SlotNumber.u.bits.Reserved = 0;
  1965. //
  1966. // Read every possible PCI Device/Function and display it's
  1967. // default info.
  1968. //
  1969. // (note this destories it's current settings)
  1970. //
  1971. flag = TRUE;
  1972. for (bus = 0; flag; bus++) {
  1973. for (i = 0; i < PCI_MAX_DEVICES; i++) {
  1974. SlotNumber.u.bits.DeviceNumber = i;
  1975. for (f = 0; f < PCI_MAX_FUNCTION; f++) {
  1976. SlotNumber.u.bits.FunctionNumber = f;
  1977. //
  1978. // Note: This is reading the DeviceSpecific area of
  1979. // the device's configuration - normally this should
  1980. // only be done on device for which the caller understands.
  1981. // I'm doing it here only for debugging.
  1982. //
  1983. j = HalGetBusData (
  1984. PCIConfiguration,
  1985. bus,
  1986. SlotNumber.u.AsULONG,
  1987. &PciData,
  1988. sizeof (PciData)
  1989. );
  1990. if (j == 0) {
  1991. // out of buses
  1992. flag = FALSE;
  1993. break;
  1994. }
  1995. if (j < PCI_COMMON_HDR_LENGTH) {
  1996. continue;
  1997. }
  1998. HalSetBusData (
  1999. PCIConfiguration,
  2000. bus,
  2001. SlotNumber.u.AsULONG,
  2002. &PciData,
  2003. 1
  2004. );
  2005. HalGetBusData (
  2006. PCIConfiguration,
  2007. bus,
  2008. SlotNumber.u.AsULONG,
  2009. &PciData,
  2010. sizeof (PciData)
  2011. );
  2012. #if 0
  2013. memcpy (&OrigData, &PciData, sizeof PciData);
  2014. for (j=0; j < PCI_TYPE0_ADDRESSES; j++) {
  2015. PciData.u.type0.BaseAddresses[j] = 0xFFFFFFFF;
  2016. }
  2017. PciData.u.type0.ROMBaseAddress = 0xFFFFFFFF;
  2018. HalSetBusData (
  2019. PCIConfiguration,
  2020. bus,
  2021. SlotNumber.u.AsULONG,
  2022. &PciData,
  2023. sizeof (PciData)
  2024. );
  2025. HalGetBusData (
  2026. PCIConfiguration,
  2027. bus,
  2028. SlotNumber.u.AsULONG,
  2029. &PciData,
  2030. sizeof (PciData)
  2031. );
  2032. #endif
  2033. DbgPrint ("PCI Bus %d Slot %2d %2d ID:%04lx-%04lx Rev:%04lx",
  2034. bus, i, f, PciData.VendorID, PciData.DeviceID,
  2035. PciData.RevisionID);
  2036. if (PciData.u.type0.InterruptPin) {
  2037. DbgPrint (" IntPin:%x", PciData.u.type0.InterruptPin);
  2038. }
  2039. if (PciData.u.type0.InterruptLine) {
  2040. DbgPrint (" IntLine:%x", PciData.u.type0.InterruptLine);
  2041. }
  2042. if (PciData.u.type0.ROMBaseAddress) {
  2043. DbgPrint (" ROM:%08lx", PciData.u.type0.ROMBaseAddress);
  2044. }
  2045. DbgPrint ("\n Cmd:%04x Status:%04x ProgIf:%04x SubClass:%04x BaseClass:%04lx\n",
  2046. PciData.Command, PciData.Status, PciData.ProgIf,
  2047. PciData.SubClass, PciData.BaseClass);
  2048. k = 0;
  2049. for (j=0; j < PCI_TYPE0_ADDRESSES; j++) {
  2050. if (PciData.u.type0.BaseAddresses[j]) {
  2051. DbgPrint (" Ad%d:%08lx", j, PciData.u.type0.BaseAddresses[j]);
  2052. k = 1;
  2053. }
  2054. }
  2055. #if 0
  2056. if (PciData.u.type0.ROMBaseAddress == 0xC08001) {
  2057. PciData.u.type0.ROMBaseAddress = 0xC00001;
  2058. HalSetBusData (
  2059. PCIConfiguration,
  2060. bus,
  2061. SlotNumber.u.AsULONG,
  2062. &PciData,
  2063. sizeof (PciData)
  2064. );
  2065. HalGetBusData (
  2066. PCIConfiguration,
  2067. bus,
  2068. SlotNumber.u.AsULONG,
  2069. &PciData,
  2070. sizeof (PciData)
  2071. );
  2072. DbgPrint ("\n Bogus rom address, edit yields:%08lx",
  2073. PciData.u.type0.ROMBaseAddress);
  2074. }
  2075. #endif
  2076. if (k) {
  2077. DbgPrint ("\n");
  2078. }
  2079. if (PciData.VendorID == 0x8086) {
  2080. // dump complete buffer
  2081. DbgPrint ("Command %x, Status %x, BIST %x\n",
  2082. PciData.Command, PciData.Status,
  2083. PciData.BIST
  2084. );
  2085. DbgPrint ("CacheLineSz %x, LatencyTimer %x",
  2086. PciData.CacheLineSize, PciData.LatencyTimer
  2087. );
  2088. for (j=0; j < 192; j++) {
  2089. if ((j & 0xf) == 0) {
  2090. DbgPrint ("\n%02x: ", j + 0x40);
  2091. }
  2092. DbgPrint ("%02x ", PciData.DeviceSpecific[j]);
  2093. }
  2094. DbgPrint ("\n");
  2095. }
  2096. #if 0
  2097. //
  2098. // now print original data
  2099. //
  2100. if (OrigData.u.type0.ROMBaseAddress) {
  2101. DbgPrint (" oROM:%08lx", OrigData.u.type0.ROMBaseAddress);
  2102. }
  2103. DbgPrint ("\n");
  2104. k = 0;
  2105. for (j=0; j < PCI_TYPE0_ADDRESSES; j++) {
  2106. if (OrigData.u.type0.BaseAddresses[j]) {
  2107. DbgPrint (" oAd%d:%08lx", j, OrigData.u.type0.BaseAddresses[j]);
  2108. k = 1;
  2109. }
  2110. }
  2111. //
  2112. // Restore original settings
  2113. //
  2114. HalSetBusData (
  2115. PCIConfiguration,
  2116. bus,
  2117. SlotNumber.u.AsULONG,
  2118. &OrigData,
  2119. sizeof (PciData)
  2120. );
  2121. #endif
  2122. //
  2123. // Next
  2124. //
  2125. if (k) {
  2126. DbgPrint ("\n\n");
  2127. }
  2128. }
  2129. }
  2130. }
  2131. DbgBreakPoint ();
  2132. }
  2133. #endif