Commit 5be90f99 authored by David S. Miller's avatar David S. Miller

Merge branch 'aquantia-next'

Igor Russkikh says:

====================
net: atlantic: Aquantia driver updates 2019-04

This patchset contains various improvements:

- Work targeting link up speedups: link interrupt introduced, some other
  logic changes to imrove this.
- FW operations securing with mutex
- Counters and statistics logic improved by Dmitry
- read out of chip temperature via hwmon interface implemented by
  Yana and Nikita.

v4 changes:
- remove drvinfo_exit noop
- 64bit stats should be readed out sequentially (lsw, then msw)
  declare 64bit read ops for that

v3 changes:
- temp ops renamed to phy_temp ops
- mutex commits squashed for better structure

v2 changes:
- use threaded irq for link state handling
- rework hwmon via devm_hwmon_device_register_with_info
Extra comments on review from Andrew:
- direct device name pointer is used in hwmon registration.
  This causes hwmon device to derive possible interface name changes
- Will consider sanity checks for firmware mutex lock separately.
  Right now there is no single point exsists where such check could
  be easily added.
- There is no way now to fetch and configure min/max/crit temperatures
  via FW. Will investigate this separately.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 2b5bc3c8 9eec0303
...@@ -36,6 +36,7 @@ atlantic-objs := aq_main.o \ ...@@ -36,6 +36,7 @@ atlantic-objs := aq_main.o \
aq_ring.o \ aq_ring.o \
aq_hw_utils.o \ aq_hw_utils.o \
aq_ethtool.o \ aq_ethtool.o \
aq_drvinfo.o \
aq_filters.o \ aq_filters.o \
hw_atl/hw_atl_a0.o \ hw_atl/hw_atl_a0.o \
hw_atl/hw_atl_b0.o \ hw_atl/hw_atl_b0.o \
......
...@@ -41,9 +41,6 @@ ...@@ -41,9 +41,6 @@
#define AQ_DEVICE_ID_AQC111S 0x91B1 #define AQ_DEVICE_ID_AQC111S 0x91B1
#define AQ_DEVICE_ID_AQC112S 0x92B1 #define AQ_DEVICE_ID_AQC112S 0x92B1
#define AQ_DEVICE_ID_AQC111E 0x51B1
#define AQ_DEVICE_ID_AQC112E 0x52B1
#define HW_ATL_NIC_NAME "aQuantia AQtion 10Gbit Network Adapter" #define HW_ATL_NIC_NAME "aQuantia AQtion 10Gbit Network Adapter"
#define AQ_HWREV_ANY 0 #define AQ_HWREV_ANY 0
......
// SPDX-License-Identifier: GPL-2.0-or-later
/* Copyright (C) 2014-2019 aQuantia Corporation. */
/* File aq_drvinfo.c: Definition of common code for firmware info in sys.*/
#include <linux/init.h>
#include <linux/kobject.h>
#include <linux/module.h>
#include <linux/stat.h>
#include <linux/string.h>
#include <linux/hwmon.h>
#include <linux/uaccess.h>
#include "aq_drvinfo.h"
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 temp;
int err;
if (!aq_nic)
return -EIO;
if (type != hwmon_temp)
return -EOPNOTSUPP;
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;
default:
return -EOPNOTSUPP;
}
}
static int aq_hwmon_read_string(struct device *dev,
enum hwmon_sensor_types type,
u32 attr, int channel, const char **str)
{
struct aq_nic_s *aq_nic = dev_get_drvdata(dev);
if (!aq_nic)
return -EIO;
if (type != hwmon_temp)
return -EOPNOTSUPP;
if (!aq_nic->aq_fw_ops->get_phy_temp)
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)
{
if (type != hwmon_temp)
return 0;
switch (attr) {
case hwmon_temp_input:
case hwmon_temp_label:
return 0444;
default:
return 0;
}
}
static const struct hwmon_ops aq_hwmon_ops = {
.is_visible = aq_hwmon_is_visible,
.read = aq_hwmon_read,
.read_string = aq_hwmon_read_string,
};
static u32 aq_hwmon_temp_config[] = {
HWMON_T_INPUT | HWMON_T_LABEL,
0,
};
static const struct hwmon_channel_info aq_hwmon_temp = {
.type = hwmon_temp,
.config = aq_hwmon_temp_config,
};
static const struct hwmon_channel_info *aq_hwmon_info[] = {
&aq_hwmon_temp,
NULL,
};
static const struct hwmon_chip_info aq_hwmon_chip_info = {
.ops = &aq_hwmon_ops,
.info = aq_hwmon_info,
};
int aq_drvinfo_init(struct net_device *ndev)
{
struct aq_nic_s *aq_nic = netdev_priv(ndev);
struct device *dev = &aq_nic->pdev->dev;
struct device *hwmon_dev;
int err = 0;
hwmon_dev = devm_hwmon_device_register_with_info(dev,
ndev->name,
aq_nic,
&aq_hwmon_chip_info,
NULL);
if (IS_ERR(hwmon_dev))
err = PTR_ERR(hwmon_dev);
return err;
}
/* SPDX-License-Identifier: GPL-2.0-or-later */
/* Copyright (C) 2014-2017 aQuantia Corporation. */
/* 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"
int aq_drvinfo_init(struct net_device *ndev);
#endif /* AQ_DRVINFO_H */
...@@ -405,8 +405,10 @@ static int aq_ethtool_get_eee(struct net_device *ndev, struct ethtool_eee *eee) ...@@ -405,8 +405,10 @@ static int aq_ethtool_get_eee(struct net_device *ndev, struct ethtool_eee *eee)
if (!aq_nic->aq_fw_ops->get_eee_rate) if (!aq_nic->aq_fw_ops->get_eee_rate)
return -EOPNOTSUPP; return -EOPNOTSUPP;
mutex_lock(&aq_nic->fwreq_mutex);
err = aq_nic->aq_fw_ops->get_eee_rate(aq_nic->aq_hw, &rate, err = aq_nic->aq_fw_ops->get_eee_rate(aq_nic->aq_hw, &rate,
&supported_rates); &supported_rates);
mutex_unlock(&aq_nic->fwreq_mutex);
if (err < 0) if (err < 0)
return err; return err;
...@@ -439,8 +441,10 @@ static int aq_ethtool_set_eee(struct net_device *ndev, struct ethtool_eee *eee) ...@@ -439,8 +441,10 @@ static int aq_ethtool_set_eee(struct net_device *ndev, struct ethtool_eee *eee)
!aq_nic->aq_fw_ops->set_eee_rate)) !aq_nic->aq_fw_ops->set_eee_rate))
return -EOPNOTSUPP; return -EOPNOTSUPP;
mutex_lock(&aq_nic->fwreq_mutex);
err = aq_nic->aq_fw_ops->get_eee_rate(aq_nic->aq_hw, &rate, err = aq_nic->aq_fw_ops->get_eee_rate(aq_nic->aq_hw, &rate,
&supported_rates); &supported_rates);
mutex_unlock(&aq_nic->fwreq_mutex);
if (err < 0) if (err < 0)
return err; return err;
...@@ -452,20 +456,28 @@ static int aq_ethtool_set_eee(struct net_device *ndev, struct ethtool_eee *eee) ...@@ -452,20 +456,28 @@ static int aq_ethtool_set_eee(struct net_device *ndev, struct ethtool_eee *eee)
cfg->eee_speeds = 0; cfg->eee_speeds = 0;
} }
return aq_nic->aq_fw_ops->set_eee_rate(aq_nic->aq_hw, rate); mutex_lock(&aq_nic->fwreq_mutex);
err = aq_nic->aq_fw_ops->set_eee_rate(aq_nic->aq_hw, rate);
mutex_unlock(&aq_nic->fwreq_mutex);
return err;
} }
static int aq_ethtool_nway_reset(struct net_device *ndev) static int aq_ethtool_nway_reset(struct net_device *ndev)
{ {
struct aq_nic_s *aq_nic = netdev_priv(ndev); struct aq_nic_s *aq_nic = netdev_priv(ndev);
int err = 0;
if (unlikely(!aq_nic->aq_fw_ops->renegotiate)) if (unlikely(!aq_nic->aq_fw_ops->renegotiate))
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (netif_running(ndev)) if (netif_running(ndev)) {
return aq_nic->aq_fw_ops->renegotiate(aq_nic->aq_hw); mutex_lock(&aq_nic->fwreq_mutex);
err = aq_nic->aq_fw_ops->renegotiate(aq_nic->aq_hw);
mutex_unlock(&aq_nic->fwreq_mutex);
}
return 0; return err;
} }
static void aq_ethtool_get_pauseparam(struct net_device *ndev, static void aq_ethtool_get_pauseparam(struct net_device *ndev,
...@@ -503,7 +515,9 @@ static int aq_ethtool_set_pauseparam(struct net_device *ndev, ...@@ -503,7 +515,9 @@ static int aq_ethtool_set_pauseparam(struct net_device *ndev,
else else
aq_nic->aq_hw->aq_nic_cfg->flow_control &= ~AQ_NIC_FC_TX; aq_nic->aq_hw->aq_nic_cfg->flow_control &= ~AQ_NIC_FC_TX;
mutex_lock(&aq_nic->fwreq_mutex);
err = aq_nic->aq_fw_ops->set_flow_control(aq_nic->aq_hw); err = aq_nic->aq_fw_ops->set_flow_control(aq_nic->aq_hw);
mutex_unlock(&aq_nic->fwreq_mutex);
return err; return err;
} }
......
...@@ -88,6 +88,8 @@ struct aq_stats_s { ...@@ -88,6 +88,8 @@ struct aq_stats_s {
#define AQ_HW_IRQ_MSI 2U #define AQ_HW_IRQ_MSI 2U
#define AQ_HW_IRQ_MSIX 3U #define AQ_HW_IRQ_MSIX 3U
#define AQ_HW_SERVICE_IRQS 1U
#define AQ_HW_POWER_STATE_D0 0U #define AQ_HW_POWER_STATE_D0 0U
#define AQ_HW_POWER_STATE_D3 3U #define AQ_HW_POWER_STATE_D3 3U
...@@ -259,6 +261,8 @@ struct aq_fw_ops { ...@@ -259,6 +261,8 @@ struct aq_fw_ops {
int (*update_stats)(struct aq_hw_s *self); int (*update_stats)(struct aq_hw_s *self);
int (*get_phy_temp)(struct aq_hw_s *self, int *temp);
u32 (*get_flow_control)(struct aq_hw_s *self, u32 *fcmode); u32 (*get_flow_control)(struct aq_hw_s *self, u32 *fcmode);
int (*set_flow_control)(struct aq_hw_s *self); int (*set_flow_control)(struct aq_hw_s *self);
......
...@@ -53,6 +53,18 @@ void aq_hw_write_reg(struct aq_hw_s *hw, u32 reg, u32 value) ...@@ -53,6 +53,18 @@ void aq_hw_write_reg(struct aq_hw_s *hw, u32 reg, u32 value)
writel(value, hw->mmio + reg); writel(value, hw->mmio + reg);
} }
/* Most of 64-bit registers are in LSW, MSW form.
Counters are normally implemented by HW as latched pairs:
reading LSW first locks MSW, to overcome LSW overflow
*/
u64 aq_hw_read_reg64(struct aq_hw_s *hw, u32 reg)
{
u64 value = aq_hw_read_reg(hw, reg);
value |= (u64)aq_hw_read_reg(hw, reg + 4) << 32;
return value;
}
int aq_hw_err_from_flags(struct aq_hw_s *hw) int aq_hw_err_from_flags(struct aq_hw_s *hw)
{ {
int err = 0; int err = 0;
......
...@@ -35,6 +35,7 @@ void aq_hw_write_reg_bit(struct aq_hw_s *aq_hw, u32 addr, u32 msk, ...@@ -35,6 +35,7 @@ void aq_hw_write_reg_bit(struct aq_hw_s *aq_hw, u32 addr, u32 msk,
u32 aq_hw_read_reg_bit(struct aq_hw_s *aq_hw, u32 addr, u32 msk, u32 shift); 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); 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); 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);
int aq_hw_err_from_flags(struct aq_hw_s *hw); int aq_hw_err_from_flags(struct aq_hw_s *hw);
#endif /* AQ_HW_UTILS_H */ #endif /* AQ_HW_UTILS_H */
...@@ -23,8 +23,17 @@ MODULE_VERSION(AQ_CFG_DRV_VERSION); ...@@ -23,8 +23,17 @@ MODULE_VERSION(AQ_CFG_DRV_VERSION);
MODULE_AUTHOR(AQ_CFG_DRV_AUTHOR); MODULE_AUTHOR(AQ_CFG_DRV_AUTHOR);
MODULE_DESCRIPTION(AQ_CFG_DRV_DESC); MODULE_DESCRIPTION(AQ_CFG_DRV_DESC);
const char aq_ndev_driver_name[] = AQ_CFG_DRV_NAME;
static const struct net_device_ops aq_ndev_ops; static const struct net_device_ops aq_ndev_ops;
static struct workqueue_struct *aq_ndev_wq;
void aq_ndev_schedule_work(struct work_struct *work)
{
queue_work(aq_ndev_wq, work);
}
struct net_device *aq_ndev_alloc(void) struct net_device *aq_ndev_alloc(void)
{ {
struct net_device *ndev = NULL; struct net_device *ndev = NULL;
...@@ -209,3 +218,35 @@ static const struct net_device_ops aq_ndev_ops = { ...@@ -209,3 +218,35 @@ static const struct net_device_ops aq_ndev_ops = {
.ndo_vlan_rx_add_vid = aq_ndo_vlan_rx_add_vid, .ndo_vlan_rx_add_vid = aq_ndo_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = aq_ndo_vlan_rx_kill_vid, .ndo_vlan_rx_kill_vid = aq_ndo_vlan_rx_kill_vid,
}; };
static int __init aq_ndev_init_module(void)
{
int ret;
aq_ndev_wq = create_singlethread_workqueue(aq_ndev_driver_name);
if (!aq_ndev_wq) {
pr_err("Failed to create workqueue\n");
return -ENOMEM;
}
ret = aq_pci_func_register_driver();
if (ret) {
destroy_workqueue(aq_ndev_wq);
return ret;
}
return 0;
}
static void __exit aq_ndev_exit_module(void)
{
aq_pci_func_unregister_driver();
if (aq_ndev_wq) {
destroy_workqueue(aq_ndev_wq);
aq_ndev_wq = NULL;
}
}
module_init(aq_ndev_init_module);
module_exit(aq_ndev_exit_module);
...@@ -13,7 +13,9 @@ ...@@ -13,7 +13,9 @@
#define AQ_MAIN_H #define AQ_MAIN_H
#include "aq_common.h" #include "aq_common.h"
#include "aq_nic.h"
void aq_ndev_schedule_work(struct work_struct *work);
struct net_device *aq_ndev_alloc(void); struct net_device *aq_ndev_alloc(void);
#endif /* AQ_MAIN_H */ #endif /* AQ_MAIN_H */
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "aq_vec.h" #include "aq_vec.h"
#include "aq_hw.h" #include "aq_hw.h"
#include "aq_pci_func.h" #include "aq_pci_func.h"
#include "aq_main.h"
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
...@@ -92,7 +93,8 @@ void aq_nic_cfg_start(struct aq_nic_s *self) ...@@ -92,7 +93,8 @@ void aq_nic_cfg_start(struct aq_nic_s *self)
/*rss rings */ /*rss rings */
cfg->vecs = min(cfg->aq_hw_caps->vecs, AQ_CFG_VECS_DEF); cfg->vecs = min(cfg->aq_hw_caps->vecs, AQ_CFG_VECS_DEF);
cfg->vecs = min(cfg->vecs, num_online_cpus()); cfg->vecs = min(cfg->vecs, num_online_cpus());
cfg->vecs = min(cfg->vecs, self->irqvecs); if (self->irqvecs > AQ_HW_SERVICE_IRQS)
cfg->vecs = min(cfg->vecs, self->irqvecs - AQ_HW_SERVICE_IRQS);
/* cfg->vecs should be power of 2 for RSS */ /* cfg->vecs should be power of 2 for RSS */
if (cfg->vecs >= 8U) if (cfg->vecs >= 8U)
cfg->vecs = 8U; cfg->vecs = 8U;
...@@ -116,6 +118,15 @@ void aq_nic_cfg_start(struct aq_nic_s *self) ...@@ -116,6 +118,15 @@ void aq_nic_cfg_start(struct aq_nic_s *self)
cfg->vecs = 1U; cfg->vecs = 1U;
} }
/* Check if we have enough vectors allocated for
* link status IRQ. If no - we'll know link state from
* slower service task.
*/
if (AQ_HW_SERVICE_IRQS > 0 && cfg->vecs + 1 <= self->irqvecs)
cfg->link_irq_vec = cfg->vecs;
else
cfg->link_irq_vec = 0;
cfg->link_speed_msk &= cfg->aq_hw_caps->link_speed_msk; cfg->link_speed_msk &= cfg->aq_hw_caps->link_speed_msk;
cfg->features = cfg->aq_hw_caps->hw_features; cfg->features = cfg->aq_hw_caps->hw_features;
} }
...@@ -161,30 +172,48 @@ static int aq_nic_update_link_status(struct aq_nic_s *self) ...@@ -161,30 +172,48 @@ static int aq_nic_update_link_status(struct aq_nic_s *self)
return 0; return 0;
} }
static void aq_nic_service_timer_cb(struct timer_list *t) static irqreturn_t aq_linkstate_threaded_isr(int irq, void *private)
{ {
struct aq_nic_s *self = from_timer(self, t, service_timer); struct aq_nic_s *self = private;
int ctimer = AQ_CFG_SERVICE_TIMER_INTERVAL;
int err = 0; if (!self)
return IRQ_NONE;
aq_nic_update_link_status(self);
self->aq_hw_ops->hw_irq_enable(self->aq_hw,
BIT(self->aq_nic_cfg.link_irq_vec));
return IRQ_HANDLED;
}
static void aq_nic_service_task(struct work_struct *work)
{
struct aq_nic_s *self = container_of(work, struct aq_nic_s,
service_task);
int err;
if (aq_utils_obj_test(&self->flags, AQ_NIC_FLAGS_IS_NOT_READY)) if (aq_utils_obj_test(&self->flags, AQ_NIC_FLAGS_IS_NOT_READY))
goto err_exit; return;
err = aq_nic_update_link_status(self); err = aq_nic_update_link_status(self);
if (err) if (err)
goto err_exit; return;
mutex_lock(&self->fwreq_mutex);
if (self->aq_fw_ops->update_stats) if (self->aq_fw_ops->update_stats)
self->aq_fw_ops->update_stats(self->aq_hw); self->aq_fw_ops->update_stats(self->aq_hw);
mutex_unlock(&self->fwreq_mutex);
aq_nic_update_ndev_stats(self); aq_nic_update_ndev_stats(self);
}
static void aq_nic_service_timer_cb(struct timer_list *t)
{
struct aq_nic_s *self = from_timer(self, t, service_timer);
/* If no link - use faster timer rate to detect link up asap */ mod_timer(&self->service_timer, jiffies + AQ_CFG_SERVICE_TIMER_INTERVAL);
if (!netif_carrier_ok(self->ndev))
ctimer = max(ctimer / 2, 1);
err_exit: aq_ndev_schedule_work(&self->service_task);
mod_timer(&self->service_timer, jiffies + ctimer);
} }
static void aq_nic_polling_timer_cb(struct timer_list *t) static void aq_nic_polling_timer_cb(struct timer_list *t)
...@@ -214,8 +243,10 @@ int aq_nic_ndev_register(struct aq_nic_s *self) ...@@ -214,8 +243,10 @@ int aq_nic_ndev_register(struct aq_nic_s *self)
if (err) if (err)
goto err_exit; goto err_exit;
mutex_lock(&self->fwreq_mutex);
err = self->aq_fw_ops->get_mac_permanent(self->aq_hw, err = self->aq_fw_ops->get_mac_permanent(self->aq_hw,
self->ndev->dev_addr); self->ndev->dev_addr);
mutex_unlock(&self->fwreq_mutex);
if (err) if (err)
goto err_exit; goto err_exit;
...@@ -284,7 +315,9 @@ int aq_nic_init(struct aq_nic_s *self) ...@@ -284,7 +315,9 @@ int aq_nic_init(struct aq_nic_s *self)
unsigned int i = 0U; unsigned int i = 0U;
self->power_state = AQ_HW_POWER_STATE_D0; self->power_state = AQ_HW_POWER_STATE_D0;
mutex_lock(&self->fwreq_mutex);
err = self->aq_hw_ops->hw_reset(self->aq_hw); err = self->aq_hw_ops->hw_reset(self->aq_hw);
mutex_unlock(&self->fwreq_mutex);
if (err < 0) if (err < 0)
goto err_exit; goto err_exit;
...@@ -334,9 +367,11 @@ int aq_nic_start(struct aq_nic_s *self) ...@@ -334,9 +367,11 @@ int aq_nic_start(struct aq_nic_s *self)
err = aq_nic_update_interrupt_moderation_settings(self); err = aq_nic_update_interrupt_moderation_settings(self);
if (err) if (err)
goto err_exit; goto err_exit;
INIT_WORK(&self->service_task, aq_nic_service_task);
timer_setup(&self->service_timer, aq_nic_service_timer_cb, 0); timer_setup(&self->service_timer, aq_nic_service_timer_cb, 0);
mod_timer(&self->service_timer, jiffies + aq_nic_service_timer_cb(&self->service_timer);
AQ_CFG_SERVICE_TIMER_INTERVAL);
if (self->aq_nic_cfg.is_polling) { if (self->aq_nic_cfg.is_polling) {
timer_setup(&self->polling_timer, aq_nic_polling_timer_cb, 0); timer_setup(&self->polling_timer, aq_nic_polling_timer_cb, 0);
...@@ -345,13 +380,25 @@ int aq_nic_start(struct aq_nic_s *self) ...@@ -345,13 +380,25 @@ int aq_nic_start(struct aq_nic_s *self)
} else { } else {
for (i = 0U, aq_vec = self->aq_vec[0]; for (i = 0U, aq_vec = self->aq_vec[0];
self->aq_vecs > i; ++i, aq_vec = self->aq_vec[i]) { self->aq_vecs > i; ++i, aq_vec = self->aq_vec[i]) {
err = aq_pci_func_alloc_irq(self, i, err = aq_pci_func_alloc_irq(self, i, self->ndev->name,
self->ndev->name, aq_vec, aq_vec_isr, aq_vec,
aq_vec_get_affinity_mask(aq_vec)); aq_vec_get_affinity_mask(aq_vec));
if (err < 0) if (err < 0)
goto err_exit; goto err_exit;
} }
if (self->aq_nic_cfg.link_irq_vec) {
int irqvec = pci_irq_vector(self->pdev,
self->aq_nic_cfg.link_irq_vec);
err = request_threaded_irq(irqvec, NULL,
aq_linkstate_threaded_isr,
IRQF_SHARED,
self->ndev->name, self);
if (err < 0)
goto err_exit;
self->msix_entry_mask |= (1 << self->aq_nic_cfg.link_irq_vec);
}
err = self->aq_hw_ops->hw_irq_enable(self->aq_hw, err = self->aq_hw_ops->hw_irq_enable(self->aq_hw,
AQ_CFG_IRQ_MASK); AQ_CFG_IRQ_MASK);
if (err < 0) if (err < 0)
...@@ -653,7 +700,14 @@ void aq_nic_get_stats(struct aq_nic_s *self, u64 *data) ...@@ -653,7 +700,14 @@ void aq_nic_get_stats(struct aq_nic_s *self, u64 *data)
unsigned int i = 0U; unsigned int i = 0U;
unsigned int count = 0U; unsigned int count = 0U;
struct aq_vec_s *aq_vec = NULL; struct aq_vec_s *aq_vec = NULL;
struct aq_stats_s *stats = self->aq_hw_ops->hw_get_hw_stats(self->aq_hw); struct aq_stats_s *stats;
if (self->aq_fw_ops->update_stats) {
mutex_lock(&self->fwreq_mutex);
self->aq_fw_ops->update_stats(self->aq_hw);
mutex_unlock(&self->fwreq_mutex);
}
stats = self->aq_hw_ops->hw_get_hw_stats(self->aq_hw);
if (!stats) if (!stats)
goto err_exit; goto err_exit;
...@@ -699,11 +753,12 @@ static void aq_nic_update_ndev_stats(struct aq_nic_s *self) ...@@ -699,11 +753,12 @@ static void aq_nic_update_ndev_stats(struct aq_nic_s *self)
struct net_device *ndev = self->ndev; struct net_device *ndev = self->ndev;
struct aq_stats_s *stats = self->aq_hw_ops->hw_get_hw_stats(self->aq_hw); struct aq_stats_s *stats = self->aq_hw_ops->hw_get_hw_stats(self->aq_hw);
ndev->stats.rx_packets = stats->uprc + stats->mprc + stats->bprc; ndev->stats.rx_packets = stats->dma_pkt_rc;
ndev->stats.rx_bytes = stats->ubrc + stats->mbrc + stats->bbrc; ndev->stats.rx_bytes = stats->dma_oct_rc;
ndev->stats.rx_errors = stats->erpr; ndev->stats.rx_errors = stats->erpr;
ndev->stats.tx_packets = stats->uptc + stats->mptc + stats->bptc; ndev->stats.rx_dropped = stats->dpc;
ndev->stats.tx_bytes = stats->ubtc + stats->mbtc + stats->bbtc; ndev->stats.tx_packets = stats->dma_pkt_tc;
ndev->stats.tx_bytes = stats->dma_oct_tc;
ndev->stats.tx_errors = stats->erpt; ndev->stats.tx_errors = stats->erpt;
ndev->stats.multicast = stats->mprc; ndev->stats.multicast = stats->mprc;
} }
...@@ -840,7 +895,9 @@ int aq_nic_set_link_ksettings(struct aq_nic_s *self, ...@@ -840,7 +895,9 @@ int aq_nic_set_link_ksettings(struct aq_nic_s *self,
self->aq_nic_cfg.is_autoneg = false; self->aq_nic_cfg.is_autoneg = false;
} }
mutex_lock(&self->fwreq_mutex);
err = self->aq_fw_ops->set_link_speed(self->aq_hw, rate); err = self->aq_fw_ops->set_link_speed(self->aq_hw, rate);
mutex_unlock(&self->fwreq_mutex);
if (err < 0) if (err < 0)
goto err_exit; goto err_exit;
...@@ -873,6 +930,7 @@ int aq_nic_stop(struct aq_nic_s *self) ...@@ -873,6 +930,7 @@ int aq_nic_stop(struct aq_nic_s *self)
netif_carrier_off(self->ndev); netif_carrier_off(self->ndev);
del_timer_sync(&self->service_timer); del_timer_sync(&self->service_timer);
cancel_work_sync(&self->service_task);
self->aq_hw_ops->hw_irq_disable(self->aq_hw, AQ_CFG_IRQ_MASK); self->aq_hw_ops->hw_irq_disable(self->aq_hw, AQ_CFG_IRQ_MASK);
...@@ -900,14 +958,22 @@ void aq_nic_deinit(struct aq_nic_s *self) ...@@ -900,14 +958,22 @@ void aq_nic_deinit(struct aq_nic_s *self)
self->aq_vecs > i; ++i, aq_vec = self->aq_vec[i]) self->aq_vecs > i; ++i, aq_vec = self->aq_vec[i])
aq_vec_deinit(aq_vec); aq_vec_deinit(aq_vec);
self->aq_fw_ops->deinit(self->aq_hw); if (likely(self->aq_fw_ops->deinit)) {
mutex_lock(&self->fwreq_mutex);
self->aq_fw_ops->deinit(self->aq_hw);
mutex_unlock(&self->fwreq_mutex);
}
if (self->power_state != AQ_HW_POWER_STATE_D0 || if (self->power_state != AQ_HW_POWER_STATE_D0 ||
self->aq_hw->aq_nic_cfg->wol) { self->aq_hw->aq_nic_cfg->wol)
self->aq_fw_ops->set_power(self->aq_hw, if (likely(self->aq_fw_ops->set_power)) {
self->power_state, mutex_lock(&self->fwreq_mutex);
self->ndev->dev_addr); self->aq_fw_ops->set_power(self->aq_hw,
} self->power_state,
self->ndev->dev_addr);
mutex_unlock(&self->fwreq_mutex);
}
err_exit:; err_exit:;
} }
......
...@@ -26,7 +26,8 @@ struct aq_nic_cfg_s { ...@@ -26,7 +26,8 @@ struct aq_nic_cfg_s {
u64 features; u64 features;
u32 rxds; /* rx ring size, descriptors # */ u32 rxds; /* rx ring size, descriptors # */
u32 txds; /* tx ring size, descriptors # */ u32 txds; /* tx ring size, descriptors # */
u32 vecs; /* vecs==allocated irqs */ u32 vecs; /* allocated rx/tx vectors */
u32 link_irq_vec;
u32 irq_type; u32 irq_type;
u32 itr; u32 itr;
u16 rx_itr; u16 rx_itr;
...@@ -92,6 +93,7 @@ struct aq_nic_s { ...@@ -92,6 +93,7 @@ struct aq_nic_s {
const struct aq_fw_ops *aq_fw_ops; const struct aq_fw_ops *aq_fw_ops;
struct aq_nic_cfg_s aq_nic_cfg; struct aq_nic_cfg_s aq_nic_cfg;
struct timer_list service_timer; struct timer_list service_timer;
struct work_struct service_task;
struct timer_list polling_timer; struct timer_list polling_timer;
struct aq_hw_link_status_s link_status; struct aq_hw_link_status_s link_status;
struct { struct {
...@@ -104,6 +106,8 @@ struct aq_nic_s { ...@@ -104,6 +106,8 @@ struct aq_nic_s {
struct pci_dev *pdev; struct pci_dev *pdev;
unsigned int msix_entry_mask; unsigned int msix_entry_mask;
u32 irqvecs; u32 irqvecs;
/* mutex to serialize FW interface access operations */
struct mutex fwreq_mutex;
struct aq_hw_rx_fltrs_s aq_hw_rx_fltrs; struct aq_hw_rx_fltrs_s aq_hw_rx_fltrs;
}; };
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include "hw_atl/hw_atl_a0.h" #include "hw_atl/hw_atl_a0.h"
#include "hw_atl/hw_atl_b0.h" #include "hw_atl/hw_atl_b0.h"
#include "aq_filters.h" #include "aq_filters.h"
#include "aq_drvinfo.h"
static const struct pci_device_id aq_pci_tbl[] = { static const struct pci_device_id aq_pci_tbl[] = {
{ PCI_VDEVICE(AQUANTIA, AQ_DEVICE_ID_0001), }, { PCI_VDEVICE(AQUANTIA, AQ_DEVICE_ID_0001), },
...@@ -42,9 +43,6 @@ static const struct pci_device_id aq_pci_tbl[] = { ...@@ -42,9 +43,6 @@ static const struct pci_device_id aq_pci_tbl[] = {
{ PCI_VDEVICE(AQUANTIA, AQ_DEVICE_ID_AQC111S), }, { PCI_VDEVICE(AQUANTIA, AQ_DEVICE_ID_AQC111S), },
{ PCI_VDEVICE(AQUANTIA, AQ_DEVICE_ID_AQC112S), }, { PCI_VDEVICE(AQUANTIA, AQ_DEVICE_ID_AQC112S), },
{ PCI_VDEVICE(AQUANTIA, AQ_DEVICE_ID_AQC111E), },
{ PCI_VDEVICE(AQUANTIA, AQ_DEVICE_ID_AQC112E), },
{} {}
}; };
...@@ -74,9 +72,6 @@ static const struct aq_board_revision_s hw_atl_boards[] = { ...@@ -74,9 +72,6 @@ static const struct aq_board_revision_s hw_atl_boards[] = {
{ AQ_DEVICE_ID_AQC109S, AQ_HWREV_ANY, &hw_atl_ops_b1, &hw_atl_b0_caps_aqc109s, }, { AQ_DEVICE_ID_AQC109S, AQ_HWREV_ANY, &hw_atl_ops_b1, &hw_atl_b0_caps_aqc109s, },
{ AQ_DEVICE_ID_AQC111S, AQ_HWREV_ANY, &hw_atl_ops_b1, &hw_atl_b0_caps_aqc111s, }, { AQ_DEVICE_ID_AQC111S, AQ_HWREV_ANY, &hw_atl_ops_b1, &hw_atl_b0_caps_aqc111s, },
{ AQ_DEVICE_ID_AQC112S, AQ_HWREV_ANY, &hw_atl_ops_b1, &hw_atl_b0_caps_aqc112s, }, { AQ_DEVICE_ID_AQC112S, AQ_HWREV_ANY, &hw_atl_ops_b1, &hw_atl_b0_caps_aqc112s, },
{ AQ_DEVICE_ID_AQC111E, AQ_HWREV_ANY, &hw_atl_ops_b1, &hw_atl_b0_caps_aqc111e, },
{ AQ_DEVICE_ID_AQC112E, AQ_HWREV_ANY, &hw_atl_ops_b1, &hw_atl_b0_caps_aqc112e, },
}; };
MODULE_DEVICE_TABLE(pci, aq_pci_tbl); MODULE_DEVICE_TABLE(pci, aq_pci_tbl);
...@@ -139,26 +134,27 @@ int aq_pci_func_init(struct pci_dev *pdev) ...@@ -139,26 +134,27 @@ int aq_pci_func_init(struct pci_dev *pdev)
} }
int aq_pci_func_alloc_irq(struct aq_nic_s *self, unsigned int i, int aq_pci_func_alloc_irq(struct aq_nic_s *self, unsigned int i,
char *name, void *aq_vec, cpumask_t *affinity_mask) char *name, irq_handler_t irq_handler,
void *irq_arg, cpumask_t *affinity_mask)
{ {
struct pci_dev *pdev = self->pdev; struct pci_dev *pdev = self->pdev;
int err; int err;
if (pdev->msix_enabled || pdev->msi_enabled) if (pdev->msix_enabled || pdev->msi_enabled)
err = request_irq(pci_irq_vector(pdev, i), aq_vec_isr, 0, err = request_irq(pci_irq_vector(pdev, i), irq_handler, 0,
name, aq_vec); name, irq_arg);
else else
err = request_irq(pci_irq_vector(pdev, i), aq_vec_isr_legacy, err = request_irq(pci_irq_vector(pdev, i), aq_vec_isr_legacy,
IRQF_SHARED, name, aq_vec); IRQF_SHARED, name, irq_arg);
if (err >= 0) { if (err >= 0) {
self->msix_entry_mask |= (1 << i); self->msix_entry_mask |= (1 << i);
self->aq_vec[i] = aq_vec;
if (pdev->msix_enabled) if (pdev->msix_enabled && affinity_mask)
irq_set_affinity_hint(pci_irq_vector(pdev, i), irq_set_affinity_hint(pci_irq_vector(pdev, i),
affinity_mask); affinity_mask);
} }
return err; return err;
} }
...@@ -166,16 +162,22 @@ void aq_pci_func_free_irqs(struct aq_nic_s *self) ...@@ -166,16 +162,22 @@ void aq_pci_func_free_irqs(struct aq_nic_s *self)
{ {
struct pci_dev *pdev = self->pdev; struct pci_dev *pdev = self->pdev;
unsigned int i; unsigned int i;
void *irq_data;
for (i = 32U; i--;) { for (i = 32U; i--;) {
if (!((1U << i) & self->msix_entry_mask)) if (!((1U << i) & self->msix_entry_mask))
continue; continue;
if (i >= AQ_CFG_VECS_MAX) if (self->aq_nic_cfg.link_irq_vec &&
i == self->aq_nic_cfg.link_irq_vec)
irq_data = self;
else if (i < AQ_CFG_VECS_MAX)
irq_data = self->aq_vec[i];
else
continue; continue;
if (pdev->msix_enabled) if (pdev->msix_enabled)
irq_set_affinity_hint(pci_irq_vector(pdev, i), NULL); irq_set_affinity_hint(pci_irq_vector(pdev, i), NULL);
free_irq(pci_irq_vector(pdev, i), self->aq_vec[i]); free_irq(pci_irq_vector(pdev, i), irq_data);
self->msix_entry_mask &= ~(1U << i); self->msix_entry_mask &= ~(1U << i);
} }
} }
...@@ -185,7 +187,7 @@ unsigned int aq_pci_func_get_irq_type(struct aq_nic_s *self) ...@@ -185,7 +187,7 @@ unsigned int aq_pci_func_get_irq_type(struct aq_nic_s *self)
if (self->pdev->msix_enabled) if (self->pdev->msix_enabled)
return AQ_HW_IRQ_MSIX; return AQ_HW_IRQ_MSIX;
if (self->pdev->msi_enabled) if (self->pdev->msi_enabled)
return AQ_HW_IRQ_MSIX; return AQ_HW_IRQ_MSI;
return AQ_HW_IRQ_LEGACY; return AQ_HW_IRQ_LEGACY;
} }
...@@ -223,6 +225,8 @@ static int aq_pci_probe(struct pci_dev *pdev, ...@@ -223,6 +225,8 @@ static int aq_pci_probe(struct pci_dev *pdev,
SET_NETDEV_DEV(ndev, &pdev->dev); SET_NETDEV_DEV(ndev, &pdev->dev);
pci_set_drvdata(pdev, self); pci_set_drvdata(pdev, self);
mutex_init(&self->fwreq_mutex);
err = aq_pci_probe_get_hw_by_id(pdev, &self->aq_hw_ops, err = aq_pci_probe_get_hw_by_id(pdev, &self->aq_hw_ops,
&aq_nic_get_cfg(self)->aq_hw_caps); &aq_nic_get_cfg(self)->aq_hw_caps);
if (err) if (err)
...@@ -268,6 +272,7 @@ static int aq_pci_probe(struct pci_dev *pdev, ...@@ -268,6 +272,7 @@ static int aq_pci_probe(struct pci_dev *pdev,
numvecs = min((u8)AQ_CFG_VECS_DEF, numvecs = min((u8)AQ_CFG_VECS_DEF,
aq_nic_get_cfg(self)->aq_hw_caps->msix_irqs); aq_nic_get_cfg(self)->aq_hw_caps->msix_irqs);
numvecs = min(numvecs, num_online_cpus()); numvecs = min(numvecs, num_online_cpus());
numvecs += AQ_HW_SERVICE_IRQS;
/*enable interrupts */ /*enable interrupts */
#if !AQ_CFG_FORCE_LEGACY_INT #if !AQ_CFG_FORCE_LEGACY_INT
err = pci_alloc_irq_vectors(self->pdev, 1, numvecs, err = pci_alloc_irq_vectors(self->pdev, 1, numvecs,
...@@ -289,6 +294,8 @@ static int aq_pci_probe(struct pci_dev *pdev, ...@@ -289,6 +294,8 @@ static int aq_pci_probe(struct pci_dev *pdev,
if (err < 0) if (err < 0)
goto err_register; goto err_register;
aq_drvinfo_init(ndev);
return 0; return 0;
err_register: err_register:
...@@ -365,4 +372,13 @@ static struct pci_driver aq_pci_ops = { ...@@ -365,4 +372,13 @@ static struct pci_driver aq_pci_ops = {
.shutdown = aq_pci_shutdown, .shutdown = aq_pci_shutdown,
}; };
module_pci_driver(aq_pci_ops); int aq_pci_func_register_driver(void)
{
return pci_register_driver(&aq_pci_ops);
}
void aq_pci_func_unregister_driver(void)
{
pci_unregister_driver(&aq_pci_ops);
}
...@@ -24,9 +24,12 @@ struct aq_board_revision_s { ...@@ -24,9 +24,12 @@ struct aq_board_revision_s {
int aq_pci_func_init(struct pci_dev *pdev); int aq_pci_func_init(struct pci_dev *pdev);
int aq_pci_func_alloc_irq(struct aq_nic_s *self, unsigned int i, int aq_pci_func_alloc_irq(struct aq_nic_s *self, unsigned int i,
char *name, void *aq_vec, char *name, irq_handler_t irq_handler,
cpumask_t *affinity_mask); void *irq_arg, cpumask_t *affinity_mask);
void aq_pci_func_free_irqs(struct aq_nic_s *self); void aq_pci_func_free_irqs(struct aq_nic_s *self);
unsigned int aq_pci_func_get_irq_type(struct aq_nic_s *self); unsigned int aq_pci_func_get_irq_type(struct aq_nic_s *self);
int aq_pci_func_register_driver(void);
void aq_pci_func_unregister_driver(void);
#endif /* AQ_PCI_FUNC_H */ #endif /* AQ_PCI_FUNC_H */
...@@ -350,10 +350,10 @@ static int hw_atl_a0_hw_mac_addr_set(struct aq_hw_s *self, u8 *mac_addr) ...@@ -350,10 +350,10 @@ static int hw_atl_a0_hw_mac_addr_set(struct aq_hw_s *self, u8 *mac_addr)
static int hw_atl_a0_hw_init(struct aq_hw_s *self, u8 *mac_addr) static int hw_atl_a0_hw_init(struct aq_hw_s *self, u8 *mac_addr)
{ {
static u32 aq_hw_atl_igcr_table_[4][2] = { static u32 aq_hw_atl_igcr_table_[4][2] = {
{ 0x20000000U, 0x20000000U }, /* AQ_IRQ_INVALID */ [AQ_HW_IRQ_INVALID] = { 0x20000000U, 0x20000000U },
{ 0x20000080U, 0x20000080U }, /* AQ_IRQ_LEGACY */ [AQ_HW_IRQ_LEGACY] = { 0x20000080U, 0x20000080U },
{ 0x20000021U, 0x20000025U }, /* AQ_IRQ_MSI */ [AQ_HW_IRQ_MSI] = { 0x20000021U, 0x20000025U },
{ 0x20000022U, 0x20000026U } /* AQ_IRQ_MSIX */ [AQ_HW_IRQ_MSIX] = { 0x20000022U, 0x20000026U },
}; };
int err = 0; int err = 0;
......
...@@ -388,10 +388,10 @@ static int hw_atl_b0_hw_mac_addr_set(struct aq_hw_s *self, u8 *mac_addr) ...@@ -388,10 +388,10 @@ static int hw_atl_b0_hw_mac_addr_set(struct aq_hw_s *self, u8 *mac_addr)
static int hw_atl_b0_hw_init(struct aq_hw_s *self, u8 *mac_addr) static int hw_atl_b0_hw_init(struct aq_hw_s *self, u8 *mac_addr)
{ {
static u32 aq_hw_atl_igcr_table_[4][2] = { static u32 aq_hw_atl_igcr_table_[4][2] = {
{ 0x20000000U, 0x20000000U }, /* AQ_IRQ_INVALID */ [AQ_HW_IRQ_INVALID] = { 0x20000000U, 0x20000000U },
{ 0x20000080U, 0x20000080U }, /* AQ_IRQ_LEGACY */ [AQ_HW_IRQ_LEGACY] = { 0x20000080U, 0x20000080U },
{ 0x20000021U, 0x20000025U }, /* AQ_IRQ_MSI */ [AQ_HW_IRQ_MSI] = { 0x20000021U, 0x20000025U },
{ 0x20000022U, 0x20000026U } /* AQ_IRQ_MSIX */ [AQ_HW_IRQ_MSIX] = { 0x20000022U, 0x20000026U },
}; };
int err = 0; int err = 0;
...@@ -443,6 +443,11 @@ static int hw_atl_b0_hw_init(struct aq_hw_s *self, u8 *mac_addr) ...@@ -443,6 +443,11 @@ static int hw_atl_b0_hw_init(struct aq_hw_s *self, u8 *mac_addr)
((HW_ATL_B0_ERR_INT << 0x18) | (1U << 0x1F)) | ((HW_ATL_B0_ERR_INT << 0x18) | (1U << 0x1F)) |
((HW_ATL_B0_ERR_INT << 0x10) | (1U << 0x17)), 0U); ((HW_ATL_B0_ERR_INT << 0x10) | (1U << 0x17)), 0U);
/* Enable link interrupt */
if (aq_nic_cfg->link_irq_vec)
hw_atl_reg_gen_irq_map_set(self, BIT(7) |
aq_nic_cfg->link_irq_vec, 3U);
hw_atl_b0_hw_offload_set(self, aq_nic_cfg); hw_atl_b0_hw_offload_set(self, aq_nic_cfg);
err_exit: err_exit:
......
...@@ -32,9 +32,6 @@ extern const struct aq_hw_caps_s hw_atl_b0_caps_aqc109; ...@@ -32,9 +32,6 @@ extern const struct aq_hw_caps_s hw_atl_b0_caps_aqc109;
#define hw_atl_b0_caps_aqc111s hw_atl_b0_caps_aqc108 #define hw_atl_b0_caps_aqc111s hw_atl_b0_caps_aqc108
#define hw_atl_b0_caps_aqc112s hw_atl_b0_caps_aqc109 #define hw_atl_b0_caps_aqc112s hw_atl_b0_caps_aqc109
#define hw_atl_b0_caps_aqc111e hw_atl_b0_caps_aqc108
#define hw_atl_b0_caps_aqc112e hw_atl_b0_caps_aqc109
extern const struct aq_hw_ops hw_atl_ops_b0; extern const struct aq_hw_ops hw_atl_ops_b0;
#define hw_atl_ops_b1 hw_atl_ops_b0 #define hw_atl_ops_b1 hw_atl_ops_b0
......
...@@ -49,11 +49,6 @@ u32 hw_atl_glb_soft_res_get(struct aq_hw_s *aq_hw) ...@@ -49,11 +49,6 @@ u32 hw_atl_glb_soft_res_get(struct aq_hw_s *aq_hw)
HW_ATL_GLB_SOFT_RES_SHIFT); HW_ATL_GLB_SOFT_RES_SHIFT);
} }
u32 hw_atl_reg_rx_dma_stat_counter7get(struct aq_hw_s *aq_hw)
{
return aq_hw_read_reg(aq_hw, HW_ATL_RX_DMA_STAT_COUNTER7_ADR);
}
u32 hw_atl_reg_glb_mif_id_get(struct aq_hw_s *aq_hw) u32 hw_atl_reg_glb_mif_id_get(struct aq_hw_s *aq_hw)
{ {
return aq_hw_read_reg(aq_hw, HW_ATL_GLB_MIF_ID_ADR); return aq_hw_read_reg(aq_hw, HW_ATL_GLB_MIF_ID_ADR);
...@@ -65,44 +60,24 @@ u32 hw_atl_rpb_rx_dma_drop_pkt_cnt_get(struct aq_hw_s *aq_hw) ...@@ -65,44 +60,24 @@ u32 hw_atl_rpb_rx_dma_drop_pkt_cnt_get(struct aq_hw_s *aq_hw)
return aq_hw_read_reg(aq_hw, HW_ATL_RPB_RX_DMA_DROP_PKT_CNT_ADR); return aq_hw_read_reg(aq_hw, HW_ATL_RPB_RX_DMA_DROP_PKT_CNT_ADR);
} }
u32 hw_atl_stats_rx_dma_good_octet_counterlsw_get(struct aq_hw_s *aq_hw) u64 hw_atl_stats_rx_dma_good_octet_counter_get(struct aq_hw_s *aq_hw)
{
return aq_hw_read_reg(aq_hw, HW_ATL_STATS_RX_DMA_GOOD_OCTET_COUNTERLSW);
}
u32 hw_atl_stats_rx_dma_good_pkt_counterlsw_get(struct aq_hw_s *aq_hw)
{
return aq_hw_read_reg(aq_hw, HW_ATL_STATS_RX_DMA_GOOD_PKT_COUNTERLSW);
}
u32 hw_atl_stats_tx_dma_good_octet_counterlsw_get(struct aq_hw_s *aq_hw)
{
return aq_hw_read_reg(aq_hw, HW_ATL_STATS_TX_DMA_GOOD_OCTET_COUNTERLSW);
}
u32 hw_atl_stats_tx_dma_good_pkt_counterlsw_get(struct aq_hw_s *aq_hw)
{
return aq_hw_read_reg(aq_hw, HW_ATL_STATS_TX_DMA_GOOD_PKT_COUNTERLSW);
}
u32 hw_atl_stats_rx_dma_good_octet_countermsw_get(struct aq_hw_s *aq_hw)
{ {
return aq_hw_read_reg(aq_hw, HW_ATL_STATS_RX_DMA_GOOD_OCTET_COUNTERMSW); return aq_hw_read_reg64(aq_hw, HW_ATL_STATS_RX_DMA_GOOD_OCTET_COUNTERLSW);
} }
u32 hw_atl_stats_rx_dma_good_pkt_countermsw_get(struct aq_hw_s *aq_hw) u64 hw_atl_stats_rx_dma_good_pkt_counter_get(struct aq_hw_s *aq_hw)
{ {
return aq_hw_read_reg(aq_hw, HW_ATL_STATS_RX_DMA_GOOD_PKT_COUNTERMSW); return aq_hw_read_reg64(aq_hw, HW_ATL_STATS_RX_DMA_GOOD_PKT_COUNTERLSW);
} }
u32 hw_atl_stats_tx_dma_good_octet_countermsw_get(struct aq_hw_s *aq_hw) u64 hw_atl_stats_tx_dma_good_octet_counter_get(struct aq_hw_s *aq_hw)
{ {
return aq_hw_read_reg(aq_hw, HW_ATL_STATS_TX_DMA_GOOD_OCTET_COUNTERMSW); return aq_hw_read_reg64(aq_hw, HW_ATL_STATS_TX_DMA_GOOD_OCTET_COUNTERLSW);
} }
u32 hw_atl_stats_tx_dma_good_pkt_countermsw_get(struct aq_hw_s *aq_hw) u64 hw_atl_stats_tx_dma_good_pkt_counter_get(struct aq_hw_s *aq_hw)
{ {
return aq_hw_read_reg(aq_hw, HW_ATL_STATS_TX_DMA_GOOD_PKT_COUNTERMSW); return aq_hw_read_reg64(aq_hw, HW_ATL_STATS_TX_DMA_GOOD_PKT_COUNTERLSW);
} }
/* interrupt */ /* interrupt */
......
...@@ -40,29 +40,17 @@ u32 hw_atl_glb_soft_res_get(struct aq_hw_s *aq_hw); ...@@ -40,29 +40,17 @@ u32 hw_atl_glb_soft_res_get(struct aq_hw_s *aq_hw);
u32 hw_atl_rpb_rx_dma_drop_pkt_cnt_get(struct aq_hw_s *aq_hw); u32 hw_atl_rpb_rx_dma_drop_pkt_cnt_get(struct aq_hw_s *aq_hw);
/* get rx dma good octet counter lsw */ /* get rx dma good octet counter */
u32 hw_atl_stats_rx_dma_good_octet_counterlsw_get(struct aq_hw_s *aq_hw); u64 hw_atl_stats_rx_dma_good_octet_counter_get(struct aq_hw_s *aq_hw);
/* get rx dma good packet counter lsw */ /* get rx dma good packet counter */
u32 hw_atl_stats_rx_dma_good_pkt_counterlsw_get(struct aq_hw_s *aq_hw); u64 hw_atl_stats_rx_dma_good_pkt_counter_get(struct aq_hw_s *aq_hw);
/* get tx dma good octet counter lsw */ /* get tx dma good octet counter */
u32 hw_atl_stats_tx_dma_good_octet_counterlsw_get(struct aq_hw_s *aq_hw); u64 hw_atl_stats_tx_dma_good_octet_counter_get(struct aq_hw_s *aq_hw);
/* get tx dma good packet counter lsw */ /* get tx dma good packet counter */
u32 hw_atl_stats_tx_dma_good_pkt_counterlsw_get(struct aq_hw_s *aq_hw); u64 hw_atl_stats_tx_dma_good_pkt_counter_get(struct aq_hw_s *aq_hw);
/* get rx dma good octet counter msw */
u32 hw_atl_stats_rx_dma_good_octet_countermsw_get(struct aq_hw_s *aq_hw);
/* get rx dma good packet counter msw */
u32 hw_atl_stats_rx_dma_good_pkt_countermsw_get(struct aq_hw_s *aq_hw);
/* get tx dma good octet counter msw */
u32 hw_atl_stats_tx_dma_good_octet_countermsw_get(struct aq_hw_s *aq_hw);
/* get tx dma good packet counter msw */
u32 hw_atl_stats_tx_dma_good_pkt_countermsw_get(struct aq_hw_s *aq_hw);
/* get msm rx errors counter register */ /* get msm rx errors counter register */
u32 hw_atl_reg_mac_msm_rx_errs_cnt_get(struct aq_hw_s *aq_hw); u32 hw_atl_reg_mac_msm_rx_errs_cnt_get(struct aq_hw_s *aq_hw);
...@@ -82,9 +70,6 @@ u32 hw_atl_reg_mac_msm_rx_bcst_octets_counter1get(struct aq_hw_s *aq_hw); ...@@ -82,9 +70,6 @@ u32 hw_atl_reg_mac_msm_rx_bcst_octets_counter1get(struct aq_hw_s *aq_hw);
/* get msm rx unicast octets counter register 0 */ /* get msm rx unicast octets counter register 0 */
u32 hw_atl_reg_mac_msm_rx_ucst_octets_counter0get(struct aq_hw_s *aq_hw); u32 hw_atl_reg_mac_msm_rx_ucst_octets_counter0get(struct aq_hw_s *aq_hw);
/* get rx dma statistics counter 7 */
u32 hw_atl_reg_rx_dma_stat_counter7get(struct aq_hw_s *aq_hw);
/* get msm tx errors counter register */ /* get msm tx errors counter register */
u32 hw_atl_reg_mac_msm_tx_errs_cnt_get(struct aq_hw_s *aq_hw); u32 hw_atl_reg_mac_msm_tx_errs_cnt_get(struct aq_hw_s *aq_hw);
......
...@@ -58,9 +58,6 @@ ...@@ -58,9 +58,6 @@
/* preprocessor definitions for msm rx unicast octets counter register 0 */ /* preprocessor definitions for msm rx unicast octets counter register 0 */
#define HW_ATL_MAC_MSM_RX_UCST_OCTETS_COUNTER0_ADR 0x000001b8u #define HW_ATL_MAC_MSM_RX_UCST_OCTETS_COUNTER0_ADR 0x000001b8u
/* preprocessor definitions for rx dma statistics counter 7 */
#define HW_ATL_RX_DMA_STAT_COUNTER7_ADR 0x00006818u
/* preprocessor definitions for msm tx unicast frames counter register */ /* preprocessor definitions for msm tx unicast frames counter register */
#define HW_ATL_MAC_MSM_TX_UCST_FRM_CNT_ADR 0x00000108u #define HW_ATL_MAC_MSM_TX_UCST_FRM_CNT_ADR 0x00000108u
......
...@@ -545,7 +545,7 @@ void hw_atl_utils_mpi_read_stats(struct aq_hw_s *self, ...@@ -545,7 +545,7 @@ void hw_atl_utils_mpi_read_stats(struct aq_hw_s *self,
pmbox->stats.ubtc = pmbox->stats.uptc * mtu; pmbox->stats.ubtc = pmbox->stats.uptc * mtu;
pmbox->stats.dpc = atomic_read(&self->dpc); pmbox->stats.dpc = atomic_read(&self->dpc);
} else { } else {
pmbox->stats.dpc = hw_atl_reg_rx_dma_stat_counter7get(self); pmbox->stats.dpc = hw_atl_rpb_rx_dma_drop_pkt_cnt_get(self);
} }
err_exit:; err_exit:;
...@@ -763,6 +763,7 @@ static int hw_atl_fw1x_deinit(struct aq_hw_s *self) ...@@ -763,6 +763,7 @@ static int hw_atl_fw1x_deinit(struct aq_hw_s *self)
int hw_atl_utils_update_stats(struct aq_hw_s *self) int hw_atl_utils_update_stats(struct aq_hw_s *self)
{ {
struct hw_atl_utils_mbox mbox; struct hw_atl_utils_mbox mbox;
struct aq_stats_s *cs = &self->curr_stats;
hw_atl_utils_mpi_read_stats(self, &mbox); hw_atl_utils_mpi_read_stats(self, &mbox);
...@@ -789,10 +790,11 @@ int hw_atl_utils_update_stats(struct aq_hw_s *self) ...@@ -789,10 +790,11 @@ int hw_atl_utils_update_stats(struct aq_hw_s *self)
AQ_SDELTA(dpc); AQ_SDELTA(dpc);
} }
#undef AQ_SDELTA #undef AQ_SDELTA
self->curr_stats.dma_pkt_rc = hw_atl_stats_rx_dma_good_pkt_counterlsw_get(self);
self->curr_stats.dma_pkt_tc = hw_atl_stats_tx_dma_good_pkt_counterlsw_get(self); cs->dma_pkt_rc = hw_atl_stats_rx_dma_good_pkt_counter_get(self);
self->curr_stats.dma_oct_rc = hw_atl_stats_rx_dma_good_octet_counterlsw_get(self); cs->dma_pkt_tc = hw_atl_stats_tx_dma_good_pkt_counter_get(self);
self->curr_stats.dma_oct_tc = hw_atl_stats_tx_dma_good_octet_counterlsw_get(self); cs->dma_oct_rc = hw_atl_stats_rx_dma_good_octet_counter_get(self);
cs->dma_oct_tc = hw_atl_stats_tx_dma_good_octet_counter_get(self);
memcpy(&self->last_stats, &mbox.stats, sizeof(mbox.stats)); memcpy(&self->last_stats, &mbox.stats, sizeof(mbox.stats));
...@@ -960,6 +962,7 @@ const struct aq_fw_ops aq_fw_1x_ops = { ...@@ -960,6 +962,7 @@ const struct aq_fw_ops aq_fw_1x_ops = {
.set_state = hw_atl_utils_mpi_set_state, .set_state = hw_atl_utils_mpi_set_state,
.update_link_status = hw_atl_utils_mpi_get_link_status, .update_link_status = hw_atl_utils_mpi_get_link_status,
.update_stats = hw_atl_utils_update_stats, .update_stats = hw_atl_utils_update_stats,
.get_phy_temp = NULL,
.set_power = aq_fw1x_set_power, .set_power = aq_fw1x_set_power,
.set_eee_rate = NULL, .set_eee_rate = NULL,
.get_eee_rate = NULL, .get_eee_rate = NULL,
......
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
#define HW_ATL_FW2X_CTRL_WOL BIT(CTRL_WOL) #define HW_ATL_FW2X_CTRL_WOL BIT(CTRL_WOL)
#define HW_ATL_FW2X_CTRL_LINK_DROP BIT(CTRL_LINK_DROP) #define HW_ATL_FW2X_CTRL_LINK_DROP BIT(CTRL_LINK_DROP)
#define HW_ATL_FW2X_CTRL_PAUSE BIT(CTRL_PAUSE) #define HW_ATL_FW2X_CTRL_PAUSE BIT(CTRL_PAUSE)
#define HW_ATL_FW2X_CTRL_TEMPERATURE BIT(CTRL_TEMPERATURE)
#define HW_ATL_FW2X_CTRL_ASYMMETRIC_PAUSE BIT(CTRL_ASYMMETRIC_PAUSE) #define HW_ATL_FW2X_CTRL_ASYMMETRIC_PAUSE BIT(CTRL_ASYMMETRIC_PAUSE)
#define HW_ATL_FW2X_CTRL_FORCE_RECONNECT BIT(CTRL_FORCE_RECONNECT) #define HW_ATL_FW2X_CTRL_FORCE_RECONNECT BIT(CTRL_FORCE_RECONNECT)
...@@ -310,6 +311,40 @@ static int aq_fw2x_update_stats(struct aq_hw_s *self) ...@@ -310,6 +311,40 @@ static int aq_fw2x_update_stats(struct aq_hw_s *self)
return hw_atl_utils_update_stats(self); return hw_atl_utils_update_stats(self);
} }
static int aq_fw2x_get_phy_temp(struct aq_hw_s *self, int *temp)
{
u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
u32 temp_val = mpi_opts & HW_ATL_FW2X_CTRL_TEMPERATURE;
u32 phy_temp_offset;
u32 temp_res;
int err = 0;
u32 val;
phy_temp_offset = self->mbox_addr +
offsetof(struct hw_atl_utils_mbox, info) +
offsetof(struct hw_aq_info, phy_temperature);
/* Toggle statistics bit for FW to 0x36C.18 (CTRL_TEMPERATURE) */
mpi_opts = mpi_opts ^ HW_ATL_FW2X_CTRL_TEMPERATURE;
aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
/* Wait FW to report back */
err = readx_poll_timeout_atomic(aq_fw2x_state2_get, self, val,
temp_val !=
(val & HW_ATL_FW2X_CTRL_TEMPERATURE),
1U, 10000U);
err = hw_atl_utils_fw_downld_dwords(self, phy_temp_offset,
&temp_res, 1);
if (err)
return err;
/* Convert PHY temperature from 1/256 degree Celsius
* to 1/1000 degree Celsius.
*/
*temp = temp_res * 1000 / 256;
return 0;
}
static int aq_fw2x_set_sleep_proxy(struct aq_hw_s *self, u8 *mac) static int aq_fw2x_set_sleep_proxy(struct aq_hw_s *self, u8 *mac)
{ {
struct hw_atl_utils_fw_rpc *rpc = NULL; struct hw_atl_utils_fw_rpc *rpc = NULL;
...@@ -509,6 +544,7 @@ const struct aq_fw_ops aq_fw_2x_ops = { ...@@ -509,6 +544,7 @@ const struct aq_fw_ops aq_fw_2x_ops = {
.set_state = aq_fw2x_set_state, .set_state = aq_fw2x_set_state,
.update_link_status = aq_fw2x_update_link_status, .update_link_status = aq_fw2x_update_link_status,
.update_stats = aq_fw2x_update_stats, .update_stats = aq_fw2x_update_stats,
.get_phy_temp = aq_fw2x_get_phy_temp,
.set_power = aq_fw2x_set_power, .set_power = aq_fw2x_set_power,
.set_eee_rate = aq_fw2x_set_eee_rate, .set_eee_rate = aq_fw2x_set_eee_rate,
.get_eee_rate = aq_fw2x_get_eee_rate, .get_eee_rate = aq_fw2x_get_eee_rate,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment