mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-22 03:44:51 -04:00
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: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -17,10 +17,15 @@
|
||||
|
||||
void txgbe_gpio_init_aml(struct wx *wx)
|
||||
{
|
||||
u32 status;
|
||||
u32 status, mod_rst;
|
||||
|
||||
wr32(wx, WX_GPIO_INTTYPE_LEVEL, TXGBE_GPIOBIT_2);
|
||||
wr32(wx, WX_GPIO_INTEN, TXGBE_GPIOBIT_2);
|
||||
if (wx->mac.type == wx_mac_aml40)
|
||||
mod_rst = TXGBE_GPIOBIT_4;
|
||||
else
|
||||
mod_rst = 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;
|
||||
|
||||
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_i2c_read),
|
||||
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,25 +201,49 @@ 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)) {
|
||||
phylink_set(modes, 25000baseSR_Full);
|
||||
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);
|
||||
}
|
||||
if (id->com_10g_code & TXGBE_SFF_10GBASESR_CAPABLE) {
|
||||
phylink_set(modes, 10000baseSR_Full);
|
||||
__set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces);
|
||||
}
|
||||
if (id->com_10g_code & TXGBE_SFF_10GBASELR_CAPABLE) {
|
||||
phylink_set(modes, 10000baseLR_Full);
|
||||
__set_bit(PHY_INTERFACE_MODE_10GBASER, 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)) {
|
||||
@@ -177,11 +254,10 @@ 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);
|
||||
txgbe->link_port = PORT_FIBRE;
|
||||
|
||||
if (!linkmode_equal(txgbe->sfp_support, modes)) {
|
||||
linkmode_copy(txgbe->sfp_support, modes);
|
||||
phy_interface_and(txgbe->sfp_interfaces,
|
||||
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 +268,118 @@ static int txgbe_sfp_to_linkmodes(struct wx *wx, struct txgbe_sfp_id *id)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int txgbe_identify_sfp(struct wx *wx)
|
||||
static int txgbe_qsfp_to_linkmodes(struct wx *wx, struct txgbe_sff_id *id)
|
||||
{
|
||||
struct txgbe_hic_i2c_read buffer;
|
||||
struct txgbe_sfp_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 (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);
|
||||
|
||||
set_bit(WX_FLAG_NEED_LINK_CONFIG, wx->flags);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int txgbe_identify_module(struct wx *wx)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
return txgbe_sfp_to_linkmodes(wx, id);
|
||||
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;
|
||||
|
||||
phy_mode = PHY_INTERFACE_MODE_25GBASER;
|
||||
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");
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -23,7 +23,7 @@ void txgbe_irq_enable(struct wx *wx, bool queues)
|
||||
{
|
||||
u32 misc_ien = TXGBE_PX_MISC_IEN_MASK;
|
||||
|
||||
if (wx->mac.type == wx_mac_aml) {
|
||||
if (wx->mac.type != wx_mac_sp) {
|
||||
misc_ien |= TXGBE_PX_MISC_GPIO;
|
||||
txgbe_gpio_init_aml(wx);
|
||||
}
|
||||
@@ -201,10 +201,7 @@ static void txgbe_del_irq_domain(struct txgbe *txgbe)
|
||||
|
||||
void txgbe_free_misc_irq(struct txgbe *txgbe)
|
||||
{
|
||||
if (txgbe->wx->mac.type == wx_mac_aml40)
|
||||
return;
|
||||
|
||||
if (txgbe->wx->mac.type == wx_mac_aml)
|
||||
if (txgbe->wx->mac.type != wx_mac_sp)
|
||||
free_irq(txgbe->gpio_irq, txgbe);
|
||||
|
||||
free_irq(txgbe->link_irq, txgbe);
|
||||
@@ -219,9 +216,6 @@ int txgbe_setup_misc_irq(struct txgbe *txgbe)
|
||||
struct wx *wx = txgbe->wx;
|
||||
int hwirq, err;
|
||||
|
||||
if (wx->mac.type == wx_mac_aml40)
|
||||
goto skip_sp_irq;
|
||||
|
||||
txgbe->misc.nirqs = TXGBE_IRQ_MAX;
|
||||
txgbe->misc.domain = irq_domain_create_simple(NULL, txgbe->misc.nirqs, 0,
|
||||
&txgbe_misc_irq_domain_ops, txgbe);
|
||||
|
||||
@@ -89,21 +89,21 @@ static int txgbe_enumerate_functions(struct wx *wx)
|
||||
return physfns;
|
||||
}
|
||||
|
||||
static void txgbe_sfp_detection_subtask(struct wx *wx)
|
||||
static void txgbe_module_detection_subtask(struct wx *wx)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (!test_bit(WX_FLAG_NEED_SFP_RESET, wx->flags))
|
||||
if (!test_bit(WX_FLAG_NEED_MODULE_RESET, wx->flags))
|
||||
return;
|
||||
|
||||
/* wait for SFP module ready */
|
||||
/* wait for SFF module ready */
|
||||
msleep(200);
|
||||
|
||||
err = txgbe_identify_sfp(wx);
|
||||
err = txgbe_identify_module(wx);
|
||||
if (err)
|
||||
return;
|
||||
|
||||
clear_bit(WX_FLAG_NEED_SFP_RESET, wx->flags);
|
||||
clear_bit(WX_FLAG_NEED_MODULE_RESET, wx->flags);
|
||||
}
|
||||
|
||||
static void txgbe_link_config_subtask(struct wx *wx)
|
||||
@@ -128,7 +128,7 @@ static void txgbe_service_task(struct work_struct *work)
|
||||
{
|
||||
struct wx *wx = container_of(work, struct wx, service_task);
|
||||
|
||||
txgbe_sfp_detection_subtask(wx);
|
||||
txgbe_module_detection_subtask(wx);
|
||||
txgbe_link_config_subtask(wx);
|
||||
|
||||
wx_service_event_complete(wx);
|
||||
@@ -144,7 +144,6 @@ static void txgbe_init_service(struct wx *wx)
|
||||
static void txgbe_up_complete(struct wx *wx)
|
||||
{
|
||||
struct net_device *netdev = wx->netdev;
|
||||
u32 reg;
|
||||
|
||||
wx_control_hw(wx, true);
|
||||
wx_configure_vectors(wx);
|
||||
@@ -155,12 +154,8 @@ static void txgbe_up_complete(struct wx *wx)
|
||||
|
||||
switch (wx->mac.type) {
|
||||
case wx_mac_aml40:
|
||||
reg = rd32(wx, TXGBE_AML_MAC_TX_CFG);
|
||||
reg &= ~TXGBE_AML_MAC_TX_CFG_SPEED_MASK;
|
||||
reg |= TXGBE_AML_MAC_TX_CFG_SPEED_40G;
|
||||
wr32(wx, WX_MAC_TX_CFG, reg);
|
||||
txgbe_enable_sec_tx_path(wx);
|
||||
netif_carrier_on(wx->netdev);
|
||||
txgbe_setup_link(wx);
|
||||
phylink_start(wx->phylink);
|
||||
break;
|
||||
case wx_mac_aml:
|
||||
/* Enable TX laser */
|
||||
@@ -276,7 +271,7 @@ void txgbe_down(struct wx *wx)
|
||||
|
||||
switch (wx->mac.type) {
|
||||
case wx_mac_aml40:
|
||||
netif_carrier_off(wx->netdev);
|
||||
phylink_stop(wx->phylink);
|
||||
break;
|
||||
case wx_mac_aml:
|
||||
phylink_stop(wx->phylink);
|
||||
|
||||
@@ -579,7 +579,6 @@ int txgbe_init_phy(struct txgbe *txgbe)
|
||||
|
||||
switch (wx->mac.type) {
|
||||
case wx_mac_aml40:
|
||||
return 0;
|
||||
case wx_mac_aml:
|
||||
return txgbe_phylink_init_aml(txgbe);
|
||||
case wx_mac_sp:
|
||||
@@ -653,7 +652,6 @@ void txgbe_remove_phy(struct txgbe *txgbe)
|
||||
{
|
||||
switch (txgbe->wx->mac.type) {
|
||||
case wx_mac_aml40:
|
||||
return;
|
||||
case wx_mac_aml:
|
||||
phylink_destroy(txgbe->wx->phylink);
|
||||
return;
|
||||
|
||||
@@ -98,6 +98,7 @@
|
||||
/* Port cfg registers */
|
||||
#define TXGBE_CFG_PORT_ST 0x14404
|
||||
#define TXGBE_CFG_PORT_ST_LINK_UP BIT(0)
|
||||
#define TXGBE_CFG_PORT_ST_LINK_AML_40G BIT(2)
|
||||
#define TXGBE_CFG_PORT_ST_LINK_AML_25G BIT(3)
|
||||
#define TXGBE_CFG_PORT_ST_LINK_AML_10G BIT(4)
|
||||
#define TXGBE_CFG_VXLAN 0x14410
|
||||
@@ -317,8 +318,12 @@ void txgbe_do_reset(struct net_device *netdev);
|
||||
#define TXGBE_LINK_SPEED_UNKNOWN 0
|
||||
#define TXGBE_LINK_SPEED_10GB_FULL 4
|
||||
#define TXGBE_LINK_SPEED_25GB_FULL 0x10
|
||||
#define TXGBE_LINK_SPEED_40GB_FULL 0x20
|
||||
|
||||
#define TXGBE_SFF_IDENTIFIER_SFP 0x3
|
||||
#define TXGBE_SFF_IDENTIFIER_QSFP 0xC
|
||||
#define TXGBE_SFF_IDENTIFIER_QSFP_PLUS 0xD
|
||||
#define TXGBE_SFF_IDENTIFIER_QSFP28 0x11
|
||||
#define TXGBE_SFF_DA_PASSIVE_CABLE 0x4
|
||||
#define TXGBE_SFF_DA_ACTIVE_CABLE 0x8
|
||||
#define TXGBE_SFF_DA_SPEC_ACTIVE_LIMIT 0x4
|
||||
@@ -331,6 +336,12 @@ void txgbe_do_reset(struct net_device *netdev);
|
||||
#define TXGBE_SFF_25GBASECR_91FEC 0xB
|
||||
#define TXGBE_SFF_25GBASECR_74FEC 0xC
|
||||
#define TXGBE_SFF_25GBASECR_NOFEC 0xD
|
||||
#define TXGBE_SFF_ETHERNET_RSRVD BIT(7)
|
||||
#define TXGBE_SFF_ETHERNET_40G_CR4 BIT(3)
|
||||
#define TXGBE_SFF_ETHERNET_40G_SR4 BIT(2)
|
||||
#define TXGBE_SFF_ETHERNET_40G_LR4 BIT(1)
|
||||
#define TXGBE_SFF_ETHERNET_40G_ACTIVE BIT(0)
|
||||
#define TXGBE_SFF_ETHERNET_100G_CR4 0xB
|
||||
|
||||
#define TXGBE_PHY_FEC_RS BIT(0)
|
||||
#define TXGBE_PHY_FEC_BASER BIT(1)
|
||||
@@ -341,9 +352,10 @@ void txgbe_do_reset(struct net_device *netdev);
|
||||
|
||||
#define FW_PHY_GET_LINK_CMD 0xC0
|
||||
#define FW_PHY_SET_LINK_CMD 0xC1
|
||||
#define FW_READ_SFP_INFO_CMD 0xC5
|
||||
#define FW_GET_MODULE_INFO_CMD 0xC5
|
||||
#define FW_READ_EEPROM_CMD 0xC6
|
||||
|
||||
struct txgbe_sfp_id {
|
||||
struct txgbe_sff_id {
|
||||
u8 identifier; /* A0H 0x00 */
|
||||
u8 com_1g_code; /* A0H 0x06 */
|
||||
u8 com_10g_code; /* A0H 0x03 */
|
||||
@@ -358,9 +370,9 @@ struct txgbe_sfp_id {
|
||||
u8 reserved[5];
|
||||
};
|
||||
|
||||
struct txgbe_hic_i2c_read {
|
||||
struct txgbe_hic_get_module_info {
|
||||
struct wx_hic_hdr hdr;
|
||||
struct txgbe_sfp_id id;
|
||||
struct txgbe_sff_id id;
|
||||
};
|
||||
|
||||
struct txgbe_hic_ephy_setlink {
|
||||
@@ -383,6 +395,16 @@ struct txgbe_hic_ephy_getlink {
|
||||
u8 resv[6];
|
||||
};
|
||||
|
||||
struct txgbe_hic_i2c_read {
|
||||
struct wx_hic_hdr hdr;
|
||||
__be32 offset;
|
||||
__be32 length;
|
||||
u8 page;
|
||||
u8 bank;
|
||||
u8 i2c_address;
|
||||
u8 resv;
|
||||
};
|
||||
|
||||
#define NODE_PROP(_NAME, _PROP) \
|
||||
(const struct software_node) { \
|
||||
.name = _NAME, \
|
||||
@@ -451,8 +473,8 @@ struct txgbe {
|
||||
int fdir_filter_count;
|
||||
spinlock_t fdir_perfect_lock; /* spinlock for FDIR */
|
||||
|
||||
DECLARE_PHY_INTERFACE_MASK(sfp_interfaces);
|
||||
__ETHTOOL_DECLARE_LINK_MODE_MASK(sfp_support);
|
||||
DECLARE_PHY_INTERFACE_MASK(link_interfaces);
|
||||
__ETHTOOL_DECLARE_LINK_MODE_MASK(link_support);
|
||||
__ETHTOOL_DECLARE_LINK_MODE_MASK(advertising);
|
||||
u8 link_port;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user