Merge branch 'aquantia-fixes'

Igor Russkikh says:

====================
net: aquantia: Atlantic driver 10/2017 updates

This patchset fixes various issues in driver,
improves parameters for better performance on 10Gbit link
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2017-10-21 12:32:25 +01:00
commit 43ebf97fa4
12 changed files with 282 additions and 144 deletions

View File

@ -22,8 +22,12 @@
#define AQ_CFG_FORCE_LEGACY_INT 0U
#define AQ_CFG_IS_INTERRUPT_MODERATION_DEF 1U
#define AQ_CFG_INTERRUPT_MODERATION_RATE_DEF 0xFFFFU
#define AQ_CFG_INTERRUPT_MODERATION_OFF 0
#define AQ_CFG_INTERRUPT_MODERATION_ON 1
#define AQ_CFG_INTERRUPT_MODERATION_AUTO 0xFFFFU
#define AQ_CFG_INTERRUPT_MODERATION_USEC_MAX (0x1FF * 2)
#define AQ_CFG_IRQ_MASK 0x1FFU
#define AQ_CFG_VECS_MAX 8U

View File

@ -56,10 +56,6 @@ aq_ethtool_set_link_ksettings(struct net_device *ndev,
return aq_nic_set_link_ksettings(aq_nic, cmd);
}
/* there "5U" is number of queue[#] stats lines (InPackets+...+InErrors) */
static const unsigned int aq_ethtool_stat_queue_lines = 5U;
static const unsigned int aq_ethtool_stat_queue_chars =
5U * ETH_GSTRING_LEN;
static const char aq_ethtool_stat_names[][ETH_GSTRING_LEN] = {
"InPackets",
"InUCast",
@ -83,56 +79,26 @@ static const char aq_ethtool_stat_names[][ETH_GSTRING_LEN] = {
"InOctetsDma",
"OutOctetsDma",
"InDroppedDma",
"Queue[0] InPackets",
"Queue[0] OutPackets",
"Queue[0] InJumboPackets",
"Queue[0] InLroPackets",
"Queue[0] InErrors",
"Queue[1] InPackets",
"Queue[1] OutPackets",
"Queue[1] InJumboPackets",
"Queue[1] InLroPackets",
"Queue[1] InErrors",
"Queue[2] InPackets",
"Queue[2] OutPackets",
"Queue[2] InJumboPackets",
"Queue[2] InLroPackets",
"Queue[2] InErrors",
"Queue[3] InPackets",
"Queue[3] OutPackets",
"Queue[3] InJumboPackets",
"Queue[3] InLroPackets",
"Queue[3] InErrors",
"Queue[4] InPackets",
"Queue[4] OutPackets",
"Queue[4] InJumboPackets",
"Queue[4] InLroPackets",
"Queue[4] InErrors",
"Queue[5] InPackets",
"Queue[5] OutPackets",
"Queue[5] InJumboPackets",
"Queue[5] InLroPackets",
"Queue[5] InErrors",
"Queue[6] InPackets",
"Queue[6] OutPackets",
"Queue[6] InJumboPackets",
"Queue[6] InLroPackets",
"Queue[6] InErrors",
"Queue[7] InPackets",
"Queue[7] OutPackets",
"Queue[7] InJumboPackets",
"Queue[7] InLroPackets",
"Queue[7] InErrors",
};
static const char aq_ethtool_queue_stat_names[][ETH_GSTRING_LEN] = {
"Queue[%d] InPackets",
"Queue[%d] OutPackets",
"Queue[%d] Restarts",
"Queue[%d] InJumboPackets",
"Queue[%d] InLroPackets",
"Queue[%d] InErrors",
};
static void aq_ethtool_stats(struct net_device *ndev,
struct ethtool_stats *stats, u64 *data)
{
struct aq_nic_s *aq_nic = netdev_priv(ndev);
struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic);
/* ASSERT: Need add lines to aq_ethtool_stat_names if AQ_CFG_VECS_MAX > 8 */
BUILD_BUG_ON(AQ_CFG_VECS_MAX > 8);
memset(data, 0, ARRAY_SIZE(aq_ethtool_stat_names) * sizeof(u64));
memset(data, 0, (ARRAY_SIZE(aq_ethtool_stat_names) +
ARRAY_SIZE(aq_ethtool_queue_stat_names) *
cfg->vecs) * sizeof(u64));
aq_nic_get_stats(aq_nic, data);
}
@ -154,8 +120,8 @@ static void aq_ethtool_get_drvinfo(struct net_device *ndev,
strlcpy(drvinfo->bus_info, pdev ? pci_name(pdev) : "",
sizeof(drvinfo->bus_info));
drvinfo->n_stats = ARRAY_SIZE(aq_ethtool_stat_names) -
(AQ_CFG_VECS_MAX - cfg->vecs) * aq_ethtool_stat_queue_lines;
drvinfo->n_stats = ARRAY_SIZE(aq_ethtool_stat_names) +
cfg->vecs * ARRAY_SIZE(aq_ethtool_queue_stat_names);
drvinfo->testinfo_len = 0;
drvinfo->regdump_len = regs_count;
drvinfo->eedump_len = 0;
@ -164,14 +130,25 @@ static void aq_ethtool_get_drvinfo(struct net_device *ndev,
static void aq_ethtool_get_strings(struct net_device *ndev,
u32 stringset, u8 *data)
{
int i, si;
struct aq_nic_s *aq_nic = netdev_priv(ndev);
struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic);
u8 *p = data;
if (stringset == ETH_SS_STATS)
memcpy(data, *aq_ethtool_stat_names,
sizeof(aq_ethtool_stat_names) -
(AQ_CFG_VECS_MAX - cfg->vecs) *
aq_ethtool_stat_queue_chars);
if (stringset == ETH_SS_STATS) {
memcpy(p, *aq_ethtool_stat_names,
sizeof(aq_ethtool_stat_names));
p = p + sizeof(aq_ethtool_stat_names);
for (i = 0; i < cfg->vecs; i++) {
for (si = 0;
si < ARRAY_SIZE(aq_ethtool_queue_stat_names);
si++) {
snprintf(p, ETH_GSTRING_LEN,
aq_ethtool_queue_stat_names[si], i);
p += ETH_GSTRING_LEN;
}
}
}
}
static int aq_ethtool_get_sset_count(struct net_device *ndev, int stringset)
@ -182,9 +159,8 @@ static int aq_ethtool_get_sset_count(struct net_device *ndev, int stringset)
switch (stringset) {
case ETH_SS_STATS:
ret = ARRAY_SIZE(aq_ethtool_stat_names) -
(AQ_CFG_VECS_MAX - cfg->vecs) *
aq_ethtool_stat_queue_lines;
ret = ARRAY_SIZE(aq_ethtool_stat_names) +
cfg->vecs * ARRAY_SIZE(aq_ethtool_queue_stat_names);
break;
default:
ret = -EOPNOTSUPP;
@ -245,6 +221,69 @@ static int aq_ethtool_get_rxnfc(struct net_device *ndev,
return err;
}
int aq_ethtool_get_coalesce(struct net_device *ndev,
struct ethtool_coalesce *coal)
{
struct aq_nic_s *aq_nic = netdev_priv(ndev);
struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic);
if (cfg->itr == AQ_CFG_INTERRUPT_MODERATION_ON ||
cfg->itr == AQ_CFG_INTERRUPT_MODERATION_AUTO) {
coal->rx_coalesce_usecs = cfg->rx_itr;
coal->tx_coalesce_usecs = cfg->tx_itr;
coal->rx_max_coalesced_frames = 0;
coal->tx_max_coalesced_frames = 0;
} else {
coal->rx_coalesce_usecs = 0;
coal->tx_coalesce_usecs = 0;
coal->rx_max_coalesced_frames = 1;
coal->tx_max_coalesced_frames = 1;
}
return 0;
}
int aq_ethtool_set_coalesce(struct net_device *ndev,
struct ethtool_coalesce *coal)
{
struct aq_nic_s *aq_nic = netdev_priv(ndev);
struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic);
/* This is not yet supported
*/
if (coal->use_adaptive_rx_coalesce || coal->use_adaptive_tx_coalesce)
return -EOPNOTSUPP;
/* Atlantic only supports timing based coalescing
*/
if (coal->rx_max_coalesced_frames > 1 ||
coal->rx_coalesce_usecs_irq ||
coal->rx_max_coalesced_frames_irq)
return -EOPNOTSUPP;
if (coal->tx_max_coalesced_frames > 1 ||
coal->tx_coalesce_usecs_irq ||
coal->tx_max_coalesced_frames_irq)
return -EOPNOTSUPP;
/* We do not support frame counting. Check this
*/
if (!(coal->rx_max_coalesced_frames == !coal->rx_coalesce_usecs))
return -EOPNOTSUPP;
if (!(coal->tx_max_coalesced_frames == !coal->tx_coalesce_usecs))
return -EOPNOTSUPP;
if (coal->rx_coalesce_usecs > AQ_CFG_INTERRUPT_MODERATION_USEC_MAX ||
coal->tx_coalesce_usecs > AQ_CFG_INTERRUPT_MODERATION_USEC_MAX)
return -EINVAL;
cfg->itr = AQ_CFG_INTERRUPT_MODERATION_ON;
cfg->rx_itr = coal->rx_coalesce_usecs;
cfg->tx_itr = coal->tx_coalesce_usecs;
return aq_nic_update_interrupt_moderation_settings(aq_nic);
}
const struct ethtool_ops aq_ethtool_ops = {
.get_link = aq_ethtool_get_link,
.get_regs_len = aq_ethtool_get_regs_len,
@ -259,4 +298,6 @@ const struct ethtool_ops aq_ethtool_ops = {
.get_ethtool_stats = aq_ethtool_stats,
.get_link_ksettings = aq_ethtool_get_link_ksettings,
.set_link_ksettings = aq_ethtool_set_link_ksettings,
.get_coalesce = aq_ethtool_get_coalesce,
.set_coalesce = aq_ethtool_set_coalesce,
};

View File

@ -151,8 +151,7 @@ struct aq_hw_ops {
[ETH_ALEN],
u32 count);
int (*hw_interrupt_moderation_set)(struct aq_hw_s *self,
bool itr_enabled);
int (*hw_interrupt_moderation_set)(struct aq_hw_s *self);
int (*hw_rss_set)(struct aq_hw_s *self,
struct aq_rss_parameters *rss_params);
@ -163,6 +162,8 @@ struct aq_hw_ops {
int (*hw_get_regs)(struct aq_hw_s *self,
struct aq_hw_caps_s *aq_hw_caps, u32 *regs_buff);
int (*hw_update_stats)(struct aq_hw_s *self);
int (*hw_get_hw_stats)(struct aq_hw_s *self, u64 *data,
unsigned int *p_count);

View File

@ -16,6 +16,7 @@
#include "aq_pci_func.h"
#include "aq_nic_internal.h"
#include <linux/moduleparam.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/timer.h>
@ -24,6 +25,18 @@
#include <linux/tcp.h>
#include <net/ip.h>
static unsigned int aq_itr = AQ_CFG_INTERRUPT_MODERATION_AUTO;
module_param_named(aq_itr, aq_itr, uint, 0644);
MODULE_PARM_DESC(aq_itr, "Interrupt throttling mode");
static unsigned int aq_itr_tx;
module_param_named(aq_itr_tx, aq_itr_tx, uint, 0644);
MODULE_PARM_DESC(aq_itr_tx, "TX interrupt throttle rate");
static unsigned int aq_itr_rx;
module_param_named(aq_itr_rx, aq_itr_rx, uint, 0644);
MODULE_PARM_DESC(aq_itr_rx, "RX interrupt throttle rate");
static void aq_nic_rss_init(struct aq_nic_s *self, unsigned int num_rss_queues)
{
struct aq_nic_cfg_s *cfg = &self->aq_nic_cfg;
@ -61,9 +74,9 @@ static void aq_nic_cfg_init_defaults(struct aq_nic_s *self)
cfg->is_polling = AQ_CFG_IS_POLLING_DEF;
cfg->is_interrupt_moderation = AQ_CFG_IS_INTERRUPT_MODERATION_DEF;
cfg->itr = cfg->is_interrupt_moderation ?
AQ_CFG_INTERRUPT_MODERATION_RATE_DEF : 0U;
cfg->itr = aq_itr;
cfg->tx_itr = aq_itr_tx;
cfg->rx_itr = aq_itr_rx;
cfg->is_rss = AQ_CFG_IS_RSS_DEF;
cfg->num_rss_queues = AQ_CFG_NUM_RSS_QUEUES_DEF;
@ -126,10 +139,12 @@ static int aq_nic_update_link_status(struct aq_nic_s *self)
if (err)
return err;
if (self->link_status.mbps != self->aq_hw->aq_link_status.mbps)
if (self->link_status.mbps != self->aq_hw->aq_link_status.mbps) {
pr_info("%s: link change old %d new %d\n",
AQ_CFG_DRV_NAME, self->link_status.mbps,
self->aq_hw->aq_link_status.mbps);
aq_nic_update_interrupt_moderation_settings(self);
}
self->link_status = self->aq_hw->aq_link_status;
if (!netif_carrier_ok(self->ndev) && self->link_status.mbps) {
@ -164,8 +179,8 @@ static void aq_nic_service_timer_cb(unsigned long param)
if (err)
goto err_exit;
self->aq_hw_ops.hw_interrupt_moderation_set(self->aq_hw,
self->aq_nic_cfg.is_interrupt_moderation);
if (self->aq_hw_ops.hw_update_stats)
self->aq_hw_ops.hw_update_stats(self->aq_hw);
memset(&stats_rx, 0U, sizeof(struct aq_ring_stats_rx_s));
memset(&stats_tx, 0U, sizeof(struct aq_ring_stats_tx_s));
@ -334,6 +349,7 @@ struct aq_nic_s *aq_nic_alloc_hot(struct net_device *ndev)
}
if (netif_running(ndev))
netif_tx_disable(ndev);
netif_carrier_off(self->ndev);
for (self->aq_vecs = 0; self->aq_vecs < self->aq_nic_cfg.vecs;
self->aq_vecs++) {
@ -421,9 +437,8 @@ int aq_nic_start(struct aq_nic_s *self)
if (err < 0)
goto err_exit;
err = self->aq_hw_ops.hw_interrupt_moderation_set(self->aq_hw,
self->aq_nic_cfg.is_interrupt_moderation);
if (err < 0)
err = aq_nic_update_interrupt_moderation_settings(self);
if (err)
goto err_exit;
setup_timer(&self->service_timer, &aq_nic_service_timer_cb,
(unsigned long)self);
@ -645,6 +660,11 @@ err_exit:
return err;
}
int aq_nic_update_interrupt_moderation_settings(struct aq_nic_s *self)
{
return self->aq_hw_ops.hw_interrupt_moderation_set(self->aq_hw);
}
int aq_nic_set_packet_filter(struct aq_nic_s *self, unsigned int flags)
{
int err = 0;
@ -899,6 +919,7 @@ int aq_nic_stop(struct aq_nic_s *self)
unsigned int i = 0U;
netif_tx_disable(self->ndev);
netif_carrier_off(self->ndev);
del_timer_sync(&self->service_timer);

View File

@ -40,6 +40,8 @@ struct aq_nic_cfg_s {
u32 vecs; /* vecs==allocated irqs */
u32 irq_type;
u32 itr;
u16 rx_itr;
u16 tx_itr;
u32 num_rss_queues;
u32 mtu;
u32 ucp_0x364;
@ -49,7 +51,6 @@ struct aq_nic_cfg_s {
u16 is_mc_list_enabled;
u16 mc_list_count;
bool is_autoneg;
bool is_interrupt_moderation;
bool is_polling;
bool is_rss;
bool is_lro;
@ -104,5 +105,6 @@ int aq_nic_set_link_ksettings(struct aq_nic_s *self,
struct aq_nic_cfg_s *aq_nic_get_cfg(struct aq_nic_s *self);
u32 aq_nic_get_fw_version(struct aq_nic_s *self);
int aq_nic_change_pm_state(struct aq_nic_s *self, pm_message_t *pm_msg);
int aq_nic_update_interrupt_moderation_settings(struct aq_nic_s *self);
#endif /* AQ_NIC_H */

View File

@ -85,6 +85,7 @@ int aq_pci_func_init(struct aq_pci_func_s *self)
int err = 0;
unsigned int bar = 0U;
unsigned int port = 0U;
unsigned int numvecs = 0U;
err = pci_enable_device(self->pdev);
if (err < 0)
@ -142,10 +143,12 @@ int aq_pci_func_init(struct aq_pci_func_s *self)
}
}
/*enable interrupts */
numvecs = min((u8)AQ_CFG_VECS_DEF, self->aq_hw_caps.msix_irqs);
numvecs = min(numvecs, num_online_cpus());
/* enable interrupts */
#if !AQ_CFG_FORCE_LEGACY_INT
err = pci_alloc_irq_vectors(self->pdev, self->aq_hw_caps.msix_irqs,
self->aq_hw_caps.msix_irqs, PCI_IRQ_MSIX);
err = pci_alloc_irq_vectors(self->pdev, numvecs, numvecs, PCI_IRQ_MSIX);
if (err < 0) {
err = pci_alloc_irq_vectors(self->pdev, 1, 1,
@ -153,7 +156,7 @@ int aq_pci_func_init(struct aq_pci_func_s *self)
if (err < 0)
goto err_exit;
}
#endif
#endif /* AQ_CFG_FORCE_LEGACY_INT */
/* net device init */
for (port = 0; port < self->ports; ++port) {
@ -265,6 +268,9 @@ void aq_pci_func_free(struct aq_pci_func_s *self)
aq_nic_ndev_free(self->port[port]);
}
if (self->mmio)
iounmap(self->mmio);
kfree(self);
err_exit:;

View File

@ -373,8 +373,11 @@ int aq_vec_get_sw_stats(struct aq_vec_s *self, u64 *data, unsigned int *p_count)
memset(&stats_tx, 0U, sizeof(struct aq_ring_stats_tx_s));
aq_vec_add_stats(self, &stats_rx, &stats_tx);
/* This data should mimic aq_ethtool_queue_stat_names structure
*/
data[count] += stats_rx.packets;
data[++count] += stats_tx.packets;
data[++count] += stats_tx.queue_restarts;
data[++count] += stats_rx.jumbo_packets;
data[++count] += stats_rx.lro_packets;
data[++count] += stats_rx.errors;

View File

@ -765,24 +765,23 @@ err_exit:
return err;
}
static int hw_atl_a0_hw_interrupt_moderation_set(struct aq_hw_s *self,
bool itr_enabled)
static int hw_atl_a0_hw_interrupt_moderation_set(struct aq_hw_s *self)
{
unsigned int i = 0U;
u32 itr_rx;
if (itr_enabled && self->aq_nic_cfg->itr) {
if (self->aq_nic_cfg->itr != 0xFFFFU) {
if (self->aq_nic_cfg->itr) {
if (self->aq_nic_cfg->itr != AQ_CFG_INTERRUPT_MODERATION_AUTO) {
u32 itr_ = (self->aq_nic_cfg->itr >> 1);
itr_ = min(AQ_CFG_IRQ_MASK, itr_);
PHAL_ATLANTIC_A0->itr_rx = 0x80000000U |
(itr_ << 0x10);
itr_rx = 0x80000000U | (itr_ << 0x10);
} else {
u32 n = 0xFFFFU & aq_hw_read_reg(self, 0x00002A00U);
if (n < self->aq_link_status.mbps) {
PHAL_ATLANTIC_A0->itr_rx = 0U;
itr_rx = 0U;
} else {
static unsigned int hw_timers_tbl_[] = {
0x01CU, /* 10Gbit */
@ -797,8 +796,7 @@ static int hw_atl_a0_hw_interrupt_moderation_set(struct aq_hw_s *self,
hw_atl_utils_mbps_2_speed_index(
self->aq_link_status.mbps);
PHAL_ATLANTIC_A0->itr_rx =
0x80000000U |
itr_rx = 0x80000000U |
(hw_timers_tbl_[speed_index] << 0x10U);
}
@ -806,11 +804,11 @@ static int hw_atl_a0_hw_interrupt_moderation_set(struct aq_hw_s *self,
aq_hw_write_reg(self, 0x00002A00U, 0x8D000000U);
}
} else {
PHAL_ATLANTIC_A0->itr_rx = 0U;
itr_rx = 0U;
}
for (i = HW_ATL_A0_RINGS_MAX; i--;)
reg_irq_thr_set(self, PHAL_ATLANTIC_A0->itr_rx, i);
reg_irq_thr_set(self, itr_rx, i);
return aq_hw_err_from_flags(self);
}
@ -885,6 +883,7 @@ static struct aq_hw_ops hw_atl_ops_ = {
.hw_rss_set = hw_atl_a0_hw_rss_set,
.hw_rss_hash_set = hw_atl_a0_hw_rss_hash_set,
.hw_get_regs = hw_atl_utils_hw_get_regs,
.hw_update_stats = hw_atl_utils_update_stats,
.hw_get_hw_stats = hw_atl_utils_get_hw_stats,
.hw_get_fw_version = hw_atl_utils_get_fw_version,
};

View File

@ -788,39 +788,45 @@ err_exit:
return err;
}
static int hw_atl_b0_hw_interrupt_moderation_set(struct aq_hw_s *self,
bool itr_enabled)
static int hw_atl_b0_hw_interrupt_moderation_set(struct aq_hw_s *self)
{
unsigned int i = 0U;
u32 itr_tx = 2U;
u32 itr_rx = 2U;
if (itr_enabled && self->aq_nic_cfg->itr) {
switch (self->aq_nic_cfg->itr) {
case AQ_CFG_INTERRUPT_MODERATION_ON:
case AQ_CFG_INTERRUPT_MODERATION_AUTO:
tdm_tx_desc_wr_wb_irq_en_set(self, 0U);
tdm_tdm_intr_moder_en_set(self, 1U);
rdm_rx_desc_wr_wb_irq_en_set(self, 0U);
rdm_rdm_intr_moder_en_set(self, 1U);
PHAL_ATLANTIC_B0->itr_tx = 2U;
PHAL_ATLANTIC_B0->itr_rx = 2U;
if (self->aq_nic_cfg->itr == AQ_CFG_INTERRUPT_MODERATION_ON) {
/* HW timers are in 2us units */
int tx_max_timer = self->aq_nic_cfg->tx_itr / 2;
int tx_min_timer = tx_max_timer / 2;
if (self->aq_nic_cfg->itr != 0xFFFFU) {
unsigned int max_timer = self->aq_nic_cfg->itr / 2U;
unsigned int min_timer = self->aq_nic_cfg->itr / 32U;
int rx_max_timer = self->aq_nic_cfg->rx_itr / 2;
int rx_min_timer = rx_max_timer / 2;
max_timer = min(0x1FFU, max_timer);
min_timer = min(0xFFU, min_timer);
tx_max_timer = min(HW_ATL_INTR_MODER_MAX, tx_max_timer);
tx_min_timer = min(HW_ATL_INTR_MODER_MIN, tx_min_timer);
rx_max_timer = min(HW_ATL_INTR_MODER_MAX, rx_max_timer);
rx_min_timer = min(HW_ATL_INTR_MODER_MIN, rx_min_timer);
PHAL_ATLANTIC_B0->itr_tx |= min_timer << 0x8U;
PHAL_ATLANTIC_B0->itr_tx |= max_timer << 0x10U;
PHAL_ATLANTIC_B0->itr_rx |= min_timer << 0x8U;
PHAL_ATLANTIC_B0->itr_rx |= max_timer << 0x10U;
itr_tx |= tx_min_timer << 0x8U;
itr_tx |= tx_max_timer << 0x10U;
itr_rx |= rx_min_timer << 0x8U;
itr_rx |= rx_max_timer << 0x10U;
} else {
static unsigned int hw_atl_b0_timers_table_tx_[][2] = {
{0xffU, 0xffU}, /* 10Gbit */
{0xffU, 0x1ffU}, /* 5Gbit */
{0xffU, 0x1ffU}, /* 5Gbit 5GS */
{0xffU, 0x1ffU}, /* 2.5Gbit */
{0xffU, 0x1ffU}, /* 1Gbit */
{0xffU, 0x1ffU}, /* 100Mbit */
{0xfU, 0xffU}, /* 10Gbit */
{0xfU, 0x1ffU}, /* 5Gbit */
{0xfU, 0x1ffU}, /* 5Gbit 5GS */
{0xfU, 0x1ffU}, /* 2.5Gbit */
{0xfU, 0x1ffU}, /* 1Gbit */
{0xfU, 0x1ffU}, /* 100Mbit */
};
static unsigned int hw_atl_b0_timers_table_rx_[][2] = {
@ -836,34 +842,36 @@ static int hw_atl_b0_hw_interrupt_moderation_set(struct aq_hw_s *self,
hw_atl_utils_mbps_2_speed_index(
self->aq_link_status.mbps);
PHAL_ATLANTIC_B0->itr_tx |=
hw_atl_b0_timers_table_tx_[speed_index]
[0] << 0x8U; /* set min timer value */
PHAL_ATLANTIC_B0->itr_tx |=
hw_atl_b0_timers_table_tx_[speed_index]
[1] << 0x10U; /* set max timer value */
/* Update user visible ITR settings */
self->aq_nic_cfg->tx_itr = hw_atl_b0_timers_table_tx_
[speed_index][1] * 2;
self->aq_nic_cfg->rx_itr = hw_atl_b0_timers_table_rx_
[speed_index][1] * 2;
PHAL_ATLANTIC_B0->itr_rx |=
hw_atl_b0_timers_table_rx_[speed_index]
[0] << 0x8U; /* set min timer value */
PHAL_ATLANTIC_B0->itr_rx |=
hw_atl_b0_timers_table_rx_[speed_index]
[1] << 0x10U; /* set max timer value */
itr_tx |= hw_atl_b0_timers_table_tx_
[speed_index][0] << 0x8U;
itr_tx |= hw_atl_b0_timers_table_tx_
[speed_index][1] << 0x10U;
itr_rx |= hw_atl_b0_timers_table_rx_
[speed_index][0] << 0x8U;
itr_rx |= hw_atl_b0_timers_table_rx_
[speed_index][1] << 0x10U;
}
} else {
break;
case AQ_CFG_INTERRUPT_MODERATION_OFF:
tdm_tx_desc_wr_wb_irq_en_set(self, 1U);
tdm_tdm_intr_moder_en_set(self, 0U);
rdm_rx_desc_wr_wb_irq_en_set(self, 1U);
rdm_rdm_intr_moder_en_set(self, 0U);
PHAL_ATLANTIC_B0->itr_tx = 0U;
PHAL_ATLANTIC_B0->itr_rx = 0U;
itr_tx = 0U;
itr_rx = 0U;
break;
}
for (i = HW_ATL_B0_RINGS_MAX; i--;) {
reg_tx_intr_moder_ctrl_set(self,
PHAL_ATLANTIC_B0->itr_tx, i);
reg_rx_intr_moder_ctrl_set(self,
PHAL_ATLANTIC_B0->itr_rx, i);
reg_tx_intr_moder_ctrl_set(self, itr_tx, i);
reg_rx_intr_moder_ctrl_set(self, itr_rx, i);
}
return aq_hw_err_from_flags(self);
@ -939,6 +947,7 @@ static struct aq_hw_ops hw_atl_ops_ = {
.hw_rss_set = hw_atl_b0_hw_rss_set,
.hw_rss_hash_set = hw_atl_b0_hw_rss_hash_set,
.hw_get_regs = hw_atl_utils_hw_get_regs,
.hw_update_stats = hw_atl_utils_update_stats,
.hw_get_hw_stats = hw_atl_utils_get_hw_stats,
.hw_get_fw_version = hw_atl_utils_get_fw_version,
};

View File

@ -139,6 +139,9 @@
#define HW_ATL_B0_FW_VER_EXPECTED 0x01050006U
#define HW_ATL_INTR_MODER_MAX 0x1FF
#define HW_ATL_INTR_MODER_MIN 0xFF
/* Hardware tx descriptor */
struct __packed hw_atl_txd_s {
u64 buf_addr;

View File

@ -255,6 +255,15 @@ err_exit:
return err;
}
int hw_atl_utils_mpi_read_mbox(struct aq_hw_s *self,
struct hw_aq_atl_utils_mbox_header *pmbox)
{
return hw_atl_utils_fw_downld_dwords(self,
PHAL_ATLANTIC->mbox_addr,
(u32 *)(void *)pmbox,
sizeof(*pmbox) / sizeof(u32));
}
void hw_atl_utils_mpi_read_stats(struct aq_hw_s *self,
struct hw_aq_atl_utils_mbox *pmbox)
{
@ -267,9 +276,6 @@ void hw_atl_utils_mpi_read_stats(struct aq_hw_s *self,
if (err < 0)
goto err_exit;
if (pmbox != &PHAL_ATLANTIC->mbox)
memcpy(pmbox, &PHAL_ATLANTIC->mbox, sizeof(*pmbox));
if (IS_CHIP_FEATURE(REVISION_A0)) {
unsigned int mtu = self->aq_nic_cfg ?
self->aq_nic_cfg->mtu : 1514U;
@ -299,17 +305,17 @@ void hw_atl_utils_mpi_set(struct aq_hw_s *self,
{
int err = 0;
u32 transaction_id = 0;
struct hw_aq_atl_utils_mbox_header mbox;
if (state == MPI_RESET) {
hw_atl_utils_mpi_read_stats(self, &PHAL_ATLANTIC->mbox);
hw_atl_utils_mpi_read_mbox(self, &mbox);
transaction_id = PHAL_ATLANTIC->mbox.transaction_id;
transaction_id = mbox.transaction_id;
AQ_HW_WAIT_FOR(transaction_id !=
(hw_atl_utils_mpi_read_stats
(self, &PHAL_ATLANTIC->mbox),
PHAL_ATLANTIC->mbox.transaction_id),
1000U, 100U);
(hw_atl_utils_mpi_read_mbox(self, &mbox),
mbox.transaction_id),
1000U, 100U);
if (err < 0)
goto err_exit;
}
@ -492,16 +498,51 @@ int hw_atl_utils_hw_set_power(struct aq_hw_s *self,
return 0;
}
int hw_atl_utils_update_stats(struct aq_hw_s *self)
{
struct hw_atl_s *hw_self = PHAL_ATLANTIC;
struct hw_aq_atl_utils_mbox mbox;
if (!self->aq_link_status.mbps)
return 0;
hw_atl_utils_mpi_read_stats(self, &mbox);
#define AQ_SDELTA(_N_) (hw_self->curr_stats._N_ += \
mbox.stats._N_ - hw_self->last_stats._N_)
AQ_SDELTA(uprc);
AQ_SDELTA(mprc);
AQ_SDELTA(bprc);
AQ_SDELTA(erpt);
AQ_SDELTA(uptc);
AQ_SDELTA(mptc);
AQ_SDELTA(bptc);
AQ_SDELTA(erpr);
AQ_SDELTA(ubrc);
AQ_SDELTA(ubtc);
AQ_SDELTA(mbrc);
AQ_SDELTA(mbtc);
AQ_SDELTA(bbrc);
AQ_SDELTA(bbtc);
AQ_SDELTA(dpc);
#undef AQ_SDELTA
memcpy(&hw_self->last_stats, &mbox.stats, sizeof(mbox.stats));
return 0;
}
int hw_atl_utils_get_hw_stats(struct aq_hw_s *self,
u64 *data, unsigned int *p_count)
{
struct hw_atl_stats_s *stats = NULL;
struct hw_atl_s *hw_self = PHAL_ATLANTIC;
struct hw_atl_stats_s *stats = &hw_self->curr_stats;
int i = 0;
hw_atl_utils_mpi_read_stats(self, &PHAL_ATLANTIC->mbox);
stats = &PHAL_ATLANTIC->mbox.stats;
data[i] = stats->uprc + stats->mprc + stats->bprc;
data[++i] = stats->uprc;
data[++i] = stats->mprc;

View File

@ -115,19 +115,22 @@ struct __packed hw_aq_atl_utils_fw_rpc {
};
};
struct __packed hw_aq_atl_utils_mbox {
struct __packed hw_aq_atl_utils_mbox_header {
u32 version;
u32 transaction_id;
int error;
u32 error;
};
struct __packed hw_aq_atl_utils_mbox {
struct hw_aq_atl_utils_mbox_header header;
struct hw_atl_stats_s stats;
};
struct __packed hw_atl_s {
struct aq_hw_s base;
struct hw_aq_atl_utils_mbox mbox;
struct hw_atl_stats_s last_stats;
struct hw_atl_stats_s curr_stats;
u64 speed;
u32 itr_tx;
u32 itr_rx;
unsigned int chip_features;
u32 fw_ver_actual;
atomic_t dpc;
@ -170,6 +173,9 @@ enum hal_atl_utils_fw_state_e {
void hw_atl_utils_hw_chip_features_init(struct aq_hw_s *self, u32 *p);
int hw_atl_utils_mpi_read_mbox(struct aq_hw_s *self,
struct hw_aq_atl_utils_mbox_header *pmbox);
void hw_atl_utils_mpi_read_stats(struct aq_hw_s *self,
struct hw_aq_atl_utils_mbox *pmbox);
@ -199,6 +205,8 @@ int hw_atl_utils_hw_deinit(struct aq_hw_s *self);
int hw_atl_utils_get_fw_version(struct aq_hw_s *self, u32 *fw_version);
int hw_atl_utils_update_stats(struct aq_hw_s *self);
int hw_atl_utils_get_hw_stats(struct aq_hw_s *self,
u64 *data,
unsigned int *p_count);