feat(qemu-sbsa): handle CPU information
We want to remove use of DeviceTree from EDK2. So we move
functions to TF-A:
- counting cpu cores
- checking NUMA node id
- checking MPIDR
And then it gets passed to EDK2 via SMC calls.
Change-Id: I1c7fc234ba90ba32433b6e4aa2cf127f26da00fd
Signed-off-by: Marcin Juszkiewicz <marcin.juszkiewicz@linaro.org>
diff --git a/plat/qemu/qemu_sbsa/sbsa_sip_svc.c b/plat/qemu/qemu_sbsa/sbsa_sip_svc.c
index 05ebec4..31c083f 100644
--- a/plat/qemu/qemu_sbsa/sbsa_sip_svc.c
+++ b/plat/qemu/qemu_sbsa/sbsa_sip_svc.c
@@ -28,13 +28,88 @@
#define SIP_SVC_VERSION SIP_FUNCTION_ID(1)
#define SIP_SVC_GET_GIC SIP_FUNCTION_ID(100)
#define SIP_SVC_GET_GIC_ITS SIP_FUNCTION_ID(101)
+#define SIP_SVC_GET_CPU_COUNT SIP_FUNCTION_ID(200)
+#define SIP_SVC_GET_CPU_NODE SIP_FUNCTION_ID(201)
static uint64_t gic_its_addr;
+typedef struct {
+ uint32_t nodeid;
+ uint32_t mpidr;
+} cpu_data;
+
+static struct {
+ uint32_t num_cpus;
+ cpu_data cpu[PLATFORM_CORE_COUNT];
+} dynamic_platform_info;
+
void sbsa_set_gic_bases(const uintptr_t gicd_base, const uintptr_t gicr_base);
uintptr_t sbsa_get_gicd(void);
uintptr_t sbsa_get_gicr(void);
+void read_cpuinfo_from_dt(void *dtb)
+{
+ int node;
+ int prev;
+ int cpu = 0;
+ uint32_t nodeid = 0;
+ uintptr_t mpidr;
+
+ /*
+ * QEMU gives us this DeviceTree node:
+ * numa-node-id entries are only when NUMA config is used
+ *
+ * cpus {
+ * #size-cells = <0x00>;
+ * #address-cells = <0x02>;
+ *
+ * cpu@0 {
+ * numa-node-id = <0x00>;
+ * reg = <0x00 0x00>;
+ * };
+ *
+ * cpu@1 {
+ * numa-node-id = <0x03>;
+ * reg = <0x00 0x01>;
+ * };
+ * };
+ */
+ node = fdt_path_offset(dtb, "/cpus");
+ if (node < 0) {
+ ERROR("No information about cpus in DeviceTree.\n");
+ panic();
+ }
+
+ /*
+ * QEMU numbers cpus from 0 and there can be /cpus/cpu-map present so we
+ * cannot use fdt_first_subnode() here
+ */
+ node = fdt_path_offset(dtb, "/cpus/cpu@0");
+
+ while (node > 0) {
+ if (fdt_getprop(dtb, node, "reg", NULL)) {
+ fdt_get_reg_props_by_index(dtb, node, 0, &mpidr, NULL);
+ }
+
+ if (fdt_getprop(dtb, node, "numa-node-id", NULL)) {
+ fdt_read_uint32(dtb, node, "numa-node-id", &nodeid);
+ }
+
+ dynamic_platform_info.cpu[cpu].nodeid = nodeid;
+ dynamic_platform_info.cpu[cpu].mpidr = mpidr;
+
+ INFO("CPU %d: node-id: %d, mpidr: %ld\n", cpu, nodeid, mpidr);
+
+ cpu++;
+
+ prev = node;
+ node = fdt_next_subnode(dtb, prev);
+ }
+
+ dynamic_platform_info.num_cpus = cpu;
+ INFO("Found %d cpus\n", dynamic_platform_info.num_cpus);
+}
+
void read_platform_config_from_dt(void *dtb)
{
int node;
@@ -129,6 +204,7 @@
INFO("Platform version: %d.%d\n", platform_version_major, platform_version_minor);
read_platform_config_from_dt(dtb);
+ read_cpuinfo_from_dt(dtb);
}
/*
@@ -144,6 +220,7 @@
u_register_t flags)
{
uint32_t ns;
+ uint64_t index;
/* Determine which security state this SMC originated from */
ns = is_caller_non_secure(flags);
@@ -163,6 +240,19 @@
case SIP_SVC_GET_GIC_ITS:
SMC_RET2(handle, NULL, gic_its_addr);
+ case SIP_SVC_GET_CPU_COUNT:
+ SMC_RET2(handle, NULL, dynamic_platform_info.num_cpus);
+
+ case SIP_SVC_GET_CPU_NODE:
+ index = x1;
+ if (index < PLATFORM_CORE_COUNT) {
+ SMC_RET3(handle, NULL,
+ dynamic_platform_info.cpu[index].nodeid,
+ dynamic_platform_info.cpu[index].mpidr);
+ } else {
+ SMC_RET1(handle, SMC_ARCH_CALL_INVAL_PARAM);
+ }
+
default:
ERROR("%s: unhandled SMC (0x%x) (function id: %d)\n", __func__, smc_fid,
smc_fid - SIP_FUNCTION);