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

ibmpex.c (14522B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * A hwmon driver for the IBM PowerExecutive temperature/power sensors
      4 * Copyright (C) 2007 IBM
      5 *
      6 * Author: Darrick J. Wong <darrick.wong@oracle.com>
      7 */
      8
      9#include <linux/ipmi.h>
     10#include <linux/module.h>
     11#include <linux/hwmon.h>
     12#include <linux/hwmon-sysfs.h>
     13#include <linux/jiffies.h>
     14#include <linux/mutex.h>
     15#include <linux/slab.h>
     16#include <linux/err.h>
     17
     18#define REFRESH_INTERVAL	(2 * HZ)
     19#define DRVNAME			"ibmpex"
     20
     21#define PEX_GET_VERSION		1
     22#define PEX_GET_SENSOR_COUNT	2
     23#define PEX_GET_SENSOR_NAME	3
     24#define PEX_RESET_HIGH_LOW	4
     25#define PEX_GET_SENSOR_DATA	6
     26
     27#define PEX_NET_FUNCTION	0x3A
     28#define PEX_COMMAND		0x3C
     29
     30static inline u16 extract_value(const char *data, int offset)
     31{
     32	return be16_to_cpup((__be16 *)&data[offset]);
     33}
     34
     35#define TEMP_SENSOR		1
     36#define POWER_SENSOR		2
     37
     38#define PEX_SENSOR_TYPE_LEN	3
     39static u8 const power_sensor_sig[] = {0x70, 0x77, 0x72};
     40static u8 const temp_sensor_sig[]  = {0x74, 0x65, 0x6D};
     41
     42#define PEX_MULT_LEN		2
     43static u8 const watt_sensor_sig[]  = {0x41, 0x43};
     44
     45#define PEX_NUM_SENSOR_FUNCS	3
     46static const char * const sensor_name_suffixes[] = {
     47	"",
     48	"_lowest",
     49	"_highest"
     50};
     51
     52static void ibmpex_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data);
     53static void ibmpex_register_bmc(int iface, struct device *dev);
     54static void ibmpex_bmc_gone(int iface);
     55
     56struct ibmpex_sensor_data {
     57	int			in_use;
     58	s16			values[PEX_NUM_SENSOR_FUNCS];
     59	int			multiplier;
     60
     61	struct sensor_device_attribute_2	attr[PEX_NUM_SENSOR_FUNCS];
     62};
     63
     64struct ibmpex_bmc_data {
     65	struct list_head	list;
     66	struct device		*hwmon_dev;
     67	struct device		*bmc_device;
     68	struct mutex		lock;
     69	bool			valid;
     70	unsigned long		last_updated;	/* In jiffies */
     71
     72	struct ipmi_addr	address;
     73	struct completion	read_complete;
     74	struct ipmi_user	*user;
     75	int			interface;
     76
     77	struct kernel_ipmi_msg	tx_message;
     78	unsigned char		tx_msg_data[IPMI_MAX_MSG_LENGTH];
     79	long			tx_msgid;
     80
     81	unsigned char		rx_msg_data[IPMI_MAX_MSG_LENGTH];
     82	unsigned long		rx_msg_len;
     83	unsigned char		rx_result;
     84	int			rx_recv_type;
     85
     86	unsigned char		sensor_major;
     87	unsigned char		sensor_minor;
     88
     89	unsigned char		num_sensors;
     90	struct ibmpex_sensor_data	*sensors;
     91};
     92
     93struct ibmpex_driver_data {
     94	struct list_head	bmc_data;
     95	struct ipmi_smi_watcher	bmc_events;
     96	struct ipmi_user_hndl	ipmi_hndlrs;
     97};
     98
     99static struct ibmpex_driver_data driver_data = {
    100	.bmc_data = LIST_HEAD_INIT(driver_data.bmc_data),
    101	.bmc_events = {
    102		.owner = THIS_MODULE,
    103		.new_smi = ibmpex_register_bmc,
    104		.smi_gone = ibmpex_bmc_gone,
    105	},
    106	.ipmi_hndlrs = {
    107		.ipmi_recv_hndl = ibmpex_msg_handler,
    108	},
    109};
    110
    111static int ibmpex_send_message(struct ibmpex_bmc_data *data)
    112{
    113	int err;
    114
    115	err = ipmi_validate_addr(&data->address, sizeof(data->address));
    116	if (err)
    117		goto out;
    118
    119	data->tx_msgid++;
    120	err = ipmi_request_settime(data->user, &data->address, data->tx_msgid,
    121				   &data->tx_message, data, 0, 0, 0);
    122	if (err)
    123		goto out1;
    124
    125	return 0;
    126out1:
    127	dev_err(data->bmc_device, "request_settime=%x\n", err);
    128	return err;
    129out:
    130	dev_err(data->bmc_device, "validate_addr=%x\n", err);
    131	return err;
    132}
    133
    134static int ibmpex_ver_check(struct ibmpex_bmc_data *data)
    135{
    136	data->tx_msg_data[0] = PEX_GET_VERSION;
    137	data->tx_message.data_len = 1;
    138	ibmpex_send_message(data);
    139
    140	wait_for_completion(&data->read_complete);
    141
    142	if (data->rx_result || data->rx_msg_len != 6)
    143		return -ENOENT;
    144
    145	data->sensor_major = data->rx_msg_data[0];
    146	data->sensor_minor = data->rx_msg_data[1];
    147
    148	dev_info(data->bmc_device,
    149		 "Found BMC with sensor interface v%d.%d %d-%02d-%02d on interface %d\n",
    150		 data->sensor_major,
    151		 data->sensor_minor,
    152		 extract_value(data->rx_msg_data, 2),
    153		 data->rx_msg_data[4],
    154		 data->rx_msg_data[5],
    155		 data->interface);
    156
    157	return 0;
    158}
    159
    160static int ibmpex_query_sensor_count(struct ibmpex_bmc_data *data)
    161{
    162	data->tx_msg_data[0] = PEX_GET_SENSOR_COUNT;
    163	data->tx_message.data_len = 1;
    164	ibmpex_send_message(data);
    165
    166	wait_for_completion(&data->read_complete);
    167
    168	if (data->rx_result || data->rx_msg_len != 1)
    169		return -ENOENT;
    170
    171	return data->rx_msg_data[0];
    172}
    173
    174static int ibmpex_query_sensor_name(struct ibmpex_bmc_data *data, int sensor)
    175{
    176	data->tx_msg_data[0] = PEX_GET_SENSOR_NAME;
    177	data->tx_msg_data[1] = sensor;
    178	data->tx_message.data_len = 2;
    179	ibmpex_send_message(data);
    180
    181	wait_for_completion(&data->read_complete);
    182
    183	if (data->rx_result || data->rx_msg_len < 1)
    184		return -ENOENT;
    185
    186	return 0;
    187}
    188
    189static int ibmpex_query_sensor_data(struct ibmpex_bmc_data *data, int sensor)
    190{
    191	data->tx_msg_data[0] = PEX_GET_SENSOR_DATA;
    192	data->tx_msg_data[1] = sensor;
    193	data->tx_message.data_len = 2;
    194	ibmpex_send_message(data);
    195
    196	wait_for_completion(&data->read_complete);
    197
    198	if (data->rx_result || data->rx_msg_len < 26) {
    199		dev_err(data->bmc_device, "Error reading sensor %d.\n",
    200			sensor);
    201		return -ENOENT;
    202	}
    203
    204	return 0;
    205}
    206
    207static int ibmpex_reset_high_low_data(struct ibmpex_bmc_data *data)
    208{
    209	data->tx_msg_data[0] = PEX_RESET_HIGH_LOW;
    210	data->tx_message.data_len = 1;
    211	ibmpex_send_message(data);
    212
    213	wait_for_completion(&data->read_complete);
    214
    215	return 0;
    216}
    217
    218static void ibmpex_update_device(struct ibmpex_bmc_data *data)
    219{
    220	int i, err;
    221
    222	mutex_lock(&data->lock);
    223	if (time_before(jiffies, data->last_updated + REFRESH_INTERVAL) &&
    224	    data->valid)
    225		goto out;
    226
    227	for (i = 0; i < data->num_sensors; i++) {
    228		if (!data->sensors[i].in_use)
    229			continue;
    230		err = ibmpex_query_sensor_data(data, i);
    231		if (err)
    232			continue;
    233		data->sensors[i].values[0] =
    234			extract_value(data->rx_msg_data, 16);
    235		data->sensors[i].values[1] =
    236			extract_value(data->rx_msg_data, 18);
    237		data->sensors[i].values[2] =
    238			extract_value(data->rx_msg_data, 20);
    239	}
    240
    241	data->last_updated = jiffies;
    242	data->valid = true;
    243
    244out:
    245	mutex_unlock(&data->lock);
    246}
    247
    248static struct ibmpex_bmc_data *get_bmc_data(int iface)
    249{
    250	struct ibmpex_bmc_data *p, *next;
    251
    252	list_for_each_entry_safe(p, next, &driver_data.bmc_data, list)
    253		if (p->interface == iface)
    254			return p;
    255
    256	return NULL;
    257}
    258
    259static ssize_t name_show(struct device *dev, struct device_attribute *devattr,
    260			 char *buf)
    261{
    262	return sprintf(buf, "%s\n", DRVNAME);
    263}
    264static SENSOR_DEVICE_ATTR_RO(name, name, 0);
    265
    266static ssize_t ibmpex_show_sensor(struct device *dev,
    267				  struct device_attribute *devattr,
    268				  char *buf)
    269{
    270	struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
    271	struct ibmpex_bmc_data *data = dev_get_drvdata(dev);
    272	int mult = data->sensors[attr->index].multiplier;
    273	ibmpex_update_device(data);
    274
    275	return sprintf(buf, "%d\n",
    276		       data->sensors[attr->index].values[attr->nr] * mult);
    277}
    278
    279static ssize_t ibmpex_high_low_store(struct device *dev,
    280				     struct device_attribute *devattr,
    281				     const char *buf, size_t count)
    282{
    283	struct ibmpex_bmc_data *data = dev_get_drvdata(dev);
    284
    285	ibmpex_reset_high_low_data(data);
    286
    287	return count;
    288}
    289
    290static SENSOR_DEVICE_ATTR_WO(reset_high_low, ibmpex_high_low, 0);
    291
    292static int is_power_sensor(const char *sensor_id, int len)
    293{
    294	if (len < PEX_SENSOR_TYPE_LEN)
    295		return 0;
    296
    297	if (!memcmp(sensor_id, power_sensor_sig, PEX_SENSOR_TYPE_LEN))
    298		return 1;
    299	return 0;
    300}
    301
    302static int is_temp_sensor(const char *sensor_id, int len)
    303{
    304	if (len < PEX_SENSOR_TYPE_LEN)
    305		return 0;
    306
    307	if (!memcmp(sensor_id, temp_sensor_sig, PEX_SENSOR_TYPE_LEN))
    308		return 1;
    309	return 0;
    310}
    311
    312static int power_sensor_multiplier(struct ibmpex_bmc_data *data,
    313				   const char *sensor_id, int len)
    314{
    315	int i;
    316
    317	if (data->sensor_major == 2)
    318		return 1000000;
    319
    320	for (i = PEX_SENSOR_TYPE_LEN; i < len - 1; i++)
    321		if (!memcmp(&sensor_id[i], watt_sensor_sig, PEX_MULT_LEN))
    322			return 1000000;
    323
    324	return 100000;
    325}
    326
    327static int create_sensor(struct ibmpex_bmc_data *data, int type,
    328			 int counter, int sensor, int func)
    329{
    330	int err;
    331	char *n;
    332
    333	n = kmalloc(32, GFP_KERNEL);
    334	if (!n)
    335		return -ENOMEM;
    336
    337	if (type == TEMP_SENSOR)
    338		sprintf(n, "temp%d_input%s",
    339			counter, sensor_name_suffixes[func]);
    340	else if (type == POWER_SENSOR)
    341		sprintf(n, "power%d_average%s",
    342			counter, sensor_name_suffixes[func]);
    343
    344	sysfs_attr_init(&data->sensors[sensor].attr[func].dev_attr.attr);
    345	data->sensors[sensor].attr[func].dev_attr.attr.name = n;
    346	data->sensors[sensor].attr[func].dev_attr.attr.mode = 0444;
    347	data->sensors[sensor].attr[func].dev_attr.show = ibmpex_show_sensor;
    348	data->sensors[sensor].attr[func].index = sensor;
    349	data->sensors[sensor].attr[func].nr = func;
    350
    351	err = device_create_file(data->bmc_device,
    352				 &data->sensors[sensor].attr[func].dev_attr);
    353	if (err) {
    354		data->sensors[sensor].attr[func].dev_attr.attr.name = NULL;
    355		kfree(n);
    356		return err;
    357	}
    358
    359	return 0;
    360}
    361
    362static int ibmpex_find_sensors(struct ibmpex_bmc_data *data)
    363{
    364	int i, j, err;
    365	int sensor_type;
    366	int sensor_counter;
    367	int num_power = 0;
    368	int num_temp = 0;
    369
    370	err = ibmpex_query_sensor_count(data);
    371	if (err <= 0)
    372		return -ENOENT;
    373	data->num_sensors = err;
    374
    375	data->sensors = kcalloc(data->num_sensors, sizeof(*data->sensors),
    376				GFP_KERNEL);
    377	if (!data->sensors)
    378		return -ENOMEM;
    379
    380	for (i = 0; i < data->num_sensors; i++) {
    381		err = ibmpex_query_sensor_name(data, i);
    382		if (err)
    383			continue;
    384
    385		if (is_power_sensor(data->rx_msg_data, data->rx_msg_len)) {
    386			sensor_type = POWER_SENSOR;
    387			num_power++;
    388			sensor_counter = num_power;
    389			data->sensors[i].multiplier =
    390				power_sensor_multiplier(data,
    391							data->rx_msg_data,
    392							data->rx_msg_len);
    393		} else if (is_temp_sensor(data->rx_msg_data,
    394					  data->rx_msg_len)) {
    395			sensor_type = TEMP_SENSOR;
    396			num_temp++;
    397			sensor_counter = num_temp;
    398			data->sensors[i].multiplier = 1000;
    399		} else
    400			continue;
    401
    402		data->sensors[i].in_use = 1;
    403
    404		/* Create attributes */
    405		for (j = 0; j < PEX_NUM_SENSOR_FUNCS; j++) {
    406			err = create_sensor(data, sensor_type, sensor_counter,
    407					    i, j);
    408			if (err)
    409				goto exit_remove;
    410		}
    411	}
    412
    413	err = device_create_file(data->bmc_device,
    414			&sensor_dev_attr_reset_high_low.dev_attr);
    415	if (err)
    416		goto exit_remove;
    417
    418	err = device_create_file(data->bmc_device,
    419			&sensor_dev_attr_name.dev_attr);
    420	if (err)
    421		goto exit_remove;
    422
    423	return 0;
    424
    425exit_remove:
    426	device_remove_file(data->bmc_device,
    427			   &sensor_dev_attr_reset_high_low.dev_attr);
    428	device_remove_file(data->bmc_device, &sensor_dev_attr_name.dev_attr);
    429	for (i = 0; i < data->num_sensors; i++)
    430		for (j = 0; j < PEX_NUM_SENSOR_FUNCS; j++) {
    431			if (!data->sensors[i].attr[j].dev_attr.attr.name)
    432				continue;
    433			device_remove_file(data->bmc_device,
    434				&data->sensors[i].attr[j].dev_attr);
    435			kfree(data->sensors[i].attr[j].dev_attr.attr.name);
    436		}
    437
    438	kfree(data->sensors);
    439	return err;
    440}
    441
    442static void ibmpex_register_bmc(int iface, struct device *dev)
    443{
    444	struct ibmpex_bmc_data *data;
    445	int err;
    446
    447	data = kzalloc(sizeof(*data), GFP_KERNEL);
    448	if (!data)
    449		return;
    450
    451	data->address.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
    452	data->address.channel = IPMI_BMC_CHANNEL;
    453	data->address.data[0] = 0;
    454	data->interface = iface;
    455	data->bmc_device = dev;
    456
    457	/* Create IPMI messaging interface user */
    458	err = ipmi_create_user(data->interface, &driver_data.ipmi_hndlrs,
    459			       data, &data->user);
    460	if (err < 0) {
    461		dev_err(dev,
    462			"Unable to register user with IPMI interface %d\n",
    463			data->interface);
    464		goto out;
    465	}
    466
    467	mutex_init(&data->lock);
    468
    469	/* Initialize message */
    470	data->tx_msgid = 0;
    471	init_completion(&data->read_complete);
    472	data->tx_message.netfn = PEX_NET_FUNCTION;
    473	data->tx_message.cmd = PEX_COMMAND;
    474	data->tx_message.data = data->tx_msg_data;
    475
    476	/* Does this BMC support PowerExecutive? */
    477	err = ibmpex_ver_check(data);
    478	if (err)
    479		goto out_user;
    480
    481	/* Register the BMC as a HWMON class device */
    482	data->hwmon_dev = hwmon_device_register(data->bmc_device);
    483
    484	if (IS_ERR(data->hwmon_dev)) {
    485		dev_err(data->bmc_device,
    486			"Unable to register hwmon device for IPMI interface %d\n",
    487			data->interface);
    488		goto out_user;
    489	}
    490
    491	/* finally add the new bmc data to the bmc data list */
    492	dev_set_drvdata(dev, data);
    493	list_add_tail(&data->list, &driver_data.bmc_data);
    494
    495	/* Now go find all the sensors */
    496	err = ibmpex_find_sensors(data);
    497	if (err) {
    498		dev_err(data->bmc_device, "Error %d finding sensors\n", err);
    499		goto out_register;
    500	}
    501
    502	return;
    503
    504out_register:
    505	hwmon_device_unregister(data->hwmon_dev);
    506out_user:
    507	ipmi_destroy_user(data->user);
    508out:
    509	kfree(data);
    510}
    511
    512static void ibmpex_bmc_delete(struct ibmpex_bmc_data *data)
    513{
    514	int i, j;
    515
    516	device_remove_file(data->bmc_device,
    517			   &sensor_dev_attr_reset_high_low.dev_attr);
    518	device_remove_file(data->bmc_device, &sensor_dev_attr_name.dev_attr);
    519	for (i = 0; i < data->num_sensors; i++)
    520		for (j = 0; j < PEX_NUM_SENSOR_FUNCS; j++) {
    521			if (!data->sensors[i].attr[j].dev_attr.attr.name)
    522				continue;
    523			device_remove_file(data->bmc_device,
    524				&data->sensors[i].attr[j].dev_attr);
    525			kfree(data->sensors[i].attr[j].dev_attr.attr.name);
    526		}
    527
    528	list_del(&data->list);
    529	dev_set_drvdata(data->bmc_device, NULL);
    530	hwmon_device_unregister(data->hwmon_dev);
    531	ipmi_destroy_user(data->user);
    532	kfree(data->sensors);
    533	kfree(data);
    534}
    535
    536static void ibmpex_bmc_gone(int iface)
    537{
    538	struct ibmpex_bmc_data *data = get_bmc_data(iface);
    539
    540	if (!data)
    541		return;
    542
    543	ibmpex_bmc_delete(data);
    544}
    545
    546static void ibmpex_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data)
    547{
    548	struct ibmpex_bmc_data *data = (struct ibmpex_bmc_data *)user_msg_data;
    549
    550	if (msg->msgid != data->tx_msgid) {
    551		dev_err(data->bmc_device,
    552			"Mismatch between received msgid (%02x) and transmitted msgid (%02x)!\n",
    553			(int)msg->msgid,
    554			(int)data->tx_msgid);
    555		ipmi_free_recv_msg(msg);
    556		return;
    557	}
    558
    559	data->rx_recv_type = msg->recv_type;
    560	if (msg->msg.data_len > 0)
    561		data->rx_result = msg->msg.data[0];
    562	else
    563		data->rx_result = IPMI_UNKNOWN_ERR_COMPLETION_CODE;
    564
    565	if (msg->msg.data_len > 1) {
    566		data->rx_msg_len = msg->msg.data_len - 1;
    567		memcpy(data->rx_msg_data, msg->msg.data + 1, data->rx_msg_len);
    568	} else
    569		data->rx_msg_len = 0;
    570
    571	ipmi_free_recv_msg(msg);
    572	complete(&data->read_complete);
    573}
    574
    575static int __init ibmpex_init(void)
    576{
    577	return ipmi_smi_watcher_register(&driver_data.bmc_events);
    578}
    579
    580static void __exit ibmpex_exit(void)
    581{
    582	struct ibmpex_bmc_data *p, *next;
    583
    584	ipmi_smi_watcher_unregister(&driver_data.bmc_events);
    585	list_for_each_entry_safe(p, next, &driver_data.bmc_data, list)
    586		ibmpex_bmc_delete(p);
    587}
    588
    589MODULE_AUTHOR("Darrick J. Wong <darrick.wong@oracle.com>");
    590MODULE_DESCRIPTION("IBM PowerExecutive power/temperature sensor driver");
    591MODULE_LICENSE("GPL");
    592
    593module_init(ibmpex_init);
    594module_exit(ibmpex_exit);
    595
    596MODULE_ALIAS("dmi:bvnIBM:*:pnIBMSystemx3350-*");
    597MODULE_ALIAS("dmi:bvnIBM:*:pnIBMSystemx3550-*");
    598MODULE_ALIAS("dmi:bvnIBM:*:pnIBMSystemx3650-*");
    599MODULE_ALIAS("dmi:bvnIBM:*:pnIBMSystemx3655-*");
    600MODULE_ALIAS("dmi:bvnIBM:*:pnIBMSystemx3755-*");