windows-nt/Source/XPSP1/NT/base/busdrv/agp/agplib/config.c

916 lines
23 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1997 Microsoft Corporation
Module Name:
config.c
Abstract:
Routines for accessing config space in the PCI-PCI bridge
Author:
John Vert (jvert) 10/27/1997
Revision History:
--*/
#include "agplib.h"
typedef struct _BUS_SLOT_ID {
ULONG BusId;
ULONG SlotId;
} BUS_SLOT_ID, *PBUS_SLOT_ID;
//
// Local function prototypes
//
NTSTATUS
ApGetSetDeviceBusData(
IN PCOMMON_EXTENSION Extension,
IN BOOLEAN Read,
IN PVOID Buffer,
IN ULONG Offset,
IN ULONG Length
);
NTSTATUS
ApGetSetBusData(
IN PBUS_SLOT_ID BusSlotId,
IN BOOLEAN Read,
IN PVOID Buffer,
IN ULONG Offset,
IN ULONG Length
);
NTSTATUS
ApFindAgpCapability(
IN PAGP_GETSET_CONFIG_SPACE pConfigFn,
IN PVOID Context,
OUT PPCI_AGP_CAPABILITY Capability,
OUT UCHAR *pOffset,
OUT PPCI_COMMON_CONFIG PciCommonConfig OPTIONAL
);
NTSTATUS
ApQueryBusInterface(
IN PDEVICE_OBJECT DeviceObject,
OUT PBUS_INTERFACE_STANDARD BusInterface
)
/*++
Routine Description:
Sends a query-interface IRP to the specified device object
to obtain the BUS_INTERFACE_STANDARD interface.
Arguments:
DeviceObject - Supplies the device object to send the BUS_INTERFACE_STANDARD to
BusInterface - Returns the bus interface
Return Value:
STATUS_SUCCESS if successful
NTSTATUS if unsuccessful
--*/
{
PIRP Irp;
KEVENT Event;
PIO_STACK_LOCATION IrpSp;
IO_STATUS_BLOCK IoStatusBlock;
NTSTATUS Status;
ULONG ReturnLength;
KeInitializeEvent( &Event, NotificationEvent, FALSE );
Irp = IoBuildSynchronousFsdRequest( IRP_MJ_PNP,
DeviceObject,
NULL,
0,
NULL,
&Event,
&IoStatusBlock );
if (Irp == NULL) {
return(STATUS_INSUFFICIENT_RESOURCES);
}
IrpSp = IoGetNextIrpStackLocation( Irp );
ASSERT(IrpSp != NULL);
Irp->IoStatus.Status = STATUS_NOT_SUPPORTED ;
IrpSp->MajorFunction = IRP_MJ_PNP;
IrpSp->MinorFunction = IRP_MN_QUERY_INTERFACE;
IrpSp->Parameters.QueryInterface.InterfaceType = (LPGUID)&GUID_BUS_INTERFACE_STANDARD;
IrpSp->Parameters.QueryInterface.Size = sizeof(BUS_INTERFACE_STANDARD);
IrpSp->Parameters.QueryInterface.Version = 1;
IrpSp->Parameters.QueryInterface.Interface = (PINTERFACE) BusInterface;
IrpSp->Parameters.QueryInterface.InterfaceSpecificData = NULL;
Status = IoCallDriver(DeviceObject, Irp);
if (Status == STATUS_PENDING) {
KeWaitForSingleObject( &Event, Executive, KernelMode, FALSE, NULL );
Status = Irp->IoStatus.Status;
}
return(Status);
}
NTSTATUS
ApGetSetDeviceBusData(
IN PCOMMON_EXTENSION Extension,
IN BOOLEAN Read,
IN PVOID Buffer,
IN ULONG Offset,
IN ULONG Length
)
/*++
Routine Description:
Reads or writes PCI config space for the specified device.
Arguments:
Extension - Supplies the common AGP extension
Read - if TRUE, this is a READ IRP
if FALSE, this is a WRITE IRP
Buffer - Returns the PCI config data
Offset - Supplies the offset into the PCI config data where the read should begin
Length - Supplies the number of bytes to be read
Return Value:
NTSTATUS
--*/
{
NTSTATUS Status;
ULONG ReturnLength;
ULONG Transferred;
//
// First check our device extension. This must be either a master
// or target extension, we don't care too much which.
//
ASSERT((Extension->Signature == TARGET_SIG) ||
(Extension->Signature == MASTER_SIG));
//
// Now we simply use our bus interface to call directly to PCI.
//
if (Read) {
Transferred = Extension->BusInterface.GetBusData(Extension->BusInterface.Context,
PCI_WHICHSPACE_CONFIG,
Buffer,
Offset,
Length);
} else {
Transferred = Extension->BusInterface.SetBusData(Extension->BusInterface.Context,
PCI_WHICHSPACE_CONFIG,
Buffer,
Offset,
Length);
}
if (Transferred == Length) {
return(STATUS_SUCCESS);
} else {
return(STATUS_UNSUCCESSFUL);
}
}
NTSTATUS
ApGetSetBusData(
IN PBUS_SLOT_ID BusSlotId,
IN BOOLEAN Read,
IN PVOID Buffer,
IN ULONG Offset,
IN ULONG Length
)
/*++
Routine Description:
Calls HalGet/SetBusData for the specified PCI bus/slot ID.
Arguments:
BusSlotId - Supplies the bus and slot ID.
Read - if TRUE, this is a GetBusData
if FALSE, this is a SetBusData
Buffer - Returns the PCI config data
Offset - Supplies the offset into the PCI config data where the read should begin
Length - Supplies the number of bytes to be read
Return Value:
NTSTATUS
--*/
{
ULONG Transferred;
if (Read) {
Transferred = HalGetBusDataByOffset(PCIConfiguration,
BusSlotId->BusId,
BusSlotId->SlotId,
Buffer,
Offset,
Length);
} else {
Transferred = HalSetBusDataByOffset(PCIConfiguration,
BusSlotId->BusId,
BusSlotId->SlotId,
Buffer,
Offset,
Length);
}
if (Transferred == Length) {
return(STATUS_SUCCESS);
} else {
return(STATUS_UNSUCCESSFUL);
}
}
NTSTATUS
ApFindAgpCapability(
IN PAGP_GETSET_CONFIG_SPACE pConfigFn,
IN PVOID Context,
OUT PPCI_AGP_CAPABILITY Capability,
OUT UCHAR *pOffset,
OUT PPCI_COMMON_CONFIG PciCommonConfig OPTIONAL
)
/*++
Routine Description:
Finds the capability offset for the specified device and
reads in the header.
Arguments:
pConfigFn - Supplies the function to call for accessing config space
on the appropriate device.
Context - Supplies the context to pass to pConfigFn
Capabilities - Returns the AGP Capabilities common header
pOffset - Returns the offset into config space.
PciCommonConfig - NULL, or points to the PCI common configuration header
Return Value:
NTSTATUS
--*/
{
PCI_COMMON_HEADER Header;
PPCI_COMMON_CONFIG PciConfig = (PPCI_COMMON_CONFIG)&Header;
NTSTATUS Status;
UCHAR CapabilityOffset;
//
// Read the PCI common header to get the capabilities pointer
//
Status = (pConfigFn)(Context,
TRUE,
PciConfig,
0,
sizeof(PCI_COMMON_HEADER));
if (!NT_SUCCESS(Status)) {
AGPLOG(AGP_CRITICAL,
("AgpLibGetAgpCapability - read PCI Config space for Context %08lx failed %08lx\n",
Context,
Status));
return(Status);
}
//
// Check the Status register to see if this device supports capability lists.
// If not, it is not an AGP-compliant device.
//
if ((PciConfig->Status & PCI_STATUS_CAPABILITIES_LIST) == 0) {
AGPLOG(AGP_CRITICAL,
("AgpLibGetAgpCapability - Context %08lx does not support Capabilities list, not an AGP device\n",
Context));
return(STATUS_NOT_IMPLEMENTED);
}
//
// The device supports capability lists, find the AGP capabilities
//
if ((PciConfig->HeaderType & (~PCI_MULTIFUNCTION)) == PCI_BRIDGE_TYPE) {
CapabilityOffset = PciConfig->u.type1.CapabilitiesPtr;
} else {
ASSERT((PciConfig->HeaderType & (~PCI_MULTIFUNCTION)) == PCI_DEVICE_TYPE);
CapabilityOffset = PciConfig->u.type0.CapabilitiesPtr;
}
while (CapabilityOffset != 0) {
//
// Read the Capability at this offset
//
Status = (pConfigFn)(Context,
TRUE,
Capability,
CapabilityOffset,
sizeof(PCI_CAPABILITIES_HEADER));
if (!NT_SUCCESS(Status)) {
AGPLOG(AGP_CRITICAL,
("AgpLibGetAgpCapability - read PCI Capability at offset %x for Context %08lx failed %08lx\n",
CapabilityOffset,
Context,
Status));
return(Status);
}
if (Capability->Header.CapabilityID == PCI_CAPABILITY_ID_AGP) {
//
// Found the AGP Capability
//
break;
} else {
//
// This is some other Capability, keep looking for the AGP Capability
//
CapabilityOffset = Capability->Header.Next;
}
}
if (CapabilityOffset == 0) {
//
// No AGP capability was found
//
AGPLOG(AGP_CRITICAL,
("AgpLibGetAgpCapability - Context %08lx does have an AGP Capability entry, not an AGP device\n",
Context));
return(STATUS_NOT_IMPLEMENTED);
}
AGPLOG(AGP_NOISE,
("AgpLibGetAgpCapability - Context %08lx has AGP Capability at offset %x\n",
Context,
CapabilityOffset));
*pOffset = CapabilityOffset;
if (PciCommonConfig) {
RtlCopyMemory(PciCommonConfig, PciConfig, sizeof(PCI_COMMON_HEADER));
}
return(STATUS_SUCCESS);
}
NTSTATUS
AgpLibGetAgpCapability(
IN PAGP_GETSET_CONFIG_SPACE pConfigFn,
IN PVOID Context,
IN BOOLEAN DoSpecial,
OUT PPCI_AGP_CAPABILITY Capability
)
/*++
Routine Description:
This routine finds and retrieves the AGP capabilities in the
PCI config space of the AGP master (graphics card).
Arguments:
pConfigFn - Supplies the function to call for accessing config space
on the appropriate device.
Context - Supplies the context to pass to pConfigFn
DoSpecial - Indicates whether we should apply any "pecial" tweaks
Capabilities - Returns the current AGP Capabilities
Return Value:
NTSTATUS
--*/
{
NTSTATUS Status;
ULONGLONG DeviceFlags;
UCHAR CapabilityOffset;
PCI_COMMON_HEADER Header;
USHORT SubVendorID, SubSystemID;
PPCI_COMMON_CONFIG PciConfig = (PPCI_COMMON_CONFIG)&Header;
Status = ApFindAgpCapability(pConfigFn,
Context,
Capability,
&CapabilityOffset,
PciConfig);
if (!NT_SUCCESS(Status)) {
return(Status);
}
//
// Read the rest of the AGP capability
//
Status = (pConfigFn)(Context,
TRUE,
&Capability->Header + 1,
CapabilityOffset + sizeof(PCI_CAPABILITIES_HEADER),
sizeof(PCI_AGP_CAPABILITY) - sizeof(PCI_CAPABILITIES_HEADER));
if (!NT_SUCCESS(Status)) {
AGPLOG(AGP_CRITICAL,
("AgpLibGetAgpCapability - read AGP Capability at offset %x for Context %08lx failed %08lx\n",
CapabilityOffset,
Context,
Status));
return(Status);
}
//
// Check device flags for broken HW, we may need to tweak caps
//
if ((PCI_CONFIGURATION_TYPE(PciConfig) == PCI_DEVICE_TYPE) &&
(PciConfig->BaseClass != PCI_CLASS_BRIDGE_DEV)) {
SubVendorID = PciConfig->u.type0.SubVendorID;
SubSystemID = PciConfig->u.type0.SubSystemID;
} else {
SubVendorID = 0;
SubSystemID = 0;
}
DeviceFlags = AgpGetDeviceFlags(AgpGlobalHackTable,
PciConfig->VendorID,
PciConfig->DeviceID,
SubVendorID,
SubSystemID,
PciConfig->RevisionID);
DeviceFlags |= AgpGetDeviceFlags(AgpDeviceHackTable,
PciConfig->VendorID,
PciConfig->DeviceID,
SubVendorID,
SubSystemID,
PciConfig->RevisionID);
if (DeviceFlags & AGP_FLAG_NO_1X_RATE) {
Capability->AGPStatus.Rate &= ~PCI_AGP_RATE_1X;
AGPLOG(AGP_WARNING,
("AGP HAMMER CAPS: NO_1X_RATE Vendor %x, Device %x.\n",
PciConfig->VendorID,
PciConfig->DeviceID));
}
if (DeviceFlags & AGP_FLAG_NO_2X_RATE) {
Capability->AGPStatus.Rate &= ~PCI_AGP_RATE_2X;
AGPLOG(AGP_WARNING,
("AGP HAMMER CAPS: NO_2X_RATE Vendor %x, Device %x.\n",
PciConfig->VendorID,
PciConfig->DeviceID));
}
if (DeviceFlags & AGP_FLAG_NO_4X_RATE) {
Capability->AGPStatus.Rate &= ~PCI_AGP_RATE_4X;
AGPLOG(AGP_WARNING,
("AGP HAMMER CAPS: NO_4X_RATE Vendor %x, Device %x.\n",
PciConfig->VendorID,
PciConfig->DeviceID));
}
if (DeviceFlags & AGP_FLAG_NO_8X_RATE) {
Capability->AGPStatus.Rate &= ~8;
AGPLOG(AGP_WARNING,
("AGP HAMMER CAPS: NO_8X_RATE Vendor %x, Device %x.\n",
PciConfig->VendorID,
PciConfig->DeviceID));
}
if (DeviceFlags & AGP_FLAG_NO_SBA_ENABLE) {
Capability->AGPStatus.SideBandAddressing = 0;
AGPLOG(AGP_WARNING,
("AGP HAMMER CAPS: NO_SBA_ENABLE Vendor %x, Device %x.\n",
PciConfig->VendorID,
PciConfig->DeviceID));
}
if (DeviceFlags & AGP_FLAG_REVERSE_INITIALIZATION) {
AGPLOG(AGP_WARNING,
("AGP GLOBAL HACK: REVERSE_INITIALIZATION Vendor %x, "
"Device %x.\n",
PciConfig->VendorID,
PciConfig->DeviceID));
}
//
// Test if this device requires any platform specific AGP tweaks
//
if (DoSpecial && (DeviceFlags > AGP_FLAG_SPECIAL_TARGET) ||
(DeviceFlags & AGP_FLAG_REVERSE_INITIALIZATION)) {
AgpSpecialTarget(GET_AGP_CONTEXT_FROM_MASTER((PMASTER_EXTENSION)Context), ((DeviceFlags & ~AGP_FLAG_SPECIAL_TARGET) | (DeviceFlags & AGP_FLAG_REVERSE_INITIALIZATION)));
}
AGPLOG(AGP_NOISE,
("AGP CAPABILITY: version %d.%d\n",Capability->Major, Capability->Minor));
AGPLOG(AGP_NOISE,
("\tSTATUS - Rate: %x SBA: %x RQ: %02x\n",
Capability->AGPStatus.Rate,
Capability->AGPStatus.SideBandAddressing,
Capability->AGPStatus.RequestQueueDepthMaximum));
AGPLOG(AGP_NOISE,
("\tCOMMAND - Rate: %x SBA: %x RQ: %02x AGPEnable: %x\n",
Capability->AGPCommand.Rate,
Capability->AGPCommand.SBAEnable,
Capability->AGPCommand.RequestQueueDepth,
Capability->AGPCommand.AGPEnable));
return(STATUS_SUCCESS);
}
NTSTATUS
AgpLibGetTargetCapability(
IN PVOID AgpExtension,
OUT PPCI_AGP_CAPABILITY Capability
)
/*++
Routine Description:
Retrieves the AGP capability for the AGP target (AGP bridge)
Arguments:
AgpExtension - Supplies the AGP extension
Capability - Returns the AGP capability
Return Value:
NTSTATUS
--*/
{
PTARGET_EXTENSION Extension;
GET_TARGET_EXTENSION(Extension, AgpExtension);
return(AgpLibGetAgpCapability(ApGetSetDeviceBusData,
Extension,
FALSE,
Capability));
}
NTSTATUS
AgpLibGetMasterCapability(
IN PVOID AgpExtension,
OUT PPCI_AGP_CAPABILITY Capability
)
/*++
Routine Description:
Retrieves the AGP capability for the AGP master (graphics card)
Arguments:
AgpExtension - Supplies the AGP extension
Capability - Returns the AGP capability
Return Value:
NTSTATUS
--*/
{
PMASTER_EXTENSION Extension;
GET_MASTER_EXTENSION(Extension, AgpExtension);
return(AgpLibGetAgpCapability(ApGetSetDeviceBusData,
Extension,
TRUE,
Capability));
}
NTSTATUS
AgpLibGetPciDeviceCapability(
IN ULONG BusId,
IN ULONG SlotId,
OUT PPCI_AGP_CAPABILITY Capability
)
/*++
Routine Description:
Retrieves the AGP capability for the specified PCI slot.
Caller is responsible for figuring out what the correct
Bus/Slot ID is. These are just passed right to HalGetBusData.
Arguments:
BusId - supplies the bus id
SlotId - Supplies the slot id
Capability - Returns the AGP capability
Return Value:
NTSTATUS
--*/
{
BUS_SLOT_ID BusSlotId;
BusSlotId.BusId = BusId;
BusSlotId.SlotId = SlotId;
return(AgpLibGetAgpCapability(ApGetSetBusData,
&BusSlotId,
FALSE,
Capability));
}
NTSTATUS
AgpLibSetAgpCapability(
IN PAGP_GETSET_CONFIG_SPACE pConfigFn,
IN PVOID Context,
OUT PPCI_AGP_CAPABILITY Capability
)
/*++
Routine Description:
This routine finds and retrieves the AGP capabilities in the
PCI config space of the AGP master (graphics card).
Arguments:
pConfigFn - Supplies the function to call for accessing config space
on the appropriate device.
Context - Supplies the context to pass to pConfigFn
Capabilities - Returns the current AGP Capabilities
Return Value:
NTSTATUS
--*/
{
NTSTATUS Status;
UCHAR CapabilityOffset;
Status = ApFindAgpCapability(pConfigFn,
Context,
Capability,
&CapabilityOffset,
NULL);
if (!NT_SUCCESS(Status)) {
return(Status);
}
//
// Now that we know the offset, write the supplied command register
//
Status = (pConfigFn)(Context,
FALSE,
&Capability->AGPCommand,
CapabilityOffset + FIELD_OFFSET(PCI_AGP_CAPABILITY, AGPCommand),
sizeof(Capability->AGPCommand));
if (!NT_SUCCESS(Status)) {
AGPLOG(AGP_CRITICAL,
("AgpLibSetAgpCapability - Set AGP command at offset %x for Context %08lx failed %08lx\n",
CapabilityOffset,
Context,
Status));
return(Status);
}
return(STATUS_SUCCESS);
}
NTSTATUS
AgpLibSetTargetCapability(
IN PVOID AgpExtension,
OUT PPCI_AGP_CAPABILITY Capability
)
/*++
Routine Description:
Sets the AGP capability for the AGP target (AGP bridge)
Arguments:
AgpExtension - Supplies the AGP extension
Capability - Returns the AGP capability
Return Value:
NTSTATUS
--*/
{
PTARGET_EXTENSION Extension;
GET_TARGET_EXTENSION(Extension, AgpExtension);
return(AgpLibSetAgpCapability(ApGetSetDeviceBusData,
Extension,
Capability));
}
NTSTATUS
AgpLibSetMasterCapability(
IN PVOID AgpExtension,
OUT PPCI_AGP_CAPABILITY Capability
)
/*++
Routine Description:
Sets the AGP capability for the AGP master (graphics card)
Arguments:
AgpExtension - Supplies the AGP extension
Capability - Returns the AGP capability
Return Value:
NTSTATUS
--*/
{
PMASTER_EXTENSION Extension;
GET_MASTER_EXTENSION(Extension, AgpExtension);
return(AgpLibSetAgpCapability(ApGetSetDeviceBusData,
Extension,
Capability));
}
NTSTATUS
AgpLibSetPciDeviceCapability(
IN ULONG BusId,
IN ULONG SlotId,
OUT PPCI_AGP_CAPABILITY Capability
)
/*++
Routine Description:
Sets the AGP capability for the specified PCI slot.
Caller is responsible for figuring out what the correct
Bus/Slot ID is. These are just passed right to HalSetBusData.
Arguments:
BusId - supplies the bus id
SlotId - Supplies the slot id
Capability - Returns the AGP capability
Return Value:
NTSTATUS
--*/
{
BUS_SLOT_ID BusSlotId;
BusSlotId.BusId = BusId;
BusSlotId.SlotId = SlotId;
return(AgpLibSetAgpCapability(ApGetSetBusData,
&BusSlotId,
Capability));
}
NTSTATUS
AgpLibGetMasterDeviceId(
IN PVOID AgpExtension,
OUT PULONG DeviceId
)
/*++
Routine Description:
This function returns the PCI DeviceId/Vendo58rId of the master AGP
device
Arguments:
DeviceId - Identifies PCI manufaturer and device of master
Return Value:
STATUS_SUCCESS or an appropriate error status
--*/
{
PCI_COMMON_HEADER Header;
PPCI_COMMON_CONFIG PciConfig = (PPCI_COMMON_CONFIG)&Header;
NTSTATUS Status;
PMASTER_EXTENSION Master = NULL;
PTARGET_EXTENSION Target = NULL;
//
// Try to make this as idiot proof as possible for the case
// where this is called from SetAperture on a system without
// an AGP adapter, so we don't AV if some context hasn't been
// initialized, or is missing...
//
Target = CONTAINING_RECORD(AgpExtension,
TARGET_EXTENSION,
AgpContext);
if (Target) {
if (Target->CommonExtension.Signature == TARGET_SIG) {
if (Target->ChildDevice) {
if (Target->ChildDevice->CommonExtension.Signature ==
MASTER_SIG) {
Master = Target->ChildDevice;
}
}
}
}
if (Master) {
//
// Read the PCI common header to get the capabilities pointer
//
Status = (ApGetSetDeviceBusData)((PCOMMON_EXTENSION)Master,
TRUE,
PciConfig,
0,
sizeof(PCI_COMMON_HEADER));
if (!NT_SUCCESS(Status)) {
AGPLOG(AGP_CRITICAL,
("AgpLibGetMasterDeviceId - read PCI Config space for Context %08lx failed %08lx\n",
Master,
Status));
return Status;
}
*DeviceId = *(PULONG)PciConfig;
} else {
*DeviceId = (ULONG)-1;
}
return STATUS_SUCCESS;
}