Skip to content

Commit aed1b7b

Browse files
fancerjonmason
authored andcommitted
ntb: idt: Add basic hwmon sysfs interface
IDT PCIe switches provide an embedded temperature sensor working within [0; 127.5]C with resolution of 0.5C. They also can generate a PCIe upstream interrupt in case if the temperature passes through specified thresholds. Since this thresholds interface is very broken the created hwmon-sysfs interface exposes only the next set of hwmon nodes: current input temperature, lowest and highest values measured, history resetting, value offset. HWmon alarm interface isn't provided. IDT PCIe switch also've got an ADC/filter settings of the sensor. This driver doesn't expose them to the hwmon-sysfs interface at the moment, except the offset node. Signed-off-by: Serge Semin <fancer.lancer@gmail.com> Signed-off-by: Jon Mason <jdmason@kudzu.us>
1 parent 4007040 commit aed1b7b

File tree

3 files changed

+206
-1
lines changed

3 files changed

+206
-1
lines changed

drivers/ntb/hw/idt/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
config NTB_IDT
22
tristate "IDT PCIe-switch Non-Transparent Bridge support"
33
depends on PCI
4+
select HWMON
45
help
56
This driver supports NTB of cappable IDT PCIe-switches.
67

drivers/ntb/hw/idt/ntb_hw_idt.c

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,14 @@
4949
#include <linux/init.h>
5050
#include <linux/interrupt.h>
5151
#include <linux/spinlock.h>
52+
#include <linux/mutex.h>
5253
#include <linux/pci.h>
5354
#include <linux/aer.h>
5455
#include <linux/slab.h>
5556
#include <linux/list.h>
5657
#include <linux/debugfs.h>
58+
#include <linux/hwmon.h>
59+
#include <linux/hwmon-sysfs.h>
5760
#include <linux/ntb.h>
5861

5962
#include "ntb_hw_idt.h"
@@ -1924,6 +1927,153 @@ static void idt_read_temp(struct idt_ntb_dev *ndev,
19241927
*val = idt_get_temp_uval(data);
19251928
}
19261929

1930+
/*
1931+
* idt_write_temp() - write temperature to the chip sensor register
1932+
* @ntb: NTB device context.
1933+
* @type: IN - type of the temperature value to change
1934+
* @val: IN - integer value of temperature in millidegree Celsius
1935+
*/
1936+
static void idt_write_temp(struct idt_ntb_dev *ndev,
1937+
const enum idt_temp_val type, const long val)
1938+
{
1939+
unsigned int reg;
1940+
u32 data;
1941+
u8 fmt;
1942+
1943+
/* Retrieve the properly formatted temperature value */
1944+
fmt = idt_temp_get_fmt(val);
1945+
1946+
mutex_lock(&ndev->hwmon_mtx);
1947+
switch (type) {
1948+
case IDT_TEMP_LOW:
1949+
reg = IDT_SW_TMPALARM;
1950+
data = SET_FIELD(TMPALARM_LTEMP, idt_sw_read(ndev, reg), fmt) &
1951+
~IDT_TMPALARM_IRQ_MASK;
1952+
break;
1953+
case IDT_TEMP_HIGH:
1954+
reg = IDT_SW_TMPALARM;
1955+
data = SET_FIELD(TMPALARM_HTEMP, idt_sw_read(ndev, reg), fmt) &
1956+
~IDT_TMPALARM_IRQ_MASK;
1957+
break;
1958+
case IDT_TEMP_OFFSET:
1959+
reg = IDT_SW_TMPADJ;
1960+
data = SET_FIELD(TMPADJ_OFFSET, idt_sw_read(ndev, reg), fmt);
1961+
break;
1962+
default:
1963+
goto inval_spin_unlock;
1964+
}
1965+
1966+
idt_sw_write(ndev, reg, data);
1967+
1968+
inval_spin_unlock:
1969+
mutex_unlock(&ndev->hwmon_mtx);
1970+
}
1971+
1972+
/*
1973+
* idt_sysfs_show_temp() - printout corresponding temperature value
1974+
* @dev: Pointer to the NTB device structure
1975+
* @da: Sensor device attribute structure
1976+
* @buf: Buffer to print temperature out
1977+
*
1978+
* Return: Number of written symbols or negative error
1979+
*/
1980+
static ssize_t idt_sysfs_show_temp(struct device *dev,
1981+
struct device_attribute *da, char *buf)
1982+
{
1983+
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
1984+
struct idt_ntb_dev *ndev = dev_get_drvdata(dev);
1985+
enum idt_temp_val type = attr->index;
1986+
long mdeg;
1987+
1988+
idt_read_temp(ndev, type, &mdeg);
1989+
return sprintf(buf, "%ld\n", mdeg);
1990+
}
1991+
1992+
/*
1993+
* idt_sysfs_set_temp() - set corresponding temperature value
1994+
* @dev: Pointer to the NTB device structure
1995+
* @da: Sensor device attribute structure
1996+
* @buf: Buffer to print temperature out
1997+
* @count: Size of the passed buffer
1998+
*
1999+
* Return: Number of written symbols or negative error
2000+
*/
2001+
static ssize_t idt_sysfs_set_temp(struct device *dev,
2002+
struct device_attribute *da, const char *buf,
2003+
size_t count)
2004+
{
2005+
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
2006+
struct idt_ntb_dev *ndev = dev_get_drvdata(dev);
2007+
enum idt_temp_val type = attr->index;
2008+
long mdeg;
2009+
int ret;
2010+
2011+
ret = kstrtol(buf, 10, &mdeg);
2012+
if (ret)
2013+
return ret;
2014+
2015+
/* Clamp the passed value in accordance with the type */
2016+
if (type == IDT_TEMP_OFFSET)
2017+
mdeg = clamp_val(mdeg, IDT_TEMP_MIN_OFFSET,
2018+
IDT_TEMP_MAX_OFFSET);
2019+
else
2020+
mdeg = clamp_val(mdeg, IDT_TEMP_MIN_MDEG, IDT_TEMP_MAX_MDEG);
2021+
2022+
idt_write_temp(ndev, type, mdeg);
2023+
2024+
return count;
2025+
}
2026+
2027+
/*
2028+
* idt_sysfs_reset_hist() - reset temperature history
2029+
* @dev: Pointer to the NTB device structure
2030+
* @da: Sensor device attribute structure
2031+
* @buf: Buffer to print temperature out
2032+
* @count: Size of the passed buffer
2033+
*
2034+
* Return: Number of written symbols or negative error
2035+
*/
2036+
static ssize_t idt_sysfs_reset_hist(struct device *dev,
2037+
struct device_attribute *da,
2038+
const char *buf, size_t count)
2039+
{
2040+
struct idt_ntb_dev *ndev = dev_get_drvdata(dev);
2041+
2042+
/* Just set the maximal value to the lowest temperature field and
2043+
* minimal value to the highest temperature field
2044+
*/
2045+
idt_write_temp(ndev, IDT_TEMP_LOW, IDT_TEMP_MAX_MDEG);
2046+
idt_write_temp(ndev, IDT_TEMP_HIGH, IDT_TEMP_MIN_MDEG);
2047+
2048+
return count;
2049+
}
2050+
2051+
/*
2052+
* Hwmon IDT sysfs attributes
2053+
*/
2054+
static SENSOR_DEVICE_ATTR(temp1_input, 0444, idt_sysfs_show_temp, NULL,
2055+
IDT_TEMP_CUR);
2056+
static SENSOR_DEVICE_ATTR(temp1_lowest, 0444, idt_sysfs_show_temp, NULL,
2057+
IDT_TEMP_LOW);
2058+
static SENSOR_DEVICE_ATTR(temp1_highest, 0444, idt_sysfs_show_temp, NULL,
2059+
IDT_TEMP_HIGH);
2060+
static SENSOR_DEVICE_ATTR(temp1_offset, 0644, idt_sysfs_show_temp,
2061+
idt_sysfs_set_temp, IDT_TEMP_OFFSET);
2062+
static DEVICE_ATTR(temp1_reset_history, 0200, NULL, idt_sysfs_reset_hist);
2063+
2064+
/*
2065+
* Hwmon IDT sysfs attributes group
2066+
*/
2067+
static struct attribute *idt_temp_attrs[] = {
2068+
&sensor_dev_attr_temp1_input.dev_attr.attr,
2069+
&sensor_dev_attr_temp1_lowest.dev_attr.attr,
2070+
&sensor_dev_attr_temp1_highest.dev_attr.attr,
2071+
&sensor_dev_attr_temp1_offset.dev_attr.attr,
2072+
&dev_attr_temp1_reset_history.attr,
2073+
NULL
2074+
};
2075+
ATTRIBUTE_GROUPS(idt_temp);
2076+
19272077
/*
19282078
* idt_temp_isr() - temperature sensor alarm events ISR
19292079
* @ndev: IDT NTB hardware driver descriptor
@@ -1956,6 +2106,35 @@ static void idt_temp_isr(struct idt_ntb_dev *ndev, u32 ntint_sts)
19562106
idt_get_deg(mdeg), idt_get_deg_frac(mdeg));
19572107
}
19582108

2109+
/*
2110+
* idt_init_temp() - initialize temperature sensor interface
2111+
* @ndev: IDT NTB hardware driver descriptor
2112+
*
2113+
* Simple sensor initializarion method is responsible for device switching
2114+
* on and resource management based hwmon interface registration. Note, that
2115+
* since the device is shared we won't disable it on remove, but leave it
2116+
* working until the system is powered off.
2117+
*/
2118+
static void idt_init_temp(struct idt_ntb_dev *ndev)
2119+
{
2120+
struct device *hwmon;
2121+
2122+
/* Enable sensor if it hasn't been already */
2123+
idt_sw_write(ndev, IDT_SW_TMPCTL, 0x0);
2124+
2125+
/* Initialize hwmon interface fields */
2126+
mutex_init(&ndev->hwmon_mtx);
2127+
2128+
hwmon = devm_hwmon_device_register_with_groups(&ndev->ntb.pdev->dev,
2129+
ndev->swcfg->name, ndev, idt_temp_groups);
2130+
if (IS_ERR(hwmon)) {
2131+
dev_err(&ndev->ntb.pdev->dev, "Couldn't create hwmon device");
2132+
return;
2133+
}
2134+
2135+
dev_dbg(&ndev->ntb.pdev->dev, "Temperature HWmon interface registered");
2136+
}
2137+
19592138
/*=============================================================================
19602139
* 8. ISRs related operations
19612140
*
@@ -2650,6 +2829,9 @@ static int idt_pci_probe(struct pci_dev *pdev,
26502829
/* Initialize Messaging subsystem */
26512830
idt_init_msg(ndev);
26522831

2832+
/* Initialize hwmon interface */
2833+
idt_init_temp(ndev);
2834+
26532835
/* Initialize IDT interrupts handler */
26542836
ret = idt_init_isr(ndev);
26552837
if (ret != 0)

drivers/ntb/hw/idt/ntb_hw_idt.h

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,9 @@
4747
#include <linux/pci_ids.h>
4848
#include <linux/interrupt.h>
4949
#include <linux/spinlock.h>
50+
#include <linux/mutex.h>
5051
#include <linux/ntb.h>
5152

52-
5353
/*
5454
* Macro is used to create the struct pci_device_id that matches
5555
* the supported IDT PCIe-switches
@@ -907,6 +907,10 @@
907907
* TMPSTS register fields related constants
908908
* @IDT_TMPSTS_TEMP_MASK: Current temperature field mask
909909
* @IDT_TMPSTS_TEMP_FLD: Current temperature field offset
910+
* @IDT_TMPSTS_LTEMP_MASK: Lowest temperature field mask
911+
* @IDT_TMPSTS_LTEMP_FLD: Lowest temperature field offset
912+
* @IDT_TMPSTS_HTEMP_MASK: Highest temperature field mask
913+
* @IDT_TMPSTS_HTEMP_FLD: Highest temperature field offset
910914
*/
911915
#define IDT_TMPSTS_TEMP_MASK 0x000000FFU
912916
#define IDT_TMPSTS_TEMP_FLD 0
@@ -915,6 +919,20 @@
915919
#define IDT_TMPSTS_HTEMP_MASK 0x00FF0000U
916920
#define IDT_TMPSTS_HTEMP_FLD 16
917921

922+
/*
923+
* TMPALARM register fields related constants
924+
* @IDT_TMPALARM_LTEMP_MASK: Lowest temperature field mask
925+
* @IDT_TMPALARM_LTEMP_FLD: Lowest temperature field offset
926+
* @IDT_TMPALARM_HTEMP_MASK: Highest temperature field mask
927+
* @IDT_TMPALARM_HTEMP_FLD: Highest temperature field offset
928+
* @IDT_TMPALARM_IRQ_MASK: Alarm IRQ status mask
929+
*/
930+
#define IDT_TMPALARM_LTEMP_MASK 0x0000FF00U
931+
#define IDT_TMPALARM_LTEMP_FLD 8
932+
#define IDT_TMPALARM_HTEMP_MASK 0x00FF0000U
933+
#define IDT_TMPALARM_HTEMP_FLD 16
934+
#define IDT_TMPALARM_IRQ_MASK 0x3F000000U
935+
918936
/*
919937
* TMPADJ register fields related constants
920938
* @IDT_TMPADJ_OFFSET_MASK: Temperature value offset field mask
@@ -1100,6 +1118,8 @@ struct idt_ntb_peer {
11001118
* @msg_mask_lock: Message mask register lock
11011119
* @gasa_lock: GASA registers access lock
11021120
*
1121+
* @hwmon_mtx: Temperature sensor interface update mutex
1122+
*
11031123
* @dbgfs_info: DebugFS info node
11041124
*/
11051125
struct idt_ntb_dev {
@@ -1127,6 +1147,8 @@ struct idt_ntb_dev {
11271147
spinlock_t msg_mask_lock;
11281148
spinlock_t gasa_lock;
11291149

1150+
struct mutex hwmon_mtx;
1151+
11301152
struct dentry *dbgfs_info;
11311153
};
11321154
#define to_ndev_ntb(__ntb) container_of(__ntb, struct idt_ntb_dev, ntb)

0 commit comments

Comments
 (0)