www.pudn.com > PlxSdk.rar > PciSupport.c
/*******************************************************************************
* Copyright (c) 2007 PLX Technology, Inc.
*
* PLX Technology Inc. licenses this software under specific terms and
* conditions. Use of any of the software or derviatives thereof in any
* product without a PLX Technology chip is strictly prohibited.
*
* PLX Technology, Inc. provides this software AS IS, WITHOUT ANY WARRANTY,
* EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, ANY WARRANTY OF
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. PLX makes no guarantee
* or representations regarding the use of, or the results of the use of,
* the software and documentation in terms of correctness, accuracy,
* reliability, currentness, or otherwise; and you rely on the software,
* documentation and results solely at your own risk.
*
* IN NO EVENT SHALL PLX BE LIABLE FOR ANY LOSS OF USE, LOSS OF BUSINESS,
* LOSS OF PROFITS, INDIRECT, INCIDENTAL, SPECIAL OR CONSEQUENTIAL DAMAGES
* OF ANY KIND. IN NO EVENT SHALL PLX'S TOTAL LIABILITY EXCEED THE SUM
* PAID TO PLX FOR THE PRODUCT LICENSED HEREUNDER.
*
******************************************************************************/
/******************************************************************************
*
* File Name:
*
* PciSupport.c
*
* Description:
*
* This file contains the PCI support functions
*
* Revision History:
*
* 02-01-07 : PLX SDK v5.00
*
******************************************************************************/
#include "PciSupport.h"
/***********************************************
* Globals
**********************************************/
// Global ECAM 64-bit address from ACPI table (0=Not Probed, -1=Not Available)
static U32 Gbl_Acpi_Addr_ECAM[2] = {ACPI_PCIE_NOT_PROBED, ACPI_PCIE_NOT_PROBED};
/******************************************************************************
*
* Function : PlxPciRegisterRead
*
* Description: Reads a PCI register at the specified offset
*
******************************************************************************/
RETURN_CODE
PlxPciRegisterRead(
U8 bus,
U8 slot,
U8 function,
U16 offset,
U32 *pValue
)
{
int rc;
U32 RegValue;
struct pci_dev *pPciDevice;
// For PCIe extended register, use Enhanced PCIe Mechanism
if (offset >= 0x100)
{
return PlxPciExpressRegRead(
bus,
slot,
function,
offset,
pValue
);
}
// Offset must on a 4-byte boundary
if (offset & 0x3)
{
*pValue = (U32)-1;
return ApiInvalidOffset;
}
// Locate PCI device
pPciDevice =
pci_find_slot(
bus,
PCI_DEVFN(slot, function)
);
if (pPciDevice == NULL)
{
DebugPrintf((
"ERROR - Device at bus %02d, slot %02d does not exist\n",
bus, slot
));
*pValue = (U32)-1;
return ApiInvalidDeviceInfo;
}
rc =
pci_read_config_dword(
pPciDevice,
offset,
&RegValue
);
if (rc != 0)
{
DebugPrintf((
"ERROR - Unable to read PCI register 0x%02x\n",
offset
));
*pValue = (U32)-1;
return ApiConfigAccessFailed;
}
*pValue = RegValue;
return ApiSuccess;
}
/******************************************************************************
*
* Function : PlxPciRegisterWrite
*
* Description: Writes a value to a PCI register at the specified offset
*
******************************************************************************/
RETURN_CODE
PlxPciRegisterWrite(
U8 bus,
U8 slot,
U8 function,
U16 offset,
U32 value
)
{
int rc;
struct pci_dev *pPciDevice;
// For PCIe extended register, use Enhanced PCIe Mechanism
if (offset >= 0x100)
{
return PlxPciExpressRegWrite(
bus,
slot,
function,
offset,
value
);
}
// Offset must on a 4-byte boundary
if (offset & 0x3)
{
return ApiInvalidOffset;
}
// Locate PCI device
pPciDevice =
pci_find_slot(
bus,
PCI_DEVFN(slot, function)
);
if (pPciDevice == NULL)
{
DebugPrintf((
"ERROR - Device at bus %02d, slot %02d does not exist\n",
bus, slot
));
return ApiInvalidDeviceInfo;
}
rc =
pci_write_config_dword(
pPciDevice,
offset,
value
);
if (rc != 0)
{
DebugPrintf((
"ERROR - Unable to write to PCI register 0x%02x\n",
offset
));
return ApiConfigAccessFailed;
}
return ApiSuccess;
}
/******************************************************************************
*
* Function : PlxPciExpressRegRead
*
* Description: Reads a PCI Express register using the enhanced configuration mechanism
*
*****************************************************************************/
RETURN_CODE
PlxPciExpressRegRead(
U8 bus,
U8 slot,
U8 function,
U16 offset,
U32 *pValue
)
{
U32 address;
// Offset must on a 4-byte boundary
if (offset & 0x3)
{
return ApiInvalidOffset;
}
// Check if PCIe ECAM was probed for
if (Gbl_Acpi_Addr_ECAM[0] == ACPI_PCIE_NOT_PROBED)
PlxProbeForEcamBase();
// Check if Enhanced mechanism available through ACPI
if (Gbl_Acpi_Addr_ECAM[0] == ACPI_PCIE_NOT_AVAILABLE)
{
*pValue = (U32)-1;
return ApiUnsupportedFunction;
}
// Setup base address for register access
address =
Gbl_Acpi_Addr_ECAM[0] |
(bus << 20) |
(slot << 15) |
(function << 12) |
(offset << 0);
// Read the register
*pValue = PHYS_MEM_READ_32(address);
return ApiSuccess;
}
/******************************************************************************
*
* Function : PlxPciExpressRegWrite
*
* Description: Writes a PCI Express register using the enhanced configuration mechanism
*
*****************************************************************************/
RETURN_CODE
PlxPciExpressRegWrite(
U8 bus,
U8 slot,
U8 function,
U16 offset,
U32 value
)
{
U32 address;
// Offset must on a 4-byte boundary
if (offset & 0x3)
{
return ApiInvalidOffset;
}
// Check if PCIe ECAM was probed for
if (Gbl_Acpi_Addr_ECAM[0] == ACPI_PCIE_NOT_PROBED)
PlxProbeForEcamBase();
// Check if Enhanced mechanism available through ACPI
if (Gbl_Acpi_Addr_ECAM[0] == ACPI_PCIE_NOT_AVAILABLE)
{
return ApiUnsupportedFunction;
}
// Setup base address for register access
address =
Gbl_Acpi_Addr_ECAM[0] |
(bus << 20) |
(slot << 15) |
(function << 12) |
(offset << 0);
// Write the register
PHYS_MEM_WRITE_32(address, value);
return ApiSuccess;
}
/******************************************************************************
*
* Function : PlxProbeForEcamBase
*
* Description: Probes for Enhanced Configuration Access Mechanism base
* address through ACPI
*
*****************************************************************************/
VOID
PlxProbeForEcamBase(
VOID
)
{
U8 Str_ID[9];
U32 Entry;
U32 address;
U32 value;
U32 NumEntries;
U32 Acpi_Addr_RSDP;
U32 Acpi_Addr_RSDT;
BOOLEAN bFound;
ACPI_RSDT_v1_0 Acpi_Rsdt;
// Added for compiler warning
Acpi_Addr_RSDP = 0;
// Default to ACPI and/or ECAM not detected
Gbl_Acpi_Addr_ECAM[0] = ACPI_PCIE_NOT_AVAILABLE;
// Mark end of string
Str_ID[8] = '\0';
// Setup starting address on 16-byte boundary
address = BIOS_MEM_START;
address = (address + 0xF) & ~0xF;
bFound = FALSE;
// Scan system ROM for ACPI RSDP pointer
do
{
// Read 8-bytes
*(U32*)Str_ID = PHYS_MEM_READ_32(address);
*(U32*)(Str_ID + 4) = PHYS_MEM_READ_32(address + 4);
// Check for header signature
if (memcmp(
"RSD PTR ",
Str_ID,
8 // 8 bytes
) == 0)
{
// Store ACPI RSDP table address
Acpi_Addr_RSDP = address;
bFound = TRUE;
}
else
{
// Increment to next 16-byte boundary
address += 16;
}
}
while (!bFound && (address <= BIOS_MEM_END));
if (!bFound)
{
DebugPrintf(("ACPI Probe - ACPI not detected\n"));
return;
}
DebugPrintf((
"ACPI Probe - 'RSD PTR ' found at 0x%08X\n",
Acpi_Addr_RSDP
));
// Store RSDT address
Acpi_Addr_RSDT = PHYS_MEM_READ_32(Acpi_Addr_RSDP + 16);
// Get RSDT size
Acpi_Rsdt.Length = PHYS_MEM_READ_32(Acpi_Addr_RSDT + 4);
if (Acpi_Rsdt.Length == 0)
{
DebugPrintf(("ACPI Probe - Unable to read RSDT table length\n"));
return;
}
// Calculate number of entries
NumEntries = (Acpi_Rsdt.Length - sizeof(ACPI_RSDT_v1_0)) / sizeof(U32);
if (NumEntries > 20)
{
DebugPrintf(("ACPI Probe - Unable to determine number of entries in RSDT table\n"));
return;
}
DebugPrintf((
"ACPI Probe - RSDT table at 0x%08X has %d entries\n",
Acpi_Addr_RSDT,
NumEntries
));
// Get address of first entry
Entry = Acpi_Addr_RSDT + sizeof(ACPI_RSDT_v1_0);
bFound = FALSE;
// Parse entry pointers for MCFG table
while ((bFound == FALSE) && (NumEntries != 0))
{
// Get address of entry
address = PHYS_MEM_READ_32(Entry);
// Get table signature
value = PHYS_MEM_READ_32(address);
DebugPrintf((
"ACPI Probe - Located '%c%c%c%c' table at 0x%08X\n",
(char)(value >> 0),
(char)(value >> 8),
(char)(value >> 16),
(char)(value >> 24),
address
));
// Check if MCFG table
if (memcmp(
"MCFG",
&value,
sizeof(U32)
) == 0)
{
// Get 64-bit base address of Enhanced Config Access Mechanism
Gbl_Acpi_Addr_ECAM[0] = PHYS_MEM_READ_32(address + 44);
Gbl_Acpi_Addr_ECAM[1] = PHYS_MEM_READ_32(address + 48);
bFound = TRUE;
}
else
{
// Get address of next entry
Entry += sizeof(U32);
// Decrement count
NumEntries--;
}
}
if (bFound)
{
DebugPrintf((
"ACPI Probe - PCIe ECAM is located at 0x%08X_%08X\n",
Gbl_Acpi_Addr_ECAM[1], Gbl_Acpi_Addr_ECAM[0]
));
}
else
{
DebugPrintf((
"ACPI Probe - MCFG entry not found (PCIe ECAM not supported)\n"
));
}
}
/******************************************************************************
*
* Function : PlxPhysicalMemRead
*
* Description: Maps a memory location and performs a read from it
*
*****************************************************************************/
U32
PlxPhysicalMemRead(
U32 address,
U8 size
)
{
U32 value;
VOID *KernelVa;
// Map address into kernel space
KernelVa =
ioremap(
address,
sizeof(U32)
);
if (KernelVa == NULL)
{
DebugPrintf(("ERROR: Unable to map address into kernel space\n"));
return -1;
}
// Read memory
switch (size)
{
case sizeof(U8):
value = *(U8*)KernelVa;
break;
case sizeof(U16):
value = *(U16*)KernelVa;
break;
case sizeof(U32):
value = *(U32*)KernelVa;
break;
default:
value = 0;
}
// Release the mapping
iounmap(
KernelVa
);
return value;
}
/******************************************************************************
*
* Function : PlxPhysicalMemWrite
*
* Description: Maps a memory location and performs a write to it
*
*****************************************************************************/
U32
PlxPhysicalMemWrite(
U32 address,
U32 value,
U8 size
)
{
VOID *KernelVa;
// Map address into kernel space
KernelVa =
ioremap(
address,
sizeof(U32)
);
if (KernelVa == NULL)
{
DebugPrintf(("ERROR: Unable to map address into kernel space\n"));
return -1;
}
// Write memory
switch (size)
{
case sizeof(U8):
*(U8*)KernelVa = (U8)value;
break;
case sizeof(U16):
*(U16*)KernelVa = (U16)value;
break;
case sizeof(U32):
*(U32*)KernelVa = (U32)value;
break;
}
// Release the mapping
iounmap(
KernelVa
);
return 0;
}