mbox series

[v3,0/3] Add support for Actions Semi Owl Ethernet MAC

Message ID cover.1616368101.git.cristian.ciocaltea@gmail.com
Headers show
Series Add support for Actions Semi Owl Ethernet MAC | expand

Message

Cristian Ciocaltea March 21, 2021, 11:29 p.m. UTC
This patch series adds support for the Ethernet MAC found on the Actions
Semi Owl family of SoCs.

For the moment I have only tested the driver on RoseapplePi SBC, which is
based on the S500 SoC variant. It might work on S900 as well, but I cannot
tell for sure since the S900 datasheet I currently have doesn't provide
any information regarding the MAC registers - so I couldn't check the
compatibility with S500.

Similar story for S700: the datasheet I own is incomplete, but it seems
the MAC is advertised with Gigabit capabilities. For that reason most
probably we need to extend the current implementation in order to support
this SoC variant as well.

Please note that for testing the driver it is also necessary to update the
S500 clock subsystem:

https://lore.kernel.org/lkml/cover.1615221459.git.cristian.ciocaltea@gmail.com/

The DTS changes for the S500 SBCs will be provided separately.

Thanks,
Cristi

Changes in v3:
 - Dropped the 'debug' module parameter and passed the default NETIF_MSG flags
to netif_msg_init(), according to David's review

 - Removed the owl_emac_generate_mac_addr() function and the related
OWL_EMAC_GEN_ADDR_SYS_SN config option until a portable solution to get
the system serial number is found - when building on arm64 the following
error is thrown (as reported by Rob's kernel bot):
 '[...]/owl-emac.c:9:10: fatal error: asm/system_info.h: No such file or directory'

 - Rebased patchset on v5.12-rc4

Changes in v2:
* According to Philipp's review
 - Requested exclusive control over serial line via
   devm_reset_control_get_exclusive()
 - Optimized error handling by using dev_err_probe()

* According to Andrew's review
 - Dropped the inline keywords
 - Applied Reverse Christmas Tree format to local variable declarations
 - Renamed owl_emac_phy_config() to owl_emac_update_link_state()
 - Documented the purpose of the special descriptor used in the context of
   owl_emac_setup_frame_xmit()
 - Updated comment inside owl_emac_mdio_clock_enable() regarding the MDC
   clock divider setup
 - Indicated MAC support for symmetric pause via phy_set_sym_pause()
   in owl_emac_phy_init()
 - Changed the MAC addr generation algorithm in owl_emac_generate_mac_addr()
   by setting the locally administered bit in byte 0 and replacing bytes 1 & 2
   with additional entries from enc_sn
 - Moved devm_add_action_or_reset() before clk_set_rate() in owl_emac_probe()

* Other
 - Added SMII interface support: updated owl_emac_core_sw_reset(), added
   owl_emac_clk_set_rate(), updated description in the YAML binding
 - Changed OWL_EMAC_TX_TIMEOUT from 0.05*HZ to 2*HZ
 - Rebased patchset on v5.12-rc3

Cristian Ciocaltea (3):
  dt-bindings: net: Add Actions Semi Owl Ethernet MAC binding
  net: ethernet: actions: Add Actions Semi Owl Ethernet MAC driver
  MAINTAINERS: Add entries for Actions Semi Owl Ethernet MAC

 .../bindings/net/actions,owl-emac.yaml        |   92 +
 MAINTAINERS                                   |    2 +
 drivers/net/ethernet/Kconfig                  |    1 +
 drivers/net/ethernet/Makefile                 |    1 +
 drivers/net/ethernet/actions/Kconfig          |   26 +
 drivers/net/ethernet/actions/Makefile         |    6 +
 drivers/net/ethernet/actions/owl-emac.c       | 1625 +++++++++++++++++
 drivers/net/ethernet/actions/owl-emac.h       |  280 +++
 8 files changed, 2033 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/net/actions,owl-emac.yaml
 create mode 100644 drivers/net/ethernet/actions/Kconfig
 create mode 100644 drivers/net/ethernet/actions/Makefile
 create mode 100644 drivers/net/ethernet/actions/owl-emac.c
 create mode 100644 drivers/net/ethernet/actions/owl-emac.h

Comments

Florian Fainelli March 22, 2021, 3:30 a.m. UTC | #1
Hi Christian,

On 3/21/2021 4:29 PM, Cristian Ciocaltea wrote:
> Add new driver for the Ethernet MAC used on the Actions Semi Owl

> family of SoCs.

> 

> Currently this has been tested only on the Actions Semi S500 SoC

> variant.

> 

> Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@gmail.com>


[snip]

Do you know the story behind this Ethernet controller? The various
receive/transmit descriptor definitions are 99% those defined in
drivers/net/ethernet/stmmicro/stmmac/descs.h for the normal descriptor.

The register layout of the MAC looks completely different from a
dwmac100 or dwmac1000 however.
-- 
Florian
Cristian Ciocaltea March 22, 2021, 8:44 a.m. UTC | #2
Hi Florian,

On Sun, Mar 21, 2021 at 08:30:07PM -0700, Florian Fainelli wrote:
> Hi Christian,

> 

> On 3/21/2021 4:29 PM, Cristian Ciocaltea wrote:

> > Add new driver for the Ethernet MAC used on the Actions Semi Owl

> > family of SoCs.

> > 

> > Currently this has been tested only on the Actions Semi S500 SoC

> > variant.

> > 

> > Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@gmail.com>

> 

> [snip]

> 

> Do you know the story behind this Ethernet controller? 


I just happened to get a board based on the S500 SoC, so I took this
opportunity to help improving the mainline kernel support, but other
than that I do not really know much about the hardware history.

> The various

> receive/transmit descriptor definitions are 99% those defined in

> drivers/net/ethernet/stmmicro/stmmac/descs.h for the normal descriptor.


That's an interesting observation. I could only assume the vendor did
not want to reinvent the wheel here, but I cannot say if this is a
common design scheme or is something specific to STMicroelectronics
only.

> The register layout of the MAC looks completely different from a

> dwmac100 or dwmac1000 however.


Most probably this is Actions specific.. 

> -- 

> Florian
patchwork-bot+netdevbpf@kernel.org March 22, 2021, 8 p.m. UTC | #3
Hello:

This series was applied to netdev/net-next.git (refs/heads/master):

On Mon, 22 Mar 2021 01:29:42 +0200 you wrote:
> This patch series adds support for the Ethernet MAC found on the Actions

> Semi Owl family of SoCs.

> 

> For the moment I have only tested the driver on RoseapplePi SBC, which is

> based on the S500 SoC variant. It might work on S900 as well, but I cannot

> tell for sure since the S900 datasheet I currently have doesn't provide

> any information regarding the MAC registers - so I couldn't check the

> compatibility with S500.

> 

> [...]


Here is the summary with links:
  - [v3,1/3] dt-bindings: net: Add Actions Semi Owl Ethernet MAC binding
    https://git.kernel.org/netdev/net-next/c/fd42327f31bb
  - [v3,2/3] net: ethernet: actions: Add Actions Semi Owl Ethernet MAC driver
    https://git.kernel.org/netdev/net-next/c/de6e0b198239
  - [v3,3/3] MAINTAINERS: Add entries for Actions Semi Owl Ethernet MAC
    https://git.kernel.org/netdev/net-next/c/b31f51832acf

You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
Andrew Lunn March 22, 2021, 11:38 p.m. UTC | #4
> +static void owl_emac_set_multicast(struct net_device *netdev, int count)

> +{

> +	struct owl_emac_priv *priv = netdev_priv(netdev);

> +	struct netdev_hw_addr *ha;

> +	int index = 0;

> +

> +	if (count <= 0) {

> +		priv->mcaddr_list.count = 0;

> +		return;

> +	}

> +

> +	netdev_for_each_mc_addr(ha, netdev) {

> +		if (!is_multicast_ether_addr(ha->addr))

> +			continue;


Is this possible?

> +

> +		WARN_ON(index >= OWL_EMAC_MAX_MULTICAST_ADDRS);

> +		ether_addr_copy(priv->mcaddr_list.addrs[index++], ha->addr);

> +	}

> +

> +	priv->mcaddr_list.count = index;

> +

> +	owl_emac_setup_frame_xmit(priv);

> +}

> +

> +static void owl_emac_ndo_set_rx_mode(struct net_device *netdev)

> +{

> +	struct owl_emac_priv *priv = netdev_priv(netdev);

> +	u32 status, val = 0;

> +	int mcast_count = 0;

> +

> +	if (netdev->flags & IFF_PROMISC) {

> +		val = OWL_EMAC_BIT_MAC_CSR6_PR;

> +	} else if (netdev->flags & IFF_ALLMULTI) {

> +		val = OWL_EMAC_BIT_MAC_CSR6_PM;

> +	} else if (netdev->flags & IFF_MULTICAST) {

> +		mcast_count = netdev_mc_count(netdev);

> +

> +		if (mcast_count > OWL_EMAC_MAX_MULTICAST_ADDRS) {

> +			val = OWL_EMAC_BIT_MAC_CSR6_PM;

> +			mcast_count = 0;

> +		}

> +	}

> +

> +	spin_lock_bh(&priv->lock);

> +

> +	/* Temporarily stop DMA TX & RX. */

> +	status = owl_emac_dma_cmd_stop(priv);

> +

> +	/* Update operation modes. */

> +	owl_emac_reg_update(priv, OWL_EMAC_REG_MAC_CSR6,

> +			    OWL_EMAC_BIT_MAC_CSR6_PR | OWL_EMAC_BIT_MAC_CSR6_PM,

> +			    val);

> +

> +	/* Restore DMA TX & RX status. */

> +	owl_emac_dma_cmd_set(priv, status);

> +

> +	spin_unlock_bh(&priv->lock);

> +

> +	/* Set/reset multicast addr list. */

> +	owl_emac_set_multicast(netdev, mcast_count);

> +}


I think this can be simplified. At least, you had me going around in
circles a while trying to see if WARN_ON() could be triggered from
user space.

If you have more than OWL_EMAC_MAX_MULTICAST_ADDRS MC addresses, you
go into promisc mode. Can you then skip calling
owl_emac_set_multicast(), which appears not to do too much useful when
passed 0?

       Andrew
Cristian Ciocaltea March 23, 2021, 8:34 a.m. UTC | #5
On Tue, Mar 23, 2021 at 12:38:10AM +0100, Andrew Lunn wrote:
> > +static void owl_emac_set_multicast(struct net_device *netdev, int count)

> > +{

> > +	struct owl_emac_priv *priv = netdev_priv(netdev);

> > +	struct netdev_hw_addr *ha;

> > +	int index = 0;

> > +

> > +	if (count <= 0) {

> > +		priv->mcaddr_list.count = 0;

> > +		return;

> > +	}

> > +

> > +	netdev_for_each_mc_addr(ha, netdev) {

> > +		if (!is_multicast_ether_addr(ha->addr))

> > +			continue;

> 

> Is this possible?


I remember I've seen this in one of the drivers I have studied, but
I'm not really sure it is actually necessary. I added it to be on the
safe side..

> > +

> > +		WARN_ON(index >= OWL_EMAC_MAX_MULTICAST_ADDRS);

> > +		ether_addr_copy(priv->mcaddr_list.addrs[index++], ha->addr);

> > +	}

> > +

> > +	priv->mcaddr_list.count = index;

> > +

> > +	owl_emac_setup_frame_xmit(priv);

> > +}

> > +

> > +static void owl_emac_ndo_set_rx_mode(struct net_device *netdev)

> > +{

> > +	struct owl_emac_priv *priv = netdev_priv(netdev);

> > +	u32 status, val = 0;

> > +	int mcast_count = 0;

> > +

> > +	if (netdev->flags & IFF_PROMISC) {

> > +		val = OWL_EMAC_BIT_MAC_CSR6_PR;

> > +	} else if (netdev->flags & IFF_ALLMULTI) {

> > +		val = OWL_EMAC_BIT_MAC_CSR6_PM;

> > +	} else if (netdev->flags & IFF_MULTICAST) {

> > +		mcast_count = netdev_mc_count(netdev);

> > +

> > +		if (mcast_count > OWL_EMAC_MAX_MULTICAST_ADDRS) {

> > +			val = OWL_EMAC_BIT_MAC_CSR6_PM;

> > +			mcast_count = 0;

> > +		}

> > +	}

> > +

> > +	spin_lock_bh(&priv->lock);

> > +

> > +	/* Temporarily stop DMA TX & RX. */

> > +	status = owl_emac_dma_cmd_stop(priv);

> > +

> > +	/* Update operation modes. */

> > +	owl_emac_reg_update(priv, OWL_EMAC_REG_MAC_CSR6,

> > +			    OWL_EMAC_BIT_MAC_CSR6_PR | OWL_EMAC_BIT_MAC_CSR6_PM,

> > +			    val);

> > +

> > +	/* Restore DMA TX & RX status. */

> > +	owl_emac_dma_cmd_set(priv, status);

> > +

> > +	spin_unlock_bh(&priv->lock);

> > +

> > +	/* Set/reset multicast addr list. */

> > +	owl_emac_set_multicast(netdev, mcast_count);

> > +}

> 

> I think this can be simplified. At least, you had me going around in

> circles a while trying to see if WARN_ON() could be triggered from

> user space.

> 

> If you have more than OWL_EMAC_MAX_MULTICAST_ADDRS MC addresses, you

> go into promisc mode. Can you then skip calling

> owl_emac_set_multicast(), which appears not to do too much useful when

> passed 0?


The main purpose of always calling owl_emac_set_multicast() is to ensure
the size of the mcaddr_list is correctly updated (either set or reset).
This prevents owl_emac_setup_frame_xmit() using obsolete data, when
invoked from different contexts (i.e. MAC address changed).

A conditional call involves splitting the mcaddr_list management logic
(i.e. moving the 'reset' operation from the callee to the caller), which
IMO would make the usage of a separate function less justified.

Thanks,
Cristi

> 

>        Andrew
Amit Tomer June 28, 2021, 8:25 a.m. UTC | #6
Hi,

> > Do you know the story behind this Ethernet controller?

>

> I just happened to get a board based on the S500 SoC, so I took this

> opportunity to help improving the mainline kernel support, but other

> than that I do not really know much about the hardware history.

>

> > The various

> > receive/transmit descriptor definitions are 99% those defined in

> > drivers/net/ethernet/stmmicro/stmmac/descs.h for the normal descriptor.

>

> That's an interesting observation. I could only assume the vendor did

> not want to reinvent the wheel here, but I cannot say if this is a

> common design scheme or is something specific to STMicroelectronics

> only.


I am not entirely sure about it but it looks like it *may* only need
to have a glue driver to
connect to DWMAC.
For instance, on the U-boot[1] side (S700 is one of 64bit OWL SoC from
actions), we kind of re-uses already
existing DWMAC and provide a glue code, and on the Linux side as well
have some similar implementation (locally).

Thanks
-Amit.

[1]: https://source.denx.de/u-boot/u-boot/-/blob/master/drivers/net/dwmac_s700.c
Cristian Ciocaltea June 28, 2021, 9:57 a.m. UTC | #7
Hi Amit,

On Mon, Jun 28, 2021 at 01:55:40PM +0530, Amit Tomer wrote:
> Hi,

> 

> > > Do you know the story behind this Ethernet controller?

> >

> > I just happened to get a board based on the S500 SoC, so I took this

> > opportunity to help improving the mainline kernel support, but other

> > than that I do not really know much about the hardware history.

> >

> > > The various

> > > receive/transmit descriptor definitions are 99% those defined in

> > > drivers/net/ethernet/stmmicro/stmmac/descs.h for the normal descriptor.

> >

> > That's an interesting observation. I could only assume the vendor did

> > not want to reinvent the wheel here, but I cannot say if this is a

> > common design scheme or is something specific to STMicroelectronics

> > only.

> 

> I am not entirely sure about it but it looks like it *may* only need

> to have a glue driver to

> connect to DWMAC.


From the RX/TX descriptors perspective, this looks like a Synopsys IP,
but the MAC register layout is not similar at all.

Thanks to Mani, a request for clarification has been also sent to Actions,
but they could not confirm. Hence, at the moment, we do not have clear
evidences that it is based on Designware.

> For instance, on the U-boot[1] side (S700 is one of 64bit OWL SoC from

> actions), we kind of re-uses already

> existing DWMAC and provide a glue code, and on the Linux side as well

> have some similar implementation (locally).


The S700 SoC provides Gigabit ethernet capabilities and I assume the
controller is quite different from the 10/100 variant present on S500.
As a matter of fact, Actions has confirmed that in the case of S700, the
licensing was obtained from a third party IP company, although they were
not certain if the provider had previous agreements with Synopsys.

Regards,
Cristi

> Thanks

> -Amit.

> 

> [1]: https://source.denx.de/u-boot/u-boot/-/blob/master/drivers/net/dwmac_s700.c