Commit 24856a36 authored by Zhang Zekun's avatar Zhang Zekun Committed by Zhong Jinghua
Browse files

soc: hbmcache: Add support for online and offline the hbm cache

hulk inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/I6I7DH


CVE: NA

--------------------------------------------------

Add a driver for hbm cache, which support for power on/off the
hbm cache device. Hbm can be used as a cache, for which a normal
memory access can take advantage of the high band width of hbm.

Signed-off-by: default avatarZhang Zekun <zhangzekun11@huawei.com>
Reviewed-by: default avatarKefeng Wang <wangkefeng.wang@huawei.com>
parent a1390bb0
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -19,4 +19,15 @@ config HISI_HBMDEV
	  To compile this driver as a module, choose M here:
	  the module will be called hisi_hbmdev.

config HISI_HBMCACHE
	tristate "HBM cache memory device"
	depends on ACPI
	help
	  This driver provids methods to control the power of hbm cache device
	  in hisi soc. Use hbm as a cache can take advantage of hbm's high
	  bandwidth in normal memory access.

	  To compile the driver as a module, choose M here:
	  the module will be called hisi_hbmcache.

endmenu
+1 −0
Original line number Diff line number Diff line
# SPDX-License-Identifier: GPL-2.0

obj-$(CONFIG_HISI_HBMDEV)	+= hisi_hbmdev.o
obj-$(CONFIG_HISI_HBMCACHE)	+= hisi_hbmcache.o
+147 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (C) Huawei Technologies Co., Ltd. 2023. All rights reserved.
 */

#include <linux/err.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/acpi.h>
#include <linux/device.h>

#include "hisi_internal.h"

#define MODULE_NAME            "hbm_cache"

static struct kobject *cache_kobj;

static ssize_t state_store(struct device *d, struct device_attribute *attr,
			   const char *buf, size_t count)
{
	struct acpi_device *adev = ACPI_COMPANION(d);
	const int type = online_type_from_str(buf);
	int ret = -EINVAL;

	switch (type) {
	case STATE_ONLINE:
		ret = acpi_device_set_power(adev, ACPI_STATE_D0);
		break;
	case STATE_OFFLINE:
		ret = acpi_device_set_power(adev, ACPI_STATE_D3);
		break;
	default:
		break;
	}

	if (ret)
		return ret;

	return count;
}

static ssize_t state_show(struct device *d, struct device_attribute *attr,
			  char *buf)
{
	struct acpi_device *adev = ACPI_COMPANION(d);
	unsigned long long sta = 0;
	acpi_status status;
	const char *output;

	status = acpi_evaluate_integer(adev->handle, "_STA", NULL, &sta);
	if (ACPI_FAILURE(status))
		return -EINVAL;

	output = (sta & 0x01) ? online_type_to_str[STATE_ONLINE] :
				online_type_to_str[STATE_OFFLINE];

	return sysfs_emit(buf, "%s\n", output);
}
static DEVICE_ATTR_RW(state);

static ssize_t socket_id_show(struct device *d, struct device_attribute *attr,
				char *buf)
{
	int socket_id;

	if (device_property_read_u32(d, "socket_id", &socket_id))
		return -EINVAL;

	return sysfs_emit(buf, "%d\n", socket_id);
}
static DEVICE_ATTR_RO(socket_id);

static struct attribute *attrs[] = {
	&dev_attr_state.attr,
	&dev_attr_socket_id.attr,
	NULL,
};

static struct attribute_group attr_group = {
	.attrs = attrs,
};

static int cache_probe(struct platform_device *pdev)
{
	int ret;

	ret = sysfs_create_group(&pdev->dev.kobj, &attr_group);
	if (ret)
		return ret;

	ret = sysfs_create_link(cache_kobj,
				&pdev->dev.kobj,
				kobject_name(&pdev->dev.kobj));
	if (ret) {
		sysfs_remove_group(&pdev->dev.kobj, &attr_group);
		return ret;
	}

	return 0;
}

static int cache_remove(struct platform_device *pdev)
{
	sysfs_remove_group(&pdev->dev.kobj, &attr_group);
	sysfs_remove_link(&pdev->dev.kobj,
			  kobject_name(&pdev->dev.kobj));
	return 0;
}

static const struct acpi_device_id cache_acpi_ids[] = {
	{"HISI04A1"},
	{},
};

static struct platform_driver hbm_cache_driver = {
	.probe = cache_probe,
	.remove = cache_remove,
	.driver = {
		.name = MODULE_NAME,
		.acpi_match_table = ACPI_PTR(cache_acpi_ids),
	},
};

static int __init hbm_cache_module_init(void)
{
	int ret;

	cache_kobj = kobject_create_and_add("hbm_cache", kernel_kobj);
	if (!cache_kobj)
		return -ENOMEM;

	ret = platform_driver_register(&hbm_cache_driver);
	if (ret) {
		kobject_put(cache_kobj);
		return ret;
	}
	return 0;
}
module_init(hbm_cache_module_init);

static void __exit hbm_cache_module_exit(void)
{
	kobject_put(cache_kobj);
	platform_driver_unregister(&hbm_cache_driver);
}
module_exit(hbm_cache_module_exit);
MODULE_LICENSE("GPL");