Skip to content

Commit

Permalink
Merge branch 'net-atlantic-various-features'
Browse files Browse the repository at this point in the history
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: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Jul 21, 2020
2 parents 5c5b758 + 8dcf2ad commit 4f1b4da
Show file tree
Hide file tree
Showing 22 changed files with 608 additions and 183 deletions.
62 changes: 45 additions & 17 deletions drivers/net/ethernet/aquantia/atlantic/aq_drvinfo.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
// 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.*/

Expand All @@ -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;

if (!aq_nic->aq_fw_ops->get_phy_temp)
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,
Expand All @@ -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;
}
return 0;
}

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:
Expand All @@ -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,
};
Expand Down
10 changes: 6 additions & 4 deletions drivers/net/ethernet/aquantia/atlantic/aq_drvinfo.h
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
/* 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);

Expand Down
68 changes: 60 additions & 8 deletions drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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) {
Expand All @@ -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
Expand Down Expand Up @@ -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;

Expand All @@ -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_stat_names[si],
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_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;
Expand Down
7 changes: 7 additions & 0 deletions drivers/net/ethernet/aquantia/atlantic/aq_hw.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */

Expand Down Expand Up @@ -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;
};

Expand Down Expand Up @@ -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 {
Expand All @@ -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);
Expand Down
34 changes: 26 additions & 8 deletions drivers/net/ethernet/aquantia/atlantic/aq_hw_utils.c
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
// 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
* hardware layer.
*/

#include "aq_hw_utils.h"

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

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

Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down
8 changes: 5 additions & 3 deletions drivers/net/ethernet/aquantia/atlantic/aq_hw_utils.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
/* 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.h: Declaration of helper functions used across hardware
Expand Down Expand Up @@ -33,6 +34,7 @@ u32 aq_hw_read_reg_bit(struct aq_hw_s *aq_hw, u32 addr, u32 msk, u32 shift);
u32 aq_hw_read_reg(struct aq_hw_s *hw, u32 reg);
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);
void aq_hw_write_reg64(struct aq_hw_s *hw, u32 reg, u64 value);
int aq_hw_err_from_flags(struct aq_hw_s *hw);
int aq_hw_num_tcs(struct aq_hw_s *hw);
int aq_hw_q_per_tc(struct aq_hw_s *hw);
Expand Down
Loading

0 comments on commit 4f1b4da

Please sign in to comment.