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

voltage.c (10970B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * System Control and Management Interface (SCMI) Voltage Protocol
      4 *
      5 * Copyright (C) 2020-2022 ARM Ltd.
      6 */
      7
      8#include <linux/module.h>
      9#include <linux/scmi_protocol.h>
     10
     11#include "protocols.h"
     12
     13#define VOLTAGE_DOMS_NUM_MASK		GENMASK(15, 0)
     14#define REMAINING_LEVELS_MASK		GENMASK(31, 16)
     15#define RETURNED_LEVELS_MASK		GENMASK(11, 0)
     16
     17enum scmi_voltage_protocol_cmd {
     18	VOLTAGE_DOMAIN_ATTRIBUTES = 0x3,
     19	VOLTAGE_DESCRIBE_LEVELS = 0x4,
     20	VOLTAGE_CONFIG_SET = 0x5,
     21	VOLTAGE_CONFIG_GET = 0x6,
     22	VOLTAGE_LEVEL_SET = 0x7,
     23	VOLTAGE_LEVEL_GET = 0x8,
     24	VOLTAGE_DOMAIN_NAME_GET = 0x09,
     25};
     26
     27#define NUM_VOLTAGE_DOMAINS(x)	((u16)(FIELD_GET(VOLTAGE_DOMS_NUM_MASK, (x))))
     28
     29struct scmi_msg_resp_domain_attributes {
     30	__le32 attr;
     31#define SUPPORTS_ASYNC_LEVEL_SET(x)	((x) & BIT(31))
     32#define SUPPORTS_EXTENDED_NAMES(x)	((x) & BIT(30))
     33	u8 name[SCMI_SHORT_NAME_MAX_SIZE];
     34};
     35
     36struct scmi_msg_cmd_describe_levels {
     37	__le32 domain_id;
     38	__le32 level_index;
     39};
     40
     41struct scmi_msg_resp_describe_levels {
     42	__le32 flags;
     43#define NUM_REMAINING_LEVELS(f)	((u16)(FIELD_GET(REMAINING_LEVELS_MASK, (f))))
     44#define NUM_RETURNED_LEVELS(f)	((u16)(FIELD_GET(RETURNED_LEVELS_MASK, (f))))
     45#define SUPPORTS_SEGMENTED_LEVELS(f)	((f) & BIT(12))
     46	__le32 voltage[];
     47};
     48
     49struct scmi_msg_cmd_config_set {
     50	__le32 domain_id;
     51	__le32 config;
     52};
     53
     54struct scmi_msg_cmd_level_set {
     55	__le32 domain_id;
     56	__le32 flags;
     57	__le32 voltage_level;
     58};
     59
     60struct scmi_resp_voltage_level_set_complete {
     61	__le32 domain_id;
     62	__le32 voltage_level;
     63};
     64
     65struct voltage_info {
     66	unsigned int version;
     67	unsigned int num_domains;
     68	struct scmi_voltage_info *domains;
     69};
     70
     71static int scmi_protocol_attributes_get(const struct scmi_protocol_handle *ph,
     72					struct voltage_info *vinfo)
     73{
     74	int ret;
     75	struct scmi_xfer *t;
     76
     77	ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES, 0,
     78				      sizeof(__le32), &t);
     79	if (ret)
     80		return ret;
     81
     82	ret = ph->xops->do_xfer(ph, t);
     83	if (!ret)
     84		vinfo->num_domains =
     85			NUM_VOLTAGE_DOMAINS(get_unaligned_le32(t->rx.buf));
     86
     87	ph->xops->xfer_put(ph, t);
     88	return ret;
     89}
     90
     91static int scmi_init_voltage_levels(struct device *dev,
     92				    struct scmi_voltage_info *v,
     93				    u32 num_returned, u32 num_remaining,
     94				    bool segmented)
     95{
     96	u32 num_levels;
     97
     98	num_levels = num_returned + num_remaining;
     99	/*
    100	 * segmented levels entries are represented by a single triplet
    101	 * returned all in one go.
    102	 */
    103	if (!num_levels ||
    104	    (segmented && (num_remaining || num_returned != 3))) {
    105		dev_err(dev,
    106			"Invalid level descriptor(%d/%d/%d) for voltage dom %d\n",
    107			num_levels, num_returned, num_remaining, v->id);
    108		return -EINVAL;
    109	}
    110
    111	v->levels_uv = devm_kcalloc(dev, num_levels, sizeof(u32), GFP_KERNEL);
    112	if (!v->levels_uv)
    113		return -ENOMEM;
    114
    115	v->num_levels = num_levels;
    116	v->segmented = segmented;
    117
    118	return 0;
    119}
    120
    121struct scmi_volt_ipriv {
    122	struct device *dev;
    123	struct scmi_voltage_info *v;
    124};
    125
    126static void iter_volt_levels_prepare_message(void *message,
    127					     unsigned int desc_index,
    128					     const void *priv)
    129{
    130	struct scmi_msg_cmd_describe_levels *msg = message;
    131	const struct scmi_volt_ipriv *p = priv;
    132
    133	msg->domain_id = cpu_to_le32(p->v->id);
    134	msg->level_index = cpu_to_le32(desc_index);
    135}
    136
    137static int iter_volt_levels_update_state(struct scmi_iterator_state *st,
    138					 const void *response, void *priv)
    139{
    140	int ret = 0;
    141	u32 flags;
    142	const struct scmi_msg_resp_describe_levels *r = response;
    143	struct scmi_volt_ipriv *p = priv;
    144
    145	flags = le32_to_cpu(r->flags);
    146	st->num_returned = NUM_RETURNED_LEVELS(flags);
    147	st->num_remaining = NUM_REMAINING_LEVELS(flags);
    148
    149	/* Allocate space for num_levels if not already done */
    150	if (!p->v->num_levels) {
    151		ret = scmi_init_voltage_levels(p->dev, p->v, st->num_returned,
    152					       st->num_remaining,
    153					      SUPPORTS_SEGMENTED_LEVELS(flags));
    154		if (!ret)
    155			st->max_resources = p->v->num_levels;
    156	}
    157
    158	return ret;
    159}
    160
    161static int
    162iter_volt_levels_process_response(const struct scmi_protocol_handle *ph,
    163				  const void *response,
    164				  struct scmi_iterator_state *st, void *priv)
    165{
    166	s32 val;
    167	const struct scmi_msg_resp_describe_levels *r = response;
    168	struct scmi_volt_ipriv *p = priv;
    169
    170	val = (s32)le32_to_cpu(r->voltage[st->loop_idx]);
    171	p->v->levels_uv[st->desc_index + st->loop_idx] = val;
    172	if (val < 0)
    173		p->v->negative_volts_allowed = true;
    174
    175	return 0;
    176}
    177
    178static int scmi_voltage_levels_get(const struct scmi_protocol_handle *ph,
    179				   struct scmi_voltage_info *v)
    180{
    181	int ret;
    182	void *iter;
    183	struct scmi_iterator_ops ops = {
    184		.prepare_message = iter_volt_levels_prepare_message,
    185		.update_state = iter_volt_levels_update_state,
    186		.process_response = iter_volt_levels_process_response,
    187	};
    188	struct scmi_volt_ipriv vpriv = {
    189		.dev = ph->dev,
    190		.v = v,
    191	};
    192
    193	iter = ph->hops->iter_response_init(ph, &ops, v->num_levels,
    194					    VOLTAGE_DESCRIBE_LEVELS,
    195					    sizeof(struct scmi_msg_cmd_describe_levels),
    196					    &vpriv);
    197	if (IS_ERR(iter))
    198		return PTR_ERR(iter);
    199
    200	ret = ph->hops->iter_response_run(iter);
    201	if (ret) {
    202		v->num_levels = 0;
    203		devm_kfree(ph->dev, v->levels_uv);
    204	}
    205
    206	return ret;
    207}
    208
    209static int scmi_voltage_descriptors_get(const struct scmi_protocol_handle *ph,
    210					struct voltage_info *vinfo)
    211{
    212	int ret, dom;
    213	struct scmi_xfer *td;
    214	struct scmi_msg_resp_domain_attributes *resp_dom;
    215
    216	ret = ph->xops->xfer_get_init(ph, VOLTAGE_DOMAIN_ATTRIBUTES,
    217				      sizeof(__le32), sizeof(*resp_dom), &td);
    218	if (ret)
    219		return ret;
    220	resp_dom = td->rx.buf;
    221
    222	for (dom = 0; dom < vinfo->num_domains; dom++) {
    223		u32 attributes;
    224		struct scmi_voltage_info *v;
    225
    226		/* Retrieve domain attributes at first ... */
    227		put_unaligned_le32(dom, td->tx.buf);
    228		/* Skip domain on comms error */
    229		if (ph->xops->do_xfer(ph, td))
    230			continue;
    231
    232		v = vinfo->domains + dom;
    233		v->id = dom;
    234		attributes = le32_to_cpu(resp_dom->attr);
    235		strscpy(v->name, resp_dom->name, SCMI_SHORT_NAME_MAX_SIZE);
    236
    237		/*
    238		 * If supported overwrite short name with the extended one;
    239		 * on error just carry on and use already provided short name.
    240		 */
    241		if (PROTOCOL_REV_MAJOR(vinfo->version) >= 0x2) {
    242			if (SUPPORTS_EXTENDED_NAMES(attributes))
    243				ph->hops->extended_name_get(ph,
    244							VOLTAGE_DOMAIN_NAME_GET,
    245							v->id, v->name,
    246							SCMI_MAX_STR_SIZE);
    247			if (SUPPORTS_ASYNC_LEVEL_SET(attributes))
    248				v->async_level_set = true;
    249		}
    250
    251		/* Skip invalid voltage descriptors */
    252		scmi_voltage_levels_get(ph, v);
    253	}
    254
    255	ph->xops->xfer_put(ph, td);
    256
    257	return ret;
    258}
    259
    260static int __scmi_voltage_get_u32(const struct scmi_protocol_handle *ph,
    261				  u8 cmd_id, u32 domain_id, u32 *value)
    262{
    263	int ret;
    264	struct scmi_xfer *t;
    265	struct voltage_info *vinfo = ph->get_priv(ph);
    266
    267	if (domain_id >= vinfo->num_domains)
    268		return -EINVAL;
    269
    270	ret = ph->xops->xfer_get_init(ph, cmd_id, sizeof(__le32), 0, &t);
    271	if (ret)
    272		return ret;
    273
    274	put_unaligned_le32(domain_id, t->tx.buf);
    275	ret = ph->xops->do_xfer(ph, t);
    276	if (!ret)
    277		*value = get_unaligned_le32(t->rx.buf);
    278
    279	ph->xops->xfer_put(ph, t);
    280	return ret;
    281}
    282
    283static int scmi_voltage_config_set(const struct scmi_protocol_handle *ph,
    284				   u32 domain_id, u32 config)
    285{
    286	int ret;
    287	struct scmi_xfer *t;
    288	struct voltage_info *vinfo = ph->get_priv(ph);
    289	struct scmi_msg_cmd_config_set *cmd;
    290
    291	if (domain_id >= vinfo->num_domains)
    292		return -EINVAL;
    293
    294	ret = ph->xops->xfer_get_init(ph, VOLTAGE_CONFIG_SET,
    295				     sizeof(*cmd), 0, &t);
    296	if (ret)
    297		return ret;
    298
    299	cmd = t->tx.buf;
    300	cmd->domain_id = cpu_to_le32(domain_id);
    301	cmd->config = cpu_to_le32(config & GENMASK(3, 0));
    302
    303	ret = ph->xops->do_xfer(ph, t);
    304
    305	ph->xops->xfer_put(ph, t);
    306	return ret;
    307}
    308
    309static int scmi_voltage_config_get(const struct scmi_protocol_handle *ph,
    310				   u32 domain_id, u32 *config)
    311{
    312	return __scmi_voltage_get_u32(ph, VOLTAGE_CONFIG_GET,
    313				      domain_id, config);
    314}
    315
    316static int scmi_voltage_level_set(const struct scmi_protocol_handle *ph,
    317				  u32 domain_id,
    318				  enum scmi_voltage_level_mode mode,
    319				  s32 volt_uV)
    320{
    321	int ret;
    322	struct scmi_xfer *t;
    323	struct voltage_info *vinfo = ph->get_priv(ph);
    324	struct scmi_msg_cmd_level_set *cmd;
    325	struct scmi_voltage_info *v;
    326
    327	if (domain_id >= vinfo->num_domains)
    328		return -EINVAL;
    329
    330	ret = ph->xops->xfer_get_init(ph, VOLTAGE_LEVEL_SET,
    331				      sizeof(*cmd), 0, &t);
    332	if (ret)
    333		return ret;
    334
    335	v = vinfo->domains + domain_id;
    336
    337	cmd = t->tx.buf;
    338	cmd->domain_id = cpu_to_le32(domain_id);
    339	cmd->voltage_level = cpu_to_le32(volt_uV);
    340
    341	if (!v->async_level_set || mode != SCMI_VOLTAGE_LEVEL_SET_AUTO) {
    342		cmd->flags = cpu_to_le32(0x0);
    343		ret = ph->xops->do_xfer(ph, t);
    344	} else {
    345		cmd->flags = cpu_to_le32(0x1);
    346		ret = ph->xops->do_xfer_with_response(ph, t);
    347		if (!ret) {
    348			struct scmi_resp_voltage_level_set_complete *resp;
    349
    350			resp = t->rx.buf;
    351			if (le32_to_cpu(resp->domain_id) == domain_id)
    352				dev_dbg(ph->dev,
    353					"Voltage domain %d set async to %d\n",
    354					v->id,
    355					le32_to_cpu(resp->voltage_level));
    356			else
    357				ret = -EPROTO;
    358		}
    359	}
    360
    361	ph->xops->xfer_put(ph, t);
    362	return ret;
    363}
    364
    365static int scmi_voltage_level_get(const struct scmi_protocol_handle *ph,
    366				  u32 domain_id, s32 *volt_uV)
    367{
    368	return __scmi_voltage_get_u32(ph, VOLTAGE_LEVEL_GET,
    369				      domain_id, (u32 *)volt_uV);
    370}
    371
    372static const struct scmi_voltage_info * __must_check
    373scmi_voltage_info_get(const struct scmi_protocol_handle *ph, u32 domain_id)
    374{
    375	struct voltage_info *vinfo = ph->get_priv(ph);
    376
    377	if (domain_id >= vinfo->num_domains ||
    378	    !vinfo->domains[domain_id].num_levels)
    379		return NULL;
    380
    381	return vinfo->domains + domain_id;
    382}
    383
    384static int scmi_voltage_domains_num_get(const struct scmi_protocol_handle *ph)
    385{
    386	struct voltage_info *vinfo = ph->get_priv(ph);
    387
    388	return vinfo->num_domains;
    389}
    390
    391static struct scmi_voltage_proto_ops voltage_proto_ops = {
    392	.num_domains_get = scmi_voltage_domains_num_get,
    393	.info_get = scmi_voltage_info_get,
    394	.config_set = scmi_voltage_config_set,
    395	.config_get = scmi_voltage_config_get,
    396	.level_set = scmi_voltage_level_set,
    397	.level_get = scmi_voltage_level_get,
    398};
    399
    400static int scmi_voltage_protocol_init(const struct scmi_protocol_handle *ph)
    401{
    402	int ret;
    403	u32 version;
    404	struct voltage_info *vinfo;
    405
    406	ret = ph->xops->version_get(ph, &version);
    407	if (ret)
    408		return ret;
    409
    410	dev_dbg(ph->dev, "Voltage Version %d.%d\n",
    411		PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
    412
    413	vinfo = devm_kzalloc(ph->dev, sizeof(*vinfo), GFP_KERNEL);
    414	if (!vinfo)
    415		return -ENOMEM;
    416	vinfo->version = version;
    417
    418	ret = scmi_protocol_attributes_get(ph, vinfo);
    419	if (ret)
    420		return ret;
    421
    422	if (vinfo->num_domains) {
    423		vinfo->domains = devm_kcalloc(ph->dev, vinfo->num_domains,
    424					      sizeof(*vinfo->domains),
    425					      GFP_KERNEL);
    426		if (!vinfo->domains)
    427			return -ENOMEM;
    428		ret = scmi_voltage_descriptors_get(ph, vinfo);
    429		if (ret)
    430			return ret;
    431	} else {
    432		dev_warn(ph->dev, "No Voltage domains found.\n");
    433	}
    434
    435	return ph->set_priv(ph, vinfo);
    436}
    437
    438static const struct scmi_protocol scmi_voltage = {
    439	.id = SCMI_PROTOCOL_VOLTAGE,
    440	.owner = THIS_MODULE,
    441	.instance_init = &scmi_voltage_protocol_init,
    442	.ops = &voltage_proto_ops,
    443};
    444
    445DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(voltage, scmi_voltage)