@@ -65,6 +65,7 @@ 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
@@ -114,6 +115,7 @@ struct nfp_pf {
bool fw_loaded;
bool unload_fw_on_remove;
+ bool sp_indiff;
struct nfp_net *ctrl_vnic;
@@ -148,6 +148,14 @@ 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;
@@ -492,6 +492,10 @@
* %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
@@ -505,6 +509,7 @@
#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;
@@ -519,6 +524,7 @@ 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;
@@ -531,6 +537,7 @@ 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,
@@ -206,6 +206,7 @@ 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)
@@ -307,6 +308,37 @@ static int nfp_net_pf_init_vnics(struct nfp_pf *pf)
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)
{
@@ -318,6 +350,8 @@ 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);
@@ -780,10 +814,14 @@ int nfp_net_pci_probe(struct nfp_pf *pf)
if (err)
goto err_clean_ddir;
- err = nfp_net_pf_alloc_irqs(pf);
+ 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;
+
err = nfp_net_pf_app_start(pf);
if (err)
goto err_free_irqs;
@@ -801,6 +839,8 @@ int nfp_net_pci_probe(struct nfp_pf *pf)
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:
@@ -831,6 +871,7 @@ 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);