drivers/platform/x86/amd/pmc/mp1_stb.c

Source file repositories/reference/linux-study-clean/drivers/platform/x86/amd/pmc/mp1_stb.c

File Facts

System
Linux kernel
Corpus path
drivers/platform/x86/amd/pmc/mp1_stb.c
Extension
.c
Size
8724 bytes
Lines
333
Domain
Driver Families
Bucket
drivers/platform
Inferred role
Driver Families: operation-table or driver-model contract
Status
pattern implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

static const struct file_operations amd_stb_debugfs_fops = {
	.owner = THIS_MODULE,
	.open = amd_stb_debugfs_open,
	.read = amd_stb_debugfs_read,
	.release = amd_stb_debugfs_release,
};

/* Enhanced STB Firmware Reporting Mechanism */
static int amd_stb_handle_efr(struct file *filp)
{
	struct amd_pmc_dev *dev = filp->f_inode->i_private;
	struct amd_stb_v2_data *stb_data_arr;
	u32 fsize;

	fsize = dev->dram_size - S2D_RSVD_RAM_SPACE;
	stb_data_arr = kmalloc_flex(*stb_data_arr, data, fsize);
	if (!stb_data_arr)
		return -ENOMEM;

	stb_data_arr->size = fsize;
	memcpy_fromio(stb_data_arr->data, dev->stb_virt_addr, fsize);
	filp->private_data = stb_data_arr;

	return 0;
}

static int amd_stb_debugfs_open_v2(struct inode *inode, struct file *filp)
{
	struct amd_pmc_dev *dev = filp->f_inode->i_private;
	u32 fsize, num_samples, val, stb_rdptr_offset = 0;
	struct amd_stb_v2_data *stb_data_arr;
	int ret;

	/* Write dummy postcode while reading the STB buffer */
	ret = amd_stb_write(dev, AMD_PMC_STB_DUMMY_PC);
	if (ret)
		dev_err(dev->dev, "error writing to STB: %d\n", ret);

	/* Spill to DRAM num_samples uses separate SMU message port */
	dev->msg_port = MSG_PORT_S2D;

	ret = amd_pmc_send_cmd(dev, 0, &val, STB_FORCE_FLUSH_DATA, 1);
	if (ret)
		dev_dbg_once(dev->dev, "S2D force flush not supported: %d\n", ret);

	/*
	 * 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)
		return amd_stb_handle_efr(filp);

	/* Get the num_samples to calculate the last push location */
	ret = amd_pmc_send_cmd(dev, S2D_NUM_SAMPLES, &num_samples, dev->stb_arg.s2d_msg_id, true);
	/* Clear msg_port for other SMU operation */
	dev->msg_port = MSG_PORT_PMC;
	if (ret) {
		dev_err(dev->dev, "error: S2D_NUM_SAMPLES not supported : %d\n", ret);
		return ret;
	}

	fsize = min(num_samples, S2D_TELEMETRY_BYTES_MAX);
	stb_data_arr = kmalloc_flex(*stb_data_arr, data, fsize);
	if (!stb_data_arr)
		return -ENOMEM;

	stb_data_arr->size = fsize;

	/*
	 * Start capturing data from the last push location.
	 * This is for general cases, where the stb limits
	 * are meant for standard usage.
	 */
	if (num_samples > S2D_TELEMETRY_BYTES_MAX) {
		/* First read oldest data starting 1 behind last write till end of ringbuffer */
		stb_rdptr_offset = num_samples % S2D_TELEMETRY_BYTES_MAX;
		fsize = S2D_TELEMETRY_BYTES_MAX - stb_rdptr_offset;

		memcpy_fromio(stb_data_arr->data, dev->stb_virt_addr + stb_rdptr_offset, fsize);
		/* Second copy the newer samples from offset 0 - last write */
		memcpy_fromio(stb_data_arr->data + fsize, dev->stb_virt_addr, stb_rdptr_offset);
	} else {
		memcpy_fromio(stb_data_arr->data, dev->stb_virt_addr, fsize);
	}

	filp->private_data = stb_data_arr;

	return 0;
}

Annotation

Implementation Notes