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..7aa87c8 100755 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ MOD := ryzen_smu -VERSION := 0.1.6 +VERSION := 0.1.7 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 +$(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..117f189 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. @@ -88,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,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://github.com/amkillam/ryzen_smu.git +cd ryzen_smu + +sudo make dkms-install ``` ### Stand-alone Installation @@ -109,7 +107,7 @@ yay -S ryzen_smu-dkms-git 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 @@ -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 ... ``` @@ -172,9 +170,6 @@ SMU v46.54.0 # cat /sys/kernel/ryzen_smu_drv/codename 4 -# cat /sys/kernel/ryzen_smu_drv/drv_version -0.1.7 - ``` Following which, you can run the [test.py script](scripts/test.py) to verify that SMU and SMN @@ -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 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` 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..0e4795d 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,28 +26,25 @@ 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_M60H_ROOT 0x1122 +#define PCI_DEVICE_ID_AMD_17H_M60H_ROOT 0x1630 #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 #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 +70,6 @@ static struct ryzen_smu_data { size_t pm_table_read_size; } g_driver = { .device = NULL, - .drv_kobj = NULL, .smu_version = { 0 }, @@ -119,27 +115,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 +156,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 +183,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 +210,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 +225,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 +307,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 +330,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 +343,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 +362,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 +372,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 +396,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); } @@ -441,14 +434,14 @@ static struct pci_device_id ryzen_smu_id_table[] = { { 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) }, { 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 3c2c461..1e976d9 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,29 +291,26 @@ 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: return SMU_Return_Unsupported; } - // Check if fd is valid. if (!fd_smu_cmd) return SMU_Return_Unsupported; @@ -366,7 +356,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 +381,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 +416,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 get_code_name(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..45f381d 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/lib/smu_common.c b/lib/smu_common.c new file mode 100644 index 0000000..7783460 --- /dev/null +++ b/lib/smu_common.c @@ -0,0 +1,32 @@ +#include "smu_common.h" + +const char* get_code_name(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 "Unknown"; + } +} diff --git a/lib/smu_common.h b/lib/smu_common.h new file mode 100644 index 0000000..e820aef --- /dev/null +++ b/lib/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* get_code_name(smu_processor_codename codename); diff --git a/smu.c b/smu.c index 3c439e6..2d13681 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", get_code_name(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; + +smu_processor_codename smu_get_codename(void) { + return 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..97ee25d 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 "lib/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); +smu_processor_codename 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/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]);