Merge branch 'nfp-support-fec-mode-reporting-and-auto-neg'
Simon Horman says: ==================== nfp: support FEC mode reporting and auto-neg this series adds support for the following features to the nfp driver: * Patch 1/5: Support active FEC mode * Patch 2/5: Don't halt driver on non-fatal error when interacting with fw * Patch 3/5: Treat port independence as a firmware rather than port property * Patch 4/5: Support link auto negotiation * Patch 5/5: Support restart of link auto negotiation ==================== Link: https://lore.kernel.org/r/20220929085832.622510-1-simon.horman@corigine.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
5fcc2cfc14
|
@ -691,6 +691,71 @@ static int nfp_pf_find_rtsyms(struct nfp_pf *pf)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int nfp_net_pf_get_app_id(struct nfp_pf *pf)
|
||||
{
|
||||
return nfp_pf_rtsym_read_optional(pf, "_pf%u_net_app_id",
|
||||
NFP_APP_CORE_NIC);
|
||||
}
|
||||
|
||||
static u64 nfp_net_pf_get_app_cap(struct nfp_pf *pf)
|
||||
{
|
||||
char name[32];
|
||||
int err = 0;
|
||||
u64 val;
|
||||
|
||||
snprintf(name, sizeof(name), "_pf%u_net_app_cap", nfp_cppcore_pcie_unit(pf->cpp));
|
||||
|
||||
val = nfp_rtsym_read_le(pf->rtbl, name, &err);
|
||||
if (err) {
|
||||
if (err != -ENOENT)
|
||||
nfp_err(pf->cpp, "Unable to read symbol %s\n", name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static int nfp_pf_cfg_hwinfo(struct nfp_pf *pf, bool sp_indiff)
|
||||
{
|
||||
struct nfp_nsp *nsp;
|
||||
char hwinfo[32];
|
||||
int err;
|
||||
|
||||
nsp = nfp_nsp_open(pf->cpp);
|
||||
if (IS_ERR(nsp))
|
||||
return PTR_ERR(nsp);
|
||||
|
||||
snprintf(hwinfo, sizeof(hwinfo), "sp_indiff=%d", sp_indiff);
|
||||
err = nfp_nsp_hwinfo_set(nsp, hwinfo, sizeof(hwinfo));
|
||||
/* Not a fatal error, no need to return error to stop driver from loading */
|
||||
if (err) {
|
||||
nfp_warn(pf->cpp, "HWinfo(sp_indiff=%d) set failed: %d\n", sp_indiff, err);
|
||||
} else {
|
||||
/* Need reinit eth_tbl since the eth table state may change
|
||||
* after sp_indiff is configured.
|
||||
*/
|
||||
kfree(pf->eth_tbl);
|
||||
pf->eth_tbl = __nfp_eth_read_ports(pf->cpp, nsp);
|
||||
}
|
||||
|
||||
nfp_nsp_close(nsp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nfp_pf_nsp_cfg(struct nfp_pf *pf)
|
||||
{
|
||||
bool sp_indiff = (nfp_net_pf_get_app_id(pf) == NFP_APP_FLOWER_NIC) ||
|
||||
(nfp_net_pf_get_app_cap(pf) & NFP_NET_APP_CAP_SP_INDIFF);
|
||||
|
||||
return nfp_pf_cfg_hwinfo(pf, sp_indiff);
|
||||
}
|
||||
|
||||
static void nfp_pf_nsp_clean(struct nfp_pf *pf)
|
||||
{
|
||||
nfp_pf_cfg_hwinfo(pf, false);
|
||||
}
|
||||
|
||||
static int nfp_pci_probe(struct pci_dev *pdev,
|
||||
const struct pci_device_id *pci_id)
|
||||
{
|
||||
|
@ -791,10 +856,14 @@ static int nfp_pci_probe(struct pci_dev *pdev,
|
|||
goto err_fw_unload;
|
||||
}
|
||||
|
||||
err = nfp_net_pci_probe(pf);
|
||||
err = nfp_pf_nsp_cfg(pf);
|
||||
if (err)
|
||||
goto err_fw_unload;
|
||||
|
||||
err = nfp_net_pci_probe(pf);
|
||||
if (err)
|
||||
goto err_nsp_clean;
|
||||
|
||||
err = nfp_hwmon_register(pf);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "Failed to register hwmon info\n");
|
||||
|
@ -805,6 +874,8 @@ static int nfp_pci_probe(struct pci_dev *pdev,
|
|||
|
||||
err_net_remove:
|
||||
nfp_net_pci_remove(pf);
|
||||
err_nsp_clean:
|
||||
nfp_pf_nsp_clean(pf);
|
||||
err_fw_unload:
|
||||
kfree(pf->rtbl);
|
||||
nfp_mip_close(pf->mip);
|
||||
|
@ -844,6 +915,7 @@ static void __nfp_pci_shutdown(struct pci_dev *pdev, bool unload_fw)
|
|||
|
||||
nfp_net_pci_remove(pf);
|
||||
|
||||
nfp_pf_nsp_clean(pf);
|
||||
vfree(pf->dumpspec);
|
||||
kfree(pf->rtbl);
|
||||
nfp_mip_close(pf->mip);
|
||||
|
|
|
@ -65,7 +65,6 @@ struct nfp_dumpspec {
|
|||
* @num_vfs: Number of SR-IOV VFs enabled
|
||||
* @fw_loaded: Is the firmware loaded?
|
||||
* @unload_fw_on_remove:Do we need to unload firmware on driver removal?
|
||||
* @sp_indiff: Is the firmware indifferent to physical port speed?
|
||||
* @ctrl_vnic: Pointer to the control vNIC if available
|
||||
* @mip: MIP handle
|
||||
* @rtbl: RTsym table
|
||||
|
@ -115,7 +114,6 @@ struct nfp_pf {
|
|||
|
||||
bool fw_loaded;
|
||||
bool unload_fw_on_remove;
|
||||
bool sp_indiff;
|
||||
|
||||
struct nfp_net *ctrl_vnic;
|
||||
|
||||
|
@ -163,6 +161,7 @@ bool nfp_ctrl_tx(struct nfp_net *nn, struct sk_buff *skb);
|
|||
|
||||
int nfp_pf_rtsym_read_optional(struct nfp_pf *pf, const char *format,
|
||||
unsigned int default_val);
|
||||
int nfp_net_pf_get_app_id(struct nfp_pf *pf);
|
||||
u8 __iomem *
|
||||
nfp_pf_map_rtsym(struct nfp_pf *pf, const char *name, const char *sym_fmt,
|
||||
unsigned int min_size, struct nfp_cpp_area **area);
|
||||
|
|
|
@ -148,14 +148,6 @@ int nfp_net_tlv_caps_parse(struct device *dev, u8 __iomem *ctrl_mem,
|
|||
true))
|
||||
return -EINVAL;
|
||||
break;
|
||||
case NFP_NET_CFG_TLV_TYPE_SP_INDIFF:
|
||||
if (length) {
|
||||
dev_err(dev, "Unexpected len of SP_INDIFF TLV:%u\n", length);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
caps->sp_indiff = true;
|
||||
break;
|
||||
default:
|
||||
if (!FIELD_GET(NFP_NET_CFG_TLV_HEADER_REQUIRED, hdr))
|
||||
break;
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
#include <linux/types.h>
|
||||
|
||||
/* 64-bit per app capabilities */
|
||||
#define NFP_NET_APP_CAP_SP_INDIFF BIT_ULL(0) /* indifferent to port speed */
|
||||
|
||||
/* Configuration BAR size.
|
||||
*
|
||||
* The configuration BAR is 8K in size, but due to
|
||||
|
@ -492,10 +495,6 @@
|
|||
* %NFP_NET_CFG_TLV_TYPE_CRYPTO_OPS_RX_SCAN:
|
||||
* Same as %NFP_NET_CFG_TLV_TYPE_CRYPTO_OPS, but crypto TLS does stream scan
|
||||
* RX sync, rather than kernel-assisted sync.
|
||||
*
|
||||
* %NFP_NET_CFG_TLV_TYPE_SP_INDIFF:
|
||||
* Empty, indicate the firmware is indifferent to port speed. Then no need to
|
||||
* reload driver and firmware when port speed is changed.
|
||||
*/
|
||||
#define NFP_NET_CFG_TLV_TYPE_UNKNOWN 0
|
||||
#define NFP_NET_CFG_TLV_TYPE_RESERVED 1
|
||||
|
@ -509,7 +508,6 @@
|
|||
#define NFP_NET_CFG_TLV_TYPE_CRYPTO_OPS 11 /* see crypto/fw.h */
|
||||
#define NFP_NET_CFG_TLV_TYPE_VNIC_STATS 12
|
||||
#define NFP_NET_CFG_TLV_TYPE_CRYPTO_OPS_RX_SCAN 13
|
||||
#define NFP_NET_CFG_TLV_TYPE_SP_INDIFF 14
|
||||
|
||||
struct device;
|
||||
|
||||
|
@ -524,7 +522,6 @@ struct device;
|
|||
* @vnic_stats_off: offset of vNIC stats area
|
||||
* @vnic_stats_cnt: number of vNIC stats
|
||||
* @tls_resync_ss: TLS resync will be performed via stream scan
|
||||
* @sp_indiff: Firmware is indifferent to port speed
|
||||
*/
|
||||
struct nfp_net_tlv_caps {
|
||||
u32 me_freq_mhz;
|
||||
|
@ -537,7 +534,6 @@ struct nfp_net_tlv_caps {
|
|||
unsigned int vnic_stats_off;
|
||||
unsigned int vnic_stats_cnt;
|
||||
unsigned int tls_resync_ss:1;
|
||||
unsigned int sp_indiff:1;
|
||||
};
|
||||
|
||||
int nfp_net_tlv_caps_parse(struct device *dev, u8 __iomem *ctrl_mem,
|
||||
|
|
|
@ -228,6 +228,37 @@ nfp_net_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
|
|||
nfp_get_drvinfo(nn->app, nn->pdev, vnic_version, drvinfo);
|
||||
}
|
||||
|
||||
static int
|
||||
nfp_net_nway_reset(struct net_device *netdev)
|
||||
{
|
||||
struct nfp_eth_table_port *eth_port;
|
||||
struct nfp_port *port;
|
||||
int err;
|
||||
|
||||
port = nfp_port_from_netdev(netdev);
|
||||
eth_port = nfp_port_get_eth_port(port);
|
||||
if (!eth_port)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!netif_running(netdev))
|
||||
return 0;
|
||||
|
||||
err = nfp_eth_set_configured(port->app->cpp, eth_port->index, false);
|
||||
if (err) {
|
||||
netdev_info(netdev, "Link down failed: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = nfp_eth_set_configured(port->app->cpp, eth_port->index, true);
|
||||
if (err) {
|
||||
netdev_info(netdev, "Link up failed: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
netdev_info(netdev, "Link reset succeeded\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
nfp_app_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
|
||||
{
|
||||
|
@ -290,8 +321,13 @@ nfp_net_get_link_ksettings(struct net_device *netdev,
|
|||
if (eth_port) {
|
||||
ethtool_link_ksettings_add_link_mode(cmd, supported, Pause);
|
||||
ethtool_link_ksettings_add_link_mode(cmd, advertising, Pause);
|
||||
cmd->base.autoneg = eth_port->aneg != NFP_ANEG_DISABLED ?
|
||||
AUTONEG_ENABLE : AUTONEG_DISABLE;
|
||||
if (eth_port->supp_aneg) {
|
||||
ethtool_link_ksettings_add_link_mode(cmd, supported, Autoneg);
|
||||
if (eth_port->aneg == NFP_ANEG_AUTO) {
|
||||
ethtool_link_ksettings_add_link_mode(cmd, advertising, Autoneg);
|
||||
cmd->base.autoneg = AUTONEG_ENABLE;
|
||||
}
|
||||
}
|
||||
nfp_net_set_fec_link_mode(eth_port, cmd);
|
||||
}
|
||||
|
||||
|
@ -327,6 +363,7 @@ static int
|
|||
nfp_net_set_link_ksettings(struct net_device *netdev,
|
||||
const struct ethtool_link_ksettings *cmd)
|
||||
{
|
||||
bool req_aneg = (cmd->base.autoneg == AUTONEG_ENABLE);
|
||||
struct nfp_eth_table_port *eth_port;
|
||||
struct nfp_port *port;
|
||||
struct nfp_nsp *nsp;
|
||||
|
@ -346,13 +383,25 @@ nfp_net_set_link_ksettings(struct net_device *netdev,
|
|||
if (IS_ERR(nsp))
|
||||
return PTR_ERR(nsp);
|
||||
|
||||
err = __nfp_eth_set_aneg(nsp, cmd->base.autoneg == AUTONEG_ENABLE ?
|
||||
NFP_ANEG_AUTO : NFP_ANEG_DISABLED);
|
||||
if (req_aneg && !eth_port->supp_aneg) {
|
||||
netdev_warn(netdev, "Autoneg is not supported.\n");
|
||||
err = -EOPNOTSUPP;
|
||||
goto err_bad_set;
|
||||
}
|
||||
|
||||
err = __nfp_eth_set_aneg(nsp, req_aneg ? NFP_ANEG_AUTO : NFP_ANEG_DISABLED);
|
||||
if (err)
|
||||
goto err_bad_set;
|
||||
|
||||
if (cmd->base.speed != SPEED_UNKNOWN) {
|
||||
u32 speed = cmd->base.speed / eth_port->lanes;
|
||||
|
||||
if (req_aneg) {
|
||||
netdev_err(netdev, "Speed changing is not allowed when working on autoneg mode.\n");
|
||||
err = -EINVAL;
|
||||
goto err_bad_set;
|
||||
}
|
||||
|
||||
err = __nfp_eth_set_speed(nsp, speed);
|
||||
if (err)
|
||||
goto err_bad_set;
|
||||
|
@ -996,7 +1045,7 @@ nfp_port_get_fecparam(struct net_device *netdev,
|
|||
return 0;
|
||||
|
||||
param->fec = nfp_port_fec_nsp_to_ethtool(eth_port->fec_modes_supported);
|
||||
param->active_fec = nfp_port_fec_nsp_to_ethtool(eth_port->fec);
|
||||
param->active_fec = nfp_port_fec_nsp_to_ethtool(BIT(eth_port->act_fec));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1823,6 +1872,7 @@ static const struct ethtool_ops nfp_net_ethtool_ops = {
|
|||
ETHTOOL_COALESCE_MAX_FRAMES |
|
||||
ETHTOOL_COALESCE_USE_ADAPTIVE,
|
||||
.get_drvinfo = nfp_net_get_drvinfo,
|
||||
.nway_reset = nfp_net_nway_reset,
|
||||
.get_link = ethtool_op_get_link,
|
||||
.get_ringparam = nfp_net_get_ringparam,
|
||||
.set_ringparam = nfp_net_set_ringparam,
|
||||
|
@ -1860,6 +1910,7 @@ static const struct ethtool_ops nfp_net_ethtool_ops = {
|
|||
|
||||
const struct ethtool_ops nfp_port_ethtool_ops = {
|
||||
.get_drvinfo = nfp_app_get_drvinfo,
|
||||
.nway_reset = nfp_net_nway_reset,
|
||||
.get_link = ethtool_op_get_link,
|
||||
.get_strings = nfp_port_get_strings,
|
||||
.get_ethtool_stats = nfp_port_get_stats,
|
||||
|
|
|
@ -77,12 +77,6 @@ static int nfp_net_pf_get_num_ports(struct nfp_pf *pf)
|
|||
return nfp_pf_rtsym_read_optional(pf, "nfd_cfg_pf%u_num_ports", 1);
|
||||
}
|
||||
|
||||
static int nfp_net_pf_get_app_id(struct nfp_pf *pf)
|
||||
{
|
||||
return nfp_pf_rtsym_read_optional(pf, "_pf%u_net_app_id",
|
||||
NFP_APP_CORE_NIC);
|
||||
}
|
||||
|
||||
static void nfp_net_pf_free_vnic(struct nfp_pf *pf, struct nfp_net *nn)
|
||||
{
|
||||
if (nfp_net_is_data_vnic(nn))
|
||||
|
@ -206,7 +200,6 @@ nfp_net_pf_alloc_vnics(struct nfp_pf *pf, void __iomem *ctrl_bar,
|
|||
nn->port->link_cb = nfp_net_refresh_port_table;
|
||||
|
||||
ctrl_bar += NFP_PF_CSR_SLICE_SIZE;
|
||||
pf->sp_indiff |= nn->tlv_caps.sp_indiff;
|
||||
|
||||
/* Kill the vNIC if app init marked it as invalid */
|
||||
if (nn->port && nn->port->type == NFP_PORT_INVALID)
|
||||
|
@ -308,37 +301,6 @@ err_prev_deinit:
|
|||
return err;
|
||||
}
|
||||
|
||||
static int nfp_net_pf_cfg_nsp(struct nfp_pf *pf, bool sp_indiff)
|
||||
{
|
||||
struct nfp_nsp *nsp;
|
||||
char hwinfo[32];
|
||||
int err;
|
||||
|
||||
nsp = nfp_nsp_open(pf->cpp);
|
||||
if (IS_ERR(nsp)) {
|
||||
err = PTR_ERR(nsp);
|
||||
return err;
|
||||
}
|
||||
|
||||
snprintf(hwinfo, sizeof(hwinfo), "sp_indiff=%d", sp_indiff);
|
||||
err = nfp_nsp_hwinfo_set(nsp, hwinfo, sizeof(hwinfo));
|
||||
if (err)
|
||||
nfp_warn(pf->cpp, "HWinfo(sp_indiff=%d) set failed: %d\n", sp_indiff, err);
|
||||
|
||||
nfp_nsp_close(nsp);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int nfp_net_pf_init_nsp(struct nfp_pf *pf)
|
||||
{
|
||||
return nfp_net_pf_cfg_nsp(pf, pf->sp_indiff);
|
||||
}
|
||||
|
||||
static void nfp_net_pf_clean_nsp(struct nfp_pf *pf)
|
||||
{
|
||||
(void)nfp_net_pf_cfg_nsp(pf, false);
|
||||
}
|
||||
|
||||
static int
|
||||
nfp_net_pf_app_init(struct nfp_pf *pf, u8 __iomem *qc_bar, unsigned int stride)
|
||||
{
|
||||
|
@ -350,8 +312,6 @@ nfp_net_pf_app_init(struct nfp_pf *pf, u8 __iomem *qc_bar, unsigned int stride)
|
|||
if (IS_ERR(pf->app))
|
||||
return PTR_ERR(pf->app);
|
||||
|
||||
pf->sp_indiff |= pf->app->type->id == NFP_APP_FLOWER_NIC;
|
||||
|
||||
devl_lock(devlink);
|
||||
err = nfp_app_init(pf->app);
|
||||
devl_unlock(devlink);
|
||||
|
@ -814,13 +774,9 @@ int nfp_net_pci_probe(struct nfp_pf *pf)
|
|||
if (err)
|
||||
goto err_clean_ddir;
|
||||
|
||||
err = nfp_net_pf_init_nsp(pf);
|
||||
if (err)
|
||||
goto err_free_vnics;
|
||||
|
||||
err = nfp_net_pf_alloc_irqs(pf);
|
||||
if (err)
|
||||
goto err_clean_nsp;
|
||||
goto err_free_vnics;
|
||||
|
||||
err = nfp_net_pf_app_start(pf);
|
||||
if (err)
|
||||
|
@ -839,8 +795,6 @@ err_stop_app:
|
|||
nfp_net_pf_app_stop(pf);
|
||||
err_free_irqs:
|
||||
nfp_net_pf_free_irqs(pf);
|
||||
err_clean_nsp:
|
||||
nfp_net_pf_clean_nsp(pf);
|
||||
err_free_vnics:
|
||||
nfp_net_pf_free_vnics(pf);
|
||||
err_clean_ddir:
|
||||
|
@ -871,7 +825,6 @@ void nfp_net_pci_remove(struct nfp_pf *pf)
|
|||
nfp_net_pf_free_vnic(pf, nn);
|
||||
}
|
||||
|
||||
nfp_net_pf_clean_nsp(pf);
|
||||
nfp_net_pf_app_stop(pf);
|
||||
/* stop app first, to avoid double free of ctrl vNIC's ddir */
|
||||
nfp_net_debugfs_dir_clean(&pf->ddir);
|
||||
|
|
|
@ -132,6 +132,7 @@ enum nfp_eth_fec {
|
|||
* @ports.interface: interface (module) plugged in
|
||||
* @ports.media: media type of the @interface
|
||||
* @ports.fec: forward error correction mode
|
||||
* @ports.act_fec: active forward error correction mode
|
||||
* @ports.aneg: auto negotiation mode
|
||||
* @ports.mac_addr: interface MAC address
|
||||
* @ports.label_port: port id
|
||||
|
@ -162,6 +163,7 @@ struct nfp_eth_table {
|
|||
enum nfp_eth_media media;
|
||||
|
||||
enum nfp_eth_fec fec;
|
||||
enum nfp_eth_fec act_fec;
|
||||
enum nfp_eth_aneg aneg;
|
||||
|
||||
u8 mac_addr[ETH_ALEN];
|
||||
|
@ -172,6 +174,7 @@ struct nfp_eth_table {
|
|||
bool enabled;
|
||||
bool tx_enabled;
|
||||
bool rx_enabled;
|
||||
bool supp_aneg;
|
||||
|
||||
bool override_changed;
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#define NSP_ETH_PORT_PHYLABEL GENMASK_ULL(59, 54)
|
||||
#define NSP_ETH_PORT_FEC_SUPP_BASER BIT_ULL(60)
|
||||
#define NSP_ETH_PORT_FEC_SUPP_RS BIT_ULL(61)
|
||||
#define NSP_ETH_PORT_SUPP_ANEG BIT_ULL(63)
|
||||
|
||||
#define NSP_ETH_PORT_LANES_MASK cpu_to_le64(NSP_ETH_PORT_LANES)
|
||||
|
||||
|
@ -40,6 +41,7 @@
|
|||
#define NSP_ETH_STATE_OVRD_CHNG BIT_ULL(22)
|
||||
#define NSP_ETH_STATE_ANEG GENMASK_ULL(25, 23)
|
||||
#define NSP_ETH_STATE_FEC GENMASK_ULL(27, 26)
|
||||
#define NSP_ETH_STATE_ACT_FEC GENMASK_ULL(29, 28)
|
||||
|
||||
#define NSP_ETH_CTRL_CONFIGURED BIT_ULL(0)
|
||||
#define NSP_ETH_CTRL_ENABLED BIT_ULL(1)
|
||||
|
@ -170,7 +172,14 @@ nfp_eth_port_translate(struct nfp_nsp *nsp, const union eth_table_entry *src,
|
|||
if (dst->fec_modes_supported)
|
||||
dst->fec_modes_supported |= NFP_FEC_AUTO | NFP_FEC_DISABLED;
|
||||
|
||||
dst->fec = 1 << FIELD_GET(NSP_ETH_STATE_FEC, state);
|
||||
dst->fec = FIELD_GET(NSP_ETH_STATE_FEC, state);
|
||||
dst->act_fec = dst->fec;
|
||||
|
||||
if (nfp_nsp_get_abi_ver_minor(nsp) < 33)
|
||||
return;
|
||||
|
||||
dst->act_fec = FIELD_GET(NSP_ETH_STATE_ACT_FEC, state);
|
||||
dst->supp_aneg = FIELD_GET(NSP_ETH_PORT_SUPP_ANEG, port);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
Loading…
Reference in New Issue