Commit 4f1b4da5 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'net-atlantic-various-features'

Mark Starovoytov says:

====================
net: atlantic: various features

This patchset adds more features for Atlantic NICs:
 * media detect;
 * additional per-queue stats;
 * PTP stats;
 * ipv6 support for TCP LSO and UDP GSO;
 * 64-bit operations;
 * A0 ntuple filters;
 * MAC temperature (hwmon).

This work is a joint effort of Marvell developers.

v3:
 * reworked patches related to stats:
   . fixed u64_stats_update_* usage;
   . use simple assignment in _get_stats / _fill_stats_data;
   . made _get_sw_stats / _fill_stats_data return count as return value;
   . split rx and tx per-queue stats;

v2: https://patchwork.ozlabs.org/cover/1329652/
 * removed media detect feature (will be reworked and submitted later);
 * removed irq counter from stats;
 * use u64_stats_update_* to protect 64-bit stats;
 * use io-64-nonatomic-lo-hi.h for readq/writeq fallbacks;

v1: https://patchwork.ozlabs.org/cover/1327894/


====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 5c5b7581 8dcf2ad3
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);

+60 −8
Original line number Diff line number Diff line
@@ -89,13 +89,19 @@ static const char aq_ethtool_stat_names[][ETH_GSTRING_LEN] = {
	"InDroppedDma",
};

static const char * const aq_ethtool_queue_stat_names[] = {
static const char * const aq_ethtool_queue_rx_stat_names[] = {
	"%sQueue[%d] InPackets",
	"%sQueue[%d] OutPackets",
	"%sQueue[%d] Restarts",
	"%sQueue[%d] InJumboPackets",
	"%sQueue[%d] InLroPackets",
	"%sQueue[%d] InErrors",
	"%sQueue[%d] AllocFails",
	"%sQueue[%d] SkbAllocFails",
	"%sQueue[%d] Polls",
};

static const char * const aq_ethtool_queue_tx_stat_names[] = {
	"%sQueue[%d] OutPackets",
	"%sQueue[%d] Restarts",
};

#if IS_ENABLED(CONFIG_MACSEC)
@@ -164,11 +170,17 @@ static const char aq_ethtool_priv_flag_names[][ETH_GSTRING_LEN] = {

static u32 aq_ethtool_n_stats(struct net_device *ndev)
{
	const int rx_stat_cnt = ARRAY_SIZE(aq_ethtool_queue_rx_stat_names);
	const int tx_stat_cnt = ARRAY_SIZE(aq_ethtool_queue_tx_stat_names);
	struct aq_nic_s *nic = netdev_priv(ndev);
	struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(nic);
	u32 n_stats = ARRAY_SIZE(aq_ethtool_stat_names) +
		      ARRAY_SIZE(aq_ethtool_queue_stat_names) * cfg->vecs *
			cfg->tcs;
		      (rx_stat_cnt + tx_stat_cnt) * cfg->vecs * cfg->tcs;

#if IS_REACHABLE(CONFIG_PTP_1588_CLOCK)
	n_stats += rx_stat_cnt * aq_ptp_get_ring_cnt(nic, ATL_RING_RX) +
		   tx_stat_cnt * aq_ptp_get_ring_cnt(nic, ATL_RING_TX);
#endif

#if IS_ENABLED(CONFIG_MACSEC)
	if (nic->macsec_cfg) {
@@ -192,6 +204,9 @@ static void aq_ethtool_stats(struct net_device *ndev,

	memset(data, 0, aq_ethtool_n_stats(ndev) * sizeof(u64));
	data = aq_nic_get_stats(aq_nic, data);
#if IS_REACHABLE(CONFIG_PTP_1588_CLOCK)
	data = aq_ptp_get_stats(aq_nic, data);
#endif
#if IS_ENABLED(CONFIG_MACSEC)
	data = aq_macsec_get_stats(aq_nic, data);
#endif
@@ -237,7 +252,8 @@ static void aq_ethtool_get_strings(struct net_device *ndev,

	switch (stringset) {
	case ETH_SS_STATS: {
		const int stat_cnt = ARRAY_SIZE(aq_ethtool_queue_stat_names);
		const int rx_stat_cnt = ARRAY_SIZE(aq_ethtool_queue_rx_stat_names);
		const int tx_stat_cnt = ARRAY_SIZE(aq_ethtool_queue_tx_stat_names);
		char tc_string[8];
		int tc;

@@ -251,15 +267,51 @@ static void aq_ethtool_get_strings(struct net_device *ndev,
				snprintf(tc_string, 8, "TC%d ", tc);

			for (i = 0; i < cfg->vecs; i++) {
				for (si = 0; si < stat_cnt; si++) {
				for (si = 0; si < rx_stat_cnt; si++) {
					snprintf(p, ETH_GSTRING_LEN,
					     aq_ethtool_queue_rx_stat_names[si],
					     tc_string,
					     AQ_NIC_CFG_TCVEC2RING(cfg, tc, i));
					p += ETH_GSTRING_LEN;
				}
				for (si = 0; si < tx_stat_cnt; si++) {
					snprintf(p, ETH_GSTRING_LEN,
					     aq_ethtool_queue_stat_names[si],
					     aq_ethtool_queue_tx_stat_names[si],
					     tc_string,
					     AQ_NIC_CFG_TCVEC2RING(cfg, tc, i));
					p += ETH_GSTRING_LEN;
				}
			}
		}
#if IS_REACHABLE(CONFIG_PTP_1588_CLOCK)
		if (nic->aq_ptp) {
			const int rx_ring_cnt = aq_ptp_get_ring_cnt(nic, ATL_RING_RX);
			const int tx_ring_cnt = aq_ptp_get_ring_cnt(nic, ATL_RING_TX);
			unsigned int ptp_ring_idx =
				aq_ptp_ring_idx(nic->aq_nic_cfg.tc_mode);

			snprintf(tc_string, 8, "PTP ");

			for (i = 0; i < max(rx_ring_cnt, tx_ring_cnt); i++) {
				for (si = 0; si < rx_stat_cnt; si++) {
					snprintf(p, ETH_GSTRING_LEN,
						 aq_ethtool_queue_rx_stat_names[si],
						 tc_string,
						 i ? PTP_HWST_RING_IDX : ptp_ring_idx);
					p += ETH_GSTRING_LEN;
				}
				if (i >= tx_ring_cnt)
					continue;
				for (si = 0; si < tx_stat_cnt; si++) {
					snprintf(p, ETH_GSTRING_LEN,
						 aq_ethtool_queue_tx_stat_names[si],
						 tc_string,
						 i ? PTP_HWST_RING_IDX : ptp_ring_idx);
					p += ETH_GSTRING_LEN;
				}
			}
		}
#endif
#if IS_ENABLED(CONFIG_MACSEC)
		if (!nic->macsec_cfg)
			break;
+7 −0
Original line number Diff line number Diff line
@@ -36,6 +36,8 @@ enum aq_tc_mode {
			(AQ_RX_LAST_LOC_FVLANID - AQ_RX_FIRST_LOC_FVLANID + 1U)
#define AQ_RX_QUEUE_NOT_ASSIGNED   0xFFU

#define AQ_FRAC_PER_NS 0x100000000LL

/* Used for rate to Mbps conversion */
#define AQ_MBPS_DIVISOR         125000 /* 1000000 / 8 */

@@ -65,6 +67,7 @@ struct aq_hw_caps_s {
	u8 rx_rings;
	bool flow_control;
	bool is_64_dma;
	bool op64bit;
	u32 priv_data_len;
};

@@ -330,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 {
@@ -352,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);
+26 −8
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/*
 * aQuantia Corporation Network Driver
 * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved
/* Atlantic Network Driver
 *
 * Copyright (C) 2014-2019 aQuantia Corporation
 * Copyright (C) 2019-2020 Marvell International Ltd.
 */

/* File aq_hw_utils.c: Definitions of helper functions used across
@@ -9,6 +10,9 @@
 */

#include "aq_hw_utils.h"

#include <linux/io-64-nonatomic-lo-hi.h>

#include "aq_hw.h"
#include "aq_nic.h"

@@ -37,9 +41,8 @@ u32 aq_hw_read_reg(struct aq_hw_s *hw, u32 reg)
{
	u32 value = readl(hw->mmio + reg);

	if ((~0U) == value &&
	    (~0U) == readl(hw->mmio +
			   hw->aq_nic_cfg->aq_hw_caps->hw_alive_check_addr))
	if (value == U32_MAX &&
	    readl(hw->mmio + hw->aq_nic_cfg->aq_hw_caps->hw_alive_check_addr) == U32_MAX)
		aq_utils_obj_set(&hw->flags, AQ_HW_FLAG_ERR_UNPLUG);

	return value;
@@ -56,13 +59,28 @@ void aq_hw_write_reg(struct aq_hw_s *hw, u32 reg, u32 value)
 */
u64 aq_hw_read_reg64(struct aq_hw_s *hw, u32 reg)
{
	u64 value = aq_hw_read_reg(hw, reg);
	u64 value = U64_MAX;

	value |= (u64)aq_hw_read_reg(hw, reg + 4) << 32;
	if (hw->aq_nic_cfg->aq_hw_caps->op64bit)
		value = readq(hw->mmio + reg);
	else
		value = lo_hi_readq(hw->mmio + reg);

	if (value == U64_MAX &&
	    readl(hw->mmio + hw->aq_nic_cfg->aq_hw_caps->hw_alive_check_addr) == U32_MAX)
		aq_utils_obj_set(&hw->flags, AQ_HW_FLAG_ERR_UNPLUG);

	return value;
}

void aq_hw_write_reg64(struct aq_hw_s *hw, u32 reg, u64 value)
{
	if (hw->aq_nic_cfg->aq_hw_caps->op64bit)
		writeq(value, hw->mmio + reg);
	else
		lo_hi_writeq(value, hw->mmio + reg);
}

int aq_hw_err_from_flags(struct aq_hw_s *hw)
{
	int err = 0;
Loading