windows-nt/Source/XPSP1/NT/base/busdrv/agp/agpcpq/init.c
2020-09-26 16:20:57 +08:00

432 lines
14 KiB
C

/*++
Copyright (c) 1996, 1997 Microsoft Corporation
Module Name:
init.c
Abstract:
This module contains the initialization code for the Compaq driver.
Author:
John Vert (jvert) 10/21/1997
Revision History:
12/15/97 John Theisen Modified to support Compaq Chipsets
10/09/98 John Theisen Modified to workaround an RCC silicon bug.
If RCC Silicon Rev <= 4, then limit DATA_RATE to 1X.
10/09/98 John Theisen Modified to enable Shadowing in the SP700 prior to MMIO writes.
01/15/98 John Theisen Modified to set RQ depth to be 0x0F for all REV_IDs
03/14/00 Peter Johnston Add support for HE chipset.
--*/
#include "AGPCPQ.H"
ULONG AgpExtensionSize = sizeof(AGPCPQ_EXTENSION);
PAGP_FLUSH_PAGES AgpFlushPages = NULL; // not implemented
NTSTATUS
AgpInitializeTarget(
IN PVOID AgpExtension
)
/*******************************************************************************
*
* Routine Functional Description:
*
* This function is the entrypoint for initialization of the AGP Target. It
* is called first, and performs initialization of the chipset and extension.
*
* Assumptions: Regardless of whether we are running on a dual north bridge platform,
* this driver will only be installed and invoked once (for the AGP bridge at B0D0F1).
*
* Arguments:
*
* AgpExtension -- Supplies the AGP Extension
*
* Return Value:
*
* STATUS_SUCCESS if successfull
*
*******************************************************************************/
{
ULONG DeviceVendorID = 0;
ULONG BAR1 = 0;
PAGPCPQ_EXTENSION Extension = AgpExtension;
PHYSICAL_ADDRESS pa;
ULONG BytesReturned = 0;
AGPLOG(AGP_NOISE, ("AgpCpq: AgpInitializeTarget entered.\n"));
//
// Initialize our Extension
//
RtlZeroMemory(Extension, sizeof(AGPCPQ_EXTENSION));
//
// Verify that the chipset is a supported RCC Chipset.
//
ReadCPQConfig(&DeviceVendorID,OFFSET_DEVICE_VENDOR_ID,sizeof(DeviceVendorID));
if ((DeviceVendorID != AGP_CNB20_LE_IDENTIFIER) &&
(DeviceVendorID != AGP_CNB20_HE_IDENTIFIER) &&
(DeviceVendorID != AGP_CNB20_HE4X_IDENTIFIER) &&
(DeviceVendorID != AGP_CMIC_GC_IDENTIFIER)) {
AGPLOG(AGP_CRITICAL,
("AGPCPQ - AgpInitializeTarget was called for platform %08x, which is not a known RCC AGP chipset!\n",
DeviceVendorID));
return(STATUS_UNSUCCESSFUL);
}
Extension->DeviceVendorID = DeviceVendorID;
//
// Read the chipset's BAR1 Register, and then map the chipset's
// Memory Mapped Control Registers into kernel mode address space.
//
ReadCPQConfig(&BAR1,OFFSET_BAR1,sizeof(BAR1));
pa.HighPart = 0;
pa.LowPart = BAR1;
Extension->MMIO = (PMM_CONTROL_REGS)MmMapIoSpace(pa, sizeof(MM_CONTROL_REGS), FALSE);
if (Extension->MMIO == NULL)
{
AGPLOG(AGP_CRITICAL,
("AgpInitializeTarget - Couldn't allocate %08x bytes for MMIO\n",
sizeof(MM_CONTROL_REGS)));
return(STATUS_UNSUCCESSFUL);
}
//
// Verify that the chipset's Revision ID is correct, but only complain, if it isn't.
//
if (Extension->MMIO->RevisionID < LOWEST_REVISION_ID_SUPPORTED)
{
AGPLOG(AGP_CRITICAL,
("AgpInitializeTarget - Revision ID = %08x, it should = 1.\n",
Extension->MMIO->RevisionID));
}
//
// Determine if there are two RCC North Bridges in this system.
//
DeviceVendorID = 0;
BytesReturned = HalGetBusDataByOffset(PCIConfiguration, SECONDARY_LE_BUS_ID, SECONDARY_LE_HOSTPCI_SLOT_ID,
&DeviceVendorID, OFFSET_DEVICE_VENDOR_ID, sizeof(DeviceVendorID));
if((DeviceVendorID != Extension->DeviceVendorID) || (BytesReturned != sizeof(DeviceVendorID)) ) {
Extension->IsHPSA = FALSE;
} else {
Extension->IsHPSA = TRUE;
}
//
// Enable the GART cache
//
if (Extension->IsHPSA) DnbSetShadowBit(0);
Extension->MMIO->FeatureControl.GARTCacheEnable = 1;
Extension->GartPointer = 0;
Extension->SpecialTarget = 0;
//
// If the chipset supports linking then enable linking.
//
if (Extension->MMIO->Capabilities.LinkingSupported==1) {
Extension->MMIO->FeatureControl.LinkingEnable=1;
}
if (Extension->IsHPSA) DnbSetShadowBit(1);
return(STATUS_SUCCESS);
}
NTSTATUS
AgpInitializeMaster(
IN PVOID AgpExtension,
OUT ULONG *AgpCapabilities
)
/*******************************************************************************
*
* Routine Functional Description:
*
* This function is the entrypoint for initialization of the AGP Master. It
* is called after Target initialization, and is intended to be used to
* initialize the AGP capabilities of both master and target.
*
* Arguments:
*
* AgpExtension -- Supplies the AGP Extension
*
* AgpCapabilities -- Returns the "software-visible" capabilities of the device
*
* Return Value:
*
* NTSTATUS
*
*******************************************************************************/
{
NTSTATUS Status;
PCI_AGP_CAPABILITY MasterCap;
PCI_AGP_CAPABILITY TargetCap;
PAGPCPQ_EXTENSION Extension = AgpExtension;
ULONG SBAEnable;
ULONG FastWrite;
ULONG DataRate;
UCHAR RevID = 0;
BOOLEAN ReverseInit;
AGPLOG(AGP_NOISE, ("AgpCpq: AgpInitializeMaster entered.\n"));
//
// Get the master and target AGP capabilities
//
Status = AgpLibGetMasterCapability(AgpExtension, &MasterCap);
if (!NT_SUCCESS(Status))
{
AGPLOG(AGP_CRITICAL,
("AGPCPQInitializeDevice - AgpLibGetMasterCapability failed %08lx\n",
Status));
return(Status);
}
Status = AgpLibGetPciDeviceCapability(AGP_CPQ_BUS_ID,
AGP_CPQ_PCIPCI_SLOT_ID,
&TargetCap);
if (!NT_SUCCESS(Status))
{
AGPLOG(AGP_CRITICAL,
("AGPCPQInitializeDevice - AgpLibGetPciDeviceCapability failed %08lx\n",
Status));
return(Status);
}
//
// Determine the greatest common denominator for data rate.
//
DataRate = TargetCap.AGPStatus.Rate & MasterCap.AGPStatus.Rate;
ASSERT(DataRate != 0);
//
// Select the highest common rate.
//
if (DataRate & PCI_AGP_RATE_4X) {
DataRate = PCI_AGP_RATE_4X;
} else if (DataRate & PCI_AGP_RATE_2X) {
DataRate = PCI_AGP_RATE_2X;
} else if (DataRate & PCI_AGP_RATE_1X) {
DataRate = PCI_AGP_RATE_1X;
}
//
// Previously a call was made to change the rate (successfully),
// use this rate again now
//
if (Extension->SpecialTarget & AGP_FLAG_SPECIAL_RESERVE) {
DataRate = (ULONG)((Extension->SpecialTarget &
AGP_FLAG_SPECIAL_RESERVE) >>
AGP_FLAG_SET_RATE_SHIFT);
}
//
// FIX RCC silicon bugs:
// If RevID <= 4, then the reported Data Rate is 2X but the chip only supports 1X.
// Regardless of RevID the reported RQDepth should be 0x0F.
//
if (Extension->DeviceVendorID == AGP_CNB20_LE_IDENTIFIER) {
ReadCPQConfig(&RevID, OFFSET_REV_ID, sizeof(RevID));
ASSERT(TargetCap.AGPStatus.RequestQueueDepthMaximum == 0x10);
TargetCap.AGPStatus.RequestQueueDepthMaximum = 0x0F;
if (RevID <= MAX_REV_ID_TO_LIMIT_1X) {
DataRate = PCI_AGP_RATE_1X;
}
}
//
// Enable SBA if both master and target support it.
//
SBAEnable = (TargetCap.AGPStatus.SideBandAddressing &
MasterCap.AGPStatus.SideBandAddressing);
//
// Enable FastWrite if both master and target support it.
//
FastWrite = (TargetCap.AGPStatus.FastWrite &
MasterCap.AGPStatus.FastWrite);
//
// Enable the Master first.
//
ReverseInit =
(Extension->SpecialTarget & AGP_FLAG_REVERSE_INITIALIZATION) ==
AGP_FLAG_REVERSE_INITIALIZATION;
if (ReverseInit) {
MasterCap.AGPCommand.Rate = DataRate;
MasterCap.AGPCommand.AGPEnable = 1;
MasterCap.AGPCommand.SBAEnable = SBAEnable;
MasterCap.AGPCommand.FastWriteEnable = FastWrite;
MasterCap.AGPCommand.RequestQueueDepth = TargetCap.AGPStatus.RequestQueueDepthMaximum;
Status = AgpLibSetMasterCapability(AgpExtension, &MasterCap);
if (!NT_SUCCESS(Status))
{
AGPLOG(AGP_CRITICAL,
("AGPCPQInitializeDevice - AgpLibSetMasterCapability %08lx failed %08lx\n",
&MasterCap,
Status));
}
}
//
// Now enable the Target.
//
TargetCap.AGPCommand.Rate = DataRate;
TargetCap.AGPCommand.AGPEnable = 1;
TargetCap.AGPCommand.SBAEnable = SBAEnable;
TargetCap.AGPCommand.FastWriteEnable = FastWrite;
Status = AgpLibSetPciDeviceCapability(AGP_CPQ_BUS_ID,
AGP_CPQ_PCIPCI_SLOT_ID,
&TargetCap);
if (!NT_SUCCESS(Status))
{
AGPLOG(AGP_CRITICAL,
("AGPCPQInitializeDevice - AgpLibSetPciDeviceCapability %08lx for target failed %08lx\n",
&TargetCap,
Status));
return(Status);
}
if (!ReverseInit) {
MasterCap.AGPCommand.Rate = DataRate;
MasterCap.AGPCommand.AGPEnable = 1;
MasterCap.AGPCommand.SBAEnable = SBAEnable;
MasterCap.AGPCommand.FastWriteEnable = FastWrite;
MasterCap.AGPCommand.RequestQueueDepth = TargetCap.AGPStatus.RequestQueueDepthMaximum;
Status = AgpLibSetMasterCapability(AgpExtension, &MasterCap);
if (!NT_SUCCESS(Status))
{
AGPLOG(AGP_CRITICAL,
("AGPCPQInitializeDevice - AgpLibSetMasterCapability %08lx failed %08lx\n",
&MasterCap,
Status));
}
}
#if DBG
{
PCI_AGP_CAPABILITY CurrentCap;
//
// Read them back, see if it worked
//
Status = AgpLibGetMasterCapability(AgpExtension, &CurrentCap);
ASSERT(NT_SUCCESS(Status));
//
// If the target request queue depth is greater than the master will
// allow, it will be trimmed. Loosen the assert to not require an
// exact match.
//
ASSERT(CurrentCap.AGPCommand.RequestQueueDepth <= MasterCap.AGPCommand.RequestQueueDepth);
CurrentCap.AGPCommand.RequestQueueDepth = MasterCap.AGPCommand.RequestQueueDepth;
ASSERT(RtlEqualMemory(&CurrentCap.AGPCommand, &MasterCap.AGPCommand, sizeof(CurrentCap.AGPCommand)));
Status = AgpLibGetPciDeviceCapability(AGP_CPQ_BUS_ID,
AGP_CPQ_PCIPCI_SLOT_ID,
&CurrentCap);
ASSERT(NT_SUCCESS(Status));
ASSERT(RtlEqualMemory(&CurrentCap.AGPCommand, &TargetCap.AGPCommand,
sizeof(CurrentCap.AGPCommand)));
}
#endif
//
// Indicate that we can map memory through the GART aperture
//
*AgpCapabilities = AGP_CAPABILITIES_MAP_PHYSICAL;
return(Status);
}
NTSTATUS
DnbSetShadowBit(
ULONG SetToOne
)
//
// This routine is required, (because of a new requirement in the RCC chipset.).
// When there are two NorthBridge's, the shadow bit must be set to 0 prior
// to any MMIO writes, and then set back to 1 when done.
//
{
NTSTATUS Status = STATUS_SUCCESS; // Assume Success
UCHAR ShadowByte = 0;
ULONG BytesReturned = 0;
ULONG length = 1;
if (SetToOne == 1) {
//
// Set the shadow bit to a one. (This disables shadowing.)
//
BytesReturned = HalGetBusDataByOffset(PCIConfiguration, SECONDARY_LE_BUS_ID,
SECONDARY_LE_HOSTPCI_SLOT_ID, &ShadowByte, OFFSET_SHADOW_BYTE, length);
if(BytesReturned != length) {
AGPLOG(AGP_CRITICAL,("ERROR: Failed to read shadow register!\n"));
Status = STATUS_UNSUCCESSFUL;
goto exit_routine;
}
ShadowByte |= FLAG_DISABLE_SHADOW;
HalSetBusDataByOffset(PCIConfiguration, SECONDARY_LE_BUS_ID,
SECONDARY_LE_HOSTPCI_SLOT_ID, &ShadowByte, OFFSET_SHADOW_BYTE, length);
if(BytesReturned != length) {
AGPLOG(AGP_CRITICAL,("ERROR: Failed to write shadow register!\n"));
Status = STATUS_UNSUCCESSFUL;
goto exit_routine;
}
} else {
//
// Set the shadow bit to a zero. (This enables shadowing.)
//
BytesReturned = HalGetBusDataByOffset(PCIConfiguration, SECONDARY_LE_BUS_ID,
SECONDARY_LE_HOSTPCI_SLOT_ID, &ShadowByte, OFFSET_SHADOW_BYTE, length);
if(BytesReturned != length) {
AGPLOG(AGP_CRITICAL,("ERROR: Failed to read shadow register!"));
Status = STATUS_UNSUCCESSFUL;
goto exit_routine;
}
ShadowByte &= MASK_ENABLE_SHADOW;
HalSetBusDataByOffset(PCIConfiguration, SECONDARY_LE_BUS_ID,
SECONDARY_LE_HOSTPCI_SLOT_ID, &ShadowByte, OFFSET_SHADOW_BYTE, length);
if(BytesReturned != length) {
AGPLOG(AGP_CRITICAL,("ERROR: Failed to write shadow register!"));
Status = STATUS_UNSUCCESSFUL;
goto exit_routine;
}
}
exit_routine:
return(Status);
}