提交 44a4c469 编写于 作者: D David S. Miller

Merge branch 'aquantia-various-ethtool-ops-implementation'

Igor Russkikh says:

====================
net: aquantia: various ethtool ops implementation

In this patchset Anton Mikaev and I added some useful ethtool operations:
- ring size changes
- link renegotioation
- flow control management

The patch also improves init/deinit sequence.

V3 changes:
- After review and analysis it is clear that rtnl lock (which is
  captured by default on ethtool ops) is enough to secure possible
  overlapping of dev open/close. Thus, just dropping internal mutex.

V2 changes:
- using mutex to secure simultaneous dev close/open
- using state var to store/restore dev state
====================
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "aq_ethtool.h" #include "aq_ethtool.h"
#include "aq_nic.h" #include "aq_nic.h"
#include "aq_vec.h"
static void aq_ethtool_get_regs(struct net_device *ndev, static void aq_ethtool_get_regs(struct net_device *ndev,
struct ethtool_regs *regs, void *p) struct ethtool_regs *regs, void *p)
...@@ -284,6 +285,117 @@ static int aq_ethtool_set_coalesce(struct net_device *ndev, ...@@ -284,6 +285,117 @@ static int aq_ethtool_set_coalesce(struct net_device *ndev,
return aq_nic_update_interrupt_moderation_settings(aq_nic); return aq_nic_update_interrupt_moderation_settings(aq_nic);
} }
static int aq_ethtool_nway_reset(struct net_device *ndev)
{
struct aq_nic_s *aq_nic = netdev_priv(ndev);
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);
return 0;
}
static void aq_ethtool_get_pauseparam(struct net_device *ndev,
struct ethtool_pauseparam *pause)
{
struct aq_nic_s *aq_nic = netdev_priv(ndev);
pause->autoneg = 0;
if (aq_nic->aq_hw->aq_nic_cfg->flow_control & AQ_NIC_FC_RX)
pause->rx_pause = 1;
if (aq_nic->aq_hw->aq_nic_cfg->flow_control & AQ_NIC_FC_TX)
pause->tx_pause = 1;
}
static int aq_ethtool_set_pauseparam(struct net_device *ndev,
struct ethtool_pauseparam *pause)
{
struct aq_nic_s *aq_nic = netdev_priv(ndev);
int err = 0;
if (!aq_nic->aq_fw_ops->set_flow_control)
return -EOPNOTSUPP;
if (pause->autoneg == AUTONEG_ENABLE)
return -EOPNOTSUPP;
if (pause->rx_pause)
aq_nic->aq_hw->aq_nic_cfg->flow_control |= AQ_NIC_FC_RX;
else
aq_nic->aq_hw->aq_nic_cfg->flow_control &= ~AQ_NIC_FC_RX;
if (pause->tx_pause)
aq_nic->aq_hw->aq_nic_cfg->flow_control |= AQ_NIC_FC_TX;
else
aq_nic->aq_hw->aq_nic_cfg->flow_control &= ~AQ_NIC_FC_TX;
err = aq_nic->aq_fw_ops->set_flow_control(aq_nic->aq_hw);
return err;
}
static void aq_get_ringparam(struct net_device *ndev,
struct ethtool_ringparam *ring)
{
struct aq_nic_s *aq_nic = netdev_priv(ndev);
struct aq_nic_cfg_s *aq_nic_cfg = aq_nic_get_cfg(aq_nic);
ring->rx_pending = aq_nic_cfg->rxds;
ring->tx_pending = aq_nic_cfg->txds;
ring->rx_max_pending = aq_nic_cfg->aq_hw_caps->rxds_max;
ring->tx_max_pending = aq_nic_cfg->aq_hw_caps->txds_max;
}
static int aq_set_ringparam(struct net_device *ndev,
struct ethtool_ringparam *ring)
{
int err = 0;
bool ndev_running = false;
struct aq_nic_s *aq_nic = netdev_priv(ndev);
struct aq_nic_cfg_s *aq_nic_cfg = aq_nic_get_cfg(aq_nic);
const struct aq_hw_caps_s *hw_caps = aq_nic_cfg->aq_hw_caps;
if (ring->rx_mini_pending || ring->rx_jumbo_pending) {
err = -EOPNOTSUPP;
goto err_exit;
}
if (netif_running(ndev)) {
ndev_running = true;
dev_close(ndev);
}
aq_nic_free_vectors(aq_nic);
aq_nic_cfg->rxds = max(ring->rx_pending, hw_caps->rxds_min);
aq_nic_cfg->rxds = min(aq_nic_cfg->rxds, hw_caps->rxds_max);
aq_nic_cfg->rxds = ALIGN(aq_nic_cfg->rxds, AQ_HW_RXD_MULTIPLE);
aq_nic_cfg->txds = max(ring->tx_pending, hw_caps->txds_min);
aq_nic_cfg->txds = min(aq_nic_cfg->txds, hw_caps->txds_max);
aq_nic_cfg->txds = ALIGN(aq_nic_cfg->txds, AQ_HW_TXD_MULTIPLE);
for (aq_nic->aq_vecs = 0; aq_nic->aq_vecs < aq_nic_cfg->vecs;
aq_nic->aq_vecs++) {
aq_nic->aq_vec[aq_nic->aq_vecs] =
aq_vec_alloc(aq_nic, aq_nic->aq_vecs, aq_nic_cfg);
if (unlikely(!aq_nic->aq_vec[aq_nic->aq_vecs])) {
err = -ENOMEM;
goto err_exit;
}
}
if (ndev_running)
err = dev_open(ndev);
err_exit:
return err;
}
const struct ethtool_ops aq_ethtool_ops = { const struct ethtool_ops aq_ethtool_ops = {
.get_link = aq_ethtool_get_link, .get_link = aq_ethtool_get_link,
.get_regs_len = aq_ethtool_get_regs_len, .get_regs_len = aq_ethtool_get_regs_len,
...@@ -291,6 +403,11 @@ const struct ethtool_ops aq_ethtool_ops = { ...@@ -291,6 +403,11 @@ const struct ethtool_ops aq_ethtool_ops = {
.get_drvinfo = aq_ethtool_get_drvinfo, .get_drvinfo = aq_ethtool_get_drvinfo,
.get_strings = aq_ethtool_get_strings, .get_strings = aq_ethtool_get_strings,
.get_rxfh_indir_size = aq_ethtool_get_rss_indir_size, .get_rxfh_indir_size = aq_ethtool_get_rss_indir_size,
.nway_reset = aq_ethtool_nway_reset,
.get_ringparam = aq_get_ringparam,
.set_ringparam = aq_set_ringparam,
.get_pauseparam = aq_ethtool_get_pauseparam,
.set_pauseparam = aq_ethtool_set_pauseparam,
.get_rxfh_key_size = aq_ethtool_get_rss_key_size, .get_rxfh_key_size = aq_ethtool_get_rss_key_size,
.get_rxfh = aq_ethtool_get_rss, .get_rxfh = aq_ethtool_get_rss,
.get_rxnfc = aq_ethtool_get_rxnfc, .get_rxnfc = aq_ethtool_get_rxnfc,
......
...@@ -24,8 +24,10 @@ struct aq_hw_caps_s { ...@@ -24,8 +24,10 @@ struct aq_hw_caps_s {
u64 link_speed_msk; u64 link_speed_msk;
unsigned int hw_priv_flags; unsigned int hw_priv_flags;
u32 media_type; u32 media_type;
u32 rxds; u32 rxds_max;
u32 txds; u32 txds_max;
u32 rxds_min;
u32 txds_min;
u32 txhwb_alignment; u32 txhwb_alignment;
u32 irq_mask; u32 irq_mask;
u32 vecs; u32 vecs;
...@@ -98,6 +100,9 @@ struct aq_stats_s { ...@@ -98,6 +100,9 @@ struct aq_stats_s {
#define AQ_HW_MEDIA_TYPE_TP 1U #define AQ_HW_MEDIA_TYPE_TP 1U
#define AQ_HW_MEDIA_TYPE_FIBRE 2U #define AQ_HW_MEDIA_TYPE_FIBRE 2U
#define AQ_HW_TXD_MULTIPLE 8U
#define AQ_HW_RXD_MULTIPLE 8U
struct aq_hw_s { struct aq_hw_s {
atomic_t flags; atomic_t flags;
u8 rbl_enabled:1; u8 rbl_enabled:1;
...@@ -197,25 +202,30 @@ struct aq_hw_ops { ...@@ -197,25 +202,30 @@ struct aq_hw_ops {
int (*hw_get_fw_version)(struct aq_hw_s *self, u32 *fw_version); int (*hw_get_fw_version)(struct aq_hw_s *self, u32 *fw_version);
int (*hw_deinit)(struct aq_hw_s *self);
int (*hw_set_power)(struct aq_hw_s *self, unsigned int power_state); int (*hw_set_power)(struct aq_hw_s *self, unsigned int power_state);
}; };
struct aq_fw_ops { struct aq_fw_ops {
int (*init)(struct aq_hw_s *self); int (*init)(struct aq_hw_s *self);
int (*deinit)(struct aq_hw_s *self);
int (*reset)(struct aq_hw_s *self); int (*reset)(struct aq_hw_s *self);
int (*renegotiate)(struct aq_hw_s *self);
int (*get_mac_permanent)(struct aq_hw_s *self, u8 *mac); int (*get_mac_permanent)(struct aq_hw_s *self, u8 *mac);
int (*set_link_speed)(struct aq_hw_s *self, u32 speed); int (*set_link_speed)(struct aq_hw_s *self, u32 speed);
int (*set_state)(struct aq_hw_s *self, enum hal_atl_utils_fw_state_e state); int (*set_state)(struct aq_hw_s *self,
enum hal_atl_utils_fw_state_e state);
int (*update_link_status)(struct aq_hw_s *self); int (*update_link_status)(struct aq_hw_s *self);
int (*update_stats)(struct aq_hw_s *self); int (*update_stats)(struct aq_hw_s *self);
int (*set_flow_control)(struct aq_hw_s *self);
}; };
#endif /* AQ_HW_H */ #endif /* AQ_HW_H */
...@@ -89,8 +89,8 @@ void aq_nic_cfg_start(struct aq_nic_s *self) ...@@ -89,8 +89,8 @@ void aq_nic_cfg_start(struct aq_nic_s *self)
aq_nic_rss_init(self, cfg->num_rss_queues); aq_nic_rss_init(self, cfg->num_rss_queues);
/*descriptors */ /*descriptors */
cfg->rxds = min(cfg->aq_hw_caps->rxds, AQ_CFG_RXDS_DEF); cfg->rxds = min(cfg->aq_hw_caps->rxds_max, AQ_CFG_RXDS_DEF);
cfg->txds = min(cfg->aq_hw_caps->txds, AQ_CFG_TXDS_DEF); cfg->txds = min(cfg->aq_hw_caps->txds_max, AQ_CFG_TXDS_DEF);
/*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);
...@@ -761,10 +761,14 @@ void aq_nic_get_link_ksettings(struct aq_nic_s *self, ...@@ -761,10 +761,14 @@ void aq_nic_get_link_ksettings(struct aq_nic_s *self,
ethtool_link_ksettings_add_link_mode(cmd, advertising, ethtool_link_ksettings_add_link_mode(cmd, advertising,
100baseT_Full); 100baseT_Full);
if (self->aq_nic_cfg.flow_control) if (self->aq_nic_cfg.flow_control & AQ_NIC_FC_RX)
ethtool_link_ksettings_add_link_mode(cmd, advertising, ethtool_link_ksettings_add_link_mode(cmd, advertising,
Pause); Pause);
if (self->aq_nic_cfg.flow_control & AQ_NIC_FC_TX)
ethtool_link_ksettings_add_link_mode(cmd, advertising,
Asym_Pause);
if (self->aq_nic_cfg.aq_hw_caps->media_type == AQ_HW_MEDIA_TYPE_FIBRE) if (self->aq_nic_cfg.aq_hw_caps->media_type == AQ_HW_MEDIA_TYPE_FIBRE)
ethtool_link_ksettings_add_link_mode(cmd, advertising, FIBRE); ethtool_link_ksettings_add_link_mode(cmd, advertising, FIBRE);
else else
...@@ -879,7 +883,7 @@ void aq_nic_deinit(struct aq_nic_s *self) ...@@ -879,7 +883,7 @@ void aq_nic_deinit(struct aq_nic_s *self)
aq_vec_deinit(aq_vec); aq_vec_deinit(aq_vec);
if (self->power_state == AQ_HW_POWER_STATE_D0) { if (self->power_state == AQ_HW_POWER_STATE_D0) {
(void)self->aq_hw_ops->hw_deinit(self->aq_hw); (void)self->aq_fw_ops->deinit(self->aq_hw);
} else { } else {
(void)self->aq_hw_ops->hw_set_power(self->aq_hw, (void)self->aq_hw_ops->hw_set_power(self->aq_hw,
self->power_state); self->power_state);
......
...@@ -19,29 +19,31 @@ ...@@ -19,29 +19,31 @@
#include "hw_atl_a0_internal.h" #include "hw_atl_a0_internal.h"
#define DEFAULT_A0_BOARD_BASIC_CAPABILITIES \ #define DEFAULT_A0_BOARD_BASIC_CAPABILITIES \
.is_64_dma = true, \ .is_64_dma = true, \
.msix_irqs = 4U, \ .msix_irqs = 4U, \
.irq_mask = ~0U, \ .irq_mask = ~0U, \
.vecs = HW_ATL_A0_RSS_MAX, \ .vecs = HW_ATL_A0_RSS_MAX, \
.tcs = HW_ATL_A0_TC_MAX, \ .tcs = HW_ATL_A0_TC_MAX, \
.rxd_alignment = 1U, \ .rxd_alignment = 1U, \
.rxd_size = HW_ATL_A0_RXD_SIZE, \ .rxd_size = HW_ATL_A0_RXD_SIZE, \
.rxds = 248U, \ .rxds_max = HW_ATL_A0_MAX_RXD, \
.txd_alignment = 1U, \ .rxds_min = HW_ATL_A0_MIN_RXD, \
.txd_size = HW_ATL_A0_TXD_SIZE, \ .txd_alignment = 1U, \
.txds = 8U * 1024U, \ .txd_size = HW_ATL_A0_TXD_SIZE, \
.txhwb_alignment = 4096U, \ .txds_max = HW_ATL_A0_MAX_TXD, \
.tx_rings = HW_ATL_A0_TX_RINGS, \ .txds_min = HW_ATL_A0_MIN_RXD, \
.rx_rings = HW_ATL_A0_RX_RINGS, \ .txhwb_alignment = 4096U, \
.hw_features = NETIF_F_HW_CSUM | \ .tx_rings = HW_ATL_A0_TX_RINGS, \
NETIF_F_RXHASH | \ .rx_rings = HW_ATL_A0_RX_RINGS, \
NETIF_F_RXCSUM | \ .hw_features = NETIF_F_HW_CSUM | \
NETIF_F_SG | \ NETIF_F_RXHASH | \
NETIF_F_TSO, \ NETIF_F_RXCSUM | \
NETIF_F_SG | \
NETIF_F_TSO, \
.hw_priv_flags = IFF_UNICAST_FLT, \ .hw_priv_flags = IFF_UNICAST_FLT, \
.flow_control = true, \ .flow_control = true, \
.mtu = HW_ATL_A0_MTU_JUMBO, \ .mtu = HW_ATL_A0_MTU_JUMBO, \
.mac_regs_count = 88, \ .mac_regs_count = 88, \
.hw_alive_check_addr = 0x10U .hw_alive_check_addr = 0x10U
const struct aq_hw_caps_s hw_atl_a0_caps_aqc100 = { const struct aq_hw_caps_s hw_atl_a0_caps_aqc100 = {
...@@ -875,7 +877,6 @@ static int hw_atl_a0_hw_ring_rx_stop(struct aq_hw_s *self, ...@@ -875,7 +877,6 @@ static int hw_atl_a0_hw_ring_rx_stop(struct aq_hw_s *self,
const struct aq_hw_ops hw_atl_ops_a0 = { const struct aq_hw_ops hw_atl_ops_a0 = {
.hw_set_mac_address = hw_atl_a0_hw_mac_addr_set, .hw_set_mac_address = hw_atl_a0_hw_mac_addr_set,
.hw_init = hw_atl_a0_hw_init, .hw_init = hw_atl_a0_hw_init,
.hw_deinit = hw_atl_utils_hw_deinit,
.hw_set_power = hw_atl_utils_hw_set_power, .hw_set_power = hw_atl_utils_hw_set_power,
.hw_reset = hw_atl_a0_hw_reset, .hw_reset = hw_atl_a0_hw_reset,
.hw_start = hw_atl_a0_hw_start, .hw_start = hw_atl_a0_hw_start,
......
...@@ -88,4 +88,12 @@ ...@@ -88,4 +88,12 @@
#define HW_ATL_A0_FW_VER_EXPECTED 0x01050006U #define HW_ATL_A0_FW_VER_EXPECTED 0x01050006U
#define HW_ATL_A0_MIN_RXD \
(ALIGN(AQ_CFG_SKB_FRAGS_MAX + 1U, AQ_HW_RXD_MULTIPLE))
#define HW_ATL_A0_MIN_TXD \
(ALIGN(AQ_CFG_SKB_FRAGS_MAX + 1U, AQ_HW_TXD_MULTIPLE))
#define HW_ATL_A0_MAX_RXD 8184U
#define HW_ATL_A0_MAX_TXD 8184U
#endif /* HW_ATL_A0_INTERNAL_H */ #endif /* HW_ATL_A0_INTERNAL_H */
...@@ -20,30 +20,32 @@ ...@@ -20,30 +20,32 @@
#include "hw_atl_llh_internal.h" #include "hw_atl_llh_internal.h"
#define DEFAULT_B0_BOARD_BASIC_CAPABILITIES \ #define DEFAULT_B0_BOARD_BASIC_CAPABILITIES \
.is_64_dma = true, \ .is_64_dma = true, \
.msix_irqs = 4U, \ .msix_irqs = 4U, \
.irq_mask = ~0U, \ .irq_mask = ~0U, \
.vecs = HW_ATL_B0_RSS_MAX, \ .vecs = HW_ATL_B0_RSS_MAX, \
.tcs = HW_ATL_B0_TC_MAX, \ .tcs = HW_ATL_B0_TC_MAX, \
.rxd_alignment = 1U, \ .rxd_alignment = 1U, \
.rxd_size = HW_ATL_B0_RXD_SIZE, \ .rxd_size = HW_ATL_B0_RXD_SIZE, \
.rxds = 4U * 1024U, \ .rxds_max = HW_ATL_B0_MAX_RXD, \
.txd_alignment = 1U, \ .rxds_min = HW_ATL_B0_MIN_RXD, \
.txd_size = HW_ATL_B0_TXD_SIZE, \ .txd_alignment = 1U, \
.txds = 8U * 1024U, \ .txd_size = HW_ATL_B0_TXD_SIZE, \
.txhwb_alignment = 4096U, \ .txds_max = HW_ATL_B0_MAX_TXD, \
.tx_rings = HW_ATL_B0_TX_RINGS, \ .txds_min = HW_ATL_B0_MIN_TXD, \
.rx_rings = HW_ATL_B0_RX_RINGS, \ .txhwb_alignment = 4096U, \
.hw_features = NETIF_F_HW_CSUM | \ .tx_rings = HW_ATL_B0_TX_RINGS, \
NETIF_F_RXCSUM | \ .rx_rings = HW_ATL_B0_RX_RINGS, \
NETIF_F_RXHASH | \ .hw_features = NETIF_F_HW_CSUM | \
NETIF_F_SG | \ NETIF_F_RXCSUM | \
NETIF_F_TSO | \ NETIF_F_RXHASH | \
NETIF_F_LRO, \ NETIF_F_SG | \
.hw_priv_flags = IFF_UNICAST_FLT, \ NETIF_F_TSO | \
.flow_control = true, \ NETIF_F_LRO, \
.mtu = HW_ATL_B0_MTU_JUMBO, \ .hw_priv_flags = IFF_UNICAST_FLT, \
.mac_regs_count = 88, \ .flow_control = true, \
.mtu = HW_ATL_B0_MTU_JUMBO, \
.mac_regs_count = 88, \
.hw_alive_check_addr = 0x10U .hw_alive_check_addr = 0x10U
const struct aq_hw_caps_s hw_atl_b0_caps_aqc100 = { const struct aq_hw_caps_s hw_atl_b0_caps_aqc100 = {
...@@ -933,7 +935,6 @@ static int hw_atl_b0_hw_ring_rx_stop(struct aq_hw_s *self, ...@@ -933,7 +935,6 @@ static int hw_atl_b0_hw_ring_rx_stop(struct aq_hw_s *self,
const struct aq_hw_ops hw_atl_ops_b0 = { const struct aq_hw_ops hw_atl_ops_b0 = {
.hw_set_mac_address = hw_atl_b0_hw_mac_addr_set, .hw_set_mac_address = hw_atl_b0_hw_mac_addr_set,
.hw_init = hw_atl_b0_hw_init, .hw_init = hw_atl_b0_hw_init,
.hw_deinit = hw_atl_utils_hw_deinit,
.hw_set_power = hw_atl_utils_hw_set_power, .hw_set_power = hw_atl_utils_hw_set_power,
.hw_reset = hw_atl_b0_hw_reset, .hw_reset = hw_atl_b0_hw_reset,
.hw_start = hw_atl_b0_hw_start, .hw_start = hw_atl_b0_hw_start,
......
...@@ -142,6 +142,14 @@ ...@@ -142,6 +142,14 @@
#define HW_ATL_INTR_MODER_MAX 0x1FF #define HW_ATL_INTR_MODER_MAX 0x1FF
#define HW_ATL_INTR_MODER_MIN 0xFF #define HW_ATL_INTR_MODER_MIN 0xFF
#define HW_ATL_B0_MIN_RXD \
(ALIGN(AQ_CFG_SKB_FRAGS_MAX + 1U, AQ_HW_RXD_MULTIPLE))
#define HW_ATL_B0_MIN_TXD \
(ALIGN(AQ_CFG_SKB_FRAGS_MAX + 1U, AQ_HW_TXD_MULTIPLE))
#define HW_ATL_B0_MAX_RXD 8184U
#define HW_ATL_B0_MAX_TXD 8184U
/* HW layer capabilities */ /* HW layer capabilities */
#endif /* HW_ATL_B0_INTERNAL_H */ #endif /* HW_ATL_B0_INTERNAL_H */
...@@ -30,10 +30,11 @@ ...@@ -30,10 +30,11 @@
#define HW_ATL_MPI_CONTROL_ADR 0x0368U #define HW_ATL_MPI_CONTROL_ADR 0x0368U
#define HW_ATL_MPI_STATE_ADR 0x036CU #define HW_ATL_MPI_STATE_ADR 0x036CU
#define HW_ATL_MPI_STATE_MSK 0x00FFU #define HW_ATL_MPI_STATE_MSK 0x00FFU
#define HW_ATL_MPI_STATE_SHIFT 0U #define HW_ATL_MPI_STATE_SHIFT 0U
#define HW_ATL_MPI_SPEED_MSK 0xFFFF0000U #define HW_ATL_MPI_SPEED_MSK 0x00FF0000U
#define HW_ATL_MPI_SPEED_SHIFT 16U #define HW_ATL_MPI_SPEED_SHIFT 16U
#define HW_ATL_MPI_DIRTY_WAKE_MSK 0x02000000U
#define HW_ATL_MPI_DAISY_CHAIN_STATUS 0x704 #define HW_ATL_MPI_DAISY_CHAIN_STATUS 0x704
#define HW_ATL_MPI_BOOT_EXIT_CODE 0x388 #define HW_ATL_MPI_BOOT_EXIT_CODE 0x388
...@@ -521,23 +522,24 @@ void hw_atl_utils_mpi_read_stats(struct aq_hw_s *self, ...@@ -521,23 +522,24 @@ void hw_atl_utils_mpi_read_stats(struct aq_hw_s *self,
err_exit:; err_exit:;
} }
static int hw_atl_utils_mpi_set_speed(struct aq_hw_s *self, u32 speed) int hw_atl_utils_mpi_set_speed(struct aq_hw_s *self, u32 speed)
{ {
u32 val = aq_hw_read_reg(self, HW_ATL_MPI_CONTROL_ADR); u32 val = aq_hw_read_reg(self, HW_ATL_MPI_CONTROL_ADR);
val = (val & HW_ATL_MPI_STATE_MSK) | (speed << HW_ATL_MPI_SPEED_SHIFT); val = val & ~HW_ATL_MPI_SPEED_MSK;
val |= speed << HW_ATL_MPI_SPEED_SHIFT;
aq_hw_write_reg(self, HW_ATL_MPI_CONTROL_ADR, val); aq_hw_write_reg(self, HW_ATL_MPI_CONTROL_ADR, val);
return 0; return 0;
} }
void hw_atl_utils_mpi_set(struct aq_hw_s *self, int hw_atl_utils_mpi_set_state(struct aq_hw_s *self,
enum hal_atl_utils_fw_state_e state, enum hal_atl_utils_fw_state_e state)
u32 speed)
{ {
int err = 0; int err = 0;
u32 transaction_id = 0; u32 transaction_id = 0;
struct hw_aq_atl_utils_mbox_header mbox; struct hw_aq_atl_utils_mbox_header mbox;
u32 val = aq_hw_read_reg(self, HW_ATL_MPI_CONTROL_ADR);
if (state == MPI_RESET) { if (state == MPI_RESET) {
hw_atl_utils_mpi_read_mbox(self, &mbox); hw_atl_utils_mpi_read_mbox(self, &mbox);
...@@ -551,21 +553,21 @@ void hw_atl_utils_mpi_set(struct aq_hw_s *self, ...@@ -551,21 +553,21 @@ void hw_atl_utils_mpi_set(struct aq_hw_s *self,
if (err < 0) if (err < 0)
goto err_exit; goto err_exit;
} }
/* On interface DEINIT we disable DW (raise bit)
* Otherwise enable DW (clear bit)
*/
if (state == MPI_DEINIT || state == MPI_POWER)
val |= HW_ATL_MPI_DIRTY_WAKE_MSK;
else
val &= ~HW_ATL_MPI_DIRTY_WAKE_MSK;
aq_hw_write_reg(self, HW_ATL_MPI_CONTROL_ADR, /* Set new state bits */
(speed << HW_ATL_MPI_SPEED_SHIFT) | state); val = val & ~HW_ATL_MPI_STATE_MSK;
val |= state & HW_ATL_MPI_STATE_MSK;
err_exit:;
}
static int hw_atl_utils_mpi_set_state(struct aq_hw_s *self,
enum hal_atl_utils_fw_state_e state)
{
u32 val = aq_hw_read_reg(self, HW_ATL_MPI_CONTROL_ADR);
val = state | (val & HW_ATL_MPI_SPEED_MSK);
aq_hw_write_reg(self, HW_ATL_MPI_CONTROL_ADR, val); aq_hw_write_reg(self, HW_ATL_MPI_CONTROL_ADR, val);
return 0; err_exit:
return err;
} }
int hw_atl_utils_mpi_get_link_status(struct aq_hw_s *self) int hw_atl_utils_mpi_get_link_status(struct aq_hw_s *self)
...@@ -721,16 +723,18 @@ void hw_atl_utils_hw_chip_features_init(struct aq_hw_s *self, u32 *p) ...@@ -721,16 +723,18 @@ void hw_atl_utils_hw_chip_features_init(struct aq_hw_s *self, u32 *p)
*p = chip_features; *p = chip_features;
} }
int hw_atl_utils_hw_deinit(struct aq_hw_s *self) static int hw_atl_fw1x_deinit(struct aq_hw_s *self)
{ {
hw_atl_utils_mpi_set(self, MPI_DEINIT, 0x0U); hw_atl_utils_mpi_set_speed(self, 0);
hw_atl_utils_mpi_set_state(self, MPI_DEINIT);
return 0; return 0;
} }
int hw_atl_utils_hw_set_power(struct aq_hw_s *self, int hw_atl_utils_hw_set_power(struct aq_hw_s *self,
unsigned int power_state) unsigned int power_state)
{ {
hw_atl_utils_mpi_set(self, MPI_POWER, 0x0U); hw_atl_utils_mpi_set_speed(self, 0);
hw_atl_utils_mpi_set_state(self, MPI_POWER);
return 0; return 0;
} }
...@@ -823,10 +827,12 @@ int hw_atl_utils_get_fw_version(struct aq_hw_s *self, u32 *fw_version) ...@@ -823,10 +827,12 @@ int hw_atl_utils_get_fw_version(struct aq_hw_s *self, u32 *fw_version)
const struct aq_fw_ops aq_fw_1x_ops = { const struct aq_fw_ops aq_fw_1x_ops = {
.init = hw_atl_utils_mpi_create, .init = hw_atl_utils_mpi_create,
.deinit = hw_atl_fw1x_deinit,
.reset = NULL, .reset = NULL,
.get_mac_permanent = hw_atl_utils_get_mac_permanent, .get_mac_permanent = hw_atl_utils_get_mac_permanent,
.set_link_speed = hw_atl_utils_mpi_set_speed, .set_link_speed = hw_atl_utils_mpi_set_speed,
.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,
.set_flow_control = NULL,
}; };
...@@ -239,6 +239,41 @@ enum hw_atl_fw2x_caps_hi { ...@@ -239,6 +239,41 @@ enum hw_atl_fw2x_caps_hi {
CAPS_HI_TRANSACTION_ID, CAPS_HI_TRANSACTION_ID,
}; };
enum hw_atl_fw2x_ctrl {
CTRL_RESERVED1 = 0x00,
CTRL_RESERVED2,
CTRL_RESERVED3,
CTRL_PAUSE,
CTRL_ASYMMETRIC_PAUSE,
CTRL_RESERVED4,
CTRL_RESERVED5,
CTRL_RESERVED6,
CTRL_1GBASET_FD_EEE,
CTRL_2P5GBASET_FD_EEE,
CTRL_5GBASET_FD_EEE,
CTRL_10GBASET_FD_EEE,
CTRL_THERMAL_SHUTDOWN,
CTRL_PHY_LOGS,
CTRL_EEE_AUTO_DISABLE,
CTRL_PFC,
CTRL_WAKE_ON_LINK,
CTRL_CABLE_DIAG,
CTRL_TEMPERATURE,
CTRL_DOWNSHIFT,
CTRL_PTP_AVB,
CTRL_RESERVED7,
CTRL_LINK_DROP,
CTRL_SLEEP_PROXY,
CTRL_WOL,
CTRL_MAC_STOP,
CTRL_EXT_LOOPBACK,
CTRL_INT_LOOPBACK,
CTRL_RESERVED8,
CTRL_WOL_TIMER,
CTRL_STATISTICS,
CTRL_FORCE_RECONNECT,
};
struct aq_hw_s; struct aq_hw_s;
struct aq_fw_ops; struct aq_fw_ops;
struct aq_hw_caps_s; struct aq_hw_caps_s;
......
...@@ -28,6 +28,10 @@ ...@@ -28,6 +28,10 @@
#define HW_ATL_FW2X_MPI_STATE_ADDR 0x370 #define HW_ATL_FW2X_MPI_STATE_ADDR 0x370
#define HW_ATL_FW2X_MPI_STATE2_ADDR 0x374 #define HW_ATL_FW2X_MPI_STATE2_ADDR 0x374
static int aq_fw2x_set_link_speed(struct aq_hw_s *self, u32 speed);
static int aq_fw2x_set_state(struct aq_hw_s *self,
enum hal_atl_utils_fw_state_e state);
static int aq_fw2x_init(struct aq_hw_s *self) static int aq_fw2x_init(struct aq_hw_s *self)
{ {
int err = 0; int err = 0;
...@@ -39,6 +43,16 @@ static int aq_fw2x_init(struct aq_hw_s *self) ...@@ -39,6 +43,16 @@ static int aq_fw2x_init(struct aq_hw_s *self)
return err; return err;
} }
static int aq_fw2x_deinit(struct aq_hw_s *self)
{
int err = aq_fw2x_set_link_speed(self, 0);
if (!err)
err = aq_fw2x_set_state(self, MPI_DEINIT);
return err;
}
static enum hw_atl_fw2x_rate link_speed_mask_2fw2x_ratemask(u32 speed) static enum hw_atl_fw2x_rate link_speed_mask_2fw2x_ratemask(u32 speed)
{ {
enum hw_atl_fw2x_rate rate = 0; enum hw_atl_fw2x_rate rate = 0;
...@@ -73,10 +87,38 @@ static int aq_fw2x_set_link_speed(struct aq_hw_s *self, u32 speed) ...@@ -73,10 +87,38 @@ static int aq_fw2x_set_link_speed(struct aq_hw_s *self, u32 speed)
return 0; return 0;
} }
static void aq_fw2x_set_mpi_flow_control(struct aq_hw_s *self, u32 *mpi_state)
{
if (self->aq_nic_cfg->flow_control & AQ_NIC_FC_RX)
*mpi_state |= BIT(CAPS_HI_PAUSE);
else
*mpi_state &= ~BIT(CAPS_HI_PAUSE);
if (self->aq_nic_cfg->flow_control & AQ_NIC_FC_TX)
*mpi_state |= BIT(CAPS_HI_ASYMMETRIC_PAUSE);
else
*mpi_state &= ~BIT(CAPS_HI_ASYMMETRIC_PAUSE);
}
static int aq_fw2x_set_state(struct aq_hw_s *self, static int aq_fw2x_set_state(struct aq_hw_s *self,
enum hal_atl_utils_fw_state_e state) enum hal_atl_utils_fw_state_e state)
{ {
/* No explicit state in 2x fw */ u32 mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
switch (state) {
case MPI_INIT:
mpi_state &= ~BIT(CAPS_HI_LINK_DROP);
aq_fw2x_set_mpi_flow_control(self, &mpi_state);
break;
case MPI_DEINIT:
mpi_state |= BIT(CAPS_HI_LINK_DROP);
break;
case MPI_RESET:
case MPI_POWER:
/* No actions */
break;
}
aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_state);
return 0; return 0;
} }
...@@ -173,12 +215,37 @@ static int aq_fw2x_update_stats(struct aq_hw_s *self) ...@@ -173,12 +215,37 @@ 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_renegotiate(struct aq_hw_s *self)
{
u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
mpi_opts |= BIT(CTRL_FORCE_RECONNECT);
aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
return 0;
}
static int aq_fw2x_set_flow_control(struct aq_hw_s *self)
{
u32 mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
aq_fw2x_set_mpi_flow_control(self, &mpi_state);
aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_state);
return 0;
}
const struct aq_fw_ops aq_fw_2x_ops = { const struct aq_fw_ops aq_fw_2x_ops = {
.init = aq_fw2x_init, .init = aq_fw2x_init,
.deinit = aq_fw2x_deinit,
.reset = NULL, .reset = NULL,
.renegotiate = aq_fw2x_renegotiate,
.get_mac_permanent = aq_fw2x_get_mac_permanent, .get_mac_permanent = aq_fw2x_get_mac_permanent,
.set_link_speed = aq_fw2x_set_link_speed, .set_link_speed = aq_fw2x_set_link_speed,
.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,
.set_flow_control = aq_fw2x_set_flow_control,
}; };
...@@ -12,8 +12,8 @@ ...@@ -12,8 +12,8 @@
#define NIC_MAJOR_DRIVER_VERSION 2 #define NIC_MAJOR_DRIVER_VERSION 2
#define NIC_MINOR_DRIVER_VERSION 0 #define NIC_MINOR_DRIVER_VERSION 0
#define NIC_BUILD_DRIVER_VERSION 2 #define NIC_BUILD_DRIVER_VERSION 3
#define NIC_REVISION_DRIVER_VERSION 1 #define NIC_REVISION_DRIVER_VERSION 0
#define AQ_CFG_DRV_VERSION_SUFFIX "-kern" #define AQ_CFG_DRV_VERSION_SUFFIX "-kern"
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册