Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.2.
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * AMD 3D V-Cache Performance Optimizer Driver
  4 *
  5 * Copyright (c) 2024, Advanced Micro Devices, Inc.
  6 * All Rights Reserved.
  7 *
  8 * Authors: Basavaraj Natikar <Basavaraj.Natikar@amd.com>
  9 *          Perry Yuan <perry.yuan@amd.com>
 10 *          Mario Limonciello <mario.limonciello@amd.com>
 11 */
 12
 13#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 14
 15#include <linux/acpi.h>
 16#include <linux/array_size.h>
 17#include <linux/device.h>
 18#include <linux/errno.h>
 19#include <linux/module.h>
 20#include <linux/mutex.h>
 21#include <linux/platform_device.h>
 22#include <linux/pm.h>
 23#include <linux/sysfs.h>
 24#include <linux/uuid.h>
 25
 26static char *x3d_mode = "frequency";
 27module_param(x3d_mode, charp, 0);
 28MODULE_PARM_DESC(x3d_mode, "Initial 3D-VCache mode; 'frequency' (default) or 'cache'");
 29
 30#define DSM_REVISION_ID			0
 31#define DSM_SET_X3D_MODE		1
 32
 33static guid_t x3d_guid = GUID_INIT(0xdff8e55f, 0xbcfd, 0x46fb, 0xba, 0x0a,
 34				   0xef, 0xd0, 0x45, 0x0f, 0x34, 0xee);
 35
 36enum amd_x3d_mode_type {
 37	MODE_INDEX_FREQ,
 38	MODE_INDEX_CACHE,
 39};
 40
 41static const char * const amd_x3d_mode_strings[] = {
 42	[MODE_INDEX_FREQ] = "frequency",
 43	[MODE_INDEX_CACHE] = "cache",
 44};
 45
 46struct amd_x3d_dev {
 47	struct device *dev;
 48	acpi_handle ahandle;
 49	/* To protect x3d mode setting */
 50	struct mutex lock;
 51	enum amd_x3d_mode_type curr_mode;
 52};
 53
 54static int amd_x3d_get_mode(struct amd_x3d_dev *data)
 55{
 56	guard(mutex)(&data->lock);
 57
 58	return data->curr_mode;
 59}
 60
 61static int amd_x3d_mode_switch(struct amd_x3d_dev *data, int new_state)
 62{
 63	union acpi_object *out, argv;
 64
 65	guard(mutex)(&data->lock);
 66	argv.type = ACPI_TYPE_INTEGER;
 67	argv.integer.value = new_state;
 68
 69	out = acpi_evaluate_dsm(data->ahandle, &x3d_guid, DSM_REVISION_ID,
 70				DSM_SET_X3D_MODE, &argv);
 71	if (!out) {
 72		dev_err(data->dev, "failed to evaluate _DSM\n");
 73		return -EINVAL;
 74	}
 75
 76	data->curr_mode = new_state;
 77
 78	kfree(out);
 79
 80	return 0;
 81}
 82
 83static ssize_t amd_x3d_mode_store(struct device *dev, struct device_attribute *attr,
 84				  const char *buf, size_t count)
 85{
 86	struct amd_x3d_dev *data = dev_get_drvdata(dev);
 87	int ret;
 88
 89	ret = sysfs_match_string(amd_x3d_mode_strings, buf);
 90	if (ret < 0)
 91		return ret;
 92
 93	ret = amd_x3d_mode_switch(data, ret);
 94	if (ret < 0)
 95		return ret;
 96
 97	return count;
 98}
 99
100static ssize_t amd_x3d_mode_show(struct device *dev, struct device_attribute *attr, char *buf)
101{
102	struct amd_x3d_dev *data = dev_get_drvdata(dev);
103	int mode = amd_x3d_get_mode(data);
104
105	return sysfs_emit(buf, "%s\n", amd_x3d_mode_strings[mode]);
106}
107static DEVICE_ATTR_RW(amd_x3d_mode);
108
109static struct attribute *amd_x3d_attrs[] = {
110	&dev_attr_amd_x3d_mode.attr,
111	NULL
112};
113ATTRIBUTE_GROUPS(amd_x3d);
114
115static int amd_x3d_resume_handler(struct device *dev)
116{
117	struct amd_x3d_dev *data = dev_get_drvdata(dev);
118	int ret = amd_x3d_get_mode(data);
119
120	return amd_x3d_mode_switch(data, ret);
121}
122
123static DEFINE_SIMPLE_DEV_PM_OPS(amd_x3d_pm, NULL, amd_x3d_resume_handler);
124
125static const struct acpi_device_id amd_x3d_acpi_ids[] = {
126	{"AMDI0101"},
127	{ },
128};
129MODULE_DEVICE_TABLE(acpi, amd_x3d_acpi_ids);
130
131static int amd_x3d_probe(struct platform_device *pdev)
132{
133	struct amd_x3d_dev *data;
134	acpi_handle handle;
135	int ret;
136
137	handle = ACPI_HANDLE(&pdev->dev);
138	if (!handle)
139		return -ENODEV;
140
141	if (!acpi_check_dsm(handle, &x3d_guid, DSM_REVISION_ID, BIT(DSM_SET_X3D_MODE)))
142		return -ENODEV;
143
144	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
145	if (!data)
146		return -ENOMEM;
147
148	data->dev = &pdev->dev;
149
150	ret = devm_mutex_init(data->dev, &data->lock);
151	if (ret)
152		return ret;
153
154	data->ahandle = handle;
155	platform_set_drvdata(pdev, data);
156
157	ret = match_string(amd_x3d_mode_strings, ARRAY_SIZE(amd_x3d_mode_strings), x3d_mode);
158	if (ret < 0)
159		return dev_err_probe(&pdev->dev, -EINVAL, "invalid mode %s\n", x3d_mode);
160
161	return amd_x3d_mode_switch(data, ret);
162}
163
164static struct platform_driver amd_3d_vcache_driver = {
165	.driver = {
166		.name = "amd_x3d_vcache",
167		.dev_groups = amd_x3d_groups,
168		.acpi_match_table = amd_x3d_acpi_ids,
169		.pm = pm_sleep_ptr(&amd_x3d_pm),
170	},
171	.probe = amd_x3d_probe,
172};
173module_platform_driver(amd_3d_vcache_driver);
174
175MODULE_DESCRIPTION("AMD 3D V-Cache Performance Optimizer Driver");
176MODULE_LICENSE("GPL");