linux/drivers/net/ethernet/sfc/mcdi_mon.c
<<
>>
Prefs
   1/****************************************************************************
   2 * Driver for Solarflare Solarstorm network controllers and boards
   3 * Copyright 2011 Solarflare Communications Inc.
   4 *
   5 * This program is free software; you can redistribute it and/or modify it
   6 * under the terms of the GNU General Public License version 2 as published
   7 * by the Free Software Foundation, incorporated herein by reference.
   8 */
   9
  10#include <linux/bitops.h>
  11#include <linux/slab.h>
  12#include <linux/hwmon.h>
  13#include <linux/stat.h>
  14
  15#include "net_driver.h"
  16#include "mcdi.h"
  17#include "mcdi_pcol.h"
  18#include "nic.h"
  19
  20enum efx_hwmon_type {
  21        EFX_HWMON_UNKNOWN,
  22        EFX_HWMON_TEMP,         /* temperature */
  23        EFX_HWMON_COOL,         /* cooling device, probably a heatsink */
  24        EFX_HWMON_IN            /* input voltage */
  25};
  26
  27static const struct {
  28        const char *label;
  29        enum efx_hwmon_type hwmon_type;
  30        int port;
  31} efx_mcdi_sensor_type[MC_CMD_SENSOR_ENTRY_MAXNUM] = {
  32#define SENSOR(name, label, hwmon_type, port)                   \
  33        [MC_CMD_SENSOR_##name] = { label, hwmon_type, port }
  34        SENSOR(CONTROLLER_TEMP,    "Controller temp.",     EFX_HWMON_TEMP, -1),
  35        SENSOR(PHY_COMMON_TEMP,    "PHY temp.",            EFX_HWMON_TEMP, -1),
  36        SENSOR(CONTROLLER_COOLING, "Controller cooling",   EFX_HWMON_COOL, -1),
  37        SENSOR(PHY0_TEMP,          "PHY temp.",            EFX_HWMON_TEMP, 0),
  38        SENSOR(PHY0_COOLING,       "PHY cooling",          EFX_HWMON_COOL, 0),
  39        SENSOR(PHY1_TEMP,          "PHY temp.",            EFX_HWMON_TEMP, 1),
  40        SENSOR(PHY1_COOLING,       "PHY cooling",          EFX_HWMON_COOL, 1),
  41        SENSOR(IN_1V0,             "1.0V supply",          EFX_HWMON_IN,   -1),
  42        SENSOR(IN_1V2,             "1.2V supply",          EFX_HWMON_IN,   -1),
  43        SENSOR(IN_1V8,             "1.8V supply",          EFX_HWMON_IN,   -1),
  44        SENSOR(IN_2V5,             "2.5V supply",          EFX_HWMON_IN,   -1),
  45        SENSOR(IN_3V3,             "3.3V supply",          EFX_HWMON_IN,   -1),
  46        SENSOR(IN_12V0,            "12.0V supply",         EFX_HWMON_IN,   -1),
  47        SENSOR(IN_1V2A,            "1.2V analogue supply", EFX_HWMON_IN,   -1),
  48        SENSOR(IN_VREF,            "ref. voltage",         EFX_HWMON_IN,   -1),
  49#undef SENSOR
  50};
  51
  52static const char *const sensor_status_names[] = {
  53        [MC_CMD_SENSOR_STATE_OK] = "OK",
  54        [MC_CMD_SENSOR_STATE_WARNING] = "Warning",
  55        [MC_CMD_SENSOR_STATE_FATAL] = "Fatal",
  56        [MC_CMD_SENSOR_STATE_BROKEN] = "Device failure",
  57};
  58
  59void efx_mcdi_sensor_event(struct efx_nic *efx, efx_qword_t *ev)
  60{
  61        unsigned int type, state, value;
  62        const char *name = NULL, *state_txt;
  63
  64        type = EFX_QWORD_FIELD(*ev, MCDI_EVENT_SENSOREVT_MONITOR);
  65        state = EFX_QWORD_FIELD(*ev, MCDI_EVENT_SENSOREVT_STATE);
  66        value = EFX_QWORD_FIELD(*ev, MCDI_EVENT_SENSOREVT_VALUE);
  67
  68        /* Deal gracefully with the board having more drivers than we
  69         * know about, but do not expect new sensor states. */
  70        if (type < ARRAY_SIZE(efx_mcdi_sensor_type))
  71                name = efx_mcdi_sensor_type[type].label;
  72        if (!name)
  73                name = "No sensor name available";
  74        EFX_BUG_ON_PARANOID(state >= ARRAY_SIZE(sensor_status_names));
  75        state_txt = sensor_status_names[state];
  76
  77        netif_err(efx, hw, efx->net_dev,
  78                  "Sensor %d (%s) reports condition '%s' for raw value %d\n",
  79                  type, name, state_txt, value);
  80}
  81
  82#ifdef CONFIG_SFC_MCDI_MON
  83
  84struct efx_mcdi_mon_attribute {
  85        struct device_attribute dev_attr;
  86        unsigned int index;
  87        unsigned int type;
  88        unsigned int limit_value;
  89        char name[12];
  90};
  91
  92static int efx_mcdi_mon_update(struct efx_nic *efx)
  93{
  94        struct efx_mcdi_mon *hwmon = efx_mcdi_mon(efx);
  95        u8 inbuf[MC_CMD_READ_SENSORS_IN_LEN];
  96        int rc;
  97
  98        MCDI_SET_DWORD(inbuf, READ_SENSORS_IN_DMA_ADDR_LO,
  99                       hwmon->dma_buf.dma_addr & 0xffffffff);
 100        MCDI_SET_DWORD(inbuf, READ_SENSORS_IN_DMA_ADDR_HI,
 101                       (u64)hwmon->dma_buf.dma_addr >> 32);
 102
 103        rc = efx_mcdi_rpc(efx, MC_CMD_READ_SENSORS,
 104                          inbuf, sizeof(inbuf), NULL, 0, NULL);
 105        if (rc == 0)
 106                hwmon->last_update = jiffies;
 107        return rc;
 108}
 109
 110static ssize_t efx_mcdi_mon_show_name(struct device *dev,
 111                                      struct device_attribute *attr,
 112                                      char *buf)
 113{
 114        return sprintf(buf, "%s\n", KBUILD_MODNAME);
 115}
 116
 117static int efx_mcdi_mon_get_entry(struct device *dev, unsigned int index,
 118                                  efx_dword_t *entry)
 119{
 120        struct efx_nic *efx = dev_get_drvdata(dev);
 121        struct efx_mcdi_mon *hwmon = efx_mcdi_mon(efx);
 122        int rc;
 123
 124        BUILD_BUG_ON(MC_CMD_READ_SENSORS_OUT_LEN != 0);
 125
 126        mutex_lock(&hwmon->update_lock);
 127
 128        /* Use cached value if last update was < 1 s ago */
 129        if (time_before(jiffies, hwmon->last_update + HZ))
 130                rc = 0;
 131        else
 132                rc = efx_mcdi_mon_update(efx);
 133
 134        /* Copy out the requested entry */
 135        *entry = ((efx_dword_t *)hwmon->dma_buf.addr)[index];
 136
 137        mutex_unlock(&hwmon->update_lock);
 138
 139        return rc;
 140}
 141
 142static ssize_t efx_mcdi_mon_show_value(struct device *dev,
 143                                       struct device_attribute *attr,
 144                                       char *buf)
 145{
 146        struct efx_mcdi_mon_attribute *mon_attr =
 147                container_of(attr, struct efx_mcdi_mon_attribute, dev_attr);
 148        efx_dword_t entry;
 149        unsigned int value;
 150        int rc;
 151
 152        rc = efx_mcdi_mon_get_entry(dev, mon_attr->index, &entry);
 153        if (rc)
 154                return rc;
 155
 156        value = EFX_DWORD_FIELD(entry, MC_CMD_SENSOR_VALUE_ENTRY_TYPEDEF_VALUE);
 157
 158        /* Convert temperature from degrees to milli-degrees Celsius */
 159        if (efx_mcdi_sensor_type[mon_attr->type].hwmon_type == EFX_HWMON_TEMP)
 160                value *= 1000;
 161
 162        return sprintf(buf, "%u\n", value);
 163}
 164
 165static ssize_t efx_mcdi_mon_show_limit(struct device *dev,
 166                                       struct device_attribute *attr,
 167                                       char *buf)
 168{
 169        struct efx_mcdi_mon_attribute *mon_attr =
 170                container_of(attr, struct efx_mcdi_mon_attribute, dev_attr);
 171        unsigned int value;
 172
 173        value = mon_attr->limit_value;
 174
 175        /* Convert temperature from degrees to milli-degrees Celsius */
 176        if (efx_mcdi_sensor_type[mon_attr->type].hwmon_type == EFX_HWMON_TEMP)
 177                value *= 1000;
 178
 179        return sprintf(buf, "%u\n", value);
 180}
 181
 182static ssize_t efx_mcdi_mon_show_alarm(struct device *dev,
 183                                       struct device_attribute *attr,
 184                                       char *buf)
 185{
 186        struct efx_mcdi_mon_attribute *mon_attr =
 187                container_of(attr, struct efx_mcdi_mon_attribute, dev_attr);
 188        efx_dword_t entry;
 189        int state;
 190        int rc;
 191
 192        rc = efx_mcdi_mon_get_entry(dev, mon_attr->index, &entry);
 193        if (rc)
 194                return rc;
 195
 196        state = EFX_DWORD_FIELD(entry, MC_CMD_SENSOR_VALUE_ENTRY_TYPEDEF_STATE);
 197        return sprintf(buf, "%d\n", state != MC_CMD_SENSOR_STATE_OK);
 198}
 199
 200static ssize_t efx_mcdi_mon_show_label(struct device *dev,
 201                                       struct device_attribute *attr,
 202                                       char *buf)
 203{
 204        struct efx_mcdi_mon_attribute *mon_attr =
 205                container_of(attr, struct efx_mcdi_mon_attribute, dev_attr);
 206        return sprintf(buf, "%s\n",
 207                       efx_mcdi_sensor_type[mon_attr->type].label);
 208}
 209
 210static int
 211efx_mcdi_mon_add_attr(struct efx_nic *efx, const char *name,
 212                      ssize_t (*reader)(struct device *,
 213                                        struct device_attribute *, char *),
 214                      unsigned int index, unsigned int type,
 215                      unsigned int limit_value)
 216{
 217        struct efx_mcdi_mon *hwmon = efx_mcdi_mon(efx);
 218        struct efx_mcdi_mon_attribute *attr = &hwmon->attrs[hwmon->n_attrs];
 219        int rc;
 220
 221        strlcpy(attr->name, name, sizeof(attr->name));
 222        attr->index = index;
 223        attr->type = type;
 224        attr->limit_value = limit_value;
 225        attr->dev_attr.attr.name = attr->name;
 226        attr->dev_attr.attr.mode = S_IRUGO;
 227        attr->dev_attr.show = reader;
 228        rc = device_create_file(&efx->pci_dev->dev, &attr->dev_attr);
 229        if (rc == 0)
 230                ++hwmon->n_attrs;
 231        return rc;
 232}
 233
 234int efx_mcdi_mon_probe(struct efx_nic *efx)
 235{
 236        struct efx_mcdi_mon *hwmon = efx_mcdi_mon(efx);
 237        unsigned int n_attrs, n_temp = 0, n_cool = 0, n_in = 0;
 238        u8 outbuf[MC_CMD_SENSOR_INFO_OUT_LENMAX];
 239        size_t outlen;
 240        char name[12];
 241        u32 mask;
 242        int rc, i, type;
 243
 244        BUILD_BUG_ON(MC_CMD_SENSOR_INFO_IN_LEN != 0);
 245
 246        rc = efx_mcdi_rpc(efx, MC_CMD_SENSOR_INFO, NULL, 0,
 247                          outbuf, sizeof(outbuf), &outlen);
 248        if (rc)
 249                return rc;
 250        if (outlen < MC_CMD_SENSOR_INFO_OUT_LENMIN)
 251                return -EIO;
 252
 253        /* Find out which sensors are present.  Don't create a device
 254         * if there are none.
 255         */
 256        mask = MCDI_DWORD(outbuf, SENSOR_INFO_OUT_MASK);
 257        if (mask == 0)
 258                return 0;
 259
 260        /* Check again for short response */
 261        if (outlen < MC_CMD_SENSOR_INFO_OUT_LEN(hweight32(mask)))
 262                return -EIO;
 263
 264        rc = efx_nic_alloc_buffer(efx, &hwmon->dma_buf,
 265                                  4 * MC_CMD_SENSOR_ENTRY_MAXNUM);
 266        if (rc)
 267                return rc;
 268
 269        mutex_init(&hwmon->update_lock);
 270        efx_mcdi_mon_update(efx);
 271
 272        /* Allocate space for the maximum possible number of
 273         * attributes for this set of sensors: name of the driver plus
 274         * value, min, max, crit, alarm and label for each sensor.
 275         */
 276        n_attrs = 1 + 6 * hweight32(mask);
 277        hwmon->attrs = kcalloc(n_attrs, sizeof(*hwmon->attrs), GFP_KERNEL);
 278        if (!hwmon->attrs) {
 279                rc = -ENOMEM;
 280                goto fail;
 281        }
 282
 283        hwmon->device = hwmon_device_register(&efx->pci_dev->dev);
 284        if (IS_ERR(hwmon->device)) {
 285                rc = PTR_ERR(hwmon->device);
 286                goto fail;
 287        }
 288
 289        rc = efx_mcdi_mon_add_attr(efx, "name", efx_mcdi_mon_show_name, 0, 0, 0);
 290        if (rc)
 291                goto fail;
 292
 293        for (i = 0, type = -1; ; i++) {
 294                const char *hwmon_prefix;
 295                unsigned hwmon_index;
 296                u16 min1, max1, min2, max2;
 297
 298                /* Find next sensor type or exit if there is none */
 299                type++;
 300                while (!(mask & (1 << type))) {
 301                        type++;
 302                        if (type == 32)
 303                                return 0;
 304                }
 305
 306                /* Skip sensors specific to a different port */
 307                if (efx_mcdi_sensor_type[type].hwmon_type != EFX_HWMON_UNKNOWN &&
 308                    efx_mcdi_sensor_type[type].port >= 0 &&
 309                    efx_mcdi_sensor_type[type].port != efx_port_num(efx))
 310                        continue;
 311
 312                switch (efx_mcdi_sensor_type[type].hwmon_type) {
 313                case EFX_HWMON_TEMP:
 314                        hwmon_prefix = "temp";
 315                        hwmon_index = ++n_temp; /* 1-based */
 316                        break;
 317                case EFX_HWMON_COOL:
 318                        /* This is likely to be a heatsink, but there
 319                         * is no convention for representing cooling
 320                         * devices other than fans.
 321                         */
 322                        hwmon_prefix = "fan";
 323                        hwmon_index = ++n_cool; /* 1-based */
 324                        break;
 325                default:
 326                        hwmon_prefix = "in";
 327                        hwmon_index = n_in++; /* 0-based */
 328                        break;
 329                }
 330
 331                min1 = MCDI_ARRAY_FIELD(outbuf, SENSOR_ENTRY,
 332                                        SENSOR_INFO_ENTRY, i, MIN1);
 333                max1 = MCDI_ARRAY_FIELD(outbuf, SENSOR_ENTRY,
 334                                        SENSOR_INFO_ENTRY, i, MAX1);
 335                min2 = MCDI_ARRAY_FIELD(outbuf, SENSOR_ENTRY,
 336                                        SENSOR_INFO_ENTRY, i, MIN2);
 337                max2 = MCDI_ARRAY_FIELD(outbuf, SENSOR_ENTRY,
 338                                        SENSOR_INFO_ENTRY, i, MAX2);
 339
 340                if (min1 != max1) {
 341                        snprintf(name, sizeof(name), "%s%u_input",
 342                                 hwmon_prefix, hwmon_index);
 343                        rc = efx_mcdi_mon_add_attr(
 344                                efx, name, efx_mcdi_mon_show_value, i, type, 0);
 345                        if (rc)
 346                                goto fail;
 347
 348                        snprintf(name, sizeof(name), "%s%u_min",
 349                                 hwmon_prefix, hwmon_index);
 350                        rc = efx_mcdi_mon_add_attr(
 351                                efx, name, efx_mcdi_mon_show_limit,
 352                                i, type, min1);
 353                        if (rc)
 354                                goto fail;
 355
 356                        snprintf(name, sizeof(name), "%s%u_max",
 357                                 hwmon_prefix, hwmon_index);
 358                        rc = efx_mcdi_mon_add_attr(
 359                                efx, name, efx_mcdi_mon_show_limit,
 360                                i, type, max1);
 361                        if (rc)
 362                                goto fail;
 363
 364                        if (min2 != max2) {
 365                                /* Assume max2 is critical value.
 366                                 * But we have no good way to expose min2.
 367                                 */
 368                                snprintf(name, sizeof(name), "%s%u_crit",
 369                                         hwmon_prefix, hwmon_index);
 370                                rc = efx_mcdi_mon_add_attr(
 371                                        efx, name, efx_mcdi_mon_show_limit,
 372                                        i, type, max2);
 373                                if (rc)
 374                                        goto fail;
 375                        }
 376                }
 377
 378                snprintf(name, sizeof(name), "%s%u_alarm",
 379                         hwmon_prefix, hwmon_index);
 380                rc = efx_mcdi_mon_add_attr(
 381                        efx, name, efx_mcdi_mon_show_alarm, i, type, 0);
 382                if (rc)
 383                        goto fail;
 384
 385                if (efx_mcdi_sensor_type[type].label) {
 386                        snprintf(name, sizeof(name), "%s%u_label",
 387                                 hwmon_prefix, hwmon_index);
 388                        rc = efx_mcdi_mon_add_attr(
 389                                efx, name, efx_mcdi_mon_show_label, i, type, 0);
 390                        if (rc)
 391                                goto fail;
 392                }
 393        }
 394
 395fail:
 396        efx_mcdi_mon_remove(efx);
 397        return rc;
 398}
 399
 400void efx_mcdi_mon_remove(struct efx_nic *efx)
 401{
 402        struct siena_nic_data *nic_data = efx->nic_data;
 403        struct efx_mcdi_mon *hwmon = &nic_data->hwmon;
 404        unsigned int i;
 405
 406        for (i = 0; i < hwmon->n_attrs; i++)
 407                device_remove_file(&efx->pci_dev->dev,
 408                                   &hwmon->attrs[i].dev_attr);
 409        kfree(hwmon->attrs);
 410        if (hwmon->device)
 411                hwmon_device_unregister(hwmon->device);
 412        efx_nic_free_buffer(efx, &hwmon->dma_buf);
 413}
 414
 415#endif /* CONFIG_SFC_MCDI_MON */
 416