diff options
Diffstat (limited to 'drivers/hwmon/ibmaem.c')
| -rw-r--r-- | drivers/hwmon/ibmaem.c | 164 |
1 files changed, 75 insertions, 89 deletions
diff --git a/drivers/hwmon/ibmaem.c b/drivers/hwmon/ibmaem.c index bc6e2ab3a36..632f1dc0fe1 100644 --- a/drivers/hwmon/ibmaem.c +++ b/drivers/hwmon/ibmaem.c @@ -3,7 +3,7 @@ * temperature/power/energy sensors and capping functionality. * Copyright (C) 2008 IBM * - * Author: Darrick J. Wong <djwong@us.ibm.com> + * Author: Darrick J. Wong <darrick.wong@oracle.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -36,6 +36,7 @@ #include <linux/platform_device.h> #include <linux/math64.h> #include <linux/time.h> +#include <linux/err.h> #define REFRESH_INTERVAL (HZ) #define IPMI_TIMEOUT (30 * HZ) @@ -88,8 +89,7 @@ #define AEM_MIN_POWER_INTERVAL 200 #define UJ_PER_MJ 1000L -static DEFINE_IDR(aem_idr); -static DEFINE_SPINLOCK(aem_idr_lock); +static DEFINE_IDA(aem_ida); static struct platform_driver aem_driver = { .driver = { @@ -148,8 +148,9 @@ struct aem_data { int id; struct aem_ipmi_data ipmi; - /* Function to update sensors */ + /* Function and buffer to update sensors */ void (*update)(struct aem_data *data); + struct aem_read_sensor_resp *rs_resp; /* * AEM 1.x sensors: @@ -246,8 +247,6 @@ static void aem_bmc_gone(int iface); static void aem_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data); static void aem_remove_sensors(struct aem_data *data); -static int aem_init_aem1(struct aem_ipmi_data *probe); -static int aem_init_aem2(struct aem_ipmi_data *probe); static int aem1_find_sensors(struct aem_data *data); static int aem2_find_sensors(struct aem_data *data); static void update_aem1_sensors(struct aem_data *data); @@ -290,9 +289,10 @@ static int aem_init_ipmi_data(struct aem_ipmi_data *data, int iface, err = ipmi_create_user(data->interface, &driver_data.ipmi_hndlrs, data, &data->user); if (err < 0) { - dev_err(bmc, "Unable to register user with IPMI " - "interface %d\n", data->interface); - return -EACCES; + dev_err(bmc, + "Unable to register user with IPMI interface %d\n", + data->interface); + return err; } return 0; @@ -329,8 +329,8 @@ static void aem_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data) struct aem_ipmi_data *data = user_msg_data; if (msg->msgid != data->tx_msgid) { - dev_err(data->bmc_device, "Mismatch between received msgid " - "(%02x) and transmitted msgid (%02x)!\n", + dev_err(data->bmc_device, + "Mismatch between received msgid (%02x) and transmitted msgid (%02x)!\n", (int)msg->msgid, (int)data->tx_msgid); ipmi_free_recv_msg(msg); @@ -356,47 +356,16 @@ static void aem_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data) complete(&data->read_complete); } -/* ID functions */ - -/* Obtain an id */ -static int aem_idr_get(int *id) -{ - int i, err; - -again: - if (unlikely(!idr_pre_get(&aem_idr, GFP_KERNEL))) - return -ENOMEM; - - spin_lock(&aem_idr_lock); - err = idr_get_new(&aem_idr, NULL, &i); - spin_unlock(&aem_idr_lock); - - if (unlikely(err == -EAGAIN)) - goto again; - else if (unlikely(err)) - return err; - - *id = i & MAX_ID_MASK; - return 0; -} - -/* Release an object ID */ -static void aem_idr_put(int id) -{ - spin_lock(&aem_idr_lock); - idr_remove(&aem_idr, id); - spin_unlock(&aem_idr_lock); -} - /* Sensor support functions */ -/* Read a sensor value */ +/* Read a sensor value; must be called with data->lock held */ static int aem_read_sensor(struct aem_data *data, u8 elt, u8 reg, void *buf, size_t size) { int rs_size, res; struct aem_read_sensor_req rs_req; - struct aem_read_sensor_resp *rs_resp; + /* Use preallocated rx buffer */ + struct aem_read_sensor_resp *rs_resp = data->rs_resp; struct aem_ipmi_data *ipmi = &data->ipmi; /* AEM registers are 1, 2, 4 or 8 bytes */ @@ -422,23 +391,21 @@ static int aem_read_sensor(struct aem_data *data, u8 elt, u8 reg, ipmi->tx_message.data_len = sizeof(rs_req); rs_size = sizeof(*rs_resp) + size; - rs_resp = kzalloc(rs_size, GFP_KERNEL); - if (!rs_resp) - return -ENOMEM; - ipmi->rx_msg_data = rs_resp; ipmi->rx_msg_len = rs_size; aem_send_message(ipmi); res = wait_for_completion_timeout(&ipmi->read_complete, IPMI_TIMEOUT); - if (!res) - return -ETIMEDOUT; + if (!res) { + res = -ETIMEDOUT; + goto out; + } if (ipmi->rx_result || ipmi->rx_msg_len != rs_size || memcmp(&rs_resp->id, &system_x_id, sizeof(system_x_id))) { - kfree(rs_resp); - return -ENOENT; + res = -ENOENT; + goto out; } switch (size) { @@ -463,8 +430,10 @@ static int aem_read_sensor(struct aem_data *data, u8 elt, u8 reg, break; } } + res = 0; - return 0; +out: + return res; } /* Update AEM energy registers */ @@ -521,11 +490,12 @@ static void aem_delete(struct aem_data *data) { list_del(&data->list); aem_remove_sensors(data); + kfree(data->rs_resp); hwmon_device_unregister(data->hwmon_dev); ipmi_destroy_user(data->ipmi.user); - dev_set_drvdata(&data->pdev->dev, NULL); + platform_set_drvdata(data->pdev, NULL); platform_device_unregister(data->pdev); - aem_idr_put(data->id); + ida_simple_remove(&aem_ida, data->id); kfree(data); } @@ -582,7 +552,8 @@ static int aem_init_aem1_inst(struct aem_ipmi_data *probe, u8 module_handle) data->power_period[i] = AEM_DEFAULT_POWER_INTERVAL; /* Create sub-device for this fw instance */ - if (aem_idr_get(&data->id)) + data->id = ida_simple_get(&aem_ida, 0, 0, GFP_KERNEL); + if (data->id < 0) goto id_err; data->pdev = platform_device_alloc(DRVNAME, data->id); @@ -594,27 +565,34 @@ static int aem_init_aem1_inst(struct aem_ipmi_data *probe, u8 module_handle) if (res) goto ipmi_err; - dev_set_drvdata(&data->pdev->dev, data); + platform_set_drvdata(data->pdev, data); /* Set up IPMI interface */ - if (aem_init_ipmi_data(&data->ipmi, probe->interface, - probe->bmc_device)) + res = aem_init_ipmi_data(&data->ipmi, probe->interface, + probe->bmc_device); + if (res) goto ipmi_err; /* Register with hwmon */ data->hwmon_dev = hwmon_device_register(&data->pdev->dev); - if (IS_ERR(data->hwmon_dev)) { - dev_err(&data->pdev->dev, "Unable to register hwmon " - "device for IPMI interface %d\n", + dev_err(&data->pdev->dev, + "Unable to register hwmon device for IPMI interface %d\n", probe->interface); + res = PTR_ERR(data->hwmon_dev); goto hwmon_reg_err; } data->update = update_aem1_sensors; + data->rs_resp = kzalloc(sizeof(*(data->rs_resp)) + 8, GFP_KERNEL); + if (!data->rs_resp) { + res = -ENOMEM; + goto alloc_resp_err; + } /* Find sensors */ - if (aem1_find_sensors(data)) + res = aem1_find_sensors(data); + if (res) goto sensor_err; /* Add to our list of AEM devices */ @@ -626,14 +604,16 @@ static int aem_init_aem1_inst(struct aem_ipmi_data *probe, u8 module_handle) return 0; sensor_err: + kfree(data->rs_resp); +alloc_resp_err: hwmon_device_unregister(data->hwmon_dev); hwmon_reg_err: ipmi_destroy_user(data->ipmi.user); ipmi_err: - dev_set_drvdata(&data->pdev->dev, NULL); + platform_set_drvdata(data->pdev, NULL); platform_device_unregister(data->pdev); dev_err: - aem_idr_put(data->id); + ida_simple_remove(&aem_ida, data->id); id_err: kfree(data); @@ -641,7 +621,7 @@ id_err: } /* Find and initialize all AEM1 instances */ -static int aem_init_aem1(struct aem_ipmi_data *probe) +static void aem_init_aem1(struct aem_ipmi_data *probe) { int num, i, err; @@ -652,11 +632,8 @@ static int aem_init_aem1(struct aem_ipmi_data *probe) dev_err(probe->bmc_device, "Error %d initializing AEM1 0x%X\n", err, i); - return err; } } - - return 0; } /* Probe functions for AEM2 devices */ @@ -715,7 +692,8 @@ static int aem_init_aem2_inst(struct aem_ipmi_data *probe, data->power_period[i] = AEM_DEFAULT_POWER_INTERVAL; /* Create sub-device for this fw instance */ - if (aem_idr_get(&data->id)) + data->id = ida_simple_get(&aem_ida, 0, 0, GFP_KERNEL); + if (data->id < 0) goto id_err; data->pdev = platform_device_alloc(DRVNAME, data->id); @@ -727,27 +705,34 @@ static int aem_init_aem2_inst(struct aem_ipmi_data *probe, if (res) goto ipmi_err; - dev_set_drvdata(&data->pdev->dev, data); + platform_set_drvdata(data->pdev, data); /* Set up IPMI interface */ - if (aem_init_ipmi_data(&data->ipmi, probe->interface, - probe->bmc_device)) + res = aem_init_ipmi_data(&data->ipmi, probe->interface, + probe->bmc_device); + if (res) goto ipmi_err; /* Register with hwmon */ data->hwmon_dev = hwmon_device_register(&data->pdev->dev); - if (IS_ERR(data->hwmon_dev)) { - dev_err(&data->pdev->dev, "Unable to register hwmon " - "device for IPMI interface %d\n", + dev_err(&data->pdev->dev, + "Unable to register hwmon device for IPMI interface %d\n", probe->interface); + res = PTR_ERR(data->hwmon_dev); goto hwmon_reg_err; } data->update = update_aem2_sensors; + data->rs_resp = kzalloc(sizeof(*(data->rs_resp)) + 8, GFP_KERNEL); + if (!data->rs_resp) { + res = -ENOMEM; + goto alloc_resp_err; + } /* Find sensors */ - if (aem2_find_sensors(data)) + res = aem2_find_sensors(data); + if (res) goto sensor_err; /* Add to our list of AEM devices */ @@ -759,14 +744,16 @@ static int aem_init_aem2_inst(struct aem_ipmi_data *probe, return 0; sensor_err: + kfree(data->rs_resp); +alloc_resp_err: hwmon_device_unregister(data->hwmon_dev); hwmon_reg_err: ipmi_destroy_user(data->ipmi.user); ipmi_err: - dev_set_drvdata(&data->pdev->dev, NULL); + platform_set_drvdata(data->pdev, NULL); platform_device_unregister(data->pdev); dev_err: - aem_idr_put(data->id); + ida_simple_remove(&aem_ida, data->id); id_err: kfree(data); @@ -774,7 +761,7 @@ id_err: } /* Find and initialize all AEM2 instances */ -static int aem_init_aem2(struct aem_ipmi_data *probe) +static void aem_init_aem2(struct aem_ipmi_data *probe) { struct aem_find_instance_resp fi_resp; int err; @@ -782,8 +769,8 @@ static int aem_init_aem2(struct aem_ipmi_data *probe) while (!aem_find_aem2(probe, &fi_resp, i)) { if (fi_resp.major != 2) { - dev_err(probe->bmc_device, "Unknown AEM v%d; please " - "report this to the maintainer.\n", + dev_err(probe->bmc_device, + "Unknown AEM v%d; please report this to the maintainer.\n", fi_resp.major); i++; continue; @@ -793,12 +780,9 @@ static int aem_init_aem2(struct aem_ipmi_data *probe) dev_err(probe->bmc_device, "Error %d initializing AEM2 0x%X\n", err, fi_resp.module_handle); - return err; } i++; } - - return 0; } /* Probe a BMC for AEM firmware instances */ @@ -922,7 +906,7 @@ static ssize_t aem_set_power_period(struct device *dev, unsigned long temp; int res; - res = strict_strtoul(buf, 10, &temp); + res = kstrtoul(buf, 10, &temp); if (res) return res; @@ -947,6 +931,7 @@ static int aem_register_sensors(struct aem_data *data, /* Set up read-only sensors */ while (ro->label) { + sysfs_attr_init(&sensors->dev_attr.attr); sensors->dev_attr.attr.name = ro->label; sensors->dev_attr.attr.mode = S_IRUGO; sensors->dev_attr.show = ro->show; @@ -963,6 +948,7 @@ static int aem_register_sensors(struct aem_data *data, /* Set up read-write sensors */ while (rw->label) { + sysfs_attr_init(&sensors->dev_attr.attr); sensors->dev_attr.attr.name = rw->label; sensors->dev_attr.attr.mode = S_IRUGO | S_IWUSR; sensors->dev_attr.show = rw->show; @@ -1061,7 +1047,7 @@ static struct aem_ro_sensor_template aem2_ro_sensors[] = { {"power6_average", aem2_show_pcap_value, POWER_CAP_MIN_WARNING}, {"power7_average", aem2_show_pcap_value, POWER_CAP_MIN}, -{"power3_average", aem2_show_pcap_value, POWER_AUX}, +{"power3_average", aem2_show_pcap_value, POWER_AUX}, {"power_cap", aem2_show_pcap_value, POWER_CAP}, {NULL, NULL, 0}, }; @@ -1117,7 +1103,7 @@ static void __exit aem_exit(void) aem_delete(p1); } -MODULE_AUTHOR("Darrick J. Wong <djwong@us.ibm.com>"); +MODULE_AUTHOR("Darrick J. Wong <darrick.wong@oracle.com>"); MODULE_DESCRIPTION("IBM AEM power/temp/energy sensor driver"); MODULE_LICENSE("GPL"); |
