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.

1406 lines
41 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. i64pcibus.c
  5. Abstract:
  6. Get/Set bus data routines for the PCI bus
  7. Author:
  8. Ken Reneris (kenr) 14-June-1994
  9. Chris Hyser (chrish@fc.hp.com) 1-Feb-98
  10. Environment:
  11. Kernel mode
  12. Revision History:
  13. --*/
  14. #include "halp.h"
  15. #include "pci.h"
  16. #include "pcip.h"
  17. #include "i64fw.h"
  18. //
  19. // Prototypes
  20. //
  21. ULONG
  22. HalpGetPCIData(
  23. IN PBUS_HANDLER BusHandler,
  24. IN PBUS_HANDLER RootHandler,
  25. IN PCI_SLOT_NUMBER SlotNumber,
  26. IN PVOID Buffer,
  27. IN ULONG Offset,
  28. IN ULONG Length
  29. );
  30. ULONG
  31. HalpSetPCIData(
  32. IN PBUS_HANDLER BusHandler,
  33. IN PBUS_HANDLER RootHandler,
  34. IN PCI_SLOT_NUMBER SlotNumber,
  35. IN PVOID Buffer,
  36. IN ULONG Offset,
  37. IN ULONG Length
  38. );
  39. NTSTATUS
  40. HalpAssignPCISlotResources(
  41. IN PBUS_HANDLER BusHandler,
  42. IN PBUS_HANDLER RootHandler,
  43. IN PUNICODE_STRING RegistryPath,
  44. IN PUNICODE_STRING DriverClassName OPTIONAL,
  45. IN PDRIVER_OBJECT DriverObject,
  46. IN PDEVICE_OBJECT DeviceObject OPTIONAL,
  47. IN ULONG SlotNumber,
  48. IN OUT PCM_RESOURCE_LIST *AllocatedResources
  49. );
  50. VOID
  51. HalpInitializePciBus(
  52. VOID
  53. );
  54. BOOLEAN
  55. HalpIsValidPCIDevice(
  56. IN PBUS_HANDLER BusHandler,
  57. IN PCI_SLOT_NUMBER Slot
  58. );
  59. BOOLEAN
  60. HalpValidPCISlot(
  61. IN PBUS_HANDLER BusHandler,
  62. IN PCI_SLOT_NUMBER Slot
  63. );
  64. //
  65. // PCI Configuration Space Accessor types
  66. //
  67. typedef enum {
  68. PCI_READ,
  69. PCI_WRITE
  70. } PCI_ACCESS_TYPE;
  71. VOID
  72. HalpPCIConfig(
  73. IN PBUS_HANDLER BusHandler,
  74. IN PCI_SLOT_NUMBER Slot,
  75. IN PUCHAR Buffer,
  76. IN ULONG Offset,
  77. IN ULONG Length,
  78. IN PCI_ACCESS_TYPE Acctype
  79. );
  80. #if DBG
  81. #if !defined(NO_LEGACY_DRIVERS)
  82. VOID
  83. HalpTestPci(
  84. ULONG
  85. );
  86. #endif
  87. #endif
  88. #ifdef ALLOC_PRAGMA
  89. #pragma alloc_text(INIT,HalpInitializePciBus)
  90. #pragma alloc_text(INIT,HalpAllocateAndInitPciBusHandler)
  91. #pragma alloc_text(INIT,HalpIsValidPCIDevice)
  92. #pragma alloc_text(PAGE,HalpAssignPCISlotResources)
  93. #endif
  94. ULONG
  95. HalpGetPCIData(
  96. IN PBUS_HANDLER BusHandler,
  97. IN PBUS_HANDLER RootHandler,
  98. IN PCI_SLOT_NUMBER Slot,
  99. IN PUCHAR Buffer,
  100. IN ULONG Offset,
  101. IN ULONG Length
  102. )
  103. /*++
  104. Routine Description:
  105. The function returns the PCI bus data for a specified PCI "slot". This
  106. function is called on behalf of
  107. Arguments:
  108. BusHandler - An encapsulation of data and manipulation functions specific to
  109. this bus.
  110. RootHandler - ???
  111. Slot - A PCI "slot" description (ie bus number, device number and function
  112. number.)
  113. Buffer - A pointer to the space to store the data.
  114. Offset - The byte offset into the configuration space for this PCI "slot".
  115. Length - Supplies a count in bytes of the maximum amount to return. (ie
  116. equal or less than the size of the Buffer.)
  117. Return Value:
  118. Returns the amount of data stored into the buffer.
  119. If this PCI slot has never been set, then the configuration information
  120. returned is zeroed.
  121. --*/
  122. {
  123. PPCI_COMMON_CONFIG PciData;
  124. UCHAR iBuffer[PCI_COMMON_HDR_LENGTH];
  125. PPCIPBUSDATA BusData;
  126. ULONG Len;
  127. ULONG i, bit;
  128. if (Length > sizeof(PCI_COMMON_CONFIG))
  129. Length = sizeof(PCI_COMMON_CONFIG);
  130. Len = 0;
  131. PciData = (PPCI_COMMON_CONFIG)iBuffer;
  132. //
  133. // If the requested offset does not lie in the PCI onfiguration space common
  134. // header, we will read the vendor ID from the common header to ensure this
  135. // is a valid device. Note: The common header is from 0 to
  136. // PCI_COMMON_HEADER_LENGTH inclusive. We know Offset is > 0 because it is
  137. // unsigned.
  138. //
  139. if (Offset >= PCI_COMMON_HDR_LENGTH) {
  140. //
  141. // No data was requested from the common header. Verify the PCI device
  142. // exists, then continue in the device specific area.
  143. //
  144. HalpReadPCIConfig(BusHandler, Slot, PciData, 0, sizeof(ULONG));
  145. if (PciData->VendorID == PCI_INVALID_VENDORID)
  146. return(0);
  147. } else {
  148. //
  149. // Caller requested at least some data within the common header. Read
  150. // the whole header, effect the fields we need to and then copy the
  151. // user's requested bytes from the header
  152. //
  153. BusData = (PPCIPBUSDATA)BusHandler->BusData;
  154. //
  155. // Read this PCI devices slot data
  156. //
  157. Len = PCI_COMMON_HDR_LENGTH;
  158. HalpReadPCIConfig(BusHandler, Slot, PciData, 0, Len);
  159. if (PciData->VendorID == PCI_INVALID_VENDORID) {
  160. PciData->VendorID = PCI_INVALID_VENDORID;
  161. Len = 2; // only return invalid id
  162. } else {
  163. BusData->CommonData.Pin2Line(BusHandler, RootHandler, Slot, PciData);
  164. }
  165. //
  166. // Copy whatever data overlaps into the callers buffer
  167. //
  168. if (Len < Offset)
  169. return(0);
  170. Len -= Offset;
  171. if (Len > Length)
  172. Len = Length;
  173. RtlMoveMemory(Buffer, iBuffer + Offset, Len);
  174. Offset += Len;
  175. Buffer += Len;
  176. Length -= Len;
  177. }
  178. if (Length) {
  179. if (Offset >= PCI_COMMON_HDR_LENGTH) {
  180. //
  181. // The remaining Buffer comes from the Device Specific
  182. // area - put on the kitten gloves and read from it.
  183. //
  184. // Specific read/writes to the PCI device specific area
  185. // are guarenteed:
  186. //
  187. // Not to read/write any byte outside the area specified
  188. // by the caller. (this may cause WORD or BYTE references
  189. // to the area in order to read the non-dword aligned
  190. // ends of the request)
  191. //
  192. // To use a WORD access if the requested length is exactly
  193. // a WORD long.
  194. //
  195. // To use a BYTE access if the requested length is exactly
  196. // a BYTE long.
  197. //
  198. HalpReadPCIConfig(BusHandler, Slot, Buffer, Offset, Length);
  199. Len += Length;
  200. }
  201. }
  202. return(Len);
  203. }
  204. ULONG
  205. HalpSetPCIData(
  206. IN PBUS_HANDLER BusHandler,
  207. IN PBUS_HANDLER RootHandler,
  208. IN PCI_SLOT_NUMBER Slot,
  209. IN PUCHAR Buffer,
  210. IN ULONG Offset,
  211. IN ULONG Length
  212. )
  213. /*++
  214. Routine Description:
  215. The function sets the PCI bus data for a specified PCI "slot".
  216. Arguments:
  217. BusHandler - An encapsulation of data and manipulation functions specific to
  218. this bus.
  219. RootHandler - ???
  220. Slot - A PCI "slot" description (ie bus number, device number and function
  221. number.)
  222. Buffer - Supplies the space to store the data.
  223. Length - Supplies a count in bytes of the maximum amount to return.
  224. Return Value:
  225. Returns the amount of data stored into the buffer. ???
  226. --*/
  227. {
  228. PPCI_COMMON_CONFIG PciData, PciData2;
  229. UCHAR iBuffer[PCI_COMMON_HDR_LENGTH];
  230. UCHAR iBuffer2[PCI_COMMON_HDR_LENGTH];
  231. PPCIPBUSDATA BusData;
  232. ULONG Len, cnt;
  233. if (Length > sizeof(PCI_COMMON_CONFIG))
  234. Length = sizeof(PCI_COMMON_CONFIG);
  235. Len = 0;
  236. PciData = (PPCI_COMMON_CONFIG)iBuffer;
  237. PciData2 = (PPCI_COMMON_CONFIG)iBuffer2;
  238. if (Offset >= PCI_COMMON_HDR_LENGTH) {
  239. //
  240. // The user did not request any data from the common
  241. // header. Verify the PCI device exists, then continue in
  242. // the device specific area.
  243. //
  244. HalpReadPCIConfig(BusHandler, Slot, PciData, 0, sizeof(ULONG));
  245. if (PciData->VendorID == PCI_INVALID_VENDORID)
  246. return(0);
  247. } else {
  248. //
  249. // Caller requested to set at least some data within the
  250. // common header.
  251. //
  252. Len = PCI_COMMON_HDR_LENGTH;
  253. HalpReadPCIConfig(BusHandler, Slot, PciData, 0, Len);
  254. //
  255. // return error if no device or header type unknown
  256. //
  257. if (PciData->VendorID == PCI_INVALID_VENDORID ||
  258. PCI_CONFIG_TYPE(PciData) != PCI_DEVICE_TYPE)
  259. return(0);
  260. //
  261. // Set this device as configured
  262. //
  263. BusData = (PPCIPBUSDATA)BusHandler->BusData;
  264. #if DBG1
  265. cnt = PciBitIndex(Slot.u.bits.DeviceNumber, Slot.u.bits.FunctionNumber);
  266. RtlSetBits(&BusData->DeviceConfigured, cnt, 1);
  267. #endif
  268. //
  269. // Copy COMMON_HDR values to buffer2, then overlay callers changes.
  270. //
  271. RtlMoveMemory(iBuffer2, iBuffer, Len);
  272. BusData->CommonData.Pin2Line(BusHandler, RootHandler, Slot, PciData2);
  273. Len -= Offset;
  274. if (Len > Length)
  275. Len = Length;
  276. RtlMoveMemory(iBuffer2+Offset, Buffer, Len);
  277. //
  278. // in case interrupt line or pin was edited
  279. //
  280. BusData->CommonData.Line2Pin(BusHandler, RootHandler, Slot, PciData2, PciData);
  281. #if DBG1
  282. //
  283. // Verify R/O fields haven't changed
  284. //
  285. if (PciData2->VendorID != PciData->VendorID ||
  286. PciData2->DeviceID != PciData->DeviceID ||
  287. PciData2->RevisionID != PciData->RevisionID ||
  288. PciData2->ProgIf != PciData->ProgIf ||
  289. PciData2->SubClass != PciData->SubClass ||
  290. PciData2->BaseClass != PciData->BaseClass ||
  291. PciData2->HeaderType != PciData->HeaderType ||
  292. PciData2->BaseClass != PciData->BaseClass ||
  293. PciData2->u.type0.MinimumGrant != PciData->u.type0.MinimumGrant ||
  294. PciData2->u.type0.MaximumLatency != PciData->u.type0.MaximumLatency) {
  295. HalDebugPrint(( HAL_INFO, "HAL: PCI SetBusData - Read-Only configuration value changed\n" ));
  296. }
  297. #endif
  298. //
  299. // Set new PCI configuration
  300. //
  301. HalpWritePCIConfig(BusHandler, Slot, iBuffer2+Offset, Offset, Len);
  302. Offset += Len;
  303. Buffer += Len;
  304. Length -= Len;
  305. }
  306. if (Length) {
  307. if (Offset >= PCI_COMMON_HDR_LENGTH) {
  308. //
  309. // The remaining Buffer comes from the Device Specific
  310. // area - put on the kitten gloves and write it
  311. //
  312. // Specific read/writes to the PCI device specific area
  313. // are guarenteed:
  314. //
  315. // Not to read/write any byte outside the area specified
  316. // by the caller. (this may cause WORD or BYTE references
  317. // to the area in order to read the non-dword aligned
  318. // ends of the request)
  319. //
  320. // To use a WORD access if the requested length is exactly
  321. // a WORD long.
  322. //
  323. // To use a BYTE access if the requested length is exactly
  324. // a BYTE long.
  325. //
  326. HalpWritePCIConfig(BusHandler, Slot, Buffer, Offset, Length);
  327. Len += Length;
  328. }
  329. }
  330. return(Len);
  331. }
  332. NTSTATUS
  333. HalpAssignPCISlotResources(
  334. IN PBUS_HANDLER BusHandler,
  335. IN PBUS_HANDLER RootHandler,
  336. IN PUNICODE_STRING RegistryPath,
  337. IN PUNICODE_STRING DriverClassName OPTIONAL,
  338. IN PDRIVER_OBJECT DriverObject,
  339. IN PDEVICE_OBJECT DeviceObject OPTIONAL,
  340. IN ULONG Slot,
  341. IN OUT PCM_RESOURCE_LIST *pAllocatedResources
  342. )
  343. /*++
  344. Routine Description:
  345. Reads the targeted device to determine it's required resources.
  346. Calls IoAssignResources to allocate them.
  347. Sets the targeted device with it's assigned resoruces
  348. and returns the assignments to the caller.
  349. Note: This function assumes all of a PCI "slots" resources as indicated by
  350. it's configuration space are REQUIRED.
  351. Arguments:
  352. Return Value:
  353. STATUS_SUCCESS or error
  354. --*/
  355. {
  356. NTSTATUS status;
  357. PUCHAR WorkingPool;
  358. PPCI_COMMON_CONFIG PciData, PciOrigData, PciData2;
  359. PCI_SLOT_NUMBER PciSlot;
  360. PPCIPBUSDATA BusData;
  361. PIO_RESOURCE_REQUIREMENTS_LIST CompleteList;
  362. PIO_RESOURCE_DESCRIPTOR Descriptor;
  363. PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescriptor;
  364. ULONG BusNumber;
  365. ULONG i, j, m, length, memtype;
  366. ULONG NoBaseAddress, RomIndex, Option;
  367. PULONG BaseAddress[PCI_TYPE0_ADDRESSES + 1];
  368. PULONG OrigAddress[PCI_TYPE0_ADDRESSES + 1];
  369. BOOLEAN Match, EnableRomBase, RequestedInterrupt;
  370. *pAllocatedResources = NULL;
  371. PciSlot = *((PPCI_SLOT_NUMBER) &Slot);
  372. BusNumber = BusHandler->BusNumber;
  373. BusData = (PPCIPBUSDATA) BusHandler->BusData;
  374. //
  375. // Allocate some pool for working space
  376. //
  377. i = sizeof(IO_RESOURCE_REQUIREMENTS_LIST) +
  378. sizeof(IO_RESOURCE_DESCRIPTOR) * (PCI_TYPE0_ADDRESSES + 2) * 2 +
  379. PCI_COMMON_HDR_LENGTH * 3;
  380. WorkingPool = (PUCHAR)ExAllocatePool(PagedPool, i);
  381. if (!WorkingPool)
  382. return(STATUS_INSUFFICIENT_RESOURCES);
  383. //
  384. // Zero initialize pool, and get pointers into memory
  385. //
  386. RtlZeroMemory(WorkingPool, i);
  387. CompleteList = (PIO_RESOURCE_REQUIREMENTS_LIST)WorkingPool;
  388. PciData = (PPCI_COMMON_CONFIG) (WorkingPool + i - PCI_COMMON_HDR_LENGTH * 3);
  389. PciData2 = (PPCI_COMMON_CONFIG) (WorkingPool + i - PCI_COMMON_HDR_LENGTH * 2);
  390. PciOrigData = (PPCI_COMMON_CONFIG) (WorkingPool + i - PCI_COMMON_HDR_LENGTH * 1);
  391. //
  392. // Read the PCI device's configuration
  393. //
  394. HalpReadPCIConfig(BusHandler, PciSlot, PciData, 0, PCI_COMMON_HDR_LENGTH);
  395. if (PciData->VendorID == PCI_INVALID_VENDORID) {
  396. ExFreePool(WorkingPool);
  397. return(STATUS_NO_SUCH_DEVICE);
  398. }
  399. //
  400. // For now since there's not PnP support in the OS, if the BIOS hasn't
  401. // enable a VGA device don't allow it to get enabled via this interface.
  402. //
  403. if ((PciData->BaseClass == 0 && PciData->SubClass == 1) ||
  404. (PciData->BaseClass == 3 && PciData->SubClass == 0)) {
  405. if ((PciData->Command & (PCI_ENABLE_IO_SPACE | PCI_ENABLE_MEMORY_SPACE)) == 0) {
  406. ExFreePool (WorkingPool);
  407. return(STATUS_DEVICE_NOT_CONNECTED);
  408. }
  409. }
  410. //
  411. // Make a copy of the device's current settings
  412. //
  413. RtlMoveMemory(PciOrigData, PciData, PCI_COMMON_HDR_LENGTH);
  414. //
  415. // Initialize base addresses base on configuration data type
  416. //
  417. switch (PCI_CONFIG_TYPE(PciData)) {
  418. case 0 :
  419. NoBaseAddress = PCI_TYPE0_ADDRESSES+1;
  420. for (j=0; j < PCI_TYPE0_ADDRESSES; j++) {
  421. BaseAddress[j] = &PciData->u.type0.BaseAddresses[j];
  422. OrigAddress[j] = &PciOrigData->u.type0.BaseAddresses[j];
  423. }
  424. BaseAddress[j] = &PciData->u.type0.ROMBaseAddress;
  425. OrigAddress[j] = &PciOrigData->u.type0.ROMBaseAddress;
  426. RomIndex = j;
  427. break;
  428. case 1:
  429. NoBaseAddress = PCI_TYPE1_ADDRESSES+1;
  430. for (j=0; j < PCI_TYPE1_ADDRESSES; j++) {
  431. BaseAddress[j] = &PciData->u.type1.BaseAddresses[j];
  432. OrigAddress[j] = &PciOrigData->u.type1.BaseAddresses[j];
  433. }
  434. BaseAddress[j] = &PciData->u.type1.ROMBaseAddress;
  435. OrigAddress[j] = &PciOrigData->u.type1.ROMBaseAddress;
  436. RomIndex = j;
  437. break;
  438. default:
  439. ExFreePool (WorkingPool);
  440. return(STATUS_NO_SUCH_DEVICE);
  441. }
  442. //
  443. // If the BIOS doesn't have the device's ROM enabled, then we won't enable
  444. // it either. Remove it from the list.
  445. //
  446. EnableRomBase = TRUE;
  447. if (!(*BaseAddress[RomIndex] & PCI_ROMADDRESS_ENABLED)) {
  448. ASSERT (RomIndex+1 == NoBaseAddress);
  449. EnableRomBase = FALSE;
  450. NoBaseAddress -= 1;
  451. }
  452. //
  453. // Set resources to all bits on to see what type of resources are required.
  454. //
  455. for (j=0; j < NoBaseAddress; j++)
  456. *BaseAddress[j] = 0xFFFFFFFF;
  457. PciData->Command &= ~(PCI_ENABLE_IO_SPACE | PCI_ENABLE_MEMORY_SPACE);
  458. *BaseAddress[RomIndex] &= ~PCI_ROMADDRESS_ENABLED;
  459. HalpWritePCIConfig (BusHandler, PciSlot, PciData, 0, PCI_COMMON_HDR_LENGTH);
  460. HalpReadPCIConfig (BusHandler, PciSlot, PciData, 0, PCI_COMMON_HDR_LENGTH);
  461. //
  462. // note type0 & type1 overlay ROMBaseAddress, InterruptPin, and InterruptLine
  463. //
  464. BusData->CommonData.Pin2Line (BusHandler, RootHandler, PciSlot, PciData);
  465. //
  466. // Build an IO_RESOURCE_REQUIREMENTS_LIST for the PCI device
  467. //
  468. CompleteList->InterfaceType = PCIBus;
  469. CompleteList->BusNumber = BusNumber;
  470. CompleteList->SlotNumber = Slot;
  471. CompleteList->AlternativeLists = 1;
  472. CompleteList->List[0].Version = 1;
  473. CompleteList->List[0].Revision = 1;
  474. Descriptor = CompleteList->List[0].Descriptors;
  475. //
  476. // If PCI device has an interrupt resource, add it
  477. //
  478. RequestedInterrupt = FALSE;
  479. if (PciData->u.type0.InterruptPin &&
  480. PciData->u.type0.InterruptLine != (0 ^ IRQXOR) &&
  481. PciData->u.type0.InterruptLine != (0xFF ^ IRQXOR)) {
  482. RequestedInterrupt = TRUE;
  483. CompleteList->List[0].Count++;
  484. Descriptor->Option = 0;
  485. Descriptor->Type = CmResourceTypeInterrupt;
  486. Descriptor->ShareDisposition = CmResourceShareShared;
  487. Descriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
  488. // Fill in any vector here - we'll pick it back up in
  489. // HalAdjustResourceList and adjust it to it's allowed settings
  490. Descriptor->u.Interrupt.MinimumVector = 0;
  491. Descriptor->u.Interrupt.MaximumVector = 0xff;
  492. Descriptor++;
  493. }
  494. //
  495. // Add a memory/port resoruce for each PCI resource
  496. //
  497. // Clear ROM reserved bits
  498. *BaseAddress[RomIndex] &= ~0x7FF;
  499. for (j=0; j < NoBaseAddress; j++) {
  500. if (*BaseAddress[j]) {
  501. i = *BaseAddress[j];
  502. //
  503. // scan for first set bit, that's the length & alignment
  504. //
  505. length = 1 << (i & PCI_ADDRESS_IO_SPACE ? 2 : 4);
  506. while (!(i & length) && length)
  507. length <<= 1;
  508. //
  509. // scan for last set bit, that's the maxaddress + 1
  510. //
  511. for (m = length; i & m; m <<= 1) ;
  512. m--;
  513. //
  514. // check for hosed PCI configuration requirements
  515. //
  516. if (length & ~m) {
  517. #if DBG
  518. HalDebugPrint(( HAL_INFO, "HAL: PCI - defective device! Bus %d, Slot %d, Function %d\n",
  519. BusNumber,
  520. PciSlot.u.bits.DeviceNumber,
  521. PciSlot.u.bits.FunctionNumber
  522. ));
  523. HalDebugPrint(( HAL_INFO, "HAL: PCI - BaseAddress[%d] = %08lx\n", j, i ));
  524. #endif
  525. //
  526. // The device is in error - punt. don't allow this
  527. // resource any option - it either gets set to whatever
  528. // bits it was able to return, or it doesn't get set.
  529. //
  530. if (i & PCI_ADDRESS_IO_SPACE) {
  531. m = i & ~0x3;
  532. Descriptor->u.Port.MinimumAddress.LowPart = m;
  533. } else {
  534. m = i & ~0xf;
  535. Descriptor->u.Memory.MinimumAddress.LowPart = m;
  536. }
  537. m += length; // max address is min address + length
  538. }
  539. //
  540. // Add requested resource
  541. //
  542. Descriptor->Option = 0;
  543. if (i & PCI_ADDRESS_IO_SPACE) {
  544. memtype = 0;
  545. if (!Is64BitBaseAddress(i) &&
  546. PciOrigData->Command & PCI_ENABLE_IO_SPACE) {
  547. //
  548. // The IO range is/was already enabled at some location, add that
  549. // as it's preferred setting.
  550. //
  551. Descriptor->Type = CmResourceTypePort;
  552. Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
  553. Descriptor->Flags = CM_RESOURCE_PORT_IO;
  554. Descriptor->Option = IO_RESOURCE_PREFERRED;
  555. Descriptor->u.Port.Length = length;
  556. Descriptor->u.Port.Alignment = length;
  557. Descriptor->u.Port.MinimumAddress.LowPart = *OrigAddress[j] & ~0x3;
  558. Descriptor->u.Port.MaximumAddress.LowPart =
  559. Descriptor->u.Port.MinimumAddress.LowPart + length - 1;
  560. CompleteList->List[0].Count++;
  561. Descriptor++;
  562. Descriptor->Option = IO_RESOURCE_ALTERNATIVE;
  563. }
  564. //
  565. // Add this IO range
  566. //
  567. Descriptor->Type = CmResourceTypePort;
  568. Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
  569. Descriptor->Flags = CM_RESOURCE_PORT_IO;
  570. Descriptor->u.Port.Length = length;
  571. Descriptor->u.Port.Alignment = length;
  572. Descriptor->u.Port.MaximumAddress.LowPart = m;
  573. } else {
  574. memtype = i & PCI_ADDRESS_MEMORY_TYPE_MASK;
  575. Descriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
  576. if (j == RomIndex) {
  577. // this is a ROM address
  578. Descriptor->Flags = CM_RESOURCE_MEMORY_READ_ONLY;
  579. }
  580. if (i & PCI_ADDRESS_MEMORY_PREFETCHABLE) {
  581. Descriptor->Flags |= CM_RESOURCE_MEMORY_PREFETCHABLE;
  582. }
  583. if (!Is64BitBaseAddress(i) &&
  584. (j == RomIndex ||
  585. PciOrigData->Command & PCI_ENABLE_MEMORY_SPACE)) {
  586. //
  587. // The memory range is/was already enabled at some location, add that
  588. // as it's preferred setting.
  589. //
  590. Descriptor->Type = CmResourceTypeMemory;
  591. Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
  592. Descriptor->Option = IO_RESOURCE_PREFERRED;
  593. Descriptor->u.Port.Length = length;
  594. Descriptor->u.Port.Alignment = length;
  595. Descriptor->u.Port.MinimumAddress.LowPart = *OrigAddress[j] & ~0xF;
  596. Descriptor->u.Port.MaximumAddress.LowPart =
  597. Descriptor->u.Port.MinimumAddress.LowPart + length - 1;
  598. CompleteList->List[0].Count++;
  599. Descriptor++;
  600. Descriptor->Flags = Descriptor[-1].Flags;
  601. Descriptor->Option = IO_RESOURCE_ALTERNATIVE;
  602. }
  603. //
  604. // Add this memory range
  605. //
  606. Descriptor->Type = CmResourceTypeMemory;
  607. Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
  608. Descriptor->u.Memory.Length = length;
  609. Descriptor->u.Memory.Alignment = length;
  610. Descriptor->u.Memory.MaximumAddress.LowPart = m;
  611. if (memtype == PCI_TYPE_20BIT && m > 0xFFFFF) {
  612. // limit to 20 bit address
  613. Descriptor->u.Memory.MaximumAddress.LowPart = 0xFFFFF;
  614. }
  615. }
  616. CompleteList->List[0].Count++;
  617. Descriptor++;
  618. if (Is64BitBaseAddress(i)) {
  619. //
  620. // Eventually we may want to do some work here for 64-bit
  621. // configs...
  622. //
  623. // skip upper half of 64 bit address since this processor
  624. // only supports 32 bits of address space
  625. //
  626. j++;
  627. }
  628. }
  629. }
  630. CompleteList->ListSize = (ULONG)
  631. ((PUCHAR) Descriptor - (PUCHAR) CompleteList);
  632. //
  633. // Restore the device settings as we found them, enable memory
  634. // and io decode after setting base addresses. This is done in
  635. // case HalAdjustResourceList wants to read the current settings
  636. // in the device.
  637. //
  638. HalpWritePCIConfig (
  639. BusHandler,
  640. PciSlot,
  641. &PciOrigData->Status,
  642. FIELD_OFFSET (PCI_COMMON_CONFIG, Status),
  643. PCI_COMMON_HDR_LENGTH - FIELD_OFFSET (PCI_COMMON_CONFIG, Status)
  644. );
  645. HalpWritePCIConfig (
  646. BusHandler,
  647. PciSlot,
  648. PciOrigData,
  649. 0,
  650. FIELD_OFFSET (PCI_COMMON_CONFIG, Status)
  651. );
  652. //
  653. // Have the IO system allocate resource assignments
  654. //
  655. status = IoAssignResources (
  656. RegistryPath,
  657. DriverClassName,
  658. DriverObject,
  659. DeviceObject,
  660. CompleteList,
  661. pAllocatedResources
  662. );
  663. if (!NT_SUCCESS(status)) {
  664. goto CleanUp;
  665. }
  666. //
  667. // Slurp the assigments back into the PciData structure and perform them
  668. //
  669. CmDescriptor = (*pAllocatedResources)->List[0].PartialResourceList.PartialDescriptors;
  670. //
  671. // If PCI device has an interrupt resource then that was passed in as the
  672. // first requested resource
  673. //
  674. if (RequestedInterrupt) {
  675. PciData->u.type0.InterruptLine = (UCHAR) CmDescriptor->u.Interrupt.Vector;
  676. BusData->CommonData.Line2Pin (BusHandler, RootHandler, PciSlot, PciData, PciOrigData);
  677. CmDescriptor++;
  678. }
  679. //
  680. // Pull out resources in the order they were passed to IoAssignResources
  681. //
  682. for (j=0; j < NoBaseAddress; j++) {
  683. i = *BaseAddress[j];
  684. if (i) {
  685. if (i & PCI_ADDRESS_IO_SPACE) {
  686. *BaseAddress[j] = CmDescriptor->u.Port.Start.LowPart;
  687. } else {
  688. *BaseAddress[j] = CmDescriptor->u.Memory.Start.LowPart;
  689. }
  690. CmDescriptor++;
  691. }
  692. if (Is64BitBaseAddress(i)) {
  693. // skip upper 32 bits
  694. j++;
  695. }
  696. }
  697. //
  698. // Turn off decodes, then set new addresses
  699. //
  700. HalpWritePCIConfig (BusHandler, PciSlot, PciData, 0, PCI_COMMON_HDR_LENGTH);
  701. //
  702. // Read configuration back and verify address settings took
  703. //
  704. HalpReadPCIConfig(BusHandler, PciSlot, PciData2, 0, PCI_COMMON_HDR_LENGTH);
  705. Match = TRUE;
  706. if (PciData->u.type0.InterruptLine != PciData2->u.type0.InterruptLine ||
  707. PciData->u.type0.InterruptPin != PciData2->u.type0.InterruptPin ||
  708. PciData->u.type0.ROMBaseAddress != PciData2->u.type0.ROMBaseAddress) {
  709. Match = FALSE;
  710. }
  711. for (j=0; j < NoBaseAddress; j++) {
  712. if (*BaseAddress[j]) {
  713. if (*BaseAddress[j] & PCI_ADDRESS_IO_SPACE) {
  714. i = (ULONG) ~0x3;
  715. } else {
  716. i = (ULONG) ~0xF;
  717. }
  718. if (( (*BaseAddress[j]) & i) !=
  719. (*((PULONG) ((PUCHAR) BaseAddress[j] -
  720. (PUCHAR) PciData +
  721. (PUCHAR) PciData2)) & i)) {
  722. Match = FALSE;
  723. }
  724. if (Is64BitBaseAddress(*BaseAddress[j])) {
  725. //
  726. // Eventually we may want to do something with the upper
  727. // 32 bits
  728. //
  729. j++;
  730. }
  731. }
  732. }
  733. if (!Match) {
  734. HalDebugPrint(( HAL_INFO, "HAL: PCI - defective device! Bus %d, Slot %d, Function %d\n",
  735. BusNumber,
  736. PciSlot.u.bits.DeviceNumber,
  737. PciSlot.u.bits.FunctionNumber
  738. ));
  739. status = STATUS_DEVICE_PROTOCOL_ERROR;
  740. goto CleanUp;
  741. }
  742. //
  743. // Settings took - turn on the appropiate decodes
  744. //
  745. if (EnableRomBase && *BaseAddress[RomIndex]) {
  746. //
  747. // A rom address was allocated and should be enabled
  748. //
  749. *BaseAddress[RomIndex] |= PCI_ROMADDRESS_ENABLED;
  750. HalpWritePCIConfig(
  751. BusHandler,
  752. PciSlot,
  753. BaseAddress[RomIndex],
  754. (ULONG) ((PUCHAR) BaseAddress[RomIndex] - (PUCHAR) PciData),
  755. sizeof (ULONG)
  756. );
  757. }
  758. //
  759. // Enable IO, Memory, and BUS_MASTER decodes
  760. // (use HalSetBusData since valid settings now set)
  761. //
  762. PciData->Command |= PCI_ENABLE_IO_SPACE |
  763. PCI_ENABLE_MEMORY_SPACE |
  764. PCI_ENABLE_BUS_MASTER;
  765. HalSetBusDataByOffset(
  766. PCIConfiguration,
  767. BusHandler->BusNumber,
  768. PciSlot.u.AsULONG,
  769. &PciData->Command,
  770. FIELD_OFFSET (PCI_COMMON_CONFIG, Command),
  771. sizeof (PciData->Command)
  772. );
  773. CleanUp:
  774. if (!NT_SUCCESS(status)) {
  775. //
  776. // Failure, if there are any allocated resources free them
  777. //
  778. if (*pAllocatedResources) {
  779. IoAssignResources(
  780. RegistryPath,
  781. DriverClassName,
  782. DriverObject,
  783. DeviceObject,
  784. NULL,
  785. NULL
  786. );
  787. ExFreePool(*pAllocatedResources);
  788. *pAllocatedResources = NULL;
  789. }
  790. //
  791. // Restore the device settings as we found them, enable memory
  792. // and io decode after setting base addresses
  793. //
  794. HalpWritePCIConfig(
  795. BusHandler,
  796. PciSlot,
  797. &PciOrigData->Status,
  798. FIELD_OFFSET(PCI_COMMON_CONFIG, Status),
  799. PCI_COMMON_HDR_LENGTH - FIELD_OFFSET (PCI_COMMON_CONFIG, Status)
  800. );
  801. HalpWritePCIConfig(
  802. BusHandler,
  803. PciSlot,
  804. PciOrigData,
  805. 0,
  806. FIELD_OFFSET(PCI_COMMON_CONFIG, Status)
  807. );
  808. }
  809. ExFreePool(WorkingPool);
  810. return(status);
  811. }
  812. BOOLEAN
  813. HalpValidPCISlot(
  814. IN PBUS_HANDLER BusHandler,
  815. IN PCI_SLOT_NUMBER Slot
  816. )
  817. /*++
  818. Routine Description:
  819. The function validates the information specifying a PCI "slot".
  820. Arguments:
  821. BusHandler - An encapsulation of data and manipulation functions specific to
  822. this bus.
  823. Slot - A PCI "slot" description (ie bus number, device number and function
  824. number.)
  825. Return Value:
  826. Returns TRUE if "slot" valid, otherwise FALSE.
  827. --*/
  828. {
  829. PCI_SLOT_NUMBER Slot2;
  830. PPCIPBUSDATA BusData;
  831. UCHAR HeaderType;
  832. ULONG i;
  833. BusData = (PPCIPBUSDATA)BusHandler->BusData;
  834. if (Slot.u.bits.Reserved != 0)
  835. return(FALSE);
  836. if (Slot.u.bits.DeviceNumber >= BusData->MaxDevice)
  837. return(FALSE);
  838. if (Slot.u.bits.FunctionNumber == 0)
  839. return(TRUE);
  840. //
  841. // Read DeviceNumber, Function zero, to determine if the
  842. // PCI supports multifunction devices
  843. //
  844. Slot.u.bits.FunctionNumber = 0;
  845. HalpPCIConfig(
  846. BusHandler,
  847. Slot,
  848. &HeaderType,
  849. FIELD_OFFSET(PCI_COMMON_CONFIG, HeaderType),
  850. sizeof(UCHAR),
  851. PCI_READ
  852. );
  853. //
  854. // FALSE if this device doesn't exist or doesn't support MULTIFUNCTION types
  855. //
  856. if (!(HeaderType & PCI_MULTIFUNCTION) || HeaderType == 0xFF)
  857. return(FALSE);
  858. return(TRUE);
  859. }
  860. //
  861. // This table is used to determine correct access size to PCI configuration
  862. // space given (offset % 4) and (length % 4).
  863. //
  864. // usage: PCIDeref[offset%4][length%4];
  865. //
  866. // Key:
  867. // 4 - implies a ULONG access and is the number of bytes returned
  868. // 1 - implies a UCHAR access and is the number of bytes returned
  869. // 2 - implies a USHORT access and is the number of bytes returned
  870. //
  871. UCHAR PCIDeref[4][4] = {{4,1,2,2}, {1,1,1,1}, {2,1,2,2}, {1,1,1,1}};
  872. #define SIZEOF_PARTIAL_INFO_HEADER FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data)
  873. VOID
  874. HalpPCIConfig(
  875. IN PBUS_HANDLER BusHandler,
  876. IN PCI_SLOT_NUMBER Slot,
  877. IN OUT PUCHAR Buffer,
  878. IN ULONG Offset,
  879. IN ULONG Length,
  880. IN PCI_ACCESS_TYPE AccType
  881. )
  882. {
  883. KIRQL Irql;
  884. ULONG Size;
  885. ULONG SALFunc;
  886. ULONG CfgAddr;
  887. ULONG WriteVal;
  888. SAL_PAL_RETURN_VALUES RetVals;
  889. SAL_STATUS Stat;
  890. //
  891. // Generate a PCI configuration address
  892. //
  893. CfgAddr = (BusHandler->BusNumber << 16) |
  894. (Slot.u.bits.DeviceNumber << 11) |
  895. (Slot.u.bits.FunctionNumber << 8);
  896. //
  897. // SAL or HalpSalCall will do whatever locking required.
  898. //
  899. while (Length) {
  900. Size = PCIDeref[Offset % sizeof(ULONG)][Length % sizeof(ULONG)];
  901. //
  902. // Set up input parameters
  903. //
  904. if (AccType == PCI_READ) {
  905. SALFunc = SAL_PCI_CONFIG_READ;
  906. WriteVal = 0;
  907. } else {
  908. switch (Size) {
  909. case 4: WriteVal = *((ULONG UNALIGNED *)Buffer); break;
  910. case 2: WriteVal = *((USHORT UNALIGNED *)Buffer); break;
  911. case 1: WriteVal = *Buffer; break;
  912. }
  913. SALFunc = SAL_PCI_CONFIG_WRITE;
  914. }
  915. //
  916. // Make SAL call
  917. //
  918. Stat = HalpSalCall(SALFunc, CfgAddr | Offset, Size, WriteVal, 0, 0, 0, 0, &RetVals);
  919. //
  920. // Retrieve SAL return data
  921. //
  922. if (AccType == PCI_READ) {
  923. switch (Size) {
  924. case 4: *((ULONG UNALIGNED *)Buffer) = (ULONG)RetVals.ReturnValues[1]; break;
  925. case 2: *((USHORT UNALIGNED *)Buffer) = (USHORT)RetVals.ReturnValues[1]; break;
  926. case 1: *Buffer = (UCHAR)RetVals.ReturnValues[1]; break;
  927. }
  928. }
  929. Offset += Size;
  930. Buffer += Size;
  931. Length -= Size;
  932. }
  933. }
  934. VOID
  935. HalpReadPCIConfig(
  936. IN PBUS_HANDLER BusHandler,
  937. IN PCI_SLOT_NUMBER Slot,
  938. OUT PVOID Buffer,
  939. IN ULONG Offset,
  940. IN ULONG Length
  941. )
  942. {
  943. //
  944. // If request for an invalid slot, fill return buffer with -1
  945. //
  946. if (!HalpValidPCISlot(BusHandler, Slot)) {
  947. RtlFillMemory(Buffer, Length, (UCHAR)-1);
  948. return;
  949. }
  950. HalpPCIConfig(BusHandler, Slot, Buffer, Offset, Length, PCI_READ);
  951. }
  952. VOID
  953. HalpWritePCIConfig(
  954. IN PBUS_HANDLER BusHandler,
  955. IN PCI_SLOT_NUMBER Slot,
  956. IN PVOID Buffer,
  957. IN ULONG Offset,
  958. IN ULONG Length
  959. )
  960. {
  961. //
  962. // If request for an invalid slot, do nothing
  963. //
  964. if (!HalpValidPCISlot(BusHandler, Slot))
  965. return;
  966. HalpPCIConfig(BusHandler, Slot, Buffer, Offset, Length, PCI_WRITE);
  967. }
  968. BOOLEAN
  969. HalpIsValidPCIDevice(
  970. IN PBUS_HANDLER BusHandler,
  971. IN PCI_SLOT_NUMBER Slot
  972. )
  973. /*++
  974. Routine Description:
  975. Reads the device configuration data for the given slot and
  976. returns TRUE if the configuration data appears to be valid for
  977. a PCI device; otherwise returns FALSE.
  978. Arguments:
  979. BusHandler - Bus to check
  980. Slot - Slot to check
  981. --*/
  982. {
  983. PPCI_COMMON_CONFIG PciData;
  984. UCHAR iBuffer[PCI_COMMON_HDR_LENGTH];
  985. ULONG i, j;
  986. PciData = (PPCI_COMMON_CONFIG)iBuffer;
  987. //
  988. // Read device common header.
  989. //
  990. HalpReadPCIConfig(BusHandler, Slot, PciData, 0, PCI_COMMON_HDR_LENGTH);
  991. //
  992. // Valid device header?
  993. //
  994. if (PciData->VendorID == PCI_INVALID_VENDORID ||
  995. PCI_CONFIG_TYPE(PciData) != PCI_DEVICE_TYPE) {
  996. return(FALSE);
  997. }
  998. //
  999. // Check fields for reasonable values.
  1000. //
  1001. //
  1002. // Do these values make sense for IA64
  1003. //
  1004. if ((PciData->u.type0.InterruptPin && PciData->u.type0.InterruptPin > 4) ||
  1005. (PciData->u.type0.InterruptLine & 0x70)) {
  1006. return(FALSE);
  1007. }
  1008. for (i=0; i < PCI_TYPE0_ADDRESSES; i++) {
  1009. j = PciData->u.type0.BaseAddresses[i];
  1010. if (j & PCI_ADDRESS_IO_SPACE) {
  1011. if (j > 0xffff) {
  1012. // IO port > 64k?
  1013. return(FALSE);
  1014. }
  1015. } else {
  1016. if (j > 0xf && j < 0x80000) {
  1017. // Mem address < 0x8000h?
  1018. return(FALSE);
  1019. }
  1020. }
  1021. if (Is64BitBaseAddress(j))
  1022. i++;
  1023. }
  1024. //
  1025. // Guess it's a valid device..
  1026. //
  1027. return(TRUE);
  1028. }
  1029. #if !defined(NO_LEGACY_DRIVERS)
  1030. #if DBG
  1031. VOID
  1032. HalpTestPci (ULONG flag2)
  1033. {
  1034. PCI_SLOT_NUMBER SlotNumber;
  1035. PCI_COMMON_CONFIG PciData, OrigData;
  1036. ULONG i, f, j, k, bus;
  1037. BOOLEAN flag;
  1038. if (!flag2) {
  1039. return ;
  1040. }
  1041. DbgBreakPoint ();
  1042. SlotNumber.u.bits.Reserved = 0;
  1043. //
  1044. // Read every possible PCI Device/Function and display it's
  1045. // default info.
  1046. //
  1047. // (note this destories it's current settings)
  1048. //
  1049. flag = TRUE;
  1050. for (bus = 0; flag; bus++) {
  1051. for (i = 0; i < PCI_MAX_DEVICES; i++) {
  1052. SlotNumber.u.bits.DeviceNumber = i;
  1053. for (f = 0; f < PCI_MAX_FUNCTION; f++) {
  1054. SlotNumber.u.bits.FunctionNumber = f;
  1055. //
  1056. // Note: This is reading the DeviceSpecific area of
  1057. // the device's configuration - normally this should
  1058. // only be done on device for which the caller understands.
  1059. // I'm doing it here only for debugging.
  1060. //
  1061. j = HalGetBusData (
  1062. PCIConfiguration,
  1063. bus,
  1064. SlotNumber.u.AsULONG,
  1065. &PciData,
  1066. sizeof (PciData)
  1067. );
  1068. if (j == 0) {
  1069. // out of buses
  1070. flag = FALSE;
  1071. break;
  1072. }
  1073. if (j < PCI_COMMON_HDR_LENGTH) {
  1074. continue;
  1075. }
  1076. HalSetBusData (
  1077. PCIConfiguration,
  1078. bus,
  1079. SlotNumber.u.AsULONG,
  1080. &PciData,
  1081. 1
  1082. );
  1083. HalGetBusData (
  1084. PCIConfiguration,
  1085. bus,
  1086. SlotNumber.u.AsULONG,
  1087. &PciData,
  1088. sizeof (PciData)
  1089. );
  1090. HalDebugPrint(( HAL_INFO, "HAL: PCI Bus %d Slot %2d %2d ID:%04lx-%04lx Rev:%04lx",
  1091. bus, i, f, PciData.VendorID, PciData.DeviceID,
  1092. PciData.RevisionID ));
  1093. if (PciData.u.type0.InterruptPin) {
  1094. HalDebugPrint(( HAL_INFO, " IntPin:%x", PciData.u.type0.InterruptPin ));
  1095. }
  1096. if (PciData.u.type0.InterruptLine) {
  1097. HalDebugPrint(( HAL_INFO, " IntLine:%x", PciData.u.type0.InterruptLine ));
  1098. }
  1099. if (PciData.u.type0.ROMBaseAddress) {
  1100. HalDebugPrint(( HAL_INFO, " ROM:%08lx", PciData.u.type0.ROMBaseAddress ));
  1101. }
  1102. HalDebugPrint(( HAL_INFO, "\nHAL: Cmd:%04x Status:%04x ProgIf:%04x SubClass:%04x BaseClass:%04lx\n",
  1103. PciData.Command, PciData.Status, PciData.ProgIf,
  1104. PciData.SubClass, PciData.BaseClass ));
  1105. k = 0;
  1106. for (j=0; j < PCI_TYPE0_ADDRESSES; j++) {
  1107. if (PciData.u.type0.BaseAddresses[j]) {
  1108. HalDebugPrint(( HAL_INFO, " Ad%d:%08lx", j, PciData.u.type0.BaseAddresses[j] ));
  1109. k = 1;
  1110. }
  1111. }
  1112. if (k) {
  1113. HalDebugPrint(( HAL_INFO, "\n" ));
  1114. }
  1115. if (PciData.VendorID == 0x8086) {
  1116. // dump complete buffer
  1117. HalDebugPrint(( HAL_INFO, "HAL: Command %x, Status %x, BIST %x\n",
  1118. PciData.Command, PciData.Status,
  1119. PciData.BIST
  1120. ));
  1121. HalDebugPrint(( HAL_INFO, "HAL: CacheLineSz %x, LatencyTimer %x",
  1122. PciData.CacheLineSize, PciData.LatencyTimer
  1123. ));
  1124. for (j=0; j < 192; j++) {
  1125. if ((j & 0xf) == 0) {
  1126. HalDebugPrint(( HAL_INFO, "\n%02x: ", j + 0x40 ));
  1127. }
  1128. HalDebugPrint(( HAL_INFO, "%02x ", PciData.DeviceSpecific[j] ));
  1129. }
  1130. HalDebugPrint(( HAL_INFO, "\n" ));
  1131. }
  1132. //
  1133. // Next
  1134. //
  1135. if (k) {
  1136. HalDebugPrint(( HAL_INFO, "\n\n" ));
  1137. }
  1138. }
  1139. }
  1140. }
  1141. DbgBreakPoint ();
  1142. }
  1143. #endif
  1144. #endif // NO_LEGACY_DRIVERS
  1145. //------------------------------------------------------------------------------