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

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

File Facts

System
Linux kernel
Corpus path
drivers/platform/x86/amd/pmc/pmc.c
Extension
.c
Size
21509 bytes
Lines
848
Domain
Driver Families
Bucket
drivers/platform
Inferred role
Driver Families: implementation source
Status
source 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

if (boot_cpu_data.x86_model == 0x70) {
			dev->num_ips = ARRAY_SIZE(soc15_ip_blk_v2);
			dev->ips_ptr = soc15_ip_blk_v2;
		} else {
			dev->num_ips = ARRAY_SIZE(soc15_ip_blk);
			dev->ips_ptr = soc15_ip_blk;
		}
		dev->smu_msg = 0x938;
		break;
	}
}

static int amd_pmc_setup_smu_logging(struct amd_pmc_dev *dev)
{
	if (dev->cpu_id == AMD_CPU_ID_PCO) {
		dev_warn_once(dev->dev, "SMU debugging info not supported on this platform\n");
		return -EINVAL;
	}

	/* Get Active devices list from SMU */
	if (!dev->active_ips)
		amd_pmc_send_cmd(dev, 0, &dev->active_ips, SMU_MSG_GET_SUP_CONSTRAINTS, true);

	/* Get dram address */
	if (!dev->smu_virt_addr) {
		u32 phys_addr_low, phys_addr_hi;
		u64 smu_phys_addr;

		amd_pmc_send_cmd(dev, 0, &phys_addr_low, SMU_MSG_LOG_GETDRAM_ADDR_LO, true);
		amd_pmc_send_cmd(dev, 0, &phys_addr_hi, SMU_MSG_LOG_GETDRAM_ADDR_HI, true);
		smu_phys_addr = ((u64)phys_addr_hi << 32 | phys_addr_low);

		dev->smu_virt_addr = devm_ioremap(dev->dev, smu_phys_addr,
						  sizeof(struct smu_metrics));
		if (!dev->smu_virt_addr)
			return -ENOMEM;
	}

	memset_io(dev->smu_virt_addr, 0, sizeof(struct smu_metrics));

	/* Start the logging */
	amd_pmc_send_cmd(dev, 0, NULL, SMU_MSG_LOG_RESET, false);
	amd_pmc_send_cmd(dev, 0, NULL, SMU_MSG_LOG_START, false);

	return 0;
}

static int get_metrics_table(struct amd_pmc_dev *pdev, struct smu_metrics *table)
{
	int rc;

	if (!pdev->smu_virt_addr) {
		rc = amd_pmc_setup_smu_logging(pdev);
		if (rc)
			return rc;
	}

	if (pdev->cpu_id == AMD_CPU_ID_PCO)
		return -ENODEV;
	memcpy_fromio(table, pdev->smu_virt_addr, sizeof(struct smu_metrics));
	return 0;
}

static void amd_pmc_validate_deepest(struct amd_pmc_dev *pdev)
{
	struct smu_metrics table;

	if (get_metrics_table(pdev, &table))
		return;

	if (!table.s0i3_last_entry_status)
		dev_warn(pdev->dev, "Last suspend didn't reach deepest state\n");
	pm_report_hw_sleep_time(table.s0i3_last_entry_status ?
				table.timein_s0i3_lastcapture : 0);
}

static int amd_pmc_get_smu_version(struct amd_pmc_dev *dev)
{
	int rc;
	u32 val;

	if (dev->cpu_id == AMD_CPU_ID_PCO)
		return -ENODEV;

	rc = amd_pmc_send_cmd(dev, 0, &val, SMU_MSG_GETSMUVERSION, true);
	if (rc)
		return rc;

	dev->smu_program = (val >> 24) & GENMASK(7, 0);
	dev->major = (val >> 16) & GENMASK(7, 0);

Annotation

Implementation Notes