diff --git a/lib/s390x/stsi.h b/lib/s390x/stsi.h
index 1e9d095..f2290ca 100644
--- a/lib/s390x/stsi.h
+++ b/lib/s390x/stsi.h
@@ -30,15 +30,18 @@ struct sysinfo_3_2_2 {
 };
 
 #define CPUS_TLE_RES_BITS 0x00fffffff8000000UL
-struct topology_cpu {
-	uint8_t nl;
-	uint8_t reserved1[3];
-	uint8_t reserved4:5;
-	uint8_t d:1;
-	uint8_t pp:2;
-	uint8_t type;
-	uint16_t origin;
-	uint64_t mask;
+union topology_cpu {
+	uint64_t raw[2];
+	struct {
+		uint8_t nl;
+		uint8_t reserved1[3];
+		uint8_t reserved4:5;
+		uint8_t d:1;
+		uint8_t pp:2;
+		uint8_t type;
+		uint16_t origin;
+		uint64_t mask;
+	};
 };
 
 enum topology_polarization {
@@ -53,16 +56,19 @@ enum cpu_type {
 };
 
 #define CONTAINER_TLE_RES_BITS 0x00ffffffffffff00UL
-struct topology_container {
-	uint8_t nl;
-	uint8_t reserved[6];
-	uint8_t id;
+union topology_container {
+	uint64_t raw;
+	struct {
+		uint8_t nl;
+		uint8_t reserved[6];
+		uint8_t id;
+	};
 };
 
 union topology_entry {
 	uint8_t nl;
-	struct topology_cpu cpu;
-	struct topology_container container;
+	union topology_cpu cpu;
+	union topology_container container;
 };
 
 #define CPU_TOPOLOGY_MAX_LEVEL 6
diff --git a/s390x/topology.c b/s390x/topology.c
index df158ae..01021eb 100644
--- a/s390x/topology.c
+++ b/s390x/topology.c
@@ -2,7 +2,7 @@
 /*
  * CPU Topology
  *
- * Copyright IBM Corp. 2022
+ * Copyright IBM Corp. 2022, 2023
  *
  * Authors:
  *  Pierre Morel <pmorel@linux.ibm.com>
@@ -23,7 +23,6 @@ static uint8_t pagebuf[PAGE_SIZE] __attribute__((aligned(PAGE_SIZE)));
 
 static int max_nested_lvl;
 static int number_of_cpus;
-static int cpus_in_masks;
 static int max_cpus;
 
 /*
@@ -238,108 +237,163 @@ done:
 }
 
 /**
- * check_tle:
- * @tc: pointer to first TLE
+ * stsi_get_sysib:
+ * @info: pointer to the STSI info structure
+ * @sel2: the selector giving the topology level to check
  *
- * Recursively check the containers TLEs until we
- * find a CPU TLE.
+ * Fill the sysinfo_15_1_x info structure and check the
+ * SYSIB header.
+ *
+ * Returns instruction validity.
  */
-static uint8_t *check_tle(void *tc)
+static int stsi_get_sysib(struct sysinfo_15_1_x *info, int sel2)
 {
-	struct topology_container *container = tc;
-	struct topology_cpu *cpus;
-	int n;
+	int ret;
 
-	if (container->nl) {
-		report_info("NL: %d id: %d", container->nl, container->id);
+	report_prefix_pushf("SYSIB");
 
-		report(!(*(uint64_t *)tc & CONTAINER_TLE_RES_BITS),
-		       "reserved bits %016lx",
-		       *(uint64_t *)tc & CONTAINER_TLE_RES_BITS);
+	ret = stsi(info, 15, 1, sel2);
 
-		return check_tle(tc + sizeof(*container));
+	if (max_nested_lvl >= sel2) {
+		report(!ret, "Valid instruction");
+	} else {
+		report(ret, "Invalid instruction");
 	}
 
-	report_info("NL: %d", container->nl);
-	cpus = tc;
+	report_prefix_pop();
 
-	report(!(*(uint64_t *)tc & CPUS_TLE_RES_BITS), "reserved bits %016lx",
-	       *(uint64_t *)tc & CPUS_TLE_RES_BITS);
+	return ret;
+}
 
-	report(cpus->type == CPU_TYPE_IFL, "type IFL");
+static int check_cpu(union topology_cpu *cpu,
+		     union topology_container *parent)
+{
+	report_prefix_pushf("%d:%d:%d:%d", cpu->d, cpu->pp, cpu->type, cpu->origin);
 
-	report_info("origin: %d", cpus->origin);
-	report_info("mask: %016lx", cpus->mask);
-	report_info("dedicated: %d entitlement: %d", cpus->d, cpus->pp);
+	report(!(cpu->raw[0] & CPUS_TLE_RES_BITS), "reserved bits %016lx",
+	       cpu->raw[0] & CPUS_TLE_RES_BITS);
 
-	n = __builtin_popcountl(cpus->mask);
-	report(n <= expected_topo_lvl[0], "CPUs per mask: %d out of max %d",
-	       n, expected_topo_lvl[0]);
-	cpus_in_masks += n;
+	report(cpu->type == CPU_TYPE_IFL, "type IFL");
 
-	if (!cpus->d)
-		report_skip("Not dedicated");
-	else
-		report(cpus->pp == POLARIZATION_VERTICAL_HIGH ||
-		       cpus->pp == POLARIZATION_HORIZONTAL,
+	if (cpu->d)
+		report(cpu->pp == POLARIZATION_VERTICAL_HIGH ||
+		       cpu->pp == POLARIZATION_HORIZONTAL,
 		       "Dedicated CPUs are either horizontally polarized or have high entitlement");
+	else
+		report_skip("Not dedicated");
+
+	report_prefix_pop();
 
-	return tc + sizeof(*cpus);
+	return __builtin_popcountl(cpu->mask);
 }
 
-/**
- * stsi_check_tle_coherency:
- * @info: Pointer to the stsi information
- *
- * We verify that we get the expected number of Topology List Entry
- * containers for a specific level.
- */
-static void stsi_check_tle_coherency(struct sysinfo_15_1_x *info)
+static union topology_container *check_child_cpus(struct sysinfo_15_1_x *info,
+						  union topology_container *cont,
+						  union topology_cpu *child,
+						  unsigned int *cpus_in_masks)
 {
-	void *tc, *end;
+	void *last = ((void *)info) + info->length;
+	union topology_cpu *prev_cpu = NULL;
+	bool correct_ordering = true;
+	unsigned int cpus = 0;
+	int i;
 
-	report_prefix_push("TLE");
-	cpus_in_masks = 0;
+	for (i = 0; (void *)&child[i] < last && child[i].nl == 0; prev_cpu = &child[i++]) {
+		cpus += check_cpu(&child[i], cont);
+		if (prev_cpu) {
+			if (prev_cpu->type > child[i].type) {
+				report_info("Incorrect ordering wrt type for child %d", i);
+				correct_ordering = false;
+			}
+			if (prev_cpu->type < child[i].type)
+				continue;
+			if (prev_cpu->pp < child[i].pp) {
+				report_info("Incorrect ordering wrt polarization for child %d", i);
+				correct_ordering = false;
+			}
+			if (prev_cpu->pp > child[i].pp)
+				continue;
+			if (!prev_cpu->d && child[i].d) {
+				report_info("Incorrect ordering wrt dedication for child %d", i);
+				correct_ordering = false;
+			}
+			if (prev_cpu->d && !child[i].d)
+				continue;
+			if (prev_cpu->origin > child[i].origin) {
+				report_info("Incorrect ordering wrt origin for child %d", i);
+				correct_ordering = false;
+			}
+		}
+	}
+	report(correct_ordering, "children correctly ordered");
+	report(cpus <= expected_topo_lvl[0], "%d children <= max of %d",
+	       cpus, expected_topo_lvl[0]);
+	*cpus_in_masks += cpus;
 
-	tc = info->tle;
-	end = (void *)info + info->length;
+	return (union topology_container *)&child[i];
+}
 
-	while (tc < end)
-		tc = check_tle(tc);
+static union topology_container *check_container(struct sysinfo_15_1_x *info,
+						 union topology_container *cont,
+						 union topology_entry *child,
+						 unsigned int *cpus_in_masks);
 
-	report(cpus_in_masks == number_of_cpus, "CPUs in mask %d",
-	       cpus_in_masks);
+static union topology_container *check_child_containers(struct sysinfo_15_1_x *info,
+							union topology_container *cont,
+							union topology_container *child,
+							unsigned int *cpus_in_masks)
+{
+	void *last = ((void *)info) + info->length;
+	union topology_container *entry;
+	int i;
 
-	report_prefix_pop();
+	for (i = 0, entry = child; (void *)entry < last && entry->nl == cont->nl - 1; i++) {
+		entry = check_container(info, entry, (union topology_entry *)(entry + 1),
+					cpus_in_masks);
+	}
+	if (max_nested_lvl == info->mnest)
+		report(i <= expected_topo_lvl[cont->nl - 1], "%d children <= max of %d",
+		       i, expected_topo_lvl[cont->nl - 1]);
+
+	return entry;
 }
 
-/**
- * stsi_get_sysib:
- * @info: pointer to the STSI info structure
- * @sel2: the selector giving the topology level to check
- *
- * Fill the sysinfo_15_1_x info structure and check the
- * SYSIB header.
- *
- * Returns instruction validity.
- */
-static int stsi_get_sysib(struct sysinfo_15_1_x *info, int sel2)
+static union topology_container *check_container(struct sysinfo_15_1_x *info,
+						 union topology_container *cont,
+						 union topology_entry *child,
+						 unsigned int *cpus_in_masks)
 {
-	int ret;
+	union topology_container *entry;
 
-	report_prefix_pushf("SYSIB");
+	report_prefix_pushf("%d", cont->id);
 
-	ret = stsi(info, 15, 1, sel2);
+	report(cont->nl - 1 == child->nl, "Level %d one above child level %d",
+	       cont->nl, child->nl);
+	report(!(cont->raw & CONTAINER_TLE_RES_BITS), "reserved bits %016lx",
+	       cont->raw & CONTAINER_TLE_RES_BITS);
 
-	if (max_nested_lvl >= sel2) {
-		report(!ret, "Valid instruction");
-	} else {
-		report(ret, "Invalid instruction");
-	}
+	if (cont->nl > 1)
+		entry = check_child_containers(info, cont, &child->container, cpus_in_masks);
+	else
+		entry = check_child_cpus(info, cont, &child->cpu, cpus_in_masks);
 
 	report_prefix_pop();
+	return entry;
+}
 
-	return ret;
+static void check_topology_list(struct sysinfo_15_1_x *info, int sel2)
+{
+	union topology_container dummy = { .nl = sel2, .id = 0 };
+	unsigned int cpus_in_masks = 0;
+
+	report_prefix_push("TLE");
+
+	check_container(info, &dummy, info->tle, &cpus_in_masks);
+	report(cpus_in_masks == number_of_cpus,
+	       "Number of CPUs %d equals  %d CPUs in masks",
+	       number_of_cpus, cpus_in_masks);
+
+	report_prefix_pop();
 }
 
 /**
@@ -372,7 +426,7 @@ static void check_sysinfo_15_1_x(struct sysinfo_15_1_x *info, int sel2)
 	}
 
 	stsi_check_header(info, sel2);
-	stsi_check_tle_coherency(info);
+	check_topology_list(info, sel2);
 
 vertical:
 	report_prefix_pop();
@@ -385,7 +439,7 @@ vertical:
 	}
 
 	stsi_check_header(info, sel2);
-	stsi_check_tle_coherency(info);
+	check_topology_list(info, sel2);
 	report_prefix_pop();
 
 end:
