From nobody Sat Jun 13 07:46:58 2026 Received: from out28-197.mail.aliyun.com (out28-197.mail.aliyun.com [115.124.28.197]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 23DFA3A0B24 for ; Tue, 7 Apr 2026 08:21:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=115.124.28.197 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775550104; cv=none; b=TR+XD43Um6rRbF7jJhHjv9Ex93Gpfm87vQEZ20x2zJXasd1Fu7dRa6B4uiVCHBSYQoDZOvqXKv53GPgUUWBVNXr6dbzON1sxCv169EC9w6RhTCDmcIobSKtxmuvgcBKuvSLVpGqSB1ikAypffYmuyZjfBCHUXK8ZUlZw3lRzP/0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775550104; c=relaxed/simple; bh=GQE1Yvwmd2mqYQ1WAAHuDxHn4Z6f1tS6Cti+YexE7Yc=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=PzaH/AzJQCopvbz2REANuzDx8DS0g6XE6pZ+LUQ4Z5pR4xHnS/bJkckuoUfIDnFVhmr07ST0VjpYujhMRDcrvMK6wtijNKltF8pG7WgAXb46Pj9V4fBFC3ZHe/Y7vcFE+b+rk4XMbVkqE/FHMY+2jh/ranpL+YLaTsyd+I4h6eg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=open-hieco.net; spf=pass smtp.mailfrom=open-hieco.net; arc=none smtp.client-ip=115.124.28.197 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=open-hieco.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=open-hieco.net X-Alimail-AntiSpam: AC=CONTINUE;BC=0.2888092|-1;CH=green;DM=|CONTINUE|false|;DS=CONTINUE|ham_system_inform|0.0077927-6.21147e-05-0.992145;FP=14402608404107038143|1|1|1|0|-1|-1|-1;HT=maildocker-contentspam033037021217;MF=fuhao@open-hieco.net;NM=1;PH=DS;RN=9;RT=9;SR=0;TI=SMTPD_---.h6UZe7i_1775550086; Received: from higon..(mailfrom:fuhao@open-hieco.net fp:SMTPD_---.h6UZe7i_1775550086 cluster:ay29) by smtp.aliyun-inc.com; Tue, 07 Apr 2026 16:21:33 +0800 From: Fu Hao To: puwen@hygon.cn, tglx@kernel.org, mingo@redhat.com, bp@alien8.de, dave.hansen@linux.intel.com, x86@kernel.org, hpa@zytor.com Cc: linux-kernel@vger.kernel.org, Fu Hao Subject: [PATCH v2 1/8] x86/cpu/hygon: Adjust the die_id and logical_die_id for Hygon models 0x4-0x8 Date: Tue, 7 Apr 2026 16:22:42 +0800 Message-Id: <643b60a2f121e8f2cc7c7e7543503ee945776fd2.1775548724.git.fuhao@open-hieco.net> X-Mailer: git-send-email 2.34.1 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The die ID should be got from the NodeId field of CPUID leaf 0x8000001e ecx for Hygon models 0x4-0x8 processors. Signed-off-by: Fu Hao Tested-by: Tingyin Duan --- arch/x86/kernel/cpu/hygon.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/x86/kernel/cpu/hygon.c b/arch/x86/kernel/cpu/hygon.c index 7f95a74e4..0bf99072f 100644 --- a/arch/x86/kernel/cpu/hygon.c +++ b/arch/x86/kernel/cpu/hygon.c @@ -191,6 +191,16 @@ static void init_hygon(struct cpuinfo_x86 *c) =20 init_hygon_cacheinfo(c); =20 + /* + * Adjust the die_id and logical_die_id for Hygon models 0x4-0x8. + */ + if (c->x86_model >=3D 0x4 && c->x86_model <=3D 0x8) { + c->topo.die_id =3D cpuid_ecx(0x8000001e) & 0xff; + c->topo.logical_die_id =3D (c->topo.die_id >> 4) * + topology_amd_nodes_per_pkg() + + (c->topo.die_id & 0xf); + } + if (cpu_has(c, X86_FEATURE_SVM)) { rdmsrq(MSR_VM_CR, vm_cr); if (vm_cr & SVM_VM_CR_SVM_DIS_MASK) { --=20 2.34.1 From nobody Sat Jun 13 07:46:58 2026 Received: from out198-19.us.a.mail.aliyun.com (out198-19.us.a.mail.aliyun.com [47.90.198.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9EE133A382D for ; Tue, 7 Apr 2026 08:22:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=47.90.198.19 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775550139; cv=none; b=SdDlWlB6pGnjbbm6Gds9fZKKzJYhV0I1CnzB0/3ygYl7TuhsfhgFryI0Xzq9QgYVvczo2y+/kghqSYnak3L4dIQoW8KYd+Zv7TPRLTDSJsqZQT4y50JWFQGvJztz2q/72kL/Ul1Xgzw9aBqW4N9k0dbLZByw0AU2xJu459Xr3Qo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775550139; c=relaxed/simple; bh=oibeUgxHcNCRV8WSG7Akkc5rxD45S1mXhPzoWTwmtys=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=UAGH3iN7FgiO3RMu8Muvj/cfuFb1Ei/lQPB3r//1K6dX4ACvI2iaUZPO+HfOkm5Q8l+eT9uf/Qmv9SazscwBI4kYlhVHW9ixpmi4NbqpdGabfFhBer6h8D2r76UF6cj0SsHaFbz/9TDGJZHmEBXBPbIifOj8hAp3XM4MfGQREJE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=open-hieco.net; spf=pass smtp.mailfrom=open-hieco.net; arc=none smtp.client-ip=47.90.198.19 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=open-hieco.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=open-hieco.net X-Alimail-AntiSpam: AC=CONTINUE;BC=0.09553488|-1;CH=green;DM=|CONTINUE|false|;DS=CONTINUE|ham_system_inform|0.0559394-0.000520006-0.943541;FP=5616368311665788086|2|1|1|0|-1|-1|-1;HT=maildocker-contentspam033037028158;MF=fuhao@open-hieco.net;NM=1;PH=DS;RN=8;RT=8;SR=0;TI=SMTPD_---.h6XS1E._1775550114; Received: from higon..(mailfrom:fuhao@open-hieco.net fp:SMTPD_---.h6XS1E._1775550114 cluster:ay29) by smtp.aliyun-inc.com; Tue, 07 Apr 2026 16:21:59 +0800 From: Fu Hao To: tglx@kernel.org, mingo@redhat.com, bp@alien8.de, dave.hansen@linux.intel.com, x86@kernel.org, hpa@zytor.com Cc: linux-kernel@vger.kernel.org, Fu Hao Subject: [PATCH v2 2/8] x86/cpu: Get LLC ID for Hygon family 18h model 4h Date: Tue, 7 Apr 2026 16:23:09 +0800 Message-Id: X-Mailer: git-send-email 2.34.1 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add support to calculate LLC ID from the number of threads sharing the cache for Hygon family 18h model 4h processor. Signed-off-by: Fu Hao Tested-by: Tingyin Duan --- arch/x86/kernel/cpu/cacheinfo.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/arch/x86/kernel/cpu/cacheinfo.c b/arch/x86/kernel/cpu/cacheinf= o.c index 51a95b078..98862afc4 100644 --- a/arch/x86/kernel/cpu/cacheinfo.c +++ b/arch/x86/kernel/cpu/cacheinfo.c @@ -341,11 +341,23 @@ void cacheinfo_hygon_init_llc_id(struct cpuinfo_x86 *= c) if (!cpuid_amd_hygon_has_l3_cache()) return; =20 - /* - * Hygons are similar to AMD Family 17h up to 1F models: LLC is - * at the core complex level. Core complex ID is ApicId[3]. - */ - c->topo.llc_id =3D c->topo.apicid >> 3; + if (c->x86_model >=3D 0x4) { + /* + * From model 4h: LLC ID is calculated from the number + * of threads sharing the L3 cache. + */ + u32 llc_index =3D find_num_cache_leaves(c) - 1; + struct _cpuid4_info id4 =3D {}; + + if (!amd_fill_cpuid4_info(llc_index, &id4)) + c->topo.llc_id =3D get_cache_id(c->topo.apicid, &id4); + } else { + /* + * The others are similar to AMD Family 17h up to 1F models: LLC is + * at the core complex level. Core complex ID is ApicId[3]. + */ + c->topo.llc_id =3D c->topo.apicid >> 3; + } } =20 void init_amd_cacheinfo(struct cpuinfo_x86 *c) --=20 2.34.1 From nobody Sat Jun 13 07:46:58 2026 Received: from out28-147.mail.aliyun.com (out28-147.mail.aliyun.com [115.124.28.147]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 24CE0329C7F for ; Tue, 7 Apr 2026 08:22:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=115.124.28.147 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775550157; cv=none; b=E9Fe8r3xa2O5NUwl+wyaM8uv5pUpxo3VDsySnHsueC9PLsaiz3T25BhRJjUoXS7j3BbTKK+RVi52J2BzA+k+R4GWeEvObxUCUlOdOtFunJ9jBE2u5pc522QzR/OXeXLdnUk+fqSbDRMmp9nwiMW1PFnst0noKP5y7DiKKiVfZcw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775550157; c=relaxed/simple; bh=HLEAHRk/DQxHaftJBOllz8+A0iyPWF9gLRwWY9RbXGo=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=fQnrecgD6rmFHDYk0DbinL9FV+aFm7c8sRilrkIdHvGx6aQsrMTuBIgdzBizG4HWJaNAFylQ5q0CqwAM0g7z6VYQiBB9+JcG3w6Yl40udA7JBDBVqftMyD4Q10rx5O2Dg9Hu2t6FMk7Wos25zT/D+g/kZX+mpa350y0tv4q8UwM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=open-hieco.net; spf=pass smtp.mailfrom=open-hieco.net; arc=none smtp.client-ip=115.124.28.147 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=open-hieco.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=open-hieco.net X-Alimail-AntiSpam: AC=CONTINUE;BC=0.2138753|-1;CH=green;DM=|CONTINUE|false|;DS=CONTINUE|ham_system_inform|0.00467615-0.000235886-0.995088;FP=2867482401963607501|1|1|1|0|-1|-1|-1;HT=maildocker-contentspam033037022039;MF=fuhao@open-hieco.net;NM=1;PH=DS;RN=9;RT=9;SR=0;TI=SMTPD_---.h6dlIrL_1775550140; Received: from higon..(mailfrom:fuhao@open-hieco.net fp:SMTPD_---.h6dlIrL_1775550140 cluster:ay29) by smtp.aliyun-inc.com; Tue, 07 Apr 2026 16:22:24 +0800 From: Fu Hao To: puwen@hygon.cn, tglx@kernel.org, mingo@redhat.com, bp@alien8.de, dave.hansen@linux.intel.com, x86@kernel.org, hpa@zytor.com Cc: linux-kernel@vger.kernel.org, Fu Hao Subject: [PATCH v2 3/8] x86/cpu/hygon: Remove Spectral Chicken for Hygon processors Date: Tue, 7 Apr 2026 16:23:33 +0800 Message-Id: <3582ba7dcbbb738bf4cdc44f9ccb0b8bcb7a48be.1775548724.git.fuhao@open-hieco.net> X-Mailer: git-send-email 2.34.1 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The chicken bit does not need to be set for Hygon processors, so remove it. Fixes: d7caac991fee ("x86/cpu/amd: Add Spectral Chicken") Signed-off-by: Fu Hao Tested-by: Tingyin Duan --- arch/x86/kernel/cpu/hygon.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/arch/x86/kernel/cpu/hygon.c b/arch/x86/kernel/cpu/hygon.c index 0bf99072f..d5513c0f1 100644 --- a/arch/x86/kernel/cpu/hygon.c +++ b/arch/x86/kernel/cpu/hygon.c @@ -176,12 +176,6 @@ static void init_hygon(struct cpuinfo_x86 *c) =20 set_cpu_cap(c, X86_FEATURE_REP_GOOD); =20 - /* - * XXX someone from Hygon needs to confirm this DTRT - * - init_spectral_chicken(c); - */ - set_cpu_cap(c, X86_FEATURE_ZEN); set_cpu_cap(c, X86_FEATURE_CPB); =20 --=20 2.34.1 From nobody Sat Jun 13 07:46:58 2026 Received: from out28-146.mail.aliyun.com (out28-146.mail.aliyun.com [115.124.28.146]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E96E83A1E8C; Tue, 7 Apr 2026 08:22:54 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=115.124.28.146 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775550176; cv=none; b=fnAOiPOQv8/rPUzVR2kOi5eqqVYDe1akfp0eCbYq2can4zI4dL1YlkRO9ajeHz6U5NWrC7LSe/o0Qyvdq7cp7stigPiG/qqV7wlIiFgTAacjHTQEjCdgeMOLDaRIDsI3vgysecq3HFbP2vu7mcjkk16hQh4TrPqX79UIVbJ9/qg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775550176; c=relaxed/simple; bh=jekUoRM6xAl2PNYqAev73aVpcZjT/bi7bFrfh8DgPEI=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=se2Kh7w+ppA4ftiaMhjowj9Q4OwOQw3U85OZYm6Hys2Zv2xP2QwndXy58MZP7fyYGWOzQ3kNIF3Z8l8ijJmzbX8EBzxExPT8tUfQ4HC5p0t/awCZejk/RMLHkQFYPxT6TFG1YmxjMwbWn6c9mG9Rx9VCptwb8bdmD7DPmuz5tTo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=open-hieco.net; spf=pass smtp.mailfrom=open-hieco.net; arc=none smtp.client-ip=115.124.28.146 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=open-hieco.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=open-hieco.net X-Alimail-AntiSpam: AC=CONTINUE;BC=0.07436478|-1;CH=green;DM=|CONTINUE|false|;DS=CONTINUE|ham_alarm|0.00828711-0.000511096-0.991202;FP=5963414997120388496|2|1|1|0|-1|-1|-1;HT=maildocker-contentspam033037028158;MF=fuhao@open-hieco.net;NM=1;PH=DS;RN=16;RT=16;SR=0;TI=SMTPD_---.h6XWDzQ_1775550165; Received: from higon..(mailfrom:fuhao@open-hieco.net fp:SMTPD_---.h6XWDzQ_1775550165 cluster:ay29) by smtp.aliyun-inc.com; Tue, 07 Apr 2026 16:22:50 +0800 From: Fu Hao To: peterz@infradead.org, mingo@redhat.com, acme@kernel.org, namhyung@kernel.org, tglx@kernel.org, bp@alien8.de, dave.hansen@linux.intel.com, x86@kernel.org, alexander.shishkin@linux.intel.com, jolsa@kernel.org, irogers@google.com, james.clark@linaro.org, hpa@zytor.com Cc: linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org, Fu Hao Subject: [PATCH v2 4/8] perf/x86/uncore: Add L3 PMU support for Hygon family 18h model 6h Date: Tue, 7 Apr 2026 16:23:58 +0800 Message-Id: <9a4731a46cc0a7645838bd848a40a6574a97bad6.1775548724.git.fuhao@open-hieco.net> X-Mailer: git-send-email 2.34.1 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Adjust the L3 PMU slicemask and threadmask for Hygon family 18h model 6h processor. Signed-off-by: Fu Hao Tested-by: Tingyin Duan --- arch/x86/events/amd/uncore.c | 48 ++++++++++++++++++++++++++++++- arch/x86/include/asm/perf_event.h | 8 ++++++ 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/arch/x86/events/amd/uncore.c b/arch/x86/events/amd/uncore.c index dd956cfca..e71d9e784 100644 --- a/arch/x86/events/amd/uncore.c +++ b/arch/x86/events/amd/uncore.c @@ -308,6 +308,14 @@ amd_f17h_uncore_is_visible(struct kobject *kobj, struc= t attribute *attr, int i) attr->mode : 0; } =20 +static umode_t +hygon_f18h_m6h_uncore_is_visible(struct kobject *kobj, struct attribute *a= ttr, int i) +{ + return boot_cpu_data.x86 =3D=3D 0x18 && + boot_cpu_data.x86_model >=3D 0x6 && boot_cpu_data.x86_model <=3D 0= xf ? + attr->mode : 0; +} + static umode_t amd_f19h_uncore_is_visible(struct kobject *kobj, struct attribute *attr, i= nt i) { @@ -359,6 +367,8 @@ DEFINE_UNCORE_FORMAT_ATTR(enallslices, enallslices, "co= nfig:46"); /* F19h L3 DEFINE_UNCORE_FORMAT_ATTR(enallcores, enallcores, "config:47"); /* F19= h L3 */ DEFINE_UNCORE_FORMAT_ATTR(sliceid, sliceid, "config:48-50"); /* F19h L3= */ DEFINE_UNCORE_FORMAT_ATTR(rdwrmask, rdwrmask, "config:8-9"); /* PerfMo= nV2 UMC */ +DEFINE_UNCORE_FORMAT_ATTR(slicemask4, slicemask, "config:28-31"); /* F1= 8h L3 */ +DEFINE_UNCORE_FORMAT_ATTR(threadmask32, threadmask, "config:32-63"); /*= F18h L3 */ =20 /* Common DF and NB attributes */ static struct attribute *amd_uncore_df_format_attr[] =3D { @@ -388,6 +398,12 @@ static struct attribute *amd_f17h_uncore_l3_format_att= r[] =3D { NULL, }; =20 +/* F18h M06h unique L3 attributes */ +static struct attribute *hygon_f18h_m6h_uncore_l3_format_attr[] =3D { + &format_attr_slicemask4.attr, /* slicemask */ + NULL, +}; + /* F19h unique L3 attributes */ static struct attribute *amd_f19h_uncore_l3_format_attr[] =3D { &format_attr_coreid.attr, /* coreid */ @@ -413,6 +429,12 @@ static struct attribute_group amd_f17h_uncore_l3_forma= t_group =3D { .is_visible =3D amd_f17h_uncore_is_visible, }; =20 +static struct attribute_group hygon_f18h_m6h_uncore_l3_format_group =3D { + .name =3D "format", + .attrs =3D hygon_f18h_m6h_uncore_l3_format_attr, + .is_visible =3D hygon_f18h_m6h_uncore_is_visible, +}; + static struct attribute_group amd_f19h_uncore_l3_format_group =3D { .name =3D "format", .attrs =3D amd_f19h_uncore_l3_format_attr, @@ -442,6 +464,11 @@ static const struct attribute_group *amd_uncore_l3_att= r_update[] =3D { NULL, }; =20 +static const struct attribute_group *hygon_uncore_l3_attr_update[] =3D { + &hygon_f18h_m6h_uncore_l3_format_group, + NULL, +}; + static const struct attribute_group *amd_uncore_umc_attr_groups[] =3D { &amd_uncore_attr_group, &amd_uncore_umc_format_group, @@ -820,6 +847,12 @@ static int amd_uncore_l3_event_init(struct perf_event = *event) mask =3D AMD64_L3_F19H_THREAD_MASK | AMD64_L3_EN_ALL_SLICES | AMD64_L3_EN_ALL_CORES; =20 + if (boot_cpu_data.x86 =3D=3D 0x18 && + boot_cpu_data.x86_model >=3D 0x6 && + boot_cpu_data.x86_model <=3D 0xf) + mask =3D ((config & HYGON_L3_SLICE_MASK) ? : HYGON_L3_SLICE_MASK) | + ((config & HYGON_L3_THREAD_MASK) ? : HYGON_L3_THREAD_MASK); + hwc->config |=3D mask; =20 return 0; @@ -877,7 +910,8 @@ int amd_uncore_l3_ctx_init(struct amd_uncore *uncore, u= nsigned int cpu) pmu->rdpmc_base =3D RDPMC_BASE_LLC; pmu->group =3D amd_uncore_ctx_gid(uncore, cpu); =20 - if (boot_cpu_data.x86 >=3D 0x17) { + if (boot_cpu_data.x86_vendor =3D=3D X86_VENDOR_AMD && + boot_cpu_data.x86 >=3D 0x17) { *l3_attr++ =3D &format_attr_event8.attr; *l3_attr++ =3D &format_attr_umask8.attr; *l3_attr++ =3D boot_cpu_data.x86 >=3D 0x19 ? @@ -904,6 +938,18 @@ int amd_uncore_l3_ctx_init(struct amd_uncore *uncore, = unsigned int cpu) .module =3D THIS_MODULE, }; =20 + if (boot_cpu_data.x86_vendor =3D=3D X86_VENDOR_HYGON && + boot_cpu_data.x86 =3D=3D 0x18) { + *l3_attr++ =3D &format_attr_event8.attr; + *l3_attr++ =3D &format_attr_umask8.attr; + if (boot_cpu_data.x86_model >=3D 0x6 && boot_cpu_data.x86_model <=3D 0xf= ) { + *l3_attr++ =3D &format_attr_threadmask32.attr; + pmu->pmu.attr_update =3D hygon_uncore_l3_attr_update; + } else { + *l3_attr++ =3D &format_attr_threadmask8.attr; + } + } + if (perf_pmu_register(&pmu->pmu, pmu->pmu.name, -1)) { free_percpu(pmu->ctx); pmu->ctx =3D NULL; diff --git a/arch/x86/include/asm/perf_event.h b/arch/x86/include/asm/perf_= event.h index ff5acb8b1..404752601 100644 --- a/arch/x86/include/asm/perf_event.h +++ b/arch/x86/include/asm/perf_event.h @@ -89,6 +89,14 @@ #define AMD64_L3_COREID_MASK \ (0x7ULL << AMD64_L3_COREID_SHIFT) =20 +#define HYGON_L3_SLICE_SHIFT 28 +#define HYGON_L3_SLICE_MASK \ + (0xFULL << HYGON_L3_SLICE_SHIFT) + +#define HYGON_L3_THREAD_SHIFT 32 +#define HYGON_L3_THREAD_MASK \ + (0xFFFFFFFFULL << HYGON_L3_THREAD_SHIFT) + #define X86_RAW_EVENT_MASK \ (ARCH_PERFMON_EVENTSEL_EVENT | \ ARCH_PERFMON_EVENTSEL_UMASK | \ --=20 2.34.1 From nobody Sat Jun 13 07:46:58 2026 Received: from out198-16.us.a.mail.aliyun.com (out198-16.us.a.mail.aliyun.com [47.90.198.16]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 676C63A3E72 for ; Tue, 7 Apr 2026 08:23:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=47.90.198.16 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775550225; cv=none; b=R5Nz1lkwdGRmuGGI9rH2F9RFgZHkPEG8Z5I1u1G9qn8Td5OfDTsXIpKL7mzesax0Eo/WkCaajGne02wyAwPsetDkwQvS0tAPdZOnmSIQsEIhzVJhemjsg1O4NiDmRWbb8ryVZ63M775YxcLBPzN6Fj9CkLgUssRedKQzrs/6rk4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775550225; c=relaxed/simple; bh=E13mcpCm/KJ04Gd7HfqKiRvdbSdjxtYsYvdMGoA1saE=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=T+cdOEPmh9HpT6AEA6b3a+UnZuIlPMdXhDKZwdjPJL1JnzkzZMgc4yPXPukEH99cpF6fU5oTYlOEtSwE5ao4kynIAXt/QbrOo0dK7dH6BEmF4BfoHSaEj36ic7nSkelI/kFkE0QEqUzfYIcS4LXV9Xmkt24ZJRaUeNskTSibBHk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=open-hieco.net; spf=pass smtp.mailfrom=open-hieco.net; arc=none smtp.client-ip=47.90.198.16 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=open-hieco.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=open-hieco.net X-Alimail-AntiSpam: AC=CONTINUE;BC=0.07436259|-1;CH=green;DM=|CONTINUE|false|;DS=CONTINUE|ham_alarm|0.0080075-0.00372199-0.988271;FP=13688457270910321786|2|1|1|0|-1|-1|-1;HT=maildocker-contentspam033040074035;MF=fuhao@open-hieco.net;NM=1;PH=DS;RN=8;RT=8;SR=0;TI=SMTPD_---.h6XWEiQ_1775550200; Received: from higon..(mailfrom:fuhao@open-hieco.net fp:SMTPD_---.h6XWEiQ_1775550200 cluster:ay29) by smtp.aliyun-inc.com; Tue, 07 Apr 2026 16:23:24 +0800 From: Fu Hao To: tglx@kernel.org, mingo@redhat.com, bp@alien8.de, dave.hansen@linux.intel.com, x86@kernel.org, hpa@zytor.com Cc: linux-kernel@vger.kernel.org, Fu Hao Subject: [PATCH v2 5/8] x86/microcode/hygon: Add microcode loading support for Hygon processors Date: Tue, 7 Apr 2026 16:24:35 +0800 Message-Id: X-Mailer: git-send-email 2.34.1 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add support for loading Hygon microcode. There are two loading methods: 1. Loading from the initrd/builtin. 2. Late loading, which depends on the kernel configuration option CONFIG_MICROCODE_LATE_LOADING being enabled, and this option is usually disabled by default, so it's not recommended. Signed-off-by: Fu Hao Tested-by: Tingyin Duan --- arch/x86/Kconfig | 2 +- arch/x86/kernel/cpu/microcode/Makefile | 1 + arch/x86/kernel/cpu/microcode/core.c | 17 +- arch/x86/kernel/cpu/microcode/hygon.c | 927 +++++++++++++++++++++++ arch/x86/kernel/cpu/microcode/internal.h | 20 + 5 files changed, 965 insertions(+), 2 deletions(-) create mode 100644 arch/x86/kernel/cpu/microcode/hygon.c diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index e2df1b147..b94f3dbf1 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -1330,7 +1330,7 @@ config X86_REBOOTFIXUPS =20 config MICROCODE def_bool y - depends on CPU_SUP_AMD || CPU_SUP_INTEL + depends on CPU_SUP_AMD || CPU_SUP_INTEL || CPU_SUP_HYGON select CRYPTO_LIB_SHA256 if CPU_SUP_AMD =20 config MICROCODE_INITRD32 diff --git a/arch/x86/kernel/cpu/microcode/Makefile b/arch/x86/kernel/cpu/m= icrocode/Makefile index 193d98b33..671d9a095 100644 --- a/arch/x86/kernel/cpu/microcode/Makefile +++ b/arch/x86/kernel/cpu/microcode/Makefile @@ -3,3 +3,4 @@ microcode-y :=3D core.o obj-$(CONFIG_MICROCODE) +=3D microcode.o microcode-$(CONFIG_CPU_SUP_INTEL) +=3D intel.o microcode-$(CONFIG_CPU_SUP_AMD) +=3D amd.o +microcode-$(CONFIG_CPU_SUP_HYGON) +=3D hygon.o diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/mic= rocode/core.c index 651202e6f..5f82f2436 100644 --- a/arch/x86/kernel/cpu/microcode/core.c +++ b/arch/x86/kernel/cpu/microcode/core.c @@ -195,6 +195,9 @@ void __init load_ucode_bsp(void) return; intel =3D false; break; + case X86_VENDOR_HYGON: + intel =3D false; + break; =20 default: return; @@ -203,7 +206,11 @@ void __init load_ucode_bsp(void) if (intel) load_ucode_intel_bsp(&early_data); else - load_ucode_amd_bsp(&early_data, cpuid_1_eax); + if (x86_cpuid_vendor() =3D=3D X86_VENDOR_HYGON) + load_ucode_hygon_bsp(&early_data, cpuid_1_eax); + else + load_ucode_amd_bsp(&early_data, cpuid_1_eax); + } =20 void load_ucode_ap(void) @@ -229,6 +236,9 @@ void load_ucode_ap(void) if (x86_family(cpuid_1_eax) >=3D 0x10) load_ucode_amd_ap(cpuid_1_eax); break; + case X86_VENDOR_HYGON: + load_ucode_hygon_ap(cpuid_1_eax); + break; default: break; } @@ -288,6 +298,9 @@ static void reload_early_microcode(unsigned int cpu) if (family >=3D 0x10) reload_ucode_amd(cpu); break; + case X86_VENDOR_HYGON: + reload_ucode_hygon(cpu); + break; default: break; } @@ -895,6 +908,8 @@ static int __init microcode_init(void) microcode_ops =3D init_intel_microcode(); else if (c->x86_vendor =3D=3D X86_VENDOR_AMD) microcode_ops =3D init_amd_microcode(); + else if (c->x86_vendor =3D=3D X86_VENDOR_HYGON) + microcode_ops =3D init_hygon_microcode(); else pr_err("no support for this CPU vendor\n"); =20 diff --git a/arch/x86/kernel/cpu/microcode/hygon.c b/arch/x86/kernel/cpu/mi= crocode/hygon.c new file mode 100644 index 000000000..e46c09582 --- /dev/null +++ b/arch/x86/kernel/cpu/microcode/hygon.c @@ -0,0 +1,927 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Hygon CPU Microcode Update Driver for Linux + * + * This driver allows to upgrade microcode on Hygon CPUs. + * + */ +#define pr_fmt(fmt) "microcode: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "internal.h" + +struct ucode_patch { + struct list_head plist; + void *data; + unsigned int size; + u32 patch_id; + u16 equiv_cpu; +}; + +static LIST_HEAD(microcode_cache); + +#define UCODE_MAGIC 0x00414d44 +#define UCODE_EQUIV_CPU_TABLE_TYPE 0x00000000 +#define UCODE_UCODE_TYPE 0x00000001 + +#define SECTION_HDR_SIZE 8 +#define CONTAINER_HDR_SZ 12 + +struct equiv_cpu_entry { + u32 installed_cpu; + u32 fixed_errata_mask; + u32 fixed_errata_compare; + u16 equiv_cpu; + u16 res; +} __packed; + +struct microcode_header_hygon { + u32 data_code; + u32 patch_id; + u16 mc_patch_data_id; + u8 mc_patch_data_len; + u8 init_flag; + u32 mc_patch_data_checksum; + u32 nb_dev_id; + u32 sb_dev_id; + u16 processor_rev_id; + u8 nb_rev_id; + u8 sb_rev_id; + u8 bios_api_rev; + u8 reserved1[3]; + u32 match_reg[8]; +} __packed; + +struct microcode_hygon { + struct microcode_header_hygon hdr; + unsigned int mpb[]; +}; + +static struct equiv_cpu_table { + unsigned int num_entries; + struct equiv_cpu_entry *entry; +} equiv_table; + +union cpuid_1_eax { + struct { + __u32 stepping : 4, + model : 4, + family : 4, + __reserved0 : 4, + ext_model : 4, + ext_fam : 8, + __reserved1 : 4; + }; + __u32 full; +}; + +/* + * This points to the current valid container of microcode patches which w= e will + * save from the initrd/builtin before jettisoning its contents. @mc is the + * microcode patch we found to match. + */ +struct cont_desc { + struct microcode_hygon *mc; + u32 psize; + u8 *data; + size_t size; +}; + +/* + * Microcode patch container file is prepended to the initrd in cpio + * format. See Documentation/arch/x86/microcode.rst + */ +static const char +ucode_path[] __maybe_unused =3D "kernel/x86/microcode/HygonGenuine.bin"; + +static u32 bsp_cpuid_1_eax __ro_after_init; + +static u32 get_patch_level(void) +{ + u32 rev, dummy __always_unused; + + native_rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy); + + return rev; +} + +static u16 find_equiv_id(struct equiv_cpu_table *et, u32 sig) +{ + unsigned int i; + + if (!et || !et->num_entries) + return 0; + + for (i =3D 0; i < et->num_entries; i++) { + struct equiv_cpu_entry *e =3D &et->entry[i]; + + if (sig =3D=3D e->installed_cpu) + return e->equiv_cpu; + } + return 0; +} + +/* + * Check whether there is a valid microcode container file at the beginning + * of @buf of size @buf_size. + */ +static bool verify_container(const u8 *buf, size_t buf_size) +{ + u32 cont_magic; + + if (buf_size <=3D CONTAINER_HDR_SZ) { + ucode_dbg("Truncated microcode container header.\n"); + return false; + } + + cont_magic =3D *(const u32 *)buf; + if (cont_magic !=3D UCODE_MAGIC) { + ucode_dbg("Invalid magic value (0x%08x).\n", cont_magic); + return false; + } + + return true; +} + +/* + * Check whether there is a valid, non-truncated CPU equivalence table at = the + * beginning of @buf of size @buf_size. + */ +static bool verify_equivalence_table(const u8 *buf, size_t buf_size) +{ + const u32 *hdr =3D (const u32 *)buf; + u32 cont_type, equiv_tbl_len; + + if (!verify_container(buf, buf_size)) + return false; + + cont_type =3D hdr[1]; + if (cont_type !=3D UCODE_EQUIV_CPU_TABLE_TYPE) { + ucode_dbg("Wrong microcode container equivalence table type: %u.\n", + cont_type); + return false; + } + + buf_size -=3D CONTAINER_HDR_SZ; + + equiv_tbl_len =3D hdr[2]; + if (equiv_tbl_len < sizeof(struct equiv_cpu_entry) || + buf_size < equiv_tbl_len) { + ucode_dbg("Truncated equivalence table.\n"); + return false; + } + + return true; +} + +/* + * Check whether there is a valid, non-truncated microcode patch section a= t the + * beginning of @buf of size @buf_size. + * + * On success, @sh_psize returns the patch size according to the section h= eader, + * to the caller. + */ +static bool __verify_patch_section(const u8 *buf, size_t buf_size, u32 *sh= _psize) +{ + u32 p_type, p_size; + const u32 *hdr; + + if (buf_size < SECTION_HDR_SIZE) { + ucode_dbg("Truncated patch section.\n"); + return false; + } + + hdr =3D (const u32 *)buf; + p_type =3D hdr[0]; + p_size =3D hdr[1]; + + if (p_type !=3D UCODE_UCODE_TYPE) { + ucode_dbg("Invalid type field (0x%x) in container file section header.\n= ", + p_type); + return false; + } + + if (p_size < sizeof(struct microcode_header_hygon)) { + ucode_dbg("Patch of size %u too short.\n", p_size); + return false; + } + + *sh_psize =3D p_size; + + return true; +} + +/* + * Check whether the passed remaining file @buf_size is large enough to co= ntain + * a patch of the indicated @sh_psize (and also whether this size does not + * exceed the per-family maximum). @sh_psize is the size read from the sec= tion + * header. + */ +static bool __verify_patch_size(u32 sh_psize, size_t buf_size) +{ + /* Working with the whole buffer so < is ok. */ + return sh_psize <=3D buf_size; +} + +/* + * Verify the patch in @buf. + * + * Returns: + * negative: on error + * positive: patch is not for this family, skip it + * 0: success + */ +static int verify_patch(const u8 *buf, size_t buf_size, u32 *patch_size) +{ + u8 family =3D x86_family(bsp_cpuid_1_eax); + struct microcode_header_hygon *mc_hdr; + u32 sh_psize; + u16 proc_id; + u8 patch_fam; + + if (!__verify_patch_section(buf, buf_size, &sh_psize)) + return -1; + + /* + * The section header length is not included in this indicated size + * but is present in the leftover file length so we need to subtract + * it before passing this value to the function below. + */ + buf_size -=3D SECTION_HDR_SIZE; + + /* + * Check if the remaining buffer is big enough to contain a patch of + * size sh_psize, as the section claims. + */ + if (buf_size < sh_psize) { + ucode_dbg("Patch of size %u truncated.\n", sh_psize); + return -1; + } + + if (!__verify_patch_size(sh_psize, buf_size)) { + ucode_dbg("Per-family patch size mismatch.\n"); + return -1; + } + + *patch_size =3D sh_psize; + + mc_hdr =3D (struct microcode_header_hygon *)(buf + SECTION_HDR_SIZE); + if (mc_hdr->nb_dev_id || mc_hdr->sb_dev_id) { + pr_err("Patch-ID 0x%08x: chipset-specific code unsupported.\n", mc_hdr->= patch_id); + return -1; + } + + proc_id =3D mc_hdr->processor_rev_id; + patch_fam =3D 0xf + (proc_id >> 12); + + if (patch_fam !=3D family) + return 1; + + return 0; +} + +/* + * This scans the ucode blob for the proper container as we can have multi= ple + * containers glued together. + * + * Returns the amount of bytes consumed while scanning. @desc contains all= the + * data we're going to use in later stages of the application. + */ +static size_t parse_container(u8 *ucode, size_t size, struct cont_desc *de= sc) +{ + struct equiv_cpu_table table; + size_t orig_size =3D size; + u32 *hdr =3D (u32 *)ucode; + u16 eq_id; + u8 *buf; + + if (!verify_equivalence_table(ucode, size)) + return 0; + + buf =3D ucode; + + table.entry =3D (struct equiv_cpu_entry *)(buf + CONTAINER_HDR_SZ); + table.num_entries =3D hdr[2] / sizeof(struct equiv_cpu_entry); + + /* + * Find the equivalence ID of our CPU in this table. Even if this table + * doesn't contain a patch for the CPU, scan through the whole container + * so that it can be skipped in case there are other containers appended. + */ + eq_id =3D find_equiv_id(&table, bsp_cpuid_1_eax); + + buf +=3D hdr[2] + CONTAINER_HDR_SZ; + size -=3D hdr[2] + CONTAINER_HDR_SZ; + + /* + * Scan through the rest of the container to find where it ends. We do + * some basic sanity-checking too. + */ + while (size > 0) { + struct microcode_hygon *mc; + u32 patch_size; + int ret; + + ret =3D verify_patch(buf, size, &patch_size); + if (ret < 0) { + /* + * Patch verification failed, skip to the next container, if + * there is one. Before exit, check whether that container has + * found a patch already. If so, use it. + */ + goto out; + } else if (ret > 0) { + goto skip; + } + + mc =3D (struct microcode_hygon *)(buf + SECTION_HDR_SIZE); + + if (eq_id =3D=3D mc->hdr.processor_rev_id) { + desc->psize =3D patch_size; + desc->mc =3D mc; + + ucode_dbg(" match: size: %d\n", patch_size); + } + +skip: + /* Skip patch section header too: */ + buf +=3D patch_size + SECTION_HDR_SIZE; + size -=3D patch_size + SECTION_HDR_SIZE; + } + +out: + /* + * If we have found a patch (desc->mc), it means we're looking at the + * container which has a patch for this CPU so return 0 to mean, @ucode + * already points to the proper container. Otherwise, we return the size + * we scanned so that we can advance to the next container in the + * buffer. + */ + if (desc->mc) { + desc->data =3D ucode; + desc->size =3D orig_size - size; + + return 0; + } + + return orig_size - size; +} + +/* + * Scan the ucode blob for the proper container as we can have multiple + * containers glued together. + */ +static void scan_containers(u8 *ucode, size_t size, struct cont_desc *desc) +{ + while (size) { + size_t s =3D parse_container(ucode, size, desc); + + if (!s) + return; + + /* catch wraparound */ + if (size >=3D s) { + ucode +=3D s; + size -=3D s; + } else { + return; + } + } +} + +static bool __apply_microcode_hygon(struct microcode_hygon *mc, u32 *cur_r= ev, + unsigned int psize) +{ + unsigned long p_addr, p_addr_end; + + p_addr =3D (unsigned long)&mc->hdr.data_code; + native_wrmsrq(MSR_AMD64_PATCH_LOADER, p_addr); + p_addr_end =3D p_addr + psize - 1; + invlpg(p_addr); + + /* + * Flush next page too if patch image is crossing a page + * boundary. + */ + if (p_addr >> PAGE_SHIFT !=3D p_addr_end >> PAGE_SHIFT) + invlpg(p_addr_end); + + if (IS_ENABLED(CONFIG_MICROCODE_DBG) && hypervisor_present) + microcode_rev[smp_processor_id()] =3D mc->hdr.patch_id; + + /* verify patch application was successful */ + *cur_rev =3D get_patch_level(); + + ucode_dbg("updated rev: 0x%x\n", *cur_rev); + + if (*cur_rev !=3D mc->hdr.patch_id) + return false; + + return true; +} + +static bool get_builtin_microcode(struct cpio_data *cp) +{ + char fw_name[40] =3D "hygon-ucode/microcode_hygon_fam18h.bin"; + struct firmware fw; + + if (IS_ENABLED(CONFIG_X86_32)) + return false; + + if (firmware_request_builtin(&fw, fw_name)) { + cp->size =3D fw.size; + cp->data =3D (void *)fw.data; + return true; + } + + return false; +} + +static bool __init find_blobs_in_containers(struct cpio_data *ret) +{ + struct cpio_data cp; + bool found; + + if (!get_builtin_microcode(&cp)) + cp =3D find_microcode_in_initrd(ucode_path); + + found =3D cp.data && cp.size; + if (found) + *ret =3D cp; + + return found; +} + +/* + * Early load occurs before we can vmalloc(). So we look for the microcode + * patch container file in initrd, traverse equivalent cpu table, look for= a + * matching microcode patch, and update, all in initrd memory in place. + * When vmalloc() is available for use later -- on 64-bit during first AP = load, + * and on 32-bit during save_microcode_in_initrd() -- we can call + * load_microcode_hygon() to save equivalent cpu table and microcode patch= es in + * kernel heap memory. + */ +void __init load_ucode_hygon_bsp(struct early_load_data *ed, unsigned int = cpuid_1_eax) +{ + struct cont_desc desc =3D { }; + struct microcode_hygon *mc; + struct cpio_data cp =3D { }; + u32 rev; + + bsp_cpuid_1_eax =3D cpuid_1_eax; + + rev =3D get_patch_level(); + ed->old_rev =3D rev; + + /* Needed in load_microcode_hygon() */ + ucode_cpu_info[0].cpu_sig.sig =3D cpuid_1_eax; + + if (!find_blobs_in_containers(&cp)) + return; + + scan_containers(cp.data, cp.size, &desc); + + mc =3D desc.mc; + if (!mc) + return; + + /* + * Allow application of the same revision to pick up SMT-specific + * changes even if the revision of the other SMT thread is already + * up-to-date. + */ + if (ed->old_rev > mc->hdr.patch_id) + return; + + if (__apply_microcode_hygon(mc, &rev, desc.psize)) + ed->new_rev =3D rev; +} + +/* + * a small, trivial cache of per-family ucode patches + */ +static struct ucode_patch *cache_find_patch(struct ucode_cpu_info *uci, u1= 6 equiv_cpu) +{ + struct ucode_patch *p; + + list_for_each_entry(p, µcode_cache, plist) + if (p->equiv_cpu =3D=3D equiv_cpu) + return p; + + return NULL; +} + +static void update_cache(struct ucode_patch *new_patch) +{ + struct ucode_patch *p; + + list_for_each_entry(p, µcode_cache, plist) { + if (p->equiv_cpu =3D=3D new_patch->equiv_cpu) { + if (p->patch_id >=3D new_patch->patch_id) { + /* we already have the latest patch */ + kfree(new_patch->data); + kfree(new_patch); + return; + } + + list_replace(&p->plist, &new_patch->plist); + kfree(p->data); + kfree(p); + return; + } + } + /* no patch found, add it */ + list_add_tail(&new_patch->plist, µcode_cache); +} + +static void free_cache(void) +{ + struct ucode_patch *p, *tmp; + + list_for_each_entry_safe(p, tmp, µcode_cache, plist) { + __list_del(p->plist.prev, p->plist.next); + kfree(p->data); + kfree(p); + } +} + +static struct ucode_patch *find_patch(unsigned int cpu) +{ + struct ucode_cpu_info *uci =3D ucode_cpu_info + cpu; + u16 equiv_id =3D 0; + + uci->cpu_sig.rev =3D get_patch_level(); + + equiv_id =3D find_equiv_id(&equiv_table, uci->cpu_sig.sig); + if (!equiv_id) + return NULL; + + return cache_find_patch(uci, equiv_id); +} + +void reload_ucode_hygon(unsigned int cpu) +{ + u32 rev, dummy __always_unused; + struct microcode_hygon *mc; + struct ucode_patch *p; + + p =3D find_patch(cpu); + if (!p) + return; + + mc =3D p->data; + + rev =3D get_patch_level(); + if (rev < mc->hdr.patch_id) { + if (__apply_microcode_hygon(mc, &rev, p->size)) + pr_info_once("reload revision: 0x%08x\n", rev); + } +} + +static int collect_cpu_info_hygon(int cpu, struct cpu_signature *csig) +{ + struct ucode_cpu_info *uci =3D ucode_cpu_info + cpu; + struct ucode_patch *p; + + csig->sig =3D cpuid_eax(0x00000001); + csig->rev =3D get_patch_level(); + + /* + * a patch could have been loaded early, set uci->mc so that + * mc_bp_resume() can call apply_microcode() + */ + p =3D find_patch(cpu); + if (p && (p->patch_id =3D=3D csig->rev)) + uci->mc =3D p->data; + + return 0; +} + +static enum ucode_state apply_microcode_hygon(int cpu) +{ + struct cpuinfo_x86 *c =3D &cpu_data(cpu); + struct microcode_hygon *mc_hygon; + struct ucode_cpu_info *uci; + struct ucode_patch *p; + enum ucode_state ret; + u32 rev; + + BUG_ON(raw_smp_processor_id() !=3D cpu); + + uci =3D ucode_cpu_info + cpu; + + p =3D find_patch(cpu); + if (!p) + return UCODE_NFOUND; + + rev =3D uci->cpu_sig.rev; + + mc_hygon =3D p->data; + uci->mc =3D p->data; + + /* need to apply patch? */ + if (rev > mc_hygon->hdr.patch_id) { + ret =3D UCODE_OK; + goto out; + } + + if (!__apply_microcode_hygon(mc_hygon, &rev, p->size)) { + pr_err("CPU%d: update failed for patch_level=3D0x%08x\n", + cpu, mc_hygon->hdr.patch_id); + return UCODE_ERROR; + } + + rev =3D mc_hygon->hdr.patch_id; + ret =3D UCODE_UPDATED; + +out: + uci->cpu_sig.rev =3D rev; + c->microcode =3D rev; + + /* Update boot_cpu_data's revision too, if we're on the BSP: */ + if (c->cpu_index =3D=3D boot_cpu_data.cpu_index) + boot_cpu_data.microcode =3D rev; + + return ret; +} + +void load_ucode_hygon_ap(unsigned int cpuid_1_eax) +{ + unsigned int cpu =3D smp_processor_id(); + + ucode_cpu_info[cpu].cpu_sig.sig =3D cpuid_1_eax; + apply_microcode_hygon(cpu); +} + +static size_t install_equiv_cpu_table(const u8 *buf, size_t buf_size) +{ + u32 equiv_tbl_len; + const u32 *hdr; + + if (!verify_equivalence_table(buf, buf_size)) + return 0; + + hdr =3D (const u32 *)buf; + equiv_tbl_len =3D hdr[2]; + + equiv_table.entry =3D vmalloc(equiv_tbl_len); + if (!equiv_table.entry) { + pr_err("failed to allocate equivalent CPU table\n"); + return 0; + } + + memcpy(equiv_table.entry, buf + CONTAINER_HDR_SZ, equiv_tbl_len); + equiv_table.num_entries =3D equiv_tbl_len / sizeof(struct equiv_cpu_entry= ); + + /* add header length */ + return equiv_tbl_len + CONTAINER_HDR_SZ; +} + +static void free_equiv_cpu_table(void) +{ + vfree(equiv_table.entry); + memset(&equiv_table, 0, sizeof(equiv_table)); +} + +static void cleanup(void) +{ + free_equiv_cpu_table(); + free_cache(); +} + +/* + * Return a non-negative value even if some of the checks failed so that + * we can skip over the next patch. If we return a negative value, we + * signal a grave error like a memory allocation has failed and the + * driver cannot continue functioning normally. In such cases, we tear + * down everything we've used up so far and exit. + */ +static int verify_and_add_patch(u8 family, u8 *fw, unsigned int leftover, + unsigned int *patch_size) +{ + struct microcode_header_hygon *mc_hdr; + struct ucode_patch *patch; + u16 proc_id; + int ret; + + ret =3D verify_patch(fw, leftover, patch_size); + if (ret) + return ret; + + patch =3D kzalloc_obj(*patch); + if (!patch) { + pr_err("Patch allocation failure.\n"); + return -EINVAL; + } + + patch->data =3D kmemdup(fw + SECTION_HDR_SIZE, *patch_size, GFP_KERNEL); + if (!patch->data) { + pr_err("Patch data allocation failure.\n"); + kfree(patch); + return -EINVAL; + } + patch->size =3D *patch_size; + + mc_hdr =3D (struct microcode_header_hygon *)(fw + SECTION_HDR_SIZE); + proc_id =3D mc_hdr->processor_rev_id; + + INIT_LIST_HEAD(&patch->plist); + patch->patch_id =3D mc_hdr->patch_id; + patch->equiv_cpu =3D proc_id; + + ucode_dbg("%s: Adding patch_id: 0x%08x, proc_id: 0x%04x\n", + __func__, patch->patch_id, proc_id); + + /* ... and add to cache. */ + update_cache(patch); + + return 0; +} + +/* Scan the blob in @data and add microcode patches to the cache. */ +static enum ucode_state __load_microcode_hygon(u8 family, const u8 *data, = size_t size) +{ + u8 *fw =3D (u8 *)data; + size_t offset; + + offset =3D install_equiv_cpu_table(data, size); + if (!offset) + return UCODE_ERROR; + + fw +=3D offset; + size -=3D offset; + + if (*(u32 *)fw !=3D UCODE_UCODE_TYPE) { + pr_err("invalid type field in container file section header\n"); + free_equiv_cpu_table(); + return UCODE_ERROR; + } + + while (size > 0) { + unsigned int crnt_size =3D 0; + int ret; + + ret =3D verify_and_add_patch(family, fw, size, &crnt_size); + if (ret < 0) + return UCODE_ERROR; + + fw +=3D crnt_size + SECTION_HDR_SIZE; + size -=3D (crnt_size + SECTION_HDR_SIZE); + } + + return UCODE_OK; +} + +static enum ucode_state _load_microcode_hygon(u8 family, const u8 *data, s= ize_t size) +{ + enum ucode_state ret; + + /* free old equiv table */ + free_equiv_cpu_table(); + + ret =3D __load_microcode_hygon(family, data, size); + if (ret !=3D UCODE_OK) + cleanup(); + + return ret; +} + +static enum ucode_state load_microcode_hygon(u8 family, const u8 *data, si= ze_t size) +{ + struct cpuinfo_x86 *c; + unsigned int nid, cpu; + struct ucode_patch *p; + enum ucode_state ret; + + ret =3D _load_microcode_hygon(family, data, size); + if (ret !=3D UCODE_OK) + return ret; + + for_each_node_with_cpus(nid) { + cpu =3D cpumask_first(cpumask_of_node(nid)); + c =3D &cpu_data(cpu); + + p =3D find_patch(cpu); + if (!p) + continue; + + if (c->microcode >=3D p->patch_id) + continue; + + ret =3D UCODE_NEW; + } + + return ret; +} + +static int __init save_microcode_in_initrd(void) +{ + struct cpuinfo_x86 *c =3D &boot_cpu_data; + struct cont_desc desc =3D { 0 }; + unsigned int cpuid_1_eax; + enum ucode_state ret; + struct cpio_data cp; + + if (microcode_loader_disabled() || (c->x86_vendor !=3D X86_VENDOR_HYGON)) + return 0; + + cpuid_1_eax =3D native_cpuid_eax(1); + + if (!find_blobs_in_containers(&cp)) + return -EINVAL; + + scan_containers(cp.data, cp.size, &desc); + if (!desc.mc) + return -EINVAL; + + ret =3D _load_microcode_hygon(x86_family(cpuid_1_eax), desc.data, desc.si= ze); + if (ret > UCODE_UPDATED) + return -EINVAL; + + return 0; +} +early_initcall(save_microcode_in_initrd); + +/* + * Hygon microcode firmware naming are in family-specific firmware files: + * hygon-ucode/microcode_hygon_fam18h.bin + */ +static enum ucode_state request_microcode_hygon(int cpu, struct device *de= vice) +{ + char fw_name[40] =3D "hygon-ucode/microcode_hygon_fam18h.bin"; + struct cpuinfo_x86 *c =3D &cpu_data(cpu); + enum ucode_state ret =3D UCODE_NFOUND; + const struct firmware *fw; + + if (force_minrev) + return UCODE_NFOUND; + + if (request_firmware_direct(&fw, (const char *)fw_name, device)) { + ucode_dbg("failed to load file %s\n", fw_name); + goto out; + } + + ret =3D UCODE_ERROR; + if (!verify_container(fw->data, fw->size)) + goto fw_release; + + ret =3D load_microcode_hygon(c->x86, fw->data, fw->size); + + fw_release: + release_firmware(fw); + + out: + return ret; +} + +static void microcode_fini_cpu_hygon(int cpu) +{ + struct ucode_cpu_info *uci =3D ucode_cpu_info + cpu; + + uci->mc =3D NULL; +} + +static void finalize_late_load_hygon(int result) +{ + if (result) + cleanup(); +} + +static struct microcode_ops microcode_hygon_ops =3D { + .request_microcode_fw =3D request_microcode_hygon, + .collect_cpu_info =3D collect_cpu_info_hygon, + .apply_microcode =3D apply_microcode_hygon, + .microcode_fini_cpu =3D microcode_fini_cpu_hygon, + .finalize_late_load =3D finalize_late_load_hygon, + .nmi_safe =3D true, +}; + +struct microcode_ops * __init init_hygon_microcode(void) +{ + struct cpuinfo_x86 *c =3D &boot_cpu_data; + + if (c->x86_vendor !=3D X86_VENDOR_HYGON) + return NULL; + + return µcode_hygon_ops; +} + +void __exit exit_hygon_microcode(void) +{ + cleanup(); +} diff --git a/arch/x86/kernel/cpu/microcode/internal.h b/arch/x86/kernel/cpu= /microcode/internal.h index 3b93c0676..1dbb48651 100644 --- a/arch/x86/kernel/cpu/microcode/internal.h +++ b/arch/x86/kernel/cpu/microcode/internal.h @@ -61,6 +61,9 @@ struct cpio_data find_microcode_in_initrd(const char *pat= h); #define CPUID_AMD1 QCHAR('A', 'u', 't', 'h') #define CPUID_AMD2 QCHAR('e', 'n', 't', 'i') #define CPUID_AMD3 QCHAR('c', 'A', 'M', 'D') +#define CPUID_HYGON1 QCHAR('H', 'y', 'g', 'o') +#define CPUID_HYGON2 QCHAR('n', 'G', 'e', 'n') +#define CPUID_HYGON3 QCHAR('u', 'i', 'n', 'e') =20 #define CPUID_IS(a, b, c, ebx, ecx, edx) \ (!(((ebx) ^ (a)) | ((edx) ^ (b)) | ((ecx) ^ (c)))) @@ -87,6 +90,9 @@ static inline int x86_cpuid_vendor(void) if (CPUID_IS(CPUID_AMD1, CPUID_AMD2, CPUID_AMD3, ebx, ecx, edx)) return X86_VENDOR_AMD; =20 + if (CPUID_IS(CPUID_HYGON1, CPUID_HYGON2, CPUID_HYGON3, ebx, ecx, edx)) + return X86_VENDOR_HYGON; + return X86_VENDOR_UNKNOWN; } =20 @@ -128,6 +134,20 @@ static inline void reload_ucode_intel(void) { } static inline struct microcode_ops *init_intel_microcode(void) { return NU= LL; } #endif /* !CONFIG_CPU_SUP_INTEL */ =20 +#ifdef CONFIG_CPU_SUP_HYGON +void load_ucode_hygon_bsp(struct early_load_data *ed, unsigned int family); +void load_ucode_hygon_ap(unsigned int family); +void reload_ucode_hygon(unsigned int cpu); +struct microcode_ops *init_hygon_microcode(void); +void exit_hygon_microcode(void); +#else /* CONFIG_CPU_SUP_HYGON */ +static inline void load_ucode_hygon_bsp(struct early_load_data *ed, unsign= ed int family) { } +static inline void load_ucode_hygon_ap(unsigned int family) { } +static inline void reload_ucode_hygon(unsigned int cpu) { } +static inline struct microcode_ops *init_hygon_microcode(void) { return NU= LL; } +static inline void exit_hygon_microcode(void) { } +#endif /* !CONFIG_CPU_SUP_HYGON */ + #define ucode_dbg(fmt, ...) \ ({ \ if (IS_ENABLED(CONFIG_MICROCODE_DBG)) \ --=20 2.34.1 From nobody Sat Jun 13 07:46:58 2026 Received: from out28-99.mail.aliyun.com (out28-99.mail.aliyun.com [115.124.28.99]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 12AE5394493; Tue, 7 Apr 2026 08:29:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=115.124.28.99 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775550561; cv=none; b=S97/9Vp1YmQK+1Rxcvm9iC70YYOBVBMEwdUl6p0GOrvC1Aw4l880d6VYljWwEZ+jElHQHB+AEQr4v09aplbYvpABtff28QCVpctbj0DUDyRBm4T34be/W4twZJy9qVSdFrvMNXRUJQOQqNqOfYEcQJzG16oe47iCV0m55Hlo+7c= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775550561; c=relaxed/simple; bh=tKOmSJCKRzDDvI3cVgRc3Qh9AjlKtYmswmCIrXnn5Ck=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=Taa5RBiyLpd8caDoOfH3hYD2eCd2BCgF9aXtnzUDx/QcRKuH+1jyns9mUrggY0h6HQfzYcfiEdYxvBOsVc/8mVTNQ307JRegASPMxB6XsG2dKaK/zw10oBWdklFYRPvUC/2iUCPeJL64usSQNMrGI+cIIyf0jVke3bsfNSJ2vJg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=open-hieco.net; spf=pass smtp.mailfrom=open-hieco.net; arc=none smtp.client-ip=115.124.28.99 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=open-hieco.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=open-hieco.net X-Alimail-AntiSpam: AC=CONTINUE;BC=0.1027766|-1;CH=green;DM=|CONTINUE|false|;DS=CONTINUE|ham_system_inform|0.0125103-0.000100357-0.987389;FP=12517315119771303843|2|1|1|0|-1|-1|-1;HT=maildocker-contentspam033040074035;MF=fuhao@open-hieco.net;NM=1;PH=DS;RN=7;RT=7;SR=0;TI=SMTPD_---.h6alull_1775550222; Received: from higon..(mailfrom:fuhao@open-hieco.net fp:SMTPD_---.h6alull_1775550222 cluster:ay29) by smtp.aliyun-inc.com; Tue, 07 Apr 2026 16:23:47 +0800 From: Fu Hao To: bhelgaas@google.com, perex@perex.cz, tiwai@suse.com Cc: linux-kernel@vger.kernel.org, linux-sound@vger.kernel.org, linux-pci@vger.kernel.org, Fu Hao Subject: [PATCH v2 6/8] ALSA: hda: Add support for Hygon family 18h model 5h HD-Audio Date: Tue, 7 Apr 2026 16:24:56 +0800 Message-Id: X-Mailer: git-send-email 2.34.1 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add the new PCI ID 0x1d94 0x14a9 for Hygon family 18h model 5h HDA controller. Signed-off-by: Fu Hao Tested-by: Tingyin Duan --- include/linux/pci_ids.h | 1 + sound/hda/controllers/intel.c | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 406abf629..19d968017 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2613,6 +2613,7 @@ #define PCI_VENDOR_ID_ROCKCHIP 0x1d87 =20 #define PCI_VENDOR_ID_HYGON 0x1d94 +#define PCI_DEVICE_ID_HYGON_18H_M05H_HDA 0x14a9 =20 #define PCI_VENDOR_ID_META 0x1d9b =20 diff --git a/sound/hda/controllers/intel.c b/sound/hda/controllers/intel.c index 3f434994c..eb5d48d90 100644 --- a/sound/hda/controllers/intel.c +++ b/sound/hda/controllers/intel.c @@ -241,6 +241,7 @@ enum { AZX_DRIVER_ZHAOXIN, AZX_DRIVER_ZHAOXINHDMI, AZX_DRIVER_LOONGSON, + AZX_DRIVER_HYGON, AZX_DRIVER_GENERIC, AZX_NUM_DRIVERS, /* keep this as last entry */ }; @@ -357,6 +358,7 @@ static const char * const driver_short_names[] =3D { [AZX_DRIVER_ZHAOXIN] =3D "HDA Zhaoxin", [AZX_DRIVER_ZHAOXINHDMI] =3D "HDA Zhaoxin HDMI", [AZX_DRIVER_LOONGSON] =3D "HDA Loongson", + [AZX_DRIVER_HYGON] =3D "HDA Hygon", [AZX_DRIVER_GENERIC] =3D "HD-Audio Generic", }; =20 @@ -2818,6 +2820,9 @@ static const struct pci_device_id azx_ids[] =3D { .driver_data =3D AZX_DRIVER_LOONGSON | AZX_DCAPS_NO_TCSEL }, { PCI_VDEVICE(LOONGSON, PCI_DEVICE_ID_LOONGSON_HDMI), .driver_data =3D AZX_DRIVER_LOONGSON | AZX_DCAPS_NO_TCSEL }, + /* Hygon HDAudio */ + { PCI_VDEVICE(HYGON, PCI_DEVICE_ID_HYGON_18H_M05H_HDA), + .driver_data =3D AZX_DRIVER_HYGON | AZX_DCAPS_POSFIX_LPIB | AZX_DCAPS_N= O_MSI }, { 0, } }; MODULE_DEVICE_TABLE(pci, azx_ids); --=20 2.34.1 From nobody Sat Jun 13 07:46:58 2026 Received: from out28-73.mail.aliyun.com (out28-73.mail.aliyun.com [115.124.28.73]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6D3A33A1E8C; Tue, 7 Apr 2026 08:24:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=115.124.28.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775550261; cv=none; b=k0pRfjz0gv1Rn2+J/ERTOHtfIUKlx2TPxUnXiqJXTBYVszqeQzB6cu43SULiTmUSohAqAa6QZUB//ff9r/Ob6VcfqxmnB472AqmzVY61iyxqYF2DXLoIibQ3HpfZb9VkJb6YlVsqWfzfVbX77a4t3pPJEuJOtxDoG49Tzhv0dG8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775550261; c=relaxed/simple; bh=/rjeYuATgtaqTiyQXZZEsBDu3ZZyIsvyE9WXW+Gl6Ic=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=PdZs2RL34NOtfT1POJFNmKCqXN9mUUlCFmNwbKQN79bq5OLJXSJrdKcB2eG4f/8mVx1RG+6Noefn5w64pUhYQ1TdScAh+F2lOm0S0dnWaCJFRttfYo58FSDqJpcfndTjE0MzDjd7OgrCs4HSUMyCHiRjldkb1U7DVq7MbTjvu3o= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=open-hieco.net; spf=pass smtp.mailfrom=open-hieco.net; arc=none smtp.client-ip=115.124.28.73 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=open-hieco.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=open-hieco.net X-Alimail-AntiSpam: AC=CONTINUE;BC=0.07436268|-1;CH=green;DM=|CONTINUE|false|;DS=CONTINUE|ham_system_inform|0.00383647-0.000630138-0.995533;FP=13771291786202451602|2|1|1|0|-1|-1|-1;HT=maildocker-contentspam033045018182;MF=fuhao@open-hieco.net;NM=1;PH=DS;RN=5;RT=5;SR=0;TI=SMTPD_---.h6Yq2EJ_1775550242; Received: from higon..(mailfrom:fuhao@open-hieco.net fp:SMTPD_---.h6Yq2EJ_1775550242 cluster:ay29) by smtp.aliyun-inc.com; Tue, 07 Apr 2026 16:24:06 +0800 From: Fu Hao To: perex@perex.cz, tiwai@suse.com Cc: linux-kernel@vger.kernel.org, linux-sound@vger.kernel.org, Fu Hao Subject: [PATCH v2 7/8] ALSA: hda: Fix single byte writing issue for Hygon family 18h model 5h Date: Tue, 7 Apr 2026 16:25:18 +0800 Message-Id: <074f9ceb9e1407220ff60a34f57ba62e7c0ef50f.1775548724.git.fuhao@open-hieco.net> X-Mailer: git-send-email 2.34.1 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" On Hygon family 18h model 5h controller, some registers such as GCTL, SD_CTL and SD_CTL_3B should be accessed in dword, or the writing will fail. Signed-off-by: Fu Hao Tested-by: Tingyin Duan --- sound/hda/controllers/intel.c | 4 ++++ sound/hda/core/controller.c | 10 +++++++-- sound/hda/core/stream.c | 40 +++++++++++++++++++++++++++-------- 3 files changed, 43 insertions(+), 11 deletions(-) diff --git a/sound/hda/controllers/intel.c b/sound/hda/controllers/intel.c index eb5d48d90..81797a68e 100644 --- a/sound/hda/controllers/intel.c +++ b/sound/hda/controllers/intel.c @@ -1885,6 +1885,10 @@ static int azx_first_init(struct azx *chip) if (chip->driver_type =3D=3D AZX_DRIVER_ZHAOXINHDMI) bus->polling_mode =3D 1; =20 + if (chip->driver_type =3D=3D AZX_DRIVER_HYGON && + chip->pci->device =3D=3D PCI_DEVICE_ID_HYGON_18H_M05H_HDA) + bus->access_sdnctl_in_dword =3D 1; + bus->remap_addr =3D pcim_iomap_region(pci, 0, "ICH HD audio"); if (IS_ERR(bus->remap_addr)) return PTR_ERR(bus->remap_addr); diff --git a/sound/hda/core/controller.c b/sound/hda/core/controller.c index 69e11d62b..6312ad7af 100644 --- a/sound/hda/core/controller.c +++ b/sound/hda/core/controller.c @@ -511,7 +511,10 @@ void snd_hdac_bus_exit_link_reset(struct hdac_bus *bus) { unsigned long timeout; =20 - snd_hdac_chip_updateb(bus, GCTL, AZX_GCTL_RESET, AZX_GCTL_RESET); + if (bus->access_sdnctl_in_dword) + snd_hdac_chip_updatel(bus, GCTL, AZX_GCTL_RESET, AZX_GCTL_RESET); + else + snd_hdac_chip_updateb(bus, GCTL, AZX_GCTL_RESET, AZX_GCTL_RESET); =20 timeout =3D jiffies + msecs_to_jiffies(100); while (!snd_hdac_chip_readb(bus, GCTL) && time_before(jiffies, timeout)) @@ -576,7 +579,10 @@ static void azx_int_disable(struct hdac_bus *bus) =20 /* disable interrupts in stream descriptor */ list_for_each_entry(azx_dev, &bus->stream_list, list) - snd_hdac_stream_updateb(azx_dev, SD_CTL, SD_INT_MASK, 0); + if (bus->access_sdnctl_in_dword) + snd_hdac_stream_updatel(azx_dev, SD_CTL, SD_INT_MASK, 0); + else + snd_hdac_stream_updateb(azx_dev, SD_CTL, SD_INT_MASK, 0); =20 /* disable SIE for all streams & disable controller CIE and GIE */ snd_hdac_chip_writel(bus, INTCTL, 0); diff --git a/sound/hda/core/stream.c b/sound/hda/core/stream.c index b471a038b..0091c4ef6 100644 --- a/sound/hda/core/stream.c +++ b/sound/hda/core/stream.c @@ -146,8 +146,12 @@ void snd_hdac_stream_start(struct hdac_stream *azx_dev) stripe_ctl =3D snd_hdac_get_stream_stripe_ctl(bus, azx_dev->substream); else stripe_ctl =3D 0; - snd_hdac_stream_updateb(azx_dev, SD_CTL_3B, SD_CTL_STRIPE_MASK, - stripe_ctl); + if (bus->access_sdnctl_in_dword) + snd_hdac_stream_updatel(azx_dev, SD_CTL_3B, SD_CTL_STRIPE_MASK, + stripe_ctl); + else + snd_hdac_stream_updateb(azx_dev, SD_CTL_3B, SD_CTL_STRIPE_MASK, + stripe_ctl); } /* set DMA start and interrupt mask */ if (bus->access_sdnctl_in_dword) @@ -166,11 +170,22 @@ EXPORT_SYMBOL_GPL(snd_hdac_stream_start); */ static void snd_hdac_stream_clear(struct hdac_stream *azx_dev) { - snd_hdac_stream_updateb(azx_dev, SD_CTL, - SD_CTL_DMA_START | SD_INT_MASK, 0); - snd_hdac_stream_writeb(azx_dev, SD_STS, SD_INT_MASK); /* to be sure */ - if (azx_dev->stripe) - snd_hdac_stream_updateb(azx_dev, SD_CTL_3B, SD_CTL_STRIPE_MASK, 0); + struct hdac_bus *bus =3D azx_dev->bus; + + if (bus->access_sdnctl_in_dword) { + snd_hdac_stream_updatel(azx_dev, SD_CTL, + SD_CTL_DMA_START | SD_INT_MASK, 0); + snd_hdac_stream_writeb(azx_dev, SD_STS, SD_INT_MASK); /* to be sure */ + if (azx_dev->stripe) + snd_hdac_stream_updatel(azx_dev, SD_CTL_3B, SD_CTL_STRIPE_MASK, 0); + } else { + snd_hdac_stream_updateb(azx_dev, SD_CTL, + SD_CTL_DMA_START | SD_INT_MASK, 0); + snd_hdac_stream_writeb(azx_dev, SD_STS, SD_INT_MASK); /* to be sure */ + if (azx_dev->stripe) + snd_hdac_stream_updateb(azx_dev, SD_CTL_3B, SD_CTL_STRIPE_MASK, 0); + } + azx_dev->running =3D false; } =20 @@ -225,12 +240,16 @@ void snd_hdac_stream_reset(struct hdac_stream *azx_de= v) { unsigned char val; int dma_run_state; + struct hdac_bus *bus =3D azx_dev->bus; =20 snd_hdac_stream_clear(azx_dev); =20 dma_run_state =3D snd_hdac_stream_readb(azx_dev, SD_CTL) & SD_CTL_DMA_STA= RT; =20 - snd_hdac_stream_updateb(azx_dev, SD_CTL, 0, SD_CTL_STREAM_RESET); + if (bus->access_sdnctl_in_dword) + snd_hdac_stream_updatel(azx_dev, SD_CTL, 0, SD_CTL_STREAM_RESET); + else + snd_hdac_stream_updateb(azx_dev, SD_CTL, 0, SD_CTL_STREAM_RESET); =20 /* wait for hardware to report that the stream entered reset */ snd_hdac_stream_readb_poll(azx_dev, SD_CTL, val, (val & SD_CTL_STREAM_RES= ET), 3, 300); @@ -238,7 +257,10 @@ void snd_hdac_stream_reset(struct hdac_stream *azx_dev) if (azx_dev->bus->dma_stop_delay && dma_run_state) udelay(azx_dev->bus->dma_stop_delay); =20 - snd_hdac_stream_updateb(azx_dev, SD_CTL, SD_CTL_STREAM_RESET, 0); + if (bus->access_sdnctl_in_dword) + snd_hdac_stream_updatel(azx_dev, SD_CTL, SD_CTL_STREAM_RESET, 0); + else + snd_hdac_stream_updateb(azx_dev, SD_CTL, SD_CTL_STREAM_RESET, 0); =20 /* wait for hardware to report that the stream is out of reset */ snd_hdac_stream_readb_poll(azx_dev, SD_CTL, val, !(val & SD_CTL_STREAM_RE= SET), 3, 300); --=20 2.34.1 From nobody Sat Jun 13 07:46:58 2026 Received: from out28-145.mail.aliyun.com (out28-145.mail.aliyun.com [115.124.28.145]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 63BCD3A382D for ; Tue, 7 Apr 2026 08:24:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=115.124.28.145 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775550275; cv=none; b=XA9vFNJzAhcQ8syx4SCB048TNO2tU6V7omqU7+YmvMvGOGpsQir91pkvoqMfiIgcOlgXLcOf7bHWgxvEwDxaPZs3tbOSjDUcB0KpbtUPiLe3ze2h4NM8bjwQw/InSVnTsulHz6DT7baPRRSzCbVTSGkeD2yT+qlmps4dvCnoX7E= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775550275; c=relaxed/simple; bh=sxgmmB/s8dU0sog7lx+d0UeghLAKezo0fo702m0l6r8=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=BpsJqRlrqTdxzKNJ7XT9lOydzoYcgBC8r3Tfx/QKqdXKtHtYgs/JIBIBHc/nd4aU37CJ6Gww3UCgvvny88F9OtRnR9tzOSYA7NVRBZrhOL1TCbx+4UMZPYBKmfOxmQeKMQCyivR1/KSToUBA1YMv1biaMDY9+9/5On+HGmsHdas= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=open-hieco.net; spf=pass smtp.mailfrom=open-hieco.net; arc=none smtp.client-ip=115.124.28.145 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=open-hieco.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=open-hieco.net X-Alimail-AntiSpam: AC=CONTINUE;BC=0.07663862|-1;CH=green;DM=|CONTINUE|false|;DS=CONTINUE|ham_regular_dialog|0.0156302-0.00341411-0.980956;FP=1117291624617541927|2|1|1|0|-1|-1|-1;HT=maildocker-contentspam033032027189;MF=fuhao@open-hieco.net;NM=1;PH=DS;RN=7;RT=7;SR=0;TI=SMTPD_---.h6dNpqZ_1775550264; Received: from higon..(mailfrom:fuhao@open-hieco.net fp:SMTPD_---.h6dNpqZ_1775550264 cluster:ay29) by smtp.aliyun-inc.com; Tue, 07 Apr 2026 16:24:29 +0800 From: Fu Hao To: joro@8bytes.org, will@kernel.org, suravee.suthikulpanit@amd.com, robin.murphy@arm.com Cc: linux-kernel@vger.kernel.org, iommu@lists.linux.dev, Fu Hao Subject: [PATCH v2 8/8] iommu/hygon: Add support for Hygon family 18h model 4h IOAPIC Date: Tue, 7 Apr 2026 16:25:40 +0800 Message-Id: <3c1d95e3f53b250c97c60f613ead7e0ec0ea2d87.1775548724.git.fuhao@open-hieco.net> X-Mailer: git-send-email 2.34.1 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The SB IOAPIC is on the device 0xb from Hygon family 18h model 4h. Signed-off-by: Fu Hao Tested-by: Tingyin Duan --- drivers/iommu/amd/init.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c index f3fd7f39e..568851cc2 100644 --- a/drivers/iommu/amd/init.c +++ b/drivers/iommu/amd/init.c @@ -3096,6 +3096,9 @@ static void __init free_iommu_resources(void) /* SB IOAPIC is always on this device in AMD systems */ #define IOAPIC_SB_DEVID ((0x00 << 8) | PCI_DEVFN(0x14, 0)) =20 +/* SB IOAPIC for Hygon family 18h model 4h is on the device 0xb */ +#define IOAPIC_SB_DEVID_FAM18H_M4H ((0x00 << 8) | PCI_DEVFN(0xb, 0)) + static bool __init check_ioapic_information(void) { const char *fw_bug =3D FW_BUG; @@ -3121,7 +3124,12 @@ static bool __init check_ioapic_information(void) pr_err("%s: IOAPIC[%d] not in IVRS table\n", fw_bug, id); ret =3D false; - } else if (devid =3D=3D IOAPIC_SB_DEVID) { + } else if (devid =3D=3D IOAPIC_SB_DEVID || + (boot_cpu_data.x86_vendor =3D=3D X86_VENDOR_HYGON && + boot_cpu_data.x86 =3D=3D 0x18 && + boot_cpu_data.x86_model >=3D 0x4 && + boot_cpu_data.x86_model <=3D 0xf && + devid =3D=3D IOAPIC_SB_DEVID_FAM18H_M4H)) { has_sb_ioapic =3D true; ret =3D true; } --=20 2.34.1