From nobody Sun Jul 26 10:59:41 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=reject dis=none) header.from=linux.ibm.com ARC-Seal: i=1; a=rsa-sha256; t=1783161473; cv=none; d=zohomail.com; s=zohoarc; b=WJbFTy27jc6HJneqGQSumcXSevlR56mClQPQ6hS2dmVFZCoUeq8DGj4SOyJVMLZboDgEr2EDnaLb2fv0u0aFHGv687lIIXZvLlRWw1pIH/WqWMO7EfWlEeQ0NGjRSWH7mog8mda922nKiOOGcrYg0w7xBmOQQrmE3qccw3gl+Jg= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1783161473; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=A87RKtbDO4DcV+crlwTe7vWoL1PLlKly19ku5OZg2WY=; b=hswYyVFb3qBvEo3UVaZESgs4W9Was6XLvFXns2X+40SGPaRThOMzxIZKWrbhZg914KQm1bbPzoJGuHwaf3YyKL2aTRtxwQNxfWUP7/vpptoVXRUbpMldHH0oCh7QRSG000JqvLupdy16Mj283ZHV+7jaG1K3OHPwzQFlfe1W7rw= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=reject dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1783161473033552.8906649061494; Sat, 4 Jul 2026 03:37:53 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wfxk2-0002jf-5O; Sat, 04 Jul 2026 06:36:58 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wfxjz-0002hh-W5; Sat, 04 Jul 2026 06:36:56 -0400 Received: from mx0a-001b2d01.pphosted.com ([148.163.156.1]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wfxjv-0003HD-7H; Sat, 04 Jul 2026 06:36:55 -0400 Received: from pps.filterd (m0353729.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 6646o7FT1016972; Sat, 4 Jul 2026 10:36:49 GMT Received: from ppma21.wdc07v.mail.ibm.com (5b.69.3da9.ip4.static.sl-reverse.com [169.61.105.91]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 4f6suq914c-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Sat, 04 Jul 2026 10:36:48 +0000 (GMT) Received: from pps.filterd (ppma21.wdc07v.mail.ibm.com [127.0.0.1]) by ppma21.wdc07v.mail.ibm.com (8.18.1.7/8.18.1.7) with ESMTP id 664AYlvu029296; Sat, 4 Jul 2026 10:36:47 GMT Received: from smtprelay02.fra02v.mail.ibm.com ([9.218.2.226]) by ppma21.wdc07v.mail.ibm.com (PPS) with ESMTPS id 4f2sukmbr7-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Sat, 04 Jul 2026 10:36:47 +0000 (GMT) Received: from smtpav05.fra02v.mail.ibm.com (smtpav05.fra02v.mail.ibm.com [10.20.54.104]) by smtprelay02.fra02v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 664AagTv46137838 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Sat, 4 Jul 2026 10:36:42 GMT Received: from smtpav05.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 9ECC220043; Sat, 4 Jul 2026 10:36:42 +0000 (GMT) Received: from smtpav05.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 33CCB20040; Sat, 4 Jul 2026 10:36:38 +0000 (GMT) Received: from vishalc-ibm.ibm.com (unknown [9.124.212.207]) by smtpav05.fra02v.mail.ibm.com (Postfix) with ESMTP; Sat, 4 Jul 2026 10:36:37 +0000 (GMT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=cc :content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=pp1; bh=A87RKt bDO4DcV+crlwTe7vWoL1PLlKly19ku5OZg2WY=; b=VBgN57+8Im+gBsiDx32VnC ipemXcRLFSIcs6wZfp6LgD8I+xHi2G8GQ86fBxfFc5tMsiKAYU1y0x2fx97gBqkC hWISlf36HYIMN8s5pToCIgtB/IaJ8hdzeFKjycqlW1VPGlc7BmKKFdzh+yJborik cwUgNyvUbRZO7P564fAqQyeb2SlrWc76/rBm+UOkrq3XZOX30EBXu1SL0zZkefT3 4D9CQhg0/8noQHBM79U1e5DU1vTM9s/V7+ttJwAAb9u1HhlHCXpfq0zVlDnBXZw3 /K6P7YBZ4Qo5L/kTtsk4ZfTmrgZ0aXVXMbCkYaJWrUr1Doq1iDfxIuCUCkXqJuCQ == From: Vishal Chourasia To: qemu-devel@nongnu.org, qemu-ppc@nongnu.org Cc: npiggin@gmail.com, rathc@linux.ibm.com, harshpb@linux.ibm.com, amachhiw@linux.ibm.com, sbhat@linux.ibm.com, gautam@linux.ibm.com, Vishal Chourasia Subject: [PATCH 1/2] ppc/spapr: refactor cpu hotplug code to separate file Date: Sat, 4 Jul 2026 16:06:14 +0530 Message-ID: <20260704103617.632929-4-vishalc@linux.ibm.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260704103617.632929-2-vishalc@linux.ibm.com> References: <20260704103617.632929-2-vishalc@linux.ibm.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-TM-AS-GCONF: 00 X-Proofpoint-Reinject: loops=2 maxloops=12 X-Proofpoint-Spam-Info: AW1haW4tMjYwNzA0MDEwMiBTYWx0ZWRfX02pHS2zsjpw5 kV7t0wmFqno51fV6HPbFnKwoNlq/N9gbsQsvy+TBAci1GxxfQcIQnLsCBtUYLU2EhWytW3axbJO 9I0p2FSZeqHm89KVRlfgcKqgut9cj7s= X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwNzA0MDEwMiBTYWx0ZWRfXzL8OBVg/aC8w JFRTmyL8ff7lg/tJqcwWwz5QQFK/4Vzyn7yyheEhJGC+h4x67z0mMT5GFFXqRE52M+sd/INC6Tz IYhtSEvLEqKn1L6s+/ZTt7jC06H79BH/HUwwU1kGwonxjporWjKuYqf0S9w2UB3apaT+UGuTbvi NWnPcV7C3Jpx8yoc+9yTs7FiJTnimVkNFtqslrn1ohoHjhoM1l2XBS8/aAcvNlhBKOhYS7tlQ4Q oR+x3tcvcOCP6Xqphm+mQCzXFx11MP4LLuMBHOHPC/GhV1wC/Yiq0etp9AKvG5JwR50prGnwUe5 rF4QGhZNKuSaoXUVLqiiVcxGt06MOxM1TcfBb18d+wR+zozcYliOq4qM89DOayEvBtvRG5zgl2E GOiPk0NEN+cfqjG6MbDbfwq6CJqegaSStIL7sQwaxgiP2HBE+xosdYbKJIc/u8txLrUuSPl68bl C1knNM3FlSZUIqEVziA== X-Proofpoint-GUID: 5mghCe_gL_gk9VKQ8-dQcQyeIqQ1O77P X-Authority-Analysis: v=2.4 cv=Oot/DS/t c=1 sm=1 tr=0 ts=6a48e241 cx=c_pps a=GFwsV6G8L6GxiO2Y/PsHdQ==:117 a=GFwsV6G8L6GxiO2Y/PsHdQ==:17 a=IkcTkHD0fZMA:10 a=RAioF0-LDSMA:10 a=VkNPw1HP01LnGYTKEx00:22 a=RnoormkPH1_aCDwRdu11:22 a=uAbxVGIbfxUO_5tXvNgY:22 a=VnNF1IyMAAAA:8 a=pGLkceISAAAA:8 a=QV2DFvGgecQSnC3fnDYA:9 a=3ZKOabzyN94A:10 a=QEXdDO2ut3YA:10 X-Proofpoint-ORIG-GUID: Y8MQLPSljNqRoJRIpON7vpAZeE1yBgoc X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1143,Hydra:6.1.125,FMLib:17.12.100.49 definitions=2026-07-04_01,2026-07-03_01,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 bulkscore=0 lowpriorityscore=0 clxscore=1015 impostorscore=0 phishscore=0 malwarescore=0 suspectscore=0 spamscore=0 adultscore=0 priorityscore=1501 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2606150000 definitions=main-2607040102 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=148.163.156.1; envelope-from=vishalc@linux.ibm.com; helo=mx0a-001b2d01.pphosted.com X-Spam_score_int: -26 X-Spam_score: -2.7 X-Spam_bar: -- X-Spam_report: (-2.7 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_MSPIKE_H4=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @ibm.com) X-ZM-MESSAGEID: 1783161475252158501 Move CPU hotplug-related code from spapr.c into a new dedicated file spapr_cpu_hotplug.c. A corresponding header file exports the public interfaces needed by other sPAPR subsystems. Also updating MAINTAINERS entry for PPC KVM CPUs to include these newly added files along with spapr_cpu_core.c for better maintainability. Signed-off-by: Vishal Chourasia --- MAINTAINERS | 3 + hw/ppc/meson.build | 1 + hw/ppc/spapr.c | 903 +------------------------- hw/ppc/spapr_cpu_hotplug.c | 984 +++++++++++++++++++++++++++++ include/hw/ppc/spapr_cpu_hotplug.h | 74 +++ 5 files changed, 1063 insertions(+), 902 deletions(-) create mode 100644 hw/ppc/spapr_cpu_hotplug.c create mode 100644 include/hw/ppc/spapr_cpu_hotplug.h diff --git a/MAINTAINERS b/MAINTAINERS index 97dcc78ded..cb19e868b4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -490,6 +490,9 @@ M: Nicholas Piggin R: Harsh Prateek Bora S: Odd Fixes F: target/ppc/kvm.c +F: hw/ppc/spapr_cpu_core.c +F: hw/ppc/spapr_cpu_hotplug.c +F: include/hw/ppc/spapr_cpu_hotplug.h =20 S390 KVM CPUs M: Halil Pasic diff --git a/hw/ppc/meson.build b/hw/ppc/meson.build index 37aa535db2..98435bbca9 100644 --- a/hw/ppc/meson.build +++ b/hw/ppc/meson.build @@ -20,6 +20,7 @@ ppc_ss.add(when: 'CONFIG_PSERIES', if_true: files( 'spapr_rtc.c', 'spapr_drc.c', 'spapr_cpu_core.c', + 'spapr_cpu_hotplug.c', 'spapr_ovec.c', 'spapr_irq.c', 'spapr_tpm_proxy.c', diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index b79828b4e9..374bf1cfbf 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -88,6 +88,7 @@ #include "hw/intc/intc.h" =20 #include "hw/ppc/spapr_cpu_core.h" +#include "hw/ppc/spapr_cpu_hotplug.h" #include "hw/mem/memory-device.h" #include "hw/ppc/spapr_tpm_proxy.h" #include "hw/ppc/spapr_nvdimm.h" @@ -116,220 +117,6 @@ =20 #define PHANDLE_INTC 0x00001111 =20 -/* These two functions implement the VCPU id numbering: one to compute them - * all and one to identify thread 0 of a VCORE. Any change to the first one - * is likely to have an impact on the second one, so let's keep them close. - */ -static int spapr_vcpu_id(SpaprMachineState *spapr, int cpu_index) -{ - MachineState *ms =3D MACHINE(spapr); - unsigned int smp_threads =3D ms->smp.threads; - - assert(spapr->vsmt); - return - (cpu_index / smp_threads) * spapr->vsmt + cpu_index % smp_threads; -} -static bool spapr_is_thread0_in_vcore(SpaprMachineState *spapr, - PowerPCCPU *cpu) -{ - assert(spapr->vsmt); - return spapr_get_vcpu_id(cpu) % spapr->vsmt =3D=3D 0; -} - -int spapr_max_server_number(SpaprMachineState *spapr) -{ - MachineState *ms =3D MACHINE(spapr); - - assert(spapr->vsmt); - return DIV_ROUND_UP(ms->smp.max_cpus * spapr->vsmt, ms->smp.threads); -} - -static int spapr_fixup_cpu_smt_dt(void *fdt, int offset, PowerPCCPU *cpu, - int smt_threads) -{ - int i, ret =3D 0; - g_autofree uint32_t *servers_prop =3D g_new(uint32_t, smt_threads); - g_autofree uint32_t *gservers_prop =3D g_new(uint32_t, smt_threads * 2= ); - int index =3D spapr_get_vcpu_id(cpu); - - if (cpu->compat_pvr) { - ret =3D fdt_setprop_cell(fdt, offset, "cpu-version", cpu->compat_p= vr); - if (ret < 0) { - return ret; - } - } - - /* Build interrupt servers and gservers properties */ - for (i =3D 0; i < smt_threads; i++) { - servers_prop[i] =3D cpu_to_be32(index + i); - /* Hack, direct the group queues back to cpu 0 */ - gservers_prop[i*2] =3D cpu_to_be32(index + i); - gservers_prop[i*2 + 1] =3D 0; - } - ret =3D fdt_setprop(fdt, offset, "ibm,ppc-interrupt-server#s", - servers_prop, sizeof(*servers_prop) * smt_threads); - if (ret < 0) { - return ret; - } - ret =3D fdt_setprop(fdt, offset, "ibm,ppc-interrupt-gserver#s", - gservers_prop, sizeof(*gservers_prop) * smt_threads = * 2); - - return ret; -} - -static void spapr_dt_pa_features(SpaprMachineState *spapr, - PowerPCCPU *cpu, - void *fdt, int offset) -{ - /* - * SSO (SAO) ordering is supported on KVM and thread=3Dsingle hosts, - * but not MTTCG, so disable it. To advertise it, a cap would have - * to be added, or support implemented for MTTCG. - * - * Copy/paste is not supported by TCG, so it is not advertised. KVM - * can execute them but it has no accelerator drivers which are usable, - * so there isn't much need for it anyway. - */ - - /* These should be kept in sync with pnv */ - uint8_t pa_features_206[] =3D { 6, 0, - 0xf6, 0x1f, 0xc7, 0x00, 0x00, 0xc0 }; - uint8_t pa_features_207[] =3D { 24, 0, - 0xf6, 0x1f, 0xc7, 0xc0, 0x00, 0xf0, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, - 0x80, 0x00, 0x80, 0x00, 0x00, 0x00 }; - uint8_t pa_features_300[] =3D { 66, 0, - /* 0: MMU|FPU|SLB|RUN|DABR|NX, 1: fri[nzpm]|DABRX|SPRG3|SLB0|PP110= */ - /* 2: VPM|DS205|PPR|DS202|DS206, 3: LSD|URG, 5: LE|CFAR|EB|LSQ */ - 0xf6, 0x1f, 0xc7, 0xc0, 0x00, 0xf0, /* 0 - 5 */ - /* 6: DS207 */ - 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, /* 6 - 11 */ - /* 16: Vector */ - 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, /* 12 - 17 */ - /* 18: Vec. Scalar, 20: Vec. XOR */ - 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, /* 18 - 23 */ - /* 24: Ext. Dec, 26: 64 bit ftrs, 28: PM ftrs */ - 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 24 - 29 */ - /* 32: LE atomic, 34: EBB + ext EBB */ - 0x00, 0x00, 0x80, 0x00, 0xC0, 0x00, /* 30 - 35 */ - /* 40: Radix MMU */ - 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, /* 36 - 41 */ - /* 42: PM, 44: PC RA, 46: SC vec'd */ - 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 42 - 47 */ - /* 48: SIMD, 50: QP BFP, 52: String */ - 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 48 - 53 */ - /* 54: DecFP, 56: DecI, 58: SHA */ - 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 54 - 59 */ - /* 60: NM atomic, 62: RNG */ - 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, /* 60 - 65 */ - }; - /* 3.1 removes SAO, HTM support */ - uint8_t pa_features_31[] =3D { 74, 0, - /* 0: MMU|FPU|SLB|RUN|DABR|NX, 1: fri[nzpm]|DABRX|SPRG3|SLB0|PP110= */ - /* 2: VPM|DS205|PPR|DS202|DS206, 3: LSD|URG, 5: LE|CFAR|EB|LSQ */ - 0xf6, 0x1f, 0xc7, 0xc0, 0x00, 0xf0, /* 0 - 5 */ - /* 6: DS207 */ - 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, /* 6 - 11 */ - /* 16: Vector */ - 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, /* 12 - 17 */ - /* 18: Vec. Scalar, 20: Vec. XOR */ - 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, /* 18 - 23 */ - /* 24: Ext. Dec, 26: 64 bit ftrs, 28: PM ftrs */ - 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 24 - 29 */ - /* 32: LE atomic, 34: EBB + ext EBB */ - 0x00, 0x00, 0x80, 0x00, 0xC0, 0x00, /* 30 - 35 */ - /* 40: Radix MMU */ - 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, /* 36 - 41 */ - /* 42: PM, 44: PC RA, 46: SC vec'd */ - 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 42 - 47 */ - /* 48: SIMD, 50: QP BFP, 52: String */ - 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 48 - 53 */ - /* 54: DecFP, 56: DecI, 58: SHA */ - 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 54 - 59 */ - /* 60: NM atomic, 62: RNG, 64: DAWR1 (ISA 3.1) */ - 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, /* 60 - 65 */ - /* 68: DEXCR[SBHE|IBRTPDUS|SRAPD|NPHIE|PHIE] */ - 0x00, 0x00, 0xce, 0x00, 0x00, 0x00, /* 66 - 71 */ - /* 72: [P]HASHST/[P]HASHCHK */ - 0x80, 0x00, /* 72 - 73 */ - }; - uint8_t *pa_features =3D NULL; - size_t pa_size; - - if (ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_06, 0, cpu->compat_pvr= )) { - pa_features =3D pa_features_206; - pa_size =3D sizeof(pa_features_206); - } - if (ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_07, 0, cpu->compat_pvr= )) { - pa_features =3D pa_features_207; - pa_size =3D sizeof(pa_features_207); - } - if (ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_3_00, 0, cpu->compat_pvr= )) { - pa_features =3D pa_features_300; - pa_size =3D sizeof(pa_features_300); - } - if (ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_3_10, 0, cpu->compat_pvr= )) { - pa_features =3D pa_features_31; - pa_size =3D sizeof(pa_features_31); - } - if (!pa_features) { - return; - } - - if (ppc_hash64_has(cpu, PPC_HASH64_CI_LARGEPAGE)) { - /* - * Note: we keep CI large pages off by default because a 64K capab= le - * guest provisioned with large pages might otherwise try to map a= qemu - * framebuffer (or other kind of memory mapped PCI BAR) using 64K = pages - * even if that qemu runs on a 4k host. - * We dd this bit back here if we are confident this is not an iss= ue - */ - pa_features[3] |=3D 0x20; - } - if ((spapr_get_cap(spapr, SPAPR_CAP_HTM) !=3D 0) && pa_size > 24) { - pa_features[24] |=3D 0x80; /* Transactional memory support */ - } - if (spapr->cas_pre_isa3_guest && pa_size > 40) { - /* Workaround for broken kernels that attempt (guest) radix - * mode when they can't handle it, if they see the radix bit set - * in pa-features. So hide it from them. */ - pa_features[40 + 2] &=3D ~0x80; /* Radix MMU */ - } - if (spapr_get_cap(spapr, SPAPR_CAP_DAWR1)) { - g_assert(pa_size > 66); - pa_features[66] |=3D 0x80; - } - - _FDT((fdt_setprop(fdt, offset, "ibm,pa-features", pa_features, pa_size= ))); -} - -static void spapr_dt_pi_features(SpaprMachineState *spapr, - PowerPCCPU *cpu, - void *fdt, int offset) -{ - uint8_t pi_features[] =3D { 1, 0, - 0x00 }; - - if (kvm_enabled() && ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_3_00, - 0, cpu->compat_pvr)) { - /* - * POWER9 and later CPUs with KVM run in LPAR-per-thread mode where - * all threads are essentially independent CPUs, and msgsndp does = not - * work (because it is physically-addressed) and therefore is - * emulated by KVM, so disable it here to ensure XIVE will be used. - * This is both KVM and CPU implementation-specific behaviour so a= KVM - * cap would be cleanest, but for now this works. If KVM ever perm= its - * native msgsndp execution by guests, a cap could be added at that - * time. - */ - pi_features[2] |=3D 0x08; /* 4: No msgsndp */ - } - - _FDT((fdt_setprop(fdt, offset, "ibm,pi-features", pi_features, - sizeof(pi_features)))); -} - static hwaddr spapr_node0_size(MachineState *machine) { if (machine->numa_state->num_nodes) { @@ -685,200 +472,6 @@ static int spapr_dt_memory(SpaprMachineState *spapr, = void *fdt) return 0; } =20 -static void spapr_dt_cpu(CPUState *cs, void *fdt, int offset, - SpaprMachineState *spapr) -{ - MachineState *ms =3D MACHINE(spapr); - PowerPCCPU *cpu =3D POWERPC_CPU(cs); - CPUPPCState *env =3D &cpu->env; - PowerPCCPUClass *pcc =3D POWERPC_CPU_GET_CLASS(cs); - int index =3D spapr_get_vcpu_id(cpu); - uint32_t segs[] =3D {cpu_to_be32(28), cpu_to_be32(40), - 0xffffffff, 0xffffffff}; - uint32_t tbfreq =3D kvm_enabled() ? kvmppc_get_tbfreq() - : SPAPR_TIMEBASE_FREQ; - uint32_t cpufreq =3D kvm_enabled() ? kvmppc_get_clockfreq() : 10000000= 00; - uint32_t page_sizes_prop[64]; - size_t page_sizes_prop_size; - unsigned int smp_threads =3D ms->smp.threads; - uint32_t vcpus_per_socket =3D smp_threads * ms->smp.cores; - uint32_t pft_size_prop[] =3D {0, cpu_to_be32(spapr->htab_shift)}; - int compat_smt =3D MIN(smp_threads, ppc_compat_max_vthreads(cpu)); - SpaprDrc *drc; - int drc_index; - uint32_t radix_AP_encodings[PPC_PAGE_SIZES_MAX_SZ]; - int i; - - drc =3D spapr_drc_by_id(TYPE_SPAPR_DRC_CPU, env->core_index); - if (drc) { - drc_index =3D spapr_drc_index(drc); - _FDT((fdt_setprop_cell(fdt, offset, "ibm,my-drc-index", drc_index)= )); - } - - _FDT((fdt_setprop_cell(fdt, offset, "reg", index))); - _FDT((fdt_setprop_string(fdt, offset, "device_type", "cpu"))); - - _FDT((fdt_setprop_cell(fdt, offset, "cpu-version", env->spr[SPR_PVR]))= ); - _FDT((fdt_setprop_cell(fdt, offset, "d-cache-block-size", - env->dcache_line_size))); - _FDT((fdt_setprop_cell(fdt, offset, "d-cache-line-size", - env->dcache_line_size))); - _FDT((fdt_setprop_cell(fdt, offset, "i-cache-block-size", - env->icache_line_size))); - _FDT((fdt_setprop_cell(fdt, offset, "i-cache-line-size", - env->icache_line_size))); - - if (pcc->l1_dcache_size) { - _FDT((fdt_setprop_cell(fdt, offset, "d-cache-size", - pcc->l1_dcache_size))); - } else { - warn_report("Unknown L1 dcache size for cpu"); - } - if (pcc->l1_icache_size) { - _FDT((fdt_setprop_cell(fdt, offset, "i-cache-size", - pcc->l1_icache_size))); - } else { - warn_report("Unknown L1 icache size for cpu"); - } - - _FDT((fdt_setprop_cell(fdt, offset, "timebase-frequency", tbfreq))); - _FDT((fdt_setprop_cell(fdt, offset, "clock-frequency", cpufreq))); - _FDT((fdt_setprop_cell(fdt, offset, "slb-size", cpu->hash64_opts->slb_= size))); - _FDT((fdt_setprop_cell(fdt, offset, "ibm,slb-size", cpu->hash64_opts->= slb_size))); - _FDT((fdt_setprop_string(fdt, offset, "status", "okay"))); - _FDT((fdt_setprop(fdt, offset, "64-bit", NULL, 0))); - - if (ppc_has_spr(cpu, SPR_PURR)) { - _FDT((fdt_setprop_cell(fdt, offset, "ibm,purr", 1))); - } - if (ppc_has_spr(cpu, SPR_PURR)) { - _FDT((fdt_setprop_cell(fdt, offset, "ibm,spurr", 1))); - } - - if (ppc_hash64_has(cpu, PPC_HASH64_1TSEG)) { - _FDT((fdt_setprop(fdt, offset, "ibm,processor-segment-sizes", - segs, sizeof(segs)))); - } - - /* Advertise VSX (vector extensions) if available - * 1 =3D=3D VMX / Altivec available - * 2 =3D=3D VSX available - * - * Only CPUs for which we create core types in spapr_cpu_core.c - * are possible, and all of those have VMX */ - if (env->insns_flags & PPC_ALTIVEC) { - if (spapr_get_cap(spapr, SPAPR_CAP_VSX) !=3D 0) { - _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", 2))); - } else { - _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", 1))); - } - } - - /* Advertise DFP (Decimal Floating Point) if available - * 0 / no property =3D=3D no DFP - * 1 =3D=3D DFP available */ - if (spapr_get_cap(spapr, SPAPR_CAP_DFP) !=3D 0) { - _FDT((fdt_setprop_cell(fdt, offset, "ibm,dfp", 1))); - } - - page_sizes_prop_size =3D ppc_create_page_sizes_prop(cpu, page_sizes_pr= op, - sizeof(page_sizes_pr= op)); - if (page_sizes_prop_size) { - _FDT((fdt_setprop(fdt, offset, "ibm,segment-page-sizes", - page_sizes_prop, page_sizes_prop_size))); - } - - spapr_dt_pa_features(spapr, cpu, fdt, offset); - - spapr_dt_pi_features(spapr, cpu, fdt, offset); - - _FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id", - cs->cpu_index / vcpus_per_socket))); - - _FDT((fdt_setprop(fdt, offset, "ibm,pft-size", - pft_size_prop, sizeof(pft_size_prop)))); - - if (ms->numa_state->num_nodes > 1) { - _FDT(spapr_numa_fixup_cpu_dt(spapr, fdt, offset, cpu)); - } - - _FDT(spapr_fixup_cpu_smt_dt(fdt, offset, cpu, compat_smt)); - - if (pcc->radix_page_info) { - for (i =3D 0; i < pcc->radix_page_info->count; i++) { - radix_AP_encodings[i] =3D - cpu_to_be32(pcc->radix_page_info->entries[i]); - } - _FDT((fdt_setprop(fdt, offset, "ibm,processor-radix-AP-encodings", - radix_AP_encodings, - pcc->radix_page_info->count * - sizeof(radix_AP_encodings[0])))); - } - - /* - * We set this property to let the guest know that it can use the large - * decrementer and its width in bits. - */ - if (spapr_get_cap(spapr, SPAPR_CAP_LARGE_DECREMENTER) !=3D SPAPR_CAP_O= FF) - _FDT((fdt_setprop_u32(fdt, offset, "ibm,dec-bits", - pcc->lrg_decr_bits))); -} - -static void spapr_dt_one_cpu(void *fdt, SpaprMachineState *spapr, CPUState= *cs, - int cpus_offset) -{ - PowerPCCPU *cpu =3D POWERPC_CPU(cs); - int index =3D spapr_get_vcpu_id(cpu); - DeviceClass *dc =3D DEVICE_GET_CLASS(cs); - g_autofree char *nodename =3D NULL; - int offset; - - if (!spapr_is_thread0_in_vcore(spapr, cpu)) { - return; - } - - nodename =3D g_strdup_printf("%s@%x", dc->fw_name, index); - offset =3D fdt_add_subnode(fdt, cpus_offset, nodename); - _FDT(offset); - spapr_dt_cpu(cs, fdt, offset, spapr); -} - - -static void spapr_dt_cpus(void *fdt, SpaprMachineState *spapr) -{ - CPUState **rev; - CPUState *cs; - int n_cpus; - int cpus_offset; - int i; - - cpus_offset =3D fdt_add_subnode(fdt, 0, "cpus"); - _FDT(cpus_offset); - _FDT((fdt_setprop_cell(fdt, cpus_offset, "#address-cells", 0x1))); - _FDT((fdt_setprop_cell(fdt, cpus_offset, "#size-cells", 0x0))); - - /* - * We walk the CPUs in reverse order to ensure that CPU DT nodes - * created by fdt_add_subnode() end up in the right order in FDT - * for the guest kernel the enumerate the CPUs correctly. - * - * The CPU list cannot be traversed in reverse order, so we need - * to do extra work. - */ - n_cpus =3D 0; - rev =3D NULL; - CPU_FOREACH(cs) { - rev =3D g_renew(CPUState *, rev, n_cpus + 1); - rev[n_cpus++] =3D cs; - } - - for (i =3D n_cpus - 1; i >=3D 0; i--) { - spapr_dt_one_cpu(fdt, spapr, rev[i], cpus_offset); - } - - g_free(rev); -} - static int spapr_dt_rng(void *fdt) { int node; @@ -2650,150 +2243,6 @@ static void spapr_validate_node_memory(MachineState= *machine, Error **errp) } =20 /* find cpu slot in machine->possible_cpus by core_id */ -static CPUArchId *spapr_find_cpu_slot(MachineState *ms, uint32_t id, int *= idx) -{ - int index =3D id / ms->smp.threads; - - if (index >=3D ms->possible_cpus->len) { - return NULL; - } - if (idx) { - *idx =3D index; - } - return &ms->possible_cpus->cpus[index]; -} - -static void spapr_set_vsmt_mode(SpaprMachineState *spapr, Error **errp) -{ - MachineState *ms =3D MACHINE(spapr); - Error *local_err =3D NULL; - bool vsmt_user =3D !!spapr->vsmt; - int kvm_smt =3D kvmppc_smt_threads(); - int ret; - unsigned int smp_threads =3D ms->smp.threads; - - if (tcg_enabled()) { - if (smp_threads > 1 && - !ppc_type_check_compat(ms->cpu_type, CPU_POWERPC_LOGICAL_2_07,= 0, - spapr->max_compat_pvr)) { - error_setg(errp, "TCG only supports SMT on POWER8 or newer CPU= s"); - return; - } - - if (smp_threads > 8) { - error_setg(errp, "TCG cannot support more than 8 threads/core " - "on a pseries machine"); - return; - } - } - if (!is_power_of_2(smp_threads)) { - error_setg(errp, "Cannot support %d threads/core on a pseries " - "machine because it must be a power of 2", smp_threads); - return; - } - - /* Determine the VSMT mode to use: */ - if (vsmt_user) { - if (spapr->vsmt < smp_threads) { - error_setg(errp, "Cannot support VSMT mode %d" - " because it must be >=3D threads/core (%d)", - spapr->vsmt, smp_threads); - return; - } - /* In this case, spapr->vsmt has been set by the command line */ - } else { - spapr->vsmt =3D smp_threads; - } - - /* KVM: If necessary, set the SMT mode: */ - if (kvm_enabled() && (spapr->vsmt !=3D kvm_smt)) { - ret =3D kvmppc_set_smt_threads(spapr->vsmt); - if (ret) { - /* Looks like KVM isn't able to change VSMT mode */ - error_setg_errno(&local_err, -ret, - "Failed to set KVM's VSMT mode to %d", - spapr->vsmt); - /* We can live with that if the default one is big enough - * for the number of threads, and a submultiple of the one - * we want. In this case we'll waste some vcpu ids, but - * behaviour will be correct */ - if ((kvm_smt >=3D smp_threads) && ((spapr->vsmt % kvm_smt) =3D= =3D 0)) { - warn_report_err(local_err); - } else { - if (!vsmt_user) { - error_append_hint(&local_err, - "On PPC, a VM with %d threads/core" - " on a host with %d threads/core" - " requires the use of VSMT mode %d.\= n", - smp_threads, kvm_smt, spapr->vsmt); - } - kvmppc_error_append_smt_possible_hint(&local_err); - error_propagate(errp, local_err); - } - } - } - /* else TCG: nothing to do currently */ -} - -static void spapr_init_cpus(SpaprMachineState *spapr) -{ - MachineState *machine =3D MACHINE(spapr); - MachineClass *mc =3D MACHINE_GET_CLASS(machine); - const char *type =3D spapr_get_cpu_core_type(machine->cpu_type); - const CPUArchIdList *possible_cpus; - unsigned int smp_cpus =3D machine->smp.cpus; - unsigned int smp_threads =3D machine->smp.threads; - unsigned int max_cpus =3D machine->smp.max_cpus; - int boot_cores_nr =3D smp_cpus / smp_threads; - int i; - - possible_cpus =3D mc->possible_cpu_arch_ids(machine); - if (mc->has_hotpluggable_cpus) { - if (smp_cpus % smp_threads) { - error_report("smp_cpus (%u) must be multiple of threads (%u)", - smp_cpus, smp_threads); - exit(1); - } - if (max_cpus % smp_threads) { - error_report("max_cpus (%u) must be multiple of threads (%u)", - max_cpus, smp_threads); - exit(1); - } - } else { - if (max_cpus !=3D smp_cpus) { - error_report("This machine version does not support CPU hotplu= g"); - exit(1); - } - boot_cores_nr =3D possible_cpus->len; - } - - for (i =3D 0; i < possible_cpus->len; i++) { - int core_id =3D i * smp_threads; - - if (mc->has_hotpluggable_cpus) { - spapr_dr_connector_new(OBJECT(spapr), TYPE_SPAPR_DRC_CPU, - spapr_vcpu_id(spapr, core_id)); - } - - if (i < boot_cores_nr) { - Object *core =3D object_new(type); - int nr_threads =3D smp_threads; - - /* Handle the partially filled core for older machine types */ - if ((i + 1) * smp_threads >=3D smp_cpus) { - nr_threads =3D smp_cpus - i * smp_threads; - } - - object_property_set_int(core, "nr-threads", nr_threads, - &error_fatal); - object_property_set_int(core, CPU_CORE_PROP_CORE_ID, core_id, - &error_fatal); - qdev_realize(DEVICE(core), NULL, &error_fatal); - - object_unref(core); - } - } -} =20 static PCIHostState *spapr_create_default_phb(void) { @@ -3896,206 +3345,6 @@ static void spapr_memory_unplug_request(HotplugHand= ler *hotplug_dev, nr_lmbs, spapr_drc_index(drc= )); } =20 -/* Callback to be called during DRC release. */ -void spapr_core_release(DeviceState *dev) -{ - HotplugHandler *hotplug_ctrl =3D qdev_get_hotplug_handler(dev); - - /* Call the unplug handler chain. This can never fail. */ - hotplug_handler_unplug(hotplug_ctrl, dev, &error_abort); - object_unparent(OBJECT(dev)); -} - -static void spapr_core_unplug(HotplugHandler *hotplug_dev, DeviceState *de= v) -{ - MachineState *ms =3D MACHINE(hotplug_dev); - CPUCore *cc =3D CPU_CORE(dev); - CPUArchId *core_slot =3D spapr_find_cpu_slot(ms, cc->core_id, NULL); - - assert(core_slot); - core_slot->cpu =3D NULL; - qdev_unrealize(dev); -} - -static -void spapr_core_unplug_request(HotplugHandler *hotplug_dev, DeviceState *d= ev, - Error **errp) -{ - SpaprMachineState *spapr =3D SPAPR_MACHINE(OBJECT(hotplug_dev)); - int index; - SpaprDrc *drc; - CPUCore *cc =3D CPU_CORE(dev); - - if (!spapr_find_cpu_slot(MACHINE(hotplug_dev), cc->core_id, &index)) { - error_setg(errp, "Unable to find CPU core with core-id: %d", - cc->core_id); - return; - } - if (index =3D=3D 0) { - error_setg(errp, "Boot CPU core may not be unplugged"); - return; - } - - drc =3D spapr_drc_by_id(TYPE_SPAPR_DRC_CPU, - spapr_vcpu_id(spapr, cc->core_id)); - g_assert(drc); - - if (!spapr_drc_unplug_requested(drc)) { - spapr_drc_unplug_request(drc); - } - - /* - * spapr_hotplug_req_remove_by_index is left unguarded, out of the - * "!spapr_drc_unplug_requested" check, to allow for multiple IRQ - * pulses removing the same CPU. Otherwise, in an failed hotunplug - * attempt (e.g. the kernel will refuse to remove the last online - * CPU), we will never attempt it again because unplug_requested - * will still be 'true' in that case. - */ - spapr_hotplug_req_remove_by_index(drc); -} - -int spapr_core_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr, - void *fdt, int *fdt_start_offset, Error **errp) -{ - SpaprCpuCore *core =3D SPAPR_CPU_CORE(drc->dev); - CPUState *cs =3D CPU(core->threads[0]); - PowerPCCPU *cpu =3D POWERPC_CPU(cs); - DeviceClass *dc =3D DEVICE_GET_CLASS(cs); - int id =3D spapr_get_vcpu_id(cpu); - g_autofree char *nodename =3D NULL; - int offset; - - nodename =3D g_strdup_printf("%s@%x", dc->fw_name, id); - offset =3D fdt_add_subnode(fdt, 0, nodename); - - spapr_dt_cpu(cs, fdt, offset, spapr); - - /* - * spapr_dt_cpu() does not fill the 'name' property in the - * CPU node. The function is called during boot process, before - * and after CAS, and overwriting the 'name' property written - * by SLOF is not allowed. - * - * Write it manually after spapr_dt_cpu(). This makes the hotplug - * CPUs more compatible with the coldplugged ones, which have - * the 'name' property. Linux Kernel also relies on this - * property to identify CPU nodes. - */ - _FDT((fdt_setprop_string(fdt, offset, "name", nodename))); - - *fdt_start_offset =3D offset; - return 0; -} - -static void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev) -{ - SpaprMachineState *spapr =3D SPAPR_MACHINE(OBJECT(hotplug_dev)); - MachineClass *mc =3D MACHINE_GET_CLASS(spapr); - SpaprCpuCore *core =3D SPAPR_CPU_CORE(OBJECT(dev)); - CPUCore *cc =3D CPU_CORE(dev); - SpaprDrc *drc; - CPUArchId *core_slot; - int index; - bool hotplugged =3D spapr_drc_hotplugged(dev); - int i; - - core_slot =3D spapr_find_cpu_slot(MACHINE(hotplug_dev), cc->core_id, &= index); - g_assert(core_slot); /* Already checked in spapr_core_pre_plug() */ - - drc =3D spapr_drc_by_id(TYPE_SPAPR_DRC_CPU, - spapr_vcpu_id(spapr, cc->core_id)); - - g_assert(drc || !mc->has_hotpluggable_cpus); - - if (drc) { - /* - * spapr_core_pre_plug() already buys us this is a brand new - * core being plugged into a free slot. Nothing should already - * be attached to the corresponding DRC. - */ - spapr_drc_attach(drc, dev); - - if (hotplugged) { - /* - * Send hotplug notification interrupt to the guest only - * in case of hotplugged CPUs. - */ - spapr_hotplug_req_add_by_index(drc); - } else { - spapr_drc_reset(drc); - } - } - - core_slot->cpu =3D CPU(dev); - - /* - * Set compatibility mode to match the boot CPU, which was either set - * by the machine reset code or by CAS. This really shouldn't fail at - * this point. - */ - if (hotplugged) { - for (i =3D 0; i < cc->nr_threads; i++) { - ppc_set_compat(core->threads[i], POWERPC_CPU(first_cpu)->compa= t_pvr, - &error_abort); - } - } - -} - -static void spapr_core_pre_plug(HotplugHandler *hotplug_dev, DeviceState *= dev, - Error **errp) -{ - MachineState *machine =3D MACHINE(OBJECT(hotplug_dev)); - MachineClass *mc =3D MACHINE_GET_CLASS(hotplug_dev); - CPUCore *cc =3D CPU_CORE(dev); - const char *base_core_type =3D spapr_get_cpu_core_type(machine->cpu_ty= pe); - const char *type =3D object_get_typename(OBJECT(dev)); - CPUArchId *core_slot; - int index; - unsigned int smp_threads =3D machine->smp.threads; - - if (dev->hotplugged && !mc->has_hotpluggable_cpus) { - error_setg(errp, "CPU hotplug not supported for this machine"); - return; - } - - if (strcmp(base_core_type, type)) { - error_setg(errp, "CPU core type should be %s", base_core_type); - return; - } - - if (cc->core_id % smp_threads) { - error_setg(errp, "invalid core id %d", cc->core_id); - return; - } - - /* - * In general we should have homogeneous threads-per-core, but old - * (pre hotplug support) machine types allow the last core to have - * reduced threads as a compatibility hack for when we allowed - * total vcpus not a multiple of threads-per-core. - */ - if (mc->has_hotpluggable_cpus && (cc->nr_threads !=3D smp_threads)) { - error_setg(errp, "invalid nr-threads %d, must be %d", cc->nr_threa= ds, - smp_threads); - return; - } - - core_slot =3D spapr_find_cpu_slot(MACHINE(hotplug_dev), cc->core_id, &= index); - if (!core_slot) { - error_setg(errp, "core id %d out of range", cc->core_id); - return; - } - - if (core_slot->cpu) { - error_setg(errp, "core %d already populated", cc->core_id); - return; - } - - numa_cpu_pre_plug(core_slot, dev, errp); -} - int spapr_phb_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr, void *fdt, int *fdt_start_offset, Error **errp) { @@ -4386,63 +3635,6 @@ static HotplugHandler *spapr_get_hotplug_handler(Mac= hineState *machine, return NULL; } =20 -static CpuInstanceProperties -spapr_cpu_index_to_props(MachineState *machine, unsigned cpu_index) -{ - CPUArchId *core_slot; - MachineClass *mc =3D MACHINE_GET_CLASS(machine); - - /* make sure possible_cpu are initialized */ - mc->possible_cpu_arch_ids(machine); - /* get CPU core slot containing thread that matches cpu_index */ - core_slot =3D spapr_find_cpu_slot(machine, cpu_index, NULL); - assert(core_slot); - return core_slot->props; -} - -static int64_t spapr_get_default_cpu_node_id(const MachineState *ms, int i= dx) -{ - return idx / ms->smp.cores % ms->numa_state->num_nodes; -} - -static const CPUArchIdList *spapr_possible_cpu_arch_ids(MachineState *mach= ine) -{ - int i; - unsigned int smp_threads =3D machine->smp.threads; - unsigned int smp_cpus =3D machine->smp.cpus; - const char *core_type; - int spapr_max_cores =3D machine->smp.max_cpus / smp_threads; - MachineClass *mc =3D MACHINE_GET_CLASS(machine); - - if (!mc->has_hotpluggable_cpus) { - spapr_max_cores =3D QEMU_ALIGN_UP(smp_cpus, smp_threads) / smp_thr= eads; - } - if (machine->possible_cpus) { - assert(machine->possible_cpus->len =3D=3D spapr_max_cores); - return machine->possible_cpus; - } - - core_type =3D spapr_get_cpu_core_type(machine->cpu_type); - if (!core_type) { - error_report("Unable to find sPAPR CPU Core definition"); - exit(1); - } - - machine->possible_cpus =3D g_malloc0(sizeof(CPUArchIdList) + - sizeof(CPUArchId) * spapr_max_cores); - machine->possible_cpus->len =3D spapr_max_cores; - for (i =3D 0; i < machine->possible_cpus->len; i++) { - int core_id =3D i * smp_threads; - - machine->possible_cpus->cpus[i].type =3D core_type; - machine->possible_cpus->cpus[i].vcpus_count =3D smp_threads; - machine->possible_cpus->cpus[i].arch_id =3D core_id; - machine->possible_cpus->cpus[i].props.has_core_id =3D true; - machine->possible_cpus->cpus[i].props.core_id =3D core_id; - } - return machine->possible_cpus; -} - static ICSState *spapr_ics_get(XICSFabric *dev, int irq) { SpaprMachineState *spapr =3D SPAPR_MACHINE(dev); @@ -4504,99 +3696,6 @@ static bool spapr_match_nvt(XiveFabric *xfb, uint8_t= format, return true; } =20 -int spapr_get_vcpu_id(PowerPCCPU *cpu) -{ - return cpu->vcpu_id; -} - -bool spapr_set_vcpu_id(PowerPCCPU *cpu, int cpu_index, Error **errp) -{ - SpaprMachineState *spapr =3D SPAPR_MACHINE(qdev_get_machine()); - MachineState *ms =3D MACHINE(spapr); - int vcpu_id; - - vcpu_id =3D spapr_vcpu_id(spapr, cpu_index); - - if (kvm_enabled() && !kvm_vcpu_id_is_valid(vcpu_id)) { - error_setg(errp, "Can't create CPU with id %d in KVM", vcpu_id); - error_append_hint(errp, "Adjust the number of cpus to %d " - "or try to raise the number of threads per core\= n", - vcpu_id * ms->smp.threads / spapr->vsmt); - return false; - } - - cpu->vcpu_id =3D vcpu_id; - return true; -} - -PowerPCCPU *spapr_find_cpu(int vcpu_id) -{ - CPUState *cs; - - CPU_FOREACH(cs) { - PowerPCCPU *cpu =3D POWERPC_CPU(cs); - - if (spapr_get_vcpu_id(cpu) =3D=3D vcpu_id) { - return cpu; - } - } - - return NULL; -} - -static bool spapr_cpu_in_nested(PowerPCCPU *cpu) -{ - SpaprCpuState *spapr_cpu =3D spapr_cpu_state(cpu); - - return spapr_cpu->in_nested; -} - -static void spapr_cpu_exec_enter(PPCVirtualHypervisor *vhyp, PowerPCCPU *c= pu) -{ - SpaprCpuState *spapr_cpu =3D spapr_cpu_state(cpu); - - /* These are only called by TCG, KVM maintains dispatch state */ - - spapr_cpu->prod =3D false; - if (spapr_cpu->vpa_addr) { - CPUState *cs =3D CPU(cpu); - uint32_t dispatch; - - dispatch =3D ldl_be_phys(cs->as, - spapr_cpu->vpa_addr + VPA_DISPATCH_COUNTER); - dispatch++; - if ((dispatch & 1) !=3D 0) { - qemu_log_mask(LOG_GUEST_ERROR, - "VPA: incorrect dispatch counter value for " - "dispatched partition %u, correcting.\n", dispat= ch); - dispatch++; - } - stl_be_phys(cs->as, - spapr_cpu->vpa_addr + VPA_DISPATCH_COUNTER, dispatch); - } -} - -static void spapr_cpu_exec_exit(PPCVirtualHypervisor *vhyp, PowerPCCPU *cp= u) -{ - SpaprCpuState *spapr_cpu =3D spapr_cpu_state(cpu); - - if (spapr_cpu->vpa_addr) { - CPUState *cs =3D CPU(cpu); - uint32_t dispatch; - - dispatch =3D ldl_be_phys(cs->as, - spapr_cpu->vpa_addr + VPA_DISPATCH_COUNTER); - dispatch++; - if ((dispatch & 1) !=3D 1) { - qemu_log_mask(LOG_GUEST_ERROR, - "VPA: incorrect dispatch counter value for " - "preempted partition %u, correcting.\n", dispatc= h); - dispatch++; - } - stl_be_phys(cs->as, - spapr_cpu->vpa_addr + VPA_DISPATCH_COUNTER, dispatch); - } -} =20 static void spapr_machine_class_init(ObjectClass *oc, const void *data) { diff --git a/hw/ppc/spapr_cpu_hotplug.c b/hw/ppc/spapr_cpu_hotplug.c new file mode 100644 index 0000000000..d570fca417 --- /dev/null +++ b/hw/ppc/spapr_cpu_hotplug.c @@ -0,0 +1,984 @@ +/* + * sPAPR CPU hotplug =E2=80=94 VCPU-id helpers, device-tree generation, and + * HotplugHandler / PPCVirtualHypervisor callbacks for sPAPR CPU cores. + * + * Code moved from hw/ppc/spapr.c; no functional changes. + * + * Copyright (c) 2004-2007 Fabrice Bellard + * Copyright (c) 2007 Jocelyn Mayer + * Copyright (c) 2010-2024 IBM Corporation. + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qemu/error-report.h" +#include "qemu/log.h" +#include "qapi/error.h" +#include "exec/cpu-common.h" +#include "system/cpus.h" +#include "system/kvm.h" +#include "system/numa.h" +#include "system/tcg.h" +#include "hw/core/cpu.h" +#include "hw/ppc/fdt.h" +#include "hw/ppc/ppc.h" +#include "hw/ppc/spapr.h" +#include "hw/ppc/spapr_cpu_core.h" +#include "hw/ppc/spapr_cpu_hotplug.h" +#include "hw/ppc/spapr_drc.h" +#include "hw/ppc/spapr_numa.h" +#include "kvm_ppc.h" +#include "mmu-hash64.h" +#include "target/ppc/cpu.h" +#include "target/ppc/cpu-qom.h" +#include "target/ppc/cpu-models.h" +#include "target/ppc/mmu-hash64.h" + +#include + +/* + * VCPU-id / VSMT helpers + */ + +/* + * These two functions implement the VCPU id numbering: one to compute them + * all and one to identify thread 0 of a VCORE. Any change to the first one + * is likely to have an impact on the second one, so let's keep them close. + */ +int spapr_vcpu_id(SpaprMachineState *spapr, int cpu_index) +{ + MachineState *ms =3D MACHINE(spapr); + unsigned int smp_threads =3D ms->smp.threads; + + assert(spapr->vsmt); + return + (cpu_index / smp_threads) * spapr->vsmt + cpu_index % smp_threads; +} + +bool spapr_is_thread0_in_vcore(SpaprMachineState *spapr, PowerPCCPU *cpu) +{ + assert(spapr->vsmt); + return spapr_get_vcpu_id(cpu) % spapr->vsmt =3D=3D 0; +} + +int spapr_max_server_number(SpaprMachineState *spapr) +{ + MachineState *ms =3D MACHINE(spapr); + + assert(spapr->vsmt); + return DIV_ROUND_UP(ms->smp.max_cpus * spapr->vsmt, ms->smp.threads); +} + +/* + * CPU slot lookup + */ + +/* find cpu slot in machine->possible_cpus by core_id */ +CPUArchId *spapr_find_cpu_slot(MachineState *ms, uint32_t id, int *idx) +{ + int index =3D id / ms->smp.threads; + + if (index >=3D ms->possible_cpus->len) { + return NULL; + } + if (idx) { + *idx =3D index; + } + return &ms->possible_cpus->cpus[index]; +} + +/* + * Machine-initialisation helpers + */ + +void spapr_set_vsmt_mode(SpaprMachineState *spapr, Error **errp) +{ + MachineState *ms =3D MACHINE(spapr); + Error *local_err =3D NULL; + bool vsmt_user =3D !!spapr->vsmt; + int kvm_smt =3D kvmppc_smt_threads(); + int ret; + unsigned int smp_threads =3D ms->smp.threads; + + if (tcg_enabled()) { + if (smp_threads > 1 && + !ppc_type_check_compat(ms->cpu_type, CPU_POWERPC_LOGICAL_2_07,= 0, + spapr->max_compat_pvr)) { + error_setg(errp, "TCG only supports SMT on POWER8 or newer CPU= s"); + return; + } + + if (smp_threads > 8) { + error_setg(errp, "TCG cannot support more than 8 threads/core " + "on a pseries machine"); + return; + } + } + if (!is_power_of_2(smp_threads)) { + error_setg(errp, "Cannot support %d threads/core on a pseries " + "machine because it must be a power of 2", smp_threads); + return; + } + + /* Determine the VSMT mode to use: */ + if (vsmt_user) { + if (spapr->vsmt < smp_threads) { + error_setg(errp, "Cannot support VSMT mode %d" + " because it must be >=3D threads/core (%d)", + spapr->vsmt, smp_threads); + return; + } + /* In this case, spapr->vsmt has been set by the command line */ + } else { + spapr->vsmt =3D smp_threads; + } + + /* KVM: If necessary, set the SMT mode: */ + if (kvm_enabled() && (spapr->vsmt !=3D kvm_smt)) { + ret =3D kvmppc_set_smt_threads(spapr->vsmt); + if (ret) { + /* Looks like KVM isn't able to change VSMT mode */ + error_setg_errno(&local_err, -ret, + "Failed to set KVM's VSMT mode to %d", + spapr->vsmt); + /* + * We can live with that if the default one is big enough + * for the number of threads, and a submultiple of the one + * we want. In this case we'll waste some vcpu ids, but + * behaviour will be correct + */ + if ((kvm_smt >=3D smp_threads) && ((spapr->vsmt % kvm_smt) =3D= =3D 0)) { + warn_report_err(local_err); + } else { + if (!vsmt_user) { + error_append_hint(&local_err, + "On PPC, a VM with %d threads/core" + " on a host with %d threads/core" + " requires the use of VSMT mode %d.\= n", + smp_threads, kvm_smt, spapr->vsmt); + } + kvmppc_error_append_smt_possible_hint(&local_err); + error_propagate(errp, local_err); + } + } + } + /* else TCG: nothing to do currently */ +} + +void spapr_init_cpus(SpaprMachineState *spapr) +{ + MachineState *machine =3D MACHINE(spapr); + MachineClass *mc =3D MACHINE_GET_CLASS(machine); + const char *type =3D spapr_get_cpu_core_type(machine->cpu_type); + const CPUArchIdList *possible_cpus; + unsigned int smp_cpus =3D machine->smp.cpus; + unsigned int smp_threads =3D machine->smp.threads; + unsigned int max_cpus =3D machine->smp.max_cpus; + int boot_cores_nr =3D smp_cpus / smp_threads; + int i; + + possible_cpus =3D mc->possible_cpu_arch_ids(machine); + if (mc->has_hotpluggable_cpus) { + if (smp_cpus % smp_threads) { + error_report("smp_cpus (%u) must be multiple of threads (%u)", + smp_cpus, smp_threads); + exit(1); + } + if (max_cpus % smp_threads) { + error_report("max_cpus (%u) must be multiple of threads (%u)", + max_cpus, smp_threads); + exit(1); + } + } else { + if (max_cpus !=3D smp_cpus) { + error_report("This machine version does not support CPU hotplu= g"); + exit(1); + } + boot_cores_nr =3D possible_cpus->len; + } + + for (i =3D 0; i < possible_cpus->len; i++) { + int core_id =3D i * smp_threads; + + if (mc->has_hotpluggable_cpus) { + spapr_dr_connector_new(OBJECT(spapr), TYPE_SPAPR_DRC_CPU, + spapr_vcpu_id(spapr, core_id)); + } + + if (i < boot_cores_nr) { + Object *core =3D object_new(type); + int nr_threads =3D smp_threads; + + /* Handle the partially filled core for older machine types */ + if ((i + 1) * smp_threads >=3D smp_cpus) { + nr_threads =3D smp_cpus - i * smp_threads; + } + + object_property_set_int(core, "nr-threads", nr_threads, + &error_fatal); + object_property_set_int(core, CPU_CORE_PROP_CORE_ID, core_id, + &error_fatal); + qdev_realize(DEVICE(core), NULL, &error_fatal); + + object_unref(core); + } + } +} + +/* + * Device-tree helpers + */ + +static int spapr_fixup_cpu_smt_dt(void *fdt, int offset, PowerPCCPU *cpu, + int smt_threads) +{ + int i, ret =3D 0; + g_autofree uint32_t *servers_prop =3D g_new(uint32_t, smt_threads); + g_autofree uint32_t *gservers_prop =3D g_new(uint32_t, smt_threads * 2= ); + int index =3D spapr_get_vcpu_id(cpu); + + if (cpu->compat_pvr) { + ret =3D fdt_setprop_cell(fdt, offset, "cpu-version", cpu->compat_p= vr); + if (ret < 0) { + return ret; + } + } + + /* Build interrupt servers and gservers properties */ + for (i =3D 0; i < smt_threads; i++) { + servers_prop[i] =3D cpu_to_be32(index + i); + /* Hack, direct the group queues back to cpu 0 */ + gservers_prop[i * 2] =3D cpu_to_be32(index + i); + gservers_prop[i * 2 + 1] =3D 0; + } + ret =3D fdt_setprop(fdt, offset, "ibm,ppc-interrupt-server#s", + servers_prop, sizeof(*servers_prop) * smt_threads); + if (ret < 0) { + return ret; + } + ret =3D fdt_setprop(fdt, offset, "ibm,ppc-interrupt-gserver#s", + gservers_prop, sizeof(*gservers_prop) * smt_threads = * 2); + + return ret; +} + +static void spapr_dt_pa_features(SpaprMachineState *spapr, + PowerPCCPU *cpu, + void *fdt, int offset) +{ + /* + * SSO (SAO) ordering is supported on KVM and thread=3Dsingle hosts, + * but not MTTCG, so disable it. To advertise it, a cap would have + * to be added, or support implemented for MTTCG. + * + * Copy/paste is not supported by TCG, so it is not advertised. KVM + * can execute them but it has no accelerator drivers which are usable, + * so there isn't much need for it anyway. + */ + + /* These should be kept in sync with pnv */ + uint8_t pa_features_206[] =3D { 6, 0, + 0xf6, 0x1f, 0xc7, 0x00, 0x00, 0xc0 }; + uint8_t pa_features_207[] =3D { 24, 0, + 0xf6, 0x1f, 0xc7, 0xc0, 0x00, 0xf0, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, + 0x80, 0x00, 0x80, 0x00, 0x00, 0x00 }; + uint8_t pa_features_300[] =3D { 66, 0, + /* 0: MMU|FPU|SLB|RUN|DABR|NX, 1: fri[nzpm]|DABRX|SPRG3|SLB0|PP110= */ + /* 2: VPM|DS205|PPR|DS202|DS206, 3: LSD|URG, 5: LE|CFAR|EB|LSQ */ + 0xf6, 0x1f, 0xc7, 0xc0, 0x00, 0xf0, /* 0 - 5 */ + /* 6: DS207 */ + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, /* 6 - 11 */ + /* 16: Vector */ + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, /* 12 - 17 */ + /* 18: Vec. Scalar, 20: Vec. XOR */ + 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, /* 18 - 23 */ + /* 24: Ext. Dec, 26: 64 bit ftrs, 28: PM ftrs */ + 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 24 - 29 */ + /* 32: LE atomic, 34: EBB + ext EBB */ + 0x00, 0x00, 0x80, 0x00, 0xC0, 0x00, /* 30 - 35 */ + /* 40: Radix MMU */ + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, /* 36 - 41 */ + /* 42: PM, 44: PC RA, 46: SC vec'd */ + 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 42 - 47 */ + /* 48: SIMD, 50: QP BFP, 52: String */ + 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 48 - 53 */ + /* 54: DecFP, 56: DecI, 58: SHA */ + 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 54 - 59 */ + /* 60: NM atomic, 62: RNG */ + 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, /* 60 - 65 */ + }; + /* 3.1 removes SAO, HTM support */ + uint8_t pa_features_31[] =3D { 74, 0, + /* 0: MMU|FPU|SLB|RUN|DABR|NX, 1: fri[nzpm]|DABRX|SPRG3|SLB0|PP110= */ + /* 2: VPM|DS205|PPR|DS202|DS206, 3: LSD|URG, 5: LE|CFAR|EB|LSQ */ + 0xf6, 0x1f, 0xc7, 0xc0, 0x00, 0xf0, /* 0 - 5 */ + /* 6: DS207 */ + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, /* 6 - 11 */ + /* 16: Vector */ + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, /* 12 - 17 */ + /* 18: Vec. Scalar, 20: Vec. XOR */ + 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, /* 18 - 23 */ + /* 24: Ext. Dec, 26: 64 bit ftrs, 28: PM ftrs */ + 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 24 - 29 */ + /* 32: LE atomic, 34: EBB + ext EBB */ + 0x00, 0x00, 0x80, 0x00, 0xC0, 0x00, /* 30 - 35 */ + /* 40: Radix MMU */ + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, /* 36 - 41 */ + /* 42: PM, 44: PC RA, 46: SC vec'd */ + 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 42 - 47 */ + /* 48: SIMD, 50: QP BFP, 52: String */ + 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 48 - 53 */ + /* 54: DecFP, 56: DecI, 58: SHA */ + 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 54 - 59 */ + /* 60: NM atomic, 62: RNG, 64: DAWR1 (ISA 3.1) */ + 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, /* 60 - 65 */ + /* 68: DEXCR[SBHE|IBRTPDUS|SRAPD|NPHIE|PHIE] */ + 0x00, 0x00, 0xce, 0x00, 0x00, 0x00, /* 66 - 71 */ + /* 72: [P]HASHST/[P]HASHCHK */ + 0x80, 0x00, /* 72 - 73 */ + }; + uint8_t *pa_features =3D NULL; + size_t pa_size; + + if (ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_06, 0, cpu->compat_pvr= )) { + pa_features =3D pa_features_206; + pa_size =3D sizeof(pa_features_206); + } + if (ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_07, 0, cpu->compat_pvr= )) { + pa_features =3D pa_features_207; + pa_size =3D sizeof(pa_features_207); + } + if (ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_3_00, 0, cpu->compat_pvr= )) { + pa_features =3D pa_features_300; + pa_size =3D sizeof(pa_features_300); + } + if (ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_3_10, 0, cpu->compat_pvr= )) { + pa_features =3D pa_features_31; + pa_size =3D sizeof(pa_features_31); + } + if (!pa_features) { + return; + } + + if (ppc_hash64_has(cpu, PPC_HASH64_CI_LARGEPAGE)) { + /* + * Note: we keep CI large pages off by default because a 64K capab= le + * guest provisioned with large pages might otherwise try to map a= qemu + * framebuffer (or other kind of memory mapped PCI BAR) using 64K = pages + * even if that qemu runs on a 4k host. + * We dd this bit back here if we are confident this is not an iss= ue + */ + pa_features[3] |=3D 0x20; + } + if ((spapr_get_cap(spapr, SPAPR_CAP_HTM) !=3D 0) && pa_size > 24) { + pa_features[24] |=3D 0x80; /* Transactional memory support */ + } + if (spapr->cas_pre_isa3_guest && pa_size > 40) { + /* + * Workaround for broken kernels that attempt (guest) radix + * mode when they can't handle it, if they see the radix bit set + * in pa-features. So hide it from them. + */ + pa_features[40 + 2] &=3D ~0x80; /* Radix MMU */ + } + if (spapr_get_cap(spapr, SPAPR_CAP_DAWR1)) { + g_assert(pa_size > 66); + pa_features[66] |=3D 0x80; + } + + _FDT((fdt_setprop(fdt, offset, "ibm,pa-features", pa_features, pa_size= ))); +} + +static void spapr_dt_pi_features(SpaprMachineState *spapr, + PowerPCCPU *cpu, + void *fdt, int offset) +{ + uint8_t pi_features[] =3D { 1, 0, + 0x00 }; + + if (kvm_enabled() && ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_3_00, + 0, cpu->compat_pvr)) { + /* + * POWER9 and later CPUs with KVM run in LPAR-per-thread mode where + * all threads are essentially independent CPUs, and msgsndp does = not + * work (because it is physically-addressed) and therefore is + * emulated by KVM, so disable it here to ensure XIVE will be used. + * This is both KVM and CPU implementation-specific behaviour so a= KVM + * cap would be cleanest, but for now this works. If KVM ever perm= its + * native msgsndp execution by guests, a cap could be added at that + * time. + */ + pi_features[2] |=3D 0x08; /* 4: No msgsndp */ + } + + _FDT((fdt_setprop(fdt, offset, "ibm,pi-features", pi_features, + sizeof(pi_features)))); +} + +void spapr_dt_cpu(CPUState *cs, void *fdt, int offset, + SpaprMachineState *spapr) +{ + MachineState *ms =3D MACHINE(spapr); + PowerPCCPU *cpu =3D POWERPC_CPU(cs); + CPUPPCState *env =3D &cpu->env; + PowerPCCPUClass *pcc =3D POWERPC_CPU_GET_CLASS(cs); + int index =3D spapr_get_vcpu_id(cpu); + uint32_t segs[] =3D {cpu_to_be32(28), cpu_to_be32(40), + 0xffffffff, 0xffffffff}; + uint32_t tbfreq =3D kvm_enabled() ? kvmppc_get_tbfreq() + : SPAPR_TIMEBASE_FREQ; + uint32_t cpufreq =3D kvm_enabled() ? kvmppc_get_clockfreq() : 10000000= 00; + uint32_t page_sizes_prop[64]; + size_t page_sizes_prop_size; + unsigned int smp_threads =3D ms->smp.threads; + uint32_t vcpus_per_socket =3D smp_threads * ms->smp.cores; + uint32_t pft_size_prop[] =3D {0, cpu_to_be32(spapr->htab_shift)}; + int compat_smt =3D MIN(smp_threads, ppc_compat_max_vthreads(cpu)); + SpaprDrc *drc; + int drc_index; + uint32_t radix_AP_encodings[PPC_PAGE_SIZES_MAX_SZ]; + int i; + + drc =3D spapr_drc_by_id(TYPE_SPAPR_DRC_CPU, env->core_index); + if (drc) { + drc_index =3D spapr_drc_index(drc); + _FDT((fdt_setprop_cell(fdt, offset, "ibm,my-drc-index", drc_index)= )); + } + + _FDT((fdt_setprop_cell(fdt, offset, "reg", index))); + _FDT((fdt_setprop_string(fdt, offset, "device_type", "cpu"))); + + _FDT((fdt_setprop_cell(fdt, offset, "cpu-version", env->spr[SPR_PVR]))= ); + _FDT((fdt_setprop_cell(fdt, offset, "d-cache-block-size", + env->dcache_line_size))); + _FDT((fdt_setprop_cell(fdt, offset, "d-cache-line-size", + env->dcache_line_size))); + _FDT((fdt_setprop_cell(fdt, offset, "i-cache-block-size", + env->icache_line_size))); + _FDT((fdt_setprop_cell(fdt, offset, "i-cache-line-size", + env->icache_line_size))); + + if (pcc->l1_dcache_size) { + _FDT((fdt_setprop_cell(fdt, offset, "d-cache-size", + pcc->l1_dcache_size))); + } else { + warn_report("Unknown L1 dcache size for cpu"); + } + if (pcc->l1_icache_size) { + _FDT((fdt_setprop_cell(fdt, offset, "i-cache-size", + pcc->l1_icache_size))); + } else { + warn_report("Unknown L1 icache size for cpu"); + } + + _FDT((fdt_setprop_cell(fdt, offset, "timebase-frequency", tbfreq))); + _FDT((fdt_setprop_cell(fdt, offset, "clock-frequency", cpufreq))); + _FDT((fdt_setprop_cell(fdt, offset, "slb-size", + cpu->hash64_opts->slb_size))); + _FDT((fdt_setprop_cell(fdt, offset, "ibm,slb-size", + cpu->hash64_opts->slb_size))); + _FDT((fdt_setprop_string(fdt, offset, "status", "okay"))); + _FDT((fdt_setprop(fdt, offset, "64-bit", NULL, 0))); + + if (ppc_has_spr(cpu, SPR_PURR)) { + _FDT((fdt_setprop_cell(fdt, offset, "ibm,purr", 1))); + } + if (ppc_has_spr(cpu, SPR_PURR)) { + _FDT((fdt_setprop_cell(fdt, offset, "ibm,spurr", 1))); + } + + if (ppc_hash64_has(cpu, PPC_HASH64_1TSEG)) { + _FDT((fdt_setprop(fdt, offset, "ibm,processor-segment-sizes", + segs, sizeof(segs)))); + } + + /* + * Advertise VSX (vector extensions) if available + * 1 =3D=3D VMX / Altivec available + * 2 =3D=3D VSX available + * + * Only CPUs for which we create core types in spapr_cpu_core.c + * are possible, and all of those have VMX + */ + if (env->insns_flags & PPC_ALTIVEC) { + if (spapr_get_cap(spapr, SPAPR_CAP_VSX) !=3D 0) { + _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", 2))); + } else { + _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", 1))); + } + } + + /* + * Advertise DFP (Decimal Floating Point) if available + * 0 / no property =3D=3D no DFP + * 1 =3D=3D DFP available + */ + if (spapr_get_cap(spapr, SPAPR_CAP_DFP) !=3D 0) { + _FDT((fdt_setprop_cell(fdt, offset, "ibm,dfp", 1))); + } + + page_sizes_prop_size =3D ppc_create_page_sizes_prop(cpu, page_sizes_pr= op, + sizeof(page_sizes_pr= op)); + if (page_sizes_prop_size) { + _FDT((fdt_setprop(fdt, offset, "ibm,segment-page-sizes", + page_sizes_prop, page_sizes_prop_size))); + } + + spapr_dt_pa_features(spapr, cpu, fdt, offset); + + spapr_dt_pi_features(spapr, cpu, fdt, offset); + + _FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id", + cs->cpu_index / vcpus_per_socket))); + + _FDT((fdt_setprop(fdt, offset, "ibm,pft-size", + pft_size_prop, sizeof(pft_size_prop)))); + + if (ms->numa_state->num_nodes > 1) { + _FDT(spapr_numa_fixup_cpu_dt(spapr, fdt, offset, cpu)); + } + + _FDT(spapr_fixup_cpu_smt_dt(fdt, offset, cpu, compat_smt)); + + if (pcc->radix_page_info) { + for (i =3D 0; i < pcc->radix_page_info->count; i++) { + radix_AP_encodings[i] =3D + cpu_to_be32(pcc->radix_page_info->entries[i]); + } + _FDT((fdt_setprop(fdt, offset, "ibm,processor-radix-AP-encodings", + radix_AP_encodings, + pcc->radix_page_info->count * + sizeof(radix_AP_encodings[0])))); + } + + /* + * We set this property to let the guest know that it can use the large + * decrementer and its width in bits. + */ + if (spapr_get_cap(spapr, SPAPR_CAP_LARGE_DECREMENTER) !=3D SPAPR_CAP_O= FF) + _FDT((fdt_setprop_u32(fdt, offset, "ibm,dec-bits", + pcc->lrg_decr_bits))); +} + +static void spapr_dt_one_cpu(void *fdt, SpaprMachineState *spapr, CPUState= *cs, + int cpus_offset) +{ + PowerPCCPU *cpu =3D POWERPC_CPU(cs); + int index =3D spapr_get_vcpu_id(cpu); + DeviceClass *dc =3D DEVICE_GET_CLASS(cs); + g_autofree char *nodename =3D NULL; + int offset; + + if (!spapr_is_thread0_in_vcore(spapr, cpu)) { + return; + } + + nodename =3D g_strdup_printf("%s@%x", dc->fw_name, index); + offset =3D fdt_add_subnode(fdt, cpus_offset, nodename); + _FDT(offset); + spapr_dt_cpu(cs, fdt, offset, spapr); +} + +void spapr_dt_cpus(void *fdt, SpaprMachineState *spapr) +{ + CPUState **rev; + CPUState *cs; + int n_cpus; + int cpus_offset; + int i; + + cpus_offset =3D fdt_add_subnode(fdt, 0, "cpus"); + _FDT(cpus_offset); + _FDT((fdt_setprop_cell(fdt, cpus_offset, "#address-cells", 0x1))); + _FDT((fdt_setprop_cell(fdt, cpus_offset, "#size-cells", 0x0))); + + /* + * We walk the CPUs in reverse order to ensure that CPU DT nodes + * created by fdt_add_subnode() end up in the right order in FDT + * for the guest kernel the enumerate the CPUs correctly. + * + * The CPU list cannot be traversed in reverse order, so we need + * to do extra work. + */ + n_cpus =3D 0; + rev =3D NULL; + CPU_FOREACH(cs) { + rev =3D g_renew(CPUState *, rev, n_cpus + 1); + rev[n_cpus++] =3D cs; + } + + for (i =3D n_cpus - 1; i >=3D 0; i--) { + spapr_dt_one_cpu(fdt, spapr, rev[i], cpus_offset); + } + + g_free(rev); +} + +/* + * HotplugHandler callbacks + */ + +/* Callback to be called during DRC release. */ +void spapr_core_release(DeviceState *dev) +{ + HotplugHandler *hotplug_ctrl =3D qdev_get_hotplug_handler(dev); + + /* Call the unplug handler chain. This can never fail. */ + hotplug_handler_unplug(hotplug_ctrl, dev, &error_abort); + object_unparent(OBJECT(dev)); +} + +void spapr_core_unplug(HotplugHandler *hotplug_dev, DeviceState *dev) +{ + MachineState *ms =3D MACHINE(hotplug_dev); + CPUCore *cc =3D CPU_CORE(dev); + CPUArchId *core_slot =3D spapr_find_cpu_slot(ms, cc->core_id, NULL); + + assert(core_slot); + core_slot->cpu =3D NULL; + qdev_unrealize(dev); +} + +void spapr_core_unplug_request(HotplugHandler *hotplug_dev, DeviceState *d= ev, + Error **errp) +{ + SpaprMachineState *spapr =3D SPAPR_MACHINE(OBJECT(hotplug_dev)); + int index; + SpaprDrc *drc; + CPUCore *cc =3D CPU_CORE(dev); + + if (!spapr_find_cpu_slot(MACHINE(hotplug_dev), cc->core_id, &index)) { + error_setg(errp, "Unable to find CPU core with core-id: %d", + cc->core_id); + return; + } + if (index =3D=3D 0) { + error_setg(errp, "Boot CPU core may not be unplugged"); + return; + } + + drc =3D spapr_drc_by_id(TYPE_SPAPR_DRC_CPU, + spapr_vcpu_id(spapr, cc->core_id)); + g_assert(drc); + + if (!spapr_drc_unplug_requested(drc)) { + spapr_drc_unplug_request(drc); + } + + /* + * spapr_hotplug_req_remove_by_index is left unguarded, out of the + * "!spapr_drc_unplug_requested" check, to allow for multiple IRQ + * pulses removing the same CPU. Otherwise, in an failed hotunplug + * attempt (e.g. the kernel will refuse to remove the last online + * CPU), we will never attempt it again because unplug_requested + * will still be 'true' in that case. + */ + spapr_hotplug_req_remove_by_index(drc); +} + +int spapr_core_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr, + void *fdt, int *fdt_start_offset, Error **errp) +{ + SpaprCpuCore *core =3D SPAPR_CPU_CORE(drc->dev); + CPUState *cs =3D CPU(core->threads[0]); + PowerPCCPU *cpu =3D POWERPC_CPU(cs); + DeviceClass *dc =3D DEVICE_GET_CLASS(cs); + int id =3D spapr_get_vcpu_id(cpu); + g_autofree char *nodename =3D NULL; + int offset; + + nodename =3D g_strdup_printf("%s@%x", dc->fw_name, id); + offset =3D fdt_add_subnode(fdt, 0, nodename); + + spapr_dt_cpu(cs, fdt, offset, spapr); + + /* + * spapr_dt_cpu() does not fill the 'name' property in the + * CPU node. The function is called during boot process, before + * and after CAS, and overwriting the 'name' property written + * by SLOF is not allowed. + * + * Write it manually after spapr_dt_cpu(). This makes the hotplug + * CPUs more compatible with the coldplugged ones, which have + * the 'name' property. Linux Kernel also relies on this + * property to identify CPU nodes. + */ + _FDT((fdt_setprop_string(fdt, offset, "name", nodename))); + + *fdt_start_offset =3D offset; + return 0; +} + +void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev) +{ + SpaprMachineState *spapr =3D SPAPR_MACHINE(OBJECT(hotplug_dev)); + MachineClass *mc =3D MACHINE_GET_CLASS(spapr); + SpaprCpuCore *core =3D SPAPR_CPU_CORE(OBJECT(dev)); + CPUCore *cc =3D CPU_CORE(dev); + SpaprDrc *drc; + CPUArchId *core_slot; + int index; + bool hotplugged =3D spapr_drc_hotplugged(dev); + int i; + + core_slot =3D spapr_find_cpu_slot(MACHINE(hotplug_dev), cc->core_id, &= index); + g_assert(core_slot); /* Already checked in spapr_core_pre_plug() */ + + drc =3D spapr_drc_by_id(TYPE_SPAPR_DRC_CPU, + spapr_vcpu_id(spapr, cc->core_id)); + + g_assert(drc || !mc->has_hotpluggable_cpus); + + if (drc) { + /* + * spapr_core_pre_plug() already buys us this is a brand new + * core being plugged into a free slot. Nothing should already + * be attached to the corresponding DRC. + */ + spapr_drc_attach(drc, dev); + + if (hotplugged) { + /* + * Send hotplug notification interrupt to the guest only + * in case of hotplugged CPUs. + */ + spapr_hotplug_req_add_by_index(drc); + } else { + spapr_drc_reset(drc); + } + } + + core_slot->cpu =3D CPU(dev); + + /* + * Set compatibility mode to match the boot CPU, which was either set + * by the machine reset code or by CAS. This really shouldn't fail at + * this point. + */ + if (hotplugged) { + for (i =3D 0; i < cc->nr_threads; i++) { + ppc_set_compat(core->threads[i], POWERPC_CPU(first_cpu)->compa= t_pvr, + &error_abort); + } + } + +} + +void spapr_core_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev, + Error **errp) +{ + MachineState *machine =3D MACHINE(OBJECT(hotplug_dev)); + MachineClass *mc =3D MACHINE_GET_CLASS(hotplug_dev); + CPUCore *cc =3D CPU_CORE(dev); + const char *base_core_type =3D spapr_get_cpu_core_type(machine->cpu_ty= pe); + const char *type =3D object_get_typename(OBJECT(dev)); + CPUArchId *core_slot; + int index; + unsigned int smp_threads =3D machine->smp.threads; + + if (dev->hotplugged && !mc->has_hotpluggable_cpus) { + error_setg(errp, "CPU hotplug not supported for this machine"); + return; + } + + if (strcmp(base_core_type, type)) { + error_setg(errp, "CPU core type should be %s", base_core_type); + return; + } + + if (cc->core_id % smp_threads) { + error_setg(errp, "invalid core id %d", cc->core_id); + return; + } + + /* + * In general we should have homogeneous threads-per-core, but old + * (pre hotplug support) machine types allow the last core to have + * reduced threads as a compatibility hack for when we allowed + * total vcpus not a multiple of threads-per-core. + */ + if (mc->has_hotpluggable_cpus && (cc->nr_threads !=3D smp_threads)) { + error_setg(errp, "invalid nr-threads %d, must be %d", cc->nr_threa= ds, + smp_threads); + return; + } + + core_slot =3D spapr_find_cpu_slot(MACHINE(hotplug_dev), cc->core_id, &= index); + if (!core_slot) { + error_setg(errp, "core id %d out of range", cc->core_id); + return; + } + + if (core_slot->cpu) { + error_setg(errp, "core %d already populated", cc->core_id); + return; + } + + numa_cpu_pre_plug(core_slot, dev, errp); +} + +/* + * VCPU-id public accessors (consumed by spapr_hcall.c, spapr_rtas.c, =E2= =80=A6) + */ + +int spapr_get_vcpu_id(PowerPCCPU *cpu) +{ + return cpu->vcpu_id; +} + +bool spapr_set_vcpu_id(PowerPCCPU *cpu, int cpu_index, Error **errp) +{ + SpaprMachineState *spapr =3D SPAPR_MACHINE(qdev_get_machine()); + MachineState *ms =3D MACHINE(spapr); + int vcpu_id; + + vcpu_id =3D spapr_vcpu_id(spapr, cpu_index); + + if (kvm_enabled() && !kvm_vcpu_id_is_valid(vcpu_id)) { + error_setg(errp, "Can't create CPU with id %d in KVM", vcpu_id); + error_append_hint(errp, "Adjust the number of cpus to %d " + "or try to raise the number of threads per core\= n", + vcpu_id * ms->smp.threads / spapr->vsmt); + return false; + } + + cpu->vcpu_id =3D vcpu_id; + return true; +} + +PowerPCCPU *spapr_find_cpu(int vcpu_id) +{ + CPUState *cs; + + CPU_FOREACH(cs) { + PowerPCCPU *cpu =3D POWERPC_CPU(cs); + + if (spapr_get_vcpu_id(cpu) =3D=3D vcpu_id) { + return cpu; + } + } + + return NULL; +} + +/* + * Machine-class CPU-topology callbacks + */ + +CpuInstanceProperties +spapr_cpu_index_to_props(MachineState *machine, unsigned cpu_index) +{ + CPUArchId *core_slot; + MachineClass *mc =3D MACHINE_GET_CLASS(machine); + + /* make sure possible_cpu are initialized */ + mc->possible_cpu_arch_ids(machine); + /* get CPU core slot containing thread that matches cpu_index */ + core_slot =3D spapr_find_cpu_slot(machine, cpu_index, NULL); + assert(core_slot); + return core_slot->props; +} + +int64_t spapr_get_default_cpu_node_id(const MachineState *ms, int idx) +{ + return idx / ms->smp.cores % ms->numa_state->num_nodes; +} + +const CPUArchIdList *spapr_possible_cpu_arch_ids(MachineState *machine) +{ + int i; + unsigned int smp_threads =3D machine->smp.threads; + unsigned int smp_cpus =3D machine->smp.cpus; + const char *core_type; + int spapr_max_cores =3D machine->smp.max_cpus / smp_threads; + MachineClass *mc =3D MACHINE_GET_CLASS(machine); + + if (!mc->has_hotpluggable_cpus) { + spapr_max_cores =3D QEMU_ALIGN_UP(smp_cpus, smp_threads) / smp_thr= eads; + } + if (machine->possible_cpus) { + assert(machine->possible_cpus->len =3D=3D spapr_max_cores); + return machine->possible_cpus; + } + + core_type =3D spapr_get_cpu_core_type(machine->cpu_type); + if (!core_type) { + error_report("Unable to find sPAPR CPU Core definition"); + exit(1); + } + + machine->possible_cpus =3D g_malloc0(sizeof(CPUArchIdList) + + sizeof(CPUArchId) * spapr_max_cores); + machine->possible_cpus->len =3D spapr_max_cores; + for (i =3D 0; i < machine->possible_cpus->len; i++) { + int core_id =3D i * smp_threads; + + machine->possible_cpus->cpus[i].type =3D core_type; + machine->possible_cpus->cpus[i].vcpus_count =3D smp_threads; + machine->possible_cpus->cpus[i].arch_id =3D core_id; + machine->possible_cpus->cpus[i].props.has_core_id =3D true; + machine->possible_cpus->cpus[i].props.core_id =3D core_id; + } + return machine->possible_cpus; +} + +/* + * PPCVirtualHypervisor callbacks + */ + +bool spapr_cpu_in_nested(PowerPCCPU *cpu) +{ + SpaprCpuState *spapr_cpu =3D spapr_cpu_state(cpu); + + return spapr_cpu->in_nested; +} + +void spapr_cpu_exec_enter(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu) +{ + SpaprCpuState *spapr_cpu =3D spapr_cpu_state(cpu); + + /* These are only called by TCG, KVM maintains dispatch state */ + + spapr_cpu->prod =3D false; + if (spapr_cpu->vpa_addr) { + CPUState *cs =3D CPU(cpu); + uint32_t dispatch; + + dispatch =3D ldl_be_phys(cs->as, + spapr_cpu->vpa_addr + VPA_DISPATCH_COUNTER); + dispatch++; + if ((dispatch & 1) !=3D 0) { + qemu_log_mask(LOG_GUEST_ERROR, + "VPA: incorrect dispatch counter value for " + "dispatched partition %u, correcting.\n", dispat= ch); + dispatch++; + } + stl_be_phys(cs->as, + spapr_cpu->vpa_addr + VPA_DISPATCH_COUNTER, dispatch); + } +} + +void spapr_cpu_exec_exit(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu) +{ + SpaprCpuState *spapr_cpu =3D spapr_cpu_state(cpu); + + if (spapr_cpu->vpa_addr) { + CPUState *cs =3D CPU(cpu); + uint32_t dispatch; + + dispatch =3D ldl_be_phys(cs->as, + spapr_cpu->vpa_addr + VPA_DISPATCH_COUNTER); + dispatch++; + if ((dispatch & 1) !=3D 1) { + qemu_log_mask(LOG_GUEST_ERROR, + "VPA: incorrect dispatch counter value for " + "preempted partition %u, correcting.\n", dispatc= h); + dispatch++; + } + stl_be_phys(cs->as, + spapr_cpu->vpa_addr + VPA_DISPATCH_COUNTER, dispatch); + } +} + diff --git a/include/hw/ppc/spapr_cpu_hotplug.h b/include/hw/ppc/spapr_cpu_= hotplug.h new file mode 100644 index 0000000000..f3b74396b5 --- /dev/null +++ b/include/hw/ppc/spapr_cpu_hotplug.h @@ -0,0 +1,74 @@ +/* + * sPAPR CPU hotplug helpers. + * + * Declarations for functions that manage CPU device-tree generation, + * VSMT/VCPU-id mapping, CPU-slot lookup, machine initialisation, and + * the HotplugHandler / PPCVirtualHypervisor callbacks for sPAPR CPU cores. + * + * Copyright (c) 2010-2024 IBM Corporation. + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef HW_SPAPR_CPU_HOTPLUG_H +#define HW_SPAPR_CPU_HOTPLUG_H + +#include "hw/ppc/spapr.h" +#include "hw/ppc/spapr_drc.h" +#include "target/ppc/cpu-qom.h" +#include "hw/core/hotplug.h" + +/* ---- VCPU-id / VSMT helpers ------------------------------------------ = */ + +/* + * These two functions implement the VCPU-id numbering: one to compute + * them all, one to identify thread 0 of a vcore. Any change to the + * first is likely to affect the second, so they live together. + */ +int spapr_vcpu_id(SpaprMachineState *spapr, int cpu_index); +bool spapr_is_thread0_in_vcore(SpaprMachineState *spapr, PowerPCCPU *cpu); + +/* ---- CPU-slot lookup ------------------------------------------------- = */ + +/* Find the CPUArchId slot in machine->possible_cpus by core_id. */ +CPUArchId *spapr_find_cpu_slot(MachineState *ms, uint32_t id, int *idx); + +/* ---- Machine-initialisation helpers ---------------------------------- = */ + +void spapr_set_vsmt_mode(SpaprMachineState *spapr, Error **errp); +void spapr_init_cpus(SpaprMachineState *spapr); + +/* ---- Device-tree helpers --------------------------------------------- = */ + +/* + * spapr_dt_cpu() fills the FDT node at @offset for vCPU @cs, including + * ibm,my-drc-index, pa-features, interrupt-server#s, etc. It is called + * both during boot-time FDT construction and from spapr_core_dt_populate() + * during CPU hotplug. + */ +void spapr_dt_cpu(CPUState *cs, void *fdt, int offset, + SpaprMachineState *spapr); +void spapr_dt_cpus(void *fdt, SpaprMachineState *spapr); + +/* ---- HotplugHandler callbacks ---------------------------------------- = */ + +void spapr_core_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev, + Error **errp); +void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev); +void spapr_core_unplug(HotplugHandler *hotplug_dev, DeviceState *dev); +void spapr_core_unplug_request(HotplugHandler *hotplug_dev, DeviceState *d= ev, + Error **errp); + +/* ---- Machine-class CPU-topology callbacks -----------------------------= */ + +CpuInstanceProperties spapr_cpu_index_to_props(MachineState *machine, + unsigned cpu_index); +int64_t spapr_get_default_cpu_node_id(const MachineState *ms, int idx); +const CPUArchIdList *spapr_possible_cpu_arch_ids(MachineState *machine); + +/* ---- PPCVirtualHypervisor callbacks ---------------------------------- = */ + +bool spapr_cpu_in_nested(PowerPCCPU *cpu); +void spapr_cpu_exec_enter(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu); +void spapr_cpu_exec_exit(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu); + +#endif /* HW_SPAPR_CPU_HOTPLUG_H */ --=20 2.54.0 From nobody Sun Jul 26 10:59:41 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=reject dis=none) header.from=linux.ibm.com ARC-Seal: i=1; a=rsa-sha256; t=1783161472; cv=none; d=zohomail.com; s=zohoarc; b=IBlsskyDvRPp2369/7rEAlHsTXGvwlLFmqld5YQBTVi10oxYWFhPAHtKw7/OELhnyGpZQ4LKgtRH137Tl8AhpbNp2+sUxSdi3bCR7Z4HLhrWjzyLuNezVLaZwiYWcDRWgdUmhaZJRnpyPqvYYcJM0N4MlTJfJu1KEHfqEYV2E9s= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1783161472; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=KoIeVJ3ETvOlh+yzjsUUUmKatfq2crTb3gHjH9JpjUg=; b=TY7i81xLBU19XoYF3XU1svca0HKg3ssGn4DA/zIIqrbS1r5MabyfSjJiaXnGQqXHRN2P7gGRhS3mHj+3p2KHtTPeOtLcxZOLX8BXs4q6A0AiotceYiph2TDSC0S2+IozlWGIIWjHP529lm/dX37ygoFNdMoB24sz1lDunnhqbro= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=reject dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1783161472764709.4967605398933; Sat, 4 Jul 2026 03:37:52 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wfxkB-0002kf-QR; Sat, 04 Jul 2026 06:37:07 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wfxkA-0002kS-8M; Sat, 04 Jul 2026 06:37:06 -0400 Received: from mx0a-001b2d01.pphosted.com ([148.163.156.1]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wfxk8-0003Hv-P0; Sat, 04 Jul 2026 06:37:06 -0400 Received: from pps.filterd (m0353729.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 6647G3bs1065842; Sat, 4 Jul 2026 10:37:03 GMT Received: from ppma22.wdc07v.mail.ibm.com (5c.69.3da9.ip4.static.sl-reverse.com [169.61.105.92]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 4f6suq9150-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Sat, 04 Jul 2026 10:37:02 +0000 (GMT) Received: from pps.filterd (ppma22.wdc07v.mail.ibm.com [127.0.0.1]) by ppma22.wdc07v.mail.ibm.com (8.18.1.7/8.18.1.7) with ESMTP id 664AYaZ5011065; Sat, 4 Jul 2026 10:37:01 GMT Received: from smtprelay05.fra02v.mail.ibm.com ([9.218.2.225]) by ppma22.wdc07v.mail.ibm.com (PPS) with ESMTPS id 4f2s7wme9y-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Sat, 04 Jul 2026 10:37:01 +0000 (GMT) Received: from smtpav05.fra02v.mail.ibm.com (smtpav05.fra02v.mail.ibm.com [10.20.54.104]) by smtprelay05.fra02v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 664AavKf29032890 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Sat, 4 Jul 2026 10:36:57 GMT Received: from smtpav05.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 80CB820040; Sat, 4 Jul 2026 10:36:57 +0000 (GMT) Received: from smtpav05.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id C146A20043; Sat, 4 Jul 2026 10:36:54 +0000 (GMT) Received: from vishalc-ibm.ibm.com (unknown [9.124.212.207]) by smtpav05.fra02v.mail.ibm.com (Postfix) with ESMTP; Sat, 4 Jul 2026 10:36:54 +0000 (GMT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=cc :content-transfer-encoding:date:from:in-reply-to:message-id :mime-version:references:subject:to; s=pp1; bh=KoIeVJ3ETvOlh+yzj sUUUmKatfq2crTb3gHjH9JpjUg=; b=olMTwptYEg+aHaL75FQugDNvmjWno0Ase Yp+lQy18BXk6kiq+ht0DaiyXJEiU7RLoCd3cENQVGnkAx2ixIdlhDY6BXp43TZlk o2GJa5C9bWEr+ihraBDoDrtX2rc22iDJsIN7bDPOrPf6Fi5r1qCfOkwNTWAsU9gL y7VMu4CuIYvv02VvCJEPlA8uuffLtI8etTFHji+ZSD5valt3+iYEc4DSMPOK7OjL MZw4uWKCv4UHGzqpXTLue81K52LIsnUB02c6Z1GCJI3kBDVTgfOdg1hL2uHBhuWN MW+DIAXp5A8v7LfXW24M/v+0WPUWD4fJNTJou3OjBkDwalSEo3pTw== From: Vishal Chourasia To: qemu-devel@nongnu.org, qemu-ppc@nongnu.org Cc: npiggin@gmail.com, rathc@linux.ibm.com, harshpb@linux.ibm.com, amachhiw@linux.ibm.com, sbhat@linux.ibm.com, gautam@linux.ibm.com, Vishal Chourasia Subject: [PATCH 2/2] MAINTAINERS: add self as reviewer for PPC KVM CPUs Date: Sat, 4 Jul 2026 16:06:16 +0530 Message-ID: <20260704103617.632929-6-vishalc@linux.ibm.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260704103617.632929-2-vishalc@linux.ibm.com> References: <20260704103617.632929-2-vishalc@linux.ibm.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-TM-AS-GCONF: 00 X-Proofpoint-Reinject: loops=2 maxloops=12 X-Proofpoint-Spam-Info: AW1haW4tMjYwNzA0MDEwMiBTYWx0ZWRfXxKy2NS7VJj95 7TatVLif9FilA54gudnkb7ebfisFKS5js/NgblBgBKQ+WiVx9kV6IuNmPomyoxwlQnwqmKCKVYy bjTiFS9sXMgkXv7vLIrUXpmGb03KPAk= X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwNzA0MDEwMiBTYWx0ZWRfX1i4oXQR/jlk0 PMyW+3rCOQd3H8Cm0BoQ9Uc8+sNUdJggmcCKXOAw857996EtKDsPcAvLKIQBvadViHf5TKwekLJ NthAX4IRIz7s75eIGvy0Qf1pMxiYnYq0TUtCUfzfxtnJIZoHaT99PE2fKxme9HZ18ABBEO2KLa7 aeqS83lSrkzV8TrgOcBI5oibwN0NLoOvJn2O+LM7xNjLf3i1gp65ppg7dkx0rfT13jmiEGETK3C PxV1nHsHO/vz2IPB0v5lWjMW0ZMYsqC/w6sgEG1PJxHq3pTL5WV9iStN8M/SNvEuQLH7Ur58DxP 1PvxGCuvcWUtMyVAP9F6p1kKFvSYVUj+ePVYDXsSAuC3SC3zGyPrc10uIdbu+3kYNw8iOEVUJXf zH/nlGNQhoWF9THlDpbuhuvyc1i/bpO9wWDoj5YWm1Z3Zuc1Ft1OqMBvcUORPWe6Xj8oNwB+2Wd TQTbXvsBqArsnGTTsxw== X-Proofpoint-GUID: AlIXd5-EqdvD2dwgQCtpYuu6Y9AqOd8T X-Authority-Analysis: v=2.4 cv=Oot/DS/t c=1 sm=1 tr=0 ts=6a48e24f cx=c_pps a=5BHTudwdYE3Te8bg5FgnPg==:117 a=5BHTudwdYE3Te8bg5FgnPg==:17 a=RAioF0-LDSMA:10 a=VkNPw1HP01LnGYTKEx00:22 a=RnoormkPH1_aCDwRdu11:22 a=uAbxVGIbfxUO_5tXvNgY:22 a=VnNF1IyMAAAA:8 a=pGLkceISAAAA:8 a=KiPbuy1ShhI8k8eQ5nMA:9 X-Proofpoint-ORIG-GUID: 4Q-1btzrP_5w_gbgdCfdAe87Fl3udhUV X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1143,Hydra:6.1.125,FMLib:17.12.100.49 definitions=2026-07-04_01,2026-07-03_01,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 bulkscore=0 lowpriorityscore=0 clxscore=1015 impostorscore=0 phishscore=0 malwarescore=0 suspectscore=0 spamscore=0 adultscore=0 priorityscore=1501 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2606150000 definitions=main-2607040102 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=148.163.156.1; envelope-from=vishalc@linux.ibm.com; helo=mx0a-001b2d01.pphosted.com X-Spam_score_int: -26 X-Spam_score: -2.7 X-Spam_bar: -- X-Spam_report: (-2.7 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_MSPIKE_H4=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @ibm.com) X-ZM-MESSAGEID: 1783161473718158500 Content-Type: text/plain; charset="utf-8" As part of my daily work responsibilities, I actively investigate CPU hotplug functionality on Linux and have been reviewing related patches for some time. I'm stepping up as a reviewer for PPC KVM CPU areas to help share the review workload and contribute to maintaining code quality in these subsystems. Signed-off-by: Vishal Chourasia --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index cb19e868b4..43f87269be 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -488,6 +488,7 @@ F: tests/functional/aarch64/test_kvm.py PPC KVM CPUs M: Nicholas Piggin R: Harsh Prateek Bora +R: Vishal Chourasia S: Odd Fixes F: target/ppc/kvm.c F: hw/ppc/spapr_cpu_core.c --=20 2.54.0