380 lines
11 KiB
C
380 lines
11 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1999 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
init.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module contains the initialization code for AGP460.SYS.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Naga Gurumoorthy 6/11/1999
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "agp460.h"
|
|||
|
|
|||
|
ULONG AgpExtensionSize = sizeof(AGP460_EXTENSION);
|
|||
|
PAGP_FLUSH_PAGES AgpFlushPages;
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
AgpInitializeTarget(
|
|||
|
IN PVOID AgpExtension
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Entrypoint for target initialization. This is called first.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
AgpExtension - Supplies the AGP extension
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
ULONG DeviceVendorID = 0;
|
|||
|
PAGP460_EXTENSION Extension = AgpExtension;
|
|||
|
|
|||
|
AGPLOG(AGP_NOISE, ("AGP460: AgpInitializeTarget entered.\n"));
|
|||
|
|
|||
|
//
|
|||
|
// Initialize our Extension
|
|||
|
//
|
|||
|
RtlZeroMemory(Extension, sizeof(AGP460_EXTENSION));
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// TO DO: Check the Device & Vendor ID for 82460GX. - Naga G
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// Initialize our chipset-specific extension
|
|||
|
//
|
|||
|
Extension->ApertureStart.QuadPart = 0;
|
|||
|
Extension->ApertureLength = 0;
|
|||
|
Extension->Gart = NULL;
|
|||
|
Extension->GartLength = 0;
|
|||
|
Extension->GlobalEnable = FALSE;
|
|||
|
Extension->ChipsetPageSize = PAGESIZE_460GX_CHIPSET;
|
|||
|
Extension->GartPhysical.QuadPart = 0;
|
|||
|
Extension->bSupportMultipleAGPDevices = FALSE;
|
|||
|
Extension->bSupportsCacheCoherency = TRUE;
|
|||
|
Extension->SpecialTarget = 0;
|
|||
|
|
|||
|
AgpFlushPages = Agp460FlushPages;
|
|||
|
|
|||
|
AGPLOG(AGP_NOISE, ("AGP460: Leaving AgpInitializeTarget.\n"));
|
|||
|
|
|||
|
return(STATUS_SUCCESS);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
AgpInitializeMaster(
|
|||
|
IN PVOID AgpExtension,
|
|||
|
OUT ULONG *AgpCapabilities
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Entrypoint for master initialization. This is called after target initialization
|
|||
|
and should be used to initialize the AGP capabilities of both master and target.
|
|||
|
|
|||
|
This is also called when the master transitions into the D0 state.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
AgpExtension - Supplies the AGP extension
|
|||
|
|
|||
|
AgpCapabilities - Returns the capabilities of this AGP device.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS Status;
|
|||
|
PCI_AGP_CAPABILITY MasterCap;
|
|||
|
PCI_AGP_CAPABILITY TargetCap;
|
|||
|
PAGP460_EXTENSION Extension = AgpExtension;
|
|||
|
ULONG SBAEnable;
|
|||
|
ULONG DataRate;
|
|||
|
ULONG FastWrite;
|
|||
|
ULONG CBN;
|
|||
|
BOOLEAN ReverseInit;
|
|||
|
|
|||
|
#if DBG
|
|||
|
PCI_AGP_CAPABILITY CurrentCap;
|
|||
|
#endif
|
|||
|
|
|||
|
AGPLOG(AGP_NOISE, ("AGP460: AgpInitializeMaster entered.\n"));
|
|||
|
|
|||
|
//
|
|||
|
// VERY IMPORTANT: In 82460GX, the GART is not part of the main memory (though it
|
|||
|
// occupies a range in the address space) and is instead hanging off the GXB. This
|
|||
|
// will make accesses from the Graphics Card to the GART pretty fast. But, the price
|
|||
|
// we pay - processor can't access the GART. Therefore, we tell the rest of the
|
|||
|
// world that is NOT OK to map the physical addresses given by GART. Instead processor
|
|||
|
// accesses should use the MDL. This is done by setting the capabilities to 0.
|
|||
|
// - Naga G
|
|||
|
//
|
|||
|
*AgpCapabilities = 0;
|
|||
|
|
|||
|
//
|
|||
|
// Get the master and target AGP capabilities
|
|||
|
//
|
|||
|
Status = AgpLibGetMasterCapability(AgpExtension, &MasterCap);
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
AGPLOG(AGP_CRITICAL,
|
|||
|
("AGP460InitializeDevice - AgpLibGetMasterCapability failed %08lx\n"));
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Some broken cards (Matrox Millenium II "AGP") report no valid
|
|||
|
// supported transfer rates. These are not really AGP cards. They
|
|||
|
// have an AGP Capabilities structure that reports no capabilities.
|
|||
|
//
|
|||
|
if (MasterCap.AGPStatus.Rate == 0) {
|
|||
|
AGPLOG(AGP_CRITICAL,
|
|||
|
("AGP460InitializeDevice - AgpLibGetMasterCapability returned no valid transfer rate\n"));
|
|||
|
return(STATUS_INVALID_DEVICE_REQUEST);
|
|||
|
}
|
|||
|
|
|||
|
// We can't get the capability for bus 0, dev 0 in 460GX. it is the SAC & we want the
|
|||
|
// GXB (Target).
|
|||
|
//Status = AgpLibGetPciDeviceCapability(0,0,&TargetCap);
|
|||
|
|
|||
|
Read460CBN((PVOID)&CBN);
|
|||
|
// CBN is of one byte width, so zero out the other bits from 32-bits - Sunil
|
|||
|
EXTRACT_LSBYTE(CBN);
|
|||
|
|
|||
|
Status = AgpLibGetPciDeviceCapability(CBN,AGP460_GXB_SLOT_ID,&TargetCap);
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
AGPLOG(AGP_CRITICAL,
|
|||
|
("AGP460InitializeDevice - AgpLibGetPciDeviceCapability failed %08lx\n"));
|
|||
|
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);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// 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 = TRUE;
|
|||
|
MasterCap.AGPCommand.SBAEnable = SBAEnable;
|
|||
|
MasterCap.AGPCommand.FastWriteEnable = FastWrite;
|
|||
|
MasterCap.AGPCommand.FourGBEnable = FALSE;
|
|||
|
MasterCap.AGPCommand.RequestQueueDepth = TargetCap.AGPStatus.RequestQueueDepthMaximum;
|
|||
|
|
|||
|
Status = AgpLibSetMasterCapability(AgpExtension, &MasterCap);
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
AGPLOG(AGP_CRITICAL,
|
|||
|
("AGP460InitializeDevice - AgpLibSetMasterCapability %08lx failed %08lx\n",
|
|||
|
&MasterCap,
|
|||
|
Status));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Now enable the Target.
|
|||
|
//
|
|||
|
TargetCap.AGPCommand.Rate = DataRate;
|
|||
|
TargetCap.AGPCommand.AGPEnable = TRUE;
|
|||
|
TargetCap.AGPCommand.SBAEnable = SBAEnable;
|
|||
|
TargetCap.AGPCommand.FastWriteEnable = FastWrite;
|
|||
|
TargetCap.AGPCommand.FourGBEnable = FALSE;
|
|||
|
|
|||
|
Status = AgpLibSetPciDeviceCapability(CBN, AGP460_GXB_SLOT_ID, &TargetCap);
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
AGPLOG(AGP_CRITICAL,
|
|||
|
("AGP460InitializeDevice - AgpLibSetPciDeviceCapability %08lx for target failed %08lx\n",
|
|||
|
&TargetCap,
|
|||
|
Status));
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
|
|||
|
if (!ReverseInit) {
|
|||
|
MasterCap.AGPCommand.Rate = DataRate;
|
|||
|
MasterCap.AGPCommand.AGPEnable = TRUE;
|
|||
|
MasterCap.AGPCommand.SBAEnable = SBAEnable;
|
|||
|
MasterCap.AGPCommand.FastWriteEnable = FastWrite;
|
|||
|
MasterCap.AGPCommand.FourGBEnable = FALSE;
|
|||
|
MasterCap.AGPCommand.RequestQueueDepth = TargetCap.AGPStatus.RequestQueueDepthMaximum;
|
|||
|
|
|||
|
Status = AgpLibSetMasterCapability(AgpExtension, &MasterCap);
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
AGPLOG(AGP_CRITICAL,
|
|||
|
("AGP460InitializeDevice - AgpLibSetMasterCapability %08lx failed %08lx\n",
|
|||
|
&MasterCap,
|
|||
|
Status));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
#if DBG
|
|||
|
//
|
|||
|
// 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(0,0,&CurrentCap);
|
|||
|
Status = AgpLibGetPciDeviceCapability(CBN,AGP460_GXB_SLOT_ID,&CurrentCap);
|
|||
|
|
|||
|
ASSERT(NT_SUCCESS(Status));
|
|||
|
ASSERT(RtlEqualMemory(&CurrentCap.AGPCommand, &TargetCap.AGPCommand, sizeof(CurrentCap.AGPCommand)));
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
AGPLOG(AGP_NOISE, ("AGP460: Leaving AgpInitializeMaster.\n"));
|
|||
|
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
Agp460FlushPages(
|
|||
|
IN PAGP460_EXTENSION AgpContext,
|
|||
|
IN PMDL Mdl
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Flush entries in the GART. Currently a stub for
|
|||
|
Win64 version of 460GX filter driver. This flushing is done previously to
|
|||
|
avoid any caching issues due to the same memory aliased with different caching
|
|||
|
attributes. Now that is taken care by the memory manager calls themselves (Win64 only).
|
|||
|
Therefore we just have a stub so that nothing gets executed in the AGPLIB code. (see
|
|||
|
AGPLIB code for details)
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
AgpContext - Supplies the AGP context
|
|||
|
|
|||
|
Mdl - Supplies the MDL describing the physical pages to be flushed
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
AGPLOG(AGP_NOISE, ("AGP460: Entering AGPFlushPages.\n"));
|
|||
|
AGPLOG(AGP_NOISE, ("AGP460: Leaving AGPFlushPages.\n"));
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
void Read460CBN(PVOID _CBN_)
|
|||
|
{
|
|||
|
ULONG _len_;
|
|||
|
_len_ = HalGetBusDataByOffset(PCIConfiguration,
|
|||
|
AGP460_SAC_BUS_ID,
|
|||
|
AGP460_SAC_CBN_SLOT_ID,
|
|||
|
_CBN_,
|
|||
|
0x40,
|
|||
|
1);
|
|||
|
ASSERT(_len_ == 1);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void Read460Config(ULONG _CBN_,PVOID _buf_,ULONG _offset_,ULONG _size_)
|
|||
|
{
|
|||
|
ULONG _len_;
|
|||
|
_len_ = HalGetBusDataByOffset(PCIConfiguration,
|
|||
|
_CBN_,
|
|||
|
AGP460_GXB_SLOT_ID,
|
|||
|
_buf_,
|
|||
|
_offset_,
|
|||
|
_size_);
|
|||
|
ASSERT(_len_ == (_size_));
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void Write460Config(ULONG _CBN_,PVOID _buf_,ULONG _offset_,ULONG _size_)
|
|||
|
{
|
|||
|
ULONG _len_;
|
|||
|
_len_ = HalSetBusDataByOffset(PCIConfiguration,
|
|||
|
(_CBN_),
|
|||
|
AGP460_GXB_SLOT_ID,
|
|||
|
(_buf_),
|
|||
|
(_offset_),
|
|||
|
(_size_));
|
|||
|
ASSERT(_len_ == (_size_));
|
|||
|
return;
|
|||
|
}
|
|||
|
|