/* * Copyright (c) 2006-2008 Advanced Micro Devices,Inc. ("AMD"). * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of the * License, or (at your option) any later version. * * This code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * You should have received a copy of the GNU Lesser General * Public License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, MA 02111-1307 USA */ //***************************************************************************** //* Implements reads of virtualized PCI configuration headers //***************************************************************************** #include "VSA2.H" #include "PCI.H" #include "VPCI.H" #include "PROTOS.H" #include "SYSMGR.H" #include "CHIPSET.H" // External function declarations: ULONG pascal Get_Device_Status(PCI_HEADER_ENTRY *); ULONG pascal Handle_PCI_PM_Rd(PCI_HEADER_ENTRY *); ULONG pascal Handle_EHCI_Rd(PCI_HEADER_ENTRY *); ULONG pascal Read_MSR_LO(ULONG); UCHAR pascal Get_Latency(PCI_HEADER_ENTRY *); PCI_HEADER_ENTRY * pascal Get_Structure(USHORT); extern Hardware HardwareInfo; // External variable declarations: extern DESCRIPTOR MSRs[]; extern UCHAR Shift, AlignedReg, Function; extern PCI_HEADER_ENTRY * CommandPtr; extern ULONG ATA_Error; //*********************************************************************** // Reads an embedded PCI register //*********************************************************************** ULONG pascal Read_EPCI(UCHAR AlignedReg) { ULONG MsrAddr; MsrAddr = MSRs[CommandPtr->Link].MsrAddr; if (MsrAddr) { (UCHAR)MsrAddr = AlignedReg/4; return Read_MSR_LO(MsrAddr); } else { return 0; } } //*********************************************************************** // // This routine implements reads to virtualized configuration space. // // NOTES: // 1) Misaligned accesses are handled. If an access crosses a DWORD // boundary, only the bytes within the addressed DWORD are read. // The remaining bytes return FFs. // 2) The variable Pci points to a PCI_HEADER_ENTRY entry that defines // the state and characteristics of the register being read. //*********************************************************************** ULONG pascal Virtual_PCI_Read_Handler(USHORT PCI_Address) { ULONG Data; register PCI_HEADER_ENTRY * Pci; // Get ptr to virtualized table entry Pci = Get_Structure(PCI_Address); switch ((USHORT)Pci) { case UNIMPLEMENTED_FUNCTION: Data = 0xFFFFFFFF; break; case UNIMPLEMENTED_REGISTER: Data = 0x00000000; break; default: // Handle special cases if (Pci->Flag & EPCI_R && AlignedReg < 0x40) { // Embedded PCI device: read its h/w PCI configuration space Data = Read_EPCI(AlignedReg); if (AlignedReg == COMMAND) { // Mark device '66 MHz capable' Data |= PCI_66MHZ_CAPABLE; } break; } Data = Pci->Value; switch (AlignedReg) { case COMMAND: // Get device's Status Data |= Get_Device_Status(Pci); break; case BAR0: case BAR1: case BAR2: case BAR3: case BAR4: case BAR5: // If I/O BAR, set bit 0 if (Pci->Flag & IO_BAR) { Data |= 1; } break; case CACHE_LINE: Pci->LatencyTimer = Get_Latency(Pci); Data = Pci->Value; break; #if SUPPORT_CAPABILITIES case (PCI_PM_REG+4): // 0x44 if (Pci->Flag & PCI_PM) { Data = Handle_PCI_PM_Rd(Pci); break; } case USBLEGCTLSTS: if (Pci->Flag & PCI_EHCI) { Data = Handle_EHCI_Rd(Pci); break; } #endif // Thor ATA vendor-specific registers: case IDE_CFG: // 0x40 case IDE_DTC: // 0x48 case IDE_CAST: // 0x4C case IDE_ETC: // 0x50 if (Pci->LBar) { ULONG MsrAddr = ATA_Error; (USHORT)MsrAddr = (USHORT)Pci->LBar; Data = Read_MSR_LO(MsrAddr); } break; } } // Handle non-dword aligned accesses Data >>= Shift; Data |= 0xFFFFFFFFL << (32-Shift); return Data; }