10e914063SShyam Sundar S K // SPDX-License-Identifier: GPL-2.0-or-later 20e914063SShyam Sundar S K /* 30e914063SShyam Sundar S K * AMD MP1 Smart Trace Buffer (STB) Layer 40e914063SShyam Sundar S K * 50e914063SShyam Sundar S K * Copyright (c) 2024, Advanced Micro Devices, Inc. 60e914063SShyam Sundar S K * All Rights Reserved. 70e914063SShyam Sundar S K * 80e914063SShyam Sundar S K * Authors: Shyam Sundar S K <Shyam-sundar.S-k@amd.com> 90e914063SShyam Sundar S K * Sanket Goswami <Sanket.Goswami@amd.com> 100e914063SShyam Sundar S K */ 110e914063SShyam Sundar S K 120e914063SShyam Sundar S K #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 130e914063SShyam Sundar S K 140e914063SShyam Sundar S K #include <asm/amd_nb.h> 150e914063SShyam Sundar S K #include <linux/debugfs.h> 160e914063SShyam Sundar S K #include <linux/seq_file.h> 170e914063SShyam Sundar S K #include <linux/uaccess.h> 180e914063SShyam Sundar S K 190e914063SShyam Sundar S K #include "pmc.h" 200e914063SShyam Sundar S K 210e914063SShyam Sundar S K /* STB Spill to DRAM Parameters */ 220e914063SShyam Sundar S K #define S2D_TELEMETRY_DRAMBYTES_MAX 0x1000000 230e914063SShyam Sundar S K #define S2D_TELEMETRY_BYTES_MAX 0x100000U 240e914063SShyam Sundar S K #define S2D_RSVD_RAM_SPACE 0x100000 250e914063SShyam Sundar S K 260e914063SShyam Sundar S K /* STB Registers */ 2700a8d002SShyam Sundar S K #define AMD_STB_PMI_0 0x03E30600 280e914063SShyam Sundar S K #define AMD_PMC_STB_DUMMY_PC 0xC6000007 290e914063SShyam Sundar S K 300e914063SShyam Sundar S K /* STB Spill to DRAM Message Definition */ 310e914063SShyam Sundar S K #define STB_FORCE_FLUSH_DATA 0xCF 320e914063SShyam Sundar S K #define FIFO_SIZE 4096 330e914063SShyam Sundar S K 343279f7a6SShyam Sundar S K /* STB S2D(Spill to DRAM) has different message port offset */ 353279f7a6SShyam Sundar S K #define AMD_S2D_REGISTER_MESSAGE 0xA20 363279f7a6SShyam Sundar S K #define AMD_S2D_REGISTER_RESPONSE 0xA80 373279f7a6SShyam Sundar S K #define AMD_S2D_REGISTER_ARGUMENT 0xA88 383279f7a6SShyam Sundar S K 39*382fe403SShyam Sundar S K /* STB S2D (Spill to DRAM) message port offset for 44h model */ 40*382fe403SShyam Sundar S K #define AMD_GNR_REGISTER_MESSAGE 0x524 41*382fe403SShyam Sundar S K #define AMD_GNR_REGISTER_RESPONSE 0x570 42*382fe403SShyam Sundar S K #define AMD_GNR_REGISTER_ARGUMENT 0xA40 43*382fe403SShyam Sundar S K 440e914063SShyam Sundar S K static bool enable_stb; 450e914063SShyam Sundar S K module_param(enable_stb, bool, 0644); 460e914063SShyam Sundar S K MODULE_PARM_DESC(enable_stb, "Enable the STB debug mechanism"); 470e914063SShyam Sundar S K 480e914063SShyam Sundar S K static bool dump_custom_stb; 490e914063SShyam Sundar S K module_param(dump_custom_stb, bool, 0644); 500e914063SShyam Sundar S K MODULE_PARM_DESC(dump_custom_stb, "Enable to dump full STB buffer"); 510e914063SShyam Sundar S K 520e914063SShyam Sundar S K enum s2d_arg { 530e914063SShyam Sundar S K S2D_TELEMETRY_SIZE = 0x01, 540e914063SShyam Sundar S K S2D_PHYS_ADDR_LOW, 550e914063SShyam Sundar S K S2D_PHYS_ADDR_HIGH, 560e914063SShyam Sundar S K S2D_NUM_SAMPLES, 570e914063SShyam Sundar S K S2D_DRAM_SIZE, 580e914063SShyam Sundar S K }; 590e914063SShyam Sundar S K 6000a8d002SShyam Sundar S K struct amd_stb_v2_data { 610e914063SShyam Sundar S K size_t size; 620e914063SShyam Sundar S K u8 data[] __counted_by(size); 630e914063SShyam Sundar S K }; 640e914063SShyam Sundar S K 6500a8d002SShyam Sundar S K int amd_stb_write(struct amd_pmc_dev *dev, u32 data) 660e914063SShyam Sundar S K { 670e914063SShyam Sundar S K int err; 680e914063SShyam Sundar S K 6900a8d002SShyam Sundar S K err = amd_smn_write(0, AMD_STB_PMI_0, data); 700e914063SShyam Sundar S K if (err) { 7100a8d002SShyam Sundar S K dev_err(dev->dev, "failed to write data in stb: 0x%X\n", AMD_STB_PMI_0); 720e914063SShyam Sundar S K return pcibios_err_to_errno(err); 730e914063SShyam Sundar S K } 740e914063SShyam Sundar S K 750e914063SShyam Sundar S K return 0; 760e914063SShyam Sundar S K } 770e914063SShyam Sundar S K 7800a8d002SShyam Sundar S K int amd_stb_read(struct amd_pmc_dev *dev, u32 *buf) 790e914063SShyam Sundar S K { 800e914063SShyam Sundar S K int i, err; 810e914063SShyam Sundar S K 820e914063SShyam Sundar S K for (i = 0; i < FIFO_SIZE; i++) { 8300a8d002SShyam Sundar S K err = amd_smn_read(0, AMD_STB_PMI_0, buf++); 840e914063SShyam Sundar S K if (err) { 8500a8d002SShyam Sundar S K dev_err(dev->dev, "error reading data from stb: 0x%X\n", AMD_STB_PMI_0); 860e914063SShyam Sundar S K return pcibios_err_to_errno(err); 870e914063SShyam Sundar S K } 880e914063SShyam Sundar S K } 890e914063SShyam Sundar S K 900e914063SShyam Sundar S K return 0; 910e914063SShyam Sundar S K } 920e914063SShyam Sundar S K 9300a8d002SShyam Sundar S K static int amd_stb_debugfs_open(struct inode *inode, struct file *filp) 940e914063SShyam Sundar S K { 950e914063SShyam Sundar S K struct amd_pmc_dev *dev = filp->f_inode->i_private; 960e914063SShyam Sundar S K u32 size = FIFO_SIZE * sizeof(u32); 970e914063SShyam Sundar S K u32 *buf; 980e914063SShyam Sundar S K int rc; 990e914063SShyam Sundar S K 1000e914063SShyam Sundar S K buf = kzalloc(size, GFP_KERNEL); 1010e914063SShyam Sundar S K if (!buf) 1020e914063SShyam Sundar S K return -ENOMEM; 1030e914063SShyam Sundar S K 10400a8d002SShyam Sundar S K rc = amd_stb_read(dev, buf); 1050e914063SShyam Sundar S K if (rc) { 1060e914063SShyam Sundar S K kfree(buf); 1070e914063SShyam Sundar S K return rc; 1080e914063SShyam Sundar S K } 1090e914063SShyam Sundar S K 1100e914063SShyam Sundar S K filp->private_data = buf; 1110e914063SShyam Sundar S K return rc; 1120e914063SShyam Sundar S K } 1130e914063SShyam Sundar S K 11400a8d002SShyam Sundar S K static ssize_t amd_stb_debugfs_read(struct file *filp, char __user *buf, size_t size, loff_t *pos) 1150e914063SShyam Sundar S K { 1160e914063SShyam Sundar S K if (!filp->private_data) 1170e914063SShyam Sundar S K return -EINVAL; 1180e914063SShyam Sundar S K 1190e914063SShyam Sundar S K return simple_read_from_buffer(buf, size, pos, filp->private_data, 1200e914063SShyam Sundar S K FIFO_SIZE * sizeof(u32)); 1210e914063SShyam Sundar S K } 1220e914063SShyam Sundar S K 12300a8d002SShyam Sundar S K static int amd_stb_debugfs_release(struct inode *inode, struct file *filp) 1240e914063SShyam Sundar S K { 1250e914063SShyam Sundar S K kfree(filp->private_data); 1260e914063SShyam Sundar S K return 0; 1270e914063SShyam Sundar S K } 1280e914063SShyam Sundar S K 12900a8d002SShyam Sundar S K static const struct file_operations amd_stb_debugfs_fops = { 1300e914063SShyam Sundar S K .owner = THIS_MODULE, 13100a8d002SShyam Sundar S K .open = amd_stb_debugfs_open, 13200a8d002SShyam Sundar S K .read = amd_stb_debugfs_read, 13300a8d002SShyam Sundar S K .release = amd_stb_debugfs_release, 1340e914063SShyam Sundar S K }; 1350e914063SShyam Sundar S K 1360e914063SShyam Sundar S K /* Enhanced STB Firmware Reporting Mechanism */ 13700a8d002SShyam Sundar S K static int amd_stb_handle_efr(struct file *filp) 1380e914063SShyam Sundar S K { 1390e914063SShyam Sundar S K struct amd_pmc_dev *dev = filp->f_inode->i_private; 14000a8d002SShyam Sundar S K struct amd_stb_v2_data *stb_data_arr; 1410e914063SShyam Sundar S K u32 fsize; 1420e914063SShyam Sundar S K 1430e914063SShyam Sundar S K fsize = dev->dram_size - S2D_RSVD_RAM_SPACE; 1440e914063SShyam Sundar S K stb_data_arr = kmalloc(struct_size(stb_data_arr, data, fsize), GFP_KERNEL); 1450e914063SShyam Sundar S K if (!stb_data_arr) 1460e914063SShyam Sundar S K return -ENOMEM; 1470e914063SShyam Sundar S K 1480e914063SShyam Sundar S K stb_data_arr->size = fsize; 1490e914063SShyam Sundar S K memcpy_fromio(stb_data_arr->data, dev->stb_virt_addr, fsize); 1500e914063SShyam Sundar S K filp->private_data = stb_data_arr; 1510e914063SShyam Sundar S K 1520e914063SShyam Sundar S K return 0; 1530e914063SShyam Sundar S K } 1540e914063SShyam Sundar S K 15500a8d002SShyam Sundar S K static int amd_stb_debugfs_open_v2(struct inode *inode, struct file *filp) 1560e914063SShyam Sundar S K { 1570e914063SShyam Sundar S K struct amd_pmc_dev *dev = filp->f_inode->i_private; 1580e914063SShyam Sundar S K u32 fsize, num_samples, val, stb_rdptr_offset = 0; 15900a8d002SShyam Sundar S K struct amd_stb_v2_data *stb_data_arr; 1600e914063SShyam Sundar S K int ret; 1610e914063SShyam Sundar S K 1620e914063SShyam Sundar S K /* Write dummy postcode while reading the STB buffer */ 16300a8d002SShyam Sundar S K ret = amd_stb_write(dev, AMD_PMC_STB_DUMMY_PC); 1640e914063SShyam Sundar S K if (ret) 1650e914063SShyam Sundar S K dev_err(dev->dev, "error writing to STB: %d\n", ret); 1660e914063SShyam Sundar S K 1670e914063SShyam Sundar S K /* Spill to DRAM num_samples uses separate SMU message port */ 1682851f4f8SShyam Sundar S K dev->msg_port = MSG_PORT_S2D; 1690e914063SShyam Sundar S K 1700e914063SShyam Sundar S K ret = amd_pmc_send_cmd(dev, 0, &val, STB_FORCE_FLUSH_DATA, 1); 1710e914063SShyam Sundar S K if (ret) 1720e914063SShyam Sundar S K dev_dbg_once(dev->dev, "S2D force flush not supported: %d\n", ret); 1730e914063SShyam Sundar S K 1740e914063SShyam Sundar S K /* 1750e914063SShyam Sundar S K * We have a custom stb size and the PMFW is supposed to give 1760e914063SShyam Sundar S K * the enhanced dram size. Note that we land here only for the 1770e914063SShyam Sundar S K * platforms that support enhanced dram size reporting. 1780e914063SShyam Sundar S K */ 1790e914063SShyam Sundar S K if (dump_custom_stb) 18000a8d002SShyam Sundar S K return amd_stb_handle_efr(filp); 1810e914063SShyam Sundar S K 1820e914063SShyam Sundar S K /* Get the num_samples to calculate the last push location */ 1833279f7a6SShyam Sundar S K ret = amd_pmc_send_cmd(dev, S2D_NUM_SAMPLES, &num_samples, dev->stb_arg.s2d_msg_id, true); 1840e914063SShyam Sundar S K /* Clear msg_port for other SMU operation */ 1852851f4f8SShyam Sundar S K dev->msg_port = MSG_PORT_PMC; 1860e914063SShyam Sundar S K if (ret) { 1870e914063SShyam Sundar S K dev_err(dev->dev, "error: S2D_NUM_SAMPLES not supported : %d\n", ret); 1880e914063SShyam Sundar S K return ret; 1890e914063SShyam Sundar S K } 1900e914063SShyam Sundar S K 1910e914063SShyam Sundar S K fsize = min(num_samples, S2D_TELEMETRY_BYTES_MAX); 1920e914063SShyam Sundar S K stb_data_arr = kmalloc(struct_size(stb_data_arr, data, fsize), GFP_KERNEL); 1930e914063SShyam Sundar S K if (!stb_data_arr) 1940e914063SShyam Sundar S K return -ENOMEM; 1950e914063SShyam Sundar S K 1960e914063SShyam Sundar S K stb_data_arr->size = fsize; 1970e914063SShyam Sundar S K 1980e914063SShyam Sundar S K /* 1990e914063SShyam Sundar S K * Start capturing data from the last push location. 2000e914063SShyam Sundar S K * This is for general cases, where the stb limits 2010e914063SShyam Sundar S K * are meant for standard usage. 2020e914063SShyam Sundar S K */ 2030e914063SShyam Sundar S K if (num_samples > S2D_TELEMETRY_BYTES_MAX) { 2040e914063SShyam Sundar S K /* First read oldest data starting 1 behind last write till end of ringbuffer */ 2050e914063SShyam Sundar S K stb_rdptr_offset = num_samples % S2D_TELEMETRY_BYTES_MAX; 2060e914063SShyam Sundar S K fsize = S2D_TELEMETRY_BYTES_MAX - stb_rdptr_offset; 2070e914063SShyam Sundar S K 2080e914063SShyam Sundar S K memcpy_fromio(stb_data_arr->data, dev->stb_virt_addr + stb_rdptr_offset, fsize); 2090e914063SShyam Sundar S K /* Second copy the newer samples from offset 0 - last write */ 2100e914063SShyam Sundar S K memcpy_fromio(stb_data_arr->data + fsize, dev->stb_virt_addr, stb_rdptr_offset); 2110e914063SShyam Sundar S K } else { 2120e914063SShyam Sundar S K memcpy_fromio(stb_data_arr->data, dev->stb_virt_addr, fsize); 2130e914063SShyam Sundar S K } 2140e914063SShyam Sundar S K 2150e914063SShyam Sundar S K filp->private_data = stb_data_arr; 2160e914063SShyam Sundar S K 2170e914063SShyam Sundar S K return 0; 2180e914063SShyam Sundar S K } 2190e914063SShyam Sundar S K 22000a8d002SShyam Sundar S K static ssize_t amd_stb_debugfs_read_v2(struct file *filp, char __user *buf, size_t size, 2210e914063SShyam Sundar S K loff_t *pos) 2220e914063SShyam Sundar S K { 22300a8d002SShyam Sundar S K struct amd_stb_v2_data *data = filp->private_data; 2240e914063SShyam Sundar S K 2250e914063SShyam Sundar S K return simple_read_from_buffer(buf, size, pos, data->data, data->size); 2260e914063SShyam Sundar S K } 2270e914063SShyam Sundar S K 22800a8d002SShyam Sundar S K static int amd_stb_debugfs_release_v2(struct inode *inode, struct file *filp) 2290e914063SShyam Sundar S K { 2300e914063SShyam Sundar S K kfree(filp->private_data); 2310e914063SShyam Sundar S K return 0; 2320e914063SShyam Sundar S K } 2330e914063SShyam Sundar S K 23400a8d002SShyam Sundar S K static const struct file_operations amd_stb_debugfs_fops_v2 = { 2350e914063SShyam Sundar S K .owner = THIS_MODULE, 23600a8d002SShyam Sundar S K .open = amd_stb_debugfs_open_v2, 23700a8d002SShyam Sundar S K .read = amd_stb_debugfs_read_v2, 23800a8d002SShyam Sundar S K .release = amd_stb_debugfs_release_v2, 2390e914063SShyam Sundar S K }; 2400e914063SShyam Sundar S K 241*382fe403SShyam Sundar S K static void amd_stb_update_args(struct amd_pmc_dev *dev) 242*382fe403SShyam Sundar S K { 243*382fe403SShyam Sundar S K if (cpu_feature_enabled(X86_FEATURE_ZEN5)) 244*382fe403SShyam Sundar S K switch (boot_cpu_data.x86_model) { 245*382fe403SShyam Sundar S K case 0x44: 246*382fe403SShyam Sundar S K dev->stb_arg.msg = AMD_GNR_REGISTER_MESSAGE; 247*382fe403SShyam Sundar S K dev->stb_arg.arg = AMD_GNR_REGISTER_ARGUMENT; 248*382fe403SShyam Sundar S K dev->stb_arg.resp = AMD_GNR_REGISTER_RESPONSE; 249*382fe403SShyam Sundar S K return; 250*382fe403SShyam Sundar S K default: 251*382fe403SShyam Sundar S K break; 252*382fe403SShyam Sundar S K } 253*382fe403SShyam Sundar S K 254*382fe403SShyam Sundar S K dev->stb_arg.msg = AMD_S2D_REGISTER_MESSAGE; 255*382fe403SShyam Sundar S K dev->stb_arg.arg = AMD_S2D_REGISTER_ARGUMENT; 256*382fe403SShyam Sundar S K dev->stb_arg.resp = AMD_S2D_REGISTER_RESPONSE; 257*382fe403SShyam Sundar S K } 258*382fe403SShyam Sundar S K 25900a8d002SShyam Sundar S K static bool amd_is_stb_supported(struct amd_pmc_dev *dev) 2600e914063SShyam Sundar S K { 2610e914063SShyam Sundar S K switch (dev->cpu_id) { 2620e914063SShyam Sundar S K case AMD_CPU_ID_YC: 2630e914063SShyam Sundar S K case AMD_CPU_ID_CB: 264*382fe403SShyam Sundar S K if (boot_cpu_data.x86_model == 0x44) 265*382fe403SShyam Sundar S K dev->stb_arg.s2d_msg_id = 0x9B; 266*382fe403SShyam Sundar S K else 2673279f7a6SShyam Sundar S K dev->stb_arg.s2d_msg_id = 0xBE; 2683279f7a6SShyam Sundar S K break; 2690e914063SShyam Sundar S K case AMD_CPU_ID_PS: 2703279f7a6SShyam Sundar S K dev->stb_arg.s2d_msg_id = 0x85; 2713279f7a6SShyam Sundar S K break; 2720e914063SShyam Sundar S K case PCI_DEVICE_ID_AMD_1AH_M20H_ROOT: 2730e914063SShyam Sundar S K case PCI_DEVICE_ID_AMD_1AH_M60H_ROOT: 2744aeca317SShyam Sundar S K if (boot_cpu_data.x86_model == 0x70) 2754aeca317SShyam Sundar S K dev->stb_arg.s2d_msg_id = 0xF1; 2764aeca317SShyam Sundar S K else 2773279f7a6SShyam Sundar S K dev->stb_arg.s2d_msg_id = 0xDE; 2783279f7a6SShyam Sundar S K break; 2790e914063SShyam Sundar S K default: 2800e914063SShyam Sundar S K return false; 2810e914063SShyam Sundar S K } 2823279f7a6SShyam Sundar S K 283*382fe403SShyam Sundar S K amd_stb_update_args(dev); 2843279f7a6SShyam Sundar S K return true; 2850e914063SShyam Sundar S K } 2860e914063SShyam Sundar S K 28700a8d002SShyam Sundar S K int amd_stb_s2d_init(struct amd_pmc_dev *dev) 2880e914063SShyam Sundar S K { 2890e914063SShyam Sundar S K u32 phys_addr_low, phys_addr_hi; 2900e914063SShyam Sundar S K u64 stb_phys_addr; 2910e914063SShyam Sundar S K u32 size = 0; 2920e914063SShyam Sundar S K int ret; 2930e914063SShyam Sundar S K 2940e914063SShyam Sundar S K if (!enable_stb) 2950e914063SShyam Sundar S K return 0; 2960e914063SShyam Sundar S K 29700a8d002SShyam Sundar S K if (amd_is_stb_supported(dev)) { 2980e914063SShyam Sundar S K debugfs_create_file("stb_read", 0644, dev->dbgfs_dir, dev, 29900a8d002SShyam Sundar S K &amd_stb_debugfs_fops_v2); 3000e914063SShyam Sundar S K } else { 3010e914063SShyam Sundar S K debugfs_create_file("stb_read", 0644, dev->dbgfs_dir, dev, 30200a8d002SShyam Sundar S K &amd_stb_debugfs_fops); 3030e914063SShyam Sundar S K return 0; 3040e914063SShyam Sundar S K } 3050e914063SShyam Sundar S K 3060e914063SShyam Sundar S K /* Spill to DRAM feature uses separate SMU message port */ 3072851f4f8SShyam Sundar S K dev->msg_port = MSG_PORT_S2D; 3080e914063SShyam Sundar S K 3093279f7a6SShyam Sundar S K amd_pmc_send_cmd(dev, S2D_TELEMETRY_SIZE, &size, dev->stb_arg.s2d_msg_id, true); 3100e914063SShyam Sundar S K if (size != S2D_TELEMETRY_BYTES_MAX) 3110e914063SShyam Sundar S K return -EIO; 3120e914063SShyam Sundar S K 3130e914063SShyam Sundar S K /* Get DRAM size */ 3143279f7a6SShyam Sundar S K ret = amd_pmc_send_cmd(dev, S2D_DRAM_SIZE, &dev->dram_size, dev->stb_arg.s2d_msg_id, true); 3150e914063SShyam Sundar S K if (ret || !dev->dram_size) 3160e914063SShyam Sundar S K dev->dram_size = S2D_TELEMETRY_DRAMBYTES_MAX; 3170e914063SShyam Sundar S K 3180e914063SShyam Sundar S K /* Get STB DRAM address */ 3193279f7a6SShyam Sundar S K amd_pmc_send_cmd(dev, S2D_PHYS_ADDR_LOW, &phys_addr_low, dev->stb_arg.s2d_msg_id, true); 3203279f7a6SShyam Sundar S K amd_pmc_send_cmd(dev, S2D_PHYS_ADDR_HIGH, &phys_addr_hi, dev->stb_arg.s2d_msg_id, true); 3210e914063SShyam Sundar S K 3220e914063SShyam Sundar S K stb_phys_addr = ((u64)phys_addr_hi << 32 | phys_addr_low); 3230e914063SShyam Sundar S K 3240e914063SShyam Sundar S K /* Clear msg_port for other SMU operation */ 3252851f4f8SShyam Sundar S K dev->msg_port = MSG_PORT_PMC; 3260e914063SShyam Sundar S K 3270e914063SShyam Sundar S K dev->stb_virt_addr = devm_ioremap(dev->dev, stb_phys_addr, dev->dram_size); 3280e914063SShyam Sundar S K if (!dev->stb_virt_addr) 3290e914063SShyam Sundar S K return -ENOMEM; 3300e914063SShyam Sundar S K 3310e914063SShyam Sundar S K return 0; 3320e914063SShyam Sundar S K } 333