From e6d5e0fe199e309f0a91baa9ea415cd8e80bea06 Mon Sep 17 00:00:00 2001 From: kylon <3252255+kylon@users.noreply.github.com> Date: Wed, 4 Jun 2025 11:50:37 +0200 Subject: [PATCH 1/5] clean up and deduplicate code remove deprecated dkms option fix codename switch mismatch (that's the problem with duplicated code) fix codename sysfs showing the enum value instead of the actual codename replaced the mess of gotos with linear code general clean up and readability/consistency --- .gitignore | 3 +- Makefile | 2 +- dkms.conf | 3 +- drv.c | 85 +- lib/libsmu.c | 140 +--- lib/libsmu.h | 108 +-- smu.c | 2129 +++++++++++++++++++++++--------------------------- smu.h | 128 +-- smu_common.c | 32 + smu_common.h | 96 +++ 10 files changed, 1202 insertions(+), 1524 deletions(-) create mode 100644 smu_common.c create mode 100644 smu_common.h diff --git a/.gitignore b/.gitignore index c546ea8..160ad6b 100755 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,10 @@ +.idea/ .vscode/ scripts/__pycache__/ scripts/pm_dumps/ userspace/monitor_cpu *.o +*.d *.ko *.cmd *.mod @@ -10,4 +12,3 @@ userspace/monitor_cpu *.bin Module.symvers modules.order -NOTES.txt diff --git a/Makefile b/Makefile index fd0cf60..c9460b5 100755 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ endif endif obj-m := $(MOD).o -$(MOD)-objs := drv.o smu.o +$(MOD)-objs := drv.o smu.o smu_common.o .PHONY: all modules clean dkms-install dkms-uninstall insmod checkmod diff --git a/dkms.conf b/dkms.conf index 25ec08b..6a68865 100755 --- a/dkms.conf +++ b/dkms.conf @@ -1,7 +1,6 @@ MAKE="make TARGET=${kernelver} CFLAGS_MODULE+=@CFLGS@" -CLEAN="make clean" PACKAGE_NAME="ryzen_smu" PACKAGE_VERSION="@VERSION@" BUILT_MODULE_NAME[0]="ryzen_smu" DEST_MODULE_LOCATION[0]="/kernel/drivers/ryzen_smu" -AUTOINSTALL="yes" \ No newline at end of file +AUTOINSTALL="yes" diff --git a/drv.c b/drv.c index 9dd7471..5abf58c 100755 --- a/drv.c +++ b/drv.c @@ -16,7 +16,7 @@ #include "smu.h" #ifndef KBUILD_MODNAME - #define KBUILD_MODNAME "ryzen_smu" +#define KBUILD_MODNAME "ryzen_smu" #endif MODULE_AUTHOR("Leonardo Gates "); @@ -26,17 +26,16 @@ MODULE_LICENSE("GPL"); #define MSEC_TO_NSEC(x) (x * 1000000) - -#define PCI_DEVICE_ID_AMD_17H_ROOT 0x1450 -#define PCI_DEVICE_ID_AMD_17H_M10H_ROOT 0x15d0 -#define PCI_DEVICE_ID_AMD_17H_M60H_ROOT 0x1630 -#define PCI_DEVICE_ID_AMD_17H_M30H_ROOT 0x1480 - -// https://github.com/torvalds/linux/blob/master/arch/x86/kernel/amd_nb.c #define PCI_DEVICE_ID_AMD_1AH_M00H_ROOT 0x153a #define PCI_DEVICE_ID_AMD_1AH_M20H_ROOT 0x1507 +#define PCI_DEVICE_ID_AMD_1AH_M44H_ROOT 0x14d8 #define PCI_DEVICE_ID_AMD_1AH_M60H_ROOT 0x1122 #define PCI_DEVICE_ID_AMD_17H_MA0H_ROOT 0x14b5 +#define PCI_DEVICE_ID_AMD_17H_ROOT 0x1450 +#define PCI_DEVICE_ID_AMD_17H_M10H_ROOT 0x15d0 +#define PCI_DEVICE_ID_AMD_17H_M30H_ROOT 0x1480 +#define PCI_DEVICE_ID_AMD_17H_M60H_ROOT 0x1630 +#define PCI_DEVICE_ID_AMD_19H_M10H_DF_F4 0x14b1 #define PCI_DEVICE_ID_AMD_19H_M10H_ROOT 0x14a4 #define PCI_DEVICE_ID_AMD_19H_M40H_ROOT 0x14b5 #define PCI_DEVICE_ID_AMD_19H_M60H_ROOT 0x14d8 @@ -47,7 +46,7 @@ MODULE_LICENSE("GPL"); #define MAX_ATTRS_LEN 13 #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0) - #error "Unsupported kernel version. Minimum: v4.19" +#error "Unsupported kernel version. Minimum: v4.19" #endif #define __RO_ATTR(attr) \ @@ -73,7 +72,6 @@ static struct ryzen_smu_data { size_t pm_table_read_size; } g_driver = { .device = NULL, - .drv_kobj = NULL, .smu_version = { 0 }, @@ -107,7 +105,7 @@ static ssize_t mp1_if_version_show(struct kobject *kobj, struct kobj_attribute * } static ssize_t codename_show(struct kobject *kobj, struct kobj_attribute *attr, char *buff) { - return sprintf(buff, "%02d\n", smu_get_codename()); + return sprintf(buff, "%s\n", smu_get_codename()); } static ssize_t pm_table_show(struct kobject *kobj, struct kobj_attribute *attr, char *buff) { @@ -119,27 +117,27 @@ static ssize_t pm_table_show(struct kobject *kobj, struct kobj_attribute *attr, } static ssize_t pm_table_version_show(struct kobject *kobj, struct kobj_attribute *attr, char *buff) { - ssize_t sz = sizeof(g_driver.pm_table_version); + const ssize_t sz = sizeof(g_driver.pm_table_version); memcpy(buff, &g_driver.pm_table_version, sz); return sz; } static ssize_t pm_table_size_show(struct kobject *kobj, struct kobj_attribute *attr, char *buff) { - ssize_t sz = sizeof(g_driver.pm_table_read_size); + const ssize_t sz = sizeof(g_driver.pm_table_read_size); memcpy(buff, &g_driver.pm_table_read_size, sz); return sz; } static ssize_t rsmu_cmd_show(struct kobject *kobj, struct kobj_attribute *attr, char *buff) { - ssize_t sz = sizeof(g_driver.smu_rsp); + const ssize_t sz = sizeof(g_driver.smu_rsp); memcpy(buff, &g_driver.smu_rsp, sz); return sz; } -static ssize_t rsmu_cmd_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buff, size_t count) { +static ssize_t rsmu_cmd_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buff, const size_t count) { u32 op; // To date, there has never been a command that actually exceeds FFh @@ -160,13 +158,13 @@ static ssize_t rsmu_cmd_store(struct kobject *kobj, struct kobj_attribute *attr, } static ssize_t mp1_smu_cmd_show(struct kobject *kobj, struct kobj_attribute *attr, char *buff) { - ssize_t sz = sizeof(g_driver.smu_rsp); + const ssize_t sz = sizeof(g_driver.smu_rsp); memcpy(buff, &g_driver.smu_rsp, sz); return sz; } -static ssize_t mp1_smu_cmd_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buff, size_t count) { +static ssize_t mp1_smu_cmd_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buff, const size_t count) { u32 op; // To date, there has never been a command that actually exceeds FFh @@ -187,13 +185,13 @@ static ssize_t mp1_smu_cmd_store(struct kobject *kobj, struct kobj_attribute *at } static ssize_t hsmp_smu_cmd_show(struct kobject* kobj, struct kobj_attribute* attr, char* buff) { - ssize_t sz = sizeof(g_driver.smu_rsp); + const ssize_t sz = sizeof(g_driver.smu_rsp); memcpy(buff, &g_driver.smu_rsp, sz); return sz; } -static ssize_t hsmp_smu_cmd_store(struct kobject* kobj, struct kobj_attribute* attr, const char* buff, size_t count) { +static ssize_t hsmp_smu_cmd_store(struct kobject* kobj, struct kobj_attribute* attr, const char* buff, const size_t count) { u32 op; // To date, there has never been a command that actually exceeds FFh @@ -214,13 +212,13 @@ static ssize_t hsmp_smu_cmd_store(struct kobject* kobj, struct kobj_attribute* a } static ssize_t smu_args_show(struct kobject *kobj, struct kobj_attribute *attr, char *buff) { - ssize_t sz = sizeof(g_driver.smu_args); + const ssize_t sz = sizeof(g_driver.smu_args); memcpy(buff, &g_driver.smu_args.args, sz); return sz; } -static ssize_t smu_args_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buff, size_t count) { +static ssize_t smu_args_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buff, const size_t count) { if (count != sizeof(u32) * 6) return 0; @@ -229,14 +227,13 @@ static ssize_t smu_args_store(struct kobject *kobj, struct kobj_attribute *attr, } static ssize_t smn_show(struct kobject *kobj, struct kobj_attribute *attr, char *buff) { - ssize_t sz = sizeof(g_driver.smn_result); + const ssize_t sz = sizeof(g_driver.smn_result); memcpy(buff, &g_driver.smn_result, sz); return sz; } -static ssize_t smn_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buff, -size_t count) { +static ssize_t smn_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buff, const size_t count) { u32 address, value; switch (count) { @@ -312,13 +309,11 @@ static struct attribute_group drv_attr_group = { .attrs = drv_attrs, }; -static int ryzen_smu_get_version(enum smu_mailbox mb, int show) { - u32 ver; +static int ryzen_smu_get_version(const smu_mailbox mb, const int show) { + const u32 ver = smu_get_version(g_driver.device, mb); - ver = smu_get_version(g_driver.device, mb); - if (ver >= 0 && ver <= 0xFF) { - pr_err("Failed to query the %sSMU version: %d", - mb == MAILBOX_TYPE_RSMU ? "R" : "MP1 ", ver); + if (ver <= 0xFF) { + pr_err("Failed to query the %sSMU version: %d", mb == MAILBOX_TYPE_RSMU ? "R" : "MP1 ", ver); return -EINVAL; } @@ -337,7 +332,7 @@ static int ryzen_smu_get_version(enum smu_mailbox mb, int show) { } static int ryzen_smu_probe(struct pci_dev *dev, const struct pci_device_id *id) { - enum smu_return_val ret; + smu_return_val ret; g_driver.device = dev; @@ -350,7 +345,7 @@ static int ryzen_smu_probe(struct pci_dev *dev, const struct pci_device_id *id) smu_timeout_attempts = SMU_RETRIES_MIN; // Detect processor class & figure out MP1/RSMU support. - if (smu_init(g_driver.device) != 0) { + if (smu_init() != 0) { pr_err("Failed to initialize the SMU for use"); return -ENODEV; } @@ -369,8 +364,8 @@ static int ryzen_smu_probe(struct pci_dev *dev, const struct pci_device_id *id) // This shouldn't *typically* cause errors unless the array structure is messed with. // So, we left a warning above to not touch it. drv_attrs[MAX_ATTRS_LEN - 5] = &dev_attr_rsmu_cmd.attr; - } - else { + + } else { pr_info("RSMU Mailbox: Disabled or not responding to commands."); goto _CONTINUE_SETUP; } @@ -379,21 +374,21 @@ static int ryzen_smu_probe(struct pci_dev *dev, const struct pci_device_id *id) ret = smu_transfer_table_to_dram(g_driver.device); if (ret == SMU_Return_OK) { ret = smu_get_pm_table_version(g_driver.device, &g_driver.pm_table_version); + if (ret != SMU_Return_OK && ret != SMU_Return_Unsupported) { - pr_err("Unable to resolve which PM table version the system uses -- disabling " - "feature (%d)", ret); + pr_err("Unable to resolve which PM table version the system uses -- disabling feature (%d)", ret); goto _CONTINUE_SETUP; } g_driver.pm_table = kzalloc(PM_TABLE_MAX_SIZE, GFP_KERNEL); if (g_driver.pm_table == NULL) { - pr_err("Unable to allocate kernel buffer for PM table mapping -- disabling PM table " - "feature"); + pr_err("Unable to allocate kernel buffer for PM table mapping -- disabling PM table feature"); goto _CONTINUE_SETUP; } // Perform an initial fill of the data for when the device is queued, saving time pr_debug("Probing the PM table for state changes"); + ret = smu_read_pm_table(dev, g_driver.pm_table, &g_driver.pm_table_read_size); if (ret == SMU_Return_OK) { pr_debug("Probe succeeded: read %ld bytes", g_driver.pm_table_read_size); @@ -403,11 +398,11 @@ static int ryzen_smu_probe(struct pci_dev *dev, const struct pci_device_id *id) if (g_driver.pm_table_version) drv_attrs[MAX_ATTRS_LEN - 2] = &dev_attr_pm_table_version.attr; - } - else + + } else { pr_err("Failed to probe the PM table -- disabling feature (%d)", ret); - } - else { + } + } else { pr_debug("Notice: PM tables are not supported for the current platform (%d)", ret); } @@ -437,13 +432,13 @@ static void ryzen_smu_remove(struct pci_dev *dev) { } static struct pci_device_id ryzen_smu_id_table[] = { + { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_1AH_M00H_ROOT) }, + { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_1AH_M20H_ROOT) }, + { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_1AH_M60H_ROOT) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_ROOT) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M10H_ROOT) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M30H_ROOT) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M60H_ROOT) }, - { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_1AH_M00H_ROOT) }, - { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_1AH_M20H_ROOT) }, - { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_1AH_M60H_ROOT) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_MA0H_ROOT) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_19H_M10H_ROOT) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_19H_M40H_ROOT) }, diff --git a/lib/libsmu.c b/lib/libsmu.c index 3c2c461..06405c8 100755 --- a/lib/libsmu.c +++ b/lib/libsmu.c @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include "libsmu.h" @@ -46,7 +48,7 @@ /* Maximum is defined as: "255.255.255.255\n" */ #define LIBSMU_MAX_SMU_VERSION_LEN 16 -static int try_open_path(const char* pathname, int mode, int* fd) { +static int try_open_path(const char* pathname, const int mode, int* fd) { int ret = 1; *fd = open(pathname, mode); @@ -59,7 +61,8 @@ static int try_open_path(const char* pathname, int mode, int* fd) { } static smu_return_val smu_init_parse(smu_obj_t* obj) { - int ver_maj, ver_min, ver_rev, ver_alt, len, i, c; + int ver_maj, ver_min, ver_rev, ver_alt; + int ver_seg_num = 0; char rd_buf[1024]; int tmp_fd, ret; @@ -92,21 +95,23 @@ static smu_return_val smu_init_parse(smu_obj_t* obj) { if (ret < 0) return SMU_Return_RWError; - len = strlen(rd_buf); - for (i = 0, c = 0; i < len; i++) + for (int i = 0, len = strlen(rd_buf); i < len; ++i) { if (rd_buf[i] == '.') - c++; + ++ver_seg_num; + } // Depending on the processor, there can be either a 3 or 4 part version segmentation. // We account for both. - switch (c) { - case 2: + switch (ver_seg_num) { + case 2: { ret = sscanf(rd_buf, "%d.%d.%d\n", &ver_maj, &ver_min, &ver_rev); obj->smu_version = ver_maj << 16 | ver_min << 8 | ver_rev; + } break; - case 3: + case 3: { ret = sscanf(rd_buf, "%d.%d.%d.%d\n", &ver_maj, &ver_min, &ver_rev, &ver_alt); obj->smu_version = ver_maj << 24 | ver_min << 16 | ver_rev << 8 | ver_alt; + } break; default: return SMU_Return_RWError; @@ -126,9 +131,7 @@ static smu_return_val smu_init_parse(smu_obj_t* obj) { return SMU_Return_RWError; obj->codename = atoi(rd_buf); - - if (obj->codename <= CODENAME_UNDEFINED || - obj->codename >= CODENAME_COUNT) + if (obj->codename <= CODENAME_UNDEFINED || obj->codename >= CODENAME_COUNT) return SMU_Return_Unsupported; // MP1 version must also be present. @@ -163,14 +166,11 @@ static smu_return_val smu_init_parse(smu_obj_t* obj) { ret = read(tmp_fd, &obj->pm_table_size, sizeof(obj->pm_table_size)); close(tmp_fd); - if (ret <= 0) - return SMU_Return_RWError; - - return SMU_Return_OK; + return ret <= 0 ? SMU_Return_RWError : SMU_Return_OK; } smu_return_val smu_init(smu_obj_t* obj) { - int i, ret; + int ret; memset(obj, 0, sizeof(*obj)); @@ -189,12 +189,11 @@ smu_return_val smu_init(smu_obj_t* obj) { // RSMU is optionally supported for some codenames. if (try_open_path(RSMU_CMD_PATH, O_RDWR, &obj->fd_rsmu_cmd)) { // This file may optionally exist only if PM tables are supported AND RSMU as well. - if (smu_pm_tables_supported(obj) && - !try_open_path(PM_PATH, O_RDONLY, &obj->fd_pm_table)) + if (smu_pm_tables_supported(obj) && !try_open_path(PM_PATH, O_RDONLY, &obj->fd_pm_table)) return SMU_Return_RWError; } - for (i = 0; i < SMU_MUTEX_COUNT; i++) + for (int i = 0; i < SMU_MUTEX_COUNT; ++i) pthread_mutex_init(&obj->lock[i], NULL); obj->init = 1; @@ -203,8 +202,6 @@ smu_return_val smu_init(smu_obj_t* obj) { } void smu_free(smu_obj_t* obj) { - int i; - if (!obj->init) return; @@ -226,33 +223,34 @@ void smu_free(smu_obj_t* obj) { if (obj->fd_pm_table) close(obj->fd_pm_table); - for (i = 0; i < SMU_MUTEX_COUNT; i++) + for (int i = 0; i < SMU_MUTEX_COUNT; ++i) pthread_mutex_destroy(&obj->lock[i]); memset(obj, 0, sizeof(*obj)); } -const char* smu_get_fw_version(smu_obj_t* obj) { - static char fw[32] = { 0 }; - +const char* smu_get_fw_version(const smu_obj_t* obj) { if (!obj->init) return "Uninitialized"; + static char fw[32] = { 0 }; + // Determine if this is a 24-bit or 32-bit version and show it accordingly. if (obj->smu_version & 0xff000000) { sprintf(fw, "%d.%d.%d.%d", (obj->smu_version >> 24) & 0xff, (obj->smu_version >> 16) & 0xff, (obj->smu_version >> 8) & 0xff, obj->smu_version & 0xff); - } - else + + } else { sprintf(fw, "%d.%d.%d", (obj->smu_version >> 16) & 0xff, (obj->smu_version >> 8) & 0xff, obj->smu_version & 0xff); + } return fw; } -smu_return_val smu_read_smn_addr(smu_obj_t* obj, unsigned int address, unsigned int* result) { +smu_return_val smu_read_smn_addr(smu_obj_t* obj, const unsigned int address, unsigned int* result) { unsigned int ret; // Don't attempt to execute without initialization. @@ -276,17 +274,12 @@ smu_return_val smu_read_smn_addr(smu_obj_t* obj, unsigned int address, unsigned return ret == sizeof(unsigned int) ? SMU_Return_OK : SMU_Return_RWError; } -smu_return_val smu_write_smn_addr(smu_obj_t* obj, unsigned int address, unsigned int value) { - unsigned int buffer[2], ret; - - // Don't attempt to execute without initialization. +smu_return_val smu_write_smn_addr(smu_obj_t* obj, const unsigned int address, const unsigned int value) { if (!obj->init) return SMU_Return_Failed; - // buffer[0] contains the destination write target. - // buffer[1] contains the value to write to the address. - buffer[0] = address; - buffer[1] = value; + const unsigned int buffer[2] = {address, value}; + unsigned int ret; pthread_mutex_lock(&obj->lock[SMU_MUTEX_SMN]); @@ -298,22 +291,20 @@ smu_return_val smu_write_smn_addr(smu_obj_t* obj, unsigned int address, unsigned return ret == sizeof(buffer) ? SMU_Return_OK : SMU_Return_RWError; } -smu_return_val smu_send_command(smu_obj_t* obj, unsigned int op, smu_arg_t* args, - enum smu_mailbox mailbox) { - unsigned int ret, status, fd_smu_cmd; - - // Don't attempt to execute without initialization. +smu_return_val smu_send_command(smu_obj_t* obj, const unsigned int op, smu_arg_t* args, const smu_mailbox mailbox) { if (!obj->init) return SMU_Return_Failed; + unsigned int ret, status, fd_smu_cmd; + switch (mailbox) { - case SMU_TYPE_RSMU: + case MAILBOX_TYPE_RSMU: fd_smu_cmd = obj->fd_rsmu_cmd; break; - case SMU_TYPE_MP1: + case MAILBOX_TYPE_MP1: fd_smu_cmd = obj->fd_mp1_smu_cmd; break; - case SMU_TYPE_HSMP: + case MAILBOX_TYPE_HSMP: fd_smu_cmd = obj->fd_hsmp_smu_cmd; break; default: @@ -366,7 +357,7 @@ smu_return_val smu_send_command(smu_obj_t* obj, unsigned int op, smu_arg_t* args return ret; } -smu_return_val smu_read_pm_table(smu_obj_t* obj, unsigned char* dst, size_t dst_len) { +smu_return_val smu_read_pm_table(smu_obj_t* obj, unsigned char* dst, const size_t dst_len) { int ret; // Don't attempt to execute without initialization. @@ -391,7 +382,7 @@ smu_return_val smu_read_pm_table(smu_obj_t* obj, unsigned char* dst, size_t dst_ return ret; } -const char* smu_return_to_str(smu_return_val val) { +const char* smu_return_to_str(const smu_return_val val) { switch (val) { case SMU_Return_OK: return "OK"; @@ -426,61 +417,10 @@ const char* smu_return_to_str(smu_return_val val) { } } -const char* smu_codename_to_str(smu_obj_t* obj) { - switch (obj->codename) { - case CODENAME_CASTLEPEAK: - return "CastlePeak"; - case CODENAME_COLFAX: - return "Colfax"; - case CODENAME_MATISSE: - return "Matisse"; - case CODENAME_PICASSO: - return "Picasso"; - case CODENAME_PINNACLERIDGE: - return "Pinnacle Ridge"; - case CODENAME_RAVENRIDGE2: - return "Raven Ridge 2"; - case CODENAME_RAVENRIDGE: - return "Raven Ridge"; - case CODENAME_RENOIR: - return "Renoir"; - case CODENAME_SUMMITRIDGE: - return "Summit Ridge"; - case CODENAME_THREADRIPPER: - return "Thread Ripper"; - case CODENAME_REMBRANDT: - return "Rembrandt"; - case CODENAME_RAPHAEL: - return "Raphael"; - case CODENAME_GRANITERIDGE: - return "GraniteRidge"; - case CODENAME_VERMEER: - return "Vermeer"; - case CODENAME_VANGOGH: - return "Van Gogh"; - case CODENAME_CEZANNE: - return "Cezanne"; - case CODENAME_MILAN: - return "Milan"; - case CODENAME_DALI: - return "Dali"; - case CODENAME_LUCIENNE: - return "Lucienne"; - case CODENAME_NAPLES: - return "Naples"; - case CODENAME_PHOENIX: - return "Phoenix"; - case CODENAME_STRIXPOINT: - return "Strix Point"; - case CODENAME_HAWKPOINT: - return "Hawk Point"; - case CODENAME_STORMPEAK: - return "Storm Peak"; - default: - return "Undefined"; - } +const char* smu_codename_to_str(const smu_obj_t* obj) { + return getCodeName(obj->codename); } -unsigned int smu_pm_tables_supported(smu_obj_t* obj) { +unsigned int smu_pm_tables_supported(const smu_obj_t* obj) { return obj->pm_table_size && obj->pm_table_version; } diff --git a/lib/libsmu.h b/lib/libsmu.h index 1d4075d..d33f9bc 100755 --- a/lib/libsmu.h +++ b/lib/libsmu.h @@ -16,106 +16,15 @@ * along with this program. If not, see . **/ -#ifndef __LIB_SMU_H__ -#define __LIB_SMU_H__ +#pragma once -#include -#include #include +#include "../smu_common.h" + /* Version the loaded driver must use to be compatible. */ #define LIBSMU_SUPPORTED_DRIVER_VERSION "0.1.7" -/** - * SMU Mailbox Target - */ -enum smu_mailbox { - SMU_TYPE_RSMU, - SMU_TYPE_MP1, - SMU_TYPE_HSMP, -}; - -/** - * Return values that can be sent from the SMU in response to a command. - */ -typedef enum { - SMU_Return_OK = 0x01, - SMU_Return_Failed = 0xFF, - SMU_Return_UnknownCmd = 0xFE, - SMU_Return_CmdRejectedPrereq = 0xFD, - SMU_Return_CmdRejectedBusy = 0xFC, - - // Custom Error Code -- Does not exist in SMU. - - // SMU Management failed to respond within the SMU_TIMEOUT_MS range. - SMU_Return_CommandTimeout = 0xFB, - // An invalid argument was sent to the function. - SMU_Return_InvalidArgument = 0xFA, - // Function is unsupported on the current processor. - SMU_Return_Unsupported = 0xF9, - // Insufficient buffer size specified. - SMU_Return_InsufficientSize = 0xF8, - // Failed to map physical address. - SMU_Return_MappedError = 0xF7, - // PCIe programming error. - SMU_Return_PCIFailed = 0xF6, - - // Userspace Library Codes - - // Driver is not currently loaded or inaccessible. - SMU_Return_DriverNotPresent = 0xF0, - // Read or write error has occurred. Check errno for last error. - SMU_Return_RWError = 0xE9, - // Driver version is incompatible. - SMU_Return_DriverVersion = 0xE8, -} smu_return_val; - -/** - * Supported processor codenames with SMU capabilities. - */ -typedef enum { - CODENAME_UNDEFINED, - CODENAME_COLFAX, - CODENAME_RENOIR, - CODENAME_PICASSO, - CODENAME_MATISSE, - CODENAME_THREADRIPPER, - CODENAME_CASTLEPEAK, - CODENAME_RAVENRIDGE, - CODENAME_RAVENRIDGE2, - CODENAME_SUMMITRIDGE, - CODENAME_PINNACLERIDGE, - CODENAME_REMBRANDT, - CODENAME_VERMEER, - CODENAME_VANGOGH, - CODENAME_CEZANNE, - CODENAME_MILAN, - CODENAME_DALI, - CODENAME_LUCIENNE, - CODENAME_NAPLES, - CODENAME_CHAGALL, - CODENAME_RAPHAEL, - CODENAME_PHOENIX, - CODENAME_STRIXPOINT, - CODENAME_GRANITERIDGE, - CODENAME_HAWKPOINT, - CODENAME_STORMPEAK, - CODENAME_COUNT -} smu_processor_codename; - -/** - * SMU MP1 Interface Version [v9-v13] - */ -typedef enum { - IF_VERSION_9, - IF_VERSION_10, - IF_VERSION_11, - IF_VERSION_12, - IF_VERSION_13, - - IF_VERSION_COUNT -} smu_if_version; - /** * Mutex lock enumeration for specific components. */ @@ -187,7 +96,7 @@ void smu_free(smu_obj_t* obj); /** * Returns the string representation of the SMU FW version. */ -const char* smu_get_fw_version(smu_obj_t* obj); +const char* smu_get_fw_version(const smu_obj_t* obj); /** * Reads or writes a 32 bit word from the SMN address space. @@ -201,8 +110,7 @@ smu_return_val smu_write_smn_addr(smu_obj_t* obj, unsigned int address, unsigned * * Returns SMU_Return_OK on success. */ -smu_return_val smu_send_command(smu_obj_t* obj, unsigned int op, smu_arg_t *args, - enum smu_mailbox mailbox); +smu_return_val smu_send_command(smu_obj_t* obj, unsigned int op, smu_arg_t *args, smu_mailbox mailbox); /** * Reads the PM table into the destination buffer. @@ -217,12 +125,10 @@ smu_return_val smu_read_pm_table(smu_obj_t* obj, unsigned char* dst, size_t dst_ * Converts SMU values to the string representation. */ const char* smu_return_to_str(smu_return_val val); -const char* smu_codename_to_str(smu_obj_t* obj); +const char* smu_codename_to_str(const smu_obj_t* obj); /** * Determines whether PM tables are supported. * Returns 1 if they are. */ -unsigned int smu_pm_tables_supported(smu_obj_t* obj); - -#endif /* __LIB_SMU_H__ */ +unsigned int smu_pm_tables_supported(const smu_obj_t* obj); diff --git a/smu.c b/smu.c index 3c439e6..c4cd9bb 100755 --- a/smu.c +++ b/smu.c @@ -2,45 +2,44 @@ /* Copyright (C) 2020 Leonardo Gates */ /* Ryzen SMU Root Complex Communication */ -#include -#include #include -#include +#include #include +#include #include "smu.h" static struct { - enum smu_processor_codename codename; - - // Optional RSMU mailbox addresses. - u32 addr_rsmu_mb_cmd; - u32 addr_rsmu_mb_rsp; - u32 addr_rsmu_mb_args; - - // Mandatory MP1 mailbox addresses. - enum smu_if_version mp1_if_ver; - u32 addr_mp1_mb_cmd; - u32 addr_mp1_mb_rsp; - u32 addr_mp1_mb_args; - - u32 addr_hsmp_mb_cmd; - u32 addr_hsmp_mb_rsp; - u32 addr_hsmp_mb_args; - - // Optional PM table information. - u64 pm_dram_base; - u32 pm_dram_base_alt; - u32 pm_dram_map_size; - u32 pm_dram_map_size_alt; - - // Internal tracker to determine the minimum interval required to - // refresh the metrics table. - u32 pm_jiffies; - - // Virtual addresses mapped to physical DRAM bases for PM table. - u8 __iomem *pm_table_virt_addr; - u8 __iomem *pm_table_virt_addr_alt; + smu_processor_codename codename; + + // Optional RSMU mailbox addresses. + u32 addr_rsmu_mb_cmd; + u32 addr_rsmu_mb_rsp; + u32 addr_rsmu_mb_args; + + // Mandatory MP1 mailbox addresses. + smu_if_version mp1_if_ver; + u32 addr_mp1_mb_cmd; + u32 addr_mp1_mb_rsp; + u32 addr_mp1_mb_args; + + u32 addr_hsmp_mb_cmd; + u32 addr_hsmp_mb_rsp; + u32 addr_hsmp_mb_args; + + // Optional PM table information. + u64 pm_dram_base; + u32 pm_dram_base_alt; + u32 pm_dram_map_size; + u32 pm_dram_map_size_alt; + + // Internal tracker to determine the minimum interval required to + // refresh the metrics table. + u32 pm_jiffies; + + // Virtual addresses mapped to physical DRAM bases for PM table. + u8 __iomem* pm_table_virt_addr; + u8 __iomem* pm_table_virt_addr_alt; } g_smu = { .codename = CODENAME_UNDEFINED, @@ -68,1239 +67,1039 @@ static struct { }; // Both mutexes are defined separately because the SMN address space can be used -// independently from the SMU but the SMU requires access to the SMN to execute -// commands. +// independently from the SMU but the SMU requires access to the SMN to execute commands. static DEFINE_MUTEX(amd_pci_mutex); static DEFINE_MUTEX(amd_smu_mutex); -int smu_smn_rw_address(struct pci_dev *dev, u32 address, u32 *value, - int write) { - int err; +int smu_smn_rw_address(const struct pci_dev* dev, const u32 address, u32* value, const int write) { + mutex_lock(&amd_pci_mutex); // This may work differently for multi-NUMA systems. - // This may work differently for multi-NUMA systems. - mutex_lock(&amd_pci_mutex); - err = pci_write_config_dword(dev, SMU_PCI_ADDR_REG, address); + int err = pci_write_config_dword(dev, SMU_PCI_ADDR_REG, address); - if (!err) { - err = (write ? pci_write_config_dword(dev, SMU_PCI_DATA_REG, *value) - : pci_read_config_dword(dev, SMU_PCI_DATA_REG, value)); + if (err) { + pr_warn("Error programming SMN address: 0x%x!\n", address); + goto exit; + } + err = write ? pci_write_config_dword(dev, SMU_PCI_DATA_REG, *value) : pci_read_config_dword(dev, SMU_PCI_DATA_REG, value); if (err) - pr_warn("Error %s SMN address: 0x%x!\n", write ? "writing" : "reading", - address); - } else - pr_warn("Error programming SMN address: 0x%x!\n", address); - mutex_unlock(&amd_pci_mutex); + pr_warn("Error %s SMN address: 0x%x!\n", write ? "writing" : "reading", address); - return err; +exit: + mutex_unlock(&amd_pci_mutex); + return err; } -enum smu_return_val smu_read_address(struct pci_dev *dev, u32 address, - u32 *value) { - return !smu_smn_rw_address(dev, address, value, 0) ? SMU_Return_OK - : SMU_Return_PCIFailed; +smu_return_val smu_read_address(const struct pci_dev* dev, const u32 address, u32* value) { + return !smu_smn_rw_address(dev, address, value, 0) ? SMU_Return_OK : SMU_Return_PCIFailed; } -enum smu_return_val smu_write_address(struct pci_dev *dev, u32 address, - u32 value) { - return !smu_smn_rw_address(dev, address, &value, 1) ? SMU_Return_OK - : SMU_Return_PCIFailed; +smu_return_val smu_write_address(const struct pci_dev* dev, const u32 address, u32 value) { + return !smu_smn_rw_address(dev, address, &value, 1) ? SMU_Return_OK : SMU_Return_PCIFailed; } -void smu_args_init(smu_req_args_t *args, u32 value) { - u32 i; - - args->args[0] = value; +void smu_args_init(smu_req_args_t* args, const u32 value) { + args->args[0] = value; - for (i = 1; i < SMU_REQ_MAX_ARGS; i++) - args->args[i] = 0; + for (u32 i = 1; i < SMU_REQ_MAX_ARGS; ++i) + args->args[i] = 0; } -enum smu_return_val smu_send_command(struct pci_dev *dev, u32 op, - smu_req_args_t *args, - enum smu_mailbox mailbox) { - u32 retries, tmp, i, rsp_addr, args_addr, cmd_addr; - - // == Pick the correct mailbox address. == - switch (mailbox) { - case MAILBOX_TYPE_RSMU: - rsp_addr = g_smu.addr_rsmu_mb_rsp; - cmd_addr = g_smu.addr_rsmu_mb_cmd; - args_addr = g_smu.addr_rsmu_mb_args; - break; - case MAILBOX_TYPE_MP1: - rsp_addr = g_smu.addr_mp1_mb_rsp; - cmd_addr = g_smu.addr_mp1_mb_cmd; - args_addr = g_smu.addr_mp1_mb_args; - break; - case MAILBOX_TYPE_HSMP: - rsp_addr = g_smu.addr_hsmp_mb_rsp; - cmd_addr = g_smu.addr_hsmp_mb_cmd; - args_addr = g_smu.addr_hsmp_mb_args; - break; - default: - return SMU_Return_Unsupported; - } - - // == In the unlikely event a mailbox is undefined, don't even attempt to - // execute. == - if (!rsp_addr || !cmd_addr || !args_addr) - return SMU_Return_Unsupported; - - pr_debug( - "SMU Service Request: ID(0x%x) Args(0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x)", - op, args->s.arg0, args->s.arg1, args->s.arg2, args->s.arg3, args->s.arg4, - args->s.arg5); +smu_return_val smu_send_command(const struct pci_dev* dev, const u32 op, smu_req_args_t* args, const smu_mailbox mailbox) { + u32 retries, tmp, rsp_addr, args_addr, cmd_addr; + + // Pick the correct mailbox address. + switch (mailbox) { + case MAILBOX_TYPE_RSMU: { + rsp_addr = g_smu.addr_rsmu_mb_rsp; + cmd_addr = g_smu.addr_rsmu_mb_cmd; + args_addr = g_smu.addr_rsmu_mb_args; + } + break; + case MAILBOX_TYPE_MP1: { + rsp_addr = g_smu.addr_mp1_mb_rsp; + cmd_addr = g_smu.addr_mp1_mb_cmd; + args_addr = g_smu.addr_mp1_mb_args; + } + break; + case MAILBOX_TYPE_HSMP: { + rsp_addr = g_smu.addr_hsmp_mb_rsp; + cmd_addr = g_smu.addr_hsmp_mb_cmd; + args_addr = g_smu.addr_hsmp_mb_args; + } + break; + default: + return SMU_Return_Unsupported; + } - mutex_lock(&amd_smu_mutex); + // In the unlikely event a mailbox is undefined, don't even attempt to execute. + if (!rsp_addr || !cmd_addr || !args_addr) + return SMU_Return_Unsupported; + + pr_debug("SMU Service Request: ID(0x%x) Args(0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x)", + op, args->s.arg0, args->s.arg1, args->s.arg2, args->s.arg3, args->s.arg4, args->s.arg5); + + mutex_lock(&amd_smu_mutex); + + // Step 1: Wait until the RSP register is non-zero. + retries = smu_timeout_attempts; + do { + if (smu_read_address(dev, rsp_addr, &tmp) != SMU_Return_OK) { + mutex_unlock(&amd_smu_mutex); + pr_warn("Failed to perform initial probe on SMU RSP!\n"); + return SMU_Return_PCIFailed; + } + } while (tmp == 0 && retries--); + + // Step 1.b: A command is still being processed meaning a new command cannot be issued. + if (!retries && !tmp) { + mutex_unlock(&amd_smu_mutex); + pr_debug("SMU Service Request Failed: Timeout on initial wait for mailbox availability."); + return SMU_Return_CommandTimeout; + } - // Step 1: Wait until the RSP register is non-zero. - retries = smu_timeout_attempts; - do - if (smu_read_address(dev, rsp_addr, &tmp) != SMU_Return_OK) { - mutex_unlock(&amd_smu_mutex); - pr_warn("Failed to perform initial probe on SMU RSP!\n"); + // Step 2: Write zero (0) to the RSP register. + smu_write_address(dev, rsp_addr, 0); + + // Step 3: Write the argument(s) into the argument register(s). + for (u32 i = 0; i < SMU_REQ_MAX_ARGS; ++i) + smu_write_address(dev, args_addr + (i * 4), args->args[i]); + + // Step 4: Write the message Id into the Message ID register. + smu_write_address(dev, cmd_addr, op); + + // Step 5: Wait until the Response register is non-zero. + do { + if (smu_read_address(dev, rsp_addr, &tmp) != SMU_Return_OK) { + mutex_unlock(&amd_smu_mutex); + pr_warn("Failed to perform probe on SMU RSP!\n"); + return SMU_Return_PCIFailed; + } + } while(tmp == 0 && retries--); + + // Step 6: If the Response register contains OK, then SMU has finished processing the message. + if (tmp != SMU_Return_OK && !retries) { + mutex_unlock(&amd_smu_mutex); + + // The RSP register is still 0, the SMU is still processing the request or has frozen. + // Either way the command has timed out so indicate as such. + if (!tmp) { + pr_debug("SMU Service Request Failed: Timeout on command (0x%x) after %d attempts.", op, smu_timeout_attempts); + return SMU_Return_CommandTimeout; + } + + pr_debug("SMU Service Request Failed: Response %Xh was unexpected.", tmp); + return tmp; + } - return SMU_Return_PCIFailed; + // Step 7: If a return argument is expected, the Argument register may be read at this time. + for (u32 i = 0; i < SMU_REQ_MAX_ARGS; ++i) { + if (smu_read_address(dev, args_addr + (i * 4), &args->args[i]) != SMU_Return_OK) + pr_warn("Failed to fetch SMU ARG [%d]!\n", i); } - while (tmp == 0 && retries--); - // Step 1.b: A command is still being processed meaning - // a new command cannot be issued. - if (!retries && !tmp) { mutex_unlock(&amd_smu_mutex); - pr_debug("SMU Service Request Failed: Timeout on initial wait for mailbox " - "availability."); - - return SMU_Return_CommandTimeout; - } - // Step 2: Write zero (0) to the RSP register. - smu_write_address(dev, rsp_addr, 0); + pr_debug("SMU Service Response: ID(0x%x) Args(0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x)", + op, args->s.arg0, args->s.arg1, args->s.arg2, args->s.arg3, args->s.arg4, args->s.arg5); - // Step 3: Write the argument(s) into the argument register(s). - for (i = 0; i < SMU_REQ_MAX_ARGS; i++) - smu_write_address(dev, args_addr + (i * 4), args->args[i]); + return SMU_Return_OK; +} - // Step 4: Write the message Id into the Message ID register. - smu_write_address(dev, cmd_addr, op); +int smu_resolve_cpu_class(void) { + // https://en.wikichip.org/wiki/amd/cpuid + // Res. + ExtFamily + ExtModel + Res. + BaseFamily + BaseModel + Stepping + // See: CPUID_Fn00000001_EAX + const u32 cpuid = cpuid_eax(0x00000001); + const u32 cpu_family = ((cpuid & 0xf00) >> 8) + ((cpuid & 0xff00000) >> 20); + const u32 cpu_model = ((cpuid & 0xf0000) >> 12) + ((cpuid & 0xf0) >> 4); + + // Combines "PkgType" and "Reserved" + // See: CPUID_Fn80000001_EBX + const u32 pkg_type = cpuid_ebx(0x80000001) >> 28; + + pr_info("CPUID: family 0x%X, model 0x%X, package 0x%X", cpu_family, cpu_model, pkg_type); + + switch (cpu_family) { + case 0x17: { // Zen, Zen+, Zen 2 + switch (cpu_model) { + case 0x01: { + switch (pkg_type) { + case 4: g_smu.codename = CODENAME_NAPLES; break; + case 7: g_smu.codename = CODENAME_THREADRIPPER; break; + default: g_smu.codename = CODENAME_SUMMITRIDGE; break; + } + } + break; + case 0x08: { + switch (pkg_type) { + case 4: + case 7: g_smu.codename = CODENAME_COLFAX; break; + default: g_smu.codename = CODENAME_PINNACLERIDGE; break; + } + } + break; + case 0x11: + g_smu.codename = CODENAME_RAVENRIDGE; + break; + case 0x18: { + switch (pkg_type) { + case 2: g_smu.codename = CODENAME_RAVENRIDGE2; break; + default: g_smu.codename = CODENAME_PICASSO; break; + } + } + break; + case 0x20: + g_smu.codename = CODENAME_DALI; + break; + case 0x31: + g_smu.codename = CODENAME_CASTLEPEAK; + break; + case 0x60: + g_smu.codename = CODENAME_RENOIR; + break; + case 0x68: + g_smu.codename = CODENAME_LUCIENNE; + break; + case 0x71: + g_smu.codename = CODENAME_MATISSE; + break; + case 0x90: + g_smu.codename = CODENAME_VANGOGH; + break; + default: { + pr_err("CPUID: Unknown Zen/Zen+/Zen2 processor model: 0x%X (CPUID: 0x%08X)", cpu_model, cpuid); + return -2; + } + } + } + break; + case 0x19: { // Zen3, Zen4 + // At least from Zen3 onward AMD reserves 16 model IDs per generation + // Chagall: 0x00-0x0F, Stormpeak: 0x10-0x1f, etc... + // Ryzen Master uses this full reserved range to identify and probe CPUs unlike us + switch (cpu_model) { + case 0x01: + g_smu.codename = CODENAME_MILAN; + break; + case 0x08: + g_smu.codename = CODENAME_CHAGALL; + break; + case 0x18: + g_smu.codename = CODENAME_STORMPEAK; + break; + case 0x20: + case 0x21: + g_smu.codename = CODENAME_VERMEER; + break; + case 0x40: + case 0x44: + g_smu.codename = CODENAME_REMBRANDT; + break; + case 0x50: + g_smu.codename = CODENAME_CEZANNE; + break; + case 0x61: + g_smu.codename = CODENAME_RAPHAEL; + break; + case 0x74: + g_smu.codename = CODENAME_PHOENIX; + break; + case 0x75: + g_smu.codename = CODENAME_HAWKPOINT; + break; + default: { + pr_err("CPUID: Unknown Zen3/4 processor model: 0x%X (CPUID: 0x%08X)", cpu_model, cpuid); + return -2; + } + } + } + break; + case 0x1a: { // Zen 5 + switch (cpu_model) { + case 0x24: + g_smu.codename = CODENAME_STRIXPOINT; + break; + case 0x44: + g_smu.codename = CODENAME_GRANITERIDGE; + break; + case 0x70: // Strix Halo (AI MAX+ 395) + default: { + pr_err("CPUID: Unknown Zen5/6 processor model: 0x%X (CPUID: 0x%08X)", cpu_model, cpuid); + return -2; + } + } + } + break; + default: { + pr_err("CPUID: Unknown Zen processor family (%Xh).", cpu_family); + return -1; + } + } - // Step 5: Wait until the Response register is non-zero. - do - if (smu_read_address(dev, rsp_addr, &tmp) != SMU_Return_OK) { - mutex_unlock(&amd_smu_mutex); - pr_warn("Failed to perform probe on SMU RSP!\n"); + return 0; +} - return SMU_Return_PCIFailed; +static int detect_rsmu_address(void) { + switch (g_smu.codename) { + case CODENAME_CASTLEPEAK: + case CODENAME_MATISSE: + case CODENAME_VERMEER: + case CODENAME_MILAN: + case CODENAME_CHAGALL: + case CODENAME_RAPHAEL: + case CODENAME_GRANITERIDGE: + case CODENAME_STORMPEAK: { + g_smu.addr_rsmu_mb_cmd = 0x3B10524; + g_smu.addr_rsmu_mb_rsp = 0x3B10570; + g_smu.addr_rsmu_mb_args = 0x3B10A40; + } + break; + case CODENAME_COLFAX: + case CODENAME_NAPLES: + case CODENAME_SUMMITRIDGE: + case CODENAME_THREADRIPPER: + case CODENAME_PINNACLERIDGE: { + g_smu.addr_rsmu_mb_cmd = 0x3B1051C; + g_smu.addr_rsmu_mb_rsp = 0x3B10568; + g_smu.addr_rsmu_mb_args = 0x3B10590; + } + break; + case CODENAME_RENOIR: + case CODENAME_LUCIENNE: + case CODENAME_PICASSO: + case CODENAME_CEZANNE: + case CODENAME_RAVENRIDGE: + case CODENAME_RAVENRIDGE2: + case CODENAME_DALI: + case CODENAME_REMBRANDT: + case CODENAME_PHOENIX: + case CODENAME_STRIXPOINT: + case CODENAME_HAWKPOINT: { + g_smu.addr_rsmu_mb_cmd = 0x3B10A20; + g_smu.addr_rsmu_mb_rsp = 0x3B10A80; + g_smu.addr_rsmu_mb_args = 0x3B10A88; + } + break; + case CODENAME_VANGOGH: { + pr_debug("RSMU Mailbox: Not supported or unknown, disabling use."); + return 0; + } + default: + return -1; } - while (tmp == 0 && retries--); - // Step 6: If the Response register contains OK, then SMU has finished - // processing - // the message. - if (tmp != SMU_Return_OK && !retries) { - mutex_unlock(&amd_smu_mutex); - - // The RSP register is still 0, the SMU is still processing the request or - // has frozen. Either way the command has timed out so indicate as such. - if (!tmp) { - pr_debug("SMU Service Request Failed: Timeout on command (0x%x) after %d " - "attempts.", - op, smu_timeout_attempts); + pr_debug("RSMU Mailbox: (cmd: 0x%X, rsp: 0x%X, args: 0x%X)", g_smu.addr_rsmu_mb_cmd, g_smu.addr_rsmu_mb_rsp, g_smu.addr_rsmu_mb_args); + return 0; +} - return SMU_Return_CommandTimeout; +static int detect_hsmp_address(void) { + switch (g_smu.codename) { + case CODENAME_CASTLEPEAK: + case CODENAME_MATISSE: + case CODENAME_VERMEER: + case CODENAME_MILAN: + case CODENAME_CHAGALL: + case CODENAME_RAPHAEL: + case CODENAME_GRANITERIDGE: + case CODENAME_STORMPEAK: { + g_smu.addr_hsmp_mb_cmd = 0x3B10534; + g_smu.addr_hsmp_mb_rsp = 0x3B10980; + g_smu.addr_hsmp_mb_args = 0x3B109E0; + } + break; + case CODENAME_CEZANNE: + case CODENAME_COLFAX: + case CODENAME_NAPLES: + case CODENAME_SUMMITRIDGE: + case CODENAME_THREADRIPPER: + case CODENAME_PINNACLERIDGE: + case CODENAME_RENOIR: + case CODENAME_LUCIENNE: + case CODENAME_PICASSO: + case CODENAME_RAVENRIDGE: + case CODENAME_RAVENRIDGE2: + case CODENAME_DALI: + case CODENAME_VANGOGH: + case CODENAME_REMBRANDT: + case CODENAME_PHOENIX: + case CODENAME_STRIXPOINT: + case CODENAME_HAWKPOINT: + return 0; + default: + return -1; } - pr_debug("SMU Service Request Failed: Response %Xh was unexpected.", tmp); - return tmp; - } + pr_debug("HSMP Mailbox: (cmd: 0x%X, rsp: 0x%X, args: 0x%X)", g_smu.addr_hsmp_mb_cmd, g_smu.addr_hsmp_mb_rsp, g_smu.addr_hsmp_mb_args); + return 0; +} - // Step 7: If a return argument is expected, the Argument register may be read - // at this time. - for (i = 0; i < SMU_REQ_MAX_ARGS; i++) - if (smu_read_address(dev, args_addr + (i * 4), &args->args[i]) != - SMU_Return_OK) - pr_warn("Failed to fetch SMU ARG [%d]!\n", i); +static int detect_mp1_address(void) { + switch (g_smu.codename) { + case CODENAME_COLFAX: + case CODENAME_NAPLES: + case CODENAME_SUMMITRIDGE: + case CODENAME_THREADRIPPER: + case CODENAME_PINNACLERIDGE: { + g_smu.mp1_if_ver = IF_VERSION_9; + g_smu.addr_mp1_mb_cmd = 0x3B10528; + g_smu.addr_mp1_mb_rsp = 0x3B10564; + g_smu.addr_mp1_mb_args = 0x3B10598; + } + break; + case CODENAME_PICASSO: + case CODENAME_RAVENRIDGE: + case CODENAME_RAVENRIDGE2: + case CODENAME_DALI: { + g_smu.mp1_if_ver = IF_VERSION_10; + g_smu.addr_mp1_mb_cmd = 0x3B10528; + g_smu.addr_mp1_mb_rsp = 0x3B10564; + g_smu.addr_mp1_mb_args = 0x3B10998; + } + break; + case CODENAME_MATISSE: + case CODENAME_VERMEER: + case CODENAME_CASTLEPEAK: + case CODENAME_MILAN: + case CODENAME_CHAGALL: + case CODENAME_RAPHAEL: + case CODENAME_GRANITERIDGE: + case CODENAME_STORMPEAK: { + g_smu.mp1_if_ver = IF_VERSION_11; + g_smu.addr_mp1_mb_cmd = 0x3B10530; + g_smu.addr_mp1_mb_rsp = 0x3B1057C; + g_smu.addr_mp1_mb_args = 0x3B109C4; + } + break; + case CODENAME_RENOIR: + case CODENAME_LUCIENNE: + case CODENAME_CEZANNE: { + g_smu.mp1_if_ver = IF_VERSION_12; + g_smu.addr_mp1_mb_cmd = 0x3B10528; + g_smu.addr_mp1_mb_rsp = 0x3B10564; + g_smu.addr_mp1_mb_args = 0x3B10998; + } + break; + case CODENAME_VANGOGH: + case CODENAME_REMBRANDT: + case CODENAME_PHOENIX: + case CODENAME_HAWKPOINT: { + g_smu.mp1_if_ver = IF_VERSION_13; + g_smu.addr_mp1_mb_cmd = 0x3B10528; + g_smu.addr_mp1_mb_rsp = 0x3B10578; + g_smu.addr_mp1_mb_args = 0x3B10998; + } + break; + case CODENAME_STRIXPOINT: { + g_smu.mp1_if_ver = IF_VERSION_13; + g_smu.addr_mp1_mb_cmd = 0x3b10928; + g_smu.addr_mp1_mb_rsp = 0x3b10978; + g_smu.addr_mp1_mb_args = 0x3b10998; + } + break; + default: + return -1; + } - mutex_unlock(&amd_smu_mutex); + pr_debug("MP1 Mailbox: (cmd: 0x%X, rsp: 0x%X, args: 0x%X)", g_smu.addr_mp1_mb_cmd, g_smu.addr_mp1_mb_rsp, g_smu.addr_mp1_mb_args); + return 0; +} - pr_debug( - "SMU Service Response: ID(0x%x) Args(0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x)", - op, args->s.arg0, args->s.arg1, args->s.arg2, args->s.arg3, args->s.arg4, - args->s.arg5); +int smu_init(void) { + // This really should never be called twice however in case it is, consider it initialized. + if (g_smu.codename != CODENAME_UNDEFINED) + return 0; - return SMU_Return_OK; -} + if (smu_resolve_cpu_class() < 0) + return -ENODEV; -int smu_resolve_cpu_class(struct pci_dev *dev) { - u32 cpuid, cpu_family, cpu_model, stepping, pkg_type; - - // https://en.wikichip.org/wiki/amd/cpuid - // Res. + ExtFamily + ExtModel + Res. + BaseFamily + BaseModel + Stepping - // See: CPUID_Fn00000001_EAX - cpuid = cpuid_eax(0x00000001); - - cpu_family = ((cpuid & 0xf00) >> 8) + ((cpuid & 0xff00000) >> 20); - cpu_model = ((cpuid & 0xf0000) >> 12) + ((cpuid & 0xf0) >> 4); - stepping = cpuid & 0xf; - - // Combines "PkgType" and "Reserved" - // See: CPUID_Fn80000001_EBX - pkg_type = cpuid_ebx(0x80000001) >> 28; - - pr_info("CPUID: family 0x%X, model 0x%X, stepping 0x%X, package 0x%X", - cpu_family, cpu_model, stepping, pkg_type); - - // Zen / Zen+ / Zen2 - if (cpu_family == 0x17) { - switch (cpu_model) { - case 0x01: - if (pkg_type == 7) - g_smu.codename = CODENAME_THREADRIPPER; - else if (pkg_type == 4) - g_smu.codename = CODENAME_NAPLES; - else - g_smu.codename = CODENAME_SUMMITRIDGE; - break; - case 0x08: - if (pkg_type == 7 || pkg_type == 4) - g_smu.codename = CODENAME_COLFAX; - else - g_smu.codename = CODENAME_PINNACLERIDGE; - break; - case 0x11: - g_smu.codename = CODENAME_RAVENRIDGE; - break; - case 0x18: - if (pkg_type == 2) - g_smu.codename = CODENAME_RAVENRIDGE2; - else - g_smu.codename = CODENAME_PICASSO; - break; - case 0x20: - g_smu.codename = CODENAME_DALI; - break; - case 0x31: - g_smu.codename = CODENAME_CASTLEPEAK; - break; - case 0x60: - g_smu.codename = CODENAME_RENOIR; - break; - case 0x68: - g_smu.codename = CODENAME_LUCIENNE; - break; - case 0x71: - g_smu.codename = CODENAME_MATISSE; - break; - case 0x90: - g_smu.codename = CODENAME_VANGOGH; - break; - default: - pr_err( - "CPUID: Unknown Zen/Zen+/Zen2 processor model: 0x%X (CPUID: 0x%08X)", - cpu_model, cpuid); - return -2; - } - return 0; - } - - // Zen3 / Zen4 - // At least from Zen3 onward AMD reserves 16 model IDs per generation - // Chagall: 0x00-0x0F, Stormpeak: 0x10-0x1f, etc... - // Ryzen Master uses this full reserved range to identify and probe CPUs unlike us - else if (cpu_family == 0x19) { - switch (cpu_model) { - case 0x01: - g_smu.codename = CODENAME_MILAN; - break; - case 0x08: - g_smu.codename = CODENAME_CHAGALL; - break; - case 0x18: - g_smu.codename = CODENAME_STORMPEAK; - break; - case 0x20: - case 0x21: - g_smu.codename = CODENAME_VERMEER; - break; - case 0x40: - case 0x44: - g_smu.codename = CODENAME_REMBRANDT; - break; - case 0x50: - g_smu.codename = CODENAME_CEZANNE; - break; - case 0x61: - g_smu.codename = CODENAME_RAPHAEL; - break; - case 0x74: - g_smu.codename = CODENAME_PHOENIX; - break; - case 0x75: - g_smu.codename = CODENAME_HAWKPOINT; - break; - default: - pr_err("CPUID: Unknown Zen3/4 processor model: 0x%X (CPUID: 0x%08X)", - cpu_model, cpuid); - return -2; - } - return 0; - } - - // Zen 5 - else if (cpu_family == 0x1a) { - switch (cpu_model) { - case 0x24: - g_smu.codename = CODENAME_STRIXPOINT; - break; - case 0x44: - g_smu.codename = CODENAME_GRANITERIDGE; - break; - case 0x70: // Strix Halo (AI MAX+ 395) - default: - pr_err("CPUID: Unknown Zen5/6 processor model: 0x%X (CPUID: 0x%08X)", - cpu_model, cpuid); - return -2; + if (detect_rsmu_address() < 0 || detect_hsmp_address() < 0 || detect_mp1_address() < 0) { + pr_err("Unknown processor codename: %d", g_smu.codename); + return -ENODEV; } + + pr_info("Family Codename: %s", getCodeName(g_smu.codename)); return 0; - } - - else { - pr_err("CPUID: failed to detect Zen processor family " - "(%Xh).", - cpu_family); - return -1; - } } -int smu_init(struct pci_dev *dev) { - // This really should never be called twice however in case it is, consider it - // initialized. - if (g_smu.codename != CODENAME_UNDEFINED) - return 0; +void smu_cleanup(void) { + // Unmap DRAM Base if required after SMU use. + if (g_smu.pm_table_virt_addr) { + iounmap(g_smu.pm_table_virt_addr); + g_smu.pm_table_virt_addr = NULL; + } - if (smu_resolve_cpu_class(dev)) - return -ENODEV; - - // Detect RSMU mailbox address. - switch (g_smu.codename) { - case CODENAME_CASTLEPEAK: - case CODENAME_MATISSE: - case CODENAME_VERMEER: - case CODENAME_MILAN: - case CODENAME_CHAGALL: - case CODENAME_RAPHAEL: - case CODENAME_GRANITERIDGE: - case CODENAME_STORMPEAK: - g_smu.addr_rsmu_mb_cmd = 0x3B10524; - g_smu.addr_rsmu_mb_rsp = 0x3B10570; - g_smu.addr_rsmu_mb_args = 0x3B10A40; - goto LOG_RSMU; - case CODENAME_COLFAX: - case CODENAME_NAPLES: - case CODENAME_SUMMITRIDGE: - case CODENAME_THREADRIPPER: - case CODENAME_PINNACLERIDGE: - g_smu.addr_rsmu_mb_cmd = 0x3B1051C; - g_smu.addr_rsmu_mb_rsp = 0x3B10568; - g_smu.addr_rsmu_mb_args = 0x3B10590; - goto LOG_RSMU; - case CODENAME_RENOIR: - case CODENAME_LUCIENNE: - case CODENAME_PICASSO: - case CODENAME_CEZANNE: - case CODENAME_RAVENRIDGE: - case CODENAME_RAVENRIDGE2: - case CODENAME_DALI: - case CODENAME_REMBRANDT: - case CODENAME_PHOENIX: - case CODENAME_STRIXPOINT: - case CODENAME_HAWKPOINT: - g_smu.addr_rsmu_mb_cmd = 0x3B10A20; - g_smu.addr_rsmu_mb_rsp = 0x3B10A80; - g_smu.addr_rsmu_mb_args = 0x3B10A88; - goto LOG_RSMU; - case CODENAME_VANGOGH: - pr_debug("RSMU Mailbox: Not supported or unknown, disabling use."); - goto MP1_DETECT; - default: - pr_err("Unknown processor codename: %d", g_smu.codename); - return -ENODEV; - } - -LOG_RSMU: - pr_debug("RSMU Mailbox: (cmd: 0x%X, rsp: 0x%X, args: 0x%X)", - g_smu.addr_rsmu_mb_cmd, g_smu.addr_rsmu_mb_rsp, - g_smu.addr_rsmu_mb_args); - - // Detect HSMP mailbox address. - switch (g_smu.codename) { - case CODENAME_CASTLEPEAK: - case CODENAME_MATISSE: - case CODENAME_VERMEER: - case CODENAME_MILAN: - case CODENAME_CHAGALL: - case CODENAME_RAPHAEL: - case CODENAME_GRANITERIDGE: - case CODENAME_STORMPEAK: - g_smu.addr_hsmp_mb_cmd = 0x3B10534; - g_smu.addr_hsmp_mb_rsp = 0x3B10980; - g_smu.addr_hsmp_mb_args = 0x3B109E0; - goto LOG_HSMP; - case CODENAME_CEZANNE: - case CODENAME_COLFAX: - case CODENAME_NAPLES: - case CODENAME_SUMMITRIDGE: - case CODENAME_THREADRIPPER: - case CODENAME_PINNACLERIDGE: - case CODENAME_RENOIR: - case CODENAME_LUCIENNE: - case CODENAME_PICASSO: - case CODENAME_RAVENRIDGE: - case CODENAME_RAVENRIDGE2: - case CODENAME_DALI: - case CODENAME_VANGOGH: - case CODENAME_REMBRANDT: - case CODENAME_PHOENIX: - case CODENAME_STRIXPOINT: - case CODENAME_HAWKPOINT: - goto MP1_DETECT; - default: - pr_err("Unknown processor codename: %d", g_smu.codename); - return -ENODEV; - } - -LOG_HSMP: - pr_debug("HSMP Mailbox: (cmd: 0x%X, rsp: 0x%X, args: 0x%X)", - g_smu.addr_hsmp_mb_cmd, g_smu.addr_hsmp_mb_rsp, - g_smu.addr_hsmp_mb_args); - -MP1_DETECT: - // Detect MP1 SMU mailbox address. - switch (g_smu.codename) { - case CODENAME_COLFAX: - case CODENAME_NAPLES: - case CODENAME_SUMMITRIDGE: - case CODENAME_THREADRIPPER: - case CODENAME_PINNACLERIDGE: - g_smu.mp1_if_ver = IF_VERSION_9; - g_smu.addr_mp1_mb_cmd = 0x3B10528; - g_smu.addr_mp1_mb_rsp = 0x3B10564; - g_smu.addr_mp1_mb_args = 0x3B10598; - break; - case CODENAME_PICASSO: - case CODENAME_RAVENRIDGE: - case CODENAME_RAVENRIDGE2: - case CODENAME_DALI: - g_smu.mp1_if_ver = IF_VERSION_10; - g_smu.addr_mp1_mb_cmd = 0x3B10528; - g_smu.addr_mp1_mb_rsp = 0x3B10564; - g_smu.addr_mp1_mb_args = 0x3B10998; - break; - case CODENAME_MATISSE: - case CODENAME_VERMEER: - case CODENAME_CASTLEPEAK: - case CODENAME_MILAN: - case CODENAME_CHAGALL: - case CODENAME_RAPHAEL: - case CODENAME_GRANITERIDGE: - case CODENAME_STORMPEAK: - g_smu.mp1_if_ver = IF_VERSION_11; - g_smu.addr_mp1_mb_cmd = 0x3B10530; - g_smu.addr_mp1_mb_rsp = 0x3B1057C; - g_smu.addr_mp1_mb_args = 0x3B109C4; - break; - case CODENAME_RENOIR: - case CODENAME_LUCIENNE: - case CODENAME_CEZANNE: - g_smu.mp1_if_ver = IF_VERSION_12; - g_smu.addr_mp1_mb_cmd = 0x3B10528; - g_smu.addr_mp1_mb_rsp = 0x3B10564; - g_smu.addr_mp1_mb_args = 0x3B10998; - break; - case CODENAME_VANGOGH: - case CODENAME_REMBRANDT: - case CODENAME_PHOENIX: - case CODENAME_HAWKPOINT: - g_smu.mp1_if_ver = IF_VERSION_13; - g_smu.addr_mp1_mb_cmd = 0x3B10528; - g_smu.addr_mp1_mb_rsp = 0x3B10578; - g_smu.addr_mp1_mb_args = 0x3B10998; - break; - case CODENAME_STRIXPOINT: - g_smu.mp1_if_ver = IF_VERSION_13; - g_smu.addr_mp1_mb_cmd = 0x3b10928; - g_smu.addr_mp1_mb_rsp = 0x3b10978; - g_smu.addr_mp1_mb_args = 0x3b10998; - break; - default: - pr_err("Unknown processor codename: %d", g_smu.codename); - return -ENODEV; - } - - pr_debug("MP1 Mailbox: (cmd: 0x%X, rsp: 0x%X, args: 0x%X)", - g_smu.addr_mp1_mb_cmd, g_smu.addr_mp1_mb_rsp, - g_smu.addr_mp1_mb_args); - - pr_info("Family Codename: %s", getCodeName(g_smu.codename)); - - return 0; -} + if (g_smu.pm_table_virt_addr_alt) { + iounmap(g_smu.pm_table_virt_addr_alt); + g_smu.pm_table_virt_addr_alt = NULL; + } -const char *getCodeName(enum smu_processor_codename codename) { - switch (codename) { - case CODENAME_COLFAX: - return "Colfax"; - case CODENAME_RENOIR: - return "Renoir"; - case CODENAME_PICASSO: - return "Picasso"; - case CODENAME_MATISSE: - return "Matisse"; - case CODENAME_THREADRIPPER: - return "ThreadRipper"; - case CODENAME_CASTLEPEAK: - return "CastelPeak"; - case CODENAME_RAVENRIDGE: - return "RavenRidge"; - case CODENAME_RAVENRIDGE2: - return "RavenRidge2"; - case CODENAME_SUMMITRIDGE: - return "SummitRidge"; - case CODENAME_PINNACLERIDGE: - return "PinnacleRidge"; - case CODENAME_REMBRANDT: - return "Rembrandt"; - case CODENAME_VERMEER: - return "Vermeer"; - case CODENAME_VANGOGH: - return "VanGogh"; - case CODENAME_CEZANNE: - return "Cezanne"; - case CODENAME_MILAN: - return "Milan"; - case CODENAME_DALI: - return "Dali"; - case CODENAME_LUCIENNE: - return "Lucienne"; - case CODENAME_NAPLES: - return "Naples"; - case CODENAME_CHAGALL: - return "Chagall"; - case CODENAME_RAPHAEL: - return "Raphael"; - case CODENAME_GRANITERIDGE: - return "GraniteRidge"; - case CODENAME_PHOENIX: - return "Phoenix"; - case CODENAME_STRIXPOINT: - return "Strix Point"; - case CODENAME_HAWKPOINT: - return "Hawk Point"; - case CODENAME_STORMPEAK: - return "Storm Peak"; - default: - return "Undefined"; - } + // Set SMU state to uninitialized, requiring a call to smu_init() again. + g_smu.codename = CODENAME_UNDEFINED; } -void smu_cleanup(void) { - // Unmap DRAM Base if required after SMU use. - if (g_smu.pm_table_virt_addr) { - iounmap(g_smu.pm_table_virt_addr); - g_smu.pm_table_virt_addr = NULL; - } - - if (g_smu.pm_table_virt_addr_alt) { - iounmap(g_smu.pm_table_virt_addr_alt); - g_smu.pm_table_virt_addr_alt = NULL; - } - - // Set SMU state to uninitialized, requiring a call to smu_init() again. - g_smu.codename = CODENAME_UNDEFINED; + +const char *smu_get_codename(void) { + return getCodeName(g_smu.codename); } -enum smu_processor_codename smu_get_codename(void) { return g_smu.codename; } +u32 smu_get_version(const struct pci_dev* dev, const smu_mailbox mb) { + smu_req_args_t args; + u32 ret; -u32 smu_get_version(struct pci_dev *dev, enum smu_mailbox mb) { - smu_req_args_t args; - u32 ret; + // First value is always 1. + smu_args_init(&args, 1); - // First value is always 1. - smu_args_init(&args, 1); + // OP 0x02 is consistent with all platforms meaning + // it can be used directly. + ret = smu_send_command(dev, 0x02, &args, mb); + if (ret != SMU_Return_OK) + return ret; - // OP 0x02 is consistent with all platforms meaning - // it can be used directly. - ret = smu_send_command(dev, 0x02, &args, mb); - if (ret != SMU_Return_OK) - return ret; + return args.s.arg0; +} - return args.s.arg0; +smu_if_version smu_get_mp1_if_version(void) { + return g_smu.mp1_if_ver; } -enum smu_if_version smu_get_mp1_if_version(void) { return g_smu.mp1_if_ver; } - -u64 smu_get_dram_base_address(struct pci_dev *dev) { - u32 fn[3], ret, parts[2]; - smu_req_args_t args; - - const enum smu_mailbox type = MAILBOX_TYPE_RSMU; - - smu_args_init(&args, 0); - - switch (g_smu.codename) { - case CODENAME_NAPLES: - case CODENAME_SUMMITRIDGE: - case CODENAME_THREADRIPPER: - fn[0] = 0xa; - goto BASE_ADDR_CLASS_1; - case CODENAME_VERMEER: - case CODENAME_MATISSE: - case CODENAME_CASTLEPEAK: - case CODENAME_MILAN: - case CODENAME_CHAGALL: - fn[0] = 0x06; - goto BASE_ADDR_CLASS_1; - case CODENAME_RAPHAEL: - case CODENAME_GRANITERIDGE: - case CODENAME_STORMPEAK: - fn[0] = 0x04; - goto BASE_ADDR_CLASS_1; - case CODENAME_RENOIR: - case CODENAME_LUCIENNE: - case CODENAME_CEZANNE: - case CODENAME_REMBRANDT: - case CODENAME_PHOENIX: - case CODENAME_STRIXPOINT: - case CODENAME_HAWKPOINT: - fn[0] = 0x66; - goto BASE_ADDR_CLASS_1; - case CODENAME_COLFAX: - case CODENAME_PINNACLERIDGE: - fn[0] = 0x0b; - fn[1] = 0x0c; - goto BASE_ADDR_CLASS_2; - case CODENAME_DALI: - case CODENAME_PICASSO: - case CODENAME_RAVENRIDGE: - case CODENAME_RAVENRIDGE2: - fn[0] = 0x0a; - fn[1] = 0x3d; - fn[2] = 0x0b; - goto BASE_ADDR_CLASS_3; - default: - return SMU_Return_Unsupported; - } +static u64 smu_get_dram_base_address_class_1(const struct pci_dev* dev, const u32 fn) { + smu_req_args_t args; + u32 ret; -BASE_ADDR_CLASS_1: - args.s.arg0 = args.s.arg1 = 1; - ret = smu_send_command(dev, fn[0], &args, type); + smu_args_init(&args, 0); - return ret != SMU_Return_OK ? ret : args.s.arg0 | ((u64)args.s.arg1 << 32); + args.s.arg0 = args.s.arg1 = 1; + ret = smu_send_command(dev, fn, &args, MAILBOX_TYPE_RSMU); -BASE_ADDR_CLASS_2: - ret = smu_send_command(dev, fn[0], &args, type); - if (ret != SMU_Return_OK) - return ret; + return ret != SMU_Return_OK ? ret : args.s.arg0 | ((u64)args.s.arg1 << 32); +} - smu_args_init(&args, 0); - ret = smu_send_command(dev, fn[1], &args, type); +static u64 smu_get_dram_base_address_class_2(const struct pci_dev* dev, const u32 fn1, const u32 fn2) { + smu_req_args_t args; + u32 ret; - return ret != SMU_Return_OK ? ret : args.s.arg0; + smu_args_init(&args, 0); -BASE_ADDR_CLASS_3: - // == Part 1 == - args.s.arg0 = 3; - ret = smu_send_command(dev, fn[0], &args, type); - if (ret != SMU_Return_OK) - return ret; + ret = smu_send_command(dev, fn1, &args, MAILBOX_TYPE_RSMU); + if (ret != SMU_Return_OK) + return ret; - smu_args_init(&args, 3); - ret = smu_send_command(dev, fn[2], &args, type); - if (ret != SMU_Return_OK) - return ret; + smu_args_init(&args, 0); - // 1st Base. - parts[0] = args.s.arg0; - // == Part 1 End == + ret = smu_send_command(dev, fn2, &args, MAILBOX_TYPE_RSMU); - // == Part 2 == - smu_args_init(&args, 3); - ret = smu_send_command(dev, fn[1], &args, type); - if (ret != SMU_Return_OK) - return ret; + return ret != SMU_Return_OK ? ret : args.s.arg0; +} - smu_args_init(&args, 5); - ret = smu_send_command(dev, fn[0], &args, type); - if (ret != SMU_Return_OK) - return ret; +static u64 smu_get_dram_base_address_class_3(const struct pci_dev* dev, const u32 fn1, const u32 fn2, const u32 fn3) { + smu_req_args_t args; + u32 parts[2]; + u32 ret; - smu_args_init(&args, 5); - ret = smu_send_command(dev, fn[2], &args, type); - if (ret != SMU_Return_OK) - return ret; + smu_args_init(&args, 0); - // 2nd base. - parts[1] = args.s.arg0; - // == Part 2 End == + // == Part 1 == + args.s.arg0 = 3; + ret = smu_send_command(dev, fn1, &args, MAILBOX_TYPE_RSMU); + if (ret != SMU_Return_OK) + return ret; - return (u64)parts[1] << 32 | parts[0]; -} + smu_args_init(&args, 3); -enum smu_return_val smu_transfer_table_to_dram(struct pci_dev *dev) { - smu_req_args_t args; - u32 fn; - - /** - * Probes (updates) the PM Table. - * SMC Message corresponds to TransferTableSmu2Dram. - * Physically mapped at the DRAM Base address(es). - */ - - // Arg[0] here specifies the PM table when set to 0. - // For GPU ASICs, it seems there's more tables that can be found but for CPUs, - // it seems this value is ignored. - smu_args_init(&args, 0); - - switch (g_smu.codename) { - case CODENAME_SUMMITRIDGE: - case CODENAME_THREADRIPPER: - case CODENAME_NAPLES: - fn = 0x0a; - break; - case CODENAME_CASTLEPEAK: - case CODENAME_MATISSE: - case CODENAME_VERMEER: - case CODENAME_MILAN: - case CODENAME_CHAGALL: - fn = 0x05; - break; - case CODENAME_RAPHAEL: - case CODENAME_GRANITERIDGE: - case CODENAME_STORMPEAK: - fn = 0x03; - break; - case CODENAME_CEZANNE: - fn = 0x65; - break; - case CODENAME_RENOIR: - case CODENAME_LUCIENNE: - case CODENAME_REMBRANDT: - case CODENAME_PHOENIX: - case CODENAME_STRIXPOINT: - case CODENAME_HAWKPOINT: - args.s.arg0 = 3; - fn = 0x65; - break; - case CODENAME_COLFAX: - case CODENAME_PINNACLERIDGE: - case CODENAME_PICASSO: - case CODENAME_RAVENRIDGE: - case CODENAME_RAVENRIDGE2: - args.s.arg0 = 3; - fn = 0x3d; - break; - default: - return SMU_Return_Unsupported; - } + ret = smu_send_command(dev, fn3, &args, MAILBOX_TYPE_RSMU); + if (ret != SMU_Return_OK) + return ret; - return smu_send_command(dev, fn, &args, MAILBOX_TYPE_RSMU); -} + // 1st Base. + parts[0] = args.s.arg0; + // == Part 1 End == -enum smu_return_val smu_transfer_2nd_table_to_dram(struct pci_dev *dev) { - smu_req_args_t args; - u32 fn; - - /** - * Probes (updates) the secondary PM Table. - * SMC Message corresponds to TransferTableSmu2Dram. - * Physically mapped at the DRAM Base address(es). - */ - - // Arg[0] here specifies the PM table when set to 0. - // For GPU ASICs, it seems there's more tables that can be found but for CPUs, - // it seems this value is ignored. - smu_args_init(&args, 0); - - switch (g_smu.codename) { - case CODENAME_COLFAX: - case CODENAME_PINNACLERIDGE: - case CODENAME_PICASSO: - case CODENAME_RAVENRIDGE: - case CODENAME_RAVENRIDGE2: - args.s.arg0 = 5; - fn = 0x3d; - break; - case CODENAME_SUMMITRIDGE: - case CODENAME_THREADRIPPER: - case CODENAME_NAPLES: - case CODENAME_CASTLEPEAK: - case CODENAME_MATISSE: - case CODENAME_VERMEER: - case CODENAME_MILAN: - case CODENAME_CEZANNE: - case CODENAME_RENOIR: - case CODENAME_LUCIENNE: - default: - return SMU_Return_Unsupported; - } + // == Part 2 == + smu_args_init(&args, 3); + ret = smu_send_command(dev, fn2, &args, MAILBOX_TYPE_RSMU); + if (ret != SMU_Return_OK) + return ret; - return smu_send_command(dev, fn, &args, MAILBOX_TYPE_RSMU); -} + smu_args_init(&args, 5); -enum smu_return_val smu_get_pm_table_version(struct pci_dev *dev, - u32 *version) { - enum smu_return_val ret; - smu_req_args_t args; - u32 fn; - - /** - * For some codenames, there are different PM tables for each chip. - * SMC Message corresponds to TableVersionId. - * Based on AGESA FW revision. - */ - switch (g_smu.codename) { - case CODENAME_RAVENRIDGE: - case CODENAME_PICASSO: - fn = 0x0c; - break; - case CODENAME_CASTLEPEAK: - case CODENAME_MATISSE: - case CODENAME_VERMEER: - case CODENAME_MILAN: - case CODENAME_CHAGALL: - fn = 0x08; - break; - case CODENAME_RAPHAEL: - case CODENAME_GRANITERIDGE: - case CODENAME_STORMPEAK: - fn = 0x05; - break; - case CODENAME_RENOIR: - case CODENAME_LUCIENNE: - case CODENAME_CEZANNE: - case CODENAME_REMBRANDT: - case CODENAME_PHOENIX: - case CODENAME_STRIXPOINT: - case CODENAME_HAWKPOINT: - fn = 0x06; - break; - default: - return SMU_Return_Unsupported; - } + ret = smu_send_command(dev, fn1, &args, MAILBOX_TYPE_RSMU); + if (ret != SMU_Return_OK) + return ret; - smu_args_init(&args, 0); + smu_args_init(&args, 5); - ret = smu_send_command(dev, fn, &args, MAILBOX_TYPE_RSMU); - *version = args.s.arg0; + ret = smu_send_command(dev, fn3, &args, MAILBOX_TYPE_RSMU); + if (ret != SMU_Return_OK) + return ret; - return ret; + // 2nd base. + parts[1] = args.s.arg0; + // == Part 2 End == + + return (u64)parts[1] << 32 | parts[0]; } -u32 smu_update_pmtable_size(u32 version) { - // These sizes are actually accurate and not just "guessed". - // Source: Ryzen Master. - switch (g_smu.codename) { - case CODENAME_CASTLEPEAK: - case CODENAME_MATISSE: - switch (version) { - case 0x240003: - g_smu.pm_dram_map_size = 0x18AC; - break; - case 0x240503: - g_smu.pm_dram_map_size = 0xD7C; - break; - case 0x240603: - g_smu.pm_dram_map_size = 0xAB0; - break; - case 0x240703: - g_smu.pm_dram_map_size = 0x7E4; - break; - case 0x240802: - g_smu.pm_dram_map_size = 0x7E0; - break; - case 0x240803: - g_smu.pm_dram_map_size = 0x7E4; - break; - case 0x240902: - g_smu.pm_dram_map_size = 0x514; - break; - case 0x240903: - g_smu.pm_dram_map_size = 0x518; - break; - default: - goto UNKNOWN_PM_TABLE_VERSION; - } - break; - case CODENAME_VERMEER: - case CODENAME_CHAGALL: - switch (version) { - case 0x2D0803: - g_smu.pm_dram_map_size = 0x894; - break; - case 0x2D0903: - g_smu.pm_dram_map_size = 0x594; - break; - case 0x380005: - g_smu.pm_dram_map_size = 0x1BB0; - break; - case 0x380505: - g_smu.pm_dram_map_size = 0xF30; - break; - case 0x380605: - g_smu.pm_dram_map_size = 0xC10; - break; - case 0x380705: - g_smu.pm_dram_map_size = 0x8F0; - break; - case 0x380804: - g_smu.pm_dram_map_size = 0x8A4; - break; - case 0x380805: - g_smu.pm_dram_map_size = 0x8F0; - break; - case 0x380904: - g_smu.pm_dram_map_size = 0x5A4; - break; - case 0x380905: - g_smu.pm_dram_map_size = 0x5D0; - break; - default: - goto UNKNOWN_PM_TABLE_VERSION; - } - break; - case CODENAME_MILAN: - switch (version) { - case 0x2D0008: // Don't exist in RM. - g_smu.pm_dram_map_size = 0x1AB0; - break; - default: - goto UNKNOWN_PM_TABLE_VERSION; - } - break; - case CODENAME_RENOIR: - case CODENAME_LUCIENNE: - switch (version) { - case 0x370000: - g_smu.pm_dram_map_size = 0x794; - break; - case 0x370001: - g_smu.pm_dram_map_size = 0x884; - break; - case 0x370002: - g_smu.pm_dram_map_size = 0x88C; - break; - case 0x370003: - g_smu.pm_dram_map_size = 0x8AC; - break; - case 0x370005: - g_smu.pm_dram_map_size = 0x8C8; - break; - default: - goto UNKNOWN_PM_TABLE_VERSION; - } - break; - case CODENAME_CEZANNE: - switch (version) { - case 0x400005: - g_smu.pm_dram_map_size = 0x944; - break; - default: - goto UNKNOWN_PM_TABLE_VERSION; - } - break; - case CODENAME_REMBRANDT: - switch (version) { - case 0x450004: - g_smu.pm_dram_map_size = 0xAA4; - break; - case 0x450005: - g_smu.pm_dram_map_size = 0xAB0; - break; - default: - goto UNKNOWN_PM_TABLE_VERSION; +u64 smu_get_dram_base_address(const struct pci_dev* dev) { + switch (g_smu.codename) { + case CODENAME_NAPLES: + case CODENAME_SUMMITRIDGE: + case CODENAME_THREADRIPPER: + return smu_get_dram_base_address_class_1(dev, 0xa); + case CODENAME_VERMEER: + case CODENAME_MATISSE: + case CODENAME_CASTLEPEAK: + case CODENAME_MILAN: + case CODENAME_CHAGALL: + return smu_get_dram_base_address_class_1(dev, 0x06); + case CODENAME_RAPHAEL: + case CODENAME_GRANITERIDGE: + case CODENAME_STORMPEAK: + return smu_get_dram_base_address_class_1(dev, 0x04); + case CODENAME_RENOIR: + case CODENAME_LUCIENNE: + case CODENAME_CEZANNE: + case CODENAME_REMBRANDT: + case CODENAME_PHOENIX: + case CODENAME_STRIXPOINT: + case CODENAME_HAWKPOINT: + return smu_get_dram_base_address_class_1(dev, 0x66); + case CODENAME_COLFAX: + case CODENAME_PINNACLERIDGE: + return smu_get_dram_base_address_class_2(dev, 0x0b, 0x0c); + case CODENAME_DALI: + case CODENAME_PICASSO: + case CODENAME_RAVENRIDGE: + case CODENAME_RAVENRIDGE2: + return smu_get_dram_base_address_class_3(dev, 0x0a, 0x3d, 0x0b); + default: + break; } - break; - case CODENAME_PICASSO: - case CODENAME_RAVENRIDGE: - case CODENAME_RAVENRIDGE2: - // These codenames have two PM tables, a larger (primary) one and a smaller - // one. The size is always fixed to 0x608 and 0xA4 bytes each. Source: Ryzen - // Master. - g_smu.pm_dram_map_size_alt = 0xA4; - g_smu.pm_dram_map_size = 0x608 + g_smu.pm_dram_map_size_alt; - - // Split DRAM base into high/low values. - g_smu.pm_dram_base_alt = g_smu.pm_dram_base >> 32; - g_smu.pm_dram_base &= 0xFFFFFFFF; - break; - case CODENAME_RAPHAEL: - switch (version) { - case 0x000400: // Some ES-time table? Don't exist in RM. - g_smu.pm_dram_map_size = 0x948; - break; - case 0x540000: - g_smu.pm_dram_map_size = 0x828; - break; - case 0x540001: - g_smu.pm_dram_map_size = 0x82C; - break; - case 0x540002: - g_smu.pm_dram_map_size = 0x87C; - break; - case 0x540003: - g_smu.pm_dram_map_size = 0x89C; - break; - case 0x540004: - g_smu.pm_dram_map_size = 0x8BC; - break; - case 0x540005: - g_smu.pm_dram_map_size = 0x8C8; - break; - case 0x540100: - g_smu.pm_dram_map_size = 0x618; - break; - case 0x540101: - g_smu.pm_dram_map_size = 0x61C; - break; - case 0x540102: - g_smu.pm_dram_map_size = 0x66C; - break; - case 0x540103: - g_smu.pm_dram_map_size = 0x68C; - break; - case 0x540104: - g_smu.pm_dram_map_size = 0x6A8; - break; - case 0x540105: - g_smu.pm_dram_map_size = 0x6B4; - break; - case 0x540108: - g_smu.pm_dram_map_size = 0x6BC; - break; - case 0x540208: - g_smu.pm_dram_map_size = 0x8D0; - break; - default: - goto UNKNOWN_PM_TABLE_VERSION; - } - break; - case CODENAME_GRANITERIDGE: - switch (version) { - case 0x620105: - g_smu.pm_dram_map_size = 0x724; - break; - case 0x620205: - g_smu.pm_dram_map_size = 0x994; - break; - default: - goto UNKNOWN_PM_TABLE_VERSION; - } - break; - case CODENAME_PHOENIX: - case CODENAME_HAWKPOINT: - switch (version) { - case 0x4C0003: - g_smu.pm_dram_map_size = 0xB18; - break; - case 0x4C0004: - g_smu.pm_dram_map_size = 0xB1C; - break; - case 0x4C0005: - g_smu.pm_dram_map_size = 0xAF8; - break; - case 0x4C0006: - g_smu.pm_dram_map_size = 0xAFC; - break; - case 0x4C0007: - g_smu.pm_dram_map_size = 0xB00; - break; - case 0x4C0008: - g_smu.pm_dram_map_size = 0xAF0; - break; - case 0x4C0009: - g_smu.pm_dram_map_size = 0xB00; - break; - default: - goto UNKNOWN_PM_TABLE_VERSION; - } - break; - case CODENAME_STRIXPOINT: - switch (version) { - case 0x5D0008: - g_smu.pm_dram_map_size = 0xD54; - break; - default: - goto UNKNOWN_PM_TABLE_VERSION; - } - break; - case CODENAME_STORMPEAK: - switch (version) { - case 0x5C0002: - g_smu.pm_dram_map_size = 0x1E3C; - break; - case 0x5C0003: - g_smu.pm_dram_map_size = 0x1E48; - break; - case 0x5C0102: - g_smu.pm_dram_map_size = 0x1A14; - break; - case 0x5C0103: - g_smu.pm_dram_map_size = 0x1A20; - break; - case 0x5C0202: - g_smu.pm_dram_map_size = 0x15EC; - break; - case 0x5C0203: - g_smu.pm_dram_map_size = 0x15F8; - break; - case 0x5C0302: - g_smu.pm_dram_map_size = 0xD9C; - break; - case 0x5C0303: - g_smu.pm_dram_map_size = 0xDA8; - break; - case 0x5C0402: - g_smu.pm_dram_map_size = 0x974; - break; - case 0x5C0403: - g_smu.pm_dram_map_size = 0x980; - break; - default: - goto UNKNOWN_PM_TABLE_VERSION; - } - break; - default: - UNKNOWN_PM_TABLE_VERSION: - return SMU_Return_Unsupported; - } - return SMU_Return_OK; + return SMU_Return_Unsupported; } -enum smu_return_val smu_read_pm_table(struct pci_dev *dev, unsigned char *dst, - size_t *len) { - u32 ret, version, size; - - // The DRAM base does not change after boot meaning it only needs to be - // fetched once. - // From testing, it also seems they are always mapped to the same address as - // well, - // at least when running the same AGESA version. - if (g_smu.pm_dram_base == 0 || g_smu.pm_dram_map_size == 0) { - g_smu.pm_dram_base = smu_get_dram_base_address(dev); - - // Verify returned value isn't an SMU return value. - if (g_smu.pm_dram_base < 0xFF && g_smu.pm_dram_base >= 0) { - pr_err("Unable to receive the DRAM base address: %X", - (u8)g_smu.pm_dram_base); - return g_smu.pm_dram_base; +smu_return_val smu_transfer_table_to_dram(const struct pci_dev* dev) { + smu_req_args_t args; + u32 fn; + + /** + * Probes (updates) the PM Table. + * SMC Message corresponds to TransferTableSmu2Dram. + * Physically mapped at the DRAM Base address(es). + */ + + // Arg[0] here specifies the PM table when set to 0. + // For GPU ASICs, it seems there's more tables that can be found but for CPUs, + // it seems this value is ignored. + smu_args_init(&args, 0); + + switch (g_smu.codename) { + case CODENAME_SUMMITRIDGE: + case CODENAME_THREADRIPPER: + case CODENAME_NAPLES: + fn = 0x0a; + break; + case CODENAME_CASTLEPEAK: + case CODENAME_MATISSE: + case CODENAME_VERMEER: + case CODENAME_MILAN: + case CODENAME_CHAGALL: + fn = 0x05; + break; + case CODENAME_RAPHAEL: + case CODENAME_GRANITERIDGE: + case CODENAME_STORMPEAK: + fn = 0x03; + break; + case CODENAME_CEZANNE: + fn = 0x65; + break; + case CODENAME_RENOIR: + case CODENAME_LUCIENNE: + case CODENAME_REMBRANDT: + case CODENAME_PHOENIX: + case CODENAME_STRIXPOINT: + case CODENAME_HAWKPOINT: { + args.s.arg0 = 3; + fn = 0x65; + } + break; + case CODENAME_COLFAX: + case CODENAME_PINNACLERIDGE: + case CODENAME_PICASSO: + case CODENAME_RAVENRIDGE: + case CODENAME_RAVENRIDGE2: { + args.s.arg0 = 3; + fn = 0x3d; + } + break; + default: + return SMU_Return_Unsupported; } - // Should help us catch where we missed table version initialization in the - // future. - version = 0xDEADC0DE; - - // These models require finding the PM table version to determine its size. - if (g_smu.codename == CODENAME_VERMEER || - g_smu.codename == CODENAME_MATISSE || - g_smu.codename == CODENAME_RAPHAEL || - g_smu.codename == CODENAME_GRANITERIDGE || - g_smu.codename == CODENAME_RENOIR || - g_smu.codename == CODENAME_LUCIENNE || - g_smu.codename == CODENAME_REMBRANDT || - g_smu.codename == CODENAME_PHOENIX || - g_smu.codename == CODENAME_STRIXPOINT || - g_smu.codename == CODENAME_CEZANNE || - g_smu.codename == CODENAME_CHAGALL || - g_smu.codename == CODENAME_MILAN || - g_smu.codename == CODENAME_HAWKPOINT || - g_smu.codename == CODENAME_STORMPEAK) { - ret = smu_get_pm_table_version(dev, &version); - - if (ret != SMU_Return_OK) { - pr_err("Failed to get PM Table version with error: %X\n", ret); - return ret; - } + return smu_send_command(dev, fn, &args, MAILBOX_TYPE_RSMU); +} + +smu_return_val smu_transfer_2nd_table_to_dram(const struct pci_dev* dev) { + smu_req_args_t args; + u32 fn; + + /** + * Probes (updates) the secondary PM Table. + * SMC Message corresponds to TransferTableSmu2Dram. + * Physically mapped at the DRAM Base address(es). + */ + + // Arg[0] here specifies the PM table when set to 0. + // For GPU ASICs, it seems there's more tables that can be found but for CPUs, + // it seems this value is ignored. + smu_args_init(&args, 0); + + switch (g_smu.codename) { + case CODENAME_COLFAX: + case CODENAME_PINNACLERIDGE: + case CODENAME_PICASSO: + case CODENAME_RAVENRIDGE: + case CODENAME_RAVENRIDGE2: { + args.s.arg0 = 5; + fn = 0x3d; + } + break; + case CODENAME_SUMMITRIDGE: + case CODENAME_THREADRIPPER: + case CODENAME_NAPLES: + case CODENAME_CASTLEPEAK: + case CODENAME_MATISSE: + case CODENAME_VERMEER: + case CODENAME_MILAN: + case CODENAME_CEZANNE: + case CODENAME_RENOIR: + case CODENAME_LUCIENNE: + default: + return SMU_Return_Unsupported; } - ret = smu_update_pmtable_size(version); - if (ret != SMU_Return_OK) { - pr_err("Unknown PM table version: 0x%08X", version); - return ret; + return smu_send_command(dev, fn, &args, MAILBOX_TYPE_RSMU); +} + + +smu_return_val smu_get_pm_table_version(const struct pci_dev* dev, u32* version) { + smu_return_val ret; + smu_req_args_t args; + u32 fn; + + /** + * For some codenames, there are different PM tables for each chip. + * SMC Message corresponds to TableVersionId. + * Based on AGESA FW revision. + */ + switch (g_smu.codename) { + case CODENAME_RAVENRIDGE: + case CODENAME_PICASSO: + fn = 0x0c; + break; + case CODENAME_CASTLEPEAK: + case CODENAME_MATISSE: + case CODENAME_VERMEER: + case CODENAME_MILAN: + case CODENAME_CHAGALL: + fn = 0x08; + break; + case CODENAME_RAPHAEL: + case CODENAME_GRANITERIDGE: + case CODENAME_STORMPEAK: + fn = 0x05; + break; + case CODENAME_RENOIR: + case CODENAME_LUCIENNE: + case CODENAME_CEZANNE: + case CODENAME_REMBRANDT: + case CODENAME_PHOENIX: + case CODENAME_STRIXPOINT: + case CODENAME_HAWKPOINT: + fn = 0x06; + break; + default: + return SMU_Return_Unsupported; } - pr_debug("Determined PM mapping size as (%xh,%xh) bytes.", - g_smu.pm_dram_map_size, g_smu.pm_dram_map_size_alt); - } + smu_args_init(&args, 0); - // Validate output buffer size. - // N.B. In the case of Picasso/RavenRidge 2, we include the secondary PM Table - // size as well - if (*len < g_smu.pm_dram_map_size) { - pr_warn( - "Insufficient buffer size for PM table read: %lu < %d version: 0x%X", - *len, g_smu.pm_dram_map_size, version); + ret = smu_send_command(dev, fn, &args, MAILBOX_TYPE_RSMU); + *version = args.s.arg0; - *len = g_smu.pm_dram_map_size; - return SMU_Return_InsufficientSize; - } + return ret; +} - // Clamp output size - *len = g_smu.pm_dram_map_size; +u32 smu_update_pmtable_size(const u32 version) { + // These sizes are actually accurate and not just "guessed". + // Source: Ryzen Master. + switch (g_smu.codename) { + case CODENAME_CASTLEPEAK: + case CODENAME_MATISSE: { + switch (version) { + case 0x240003: g_smu.pm_dram_map_size = 0x18AC; break; + case 0x240503: g_smu.pm_dram_map_size = 0xD7C; break; + case 0x240603: g_smu.pm_dram_map_size = 0xAB0; break; + case 0x240902: g_smu.pm_dram_map_size = 0x514; break; + case 0x240903: g_smu.pm_dram_map_size = 0x518; break; + case 0x240802: g_smu.pm_dram_map_size = 0x7E0; break; + case 0x240703: + case 0x240803: g_smu.pm_dram_map_size = 0x7E4; break; + default: return SMU_Return_Unsupported; + } + } + break; + case CODENAME_VERMEER: + case CODENAME_CHAGALL: { + switch (version) { + case 0x2D0803: g_smu.pm_dram_map_size = 0x894; break; + case 0x2D0903: g_smu.pm_dram_map_size = 0x594; break; + case 0x380005: g_smu.pm_dram_map_size = 0x1BB0; break; + case 0x380505: g_smu.pm_dram_map_size = 0xF30; break; + case 0x380605: g_smu.pm_dram_map_size = 0xC10; break; + case 0x380804: g_smu.pm_dram_map_size = 0x8A4; break; + case 0x380705: + case 0x380805: g_smu.pm_dram_map_size = 0x8F0; break; + case 0x380904: g_smu.pm_dram_map_size = 0x5A4; break; + case 0x380905: g_smu.pm_dram_map_size = 0x5D0; break; + default: return SMU_Return_Unsupported; + } + } + break; + case CODENAME_MILAN: { + switch (version) { + case 0x2D0008: g_smu.pm_dram_map_size = 0x1AB0; break; // Don't exist in RM. + default: return SMU_Return_Unsupported; + } + } + break; + case CODENAME_RENOIR: + case CODENAME_LUCIENNE: { + switch (version) { + case 0x370000: g_smu.pm_dram_map_size = 0x794; break; + case 0x370001: g_smu.pm_dram_map_size = 0x884; break; + case 0x370002: g_smu.pm_dram_map_size = 0x88C; break; + case 0x370003: g_smu.pm_dram_map_size = 0x8AC; break; + case 0x370005: g_smu.pm_dram_map_size = 0x8C8; break; + default: return SMU_Return_Unsupported; + } + } + break; + case CODENAME_CEZANNE: { + switch (version) { + case 0x400005: g_smu.pm_dram_map_size = 0x944; break; + default: return SMU_Return_Unsupported; + } + } + break; + case CODENAME_REMBRANDT: { + switch (version) { + case 0x450004: g_smu.pm_dram_map_size = 0xAA4; break; + case 0x450005: g_smu.pm_dram_map_size = 0xAB0; break; + default: return SMU_Return_Unsupported; + } + } + break; + case CODENAME_PICASSO: + case CODENAME_RAVENRIDGE: + case CODENAME_RAVENRIDGE2: { + // These codenames have two PM tables, a larger (primary) one and a smaller one. + // The size is always fixed to 0x608 and 0xA4 bytes each. + // Source: Ryzen Master. + g_smu.pm_dram_map_size_alt = 0xA4; + g_smu.pm_dram_map_size = 0x608 + g_smu.pm_dram_map_size_alt; + + // Split DRAM base into high/low values. + g_smu.pm_dram_base_alt = g_smu.pm_dram_base >> 32; + g_smu.pm_dram_base &= 0xFFFFFFFF; + } + break; + case CODENAME_RAPHAEL: { + switch (version) { + case 0x000400: g_smu.pm_dram_map_size = 0x948; break; // Some ES-time table? Don't exist in RM. + case 0x540000: g_smu.pm_dram_map_size = 0x828; break; + case 0x540001: g_smu.pm_dram_map_size = 0x82C; break; + case 0x540002: g_smu.pm_dram_map_size = 0x87C; break; + case 0x540003: g_smu.pm_dram_map_size = 0x89C; break; + case 0x540004: g_smu.pm_dram_map_size = 0x8BC; break; + case 0x540005: g_smu.pm_dram_map_size = 0x8C8; break; + case 0x540100: g_smu.pm_dram_map_size = 0x618; break; + case 0x540101: g_smu.pm_dram_map_size = 0x61C; break; + case 0x540102: g_smu.pm_dram_map_size = 0x66C; break; + case 0x540103: g_smu.pm_dram_map_size = 0x68C; break; + case 0x540104: g_smu.pm_dram_map_size = 0x6A8; break; + case 0x540105: g_smu.pm_dram_map_size = 0x6B4; break; + case 0x540108: g_smu.pm_dram_map_size = 0x6BC; break; + case 0x540208: g_smu.pm_dram_map_size = 0x8D0; break; + default: return SMU_Return_Unsupported; + } + } + break; + case CODENAME_GRANITERIDGE: { + switch (version) { + case 0x620105: g_smu.pm_dram_map_size = 0x724; break; + case 0x620205: g_smu.pm_dram_map_size = 0x994; break; + default: return SMU_Return_Unsupported; + } + } + break; + case CODENAME_PHOENIX: + case CODENAME_HAWKPOINT: { + switch (version) { + case 0x4C0003: g_smu.pm_dram_map_size = 0xB18; break; + case 0x4C0004: g_smu.pm_dram_map_size = 0xB1C; break; + case 0x4C0005: g_smu.pm_dram_map_size = 0xAF8; break; + case 0x4C0006: g_smu.pm_dram_map_size = 0xAFC; break; + case 0x4C0008: g_smu.pm_dram_map_size = 0xAF0; break; + case 0x4C0007: + case 0x4C0009: g_smu.pm_dram_map_size = 0xB00; break; + default: return SMU_Return_Unsupported; + } + } + break; + case CODENAME_STRIXPOINT: { + switch (version) { + case 0x5D0008: g_smu.pm_dram_map_size = 0xD54; break; + default: return SMU_Return_Unsupported; + } + } + break; + case CODENAME_STORMPEAK: { + switch (version) { + case 0x5C0002: g_smu.pm_dram_map_size = 0x1E3C; break; + case 0x5C0003: g_smu.pm_dram_map_size = 0x1E48; break; + case 0x5C0102: g_smu.pm_dram_map_size = 0x1A14; break; + case 0x5C0103: g_smu.pm_dram_map_size = 0x1A20; break; + case 0x5C0202: g_smu.pm_dram_map_size = 0x15EC; break; + case 0x5C0203: g_smu.pm_dram_map_size = 0x15F8; break; + case 0x5C0302: g_smu.pm_dram_map_size = 0xD9C; break; + case 0x5C0303: g_smu.pm_dram_map_size = 0xDA8; break; + case 0x5C0402: g_smu.pm_dram_map_size = 0x974; break; + case 0x5C0403: g_smu.pm_dram_map_size = 0x980; break; + default: return SMU_Return_Unsupported; + } + } + break; + default: + return SMU_Return_Unsupported; + } - // Check if we should tell the SMU to refresh the table via jiffies. - // Use a minimum interval of 1 ms. - if (!g_smu.pm_jiffies || - time_after(jiffies, g_smu.pm_jiffies + msecs_to_jiffies(1))) { - g_smu.pm_jiffies = jiffies; + return SMU_Return_OK; +} - ret = smu_transfer_table_to_dram(dev); - if (ret != SMU_Return_OK) - return ret; +smu_return_val smu_read_pm_table(const struct pci_dev* dev, unsigned char* dst, size_t* len) { + u32 ret, version, size; + + // The DRAM base does not change after boot meaning it only needs to be fetched once. + // From testing, it also seems they are always mapped to the same address as well, + // at least when running the same AGESA version. + if (g_smu.pm_dram_base == 0 || g_smu.pm_dram_map_size == 0) { + g_smu.pm_dram_base = smu_get_dram_base_address(dev); + + // Verify returned value isn't an SMU return value. + if (g_smu.pm_dram_base < 0xFF) { + pr_err("Unable to receive the DRAM base address: %X", (u8)g_smu.pm_dram_base); + return g_smu.pm_dram_base; + } + + // Should help us catch where we missed table version initialization in the future. + version = 0xDEADC0DE; + + // These models require finding the PM table version to determine its size. + if (g_smu.codename == CODENAME_VERMEER || + g_smu.codename == CODENAME_MATISSE || + g_smu.codename == CODENAME_RAPHAEL || + g_smu.codename == CODENAME_GRANITERIDGE || + g_smu.codename == CODENAME_RENOIR || + g_smu.codename == CODENAME_LUCIENNE || + g_smu.codename == CODENAME_REMBRANDT || + g_smu.codename == CODENAME_PHOENIX || + g_smu.codename == CODENAME_STRIXPOINT || + g_smu.codename == CODENAME_CEZANNE || + g_smu.codename == CODENAME_CHAGALL || + g_smu.codename == CODENAME_MILAN || + g_smu.codename == CODENAME_HAWKPOINT || + g_smu.codename == CODENAME_STORMPEAK) { + ret = smu_get_pm_table_version(dev, &version); + + if (ret != SMU_Return_OK) { + pr_err("Failed to get PM Table version with error: %X\n", ret); + return ret; + } + } + + ret = smu_update_pmtable_size(version); + if (ret != SMU_Return_OK) { + pr_err("Unknown PM table version: 0x%08X", version); + return ret; + } + + pr_debug("Determined PM mapping size as (%xh,%xh) bytes.", g_smu.pm_dram_map_size, g_smu.pm_dram_map_size_alt); + } - if (g_smu.pm_dram_map_size_alt) { - ret = smu_transfer_2nd_table_to_dram(dev); - if (ret != SMU_Return_OK) - return ret; + // Validate output buffer size. + // N.B. In the case of Picasso/RavenRidge 2, we include the secondary PM Table size as well + if (*len < g_smu.pm_dram_map_size) { + pr_warn("Insufficient buffer size for PM table read: %lu < %d version: 0x%X", *len, g_smu.pm_dram_map_size, version); + + *len = g_smu.pm_dram_map_size; + return SMU_Return_InsufficientSize; } - } - // Primary PM Table size - size = g_smu.pm_dram_map_size - g_smu.pm_dram_map_size_alt; + // Clamp output size + *len = g_smu.pm_dram_map_size; + + // Check if we should tell the SMU to refresh the table via jiffies. + // Use a minimum interval of 1 ms. + if (!g_smu.pm_jiffies || time_after(jiffies, g_smu.pm_jiffies + msecs_to_jiffies(1))) { + g_smu.pm_jiffies = jiffies; - // We only map the DRAM base(s) once for use. - if (g_smu.pm_table_virt_addr == NULL) { - // From Linux documentation, it seems we should use _cache() for ioremap(). - g_smu.pm_table_virt_addr = ioremap_cache(g_smu.pm_dram_base, size); + ret = smu_transfer_table_to_dram(dev); + if (ret != SMU_Return_OK) + return ret; - if (g_smu.pm_table_virt_addr == NULL) { - pr_err("Failed to map DRAM base: %llX (0x%X B)", g_smu.pm_dram_base, - size); - return SMU_Return_MappedError; + if (g_smu.pm_dram_map_size_alt) { + ret = smu_transfer_2nd_table_to_dram(dev); + if (ret != SMU_Return_OK) + return ret; + } } - // In Picasso/RavenRidge 2, we map the secondary (high) address as well. - if (g_smu.pm_dram_map_size_alt) { - g_smu.pm_table_virt_addr_alt = - ioremap_cache(g_smu.pm_dram_base_alt, g_smu.pm_dram_map_size_alt); + // Primary PM Table size + size = g_smu.pm_dram_map_size - g_smu.pm_dram_map_size_alt; - if (g_smu.pm_table_virt_addr_alt == NULL) { - pr_err("Failed to map DRAM alt base: %X (0x%X B)", - g_smu.pm_dram_base_alt, g_smu.pm_dram_map_size_alt); - return SMU_Return_MappedError; - } + // We only map the DRAM base(s) once for use. + if (g_smu.pm_table_virt_addr == NULL) { + // From Linux documentation, it seems we should use _cache() for ioremap(). + g_smu.pm_table_virt_addr = ioremap_cache(g_smu.pm_dram_base, size); + + if (g_smu.pm_table_virt_addr == NULL) { + pr_err("Failed to map DRAM base: %llX (0x%X B)", g_smu.pm_dram_base, size); + return SMU_Return_MappedError; + } + + // In Picasso/RavenRidge 2, we map the secondary (high) address as well. + if (g_smu.pm_dram_map_size_alt) { + g_smu.pm_table_virt_addr_alt = ioremap_cache( + g_smu.pm_dram_base_alt, + g_smu.pm_dram_map_size_alt + ); + + if (g_smu.pm_table_virt_addr_alt == NULL) { + pr_err("Failed to map DRAM alt base: %X (0x%X B)", g_smu.pm_dram_base_alt, g_smu.pm_dram_map_size_alt); + return SMU_Return_MappedError; + } + } } - } - // memcpy() seems to work as well but according to Linux, for physically - // mapped addresses, - // we should use _fromio(). - memcpy_fromio(dst, g_smu.pm_table_virt_addr, size); + // memcpy() seems to work as well but according to Linux, for physically mapped addresses, + // we should use _fromio(). + memcpy_fromio(dst, g_smu.pm_table_virt_addr, size); - // Append secondary table if required. - if (g_smu.pm_dram_map_size_alt) - memcpy_fromio(dst + size, g_smu.pm_table_virt_addr_alt, - g_smu.pm_dram_map_size_alt); + // Append secondary table if required. + if (g_smu.pm_dram_map_size_alt) + memcpy_fromio(dst + size, g_smu.pm_table_virt_addr_alt, g_smu.pm_dram_map_size_alt); - return SMU_Return_OK; + return SMU_Return_OK; } diff --git a/smu.h b/smu.h index 012b9a3..3d1e249 100755 --- a/smu.h +++ b/smu.h @@ -2,15 +2,16 @@ /* Copyright (C) 2020 Leonardo Gates */ /* Ryzen SMU Root Complex Communication */ -#ifndef __SMU_H__ -#define __SMU_H__ +#pragma once #include #include +#include "smu_common.h" + /* Redefine output format for nicer formatting. */ #ifdef pr_fmt - #undef pr_fmt +#undef pr_fmt #endif #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -34,89 +35,6 @@ /* Maximum number of 32-bit arguments an SMU command shall have. */ #define SMU_REQ_MAX_ARGS 6 -/** - * Return values that can be sent from the SMU in response to a command. - */ -enum smu_return_val { - SMU_Return_OK = 0x01, - SMU_Return_Failed = 0xFF, - SMU_Return_UnknownCmd = 0xFE, - SMU_Return_CmdRejectedPrereq = 0xFD, - SMU_Return_CmdRejectedBusy = 0xFC, - - // Custom Error Code -- Does not exist in SMU. - - // SMU Management failed to respond within the SMU_TIMEOUT_MS range. - SMU_Return_CommandTimeout = 0xFB, - // An invalid argument was sent to the function. - SMU_Return_InvalidArgument = 0xFA, - // Function is unsupported on the current processor. - SMU_Return_Unsupported = 0xF9, - // Insufficient buffer size specified. - SMU_Return_InsufficientSize = 0xF8, - // Failed to map physical address. - SMU_Return_MappedError = 0xF7, - // PCIe programming error. - SMU_Return_PCIFailed = 0xF6, -}; - -/** - * Supported processor codenames with SMU capabilities. - */ -enum smu_processor_codename { - CODENAME_UNDEFINED, - CODENAME_COLFAX, - CODENAME_RENOIR, - CODENAME_PICASSO, - CODENAME_MATISSE, - CODENAME_THREADRIPPER, - CODENAME_CASTLEPEAK, - CODENAME_RAVENRIDGE, - CODENAME_RAVENRIDGE2, - CODENAME_SUMMITRIDGE, - CODENAME_PINNACLERIDGE, - CODENAME_REMBRANDT, - CODENAME_VERMEER, - CODENAME_VANGOGH, - CODENAME_CEZANNE, - CODENAME_MILAN, - CODENAME_DALI, - CODENAME_LUCIENNE, - CODENAME_NAPLES, - CODENAME_CHAGALL, - CODENAME_RAPHAEL, - CODENAME_PHOENIX, - CODENAME_STRIXPOINT, - CODENAME_GRANITERIDGE, - CODENAME_HAWKPOINT, - CODENAME_STORMPEAK, - CODENAME_COUNT -}; - -/** - * SMU MP1 Interface Version [v9-v13] - */ -enum smu_if_version { - IF_VERSION_9, - IF_VERSION_10, - IF_VERSION_11, - IF_VERSION_12, - IF_VERSION_13, - - IF_VERSION_COUNT -}; - -/** - * SMU Mailbox Target - */ -enum smu_mailbox { - MAILBOX_TYPE_RSMU, - MAILBOX_TYPE_MP1, - MAILBOX_TYPE_HSMP, - - MAILBOX_TYPE_COUNT -}; - /** * SMU Service Request Arguments */ @@ -128,7 +46,7 @@ typedef union { u32 arg3; u32 arg4; u32 arg5; - } s; + } s; u32 args[SMU_REQ_MAX_ARGS]; } smu_req_args_t; @@ -140,7 +58,7 @@ extern uint smu_timeout_attempts; * * Returns 0 on success, anything else on failure. */ -int smu_init(struct pci_dev* dev); +int smu_init(void); /** * Cleans up the allocated objects after use. @@ -150,20 +68,15 @@ void smu_cleanup(void); /** * Returns the running processor's detected code name. */ -enum smu_processor_codename smu_get_codename(void); - -/** - * Returns the running processor's detected code name as a fridnly string. - */ -const char* getCodeName(enum smu_processor_codename codename); +const char* smu_get_codename(void); /** * Reads or writes 32 bit words to the SMU on the root NB PCI device. * * Returns an smu_return_val indicating the status of the operation. */ -enum smu_return_val smu_read_address(struct pci_dev* dev, u32 address, u32* value); -enum smu_return_val smu_write_address(struct pci_dev* dev, u32 address, u32 value); +smu_return_val smu_read_address(const struct pci_dev* dev, u32 address, u32* value); +smu_return_val smu_write_address(const struct pci_dev* dev, u32 address, u32 value); /** * Initializes an SMU REQ ARG structure with zeros. @@ -180,26 +93,25 @@ void smu_args_init(smu_req_args_t* args, u32 value); * * Returns an smu_return_val indicating the status of the operation. */ -enum smu_return_val smu_send_command(struct pci_dev* dev, u32 op, smu_req_args_t* args, - enum smu_mailbox mailbox); +smu_return_val smu_send_command(const struct pci_dev* dev, u32 op, smu_req_args_t* args, smu_mailbox mailbox); /** * Returns the current SMU firmware version from the specified mailbox. */ -u32 smu_get_version(struct pci_dev* dev, enum smu_mailbox mb); +u32 smu_get_version(const struct pci_dev* dev, smu_mailbox mb); /** * Returns the interface version of the MP1 mailbox. */ -enum smu_if_version smu_get_mp1_if_version(void); +smu_if_version smu_get_mp1_if_version(void); /** * Commands the SMU to update the PM table mapped at the DRAM base address. * * Returns an smu_return_val indicating the status of the operation. */ -enum smu_return_val smu_transfer_table_to_dram(struct pci_dev* dev); -enum smu_return_val smu_transfer_2nd_table_to_dram(struct pci_dev *dev); +smu_return_val smu_transfer_table_to_dram(const struct pci_dev* dev); +smu_return_val smu_transfer_2nd_table_to_dram(const struct pci_dev *dev); /** * For Matisse and Renoir processors, returns a numeric value indicating the format @@ -207,18 +119,16 @@ enum smu_return_val smu_transfer_2nd_table_to_dram(struct pci_dev *dev); * * Returns an smu_return_val indicating the status of the operation. */ -enum smu_return_val smu_get_pm_table_version(struct pci_dev* dev, u32* version); +smu_return_val smu_get_pm_table_version(const struct pci_dev* dev, u32* version); /** * Reads the PM table for the current CPU, if supported, into the destination buffer. * * Returns an smu_return_val indicating the status of the operation. */ -enum smu_return_val smu_read_pm_table(struct pci_dev* dev, unsigned char* dst, size_t* len); +smu_return_val smu_read_pm_table(const struct pci_dev* dev, unsigned char* dst, size_t* len); -int smu_smn_rw_address(struct pci_dev *dev, u32 address, u32 *value, int write); -int smu_resolve_cpu_class(struct pci_dev *dev); -u64 smu_get_dram_base_address(struct pci_dev *dev); +int smu_smn_rw_address(const struct pci_dev *dev, u32 address, u32 *value, int write); +int smu_resolve_cpu_class(void); +u64 smu_get_dram_base_address(const struct pci_dev *dev); u32 smu_update_pmtable_size(u32 version); - -#endif /* __SMU_H__ */ diff --git a/smu_common.c b/smu_common.c new file mode 100644 index 0000000..08878a9 --- /dev/null +++ b/smu_common.c @@ -0,0 +1,32 @@ +#include "smu_common.h" + +const char* getCodeName(const smu_processor_codename codename) { + switch (codename) { + case CODENAME_COLFAX: return "Colfax"; + case CODENAME_RENOIR: return "Renoir"; + case CODENAME_PICASSO: return "Picasso"; + case CODENAME_MATISSE: return "Matisse"; + case CODENAME_THREADRIPPER: return "ThreadRipper"; + case CODENAME_CASTLEPEAK: return "CastelPeak"; + case CODENAME_RAVENRIDGE: return "RavenRidge"; + case CODENAME_RAVENRIDGE2: return "RavenRidge2"; + case CODENAME_SUMMITRIDGE: return "SummitRidge"; + case CODENAME_PINNACLERIDGE: return "PinnacleRidge"; + case CODENAME_REMBRANDT: return "Rembrandt"; + case CODENAME_VERMEER: return "Vermeer"; + case CODENAME_VANGOGH: return "VanGogh"; + case CODENAME_CEZANNE: return "Cezanne"; + case CODENAME_MILAN: return "Milan"; + case CODENAME_DALI: return "Dali"; + case CODENAME_LUCIENNE: return "Lucienne"; + case CODENAME_NAPLES: return "Naples"; + case CODENAME_CHAGALL: return "Chagall"; + case CODENAME_RAPHAEL: return "Raphael"; + case CODENAME_GRANITERIDGE: return "GraniteRidge"; + case CODENAME_STORMPEAK: return "StormPeak"; + case CODENAME_PHOENIX: return "Phoenix"; + case CODENAME_STRIXPOINT: return "StrixPoint"; + case CODENAME_HAWKPOINT: return "HawkPoint"; + default: return "Undefined"; + } +} diff --git a/smu_common.h b/smu_common.h new file mode 100644 index 0000000..e27ae98 --- /dev/null +++ b/smu_common.h @@ -0,0 +1,96 @@ +#pragma once + +/** + * Return values that can be sent from the SMU in response to a command. + */ +typedef enum { + SMU_Return_OK = 0x01, + SMU_Return_Failed = 0xFF, + SMU_Return_UnknownCmd = 0xFE, + SMU_Return_CmdRejectedPrereq = 0xFD, + SMU_Return_CmdRejectedBusy = 0xFC, + + // Custom Error Code -- Does not exist in SMU. + + // SMU Management failed to respond within the SMU_TIMEOUT_MS range. + SMU_Return_CommandTimeout = 0xFB, + // An invalid argument was sent to the function. + SMU_Return_InvalidArgument = 0xFA, + // Function is unsupported on the current processor. + SMU_Return_Unsupported = 0xF9, + // Insufficient buffer size specified. + SMU_Return_InsufficientSize = 0xF8, + // Failed to map physical address. + SMU_Return_MappedError = 0xF7, + // PCIe programming error. + SMU_Return_PCIFailed = 0xF6, + + // Userspace Library Codes + + // Driver is not currently loaded or inaccessible. + SMU_Return_DriverNotPresent = 0xF0, + // Read or write error has occurred. Check errno for last error. + SMU_Return_RWError = 0xE9, + // Driver version is incompatible. + SMU_Return_DriverVersion = 0xE8, +} smu_return_val; + +/** + * Supported processor codenames with SMU capabilities. + */ +typedef enum { + CODENAME_UNDEFINED, + CODENAME_COLFAX, + CODENAME_RENOIR, + CODENAME_PICASSO, + CODENAME_MATISSE, + CODENAME_THREADRIPPER, + CODENAME_CASTLEPEAK, + CODENAME_RAVENRIDGE, + CODENAME_RAVENRIDGE2, + CODENAME_SUMMITRIDGE, + CODENAME_PINNACLERIDGE, + CODENAME_REMBRANDT, + CODENAME_VERMEER, + CODENAME_VANGOGH, + CODENAME_CEZANNE, + CODENAME_MILAN, + CODENAME_DALI, + CODENAME_LUCIENNE, + CODENAME_NAPLES, + CODENAME_CHAGALL, + CODENAME_RAPHAEL, + CODENAME_PHOENIX, + CODENAME_STRIXPOINT, + CODENAME_GRANITERIDGE, + CODENAME_HAWKPOINT, + CODENAME_STORMPEAK, + + CODENAME_COUNT +} smu_processor_codename; + +/** + * SMU MP1 Interface Version [v9-v13] + */ +typedef enum { + IF_VERSION_9, + IF_VERSION_10, + IF_VERSION_11, + IF_VERSION_12, + IF_VERSION_13, + + IF_VERSION_COUNT +} smu_if_version; + +/** + * SMU Mailbox Target + */ +typedef enum { + MAILBOX_TYPE_RSMU, + MAILBOX_TYPE_MP1, + MAILBOX_TYPE_HSMP, + + MAILBOX_TYPE_COUNT +} smu_mailbox; + +const char* getCodeName(smu_processor_codename codename); From 04df4faf22b0c2037132359f288bbc2974db8f50 Mon Sep 17 00:00:00 2001 From: kylon <3252255+kylon@users.noreply.github.com> Date: Thu, 5 Jun 2025 01:57:06 +0200 Subject: [PATCH 2/5] address comments merge leftover up version to 0.1.8 update README.md sort IDs move smu_common to lib --- Makefile | 4 +-- README.md | 57 ++++++-------------------------- drv.c | 18 +++++----- lib/libsmu.c | 3 +- lib/libsmu.h | 4 +-- smu_common.c => lib/smu_common.c | 4 +-- smu_common.h => lib/smu_common.h | 2 +- smu.c | 4 +-- smu.h | 2 +- 9 files changed, 29 insertions(+), 69 deletions(-) rename smu_common.c => lib/smu_common.c (92%) rename smu_common.h => lib/smu_common.h (97%) diff --git a/Makefile b/Makefile index c9460b5..b655cae 100755 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ MOD := ryzen_smu -VERSION := 0.1.6 +VERSION := 0.1.8 TARGET := $(shell uname -r) DKMS_ROOT_PATH := /usr/src/$(MOD)-$(VERSION) @@ -16,7 +16,7 @@ endif endif obj-m := $(MOD).o -$(MOD)-objs := drv.o smu.o smu_common.o +$(MOD)-objs := drv.o smu.o lib/smu_common.o .PHONY: all modules clean dkms-install dkms-uninstall insmod checkmod diff --git a/README.md b/README.md index a586b46..35ee7d8 100755 --- a/README.md +++ b/README.md @@ -42,8 +42,8 @@ can also be accessed: - Granite Ridge ( Ryzen 9000 Desktop Series ) - Strix Point ( Ryzen AI 300 ) -- Hawk Point ( Ryzen 8000 Mobile Series ) -- Phoenix ( Ryzen 8000 APU Series ) +- Hawk Point ( Ryzen 8000 APU Series ) +- Phoenix ( Ryzen 7000 APU Series ) - Storm Peak ( ThreadRipper 7000 Workstation Series ) - Raphael ( Ryzen 7000 Desktop Series ) - Chagall ( ThreadRipper 5000 Workstation Series ) @@ -76,8 +76,6 @@ exposed: - `pm_table_size` - `pm_table` - - ## Installation The kernel module may be installed either by DKMS or manually building and inserting the module. @@ -96,12 +94,12 @@ sudo make dkms-install ### Arch Linux -Available on the [AUR](https://aur.archlinux.org/packages/ryzen_smu-dkms-git/). - -Install it using your AUR helper of choice, example: - ```sh -yay -S ryzen_smu-dkms-git +sudo pacman -S dkms git base-devel linux-headers-$(uname -r) +git clone https://gitlab.com/leogx9r/ryzen_smu.git +cd ryzen_smu + +sudo make dkms-install ``` ### Stand-alone Installation @@ -138,7 +136,7 @@ Upon loading the module, you should see output in your `dmesg` window listing th # dmesg ... -[1091.154018] ryzen_smu: CPUID: family 0x17, model 0x71, stepping 0x0, package 0x2 +[1091.154018] ryzen_smu: CPUID: family 0x17, model 0x71, package 0x2 [1091.154385] ryzen_smu: SMU v46.54.0 ... ``` @@ -170,10 +168,7 @@ SMU v46.54.0 2 # cat /sys/kernel/ryzen_smu_drv/codename -4 - -# cat /sys/kernel/ryzen_smu_drv/drv_version -0.1.7 +StrixPoint ``` @@ -228,39 +223,7 @@ Note: This file returns a string representation of the "Value" field above. #### `/sys/kernel/ryzen_smu_drv/codename` -Returns a numeric index containing the running processor's codename based on the following -enumeration: - -| Hex | Decimal | Code Name | -|:---:|:-------:|:--------------:| -| 00h | 0 | Unknown | -| 01h | 1 | Colfax | -| 02h | 2 | Renoir | -| 03h | 3 | Picasso | -| 04h | 4 | Matisse | -| 05h | 5 | Threadripper | -| 06h | 6 | Castle Peak | -| 07h | 7 | Raven Ridge | -| 08h | 8 | Raven Ridge 2 | -| 09h | 9 | Summit Ridge | -| 0Ah | 10 | Pinnacle Ridge | -| 0Bh | 11 | Rembrandt | -| 0Ch | 12 | Vermeer | -| 0Dh | 13 | Vangogh | -| 0Eh | 14 | Cezanne | -| 0Fh | 15 | Milan | -| 10h | 16 | Dali | -| 11h | 17 | Luciene | -| 12h | 18 | Naples | -| 13h | 19 | Chagall | -| 14h | 20 | Raphael | -| 15h | 21 | Phoenix | -| 16h | 22 | Strix Point | -| 17h | 23 | Granite Ridge | -| 18h | 24 | Hawk Point | -| 19h | 25 | Storm Peak | - -Note: This file returns 2 characters of the 'Decimal' encoded index. +Returns the processor codename, or Unknown if the processor is not supported by ryzen_smu. #### `/sys/kernel/ryzen_smu_drv/rsmu_cmd` or `/sys/kernel/ryzen_smu_drv/mp1_smu_cmd` or `/sys/kernel/ryzen_smu_drv/hsmp_smu_cmd` diff --git a/drv.c b/drv.c index 5abf58c..4e0bfc1 100755 --- a/drv.c +++ b/drv.c @@ -21,25 +21,23 @@ MODULE_AUTHOR("Leonardo Gates "); MODULE_DESCRIPTION("AMD Ryzen SMU Command Driver"); -MODULE_VERSION("0.1.7"); +MODULE_VERSION("0.1.8"); MODULE_LICENSE("GPL"); #define MSEC_TO_NSEC(x) (x * 1000000) -#define PCI_DEVICE_ID_AMD_1AH_M00H_ROOT 0x153a -#define PCI_DEVICE_ID_AMD_1AH_M20H_ROOT 0x1507 -#define PCI_DEVICE_ID_AMD_1AH_M44H_ROOT 0x14d8 -#define PCI_DEVICE_ID_AMD_1AH_M60H_ROOT 0x1122 -#define PCI_DEVICE_ID_AMD_17H_MA0H_ROOT 0x14b5 #define PCI_DEVICE_ID_AMD_17H_ROOT 0x1450 #define PCI_DEVICE_ID_AMD_17H_M10H_ROOT 0x15d0 #define PCI_DEVICE_ID_AMD_17H_M30H_ROOT 0x1480 #define PCI_DEVICE_ID_AMD_17H_M60H_ROOT 0x1630 -#define PCI_DEVICE_ID_AMD_19H_M10H_DF_F4 0x14b1 +#define PCI_DEVICE_ID_AMD_17H_MA0H_ROOT 0x14b5 #define PCI_DEVICE_ID_AMD_19H_M10H_ROOT 0x14a4 #define PCI_DEVICE_ID_AMD_19H_M40H_ROOT 0x14b5 #define PCI_DEVICE_ID_AMD_19H_M60H_ROOT 0x14d8 #define PCI_DEVICE_ID_AMD_19H_M70H_ROOT 0x14e8 +#define PCI_DEVICE_ID_AMD_1AH_M00H_ROOT 0x153a +#define PCI_DEVICE_ID_AMD_1AH_M20H_ROOT 0x1507 +#define PCI_DEVICE_ID_AMD_1AH_M60H_ROOT 0x1122 #define PCI_DEVICE_ID_AMD_MI200_ROOT 0x14bb #define PCI_DEVICE_ID_AMD_MI300_ROOT 0x14f8 @@ -432,9 +430,6 @@ static void ryzen_smu_remove(struct pci_dev *dev) { } static struct pci_device_id ryzen_smu_id_table[] = { - { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_1AH_M00H_ROOT) }, - { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_1AH_M20H_ROOT) }, - { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_1AH_M60H_ROOT) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_ROOT) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M10H_ROOT) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M30H_ROOT) }, @@ -444,6 +439,9 @@ static struct pci_device_id ryzen_smu_id_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_19H_M40H_ROOT) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_19H_M60H_ROOT) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_19H_M70H_ROOT) }, + { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_1AH_M00H_ROOT) }, + { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_1AH_M20H_ROOT) }, + { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_1AH_M60H_ROOT) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_MI200_ROOT) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_MI300_ROOT) }, { } diff --git a/lib/libsmu.c b/lib/libsmu.c index 06405c8..1e976d9 100755 --- a/lib/libsmu.c +++ b/lib/libsmu.c @@ -311,7 +311,6 @@ smu_return_val smu_send_command(smu_obj_t* obj, const unsigned int op, smu_arg_t return SMU_Return_Unsupported; } - // Check if fd is valid. if (!fd_smu_cmd) return SMU_Return_Unsupported; @@ -418,7 +417,7 @@ const char* smu_return_to_str(const smu_return_val val) { } const char* smu_codename_to_str(const smu_obj_t* obj) { - return getCodeName(obj->codename); + return get_code_name(obj->codename); } unsigned int smu_pm_tables_supported(const smu_obj_t* obj) { diff --git a/lib/libsmu.h b/lib/libsmu.h index d33f9bc..50eae58 100755 --- a/lib/libsmu.h +++ b/lib/libsmu.h @@ -20,10 +20,10 @@ #include -#include "../smu_common.h" +#include "smu_common.h" /* Version the loaded driver must use to be compatible. */ -#define LIBSMU_SUPPORTED_DRIVER_VERSION "0.1.7" +#define LIBSMU_SUPPORTED_DRIVER_VERSION "0.1.8" /** * Mutex lock enumeration for specific components. diff --git a/smu_common.c b/lib/smu_common.c similarity index 92% rename from smu_common.c rename to lib/smu_common.c index 08878a9..7783460 100644 --- a/smu_common.c +++ b/lib/smu_common.c @@ -1,6 +1,6 @@ #include "smu_common.h" -const char* getCodeName(const smu_processor_codename codename) { +const char* get_code_name(const smu_processor_codename codename) { switch (codename) { case CODENAME_COLFAX: return "Colfax"; case CODENAME_RENOIR: return "Renoir"; @@ -27,6 +27,6 @@ const char* getCodeName(const smu_processor_codename codename) { case CODENAME_PHOENIX: return "Phoenix"; case CODENAME_STRIXPOINT: return "StrixPoint"; case CODENAME_HAWKPOINT: return "HawkPoint"; - default: return "Undefined"; + default: return "Unknown"; } } diff --git a/smu_common.h b/lib/smu_common.h similarity index 97% rename from smu_common.h rename to lib/smu_common.h index e27ae98..e820aef 100644 --- a/smu_common.h +++ b/lib/smu_common.h @@ -93,4 +93,4 @@ typedef enum { MAILBOX_TYPE_COUNT } smu_mailbox; -const char* getCodeName(smu_processor_codename codename); +const char* get_code_name(smu_processor_codename codename); diff --git a/smu.c b/smu.c index c4cd9bb..391179b 100755 --- a/smu.c +++ b/smu.c @@ -518,7 +518,7 @@ int smu_init(void) { return -ENODEV; } - pr_info("Family Codename: %s", getCodeName(g_smu.codename)); + pr_info("Family Codename: %s", get_code_name(g_smu.codename)); return 0; } @@ -539,7 +539,7 @@ void smu_cleanup(void) { } const char *smu_get_codename(void) { - return getCodeName(g_smu.codename); + return get_code_name(g_smu.codename); } u32 smu_get_version(const struct pci_dev* dev, const smu_mailbox mb) { diff --git a/smu.h b/smu.h index 3d1e249..2557cc2 100755 --- a/smu.h +++ b/smu.h @@ -7,7 +7,7 @@ #include #include -#include "smu_common.h" +#include "lib/smu_common.h" /* Redefine output format for nicer formatting. */ #ifdef pr_fmt From e1ce9d848e1cd9951667559ee6589b3623a78c3b Mon Sep 17 00:00:00 2001 From: kylon <3252255+kylon@users.noreply.github.com> Date: Thu, 5 Jun 2025 17:05:53 +0200 Subject: [PATCH 3/5] more comments and fix userspace build --- drv.c | 2 +- smu.c | 4 ++-- smu.h | 2 +- userspace/Makefile | 7 +++---- userspace/monitor_cpu.c | 4 ++-- 5 files changed, 9 insertions(+), 10 deletions(-) diff --git a/drv.c b/drv.c index 4e0bfc1..9814de4 100755 --- a/drv.c +++ b/drv.c @@ -103,7 +103,7 @@ static ssize_t mp1_if_version_show(struct kobject *kobj, struct kobj_attribute * } static ssize_t codename_show(struct kobject *kobj, struct kobj_attribute *attr, char *buff) { - return sprintf(buff, "%s\n", smu_get_codename()); + return sprintf(buff, "%02d\n", smu_get_codename()); } static ssize_t pm_table_show(struct kobject *kobj, struct kobj_attribute *attr, char *buff) { diff --git a/smu.c b/smu.c index 391179b..2d13681 100755 --- a/smu.c +++ b/smu.c @@ -538,8 +538,8 @@ void smu_cleanup(void) { g_smu.codename = CODENAME_UNDEFINED; } -const char *smu_get_codename(void) { - return get_code_name(g_smu.codename); +smu_processor_codename smu_get_codename(void) { + return g_smu.codename; } u32 smu_get_version(const struct pci_dev* dev, const smu_mailbox mb) { diff --git a/smu.h b/smu.h index 2557cc2..97ee25d 100755 --- a/smu.h +++ b/smu.h @@ -68,7 +68,7 @@ void smu_cleanup(void); /** * Returns the running processor's detected code name. */ -const char* smu_get_codename(void); +smu_processor_codename smu_get_codename(void); /** * Reads or writes 32 bit words to the SMU on the root NB PCI device. diff --git a/userspace/Makefile b/userspace/Makefile index 0f5f4ea..03f5487 100755 --- a/userspace/Makefile +++ b/userspace/Makefile @@ -10,9 +10,8 @@ PATHS = -I"../lib" OUT = monitor_cpu -SRC = monitor_cpu.c -SRC += "../lib/libsmu.c" +SRC = monitor_cpu.c ../lib/libsmu.c ../lib/smu_common.c -all: monitor_cpu.c ../lib/libsmu.c +all: monitor_cpu.c ../lib/libsmu.c ../lib/smu_common.c $(CC) $(PATHS) $(CFLAGS) $(LDFLAGS) -o $(OUT) $(SRC) - $(STRIP) $(SFLAGS) $(OUT) \ No newline at end of file + $(STRIP) $(SFLAGS) $(OUT) diff --git a/userspace/monitor_cpu.c b/userspace/monitor_cpu.c index f8a87d2..b5eff67 100755 --- a/userspace/monitor_cpu.c +++ b/userspace/monitor_cpu.c @@ -442,7 +442,7 @@ unsigned int get_max_cpu_freq(smu_obj_t* obj) { return 0; memset(&args, 0, sizeof(args)); - if (smu_send_command(obj, 0x6E, &args, SMU_TYPE_RSMU) != SMU_Return_OK) + if (smu_send_command(obj, 0x6E, &args, MAILBOX_TYPE_RSMU) != SMU_Return_OK) return 0; return args.args[0]; @@ -458,7 +458,7 @@ const char* get_pbo_scalar(smu_obj_t* obj) { return 0; memset(&args, 0, sizeof(args)); - if (smu_send_command(obj, 0x6C, &args, SMU_TYPE_RSMU) != SMU_Return_OK) + if (smu_send_command(obj, 0x6C, &args, MAILBOX_TYPE_RSMU) != SMU_Return_OK) return "?"; sprintf(buf, "%.fx", args.args_f[0]); From 7c59d374f06eb14ea03315c6a8d6007a0511211f Mon Sep 17 00:00:00 2001 From: kylon <3252255+kylon@users.noreply.github.com> Date: Thu, 5 Jun 2025 17:10:55 +0200 Subject: [PATCH 4/5] revert version change --- Makefile | 2 +- drv.c | 2 +- lib/libsmu.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index b655cae..7aa87c8 100755 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ MOD := ryzen_smu -VERSION := 0.1.8 +VERSION := 0.1.7 TARGET := $(shell uname -r) DKMS_ROOT_PATH := /usr/src/$(MOD)-$(VERSION) diff --git a/drv.c b/drv.c index 9814de4..0e4795d 100755 --- a/drv.c +++ b/drv.c @@ -21,7 +21,7 @@ MODULE_AUTHOR("Leonardo Gates "); MODULE_DESCRIPTION("AMD Ryzen SMU Command Driver"); -MODULE_VERSION("0.1.8"); +MODULE_VERSION("0.1.7"); MODULE_LICENSE("GPL"); #define MSEC_TO_NSEC(x) (x * 1000000) diff --git a/lib/libsmu.h b/lib/libsmu.h index 50eae58..45f381d 100755 --- a/lib/libsmu.h +++ b/lib/libsmu.h @@ -23,7 +23,7 @@ #include "smu_common.h" /* Version the loaded driver must use to be compatible. */ -#define LIBSMU_SUPPORTED_DRIVER_VERSION "0.1.8" +#define LIBSMU_SUPPORTED_DRIVER_VERSION "0.1.7" /** * Mutex lock enumeration for specific components. From e67d4dc4a8e42b8fa798b9d0b079c4d69be2c44e Mon Sep 17 00:00:00 2001 From: kylon <3252255+kylon@users.noreply.github.com> Date: Thu, 5 Jun 2025 18:20:18 +0200 Subject: [PATCH 5/5] update README.md --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 35ee7d8..117f189 100755 --- a/README.md +++ b/README.md @@ -86,7 +86,7 @@ Be sure kernel headers, dev utilities such as `gcc` and `make` are installed bef ```sh sudo apt install dkms git build-essential linux-headers-$(uname -r) -git clone https://gitlab.com/leogx9r/ryzen_smu.git +git clone https://github.com/amkillam/ryzen_smu.git cd ryzen_smu sudo make dkms-install @@ -96,7 +96,7 @@ sudo make dkms-install ```sh sudo pacman -S dkms git base-devel linux-headers-$(uname -r) -git clone https://gitlab.com/leogx9r/ryzen_smu.git +git clone https://github.com/amkillam/ryzen_smu.git cd ryzen_smu sudo make dkms-install @@ -107,7 +107,7 @@ sudo make dkms-install The module may be built and inserted into the running kernel manually as follows: ```sh -git clone https://gitlab.com/leogx9r/ryzen_smu.git +git clone https://github.com/amkillam/ryzen_smu.git cd ryzen_smu make @@ -168,7 +168,7 @@ SMU v46.54.0 2 # cat /sys/kernel/ryzen_smu_drv/codename -StrixPoint +4 ``` @@ -223,7 +223,7 @@ Note: This file returns a string representation of the "Value" field above. #### `/sys/kernel/ryzen_smu_drv/codename` -Returns the processor codename, or Unknown if the processor is not supported by ryzen_smu. +Returns a numeric value containing the running processor's codename based on the [smu_processor_codename](lib/smu_common.h) enumeration. #### `/sys/kernel/ryzen_smu_drv/rsmu_cmd` or `/sys/kernel/ryzen_smu_drv/mp1_smu_cmd` or `/sys/kernel/ryzen_smu_drv/hsmp_smu_cmd`