Commit 070b87f6 authored by Paolo Abeni's avatar Paolo Abeni
Browse files

Merge branch 'txgbe-support-more-modules'

Jiawen Wu says:

====================
TXGBE support more modules

Support CR modules for 25G devices and QSFP modules for 40G devices. And
implement .get_module_eeprom_by_page() to get module info.

v1: https://lore.kernel.org/all/20251112055841.22984-1-jiawenwu@trustnetic.com/
====================

Link: https://patch.msgid.link/20251118080259.24676-1-jiawenwu@trustnetic.com


Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parents d877b101 9b97b6b5
Loading
Loading
Loading
Loading
+0 −12
Original line number Diff line number Diff line
@@ -240,9 +240,6 @@ int wx_nway_reset(struct net_device *netdev)
{
	struct wx *wx = netdev_priv(netdev);

	if (wx->mac.type == wx_mac_aml40)
		return -EOPNOTSUPP;

	return phylink_ethtool_nway_reset(wx->phylink);
}
EXPORT_SYMBOL(wx_nway_reset);
@@ -261,9 +258,6 @@ int wx_set_link_ksettings(struct net_device *netdev,
{
	struct wx *wx = netdev_priv(netdev);

	if (wx->mac.type == wx_mac_aml40)
		return -EOPNOTSUPP;

	return phylink_ethtool_ksettings_set(wx->phylink, cmd);
}
EXPORT_SYMBOL(wx_set_link_ksettings);
@@ -273,9 +267,6 @@ void wx_get_pauseparam(struct net_device *netdev,
{
	struct wx *wx = netdev_priv(netdev);

	if (wx->mac.type == wx_mac_aml40)
		return;

	phylink_ethtool_get_pauseparam(wx->phylink, pause);
}
EXPORT_SYMBOL(wx_get_pauseparam);
@@ -285,9 +276,6 @@ int wx_set_pauseparam(struct net_device *netdev,
{
	struct wx *wx = netdev_priv(netdev);

	if (wx->mac.type == wx_mac_aml40)
		return -EOPNOTSUPP;

	return phylink_ethtool_set_pauseparam(wx->phylink, pause);
}
EXPORT_SYMBOL(wx_set_pauseparam);
+1 −1
Original line number Diff line number Diff line
@@ -1249,7 +1249,7 @@ enum wx_pf_flags {
	WX_FLAG_RX_HWTSTAMP_IN_REGISTER,
	WX_FLAG_PTP_PPS_ENABLED,
	WX_FLAG_NEED_LINK_CONFIG,
	WX_FLAG_NEED_SFP_RESET,
	WX_FLAG_NEED_MODULE_RESET,
	WX_FLAG_NEED_UPDATE_LINK,
	WX_FLAG_NEED_DO_RESET,
	WX_FLAG_RX_MERGE_ENABLED,
+213 −47
Original line number Diff line number Diff line
@@ -17,10 +17,15 @@

void txgbe_gpio_init_aml(struct wx *wx)
{
	u32 status;
	u32 status, mod_rst;

	if (wx->mac.type == wx_mac_aml40)
		mod_rst = TXGBE_GPIOBIT_4;
	else
		mod_rst = TXGBE_GPIOBIT_2;

	wr32(wx, WX_GPIO_INTTYPE_LEVEL, TXGBE_GPIOBIT_2);
	wr32(wx, WX_GPIO_INTEN, TXGBE_GPIOBIT_2);
	wr32(wx, WX_GPIO_INTTYPE_LEVEL, mod_rst);
	wr32(wx, WX_GPIO_INTEN, mod_rst);

	status = rd32(wx, WX_GPIO_INTSTATUS);
	for (int i = 0; i < 6; i++) {
@@ -33,13 +38,18 @@ irqreturn_t txgbe_gpio_irq_handler_aml(int irq, void *data)
{
	struct txgbe *txgbe = data;
	struct wx *wx = txgbe->wx;
	u32 status;
	u32 status, mod_rst;

	if (wx->mac.type == wx_mac_aml40)
		mod_rst = TXGBE_GPIOBIT_4;
	else
		mod_rst = TXGBE_GPIOBIT_2;

	wr32(wx, WX_GPIO_INTMASK, 0xFF);
	status = rd32(wx, WX_GPIO_INTSTATUS);
	if (status & TXGBE_GPIOBIT_2) {
		set_bit(WX_FLAG_NEED_SFP_RESET, wx->flags);
		wr32(wx, WX_GPIO_EOI, TXGBE_GPIOBIT_2);
	if (status & mod_rst) {
		set_bit(WX_FLAG_NEED_MODULE_RESET, wx->flags);
		wr32(wx, WX_GPIO_EOI, mod_rst);
		wx_service_event_schedule(wx);
	}

@@ -51,7 +61,7 @@ int txgbe_test_hostif(struct wx *wx)
{
	struct txgbe_hic_ephy_getlink buffer;

	if (wx->mac.type != wx_mac_aml)
	if (wx->mac.type == wx_mac_sp)
		return 0;

	buffer.hdr.cmd = FW_PHY_GET_LINK_CMD;
@@ -63,15 +73,49 @@ int txgbe_test_hostif(struct wx *wx)
					WX_HI_COMMAND_TIMEOUT, true);
}

static int txgbe_identify_sfp_hostif(struct wx *wx, struct txgbe_hic_i2c_read *buffer)
int txgbe_read_eeprom_hostif(struct wx *wx,
			     struct txgbe_hic_i2c_read *buffer,
			     u32 length, u8 *data)
{
	buffer->hdr.cmd = FW_READ_SFP_INFO_CMD;
	u32 dword_len, offset, value, i;
	int err;

	buffer->hdr.cmd = FW_READ_EEPROM_CMD;
	buffer->hdr.buf_len = sizeof(struct txgbe_hic_i2c_read) -
			      sizeof(struct wx_hic_hdr);
	buffer->hdr.cmd_or_resp.cmd_resv = FW_CEM_CMD_RESERVED;

	return wx_host_interface_command(wx, (u32 *)buffer,
	err = wx_host_interface_command(wx, (u32 *)buffer,
					sizeof(struct txgbe_hic_i2c_read),
					WX_HI_COMMAND_TIMEOUT, false);
	if (err != 0)
		return err;

	/* buffer length offset to read return data */
	offset = sizeof(struct txgbe_hic_i2c_read) >> 2;
	dword_len = round_up(length, 4) >> 2;

	for (i = 0; i < dword_len; i++) {
		value = rd32a(wx, WX_FW2SW_MBOX, i + offset);
		le32_to_cpus(&value);

		memcpy(data, &value, 4);
		data += 4;
	}

	return 0;
}

static int txgbe_identify_module_hostif(struct wx *wx,
					struct txgbe_hic_get_module_info *buffer)
{
	buffer->hdr.cmd = FW_GET_MODULE_INFO_CMD;
	buffer->hdr.buf_len = sizeof(struct txgbe_hic_get_module_info) -
			      sizeof(struct wx_hic_hdr);
	buffer->hdr.cmd_or_resp.cmd_resv = FW_CEM_CMD_RESERVED;

	return wx_host_interface_command(wx, (u32 *)buffer,
					 sizeof(struct txgbe_hic_get_module_info),
					 WX_HI_COMMAND_TIMEOUT, true);
}

@@ -85,6 +129,9 @@ static int txgbe_set_phy_link_hostif(struct wx *wx, int speed, int autoneg, int
	buffer.hdr.cmd_or_resp.cmd_resv = FW_CEM_CMD_RESERVED;

	switch (speed) {
	case SPEED_40000:
		buffer.speed = TXGBE_LINK_SPEED_40GB_FULL;
		break;
	case SPEED_25000:
		buffer.speed = TXGBE_LINK_SPEED_25GB_FULL;
		break;
@@ -104,17 +151,21 @@ static int txgbe_set_phy_link_hostif(struct wx *wx, int speed, int autoneg, int
					 WX_HI_COMMAND_TIMEOUT, true);
}

static void txgbe_get_link_capabilities(struct wx *wx, int *speed, int *duplex)
static void txgbe_get_link_capabilities(struct wx *wx, int *speed,
					int *autoneg, int *duplex)
{
	struct txgbe *txgbe = wx->priv;

	if (test_bit(PHY_INTERFACE_MODE_25GBASER, txgbe->sfp_interfaces))
	if (test_bit(PHY_INTERFACE_MODE_XLGMII, txgbe->link_interfaces))
		*speed = SPEED_40000;
	else if (test_bit(PHY_INTERFACE_MODE_25GBASER, txgbe->link_interfaces))
		*speed = SPEED_25000;
	else if (test_bit(PHY_INTERFACE_MODE_10GBASER, txgbe->sfp_interfaces))
	else if (test_bit(PHY_INTERFACE_MODE_10GBASER, txgbe->link_interfaces))
		*speed = SPEED_10000;
	else
		*speed = SPEED_UNKNOWN;

	*autoneg = phylink_test(txgbe->advertising, Autoneg);
	*duplex = *speed == SPEED_UNKNOWN ? DUPLEX_HALF : DUPLEX_FULL;
}

@@ -125,6 +176,8 @@ static void txgbe_get_mac_link(struct wx *wx, int *speed)
	status = rd32(wx, TXGBE_CFG_PORT_ST);
	if (!(status & TXGBE_CFG_PORT_ST_LINK_UP))
		*speed = SPEED_UNKNOWN;
	else if (status & TXGBE_CFG_PORT_ST_LINK_AML_40G)
		*speed = SPEED_40000;
	else if (status & TXGBE_CFG_PORT_ST_LINK_AML_25G)
		*speed = SPEED_25000;
	else if (status & TXGBE_CFG_PORT_ST_LINK_AML_10G)
@@ -135,11 +188,11 @@ static void txgbe_get_mac_link(struct wx *wx, int *speed)

int txgbe_set_phy_link(struct wx *wx)
{
	int speed, duplex, err;
	int speed, autoneg, duplex, err;

	txgbe_get_link_capabilities(wx, &speed, &duplex);
	txgbe_get_link_capabilities(wx, &speed, &autoneg, &duplex);

	err = txgbe_set_phy_link_hostif(wx, speed, 0, duplex);
	err = txgbe_set_phy_link_hostif(wx, speed, autoneg, duplex);
	if (err) {
		wx_err(wx, "Failed to setup link\n");
		return err;
@@ -148,26 +201,50 @@ int txgbe_set_phy_link(struct wx *wx)
	return 0;
}

static int txgbe_sfp_to_linkmodes(struct wx *wx, struct txgbe_sfp_id *id)
static int txgbe_sfp_to_linkmodes(struct wx *wx, struct txgbe_sff_id *id)
{
	__ETHTOOL_DECLARE_LINK_MODE_MASK(modes) = { 0, };
	DECLARE_PHY_INTERFACE_MASK(interfaces);
	struct txgbe *txgbe = wx->priv;

	if (id->com_25g_code & (TXGBE_SFF_25GBASESR_CAPABLE |
				TXGBE_SFF_25GBASEER_CAPABLE |
				TXGBE_SFF_25GBASELR_CAPABLE)) {
	if (id->cable_tech & TXGBE_SFF_DA_PASSIVE_CABLE) {
		txgbe->link_port = PORT_DA;
		phylink_set(modes, Autoneg);
		if (id->com_25g_code == TXGBE_SFF_25GBASECR_91FEC ||
		    id->com_25g_code == TXGBE_SFF_25GBASECR_74FEC ||
		    id->com_25g_code == TXGBE_SFF_25GBASECR_NOFEC) {
			phylink_set(modes, 25000baseCR_Full);
			phylink_set(modes, 10000baseCR_Full);
			__set_bit(PHY_INTERFACE_MODE_25GBASER, interfaces);
			__set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces);
		} else {
			phylink_set(modes, 10000baseCR_Full);
			__set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces);
		}
	} else if (id->cable_tech & TXGBE_SFF_DA_ACTIVE_CABLE) {
		txgbe->link_port = PORT_DA;
		phylink_set(modes, Autoneg);
		phylink_set(modes, 25000baseCR_Full);
		__set_bit(PHY_INTERFACE_MODE_25GBASER, interfaces);
	} else {
		if (id->com_25g_code == TXGBE_SFF_25GBASESR_CAPABLE ||
		    id->com_25g_code == TXGBE_SFF_25GBASEER_CAPABLE ||
		    id->com_25g_code == TXGBE_SFF_25GBASELR_CAPABLE) {
			txgbe->link_port = PORT_FIBRE;
			phylink_set(modes, 25000baseSR_Full);
			__set_bit(PHY_INTERFACE_MODE_25GBASER, interfaces);
		}
		if (id->com_10g_code & TXGBE_SFF_10GBASESR_CAPABLE) {
			txgbe->link_port = PORT_FIBRE;
			phylink_set(modes, 10000baseSR_Full);
			__set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces);
		}
		if (id->com_10g_code & TXGBE_SFF_10GBASELR_CAPABLE) {
			txgbe->link_port = PORT_FIBRE;
			phylink_set(modes, 10000baseLR_Full);
			__set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces);
		}
	}

	if (phy_interface_empty(interfaces)) {
		wx_err(wx, "unsupported SFP module\n");
@@ -177,11 +254,75 @@ static int txgbe_sfp_to_linkmodes(struct wx *wx, struct txgbe_sfp_id *id)
	phylink_set(modes, Pause);
	phylink_set(modes, Asym_Pause);
	phylink_set(modes, FIBRE);

	if (!linkmode_equal(txgbe->link_support, modes)) {
		linkmode_copy(txgbe->link_support, modes);
		phy_interface_and(txgbe->link_interfaces,
				  wx->phylink_config.supported_interfaces,
				  interfaces);
		linkmode_copy(txgbe->advertising, modes);

		set_bit(WX_FLAG_NEED_LINK_CONFIG, wx->flags);
	}

	return 0;
}

static int txgbe_qsfp_to_linkmodes(struct wx *wx, struct txgbe_sff_id *id)
{
	__ETHTOOL_DECLARE_LINK_MODE_MASK(modes) = { 0, };
	DECLARE_PHY_INTERFACE_MASK(interfaces);
	struct txgbe *txgbe = wx->priv;

	if (id->transceiver_type & TXGBE_SFF_ETHERNET_40G_CR4) {
		txgbe->link_port = PORT_DA;
		phylink_set(modes, Autoneg);
		phylink_set(modes, 40000baseCR4_Full);
		phylink_set(modes, 10000baseCR_Full);
		__set_bit(PHY_INTERFACE_MODE_XLGMII, interfaces);
		__set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces);
	}
	if (id->transceiver_type & TXGBE_SFF_ETHERNET_40G_SR4) {
		txgbe->link_port = PORT_FIBRE;
		phylink_set(modes, 40000baseSR4_Full);
		__set_bit(PHY_INTERFACE_MODE_XLGMII, interfaces);
	}
	if (id->transceiver_type & TXGBE_SFF_ETHERNET_40G_LR4) {
		txgbe->link_port = PORT_FIBRE;
		phylink_set(modes, 40000baseLR4_Full);
		__set_bit(PHY_INTERFACE_MODE_XLGMII, interfaces);
	}
	if (id->transceiver_type & TXGBE_SFF_ETHERNET_40G_ACTIVE) {
		txgbe->link_port = PORT_DA;
		phylink_set(modes, Autoneg);
		phylink_set(modes, 40000baseCR4_Full);
		__set_bit(PHY_INTERFACE_MODE_XLGMII, interfaces);
	}
	if (id->transceiver_type & TXGBE_SFF_ETHERNET_RSRVD) {
		if (id->sff_opt1 & TXGBE_SFF_ETHERNET_100G_CR4) {
			txgbe->link_port = PORT_DA;
			phylink_set(modes, Autoneg);
			phylink_set(modes, 40000baseCR4_Full);
			phylink_set(modes, 25000baseCR_Full);
			phylink_set(modes, 10000baseCR_Full);
			__set_bit(PHY_INTERFACE_MODE_XLGMII, interfaces);
			__set_bit(PHY_INTERFACE_MODE_25GBASER, interfaces);
			__set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces);
		}
	}

	if (!linkmode_equal(txgbe->sfp_support, modes)) {
		linkmode_copy(txgbe->sfp_support, modes);
		phy_interface_and(txgbe->sfp_interfaces,
	if (phy_interface_empty(interfaces)) {
		wx_err(wx, "unsupported QSFP module\n");
		return -EINVAL;
	}

	phylink_set(modes, Pause);
	phylink_set(modes, Asym_Pause);
	phylink_set(modes, FIBRE);

	if (!linkmode_equal(txgbe->link_support, modes)) {
		linkmode_copy(txgbe->link_support, modes);
		phy_interface_and(txgbe->link_interfaces,
				  wx->phylink_config.supported_interfaces,
				  interfaces);
		linkmode_copy(txgbe->advertising, modes);
@@ -192,40 +333,53 @@ static int txgbe_sfp_to_linkmodes(struct wx *wx, struct txgbe_sfp_id *id)
	return 0;
}

int txgbe_identify_sfp(struct wx *wx)
int txgbe_identify_module(struct wx *wx)
{
	struct txgbe_hic_i2c_read buffer;
	struct txgbe_sfp_id *id;
	struct txgbe_hic_get_module_info buffer;
	struct txgbe_sff_id *id;
	int err = 0;
	u32 mod_abs;
	u32 gpio;

	if (wx->mac.type == wx_mac_aml40)
		mod_abs = TXGBE_GPIOBIT_4;
	else
		mod_abs = TXGBE_GPIOBIT_2;

	gpio = rd32(wx, WX_GPIO_EXT);
	if (gpio & TXGBE_GPIOBIT_2)
	if (gpio & mod_abs)
		return -ENODEV;

	err = txgbe_identify_sfp_hostif(wx, &buffer);
	err = txgbe_identify_module_hostif(wx, &buffer);
	if (err) {
		wx_err(wx, "Failed to identify SFP module\n");
		wx_err(wx, "Failed to identify module\n");
		return err;
	}

	id = &buffer.id;
	if (id->identifier != TXGBE_SFF_IDENTIFIER_SFP) {
		wx_err(wx, "Invalid SFP module\n");
	if (id->identifier != TXGBE_SFF_IDENTIFIER_SFP &&
	    id->identifier != TXGBE_SFF_IDENTIFIER_QSFP &&
	    id->identifier != TXGBE_SFF_IDENTIFIER_QSFP_PLUS &&
	    id->identifier != TXGBE_SFF_IDENTIFIER_QSFP28) {
		wx_err(wx, "Invalid module\n");
		return -ENODEV;
	}

	if (id->transceiver_type == 0xFF)
		return txgbe_sfp_to_linkmodes(wx, id);

	return txgbe_qsfp_to_linkmodes(wx, id);
}

void txgbe_setup_link(struct wx *wx)
{
	struct txgbe *txgbe = wx->priv;

	phy_interface_zero(txgbe->sfp_interfaces);
	linkmode_zero(txgbe->sfp_support);
	phy_interface_zero(txgbe->link_interfaces);
	linkmode_zero(txgbe->link_support);

	txgbe_identify_sfp(wx);
	set_bit(WX_FLAG_NEED_MODULE_RESET, wx->flags);
	wx_service_event_schedule(wx);
}

static void txgbe_get_link_state(struct phylink_config *config,
@@ -278,6 +432,9 @@ static void txgbe_mac_link_up_aml(struct phylink_config *config,
	txcfg &= ~TXGBE_AML_MAC_TX_CFG_SPEED_MASK;

	switch (speed) {
	case SPEED_40000:
		txcfg |= TXGBE_AML_MAC_TX_CFG_SPEED_40G;
		break;
	case SPEED_25000:
		txcfg |= TXGBE_AML_MAC_TX_CFG_SPEED_25G;
		break;
@@ -342,7 +499,18 @@ int txgbe_phylink_init_aml(struct txgbe *txgbe)
				   MAC_SYM_PAUSE | MAC_ASYM_PAUSE;
	config->get_fixed_state = txgbe_get_link_state;

	if (wx->mac.type == wx_mac_aml40) {
		config->mac_capabilities |= MAC_40000FD;
		phy_mode = PHY_INTERFACE_MODE_XLGMII;
		__set_bit(PHY_INTERFACE_MODE_XLGMII, config->supported_interfaces);
		state.speed = SPEED_40000;
		state.duplex = DUPLEX_FULL;
	} else {
		phy_mode = PHY_INTERFACE_MODE_25GBASER;
		state.speed = SPEED_25000;
		state.duplex = DUPLEX_FULL;
	}

	__set_bit(PHY_INTERFACE_MODE_25GBASER, config->supported_interfaces);
	__set_bit(PHY_INTERFACE_MODE_10GBASER, config->supported_interfaces);

@@ -350,8 +518,6 @@ int txgbe_phylink_init_aml(struct txgbe *txgbe)
	if (IS_ERR(phylink))
		return PTR_ERR(phylink);

	state.speed = SPEED_25000;
	state.duplex = DUPLEX_FULL;
	err = phylink_set_fixed_link(phylink, &state);
	if (err) {
		wx_err(wx, "Failed to set fixed link\n");
+4 −1
Original line number Diff line number Diff line
@@ -7,8 +7,11 @@
void txgbe_gpio_init_aml(struct wx *wx);
irqreturn_t txgbe_gpio_irq_handler_aml(int irq, void *data);
int txgbe_test_hostif(struct wx *wx);
int txgbe_read_eeprom_hostif(struct wx *wx,
			     struct txgbe_hic_i2c_read *buffer,
			     u32 length, u8 *data);
int txgbe_set_phy_link(struct wx *wx);
int txgbe_identify_sfp(struct wx *wx);
int txgbe_identify_module(struct wx *wx);
void txgbe_setup_link(struct wx *wx);
int txgbe_phylink_init_aml(struct txgbe *txgbe);

+33 −5
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@
#include "../libwx/wx_lib.h"
#include "txgbe_type.h"
#include "txgbe_fdir.h"
#include "txgbe_aml.h"
#include "txgbe_ethtool.h"

int txgbe_get_link_ksettings(struct net_device *netdev,
@@ -19,9 +20,6 @@ int txgbe_get_link_ksettings(struct net_device *netdev,
	struct txgbe *txgbe = wx->priv;
	int err;

	if (wx->mac.type == wx_mac_aml40)
		return -EOPNOTSUPP;

	err = wx_get_link_ksettings(netdev, cmd);
	if (err)
		return err;
@@ -30,8 +28,9 @@ int txgbe_get_link_ksettings(struct net_device *netdev,
		return 0;

	cmd->base.port = txgbe->link_port;
	cmd->base.autoneg = AUTONEG_DISABLE;
	linkmode_copy(cmd->link_modes.supported, txgbe->sfp_support);
	cmd->base.autoneg = phylink_test(txgbe->advertising, Autoneg) ?
			    AUTONEG_ENABLE : AUTONEG_DISABLE;
	linkmode_copy(cmd->link_modes.supported, txgbe->link_support);
	linkmode_copy(cmd->link_modes.advertising, txgbe->advertising);

	return 0;
@@ -536,6 +535,34 @@ static int txgbe_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
	return ret;
}

static int
txgbe_get_module_eeprom_by_page(struct net_device *netdev,
				const struct ethtool_module_eeprom *page_data,
				struct netlink_ext_ack *extack)
{
	struct wx *wx = netdev_priv(netdev);
	struct txgbe_hic_i2c_read buffer;
	int err;

	if (!test_bit(WX_FLAG_SWFW_RING, wx->flags))
		return -EOPNOTSUPP;

	buffer.length = cpu_to_be32(page_data->length);
	buffer.offset = cpu_to_be32(page_data->offset);
	buffer.page = page_data->page;
	buffer.bank = page_data->bank;
	buffer.i2c_address = page_data->i2c_address;

	err = txgbe_read_eeprom_hostif(wx, &buffer, page_data->length,
				       page_data->data);
	if (err) {
		wx_err(wx, "Failed to read module EEPROM\n");
		return err;
	}

	return page_data->length;
}

static const struct ethtool_ops txgbe_ethtool_ops = {
	.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
				     ETHTOOL_COALESCE_TX_MAX_FRAMES_IRQ |
@@ -570,6 +597,7 @@ static const struct ethtool_ops txgbe_ethtool_ops = {
	.set_msglevel		= wx_set_msglevel,
	.get_ts_info		= wx_get_ts_info,
	.get_ts_stats		= wx_get_ptp_stats,
	.get_module_eeprom_by_page	= txgbe_get_module_eeprom_by_page,
};

void txgbe_set_ethtool_ops(struct net_device *netdev)
Loading