aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/drivers/net/ethernet/aquantia/atlantic/hw_atl2
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ethernet/aquantia/atlantic/hw_atl2')
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2.c10
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils.c3
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils_fw.c227
3 files changed, 233 insertions, 7 deletions
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2.c
index 8df9d4ef36f0..92f64048bf69 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2.c
@@ -21,6 +21,7 @@ static int hw_atl2_act_rslvr_table_set(struct aq_hw_s *self, u8 location,
#define DEFAULT_BOARD_BASIC_CAPABILITIES \
.is_64_dma = true, \
+ .op64bit = true, \
.msix_irqs = 8U, \
.irq_mask = ~0U, \
.vecs = HW_ATL2_RSS_MAX, \
@@ -64,8 +65,11 @@ const struct aq_hw_caps_s hw_atl2_caps_aqc113 = {
AQ_NIC_RATE_5G |
AQ_NIC_RATE_2G5 |
AQ_NIC_RATE_1G |
+ AQ_NIC_RATE_1G_HALF |
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)
@@ -178,6 +182,8 @@ static int hw_atl2_hw_qos_set(struct aq_hw_s *self)
threshold = (rx_buff_size * (1024U / 32U) * 50U) / 100U;
hw_atl_rpb_rx_buff_lo_threshold_per_tc_set(self, threshold, tc);
+
+ hw_atl_b0_set_fc(self, self->aq_nic_cfg->fc.req, tc);
}
/* QoS 802.1p priority -> TC mapping */
@@ -838,4 +844,6 @@ const struct aq_hw_ops hw_atl2_ops = {
.hw_get_hw_stats = hw_atl2_utils_get_hw_stats,
.hw_get_fw_version = hw_atl2_utils_get_fw_version,
.hw_set_offload = hw_atl_b0_hw_offload_set,
+ .hw_set_loopback = hw_atl_b0_set_loopback,
+ .hw_set_fc = hw_atl_b0_set_fc,
};
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils.c
index f3766780e975..0fe6257d9c08 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils.c
@@ -36,8 +36,7 @@ int hw_atl2_utils_initfw(struct aq_hw_s *self, const struct aq_fw_ops **fw_ops)
self->fw_ver_actual = hw_atl2_utils_get_fw_version(self);
- if (hw_atl_utils_ver_match(HW_ATL2_FW_VER_1X,
- self->fw_ver_actual) == 0) {
+ if (hw_atl_utils_ver_match(HW_ATL2_FW_VER_1X, self->fw_ver_actual)) {
*fw_ops = &aq_a2_fw_ops;
} else {
aq_pr_err("Bad FW version detected: %x, but continue\n",
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 0ffc33bd67d0..85628acbcc1d 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
@@ -7,6 +7,7 @@
#include "aq_hw.h"
#include "aq_hw_utils.h"
+#include "aq_nic.h"
#include "hw_atl/hw_atl_llh.h"
#include "hw_atl2_utils.h"
#include "hw_atl2_llh.h"
@@ -15,15 +16,29 @@
#define AQ_A2_FW_READ_TRY_MAX 1000
#define hw_atl2_shared_buffer_write(HW, ITEM, VARIABLE) \
+{\
+ BUILD_BUG_ON_MSG((offsetof(struct fw_interface_in, ITEM) % \
+ sizeof(u32)) != 0,\
+ "Unaligned write " # ITEM);\
+ BUILD_BUG_ON_MSG((sizeof(VARIABLE) % sizeof(u32)) != 0,\
+ "Unaligned write length " # ITEM);\
hw_atl2_mif_shared_buf_write(HW,\
(offsetof(struct fw_interface_in, ITEM) / sizeof(u32)),\
- (u32 *)&(VARIABLE), sizeof(VARIABLE) / sizeof(u32))
+ (u32 *)&(VARIABLE), sizeof(VARIABLE) / sizeof(u32));\
+}
#define hw_atl2_shared_buffer_get(HW, ITEM, VARIABLE) \
+{\
+ BUILD_BUG_ON_MSG((offsetof(struct fw_interface_in, ITEM) % \
+ sizeof(u32)) != 0,\
+ "Unaligned get " # ITEM);\
+ BUILD_BUG_ON_MSG((sizeof(VARIABLE) % sizeof(u32)) != 0,\
+ "Unaligned get length " # ITEM);\
hw_atl2_mif_shared_buf_get(HW, \
(offsetof(struct fw_interface_in, ITEM) / sizeof(u32)),\
(u32 *)&(VARIABLE), \
- sizeof(VARIABLE) / sizeof(u32))
+ sizeof(VARIABLE) / sizeof(u32));\
+}
/* This should never be used on non atomic fields,
* treat any > u32 read as non atomic.
@@ -32,7 +47,9 @@
{\
BUILD_BUG_ON_MSG((offsetof(struct fw_interface_out, ITEM) % \
sizeof(u32)) != 0,\
- "Non aligned read " # ITEM);\
+ "Unaligned read " # ITEM);\
+ BUILD_BUG_ON_MSG((sizeof(VARIABLE) % sizeof(u32)) != 0,\
+ "Unaligned read length " # ITEM);\
BUILD_BUG_ON_MSG(sizeof(VARIABLE) > sizeof(u32),\
"Non atomic read " # ITEM);\
hw_atl2_mif_shared_buf_read(HW, \
@@ -41,10 +58,18 @@
}
#define hw_atl2_shared_buffer_read_safe(HW, ITEM, DATA) \
+({\
+ BUILD_BUG_ON_MSG((offsetof(struct fw_interface_out, ITEM) % \
+ sizeof(u32)) != 0,\
+ "Unaligned read_safe " # ITEM);\
+ BUILD_BUG_ON_MSG((sizeof(((struct fw_interface_out *)0)->ITEM) % \
+ sizeof(u32)) != 0,\
+ "Unaligned read_safe length " # ITEM);\
hw_atl2_shared_buffer_read_block((HW), \
(offsetof(struct fw_interface_out, ITEM) / sizeof(u32)),\
sizeof(((struct fw_interface_out *)0)->ITEM) / sizeof(u32),\
- (DATA))
+ (DATA));\
+})
static int hw_atl2_shared_buffer_read_block(struct aq_hw_s *self,
u32 offset, u32 dwords, void *data)
@@ -135,6 +160,67 @@ static void a2_link_speed_mask2fw(u32 speed,
link_options->rate_1G = !!(speed & AQ_NIC_RATE_1G);
link_options->rate_100M = !!(speed & AQ_NIC_RATE_100M);
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 u32 a2_fw_dev_to_eee_mask(struct device_link_caps_s *device_link_caps)
+{
+ u32 rate = 0;
+
+ if (device_link_caps->eee_10G)
+ rate |= AQ_NIC_RATE_EEE_10G;
+ if (device_link_caps->eee_5G)
+ rate |= AQ_NIC_RATE_EEE_5G;
+ if (device_link_caps->eee_2P5G)
+ rate |= AQ_NIC_RATE_EEE_2G5;
+ if (device_link_caps->eee_1G)
+ rate |= AQ_NIC_RATE_EEE_1G;
+ if (device_link_caps->eee_100M)
+ rate |= AQ_NIC_RATE_EEE_100M;
+
+ return rate;
+}
+
+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)
+ rate |= AQ_NIC_RATE_EEE_5G;
+ if (lkp_link_caps->eee_2P5G)
+ rate |= AQ_NIC_RATE_EEE_2G5;
+ if (lkp_link_caps->eee_1G)
+ rate |= AQ_NIC_RATE_EEE_1G;
+ if (lkp_link_caps->eee_100M)
+ rate |= AQ_NIC_RATE_EEE_100M;
+
+ return rate;
}
static int aq_a2_fw_set_link_speed(struct aq_hw_s *self, u32 speed)
@@ -149,6 +235,26 @@ static int aq_a2_fw_set_link_speed(struct aq_hw_s *self, u32 speed)
return hw_atl2_shared_buffer_finish_ack(self);
}
+static void aq_a2_fw_set_mpi_flow_control(struct aq_hw_s *self,
+ struct link_options_s *link_options)
+{
+ u32 flow_control = self->aq_nic_cfg->fc.req;
+
+ link_options->pause_rx = !!(flow_control & AQ_NIC_FC_RX);
+ link_options->pause_tx = !!(flow_control & AQ_NIC_FC_TX);
+}
+
+static void aq_a2_fw_upd_eee_rate_bits(struct aq_hw_s *self,
+ struct link_options_s *link_options,
+ u32 eee_speeds)
+{
+ link_options->eee_10G = !!(eee_speeds & AQ_NIC_RATE_EEE_10G);
+ link_options->eee_5G = !!(eee_speeds & AQ_NIC_RATE_EEE_5G);
+ link_options->eee_2P5G = !!(eee_speeds & AQ_NIC_RATE_EEE_2G5);
+ link_options->eee_1G = !!(eee_speeds & AQ_NIC_RATE_EEE_1G);
+ link_options->eee_100M = !!(eee_speeds & AQ_NIC_RATE_EEE_100M);
+}
+
static int aq_a2_fw_set_state(struct aq_hw_s *self,
enum hal_atl_utils_fw_state_e state)
{
@@ -159,6 +265,9 @@ static int aq_a2_fw_set_state(struct aq_hw_s *self,
switch (state) {
case MPI_INIT:
link_options.link_up = 1U;
+ aq_a2_fw_upd_eee_rate_bits(self, &link_options,
+ self->aq_nic_cfg->eee_speeds);
+ aq_a2_fw_set_mpi_flow_control(self, &link_options);
break;
case MPI_DEINIT:
link_options.link_up = 0U;
@@ -176,6 +285,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);
@@ -202,6 +312,15 @@ static int aq_a2_fw_update_link_status(struct aq_hw_s *self)
default:
self->aq_link_status.mbps = 0;
}
+ 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;
}
@@ -260,6 +379,53 @@ static int aq_a2_fw_update_stats(struct aq_hw_s *self)
return 0;
}
+static int aq_a2_fw_get_phy_temp(struct aq_hw_s *self, int *temp)
+{
+ struct phy_health_monitor_s phy_health_monitor;
+
+ hw_atl2_shared_buffer_read_safe(self, phy_health_monitor,
+ &phy_health_monitor);
+
+ *temp = (int8_t)phy_health_monitor.phy_temperature * 1000;
+ return 0;
+}
+
+static int aq_a2_fw_get_mac_temp(struct aq_hw_s *self, int *temp)
+{
+ /* There's only one temperature sensor on A2, use it for
+ * both MAC and PHY.
+ */
+ return aq_a2_fw_get_phy_temp(self, temp);
+}
+
+static int aq_a2_fw_set_eee_rate(struct aq_hw_s *self, u32 speed)
+{
+ struct link_options_s link_options;
+
+ hw_atl2_shared_buffer_get(self, link_options, link_options);
+
+ aq_a2_fw_upd_eee_rate_bits(self, &link_options, speed);
+
+ hw_atl2_shared_buffer_write(self, link_options, link_options);
+
+ return hw_atl2_shared_buffer_finish_ack(self);
+}
+
+static int aq_a2_fw_get_eee_rate(struct aq_hw_s *self, u32 *rate,
+ u32 *supported_rates)
+{
+ struct device_link_caps_s device_link_caps;
+ struct lkp_link_caps_s lkp_link_caps;
+
+ hw_atl2_shared_buffer_read(self, device_link_caps, device_link_caps);
+ hw_atl2_shared_buffer_read(self, lkp_link_caps, lkp_link_caps);
+
+ *supported_rates = a2_fw_dev_to_eee_mask(&device_link_caps);
+ *rate = a2_fw_lkp_to_mask(&lkp_link_caps);
+
+ return 0;
+}
+
static int aq_a2_fw_renegotiate(struct aq_hw_s *self)
{
struct link_options_s link_options;
@@ -280,6 +446,52 @@ static int aq_a2_fw_renegotiate(struct aq_hw_s *self)
return err;
}
+static int aq_a2_fw_set_flow_control(struct aq_hw_s *self)
+{
+ struct link_options_s link_options;
+
+ hw_atl2_shared_buffer_get(self, link_options, link_options);
+
+ aq_a2_fw_set_mpi_flow_control(self, &link_options);
+
+ hw_atl2_shared_buffer_write(self, link_options, link_options);
+
+ return hw_atl2_shared_buffer_finish_ack(self);
+}
+
+static u32 aq_a2_fw_get_flow_control(struct aq_hw_s *self, u32 *fcmode)
+{
+ struct link_status_s link_status;
+
+ hw_atl2_shared_buffer_read(self, link_status, link_status);
+
+ *fcmode = ((link_status.pause_rx) ? AQ_NIC_FC_RX : 0) |
+ ((link_status.pause_tx) ? AQ_NIC_FC_TX : 0);
+ return 0;
+}
+
+static int aq_a2_fw_set_phyloopback(struct aq_hw_s *self, u32 mode, bool enable)
+{
+ struct link_options_s link_options;
+
+ hw_atl2_shared_buffer_get(self, link_options, link_options);
+
+ switch (mode) {
+ case AQ_HW_LOOPBACK_PHYINT_SYS:
+ link_options.internal_loopback = enable;
+ break;
+ case AQ_HW_LOOPBACK_PHYEXT_SYS:
+ link_options.external_loopback = enable;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ hw_atl2_shared_buffer_write(self, link_options, link_options);
+
+ return hw_atl2_shared_buffer_finish_ack(self);
+}
+
u32 hw_atl2_utils_get_fw_version(struct aq_hw_s *self)
{
struct version_s version;
@@ -317,4 +529,11 @@ const struct aq_fw_ops aq_a2_fw_ops = {
.set_state = aq_a2_fw_set_state,
.update_link_status = aq_a2_fw_update_link_status,
.update_stats = aq_a2_fw_update_stats,
+ .get_mac_temp = aq_a2_fw_get_mac_temp,
+ .get_phy_temp = aq_a2_fw_get_phy_temp,
+ .set_eee_rate = aq_a2_fw_set_eee_rate,
+ .get_eee_rate = aq_a2_fw_get_eee_rate,
+ .set_flow_control = aq_a2_fw_set_flow_control,
+ .get_flow_control = aq_a2_fw_get_flow_control,
+ .set_phyloopback = aq_a2_fw_set_phyloopback,
};