3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: hal/halx86/generic/pci.c
5 * PURPOSE: PCI Bus Support (Configuration Space, Resource Allocation)
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
9 /* INCLUDES ******************************************************************/
15 /* GLOBALS *******************************************************************/
17 BOOLEAN HalpPCIConfigInitialized
;
18 ULONG HalpMinPciBus
, HalpMaxPciBus
;
19 KSPIN_LOCK HalpPCIConfigLock
;
20 PCI_CONFIG_HANDLER PCIConfigHandler
;
22 /* PCI Operation Matrix */
23 UCHAR PCIDeref
[4][4] =
25 {0, 1, 2, 2}, // ULONG-aligned offset
26 {1, 1, 1, 1}, // UCHAR-aligned offset
27 {2, 1, 2, 2}, // USHORT-aligned offset
28 {1, 1, 1, 1} // UCHAR-aligned offset
32 PCI_CONFIG_HANDLER PCIConfigHandlerType1
=
35 (FncSync
)HalpPCISynchronizeType1
,
36 (FncReleaseSync
)HalpPCIReleaseSynchronzationType1
,
40 (FncConfigIO
)HalpPCIReadUlongType1
,
41 (FncConfigIO
)HalpPCIReadUcharType1
,
42 (FncConfigIO
)HalpPCIReadUshortType1
47 (FncConfigIO
)HalpPCIWriteUlongType1
,
48 (FncConfigIO
)HalpPCIWriteUcharType1
,
49 (FncConfigIO
)HalpPCIWriteUshortType1
54 PCI_CONFIG_HANDLER PCIConfigHandlerType2
=
57 (FncSync
)HalpPCISynchronizeType2
,
58 (FncReleaseSync
)HalpPCIReleaseSynchronzationType2
,
62 (FncConfigIO
)HalpPCIReadUlongType2
,
63 (FncConfigIO
)HalpPCIReadUcharType2
,
64 (FncConfigIO
)HalpPCIReadUshortType2
69 (FncConfigIO
)HalpPCIWriteUlongType2
,
70 (FncConfigIO
)HalpPCIWriteUcharType2
,
71 (FncConfigIO
)HalpPCIWriteUshortType2
75 PCIPBUSDATA HalpFakePciBusData
=
91 BUS_HANDLER HalpFakePciBusHandler
=
105 HalpAssignPCISlotResources
,
110 /* TYPE 1 FUNCTIONS **********************************************************/
114 HalpPCISynchronizeType1(IN PBUS_HANDLER BusHandler
,
115 IN PCI_SLOT_NUMBER Slot
,
117 IN PPCI_TYPE1_CFG_BITS PciCfg1
)
119 /* Setup the PCI Configuration Register */
120 PciCfg1
->u
.AsULONG
= 0;
121 PciCfg1
->u
.bits
.BusNumber
= BusHandler
->BusNumber
;
122 PciCfg1
->u
.bits
.DeviceNumber
= Slot
.u
.bits
.DeviceNumber
;
123 PciCfg1
->u
.bits
.FunctionNumber
= Slot
.u
.bits
.FunctionNumber
;
124 PciCfg1
->u
.bits
.Enable
= TRUE
;
126 /* Acquire the lock */
127 KeRaiseIrql(HIGH_LEVEL
, Irql
);
128 KiAcquireSpinLock(&HalpPCIConfigLock
);
133 HalpPCIReleaseSynchronzationType1(IN PBUS_HANDLER BusHandler
,
136 PCI_TYPE1_CFG_BITS PciCfg1
;
138 /* Clear the PCI Configuration Register */
139 PciCfg1
.u
.AsULONG
= 0;
140 WRITE_PORT_ULONG(((PPCIPBUSDATA
)BusHandler
->BusData
)->Config
.Type1
.Address
,
143 /* Release the lock */
144 KiReleaseSpinLock(&HalpPCIConfigLock
);
148 TYPE1_READ(HalpPCIReadUcharType1
, UCHAR
)
149 TYPE1_READ(HalpPCIReadUshortType1
, USHORT
)
150 TYPE1_READ(HalpPCIReadUlongType1
, ULONG
)
151 TYPE1_WRITE(HalpPCIWriteUcharType1
, UCHAR
)
152 TYPE1_WRITE(HalpPCIWriteUshortType1
, USHORT
)
153 TYPE1_WRITE(HalpPCIWriteUlongType1
, ULONG
)
155 /* TYPE 2 FUNCTIONS **********************************************************/
159 HalpPCISynchronizeType2(IN PBUS_HANDLER BusHandler
,
160 IN PCI_SLOT_NUMBER Slot
,
162 IN PPCI_TYPE2_ADDRESS_BITS PciCfg
)
164 PCI_TYPE2_CSE_BITS PciCfg2Cse
;
165 PPCIPBUSDATA BusData
= (PPCIPBUSDATA
)BusHandler
->BusData
;
167 /* Setup the configuration register */
168 PciCfg
->u
.AsUSHORT
= 0;
169 PciCfg
->u
.bits
.Agent
= (USHORT
)Slot
.u
.bits
.DeviceNumber
;
170 PciCfg
->u
.bits
.AddressBase
= (USHORT
)BusData
->Config
.Type2
.Base
;
172 /* Acquire the lock */
173 KeRaiseIrql(HIGH_LEVEL
, Irql
);
174 KiAcquireSpinLock(&HalpPCIConfigLock
);
176 /* Setup the CSE Register */
177 PciCfg2Cse
.u
.AsUCHAR
= 0;
178 PciCfg2Cse
.u
.bits
.Enable
= TRUE
;
179 PciCfg2Cse
.u
.bits
.FunctionNumber
= (UCHAR
)Slot
.u
.bits
.FunctionNumber
;
180 PciCfg2Cse
.u
.bits
.Key
= -1;
182 /* Write the bus number and CSE */
183 WRITE_PORT_UCHAR(BusData
->Config
.Type2
.Forward
,
184 (UCHAR
)BusHandler
->BusNumber
);
185 WRITE_PORT_UCHAR(BusData
->Config
.Type2
.CSE
, PciCfg2Cse
.u
.AsUCHAR
);
190 HalpPCIReleaseSynchronzationType2(IN PBUS_HANDLER BusHandler
,
193 PCI_TYPE2_CSE_BITS PciCfg2Cse
;
194 PPCIPBUSDATA BusData
= (PPCIPBUSDATA
)BusHandler
->BusData
;
196 /* Clear CSE and bus number */
197 PciCfg2Cse
.u
.AsUCHAR
= 0;
198 WRITE_PORT_UCHAR(BusData
->Config
.Type2
.CSE
, PciCfg2Cse
.u
.AsUCHAR
);
199 WRITE_PORT_UCHAR(BusData
->Config
.Type2
.Forward
, 0);
201 /* Release the lock */
202 KiReleaseSpinLock(&HalpPCIConfigLock
);
206 TYPE2_READ(HalpPCIReadUcharType2
, UCHAR
)
207 TYPE2_READ(HalpPCIReadUshortType2
, USHORT
)
208 TYPE2_READ(HalpPCIReadUlongType2
, ULONG
)
209 TYPE2_WRITE(HalpPCIWriteUcharType2
, UCHAR
)
210 TYPE2_WRITE(HalpPCIWriteUshortType2
, USHORT
)
211 TYPE2_WRITE(HalpPCIWriteUlongType2
, ULONG
)
213 /* PCI CONFIGURATION SPACE ***************************************************/
217 HalpPCIConfig(IN PBUS_HANDLER BusHandler
,
218 IN PCI_SLOT_NUMBER Slot
,
222 IN FncConfigIO
*ConfigIO
)
228 /* Synchronize the operation */
229 PCIConfigHandler
.Synchronize(BusHandler
, Slot
, &OldIrql
, State
);
231 /* Loop every increment */
234 /* Find out the type of read/write we need to do */
235 i
= PCIDeref
[Offset
% sizeof(ULONG
)][Length
% sizeof(ULONG
)];
237 /* Do the read/write and return the number of bytes */
238 i
= ConfigIO
[i
]((PPCIPBUSDATA
)BusHandler
->BusData
,
243 /* Increment the buffer position and offset, and decrease the length */
249 /* Release the lock and PCI bus */
250 PCIConfigHandler
.ReleaseSynchronzation(BusHandler
, OldIrql
);
255 HalpReadPCIConfig(IN PBUS_HANDLER BusHandler
,
256 IN PCI_SLOT_NUMBER Slot
,
261 /* Validate the PCI Slot */
262 if (!HalpValidPCISlot(BusHandler
, Slot
))
264 /* Fill the buffer with invalid data */
265 RtlFillMemory(Buffer
, Length
, -1);
269 /* Send the request */
270 HalpPCIConfig(BusHandler
,
275 PCIConfigHandler
.ConfigRead
);
281 HalpWritePCIConfig(IN PBUS_HANDLER BusHandler
,
282 IN PCI_SLOT_NUMBER Slot
,
287 /* Validate the PCI Slot */
288 if (HalpValidPCISlot(BusHandler
, Slot
))
290 /* Send the request */
291 HalpPCIConfig(BusHandler
,
296 PCIConfigHandler
.ConfigWrite
);
302 HalpValidPCISlot(IN PBUS_HANDLER BusHandler
,
303 IN PCI_SLOT_NUMBER Slot
)
305 PCI_SLOT_NUMBER MultiSlot
;
306 PPCIPBUSDATA BusData
= (PPCIPBUSDATA
)BusHandler
->BusData
;
310 /* Simple validation */
311 if (Slot
.u
.bits
.Reserved
) return FALSE
;
312 if (Slot
.u
.bits
.DeviceNumber
>= BusData
->MaxDevice
) return FALSE
;
314 /* Function 0 doesn't need checking */
315 if (!Slot
.u
.bits
.FunctionNumber
) return TRUE
;
317 /* Functions 0+ need Multi-Function support, so check the slot */
318 Device
= Slot
.u
.bits
.DeviceNumber
;
320 MultiSlot
.u
.bits
.FunctionNumber
= 0;
322 /* Send function 0 request to get the header back */
323 HalpReadPCIConfig(BusHandler
,
326 FIELD_OFFSET(PCI_COMMON_CONFIG
, HeaderType
),
329 /* Now make sure the header is multi-function */
330 if (!(HeaderType
& PCI_MULTIFUNCTION
) || (HeaderType
== 0xFF)) return FALSE
;
334 /* HAL PCI CALLBACKS *********************************************************/
338 HalpGetPCIData(IN PBUS_HANDLER BusHandler
,
339 IN PBUS_HANDLER RootHandler
,
340 IN PCI_SLOT_NUMBER Slot
,
345 UCHAR PciBuffer
[PCI_COMMON_HDR_LENGTH
];
346 PPCI_COMMON_CONFIG PciConfig
= (PPCI_COMMON_CONFIG
)PciBuffer
;
349 /* Normalize the length */
350 if (Length
> sizeof(PCI_COMMON_CONFIG
)) Length
= sizeof(PCI_COMMON_CONFIG
);
352 /* Check if this is a vendor-specific read */
353 if (Offset
>= PCI_COMMON_HDR_LENGTH
)
355 /* Read the header */
356 HalpReadPCIConfig(BusHandler
, Slot
, PciConfig
, 0, sizeof(ULONG
));
358 /* Make sure the vendor is valid */
359 if (PciConfig
->VendorID
== PCI_INVALID_VENDORID
) return 0;
363 /* Read the entire header */
364 Len
= PCI_COMMON_HDR_LENGTH
;
365 HalpReadPCIConfig(BusHandler
, Slot
, PciConfig
, 0, Len
);
367 /* Validate the vendor ID */
368 if (PciConfig
->VendorID
== PCI_INVALID_VENDORID
)
370 /* It's invalid, but we want to return this much */
371 PciConfig
->VendorID
= PCI_INVALID_VENDORID
;
372 Len
= sizeof(USHORT
);
375 /* Now check if there's space left */
376 if (Len
< Offset
) return 0;
378 /* There is, so return what's after the offset and normalize */
380 if (Len
> Length
) Len
= Length
;
382 /* Copy the data into the caller's buffer */
383 RtlMoveMemory(Buffer
, PciBuffer
+ Offset
, Len
);
385 /* Update buffer and offset, decrement total length */
391 /* Now we still have something to copy */
394 /* Check if it's vendor-specific data */
395 if (Offset
>= PCI_COMMON_HDR_LENGTH
)
398 HalpReadPCIConfig(BusHandler
, Slot
, Buffer
, Offset
, Length
);
403 /* Update the total length read */
409 HalpSetPCIData(IN PBUS_HANDLER BusHandler
,
410 IN PBUS_HANDLER RootHandler
,
411 IN PCI_SLOT_NUMBER Slot
,
416 UCHAR PciBuffer
[PCI_COMMON_HDR_LENGTH
];
417 PPCI_COMMON_CONFIG PciConfig
= (PPCI_COMMON_CONFIG
)PciBuffer
;
420 /* Normalize the length */
421 if (Length
> sizeof(PCI_COMMON_CONFIG
)) Length
= sizeof(PCI_COMMON_CONFIG
);
423 /* Check if this is a vendor-specific read */
424 if (Offset
>= PCI_COMMON_HDR_LENGTH
)
426 /* Read the header */
427 HalpReadPCIConfig(BusHandler
, Slot
, PciConfig
, 0, sizeof(ULONG
));
429 /* Make sure the vendor is valid */
430 if (PciConfig
->VendorID
== PCI_INVALID_VENDORID
) return 0;
434 /* Read the entire header and validate the vendor ID */
435 Len
= PCI_COMMON_HDR_LENGTH
;
436 HalpReadPCIConfig(BusHandler
, Slot
, PciConfig
, 0, Len
);
437 if (PciConfig
->VendorID
== PCI_INVALID_VENDORID
) return 0;
439 /* Return what's after the offset and normalize */
441 if (Len
> Length
) Len
= Length
;
443 /* Copy the specific caller data */
444 RtlMoveMemory(PciBuffer
+ Offset
, Buffer
, Len
);
446 /* Write the actual configuration data */
447 HalpWritePCIConfig(BusHandler
, Slot
, PciBuffer
+ Offset
, Offset
, Len
);
449 /* Update buffer and offset, decrement total length */
455 /* Now we still have something to copy */
458 /* Check if it's vendor-specific data */
459 if (Offset
>= PCI_COMMON_HDR_LENGTH
)
462 HalpWritePCIConfig(BusHandler
, Slot
, Buffer
, Offset
, Length
);
467 /* Update the total length read */
473 HalpSetupPciDeviceForDebugging(IN PVOID LoaderBlock
,
474 IN OUT PDEBUG_DEVICE_DESCRIPTOR PciDevice
)
476 DPRINT1("Unimplemented!\n");
477 return STATUS_NOT_IMPLEMENTED
;
482 HalpReleasePciDeviceForDebugging(IN OUT PDEBUG_DEVICE_DESCRIPTOR PciDevice
)
484 DPRINT1("Unimplemented!\n");
485 return STATUS_NOT_IMPLEMENTED
;
490 HalpAssignPCISlotResources(IN PBUS_HANDLER BusHandler
,
491 IN PBUS_HANDLER RootHandler
,
492 IN PUNICODE_STRING RegistryPath
,
493 IN PUNICODE_STRING DriverClassName OPTIONAL
,
494 IN PDRIVER_OBJECT DriverObject
,
495 IN PDEVICE_OBJECT DeviceObject OPTIONAL
,
497 IN OUT PCM_RESOURCE_LIST
*pAllocatedResources
)
500 return STATUS_SUCCESS
;
505 HaliPciInterfaceReadConfig(IN PBUS_HANDLER RootBusHandler
,
507 IN PCI_SLOT_NUMBER SlotNumber
,
512 BUS_HANDLER BusHandler
;
513 PPCI_COMMON_CONFIG PciData
= (PPCI_COMMON_CONFIG
)Buffer
;
515 /* Setup fake PCI Bus handler */
516 RtlCopyMemory(&BusHandler
, &HalpFakePciBusHandler
, sizeof(BUS_HANDLER
));
517 BusHandler
.BusNumber
= BusNumber
;
519 /* Read configuration data */
520 HalpReadPCIConfig(&BusHandler
, SlotNumber
, Buffer
, Offset
, Length
);
522 /* Check if caller only wanted at least Vendor ID */
526 if (PciData
->VendorID
!= PCI_INVALID_VENDORID
)
528 /* Check if this is the new maximum bus number */
529 if (HalpMaxPciBus
< BusHandler
.BusNumber
)
532 HalpMaxPciBus
= BusHandler
.BusNumber
;
541 PPCI_REGISTRY_INFO_INTERNAL
543 HalpQueryPciRegistryInfo(VOID
)
546 OBJECT_ATTRIBUTES ObjectAttributes
;
547 UNICODE_STRING KeyName
, ConfigName
, IdentName
;
548 HANDLE KeyHandle
, BusKeyHandle
;
550 UCHAR KeyBuffer
[sizeof(PPCI_REGISTRY_INFO
) + 100];
551 PKEY_VALUE_FULL_INFORMATION ValueInfo
= (PVOID
)KeyBuffer
;
555 PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor
;
556 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor
;
557 PPCI_REGISTRY_INFO PciRegInfo
;
558 PPCI_REGISTRY_INFO_INTERNAL PciRegistryInfo
;
560 /* Setup the object attributes for the key */
561 RtlInitUnicodeString(&KeyName
,
562 L
"\\Registry\\Machine\\Hardware\\Description\\"
563 L
"System\\MultiFunctionAdapter");
564 InitializeObjectAttributes(&ObjectAttributes
,
566 OBJ_CASE_INSENSITIVE
,
571 Status
= ZwOpenKey(&KeyHandle
, KEY_READ
, &ObjectAttributes
);
572 if (!NT_SUCCESS(Status
)) return NULL
;
574 /* Setup the receiving string */
575 KeyName
.Buffer
= NameBuffer
;
576 KeyName
.MaximumLength
= sizeof(NameBuffer
);
578 /* Setup the configuration and identifier key names */
579 RtlInitUnicodeString(&ConfigName
, L
"ConfigurationData");
580 RtlInitUnicodeString(&IdentName
, L
"Identifier");
582 /* Keep looping for each ID */
583 for (i
= 0; TRUE
; i
++)
585 /* Setup the key name */
586 RtlIntegerToUnicodeString(i
, 10, &KeyName
);
587 InitializeObjectAttributes(&ObjectAttributes
,
589 OBJ_CASE_INSENSITIVE
,
594 Status
= ZwOpenKey(&BusKeyHandle
, KEY_READ
, &ObjectAttributes
);
595 if (!NT_SUCCESS(Status
))
597 /* None left, fail */
602 /* Read the registry data */
603 Status
= ZwQueryValueKey(BusKeyHandle
,
605 KeyValueFullInformation
,
609 if (!NT_SUCCESS(Status
))
611 /* Failed, try the next one */
612 ZwClose(BusKeyHandle
);
616 /* Get the PCI Tag and validate it */
617 Tag
= (PWSTR
)((ULONG_PTR
)ValueInfo
+ ValueInfo
->DataOffset
);
618 if ((Tag
[0] != L
'P') ||
623 /* Not a valid PCI entry, skip it */
624 ZwClose(BusKeyHandle
);
628 /* Now read our PCI structure */
629 Status
= ZwQueryValueKey(BusKeyHandle
,
631 KeyValueFullInformation
,
635 ZwClose(BusKeyHandle
);
636 if (!NT_SUCCESS(Status
)) continue;
638 /* We read it OK! Get the actual resource descriptors */
639 FullDescriptor
= (PCM_FULL_RESOURCE_DESCRIPTOR
)
640 ((ULONG_PTR
)ValueInfo
+ ValueInfo
->DataOffset
);
641 PartialDescriptor
= (PCM_PARTIAL_RESOURCE_DESCRIPTOR
)
642 ((ULONG_PTR
)FullDescriptor
->
643 PartialResourceList
.PartialDescriptors
);
645 /* Check if this is our PCI Registry Information */
646 if (PartialDescriptor
->Type
== CmResourceTypeDeviceSpecific
)
651 /* FIXME: Check PnP\PCI\CardList */
653 /* Get the PCI information */
654 PciRegInfo
= (PPCI_REGISTRY_INFO
)(PartialDescriptor
+ 1);
656 /* Allocate the return structure */
657 PciRegistryInfo
= ExAllocatePoolWithTag(NonPagedPool
,
658 sizeof(PCI_REGISTRY_INFO_INTERNAL
),
660 if (!PciRegistryInfo
) return NULL
;
663 PciRegistryInfo
->HardwareMechanism
= PciRegInfo
->HardwareMechanism
;
664 PciRegistryInfo
->NoBuses
= PciRegInfo
->NoBuses
;
665 PciRegistryInfo
->MajorRevision
= PciRegInfo
->MajorRevision
;
666 PciRegistryInfo
->MinorRevision
= PciRegInfo
->MinorRevision
;
667 PciRegistryInfo
->ElementCount
= 0;
674 HalpInitializePciStubs(VOID
)
676 PPCI_REGISTRY_INFO_INTERNAL PciRegistryInfo
;
678 PPCIPBUSDATA BusData
= (PPCIPBUSDATA
)HalpFakePciBusHandler
.BusData
;
683 /* Query registry information */
684 PciRegistryInfo
= HalpQueryPciRegistryInfo();
685 if (!PciRegistryInfo
)
692 /* Get the type and free the info structure */
693 PciType
= PciRegistryInfo
->HardwareMechanism
& 0xF;
694 ExFreePool(PciRegistryInfo
);
697 /* Initialize the PCI lock */
698 KeInitializeSpinLock(&HalpPCIConfigLock
);
700 /* Check the type of PCI bus */
706 /* Copy the Type 1 handler data */
707 RtlCopyMemory(&PCIConfigHandler
,
708 &PCIConfigHandlerType1
,
709 sizeof(PCIConfigHandler
));
711 /* Set correct I/O Ports */
712 BusData
->Config
.Type1
.Address
= PCI_TYPE1_ADDRESS_PORT
;
713 BusData
->Config
.Type1
.Data
= PCI_TYPE1_DATA_PORT
;
719 /* Copy the Type 1 handler data */
720 RtlCopyMemory(&PCIConfigHandler
,
721 &PCIConfigHandlerType2
,
722 sizeof (PCIConfigHandler
));
724 /* Set correct I/O Ports */
725 BusData
->Config
.Type2
.CSE
= PCI_TYPE2_CSE_PORT
;
726 BusData
->Config
.Type2
.Forward
= PCI_TYPE2_FORWARD_PORT
;
727 BusData
->Config
.Type2
.Base
= PCI_TYPE2_ADDRESS_BASE
;
729 /* Only 16 devices supported, not 32 */
730 BusData
->MaxDevice
= 16;
736 DbgPrint("HAL: Unnkown PCI type\n");
739 /* Loop all possible buses */
740 for (i
= 0; i
< 256; i
++)
742 /* Loop all devices */
743 for (j
.u
.AsULONG
= 0; j
.u
.AsULONG
< 32; j
.u
.AsULONG
++)
745 /* Query the interface */
746 if (HaliPciInterfaceReadConfig(NULL
,
753 /* Validate the vendor ID */
754 if ((USHORT
)VendorId
!= PCI_INVALID_VENDORID
)
756 /* Set this as the maximum ID */
765 HalpPCIConfigInitialized
= TRUE
;
770 HalpInitializePciBus(VOID
)
772 /* Initialize the stubs */
773 HalpInitializePciStubs();
775 /* FIXME: Initialize NMI Crash Flag */