nfp: ethtool: fix the bug of setting unsupported port speed

Unsupported port speed can be set and cause error. Now fixing it
and return an error if setting unsupported speed.

This fix depends on the following, which was included in v6.2-rc1:
commit a61474c41e ("nfp: ethtool: support reporting link modes").

Fixes: 7c69873727 ("nfp: add support for .set_link_ksettings()")
Signed-off-by: Yu Xiao <yu.xiao@corigine.com>
Signed-off-by: Simon Horman <simon.horman@corigine.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Yu Xiao 2023-02-07 11:16:50 +01:00 committed by David S. Miller
parent c11204c78d
commit 821de68c1f
2 changed files with 170 additions and 36 deletions

View File

@ -293,35 +293,131 @@ nfp_net_set_fec_link_mode(struct nfp_eth_table_port *eth_port,
}
}
static const u16 nfp_eth_media_table[] = {
[NFP_MEDIA_1000BASE_CX] = ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
[NFP_MEDIA_1000BASE_KX] = ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
[NFP_MEDIA_10GBASE_KX4] = ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
[NFP_MEDIA_10GBASE_KR] = ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
[NFP_MEDIA_10GBASE_CX4] = ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
[NFP_MEDIA_10GBASE_CR] = ETHTOOL_LINK_MODE_10000baseCR_Full_BIT,
[NFP_MEDIA_10GBASE_SR] = ETHTOOL_LINK_MODE_10000baseSR_Full_BIT,
[NFP_MEDIA_10GBASE_ER] = ETHTOOL_LINK_MODE_10000baseER_Full_BIT,
[NFP_MEDIA_25GBASE_KR] = ETHTOOL_LINK_MODE_25000baseKR_Full_BIT,
[NFP_MEDIA_25GBASE_KR_S] = ETHTOOL_LINK_MODE_25000baseKR_Full_BIT,
[NFP_MEDIA_25GBASE_CR] = ETHTOOL_LINK_MODE_25000baseCR_Full_BIT,
[NFP_MEDIA_25GBASE_CR_S] = ETHTOOL_LINK_MODE_25000baseCR_Full_BIT,
[NFP_MEDIA_25GBASE_SR] = ETHTOOL_LINK_MODE_25000baseSR_Full_BIT,
[NFP_MEDIA_40GBASE_CR4] = ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT,
[NFP_MEDIA_40GBASE_KR4] = ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT,
[NFP_MEDIA_40GBASE_SR4] = ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT,
[NFP_MEDIA_40GBASE_LR4] = ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT,
[NFP_MEDIA_50GBASE_KR] = ETHTOOL_LINK_MODE_50000baseKR_Full_BIT,
[NFP_MEDIA_50GBASE_SR] = ETHTOOL_LINK_MODE_50000baseSR_Full_BIT,
[NFP_MEDIA_50GBASE_CR] = ETHTOOL_LINK_MODE_50000baseCR_Full_BIT,
[NFP_MEDIA_50GBASE_LR] = ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT,
[NFP_MEDIA_50GBASE_ER] = ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT,
[NFP_MEDIA_50GBASE_FR] = ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT,
[NFP_MEDIA_100GBASE_KR4] = ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT,
[NFP_MEDIA_100GBASE_SR4] = ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT,
[NFP_MEDIA_100GBASE_CR4] = ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT,
[NFP_MEDIA_100GBASE_KP4] = ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT,
[NFP_MEDIA_100GBASE_CR10] = ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT,
static const struct nfp_eth_media_link_mode {
u16 ethtool_link_mode;
u16 speed;
} nfp_eth_media_table[NFP_MEDIA_LINK_MODES_NUMBER] = {
[NFP_MEDIA_1000BASE_CX] = {
.ethtool_link_mode = ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
.speed = NFP_SPEED_1G,
},
[NFP_MEDIA_1000BASE_KX] = {
.ethtool_link_mode = ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
.speed = NFP_SPEED_1G,
},
[NFP_MEDIA_10GBASE_KX4] = {
.ethtool_link_mode = ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
.speed = NFP_SPEED_10G,
},
[NFP_MEDIA_10GBASE_KR] = {
.ethtool_link_mode = ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
.speed = NFP_SPEED_10G,
},
[NFP_MEDIA_10GBASE_CX4] = {
.ethtool_link_mode = ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
.speed = NFP_SPEED_10G,
},
[NFP_MEDIA_10GBASE_CR] = {
.ethtool_link_mode = ETHTOOL_LINK_MODE_10000baseCR_Full_BIT,
.speed = NFP_SPEED_10G,
},
[NFP_MEDIA_10GBASE_SR] = {
.ethtool_link_mode = ETHTOOL_LINK_MODE_10000baseSR_Full_BIT,
.speed = NFP_SPEED_10G,
},
[NFP_MEDIA_10GBASE_ER] = {
.ethtool_link_mode = ETHTOOL_LINK_MODE_10000baseER_Full_BIT,
.speed = NFP_SPEED_10G,
},
[NFP_MEDIA_25GBASE_KR] = {
.ethtool_link_mode = ETHTOOL_LINK_MODE_25000baseKR_Full_BIT,
.speed = NFP_SPEED_25G,
},
[NFP_MEDIA_25GBASE_KR_S] = {
.ethtool_link_mode = ETHTOOL_LINK_MODE_25000baseKR_Full_BIT,
.speed = NFP_SPEED_25G,
},
[NFP_MEDIA_25GBASE_CR] = {
.ethtool_link_mode = ETHTOOL_LINK_MODE_25000baseCR_Full_BIT,
.speed = NFP_SPEED_25G,
},
[NFP_MEDIA_25GBASE_CR_S] = {
.ethtool_link_mode = ETHTOOL_LINK_MODE_25000baseCR_Full_BIT,
.speed = NFP_SPEED_25G,
},
[NFP_MEDIA_25GBASE_SR] = {
.ethtool_link_mode = ETHTOOL_LINK_MODE_25000baseSR_Full_BIT,
.speed = NFP_SPEED_25G,
},
[NFP_MEDIA_40GBASE_CR4] = {
.ethtool_link_mode = ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT,
.speed = NFP_SPEED_40G,
},
[NFP_MEDIA_40GBASE_KR4] = {
.ethtool_link_mode = ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT,
.speed = NFP_SPEED_40G,
},
[NFP_MEDIA_40GBASE_SR4] = {
.ethtool_link_mode = ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT,
.speed = NFP_SPEED_40G,
},
[NFP_MEDIA_40GBASE_LR4] = {
.ethtool_link_mode = ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT,
.speed = NFP_SPEED_40G,
},
[NFP_MEDIA_50GBASE_KR] = {
.ethtool_link_mode = ETHTOOL_LINK_MODE_50000baseKR_Full_BIT,
.speed = NFP_SPEED_50G,
},
[NFP_MEDIA_50GBASE_SR] = {
.ethtool_link_mode = ETHTOOL_LINK_MODE_50000baseSR_Full_BIT,
.speed = NFP_SPEED_50G,
},
[NFP_MEDIA_50GBASE_CR] = {
.ethtool_link_mode = ETHTOOL_LINK_MODE_50000baseCR_Full_BIT,
.speed = NFP_SPEED_50G,
},
[NFP_MEDIA_50GBASE_LR] = {
.ethtool_link_mode = ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT,
.speed = NFP_SPEED_50G,
},
[NFP_MEDIA_50GBASE_ER] = {
.ethtool_link_mode = ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT,
.speed = NFP_SPEED_50G,
},
[NFP_MEDIA_50GBASE_FR] = {
.ethtool_link_mode = ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT,
.speed = NFP_SPEED_50G,
},
[NFP_MEDIA_100GBASE_KR4] = {
.ethtool_link_mode = ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT,
.speed = NFP_SPEED_100G,
},
[NFP_MEDIA_100GBASE_SR4] = {
.ethtool_link_mode = ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT,
.speed = NFP_SPEED_100G,
},
[NFP_MEDIA_100GBASE_CR4] = {
.ethtool_link_mode = ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT,
.speed = NFP_SPEED_100G,
},
[NFP_MEDIA_100GBASE_KP4] = {
.ethtool_link_mode = ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT,
.speed = NFP_SPEED_100G,
},
[NFP_MEDIA_100GBASE_CR10] = {
.ethtool_link_mode = ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT,
.speed = NFP_SPEED_100G,
},
};
static const unsigned int nfp_eth_speed_map[NFP_SUP_SPEED_NUMBER] = {
[NFP_SPEED_1G] = SPEED_1000,
[NFP_SPEED_10G] = SPEED_10000,
[NFP_SPEED_25G] = SPEED_25000,
[NFP_SPEED_40G] = SPEED_40000,
[NFP_SPEED_50G] = SPEED_50000,
[NFP_SPEED_100G] = SPEED_100000,
};
static void nfp_add_media_link_mode(struct nfp_port *port,
@ -334,8 +430,12 @@ static void nfp_add_media_link_mode(struct nfp_port *port,
};
struct nfp_cpp *cpp = port->app->cpp;
if (nfp_eth_read_media(cpp, &ethm))
if (nfp_eth_read_media(cpp, &ethm)) {
bitmap_fill(port->speed_bitmap, NFP_SUP_SPEED_NUMBER);
return;
}
bitmap_zero(port->speed_bitmap, NFP_SUP_SPEED_NUMBER);
for (u32 i = 0; i < 2; i++) {
supported_modes[i] = le64_to_cpu(ethm.supported_modes[i]);
@ -344,20 +444,26 @@ static void nfp_add_media_link_mode(struct nfp_port *port,
for (u32 i = 0; i < NFP_MEDIA_LINK_MODES_NUMBER; i++) {
if (i < 64) {
if (supported_modes[0] & BIT_ULL(i))
__set_bit(nfp_eth_media_table[i],
if (supported_modes[0] & BIT_ULL(i)) {
__set_bit(nfp_eth_media_table[i].ethtool_link_mode,
cmd->link_modes.supported);
__set_bit(nfp_eth_media_table[i].speed,
port->speed_bitmap);
}
if (advertised_modes[0] & BIT_ULL(i))
__set_bit(nfp_eth_media_table[i],
__set_bit(nfp_eth_media_table[i].ethtool_link_mode,
cmd->link_modes.advertising);
} else {
if (supported_modes[1] & BIT_ULL(i - 64))
__set_bit(nfp_eth_media_table[i],
if (supported_modes[1] & BIT_ULL(i - 64)) {
__set_bit(nfp_eth_media_table[i].ethtool_link_mode,
cmd->link_modes.supported);
__set_bit(nfp_eth_media_table[i].speed,
port->speed_bitmap);
}
if (advertised_modes[1] & BIT_ULL(i - 64))
__set_bit(nfp_eth_media_table[i],
__set_bit(nfp_eth_media_table[i].ethtool_link_mode,
cmd->link_modes.advertising);
}
}
@ -468,6 +574,22 @@ nfp_net_set_link_ksettings(struct net_device *netdev,
if (cmd->base.speed != SPEED_UNKNOWN) {
u32 speed = cmd->base.speed / eth_port->lanes;
bool is_supported = false;
for (u32 i = 0; i < NFP_SUP_SPEED_NUMBER; i++) {
if (cmd->base.speed == nfp_eth_speed_map[i] &&
test_bit(i, port->speed_bitmap)) {
is_supported = true;
break;
}
}
if (!is_supported) {
netdev_err(netdev, "Speed %u is not supported.\n",
cmd->base.speed);
err = -EINVAL;
goto err_bad_set;
}
if (req_aneg) {
netdev_err(netdev, "Speed changing is not allowed when working on autoneg mode.\n");

View File

@ -38,6 +38,16 @@ enum nfp_port_flags {
NFP_PORT_CHANGED = 0,
};
enum {
NFP_SPEED_1G,
NFP_SPEED_10G,
NFP_SPEED_25G,
NFP_SPEED_40G,
NFP_SPEED_50G,
NFP_SPEED_100G,
NFP_SUP_SPEED_NUMBER
};
/**
* struct nfp_port - structure representing NFP port
* @netdev: backpointer to associated netdev
@ -52,6 +62,7 @@ enum nfp_port_flags {
* @eth_forced: for %NFP_PORT_PHYS_PORT port is forced UP or DOWN, don't change
* @eth_port: for %NFP_PORT_PHYS_PORT translated ETH Table port entry
* @eth_stats: for %NFP_PORT_PHYS_PORT MAC stats if available
* @speed_bitmap: for %NFP_PORT_PHYS_PORT supported speed bitmap
* @pf_id: for %NFP_PORT_PF_PORT, %NFP_PORT_VF_PORT ID of the PCI PF (0-3)
* @vf_id: for %NFP_PORT_VF_PORT ID of the PCI VF within @pf_id
* @pf_split: for %NFP_PORT_PF_PORT %true if PCI PF has more than one vNIC
@ -78,6 +89,7 @@ struct nfp_port {
bool eth_forced;
struct nfp_eth_table_port *eth_port;
u8 __iomem *eth_stats;
DECLARE_BITMAP(speed_bitmap, NFP_SUP_SPEED_NUMBER);
};
/* NFP_PORT_PF_PORT, NFP_PORT_VF_PORT */
struct {