]> xenbits.xensource.com Git - unikraft/unikraft.git/commitdiff
plat: Enable secondary cores allocation through `ACPI` on `ARM64`
authorSergiu Moga <sergiu.moga@protonmail.com>
Sun, 21 May 2023 13:17:50 +0000 (16:17 +0300)
committerUnikraft <monkey@unikraft.io>
Fri, 11 Aug 2023 16:42:01 +0000 (16:42 +0000)
Split secondary cores enumeration in two methods:
- if CONFIG_UKPLAT_ACPI is enabled then get the information
through the `MADT`'s `GICC` structures
- else rely on the `Devicetree`'s `cpu@` nodes

Signed-off-by: Sergiu Moga <sergiu.moga@protonmail.com>
Reviewed-by: Razvan Virtan <virtanrazvan@gmail.com>
Reviewed-by: Michalis Pappas <michalis@unikraft.io>
Approved-by: Razvan Deaconescu <razvand@unikraft.io>
Tested-by: Unikraft CI <monkey@unikraft.io>
GitHub-Closes: #912

plat/common/arm/lcpu.c
plat/common/include/uk/plat/common/madt.h

index 3a827c351eec51bdd6d662fc7943235feda186cd..213b5f37e8f1db30321e3886967651d74a1633aa 100644 (file)
@@ -30,6 +30,8 @@
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  */
+#include <uk/plat/common/bootinfo.h>
+#include <uk/plat/common/acpi.h>
 #include <uk/plat/lcpu.h>
 #include <uk/plat/io.h>
 #include <arm/smccc.h>
@@ -73,7 +75,6 @@ void __noreturn lcpu_arch_jump_to(void *sp, ukplat_lcpu_entry_t entry)
 #define FDT_SIZE_CELLS_DEFAULT 0
 #define FDT_ADDR_CELLS_DEFAULT 2
 
-static void *dtb;
 void lcpu_start(struct lcpu *cpu);
 static __paddr_t lcpu_start_paddr;
 extern struct _gic_dev *gic;
@@ -92,7 +93,59 @@ int lcpu_arch_init(struct lcpu *this_lcpu)
        return ret;
 }
 
-int lcpu_arch_mp_init(void *arg)
+#ifdef CONFIG_UKPLAT_ACPI
+static int do_arch_mp_init(void *arg __unused)
+{
+       __lcpuid bsp_cpu_id = lcpu_get(0)->id;
+       int bsp_found __maybe_unused = 0;
+       union {
+               struct acpi_madt_gicc *gicc;
+               struct acpi_subsdt_hdr *h;
+       } m;
+       struct lcpu *lcpu;
+       struct acpi_madt *madt;
+       __lcpuid cpu_id;
+       __sz off, len;
+
+       uk_pr_info("Bootstrapping processor has the ID %ld\n", bsp_cpu_id);
+
+       /* Enumerate all other CPUs */
+       madt = acpi_get_madt();
+       UK_ASSERT(madt);
+
+       len = madt->hdr.tab_len - sizeof(*madt);
+       for (off = 0; off < len; off += m.h->len) {
+               m.h = (struct acpi_subsdt_hdr *)(madt->entries + off);
+
+               if (m.h->type != ACPI_MADT_GICC ||
+                   !(m.gicc->flags & ACPI_MADT_GICC_FLAGS_EN))
+                       continue;
+
+               cpu_id = m.gicc->mpidr & CPU_ID_MASK;
+
+               if (bsp_cpu_id == cpu_id) {
+                       UK_ASSERT(!bsp_found);
+
+                       bsp_found = 1;
+                       continue;
+               }
+
+               lcpu = lcpu_alloc(cpu_id);
+               if (unlikely(!lcpu)) {
+                       /* If we cannot allocate another LCPU, we probably have
+                        * reached the maximum number of supported CPUs. So
+                        * just stop here.
+                        */
+                       uk_pr_warn("Maximum number of cores exceeded.\n");
+                       return 0;
+               }
+       }
+       UK_ASSERT(bsp_found);
+
+       return 0;
+}
+#else
+static int do_arch_mp_init(void *arg)
 {
        int fdt_cpu;
        const fdt32_t *naddr_prop, *nsize_prop, *id_reg;
@@ -103,17 +156,12 @@ int lcpu_arch_mp_init(void *arg)
        __lcpuid bsp_cpu_id;
        char bsp_found __maybe_unused = 0;
        struct lcpu *lcpu;
+       void *dtb;
 
        /* MP support is dependent on an initialized GIC */
        UK_ASSERT(gic);
 
        dtb = arg;
-       /**
-        * We have to provide the physical address of the start routine when
-        * starting secondary CPUs. We thus do the translation here once and
-        * cache the result.
-        */
-       lcpu_start_paddr = ukplat_virt_to_phys(lcpu_start);
 
        bsp_cpu_id = lcpu_arch_id();
        uk_pr_info("Bootstrapping processor has the ID %ld\n",
@@ -216,6 +264,19 @@ int lcpu_arch_mp_init(void *arg)
 
        return 0;
 }
+#endif
+
+int lcpu_arch_mp_init(void *arg)
+{
+       /**
+        * We have to provide the physical address of the start routine when
+        * starting secondary CPUs. We thus do the translation here once and
+        * cache the result.
+        */
+       lcpu_start_paddr = ukplat_virt_to_phys(lcpu_start);
+
+       return do_arch_mp_init(arg);
+}
 
 int lcpu_arch_start(struct lcpu *lcpu, unsigned long flags __unused)
 {
index cabb3d9efbe82a08d129790200c0e269c5259252..a3674c5d54bb3a779bcd5e408ad77292fa4517e4 100644 (file)
@@ -167,6 +167,9 @@ struct acpi_madt_x2apic_nmi {
 } __packed;
 
 /* GIC CPU Interface (GICC) Structure */
+#define ACPI_MADT_GICC_FLAGS_EN                                        0x01
+#define ACPI_MADT_GICC_FLAGS_PERF_IRQ_MODE                     0x02
+#define ACPI_MADT_GICC_FLAGS_VGIC_IRQ_MODE                     0x03
 struct acpi_madt_gicc {
        struct acpi_subsdt_hdr hdr;
        __u16 reserved;