cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

aquantia_hwmon.c (5981B)


      1// SPDX-License-Identifier: GPL-2.0
      2/* HWMON driver for Aquantia PHY
      3 *
      4 * Author: Nikita Yushchenko <nikita.yoush@cogentembedded.com>
      5 * Author: Andrew Lunn <andrew@lunn.ch>
      6 * Author: Heiner Kallweit <hkallweit1@gmail.com>
      7 */
      8
      9#include <linux/phy.h>
     10#include <linux/device.h>
     11#include <linux/ctype.h>
     12#include <linux/hwmon.h>
     13
     14#include "aquantia.h"
     15
     16/* Vendor specific 1, MDIO_MMD_VEND2 */
     17#define VEND1_THERMAL_PROV_HIGH_TEMP_FAIL	0xc421
     18#define VEND1_THERMAL_PROV_LOW_TEMP_FAIL	0xc422
     19#define VEND1_THERMAL_PROV_HIGH_TEMP_WARN	0xc423
     20#define VEND1_THERMAL_PROV_LOW_TEMP_WARN	0xc424
     21#define VEND1_THERMAL_STAT1			0xc820
     22#define VEND1_THERMAL_STAT2			0xc821
     23#define VEND1_THERMAL_STAT2_VALID		BIT(0)
     24#define VEND1_GENERAL_STAT1			0xc830
     25#define VEND1_GENERAL_STAT1_HIGH_TEMP_FAIL	BIT(14)
     26#define VEND1_GENERAL_STAT1_LOW_TEMP_FAIL	BIT(13)
     27#define VEND1_GENERAL_STAT1_HIGH_TEMP_WARN	BIT(12)
     28#define VEND1_GENERAL_STAT1_LOW_TEMP_WARN	BIT(11)
     29
     30#if IS_REACHABLE(CONFIG_HWMON)
     31
     32static umode_t aqr_hwmon_is_visible(const void *data,
     33				    enum hwmon_sensor_types type,
     34				    u32 attr, int channel)
     35{
     36	if (type != hwmon_temp)
     37		return 0;
     38
     39	switch (attr) {
     40	case hwmon_temp_input:
     41	case hwmon_temp_min_alarm:
     42	case hwmon_temp_max_alarm:
     43	case hwmon_temp_lcrit_alarm:
     44	case hwmon_temp_crit_alarm:
     45		return 0444;
     46	case hwmon_temp_min:
     47	case hwmon_temp_max:
     48	case hwmon_temp_lcrit:
     49	case hwmon_temp_crit:
     50		return 0644;
     51	default:
     52		return 0;
     53	}
     54}
     55
     56static int aqr_hwmon_get(struct phy_device *phydev, int reg, long *value)
     57{
     58	int temp = phy_read_mmd(phydev, MDIO_MMD_VEND1, reg);
     59
     60	if (temp < 0)
     61		return temp;
     62
     63	/* 16 bit value is 2's complement with LSB = 1/256th degree Celsius */
     64	*value = (s16)temp * 1000 / 256;
     65
     66	return 0;
     67}
     68
     69static int aqr_hwmon_set(struct phy_device *phydev, int reg, long value)
     70{
     71	int temp;
     72
     73	if (value >= 128000 || value < -128000)
     74		return -ERANGE;
     75
     76	temp = value * 256 / 1000;
     77
     78	/* temp is in s16 range and we're interested in lower 16 bits only */
     79	return phy_write_mmd(phydev, MDIO_MMD_VEND1, reg, (u16)temp);
     80}
     81
     82static int aqr_hwmon_test_bit(struct phy_device *phydev, int reg, int bit)
     83{
     84	int val = phy_read_mmd(phydev, MDIO_MMD_VEND1, reg);
     85
     86	if (val < 0)
     87		return val;
     88
     89	return !!(val & bit);
     90}
     91
     92static int aqr_hwmon_status1(struct phy_device *phydev, int bit, long *value)
     93{
     94	int val = aqr_hwmon_test_bit(phydev, VEND1_GENERAL_STAT1, bit);
     95
     96	if (val < 0)
     97		return val;
     98
     99	*value = val;
    100
    101	return 0;
    102}
    103
    104static int aqr_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
    105			  u32 attr, int channel, long *value)
    106{
    107	struct phy_device *phydev = dev_get_drvdata(dev);
    108	int reg;
    109
    110	if (type != hwmon_temp)
    111		return -EOPNOTSUPP;
    112
    113	switch (attr) {
    114	case hwmon_temp_input:
    115		reg = aqr_hwmon_test_bit(phydev, VEND1_THERMAL_STAT2,
    116					 VEND1_THERMAL_STAT2_VALID);
    117		if (reg < 0)
    118			return reg;
    119		if (!reg)
    120			return -EBUSY;
    121
    122		return aqr_hwmon_get(phydev, VEND1_THERMAL_STAT1, value);
    123
    124	case hwmon_temp_lcrit:
    125		return aqr_hwmon_get(phydev, VEND1_THERMAL_PROV_LOW_TEMP_FAIL,
    126				     value);
    127	case hwmon_temp_min:
    128		return aqr_hwmon_get(phydev, VEND1_THERMAL_PROV_LOW_TEMP_WARN,
    129				     value);
    130	case hwmon_temp_max:
    131		return aqr_hwmon_get(phydev, VEND1_THERMAL_PROV_HIGH_TEMP_WARN,
    132				     value);
    133	case hwmon_temp_crit:
    134		return aqr_hwmon_get(phydev, VEND1_THERMAL_PROV_HIGH_TEMP_FAIL,
    135				     value);
    136	case hwmon_temp_lcrit_alarm:
    137		return aqr_hwmon_status1(phydev,
    138					 VEND1_GENERAL_STAT1_LOW_TEMP_FAIL,
    139					 value);
    140	case hwmon_temp_min_alarm:
    141		return aqr_hwmon_status1(phydev,
    142					 VEND1_GENERAL_STAT1_LOW_TEMP_WARN,
    143					 value);
    144	case hwmon_temp_max_alarm:
    145		return aqr_hwmon_status1(phydev,
    146					 VEND1_GENERAL_STAT1_HIGH_TEMP_WARN,
    147					 value);
    148	case hwmon_temp_crit_alarm:
    149		return aqr_hwmon_status1(phydev,
    150					 VEND1_GENERAL_STAT1_HIGH_TEMP_FAIL,
    151					 value);
    152	default:
    153		return -EOPNOTSUPP;
    154	}
    155}
    156
    157static int aqr_hwmon_write(struct device *dev, enum hwmon_sensor_types type,
    158			   u32 attr, int channel, long value)
    159{
    160	struct phy_device *phydev = dev_get_drvdata(dev);
    161
    162	if (type != hwmon_temp)
    163		return -EOPNOTSUPP;
    164
    165	switch (attr) {
    166	case hwmon_temp_lcrit:
    167		return aqr_hwmon_set(phydev, VEND1_THERMAL_PROV_LOW_TEMP_FAIL,
    168				     value);
    169	case hwmon_temp_min:
    170		return aqr_hwmon_set(phydev, VEND1_THERMAL_PROV_LOW_TEMP_WARN,
    171				     value);
    172	case hwmon_temp_max:
    173		return aqr_hwmon_set(phydev, VEND1_THERMAL_PROV_HIGH_TEMP_WARN,
    174				     value);
    175	case hwmon_temp_crit:
    176		return aqr_hwmon_set(phydev, VEND1_THERMAL_PROV_HIGH_TEMP_FAIL,
    177				     value);
    178	default:
    179		return -EOPNOTSUPP;
    180	}
    181}
    182
    183static const struct hwmon_ops aqr_hwmon_ops = {
    184	.is_visible = aqr_hwmon_is_visible,
    185	.read = aqr_hwmon_read,
    186	.write = aqr_hwmon_write,
    187};
    188
    189static u32 aqr_hwmon_chip_config[] = {
    190	HWMON_C_REGISTER_TZ,
    191	0,
    192};
    193
    194static const struct hwmon_channel_info aqr_hwmon_chip = {
    195	.type = hwmon_chip,
    196	.config = aqr_hwmon_chip_config,
    197};
    198
    199static u32 aqr_hwmon_temp_config[] = {
    200	HWMON_T_INPUT |
    201	HWMON_T_MAX | HWMON_T_MIN |
    202	HWMON_T_MAX_ALARM | HWMON_T_MIN_ALARM |
    203	HWMON_T_CRIT | HWMON_T_LCRIT |
    204	HWMON_T_CRIT_ALARM | HWMON_T_LCRIT_ALARM,
    205	0,
    206};
    207
    208static const struct hwmon_channel_info aqr_hwmon_temp = {
    209	.type = hwmon_temp,
    210	.config = aqr_hwmon_temp_config,
    211};
    212
    213static const struct hwmon_channel_info *aqr_hwmon_info[] = {
    214	&aqr_hwmon_chip,
    215	&aqr_hwmon_temp,
    216	NULL,
    217};
    218
    219static const struct hwmon_chip_info aqr_hwmon_chip_info = {
    220	.ops = &aqr_hwmon_ops,
    221	.info = aqr_hwmon_info,
    222};
    223
    224int aqr_hwmon_probe(struct phy_device *phydev)
    225{
    226	struct device *dev = &phydev->mdio.dev;
    227	struct device *hwmon_dev;
    228	char *hwmon_name;
    229	int i, j;
    230
    231	hwmon_name = devm_kstrdup(dev, dev_name(dev), GFP_KERNEL);
    232	if (!hwmon_name)
    233		return -ENOMEM;
    234
    235	for (i = j = 0; hwmon_name[i]; i++) {
    236		if (isalnum(hwmon_name[i])) {
    237			if (i != j)
    238				hwmon_name[j] = hwmon_name[i];
    239			j++;
    240		}
    241	}
    242	hwmon_name[j] = '\0';
    243
    244	hwmon_dev = devm_hwmon_device_register_with_info(dev, hwmon_name,
    245					phydev, &aqr_hwmon_chip_info, NULL);
    246
    247	return PTR_ERR_OR_ZERO(hwmon_dev);
    248}
    249
    250#endif