1 /** @file
2 
3   Multiple APIC Description Table (MADT)
4 
5   Copyright (c) 2012 - 2014, ARM Ltd. All rights reserved.<BR>
6   Copyright (c) 2014 - 2016, AMD Inc. All rights reserved.<BR>
7 
8   This program and the accompanying materials
9   are licensed and made available under the terms and conditions of the BSD License
10   which accompanies this distribution.  The full text of the license may be found at
11   http://opensource.org/licenses/bsd-license.php
12 
13   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 
16 **/
17 /**
18 
19   Derived from:
20    ArmPlatformPkg/ArmJunoPkg/AcpiTables/Madt.aslc
21 
22 **/
23 
24 #include <Uefi.h>
25 #include <Library/ArmLib.h>
26 #include <Library/DebugLib.h>
27 #include <Library/UefiBootServicesTableLib.h>
28 #include <Guid/ArmMpCoreInfo.h>
29 
30 #include <AmdStyxAcpiLib.h>
31 #include <Protocol/AmdMpCoreInfo.h>
32 
33 AMD_MP_CORE_INFO_PROTOCOL  *mAmdMpCoreInfoProtocol = NULL;
34 
35 
36 // ARM PL390 General Interrupt Controller
37 #define GIC_BASE                             (FixedPcdGet64 (PcdGicInterruptInterfaceBase))
38 #define GICD_BASE                            (FixedPcdGet64 (PcdGicDistributorBase))
39 #define GICV_BASE                            (FixedPcdGet64 (PcdGicVirtualInterruptInterfaceBase))
40 #define GICH_BASE                            (FixedPcdGet64 (PcdGicHypervisorInterruptInterfaceBase))
41 #define VGIC_MAINT_INT                       (FixedPcdGet32 (PcdGicVirtualMaintenanceInterrupt))
42 #define GICVR_BASE                           (FixedPcdGet64 (PcdGicVirtualRegisterInterfaceBase))
43 #define GIC_MSI_FRAME                        (FixedPcdGet64 (PcdGicMSIFrameBase))
44 #define GIC_VERSION                          (FixedPcdGet8  (PcdGicVersion))
45 
46 #define GICD_ID                              ( 0 )
47 #define GICD_VECTOR                          ( 0 )
48 
49 #define GICM_ID                              ( 0 )
50 #define GICM_SPI_COUNT                       ( 0x100 )
51 #define GICM_SPI_BASE                        ( 0x40 )
52 #define GSIV_SPI_OFFSET                      ( 32 )
53 
54 #if STYX_A0
55   #define MSI_TYPER_FLAG                     ( 1 ) // Ignore TYPER register and use Count/Base fields
56 #else
57   #define MSI_TYPER_FLAG                     ( 0 ) // Use TYPER register and ignore Count/Base fields
58 #endif
59 
60 #define PARKING_PROTOCOL_VERSION             (FixedPcdGet32 (PcdParkingProtocolVersion))
61 #define PARKED_OFFSET                        ( 4096 )
62 
63 #define CORES_PER_CLUSTER                    (FixedPcdGet32 (PcdSocCoresPerCluster))
64 #define PARKED_ADDRESS(Base, ClusterId, CoreId) \
65         ((Base) + (CORES_PER_CLUSTER * ClusterId + CoreId) * PARKED_OFFSET)
66 
67 
68 /* Macro to populate EFI_ACPI_5_1_GIC_STRUCTURE */
69 #define AMD_GIC(CpuNum, ClusterId, CoreId, PerfInt)  {                        \
70   EFI_ACPI_5_1_GIC,                     /* UINT8 Type */                      \
71   sizeof (EFI_ACPI_5_1_GIC_STRUCTURE),  /* UINT8 Length */                    \
72   EFI_ACPI_RESERVED_WORD,               /* UINT16 Reserved */                 \
73   CpuNum,                               /* UINT32 CPUInterfaceNumber */       \
74   (ClusterId << 8) | CoreId,            /* UINT32 AcpiProcessorUid */         \
75   EFI_ACPI_5_1_GIC_ENABLED,             /* UINT32 Flags */                    \
76   PARKING_PROTOCOL_VERSION,             /* UINT32 ParkingProtocolVersion */   \
77   PerfInt,                              /* UINT32 PerformanceInterruptGsiv */ \
78   0,                                    /* UINT64 ParkedAddress */            \
79   GIC_BASE,                             /* UINT64 PhysicalBaseAddress */      \
80   GICV_BASE,                            /* UINT64 GICV */                     \
81   GICH_BASE,                            /* UINT64 GICH */                     \
82   VGIC_MAINT_INT,                       /* UINT32 VGICMaintenanceInterrupt */ \
83   GICVR_BASE,                           /* UINT64 GICRBaseAddress */          \
84   (ClusterId << 8) | CoreId             /* UINT64 MPIDR */                    \
85   }
86 
87 /* Macro to initialise EFI_ACPI_5_1_GIC_DISTRIBUTOR_STRUCTURE */
88 #define AMD_GICD(Id, Vec) {                                                             \
89   EFI_ACPI_5_1_GICD,                                /* UINT8 Type */                    \
90   sizeof (EFI_ACPI_5_1_GIC_DISTRIBUTOR_STRUCTURE),  /* UINT8 Length */                  \
91   EFI_ACPI_RESERVED_WORD,                           /* UINT16 Reserved1 */              \
92   Id,                                               /* UINT32 GicId */                  \
93   GICD_BASE,                                        /* UINT64 PhysicalBaseAddress */    \
94   Vec,                                              /* UINT32 SystemVectorBase */       \
95   EFI_ACPI_RESERVED_DWORD                           /* UINT32 Reserved2 */              \
96   }
97 
98 /* Macro to initialise EFI_ACPI_5_1_GIC_MSI_FRAME_STRUCTURE */
99 #define AMD_GICM(Id, SpiCount, SpiBase) {                                               \
100    EFI_ACPI_5_1_GIC_MSI_FRAME,                      /* UINT8 Type */                    \
101    sizeof(EFI_ACPI_5_1_GIC_MSI_FRAME_STRUCTURE),    /* UINT8 Length */                  \
102    EFI_ACPI_RESERVED_WORD,                          /* UINT16 Reserved1 */              \
103    Id,                                              /* UINT32 GicMsiFrameId */          \
104    GIC_MSI_FRAME,                                   /* UINT64 PhysicalBaseAddress */    \
105    MSI_TYPER_FLAG,                                  /* UINT32 Flags */                  \
106    SpiCount,                                        /* UINT16 SPICount */               \
107    SpiBase                                          /* UINT16 SPIBase */                \
108    }
109 
110 
111 //
112 // NOTE: NUM_CORES is a pre-processor macro passed in with -D option
113 //
114 #pragma pack(push, 1)
115 typedef struct {
116   EFI_ACPI_5_1_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER Header;
117   EFI_ACPI_5_1_GIC_STRUCTURE                          GicC[NUM_CORES];
118   EFI_ACPI_5_1_GIC_DISTRIBUTOR_STRUCTURE              GicD;
119   EFI_ACPI_5_1_GIC_MSI_FRAME_STRUCTURE                GicM;
120 } EFI_ACPI_5_1_ARM_MADT_STRUCTURE;
121 #pragma pack(pop)
122 
123 
124 STATIC EFI_ACPI_5_1_ARM_MADT_STRUCTURE AcpiMadt = {
125   {
126     AMD_ACPI_HEADER (EFI_ACPI_5_1_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE,
127                      EFI_ACPI_5_1_ARM_MADT_STRUCTURE,
128                      EFI_ACPI_5_1_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION),
129     GIC_BASE,                                 // UINT32  LocalApicAddress
130     0                                         // UINT32  Flags
131   },
132   {
133     /*
134      * GIC Interface for Cluster 0 CPU 0
135      */
136     AMD_GIC(0, 0, 0, 39),                     // EFI_ACPI_5_1_GIC_STRUCTURE
137 #if (NUM_CORES > 1)
138     /*
139      * GIC Interface for Cluster 0 CPU 1
140      */
141     AMD_GIC(1, 0, 1, 40),                     // EFI_ACPI_5_1_GIC_STRUCTURE
142 #endif
143 #if (NUM_CORES > 2)
144     /*
145      * GIC Interface for Cluster 1 CPU 0
146      */
147     AMD_GIC(2, 1, 0, 41),                     // EFI_ACPI_5_1_GIC_STRUCTURE
148 #endif
149 #if (NUM_CORES > 3)
150     /*
151      * GIC Interface for Cluster 1 CPU 1
152      */
153     AMD_GIC(3, 1, 1, 42),                     // EFI_ACPI_5_1_GIC_STRUCTURE
154 #endif
155 #if (NUM_CORES > 4)
156     /*
157      * GIC Interface for Cluster 2 CPU 0
158      */
159     AMD_GIC(4, 2, 0, 43),                     // EFI_ACPI_5_1_GIC_STRUCTURE
160 #endif
161 #if (NUM_CORES > 5)
162     /*
163      * GIC Interface for Cluster 2 CPU 1
164      */
165     AMD_GIC(5, 2, 1, 44),                     // EFI_ACPI_5_1_GIC_STRUCTURE
166 #endif
167 #if (NUM_CORES > 6)
168     /*
169      * GIC Interface for Cluster 3 CPU 0
170      */
171     AMD_GIC(6, 3, 0, 45),                     // EFI_ACPI_5_1_GIC_STRUCTURE
172 #endif
173 #if (NUM_CORES > 7)
174     /*
175      * GIC Interface for Cluster 3 CPU 1
176      */
177     AMD_GIC(7, 3, 1, 46),                     // EFI_ACPI_5_1_GIC_STRUCTURE
178 #endif
179   },
180   /*
181    * GIC Distributor
182    */
183     AMD_GICD(GICD_ID, GICD_VECTOR),           // EFI_ACPI_5_1_GIC_DISTRIBUTOR_STRUCTURE
184   /*
185    * GIC MSI Frame
186    */
187   AMD_GICM(GICM_ID, GICM_SPI_COUNT, GICM_SPI_BASE),
188 };
189 
190 
191 STATIC
192 EFI_STATUS
BuildGicC(EFI_ACPI_5_1_GIC_STRUCTURE * GicC,UINT32 CpuNum,UINT32 ClusterId,UINT32 CoreId,EFI_PHYSICAL_ADDRESS MpParkingBase)193 BuildGicC (
194   EFI_ACPI_5_1_GIC_STRUCTURE *GicC,
195   UINT32 CpuNum,
196   UINT32 ClusterId,
197   UINT32 CoreId,
198   EFI_PHYSICAL_ADDRESS MpParkingBase
199   )
200 {
201   UINT32 MpId, PmuSpi;
202   EFI_STATUS Status;
203 
204   MpId = (UINT32) GET_MPID (ClusterId, CoreId);
205   Status = mAmdMpCoreInfoProtocol->GetPmuSpiFromMpId (MpId, &PmuSpi);
206   if (EFI_ERROR (Status))
207     return Status;
208 
209   GicC->Type = EFI_ACPI_5_1_GIC;
210   GicC->Length = sizeof (EFI_ACPI_5_1_GIC_STRUCTURE);
211   GicC->Reserved = EFI_ACPI_RESERVED_WORD;
212   GicC->CPUInterfaceNumber = CpuNum;
213   GicC->AcpiProcessorUid = MpId;
214   GicC->Flags = EFI_ACPI_5_1_GIC_ENABLED;
215   GicC->ParkingProtocolVersion = PARKING_PROTOCOL_VERSION;
216   GicC->ParkedAddress = PARKED_ADDRESS(MpParkingBase, ClusterId, CoreId);
217   GicC->PhysicalBaseAddress = GIC_BASE;
218   GicC->GICV = GICV_BASE;
219   GicC->GICH = GICH_BASE;
220   GicC->VGICMaintenanceInterrupt = VGIC_MAINT_INT;
221   GicC->GICRBaseAddress = GICVR_BASE;
222   GicC->PerformanceInterruptGsiv = PmuSpi + GSIV_SPI_OFFSET;
223   GicC->MPIDR = MpId;
224 
225   return EFI_SUCCESS;
226 }
227 
228 STATIC
229 VOID
BuildGicD(EFI_ACPI_5_1_GIC_DISTRIBUTOR_STRUCTURE * GicD,UINT32 GicId,UINT32 SystemVectorBase)230 BuildGicD (
231   EFI_ACPI_5_1_GIC_DISTRIBUTOR_STRUCTURE *GicD,
232   UINT32 GicId,
233   UINT32 SystemVectorBase
234   )
235 {
236   GicD->Type = EFI_ACPI_5_1_GICD;
237   GicD->Length = sizeof (EFI_ACPI_5_1_GIC_DISTRIBUTOR_STRUCTURE);
238   GicD->Reserved1 = EFI_ACPI_RESERVED_WORD;
239   GicD->GicId = GicId;
240   GicD->PhysicalBaseAddress = GICD_BASE;
241   GicD->SystemVectorBase = SystemVectorBase;
242 #if 0
243   GicD->Reserved2 = EFI_ACPI_RESERVED_DWORD;
244 #else
245   GicD->GicVersion = EFI_ACPI_RESERVED_BYTE;
246   GicD->Reserved2[0] = EFI_ACPI_RESERVED_BYTE;
247   GicD->Reserved2[1] = EFI_ACPI_RESERVED_BYTE;
248   GicD->Reserved2[2] = EFI_ACPI_RESERVED_BYTE;
249 #endif
250 }
251 
252 
253 STATIC
254 VOID
BuildGicM(EFI_ACPI_5_1_GIC_MSI_FRAME_STRUCTURE * GicM,UINT32 MsiFrameId,UINT16 SpiCount,UINT16 SpiBase)255 BuildGicM (
256   EFI_ACPI_5_1_GIC_MSI_FRAME_STRUCTURE *GicM,
257   UINT32 MsiFrameId,
258   UINT16 SpiCount,
259   UINT16 SpiBase
260   )
261 {
262   GicM->Type = EFI_ACPI_5_1_GIC_MSI_FRAME;
263   GicM->Length = sizeof(EFI_ACPI_5_1_GIC_MSI_FRAME_STRUCTURE);
264   GicM->Reserved1 = EFI_ACPI_RESERVED_WORD;
265   GicM->GicMsiFrameId = MsiFrameId;
266   GicM->PhysicalBaseAddress = GIC_MSI_FRAME;
267   GicM->Flags = MSI_TYPER_FLAG;
268   GicM->SPICount = SpiCount;
269   GicM->SPIBase = SpiBase;
270 }
271 
272 
273 EFI_ACPI_DESCRIPTION_HEADER *
MadtHeader(VOID)274 MadtHeader (
275   VOID
276   )
277 {
278   EFI_ACPI_5_1_GIC_STRUCTURE             *GicC;
279   EFI_ACPI_5_1_GIC_DISTRIBUTOR_STRUCTURE *GicD;
280   EFI_ACPI_5_1_GIC_MSI_FRAME_STRUCTURE   *GicM;
281   ARM_CORE_INFO                          *ArmCoreInfoTable;
282   UINTN                                  CoreCount, CpuNum;
283   EFI_STATUS                             Status;
284   EFI_PHYSICAL_ADDRESS                   MpParkingBase;
285   UINTN                                  MpParkingSize;
286 
287   Status = gBS->LocateProtocol (
288                &gAmdMpCoreInfoProtocolGuid,
289                NULL,
290                (VOID **)&mAmdMpCoreInfoProtocol
291                );
292   ASSERT_EFI_ERROR (Status);
293 
294   // Get pointer to ARM core info table
295   ArmCoreInfoTable = mAmdMpCoreInfoProtocol->GetArmCoreInfoTable (&CoreCount);
296   ASSERT (ArmCoreInfoTable != NULL);
297 
298   // Make sure SoC's core count does not exceed what we want to build
299   ASSERT (CoreCount <= NUM_CORES);
300   ASSERT (CoreCount <= PcdGet32(PcdSocCoreCount));
301 
302   MpParkingSize = 0;
303   MpParkingBase =  mAmdMpCoreInfoProtocol->GetMpParkingBase(&MpParkingSize);
304   if (MpParkingBase && MpParkingSize < (CoreCount * SIZE_4KB)) {
305     DEBUG ((EFI_D_ERROR, "MADT: Parking Protocol not supported.\n"));
306     MpParkingBase = 0;
307   }
308 
309   GicC = (EFI_ACPI_5_1_GIC_STRUCTURE *)&AcpiMadt.GicC[0];
310   AcpiMadt.Header.Header.Length = sizeof (EFI_ACPI_5_1_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER);
311 
312   for (CpuNum = 0; CpuNum < CoreCount; ++CpuNum, ++GicC) {
313     DEBUG ((EFI_D_ERROR, "MADT: Core[%d]: ClusterId = %d   CoreId = %d\n",
314             CpuNum, ArmCoreInfoTable[CpuNum].ClusterId, ArmCoreInfoTable[CpuNum].CoreId));
315 
316     Status = BuildGicC (GicC, CpuNum,
317                 ArmCoreInfoTable[CpuNum].ClusterId,
318                 ArmCoreInfoTable[CpuNum].CoreId,
319                 MpParkingBase
320                 );
321     ASSERT_EFI_ERROR (Status);
322 
323     AcpiMadt.Header.Header.Length += sizeof (EFI_ACPI_5_1_GIC_STRUCTURE);
324   }
325 
326   GicD = (EFI_ACPI_5_1_GIC_DISTRIBUTOR_STRUCTURE *)(UINT8 *)((UINTN)&AcpiMadt + (UINTN)AcpiMadt.Header.Header.Length);
327   BuildGicD (GicD, GICD_ID, GICD_VECTOR);
328   AcpiMadt.Header.Header.Length += sizeof (EFI_ACPI_5_1_GIC_DISTRIBUTOR_STRUCTURE);
329 
330   GicM = (EFI_ACPI_5_1_GIC_MSI_FRAME_STRUCTURE *)(UINT8 *)((UINTN)&AcpiMadt + (UINTN)AcpiMadt.Header.Header.Length);
331   BuildGicM (GicM, GICM_ID, GICM_SPI_COUNT, GICM_SPI_BASE);
332   AcpiMadt.Header.Header.Length += sizeof (EFI_ACPI_5_1_GIC_MSI_FRAME_STRUCTURE);
333 
334   return &AcpiMadt.Header.Header;
335 }
336 
337