drivers/platform/x86/amd/pmf/acpi.c

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

File Facts

System
Linux kernel
Corpus path
drivers/platform/x86/amd/pmf/acpi.c
Extension
.c
Size
16983 bytes
Lines
647
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

is_apmf_func_supported(pmf_dev, APMF_FUNC_SBIOS_REQUESTS)) {
		status = acpi_install_notify_handler(ahandle, ACPI_ALL_NOTIFY,
						     apmf_event_handler, pmf_dev);
		if (ACPI_FAILURE(status)) {
			dev_err(pmf_dev->dev, "failed to install notify handler\n");
			return -ENODEV;
		}

		/* Call the handler once manually to catch up with possibly missed notifies. */
		apmf_event_handler(ahandle, 0, pmf_dev);
	}

	if (!pmf_dev->smart_pc_enabled)
		return -EINVAL;

	switch (pmf_dev->pmf_if_version) {
	case PMF_IF_V1:
		if (!is_apmf_bios_input_notifications_supported(pmf_dev))
			break;
		fallthrough;
	case PMF_IF_V2:
		status = acpi_install_notify_handler(ahandle, ACPI_ALL_NOTIFY,
				apmf_event_handlers[pmf_dev->pmf_if_version], pmf_dev);
		if (ACPI_FAILURE(status)) {
			dev_err(pmf_dev->dev,
				"failed to install notify handler v%d for custom BIOS inputs\n",
				pmf_dev->pmf_if_version);
			return -ENODEV;
		}
		break;
	default:
		break;
	}

	return 0;
}

int apmf_check_smart_pc(struct amd_pmf_dev *pmf_dev)
{
	struct platform_device *pdev = to_platform_device(pmf_dev->dev);

	pmf_dev->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!pmf_dev->res) {
		dev_dbg(pmf_dev->dev, "Failed to get I/O memory resource\n");
		return -EINVAL;
	}

	pmf_dev->policy_addr = pmf_dev->res->start;
	/*
	 * We cannot use resource_size() here because it adds an extra byte to round off the size.
	 * In the case of PMF ResourceTemplate(), this rounding is already handled within the _CRS.
	 * Using resource_size() would increase the resource size by 1, causing a mismatch with the
	 * length field and leading to issues. Therefore, simply use end-start of the ACPI resource
	 * to obtain the actual length.
	 */
	pmf_dev->policy_sz = pmf_dev->res->end - pmf_dev->res->start;

	if (!pmf_dev->policy_addr || pmf_dev->policy_sz > POLICY_BUF_MAX_SZ ||
	    pmf_dev->policy_sz == 0) {
		dev_err(pmf_dev->dev, "Incorrect policy params, possibly a SBIOS bug\n");
		return -EINVAL;
	}

	return 0;
}

int amd_pmf_smartpc_apply_bios_output(struct amd_pmf_dev *dev, u32 val, u32 preq, u32 idx)
{
	if (!is_apmf_func_supported(dev, APMF_FUNC_NOTIFY_SMART_PC_UPDATES))
		return -EINVAL;

	return apmf_notify_smart_pc_update(dev, val, preq, idx);
}

void apmf_acpi_deinit(struct amd_pmf_dev *pmf_dev)
{
	acpi_handle ahandle = ACPI_HANDLE(pmf_dev->dev);

	if (pmf_dev->hb_interval && pmf_dev->pmf_if_version == PMF_IF_V1)
		cancel_delayed_work_sync(&pmf_dev->heart_beat);

	if (is_apmf_func_supported(pmf_dev, APMF_FUNC_AUTO_MODE) &&
	    is_apmf_func_supported(pmf_dev, APMF_FUNC_SBIOS_REQUESTS))
		acpi_remove_notify_handler(ahandle, ACPI_ALL_NOTIFY, apmf_event_handler);

	if (!pmf_dev->smart_pc_enabled)
		return;

	switch (pmf_dev->pmf_if_version) {
	case PMF_IF_V1:

Annotation

Implementation Notes