net/nfp: write link speed to control BAR

Message ID 20230221062955.34210-1-chaoyong.he@corigine.com (mailing list archive)
State Superseded, archived
Delegated to: Ferruh Yigit
Headers
Series net/nfp: write link speed to control BAR |

Checks

Context Check Description
ci/checkpatch success coding style OK
ci/loongarch-compilation success Compilation OK
ci/loongarch-unit-testing success Unit Testing PASS
ci/Intel-compilation success Compilation OK
ci/iol-broadcom-Performance success Performance Testing PASS
ci/iol-mellanox-Performance success Performance Testing PASS
ci/intel-Testing success Testing PASS
ci/iol-intel-Performance success Performance Testing PASS
ci/iol-broadcom-Functional success Functional Testing PASS
ci/iol-intel-Functional success Functional Testing PASS
ci/github-robot: build success github build: passed
ci/iol-testing success Testing PASS
ci/iol-x86_64-unit-testing success Testing PASS
ci/iol-x86_64-compile-testing success Testing PASS
ci/iol-abi-testing success Testing PASS

Commit Message

Chaoyong He Feb. 21, 2023, 6:29 a.m. UTC
  From: James Hershaw <james.hershaw@corigine.com>

Due to changes in the firmware for NFPs, firmware will no longer write
the link speed of a port to the control BAR. In line with the behaviour
of the kernel NFP driver, this is now handled by the PMD by reading the
value provided by the NSP in the nfp_eth_table struct within the pf_dev
of the port and subsequently writing this value to the control BAR.

Signed-off-by: James Hershaw <james.hershaw@corigine.com>
Reviewed-by: Niklas Söderlund <niklas.soderlund@corigine.com>
Reviewed-by: Chaoyong He <chaoyong.he@corigine.com>
---
 drivers/net/nfp/nfp_common.c | 90 ++++++++++++++++++++++--------------
 drivers/net/nfp/nfp_ctrl.h   |  9 ++++
 2 files changed, 65 insertions(+), 34 deletions(-)
  

Comments

Ferruh Yigit Feb. 23, 2023, 4:39 p.m. UTC | #1
On 2/21/2023 6:29 AM, Chaoyong He wrote:
> From: James Hershaw <james.hershaw@corigine.com>
> 
> Due to changes in the firmware for NFPs, firmware will no longer write
> the link speed of a port to the control BAR. In line with the behaviour
> of the kernel NFP driver, this is now handled by the PMD by reading the
> value provided by the NSP in the nfp_eth_table struct within the pf_dev
> of the port and subsequently writing this value to the control BAR.
> 

Don't you need some kind of FW version check to figure out if
'NFP_NET_CFG_STS_NSP_LINK_RATE' needs to be updated by driver or not?

How do you manage driver <-> FW dependency?


> Signed-off-by: James Hershaw <james.hershaw@corigine.com>
> Reviewed-by: Niklas Söderlund <niklas.soderlund@corigine.com>
> Reviewed-by: Chaoyong He <chaoyong.he@corigine.com>
> ---
>  drivers/net/nfp/nfp_common.c | 90 ++++++++++++++++++++++--------------
>  drivers/net/nfp/nfp_ctrl.h   |  9 ++++
>  2 files changed, 65 insertions(+), 34 deletions(-)
> 
> diff --git a/drivers/net/nfp/nfp_common.c b/drivers/net/nfp/nfp_common.c
> index 5922bfea8e..006ea58008 100644
> --- a/drivers/net/nfp/nfp_common.c
> +++ b/drivers/net/nfp/nfp_common.c
> @@ -52,6 +52,53 @@
>  #include <sys/ioctl.h>
>  #include <errno.h>
>  
> +static const uint32_t nfp_net_link_speed_nfp2rte[] = {
> +	[NFP_NET_CFG_STS_LINK_RATE_UNSUPPORTED] = RTE_ETH_SPEED_NUM_NONE,
> +	[NFP_NET_CFG_STS_LINK_RATE_UNKNOWN]     = RTE_ETH_SPEED_NUM_NONE,
> +	[NFP_NET_CFG_STS_LINK_RATE_1G]          = RTE_ETH_SPEED_NUM_1G,
> +	[NFP_NET_CFG_STS_LINK_RATE_10G]         = RTE_ETH_SPEED_NUM_10G,
> +	[NFP_NET_CFG_STS_LINK_RATE_25G]         = RTE_ETH_SPEED_NUM_25G,
> +	[NFP_NET_CFG_STS_LINK_RATE_40G]         = RTE_ETH_SPEED_NUM_40G,
> +	[NFP_NET_CFG_STS_LINK_RATE_50G]         = RTE_ETH_SPEED_NUM_50G,
> +	[NFP_NET_CFG_STS_LINK_RATE_100G]        = RTE_ETH_SPEED_NUM_100G,
> +};
> +
> +static uint32_t
> +nfp_net_link_speed_rte2nfp(uint32_t speed)
> +{
> +	uint32_t i;
> +
> +	for (i = 0; i < RTE_DIM(nfp_net_link_speed_nfp2rte); i++) {
> +		if (speed == nfp_net_link_speed_nfp2rte[i])
> +			return i;
> +	}
> +
> +	return NFP_NET_CFG_STS_LINK_RATE_UNKNOWN;
> +}
> +
> +static void
> +nfp_net_notify_port_speed(struct rte_eth_dev *dev)
> +{
> +	struct nfp_net_hw *hw;
> +	struct nfp_eth_table *eth_table;
> +	uint32_t nn_link_status;
> +
> +	hw = NFP_NET_DEV_PRIVATE_TO_HW(dev->data->dev_private);
> +	eth_table = hw->pf_dev->nfp_eth_table;
> +
> +	nn_link_status = nn_cfg_readl(hw, NFP_NET_CFG_STS);
> +	nn_link_status = (nn_link_status >> NFP_NET_CFG_STS_LINK_RATE_SHIFT) &
> +			NFP_NET_CFG_STS_LINK_RATE_MASK;
> +
> +	if ((nn_link_status & NFP_NET_CFG_STS_LINK) == 0) {
> +		nn_cfg_writel(hw, NFP_NET_CFG_STS_NSP_LINK_RATE, NFP_NET_CFG_STS_LINK_RATE_UNKNOWN);
> +		return;
> +	}
> +
> +	nn_cfg_writel(hw, NFP_NET_CFG_STS_NSP_LINK_RATE,
> +		      nfp_net_link_speed_rte2nfp(eth_table->ports[hw->idx].speed));

PF driver writes link speed to 'NFP_NET_CFG_STS_NSP_LINK_RATE' register,
but 'nfp_net_link_update()' still gets it from 'NFP_NET_CFG_STS'
register (via 'nfp_net_link_speed_nfp2rte[nn_link_status]').

Shouldn't 'nfp_net_link_update()' needs to be updated to read speed from
'NFP_NET_CFG_STS_NSP_LINK_RATE' register?
  
Chaoyong He March 6, 2023, 7:06 a.m. UTC | #2
> On 2/21/2023 6:29 AM, Chaoyong He wrote:
> > From: James Hershaw <james.hershaw@corigine.com>
> >
> > Due to changes in the firmware for NFPs, firmware will no longer write
> > the link speed of a port to the control BAR. In line with the
> > behaviour of the kernel NFP driver, this is now handled by the PMD by
> > reading the value provided by the NSP in the nfp_eth_table struct
> > within the pf_dev of the port and subsequently writing this value to the
> control BAR.
> >
> 
> Don't you need some kind of FW version check to figure out if
> 'NFP_NET_CFG_STS_NSP_LINK_RATE' needs to be updated by driver or not?
> 
> How do you manage driver <-> FW dependency?
> 
> 
> > Signed-off-by: James Hershaw <james.hershaw@corigine.com>
> > Reviewed-by: Niklas Söderlund <niklas.soderlund@corigine.com>
> > Reviewed-by: Chaoyong He <chaoyong.he@corigine.com>
> > ---
> >  drivers/net/nfp/nfp_common.c | 90 ++++++++++++++++++++++-----------
> ---
> >  drivers/net/nfp/nfp_ctrl.h   |  9 ++++
> >  2 files changed, 65 insertions(+), 34 deletions(-)
> >
> > diff --git a/drivers/net/nfp/nfp_common.c
> > b/drivers/net/nfp/nfp_common.c index 5922bfea8e..006ea58008 100644
> > --- a/drivers/net/nfp/nfp_common.c
> > +++ b/drivers/net/nfp/nfp_common.c
> > @@ -52,6 +52,53 @@
> >  #include <sys/ioctl.h>
> >  #include <errno.h>
> >
> > +static const uint32_t nfp_net_link_speed_nfp2rte[] = {
> > +	[NFP_NET_CFG_STS_LINK_RATE_UNSUPPORTED] =
> RTE_ETH_SPEED_NUM_NONE,
> > +	[NFP_NET_CFG_STS_LINK_RATE_UNKNOWN]     =
> RTE_ETH_SPEED_NUM_NONE,
> > +	[NFP_NET_CFG_STS_LINK_RATE_1G]          =
> RTE_ETH_SPEED_NUM_1G,
> > +	[NFP_NET_CFG_STS_LINK_RATE_10G]         =
> RTE_ETH_SPEED_NUM_10G,
> > +	[NFP_NET_CFG_STS_LINK_RATE_25G]         =
> RTE_ETH_SPEED_NUM_25G,
> > +	[NFP_NET_CFG_STS_LINK_RATE_40G]         =
> RTE_ETH_SPEED_NUM_40G,
> > +	[NFP_NET_CFG_STS_LINK_RATE_50G]         =
> RTE_ETH_SPEED_NUM_50G,
> > +	[NFP_NET_CFG_STS_LINK_RATE_100G]        =
> RTE_ETH_SPEED_NUM_100G,
> > +};
> > +
> > +static uint32_t
> > +nfp_net_link_speed_rte2nfp(uint32_t speed) {
> > +	uint32_t i;
> > +
> > +	for (i = 0; i < RTE_DIM(nfp_net_link_speed_nfp2rte); i++) {
> > +		if (speed == nfp_net_link_speed_nfp2rte[i])
> > +			return i;
> > +	}
> > +
> > +	return NFP_NET_CFG_STS_LINK_RATE_UNKNOWN;
> > +}
> > +
> > +static void
> > +nfp_net_notify_port_speed(struct rte_eth_dev *dev) {
> > +	struct nfp_net_hw *hw;
> > +	struct nfp_eth_table *eth_table;
> > +	uint32_t nn_link_status;
> > +
> > +	hw = NFP_NET_DEV_PRIVATE_TO_HW(dev->data->dev_private);
> > +	eth_table = hw->pf_dev->nfp_eth_table;
> > +
> > +	nn_link_status = nn_cfg_readl(hw, NFP_NET_CFG_STS);
> > +	nn_link_status = (nn_link_status >>
> NFP_NET_CFG_STS_LINK_RATE_SHIFT) &
> > +			NFP_NET_CFG_STS_LINK_RATE_MASK;
> > +
> > +	if ((nn_link_status & NFP_NET_CFG_STS_LINK) == 0) {
> > +		nn_cfg_writel(hw, NFP_NET_CFG_STS_NSP_LINK_RATE,
> NFP_NET_CFG_STS_LINK_RATE_UNKNOWN);
> > +		return;
> > +	}
> > +
> > +	nn_cfg_writel(hw, NFP_NET_CFG_STS_NSP_LINK_RATE,
> > +		      nfp_net_link_speed_rte2nfp(eth_table->ports[hw-
> >idx].speed));
> 
> PF driver writes link speed to 'NFP_NET_CFG_STS_NSP_LINK_RATE' register,
> but 'nfp_net_link_update()' still gets it from 'NFP_NET_CFG_STS'
> register (via 'nfp_net_link_speed_nfp2rte[nn_link_status]').
> 
> Shouldn't 'nfp_net_link_update()' needs to be updated to read speed from
> 'NFP_NET_CFG_STS_NSP_LINK_RATE' register?

Sorry for the late response, we spend a lot of time to check and discuss.

For older firmware, a full word is allocated (NFP_NET_CFG_STS) to report link status and port speed to the driver.
However, in the interests of keeping FW files port-speed agnostic in the future, 
the upper 16 bits are no longer written to by FW, so we write the speed to that address (NFP_NET_CFG_STS_LINK_RATE).
The lower 16 bits (link status) are still handled by firmware.

These changes are completely backwards compatible with older firmware versions, so no FW version check is required.
  
Ferruh Yigit March 7, 2023, 1:24 p.m. UTC | #3
On 3/6/2023 7:06 AM, Chaoyong He wrote:
>> On 2/21/2023 6:29 AM, Chaoyong He wrote:
>>> From: James Hershaw <james.hershaw@corigine.com>
>>>
>>> Due to changes in the firmware for NFPs, firmware will no longer write
>>> the link speed of a port to the control BAR. In line with the
>>> behaviour of the kernel NFP driver, this is now handled by the PMD by
>>> reading the value provided by the NSP in the nfp_eth_table struct
>>> within the pf_dev of the port and subsequently writing this value to the
>> control BAR.
>>>
>>
>> Don't you need some kind of FW version check to figure out if
>> 'NFP_NET_CFG_STS_NSP_LINK_RATE' needs to be updated by driver or not?
>>
>> How do you manage driver <-> FW dependency?
>>
>>
>>> Signed-off-by: James Hershaw <james.hershaw@corigine.com>
>>> Reviewed-by: Niklas Söderlund <niklas.soderlund@corigine.com>
>>> Reviewed-by: Chaoyong He <chaoyong.he@corigine.com>
>>> ---
>>>  drivers/net/nfp/nfp_common.c | 90 ++++++++++++++++++++++-----------
>> ---
>>>  drivers/net/nfp/nfp_ctrl.h   |  9 ++++
>>>  2 files changed, 65 insertions(+), 34 deletions(-)
>>>
>>> diff --git a/drivers/net/nfp/nfp_common.c
>>> b/drivers/net/nfp/nfp_common.c index 5922bfea8e..006ea58008 100644
>>> --- a/drivers/net/nfp/nfp_common.c
>>> +++ b/drivers/net/nfp/nfp_common.c
>>> @@ -52,6 +52,53 @@
>>>  #include <sys/ioctl.h>
>>>  #include <errno.h>
>>>
>>> +static const uint32_t nfp_net_link_speed_nfp2rte[] = {
>>> +	[NFP_NET_CFG_STS_LINK_RATE_UNSUPPORTED] =
>> RTE_ETH_SPEED_NUM_NONE,
>>> +	[NFP_NET_CFG_STS_LINK_RATE_UNKNOWN]     =
>> RTE_ETH_SPEED_NUM_NONE,
>>> +	[NFP_NET_CFG_STS_LINK_RATE_1G]          =
>> RTE_ETH_SPEED_NUM_1G,
>>> +	[NFP_NET_CFG_STS_LINK_RATE_10G]         =
>> RTE_ETH_SPEED_NUM_10G,
>>> +	[NFP_NET_CFG_STS_LINK_RATE_25G]         =
>> RTE_ETH_SPEED_NUM_25G,
>>> +	[NFP_NET_CFG_STS_LINK_RATE_40G]         =
>> RTE_ETH_SPEED_NUM_40G,
>>> +	[NFP_NET_CFG_STS_LINK_RATE_50G]         =
>> RTE_ETH_SPEED_NUM_50G,
>>> +	[NFP_NET_CFG_STS_LINK_RATE_100G]        =
>> RTE_ETH_SPEED_NUM_100G,
>>> +};
>>> +
>>> +static uint32_t
>>> +nfp_net_link_speed_rte2nfp(uint32_t speed) {
>>> +	uint32_t i;
>>> +
>>> +	for (i = 0; i < RTE_DIM(nfp_net_link_speed_nfp2rte); i++) {
>>> +		if (speed == nfp_net_link_speed_nfp2rte[i])
>>> +			return i;
>>> +	}
>>> +
>>> +	return NFP_NET_CFG_STS_LINK_RATE_UNKNOWN;
>>> +}
>>> +
>>> +static void
>>> +nfp_net_notify_port_speed(struct rte_eth_dev *dev) {
>>> +	struct nfp_net_hw *hw;
>>> +	struct nfp_eth_table *eth_table;
>>> +	uint32_t nn_link_status;
>>> +
>>> +	hw = NFP_NET_DEV_PRIVATE_TO_HW(dev->data->dev_private);
>>> +	eth_table = hw->pf_dev->nfp_eth_table;
>>> +
>>> +	nn_link_status = nn_cfg_readl(hw, NFP_NET_CFG_STS);
>>> +	nn_link_status = (nn_link_status >>
>> NFP_NET_CFG_STS_LINK_RATE_SHIFT) &
>>> +			NFP_NET_CFG_STS_LINK_RATE_MASK;
>>> +
>>> +	if ((nn_link_status & NFP_NET_CFG_STS_LINK) == 0) {
>>> +		nn_cfg_writel(hw, NFP_NET_CFG_STS_NSP_LINK_RATE,
>> NFP_NET_CFG_STS_LINK_RATE_UNKNOWN);
>>> +		return;
>>> +	}
>>> +
>>> +	nn_cfg_writel(hw, NFP_NET_CFG_STS_NSP_LINK_RATE,
>>> +		      nfp_net_link_speed_rte2nfp(eth_table->ports[hw-
>>> idx].speed));
>>
>> PF driver writes link speed to 'NFP_NET_CFG_STS_NSP_LINK_RATE' register,
>> but 'nfp_net_link_update()' still gets it from 'NFP_NET_CFG_STS'
>> register (via 'nfp_net_link_speed_nfp2rte[nn_link_status]').
>>
>> Shouldn't 'nfp_net_link_update()' needs to be updated to read speed from
>> 'NFP_NET_CFG_STS_NSP_LINK_RATE' register?
> 
> Sorry for the late response, we spend a lot of time to check and discuss.
> 
> For older firmware, a full word is allocated (NFP_NET_CFG_STS) to report link status and port speed to the driver.
> However, in the interests of keeping FW files port-speed agnostic in the future, 
> the upper 16 bits are no longer written to by FW, so we write the speed to that address (NFP_NET_CFG_STS_LINK_RATE).
> The lower 16 bits (link status) are still handled by firmware.
> 

But 'nfp_net_link_update()' still gets the links speed from lower 16
bits. Probably I am missing something but please let me understand.


link_update()              notify_port_speed()
 read(speed)                writel(speed)
  ▲                          │
  │                          │
  │                          │
 ┌┴─────────────────────────┐▼────────────────────────┐
 │                          │                         │
 │                          │    LINK_RATE            │
 └──────────────────────────┴─────────────────────────┘
0x34                       0x36
 │                                                    │
 └──────────────── CFG_STS ───────────────────────────┘


Or is it something like when you update upper half of the register, FW
reads it and reflects the value to the lower half of the register?


And since 'NFP_NET_CFG_STS_NSP_LINK_RATE' is 16 bits, is it correct to
use 'nn_cfg_writel()' to update it?

> These changes are completely backwards compatible with older firmware versions, so no FW version check is required.

ack
  
Chaoyong He March 10, 2023, 6:07 a.m. UTC | #4
> On 3/6/2023 7:06 AM, Chaoyong He wrote:
> >> On 2/21/2023 6:29 AM, Chaoyong He wrote:
> >>> From: James Hershaw <james.hershaw@corigine.com>
> >>>
> >>> Due to changes in the firmware for NFPs, firmware will no longer
> >>> write the link speed of a port to the control BAR. In line with the
> >>> behaviour of the kernel NFP driver, this is now handled by the PMD
> >>> by reading the value provided by the NSP in the nfp_eth_table struct
> >>> within the pf_dev of the port and subsequently writing this value to
> >>> the
> >> control BAR.
> >>>
> >>
> >> Don't you need some kind of FW version check to figure out if
> >> 'NFP_NET_CFG_STS_NSP_LINK_RATE' needs to be updated by driver or
> not?
> >>
> >> How do you manage driver <-> FW dependency?
> >>
> >>
> >>> Signed-off-by: James Hershaw <james.hershaw@corigine.com>
> >>> Reviewed-by: Niklas Söderlund <niklas.soderlund@corigine.com>
> >>> Reviewed-by: Chaoyong He <chaoyong.he@corigine.com>
> >>> ---
> >>>  drivers/net/nfp/nfp_common.c | 90 ++++++++++++++++++++++-------
> ----
> >> ---
> >>>  drivers/net/nfp/nfp_ctrl.h   |  9 ++++
> >>>  2 files changed, 65 insertions(+), 34 deletions(-)
> >>>
> >>> diff --git a/drivers/net/nfp/nfp_common.c
> >>> b/drivers/net/nfp/nfp_common.c index 5922bfea8e..006ea58008
> 100644
> >>> --- a/drivers/net/nfp/nfp_common.c
> >>> +++ b/drivers/net/nfp/nfp_common.c
> >>> @@ -52,6 +52,53 @@
> >>>  #include <sys/ioctl.h>
> >>>  #include <errno.h>
> >>>
> >>> +static const uint32_t nfp_net_link_speed_nfp2rte[] = {
> >>> +	[NFP_NET_CFG_STS_LINK_RATE_UNSUPPORTED] =
> >> RTE_ETH_SPEED_NUM_NONE,
> >>> +	[NFP_NET_CFG_STS_LINK_RATE_UNKNOWN]     =
> >> RTE_ETH_SPEED_NUM_NONE,
> >>> +	[NFP_NET_CFG_STS_LINK_RATE_1G]          =
> >> RTE_ETH_SPEED_NUM_1G,
> >>> +	[NFP_NET_CFG_STS_LINK_RATE_10G]         =
> >> RTE_ETH_SPEED_NUM_10G,
> >>> +	[NFP_NET_CFG_STS_LINK_RATE_25G]         =
> >> RTE_ETH_SPEED_NUM_25G,
> >>> +	[NFP_NET_CFG_STS_LINK_RATE_40G]         =
> >> RTE_ETH_SPEED_NUM_40G,
> >>> +	[NFP_NET_CFG_STS_LINK_RATE_50G]         =
> >> RTE_ETH_SPEED_NUM_50G,
> >>> +	[NFP_NET_CFG_STS_LINK_RATE_100G]        =
> >> RTE_ETH_SPEED_NUM_100G,
> >>> +};
> >>> +
> >>> +static uint32_t
> >>> +nfp_net_link_speed_rte2nfp(uint32_t speed) {
> >>> +	uint32_t i;
> >>> +
> >>> +	for (i = 0; i < RTE_DIM(nfp_net_link_speed_nfp2rte); i++) {
> >>> +		if (speed == nfp_net_link_speed_nfp2rte[i])
> >>> +			return i;
> >>> +	}
> >>> +
> >>> +	return NFP_NET_CFG_STS_LINK_RATE_UNKNOWN;
> >>> +}
> >>> +
> >>> +static void
> >>> +nfp_net_notify_port_speed(struct rte_eth_dev *dev) {
> >>> +	struct nfp_net_hw *hw;
> >>> +	struct nfp_eth_table *eth_table;
> >>> +	uint32_t nn_link_status;
> >>> +
> >>> +	hw = NFP_NET_DEV_PRIVATE_TO_HW(dev->data->dev_private);
> >>> +	eth_table = hw->pf_dev->nfp_eth_table;
> >>> +
> >>> +	nn_link_status = nn_cfg_readl(hw, NFP_NET_CFG_STS);
> >>> +	nn_link_status = (nn_link_status >>
> >> NFP_NET_CFG_STS_LINK_RATE_SHIFT) &
> >>> +			NFP_NET_CFG_STS_LINK_RATE_MASK;
> >>> +
> >>> +	if ((nn_link_status & NFP_NET_CFG_STS_LINK) == 0) {
> >>> +		nn_cfg_writel(hw, NFP_NET_CFG_STS_NSP_LINK_RATE,
> >> NFP_NET_CFG_STS_LINK_RATE_UNKNOWN);
> >>> +		return;
> >>> +	}
> >>> +
> >>> +	nn_cfg_writel(hw, NFP_NET_CFG_STS_NSP_LINK_RATE,
> >>> +		      nfp_net_link_speed_rte2nfp(eth_table->ports[hw-
> >>> idx].speed));
> >>
> >> PF driver writes link speed to 'NFP_NET_CFG_STS_NSP_LINK_RATE'
> >> register, but 'nfp_net_link_update()' still gets it from 'NFP_NET_CFG_STS'
> >> register (via 'nfp_net_link_speed_nfp2rte[nn_link_status]').
> >>
> >> Shouldn't 'nfp_net_link_update()' needs to be updated to read speed
> >> from 'NFP_NET_CFG_STS_NSP_LINK_RATE' register?
> >
> > Sorry for the late response, we spend a lot of time to check and discuss.
> >
> > For older firmware, a full word is allocated (NFP_NET_CFG_STS) to report
> link status and port speed to the driver.
> > However, in the interests of keeping FW files port-speed agnostic in
> > the future, the upper 16 bits are no longer written to by FW, so we write
> the speed to that address (NFP_NET_CFG_STS_LINK_RATE).
> > The lower 16 bits (link status) are still handled by firmware.
> >
> 
> But 'nfp_net_link_update()' still gets the links speed from lower 16 bits.
> Probably I am missing something but please let me understand.
> 
> 
> link_update()              notify_port_speed()
>  read(speed)                writel(speed)
>   ▲                          │
>   │                          │
>   │                          │
>  ┌┴─────────────────────────┐▼──
> ──────────────────────┐
>  │                          │                         │
>  │                          │    LINK_RATE            │
>  └──────────────────────────┴───
> ──────────────────────┘
> 0x34                       0x36
>  │                                                    │
>  └──────────────── CFG_STS ──────────
> ─────────────────┘
> 
> 
> Or is it something like when you update upper half of the register, FW reads
> it and reflects the value to the lower half of the register?
> 
> 
> And since 'NFP_NET_CFG_STS_NSP_LINK_RATE' is 16 bits, is it correct to use
> 'nn_cfg_writel()' to update it?
> 

Oh, yes, thanks for your careful review, here we do make a mistake, sorry for that.
We'll send a v2 patch with the right 16bits read/write api soon, thanks again.

> > These changes are completely backwards compatible with older firmware
> versions, so no FW version check is required.
> 
> ack
  

Patch

diff --git a/drivers/net/nfp/nfp_common.c b/drivers/net/nfp/nfp_common.c
index 5922bfea8e..006ea58008 100644
--- a/drivers/net/nfp/nfp_common.c
+++ b/drivers/net/nfp/nfp_common.c
@@ -52,6 +52,53 @@ 
 #include <sys/ioctl.h>
 #include <errno.h>
 
+static const uint32_t nfp_net_link_speed_nfp2rte[] = {
+	[NFP_NET_CFG_STS_LINK_RATE_UNSUPPORTED] = RTE_ETH_SPEED_NUM_NONE,
+	[NFP_NET_CFG_STS_LINK_RATE_UNKNOWN]     = RTE_ETH_SPEED_NUM_NONE,
+	[NFP_NET_CFG_STS_LINK_RATE_1G]          = RTE_ETH_SPEED_NUM_1G,
+	[NFP_NET_CFG_STS_LINK_RATE_10G]         = RTE_ETH_SPEED_NUM_10G,
+	[NFP_NET_CFG_STS_LINK_RATE_25G]         = RTE_ETH_SPEED_NUM_25G,
+	[NFP_NET_CFG_STS_LINK_RATE_40G]         = RTE_ETH_SPEED_NUM_40G,
+	[NFP_NET_CFG_STS_LINK_RATE_50G]         = RTE_ETH_SPEED_NUM_50G,
+	[NFP_NET_CFG_STS_LINK_RATE_100G]        = RTE_ETH_SPEED_NUM_100G,
+};
+
+static uint32_t
+nfp_net_link_speed_rte2nfp(uint32_t speed)
+{
+	uint32_t i;
+
+	for (i = 0; i < RTE_DIM(nfp_net_link_speed_nfp2rte); i++) {
+		if (speed == nfp_net_link_speed_nfp2rte[i])
+			return i;
+	}
+
+	return NFP_NET_CFG_STS_LINK_RATE_UNKNOWN;
+}
+
+static void
+nfp_net_notify_port_speed(struct rte_eth_dev *dev)
+{
+	struct nfp_net_hw *hw;
+	struct nfp_eth_table *eth_table;
+	uint32_t nn_link_status;
+
+	hw = NFP_NET_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	eth_table = hw->pf_dev->nfp_eth_table;
+
+	nn_link_status = nn_cfg_readl(hw, NFP_NET_CFG_STS);
+	nn_link_status = (nn_link_status >> NFP_NET_CFG_STS_LINK_RATE_SHIFT) &
+			NFP_NET_CFG_STS_LINK_RATE_MASK;
+
+	if ((nn_link_status & NFP_NET_CFG_STS_LINK) == 0) {
+		nn_cfg_writel(hw, NFP_NET_CFG_STS_NSP_LINK_RATE, NFP_NET_CFG_STS_LINK_RATE_UNKNOWN);
+		return;
+	}
+
+	nn_cfg_writel(hw, NFP_NET_CFG_STS_NSP_LINK_RATE,
+		      nfp_net_link_speed_rte2nfp(eth_table->ports[hw->idx].speed));
+}
+
 static int
 __nfp_net_reconfig(struct nfp_net_hw *hw, uint32_t update)
 {
@@ -111,6 +158,9 @@  nfp_net_reconfig(struct nfp_net_hw *hw, uint32_t ctrl, uint32_t update)
 	PMD_DRV_LOG(DEBUG, "nfp_net_reconfig: ctrl=%08x update=%08x",
 		    ctrl, update);
 
+	if (hw->pf_dev != NULL && hw->pf_dev->app_fw_id == NFP_APP_FW_CORE_NIC)
+		nfp_net_notify_port_speed(hw->eth_dev);
+
 	rte_spinlock_lock(&hw->reconfig_lock);
 
 	nn_cfg_writel(hw, NFP_NET_CFG_CTRL, ctrl);
@@ -538,22 +588,9 @@  nfp_net_link_update(struct rte_eth_dev *dev, __rte_unused int wait_to_complete)
 {
 	struct nfp_net_hw *hw;
 	struct rte_eth_link link;
-	struct nfp_eth_table *nfp_eth_table;
 	uint32_t nn_link_status;
-	uint32_t i;
 	int ret;
 
-	static const uint32_t ls_to_ethtool[] = {
-		[NFP_NET_CFG_STS_LINK_RATE_UNSUPPORTED] = RTE_ETH_SPEED_NUM_NONE,
-		[NFP_NET_CFG_STS_LINK_RATE_UNKNOWN]     = RTE_ETH_SPEED_NUM_NONE,
-		[NFP_NET_CFG_STS_LINK_RATE_1G]          = RTE_ETH_SPEED_NUM_1G,
-		[NFP_NET_CFG_STS_LINK_RATE_10G]         = RTE_ETH_SPEED_NUM_10G,
-		[NFP_NET_CFG_STS_LINK_RATE_25G]         = RTE_ETH_SPEED_NUM_25G,
-		[NFP_NET_CFG_STS_LINK_RATE_40G]         = RTE_ETH_SPEED_NUM_40G,
-		[NFP_NET_CFG_STS_LINK_RATE_50G]         = RTE_ETH_SPEED_NUM_50G,
-		[NFP_NET_CFG_STS_LINK_RATE_100G]        = RTE_ETH_SPEED_NUM_100G,
-	};
-
 	PMD_DRV_LOG(DEBUG, "Link update");
 
 	hw = NFP_NET_DEV_PRIVATE_TO_HW(dev->data->dev_private);
@@ -567,28 +604,13 @@  nfp_net_link_update(struct rte_eth_dev *dev, __rte_unused int wait_to_complete)
 
 	link.link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
 
-	if (hw->pf_dev != NULL) {
-		nfp_eth_table = hw->pf_dev->nfp_eth_table;
-		if (nfp_eth_table != NULL) {
-			link.link_speed = nfp_eth_table->ports[hw->idx].speed;
-			for (i = 0; i < RTE_DIM(ls_to_ethtool); i++) {
-				if (ls_to_ethtool[i] == link.link_speed)
-					break;
-			}
-			if (i == RTE_DIM(ls_to_ethtool))
-				link.link_speed = RTE_ETH_SPEED_NUM_NONE;
-		} else {
-			link.link_speed = RTE_ETH_SPEED_NUM_NONE;
-		}
-	} else {
-		nn_link_status = (nn_link_status >> NFP_NET_CFG_STS_LINK_RATE_SHIFT) &
-				NFP_NET_CFG_STS_LINK_RATE_MASK;
+	nn_link_status = (nn_link_status >> NFP_NET_CFG_STS_LINK_RATE_SHIFT) &
+			 NFP_NET_CFG_STS_LINK_RATE_MASK;
 
-		if (nn_link_status >= RTE_DIM(ls_to_ethtool))
-			link.link_speed = RTE_ETH_SPEED_NUM_NONE;
-		else
-			link.link_speed = ls_to_ethtool[nn_link_status];
-	}
+	if (nn_link_status >= RTE_DIM(nfp_net_link_speed_nfp2rte))
+		link.link_speed = RTE_ETH_SPEED_NUM_NONE;
+	else
+		link.link_speed = nfp_net_link_speed_nfp2rte[nn_link_status];
 
 	ret = rte_eth_linkstatus_set(dev, &link);
 	if (ret == 0) {
diff --git a/drivers/net/nfp/nfp_ctrl.h b/drivers/net/nfp/nfp_ctrl.h
index 75e4458a1b..244048796c 100644
--- a/drivers/net/nfp/nfp_ctrl.h
+++ b/drivers/net/nfp/nfp_ctrl.h
@@ -178,6 +178,15 @@ 
 #define   NFP_NET_CFG_STS_LINK_RATE_40G           5
 #define   NFP_NET_CFG_STS_LINK_RATE_50G           6
 #define   NFP_NET_CFG_STS_LINK_RATE_100G          7
+
+/*
+ * NSP Link rate is a 16-bit word. It is no longer determined by
+ * firmware, instead it is read from the nfp_eth_table of the
+ * associated pf_dev and written to the NFP_NET_CFG_STS_NSP_LINK_RATE
+ * address by the PMD each time the port is reconfigured.
+ */
+#define NFP_NET_CFG_STS_NSP_LINK_RATE   0x0036
+
 #define NFP_NET_CFG_CAP                 0x0038
 #define NFP_NET_CFG_MAX_TXRINGS         0x003c
 #define NFP_NET_CFG_MAX_RXRINGS         0x0040