Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(kernel-rolling) Add support for Hygon model 4h~7h and model 10h processors #213

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
d9158d7
x86/cpu/hygon: Fix __max_die_per_package for Hygon family 18h model 4h
May 14, 2024
452d1e5
x86/amd_nb: Add Hygon family 18h model 4h PCI IDs
May 14, 2024
f607ad9
x86/amd_nb: Add northbridge support for Hygon family 18h model 4h
May 14, 2024
f5a4fac
iommu/hygon: Add support for Hygon family 18h model 4h IOAPIC
May 14, 2024
e875ed7
EDAC/amd64: Get UMC channel from the 6th nibble for Hygon
May 14, 2024
c423112
EDAC/amd64: Add support for Hygon family 18h model 4h
May 14, 2024
b1fe466
EDAC/amd64: Adjust address translation for Hygon family 18h model 4h
May 14, 2024
638e4ba
EDAC/mce_amd: Use struct cpuinfo_x86.logical_die_id for Hygon NodeId
May 14, 2024
3ab451d
hwmon/k10temp: Add support for Hygon family 18h model 4h
May 14, 2024
be67876
i2c-piix4: Remove the IMC detecting for Hygon SMBus
May 14, 2024
ea976c0
x86/cpu: Get LLC ID for Hygon family 18h model 5h
May 14, 2024
5c3559a
x86/amd_nb: Add support for Hygon family 18h model 5h
May 14, 2024
c90bbe5
EDAC/amd64: Add support for Hygon family 18h model 5h
May 14, 2024
e0071cf
hwmon/k10temp: Add support for Hygon family 18h model 5h
May 14, 2024
d8e2756
x86/amd_nb: Add support for Hygon family 18h model 6h
May 14, 2024
cd32102
EDAC/amd64: Add support for Hygon family 18h model 6h
May 14, 2024
613988a
EDAC/amd64: Adjust UMC channel for Hygon family 18h model 6h
May 14, 2024
e5030bb
x86/resctrl: Add Hygon QoS support
May 14, 2024
f6b0fbd
ALSA: hda: Add support for Hygon family 18h model 5h HD-Audio
May 14, 2024
8434171
ALSA: hda: Fix single byte writing issue for Hygon family 18h model 5h
May 14, 2024
2e51350
x86/amd_nb: Add support for Hygon family 18h model 7h
May 13, 2024
eb2bafc
EDAC/amd64: Add support for Hygon family 18h model 7h
May 13, 2024
2f3609e
x86/cpu: Get LLC ID for Hygon family 18h model 10h
May 16, 2024
878f7cd
x86/amd_nb: Add support for Hygon family 18h model 10h
May 16, 2024
6af820e
EDAC/amd64: Add support for Hygon family 18h model 10h
May 16, 2024
b9d357d
hwmon/k10temp: Add support for Hygon family 18h model 10h
May 16, 2024
05817e3
ALSA: hda: Add support for Hygon family 18h model 10h HD-Audio
May 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions arch/x86/include/asm/amd_nb.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ u16 amd_nb_num(void);
bool amd_nb_has_feature(unsigned int feature);
struct amd_northbridge *node_to_amd_nb(int node);

bool hygon_f18h_m4h(void);
u16 hygon_nb_num(void);
int get_df_id(struct pci_dev *misc, u8 *id);

static inline u16 amd_pci_dev_to_node_id(struct pci_dev *pdev)
{
struct pci_dev *misc;
Expand Down Expand Up @@ -119,6 +123,10 @@ static inline bool amd_gart_present(void)
#define node_to_amd_nb(x) NULL
#define amd_gart_present(x) false

#define hygon_f18h_m4h false
#define hygon_nb_num(x) 0
#define get_df_id(x, y) NULL

#endif


Expand Down
245 changes: 245 additions & 0 deletions arch/x86/kernel/amd_nb.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,19 @@
#define PCI_DEVICE_ID_AMD_MI200_DF_F4 0x14d4
#define PCI_DEVICE_ID_AMD_MI300_DF_F4 0x152c

#define PCI_DEVICE_ID_HYGON_18H_M05H_ROOT 0x14a0
#define PCI_DEVICE_ID_HYGON_18H_M10H_ROOT 0x14c0
#define PCI_DEVICE_ID_HYGON_18H_M04H_DF_F1 0x1491
#define PCI_DEVICE_ID_HYGON_18H_M05H_DF_F1 0x14b1
#define PCI_DEVICE_ID_HYGON_18H_M05H_DF_F4 0x14b4
#define PCI_DEVICE_ID_HYGON_18H_M10H_DF_F4 0x14d4
#define PCI_DEVICE_ID_HYGON_18H_M06H_DF_F5 0x14b5

/* Protect the PCI config register pairs used for SMN. */
static DEFINE_MUTEX(smn_mutex);

static u32 *flush_words;
static u16 nb_num;

static const struct pci_device_id amd_root_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_ROOT) },
Expand Down Expand Up @@ -128,16 +137,25 @@ static const struct pci_device_id amd_nb_link_ids[] = {

static const struct pci_device_id hygon_root_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_HYGON, PCI_DEVICE_ID_AMD_17H_ROOT) },
{ PCI_DEVICE(PCI_VENDOR_ID_HYGON, PCI_DEVICE_ID_AMD_17H_M30H_ROOT) },
{ PCI_DEVICE(PCI_VENDOR_ID_HYGON, PCI_DEVICE_ID_HYGON_18H_M05H_ROOT) },
{ PCI_DEVICE(PCI_VENDOR_ID_HYGON, PCI_DEVICE_ID_HYGON_18H_M10H_ROOT) },
{}
};

static const struct pci_device_id hygon_nb_misc_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_HYGON, PCI_DEVICE_ID_AMD_17H_DF_F3) },
{ PCI_DEVICE(PCI_VENDOR_ID_HYGON, PCI_DEVICE_ID_AMD_17H_M30H_DF_F3) },
{ PCI_DEVICE(PCI_VENDOR_ID_HYGON, PCI_DEVICE_ID_HYGON_18H_M05H_DF_F3) },
{ PCI_DEVICE(PCI_VENDOR_ID_HYGON, PCI_DEVICE_ID_HYGON_18H_M10H_DF_F3) },
{}
};

static const struct pci_device_id hygon_nb_link_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_HYGON, PCI_DEVICE_ID_AMD_17H_DF_F4) },
{ PCI_DEVICE(PCI_VENDOR_ID_HYGON, PCI_DEVICE_ID_AMD_17H_M30H_DF_F4) },
{ PCI_DEVICE(PCI_VENDOR_ID_HYGON, PCI_DEVICE_ID_HYGON_18H_M05H_DF_F4) },
{ PCI_DEVICE(PCI_VENDOR_ID_HYGON, PCI_DEVICE_ID_HYGON_18H_M10H_DF_F4) },
{}
};

Expand Down Expand Up @@ -224,6 +242,228 @@ int amd_smn_write(u16 node, u32 address, u32 value)
}
EXPORT_SYMBOL_GPL(amd_smn_write);

bool hygon_f18h_m4h(void)
{
if (boot_cpu_data.x86_vendor != X86_VENDOR_HYGON)
return false;

if (boot_cpu_data.x86 == 0x18 &&
boot_cpu_data.x86_model >= 0x4 &&
boot_cpu_data.x86_model <= 0xf)
return true;

return false;
}
EXPORT_SYMBOL_GPL(hygon_f18h_m4h);

u16 hygon_nb_num(void)
{
return nb_num;
}
EXPORT_SYMBOL_GPL(hygon_nb_num);

static int get_df_register(struct pci_dev *misc, u8 func, int offset, u32 *value)
{
struct pci_dev *df_func = NULL;
u32 device;
int err;

if (func == 1) {
switch (boot_cpu_data.x86_model) {
case 0x4:
device = PCI_DEVICE_ID_HYGON_18H_M04H_DF_F1;
break;
case 0x5:
if (misc->device == PCI_DEVICE_ID_HYGON_18H_M05H_DF_F3)
device = PCI_DEVICE_ID_HYGON_18H_M05H_DF_F1;
else
device = PCI_DEVICE_ID_HYGON_18H_M04H_DF_F1;
break;
case 0x6:
case 0x7:
device = PCI_DEVICE_ID_HYGON_18H_M05H_DF_F1;
break;
default:
return -ENODEV;
}
} else if (func == 5) {
switch (boot_cpu_data.x86_model) {
case 0x6:
case 0x7:
device = PCI_DEVICE_ID_HYGON_18H_M06H_DF_F5;
break;
default:
return -ENODEV;
}
} else {
return -ENODEV;
}

while ((df_func = pci_get_device(misc->vendor, device, df_func)))
if (pci_domain_nr(df_func->bus) == pci_domain_nr(misc->bus) &&
df_func->bus->number == misc->bus->number &&
PCI_SLOT(df_func->devfn) == PCI_SLOT(misc->devfn))
break;

if (!df_func) {
pr_warn("Error getting DF F%d device.\n", func);
return -ENODEV;
}

err = pci_read_config_dword(df_func, offset, value);
if (err)
pr_warn("Error reading DF F%d register.\n", func);

return err;
}

int get_df_id(struct pci_dev *misc, u8 *id)
{
u32 value;
int ret;

if (boot_cpu_data.x86_model == 0x6) {
/* F5x180[19:16]: DF ID */
ret = get_df_register(misc, 5, 0x180, &value);
*id = (value >> 16) & 0xf;
} else {
/* F1x200[23:20]: DF ID */
ret = get_df_register(misc, 1, 0x200, &value);
*id = (value >> 20) & 0xf;
}

return ret;
}
EXPORT_SYMBOL_GPL(get_df_id);

static u8 get_socket_num(struct pci_dev *misc)
{
u32 value;
int ret;

/* F1x200[7:0]: Which socket is present. */
ret = get_df_register(misc, 1, 0x200, &value);

return ret ? 0 : hweight8(value & 0xff);
}

static int northbridge_init_f18h_m4h(const struct pci_device_id *root_ids,
const struct pci_device_id *misc_ids,
const struct pci_device_id *link_ids)
{
struct pci_dev *root, *misc, *link;
struct pci_dev *root_first = NULL;
struct amd_northbridge *nb;
u16 roots_per_socket = 0;
u16 miscs_per_socket = 0;
u16 socket_num = 0;
u16 root_count = 0;
u16 misc_count = 0;
int err = -ENODEV;
u8 i, j, m, n;
u8 id;

pr_info("Hygon Fam%xh Model%xh NB driver.\n",
boot_cpu_data.x86, boot_cpu_data.x86_model);

misc = next_northbridge(NULL, misc_ids);
if (misc != NULL) {
socket_num = get_socket_num(misc);
pr_info("Socket number: %d\n", socket_num);
if (!socket_num) {
err = -ENODEV;
goto ret;
}
} else {
err = -ENODEV;
goto ret;
}

misc = NULL;
while ((misc = next_northbridge(misc, misc_ids)) != NULL)
misc_count++;

root = NULL;
while ((root = next_northbridge(root, root_ids)) != NULL)
root_count++;

if (!root_count || !misc_count) {
err = -ENODEV;
goto ret;
}

/*
* There should be _exactly_ N roots for each DF/SMN
* interface, and M DF/SMN interfaces in one socket.
*/
roots_per_socket = root_count / socket_num;
miscs_per_socket = misc_count / socket_num;

if (!roots_per_socket || !miscs_per_socket) {
err = -ENODEV;
goto ret;
}

nb = kcalloc(misc_count, sizeof(struct amd_northbridge), GFP_KERNEL);
if (!nb) {
err = -ENOMEM;
goto ret;
}

amd_northbridges.nb = nb;
amd_northbridges.num = misc_count;

link = misc = root = NULL;
j = m = n = 0;
for (i = 0; i < amd_northbridges.num; i++) {
misc = next_northbridge(misc, misc_ids);
link = next_northbridge(link, link_ids);

/* Only save the first PCI root device for each socket. */
if (!(i % miscs_per_socket)) {
root_first = next_northbridge(root, root_ids);
root = root_first;
j = 1;
}

if (get_df_id(misc, &id)) {
err = -ENODEV;
goto err;
}
pr_info("DF ID: %d\n", id);

if (id < 4) {
/* Add the devices with id<4 from the tail. */
node_to_amd_nb(misc_count - m - 1)->misc = misc;
node_to_amd_nb(misc_count - m - 1)->link = link;
node_to_amd_nb(misc_count - m - 1)->root = root_first;
m++;
} else {
node_to_amd_nb(n)->misc = misc;
node_to_amd_nb(n)->link = link;
node_to_amd_nb(n)->root = root_first;
n++;
}

/* Skip the redundant PCI root devices per socket. */
while (j < roots_per_socket) {
root = next_northbridge(root, root_ids);
j++;
}
}
nb_num = n;

return 0;

err:
kfree(nb);
amd_northbridges.nb = NULL;

ret:
pr_err("Hygon Fam%xh Model%xh northbridge init failed(%d)!\n",
boot_cpu_data.x86, boot_cpu_data.x86_model, err);
return err;
}

static int amd_cache_northbridges(void)
{
Expand All @@ -244,6 +484,11 @@ static int amd_cache_northbridges(void)
root_ids = hygon_root_ids;
misc_ids = hygon_nb_misc_ids;
link_ids = hygon_nb_link_ids;

if (boot_cpu_data.x86_model >= 0x4 &&
boot_cpu_data.x86_model <= 0xf)
return northbridge_init_f18h_m4h(root_ids,
misc_ids, link_ids);
}

misc = NULL;
Expand Down
30 changes: 25 additions & 5 deletions arch/x86/kernel/cpu/cacheinfo.c
Original file line number Diff line number Diff line change
Expand Up @@ -708,11 +708,31 @@ void cacheinfo_hygon_init_llc_id(struct cpuinfo_x86 *c)
if (!cpuid_edx(0x80000006))
return;

/*
* LLC is at the core complex level.
* Core complex ID is ApicId[3] for these processors.
*/
c->topo.llc_id = c->topo.apicid >> 3;
if (c->x86_model < 0x5 ||
(c->x86_model >= 0x10 && c->x86_model <= 0x1f)) {
/*
* LLC is at the core complex level.
* Core complex ID is ApicId[3] for these processors.
*/
per_cpu(cpu_llc_id, cpu) = c->apicid >> 3;
} else {
/*
* LLC ID is calculated from the number of threads
* sharing the cache.
*/
u32 eax, ebx, ecx, edx, num_sharing_cache = 0;
u32 llc_index = find_num_cache_leaves(c) - 1;

cpuid_count(0x8000001d, llc_index, &eax, &ebx, &ecx, &edx);
if (eax)
num_sharing_cache = ((eax >> 14) & 0xfff) + 1;

if (num_sharing_cache) {
int bits = get_count_order(num_sharing_cache);

per_cpu(cpu_llc_id, cpu) = c->apicid >> bits;
}
}
}

void init_amd_cacheinfo(struct cpuinfo_x86 *c)
Expand Down
8 changes: 6 additions & 2 deletions arch/x86/kernel/cpu/hygon.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <asm/cacheinfo.h>
#include <asm/spec-ctrl.h>
#include <asm/delay.h>
#include <asm/resctrl.h>

#include "cpu.h"

Expand Down Expand Up @@ -78,12 +79,14 @@ static void hygon_get_topology(struct cpuinfo_x86 *c)
c->x86_max_cores /= smp_num_siblings;

/*
* In case leaf B is available, use it to derive
* From model 0x4, leaf B is available, so use it to derive
* topology information.
*/
err = detect_extended_topology(c);
if (!err)
if (!err) {
c->x86_coreid_bits = get_count_order(c->x86_max_cores);
__max_die_per_package = nodes_per_socket;
}

/*
* Socket ID is ApicId[6] for the processors with model <= 0x3
Expand Down Expand Up @@ -236,6 +239,7 @@ static void bsp_init_hygon(struct cpuinfo_x86 *c)
x86_amd_ls_cfg_ssbd_mask = 1ULL << 10;
}
}
resctrl_cpu_detect(c);
}

static void early_init_hygon(struct cpuinfo_x86 *c)
Expand Down
Loading