/** * @file * * Routines for IOMMU. * * Implement the IOMMU init and ACPI feature. * * @xrefitem bom "File Content Label" "Release Content" * @e project: CIMx-NB * @e sub-project: * @e \$Revision:$ @e \$Date:$ * */ /***************************************************************************** * * Copyright (C) 2012 Advanced Micro Devices, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of Advanced Micro Devices, Inc. nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * ***************************************************************************/ // Identifying an IOMMU: // RD890S - IOMMU present // all other (including RD890) - IOMMU not present // Class = System Base Peripheral (08h) // Subclass = IOMMU (06h) // Programming Interface Code = 0h // Must reside on top/root complex PCI hierarchy // There is always a NB device at bus 0 device 0 function 0 (fcn 2 for IOMMU) - device ID 0x5A23 // Inputs: // From OEM: Get exclusion table // From OEM: Get text buffer // Outputs: // To OEM: Complete IVRS table for linking #ifndef _NBIOMMU_H_ #define _NBIOMMU_H_ /*---------------------------------------------------------------------------------------- * E X P O R T E D F U N C T I O N S *---------------------------------------------------------------------------------------- */ AGESA_STATUS NbIommuInit ( IN OUT AMD_NB_CONFIG_BLOCK *ConfigPtr ); AGESA_STATUS NbIommuInitS3 ( IN OUT AMD_NB_CONFIG_BLOCK *ConfigPtr ); AGESA_STATUS NbIommuAcpiInit ( IN OUT AMD_NB_CONFIG_BLOCK *ConfigPtr ); AGESA_STATUS NbIommuAcpiFixup ( IN OUT AMD_NB_CONFIG_BLOCK *ConfigPtr ); VOID NbIommuDisconnectPcieCore ( IN CORE CoreId, IN AMD_NB_CONFIG *pConfig ); /*---------------------------------------------------------------------------------------- * D E F I N I T I O N S A N D M A C R O S *---------------------------------------------------------------------------------------- */ // IOMMU Architectural #define IVRS_BUFFER_SIZE 0x2000 // Default 8KB allocated to table //#define IVHD_MIN_8BYTE_ALIGNMENT // Align IVHD entries on 8 byte boundary #define IVHD_SIZE_ALIGNMENT // Align IVHD entries on MOD entry-size boundary #define IVHD_HPET_SUPPORT // Create HPET entries #define IVHD_APIC_SUPPORT // Create IOAPIC entries // IOMMU Northbridge #define RD890S_CAP_MISC 0x50 // RD890/S Capabilities Misc Info #define NB_PCI_DEV 0 // PCI NB device number #define NB_HOST 0 // Function 0 = NB HOST #define NB_IOMMU 2 // Function 2 = IOMMU #define SB_DEV 0x14 // PCI SB device number #define SB_SMBUS 3 // Function 3 = SMBUS #define SB_SATA 0x11 // SB SATA #define SATA_ENABLE_REG 0xAD // Dev. 0x14, Func 0, Reg 0xAD for SATA combined mode #define SATA_COMBINED_MODE BIT3 // Bit 3 of SB_ENABLE_REG., 1 = Combined mode #define IOMMU_CAP_HEADER_OFFSET 0x00 #define IOMMU_BASE_LOW_OFFSET 0x04 #define IOMMU_BASE_HIGH_OFFSET 0x08 #define IOMMU_RANGE_OFFSET 0x0C #define IOMMU_MISC_OFFSET 0x10 #define DEVICEID_NB ((0 << 8) + (NB_PCI_DEV << 3) + NB_HOST) #define DEVICEID_IOMMU ((0 << 8) + (NB_PCI_DEV << 3) + NB_IOMMU) #define DEVICEID_GPP1_0 ((0 << 8) + (0x2 << 3) + 0) #define DEVICEID_GPP1_1 ((0 << 8) + (0x3 << 3) + 0) #define DEVICEID_GPP2_0 ((0 << 8) + (0xB << 3) + 0) #define DEVICEID_GPP2_1 ((0 << 8) + (0xC << 3) + 0) #define DEVICEID_GPP3A_0 ((0 << 8) + (0x4 << 3) + 0) #define DEVICEID_GPP3A_1 ((0 << 8) + (0x5 << 3) + 0) #define DEVICEID_GPP3A_2 ((0 << 8) + (0x6 << 3) + 0) #define DEVICEID_GPP3A_3 ((0 << 8) + (0x7 << 3) + 0) #define DEVICEID_GPP3A_4 ((0 << 8) + (0x9 << 3) + 0) #define DEVICEID_GPP3A_5 ((0 << 8) + (0xA << 3) + 0) #define DEVICEID_GPP3B_0 ((0 << 8) + (0xD << 3) + 0) #define DEVICEID_SATA ((0 << 8) + (0x11 << 3) + 0) #define DEVICEID_IDE ((0 << 8) + (0x14 << 3) + 1) #define L1CFG_INDEX 0xF8 // There is an L1 for each device (6), which is selected by [19:16] of L1CFG_INDEX // e.g. (LibNbPciIndexRead (Address | L1CFGIND, L1_REG_0C | L1_CFG_SEL, AccessWidth32, &Value, pConfig) #define L1CFG_SEL_WR_EN 0x80000000 #define L1CFG_SEL_GPP1 0x00000000 #define L1CFG_SEL_GPP2 0x00010000 #define L1CFG_SEL_SB 0x00020000 #define L1CFG_SEL_GPP3A 0x00030000 #define L1CFG_SEL_GPP3B 0x00040000 #define L1CFG_SEL_VC1 0x00050000 #define L1REG_06 0x6 #define L1REG_0C 0xC #define L1REG_0D 0xD #define L1REG_07 0x7 #define L1CFG_DATA 0xFC #define L2CFG_INDEX 0xF0 // e.g. (LibNbPciIndexRead (Address | L2CFGIND, L2_REG_0C, AccessWidth16, &Value, pConfig) #define L2CFG_SEL_WR_EN 0x100 #define L2REG_06 0x6 #define L2REG_07 0x7 #define L2REG_0C 0xC #define L2REG_10 0x10 #define L2REG_11 0x11 #define L2REG_14 0x14 #define L2REG_15 0x15 #define L2REG_18 0x18 #define L2REG_19 0x19 #define L2REG_1C 0x1C #define L2REG_1D 0x1D #define L2REG_46 0x46 #define L2REG_47 0x47 #define L2REG_50 0x50 #define L2REG_51 0x51 #define L2REG_52 0x52 #define L2REG_56 0x56 #define L2REG_30 0x30 #define L2REG_80 0x80 #define L2CFG_DATA 0xF4 // PCI/PCIe Architectural #define PCIE_CAPID 0x10 #define PCIE_PORTMASK 0xF0 // Device cap reg 2 #define PCIE_PCIE2PCIX 0x70 // Device cap reg 2 #define PCIE_PHANTOMMASK 0x18 // Device cap reg 4 #define PCIX_CAPID 0x07 #define IOMMU_CAPID 0x0F #define PCI_DVID 0x00 #define PCI_INVALID 0xFFFFFFFF #define PCI_CLASS 0x08 #define PCI_HEADER 0x0C #define PCI_MULTIFUNCTION 0x00800000 #define PCI_BUS 0x18 #define PCI_SUBMASK 0xFF0000 #define PCI_SECMASK 0xFF00 #define PCI_PRIMASK 0xFF #define PCI_BRIDGE_CLASS 0x0604 // IVRS Table Access #define TYPE_IVHD 0x10 #define IVINFO_ATSMASK 0x00400000 // [22] = ATS #define IVINFO_VAMASK 0x003F8000 // [21:15] = Virtual Address Size #define IVINFO_PAMASK 0x00007F00 // [14:8] = Physical Address Size #define FLAGS_COHERENT BIT5 #define FLAGS_IOTLBSUP BIT4 #define FLAGS_ISOC BIT3 #define FLAGS_RESPASSPW BIT2 #define FLAGS_PASSPW BIT1 #define TYPE_IVMD_ALL 0x20 #define TYPE_IVMD_SELECT 0x21 #define TYPE_IVMD_RANGE 0x22 #define DE_PAD4 1 #define DE_BYTE0 0 #define DE_BYTE1 1 #define DE_BYTE2 2 #define DE_BYTE3 3 #define DE_SELECT 2 #define DATA_NOINTS 0 #define DATA_LINT_EINT_INIT BIT7 + BIT6 + BIT1 + BIT0 #define DATA_ALLINTS 0xD7 #define DE_START 3 #define DE_END 4 #define DE_PAD8 64 #define DE_BYTE4 4 #define DE_BYTE5 5 #define DE_BYTE6 6 #define DE_BYTE7 7 #define DE_ALIASSELECT 66 #define DE_ALIASSTART 67 #define DE_SPECIAL 72 #define VARIETY_IOAPIC 0x1 #define VARIETY_HPET 0x2 #define DE_SPECIAL_VARIETY 7 #define DE_DEVICEID 5 #define DE_SPECIAL_ID 4 // MADT Table Access #define MADT_APIC_TYPE 0x1 #define MADT_APIC_ID 0x2 #define MADT_APIC_BASE 0x4 /*---------------------------------------------------------------------------------------- * T Y P E D E F S A N D S T R U C T U R E S *---------------------------------------------------------------------------------------- */ #pragma pack (push, 1) /// IVRS header typedef struct { UINT32 Signature; ///< see IOMMU specification for details UINT32 Length; ///< see IOMMU specification for details UINT8 Revision; ///< see IOMMU specification for details UINT8 Checksum; ///< see IOMMU specification for details CHAR8 OemId[6]; ///< see IOMMU specification for details CHAR8 OemTableId[8]; ///< see IOMMU specification for details CHAR8 OemRevision[4]; ///< see IOMMU specification for details CHAR8 CreatorId[4]; ///< see IOMMU specification for details CHAR8 CreatorRevision[4]; ///< see IOMMU specification for details UINT32 IvInfo; ///< see IOMMU specification for details UINT64 Reserved; ///< see IOMMU specification for details } IOMMU_IVRS_HEADER; /// DeviceID typedef struct { UINT16 TableLength; ///< length of table UINT16 Device[]; ///< DeviceID } IOMMU_DEVICELIST; /// PCI Topology Based Settings typedef struct { // BOOLEAN PhantomFunction; ///< phantom functions present UINT8 MaxBus; ///< max bus accumulator UINT8 MaxDevice; ///< max device accumulator UINT16 MaxFunction; ///< max function accumulator } IOMMU_PCI_TOPOLOGY; /// IVHD for each hardware definition (i.e. # of northbridges) typedef struct { UINT8 Type; ///< see IOMMU specification for details UINT8 Flags; ///< see IOMMU specification for details UINT16 Length; ///< see IOMMU specification for details UINT16 DeviceId; ///< see IOMMU specification for details UINT16 CapabilityOffset; ///< see IOMMU specification for details UINT64 BaseAddress; ///< see IOMMU specification for details UINT16 PciSegment; ///< see IOMMU specification for details UINT16 IommuInfo; ///< see IOMMU specification for details UINT32 Reserved; ///< see IOMMU specification for details UINT32 DeviceEntry[]; ///< see IOMMU specification for details } IOMMU_IVHD_ENTRY; /// IVMD for each memory range typedef struct { UINT8 Type; ///< see IOMMU specification for details UINT8 Flags; ///< see IOMMU specification for details UINT16 Length; ///< see IOMMU specification for details UINT16 DeviceId; ///< see IOMMU specification for details UINT16 AuxData; ///< see IOMMU specification for details UINT64 Reserved; ///< see IOMMU specification for details UINT64 BlockStartAddress; ///< see IOMMU specification for details UINT64 BlockLength; ///< see IOMMU specification for details } IOMMU_IVMD_ENTRY; //#define IVRS_HANDLE 'SRVI' #define IVRS_HANDLE Int32FromChar ('S', 'R', 'V', 'I') #define L2_DTC_CONTROL 0x10 #define L2_ITC_CONTROL 0x14 #define L2_PTC_A_CONTROL 0x18 #define L2_PTC_B_CONTROL 0x1C #define L2_PDC_CONTROL 0x50 #define EXCLUDE_SB_DEVICE_FROM_L2_HASH /// L2 cache init typedef struct { UINT8 HashControl; ///