Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

platform/x86/amd/pmc: Add AMD MP2 STB functionality

AMD MP2 STB function provides a data buffer used to log debug information
about the system execution during S2Idle suspend/resume.

A data buffer known as the STB (Smart Trace Buffer) is a circular buffer
which is a low-level log to assist in debugging by providing insights
into any potential hangs or stalls that may occur during the S2Idle
suspend/resume processes.

The current PMC driver retrieves STB data from MP1, but there can be
scenarios where MP1 might hang or become unresponsive, leading to the
loss of critical data present in the STB buffer. This defeats the purpose
of the STB buffer, which was originally meant to help identify system
failures.

This feature creates stb_read_previous_boot debugfs allows users to
retrieve the STB log from MP2 specifically from the last occurrence of
the S2Idle suspend/resume. A userspace daemon can access STB log of last
S2Idle suspend/resume which can help to troubleshoot potential issues
related to hangs or stalls during the S2Idle suspend/resume sequence.

Reviewed-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
Signed-off-by: Basavaraj Natikar <Basavaraj.Natikar@amd.com>
Reviewed-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
Link: https://lore.kernel.org/r/20240404090702.325838-1-Basavaraj.Natikar@amd.com
Signed-off-by: Hans de Goede <hdegoede@redhat.com>

authored by

Basavaraj Natikar and committed by
Hans de Goede
2dc77993 07f48f66

+314
+15
drivers/platform/x86/amd/pmc/Kconfig
··· 18 18 19 19 If you choose to compile this driver as a module the module will be 20 20 called amd-pmc. 21 + 22 + config AMD_MP2_STB 23 + bool "AMD SoC MP2 STB function" 24 + depends on AMD_PMC 25 + default AMD_PMC 26 + help 27 + AMD MP2 STB function provides a data buffer used to log debug 28 + information about the system execution during S2Idle suspend/resume. 29 + A data buffer known as the STB (Smart Trace Buffer) is a circular 30 + buffer which is a low-level log for the SoC which is used to debug 31 + any hangs/stalls during S2Idle suspend/resume. 32 + 33 + Creates debugfs to get STB, a userspace daemon can access STB log of 34 + last S2Idle suspend/resume which can help to debug if hangs/stalls 35 + during S2Idle suspend/resume.
+1
drivers/platform/x86/amd/pmc/Makefile
··· 6 6 7 7 amd-pmc-objs := pmc.o pmc-quirks.o 8 8 obj-$(CONFIG_AMD_PMC) += amd-pmc.o 9 + amd-pmc-$(CONFIG_AMD_MP2_STB) += mp2_stb.o
+279
drivers/platform/x86/amd/pmc/mp2_stb.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * AMD MP2 STB layer 4 + * 5 + * Copyright (c) 2024, Advanced Micro Devices, Inc. 6 + * All Rights Reserved. 7 + * 8 + * Author: Basavaraj Natikar <Basavaraj.Natikar@amd.com> 9 + */ 10 + 11 + #include <linux/debugfs.h> 12 + #include <linux/device.h> 13 + #include <linux/io.h> 14 + #include <linux/iopoll.h> 15 + #include <linux/pci.h> 16 + #include <linux/sizes.h> 17 + #include <linux/time.h> 18 + 19 + #include "pmc.h" 20 + 21 + #define VALID_MSG 0xA 22 + #define VALID_RESPONSE 2 23 + 24 + #define AMD_C2P_MSG0 0x10500 25 + #define AMD_C2P_MSG1 0x10504 26 + #define AMD_P2C_MSG0 0x10680 27 + #define AMD_P2C_MSG1 0x10684 28 + 29 + #define MP2_RESP_SLEEP_US 500 30 + #define MP2_RESP_TIMEOUT_US (1600 * USEC_PER_MSEC) 31 + 32 + #define MP2_STB_DATA_LEN_2KB 1 33 + #define MP2_STB_DATA_LEN_16KB 4 34 + 35 + #define MP2_MMIO_BAR 2 36 + 37 + struct mp2_cmd_base { 38 + union { 39 + u32 ul; 40 + struct { 41 + u32 cmd_id : 4; 42 + u32 intr_disable : 1; 43 + u32 is_dma_used : 1; 44 + u32 rsvd : 26; 45 + } field; 46 + }; 47 + }; 48 + 49 + struct mp2_cmd_response { 50 + union { 51 + u32 resp; 52 + struct { 53 + u32 cmd_id : 4; 54 + u32 status : 4; 55 + u32 response : 4; 56 + u32 rsvd2 : 20; 57 + } field; 58 + }; 59 + }; 60 + 61 + struct mp2_stb_data_valid { 62 + union { 63 + u32 data_valid; 64 + struct { 65 + u32 valid : 16; 66 + u32 length : 16; 67 + } val; 68 + }; 69 + }; 70 + 71 + static int amd_mp2_wait_response(struct amd_mp2_dev *mp2, u8 cmd_id, u32 command_sts) 72 + { 73 + struct mp2_cmd_response cmd_resp; 74 + 75 + if (!readl_poll_timeout(mp2->mmio + AMD_P2C_MSG0, cmd_resp.resp, 76 + (cmd_resp.field.response == 0x0 && 77 + cmd_resp.field.status == command_sts && 78 + cmd_resp.field.cmd_id == cmd_id), MP2_RESP_SLEEP_US, 79 + MP2_RESP_TIMEOUT_US)) 80 + return cmd_resp.field.status; 81 + 82 + return -ETIMEDOUT; 83 + } 84 + 85 + static void amd_mp2_stb_send_cmd(struct amd_mp2_dev *mp2, u8 cmd_id, bool is_dma_used) 86 + { 87 + struct mp2_cmd_base cmd_base; 88 + 89 + cmd_base.ul = 0; 90 + cmd_base.field.cmd_id = cmd_id; 91 + cmd_base.field.intr_disable = 1; 92 + cmd_base.field.is_dma_used = is_dma_used; 93 + 94 + writeq(mp2->dma_addr, mp2->mmio + AMD_C2P_MSG1); 95 + writel(cmd_base.ul, mp2->mmio + AMD_C2P_MSG0); 96 + } 97 + 98 + static int amd_mp2_stb_region(struct amd_mp2_dev *mp2) 99 + { 100 + struct device *dev = &mp2->pdev->dev; 101 + unsigned int len = mp2->stb_len; 102 + 103 + if (!mp2->stbdata) { 104 + mp2->vslbase = dmam_alloc_coherent(dev, len, &mp2->dma_addr, GFP_KERNEL); 105 + if (!mp2->vslbase) 106 + return -ENOMEM; 107 + 108 + mp2->stbdata = devm_kzalloc(dev, len, GFP_KERNEL); 109 + if (!mp2->stbdata) 110 + return -ENOMEM; 111 + } 112 + 113 + return 0; 114 + } 115 + 116 + static int amd_mp2_process_cmd(struct amd_mp2_dev *mp2, struct file *filp) 117 + { 118 + struct device *dev = &mp2->pdev->dev; 119 + struct mp2_stb_data_valid stb_dv; 120 + int status; 121 + 122 + stb_dv.data_valid = readl(mp2->mmio + AMD_P2C_MSG1); 123 + 124 + if (stb_dv.val.valid != VALID_MSG) { 125 + dev_dbg(dev, "Invalid STB data\n"); 126 + return -EBADMSG; 127 + } 128 + 129 + if (stb_dv.val.length != MP2_STB_DATA_LEN_2KB && 130 + stb_dv.val.length != MP2_STB_DATA_LEN_16KB) { 131 + dev_dbg(dev, "Unsupported length\n"); 132 + return -EMSGSIZE; 133 + } 134 + 135 + mp2->stb_len = BIT(stb_dv.val.length) * SZ_1K; 136 + 137 + status = amd_mp2_stb_region(mp2); 138 + if (status) { 139 + dev_err(dev, "Failed to init STB region, status %d\n", status); 140 + return status; 141 + } 142 + 143 + amd_mp2_stb_send_cmd(mp2, VALID_MSG, true); 144 + status = amd_mp2_wait_response(mp2, VALID_MSG, VALID_RESPONSE); 145 + if (status == VALID_RESPONSE) { 146 + memcpy_fromio(mp2->stbdata, mp2->vslbase, mp2->stb_len); 147 + filp->private_data = mp2->stbdata; 148 + mp2->is_stb_data = true; 149 + } else { 150 + dev_err(dev, "Failed to start STB dump, status %d\n", status); 151 + return -EOPNOTSUPP; 152 + } 153 + 154 + return 0; 155 + } 156 + 157 + static int amd_mp2_stb_debugfs_open(struct inode *inode, struct file *filp) 158 + { 159 + struct amd_pmc_dev *dev = filp->f_inode->i_private; 160 + struct amd_mp2_dev *mp2 = dev->mp2; 161 + 162 + if (mp2) { 163 + if (!mp2->is_stb_data) 164 + return amd_mp2_process_cmd(mp2, filp); 165 + 166 + filp->private_data = mp2->stbdata; 167 + 168 + return 0; 169 + } 170 + 171 + return -ENODEV; 172 + } 173 + 174 + static ssize_t amd_mp2_stb_debugfs_read(struct file *filp, char __user *buf, size_t size, 175 + loff_t *pos) 176 + { 177 + struct amd_pmc_dev *dev = filp->f_inode->i_private; 178 + struct amd_mp2_dev *mp2 = dev->mp2; 179 + 180 + if (!mp2) 181 + return -ENODEV; 182 + 183 + if (!filp->private_data) 184 + return -EINVAL; 185 + 186 + return simple_read_from_buffer(buf, size, pos, filp->private_data, mp2->stb_len); 187 + } 188 + 189 + static const struct file_operations amd_mp2_stb_debugfs_fops = { 190 + .owner = THIS_MODULE, 191 + .open = amd_mp2_stb_debugfs_open, 192 + .read = amd_mp2_stb_debugfs_read, 193 + }; 194 + 195 + static void amd_mp2_dbgfs_register(struct amd_pmc_dev *dev) 196 + { 197 + if (!dev->dbgfs_dir) 198 + return; 199 + 200 + debugfs_create_file("stb_read_previous_boot", 0644, dev->dbgfs_dir, dev, 201 + &amd_mp2_stb_debugfs_fops); 202 + } 203 + 204 + void amd_mp2_stb_deinit(struct amd_pmc_dev *dev) 205 + { 206 + struct amd_mp2_dev *mp2 = dev->mp2; 207 + struct pci_dev *pdev; 208 + 209 + if (mp2 && mp2->pdev) { 210 + pdev = mp2->pdev; 211 + 212 + if (mp2->mmio) 213 + pci_clear_master(pdev); 214 + 215 + pci_dev_put(pdev); 216 + 217 + if (mp2->devres_gid) 218 + devres_release_group(&pdev->dev, mp2->devres_gid); 219 + 220 + dev->mp2 = NULL; 221 + } 222 + } 223 + 224 + void amd_mp2_stb_init(struct amd_pmc_dev *dev) 225 + { 226 + struct amd_mp2_dev *mp2 = NULL; 227 + struct pci_dev *pdev; 228 + int rc; 229 + 230 + mp2 = devm_kzalloc(dev->dev, sizeof(*mp2), GFP_KERNEL); 231 + if (!mp2) 232 + return; 233 + 234 + pdev = pci_get_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_MP2_STB, NULL); 235 + if (!pdev) 236 + return; 237 + 238 + dev->mp2 = mp2; 239 + mp2->pdev = pdev; 240 + 241 + mp2->devres_gid = devres_open_group(&pdev->dev, NULL, GFP_KERNEL); 242 + if (!mp2->devres_gid) { 243 + dev_err(&pdev->dev, "devres_open_group failed\n"); 244 + goto mp2_error; 245 + } 246 + 247 + rc = pcim_enable_device(pdev); 248 + if (rc) { 249 + dev_err(&pdev->dev, "pcim_enable_device failed\n"); 250 + goto mp2_error; 251 + } 252 + 253 + rc = pcim_iomap_regions(pdev, BIT(MP2_MMIO_BAR), "mp2 stb"); 254 + if (rc) { 255 + dev_err(&pdev->dev, "pcim_iomap_regions failed\n"); 256 + goto mp2_error; 257 + } 258 + 259 + mp2->mmio = pcim_iomap_table(pdev)[MP2_MMIO_BAR]; 260 + if (!mp2->mmio) { 261 + dev_err(&pdev->dev, "pcim_iomap_table failed\n"); 262 + goto mp2_error; 263 + } 264 + 265 + pci_set_master(pdev); 266 + 267 + rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); 268 + if (rc) { 269 + dev_err(&pdev->dev, "failed to set DMA mask\n"); 270 + goto mp2_error; 271 + } 272 + 273 + amd_mp2_dbgfs_register(dev); 274 + 275 + return; 276 + 277 + mp2_error: 278 + amd_mp2_stb_deinit(dev); 279 + }
+4
drivers/platform/x86/amd/pmc/pmc.c
··· 1106 1106 } 1107 1107 1108 1108 amd_pmc_dbgfs_register(dev); 1109 + if (IS_ENABLED(CONFIG_AMD_MP2_STB)) 1110 + amd_mp2_stb_init(dev); 1109 1111 pm_report_max_hw_sleep(U64_MAX); 1110 1112 return 0; 1111 1113 ··· 1124 1122 acpi_unregister_lps0_dev(&amd_pmc_s2idle_dev_ops); 1125 1123 amd_pmc_dbgfs_unregister(dev); 1126 1124 pci_dev_put(dev->rdev); 1125 + if (IS_ENABLED(CONFIG_AMD_MP2_STB)) 1126 + amd_mp2_stb_deinit(dev); 1127 1127 mutex_destroy(&dev->lock); 1128 1128 } 1129 1129
+15
drivers/platform/x86/amd/pmc/pmc.h
··· 14 14 #include <linux/types.h> 15 15 #include <linux/mutex.h> 16 16 17 + struct amd_mp2_dev { 18 + void __iomem *mmio; 19 + void __iomem *vslbase; 20 + void *stbdata; 21 + void *devres_gid; 22 + struct pci_dev *pdev; 23 + dma_addr_t dma_addr; 24 + int stb_len; 25 + bool is_stb_data; 26 + }; 27 + 17 28 struct amd_pmc_dev { 18 29 void __iomem *regbase; 19 30 void __iomem *smu_virt_addr; ··· 49 38 struct dentry *dbgfs_dir; 50 39 struct quirk_entry *quirks; 51 40 bool disable_8042_wakeup; 41 + struct amd_mp2_dev *mp2; 52 42 }; 53 43 54 44 void amd_pmc_process_restore_quirks(struct amd_pmc_dev *dev); 55 45 void amd_pmc_quirks_init(struct amd_pmc_dev *dev); 46 + void amd_mp2_stb_init(struct amd_pmc_dev *dev); 47 + void amd_mp2_stb_deinit(struct amd_pmc_dev *dev); 56 48 57 49 /* List of supported CPU ids */ 58 50 #define AMD_CPU_ID_RV 0x15D0 ··· 67 53 #define AMD_CPU_ID_PS 0x14E8 68 54 #define AMD_CPU_ID_SP 0x14A4 69 55 #define PCI_DEVICE_ID_AMD_1AH_M20H_ROOT 0x1507 56 + #define PCI_DEVICE_ID_AMD_MP2_STB 0x172c 70 57 71 58 #endif /* PMC_H */