]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/infiniband/hw/ipath/ipath_sysfs.c
IB/ipath: Misc changes to prepare for IB7220 introduction
[linux-2.6-omap-h63xx.git] / drivers / infiniband / hw / ipath / ipath_sysfs.c
index 4dc398d5e01190a29380a7043fc4d2e6410f6e54..2e6d2aab2600171c75f831339124ec512bd61f50 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006 QLogic, Inc. All rights reserved.
+ * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved.
  * Copyright (c) 2006 PathScale, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
@@ -34,6 +34,7 @@
 #include <linux/ctype.h>
 
 #include "ipath_kernel.h"
+#include "ipath_verbs.h"
 #include "ipath_common.h"
 
 /**
@@ -163,6 +164,51 @@ static ssize_t show_boardversion(struct device *dev,
        return scnprintf(buf, PAGE_SIZE, "%s", dd->ipath_boardversion);
 }
 
+static ssize_t show_localbus_info(struct device *dev,
+                              struct device_attribute *attr,
+                              char *buf)
+{
+       struct ipath_devdata *dd = dev_get_drvdata(dev);
+       /* The string printed here is already newline-terminated. */
+       return scnprintf(buf, PAGE_SIZE, "%s", dd->ipath_lbus_info);
+}
+
+static ssize_t show_lmc(struct device *dev,
+                       struct device_attribute *attr,
+                       char *buf)
+{
+       struct ipath_devdata *dd = dev_get_drvdata(dev);
+
+       return scnprintf(buf, PAGE_SIZE, "%u\n", dd->ipath_lmc);
+}
+
+static ssize_t store_lmc(struct device *dev,
+                        struct device_attribute *attr,
+                        const char *buf,
+                        size_t count)
+{
+       struct ipath_devdata *dd = dev_get_drvdata(dev);
+       u16 lmc = 0;
+       int ret;
+
+       ret = ipath_parse_ushort(buf, &lmc);
+       if (ret < 0)
+               goto invalid;
+
+       if (lmc > 7) {
+               ret = -EINVAL;
+               goto invalid;
+       }
+
+       ipath_set_lid(dd, dd->ipath_lid, lmc);
+
+       goto bail;
+invalid:
+       ipath_dev_err(dd, "attempt to set invalid LMC %u\n", lmc);
+bail:
+       return ret;
+}
+
 static ssize_t show_lid(struct device *dev,
                        struct device_attribute *attr,
                        char *buf)
@@ -190,7 +236,7 @@ static ssize_t store_lid(struct device *dev,
                goto invalid;
        }
 
-       ipath_set_lid(dd, lid, 0);
+       ipath_set_lid(dd, lid, dd->ipath_lmc);
 
        goto bail;
 invalid:
@@ -275,6 +321,8 @@ static ssize_t store_guid(struct device *dev,
 
        dd->ipath_guid = new_guid;
        dd->ipath_nguid = 1;
+       if (dd->verbs_dev)
+               dd->verbs_dev->ibdev.node_guid = new_guid;
 
        ret = strlen(buf);
        goto bail;
@@ -327,6 +375,60 @@ static ssize_t show_unit(struct device *dev,
        return scnprintf(buf, PAGE_SIZE, "%u\n", dd->ipath_unit);
 }
 
+static ssize_t show_jint_max_packets(struct device *dev,
+                                    struct device_attribute *attr,
+                                    char *buf)
+{
+       struct ipath_devdata *dd = dev_get_drvdata(dev);
+
+       return scnprintf(buf, PAGE_SIZE, "%hu\n", dd->ipath_jint_max_packets);
+}
+
+static ssize_t store_jint_max_packets(struct device *dev,
+                                     struct device_attribute *attr,
+                                     const char *buf,
+                                     size_t count)
+{
+       struct ipath_devdata *dd = dev_get_drvdata(dev);
+       u16 v = 0;
+       int ret;
+
+       ret = ipath_parse_ushort(buf, &v);
+       if (ret < 0)
+               ipath_dev_err(dd, "invalid jint_max_packets.\n");
+       else
+               dd->ipath_f_config_jint(dd, dd->ipath_jint_idle_ticks, v);
+
+       return ret;
+}
+
+static ssize_t show_jint_idle_ticks(struct device *dev,
+                                   struct device_attribute *attr,
+                                   char *buf)
+{
+       struct ipath_devdata *dd = dev_get_drvdata(dev);
+
+       return scnprintf(buf, PAGE_SIZE, "%hu\n", dd->ipath_jint_idle_ticks);
+}
+
+static ssize_t store_jint_idle_ticks(struct device *dev,
+                                    struct device_attribute *attr,
+                                    const char *buf,
+                                    size_t count)
+{
+       struct ipath_devdata *dd = dev_get_drvdata(dev);
+       u16 v = 0;
+       int ret;
+
+       ret = ipath_parse_ushort(buf, &v);
+       if (ret < 0)
+               ipath_dev_err(dd, "invalid jint_idle_ticks.\n");
+       else
+               dd->ipath_f_config_jint(dd, v, dd->ipath_jint_max_packets);
+
+       return ret;
+}
+
 #define DEVICE_COUNTER(name, attr) \
        static ssize_t show_counter_##name(struct device *dev, \
                                           struct device_attribute *attr, \
@@ -596,6 +698,294 @@ bail:
        return ret;
 }
 
+static ssize_t store_led_override(struct device *dev,
+                         struct device_attribute *attr,
+                         const char *buf,
+                         size_t count)
+{
+       struct ipath_devdata *dd = dev_get_drvdata(dev);
+       int ret;
+       u16 val;
+
+       ret = ipath_parse_ushort(buf, &val);
+       if (ret > 0)
+               ipath_set_led_override(dd, val);
+       else
+               ipath_dev_err(dd, "attempt to set invalid LED override\n");
+       return ret;
+}
+
+static ssize_t show_logged_errs(struct device *dev,
+                               struct device_attribute *attr,
+                               char *buf)
+{
+       struct ipath_devdata *dd = dev_get_drvdata(dev);
+       int idx, count;
+
+       /* force consistency with actual EEPROM */
+       if (ipath_update_eeprom_log(dd) != 0)
+               return -ENXIO;
+
+       count = 0;
+       for (idx = 0; idx < IPATH_EEP_LOG_CNT; ++idx) {
+               count += scnprintf(buf + count, PAGE_SIZE - count, "%d%c",
+                       dd->ipath_eep_st_errs[idx],
+                       idx == (IPATH_EEP_LOG_CNT - 1) ? '\n' : ' ');
+       }
+
+       return count;
+}
+
+/*
+ * New sysfs entries to control various IB config. These all turn into
+ * accesses via ipath_f_get/set_ib_cfg.
+ *
+ * Get/Set heartbeat enable. Or of 1=enabled, 2=auto
+ */
+static ssize_t show_hrtbt_enb(struct device *dev,
+                        struct device_attribute *attr,
+                        char *buf)
+{
+       struct ipath_devdata *dd = dev_get_drvdata(dev);
+       int ret;
+
+       ret = dd->ipath_f_get_ib_cfg(dd, IPATH_IB_CFG_HRTBT);
+       if (ret >= 0)
+               ret = scnprintf(buf, PAGE_SIZE, "%d\n", ret);
+       return ret;
+}
+
+static ssize_t store_hrtbt_enb(struct device *dev,
+                         struct device_attribute *attr,
+                         const char *buf,
+                         size_t count)
+{
+       struct ipath_devdata *dd = dev_get_drvdata(dev);
+       int ret, r;
+       u16 val;
+
+       ret = ipath_parse_ushort(buf, &val);
+       if (ret >= 0 && val > 3)
+               ret = -EINVAL;
+       if (ret < 0) {
+               ipath_dev_err(dd, "attempt to set invalid Heartbeat enable\n");
+               goto bail;
+       }
+
+       /*
+        * Set the "intentional" heartbeat enable per either of
+        * "Enable" and "Auto", as these are normally set together.
+        * This bit is consulted when leaving loopback mode,
+        * because entering loopback mode overrides it and automatically
+        * disables heartbeat.
+        */
+       r = dd->ipath_f_set_ib_cfg(dd, IPATH_IB_CFG_HRTBT, val);
+       if (r < 0)
+               ret = r;
+       else if (val == IPATH_IB_HRTBT_OFF)
+               dd->ipath_flags |= IPATH_NO_HRTBT;
+       else
+               dd->ipath_flags &= ~IPATH_NO_HRTBT;
+
+bail:
+       return ret;
+}
+
+/*
+ * Get/Set Link-widths enabled. Or of 1=1x, 2=4x (this is human/IB centric,
+ * _not_ the particular encoding of any given chip)
+ */
+static ssize_t show_lwid_enb(struct device *dev,
+                        struct device_attribute *attr,
+                        char *buf)
+{
+       struct ipath_devdata *dd = dev_get_drvdata(dev);
+       int ret;
+
+       ret = dd->ipath_f_get_ib_cfg(dd, IPATH_IB_CFG_LWID_ENB);
+       if (ret >= 0)
+               ret = scnprintf(buf, PAGE_SIZE, "%d\n", ret);
+       return ret;
+}
+
+static ssize_t store_lwid_enb(struct device *dev,
+                         struct device_attribute *attr,
+                         const char *buf,
+                         size_t count)
+{
+       struct ipath_devdata *dd = dev_get_drvdata(dev);
+       int ret, r;
+       u16 val;
+
+       ret = ipath_parse_ushort(buf, &val);
+       if (ret >= 0 && (val == 0 || val > 3))
+               ret = -EINVAL;
+       if (ret < 0) {
+               ipath_dev_err(dd,
+                       "attempt to set invalid Link Width (enable)\n");
+               goto bail;
+       }
+
+       r = dd->ipath_f_set_ib_cfg(dd, IPATH_IB_CFG_LWID_ENB, val);
+       if (r < 0)
+               ret = r;
+
+bail:
+       return ret;
+}
+
+/* Get current link width */
+static ssize_t show_lwid(struct device *dev,
+                        struct device_attribute *attr,
+                        char *buf)
+
+{
+       struct ipath_devdata *dd = dev_get_drvdata(dev);
+       int ret;
+
+       ret = dd->ipath_f_get_ib_cfg(dd, IPATH_IB_CFG_LWID);
+       if (ret >= 0)
+               ret = scnprintf(buf, PAGE_SIZE, "%d\n", ret);
+       return ret;
+}
+
+/*
+ * Get/Set Link-speeds enabled. Or of 1=SDR 2=DDR.
+ */
+static ssize_t show_spd_enb(struct device *dev,
+                        struct device_attribute *attr,
+                        char *buf)
+{
+       struct ipath_devdata *dd = dev_get_drvdata(dev);
+       int ret;
+
+       ret = dd->ipath_f_get_ib_cfg(dd, IPATH_IB_CFG_SPD_ENB);
+       if (ret >= 0)
+               ret = scnprintf(buf, PAGE_SIZE, "%d\n", ret);
+       return ret;
+}
+
+static ssize_t store_spd_enb(struct device *dev,
+                         struct device_attribute *attr,
+                         const char *buf,
+                         size_t count)
+{
+       struct ipath_devdata *dd = dev_get_drvdata(dev);
+       int ret, r;
+       u16 val;
+
+       ret = ipath_parse_ushort(buf, &val);
+       if (ret >= 0 && (val == 0 || val > (IPATH_IB_SDR | IPATH_IB_DDR)))
+               ret = -EINVAL;
+       if (ret < 0) {
+               ipath_dev_err(dd,
+                       "attempt to set invalid Link Speed (enable)\n");
+               goto bail;
+       }
+
+       r = dd->ipath_f_set_ib_cfg(dd, IPATH_IB_CFG_SPD_ENB, val);
+       if (r < 0)
+               ret = r;
+
+bail:
+       return ret;
+}
+
+/* Get current link speed */
+static ssize_t show_spd(struct device *dev,
+                        struct device_attribute *attr,
+                        char *buf)
+{
+       struct ipath_devdata *dd = dev_get_drvdata(dev);
+       int ret;
+
+       ret = dd->ipath_f_get_ib_cfg(dd, IPATH_IB_CFG_SPD);
+       if (ret >= 0)
+               ret = scnprintf(buf, PAGE_SIZE, "%d\n", ret);
+       return ret;
+}
+
+/*
+ * Get/Set RX polarity-invert enable. 0=no, 1=yes.
+ */
+static ssize_t show_rx_polinv_enb(struct device *dev,
+                        struct device_attribute *attr,
+                        char *buf)
+{
+       struct ipath_devdata *dd = dev_get_drvdata(dev);
+       int ret;
+
+       ret = dd->ipath_f_get_ib_cfg(dd, IPATH_IB_CFG_RXPOL_ENB);
+       if (ret >= 0)
+               ret = scnprintf(buf, PAGE_SIZE, "%d\n", ret);
+       return ret;
+}
+
+static ssize_t store_rx_polinv_enb(struct device *dev,
+                         struct device_attribute *attr,
+                         const char *buf,
+                         size_t count)
+{
+       struct ipath_devdata *dd = dev_get_drvdata(dev);
+       int ret, r;
+       u16 val;
+
+       ret = ipath_parse_ushort(buf, &val);
+       if (ret >= 0 && val > 1) {
+               ipath_dev_err(dd,
+                       "attempt to set invalid Rx Polarity (enable)\n");
+               ret = -EINVAL;
+               goto bail;
+       }
+
+       r = dd->ipath_f_set_ib_cfg(dd, IPATH_IB_CFG_RXPOL_ENB, val);
+       if (r < 0)
+               ret = r;
+
+bail:
+       return ret;
+}
+
+/*
+ * Get/Set RX lane-reversal enable. 0=no, 1=yes.
+ */
+static ssize_t show_lanerev_enb(struct device *dev,
+                        struct device_attribute *attr,
+                        char *buf)
+{
+       struct ipath_devdata *dd = dev_get_drvdata(dev);
+       int ret;
+
+       ret = dd->ipath_f_get_ib_cfg(dd, IPATH_IB_CFG_LREV_ENB);
+       if (ret >= 0)
+               ret = scnprintf(buf, PAGE_SIZE, "%d\n", ret);
+       return ret;
+}
+
+static ssize_t store_lanerev_enb(struct device *dev,
+                         struct device_attribute *attr,
+                         const char *buf,
+                         size_t count)
+{
+       struct ipath_devdata *dd = dev_get_drvdata(dev);
+       int ret, r;
+       u16 val;
+
+       ret = ipath_parse_ushort(buf, &val);
+       if (ret >= 0 && val > 1) {
+               ret = -EINVAL;
+               ipath_dev_err(dd,
+                       "attempt to set invalid Lane reversal (enable)\n");
+               goto bail;
+       }
+
+       r = dd->ipath_f_set_ib_cfg(dd, IPATH_IB_CFG_LREV_ENB, val);
+       if (r < 0)
+               ret = r;
+
+bail:
+       return ret;
+}
 
 static DRIVER_ATTR(num_units, S_IRUGO, show_num_units, NULL);
 static DRIVER_ATTR(version, S_IRUGO, show_version, NULL);
@@ -610,7 +1000,82 @@ static struct attribute_group driver_attr_group = {
        .attrs = driver_attributes
 };
 
+static ssize_t store_tempsense(struct device *dev,
+                              struct device_attribute *attr,
+                              const char *buf,
+                              size_t count)
+{
+       struct ipath_devdata *dd = dev_get_drvdata(dev);
+       int ret, stat;
+       u16 val;
+
+       ret = ipath_parse_ushort(buf, &val);
+       if (ret <= 0) {
+               ipath_dev_err(dd, "attempt to set invalid tempsense config\n");
+               goto bail;
+       }
+       /* If anything but the highest limit, enable T_CRIT_A "interrupt" */
+       stat = ipath_tempsense_write(dd, 9, (val == 0x7f7f) ? 0x80 : 0);
+       if (stat) {
+               ipath_dev_err(dd, "Unable to set tempsense config\n");
+               ret = -1;
+               goto bail;
+       }
+       stat = ipath_tempsense_write(dd, 0xB, (u8) (val & 0xFF));
+       if (stat) {
+               ipath_dev_err(dd, "Unable to set local Tcrit\n");
+               ret = -1;
+               goto bail;
+       }
+       stat = ipath_tempsense_write(dd, 0xD, (u8) (val >> 8));
+       if (stat) {
+               ipath_dev_err(dd, "Unable to set remote Tcrit\n");
+               ret = -1;
+               goto bail;
+       }
+
+bail:
+       return ret;
+}
+
+/*
+ * dump tempsense regs. in decimal, to ease shell-scripts.
+ */
+static ssize_t show_tempsense(struct device *dev,
+                             struct device_attribute *attr,
+                             char *buf)
+{
+       struct ipath_devdata *dd = dev_get_drvdata(dev);
+       int ret;
+       int idx;
+       u8 regvals[8];
+
+       ret = -ENXIO;
+       for (idx = 0; idx < 8; ++idx) {
+               if (idx == 6)
+                       continue;
+               ret = ipath_tempsense_read(dd, idx);
+               if (ret < 0)
+                       break;
+               regvals[idx] = ret;
+       }
+       if (idx == 8)
+               ret = scnprintf(buf, PAGE_SIZE, "%d %d %02X %02X %d %d\n",
+                       *(signed char *)(regvals),
+                       *(signed char *)(regvals + 1),
+                       regvals[2], regvals[3],
+                       *(signed char *)(regvals + 5),
+                       *(signed char *)(regvals + 7));
+       return ret;
+}
+
+struct attribute_group *ipath_driver_attr_groups[] = {
+       &driver_attr_group,
+       NULL,
+};
+
 static DEVICE_ATTR(guid, S_IWUSR | S_IRUGO, show_guid, store_guid);
+static DEVICE_ATTR(lmc, S_IWUSR | S_IRUGO, show_lmc, store_lmc);
 static DEVICE_ATTR(lid, S_IWUSR | S_IRUGO, show_lid, store_lid);
 static DEVICE_ATTR(link_state, S_IWUSR, NULL, store_link_state);
 static DEVICE_ATTR(mlid, S_IWUSR | S_IRUGO, show_mlid, store_mlid);
@@ -625,9 +1090,19 @@ static DEVICE_ATTR(status_str, S_IRUGO, show_status_str, NULL);
 static DEVICE_ATTR(boardversion, S_IRUGO, show_boardversion, NULL);
 static DEVICE_ATTR(unit, S_IRUGO, show_unit, NULL);
 static DEVICE_ATTR(rx_pol_inv, S_IWUSR, NULL, store_rx_pol_inv);
+static DEVICE_ATTR(led_override, S_IWUSR, NULL, store_led_override);
+static DEVICE_ATTR(logged_errors, S_IRUGO, show_logged_errs, NULL);
+static DEVICE_ATTR(localbus_info, S_IRUGO, show_localbus_info, NULL);
+static DEVICE_ATTR(jint_max_packets, S_IWUSR | S_IRUGO,
+                  show_jint_max_packets, store_jint_max_packets);
+static DEVICE_ATTR(jint_idle_ticks, S_IWUSR | S_IRUGO,
+                  show_jint_idle_ticks, store_jint_idle_ticks);
+static DEVICE_ATTR(tempsense, S_IWUSR | S_IRUGO,
+                  show_tempsense, store_tempsense);
 
 static struct attribute *dev_attributes[] = {
        &dev_attr_guid.attr,
+       &dev_attr_lmc.attr,
        &dev_attr_lid.attr,
        &dev_attr_link_state.attr,
        &dev_attr_mlid.attr,
@@ -641,6 +1116,10 @@ static struct attribute *dev_attributes[] = {
        &dev_attr_unit.attr,
        &dev_attr_enabled.attr,
        &dev_attr_rx_pol_inv.attr,
+       &dev_attr_led_override.attr,
+       &dev_attr_logged_errors.attr,
+       &dev_attr_tempsense.attr,
+       &dev_attr_localbus_info.attr,
        NULL
 };
 
@@ -648,6 +1127,34 @@ static struct attribute_group dev_attr_group = {
        .attrs = dev_attributes
 };
 
+static DEVICE_ATTR(hrtbt_enable, S_IWUSR | S_IRUGO, show_hrtbt_enb,
+                  store_hrtbt_enb);
+static DEVICE_ATTR(link_width_enable, S_IWUSR | S_IRUGO, show_lwid_enb,
+                  store_lwid_enb);
+static DEVICE_ATTR(link_width, S_IRUGO, show_lwid, NULL);
+static DEVICE_ATTR(link_speed_enable, S_IWUSR | S_IRUGO, show_spd_enb,
+                  store_spd_enb);
+static DEVICE_ATTR(link_speed, S_IRUGO, show_spd, NULL);
+static DEVICE_ATTR(rx_pol_inv_enable, S_IWUSR | S_IRUGO, show_rx_polinv_enb,
+                  store_rx_polinv_enb);
+static DEVICE_ATTR(rx_lane_rev_enable, S_IWUSR | S_IRUGO, show_lanerev_enb,
+                  store_lanerev_enb);
+
+static struct attribute *dev_ibcfg_attributes[] = {
+       &dev_attr_hrtbt_enable.attr,
+       &dev_attr_link_width_enable.attr,
+       &dev_attr_link_width.attr,
+       &dev_attr_link_speed_enable.attr,
+       &dev_attr_link_speed.attr,
+       &dev_attr_rx_pol_inv_enable.attr,
+       &dev_attr_rx_lane_rev_enable.attr,
+       NULL
+};
+
+static struct attribute_group dev_ibcfg_attr_group = {
+       .attrs = dev_ibcfg_attributes
+};
+
 /**
  * ipath_expose_reset - create a device reset file
  * @dev: the device structure
@@ -674,24 +1181,9 @@ int ipath_expose_reset(struct device *dev)
        return ret;
 }
 
-int ipath_driver_create_group(struct device_driver *drv)
-{
-       int ret;
-
-       ret = sysfs_create_group(&drv->kobj, &driver_attr_group);
-
-       return ret;
-}
-
-void ipath_driver_remove_group(struct device_driver *drv)
-{
-       sysfs_remove_group(&drv->kobj, &driver_attr_group);
-}
-
 int ipath_device_create_group(struct device *dev, struct ipath_devdata *dd)
 {
        int ret;
-       char unit[5];
 
        ret = sysfs_create_group(&dev->kobj, &dev_attr_group);
        if (ret)
@@ -701,11 +1193,26 @@ int ipath_device_create_group(struct device *dev, struct ipath_devdata *dd)
        if (ret)
                goto bail_attrs;
 
-       snprintf(unit, sizeof(unit), "%02d", dd->ipath_unit);
-       ret = sysfs_create_link(&dev->driver->kobj, &dev->kobj, unit);
-       if (ret == 0)
-               goto bail;
+       if (dd->ipath_flags & IPATH_HAS_MULT_IB_SPEED) {
+               ret = device_create_file(dev, &dev_attr_jint_idle_ticks);
+               if (ret)
+                       goto bail_counter;
+               ret = device_create_file(dev, &dev_attr_jint_max_packets);
+               if (ret)
+                       goto bail_idle;
+
+               ret = sysfs_create_group(&dev->kobj, &dev_ibcfg_attr_group);
+               if (ret)
+                       goto bail_max;
+       }
 
+       return 0;
+
+bail_max:
+       device_remove_file(dev, &dev_attr_jint_max_packets);
+bail_idle:
+       device_remove_file(dev, &dev_attr_jint_idle_ticks);
+bail_counter:
        sysfs_remove_group(&dev->kobj, &dev_counter_attr_group);
 bail_attrs:
        sysfs_remove_group(&dev->kobj, &dev_attr_group);
@@ -715,12 +1222,14 @@ bail:
 
 void ipath_device_remove_group(struct device *dev, struct ipath_devdata *dd)
 {
-       char unit[5];
+       sysfs_remove_group(&dev->kobj, &dev_counter_attr_group);
 
-       snprintf(unit, sizeof(unit), "%02d", dd->ipath_unit);
-       sysfs_remove_link(&dev->driver->kobj, unit);
+       if (dd->ipath_flags & IPATH_HAS_MULT_IB_SPEED) {
+               sysfs_remove_group(&dev->kobj, &dev_ibcfg_attr_group);
+               device_remove_file(dev, &dev_attr_jint_idle_ticks);
+               device_remove_file(dev, &dev_attr_jint_max_packets);
+       }
 
-       sysfs_remove_group(&dev->kobj, &dev_counter_attr_group);
        sysfs_remove_group(&dev->kobj, &dev_attr_group);
 
        device_remove_file(dev, &dev_attr_reset);