Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -57,4 +57,9 @@
#define AQ_NIC_RATE_1G         BIT(4)
#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 */
+111 −2
Original line number Diff line number Diff line
@@ -285,6 +285,111 @@ static int aq_ethtool_set_coalesce(struct net_device *ndev,
	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)
{
	struct aq_nic_s *aq_nic = netdev_priv(ndev);
@@ -403,9 +508,13 @@ const struct ethtool_ops aq_ethtool_ops = {
	.get_drvinfo         = aq_ethtool_get_drvinfo,
	.get_strings         = aq_ethtool_get_strings,
	.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,
	.get_ringparam       = aq_get_ringparam,
	.set_ringparam       = aq_set_ringparam,
	.get_eee             = aq_ethtool_get_eee,
	.set_eee             = aq_ethtool_set_eee,
	.get_pauseparam      = aq_ethtool_get_pauseparam,
	.set_pauseparam      = aq_ethtool_set_pauseparam,
	.get_rxfh_key_size   = aq_ethtool_get_rss_key_size,
+10 −3
Original line number Diff line number Diff line
@@ -112,7 +112,7 @@ struct aq_hw_s {
	const struct aq_fw_ops *aq_fw_ops;
	void __iomem *mmio;
	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 aq_stats_s curr_stats;
	u64 speed;
@@ -124,7 +124,7 @@ struct aq_hw_s {
	u32 mbox_addr;
	u32 rpc_addr;
	u32 rpc_tid;
	struct hw_aq_atl_utils_fw_rpc rpc;
	struct hw_atl_utils_fw_rpc rpc;
};

struct aq_ring_s;
@@ -204,7 +204,6 @@ struct aq_hw_ops {

	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 {
@@ -228,6 +227,14 @@ struct aq_fw_ops {
	int (*update_stats)(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 */
+13 −11
Original line number Diff line number Diff line
@@ -889,11 +889,13 @@ void aq_nic_deinit(struct aq_nic_s *self)
		self->aq_vecs > i; ++i, aq_vec = self->aq_vec[i])
		aq_vec_deinit(aq_vec);

	if (self->power_state == AQ_HW_POWER_STATE_D0) {
		(void)self->aq_fw_ops->deinit(self->aq_hw);
	} else {
		(void)self->aq_hw_ops->hw_set_power(self->aq_hw,
						   self->power_state);
	self->aq_fw_ops->deinit(self->aq_hw);

	if (self->power_state != AQ_HW_POWER_STATE_D0 ||
	    self->aq_hw->aq_nic_cfg->wol) {
		self->aq_fw_ops->set_power(self->aq_hw,
					   self->power_state,
					   self->ndev->dev_addr);
	}

err_exit:;
+4 −0
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ struct aq_nic_cfg_s {
	u32 flow_control;
	u32 link_speed_msk;
	u32 vlan_id;
	u32 wol;
	u16 is_mc_list_enabled;
	u16 mc_list_count;
	bool is_autoneg;
@@ -44,6 +45,7 @@ struct aq_nic_cfg_s {
	bool is_lro;
	u8  tcs;
	struct aq_rss_parameters aq_rss;
	u32 eee_speeds;
};

#define AQ_NIC_FLAG_STARTED     0x00000004U
@@ -54,6 +56,8 @@ struct aq_nic_cfg_s {
#define AQ_NIC_FLAG_ERR_UNPLUG  0x40000000U
#define AQ_NIC_FLAG_ERR_HW      0x80000000U

#define AQ_NIC_WOL_ENABLED	BIT(0)

#define AQ_NIC_TCVEC2RING(_NIC_, _TC_, _VEC_) \
	((_TC_) * AQ_CFG_TCS_MAX + (_VEC_))

Loading