diff mbox series

[iwl-next,v2,2/9] ethtool: Add forced speed to supported link modes maps

Message ID 20230819093941.15163-1-paul.greenwalt@intel.com (mailing list archive)
State Awaiting Upstream
Delegated to: Netdev Maintainers
Headers show
Series ice: Add basic E830 support | expand

Checks

Context Check Description
netdev/series_format success Posting correctly formatted
netdev/tree_selection success Guessed tree name to be net-next
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit fail Errors and warnings before: 3190 this patch: 24380
netdev/cc_maintainers warning 7 maintainers not CCed: kuba@kernel.org jdamato@fastly.com vladimir.oltean@nxp.com davem@davemloft.net pabeni@redhat.com d-tatianin@yandex-team.ru edumazet@google.com
netdev/build_clang success Errors and warnings before: 1847 this patch: 1847
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn fail Errors and warnings before: 3322 this patch: 25877
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 205 lines checked
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0

Commit Message

Greenwalt, Paul Aug. 19, 2023, 9:39 a.m. UTC
The need to map Ethtool forced speeds to  Ethtool supported link modes is
common among drivers. To support this move the supported link modes maps
implementation from the qede driver. This is an efficient solution
introduced in commit 1d4e4ecccb11 ("qede: populate supported link modes
maps on module init") for qede driver.

ethtool_forced_speed_maps_init() should be called during driver init
with an array of struct ethtool_forced_speed_map to populate the
mapping. The macro ETHTOOL_FORCED_SPEED_MAP is a helper to initialized
the struct ethtool_forced_speed_map.

The qede driver was compile tested only.

Suggested-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Paul Greenwalt <paul.greenwalt@intel.com>
---
v2: move qede Ethtool speed to link modes mapping to be shared by other
drivers (Andrew)
---
 .../net/ethernet/qlogic/qede/qede_ethtool.c   | 92 +++----------------
 include/linux/ethtool.h                       | 74 +++++++++++++++
 net/ethtool/ioctl.c                           | 15 +++
 3 files changed, 100 insertions(+), 81 deletions(-)

Comments

Simon Horman Aug. 20, 2023, 2:45 p.m. UTC | #1
On Sat, Aug 19, 2023 at 02:39:41AM -0700, Paul Greenwalt wrote:
> The need to map Ethtool forced speeds to  Ethtool supported link modes is
> common among drivers. To support this move the supported link modes maps
> implementation from the qede driver. This is an efficient solution
> introduced in commit 1d4e4ecccb11 ("qede: populate supported link modes
> maps on module init") for qede driver.
> 
> ethtool_forced_speed_maps_init() should be called during driver init
> with an array of struct ethtool_forced_speed_map to populate the
> mapping. The macro ETHTOOL_FORCED_SPEED_MAP is a helper to initialized
> the struct ethtool_forced_speed_map.
> 
> The qede driver was compile tested only.
> 
> Suggested-by: Andrew Lunn <andrew@lunn.ch>
> Signed-off-by: Paul Greenwalt <paul.greenwalt@intel.com>
> ---
> v2: move qede Ethtool speed to link modes mapping to be shared by other
> drivers (Andrew)

Hi Paul,

thanks for your efforts in adding a mechanism to share code.
It's a great step in the right direction.

Perhaps I am on the wrong track here, but it seems to me that the approach
you have taken, which is to move the definitions of the symbols into a
header file, is, perhaps, not the best. For one thing it will end up with
duplicate definitions of the symbols - one for each object in which they
are included.

For another, and this more a symtom than an actual problem,
a (W=1) build now complains about symbols that are defined but not used.

./include/linux/ethtool.h:1190:18: warning: 'ethtool_forced_speed_800000' defined but not used [-Wunused-const-variable=]  1190 | static const u32 ethtool_forced_speed_800000[] __initconst = {
...

I suspect a better approach is to leave the symbol definitions in
a .c file, one that is linked in such a way that it is available
to code that uses it - be it modules or built-in. And to make
declarations of those symbols available via a header file.
Greenwalt, Paul Aug. 20, 2023, 5:29 p.m. UTC | #2
On 8/20/2023 7:45 AM, Simon Horman wrote:
> On Sat, Aug 19, 2023 at 02:39:41AM -0700, Paul Greenwalt wrote:
>> The need to map Ethtool forced speeds to  Ethtool supported link modes is
>> common among drivers. To support this move the supported link modes maps
>> implementation from the qede driver. This is an efficient solution
>> introduced in commit 1d4e4ecccb11 ("qede: populate supported link modes
>> maps on module init") for qede driver.
>>
>> ethtool_forced_speed_maps_init() should be called during driver init
>> with an array of struct ethtool_forced_speed_map to populate the
>> mapping. The macro ETHTOOL_FORCED_SPEED_MAP is a helper to initialized
>> the struct ethtool_forced_speed_map.
>>
>> The qede driver was compile tested only.
>>
>> Suggested-by: Andrew Lunn <andrew@lunn.ch>
>> Signed-off-by: Paul Greenwalt <paul.greenwalt@intel.com>
>> ---
>> v2: move qede Ethtool speed to link modes mapping to be shared by other
>> drivers (Andrew)
> 
> Hi Paul,
> 
> thanks for your efforts in adding a mechanism to share code.
> It's a great step in the right direction.
> 
> Perhaps I am on the wrong track here, but it seems to me that the approach
> you have taken, which is to move the definitions of the symbols into a
> header file, is, perhaps, not the best. For one thing it will end up with
> duplicate definitions of the symbols - one for each object in which they
> are included.
> 
> For another, and this more a symtom than an actual problem,
> a (W=1) build now complains about symbols that are defined but not used.
> 
> ./include/linux/ethtool.h:1190:18: warning: 'ethtool_forced_speed_800000' defined but not used [-Wunused-const-variable=]  1190 | static const u32 ethtool_forced_speed_800000[] __initconst = {
> ...
> 
> I suspect a better approach is to leave the symbol definitions in
> a .c file, one that is linked in such a way that it is available
> to code that uses it - be it modules or built-in. And to make
> declarations of those symbols available via a header file.

Simon, thanks for for your suggestion and I apologize the warning wasn't
caught.
Andrew Lunn Aug. 20, 2023, 6:54 p.m. UTC | #3
On Sat, Aug 19, 2023 at 02:39:41AM -0700, Paul Greenwalt wrote:
> The need to map Ethtool forced speeds to  Ethtool supported link modes is
> common among drivers. To support this move the supported link modes maps
> implementation from the qede driver. This is an efficient solution
> introduced in commit 1d4e4ecccb11 ("qede: populate supported link modes
> maps on module init") for qede driver.
> 
> ethtool_forced_speed_maps_init() should be called during driver init
> with an array of struct ethtool_forced_speed_map to populate the
> mapping. The macro ETHTOOL_FORCED_SPEED_MAP is a helper to initialized
> the struct ethtool_forced_speed_map.

Is there any way to reuse this table:

https://elixir.bootlin.com/linux/latest/source/drivers/net/phy/phy-core.c#L161

Seems silly to have multiple tables if this one can be made to work.
It is also used a lot more than anything you will add, which has just
two users so far, so problems with it a likely to be noticed faster.

	Andrew
Greenwalt, Paul Aug. 20, 2023, 7:20 p.m. UTC | #4
On 8/20/2023 11:54 AM, Andrew Lunn wrote:
> On Sat, Aug 19, 2023 at 02:39:41AM -0700, Paul Greenwalt wrote:
>> The need to map Ethtool forced speeds to  Ethtool supported link modes is
>> common among drivers. To support this move the supported link modes maps
>> implementation from the qede driver. This is an efficient solution
>> introduced in commit 1d4e4ecccb11 ("qede: populate supported link modes
>> maps on module init") for qede driver.
>>
>> ethtool_forced_speed_maps_init() should be called during driver init
>> with an array of struct ethtool_forced_speed_map to populate the
>> mapping. The macro ETHTOOL_FORCED_SPEED_MAP is a helper to initialized
>> the struct ethtool_forced_speed_map.
> 
> Is there any way to reuse this table:
> 
> https://elixir.bootlin.com/linux/latest/source/drivers/net/phy/phy-core.c#L161
> 
> Seems silly to have multiple tables if this one can be made to work.
> It is also used a lot more than anything you will add, which has just
> two users so far, so problems with it a likely to be noticed faster.
> 
> 	Andrew

Yes, we'll can look into that.
Alexander Lobakin Aug. 21, 2023, 1 p.m. UTC | #5
From: Paul Greenwalt <paul.greenwalt@intel.com>
Date: Sat, 19 Aug 2023 02:39:41 -0700

> The need to map Ethtool forced speeds to  Ethtool supported link modes is
> common among drivers. To support this move the supported link modes maps
> implementation from the qede driver. This is an efficient solution
> introduced in commit 1d4e4ecccb11 ("qede: populate supported link modes
> maps on module init") for qede driver.

[...]

> diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
> index 62b61527bcc4..245fd4a8d85b 100644
> --- a/include/linux/ethtool.h
> +++ b/include/linux/ethtool.h
> @@ -1052,4 +1052,78 @@ static inline int ethtool_mm_frag_size_min_to_add(u32 val_min, u32 *val_add,
>   * next string.
>   */
>  extern __printf(2, 3) void ethtool_sprintf(u8 **data, const char *fmt, ...);
> +
> +/* Link mode to forced speed capabilities maps */
> +struct ethtool_forced_speed_map {
> +	u32		speed;
> +	__ETHTOOL_DECLARE_LINK_MODE_MASK(caps);
> +
> +	const u32	*cap_arr;
> +	u32		arr_size;

Please re-layout this as follows:

1. caps;
2. cap_arr;
3. arr_size;
4. speed.

Or in any other way that wouldn't provoke holes on 64-bit systems.
I wasn't really familiar with that when initially adding these
definitions :D

> +};
> +
> +#define ETHTOOL_FORCED_SPEED_MAP(value)					\
> +{									\
> +	.speed		= SPEED_##value,				\
> +	.cap_arr	= ethtool_forced_speed_##value,			\
> +	.arr_size	= ARRAY_SIZE(ethtool_forced_speed_##value),	\
> +}
> +
> +static const u32 ethtool_forced_speed_1000[] __initconst = {

2 reasons I don't like this:

1. static const in a header file.
   This implies code duplication -- every object file will have its own
   copy. If we want to reuse them, they should be declared global in one
   place (somewhere in net/ethtool), without __initconst unfortunately.
2. __initconst in a header file.
   I can refer to that declaration somewhere not in the initialization
   code and catch modpost or section reference issues. If we want to
   make those global and accessible from the drivers, it should not have
   any non-standard section placement.

> +	ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
> +	ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
> +	ETHTOOL_LINK_MODE_1000baseX_Full_BIT,

BTW, can't we share the target bitmaps instead? I mean, why not
initialize those somewhere in net/ethtool and export them, instead of
exporting the source of initialization?

> +};
> +
> +static const u32 ethtool_forced_speed_10000[] __initconst = {
> +	ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
> +	ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
> +	ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
> +	ETHTOOL_LINK_MODE_10000baseR_FEC_BIT,
> +	ETHTOOL_LINK_MODE_10000baseCR_Full_BIT,
> +	ETHTOOL_LINK_MODE_10000baseSR_Full_BIT,
> +	ETHTOOL_LINK_MODE_10000baseLR_Full_BIT,
> +	ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT,
> +};
> +
> +static const u32 ethtool_forced_speed_20000[] __initconst = {
> +	ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT,
> +};
> +
> +static const u32 ethtool_forced_speed_25000[] __initconst = {
> +	ETHTOOL_LINK_MODE_25000baseKR_Full_BIT,
> +	ETHTOOL_LINK_MODE_25000baseCR_Full_BIT,
> +	ETHTOOL_LINK_MODE_25000baseSR_Full_BIT,
> +};
> +
> +static const u32 ethtool_forced_speed_40000[] __initconst = {
> +	ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT,
> +	ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT,
> +	ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT,
> +	ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT,
> +};
> +
> +static const u32 ethtool_forced_speed_50000[] __initconst = {
> +	ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT,
> +	ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT,
> +	ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT,
> +};
> +
> +static const u32 ethtool_forced_speed_100000[] __initconst = {
> +	ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT,
> +	ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT,
> +	ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT,
> +	ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT,
> +};
> +
> +/**
> + * ethtool_forced_speed_maps_init
> + * @maps: Pointer to an array of Ethtool forced speed map
> + * @size: Array size
> + *
> + * Initialize an array of Ethtool forced speed map to Ethtool link modes. This
> + * should be called during driver module init.
> + */
> +void ethtool_forced_speed_maps_init(struct ethtool_forced_speed_map *maps,
> +				    u32 size);
>  #endif /* _LINUX_ETHTOOL_H */
> diff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c
> index 0b0ce4f81c01..ac1fdd636bc1 100644
> --- a/net/ethtool/ioctl.c
> +++ b/net/ethtool/ioctl.c
> @@ -3388,3 +3388,18 @@ void ethtool_rx_flow_rule_destroy(struct ethtool_rx_flow_rule *flow)
>  	kfree(flow);
>  }
>  EXPORT_SYMBOL(ethtool_rx_flow_rule_destroy);
> +
> +void ethtool_forced_speed_maps_init(struct ethtool_forced_speed_map *maps,
> +				    u32 size)

Alternatively, to avoid passing size here, you can just terminate @maps
array with zeroed element and treat it as the array end.

> +{
> +	u32 i;
> +
> +	for (i = 0; i < size; i++) {

	for (u32 i = 0 ...

> +		struct ethtool_forced_speed_map *map = &maps[i];
> +
> +		linkmode_set_bit_array(map->cap_arr, map->arr_size, map->caps);
> +		map->cap_arr = NULL;
> +		map->arr_size = 0;

These two are needed only if your @map really refer to
__initdata/__initconst variables.

> +	}
> +}
> +EXPORT_SYMBOL(ethtool_forced_speed_maps_init);

Not sure ioctl.c in the best place for that.

Thanks,
Olek
Pawel Chmielewski Aug. 23, 2023, 5:56 p.m. UTC | #6
On Sun, Aug 20, 2023 at 12:20:43PM -0700, Greenwalt, Paul wrote:
> 
> 
> On 8/20/2023 11:54 AM, Andrew Lunn wrote:
> > On Sat, Aug 19, 2023 at 02:39:41AM -0700, Paul Greenwalt wrote:
> >> The need to map Ethtool forced speeds to  Ethtool supported link modes is
> >> common among drivers. To support this move the supported link modes maps
> >> implementation from the qede driver. This is an efficient solution
> >> introduced in commit 1d4e4ecccb11 ("qede: populate supported link modes
> >> maps on module init") for qede driver.
> >>
> >> ethtool_forced_speed_maps_init() should be called during driver init
> >> with an array of struct ethtool_forced_speed_map to populate the
> >> mapping. The macro ETHTOOL_FORCED_SPEED_MAP is a helper to initialized
> >> the struct ethtool_forced_speed_map.
> > 
> > Is there any way to reuse this table:
> > 
> > https://elixir.bootlin.com/linux/latest/source/drivers/net/phy/phy-core.c#L161
> > 
> > Seems silly to have multiple tables if this one can be made to work.
> > It is also used a lot more than anything you will add, which has just
> > two users so far, so problems with it a likely to be noticed faster.
> > 
> > 	Andrew
> 
> Yes, we'll can look into that.

I think it would be better to leave the maps in the code of respective drivers, as they are too much hardware related. 
Even for a single speed, the sets of supported link modes may vary between the devices.
Jacob Keller Aug. 23, 2023, 6:09 p.m. UTC | #7
On 8/23/2023 10:56 AM, Pawel Chmielewski wrote:
> On Sun, Aug 20, 2023 at 12:20:43PM -0700, Greenwalt, Paul wrote:
>>
>>
>> On 8/20/2023 11:54 AM, Andrew Lunn wrote:
>>> On Sat, Aug 19, 2023 at 02:39:41AM -0700, Paul Greenwalt wrote:
>>>> The need to map Ethtool forced speeds to  Ethtool supported link modes is
>>>> common among drivers. To support this move the supported link modes maps
>>>> implementation from the qede driver. This is an efficient solution
>>>> introduced in commit 1d4e4ecccb11 ("qede: populate supported link modes
>>>> maps on module init") for qede driver.
>>>>
>>>> ethtool_forced_speed_maps_init() should be called during driver init
>>>> with an array of struct ethtool_forced_speed_map to populate the
>>>> mapping. The macro ETHTOOL_FORCED_SPEED_MAP is a helper to initialized
>>>> the struct ethtool_forced_speed_map.
>>>
>>> Is there any way to reuse this table:
>>>
>>> https://elixir.bootlin.com/linux/latest/source/drivers/net/phy/phy-core.c#L161
>>>
>>> Seems silly to have multiple tables if this one can be made to work.
>>> It is also used a lot more than anything you will add, which has just
>>> two users so far, so problems with it a likely to be noticed faster.
>>>
>>> 	Andrew
>>
>> Yes, we'll can look into that.
> 
> I think it would be better to leave the maps in the code of respective drivers, as they are too much hardware related. 
> Even for a single speed, the sets of supported link modes may vary between the devices.
> 

Isn't that what the per-driver bitwise AND is doing after the fact?
That's how qede worked: it converted the mapping from speed and then
combined it with some device support maps to avoid allowing speeds which
weren't supported..

it would be nice to reuse the same mapping that is common everywhere. I
suspect the PHY code already has some mechanism to support device
specific since not all PHYs support all link modes either....
Andrew Lunn Aug. 23, 2023, 8:58 p.m. UTC | #8
> it would be nice to reuse the same mapping that is common everywhere. I
> suspect the PHY code already has some mechanism to support device
> specific since not all PHYs support all link modes either....

phydev->supported is initialised with all the link modes a PHY
supports. The MAC driver when gets a chance to remove any it does not
support,

phylink has similar concepts, the MAC, PHY, and SFP declare what they
each support and then it all gets combined to resolve to a link mode,
to use.

So it should be possible to make this generic with the help of the MAC
driver indicating a mask of what is actually supports.

       Andrew
kernel test robot Aug. 24, 2023, 10:18 a.m. UTC | #9
Hi Paul,

kernel test robot noticed the following build warnings:

[auto build test WARNING on net-next/main]
[also build test WARNING on next-20230824]
[cannot apply to tnguy-next-queue/dev-queue tnguy-net-queue/dev-queue net/main linus/master horms-ipvs/master v6.5-rc7]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Paul-Greenwalt/ice-Add-E830-device-IDs-MAC-type-and-registers/20230821-095200
base:   net-next/main
patch link:    https://lore.kernel.org/r/20230819093941.15163-1-paul.greenwalt%40intel.com
patch subject: [Intel-wired-lan] [PATCH iwl-next v2 2/9] ethtool: Add forced speed to supported link modes maps
config: i386-randconfig-063-20230824 (https://download.01.org/0day-ci/archive/20230824/202308241737.GzJ3EfdT-lkp@intel.com/config)
compiler: gcc-11 (Debian 11.3.0-12) 11.3.0
reproduce: (https://download.01.org/0day-ci/archive/20230824/202308241737.GzJ3EfdT-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202308241737.GzJ3EfdT-lkp@intel.com/

sparse warnings: (new ones prefixed by >>)
>> drivers/net/ethernet/qlogic/qede/qede_ethtool.c:204:33: sparse: sparse: symbol 'qede_forced_speed_maps' was not declared. Should it be static?
Alexander Lobakin Aug. 25, 2023, 1:19 p.m. UTC | #10
From: Pawel Chmielewski <pawel.chmielewski@intel.com>
Date: Wed, 23 Aug 2023 19:56:24 +0200

> On Sun, Aug 20, 2023 at 12:20:43PM -0700, Greenwalt, Paul wrote:
>>
>>
>> On 8/20/2023 11:54 AM, Andrew Lunn wrote:
>>> On Sat, Aug 19, 2023 at 02:39:41AM -0700, Paul Greenwalt wrote:
>>>> The need to map Ethtool forced speeds to  Ethtool supported link modes is
>>>> common among drivers. To support this move the supported link modes maps
>>>> implementation from the qede driver. This is an efficient solution
>>>> introduced in commit 1d4e4ecccb11 ("qede: populate supported link modes
>>>> maps on module init") for qede driver.
>>>>
>>>> ethtool_forced_speed_maps_init() should be called during driver init
>>>> with an array of struct ethtool_forced_speed_map to populate the
>>>> mapping. The macro ETHTOOL_FORCED_SPEED_MAP is a helper to initialized
>>>> the struct ethtool_forced_speed_map.
>>>
>>> Is there any way to reuse this table:
>>>
>>> https://elixir.bootlin.com/linux/latest/source/drivers/net/phy/phy-core.c#L161
>>>
>>> Seems silly to have multiple tables if this one can be made to work.
>>> It is also used a lot more than anything you will add, which has just
>>> two users so far, so problems with it a likely to be noticed faster.
>>>
>>> 	Andrew
>>
>> Yes, we'll can look into that.

BTW,

drivers/net/ethernet/qlogic/qed/qed_main.c
drivers/net/pcs/pcs-xpcs.c

also have similar stuff and could probably make use of the generic stuff
you're doing as well (qed_main was also done by me).
Not speaking of

drivers/net/phy/phylink.c

We probably should unify all that...

Let me think how we could do that.
Andrew's idea is good. But most high-speed NICs, which have a standalone
management firmware for PHY, don't use phylib/phylink.
So in order to be able to unify all that, they should have ->supported
bitmap somewhere else. Not sure struct net_device is the best place...

If I recall Phylink logics correctly (it's been a while since I last
time was working with my embedded project),

1) in the NIC (MAC) driver, you initialize ->supported with *speeds* and
   stuff like duplex, no link modes;
2) Phylink core sets the corresponding link mode bits;
3) phylib core then clears the bits unsupported by the PHY IIRC

The third step in case with those NICs with FW-managed PHYs should be
done manually in the MAC driver somewhere. Like "I am qede and I don't
support mode XX at 50Gbps, but support the rest, so I clear that one bit".
Then the networking core should be able to play this association game
itself. That would remove a good amount of boilerplating.

> 
> I think it would be better to leave the maps in the code of respective drivers, as they are too much hardware related. 
> Even for a single speed, the sets of supported link modes may vary between the devices.
> _______________________________________________
> Intel-wired-lan mailing list
> Intel-wired-lan@osuosl.org
> https://lists.osuosl.org/mailman/listinfo/intel-wired-lan

Thanks,
Olek
Andrew Lunn Aug. 25, 2023, 1:47 p.m. UTC | #11
> Let me think how we could do that.
> Andrew's idea is good. But most high-speed NICs, which have a standalone
> management firmware for PHY, don't use phylib/phylink.
> So in order to be able to unify all that, they should have ->supported
> bitmap somewhere else. Not sure struct net_device is the best place...

I would probably keep it in the driver priv structure, and just pass
it as needed. So long as you only need one or two values, i don't see
the need for a shared structure.

> If I recall Phylink logics correctly (it's been a while since I last
> time was working with my embedded project),
> 
> 1) in the NIC (MAC) driver, you initialize ->supported with *speeds* and
>    stuff like duplex, no link modes;
> 2) Phylink core sets the corresponding link mode bits;
> 3) phylib core then clears the bits unsupported by the PHY IIRC

No, not really.

All i think you need is a low level helper. So don't worry too much
about how phylink works, just implement that low level helper passing
in values as needed, not phylib or phylink structure.

What i don't want is a second infrastructure to be built for those MAC
drivers which don't use Linux to control the PHY. Either share a few
helpers, or swap to phylink.

> The third step in case with those NICs with FW-managed PHYs should be
> done manually in the MAC driver somewhere. Like "I am qede and I don't
> support mode XX at 50Gbps, but support the rest, so I clear that one bit".

I don't think that will work. New bits keep getting added, more speeds
added. So 'support the rest' is not well defined. You need an explicit
list of link modes the driver needs. We already have code to convert
an array of link mode bits into an actual mask, e.g:

        linkmode_set_bit_array(phy_basic_t1_features_array,
                               ARRAY_SIZE(phy_basic_t1_features_array),
                               phy_basic_t1_features);

	Andrew
Alexander Lobakin Aug. 25, 2023, 1:57 p.m. UTC | #12
From: Andrew Lunn <andrew@lunn.ch>
Date: Fri, 25 Aug 2023 15:47:20 +0200

>> Let me think how we could do that.
>> Andrew's idea is good. But most high-speed NICs, which have a standalone
>> management firmware for PHY, don't use phylib/phylink.
>> So in order to be able to unify all that, they should have ->supported
>> bitmap somewhere else. Not sure struct net_device is the best place...
> 
> I would probably keep it in the driver priv structure, and just pass
> it as needed. So long as you only need one or two values, i don't see
> the need for a shared structure.
> 
>> If I recall Phylink logics correctly (it's been a while since I last
>> time was working with my embedded project),
>>
>> 1) in the NIC (MAC) driver, you initialize ->supported with *speeds* and
>>    stuff like duplex, no link modes;
>> 2) Phylink core sets the corresponding link mode bits;
>> 3) phylib core then clears the bits unsupported by the PHY IIRC
> 
> No, not really.
> 
> All i think you need is a low level helper. So don't worry too much
> about how phylink works, just implement that low level helper passing
> in values as needed, not phylib or phylink structure.
> 
> What i don't want is a second infrastructure to be built for those MAC
> drivers which don't use Linux to control the PHY. Either share a few
> helpers, or swap to phylink.

I'd love those drivers to be swapped to phylink, but I doubt that will
happen :D

> 
>> The third step in case with those NICs with FW-managed PHYs should be
>> done manually in the MAC driver somewhere. Like "I am qede and I don't
>> support mode XX at 50Gbps, but support the rest, so I clear that one bit".
> 
> I don't think that will work. New bits keep getting added, more speeds
> added. So 'support the rest' is not well defined. You need an explicit

Ah, correct.

> list of link modes the driver needs. We already have code to convert
> an array of link mode bits into an actual mask, e.g:
> 
>         linkmode_set_bit_array(phy_basic_t1_features_array,
>                                ARRAY_SIZE(phy_basic_t1_features_array),
>                                phy_basic_t1_features);

Now I got lost a bit in what we do really want to share now, as less
sharing was indirectly rejected by "you can share more, let PHY/whatever
take care of this" and now wider sharing was indirectly rejected by
"that won't work" :D
From what I understood, all we want now is the stuff introduced by the
original patch from that thread, but without "generic" speed arrays
definitions?

> 
> 	Andrew			       

Thanks,
Olek
Pawel Chmielewski Aug. 31, 2023, 1:08 p.m. UTC | #13
On Fri, Aug 25, 2023 at 03:47:20PM +0200, Andrew Lunn wrote:
> > Let me think how we could do that.
> > Andrew's idea is good. But most high-speed NICs, which have a standalone
> > management firmware for PHY, don't use phylib/phylink.
> > So in order to be able to unify all that, they should have ->supported
> > bitmap somewhere else. Not sure struct net_device is the best place...
> 
> I would probably keep it in the driver priv structure, and just pass
> it as needed. So long as you only need one or two values, i don't see
> the need for a shared structure.
> 
> > If I recall Phylink logics correctly (it's been a while since I last
> > time was working with my embedded project),
> > 
> > 1) in the NIC (MAC) driver, you initialize ->supported with *speeds* and
> >    stuff like duplex, no link modes;
> > 2) Phylink core sets the corresponding link mode bits;
> > 3) phylib core then clears the bits unsupported by the PHY IIRC
> 
> No, not really.
> 
> All i think you need is a low level helper. So don't worry too much
> about how phylink works, just implement that low level helper passing
> in values as needed, not phylib or phylink structure.
> 
> What i don't want is a second infrastructure to be built for those MAC
> drivers which don't use Linux to control the PHY. Either share a few
> helpers, or swap to phylink.
> 

Let me check if I understand correctly- is that what was sent with the
v3 [1] , with the initialization helper (ethtool_forced_speed_maps_init)
and the structure map in the ethtool code? Or do you have another helper
in mind?

[1] https://lore.kernel.org/netdev/20230823180633.2450617-5-pawel.chmielewski@intel.com/T/#m208153896dfd623da278427285d3bda25a74ef95
Andrew Lunn Sept. 3, 2023, 2 p.m. UTC | #14
> Let me check if I understand correctly- is that what was sent with the
> v3 [1] , with the initialization helper (ethtool_forced_speed_maps_init)
> and the structure map in the ethtool code? Or do you have another helper
> in mind?

Sorry for the late reply, been on vacation.

The main thing is you try to reuse the table:

static const struct phy_setting settings[] = {}

If you can build your helper on top of phy_lookup_setting() even
better. You don't need a phy_device to use those.

	Andrew
Pawel Chmielewski Sept. 4, 2023, 3:27 p.m. UTC | #15
On Sun, Sep 03, 2023 at 04:00:57PM +0200, Andrew Lunn wrote:
> > Let me check if I understand correctly- is that what was sent with the
> > v3 [1] , with the initialization helper (ethtool_forced_speed_maps_init)
> > and the structure map in the ethtool code? Or do you have another helper
> > in mind?
> 
> Sorry for the late reply, been on vacation.
> 
> The main thing is you try to reuse the table:
> 
> static const struct phy_setting settings[] = {}
> 
> If you can build your helper on top of phy_lookup_setting() even
> better. You don't need a phy_device to use those.
> 
> 	Andrew

Thank you for the clarification, I'll write it and propose in the next version.
Most probably split this refactoring from the original series.

Pawel
Pawel Chmielewski Sept. 14, 2023, 2:27 p.m. UTC | #16
On Sun, Sep 03, 2023 at 04:00:57PM +0200, Andrew Lunn wrote:
> > Let me check if I understand correctly- is that what was sent with the
> > v3 [1] , with the initialization helper (ethtool_forced_speed_maps_init)
> > and the structure map in the ethtool code? Or do you have another helper
> > in mind?
> 
> Sorry for the late reply, been on vacation.
> 
> The main thing is you try to reuse the table:
> 
> static const struct phy_setting settings[] = {}
> 
> If you can build your helper on top of phy_lookup_setting() even
> better. You don't need a phy_device to use those.
> 
> 	Andrew

Thank for the hint Andrew! I took a look into the phy-core code,
and a little into phylink. However, I still have the same concern
regarding modes that are supported/unsupported by hardware (managed
by the firmware in our case). Let's say I'm only looking for duplex
modes and iterate over speeds with advertised modes map as an argument
for phy_lookup_setting. In this case, I still need another table/map of
hardware compatible link modes to check against. Theese are actually
the maps we'd like to keep in the driver (and proposed in [1]), so
maybe the simple intersect check between them and the advertised modes
is sufficient?

[1] https://lore.kernel.org/netdev/20230823180633.2450617-4-pawel.chmielewski@intel.com/
Alexander Lobakin Sept. 15, 2023, 1:41 p.m. UTC | #17
From: Pawel Chmielewski <pawel.chmielewski@intel.com>
Date: Thu, 14 Sep 2023 16:27:28 +0200

> On Sun, Sep 03, 2023 at 04:00:57PM +0200, Andrew Lunn wrote:
>>> Let me check if I understand correctly- is that what was sent with the
>>> v3 [1] , with the initialization helper (ethtool_forced_speed_maps_init)
>>> and the structure map in the ethtool code? Or do you have another helper
>>> in mind?
>>
>> Sorry for the late reply, been on vacation.
>>
>> The main thing is you try to reuse the table:
>>
>> static const struct phy_setting settings[] = {}
>>
>> If you can build your helper on top of phy_lookup_setting() even
>> better. You don't need a phy_device to use those.
>>
>> 	Andrew
> 
> Thank for the hint Andrew! I took a look into the phy-core code,
> and a little into phylink. However, I still have the same concern

Here I'd like to add that we're planning to try to use Phylink in ice
soon. It may take a while and will most likely require core code
expansion, since Phylink was originally developed for embedded HW and
DeviceTree and doesn't fully support PCI devices.
Let's see how it goes.

> regarding modes that are supported/unsupported by hardware (managed
> by the firmware in our case). Let's say I'm only looking for duplex
> modes and iterate over speeds with advertised modes map as an argument
> for phy_lookup_setting. In this case, I still need another table/map of
> hardware compatible link modes to check against. Theese are actually
> the maps we'd like to keep in the driver (and proposed in [1]), so
> maybe the simple intersect check between them and the advertised modes
> is sufficient?
> 
> [1] https://lore.kernel.org/netdev/20230823180633.2450617-4-pawel.chmielewski@intel.com/

Thanks,
Olek
Andrew Lunn Sept. 15, 2023, 1:53 p.m. UTC | #18
On Thu, Sep 14, 2023 at 04:27:28PM +0200, Pawel Chmielewski wrote:
> On Sun, Sep 03, 2023 at 04:00:57PM +0200, Andrew Lunn wrote:
> > > Let me check if I understand correctly- is that what was sent with the
> > > v3 [1] , with the initialization helper (ethtool_forced_speed_maps_init)
> > > and the structure map in the ethtool code? Or do you have another helper
> > > in mind?
> > 
> > Sorry for the late reply, been on vacation.
> > 
> > The main thing is you try to reuse the table:
> > 
> > static const struct phy_setting settings[] = {}
> > 
> > If you can build your helper on top of phy_lookup_setting() even
> > better. You don't need a phy_device to use those.
> > 
> > 	Andrew
> 
> Thank for the hint Andrew! I took a look into the phy-core code,
> and a little into phylink. However, I still have the same concern
> regarding modes that are supported/unsupported by hardware (managed
> by the firmware in our case). Let's say I'm only looking for duplex
> modes and iterate over speeds with advertised modes map as an argument
> for phy_lookup_setting. In this case, I still need another table/map of
> hardware compatible link modes to check against. Theese are actually
> the maps we'd like to keep in the driver (and proposed in [1]), so
> maybe the simple intersect check between them and the advertised modes
> is sufficient?

The idea was you have a mask of link modes which your hardware
actually supports. You then ask the core code, give me a link mode
which fulfils this speed and duplex, taking into account the mask.

      Andrew
Andrew Lunn Sept. 15, 2023, 1:58 p.m. UTC | #19
> Here I'd like to add that we're planning to try to use Phylink in ice
> soon. It may take a while and will most likely require core code
> expansion, since Phylink was originally developed for embedded HW and
> DeviceTree and doesn't fully support PCI devices.

Cool.

And yes, not having device tree will require some changes, but i don't
think it will require changes to the core of phylink, just the edges
where you instantiate phylink, using a different configuration
mechanism.

	Andrew
diff mbox series

Patch

diff --git a/drivers/net/ethernet/qlogic/qede/qede_ethtool.c b/drivers/net/ethernet/qlogic/qede/qede_ethtool.c
index 95820cf1cd6c..a01acd48f7eb 100644
--- a/drivers/net/ethernet/qlogic/qede/qede_ethtool.c
+++ b/drivers/net/ethernet/qlogic/qede/qede_ethtool.c
@@ -201,90 +201,20 @@  static const char qede_tests_str_arr[QEDE_ETHTOOL_TEST_MAX][ETH_GSTRING_LEN] = {
 
 /* Forced speed capabilities maps */
 
-struct qede_forced_speed_map {
-	u32		speed;
-	__ETHTOOL_DECLARE_LINK_MODE_MASK(caps);
-
-	const u32	*cap_arr;
-	u32		arr_size;
-};
-
-#define QEDE_FORCED_SPEED_MAP(value)					\
-{									\
-	.speed		= SPEED_##value,				\
-	.cap_arr	= qede_forced_speed_##value,			\
-	.arr_size	= ARRAY_SIZE(qede_forced_speed_##value),	\
-}
-
-static const u32 qede_forced_speed_1000[] __initconst = {
-	ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
-	ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
-	ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
-};
-
-static const u32 qede_forced_speed_10000[] __initconst = {
-	ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
-	ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
-	ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
-	ETHTOOL_LINK_MODE_10000baseR_FEC_BIT,
-	ETHTOOL_LINK_MODE_10000baseCR_Full_BIT,
-	ETHTOOL_LINK_MODE_10000baseSR_Full_BIT,
-	ETHTOOL_LINK_MODE_10000baseLR_Full_BIT,
-	ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT,
-};
-
-static const u32 qede_forced_speed_20000[] __initconst = {
-	ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT,
-};
-
-static const u32 qede_forced_speed_25000[] __initconst = {
-	ETHTOOL_LINK_MODE_25000baseKR_Full_BIT,
-	ETHTOOL_LINK_MODE_25000baseCR_Full_BIT,
-	ETHTOOL_LINK_MODE_25000baseSR_Full_BIT,
-};
-
-static const u32 qede_forced_speed_40000[] __initconst = {
-	ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT,
-	ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT,
-	ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT,
-	ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT,
-};
-
-static const u32 qede_forced_speed_50000[] __initconst = {
-	ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT,
-	ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT,
-	ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT,
-};
-
-static const u32 qede_forced_speed_100000[] __initconst = {
-	ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT,
-	ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT,
-	ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT,
-	ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT,
-};
-
-static struct qede_forced_speed_map qede_forced_speed_maps[] __ro_after_init = {
-	QEDE_FORCED_SPEED_MAP(1000),
-	QEDE_FORCED_SPEED_MAP(10000),
-	QEDE_FORCED_SPEED_MAP(20000),
-	QEDE_FORCED_SPEED_MAP(25000),
-	QEDE_FORCED_SPEED_MAP(40000),
-	QEDE_FORCED_SPEED_MAP(50000),
-	QEDE_FORCED_SPEED_MAP(100000),
+struct ethtool_forced_speed_map qede_forced_speed_maps[] __ro_after_init = {
+	ETHTOOL_FORCED_SPEED_MAP(1000),
+	ETHTOOL_FORCED_SPEED_MAP(10000),
+	ETHTOOL_FORCED_SPEED_MAP(20000),
+	ETHTOOL_FORCED_SPEED_MAP(25000),
+	ETHTOOL_FORCED_SPEED_MAP(40000),
+	ETHTOOL_FORCED_SPEED_MAP(50000),
+	ETHTOOL_FORCED_SPEED_MAP(100000),
 };
 
 void __init qede_forced_speed_maps_init(void)
 {
-	struct qede_forced_speed_map *map;
-	u32 i;
-
-	for (i = 0; i < ARRAY_SIZE(qede_forced_speed_maps); i++) {
-		map = qede_forced_speed_maps + i;
-
-		linkmode_set_bit_array(map->cap_arr, map->arr_size, map->caps);
-		map->cap_arr = NULL;
-		map->arr_size = 0;
-	}
+	ethtool_forced_speed_maps_init(qede_forced_speed_maps,
+				       ARRAY_SIZE(qede_forced_speed_maps));
 }
 
 /* Ethtool callbacks */
@@ -564,8 +494,8 @@  static int qede_set_link_ksettings(struct net_device *dev,
 				   const struct ethtool_link_ksettings *cmd)
 {
 	const struct ethtool_link_settings *base = &cmd->base;
+	const struct ethtool_forced_speed_map *map;
 	struct qede_dev *edev = netdev_priv(dev);
-	const struct qede_forced_speed_map *map;
 	struct qed_link_output current_link;
 	struct qed_link_params params;
 	u32 i;
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index 62b61527bcc4..245fd4a8d85b 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -1052,4 +1052,78 @@  static inline int ethtool_mm_frag_size_min_to_add(u32 val_min, u32 *val_add,
  * next string.
  */
 extern __printf(2, 3) void ethtool_sprintf(u8 **data, const char *fmt, ...);
+
+/* Link mode to forced speed capabilities maps */
+struct ethtool_forced_speed_map {
+	u32		speed;
+	__ETHTOOL_DECLARE_LINK_MODE_MASK(caps);
+
+	const u32	*cap_arr;
+	u32		arr_size;
+};
+
+#define ETHTOOL_FORCED_SPEED_MAP(value)					\
+{									\
+	.speed		= SPEED_##value,				\
+	.cap_arr	= ethtool_forced_speed_##value,			\
+	.arr_size	= ARRAY_SIZE(ethtool_forced_speed_##value),	\
+}
+
+static const u32 ethtool_forced_speed_1000[] __initconst = {
+	ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
+	ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
+	ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
+};
+
+static const u32 ethtool_forced_speed_10000[] __initconst = {
+	ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
+	ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
+	ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
+	ETHTOOL_LINK_MODE_10000baseR_FEC_BIT,
+	ETHTOOL_LINK_MODE_10000baseCR_Full_BIT,
+	ETHTOOL_LINK_MODE_10000baseSR_Full_BIT,
+	ETHTOOL_LINK_MODE_10000baseLR_Full_BIT,
+	ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT,
+};
+
+static const u32 ethtool_forced_speed_20000[] __initconst = {
+	ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT,
+};
+
+static const u32 ethtool_forced_speed_25000[] __initconst = {
+	ETHTOOL_LINK_MODE_25000baseKR_Full_BIT,
+	ETHTOOL_LINK_MODE_25000baseCR_Full_BIT,
+	ETHTOOL_LINK_MODE_25000baseSR_Full_BIT,
+};
+
+static const u32 ethtool_forced_speed_40000[] __initconst = {
+	ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT,
+	ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT,
+	ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT,
+	ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT,
+};
+
+static const u32 ethtool_forced_speed_50000[] __initconst = {
+	ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT,
+	ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT,
+	ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT,
+};
+
+static const u32 ethtool_forced_speed_100000[] __initconst = {
+	ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT,
+	ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT,
+	ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT,
+	ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT,
+};
+
+/**
+ * ethtool_forced_speed_maps_init
+ * @maps: Pointer to an array of Ethtool forced speed map
+ * @size: Array size
+ *
+ * Initialize an array of Ethtool forced speed map to Ethtool link modes. This
+ * should be called during driver module init.
+ */
+void ethtool_forced_speed_maps_init(struct ethtool_forced_speed_map *maps,
+				    u32 size);
 #endif /* _LINUX_ETHTOOL_H */
diff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c
index 0b0ce4f81c01..ac1fdd636bc1 100644
--- a/net/ethtool/ioctl.c
+++ b/net/ethtool/ioctl.c
@@ -3388,3 +3388,18 @@  void ethtool_rx_flow_rule_destroy(struct ethtool_rx_flow_rule *flow)
 	kfree(flow);
 }
 EXPORT_SYMBOL(ethtool_rx_flow_rule_destroy);
+
+void ethtool_forced_speed_maps_init(struct ethtool_forced_speed_map *maps,
+				    u32 size)
+{
+	u32 i;
+
+	for (i = 0; i < size; i++) {
+		struct ethtool_forced_speed_map *map = &maps[i];
+
+		linkmode_set_bit_array(map->cap_arr, map->arr_size, map->caps);
+		map->cap_arr = NULL;
+		map->arr_size = 0;
+	}
+}
+EXPORT_SYMBOL(ethtool_forced_speed_maps_init);