cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

bt1-l2-ctl.c (7444B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (C) 2020 BAIKAL ELECTRONICS, JSC
      4 *
      5 * Authors:
      6 *   Serge Semin <Sergey.Semin@baikalelectronics.ru>
      7 *
      8 * Baikal-T1 CM2 L2-cache Control Block driver.
      9 */
     10
     11#include <linux/kernel.h>
     12#include <linux/module.h>
     13#include <linux/bitfield.h>
     14#include <linux/types.h>
     15#include <linux/device.h>
     16#include <linux/platform_device.h>
     17#include <linux/regmap.h>
     18#include <linux/mfd/syscon.h>
     19#include <linux/sysfs.h>
     20#include <linux/of.h>
     21
     22#define L2_CTL_REG			0x028
     23#define L2_CTL_DATA_STALL_FLD		0
     24#define L2_CTL_DATA_STALL_MASK		GENMASK(1, L2_CTL_DATA_STALL_FLD)
     25#define L2_CTL_TAG_STALL_FLD		2
     26#define L2_CTL_TAG_STALL_MASK		GENMASK(3, L2_CTL_TAG_STALL_FLD)
     27#define L2_CTL_WS_STALL_FLD		4
     28#define L2_CTL_WS_STALL_MASK		GENMASK(5, L2_CTL_WS_STALL_FLD)
     29#define L2_CTL_SET_CLKRATIO		BIT(13)
     30#define L2_CTL_CLKRATIO_LOCK		BIT(31)
     31
     32#define L2_CTL_STALL_MIN		0
     33#define L2_CTL_STALL_MAX		3
     34#define L2_CTL_STALL_SET_DELAY_US	1
     35#define L2_CTL_STALL_SET_TOUT_US	1000
     36
     37/*
     38 * struct l2_ctl - Baikal-T1 L2 Control block private data.
     39 * @dev: Pointer to the device structure.
     40 * @sys_regs: Baikal-T1 System Controller registers map.
     41 */
     42struct l2_ctl {
     43	struct device *dev;
     44
     45	struct regmap *sys_regs;
     46};
     47
     48/*
     49 * enum l2_ctl_stall - Baikal-T1 L2-cache-RAM stall identifier.
     50 * @L2_WSSTALL: Way-select latency.
     51 * @L2_TAGSTALL: Tag latency.
     52 * @L2_DATASTALL: Data latency.
     53 */
     54enum l2_ctl_stall {
     55	L2_WS_STALL,
     56	L2_TAG_STALL,
     57	L2_DATA_STALL
     58};
     59
     60/*
     61 * struct l2_ctl_device_attribute - Baikal-T1 L2-cache device attribute.
     62 * @dev_attr: Actual sysfs device attribute.
     63 * @id: L2-cache stall field identifier.
     64 */
     65struct l2_ctl_device_attribute {
     66	struct device_attribute dev_attr;
     67	enum l2_ctl_stall id;
     68};
     69
     70#define to_l2_ctl_dev_attr(_dev_attr) \
     71	container_of(_dev_attr, struct l2_ctl_device_attribute, dev_attr)
     72
     73#define L2_CTL_ATTR_RW(_name, _prefix, _id) \
     74	struct l2_ctl_device_attribute l2_ctl_attr_##_name = \
     75		{ __ATTR(_name, 0644, _prefix##_show, _prefix##_store),	_id }
     76
     77static int l2_ctl_get_latency(struct l2_ctl *l2, enum l2_ctl_stall id, u32 *val)
     78{
     79	u32 data = 0;
     80	int ret;
     81
     82	ret = regmap_read(l2->sys_regs, L2_CTL_REG, &data);
     83	if (ret)
     84		return ret;
     85
     86	switch (id) {
     87	case L2_WS_STALL:
     88		*val = FIELD_GET(L2_CTL_WS_STALL_MASK, data);
     89		break;
     90	case L2_TAG_STALL:
     91		*val = FIELD_GET(L2_CTL_TAG_STALL_MASK, data);
     92		break;
     93	case L2_DATA_STALL:
     94		*val = FIELD_GET(L2_CTL_DATA_STALL_MASK, data);
     95		break;
     96	default:
     97		return -EINVAL;
     98	}
     99
    100	return 0;
    101}
    102
    103static int l2_ctl_set_latency(struct l2_ctl *l2, enum l2_ctl_stall id, u32 val)
    104{
    105	u32 mask = 0, data = 0;
    106	int ret;
    107
    108	val = clamp_val(val, L2_CTL_STALL_MIN, L2_CTL_STALL_MAX);
    109
    110	switch (id) {
    111	case L2_WS_STALL:
    112		data = FIELD_PREP(L2_CTL_WS_STALL_MASK, val);
    113		mask = L2_CTL_WS_STALL_MASK;
    114		break;
    115	case L2_TAG_STALL:
    116		data = FIELD_PREP(L2_CTL_TAG_STALL_MASK, val);
    117		mask = L2_CTL_TAG_STALL_MASK;
    118		break;
    119	case L2_DATA_STALL:
    120		data = FIELD_PREP(L2_CTL_DATA_STALL_MASK, val);
    121		mask = L2_CTL_DATA_STALL_MASK;
    122		break;
    123	default:
    124		return -EINVAL;
    125	}
    126
    127	data |= L2_CTL_SET_CLKRATIO;
    128	mask |= L2_CTL_SET_CLKRATIO;
    129
    130	ret = regmap_update_bits(l2->sys_regs, L2_CTL_REG, mask, data);
    131	if (ret)
    132		return ret;
    133
    134	return regmap_read_poll_timeout(l2->sys_regs, L2_CTL_REG, data,
    135					data & L2_CTL_CLKRATIO_LOCK,
    136					L2_CTL_STALL_SET_DELAY_US,
    137					L2_CTL_STALL_SET_TOUT_US);
    138}
    139
    140static void l2_ctl_clear_data(void *data)
    141{
    142	struct l2_ctl *l2 = data;
    143	struct platform_device *pdev = to_platform_device(l2->dev);
    144
    145	platform_set_drvdata(pdev, NULL);
    146}
    147
    148static struct l2_ctl *l2_ctl_create_data(struct platform_device *pdev)
    149{
    150	struct device *dev = &pdev->dev;
    151	struct l2_ctl *l2;
    152	int ret;
    153
    154	l2 = devm_kzalloc(dev, sizeof(*l2), GFP_KERNEL);
    155	if (!l2)
    156		return ERR_PTR(-ENOMEM);
    157
    158	ret = devm_add_action(dev, l2_ctl_clear_data, l2);
    159	if (ret) {
    160		dev_err(dev, "Can't add L2 CTL data clear action\n");
    161		return ERR_PTR(ret);
    162	}
    163
    164	l2->dev = dev;
    165	platform_set_drvdata(pdev, l2);
    166
    167	return l2;
    168}
    169
    170static int l2_ctl_find_sys_regs(struct l2_ctl *l2)
    171{
    172	l2->sys_regs = syscon_node_to_regmap(l2->dev->of_node->parent);
    173	if (IS_ERR(l2->sys_regs)) {
    174		dev_err(l2->dev, "Couldn't get L2 CTL register map\n");
    175		return PTR_ERR(l2->sys_regs);
    176	}
    177
    178	return 0;
    179}
    180
    181static int l2_ctl_of_parse_property(struct l2_ctl *l2, enum l2_ctl_stall id,
    182				    const char *propname)
    183{
    184	int ret = 0;
    185	u32 data;
    186
    187	if (!of_property_read_u32(l2->dev->of_node, propname, &data)) {
    188		ret = l2_ctl_set_latency(l2, id, data);
    189		if (ret)
    190			dev_err(l2->dev, "Invalid value of '%s'\n", propname);
    191	}
    192
    193	return ret;
    194}
    195
    196static int l2_ctl_of_parse(struct l2_ctl *l2)
    197{
    198	int ret;
    199
    200	ret = l2_ctl_of_parse_property(l2, L2_WS_STALL, "baikal,l2-ws-latency");
    201	if (ret)
    202		return ret;
    203
    204	ret = l2_ctl_of_parse_property(l2, L2_TAG_STALL, "baikal,l2-tag-latency");
    205	if (ret)
    206		return ret;
    207
    208	return l2_ctl_of_parse_property(l2, L2_DATA_STALL,
    209					"baikal,l2-data-latency");
    210}
    211
    212static ssize_t l2_ctl_latency_show(struct device *dev,
    213				   struct device_attribute *attr,
    214				   char *buf)
    215{
    216	struct l2_ctl_device_attribute *devattr = to_l2_ctl_dev_attr(attr);
    217	struct l2_ctl *l2 = dev_get_drvdata(dev);
    218	u32 data;
    219	int ret;
    220
    221	ret = l2_ctl_get_latency(l2, devattr->id, &data);
    222	if (ret)
    223		return ret;
    224
    225	return scnprintf(buf, PAGE_SIZE, "%u\n", data);
    226}
    227
    228static ssize_t l2_ctl_latency_store(struct device *dev,
    229				    struct device_attribute *attr,
    230				    const char *buf, size_t count)
    231{
    232	struct l2_ctl_device_attribute *devattr = to_l2_ctl_dev_attr(attr);
    233	struct l2_ctl *l2 = dev_get_drvdata(dev);
    234	u32 data;
    235	int ret;
    236
    237	if (kstrtouint(buf, 0, &data) < 0)
    238		return -EINVAL;
    239
    240	ret = l2_ctl_set_latency(l2, devattr->id, data);
    241	if (ret)
    242		return ret;
    243
    244	return count;
    245}
    246
    247static L2_CTL_ATTR_RW(l2_ws_latency, l2_ctl_latency, L2_WS_STALL);
    248static L2_CTL_ATTR_RW(l2_tag_latency, l2_ctl_latency, L2_TAG_STALL);
    249static L2_CTL_ATTR_RW(l2_data_latency, l2_ctl_latency, L2_DATA_STALL);
    250
    251static struct attribute *l2_ctl_sysfs_attrs[] = {
    252	&l2_ctl_attr_l2_ws_latency.dev_attr.attr,
    253	&l2_ctl_attr_l2_tag_latency.dev_attr.attr,
    254	&l2_ctl_attr_l2_data_latency.dev_attr.attr,
    255	NULL
    256};
    257ATTRIBUTE_GROUPS(l2_ctl_sysfs);
    258
    259static void l2_ctl_remove_sysfs(void *data)
    260{
    261	struct l2_ctl *l2 = data;
    262
    263	device_remove_groups(l2->dev, l2_ctl_sysfs_groups);
    264}
    265
    266static int l2_ctl_init_sysfs(struct l2_ctl *l2)
    267{
    268	int ret;
    269
    270	ret = device_add_groups(l2->dev, l2_ctl_sysfs_groups);
    271	if (ret) {
    272		dev_err(l2->dev, "Failed to create L2 CTL sysfs nodes\n");
    273		return ret;
    274	}
    275
    276	ret = devm_add_action_or_reset(l2->dev, l2_ctl_remove_sysfs, l2);
    277	if (ret)
    278		dev_err(l2->dev, "Can't add L2 CTL sysfs remove action\n");
    279
    280	return ret;
    281}
    282
    283static int l2_ctl_probe(struct platform_device *pdev)
    284{
    285	struct l2_ctl *l2;
    286	int ret;
    287
    288	l2 = l2_ctl_create_data(pdev);
    289	if (IS_ERR(l2))
    290		return PTR_ERR(l2);
    291
    292	ret = l2_ctl_find_sys_regs(l2);
    293	if (ret)
    294		return ret;
    295
    296	ret = l2_ctl_of_parse(l2);
    297	if (ret)
    298		return ret;
    299
    300	ret = l2_ctl_init_sysfs(l2);
    301	if (ret)
    302		return ret;
    303
    304	return 0;
    305}
    306
    307static const struct of_device_id l2_ctl_of_match[] = {
    308	{ .compatible = "baikal,bt1-l2-ctl" },
    309	{ }
    310};
    311MODULE_DEVICE_TABLE(of, l2_ctl_of_match);
    312
    313static struct platform_driver l2_ctl_driver = {
    314	.probe = l2_ctl_probe,
    315	.driver = {
    316		.name = "bt1-l2-ctl",
    317		.of_match_table = l2_ctl_of_match
    318	}
    319};
    320module_platform_driver(l2_ctl_driver);
    321
    322MODULE_AUTHOR("Serge Semin <Sergey.Semin@baikalelectronics.ru>");
    323MODULE_DESCRIPTION("Baikal-T1 L2-cache driver");
    324MODULE_LICENSE("GPL v2");