Commit 071a0204 authored by Igor Russkikh's avatar Igor Russkikh Committed by David S. Miller

net: atlantic: A2: half duplex support

This patch adds support for 10M/100M/1G half duplex rates, which are
supported by A2 in additional to full duplex rates supported by A1.
Signed-off-by: default avatarIgor Russkikh <irusskikh@marvell.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 29cb9868
...@@ -58,11 +58,14 @@ ...@@ -58,11 +58,14 @@
#define AQ_NIC_RATE_1G BIT(4) #define AQ_NIC_RATE_1G BIT(4)
#define AQ_NIC_RATE_100M BIT(5) #define AQ_NIC_RATE_100M BIT(5)
#define AQ_NIC_RATE_10M BIT(6) #define AQ_NIC_RATE_10M BIT(6)
#define AQ_NIC_RATE_1G_HALF BIT(7)
#define AQ_NIC_RATE_100M_HALF BIT(8)
#define AQ_NIC_RATE_10M_HALF BIT(9)
#define AQ_NIC_RATE_EEE_10G BIT(7) #define AQ_NIC_RATE_EEE_10G BIT(10)
#define AQ_NIC_RATE_EEE_5G BIT(8) #define AQ_NIC_RATE_EEE_5G BIT(11)
#define AQ_NIC_RATE_EEE_2G5 BIT(9) #define AQ_NIC_RATE_EEE_2G5 BIT(12)
#define AQ_NIC_RATE_EEE_1G BIT(10) #define AQ_NIC_RATE_EEE_1G BIT(13)
#define AQ_NIC_RATE_EEE_100M BIT(11) #define AQ_NIC_RATE_EEE_100M BIT(14)
#endif /* AQ_COMMON_H */ #endif /* AQ_COMMON_H */
/* SPDX-License-Identifier: GPL-2.0-only */ /* SPDX-License-Identifier: GPL-2.0-only */
/* /* Atlantic Network Driver
* aQuantia Corporation Network Driver *
* Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved * Copyright (C) 2014-2019 aQuantia Corporation
* Copyright (C) 2019-2020 Marvell International Ltd.
*/ */
/* File aq_hw.h: Declaration of abstract interface for NIC hardware specific /* File aq_hw.h: Declaration of abstract interface for NIC hardware specific
...@@ -69,6 +70,7 @@ struct aq_hw_caps_s { ...@@ -69,6 +70,7 @@ struct aq_hw_caps_s {
struct aq_hw_link_status_s { struct aq_hw_link_status_s {
unsigned int mbps; unsigned int mbps;
bool full_duplex;
}; };
struct aq_stats_s { struct aq_stats_s {
......
...@@ -939,8 +939,11 @@ void aq_nic_get_link_ksettings(struct aq_nic_s *self, ...@@ -939,8 +939,11 @@ void aq_nic_get_link_ksettings(struct aq_nic_s *self,
cmd->base.port = PORT_FIBRE; cmd->base.port = PORT_FIBRE;
else else
cmd->base.port = PORT_TP; cmd->base.port = PORT_TP;
/* This driver supports only 10G capable adapters, so DUPLEX_FULL */
cmd->base.duplex = DUPLEX_FULL; cmd->base.duplex = DUPLEX_UNKNOWN;
if (self->link_status.mbps)
cmd->base.duplex = self->link_status.full_duplex ?
DUPLEX_FULL : DUPLEX_HALF;
cmd->base.autoneg = self->aq_nic_cfg.is_autoneg; cmd->base.autoneg = self->aq_nic_cfg.is_autoneg;
ethtool_link_ksettings_zero_link_mode(cmd, supported); ethtool_link_ksettings_zero_link_mode(cmd, supported);
...@@ -961,14 +964,26 @@ void aq_nic_get_link_ksettings(struct aq_nic_s *self, ...@@ -961,14 +964,26 @@ void aq_nic_get_link_ksettings(struct aq_nic_s *self,
ethtool_link_ksettings_add_link_mode(cmd, supported, ethtool_link_ksettings_add_link_mode(cmd, supported,
1000baseT_Full); 1000baseT_Full);
if (self->aq_nic_cfg.aq_hw_caps->link_speed_msk & AQ_NIC_RATE_1G_HALF)
ethtool_link_ksettings_add_link_mode(cmd, supported,
1000baseT_Half);
if (self->aq_nic_cfg.aq_hw_caps->link_speed_msk & AQ_NIC_RATE_100M) if (self->aq_nic_cfg.aq_hw_caps->link_speed_msk & AQ_NIC_RATE_100M)
ethtool_link_ksettings_add_link_mode(cmd, supported, ethtool_link_ksettings_add_link_mode(cmd, supported,
100baseT_Full); 100baseT_Full);
if (self->aq_nic_cfg.aq_hw_caps->link_speed_msk & AQ_NIC_RATE_100M_HALF)
ethtool_link_ksettings_add_link_mode(cmd, supported,
100baseT_Half);
if (self->aq_nic_cfg.aq_hw_caps->link_speed_msk & AQ_NIC_RATE_10M) if (self->aq_nic_cfg.aq_hw_caps->link_speed_msk & AQ_NIC_RATE_10M)
ethtool_link_ksettings_add_link_mode(cmd, supported, ethtool_link_ksettings_add_link_mode(cmd, supported,
10baseT_Full); 10baseT_Full);
if (self->aq_nic_cfg.aq_hw_caps->link_speed_msk & AQ_NIC_RATE_10M_HALF)
ethtool_link_ksettings_add_link_mode(cmd, supported,
10baseT_Half);
if (self->aq_nic_cfg.aq_hw_caps->flow_control) { if (self->aq_nic_cfg.aq_hw_caps->flow_control) {
ethtool_link_ksettings_add_link_mode(cmd, supported, ethtool_link_ksettings_add_link_mode(cmd, supported,
Pause); Pause);
...@@ -988,30 +1003,42 @@ void aq_nic_get_link_ksettings(struct aq_nic_s *self, ...@@ -988,30 +1003,42 @@ void aq_nic_get_link_ksettings(struct aq_nic_s *self,
if (self->aq_nic_cfg.is_autoneg) if (self->aq_nic_cfg.is_autoneg)
ethtool_link_ksettings_add_link_mode(cmd, advertising, Autoneg); ethtool_link_ksettings_add_link_mode(cmd, advertising, Autoneg);
if (self->aq_nic_cfg.link_speed_msk & AQ_NIC_RATE_10G) if (self->aq_nic_cfg.link_speed_msk & AQ_NIC_RATE_10G)
ethtool_link_ksettings_add_link_mode(cmd, advertising, ethtool_link_ksettings_add_link_mode(cmd, advertising,
10000baseT_Full); 10000baseT_Full);
if (self->aq_nic_cfg.link_speed_msk & AQ_NIC_RATE_5G) if (self->aq_nic_cfg.link_speed_msk & AQ_NIC_RATE_5G)
ethtool_link_ksettings_add_link_mode(cmd, advertising, ethtool_link_ksettings_add_link_mode(cmd, advertising,
5000baseT_Full); 5000baseT_Full);
if (self->aq_nic_cfg.link_speed_msk & AQ_NIC_RATE_2G5) if (self->aq_nic_cfg.link_speed_msk & AQ_NIC_RATE_2G5)
ethtool_link_ksettings_add_link_mode(cmd, advertising, ethtool_link_ksettings_add_link_mode(cmd, advertising,
2500baseT_Full); 2500baseT_Full);
if (self->aq_nic_cfg.link_speed_msk & AQ_NIC_RATE_1G) if (self->aq_nic_cfg.link_speed_msk & AQ_NIC_RATE_1G)
ethtool_link_ksettings_add_link_mode(cmd, advertising, ethtool_link_ksettings_add_link_mode(cmd, advertising,
1000baseT_Full); 1000baseT_Full);
if (self->aq_nic_cfg.link_speed_msk & AQ_NIC_RATE_100M) if (self->aq_nic_cfg.link_speed_msk & AQ_NIC_RATE_1G_HALF)
ethtool_link_ksettings_add_link_mode(cmd, advertising,
1000baseT_Half);
if (self->aq_nic_cfg.link_speed_msk & AQ_NIC_RATE_100M)
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.link_speed_msk & AQ_NIC_RATE_10M) if (self->aq_nic_cfg.link_speed_msk & AQ_NIC_RATE_100M_HALF)
ethtool_link_ksettings_add_link_mode(cmd, advertising,
100baseT_Half);
if (self->aq_nic_cfg.link_speed_msk & AQ_NIC_RATE_10M)
ethtool_link_ksettings_add_link_mode(cmd, advertising, ethtool_link_ksettings_add_link_mode(cmd, advertising,
10baseT_Full); 10baseT_Full);
if (self->aq_nic_cfg.link_speed_msk & AQ_NIC_RATE_10M_HALF)
ethtool_link_ksettings_add_link_mode(cmd, advertising,
10baseT_Half);
if (self->aq_nic_cfg.fc.cur & AQ_NIC_FC_RX) if (self->aq_nic_cfg.fc.cur & AQ_NIC_FC_RX)
ethtool_link_ksettings_add_link_mode(cmd, advertising, ethtool_link_ksettings_add_link_mode(cmd, advertising,
Pause); Pause);
...@@ -1031,27 +1058,32 @@ void aq_nic_get_link_ksettings(struct aq_nic_s *self, ...@@ -1031,27 +1058,32 @@ void aq_nic_get_link_ksettings(struct aq_nic_s *self,
int aq_nic_set_link_ksettings(struct aq_nic_s *self, int aq_nic_set_link_ksettings(struct aq_nic_s *self,
const struct ethtool_link_ksettings *cmd) const struct ethtool_link_ksettings *cmd)
{ {
u32 speed = 0U; int fduplex = (cmd->base.duplex == DUPLEX_FULL);
u32 speed = cmd->base.speed;
u32 rate = 0U; u32 rate = 0U;
int err = 0; int err = 0;
if (!fduplex && speed > SPEED_1000) {
err = -EINVAL;
goto err_exit;
}
if (cmd->base.autoneg == AUTONEG_ENABLE) { if (cmd->base.autoneg == AUTONEG_ENABLE) {
rate = self->aq_nic_cfg.aq_hw_caps->link_speed_msk; rate = self->aq_nic_cfg.aq_hw_caps->link_speed_msk;
self->aq_nic_cfg.is_autoneg = true; self->aq_nic_cfg.is_autoneg = true;
} else { } else {
speed = cmd->base.speed;
switch (speed) { switch (speed) {
case SPEED_10: case SPEED_10:
rate = AQ_NIC_RATE_10M; rate = fduplex ? AQ_NIC_RATE_10M : AQ_NIC_RATE_10M_HALF;
break; break;
case SPEED_100: case SPEED_100:
rate = AQ_NIC_RATE_100M; rate = fduplex ? AQ_NIC_RATE_100M
: AQ_NIC_RATE_100M_HALF;
break; break;
case SPEED_1000: case SPEED_1000:
rate = AQ_NIC_RATE_1G; rate = fduplex ? AQ_NIC_RATE_1G : AQ_NIC_RATE_1G_HALF;
break; break;
case SPEED_2500: case SPEED_2500:
......
...@@ -704,6 +704,7 @@ int hw_atl_utils_mpi_get_link_status(struct aq_hw_s *self) ...@@ -704,6 +704,7 @@ int hw_atl_utils_mpi_get_link_status(struct aq_hw_s *self)
return -EBUSY; return -EBUSY;
} }
} }
link_status->full_duplex = true;
return 0; return 0;
} }
......
...@@ -274,6 +274,7 @@ static int aq_fw2x_update_link_status(struct aq_hw_s *self) ...@@ -274,6 +274,7 @@ static int aq_fw2x_update_link_status(struct aq_hw_s *self)
} else { } else {
link_status->mbps = 0; link_status->mbps = 0;
} }
link_status->full_duplex = true;
return 0; return 0;
} }
......
...@@ -64,8 +64,11 @@ const struct aq_hw_caps_s hw_atl2_caps_aqc113 = { ...@@ -64,8 +64,11 @@ const struct aq_hw_caps_s hw_atl2_caps_aqc113 = {
AQ_NIC_RATE_5G | AQ_NIC_RATE_5G |
AQ_NIC_RATE_2G5 | AQ_NIC_RATE_2G5 |
AQ_NIC_RATE_1G | AQ_NIC_RATE_1G |
AQ_NIC_RATE_1G_HALF |
AQ_NIC_RATE_100M | AQ_NIC_RATE_100M |
AQ_NIC_RATE_10M, AQ_NIC_RATE_100M_HALF |
AQ_NIC_RATE_10M |
AQ_NIC_RATE_10M_HALF,
}; };
static u32 hw_atl2_sem_act_rslvr_get(struct aq_hw_s *self) static u32 hw_atl2_sem_act_rslvr_get(struct aq_hw_s *self)
......
...@@ -135,6 +135,10 @@ static void a2_link_speed_mask2fw(u32 speed, ...@@ -135,6 +135,10 @@ static void a2_link_speed_mask2fw(u32 speed,
link_options->rate_1G = !!(speed & AQ_NIC_RATE_1G); link_options->rate_1G = !!(speed & AQ_NIC_RATE_1G);
link_options->rate_100M = !!(speed & AQ_NIC_RATE_100M); link_options->rate_100M = !!(speed & AQ_NIC_RATE_100M);
link_options->rate_10M = !!(speed & AQ_NIC_RATE_10M); link_options->rate_10M = !!(speed & AQ_NIC_RATE_10M);
link_options->rate_1G_hd = !!(speed & AQ_NIC_RATE_1G_HALF);
link_options->rate_100M_hd = !!(speed & AQ_NIC_RATE_100M_HALF);
link_options->rate_10M_hd = !!(speed & AQ_NIC_RATE_10M_HALF);
} }
static int aq_a2_fw_set_link_speed(struct aq_hw_s *self, u32 speed) static int aq_a2_fw_set_link_speed(struct aq_hw_s *self, u32 speed)
...@@ -202,6 +206,7 @@ static int aq_a2_fw_update_link_status(struct aq_hw_s *self) ...@@ -202,6 +206,7 @@ static int aq_a2_fw_update_link_status(struct aq_hw_s *self)
default: default:
self->aq_link_status.mbps = 0; self->aq_link_status.mbps = 0;
} }
self->aq_link_status.full_duplex = link_status.duplex;
return 0; return 0;
} }
......
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