[SeaBIOS] [PATCH 3/3] Take in account hot(un)plugged cpus on reboot

Igor Mammedov imammedo at redhat.com
Sat Mar 10 12:47:28 CET 2012


Initial count of active cpus is communicated to bios from qemu via
CMOS_BIOS_SMP_COUNT io port. However if cpus are hotplugged after
boot and then guest is rebooted without taking down qemu then
bios might be stuck at smp_probe
   while (cmos_smp_count + 1 != readl(&CountCPUs))
      yield();
where cmos_smp_count + 1 will be less that CountCPUs due to
additional hotplugged cpus.

One way to fix bug is to take in account hotplugged cpus and count
online cpus in cpu status bitmap that qemu provides at 0xaf00 and
bios uses for ACPI cpu hotplug in acpi-dsdt.dsl.

Alternative ways to fix issue was disscussed on following thread:
  http://www.seabios.org/pipermail/seabios/2011-August/002147.html
without any conclusion

Rationale why counting cpus in cpu_sts bitmap at 0xaf00 might be
better that updating CMOS_BIOS_SMP_COUNT in qemu.
  feeble one: we are already relying on cpu_sts at 0xaf00 for ACPI
       cpu hotplug machinery and it seems that there is no standard
       way to pass this info (so we are now using "board extension").
  2nd: another possible use for cpu_sts bitmap is when cpus are able
       to be (hot)plugged in nonconsecutive order, MADT + CPON
       package should be build taking in account info about which
       cpus are (un)plugged.

v2 changes:
  - access cpu_sts only if qemu advertise its support
  - unconditionally use acpi_cpu_online_count if available to cover
    unplug case as well

Signed-off-by: Igor Mammedov <imammedo at redhat.com>
---
 src/smp.c |   23 +++++++++++++++++++++++
 1 files changed, 23 insertions(+), 0 deletions(-)

diff --git a/src/smp.c b/src/smp.c
index 9933ac6..835b766 100644
--- a/src/smp.c
+++ b/src/smp.c
@@ -17,6 +17,9 @@
 
 #define APIC_ENABLED 0x0100
 
+#define ACPI_CPU_STATUS_MAP 0xaf00
+#define ACPI_CPU_STATUS_MAP_SZ 32
+
 struct { u32 ecx, eax, edx; } smp_mtrr[32] VAR16VISIBLE;
 u32 smp_mtrr_count VAR16VISIBLE;
 
@@ -115,6 +118,26 @@ smp_probe(void)
         msleep(10);
     } else {
         u8 cmos_smp_count = inb_cmos(CMOS_BIOS_SMP_COUNT);
+        dprintf(1, "Powered-on with %d cpu(s)\n", cmos_smp_count + 1);
+
+        if (qemu_cfg_have_acpi_cpus_map()) {
+            u8 i = 0, acpi_cpu_online_count = 0;
+            /* count plugged in cpus in acpi PRST bitmap */
+            while (i < ACPI_CPU_STATUS_MAP_SZ) {
+                u8 j = 0, status = inb(ACPI_CPU_STATUS_MAP + (i++));
+                while (j < 8)
+                    if ((status >> j++) & 1)
+                        ++acpi_cpu_online_count;
+            }
+
+            dprintf(1, "Counted %d present cpu(s) in ACPI cpus status map\n",
+                    acpi_cpu_online_count);
+            /* if cpu(s) were hot(un)plugged then on reboot
+             * we should wait for an actual cpus number, so use
+             * acpi_cpu_online_count instead of cmos_smp_count */
+            cmos_smp_count = acpi_cpu_online_count - 1;
+        }
+
         while (cmos_smp_count + 1 != readl(&CountCPUs)) {
             if (cmos_smp_count + 1 < readl(&CountCPUs)) {
                 dprintf(1, "BUG: Expected %d cpu(s) but %d cpus started\n",
-- 
1.7.7.6




More information about the SeaBIOS mailing list