596 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * A hwmon driver for the IBM PowerExecutive temperature/power sensors4 * Copyright (C) 2007 IBM5 *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 122#define PEX_GET_SENSOR_COUNT 223#define PEX_GET_SENSOR_NAME 324#define PEX_RESET_HIGH_LOW 425#define PEX_GET_SENSOR_DATA 626 27#define PEX_NET_FUNCTION 0x3A28#define PEX_COMMAND 0x3C29 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 136#define POWER_SENSOR 237 38#define PEX_SENSOR_TYPE_LEN 339static u8 const power_sensor_sig[] = {0x70, 0x77, 0x72};40static u8 const temp_sensor_sig[] = {0x74, 0x65, 0x6D};41 42#define PEX_MULT_LEN 243static u8 const watt_sensor_sig[] = {0x41, 0x43};44 45#define PEX_NUM_SENSOR_FUNCS 346static 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 DEVICE_STRING_ATTR_RO(name, 0444, DRVNAME);260 261static ssize_t ibmpex_show_sensor(struct device *dev,262 struct device_attribute *devattr,263 char *buf)264{265 struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);266 struct ibmpex_bmc_data *data = dev_get_drvdata(dev);267 int mult = data->sensors[attr->index].multiplier;268 ibmpex_update_device(data);269 270 return sprintf(buf, "%d\n",271 data->sensors[attr->index].values[attr->nr] * mult);272}273 274static ssize_t ibmpex_high_low_store(struct device *dev,275 struct device_attribute *devattr,276 const char *buf, size_t count)277{278 struct ibmpex_bmc_data *data = dev_get_drvdata(dev);279 280 ibmpex_reset_high_low_data(data);281 282 return count;283}284 285static SENSOR_DEVICE_ATTR_WO(reset_high_low, ibmpex_high_low, 0);286 287static int is_power_sensor(const char *sensor_id, int len)288{289 if (len < PEX_SENSOR_TYPE_LEN)290 return 0;291 292 if (!memcmp(sensor_id, power_sensor_sig, PEX_SENSOR_TYPE_LEN))293 return 1;294 return 0;295}296 297static int is_temp_sensor(const char *sensor_id, int len)298{299 if (len < PEX_SENSOR_TYPE_LEN)300 return 0;301 302 if (!memcmp(sensor_id, temp_sensor_sig, PEX_SENSOR_TYPE_LEN))303 return 1;304 return 0;305}306 307static int power_sensor_multiplier(struct ibmpex_bmc_data *data,308 const char *sensor_id, int len)309{310 int i;311 312 if (data->sensor_major == 2)313 return 1000000;314 315 for (i = PEX_SENSOR_TYPE_LEN; i < len - 1; i++)316 if (!memcmp(&sensor_id[i], watt_sensor_sig, PEX_MULT_LEN))317 return 1000000;318 319 return 100000;320}321 322static int create_sensor(struct ibmpex_bmc_data *data, int type,323 int counter, int sensor, int func)324{325 int err;326 char *n;327 328 n = kmalloc(32, GFP_KERNEL);329 if (!n)330 return -ENOMEM;331 332 if (type == TEMP_SENSOR)333 sprintf(n, "temp%d_input%s",334 counter, sensor_name_suffixes[func]);335 else if (type == POWER_SENSOR)336 sprintf(n, "power%d_average%s",337 counter, sensor_name_suffixes[func]);338 339 sysfs_attr_init(&data->sensors[sensor].attr[func].dev_attr.attr);340 data->sensors[sensor].attr[func].dev_attr.attr.name = n;341 data->sensors[sensor].attr[func].dev_attr.attr.mode = 0444;342 data->sensors[sensor].attr[func].dev_attr.show = ibmpex_show_sensor;343 data->sensors[sensor].attr[func].index = sensor;344 data->sensors[sensor].attr[func].nr = func;345 346 err = device_create_file(data->bmc_device,347 &data->sensors[sensor].attr[func].dev_attr);348 if (err) {349 data->sensors[sensor].attr[func].dev_attr.attr.name = NULL;350 kfree(n);351 return err;352 }353 354 return 0;355}356 357static int ibmpex_find_sensors(struct ibmpex_bmc_data *data)358{359 int i, j, err;360 int sensor_type;361 int sensor_counter;362 int num_power = 0;363 int num_temp = 0;364 365 err = ibmpex_query_sensor_count(data);366 if (err <= 0)367 return -ENOENT;368 data->num_sensors = err;369 370 data->sensors = kcalloc(data->num_sensors, sizeof(*data->sensors),371 GFP_KERNEL);372 if (!data->sensors)373 return -ENOMEM;374 375 for (i = 0; i < data->num_sensors; i++) {376 err = ibmpex_query_sensor_name(data, i);377 if (err)378 continue;379 380 if (is_power_sensor(data->rx_msg_data, data->rx_msg_len)) {381 sensor_type = POWER_SENSOR;382 num_power++;383 sensor_counter = num_power;384 data->sensors[i].multiplier =385 power_sensor_multiplier(data,386 data->rx_msg_data,387 data->rx_msg_len);388 } else if (is_temp_sensor(data->rx_msg_data,389 data->rx_msg_len)) {390 sensor_type = TEMP_SENSOR;391 num_temp++;392 sensor_counter = num_temp;393 data->sensors[i].multiplier = 1000;394 } else395 continue;396 397 data->sensors[i].in_use = 1;398 399 /* Create attributes */400 for (j = 0; j < PEX_NUM_SENSOR_FUNCS; j++) {401 err = create_sensor(data, sensor_type, sensor_counter,402 i, j);403 if (err)404 goto exit_remove;405 }406 }407 408 err = device_create_file(data->bmc_device,409 &sensor_dev_attr_reset_high_low.dev_attr);410 if (err)411 goto exit_remove;412 413 err = device_create_file(data->bmc_device, &dev_attr_name.attr);414 if (err)415 goto exit_remove;416 417 return 0;418 419exit_remove:420 device_remove_file(data->bmc_device,421 &sensor_dev_attr_reset_high_low.dev_attr);422 device_remove_file(data->bmc_device, &dev_attr_name.attr);423 for (i = 0; i < data->num_sensors; i++)424 for (j = 0; j < PEX_NUM_SENSOR_FUNCS; j++) {425 if (!data->sensors[i].attr[j].dev_attr.attr.name)426 continue;427 device_remove_file(data->bmc_device,428 &data->sensors[i].attr[j].dev_attr);429 kfree(data->sensors[i].attr[j].dev_attr.attr.name);430 }431 432 kfree(data->sensors);433 return err;434}435 436static void ibmpex_register_bmc(int iface, struct device *dev)437{438 struct ibmpex_bmc_data *data;439 int err;440 441 data = kzalloc(sizeof(*data), GFP_KERNEL);442 if (!data)443 return;444 445 data->address.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;446 data->address.channel = IPMI_BMC_CHANNEL;447 data->address.data[0] = 0;448 data->interface = iface;449 data->bmc_device = dev;450 451 /* Create IPMI messaging interface user */452 err = ipmi_create_user(data->interface, &driver_data.ipmi_hndlrs,453 data, &data->user);454 if (err < 0) {455 dev_err(dev,456 "Unable to register user with IPMI interface %d\n",457 data->interface);458 goto out;459 }460 461 mutex_init(&data->lock);462 463 /* Initialize message */464 data->tx_msgid = 0;465 init_completion(&data->read_complete);466 data->tx_message.netfn = PEX_NET_FUNCTION;467 data->tx_message.cmd = PEX_COMMAND;468 data->tx_message.data = data->tx_msg_data;469 470 /* Does this BMC support PowerExecutive? */471 err = ibmpex_ver_check(data);472 if (err)473 goto out_user;474 475 /* Register the BMC as a HWMON class device */476 data->hwmon_dev = hwmon_device_register(data->bmc_device);477 478 if (IS_ERR(data->hwmon_dev)) {479 dev_err(data->bmc_device,480 "Unable to register hwmon device for IPMI interface %d\n",481 data->interface);482 goto out_user;483 }484 485 /* finally add the new bmc data to the bmc data list */486 dev_set_drvdata(dev, data);487 list_add_tail(&data->list, &driver_data.bmc_data);488 489 /* Now go find all the sensors */490 err = ibmpex_find_sensors(data);491 if (err) {492 dev_err(data->bmc_device, "Error %d finding sensors\n", err);493 goto out_register;494 }495 496 return;497 498out_register:499 list_del(&data->list);500 hwmon_device_unregister(data->hwmon_dev);501out_user:502 ipmi_destroy_user(data->user);503out:504 kfree(data);505}506 507static void ibmpex_bmc_delete(struct ibmpex_bmc_data *data)508{509 int i, j;510 511 device_remove_file(data->bmc_device,512 &sensor_dev_attr_reset_high_low.dev_attr);513 device_remove_file(data->bmc_device, &dev_attr_name.attr);514 for (i = 0; i < data->num_sensors; i++)515 for (j = 0; j < PEX_NUM_SENSOR_FUNCS; j++) {516 if (!data->sensors[i].attr[j].dev_attr.attr.name)517 continue;518 device_remove_file(data->bmc_device,519 &data->sensors[i].attr[j].dev_attr);520 kfree(data->sensors[i].attr[j].dev_attr.attr.name);521 }522 523 list_del(&data->list);524 dev_set_drvdata(data->bmc_device, NULL);525 hwmon_device_unregister(data->hwmon_dev);526 ipmi_destroy_user(data->user);527 kfree(data->sensors);528 kfree(data);529}530 531static void ibmpex_bmc_gone(int iface)532{533 struct ibmpex_bmc_data *data = get_bmc_data(iface);534 535 if (!data)536 return;537 538 ibmpex_bmc_delete(data);539}540 541static void ibmpex_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data)542{543 struct ibmpex_bmc_data *data = user_msg_data;544 545 if (msg->msgid != data->tx_msgid) {546 dev_err(data->bmc_device,547 "Mismatch between received msgid (%02x) and transmitted msgid (%02x)!\n",548 (int)msg->msgid,549 (int)data->tx_msgid);550 ipmi_free_recv_msg(msg);551 return;552 }553 554 data->rx_recv_type = msg->recv_type;555 if (msg->msg.data_len > 0)556 data->rx_result = msg->msg.data[0];557 else558 data->rx_result = IPMI_UNKNOWN_ERR_COMPLETION_CODE;559 560 if (msg->msg.data_len > 1) {561 data->rx_msg_len = msg->msg.data_len - 1;562 memcpy(data->rx_msg_data, msg->msg.data + 1, data->rx_msg_len);563 } else564 data->rx_msg_len = 0;565 566 ipmi_free_recv_msg(msg);567 complete(&data->read_complete);568}569 570static int __init ibmpex_init(void)571{572 return ipmi_smi_watcher_register(&driver_data.bmc_events);573}574 575static void __exit ibmpex_exit(void)576{577 struct ibmpex_bmc_data *p, *next;578 579 ipmi_smi_watcher_unregister(&driver_data.bmc_events);580 list_for_each_entry_safe(p, next, &driver_data.bmc_data, list)581 ibmpex_bmc_delete(p);582}583 584MODULE_AUTHOR("Darrick J. Wong <darrick.wong@oracle.com>");585MODULE_DESCRIPTION("IBM PowerExecutive power/temperature sensor driver");586MODULE_LICENSE("GPL");587 588module_init(ibmpex_init);589module_exit(ibmpex_exit);590 591MODULE_ALIAS("dmi:bvnIBM:*:pnIBMSystemx3350-*");592MODULE_ALIAS("dmi:bvnIBM:*:pnIBMSystemx3550-*");593MODULE_ALIAS("dmi:bvnIBM:*:pnIBMSystemx3650-*");594MODULE_ALIAS("dmi:bvnIBM:*:pnIBMSystemx3655-*");595MODULE_ALIAS("dmi:bvnIBM:*:pnIBMSystemx3755-*");596