diff options
author | Dmitry Bogdanov <dbogdanov@marvell.com> | 2020-06-22 17:53:08 +0300 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2020-06-23 07:10:22 +0300 |
commit | 2b53b04de3b185ada35155e668a24a68f6a753ba (patch) | |
tree | 4b34d19af11e736dd8ffca5a7001bec7e0437df7 /drivers/net/ethernet/aquantia | |
parent | 3e168de529b14edd13c6842ff7bd415f25672db8 (diff) | |
download | linux-2b53b04de3b185ada35155e668a24a68f6a753ba.tar.xz |
net: atlantic: A2: report link partner capabilities
This patch adds link partner capabilities reporting support on A2.
In particular, the following capabilities are available for reporting:
* link rate;
* EEE;
* flow control.
Signed-off-by: Dmitry Bogdanov <dbogdanov@marvell.com>
Signed-off-by: Mark Starovoytov <mstarovoitov@marvell.com>
Signed-off-by: Igor Russkikh <irusskikh@marvell.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/aquantia')
-rw-r--r-- | drivers/net/ethernet/aquantia/atlantic/aq_hw.h | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/aquantia/atlantic/aq_nic.c | 49 | ||||
-rw-r--r-- | drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils_fw.c | 30 |
3 files changed, 81 insertions, 0 deletions
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h index 1408a522eff1..f2663ad22209 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h @@ -71,6 +71,8 @@ struct aq_hw_caps_s { struct aq_hw_link_status_s { unsigned int mbps; bool full_duplex; + u32 lp_link_speed_msk; + u32 lp_flow_control; }; struct aq_stats_s { diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c index 49528fcdc947..647b22d89b1a 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c @@ -935,6 +935,8 @@ static void aq_nic_update_ndev_stats(struct aq_nic_s *self) void aq_nic_get_link_ksettings(struct aq_nic_s *self, struct ethtool_link_ksettings *cmd) { + u32 lp_link_speed_msk; + if (self->aq_nic_cfg.aq_hw_caps->media_type == AQ_HW_MEDIA_TYPE_FIBRE) cmd->base.port = PORT_FIBRE; else @@ -1053,6 +1055,53 @@ void aq_nic_get_link_ksettings(struct aq_nic_s *self, ethtool_link_ksettings_add_link_mode(cmd, advertising, FIBRE); else ethtool_link_ksettings_add_link_mode(cmd, advertising, TP); + + ethtool_link_ksettings_zero_link_mode(cmd, lp_advertising); + lp_link_speed_msk = self->aq_hw->aq_link_status.lp_link_speed_msk; + + if (lp_link_speed_msk & AQ_NIC_RATE_10G) + ethtool_link_ksettings_add_link_mode(cmd, lp_advertising, + 10000baseT_Full); + + if (lp_link_speed_msk & AQ_NIC_RATE_5G) + ethtool_link_ksettings_add_link_mode(cmd, lp_advertising, + 5000baseT_Full); + + if (lp_link_speed_msk & AQ_NIC_RATE_2G5) + ethtool_link_ksettings_add_link_mode(cmd, lp_advertising, + 2500baseT_Full); + + if (lp_link_speed_msk & AQ_NIC_RATE_1G) + ethtool_link_ksettings_add_link_mode(cmd, lp_advertising, + 1000baseT_Full); + + if (lp_link_speed_msk & AQ_NIC_RATE_1G_HALF) + ethtool_link_ksettings_add_link_mode(cmd, lp_advertising, + 1000baseT_Half); + + if (lp_link_speed_msk & AQ_NIC_RATE_100M) + ethtool_link_ksettings_add_link_mode(cmd, lp_advertising, + 100baseT_Full); + + if (lp_link_speed_msk & AQ_NIC_RATE_100M_HALF) + ethtool_link_ksettings_add_link_mode(cmd, lp_advertising, + 100baseT_Half); + + if (lp_link_speed_msk & AQ_NIC_RATE_10M) + ethtool_link_ksettings_add_link_mode(cmd, lp_advertising, + 10baseT_Full); + + if (lp_link_speed_msk & AQ_NIC_RATE_10M_HALF) + ethtool_link_ksettings_add_link_mode(cmd, lp_advertising, + 10baseT_Half); + + if (self->aq_hw->aq_link_status.lp_flow_control & AQ_NIC_FC_RX) + ethtool_link_ksettings_add_link_mode(cmd, lp_advertising, + Pause); + if (!!(self->aq_hw->aq_link_status.lp_flow_control & AQ_NIC_FC_TX) ^ + !!(self->aq_hw->aq_link_status.lp_flow_control & AQ_NIC_FC_RX)) + ethtool_link_ksettings_add_link_mode(cmd, lp_advertising, + Asym_Pause); } int aq_nic_set_link_ksettings(struct aq_nic_s *self, diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils_fw.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils_fw.c index 0edcc0253b2e..c5d1a1404042 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils_fw.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils_fw.c @@ -164,6 +164,27 @@ static u32 a2_fw_lkp_to_mask(struct lkp_link_caps_s *lkp_link_caps) { u32 rate = 0; + if (lkp_link_caps->rate_10G) + rate |= AQ_NIC_RATE_10G; + if (lkp_link_caps->rate_5G) + rate |= AQ_NIC_RATE_5G; + if (lkp_link_caps->rate_N5G) + rate |= AQ_NIC_RATE_5GSR; + if (lkp_link_caps->rate_2P5G) + rate |= AQ_NIC_RATE_2G5; + if (lkp_link_caps->rate_1G) + rate |= AQ_NIC_RATE_1G; + if (lkp_link_caps->rate_1G_hd) + rate |= AQ_NIC_RATE_1G_HALF; + if (lkp_link_caps->rate_100M) + rate |= AQ_NIC_RATE_100M; + if (lkp_link_caps->rate_100M_hd) + rate |= AQ_NIC_RATE_100M_HALF; + if (lkp_link_caps->rate_10M) + rate |= AQ_NIC_RATE_10M; + if (lkp_link_caps->rate_10M_hd) + rate |= AQ_NIC_RATE_10M_HALF; + if (lkp_link_caps->eee_10G) rate |= AQ_NIC_RATE_EEE_10G; if (lkp_link_caps->eee_5G) @@ -240,6 +261,7 @@ static int aq_a2_fw_set_state(struct aq_hw_s *self, static int aq_a2_fw_update_link_status(struct aq_hw_s *self) { + struct lkp_link_caps_s lkp_link_caps; struct link_status_s link_status; hw_atl2_shared_buffer_read(self, link_status, link_status); @@ -268,6 +290,14 @@ static int aq_a2_fw_update_link_status(struct aq_hw_s *self) } self->aq_link_status.full_duplex = link_status.duplex; + hw_atl2_shared_buffer_read(self, lkp_link_caps, lkp_link_caps); + + self->aq_link_status.lp_link_speed_msk = + a2_fw_lkp_to_mask(&lkp_link_caps); + self->aq_link_status.lp_flow_control = + ((lkp_link_caps.pause_rx) ? AQ_NIC_FC_RX : 0) | + ((lkp_link_caps.pause_tx) ? AQ_NIC_FC_TX : 0); + return 0; } |