File Index
Files and directories
Sign in
FILE

mp1_stb.c

File preview with syntax highlighting.

linux-6.19.14/drivers/platform/x86/amd/pmc/mp1_stb.c C
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * AMD MP1 Smart Trace Buffer (STB) Layer
  4 *
  5 * Copyright (c) 2024, Advanced Micro Devices, Inc.
  6 * All Rights Reserved.
  7 *
  8 * Authors: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
  9 *          Sanket Goswami <Sanket.Goswami@amd.com>
 10 */
 11
 12#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 13
 14#include <asm/amd/nb.h>
 15#include <linux/debugfs.h>
 16#include <linux/seq_file.h>
 17#include <linux/uaccess.h>
 18
 19#include "pmc.h"
 20
 21/* STB Spill to DRAM Parameters */
 22#define S2D_TELEMETRY_DRAMBYTES_MAX	0x1000000
 23#define S2D_TELEMETRY_BYTES_MAX		0x100000U
 24#define S2D_RSVD_RAM_SPACE		0x100000
 25
 26/* STB Registers */
 27#define AMD_STB_PMI_0			0x03E30600
 28#define AMD_PMC_STB_DUMMY_PC	0xC6000007
 29
 30/* STB Spill to DRAM Message Definition */
 31#define STB_FORCE_FLUSH_DATA		0xCF
 32#define FIFO_SIZE		4096
 33
 34/* STB S2D(Spill to DRAM) has different message port offset */
 35#define AMD_S2D_REGISTER_MESSAGE	0xA20
 36#define AMD_S2D_REGISTER_RESPONSE	0xA80
 37#define AMD_S2D_REGISTER_ARGUMENT	0xA88
 38
 39/* STB S2D (Spill to DRAM) message port offset for 44h model */
 40#define AMD_GNR_REGISTER_MESSAGE	0x524
 41#define AMD_GNR_REGISTER_RESPONSE	0x570
 42#define AMD_GNR_REGISTER_ARGUMENT	0xA40
 43
 44static bool enable_stb;
 45module_param(enable_stb, bool, 0644);
 46MODULE_PARM_DESC(enable_stb, "Enable the STB debug mechanism");
 47
 48static bool dump_custom_stb;
 49module_param(dump_custom_stb, bool, 0644);
 50MODULE_PARM_DESC(dump_custom_stb, "Enable to dump full STB buffer");
 51
 52enum s2d_arg {
 53	S2D_TELEMETRY_SIZE = 0x01,
 54	S2D_PHYS_ADDR_LOW,
 55	S2D_PHYS_ADDR_HIGH,
 56	S2D_NUM_SAMPLES,
 57	S2D_DRAM_SIZE,
 58};
 59
 60struct amd_stb_v2_data {
 61	size_t size;
 62	u8 data[] __counted_by(size);
 63};
 64
 65int amd_stb_write(struct amd_pmc_dev *dev, u32 data)
 66{
 67	int err;
 68
 69	err = amd_smn_write(0, AMD_STB_PMI_0, data);
 70	if (err) {
 71		dev_err(dev->dev, "failed to write data in stb: 0x%X\n", AMD_STB_PMI_0);
 72		return pcibios_err_to_errno(err);
 73	}
 74
 75	return 0;
 76}
 77
 78int amd_stb_read(struct amd_pmc_dev *dev, u32 *buf)
 79{
 80	int i, err;
 81
 82	for (i = 0; i < FIFO_SIZE; i++) {
 83		err = amd_smn_read(0, AMD_STB_PMI_0, buf++);
 84		if (err) {
 85			dev_err(dev->dev, "error reading data from stb: 0x%X\n", AMD_STB_PMI_0);
 86			return pcibios_err_to_errno(err);
 87		}
 88	}
 89
 90	return 0;
 91}
 92
 93static int amd_stb_debugfs_open(struct inode *inode, struct file *filp)
 94{
 95	struct amd_pmc_dev *dev = filp->f_inode->i_private;
 96	u32 size = FIFO_SIZE * sizeof(u32);
 97	u32 *buf;
 98	int rc;
 99
100	buf = kzalloc(size, GFP_KERNEL);
101	if (!buf)
102		return -ENOMEM;
103
104	rc = amd_stb_read(dev, buf);
105	if (rc) {
106		kfree(buf);
107		return rc;
108	}
109
110	filp->private_data = buf;
111	return rc;
112}
113
114static ssize_t amd_stb_debugfs_read(struct file *filp, char __user *buf, size_t size, loff_t *pos)
115{
116	if (!filp->private_data)
117		return -EINVAL;
118
119	return simple_read_from_buffer(buf, size, pos, filp->private_data,
120				       FIFO_SIZE * sizeof(u32));
121}
122
123static int amd_stb_debugfs_release(struct inode *inode, struct file *filp)
124{
125	kfree(filp->private_data);
126	return 0;
127}
128
129static const struct file_operations amd_stb_debugfs_fops = {
130	.owner = THIS_MODULE,
131	.open = amd_stb_debugfs_open,
132	.read = amd_stb_debugfs_read,
133	.release = amd_stb_debugfs_release,
134};
135
136/* Enhanced STB Firmware Reporting Mechanism */
137static int amd_stb_handle_efr(struct file *filp)
138{
139	struct amd_pmc_dev *dev = filp->f_inode->i_private;
140	struct amd_stb_v2_data *stb_data_arr;
141	u32 fsize;
142
143	fsize = dev->dram_size - S2D_RSVD_RAM_SPACE;
144	stb_data_arr = kmalloc(struct_size(stb_data_arr, data, fsize), GFP_KERNEL);
145	if (!stb_data_arr)
146		return -ENOMEM;
147
148	stb_data_arr->size = fsize;
149	memcpy_fromio(stb_data_arr->data, dev->stb_virt_addr, fsize);
150	filp->private_data = stb_data_arr;
151
152	return 0;
153}
154
155static int amd_stb_debugfs_open_v2(struct inode *inode, struct file *filp)
156{
157	struct amd_pmc_dev *dev = filp->f_inode->i_private;
158	u32 fsize, num_samples, val, stb_rdptr_offset = 0;
159	struct amd_stb_v2_data *stb_data_arr;
160	int ret;
161
162	/* Write dummy postcode while reading the STB buffer */
163	ret = amd_stb_write(dev, AMD_PMC_STB_DUMMY_PC);
164	if (ret)
165		dev_err(dev->dev, "error writing to STB: %d\n", ret);
166
167	/* Spill to DRAM num_samples uses separate SMU message port */
168	dev->msg_port = MSG_PORT_S2D;
169
170	ret = amd_pmc_send_cmd(dev, 0, &val, STB_FORCE_FLUSH_DATA, 1);
171	if (ret)
172		dev_dbg_once(dev->dev, "S2D force flush not supported: %d\n", ret);
173
174	/*
175	 * We have a custom stb size and the PMFW is supposed to give
176	 * the enhanced dram size. Note that we land here only for the
177	 * platforms that support enhanced dram size reporting.
178	 */
179	if (dump_custom_stb)
180		return amd_stb_handle_efr(filp);
181
182	/* Get the num_samples to calculate the last push location */
183	ret = amd_pmc_send_cmd(dev, S2D_NUM_SAMPLES, &num_samples, dev->stb_arg.s2d_msg_id, true);
184	/* Clear msg_port for other SMU operation */
185	dev->msg_port = MSG_PORT_PMC;
186	if (ret) {
187		dev_err(dev->dev, "error: S2D_NUM_SAMPLES not supported : %d\n", ret);
188		return ret;
189	}
190
191	fsize = min(num_samples, S2D_TELEMETRY_BYTES_MAX);
192	stb_data_arr = kmalloc(struct_size(stb_data_arr, data, fsize), GFP_KERNEL);
193	if (!stb_data_arr)
194		return -ENOMEM;
195
196	stb_data_arr->size = fsize;
197
198	/*
199	 * Start capturing data from the last push location.
200	 * This is for general cases, where the stb limits
201	 * are meant for standard usage.
202	 */
203	if (num_samples > S2D_TELEMETRY_BYTES_MAX) {
204		/* First read oldest data starting 1 behind last write till end of ringbuffer */
205		stb_rdptr_offset = num_samples % S2D_TELEMETRY_BYTES_MAX;
206		fsize = S2D_TELEMETRY_BYTES_MAX - stb_rdptr_offset;
207
208		memcpy_fromio(stb_data_arr->data, dev->stb_virt_addr + stb_rdptr_offset, fsize);
209		/* Second copy the newer samples from offset 0 - last write */
210		memcpy_fromio(stb_data_arr->data + fsize, dev->stb_virt_addr, stb_rdptr_offset);
211	} else {
212		memcpy_fromio(stb_data_arr->data, dev->stb_virt_addr, fsize);
213	}
214
215	filp->private_data = stb_data_arr;
216
217	return 0;
218}
219
220static ssize_t amd_stb_debugfs_read_v2(struct file *filp, char __user *buf, size_t size,
221				       loff_t *pos)
222{
223	struct amd_stb_v2_data *data = filp->private_data;
224
225	return simple_read_from_buffer(buf, size, pos, data->data, data->size);
226}
227
228static int amd_stb_debugfs_release_v2(struct inode *inode, struct file *filp)
229{
230	kfree(filp->private_data);
231	return 0;
232}
233
234static const struct file_operations amd_stb_debugfs_fops_v2 = {
235	.owner = THIS_MODULE,
236	.open = amd_stb_debugfs_open_v2,
237	.read = amd_stb_debugfs_read_v2,
238	.release = amd_stb_debugfs_release_v2,
239};
240
241static void amd_stb_update_args(struct amd_pmc_dev *dev)
242{
243	if (cpu_feature_enabled(X86_FEATURE_ZEN5))
244		switch (boot_cpu_data.x86_model) {
245		case 0x44:
246			dev->stb_arg.msg = AMD_GNR_REGISTER_MESSAGE;
247			dev->stb_arg.arg = AMD_GNR_REGISTER_ARGUMENT;
248			dev->stb_arg.resp = AMD_GNR_REGISTER_RESPONSE;
249			return;
250		default:
251			break;
252	}
253
254	dev->stb_arg.msg = AMD_S2D_REGISTER_MESSAGE;
255	dev->stb_arg.arg = AMD_S2D_REGISTER_ARGUMENT;
256	dev->stb_arg.resp = AMD_S2D_REGISTER_RESPONSE;
257}
258
259static bool amd_is_stb_supported(struct amd_pmc_dev *dev)
260{
261	switch (dev->cpu_id) {
262	case AMD_CPU_ID_YC:
263	case AMD_CPU_ID_CB:
264		if (boot_cpu_data.x86_model == 0x44)
265			dev->stb_arg.s2d_msg_id = 0x9B;
266		else
267			dev->stb_arg.s2d_msg_id = 0xBE;
268		break;
269	case AMD_CPU_ID_PS:
270		dev->stb_arg.s2d_msg_id = 0x85;
271		break;
272	case PCI_DEVICE_ID_AMD_1AH_M20H_ROOT:
273	case PCI_DEVICE_ID_AMD_1AH_M60H_ROOT:
274		if (boot_cpu_data.x86_model == 0x70)
275			dev->stb_arg.s2d_msg_id = 0xF1;
276		else
277			dev->stb_arg.s2d_msg_id = 0xDE;
278		break;
279	default:
280		return false;
281	}
282
283	amd_stb_update_args(dev);
284	return true;
285}
286
287int amd_stb_s2d_init(struct amd_pmc_dev *dev)
288{
289	u32 phys_addr_low, phys_addr_hi;
290	u64 stb_phys_addr;
291	u32 size = 0;
292	int ret;
293
294	if (!enable_stb)
295		return 0;
296
297	if (amd_is_stb_supported(dev)) {
298		debugfs_create_file("stb_read", 0644, dev->dbgfs_dir, dev,
299				    &amd_stb_debugfs_fops_v2);
300	} else {
301		debugfs_create_file("stb_read", 0644, dev->dbgfs_dir, dev,
302				    &amd_stb_debugfs_fops);
303		return 0;
304	}
305
306	/* Spill to DRAM feature uses separate SMU message port */
307	dev->msg_port = MSG_PORT_S2D;
308
309	amd_pmc_send_cmd(dev, S2D_TELEMETRY_SIZE, &size, dev->stb_arg.s2d_msg_id, true);
310	if (size != S2D_TELEMETRY_BYTES_MAX)
311		return -EIO;
312
313	/* Get DRAM size */
314	ret = amd_pmc_send_cmd(dev, S2D_DRAM_SIZE, &dev->dram_size, dev->stb_arg.s2d_msg_id, true);
315	if (ret || !dev->dram_size)
316		dev->dram_size = S2D_TELEMETRY_DRAMBYTES_MAX;
317
318	/* Get STB DRAM address */
319	amd_pmc_send_cmd(dev, S2D_PHYS_ADDR_LOW, &phys_addr_low, dev->stb_arg.s2d_msg_id, true);
320	amd_pmc_send_cmd(dev, S2D_PHYS_ADDR_HIGH, &phys_addr_hi, dev->stb_arg.s2d_msg_id, true);
321
322	stb_phys_addr = ((u64)phys_addr_hi << 32 | phys_addr_low);
323
324	/* Clear msg_port for other SMU operation */
325	dev->msg_port = MSG_PORT_PMC;
326
327	dev->stb_virt_addr = devm_ioremap(dev->dev, stb_phys_addr, dev->dram_size);
328	if (!dev->stb_virt_addr)
329		return -ENOMEM;
330
331	return 0;
332}
~/ Read-only file preview.