ntb: idt: Alter temperature read method
authorSerge Semin <fancer.lancer@gmail.com>
Tue, 17 Jul 2018 09:24:34 +0000 (12:24 +0300)
committerJon Mason <jdmason@kudzu.us>
Thu, 1 Nov 2018 14:33:12 +0000 (10:33 -0400)
In order to create a hwmon interface for the IDT PCIe-switch temperature
sensor the already available reader method should be improved. Particularly
we need to redesign it so one would be able to read temperature/offset
values from registers of the passed types. Since IDT sensor interface
provides temperature in unsigned format 0:7:1 (7 bits for real value
and one for fraction) we also need to have helpers for the typical sysfs
temperature data type conversion to and from this format. Even though
the IDT PCIe-switch provided temperature offset got the same but signed
type it can be translated by these methods too.

Signed-off-by: Serge Semin <fancer.lancer@gmail.com>
Signed-off-by: Jon Mason <jdmason@kudzu.us>
drivers/ntb/hw/idt/ntb_hw_idt.c
drivers/ntb/hw/idt/ntb_hw_idt.h

index 54485a8d2d7f8f5b75b1526ef78c60def6c1a283..adb71f7c104378d534a788bc175959891079af88 100644 (file)
@@ -1828,23 +1828,100 @@ static int idt_ntb_peer_msg_write(struct ntb_dev *ntb, int pidx, int midx,
  *=============================================================================
  */
 
+/*
+ * idt_get_deg() - convert millidegree Celsius value to just degree
+ * @mdegC:     IN - millidegree Celsius value
+ *
+ * Return: Degree corresponding to the passed millidegree value
+ */
+static inline s8 idt_get_deg(long mdegC)
+{
+       return mdegC / 1000;
+}
+
+/*
+ * idt_get_frac() - retrieve 0/0.5 fraction of the millidegree Celsius value
+ * @mdegC:     IN - millidegree Celsius value
+ *
+ * Return: 0/0.5 degree fraction of the passed millidegree value
+ */
+static inline u8 idt_get_deg_frac(long mdegC)
+{
+       return (mdegC % 1000) >= 500 ? 5 : 0;
+}
+
+/*
+ * idt_get_temp_fmt() - convert millidegree Celsius value to 0:7:1 format
+ * @mdegC:     IN - millidegree Celsius value
+ *
+ * Return: 0:7:1 format acceptable by the IDT temperature sensor
+ */
+static inline u8 idt_temp_get_fmt(long mdegC)
+{
+       return (idt_get_deg(mdegC) << 1) | (idt_get_deg_frac(mdegC) ? 1 : 0);
+}
+
+/*
+ * idt_get_temp_sval() - convert temp sample to signed millidegree Celsius
+ * @data:      IN - shifted to LSB 8-bits temperature sample
+ *
+ * Return: signed millidegree Celsius
+ */
+static inline long idt_get_temp_sval(u32 data)
+{
+       return ((s8)data / 2) * 1000 + (data & 0x1 ? 500 : 0);
+}
+
+/*
+ * idt_get_temp_sval() - convert temp sample to unsigned millidegree Celsius
+ * @data:      IN - shifted to LSB 8-bits temperature sample
+ *
+ * Return: unsigned millidegree Celsius
+ */
+static inline long idt_get_temp_uval(u32 data)
+{
+       return (data / 2) * 1000 + (data & 0x1 ? 500 : 0);
+}
+
 /*
  * idt_read_temp() - read temperature from chip sensor
  * @ntb:       NTB device context.
- * @val:       OUT - integer value of temperature
- * @frac:      OUT - fraction
+ * @type:      IN - type of the temperature value to read
+ * @val:       OUT - integer value of temperature in millidegree Celsius
  */
-static void idt_read_temp(struct idt_ntb_dev *ndev, unsigned char *val,
-                         unsigned char *frac)
+static void idt_read_temp(struct idt_ntb_dev *ndev,
+                         const enum idt_temp_val type, long *val)
 {
        u32 data;
 
-       /* Read the data from TEMP field of the TMPSTS register */
-       data = idt_sw_read(ndev, IDT_SW_TMPSTS);
-       data = GET_FIELD(TMPSTS_TEMP, data);
-       /* TEMP field has one fractional bit and seven integer bits */
-       *val = data >> 1;
-       *frac = ((data & 0x1) ? 5 : 0);
+       /* Alter the temperature field in accordance with the passed type */
+       switch (type) {
+       case IDT_TEMP_CUR:
+               data = GET_FIELD(TMPSTS_TEMP,
+                                idt_sw_read(ndev, IDT_SW_TMPSTS));
+               break;
+       case IDT_TEMP_LOW:
+               data = GET_FIELD(TMPSTS_LTEMP,
+                                idt_sw_read(ndev, IDT_SW_TMPSTS));
+               break;
+       case IDT_TEMP_HIGH:
+               data = GET_FIELD(TMPSTS_HTEMP,
+                                idt_sw_read(ndev, IDT_SW_TMPSTS));
+               break;
+       case IDT_TEMP_OFFSET:
+               /* This is the only field with signed 0:7:1 format */
+               data = GET_FIELD(TMPADJ_OFFSET,
+                                idt_sw_read(ndev, IDT_SW_TMPADJ));
+               *val = idt_get_temp_sval(data);
+               return;
+       default:
+               data = GET_FIELD(TMPSTS_TEMP,
+                                idt_sw_read(ndev, IDT_SW_TMPSTS));
+               break;
+       }
+
+       /* The rest of the fields accept unsigned 0:7:1 format */
+       *val = idt_get_temp_uval(data);
 }
 
 /*
@@ -1860,10 +1937,10 @@ static void idt_read_temp(struct idt_ntb_dev *ndev, unsigned char *val,
  */
 static void idt_temp_isr(struct idt_ntb_dev *ndev, u32 ntint_sts)
 {
-       unsigned char val, frac;
+       unsigned long mdeg;
 
        /* Read the current temperature value */
-       idt_read_temp(ndev, &val, &frac);
+       idt_read_temp(ndev, IDT_TEMP_CUR, &mdeg);
 
        /* Read the temperature alarm to clean the alarm status out */
        /*(void)idt_sw_read(ndev, IDT_SW_TMPALARM);*/
@@ -1875,7 +1952,8 @@ static void idt_temp_isr(struct idt_ntb_dev *ndev, u32 ntint_sts)
                "Temp sensor IRQ detected %#08x", ntint_sts);
 
        /* Print temperature value to log */
-       dev_warn(&ndev->ntb.pdev->dev, "Temperature %hhu.%hhu", val, frac);
+       dev_warn(&ndev->ntb.pdev->dev, "Temperature %hhd.%hhuC",
+               idt_get_deg(mdeg), idt_get_deg_frac(mdeg));
 }
 
 /*=============================================================================
@@ -2123,9 +2201,9 @@ static ssize_t idt_dbgfs_info_read(struct file *filp, char __user *ubuf,
                                   size_t count, loff_t *offp)
 {
        struct idt_ntb_dev *ndev = filp->private_data;
-       unsigned char temp, frac, idx, pidx, cnt;
+       unsigned char idx, pidx, cnt;
+       unsigned long irqflags, mdeg;
        ssize_t ret = 0, off = 0;
-       unsigned long irqflags;
        enum ntb_speed speed;
        enum ntb_width width;
        char *strbuf;
@@ -2274,9 +2352,10 @@ static ssize_t idt_dbgfs_info_read(struct file *filp, char __user *ubuf,
        off += scnprintf(strbuf + off, size - off, "\n");
 
        /* Current temperature */
-       idt_read_temp(ndev, &temp, &frac);
+       idt_read_temp(ndev, IDT_TEMP_CUR, &mdeg);
        off += scnprintf(strbuf + off, size - off,
-               "Switch temperature\t\t- %hhu.%hhuC\n", temp, frac);
+               "Switch temperature\t\t- %hhd.%hhuC\n",
+               idt_get_deg(mdeg), idt_get_deg_frac(mdeg));
 
        /* Copy the buffer to the User Space */
        ret = simple_read_from_buffer(ubuf, count, offp, strbuf, off);
index 856fd182f6f4f08816bd8523c338823187caf43c..9dfd6b11a621e9e15bc80f47e758c5c17092cc5c 100644 (file)
 #define IDT_SWPxMSGCTL_PART_MASK       0x00000070U
 #define IDT_SWPxMSGCTL_PART_FLD                4
 
+/*
+ * TMPCTL register fields related constants
+ * @IDT_TMPCTL_LTH_MASK:       Low temperature threshold field mask
+ * @IDT_TMPCTL_LTH_FLD:                Low temperature threshold field offset
+ * @IDT_TMPCTL_MTH_MASK:       Middle temperature threshold field mask
+ * @IDT_TMPCTL_MTH_FLD:                Middle temperature threshold field offset
+ * @IDT_TMPCTL_HTH_MASK:       High temperature threshold field mask
+ * @IDT_TMPCTL_HTH_FLD:                High temperature threshold field offset
+ * @IDT_TMPCTL_PDOWN:          Temperature sensor power down
+ */
+#define IDT_TMPCTL_LTH_MASK            0x000000FFU
+#define IDT_TMPCTL_LTH_FLD             0
+#define IDT_TMPCTL_MTH_MASK            0x0000FF00U
+#define IDT_TMPCTL_MTH_FLD             8
+#define IDT_TMPCTL_HTH_MASK            0x00FF0000U
+#define IDT_TMPCTL_HTH_FLD             16
+#define IDT_TMPCTL_PDOWN               0x80000000U
+
 /*
  * TMPSTS register fields related constants
  * @IDT_TMPSTS_TEMP_MASK:      Current temperature field mask
  */
 #define IDT_TMPSTS_TEMP_MASK           0x000000FFU
 #define IDT_TMPSTS_TEMP_FLD            0
+#define IDT_TMPSTS_LTEMP_MASK          0x0000FF00U
+#define IDT_TMPSTS_LTEMP_FLD           8
+#define IDT_TMPSTS_HTEMP_MASK          0x00FF0000U
+#define IDT_TMPSTS_HTEMP_FLD           16
+
+/*
+ * TMPADJ register fields related constants
+ * @IDT_TMPADJ_OFFSET_MASK:    Temperature value offset field mask
+ * @IDT_TMPADJ_OFFSET_FLD:     Temperature value offset field offset
+ */
+#define IDT_TMPADJ_OFFSET_MASK         0x000000FFU
+#define IDT_TMPADJ_OFFSET_FLD          0
 
 /*
  * Helper macro to get/set the corresponding field value
 #define IDT_TRANS_ALIGN                4
 #define IDT_DIR_SIZE_ALIGN     1
 
+/*
+ * IDT PCIe-switch temperature sensor value limits
+ * @IDT_TEMP_MIN_MDEG: Minimal integer value of temperature
+ * @IDT_TEMP_MAX_MDEG: Maximal integer value of temperature
+ * @IDT_TEMP_MIN_OFFSET:Minimal integer value of temperature offset
+ * @IDT_TEMP_MAX_OFFSET:Maximal integer value of temperature offset
+ */
+#define IDT_TEMP_MIN_MDEG      0
+#define IDT_TEMP_MAX_MDEG      127500
+#define IDT_TEMP_MIN_OFFSET    -64000
+#define IDT_TEMP_MAX_OFFSET    63500
+
+/*
+ * Temperature sensor values enumeration
+ * @IDT_TEMP_CUR:      Current temperature
+ * @IDT_TEMP_LOW:      Lowest historical temperature
+ * @IDT_TEMP_HIGH:     Highest historical temperature
+ * @IDT_TEMP_OFFSET:   Current temperature offset
+ */
+enum idt_temp_val {
+       IDT_TEMP_CUR,
+       IDT_TEMP_LOW,
+       IDT_TEMP_HIGH,
+       IDT_TEMP_OFFSET
+};
+
 /*
  * IDT Memory Windows type. Depending on the device settings, IDT supports
  * Direct Address Translation MW registers and Lookup Table registers