Commit 8dcf2ad3 authored by Mark Starovoytov's avatar Mark Starovoytov Committed by David S. Miller
Browse files

net: atlantic: add hwmon getter for MAC temperature



This patch adds the possibility to obtain MAC temperature via hwmon.
On A1 there are two separate temperature sensors.
On A2 there's only one temperature sensor, which is used for reporting
both MAC and PHY temperature.

Signed-off-by: default avatarMark Starovoytov <mstarovoitov@marvell.com>
Signed-off-by: default avatarIgor Russkikh <irusskikh@marvell.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent a89df867
Loading
Loading
Loading
Loading
+45 −17
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (C) 2014-2019 aQuantia Corporation. */
/* Atlantic Network Driver
 *
 * Copyright (C) 2014-2019 aQuantia Corporation
 * Copyright (C) 2019-2020 Marvell International Ltd.
 */

/* File aq_drvinfo.c: Definition of common code for firmware info in sys.*/

@@ -12,32 +16,51 @@
#include <linux/uaccess.h>

#include "aq_drvinfo.h"
#include "aq_nic.h"

#if IS_REACHABLE(CONFIG_HWMON)
static const char * const atl_temp_label[] = {
	"PHY Temperature",
	"MAC Temperature",
};

static int aq_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
			 u32 attr, int channel, long *value)
{
	struct aq_nic_s *aq_nic = dev_get_drvdata(dev);
	int err = 0;
	int temp;
	int err;

	if (!aq_nic)
		return -EIO;

	if (type != hwmon_temp)
	if (type != hwmon_temp || attr != hwmon_temp_input)
		return -EOPNOTSUPP;

	switch (channel) {
	case 0:
		if (!aq_nic->aq_fw_ops->get_phy_temp)
			return -EOPNOTSUPP;

	switch (attr) {
	case hwmon_temp_input:
		err = aq_nic->aq_fw_ops->get_phy_temp(aq_nic->aq_hw, &temp);
		*value = temp;
		return err;
		break;
	case 1:
		if (!aq_nic->aq_fw_ops->get_mac_temp &&
		    !aq_nic->aq_hw_ops->hw_get_mac_temp)
			return -EOPNOTSUPP;

		if (aq_nic->aq_fw_ops->get_mac_temp)
			err = aq_nic->aq_fw_ops->get_mac_temp(aq_nic->aq_hw, &temp);
		else
			err = aq_nic->aq_hw_ops->hw_get_mac_temp(aq_nic->aq_hw, &temp);
		*value = temp;
		break;
	default:
		return -EOPNOTSUPP;
	}

	return err;
}

static int aq_hwmon_read_string(struct device *dev,
@@ -49,28 +72,32 @@ static int aq_hwmon_read_string(struct device *dev,
	if (!aq_nic)
		return -EIO;

	if (type != hwmon_temp)
	if (type != hwmon_temp || attr != hwmon_temp_label)
		return -EOPNOTSUPP;

	if (!aq_nic->aq_fw_ops->get_phy_temp)
	if (channel < ARRAY_SIZE(atl_temp_label))
		*str = atl_temp_label[channel];
	else
		return -EOPNOTSUPP;

	switch (attr) {
	case hwmon_temp_label:
		*str = "PHY Temperature";
	return 0;
	default:
		return -EOPNOTSUPP;
	}
}

static umode_t aq_hwmon_is_visible(const void *data,
				   enum hwmon_sensor_types type,
				   u32 attr, int channel)
{
	const struct aq_nic_s *nic = data;

	if (type != hwmon_temp)
		return 0;

	if (channel == 0 && !nic->aq_fw_ops->get_phy_temp)
		return 0;
	else if (channel == 1 && !nic->aq_fw_ops->get_mac_temp &&
		 !nic->aq_hw_ops->hw_get_mac_temp)
		return 0;

	switch (attr) {
	case hwmon_temp_input:
	case hwmon_temp_label:
@@ -87,6 +114,7 @@ static const struct hwmon_ops aq_hwmon_ops = {
};

static u32 aq_hwmon_temp_config[] = {
	HWMON_T_INPUT | HWMON_T_LABEL,
	HWMON_T_INPUT | HWMON_T_LABEL,
	0,
};
+6 −4
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-only */
/* Copyright (C) 2014-2017 aQuantia Corporation. */
/* Atlantic Network Driver
 *
 * Copyright (C) 2014-2019 aQuantia Corporation
 * Copyright (C) 2019-2020 Marvell International Ltd.
 */

/* File aq_drvinfo.h: Declaration of common code for firmware info in sys.*/

#ifndef AQ_DRVINFO_H
#define AQ_DRVINFO_H

#include "aq_nic.h"
#include "aq_hw.h"
#include "hw_atl/hw_atl_utils.h"
struct net_device;

int aq_drvinfo_init(struct net_device *ndev);

+4 −0
Original line number Diff line number Diff line
@@ -333,6 +333,8 @@ struct aq_hw_ops {
	int (*hw_set_fc)(struct aq_hw_s *self, u32 fc, u32 tc);

	int (*hw_set_loopback)(struct aq_hw_s *self, u32 mode, bool enable);

	int (*hw_get_mac_temp)(struct aq_hw_s *self, u32 *temp);
};

struct aq_fw_ops {
@@ -355,6 +357,8 @@ struct aq_fw_ops {

	int (*update_stats)(struct aq_hw_s *self);

	int (*get_mac_temp)(struct aq_hw_s *self, int *temp);

	int (*get_phy_temp)(struct aq_hw_s *self, int *temp);

	u32 (*get_flow_control)(struct aq_hw_s *self, u32 *fcmode);
+44 −0
Original line number Diff line number Diff line
@@ -1581,6 +1581,48 @@ int hw_atl_b0_set_loopback(struct aq_hw_s *self, u32 mode, bool enable)
	return 0;
}

static u32 hw_atl_b0_ts_ready_and_latch_high_get(struct aq_hw_s *self)
{
	if (hw_atl_ts_ready_get(self) && hw_atl_ts_ready_latch_high_get(self))
		return 1;

	return 0;
}

static int hw_atl_b0_get_mac_temp(struct aq_hw_s *self, u32 *temp)
{
	bool ts_disabled;
	int err;
	u32 val;
	u32 ts;

	ts_disabled = (hw_atl_ts_power_down_get(self) == 1U);

	if (ts_disabled) {
		// Set AFE Temperature Sensor to on (off by default)
		hw_atl_ts_power_down_set(self, 0U);

		// Reset internal capacitors, biasing, and counters
		hw_atl_ts_reset_set(self, 1);
		hw_atl_ts_reset_set(self, 0);
	}

	err = readx_poll_timeout_atomic(hw_atl_b0_ts_ready_and_latch_high_get,
					self, val, val == 1, 10000U, 500000U);
	if (err)
		return err;

	ts = hw_atl_ts_data_get(self);
	*temp = ts * ts * 16 / 100000 + 60 * ts - 83410;

	if (ts_disabled) {
		// Set AFE Temperature Sensor back to off
		hw_atl_ts_power_down_set(self, 1U);
	}

	return 0;
}

const struct aq_hw_ops hw_atl_ops_b0 = {
	.hw_soft_reset        = hw_atl_utils_soft_reset,
	.hw_prepare           = hw_atl_utils_initfw,
@@ -1637,4 +1679,6 @@ const struct aq_hw_ops hw_atl_ops_b0 = {
	.hw_set_offload          = hw_atl_b0_hw_offload_set,
	.hw_set_loopback         = hw_atl_b0_set_loopback,
	.hw_set_fc               = hw_atl_b0_set_fc,

	.hw_get_mac_temp         = hw_atl_b0_get_mac_temp,
};
+44 −0
Original line number Diff line number Diff line
@@ -13,6 +13,50 @@
#include "hw_atl_llh_internal.h"
#include "../aq_hw_utils.h"

void hw_atl_ts_reset_set(struct aq_hw_s *aq_hw, u32 val)
{
	aq_hw_write_reg_bit(aq_hw, HW_ATL_TS_RESET_ADR,
			    HW_ATL_TS_RESET_MSK,
			    HW_ATL_TS_RESET_SHIFT,
			    val);
}

void hw_atl_ts_power_down_set(struct aq_hw_s *aq_hw, u32 val)
{
	aq_hw_write_reg_bit(aq_hw, HW_ATL_TS_POWER_DOWN_ADR,
			    HW_ATL_TS_POWER_DOWN_MSK,
			    HW_ATL_TS_POWER_DOWN_SHIFT,
			    val);
}

u32 hw_atl_ts_power_down_get(struct aq_hw_s *aq_hw)
{
	return aq_hw_read_reg_bit(aq_hw, HW_ATL_TS_POWER_DOWN_ADR,
				  HW_ATL_TS_POWER_DOWN_MSK,
				  HW_ATL_TS_POWER_DOWN_SHIFT);
}

u32 hw_atl_ts_ready_get(struct aq_hw_s *aq_hw)
{
	return aq_hw_read_reg_bit(aq_hw, HW_ATL_TS_READY_ADR,
				  HW_ATL_TS_READY_MSK,
				  HW_ATL_TS_READY_SHIFT);
}

u32 hw_atl_ts_ready_latch_high_get(struct aq_hw_s *aq_hw)
{
	return aq_hw_read_reg_bit(aq_hw, HW_ATL_TS_READY_LATCH_HIGH_ADR,
				  HW_ATL_TS_READY_LATCH_HIGH_MSK,
				  HW_ATL_TS_READY_LATCH_HIGH_SHIFT);
}

u32 hw_atl_ts_data_get(struct aq_hw_s *aq_hw)
{
	return aq_hw_read_reg_bit(aq_hw, HW_ATL_TS_DATA_OUT_ADR,
				  HW_ATL_TS_DATA_OUT_MSK,
				  HW_ATL_TS_DATA_OUT_SHIFT);
}

/* global */
void hw_atl_reg_glb_cpu_sem_set(struct aq_hw_s *aq_hw, u32 glb_cpu_sem,
				u32 semaphore)
Loading