Commit 80de556a authored by David S. Miller's avatar David S. Miller

Merge branch 'aquantia-implement-WOL-and-EEE-support'

Igor Russkikh says:

====================
net: aquantia: implement WOL and EEE support

This is v3 of WOL/EEE functionality patch for atlantic driver.

In this patchset Yana Esina and Nikita Danilov implemented:

- Upload function to interact with FW memory
- Definitions and structures necessary for the correct operation of Wake ON Lan
- The functionality Wake On Lan via ethtool (Magic packet is supported)
- The functionality for Energy-Efficient Ethernet configuration via ethtool

Version 3:
- use ETH_ALEN instead of raw number

Version 2 has the following fixes:
- patchset reorganized to extract renaming and whitespace fixes into separate
  patches
- some of magic numbers replaced with defines
- reverse christmas tree applied
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 82bcee42 85e55db7
...@@ -57,4 +57,9 @@ ...@@ -57,4 +57,9 @@
#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_EEE_10G BIT(6)
#define AQ_NIC_RATE_EEE_5G BIT(7)
#define AQ_NIC_RATE_EEE_2GS BIT(8)
#define AQ_NIC_RATE_EEE_1G BIT(9)
#endif /* AQ_COMMON_H */ #endif /* AQ_COMMON_H */
...@@ -285,6 +285,111 @@ static int aq_ethtool_set_coalesce(struct net_device *ndev, ...@@ -285,6 +285,111 @@ 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 void aq_ethtool_get_wol(struct net_device *ndev,
struct ethtool_wolinfo *wol)
{
struct aq_nic_s *aq_nic = netdev_priv(ndev);
struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic);
wol->supported = WAKE_MAGIC;
wol->wolopts = 0;
if (cfg->wol)
wol->wolopts |= WAKE_MAGIC;
}
static int aq_ethtool_set_wol(struct net_device *ndev,
struct ethtool_wolinfo *wol)
{
struct pci_dev *pdev = to_pci_dev(ndev->dev.parent);
struct aq_nic_s *aq_nic = netdev_priv(ndev);
struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic);
int err = 0;
if (wol->wolopts & WAKE_MAGIC)
cfg->wol |= AQ_NIC_WOL_ENABLED;
else
cfg->wol &= ~AQ_NIC_WOL_ENABLED;
err = device_set_wakeup_enable(&pdev->dev, wol->wolopts);
return err;
}
static enum hw_atl_fw2x_rate eee_mask_to_ethtool_mask(u32 speed)
{
u32 rate = 0;
if (speed & AQ_NIC_RATE_EEE_10G)
rate |= SUPPORTED_10000baseT_Full;
if (speed & AQ_NIC_RATE_EEE_2GS)
rate |= SUPPORTED_2500baseX_Full;
if (speed & AQ_NIC_RATE_EEE_1G)
rate |= SUPPORTED_1000baseT_Full;
return rate;
}
static int aq_ethtool_get_eee(struct net_device *ndev, struct ethtool_eee *eee)
{
struct aq_nic_s *aq_nic = netdev_priv(ndev);
u32 rate, supported_rates;
int err = 0;
if (!aq_nic->aq_fw_ops->get_eee_rate)
return -EOPNOTSUPP;
err = aq_nic->aq_fw_ops->get_eee_rate(aq_nic->aq_hw, &rate,
&supported_rates);
if (err < 0)
return err;
eee->supported = eee_mask_to_ethtool_mask(supported_rates);
if (aq_nic->aq_nic_cfg.eee_speeds)
eee->advertised = eee->supported;
eee->lp_advertised = eee_mask_to_ethtool_mask(rate);
eee->eee_enabled = !!eee->advertised;
eee->tx_lpi_enabled = eee->eee_enabled;
if (eee->advertised & eee->lp_advertised)
eee->eee_active = true;
return 0;
}
static int aq_ethtool_set_eee(struct net_device *ndev, struct ethtool_eee *eee)
{
struct aq_nic_s *aq_nic = netdev_priv(ndev);
u32 rate, supported_rates;
struct aq_nic_cfg_s *cfg;
int err = 0;
cfg = aq_nic_get_cfg(aq_nic);
if (unlikely(!aq_nic->aq_fw_ops->get_eee_rate ||
!aq_nic->aq_fw_ops->set_eee_rate))
return -EOPNOTSUPP;
err = aq_nic->aq_fw_ops->get_eee_rate(aq_nic->aq_hw, &rate,
&supported_rates);
if (err < 0)
return err;
if (eee->eee_enabled) {
rate = supported_rates;
cfg->eee_speeds = rate;
} else {
rate = 0;
cfg->eee_speeds = 0;
}
return aq_nic->aq_fw_ops->set_eee_rate(aq_nic->aq_hw, rate);
}
static int aq_ethtool_nway_reset(struct net_device *ndev) static int aq_ethtool_nway_reset(struct net_device *ndev)
{ {
struct aq_nic_s *aq_nic = netdev_priv(ndev); struct aq_nic_s *aq_nic = netdev_priv(ndev);
...@@ -403,9 +508,13 @@ const struct ethtool_ops aq_ethtool_ops = { ...@@ -403,9 +508,13 @@ 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,
.get_wol = aq_ethtool_get_wol,
.set_wol = aq_ethtool_set_wol,
.nway_reset = aq_ethtool_nway_reset, .nway_reset = aq_ethtool_nway_reset,
.get_ringparam = aq_get_ringparam, .get_ringparam = aq_get_ringparam,
.set_ringparam = aq_set_ringparam, .set_ringparam = aq_set_ringparam,
.get_eee = aq_ethtool_get_eee,
.set_eee = aq_ethtool_set_eee,
.get_pauseparam = aq_ethtool_get_pauseparam, .get_pauseparam = aq_ethtool_get_pauseparam,
.set_pauseparam = aq_ethtool_set_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,
......
...@@ -112,7 +112,7 @@ struct aq_hw_s { ...@@ -112,7 +112,7 @@ struct aq_hw_s {
const struct aq_fw_ops *aq_fw_ops; const struct aq_fw_ops *aq_fw_ops;
void __iomem *mmio; void __iomem *mmio;
struct aq_hw_link_status_s aq_link_status; struct aq_hw_link_status_s aq_link_status;
struct hw_aq_atl_utils_mbox mbox; struct hw_atl_utils_mbox mbox;
struct hw_atl_stats_s last_stats; struct hw_atl_stats_s last_stats;
struct aq_stats_s curr_stats; struct aq_stats_s curr_stats;
u64 speed; u64 speed;
...@@ -124,7 +124,7 @@ struct aq_hw_s { ...@@ -124,7 +124,7 @@ struct aq_hw_s {
u32 mbox_addr; u32 mbox_addr;
u32 rpc_addr; u32 rpc_addr;
u32 rpc_tid; u32 rpc_tid;
struct hw_aq_atl_utils_fw_rpc rpc; struct hw_atl_utils_fw_rpc rpc;
}; };
struct aq_ring_s; struct aq_ring_s;
...@@ -204,7 +204,6 @@ struct aq_hw_ops { ...@@ -204,7 +204,6 @@ 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_set_power)(struct aq_hw_s *self, unsigned int power_state);
}; };
struct aq_fw_ops { struct aq_fw_ops {
...@@ -228,6 +227,14 @@ struct aq_fw_ops { ...@@ -228,6 +227,14 @@ struct aq_fw_ops {
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); int (*set_flow_control)(struct aq_hw_s *self);
int (*set_power)(struct aq_hw_s *self, unsigned int power_state,
u8 *mac);
int (*set_eee_rate)(struct aq_hw_s *self, u32 speed);
int (*get_eee_rate)(struct aq_hw_s *self, u32 *rate,
u32 *supported_rates);
}; };
#endif /* AQ_HW_H */ #endif /* AQ_HW_H */
...@@ -889,11 +889,13 @@ void aq_nic_deinit(struct aq_nic_s *self) ...@@ -889,11 +889,13 @@ void aq_nic_deinit(struct aq_nic_s *self)
self->aq_vecs > i; ++i, aq_vec = self->aq_vec[i]) self->aq_vecs > i; ++i, aq_vec = self->aq_vec[i])
aq_vec_deinit(aq_vec); aq_vec_deinit(aq_vec);
if (self->power_state == AQ_HW_POWER_STATE_D0) { self->aq_fw_ops->deinit(self->aq_hw);
(void)self->aq_fw_ops->deinit(self->aq_hw);
} else { if (self->power_state != AQ_HW_POWER_STATE_D0 ||
(void)self->aq_hw_ops->hw_set_power(self->aq_hw, self->aq_hw->aq_nic_cfg->wol) {
self->power_state); self->aq_fw_ops->set_power(self->aq_hw,
self->power_state,
self->ndev->dev_addr);
} }
err_exit:; err_exit:;
......
...@@ -36,6 +36,7 @@ struct aq_nic_cfg_s { ...@@ -36,6 +36,7 @@ struct aq_nic_cfg_s {
u32 flow_control; u32 flow_control;
u32 link_speed_msk; u32 link_speed_msk;
u32 vlan_id; u32 vlan_id;
u32 wol;
u16 is_mc_list_enabled; u16 is_mc_list_enabled;
u16 mc_list_count; u16 mc_list_count;
bool is_autoneg; bool is_autoneg;
...@@ -44,6 +45,7 @@ struct aq_nic_cfg_s { ...@@ -44,6 +45,7 @@ struct aq_nic_cfg_s {
bool is_lro; bool is_lro;
u8 tcs; u8 tcs;
struct aq_rss_parameters aq_rss; struct aq_rss_parameters aq_rss;
u32 eee_speeds;
}; };
#define AQ_NIC_FLAG_STARTED 0x00000004U #define AQ_NIC_FLAG_STARTED 0x00000004U
...@@ -54,6 +56,8 @@ struct aq_nic_cfg_s { ...@@ -54,6 +56,8 @@ struct aq_nic_cfg_s {
#define AQ_NIC_FLAG_ERR_UNPLUG 0x40000000U #define AQ_NIC_FLAG_ERR_UNPLUG 0x40000000U
#define AQ_NIC_FLAG_ERR_HW 0x80000000U #define AQ_NIC_FLAG_ERR_HW 0x80000000U
#define AQ_NIC_WOL_ENABLED BIT(0)
#define AQ_NIC_TCVEC2RING(_NIC_, _TC_, _VEC_) \ #define AQ_NIC_TCVEC2RING(_NIC_, _TC_, _VEC_) \
((_TC_) * AQ_CFG_TCS_MAX + (_VEC_)) ((_TC_) * AQ_CFG_TCS_MAX + (_VEC_))
......
...@@ -49,37 +49,37 @@ ...@@ -49,37 +49,37 @@
const struct aq_hw_caps_s hw_atl_a0_caps_aqc100 = { const struct aq_hw_caps_s hw_atl_a0_caps_aqc100 = {
DEFAULT_A0_BOARD_BASIC_CAPABILITIES, DEFAULT_A0_BOARD_BASIC_CAPABILITIES,
.media_type = AQ_HW_MEDIA_TYPE_FIBRE, .media_type = AQ_HW_MEDIA_TYPE_FIBRE,
.link_speed_msk = HW_ATL_A0_RATE_5G | .link_speed_msk = AQ_NIC_RATE_5G |
HW_ATL_A0_RATE_2G5 | AQ_NIC_RATE_2GS |
HW_ATL_A0_RATE_1G | AQ_NIC_RATE_1G |
HW_ATL_A0_RATE_100M, AQ_NIC_RATE_100M,
}; };
const struct aq_hw_caps_s hw_atl_a0_caps_aqc107 = { const struct aq_hw_caps_s hw_atl_a0_caps_aqc107 = {
DEFAULT_A0_BOARD_BASIC_CAPABILITIES, DEFAULT_A0_BOARD_BASIC_CAPABILITIES,
.media_type = AQ_HW_MEDIA_TYPE_TP, .media_type = AQ_HW_MEDIA_TYPE_TP,
.link_speed_msk = HW_ATL_A0_RATE_10G | .link_speed_msk = AQ_NIC_RATE_10G |
HW_ATL_A0_RATE_5G | AQ_NIC_RATE_5G |
HW_ATL_A0_RATE_2G5 | AQ_NIC_RATE_2GS |
HW_ATL_A0_RATE_1G | AQ_NIC_RATE_1G |
HW_ATL_A0_RATE_100M, AQ_NIC_RATE_100M,
}; };
const struct aq_hw_caps_s hw_atl_a0_caps_aqc108 = { const struct aq_hw_caps_s hw_atl_a0_caps_aqc108 = {
DEFAULT_A0_BOARD_BASIC_CAPABILITIES, DEFAULT_A0_BOARD_BASIC_CAPABILITIES,
.media_type = AQ_HW_MEDIA_TYPE_TP, .media_type = AQ_HW_MEDIA_TYPE_TP,
.link_speed_msk = HW_ATL_A0_RATE_5G | .link_speed_msk = AQ_NIC_RATE_5G |
HW_ATL_A0_RATE_2G5 | AQ_NIC_RATE_2GS |
HW_ATL_A0_RATE_1G | AQ_NIC_RATE_1G |
HW_ATL_A0_RATE_100M, AQ_NIC_RATE_100M,
}; };
const struct aq_hw_caps_s hw_atl_a0_caps_aqc109 = { const struct aq_hw_caps_s hw_atl_a0_caps_aqc109 = {
DEFAULT_A0_BOARD_BASIC_CAPABILITIES, DEFAULT_A0_BOARD_BASIC_CAPABILITIES,
.media_type = AQ_HW_MEDIA_TYPE_TP, .media_type = AQ_HW_MEDIA_TYPE_TP,
.link_speed_msk = HW_ATL_A0_RATE_2G5 | .link_speed_msk = AQ_NIC_RATE_2GS |
HW_ATL_A0_RATE_1G | AQ_NIC_RATE_1G |
HW_ATL_A0_RATE_100M, AQ_NIC_RATE_100M,
}; };
static int hw_atl_a0_hw_reset(struct aq_hw_s *self) static int hw_atl_a0_hw_reset(struct aq_hw_s *self)
...@@ -877,7 +877,6 @@ static int hw_atl_a0_hw_ring_rx_stop(struct aq_hw_s *self, ...@@ -877,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_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,
.hw_ring_tx_start = hw_atl_a0_hw_ring_tx_start, .hw_ring_tx_start = hw_atl_a0_hw_ring_tx_start,
......
...@@ -62,12 +62,6 @@ ...@@ -62,12 +62,6 @@
#define HW_ATL_A0_MPI_SPEED_MSK 0xFFFFU #define HW_ATL_A0_MPI_SPEED_MSK 0xFFFFU
#define HW_ATL_A0_MPI_SPEED_SHIFT 16U #define HW_ATL_A0_MPI_SPEED_SHIFT 16U
#define HW_ATL_A0_RATE_10G BIT(0)
#define HW_ATL_A0_RATE_5G BIT(1)
#define HW_ATL_A0_RATE_2G5 BIT(3)
#define HW_ATL_A0_RATE_1G BIT(4)
#define HW_ATL_A0_RATE_100M BIT(5)
#define HW_ATL_A0_TXBUF_MAX 160U #define HW_ATL_A0_TXBUF_MAX 160U
#define HW_ATL_A0_RXBUF_MAX 320U #define HW_ATL_A0_RXBUF_MAX 320U
......
...@@ -51,38 +51,38 @@ ...@@ -51,38 +51,38 @@
const struct aq_hw_caps_s hw_atl_b0_caps_aqc100 = { const struct aq_hw_caps_s hw_atl_b0_caps_aqc100 = {
DEFAULT_B0_BOARD_BASIC_CAPABILITIES, DEFAULT_B0_BOARD_BASIC_CAPABILITIES,
.media_type = AQ_HW_MEDIA_TYPE_FIBRE, .media_type = AQ_HW_MEDIA_TYPE_FIBRE,
.link_speed_msk = HW_ATL_B0_RATE_10G | .link_speed_msk = AQ_NIC_RATE_10G |
HW_ATL_B0_RATE_5G | AQ_NIC_RATE_5G |
HW_ATL_B0_RATE_2G5 | AQ_NIC_RATE_2GS |
HW_ATL_B0_RATE_1G | AQ_NIC_RATE_1G |
HW_ATL_B0_RATE_100M, AQ_NIC_RATE_100M,
}; };
const struct aq_hw_caps_s hw_atl_b0_caps_aqc107 = { const struct aq_hw_caps_s hw_atl_b0_caps_aqc107 = {
DEFAULT_B0_BOARD_BASIC_CAPABILITIES, DEFAULT_B0_BOARD_BASIC_CAPABILITIES,
.media_type = AQ_HW_MEDIA_TYPE_TP, .media_type = AQ_HW_MEDIA_TYPE_TP,
.link_speed_msk = HW_ATL_B0_RATE_10G | .link_speed_msk = AQ_NIC_RATE_10G |
HW_ATL_B0_RATE_5G | AQ_NIC_RATE_5G |
HW_ATL_B0_RATE_2G5 | AQ_NIC_RATE_2GS |
HW_ATL_B0_RATE_1G | AQ_NIC_RATE_1G |
HW_ATL_B0_RATE_100M, AQ_NIC_RATE_100M,
}; };
const struct aq_hw_caps_s hw_atl_b0_caps_aqc108 = { const struct aq_hw_caps_s hw_atl_b0_caps_aqc108 = {
DEFAULT_B0_BOARD_BASIC_CAPABILITIES, DEFAULT_B0_BOARD_BASIC_CAPABILITIES,
.media_type = AQ_HW_MEDIA_TYPE_TP, .media_type = AQ_HW_MEDIA_TYPE_TP,
.link_speed_msk = HW_ATL_B0_RATE_5G | .link_speed_msk = AQ_NIC_RATE_5G |
HW_ATL_B0_RATE_2G5 | AQ_NIC_RATE_2GS |
HW_ATL_B0_RATE_1G | AQ_NIC_RATE_1G |
HW_ATL_B0_RATE_100M, AQ_NIC_RATE_100M,
}; };
const struct aq_hw_caps_s hw_atl_b0_caps_aqc109 = { const struct aq_hw_caps_s hw_atl_b0_caps_aqc109 = {
DEFAULT_B0_BOARD_BASIC_CAPABILITIES, DEFAULT_B0_BOARD_BASIC_CAPABILITIES,
.media_type = AQ_HW_MEDIA_TYPE_TP, .media_type = AQ_HW_MEDIA_TYPE_TP,
.link_speed_msk = HW_ATL_B0_RATE_2G5 | .link_speed_msk = AQ_NIC_RATE_2GS |
HW_ATL_B0_RATE_1G | AQ_NIC_RATE_1G |
HW_ATL_B0_RATE_100M, AQ_NIC_RATE_100M,
}; };
static int hw_atl_b0_hw_reset(struct aq_hw_s *self) static int hw_atl_b0_hw_reset(struct aq_hw_s *self)
...@@ -935,7 +935,6 @@ static int hw_atl_b0_hw_ring_rx_stop(struct aq_hw_s *self, ...@@ -935,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_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,
.hw_ring_tx_start = hw_atl_b0_hw_ring_tx_start, .hw_ring_tx_start = hw_atl_b0_hw_ring_tx_start,
......
...@@ -67,12 +67,6 @@ ...@@ -67,12 +67,6 @@
#define HW_ATL_B0_MPI_SPEED_MSK 0xFFFFU #define HW_ATL_B0_MPI_SPEED_MSK 0xFFFFU
#define HW_ATL_B0_MPI_SPEED_SHIFT 16U #define HW_ATL_B0_MPI_SPEED_SHIFT 16U
#define HW_ATL_B0_RATE_10G BIT(0)
#define HW_ATL_B0_RATE_5G BIT(1)
#define HW_ATL_B0_RATE_2G5 BIT(3)
#define HW_ATL_B0_RATE_1G BIT(4)
#define HW_ATL_B0_RATE_100M BIT(5)
#define HW_ATL_B0_TXBUF_MAX 160U #define HW_ATL_B0_TXBUF_MAX 160U
#define HW_ATL_B0_RXBUF_MAX 320U #define HW_ATL_B0_RXBUF_MAX 320U
......
...@@ -1460,3 +1460,11 @@ void hw_atl_reg_glb_cpu_scratch_scp_set(struct aq_hw_s *aq_hw, ...@@ -1460,3 +1460,11 @@ void hw_atl_reg_glb_cpu_scratch_scp_set(struct aq_hw_s *aq_hw,
aq_hw_write_reg(aq_hw, HW_ATL_GLB_CPU_SCRATCH_SCP_ADR(scratch_scp), aq_hw_write_reg(aq_hw, HW_ATL_GLB_CPU_SCRATCH_SCP_ADR(scratch_scp),
glb_cpu_scratch_scp); glb_cpu_scratch_scp);
} }
void hw_atl_mcp_up_force_intr_set(struct aq_hw_s *aq_hw, u32 up_force_intr)
{
aq_hw_write_reg_bit(aq_hw, HW_ATL_MCP_UP_FORCE_INTERRUPT_ADR,
HW_ATL_MCP_UP_FORCE_INTERRUPT_MSK,
HW_ATL_MCP_UP_FORCE_INTERRUPT_SHIFT,
up_force_intr);
}
...@@ -698,4 +698,7 @@ void hw_atl_msm_reg_wr_strobe_set(struct aq_hw_s *aq_hw, u32 reg_wr_strobe); ...@@ -698,4 +698,7 @@ void hw_atl_msm_reg_wr_strobe_set(struct aq_hw_s *aq_hw, u32 reg_wr_strobe);
/* set pci register reset disable */ /* set pci register reset disable */
void hw_atl_pci_pci_reg_res_dis_set(struct aq_hw_s *aq_hw, u32 pci_reg_res_dis); void hw_atl_pci_pci_reg_res_dis_set(struct aq_hw_s *aq_hw, u32 pci_reg_res_dis);
/* set uP Force Interrupt */
void hw_atl_mcp_up_force_intr_set(struct aq_hw_s *aq_hw, u32 up_force_intr);
#endif /* HW_ATL_LLH_H */ #endif /* HW_ATL_LLH_H */
...@@ -2387,4 +2387,17 @@ ...@@ -2387,4 +2387,17 @@
#define HW_ATL_GLB_CPU_SCRATCH_SCP_ADR(scratch_scp) \ #define HW_ATL_GLB_CPU_SCRATCH_SCP_ADR(scratch_scp) \
(0x00000300u + (scratch_scp) * 0x4) (0x00000300u + (scratch_scp) * 0x4)
/* register address for bitfield uP Force Interrupt */
#define HW_ATL_MCP_UP_FORCE_INTERRUPT_ADR 0x00000404
/* bitmask for bitfield uP Force Interrupt */
#define HW_ATL_MCP_UP_FORCE_INTERRUPT_MSK 0x00000002
/* inverted bitmask for bitfield uP Force Interrupt */
#define HW_ATL_MCP_UP_FORCE_INTERRUPT_MSKN 0xFFFFFFFD
/* lower bit position of bitfield uP Force Interrupt */
#define HW_ATL_MCP_UP_FORCE_INTERRUPT_SHIFT 1
/* width of bitfield uP Force Interrupt */
#define HW_ATL_MCP_UP_FORCE_INTERRUPT_WIDTH 1
/* default value of bitfield uP Force Interrupt */
#define HW_ATL_MCP_UP_FORCE_INTERRUPT_DEFAULT 0x0
#endif /* HW_ATL_LLH_INTERNAL_H */ #endif /* HW_ATL_LLH_INTERNAL_H */
...@@ -49,6 +49,7 @@ ...@@ -49,6 +49,7 @@
#define FORCE_FLASHLESS 0 #define FORCE_FLASHLESS 0
static int hw_atl_utils_ver_match(u32 ver_expected, u32 ver_actual); static int hw_atl_utils_ver_match(u32 ver_expected, u32 ver_actual);
static int hw_atl_utils_mpi_set_state(struct aq_hw_s *self, static 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);
...@@ -325,17 +326,31 @@ static int hw_atl_utils_fw_upload_dwords(struct aq_hw_s *self, u32 a, u32 *p, ...@@ -325,17 +326,31 @@ static int hw_atl_utils_fw_upload_dwords(struct aq_hw_s *self, u32 a, u32 *p,
err = -ETIME; err = -ETIME;
goto err_exit; goto err_exit;
} }
if (IS_CHIP_FEATURE(REVISION_B1)) {
u32 offset = 0;
aq_hw_write_reg(self, 0x00000208U, a); for (; offset < cnt; ++offset) {
aq_hw_write_reg(self, 0x328, p[offset]);
aq_hw_write_reg(self, 0x32C,
(0x80000000 | (0xFFFF & (offset * 4))));
hw_atl_mcp_up_force_intr_set(self, 1);
/* 1000 times by 10us = 10ms */
AQ_HW_WAIT_FOR((aq_hw_read_reg(self,
0x32C) & 0xF0000000) !=
0x80000000,
10, 1000);
}
} else {
u32 offset = 0;
for (++cnt; --cnt;) { aq_hw_write_reg(self, 0x208, a);
u32 i = 0U;
aq_hw_write_reg(self, 0x0000020CU, *(p++)); for (; offset < cnt; ++offset) {
aq_hw_write_reg(self, 0x00000200U, 0xC000U); aq_hw_write_reg(self, 0x20C, p[offset]);
aq_hw_write_reg(self, 0x200, 0xC000);
for (i = 1024U; AQ_HW_WAIT_FOR((aq_hw_read_reg(self, 0x200U) &
(0x100U & aq_hw_read_reg(self, 0x00000200U)) && --i;) { 0x100) == 0, 10, 1000);
} }
} }
...@@ -399,7 +414,7 @@ struct aq_hw_atl_utils_fw_rpc_tid_s { ...@@ -399,7 +414,7 @@ struct aq_hw_atl_utils_fw_rpc_tid_s {
#define hw_atl_utils_fw_rpc_init(_H_) hw_atl_utils_fw_rpc_wait(_H_, NULL) #define hw_atl_utils_fw_rpc_init(_H_) hw_atl_utils_fw_rpc_wait(_H_, NULL)
static int hw_atl_utils_fw_rpc_call(struct aq_hw_s *self, unsigned int rpc_size) int hw_atl_utils_fw_rpc_call(struct aq_hw_s *self, unsigned int rpc_size)
{ {
int err = 0; int err = 0;
struct aq_hw_atl_utils_fw_rpc_tid_s sw; struct aq_hw_atl_utils_fw_rpc_tid_s sw;
...@@ -423,8 +438,8 @@ static int hw_atl_utils_fw_rpc_call(struct aq_hw_s *self, unsigned int rpc_size) ...@@ -423,8 +438,8 @@ static int hw_atl_utils_fw_rpc_call(struct aq_hw_s *self, unsigned int rpc_size)
return err; return err;
} }
static int hw_atl_utils_fw_rpc_wait(struct aq_hw_s *self, int hw_atl_utils_fw_rpc_wait(struct aq_hw_s *self,
struct hw_aq_atl_utils_fw_rpc **rpc) struct hw_atl_utils_fw_rpc **rpc)
{ {
int err = 0; int err = 0;
struct aq_hw_atl_utils_fw_rpc_tid_s sw; struct aq_hw_atl_utils_fw_rpc_tid_s sw;
...@@ -489,7 +504,7 @@ static int hw_atl_utils_mpi_create(struct aq_hw_s *self) ...@@ -489,7 +504,7 @@ static int hw_atl_utils_mpi_create(struct aq_hw_s *self)
} }
int hw_atl_utils_mpi_read_mbox(struct aq_hw_s *self, int hw_atl_utils_mpi_read_mbox(struct aq_hw_s *self,
struct hw_aq_atl_utils_mbox_header *pmbox) struct hw_atl_utils_mbox_header *pmbox)
{ {
return hw_atl_utils_fw_downld_dwords(self, return hw_atl_utils_fw_downld_dwords(self,
self->mbox_addr, self->mbox_addr,
...@@ -498,7 +513,7 @@ int hw_atl_utils_mpi_read_mbox(struct aq_hw_s *self, ...@@ -498,7 +513,7 @@ int hw_atl_utils_mpi_read_mbox(struct aq_hw_s *self,
} }
void hw_atl_utils_mpi_read_stats(struct aq_hw_s *self, void hw_atl_utils_mpi_read_stats(struct aq_hw_s *self,
struct hw_aq_atl_utils_mbox *pmbox) struct hw_atl_utils_mbox *pmbox)
{ {
int err = 0; int err = 0;
...@@ -538,7 +553,7 @@ static int hw_atl_utils_mpi_set_state(struct aq_hw_s *self, ...@@ -538,7 +553,7 @@ static int hw_atl_utils_mpi_set_state(struct aq_hw_s *self,
{ {
int err = 0; int err = 0;
u32 transaction_id = 0; u32 transaction_id = 0;
struct hw_aq_atl_utils_mbox_header mbox; struct hw_atl_utils_mbox_header mbox;
u32 val = aq_hw_read_reg(self, HW_ATL_MPI_CONTROL_ADR); u32 val = aq_hw_read_reg(self, HW_ATL_MPI_CONTROL_ADR);
if (state == MPI_RESET) { if (state == MPI_RESET) {
...@@ -645,9 +660,9 @@ int hw_atl_utils_get_mac_permanent(struct aq_hw_s *self, ...@@ -645,9 +660,9 @@ int hw_atl_utils_get_mac_permanent(struct aq_hw_s *self,
if ((mac[0] & 0x01U) || ((mac[0] | mac[1] | mac[2]) == 0x00U)) { if ((mac[0] & 0x01U) || ((mac[0] | mac[1] | mac[2]) == 0x00U)) {
/* chip revision */ /* chip revision */
l = 0xE3000000U l = 0xE3000000U |
| (0xFFFFU & aq_hw_read_reg(self, HW_ATL_UCP_0X370_REG)) (0xFFFFU & aq_hw_read_reg(self, HW_ATL_UCP_0X370_REG)) |
| (0x00 << 16); (0x00 << 16);
h = 0x8001300EU; h = 0x8001300EU;
mac[5] = (u8)(0xFFU & l); mac[5] = (u8)(0xFFU & l);
...@@ -730,17 +745,9 @@ static int hw_atl_fw1x_deinit(struct aq_hw_s *self) ...@@ -730,17 +745,9 @@ static int hw_atl_fw1x_deinit(struct aq_hw_s *self)
return 0; return 0;
} }
int hw_atl_utils_hw_set_power(struct aq_hw_s *self,
unsigned int power_state)
{
hw_atl_utils_mpi_set_speed(self, 0);
hw_atl_utils_mpi_set_state(self, MPI_POWER);
return 0;
}
int hw_atl_utils_update_stats(struct aq_hw_s *self) int hw_atl_utils_update_stats(struct aq_hw_s *self)
{ {
struct hw_aq_atl_utils_mbox mbox; struct hw_atl_utils_mbox mbox;
hw_atl_utils_mpi_read_stats(self, &mbox); hw_atl_utils_mpi_read_stats(self, &mbox);
...@@ -825,6 +832,81 @@ int hw_atl_utils_get_fw_version(struct aq_hw_s *self, u32 *fw_version) ...@@ -825,6 +832,81 @@ int hw_atl_utils_get_fw_version(struct aq_hw_s *self, u32 *fw_version)
return 0; return 0;
} }
static int aq_fw1x_set_wol(struct aq_hw_s *self, bool wol_enabled, u8 *mac)
{
struct hw_atl_utils_fw_rpc *prpc = NULL;
unsigned int rpc_size = 0U;
int err = 0;
err = hw_atl_utils_fw_rpc_wait(self, &prpc);
if (err < 0)
goto err_exit;
memset(prpc, 0, sizeof(*prpc));
if (wol_enabled) {
rpc_size = sizeof(prpc->msg_id) + sizeof(prpc->msg_wol);
prpc->msg_id = HAL_ATLANTIC_UTILS_FW_MSG_WOL_ADD;
prpc->msg_wol.priority =
HAL_ATLANTIC_UTILS_FW_MSG_WOL_PRIOR;
prpc->msg_wol.pattern_id =
HAL_ATLANTIC_UTILS_FW_MSG_WOL_PATTERN;
prpc->msg_wol.wol_packet_type =
HAL_ATLANTIC_UTILS_FW_MSG_WOL_MAG_PKT;
ether_addr_copy((u8 *)&prpc->msg_wol.wol_pattern, mac);
} else {
rpc_size = sizeof(prpc->msg_id) + sizeof(prpc->msg_del_id);
prpc->msg_id = HAL_ATLANTIC_UTILS_FW_MSG_WOL_DEL;
prpc->msg_wol.pattern_id =
HAL_ATLANTIC_UTILS_FW_MSG_WOL_PATTERN;
}
err = hw_atl_utils_fw_rpc_call(self, rpc_size);
err_exit:
return err;
}
int aq_fw1x_set_power(struct aq_hw_s *self, unsigned int power_state,
u8 *mac)
{
struct hw_atl_utils_fw_rpc *prpc = NULL;
unsigned int rpc_size = 0U;
int err = 0;
if (self->aq_nic_cfg->wol & AQ_NIC_WOL_ENABLED) {
err = aq_fw1x_set_wol(self, 1, mac);
if (err < 0)
goto err_exit;
rpc_size = sizeof(prpc->msg_id) +
sizeof(prpc->msg_enable_wakeup);
err = hw_atl_utils_fw_rpc_wait(self, &prpc);
if (err < 0)
goto err_exit;
memset(prpc, 0, rpc_size);
prpc->msg_id = HAL_ATLANTIC_UTILS_FW_MSG_ENABLE_WAKEUP;
prpc->msg_enable_wakeup.pattern_mask = 0x00000002;
err = hw_atl_utils_fw_rpc_call(self, rpc_size);
if (err < 0)
goto err_exit;
}
hw_atl_utils_mpi_set_speed(self, 0);
hw_atl_utils_mpi_set_state(self, MPI_POWER);
err_exit:
return err;
}
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, .deinit = hw_atl_fw1x_deinit,
...@@ -834,5 +916,8 @@ const struct aq_fw_ops aq_fw_1x_ops = { ...@@ -834,5 +916,8 @@ const struct aq_fw_ops aq_fw_1x_ops = {
.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_power = aq_fw1x_set_power,
.set_eee_rate = NULL,
.get_eee_rate = NULL,
.set_flow_control = NULL, .set_flow_control = NULL,
}; };
...@@ -75,7 +75,7 @@ union __packed ip_addr { ...@@ -75,7 +75,7 @@ union __packed ip_addr {
} v4; } v4;
}; };
struct __packed hw_aq_atl_utils_fw_rpc { struct __packed hw_atl_utils_fw_rpc {
u32 msg_id; u32 msg_id;
union { union {
...@@ -101,8 +101,6 @@ struct __packed hw_aq_atl_utils_fw_rpc { ...@@ -101,8 +101,6 @@ struct __packed hw_aq_atl_utils_fw_rpc {
struct { struct {
u32 priority; u32 priority;
u32 wol_packet_type; u32 wol_packet_type;
u16 friendly_name_len;
u16 friendly_name[65];
u32 pattern_id; u32 pattern_id;
u32 next_wol_pattern_offset; u32 next_wol_pattern_offset;
...@@ -134,25 +132,112 @@ struct __packed hw_aq_atl_utils_fw_rpc { ...@@ -134,25 +132,112 @@ struct __packed hw_aq_atl_utils_fw_rpc {
u32 pattern_offset; u32 pattern_offset;
u32 pattern_size; u32 pattern_size;
} wol_bit_map_pattern; } wol_bit_map_pattern;
struct {
u8 mac_addr[ETH_ALEN];
} wol_magic_packet_patter;
} wol_pattern; } wol_pattern;
} msg_wol; } msg_wol;
struct { struct {
u32 is_wake_on_link_down; union {
u32 is_wake_on_link_up; u32 pattern_mask;
} msg_wolink;
struct {
u32 reason_arp_v4_pkt : 1;
u32 reason_ipv4_ping_pkt : 1;
u32 reason_ipv6_ns_pkt : 1;
u32 reason_ipv6_ping_pkt : 1;
u32 reason_link_up : 1;
u32 reason_link_down : 1;
u32 reason_maximum : 1;
};
};
union {
u32 offload_mask;
};
} msg_enable_wakeup;
struct {
u32 id;
} msg_del_id;
}; };
}; };
struct __packed hw_aq_atl_utils_mbox_header { struct __packed hw_atl_utils_mbox_header {
u32 version; u32 version;
u32 transaction_id; u32 transaction_id;
u32 error; u32 error;
}; };
struct __packed hw_aq_atl_utils_mbox { struct __packed hw_aq_info {
struct hw_aq_atl_utils_mbox_header header; u8 reserved[6];
u16 phy_fault_code;
u16 phy_temperature;
u8 cable_len;
u8 reserved1;
u32 cable_diag_data[4];
u8 reserved2[32];
u32 caps_lo;
u32 caps_hi;
};
struct __packed hw_atl_utils_mbox {
struct hw_atl_utils_mbox_header header;
struct hw_atl_stats_s stats; struct hw_atl_stats_s stats;
struct hw_aq_info info;
};
/* fw2x */
typedef u32 fw_offset_t;
struct __packed offload_ip_info {
u8 v4_local_addr_count;
u8 v4_addr_count;
u8 v6_local_addr_count;
u8 v6_addr_count;
fw_offset_t v4_addr;
fw_offset_t v4_prefix;
fw_offset_t v6_addr;
fw_offset_t v6_prefix;
};
struct __packed offload_port_info {
u16 udp_port_count;
u16 tcp_port_count;
fw_offset_t udp_port;
fw_offset_t tcp_port;
};
struct __packed offload_ka_info {
u16 v4_ka_count;
u16 v6_ka_count;
u32 retry_count;
u32 retry_interval;
fw_offset_t v4_ka;
fw_offset_t v6_ka;
};
struct __packed offload_rr_info {
u32 rr_count;
u32 rr_buf_len;
fw_offset_t rr_id_x;
fw_offset_t rr_buf;
};
struct __packed offload_info {
u32 version;
u32 len;
u8 mac_addr[ETH_ALEN];
u8 reserved[2];
struct offload_ip_info ips;
struct offload_port_info ports;
struct offload_ka_info kas;
struct offload_rr_info rrs;
u8 buf[0];
}; };
#define HAL_ATLANTIC_UTILS_CHIP_MIPS 0x00000001U #define HAL_ATLANTIC_UTILS_CHIP_MIPS 0x00000001U
...@@ -181,6 +266,21 @@ enum hal_atl_utils_fw_state_e { ...@@ -181,6 +266,21 @@ enum hal_atl_utils_fw_state_e {
#define HAL_ATLANTIC_RATE_100M BIT(5) #define HAL_ATLANTIC_RATE_100M BIT(5)
#define HAL_ATLANTIC_RATE_INVALID BIT(6) #define HAL_ATLANTIC_RATE_INVALID BIT(6)
#define HAL_ATLANTIC_UTILS_FW_MSG_PING 0x1U
#define HAL_ATLANTIC_UTILS_FW_MSG_ARP 0x2U
#define HAL_ATLANTIC_UTILS_FW_MSG_INJECT 0x3U
#define HAL_ATLANTIC_UTILS_FW_MSG_WOL_ADD 0x4U
#define HAL_ATLANTIC_UTILS_FW_MSG_WOL_PRIOR 0x10000000U
#define HAL_ATLANTIC_UTILS_FW_MSG_WOL_PATTERN 0x1U
#define HAL_ATLANTIC_UTILS_FW_MSG_WOL_MAG_PKT 0x2U
#define HAL_ATLANTIC_UTILS_FW_MSG_WOL_DEL 0x5U
#define HAL_ATLANTIC_UTILS_FW_MSG_ENABLE_WAKEUP 0x6U
#define HAL_ATLANTIC_UTILS_FW_MSG_MSM_PFC 0x7U
#define HAL_ATLANTIC_UTILS_FW_MSG_PROVISIONING 0x8U
#define HAL_ATLANTIC_UTILS_FW_MSG_OFFLOAD_ADD 0x9U
#define HAL_ATLANTIC_UTILS_FW_MSG_OFFLOAD_DEL 0xAU
#define HAL_ATLANTIC_UTILS_FW_MSG_CABLE_DIAG 0xDU
enum hw_atl_fw2x_rate { enum hw_atl_fw2x_rate {
FW2X_RATE_100M = 0x20, FW2X_RATE_100M = 0x20,
FW2X_RATE_1G = 0x100, FW2X_RATE_1G = 0x100,
...@@ -286,10 +386,10 @@ int hw_atl_utils_soft_reset(struct aq_hw_s *self); ...@@ -286,10 +386,10 @@ int hw_atl_utils_soft_reset(struct aq_hw_s *self);
void hw_atl_utils_hw_chip_features_init(struct aq_hw_s *self, u32 *p); void hw_atl_utils_hw_chip_features_init(struct aq_hw_s *self, u32 *p);
int hw_atl_utils_mpi_read_mbox(struct aq_hw_s *self, int hw_atl_utils_mpi_read_mbox(struct aq_hw_s *self,
struct hw_aq_atl_utils_mbox_header *pmbox); struct hw_atl_utils_mbox_header *pmbox);
void hw_atl_utils_mpi_read_stats(struct aq_hw_s *self, void hw_atl_utils_mpi_read_stats(struct aq_hw_s *self,
struct hw_aq_atl_utils_mbox *pmbox); struct hw_atl_utils_mbox *pmbox);
void hw_atl_utils_mpi_set(struct aq_hw_s *self, void hw_atl_utils_mpi_set(struct aq_hw_s *self,
enum hal_atl_utils_fw_state_e state, enum hal_atl_utils_fw_state_e state,
...@@ -316,9 +416,17 @@ int hw_atl_utils_get_fw_version(struct aq_hw_s *self, u32 *fw_version); ...@@ -316,9 +416,17 @@ int hw_atl_utils_get_fw_version(struct aq_hw_s *self, u32 *fw_version);
int hw_atl_utils_update_stats(struct aq_hw_s *self); int hw_atl_utils_update_stats(struct aq_hw_s *self);
struct aq_stats_s *hw_atl_utils_get_hw_stats(struct aq_hw_s *self); struct aq_stats_s *hw_atl_utils_get_hw_stats(struct aq_hw_s *self);
int hw_atl_utils_fw_downld_dwords(struct aq_hw_s *self, u32 a, int hw_atl_utils_fw_downld_dwords(struct aq_hw_s *self, u32 a,
u32 *p, u32 cnt); u32 *p, u32 cnt);
int hw_atl_utils_fw_set_wol(struct aq_hw_s *self, bool wol_enabled, u8 *mac);
int hw_atl_utils_fw_rpc_call(struct aq_hw_s *self, unsigned int rpc_size);
int hw_atl_utils_fw_rpc_wait(struct aq_hw_s *self,
struct hw_atl_utils_fw_rpc **rpc);
extern const struct aq_fw_ops aq_fw_1x_ops; extern const struct aq_fw_ops aq_fw_1x_ops;
extern const struct aq_fw_ops aq_fw_2x_ops; extern const struct aq_fw_ops aq_fw_2x_ops;
......
...@@ -16,11 +16,13 @@ ...@@ -16,11 +16,13 @@
#include "../aq_pci_func.h" #include "../aq_pci_func.h"
#include "../aq_ring.h" #include "../aq_ring.h"
#include "../aq_vec.h" #include "../aq_vec.h"
#include "../aq_nic.h"
#include "hw_atl_utils.h" #include "hw_atl_utils.h"
#include "hw_atl_llh.h" #include "hw_atl_llh.h"
#define HW_ATL_FW2X_MPI_EFUSE_ADDR 0x364 #define HW_ATL_FW2X_MPI_EFUSE_ADDR 0x364
#define HW_ATL_FW2X_MPI_MBOX_ADDR 0x360 #define HW_ATL_FW2X_MPI_MBOX_ADDR 0x360
#define HW_ATL_FW2X_MPI_RPC_ADDR 0x334
#define HW_ATL_FW2X_MPI_CONTROL_ADDR 0x368 #define HW_ATL_FW2X_MPI_CONTROL_ADDR 0x368
#define HW_ATL_FW2X_MPI_CONTROL2_ADDR 0x36C #define HW_ATL_FW2X_MPI_CONTROL2_ADDR 0x36C
...@@ -28,6 +30,42 @@ ...@@ -28,6 +30,42 @@
#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
#define HW_ATL_FW2X_CAP_SLEEP_PROXY BIT(CAPS_HI_SLEEP_PROXY)
#define HW_ATL_FW2X_CAP_WOL BIT(CAPS_HI_WOL)
#define HW_ATL_FW2X_CTRL_SLEEP_PROXY BIT(CTRL_SLEEP_PROXY)
#define HW_ATL_FW2X_CTRL_WOL BIT(CTRL_WOL)
#define HW_ATL_FW2X_CTRL_LINK_DROP BIT(CTRL_LINK_DROP)
#define HW_ATL_FW2X_CTRL_PAUSE BIT(CTRL_PAUSE)
#define HW_ATL_FW2X_CTRL_ASYMMETRIC_PAUSE BIT(CTRL_ASYMMETRIC_PAUSE)
#define HW_ATL_FW2X_CTRL_FORCE_RECONNECT BIT(CTRL_FORCE_RECONNECT)
#define HW_ATL_FW2X_CAP_EEE_1G_MASK BIT(CAPS_HI_1000BASET_FD_EEE)
#define HW_ATL_FW2X_CAP_EEE_2G5_MASK BIT(CAPS_HI_2P5GBASET_FD_EEE)
#define HW_ATL_FW2X_CAP_EEE_5G_MASK BIT(CAPS_HI_5GBASET_FD_EEE)
#define HW_ATL_FW2X_CAP_EEE_10G_MASK BIT(CAPS_HI_10GBASET_FD_EEE)
#define HAL_ATLANTIC_WOL_FILTERS_COUNT 8
#define HAL_ATLANTIC_UTILS_FW2X_MSG_WOL 0x0E
struct __packed fw2x_msg_wol_pattern {
u8 mask[16];
u32 crc;
};
struct __packed fw2x_msg_wol {
u32 msg_id;
u8 hw_addr[ETH_ALEN];
u8 magic_packet_enabled;
u8 filter_count;
struct fw2x_msg_wol_pattern filter[HAL_ATLANTIC_WOL_FILTERS_COUNT];
u8 link_up_enabled;
u8 link_down_enabled;
u16 reserved;
u32 link_up_timeout;
u32 link_down_timeout;
};
static int aq_fw2x_set_link_speed(struct aq_hw_s *self, u32 speed); 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, 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);
...@@ -40,6 +78,10 @@ static int aq_fw2x_init(struct aq_hw_s *self) ...@@ -40,6 +78,10 @@ static int aq_fw2x_init(struct aq_hw_s *self)
AQ_HW_WAIT_FOR(0U != (self->mbox_addr = AQ_HW_WAIT_FOR(0U != (self->mbox_addr =
aq_hw_read_reg(self, HW_ATL_FW2X_MPI_MBOX_ADDR)), aq_hw_read_reg(self, HW_ATL_FW2X_MPI_MBOX_ADDR)),
1000U, 10U); 1000U, 10U);
AQ_HW_WAIT_FOR(0U != (self->rpc_addr =
aq_hw_read_reg(self, HW_ATL_FW2X_MPI_RPC_ADDR)),
1000U, 100U);
return err; return err;
} }
...@@ -78,6 +120,38 @@ static enum hw_atl_fw2x_rate link_speed_mask_2fw2x_ratemask(u32 speed) ...@@ -78,6 +120,38 @@ static enum hw_atl_fw2x_rate link_speed_mask_2fw2x_ratemask(u32 speed)
return rate; return rate;
} }
static u32 fw2x_to_eee_mask(u32 speed)
{
u32 rate = 0;
if (speed & HW_ATL_FW2X_CAP_EEE_10G_MASK)
rate |= AQ_NIC_RATE_EEE_10G;
if (speed & HW_ATL_FW2X_CAP_EEE_5G_MASK)
rate |= AQ_NIC_RATE_EEE_5G;
if (speed & HW_ATL_FW2X_CAP_EEE_2G5_MASK)
rate |= AQ_NIC_RATE_EEE_2GS;
if (speed & HW_ATL_FW2X_CAP_EEE_1G_MASK)
rate |= AQ_NIC_RATE_EEE_1G;
return rate;
}
static u32 eee_mask_to_fw2x(u32 speed)
{
u32 rate = 0;
if (speed & AQ_NIC_RATE_EEE_10G)
rate |= HW_ATL_FW2X_CAP_EEE_10G_MASK;
if (speed & AQ_NIC_RATE_EEE_5G)
rate |= HW_ATL_FW2X_CAP_EEE_5G_MASK;
if (speed & AQ_NIC_RATE_EEE_2GS)
rate |= HW_ATL_FW2X_CAP_EEE_2G5_MASK;
if (speed & AQ_NIC_RATE_EEE_1G)
rate |= HW_ATL_FW2X_CAP_EEE_1G_MASK;
return rate;
}
static int aq_fw2x_set_link_speed(struct aq_hw_s *self, u32 speed) static int aq_fw2x_set_link_speed(struct aq_hw_s *self, u32 speed)
{ {
u32 val = link_speed_mask_2fw2x_ratemask(speed); u32 val = link_speed_mask_2fw2x_ratemask(speed);
...@@ -100,14 +174,27 @@ static void aq_fw2x_set_mpi_flow_control(struct aq_hw_s *self, u32 *mpi_state) ...@@ -100,14 +174,27 @@ static void aq_fw2x_set_mpi_flow_control(struct aq_hw_s *self, u32 *mpi_state)
*mpi_state &= ~BIT(CAPS_HI_ASYMMETRIC_PAUSE); *mpi_state &= ~BIT(CAPS_HI_ASYMMETRIC_PAUSE);
} }
static void aq_fw2x_upd_eee_rate_bits(struct aq_hw_s *self, u32 *mpi_opts,
u32 eee_speeds)
{
*mpi_opts &= ~(HW_ATL_FW2X_CAP_EEE_1G_MASK |
HW_ATL_FW2X_CAP_EEE_2G5_MASK |
HW_ATL_FW2X_CAP_EEE_5G_MASK |
HW_ATL_FW2X_CAP_EEE_10G_MASK);
*mpi_opts |= eee_mask_to_fw2x(eee_speeds);
}
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)
{ {
u32 mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR); u32 mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
struct aq_nic_cfg_s *cfg = self->aq_nic_cfg;
switch (state) { switch (state) {
case MPI_INIT: case MPI_INIT:
mpi_state &= ~BIT(CAPS_HI_LINK_DROP); mpi_state &= ~BIT(CAPS_HI_LINK_DROP);
aq_fw2x_upd_eee_rate_bits(self, &mpi_state, cfg->eee_speeds);
aq_fw2x_set_mpi_flow_control(self, &mpi_state); aq_fw2x_set_mpi_flow_control(self, &mpi_state);
break; break;
case MPI_DEINIT: case MPI_DEINIT:
...@@ -175,9 +262,7 @@ static int aq_fw2x_get_mac_permanent(struct aq_hw_s *self, u8 *mac) ...@@ -175,9 +262,7 @@ static int aq_fw2x_get_mac_permanent(struct aq_hw_s *self, u8 *mac)
get_random_bytes(&rnd, sizeof(unsigned int)); get_random_bytes(&rnd, sizeof(unsigned int));
l = 0xE3000000U l = 0xE3000000U | (0xFFFFU & rnd) | (0x00 << 16);
| (0xFFFFU & rnd)
| (0x00 << 16);
h = 0x8001300EU; h = 0x8001300EU;
mac[5] = (u8)(0xFFU & l); mac[5] = (u8)(0xFFU & l);
...@@ -194,7 +279,7 @@ static int aq_fw2x_get_mac_permanent(struct aq_hw_s *self, u8 *mac) ...@@ -194,7 +279,7 @@ static int aq_fw2x_get_mac_permanent(struct aq_hw_s *self, u8 *mac)
return err; return err;
} }
static int aq_fw2x_update_stats(struct aq_hw_s *self) int aq_fw2x_update_stats(struct aq_hw_s *self)
{ {
int err = 0; int err = 0;
u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR); u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
...@@ -215,6 +300,135 @@ static int aq_fw2x_update_stats(struct aq_hw_s *self) ...@@ -215,6 +300,135 @@ 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_set_sleep_proxy(struct aq_hw_s *self, u8 *mac)
{
struct hw_atl_utils_fw_rpc *rpc = NULL;
struct offload_info *cfg = NULL;
unsigned int rpc_size = 0U;
u32 mpi_opts;
int err = 0;
rpc_size = sizeof(rpc->msg_id) + sizeof(*cfg);
err = hw_atl_utils_fw_rpc_wait(self, &rpc);
if (err < 0)
goto err_exit;
memset(rpc, 0, rpc_size);
cfg = (struct offload_info *)(&rpc->msg_id + 1);
memcpy(cfg->mac_addr, mac, ETH_ALEN);
cfg->len = sizeof(*cfg);
/* Clear bit 0x36C.23 and 0x36C.22 */
mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
mpi_opts &= ~HW_ATL_FW2X_CTRL_SLEEP_PROXY;
mpi_opts &= ~HW_ATL_FW2X_CTRL_LINK_DROP;
aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
err = hw_atl_utils_fw_rpc_call(self, rpc_size);
if (err < 0)
goto err_exit;
/* Set bit 0x36C.23 */
mpi_opts |= HW_ATL_FW2X_CTRL_SLEEP_PROXY;
aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
AQ_HW_WAIT_FOR((aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE2_ADDR) &
HW_ATL_FW2X_CTRL_SLEEP_PROXY), 1U, 10000U);
err_exit:
return err;
}
static int aq_fw2x_set_wol_params(struct aq_hw_s *self, u8 *mac)
{
struct hw_atl_utils_fw_rpc *rpc = NULL;
struct fw2x_msg_wol *msg = NULL;
u32 mpi_opts;
int err = 0;
err = hw_atl_utils_fw_rpc_wait(self, &rpc);
if (err < 0)
goto err_exit;
msg = (struct fw2x_msg_wol *)rpc;
msg->msg_id = HAL_ATLANTIC_UTILS_FW2X_MSG_WOL;
msg->magic_packet_enabled = true;
memcpy(msg->hw_addr, mac, ETH_ALEN);
mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
mpi_opts &= ~(HW_ATL_FW2X_CTRL_SLEEP_PROXY | HW_ATL_FW2X_CTRL_WOL);
aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
err = hw_atl_utils_fw_rpc_call(self, sizeof(*msg));
if (err < 0)
goto err_exit;
/* Set bit 0x36C.24 */
mpi_opts |= HW_ATL_FW2X_CTRL_WOL;
aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
AQ_HW_WAIT_FOR((aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE2_ADDR) &
HW_ATL_FW2X_CTRL_WOL), 1U, 10000U);
err_exit:
return err;
}
static int aq_fw2x_set_power(struct aq_hw_s *self, unsigned int power_state,
u8 *mac)
{
int err = 0;
if (self->aq_nic_cfg->wol & AQ_NIC_WOL_ENABLED) {
err = aq_fw2x_set_sleep_proxy(self, mac);
if (err < 0)
goto err_exit;
err = aq_fw2x_set_wol_params(self, mac);
}
err_exit:
return err;
}
static int aq_fw2x_set_eee_rate(struct aq_hw_s *self, u32 speed)
{
u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
aq_fw2x_upd_eee_rate_bits(self, &mpi_opts, speed);
aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
return 0;
}
static int aq_fw2x_get_eee_rate(struct aq_hw_s *self, u32 *rate,
u32 *supported_rates)
{
u32 mpi_state;
u32 caps_hi;
int err = 0;
u32 addr = self->mbox_addr + offsetof(struct hw_atl_utils_mbox, info) +
offsetof(struct hw_aq_info, caps_hi);
err = hw_atl_utils_fw_downld_dwords(self, addr, &caps_hi,
sizeof(caps_hi) / sizeof(u32));
if (err)
return err;
*supported_rates = fw2x_to_eee_mask(caps_hi);
mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE2_ADDR);
*rate = fw2x_to_eee_mask(mpi_state);
return err;
}
static int aq_fw2x_renegotiate(struct aq_hw_s *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); u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
...@@ -247,5 +461,8 @@ const struct aq_fw_ops aq_fw_2x_ops = { ...@@ -247,5 +461,8 @@ const struct aq_fw_ops aq_fw_2x_ops = {
.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_power = aq_fw2x_set_power,
.set_eee_rate = aq_fw2x_set_eee_rate,
.get_eee_rate = aq_fw2x_get_eee_rate,
.set_flow_control = aq_fw2x_set_flow_control, .set_flow_control = aq_fw2x_set_flow_control,
}; };
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
#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 3 #define NIC_BUILD_DRIVER_VERSION 4
#define NIC_REVISION_DRIVER_VERSION 0 #define NIC_REVISION_DRIVER_VERSION 0
#define AQ_CFG_DRV_VERSION_SUFFIX "-kern" #define AQ_CFG_DRV_VERSION_SUFFIX "-kern"
......
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