* [PATCH v2 0/8] Add support for Hygon Family 18h model 4h~8h processors
@ 2026-04-07 8:22 Fu Hao
2026-04-07 8:22 ` [PATCH v2 1/8] x86/cpu/hygon: Adjust the die_id and logical_die_id for Hygon models 0x4-0x8 Fu Hao
` (7 more replies)
0 siblings, 8 replies; 14+ messages in thread
From: Fu Hao @ 2026-04-07 8:22 UTC (permalink / raw)
To: puwen, tglx, mingo, bp, dave.hansen, x86, peterz, acme, joro,
will, suravee.suthikulpanit, robin.murphy, bhelgaas, perex, tiwai,
namhyung, alexander.shishkin, jolsa, irogers, james.clark, hpa
Cc: linux-kernel, Fu Hao
This patch series introduce support for the new-generation Hygon
models 0x4-0x8 processors, addressing five key areas:
1. CPU Topology Updates
The new processor introduces a revised CPU topology hierarchy
compared to previous generations. This patch updates the kernel's
topology detection logic to correctly identify core/socket
relationships and cache sharing patterns.
2. L3 Performance Monitoring Updates
The L3 perf registers of model 6h differ from those of the
previous processor.
3. Microcode loading
Add microcode loading support for Hygon processor.
4. Audio Controller Driver
Add initial support for the integrated HD-Audio controller.
5. New SB IOAPIC information support
The southbridge IOAPIC of Hygon's new-generation processors is
located at 00:0b.0.
v1->v2:
- Refine the patch x86/cpu/hygon.
- Do a separate compilation unit on hygon microcode loading support.
- Use "access_sdnctl_in_dword" instead of "hygon_dword_acess" for
accessing the HDA registers.
Fu Hao (8):
x86/cpu/hygon: Adjust the die_id and logical_die_id for Hygon models
0x4-0x8
x86/cpu: Get LLC ID for Hygon family 18h model 4h
x86/cpu/hygon: Remove Spectral Chicken for Hygon processors
perf/x86/uncore: Add L3 PMU support for Hygon family 18h model 6h
x86/microcode/hygon: Add microcode loading support for Hygon
processors
ALSA: hda: Add support for Hygon family 18h model 5h HD-Audio
ALSA: hda: Fix single byte writing issue for Hygon family 18h model 5h
iommu/hygon: Add support for Hygon family 18h model 4h IOAPIC
arch/x86/Kconfig | 2 +-
arch/x86/events/amd/uncore.c | 48 +-
arch/x86/include/asm/perf_event.h | 8 +
arch/x86/kernel/cpu/cacheinfo.c | 22 +-
arch/x86/kernel/cpu/hygon.c | 16 +-
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 +
drivers/iommu/amd/init.c | 10 +-
include/linux/pci_ids.h | 1 +
sound/hda/controllers/intel.c | 9 +
sound/hda/core/controller.c | 10 +-
sound/hda/core/stream.c | 40 +-
14 files changed, 1105 insertions(+), 26 deletions(-)
create mode 100644 arch/x86/kernel/cpu/microcode/hygon.c
--
2.34.1
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2 1/8] x86/cpu/hygon: Adjust the die_id and logical_die_id for Hygon models 0x4-0x8
2026-04-07 8:22 [PATCH v2 0/8] Add support for Hygon Family 18h model 4h~8h processors Fu Hao
@ 2026-04-07 8:22 ` Fu Hao
2026-04-07 8:23 ` [PATCH v2 2/8] x86/cpu: Get LLC ID for Hygon family 18h model 4h Fu Hao
` (6 subsequent siblings)
7 siblings, 0 replies; 14+ messages in thread
From: Fu Hao @ 2026-04-07 8:22 UTC (permalink / raw)
To: puwen, tglx, mingo, bp, dave.hansen, x86, hpa; +Cc: linux-kernel, Fu Hao
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 <fuhao@open-hieco.net>
---
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)
init_hygon_cacheinfo(c);
+ /*
+ * Adjust the die_id and logical_die_id for Hygon models 0x4-0x8.
+ */
+ if (c->x86_model >= 0x4 && c->x86_model <= 0x8) {
+ c->topo.die_id = cpuid_ecx(0x8000001e) & 0xff;
+ c->topo.logical_die_id = (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) {
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v2 2/8] x86/cpu: Get LLC ID for Hygon family 18h model 4h
2026-04-07 8:22 [PATCH v2 0/8] Add support for Hygon Family 18h model 4h~8h processors Fu Hao
2026-04-07 8:22 ` [PATCH v2 1/8] x86/cpu/hygon: Adjust the die_id and logical_die_id for Hygon models 0x4-0x8 Fu Hao
@ 2026-04-07 8:23 ` Fu Hao
2026-04-07 8:23 ` [PATCH v2 3/8] x86/cpu/hygon: Remove Spectral Chicken for Hygon processors Fu Hao
` (5 subsequent siblings)
7 siblings, 0 replies; 14+ messages in thread
From: Fu Hao @ 2026-04-07 8:23 UTC (permalink / raw)
To: tglx, mingo, bp, dave.hansen, x86, hpa; +Cc: linux-kernel, Fu Hao
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 <fuhao@open-hieco.net>
---
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/cacheinfo.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;
- /*
- * 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 = c->topo.apicid >> 3;
+ if (c->x86_model >= 0x4) {
+ /*
+ * From model 4h: LLC ID is calculated from the number
+ * of threads sharing the L3 cache.
+ */
+ u32 llc_index = find_num_cache_leaves(c) - 1;
+ struct _cpuid4_info id4 = {};
+
+ if (!amd_fill_cpuid4_info(llc_index, &id4))
+ c->topo.llc_id = 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 = c->topo.apicid >> 3;
+ }
}
void init_amd_cacheinfo(struct cpuinfo_x86 *c)
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v2 3/8] x86/cpu/hygon: Remove Spectral Chicken for Hygon processors
2026-04-07 8:22 [PATCH v2 0/8] Add support for Hygon Family 18h model 4h~8h processors Fu Hao
2026-04-07 8:22 ` [PATCH v2 1/8] x86/cpu/hygon: Adjust the die_id and logical_die_id for Hygon models 0x4-0x8 Fu Hao
2026-04-07 8:23 ` [PATCH v2 2/8] x86/cpu: Get LLC ID for Hygon family 18h model 4h Fu Hao
@ 2026-04-07 8:23 ` Fu Hao
2026-04-07 8:23 ` [PATCH v2 4/8] perf/x86/uncore: Add L3 PMU support for Hygon family 18h model 6h Fu Hao
` (4 subsequent siblings)
7 siblings, 0 replies; 14+ messages in thread
From: Fu Hao @ 2026-04-07 8:23 UTC (permalink / raw)
To: puwen, tglx, mingo, bp, dave.hansen, x86, hpa; +Cc: linux-kernel, Fu Hao
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 <fuhao@open-hieco.net>
---
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)
set_cpu_cap(c, X86_FEATURE_REP_GOOD);
- /*
- * 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);
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v2 4/8] perf/x86/uncore: Add L3 PMU support for Hygon family 18h model 6h
2026-04-07 8:22 [PATCH v2 0/8] Add support for Hygon Family 18h model 4h~8h processors Fu Hao
` (2 preceding siblings ...)
2026-04-07 8:23 ` [PATCH v2 3/8] x86/cpu/hygon: Remove Spectral Chicken for Hygon processors Fu Hao
@ 2026-04-07 8:23 ` Fu Hao
2026-04-07 8:24 ` [PATCH v2 5/8] x86/microcode/hygon: Add microcode loading support for Hygon processors Fu Hao
` (3 subsequent siblings)
7 siblings, 0 replies; 14+ messages in thread
From: Fu Hao @ 2026-04-07 8:23 UTC (permalink / raw)
To: peterz, mingo, acme, namhyung, tglx, bp, dave.hansen, x86,
alexander.shishkin, jolsa, irogers, james.clark, hpa
Cc: linux-perf-users, linux-kernel, Fu Hao
Adjust the L3 PMU slicemask and threadmask for Hygon family 18h
model 6h processor.
Signed-off-by: Fu Hao <fuhao@open-hieco.net>
---
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, struct attribute *attr, int i)
attr->mode : 0;
}
+static umode_t
+hygon_f18h_m6h_uncore_is_visible(struct kobject *kobj, struct attribute *attr, int i)
+{
+ return boot_cpu_data.x86 == 0x18 &&
+ boot_cpu_data.x86_model >= 0x6 && boot_cpu_data.x86_model <= 0xf ?
+ attr->mode : 0;
+}
+
static umode_t
amd_f19h_uncore_is_visible(struct kobject *kobj, struct attribute *attr, int i)
{
@@ -359,6 +367,8 @@ DEFINE_UNCORE_FORMAT_ATTR(enallslices, enallslices, "config:46"); /* F19h L3
DEFINE_UNCORE_FORMAT_ATTR(enallcores, enallcores, "config:47"); /* F19h L3 */
DEFINE_UNCORE_FORMAT_ATTR(sliceid, sliceid, "config:48-50"); /* F19h L3 */
DEFINE_UNCORE_FORMAT_ATTR(rdwrmask, rdwrmask, "config:8-9"); /* PerfMonV2 UMC */
+DEFINE_UNCORE_FORMAT_ATTR(slicemask4, slicemask, "config:28-31"); /* F18h L3 */
+DEFINE_UNCORE_FORMAT_ATTR(threadmask32, threadmask, "config:32-63"); /* F18h L3 */
/* Common DF and NB attributes */
static struct attribute *amd_uncore_df_format_attr[] = {
@@ -388,6 +398,12 @@ static struct attribute *amd_f17h_uncore_l3_format_attr[] = {
NULL,
};
+/* F18h M06h unique L3 attributes */
+static struct attribute *hygon_f18h_m6h_uncore_l3_format_attr[] = {
+ &format_attr_slicemask4.attr, /* slicemask */
+ NULL,
+};
+
/* F19h unique L3 attributes */
static struct attribute *amd_f19h_uncore_l3_format_attr[] = {
&format_attr_coreid.attr, /* coreid */
@@ -413,6 +429,12 @@ static struct attribute_group amd_f17h_uncore_l3_format_group = {
.is_visible = amd_f17h_uncore_is_visible,
};
+static struct attribute_group hygon_f18h_m6h_uncore_l3_format_group = {
+ .name = "format",
+ .attrs = hygon_f18h_m6h_uncore_l3_format_attr,
+ .is_visible = hygon_f18h_m6h_uncore_is_visible,
+};
+
static struct attribute_group amd_f19h_uncore_l3_format_group = {
.name = "format",
.attrs = amd_f19h_uncore_l3_format_attr,
@@ -442,6 +464,11 @@ static const struct attribute_group *amd_uncore_l3_attr_update[] = {
NULL,
};
+static const struct attribute_group *hygon_uncore_l3_attr_update[] = {
+ &hygon_f18h_m6h_uncore_l3_format_group,
+ NULL,
+};
+
static const struct attribute_group *amd_uncore_umc_attr_groups[] = {
&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 = AMD64_L3_F19H_THREAD_MASK | AMD64_L3_EN_ALL_SLICES |
AMD64_L3_EN_ALL_CORES;
+ if (boot_cpu_data.x86 == 0x18 &&
+ boot_cpu_data.x86_model >= 0x6 &&
+ boot_cpu_data.x86_model <= 0xf)
+ mask = ((config & HYGON_L3_SLICE_MASK) ? : HYGON_L3_SLICE_MASK) |
+ ((config & HYGON_L3_THREAD_MASK) ? : HYGON_L3_THREAD_MASK);
+
hwc->config |= mask;
return 0;
@@ -877,7 +910,8 @@ int amd_uncore_l3_ctx_init(struct amd_uncore *uncore, unsigned int cpu)
pmu->rdpmc_base = RDPMC_BASE_LLC;
pmu->group = amd_uncore_ctx_gid(uncore, cpu);
- if (boot_cpu_data.x86 >= 0x17) {
+ if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD &&
+ boot_cpu_data.x86 >= 0x17) {
*l3_attr++ = &format_attr_event8.attr;
*l3_attr++ = &format_attr_umask8.attr;
*l3_attr++ = boot_cpu_data.x86 >= 0x19 ?
@@ -904,6 +938,18 @@ int amd_uncore_l3_ctx_init(struct amd_uncore *uncore, unsigned int cpu)
.module = THIS_MODULE,
};
+ if (boot_cpu_data.x86_vendor == X86_VENDOR_HYGON &&
+ boot_cpu_data.x86 == 0x18) {
+ *l3_attr++ = &format_attr_event8.attr;
+ *l3_attr++ = &format_attr_umask8.attr;
+ if (boot_cpu_data.x86_model >= 0x6 && boot_cpu_data.x86_model <= 0xf) {
+ *l3_attr++ = &format_attr_threadmask32.attr;
+ pmu->pmu.attr_update = hygon_uncore_l3_attr_update;
+ } else {
+ *l3_attr++ = &format_attr_threadmask8.attr;
+ }
+ }
+
if (perf_pmu_register(&pmu->pmu, pmu->pmu.name, -1)) {
free_percpu(pmu->ctx);
pmu->ctx = 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)
+#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 | \
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v2 5/8] x86/microcode/hygon: Add microcode loading support for Hygon processors
2026-04-07 8:22 [PATCH v2 0/8] Add support for Hygon Family 18h model 4h~8h processors Fu Hao
` (3 preceding siblings ...)
2026-04-07 8:23 ` [PATCH v2 4/8] perf/x86/uncore: Add L3 PMU support for Hygon family 18h model 6h Fu Hao
@ 2026-04-07 8:24 ` Fu Hao
2026-04-07 14:00 ` Dave Hansen
2026-04-07 8:24 ` [PATCH v2 6/8] ALSA: hda: Add support for Hygon family 18h model 5h HD-Audio Fu Hao
` (2 subsequent siblings)
7 siblings, 1 reply; 14+ messages in thread
From: Fu Hao @ 2026-04-07 8:24 UTC (permalink / raw)
To: tglx, mingo, bp, dave.hansen, x86, hpa; +Cc: linux-kernel, Fu Hao
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 <fuhao@open-hieco.net>
---
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
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
config MICROCODE_INITRD32
diff --git a/arch/x86/kernel/cpu/microcode/Makefile b/arch/x86/kernel/cpu/microcode/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 := core.o
obj-$(CONFIG_MICROCODE) += microcode.o
microcode-$(CONFIG_CPU_SUP_INTEL) += intel.o
microcode-$(CONFIG_CPU_SUP_AMD) += amd.o
+microcode-$(CONFIG_CPU_SUP_HYGON) += hygon.o
diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/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 = false;
break;
+ case X86_VENDOR_HYGON:
+ intel = false;
+ break;
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() == X86_VENDOR_HYGON)
+ load_ucode_hygon_bsp(&early_data, cpuid_1_eax);
+ else
+ load_ucode_amd_bsp(&early_data, cpuid_1_eax);
+
}
void load_ucode_ap(void)
@@ -229,6 +236,9 @@ void load_ucode_ap(void)
if (x86_family(cpuid_1_eax) >= 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 >= 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 = init_intel_microcode();
else if (c->x86_vendor == X86_VENDOR_AMD)
microcode_ops = init_amd_microcode();
+ else if (c->x86_vendor == X86_VENDOR_HYGON)
+ microcode_ops = init_hygon_microcode();
else
pr_err("no support for this CPU vendor\n");
diff --git a/arch/x86/kernel/cpu/microcode/hygon.c b/arch/x86/kernel/cpu/microcode/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 <linux/earlycpio.h>
+#include <linux/firmware.h>
+#include <linux/bsearch.h>
+#include <linux/uaccess.h>
+#include <linux/vmalloc.h>
+#include <linux/initrd.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+
+#include <asm/microcode.h>
+#include <asm/processor.h>
+#include <asm/setup.h>
+#include <asm/cpu.h>
+#include <asm/msr.h>
+#include <asm/tlb.h>
+
+#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 we 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 = "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 = 0; i < et->num_entries; i++) {
+ struct equiv_cpu_entry *e = &et->entry[i];
+
+ if (sig == 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 <= CONTAINER_HDR_SZ) {
+ ucode_dbg("Truncated microcode container header.\n");
+ return false;
+ }
+
+ cont_magic = *(const u32 *)buf;
+ if (cont_magic != 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 = (const u32 *)buf;
+ u32 cont_type, equiv_tbl_len;
+
+ if (!verify_container(buf, buf_size))
+ return false;
+
+ cont_type = hdr[1];
+ if (cont_type != UCODE_EQUIV_CPU_TABLE_TYPE) {
+ ucode_dbg("Wrong microcode container equivalence table type: %u.\n",
+ cont_type);
+ return false;
+ }
+
+ buf_size -= CONTAINER_HDR_SZ;
+
+ equiv_tbl_len = 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 at the
+ * beginning of @buf of size @buf_size.
+ *
+ * On success, @sh_psize returns the patch size according to the section header,
+ * 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 = (const u32 *)buf;
+ p_type = hdr[0];
+ p_size = hdr[1];
+
+ if (p_type != 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 = p_size;
+
+ return true;
+}
+
+/*
+ * Check whether the passed remaining file @buf_size is large enough to contain
+ * 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 section
+ * header.
+ */
+static bool __verify_patch_size(u32 sh_psize, size_t buf_size)
+{
+ /* Working with the whole buffer so < is ok. */
+ return sh_psize <= 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 = 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 -= 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 = sh_psize;
+
+ mc_hdr = (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 = mc_hdr->processor_rev_id;
+ patch_fam = 0xf + (proc_id >> 12);
+
+ if (patch_fam != family)
+ return 1;
+
+ return 0;
+}
+
+/*
+ * This scans the ucode blob for the proper container as we can have multiple
+ * 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 *desc)
+{
+ struct equiv_cpu_table table;
+ size_t orig_size = size;
+ u32 *hdr = (u32 *)ucode;
+ u16 eq_id;
+ u8 *buf;
+
+ if (!verify_equivalence_table(ucode, size))
+ return 0;
+
+ buf = ucode;
+
+ table.entry = (struct equiv_cpu_entry *)(buf + CONTAINER_HDR_SZ);
+ table.num_entries = 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 = find_equiv_id(&table, bsp_cpuid_1_eax);
+
+ buf += hdr[2] + CONTAINER_HDR_SZ;
+ size -= 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 = 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 = (struct microcode_hygon *)(buf + SECTION_HDR_SIZE);
+
+ if (eq_id == mc->hdr.processor_rev_id) {
+ desc->psize = patch_size;
+ desc->mc = mc;
+
+ ucode_dbg(" match: size: %d\n", patch_size);
+ }
+
+skip:
+ /* Skip patch section header too: */
+ buf += patch_size + SECTION_HDR_SIZE;
+ size -= 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 = ucode;
+ desc->size = 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 = parse_container(ucode, size, desc);
+
+ if (!s)
+ return;
+
+ /* catch wraparound */
+ if (size >= s) {
+ ucode += s;
+ size -= s;
+ } else {
+ return;
+ }
+ }
+}
+
+static bool __apply_microcode_hygon(struct microcode_hygon *mc, u32 *cur_rev,
+ unsigned int psize)
+{
+ unsigned long p_addr, p_addr_end;
+
+ p_addr = (unsigned long)&mc->hdr.data_code;
+ native_wrmsrq(MSR_AMD64_PATCH_LOADER, p_addr);
+ p_addr_end = p_addr + psize - 1;
+ invlpg(p_addr);
+
+ /*
+ * Flush next page too if patch image is crossing a page
+ * boundary.
+ */
+ if (p_addr >> PAGE_SHIFT != p_addr_end >> PAGE_SHIFT)
+ invlpg(p_addr_end);
+
+ if (IS_ENABLED(CONFIG_MICROCODE_DBG) && hypervisor_present)
+ microcode_rev[smp_processor_id()] = mc->hdr.patch_id;
+
+ /* verify patch application was successful */
+ *cur_rev = get_patch_level();
+
+ ucode_dbg("updated rev: 0x%x\n", *cur_rev);
+
+ if (*cur_rev != mc->hdr.patch_id)
+ return false;
+
+ return true;
+}
+
+static bool get_builtin_microcode(struct cpio_data *cp)
+{
+ char fw_name[40] = "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 = fw.size;
+ cp->data = (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 = find_microcode_in_initrd(ucode_path);
+
+ found = cp.data && cp.size;
+ if (found)
+ *ret = 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 patches in
+ * kernel heap memory.
+ */
+void __init load_ucode_hygon_bsp(struct early_load_data *ed, unsigned int cpuid_1_eax)
+{
+ struct cont_desc desc = { };
+ struct microcode_hygon *mc;
+ struct cpio_data cp = { };
+ u32 rev;
+
+ bsp_cpuid_1_eax = cpuid_1_eax;
+
+ rev = get_patch_level();
+ ed->old_rev = rev;
+
+ /* Needed in load_microcode_hygon() */
+ ucode_cpu_info[0].cpu_sig.sig = cpuid_1_eax;
+
+ if (!find_blobs_in_containers(&cp))
+ return;
+
+ scan_containers(cp.data, cp.size, &desc);
+
+ mc = 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 = rev;
+}
+
+/*
+ * a small, trivial cache of per-family ucode patches
+ */
+static struct ucode_patch *cache_find_patch(struct ucode_cpu_info *uci, u16 equiv_cpu)
+{
+ struct ucode_patch *p;
+
+ list_for_each_entry(p, µcode_cache, plist)
+ if (p->equiv_cpu == 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 == new_patch->equiv_cpu) {
+ if (p->patch_id >= 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 = ucode_cpu_info + cpu;
+ u16 equiv_id = 0;
+
+ uci->cpu_sig.rev = get_patch_level();
+
+ equiv_id = 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 = find_patch(cpu);
+ if (!p)
+ return;
+
+ mc = p->data;
+
+ rev = 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 = ucode_cpu_info + cpu;
+ struct ucode_patch *p;
+
+ csig->sig = cpuid_eax(0x00000001);
+ csig->rev = get_patch_level();
+
+ /*
+ * a patch could have been loaded early, set uci->mc so that
+ * mc_bp_resume() can call apply_microcode()
+ */
+ p = find_patch(cpu);
+ if (p && (p->patch_id == csig->rev))
+ uci->mc = p->data;
+
+ return 0;
+}
+
+static enum ucode_state apply_microcode_hygon(int cpu)
+{
+ struct cpuinfo_x86 *c = &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() != cpu);
+
+ uci = ucode_cpu_info + cpu;
+
+ p = find_patch(cpu);
+ if (!p)
+ return UCODE_NFOUND;
+
+ rev = uci->cpu_sig.rev;
+
+ mc_hygon = p->data;
+ uci->mc = p->data;
+
+ /* need to apply patch? */
+ if (rev > mc_hygon->hdr.patch_id) {
+ ret = UCODE_OK;
+ goto out;
+ }
+
+ if (!__apply_microcode_hygon(mc_hygon, &rev, p->size)) {
+ pr_err("CPU%d: update failed for patch_level=0x%08x\n",
+ cpu, mc_hygon->hdr.patch_id);
+ return UCODE_ERROR;
+ }
+
+ rev = mc_hygon->hdr.patch_id;
+ ret = UCODE_UPDATED;
+
+out:
+ uci->cpu_sig.rev = rev;
+ c->microcode = rev;
+
+ /* Update boot_cpu_data's revision too, if we're on the BSP: */
+ if (c->cpu_index == boot_cpu_data.cpu_index)
+ boot_cpu_data.microcode = rev;
+
+ return ret;
+}
+
+void load_ucode_hygon_ap(unsigned int cpuid_1_eax)
+{
+ unsigned int cpu = smp_processor_id();
+
+ ucode_cpu_info[cpu].cpu_sig.sig = 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 = (const u32 *)buf;
+ equiv_tbl_len = hdr[2];
+
+ equiv_table.entry = 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 = 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 = verify_patch(fw, leftover, patch_size);
+ if (ret)
+ return ret;
+
+ patch = kzalloc_obj(*patch);
+ if (!patch) {
+ pr_err("Patch allocation failure.\n");
+ return -EINVAL;
+ }
+
+ patch->data = 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 = *patch_size;
+
+ mc_hdr = (struct microcode_header_hygon *)(fw + SECTION_HDR_SIZE);
+ proc_id = mc_hdr->processor_rev_id;
+
+ INIT_LIST_HEAD(&patch->plist);
+ patch->patch_id = mc_hdr->patch_id;
+ patch->equiv_cpu = 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 = (u8 *)data;
+ size_t offset;
+
+ offset = install_equiv_cpu_table(data, size);
+ if (!offset)
+ return UCODE_ERROR;
+
+ fw += offset;
+ size -= offset;
+
+ if (*(u32 *)fw != 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 = 0;
+ int ret;
+
+ ret = verify_and_add_patch(family, fw, size, &crnt_size);
+ if (ret < 0)
+ return UCODE_ERROR;
+
+ fw += crnt_size + SECTION_HDR_SIZE;
+ size -= (crnt_size + SECTION_HDR_SIZE);
+ }
+
+ return UCODE_OK;
+}
+
+static enum ucode_state _load_microcode_hygon(u8 family, const u8 *data, size_t size)
+{
+ enum ucode_state ret;
+
+ /* free old equiv table */
+ free_equiv_cpu_table();
+
+ ret = __load_microcode_hygon(family, data, size);
+ if (ret != UCODE_OK)
+ cleanup();
+
+ return ret;
+}
+
+static enum ucode_state load_microcode_hygon(u8 family, const u8 *data, size_t size)
+{
+ struct cpuinfo_x86 *c;
+ unsigned int nid, cpu;
+ struct ucode_patch *p;
+ enum ucode_state ret;
+
+ ret = _load_microcode_hygon(family, data, size);
+ if (ret != UCODE_OK)
+ return ret;
+
+ for_each_node_with_cpus(nid) {
+ cpu = cpumask_first(cpumask_of_node(nid));
+ c = &cpu_data(cpu);
+
+ p = find_patch(cpu);
+ if (!p)
+ continue;
+
+ if (c->microcode >= p->patch_id)
+ continue;
+
+ ret = UCODE_NEW;
+ }
+
+ return ret;
+}
+
+static int __init save_microcode_in_initrd(void)
+{
+ struct cpuinfo_x86 *c = &boot_cpu_data;
+ struct cont_desc desc = { 0 };
+ unsigned int cpuid_1_eax;
+ enum ucode_state ret;
+ struct cpio_data cp;
+
+ if (microcode_loader_disabled() || (c->x86_vendor != X86_VENDOR_HYGON))
+ return 0;
+
+ cpuid_1_eax = 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 = _load_microcode_hygon(x86_family(cpuid_1_eax), desc.data, desc.size);
+ 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 *device)
+{
+ char fw_name[40] = "hygon-ucode/microcode_hygon_fam18h.bin";
+ struct cpuinfo_x86 *c = &cpu_data(cpu);
+ enum ucode_state ret = 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 = UCODE_ERROR;
+ if (!verify_container(fw->data, fw->size))
+ goto fw_release;
+
+ ret = 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 = ucode_cpu_info + cpu;
+
+ uci->mc = NULL;
+}
+
+static void finalize_late_load_hygon(int result)
+{
+ if (result)
+ cleanup();
+}
+
+static struct microcode_ops microcode_hygon_ops = {
+ .request_microcode_fw = request_microcode_hygon,
+ .collect_cpu_info = collect_cpu_info_hygon,
+ .apply_microcode = apply_microcode_hygon,
+ .microcode_fini_cpu = microcode_fini_cpu_hygon,
+ .finalize_late_load = finalize_late_load_hygon,
+ .nmi_safe = true,
+};
+
+struct microcode_ops * __init init_hygon_microcode(void)
+{
+ struct cpuinfo_x86 *c = &boot_cpu_data;
+
+ if (c->x86_vendor != 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 *path);
#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')
#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;
+ if (CPUID_IS(CPUID_HYGON1, CPUID_HYGON2, CPUID_HYGON3, ebx, ecx, edx))
+ return X86_VENDOR_HYGON;
+
return X86_VENDOR_UNKNOWN;
}
@@ -128,6 +134,20 @@ static inline void reload_ucode_intel(void) { }
static inline struct microcode_ops *init_intel_microcode(void) { return NULL; }
#endif /* !CONFIG_CPU_SUP_INTEL */
+#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, unsigned 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 NULL; }
+static inline void exit_hygon_microcode(void) { }
+#endif /* !CONFIG_CPU_SUP_HYGON */
+
#define ucode_dbg(fmt, ...) \
({ \
if (IS_ENABLED(CONFIG_MICROCODE_DBG)) \
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v2 6/8] ALSA: hda: Add support for Hygon family 18h model 5h HD-Audio
2026-04-07 8:22 [PATCH v2 0/8] Add support for Hygon Family 18h model 4h~8h processors Fu Hao
` (4 preceding siblings ...)
2026-04-07 8:24 ` [PATCH v2 5/8] x86/microcode/hygon: Add microcode loading support for Hygon processors Fu Hao
@ 2026-04-07 8:24 ` Fu Hao
2026-04-10 22:47 ` Bjorn Helgaas
2026-04-07 8:25 ` [PATCH v2 7/8] ALSA: hda: Fix single byte writing issue for Hygon family 18h model 5h Fu Hao
2026-04-07 8:25 ` [PATCH v2 8/8] iommu/hygon: Add support for Hygon family 18h model 4h IOAPIC Fu Hao
7 siblings, 1 reply; 14+ messages in thread
From: Fu Hao @ 2026-04-07 8:24 UTC (permalink / raw)
To: bhelgaas, perex, tiwai; +Cc: linux-kernel, linux-sound, linux-pci, Fu Hao
Add the new PCI ID 0x1d94 0x14a9 for Hygon family 18h model 5h
HDA controller.
Signed-off-by: Fu Hao <fuhao@open-hieco.net>
---
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
#define PCI_VENDOR_ID_HYGON 0x1d94
+#define PCI_DEVICE_ID_HYGON_18H_M05H_HDA 0x14a9
#define PCI_VENDOR_ID_META 0x1d9b
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[] = {
[AZX_DRIVER_ZHAOXIN] = "HDA Zhaoxin",
[AZX_DRIVER_ZHAOXINHDMI] = "HDA Zhaoxin HDMI",
[AZX_DRIVER_LOONGSON] = "HDA Loongson",
+ [AZX_DRIVER_HYGON] = "HDA Hygon",
[AZX_DRIVER_GENERIC] = "HD-Audio Generic",
};
@@ -2818,6 +2820,9 @@ static const struct pci_device_id azx_ids[] = {
.driver_data = AZX_DRIVER_LOONGSON | AZX_DCAPS_NO_TCSEL },
{ PCI_VDEVICE(LOONGSON, PCI_DEVICE_ID_LOONGSON_HDMI),
.driver_data = AZX_DRIVER_LOONGSON | AZX_DCAPS_NO_TCSEL },
+ /* Hygon HDAudio */
+ { PCI_VDEVICE(HYGON, PCI_DEVICE_ID_HYGON_18H_M05H_HDA),
+ .driver_data = AZX_DRIVER_HYGON | AZX_DCAPS_POSFIX_LPIB | AZX_DCAPS_NO_MSI },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, azx_ids);
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v2 7/8] ALSA: hda: Fix single byte writing issue for Hygon family 18h model 5h
2026-04-07 8:22 [PATCH v2 0/8] Add support for Hygon Family 18h model 4h~8h processors Fu Hao
` (5 preceding siblings ...)
2026-04-07 8:24 ` [PATCH v2 6/8] ALSA: hda: Add support for Hygon family 18h model 5h HD-Audio Fu Hao
@ 2026-04-07 8:25 ` Fu Hao
2026-04-07 8:25 ` [PATCH v2 8/8] iommu/hygon: Add support for Hygon family 18h model 4h IOAPIC Fu Hao
7 siblings, 0 replies; 14+ messages in thread
From: Fu Hao @ 2026-04-07 8:25 UTC (permalink / raw)
To: perex, tiwai; +Cc: linux-kernel, linux-sound, Fu Hao
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 <fuhao@open-hieco.net>
---
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 == AZX_DRIVER_ZHAOXINHDMI)
bus->polling_mode = 1;
+ if (chip->driver_type == AZX_DRIVER_HYGON &&
+ chip->pci->device == PCI_DEVICE_ID_HYGON_18H_M05H_HDA)
+ bus->access_sdnctl_in_dword = 1;
+
bus->remap_addr = 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;
- 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);
timeout = 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)
/* 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);
/* 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 = snd_hdac_get_stream_stripe_ctl(bus, azx_dev->substream);
else
stripe_ctl = 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 = 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 = false;
}
@@ -225,12 +240,16 @@ void snd_hdac_stream_reset(struct hdac_stream *azx_dev)
{
unsigned char val;
int dma_run_state;
+ struct hdac_bus *bus = azx_dev->bus;
snd_hdac_stream_clear(azx_dev);
dma_run_state = snd_hdac_stream_readb(azx_dev, SD_CTL) & SD_CTL_DMA_START;
- 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);
/* wait for hardware to report that the stream entered reset */
snd_hdac_stream_readb_poll(azx_dev, SD_CTL, val, (val & SD_CTL_STREAM_RESET), 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);
- 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);
/* 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_RESET), 3, 300);
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v2 8/8] iommu/hygon: Add support for Hygon family 18h model 4h IOAPIC
2026-04-07 8:22 [PATCH v2 0/8] Add support for Hygon Family 18h model 4h~8h processors Fu Hao
` (6 preceding siblings ...)
2026-04-07 8:25 ` [PATCH v2 7/8] ALSA: hda: Fix single byte writing issue for Hygon family 18h model 5h Fu Hao
@ 2026-04-07 8:25 ` Fu Hao
7 siblings, 0 replies; 14+ messages in thread
From: Fu Hao @ 2026-04-07 8:25 UTC (permalink / raw)
To: joro, will, suravee.suthikulpanit, robin.murphy
Cc: linux-kernel, iommu, Fu Hao
The SB IOAPIC is on the device 0xb from Hygon family 18h model 4h.
Signed-off-by: Fu Hao <fuhao@open-hieco.net>
---
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))
+/* 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 = 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 = false;
- } else if (devid == IOAPIC_SB_DEVID) {
+ } else if (devid == IOAPIC_SB_DEVID ||
+ (boot_cpu_data.x86_vendor == X86_VENDOR_HYGON &&
+ boot_cpu_data.x86 == 0x18 &&
+ boot_cpu_data.x86_model >= 0x4 &&
+ boot_cpu_data.x86_model <= 0xf &&
+ devid == IOAPIC_SB_DEVID_FAM18H_M4H)) {
has_sb_ioapic = true;
ret = true;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH v2 5/8] x86/microcode/hygon: Add microcode loading support for Hygon processors
2026-04-07 8:24 ` [PATCH v2 5/8] x86/microcode/hygon: Add microcode loading support for Hygon processors Fu Hao
@ 2026-04-07 14:00 ` Dave Hansen
2026-04-07 14:11 ` Borislav Petkov
2026-04-08 2:43 ` Fu Hao
0 siblings, 2 replies; 14+ messages in thread
From: Dave Hansen @ 2026-04-07 14:00 UTC (permalink / raw)
To: Fu Hao, tglx, mingo, bp, dave.hansen, x86, hpa; +Cc: linux-kernel
On 4/7/26 01:24, Fu Hao wrote:
...
> arch/x86/kernel/cpu/microcode/hygon.c | 927 +++++++++++++++++++++++
This looks a lot like:
cat amd.c | perl -pe 's/amd/hygon/' > hygon.c
If it's something like that, I think it probably needs to get mentioned
up front and discussed about what's actually *different* from the AMD
implementation.
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v2 5/8] x86/microcode/hygon: Add microcode loading support for Hygon processors
2026-04-07 14:00 ` Dave Hansen
@ 2026-04-07 14:11 ` Borislav Petkov
2026-04-08 2:53 ` Fu Hao
2026-04-08 2:43 ` Fu Hao
1 sibling, 1 reply; 14+ messages in thread
From: Borislav Petkov @ 2026-04-07 14:11 UTC (permalink / raw)
To: Dave Hansen; +Cc: Fu Hao, tglx, mingo, dave.hansen, x86, hpa, linux-kernel
On Tue, Apr 07, 2026 at 07:00:39AM -0700, Dave Hansen wrote:
> On 4/7/26 01:24, Fu Hao wrote:
> ...
> > arch/x86/kernel/cpu/microcode/hygon.c | 927 +++++++++++++++++++++++
> This looks a lot like:
>
> cat amd.c | perl -pe 's/amd/hygon/' > hygon.c
>
> If it's something like that, I think it probably needs to get mentioned
> up front and discussed about what's actually *different* from the AMD
> implementation.
Yes, and there's a *lot* of AMD-specific stuff in there.
I'd suggest you go through the code with a fine-toothed comb and remove
everything you won't need and you don't use.
Thx.
--
Regards/Gruss,
Boris.
https://people.kernel.org/tglx/notes-about-netiquette
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v2 5/8] x86/microcode/hygon: Add microcode loading support for Hygon processors
2026-04-07 14:00 ` Dave Hansen
2026-04-07 14:11 ` Borislav Petkov
@ 2026-04-08 2:43 ` Fu Hao
1 sibling, 0 replies; 14+ messages in thread
From: Fu Hao @ 2026-04-08 2:43 UTC (permalink / raw)
To: Dave Hansen, tglx, mingo, bp, dave.hansen, x86, hpa; +Cc: linux-kernel
On 2026/4/7 22:00, Dave Hansen wrote:
> On 4/7/26 01:24, Fu Hao wrote:
> ...
>> arch/x86/kernel/cpu/microcode/hygon.c | 927 +++++++++++++++++++++++
> This looks a lot like:
>
> cat amd.c | perl -pe 's/amd/hygon/' > hygon.c
>
> If it's something like that, I think it probably needs to get mentioned
> up front and discussed about what's actually *different* from the AMD
> implementation.
>
Thank you for the clear guidance. Indeed, the principles of microcode
loading and the registers are almost identical to those of AMD.
We will rethink the code structure and specific implementation, and only
retain the minimum necessary to maintain the basic functionality.
--
Regards,
Fu Hao
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v2 5/8] x86/microcode/hygon: Add microcode loading support for Hygon processors
2026-04-07 14:11 ` Borislav Petkov
@ 2026-04-08 2:53 ` Fu Hao
0 siblings, 0 replies; 14+ messages in thread
From: Fu Hao @ 2026-04-08 2:53 UTC (permalink / raw)
To: Borislav Petkov, Dave Hansen
Cc: tglx, mingo, dave.hansen, x86, hpa, linux-kernel
On 2026/4/7 22:11, Borislav Petkov wrote:
> On Tue, Apr 07, 2026 at 07:00:39AM -0700, Dave Hansen wrote:
>> On 4/7/26 01:24, Fu Hao wrote:
>> ...
>>> arch/x86/kernel/cpu/microcode/hygon.c | 927 +++++++++++++++++++++++
>> This looks a lot like:
>>
>> cat amd.c | perl -pe 's/amd/hygon/' > hygon.c
>>
>> If it's something like that, I think it probably needs to get mentioned
>> up front and discussed about what's actually *different* from the AMD
>> implementation.
>
> Yes, and there's a *lot* of AMD-specific stuff in there.
>
> I'd suggest you go through the code with a fine-toothed comb and remove
> everything you won't need and you don't use.
>
> Thx.
>
Thank you for the clear guidance. We will rethink the code structure
and specific implementation, and only retain the minimum necessary to
maintain the basic functionality.
--
Regards,
Fu Hao
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v2 6/8] ALSA: hda: Add support for Hygon family 18h model 5h HD-Audio
2026-04-07 8:24 ` [PATCH v2 6/8] ALSA: hda: Add support for Hygon family 18h model 5h HD-Audio Fu Hao
@ 2026-04-10 22:47 ` Bjorn Helgaas
0 siblings, 0 replies; 14+ messages in thread
From: Bjorn Helgaas @ 2026-04-10 22:47 UTC (permalink / raw)
To: Fu Hao; +Cc: bhelgaas, perex, tiwai, linux-kernel, linux-sound, linux-pci
On Tue, Apr 07, 2026 at 04:24:56PM +0800, Fu Hao wrote:
> Add the new PCI ID 0x1d94 0x14a9 for Hygon family 18h model 5h
> HDA controller.
>
> Signed-off-by: Fu Hao <fuhao@open-hieco.net>
> ---
> 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
>
> #define PCI_VENDOR_ID_HYGON 0x1d94
> +#define PCI_DEVICE_ID_HYGON_18H_M05H_HDA 0x14a9
It looks like PCI_DEVICE_ID_HYGON_18H_M05H_HDA is only used in
sound/hda/controllers/intel.c, so it should probably be defined there
so you don't need to modify include/linux/pci_ids.h:
* Do not add new entries to this file unless the definitions
* are shared between multiple drivers.
^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2026-04-10 22:47 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-07 8:22 [PATCH v2 0/8] Add support for Hygon Family 18h model 4h~8h processors Fu Hao
2026-04-07 8:22 ` [PATCH v2 1/8] x86/cpu/hygon: Adjust the die_id and logical_die_id for Hygon models 0x4-0x8 Fu Hao
2026-04-07 8:23 ` [PATCH v2 2/8] x86/cpu: Get LLC ID for Hygon family 18h model 4h Fu Hao
2026-04-07 8:23 ` [PATCH v2 3/8] x86/cpu/hygon: Remove Spectral Chicken for Hygon processors Fu Hao
2026-04-07 8:23 ` [PATCH v2 4/8] perf/x86/uncore: Add L3 PMU support for Hygon family 18h model 6h Fu Hao
2026-04-07 8:24 ` [PATCH v2 5/8] x86/microcode/hygon: Add microcode loading support for Hygon processors Fu Hao
2026-04-07 14:00 ` Dave Hansen
2026-04-07 14:11 ` Borislav Petkov
2026-04-08 2:53 ` Fu Hao
2026-04-08 2:43 ` Fu Hao
2026-04-07 8:24 ` [PATCH v2 6/8] ALSA: hda: Add support for Hygon family 18h model 5h HD-Audio Fu Hao
2026-04-10 22:47 ` Bjorn Helgaas
2026-04-07 8:25 ` [PATCH v2 7/8] ALSA: hda: Fix single byte writing issue for Hygon family 18h model 5h Fu Hao
2026-04-07 8:25 ` [PATCH v2 8/8] iommu/hygon: Add support for Hygon family 18h model 4h IOAPIC Fu Hao
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox