@@ -53,6 +53,7 @@
/* STB Spill to DRAM Parameters */
#define S2D_TELEMETRY_BYTES_MAX 0x100000
+#define S2D_RSVD_RAM_SPACE 0x100000
#define S2D_TELEMETRY_DRAMBYTES_MAX 0x1000000
/* STB Spill to DRAM Message Definition */
@@ -165,6 +166,10 @@ static bool disable_workarounds;
module_param(disable_workarounds, bool, 0644);
MODULE_PARM_DESC(disable_workarounds, "Disable workarounds for platform bugs");
+static bool dump_custom_stb;
+module_param(dump_custom_stb, bool, 0644);
+MODULE_PARM_DESC(dump_custom_stb, "Enable to dump full STB buffer");
+
static struct amd_pmc_dev pmc;
static int amd_pmc_send_cmd(struct amd_pmc_dev *dev, u32 arg, u32 *data, u8 msg, bool ret);
static int amd_pmc_read_stb(struct amd_pmc_dev *dev, u32 *buf);
@@ -241,6 +246,26 @@ static const struct file_operations amd_pmc_stb_debugfs_fops = {
.release = amd_pmc_stb_debugfs_release,
};
+/* Enhanced STB Firmware Reporting Mechanism */
+static int amd_pmc_stb_handle_efr(struct file *filp)
+{
+ struct amd_pmc_dev *dev = filp->f_inode->i_private;
+ struct amd_pmc_stb_v2_data *flex_arr;
+
+ dev->fsize = dev->dram_size - S2D_RSVD_RAM_SPACE;
+ dev->stb_rdptr_offset = 0;
+
+ flex_arr = kzalloc(struct_size(flex_arr, data, dev->fsize), GFP_KERNEL);
+ if (!flex_arr)
+ return -ENOMEM;
+
+ memcpy_fromio(flex_arr->data, dev->stb_virt_addr + dev->stb_rdptr_offset, dev->fsize);
+ flex_arr->size = dev->fsize;
+ filp->private_data = flex_arr->data;
+
+ return 0;
+}
+
static int amd_pmc_stb_debugfs_open_v2(struct inode *inode, struct file *filp)
{
struct amd_pmc_dev *dev = filp->f_inode->i_private;
@@ -260,6 +285,16 @@ static int amd_pmc_stb_debugfs_open_v2(struct inode *inode, struct file *filp)
if (ret)
dev_warn_once(dev->dev, "S2D force flush not supported\n");
+ /*
+ * We have a custom stb size and the PMFW is supposed to give
+ * the enhanced dram size. Note that we land here only for the
+ * platforms that support enhanced dram size reporting.
+ */
+ if (dump_custom_stb) {
+ ret = amd_pmc_stb_handle_efr(filp);
+ return ret;
+ }
+
/* Get the num_samples to calculate the last push location */
ret = amd_pmc_send_cmd(dev, S2D_NUM_SAMPLES, &dev->num_samples, dev->s2d_msg_id, true);
/* Clear msg_port for other SMU operation */
@@ -269,7 +304,11 @@ static int amd_pmc_stb_debugfs_open_v2(struct inode *inode, struct file *filp)
return ret;
}
- /* Start capturing data from the last push location */
+ /*
+ * Start capturing data from the last push location.
+ * This is for general cases, where the stb limits
+ * are meant for standard usage.
+ */
if (dev->num_samples > S2D_TELEMETRY_BYTES_MAX) {
/* First read oldest data starting 1 behind last write till end of ringbuffer */
dev->stb_rdptr_offset = dev->num_samples % S2D_TELEMETRY_BYTES_MAX;
@@ -303,11 +342,13 @@ static int amd_pmc_stb_debugfs_open_v2(struct inode *inode, struct file *filp)
static ssize_t amd_pmc_stb_debugfs_read_v2(struct file *filp, char __user *buf, size_t size,
loff_t *pos)
{
+ struct amd_pmc_dev *dev = filp->f_inode->i_private;
+
if (!filp->private_data)
return -EINVAL;
return simple_read_from_buffer(buf, size, pos, filp->private_data,
- S2D_TELEMETRY_BYTES_MAX);
+ dev->fsize);
}
static int amd_pmc_stb_debugfs_release_v2(struct inode *inode, struct file *filp)