Skip to content

Commit

Permalink
Merge branch 'aquantia-next'
Browse files Browse the repository at this point in the history
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: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed May 1, 2019
2 parents 2b5bc3c + 9eec030 commit 5be90f9
Show file tree
Hide file tree
Showing 22 changed files with 427 additions and 128 deletions.
1 change: 1 addition & 0 deletions drivers/net/ethernet/aquantia/atlantic/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ atlantic-objs := aq_main.o \
aq_ring.o \
aq_hw_utils.o \
aq_ethtool.o \
aq_drvinfo.o \
aq_filters.o \
hw_atl/hw_atl_a0.o \
hw_atl/hw_atl_b0.o \
Expand Down
3 changes: 0 additions & 3 deletions drivers/net/ethernet/aquantia/atlantic/aq_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,6 @@
#define AQ_DEVICE_ID_AQC111S 0x91B1
#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 AQ_HWREV_ANY 0
Expand Down
125 changes: 125 additions & 0 deletions drivers/net/ethernet/aquantia/atlantic/aq_drvinfo.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
// 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;
}
15 changes: 15 additions & 0 deletions drivers/net/ethernet/aquantia/atlantic/aq_drvinfo.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/* 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 */
22 changes: 18 additions & 4 deletions drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
return -EOPNOTSUPP;

mutex_lock(&aq_nic->fwreq_mutex);
err = aq_nic->aq_fw_ops->get_eee_rate(aq_nic->aq_hw, &rate,
&supported_rates);
mutex_unlock(&aq_nic->fwreq_mutex);
if (err < 0)
return err;

Expand Down Expand Up @@ -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))
return -EOPNOTSUPP;

mutex_lock(&aq_nic->fwreq_mutex);
err = aq_nic->aq_fw_ops->get_eee_rate(aq_nic->aq_hw, &rate,
&supported_rates);
mutex_unlock(&aq_nic->fwreq_mutex);
if (err < 0)
return err;

Expand All @@ -452,20 +456,28 @@ static int aq_ethtool_set_eee(struct net_device *ndev, struct ethtool_eee *eee)
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)
{
struct aq_nic_s *aq_nic = netdev_priv(ndev);
int err = 0;

if (unlikely(!aq_nic->aq_fw_ops->renegotiate))
return -EOPNOTSUPP;

if (netif_running(ndev))
return aq_nic->aq_fw_ops->renegotiate(aq_nic->aq_hw);
if (netif_running(ndev)) {
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,
Expand Down Expand Up @@ -503,7 +515,9 @@ static int aq_ethtool_set_pauseparam(struct net_device *ndev,
else
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);
mutex_unlock(&aq_nic->fwreq_mutex);

return err;
}
Expand Down
4 changes: 4 additions & 0 deletions drivers/net/ethernet/aquantia/atlantic/aq_hw.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ struct aq_stats_s {
#define AQ_HW_IRQ_MSI 2U
#define AQ_HW_IRQ_MSIX 3U

#define AQ_HW_SERVICE_IRQS 1U

#define AQ_HW_POWER_STATE_D0 0U
#define AQ_HW_POWER_STATE_D3 3U

Expand Down Expand Up @@ -259,6 +261,8 @@ struct aq_fw_ops {

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);

int (*set_flow_control)(struct aq_hw_s *self);
Expand Down
12 changes: 12 additions & 0 deletions drivers/net/ethernet/aquantia/atlantic/aq_hw_utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,18 @@ void aq_hw_write_reg(struct aq_hw_s *hw, u32 reg, u32 value)
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 err = 0;
Expand Down
1 change: 1 addition & 0 deletions drivers/net/ethernet/aquantia/atlantic/aq_hw_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -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(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);
int aq_hw_err_from_flags(struct aq_hw_s *hw);

#endif /* AQ_HW_UTILS_H */
41 changes: 41 additions & 0 deletions drivers/net/ethernet/aquantia/atlantic/aq_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,17 @@ MODULE_VERSION(AQ_CFG_DRV_VERSION);
MODULE_AUTHOR(AQ_CFG_DRV_AUTHOR);
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 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 *ndev = NULL;
Expand Down Expand Up @@ -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_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);
2 changes: 2 additions & 0 deletions drivers/net/ethernet/aquantia/atlantic/aq_main.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
#define AQ_MAIN_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);

#endif /* AQ_MAIN_H */
Loading

0 comments on commit 5be90f9

Please sign in to comment.