From 156ea392a2e62522b5aefca5a12f913b220cefcc Mon Sep 17 00:00:00 2001 From: Rob Bradford Date: Mon, 16 Dec 2019 16:42:29 +0000 Subject: [PATCH] vmm: cpu: Only do ACPI notify on newly added vCPUs When we add a vCPU set an "inserting" boolean that is exposed as an ACPI field that will be checked for and reset when the ACPI GED notification for CPU devices happens. This change is a precursor for CPU unplug. Signed-off-by: Rob Bradford --- vmm/src/cpu.rs | 44 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/vmm/src/cpu.rs b/vmm/src/cpu.rs index 40066e124..fabac3d29 100644 --- a/vmm/src/cpu.rs +++ b/vmm/src/cpu.rs @@ -388,6 +388,7 @@ pub struct CpuManager { } const CPU_ENABLE_FLAG: usize = 0; +const CPU_INSERTING_FLAG: usize = 1; const CPU_STATUS_OFFSET: u64 = 4; const CPU_SELECTION_OFFSET: u64 = 0; @@ -401,6 +402,9 @@ impl BusDevice for CpuManager { if state.active() { data[0] |= 1 << CPU_ENABLE_FLAG; } + if state.inserting { + data[0] |= 1 << CPU_INSERTING_FLAG; + } } } _ => { @@ -417,6 +421,15 @@ impl BusDevice for CpuManager { CPU_SELECTION_OFFSET => { self.selected_cpu = data[0]; } + CPU_STATUS_OFFSET => { + let state = &mut self.vcpu_states[usize::from(self.selected_cpu)]; + // The ACPI code writes back a 1 to acknowledge the insertion + if (data[0] & (1 << CPU_INSERTING_FLAG) == 1 << CPU_INSERTING_FLAG) + && state.inserting + { + state.inserting = false; + } + } _ => { warn!( "Unexpected offset for accessing CPU manager device: {:#}", @@ -428,6 +441,7 @@ impl BusDevice for CpuManager { } struct VcpuState { + inserting: bool, handle: Option>, } @@ -592,7 +606,12 @@ impl CpuManager { .map_err(Error::VcpuSpawn)?, ); - self.vcpu_states.push(VcpuState { handle }); + // On hot plug calls into this function entry_addr is None. It is for + // those hotplug CPU additions that we need to set the inserting flag. + self.vcpu_states.push(VcpuState { + handle, + inserting: entry_addr.is_none(), + }); } // Unblock all CPU threads. @@ -810,14 +829,35 @@ impl Aml for CPUMethods { 0, true, vec![ + // Take lock defined above + &aml::Acquire::new("\\_SB_.PRES.CPLK".into(), 0xfff), &aml::Store::new(&aml::Local(0), &aml::ZERO), &aml::While::new( &aml::LessThan::new(&aml::Local(0), &self.max_vcpus), vec![ - &aml::MethodCall::new("CTFY".into(), vec![&aml::Local(0), &aml::ONE]), + // Write CPU number (in first argument) to I/O port via field + &aml::Store::new(&aml::Path::new("\\_SB_.PRES.CSEL"), &aml::Local(0)), + // Check if CINS bit is set + &aml::If::new( + &aml::Equal::new(&aml::Path::new("\\_SB_.PRES.CINS"), &aml::ONE), + // Notify device if it is + vec![ + &aml::MethodCall::new( + "CTFY".into(), + vec![&aml::Local(0), &aml::ONE], + ), + // Reset CINS bit + &aml::Store::new( + &aml::Path::new("\\_SB_.PRES.CINS"), + &aml::ONE, + ), + ], + ), &aml::Add::new(&aml::Local(0), &aml::Local(0), &aml::ONE), ], ), + // Release lock + &aml::Release::new("\\_SB_.PRES.CPLK".into()), ], ) .to_aml_bytes(),