diff mbox series

[net-next,05/11] net: enetc: add enetc-pf-common driver support

Message ID 20241009095116.147412-6-wei.fang@nxp.com (mailing list archive)
State Superseded
Headers show
Series add basic support for i.MX95 NETC | expand

Commit Message

Wei Fang Oct. 9, 2024, 9:51 a.m. UTC
The ENETC of LS1028A is revision 1.0. Now, ENETC is used on the i.MX95
platform and the revision is upgraded to version 4.1. The two versions
are incompatible except for the station interface (SI) part. Therefore,
we need to add a new driver for ENETC revision 4.1 and later. However,
the logic of some interfaces of the two drivers is basically the same,
and the only difference is the hardware configuration. So in order to
reuse these interfaces and reduce code redundancy, we extract these
interfaces and compile them into a separate enetc-pf-common driver for
use by these two PF drivers. Note that the ENETC PF 4.1 driver will be
supported in subsequent patches.

Signed-off-by: Wei Fang <wei.fang@nxp.com>
---
 drivers/net/ethernet/freescale/enetc/Kconfig  |   9 +
 drivers/net/ethernet/freescale/enetc/Makefile |   3 +
 .../net/ethernet/freescale/enetc/enetc_pf.c   | 350 +---------------
 .../net/ethernet/freescale/enetc/enetc_pf.h   |  28 ++
 .../freescale/enetc/enetc_pf_common.c         | 375 ++++++++++++++++++
 5 files changed, 431 insertions(+), 334 deletions(-)
 create mode 100644 drivers/net/ethernet/freescale/enetc/enetc_pf_common.c

Comments

Frank Li Oct. 9, 2024, 5:16 p.m. UTC | #1
On Wed, Oct 09, 2024 at 05:51:10PM +0800, Wei Fang wrote:
> The ENETC of LS1028A is revision 1.0. Now, ENETC is used on the i.MX95
> platform and the revision is upgraded to version 4.1. The two versions
> are incompatible except for the station interface (SI) part. Therefore,
> we need to add a new driver for ENETC revision 4.1 and later. However,
  ^^^^^^^^^^
 just Add a new driver ...

> the logic of some interfaces of the two drivers is basically the same,
> and the only difference is the hardware configuration. So in order to
> reuse these interfaces and reduce code redundancy, we extract these
                                                     ^^
extract these .. in order to ...

> interfaces and compile them into a separate enetc-pf-common driver for
> use by these two PF drivers. Note that the ENETC PF 4.1 driver will be
                               ^^^
Prepare to add support ENETC PF 4.1 driver in subsequent patches.

> supported in subsequent patches.

>
> Signed-off-by: Wei Fang <wei.fang@nxp.com>
> ---
>  drivers/net/ethernet/freescale/enetc/Kconfig  |   9 +
>  drivers/net/ethernet/freescale/enetc/Makefile |   3 +
>  .../net/ethernet/freescale/enetc/enetc_pf.c   | 350 +---------------
>  .../net/ethernet/freescale/enetc/enetc_pf.h   |  28 ++
>  .../freescale/enetc/enetc_pf_common.c         | 375 ++++++++++++++++++
>  5 files changed, 431 insertions(+), 334 deletions(-)
>  create mode 100644 drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
>
> diff --git a/drivers/net/ethernet/freescale/enetc/Kconfig b/drivers/net/ethernet/freescale/enetc/Kconfig
> index 51d80ea959d4..6f3306f14060 100644
> --- a/drivers/net/ethernet/freescale/enetc/Kconfig
> +++ b/drivers/net/ethernet/freescale/enetc/Kconfig
> @@ -7,10 +7,19 @@ config FSL_ENETC_CORE
>
>  	  If compiled as module (M), the module name is fsl-enetc-core.
>
> +config NXP_ENETC_PF_COMMON
> +	tristate "ENETC PF common functionality driver"
> +	help
> +	  This module supports common functionality between drivers of
> +	  different versions of NXP ENETC PF controllers.
> +
> +	  If compiled as module (M), the module name is nxp-enetc-pf-common.
> +
>  config FSL_ENETC
>  	tristate "ENETC PF driver"
>  	depends on PCI_MSI
>  	select MDIO_DEVRES
> +	select NXP_ENETC_PF_COMMON
>  	select FSL_ENETC_CORE
>  	select FSL_ENETC_IERB
>  	select FSL_ENETC_MDIO
> diff --git a/drivers/net/ethernet/freescale/enetc/Makefile b/drivers/net/ethernet/freescale/enetc/Makefile
> index 5c277910d538..b81ca462e358 100644
> --- a/drivers/net/ethernet/freescale/enetc/Makefile
> +++ b/drivers/net/ethernet/freescale/enetc/Makefile
> @@ -3,6 +3,9 @@
>  obj-$(CONFIG_FSL_ENETC_CORE) += fsl-enetc-core.o
>  fsl-enetc-core-y := enetc.o enetc_cbdr.o enetc_ethtool.o
>
> +obj-$(CONFIG_NXP_ENETC_PF_COMMON) += nxp-enetc-pf-common.o
> +nxp-enetc-pf-common-y := enetc_pf_common.o
> +

I am not sure why you can't link enetc_pf_common.o into enetc_pf.o?

Frank

>  obj-$(CONFIG_FSL_ENETC) += fsl-enetc.o
>  fsl-enetc-y := enetc_pf.o
>  fsl-enetc-$(CONFIG_PCI_IOV) += enetc_msg.o
> diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.c b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
> index 8f6b0bf48139..dae8be4a1607 100644
> --- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c
> +++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
> @@ -33,18 +33,15 @@ static void enetc_pf_set_primary_mac_addr(struct enetc_hw *hw, int si,
>  	__raw_writew(lower, hw->port + ENETC_PSIPMAR1(si));
>  }
>
> -static int enetc_pf_set_mac_addr(struct net_device *ndev, void *addr)
> +static struct phylink_pcs *enetc_pf_create_pcs(struct enetc_pf *pf,
> +					       struct mii_bus *bus)
>  {
> -	struct enetc_ndev_priv *priv = netdev_priv(ndev);
> -	struct sockaddr *saddr = addr;
> -
> -	if (!is_valid_ether_addr(saddr->sa_data))
> -		return -EADDRNOTAVAIL;
> -
> -	eth_hw_addr_set(ndev, saddr->sa_data);
> -	enetc_pf_set_primary_mac_addr(&priv->si->hw, 0, saddr->sa_data);
> +	return lynx_pcs_create_mdiodev(bus, 0);
> +}
>
> -	return 0;
> +static void enetc_pf_destroy_pcs(struct phylink_pcs *pcs)
> +{
> +	lynx_pcs_destroy(pcs);
>  }
>
>  static void enetc_set_vlan_promisc(struct enetc_hw *hw, char si_map)
> @@ -393,56 +390,6 @@ static int enetc_pf_set_vf_spoofchk(struct net_device *ndev, int vf, bool en)
>  	return 0;
>  }
>
> -static int enetc_setup_mac_address(struct device_node *np, struct enetc_pf *pf,
> -				   int si)
> -{
> -	struct device *dev = &pf->si->pdev->dev;
> -	struct enetc_hw *hw = &pf->si->hw;
> -	u8 mac_addr[ETH_ALEN] = { 0 };
> -	int err;
> -
> -	/* (1) try to get the MAC address from the device tree */
> -	if (np) {
> -		err = of_get_mac_address(np, mac_addr);
> -		if (err == -EPROBE_DEFER)
> -			return err;
> -	}
> -
> -	/* (2) bootloader supplied MAC address */
> -	if (is_zero_ether_addr(mac_addr))
> -		enetc_pf_get_primary_mac_addr(hw, si, mac_addr);
> -
> -	/* (3) choose a random one */
> -	if (is_zero_ether_addr(mac_addr)) {
> -		eth_random_addr(mac_addr);
> -		dev_info(dev, "no MAC address specified for SI%d, using %pM\n",
> -			 si, mac_addr);
> -	}
> -
> -	enetc_pf_set_primary_mac_addr(hw, si, mac_addr);
> -
> -	return 0;
> -}
> -
> -static int enetc_setup_mac_addresses(struct device_node *np,
> -				     struct enetc_pf *pf)
> -{
> -	int err, i;
> -
> -	/* The PF might take its MAC from the device tree */
> -	err = enetc_setup_mac_address(np, pf, 0);
> -	if (err)
> -		return err;
> -
> -	for (i = 0; i < pf->total_vfs; i++) {
> -		err = enetc_setup_mac_address(NULL, pf, i + 1);
> -		if (err)
> -			return err;
> -	}
> -
> -	return 0;
> -}
> -
>  static void enetc_port_assign_rfs_entries(struct enetc_si *si)
>  {
>  	struct enetc_pf *pf = enetc_si_priv(si);
> @@ -656,55 +603,6 @@ void enetc_msg_handle_rxmsg(struct enetc_pf *pf, int vf_id, u16 *status)
>  	}
>  }
>
> -#ifdef CONFIG_PCI_IOV
> -static int enetc_sriov_configure(struct pci_dev *pdev, int num_vfs)
> -{
> -	struct enetc_si *si = pci_get_drvdata(pdev);
> -	struct enetc_pf *pf = enetc_si_priv(si);
> -	int err;
> -
> -	if (!num_vfs) {
> -		enetc_msg_psi_free(pf);
> -		kfree(pf->vf_state);
> -		pf->num_vfs = 0;
> -		pci_disable_sriov(pdev);
> -	} else {
> -		pf->num_vfs = num_vfs;
> -
> -		pf->vf_state = kcalloc(num_vfs, sizeof(struct enetc_vf_state),
> -				       GFP_KERNEL);
> -		if (!pf->vf_state) {
> -			pf->num_vfs = 0;
> -			return -ENOMEM;
> -		}
> -
> -		err = enetc_msg_psi_init(pf);
> -		if (err) {
> -			dev_err(&pdev->dev, "enetc_msg_psi_init (%d)\n", err);
> -			goto err_msg_psi;
> -		}
> -
> -		err = pci_enable_sriov(pdev, num_vfs);
> -		if (err) {
> -			dev_err(&pdev->dev, "pci_enable_sriov err %d\n", err);
> -			goto err_en_sriov;
> -		}
> -	}
> -
> -	return num_vfs;
> -
> -err_en_sriov:
> -	enetc_msg_psi_free(pf);
> -err_msg_psi:
> -	kfree(pf->vf_state);
> -	pf->num_vfs = 0;
> -
> -	return err;
> -}
> -#else
> -#define enetc_sriov_configure(pdev, num_vfs)	(void)0
> -#endif
> -
>  static int enetc_pf_set_features(struct net_device *ndev,
>  				 netdev_features_t features)
>  {
> @@ -775,187 +673,6 @@ static const struct net_device_ops enetc_ndev_ops = {
>  	.ndo_xdp_xmit		= enetc_xdp_xmit,
>  };
>
> -static void enetc_pf_netdev_setup(struct enetc_si *si, struct net_device *ndev,
> -				  const struct net_device_ops *ndev_ops)
> -{
> -	struct enetc_ndev_priv *priv = netdev_priv(ndev);
> -
> -	SET_NETDEV_DEV(ndev, &si->pdev->dev);
> -	priv->ndev = ndev;
> -	priv->si = si;
> -	priv->dev = &si->pdev->dev;
> -	si->ndev = ndev;
> -
> -	priv->msg_enable = (NETIF_MSG_WOL << 1) - 1;
> -	ndev->netdev_ops = ndev_ops;
> -	enetc_set_ethtool_ops(ndev);
> -	ndev->watchdog_timeo = 5 * HZ;
> -	ndev->max_mtu = ENETC_MAX_MTU;
> -
> -	ndev->hw_features = NETIF_F_SG | NETIF_F_RXCSUM |
> -			    NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX |
> -			    NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_LOOPBACK |
> -			    NETIF_F_HW_CSUM | NETIF_F_TSO | NETIF_F_TSO6;
> -	ndev->features = NETIF_F_HIGHDMA | NETIF_F_SG | NETIF_F_RXCSUM |
> -			 NETIF_F_HW_VLAN_CTAG_TX |
> -			 NETIF_F_HW_VLAN_CTAG_RX |
> -			 NETIF_F_HW_CSUM | NETIF_F_TSO | NETIF_F_TSO6;
> -	ndev->vlan_features = NETIF_F_SG | NETIF_F_HW_CSUM |
> -			      NETIF_F_TSO | NETIF_F_TSO6;
> -
> -	if (si->num_rss)
> -		ndev->hw_features |= NETIF_F_RXHASH;
> -
> -	ndev->priv_flags |= IFF_UNICAST_FLT;
> -	ndev->xdp_features = NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT |
> -			     NETDEV_XDP_ACT_NDO_XMIT | NETDEV_XDP_ACT_RX_SG |
> -			     NETDEV_XDP_ACT_NDO_XMIT_SG;
> -
> -	if (si->hw_features & ENETC_SI_F_PSFP && !enetc_psfp_enable(priv)) {
> -		priv->active_offloads |= ENETC_F_QCI;
> -		ndev->features |= NETIF_F_HW_TC;
> -		ndev->hw_features |= NETIF_F_HW_TC;
> -	}
> -
> -	/* pick up primary MAC address from SI */
> -	enetc_load_primary_mac_addr(&si->hw, ndev);
> -}
> -
> -static int enetc_mdio_probe(struct enetc_pf *pf, struct device_node *np)
> -{
> -	struct device *dev = &pf->si->pdev->dev;
> -	struct enetc_mdio_priv *mdio_priv;
> -	struct mii_bus *bus;
> -	int err;
> -
> -	bus = devm_mdiobus_alloc_size(dev, sizeof(*mdio_priv));
> -	if (!bus)
> -		return -ENOMEM;
> -
> -	bus->name = "Freescale ENETC MDIO Bus";
> -	bus->read = enetc_mdio_read_c22;
> -	bus->write = enetc_mdio_write_c22;
> -	bus->read_c45 = enetc_mdio_read_c45;
> -	bus->write_c45 = enetc_mdio_write_c45;
> -	bus->parent = dev;
> -	mdio_priv = bus->priv;
> -	mdio_priv->hw = &pf->si->hw;
> -	mdio_priv->mdio_base = ENETC_EMDIO_BASE;
> -	snprintf(bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev));
> -
> -	err = of_mdiobus_register(bus, np);
> -	if (err)
> -		return dev_err_probe(dev, err, "cannot register MDIO bus\n");
> -
> -	pf->mdio = bus;
> -
> -	return 0;
> -}
> -
> -static void enetc_mdio_remove(struct enetc_pf *pf)
> -{
> -	if (pf->mdio)
> -		mdiobus_unregister(pf->mdio);
> -}
> -
> -static int enetc_imdio_create(struct enetc_pf *pf)
> -{
> -	struct device *dev = &pf->si->pdev->dev;
> -	struct enetc_mdio_priv *mdio_priv;
> -	struct phylink_pcs *phylink_pcs;
> -	struct mii_bus *bus;
> -	int err;
> -
> -	bus = mdiobus_alloc_size(sizeof(*mdio_priv));
> -	if (!bus)
> -		return -ENOMEM;
> -
> -	bus->name = "Freescale ENETC internal MDIO Bus";
> -	bus->read = enetc_mdio_read_c22;
> -	bus->write = enetc_mdio_write_c22;
> -	bus->read_c45 = enetc_mdio_read_c45;
> -	bus->write_c45 = enetc_mdio_write_c45;
> -	bus->parent = dev;
> -	bus->phy_mask = ~0;
> -	mdio_priv = bus->priv;
> -	mdio_priv->hw = &pf->si->hw;
> -	mdio_priv->mdio_base = ENETC_PM_IMDIO_BASE;
> -	snprintf(bus->id, MII_BUS_ID_SIZE, "%s-imdio", dev_name(dev));
> -
> -	err = mdiobus_register(bus);
> -	if (err) {
> -		dev_err(dev, "cannot register internal MDIO bus (%d)\n", err);
> -		goto free_mdio_bus;
> -	}
> -
> -	phylink_pcs = lynx_pcs_create_mdiodev(bus, 0);
> -	if (IS_ERR(phylink_pcs)) {
> -		err = PTR_ERR(phylink_pcs);
> -		dev_err(dev, "cannot create lynx pcs (%d)\n", err);
> -		goto unregister_mdiobus;
> -	}
> -
> -	pf->imdio = bus;
> -	pf->pcs = phylink_pcs;
> -
> -	return 0;
> -
> -unregister_mdiobus:
> -	mdiobus_unregister(bus);
> -free_mdio_bus:
> -	mdiobus_free(bus);
> -	return err;
> -}
> -
> -static void enetc_imdio_remove(struct enetc_pf *pf)
> -{
> -	if (pf->pcs)
> -		lynx_pcs_destroy(pf->pcs);
> -	if (pf->imdio) {
> -		mdiobus_unregister(pf->imdio);
> -		mdiobus_free(pf->imdio);
> -	}
> -}
> -
> -static bool enetc_port_has_pcs(struct enetc_pf *pf)
> -{
> -	return (pf->if_mode == PHY_INTERFACE_MODE_SGMII ||
> -		pf->if_mode == PHY_INTERFACE_MODE_1000BASEX ||
> -		pf->if_mode == PHY_INTERFACE_MODE_2500BASEX ||
> -		pf->if_mode == PHY_INTERFACE_MODE_USXGMII);
> -}
> -
> -static int enetc_mdiobus_create(struct enetc_pf *pf, struct device_node *node)
> -{
> -	struct device_node *mdio_np;
> -	int err;
> -
> -	mdio_np = of_get_child_by_name(node, "mdio");
> -	if (mdio_np) {
> -		err = enetc_mdio_probe(pf, mdio_np);
> -
> -		of_node_put(mdio_np);
> -		if (err)
> -			return err;
> -	}
> -
> -	if (enetc_port_has_pcs(pf)) {
> -		err = enetc_imdio_create(pf);
> -		if (err) {
> -			enetc_mdio_remove(pf);
> -			return err;
> -		}
> -	}
> -
> -	return 0;
> -}
> -
> -static void enetc_mdiobus_destroy(struct enetc_pf *pf)
> -{
> -	enetc_mdio_remove(pf);
> -	enetc_imdio_remove(pf);
> -}
> -
>  static struct phylink_pcs *
>  enetc_pl_mac_select_pcs(struct phylink_config *config, phy_interface_t iface)
>  {
> @@ -1101,47 +818,6 @@ static const struct phylink_mac_ops enetc_mac_phylink_ops = {
>  	.mac_link_down = enetc_pl_mac_link_down,
>  };
>
> -static int enetc_phylink_create(struct enetc_ndev_priv *priv,
> -				struct device_node *node)
> -{
> -	struct enetc_pf *pf = enetc_si_priv(priv->si);
> -	struct phylink *phylink;
> -	int err;
> -
> -	pf->phylink_config.dev = &priv->ndev->dev;
> -	pf->phylink_config.type = PHYLINK_NETDEV;
> -	pf->phylink_config.mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE |
> -		MAC_10 | MAC_100 | MAC_1000 | MAC_2500FD;
> -
> -	__set_bit(PHY_INTERFACE_MODE_INTERNAL,
> -		  pf->phylink_config.supported_interfaces);
> -	__set_bit(PHY_INTERFACE_MODE_SGMII,
> -		  pf->phylink_config.supported_interfaces);
> -	__set_bit(PHY_INTERFACE_MODE_1000BASEX,
> -		  pf->phylink_config.supported_interfaces);
> -	__set_bit(PHY_INTERFACE_MODE_2500BASEX,
> -		  pf->phylink_config.supported_interfaces);
> -	__set_bit(PHY_INTERFACE_MODE_USXGMII,
> -		  pf->phylink_config.supported_interfaces);
> -	phy_interface_set_rgmii(pf->phylink_config.supported_interfaces);
> -
> -	phylink = phylink_create(&pf->phylink_config, of_fwnode_handle(node),
> -				 pf->if_mode, &enetc_mac_phylink_ops);
> -	if (IS_ERR(phylink)) {
> -		err = PTR_ERR(phylink);
> -		return err;
> -	}
> -
> -	priv->phylink = phylink;
> -
> -	return 0;
> -}
> -
> -static void enetc_phylink_destroy(struct enetc_ndev_priv *priv)
> -{
> -	phylink_destroy(priv->phylink);
> -}
> -
>  /* Initialize the entire shared memory for the flow steering entries
>   * of this port (PF + VFs)
>   */
> @@ -1259,6 +935,13 @@ static void enetc_psi_destroy(struct pci_dev *pdev)
>  	enetc_pci_remove(pdev);
>  }
>
> +static const struct enetc_pf_ops enetc_pf_ops = {
> +	.set_si_primary_mac = enetc_pf_set_primary_mac_addr,
> +	.get_si_primary_mac = enetc_pf_get_primary_mac_addr,
> +	.create_pcs = enetc_pf_create_pcs,
> +	.destroy_pcs = enetc_pf_destroy_pcs,
> +};
> +

I suppose this patch should just move functions to common.c. This involve
addition code logic change. It is not easy to follow up to make sure your
change is correct.

Frank

>  static int enetc_pf_probe(struct pci_dev *pdev,
>  			  const struct pci_device_id *ent)
>  {
> @@ -1286,6 +969,7 @@ static int enetc_pf_probe(struct pci_dev *pdev,
>  	pf = enetc_si_priv(si);
>  	pf->si = si;
>  	pf->total_vfs = pci_sriov_get_totalvfs(pdev);
> +	enetc_pf_ops_register(pf, &enetc_pf_ops);
>
>  	err = enetc_setup_mac_addresses(node, pf);
>  	if (err)
> @@ -1338,7 +1022,7 @@ static int enetc_pf_probe(struct pci_dev *pdev,
>  	if (err)
>  		goto err_mdiobus_create;
>
> -	err = enetc_phylink_create(priv, node);
> +	err = enetc_phylink_create(priv, node, &enetc_mac_phylink_ops);
>  	if (err)
>  		goto err_phylink_create;
>
> @@ -1422,9 +1106,7 @@ static struct pci_driver enetc_pf_driver = {
>  	.id_table = enetc_pf_id_table,
>  	.probe = enetc_pf_probe,
>  	.remove = enetc_pf_remove,
> -#ifdef CONFIG_PCI_IOV
>  	.sriov_configure = enetc_sriov_configure,
> -#endif
>  };
>  module_pci_driver(enetc_pf_driver);
>
> diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.h b/drivers/net/ethernet/freescale/enetc/enetc_pf.h
> index c26bd66e4597..ad7dab0eb752 100644
> --- a/drivers/net/ethernet/freescale/enetc/enetc_pf.h
> +++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.h
> @@ -28,6 +28,15 @@ struct enetc_vf_state {
>  	enum enetc_vf_flags flags;
>  };
>
> +struct enetc_pf;
> +
> +struct enetc_pf_ops {
> +	void (*set_si_primary_mac)(struct enetc_hw *hw, int si, const u8 *addr);
> +	void (*get_si_primary_mac)(struct enetc_hw *hw, int si, u8 *addr);
> +	struct phylink_pcs *(*create_pcs)(struct enetc_pf *pf, struct mii_bus *bus);
> +	void (*destroy_pcs)(struct phylink_pcs *pcs);
> +};
> +
>  struct enetc_pf {
>  	struct enetc_si *si;
>  	int num_vfs; /* number of active VFs, after sriov_init */
> @@ -50,6 +59,8 @@ struct enetc_pf {
>
>  	phy_interface_t if_mode;
>  	struct phylink_config phylink_config;
> +
> +	const struct enetc_pf_ops *ops;
>  };
>
>  #define phylink_to_enetc_pf(config) \
> @@ -58,3 +69,20 @@ struct enetc_pf {
>  int enetc_msg_psi_init(struct enetc_pf *pf);
>  void enetc_msg_psi_free(struct enetc_pf *pf);
>  void enetc_msg_handle_rxmsg(struct enetc_pf *pf, int mbox_id, u16 *status);
> +
> +int enetc_pf_set_mac_addr(struct net_device *ndev, void *addr);
> +int enetc_setup_mac_addresses(struct device_node *np, struct enetc_pf *pf);
> +void enetc_pf_netdev_setup(struct enetc_si *si, struct net_device *ndev,
> +			   const struct net_device_ops *ndev_ops);
> +int enetc_mdiobus_create(struct enetc_pf *pf, struct device_node *node);
> +void enetc_mdiobus_destroy(struct enetc_pf *pf);
> +int enetc_phylink_create(struct enetc_ndev_priv *priv, struct device_node *node,
> +			 const struct phylink_mac_ops *pl_mac_ops);
> +void enetc_phylink_destroy(struct enetc_ndev_priv *priv);
> +int enetc_sriov_configure(struct pci_dev *pdev, int num_vfs);
> +
> +static inline void enetc_pf_ops_register(struct enetc_pf *pf,
> +					 const struct enetc_pf_ops *ops)
> +{
> +	pf->ops = ops;
> +}
> diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
> new file mode 100644
> index 000000000000..bbfb5c1ffd13
> --- /dev/null
> +++ b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
> @@ -0,0 +1,375 @@
> +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
> +/* Copyright 2024 NXP */
> +#include <linux/fsl/enetc_mdio.h>
> +#include <linux/of_mdio.h>
> +#include <linux/of_net.h>
> +
> +#include "enetc_pf.h"
> +
> +static int enetc_set_si_hw_addr(struct enetc_pf *pf, int si, u8 *mac_addr)
> +{
> +	struct enetc_hw *hw = &pf->si->hw;
> +
> +	if (pf->ops->set_si_primary_mac)
> +		pf->ops->set_si_primary_mac(hw, si, mac_addr);
> +	else
> +		return -EOPNOTSUPP;
> +
> +	return 0;
> +}
> +
> +int enetc_pf_set_mac_addr(struct net_device *ndev, void *addr)
> +{
> +	struct enetc_ndev_priv *priv = netdev_priv(ndev);
> +	struct enetc_pf *pf = enetc_si_priv(priv->si);
> +	struct sockaddr *saddr = addr;
> +	int err;
> +
> +	if (!is_valid_ether_addr(saddr->sa_data))
> +		return -EADDRNOTAVAIL;
> +
> +	err = enetc_set_si_hw_addr(pf, 0, saddr->sa_data);
> +	if (err)
> +		return err;
> +
> +	eth_hw_addr_set(ndev, saddr->sa_data);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(enetc_pf_set_mac_addr);
> +
> +static int enetc_setup_mac_address(struct device_node *np, struct enetc_pf *pf,
> +				   int si)
> +{
> +	struct device *dev = &pf->si->pdev->dev;
> +	struct enetc_hw *hw = &pf->si->hw;
> +	u8 mac_addr[ETH_ALEN] = { 0 };
> +	int err;
> +
> +	/* (1) try to get the MAC address from the device tree */
> +	if (np) {
> +		err = of_get_mac_address(np, mac_addr);
> +		if (err == -EPROBE_DEFER)
> +			return err;
> +	}
> +
> +	/* (2) bootloader supplied MAC address */
> +	if (is_zero_ether_addr(mac_addr) && pf->ops->get_si_primary_mac)
> +		pf->ops->get_si_primary_mac(hw, si, mac_addr);
> +
> +	/* (3) choose a random one */
> +	if (is_zero_ether_addr(mac_addr)) {
> +		eth_random_addr(mac_addr);
> +		dev_info(dev, "no MAC address specified for SI%d, using %pM\n",
> +			 si, mac_addr);
> +	}
> +
> +	err = enetc_set_si_hw_addr(pf, si, mac_addr);
> +	if (err)
> +		return err;
> +
> +	return 0;
> +}
> +
> +int enetc_setup_mac_addresses(struct device_node *np, struct enetc_pf *pf)
> +{
> +	int err, i;
> +
> +	/* The PF might take its MAC from the device tree */
> +	err = enetc_setup_mac_address(np, pf, 0);
> +	if (err)
> +		return err;
> +
> +	for (i = 0; i < pf->total_vfs; i++) {
> +		err = enetc_setup_mac_address(NULL, pf, i + 1);
> +		if (err)
> +			return err;
> +	}
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(enetc_setup_mac_addresses);
> +
> +void enetc_pf_netdev_setup(struct enetc_si *si, struct net_device *ndev,
> +			   const struct net_device_ops *ndev_ops)
> +{
> +	struct enetc_ndev_priv *priv = netdev_priv(ndev);
> +
> +	SET_NETDEV_DEV(ndev, &si->pdev->dev);
> +	priv->ndev = ndev;
> +	priv->si = si;
> +	priv->dev = &si->pdev->dev;
> +	si->ndev = ndev;
> +
> +	priv->msg_enable = (NETIF_MSG_WOL << 1) - 1;
> +	ndev->netdev_ops = ndev_ops;
> +	enetc_set_ethtool_ops(ndev);
> +	ndev->watchdog_timeo = 5 * HZ;
> +	ndev->max_mtu = ENETC_MAX_MTU;
> +
> +	ndev->hw_features = NETIF_F_SG | NETIF_F_RXCSUM |
> +			    NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX |
> +			    NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_LOOPBACK |
> +			    NETIF_F_HW_CSUM | NETIF_F_TSO | NETIF_F_TSO6 |
> +			    NETIF_F_GSO_UDP_L4;
> +	ndev->features = NETIF_F_HIGHDMA | NETIF_F_SG | NETIF_F_RXCSUM |
> +			 NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX |
> +			 NETIF_F_HW_CSUM | NETIF_F_TSO | NETIF_F_TSO6 |
> +			 NETIF_F_GSO_UDP_L4;
> +	ndev->vlan_features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_TSO |
> +			      NETIF_F_TSO6 | NETIF_F_GSO_UDP_L4;
> +
> +	if (si->num_rss)
> +		ndev->hw_features |= NETIF_F_RXHASH;
> +
> +	ndev->priv_flags |= IFF_UNICAST_FLT;
> +	ndev->xdp_features = NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT |
> +			     NETDEV_XDP_ACT_NDO_XMIT | NETDEV_XDP_ACT_RX_SG |
> +			     NETDEV_XDP_ACT_NDO_XMIT_SG;
> +
> +	if (si->hw_features & ENETC_SI_F_PSFP && !enetc_psfp_enable(priv)) {
> +		priv->active_offloads |= ENETC_F_QCI;
> +		ndev->features |= NETIF_F_HW_TC;
> +		ndev->hw_features |= NETIF_F_HW_TC;
> +	}
> +
> +	/* pick up primary MAC address from SI */
> +	enetc_load_primary_mac_addr(&si->hw, ndev);
> +}
> +EXPORT_SYMBOL_GPL(enetc_pf_netdev_setup);
> +
> +static int enetc_mdio_probe(struct enetc_pf *pf, struct device_node *np)
> +{
> +	struct device *dev = &pf->si->pdev->dev;
> +	struct enetc_mdio_priv *mdio_priv;
> +	struct mii_bus *bus;
> +	int err;
> +
> +	bus = devm_mdiobus_alloc_size(dev, sizeof(*mdio_priv));
> +	if (!bus)
> +		return -ENOMEM;
> +
> +	bus->name = "Freescale ENETC MDIO Bus";
> +	bus->read = enetc_mdio_read_c22;
> +	bus->write = enetc_mdio_write_c22;
> +	bus->read_c45 = enetc_mdio_read_c45;
> +	bus->write_c45 = enetc_mdio_write_c45;
> +	bus->parent = dev;
> +	mdio_priv = bus->priv;
> +	mdio_priv->hw = &pf->si->hw;
> +	mdio_priv->mdio_base = ENETC_EMDIO_BASE;
> +	snprintf(bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev));
> +
> +	err = of_mdiobus_register(bus, np);
> +	if (err)
> +		return dev_err_probe(dev, err, "cannot register MDIO bus\n");
> +
> +	pf->mdio = bus;
> +
> +	return 0;
> +}
> +
> +static void enetc_mdio_remove(struct enetc_pf *pf)
> +{
> +	if (pf->mdio)
> +		mdiobus_unregister(pf->mdio);
> +}
> +
> +static bool enetc_port_has_pcs(struct enetc_pf *pf)
> +{
> +	return (pf->if_mode == PHY_INTERFACE_MODE_SGMII ||
> +		pf->if_mode == PHY_INTERFACE_MODE_1000BASEX ||
> +		pf->if_mode == PHY_INTERFACE_MODE_2500BASEX ||
> +		pf->if_mode == PHY_INTERFACE_MODE_USXGMII);
> +}
> +
> +static int enetc_imdio_create(struct enetc_pf *pf)
> +{
> +	struct device *dev = &pf->si->pdev->dev;
> +	struct enetc_mdio_priv *mdio_priv;
> +	struct phylink_pcs *phylink_pcs;
> +	struct mii_bus *bus;
> +	int err;
> +
> +	if (!pf->ops->create_pcs)
> +		return -EOPNOTSUPP;
> +
> +	bus = mdiobus_alloc_size(sizeof(*mdio_priv));
> +	if (!bus)
> +		return -ENOMEM;
> +
> +	bus->name = "Freescale ENETC internal MDIO Bus";
> +	bus->read = enetc_mdio_read_c22;
> +	bus->write = enetc_mdio_write_c22;
> +	bus->read_c45 = enetc_mdio_read_c45;
> +	bus->write_c45 = enetc_mdio_write_c45;
> +	bus->parent = dev;
> +	bus->phy_mask = ~0;
> +	mdio_priv = bus->priv;
> +	mdio_priv->hw = &pf->si->hw;
> +	mdio_priv->mdio_base = ENETC_PM_IMDIO_BASE;
> +	snprintf(bus->id, MII_BUS_ID_SIZE, "%s-imdio", dev_name(dev));
> +
> +	err = mdiobus_register(bus);
> +	if (err) {
> +		dev_err(dev, "cannot register internal MDIO bus (%d)\n", err);
> +		goto free_mdio_bus;
> +	}
> +
> +	phylink_pcs = pf->ops->create_pcs(pf, bus);
> +	if (IS_ERR(phylink_pcs)) {
> +		err = PTR_ERR(phylink_pcs);
> +		dev_err(dev, "cannot create pcs (%d)\n", err);
> +		goto unregister_mdiobus;
> +	}
> +
> +	pf->imdio = bus;
> +	pf->pcs = phylink_pcs;
> +
> +	return 0;
> +
> +unregister_mdiobus:
> +	mdiobus_unregister(bus);
> +free_mdio_bus:
> +	mdiobus_free(bus);
> +	return err;
> +}
> +
> +static void enetc_imdio_remove(struct enetc_pf *pf)
> +{
> +	if (pf->pcs && pf->ops->destroy_pcs)
> +		pf->ops->destroy_pcs(pf->pcs);
> +
> +	if (pf->imdio) {
> +		mdiobus_unregister(pf->imdio);
> +		mdiobus_free(pf->imdio);
> +	}
> +}
> +
> +int enetc_mdiobus_create(struct enetc_pf *pf, struct device_node *node)
> +{
> +	struct device_node *mdio_np;
> +	int err;
> +
> +	mdio_np = of_get_child_by_name(node, "mdio");
> +	if (mdio_np) {
> +		err = enetc_mdio_probe(pf, mdio_np);
> +
> +		of_node_put(mdio_np);
> +		if (err)
> +			return err;
> +	}
> +
> +	if (enetc_port_has_pcs(pf)) {
> +		err = enetc_imdio_create(pf);
> +		if (err) {
> +			enetc_mdio_remove(pf);
> +			return err;
> +		}
> +	}
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(enetc_mdiobus_create);
> +
> +void enetc_mdiobus_destroy(struct enetc_pf *pf)
> +{
> +	enetc_mdio_remove(pf);
> +	enetc_imdio_remove(pf);
> +}
> +EXPORT_SYMBOL_GPL(enetc_mdiobus_destroy);
> +
> +int enetc_phylink_create(struct enetc_ndev_priv *priv, struct device_node *node,
> +			 const struct phylink_mac_ops *pl_mac_ops)
> +{
> +	struct enetc_pf *pf = enetc_si_priv(priv->si);
> +	struct phylink *phylink;
> +	int err;
> +
> +	pf->phylink_config.dev = &priv->ndev->dev;
> +	pf->phylink_config.type = PHYLINK_NETDEV;
> +	pf->phylink_config.mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE |
> +		MAC_10 | MAC_100 | MAC_1000 | MAC_2500FD;
> +
> +	__set_bit(PHY_INTERFACE_MODE_INTERNAL,
> +		  pf->phylink_config.supported_interfaces);
> +	__set_bit(PHY_INTERFACE_MODE_SGMII,
> +		  pf->phylink_config.supported_interfaces);
> +	__set_bit(PHY_INTERFACE_MODE_1000BASEX,
> +		  pf->phylink_config.supported_interfaces);
> +	__set_bit(PHY_INTERFACE_MODE_2500BASEX,
> +		  pf->phylink_config.supported_interfaces);
> +	__set_bit(PHY_INTERFACE_MODE_USXGMII,
> +		  pf->phylink_config.supported_interfaces);
> +	phy_interface_set_rgmii(pf->phylink_config.supported_interfaces);
> +
> +	phylink = phylink_create(&pf->phylink_config, of_fwnode_handle(node),
> +				 pf->if_mode, pl_mac_ops);
> +	if (IS_ERR(phylink)) {
> +		err = PTR_ERR(phylink);
> +		return err;
> +	}
> +
> +	priv->phylink = phylink;
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(enetc_phylink_create);
> +
> +void enetc_phylink_destroy(struct enetc_ndev_priv *priv)
> +{
> +	phylink_destroy(priv->phylink);
> +}
> +EXPORT_SYMBOL_GPL(enetc_phylink_destroy);
> +
> +int enetc_sriov_configure(struct pci_dev *pdev, int num_vfs)
> +{
> +	struct enetc_si *si = pci_get_drvdata(pdev);
> +	struct enetc_pf *pf = enetc_si_priv(si);
> +	int err;
> +
> +	if (!IS_ENABLED(CONFIG_PCI_IOV))
> +		return 0;
> +
> +	if (!num_vfs) {
> +		pci_disable_sriov(pdev);
> +		enetc_msg_psi_free(pf);
> +		kfree(pf->vf_state);
> +		pf->num_vfs = 0;
> +	} else {
> +		pf->num_vfs = num_vfs;
> +
> +		pf->vf_state = kcalloc(num_vfs, sizeof(struct enetc_vf_state),
> +				       GFP_KERNEL);
> +		if (!pf->vf_state) {
> +			pf->num_vfs = 0;
> +			return -ENOMEM;
> +		}
> +
> +		err = enetc_msg_psi_init(pf);
> +		if (err) {
> +			dev_err(&pdev->dev, "enetc_msg_psi_init (%d)\n", err);
> +			goto err_msg_psi;
> +		}
> +
> +		err = pci_enable_sriov(pdev, num_vfs);
> +		if (err) {
> +			dev_err(&pdev->dev, "pci_enable_sriov err %d\n", err);
> +			goto err_en_sriov;
> +		}
> +	}
> +
> +	return num_vfs;
> +
> +err_en_sriov:
> +	enetc_msg_psi_free(pf);
> +err_msg_psi:
> +	kfree(pf->vf_state);
> +	pf->num_vfs = 0;
> +
> +	return err;
> +}
> +EXPORT_SYMBOL_GPL(enetc_sriov_configure);
> +
> +MODULE_DESCRIPTION("NXP ENETC PF common functionality driver");
> +MODULE_LICENSE("Dual BSD/GPL");
> --
> 2.34.1
>
Wei Fang Oct. 10, 2024, 3:19 a.m. UTC | #2
> -----Original Message-----
> From: Frank Li <frank.li@nxp.com>
> Sent: 2024年10月10日 1:16
> To: Wei Fang <wei.fang@nxp.com>
> Cc: davem@davemloft.net; edumazet@google.com; kuba@kernel.org;
> pabeni@redhat.com; robh@kernel.org; krzk+dt@kernel.org;
> conor+dt@kernel.org; Vladimir Oltean <vladimir.oltean@nxp.com>; Claudiu
> Manoil <claudiu.manoil@nxp.com>; Clark Wang <xiaoning.wang@nxp.com>;
> christophe.leroy@csgroup.eu; linux@armlinux.org.uk; bhelgaas@google.com;
> imx@lists.linux.dev; netdev@vger.kernel.org; devicetree@vger.kernel.org;
> linux-kernel@vger.kernel.org; linux-pci@vger.kernel.org
> Subject: Re: [PATCH net-next 05/11] net: enetc: add enetc-pf-common driver
> support
> 
> On Wed, Oct 09, 2024 at 05:51:10PM +0800, Wei Fang wrote:
> > The ENETC of LS1028A is revision 1.0. Now, ENETC is used on the i.MX95
> > platform and the revision is upgraded to version 4.1. The two versions
> > are incompatible except for the station interface (SI) part. Therefore,
> > we need to add a new driver for ENETC revision 4.1 and later. However,
>   ^^^^^^^^^^
>  just Add a new driver ...
> 
> > the logic of some interfaces of the two drivers is basically the same,
> > and the only difference is the hardware configuration. So in order to
> > reuse these interfaces and reduce code redundancy, we extract these
>                                                      ^^
> extract these .. in order to ...
> 
> > interfaces and compile them into a separate enetc-pf-common driver for
> > use by these two PF drivers. Note that the ENETC PF 4.1 driver will be
>                                ^^^
> Prepare to add support ENETC PF 4.1 driver in subsequent patches.
> 
> > supported in subsequent patches.
> 
> >
> > Signed-off-by: Wei Fang <wei.fang@nxp.com>
> > ---
> >  drivers/net/ethernet/freescale/enetc/Kconfig  |   9 +
> >  drivers/net/ethernet/freescale/enetc/Makefile |   3 +
> >  .../net/ethernet/freescale/enetc/enetc_pf.c   | 350 +---------------
> >  .../net/ethernet/freescale/enetc/enetc_pf.h   |  28 ++
> >  .../freescale/enetc/enetc_pf_common.c         | 375
> ++++++++++++++++++
> >  5 files changed, 431 insertions(+), 334 deletions(-)
> >  create mode 100644
> drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
> >
> > diff --git a/drivers/net/ethernet/freescale/enetc/Kconfig
> b/drivers/net/ethernet/freescale/enetc/Kconfig
> > index 51d80ea959d4..6f3306f14060 100644
> > --- a/drivers/net/ethernet/freescale/enetc/Kconfig
> > +++ b/drivers/net/ethernet/freescale/enetc/Kconfig
> > @@ -7,10 +7,19 @@ config FSL_ENETC_CORE
> >
> >  	  If compiled as module (M), the module name is fsl-enetc-core.
> >
> > +config NXP_ENETC_PF_COMMON
> > +	tristate "ENETC PF common functionality driver"
> > +	help
> > +	  This module supports common functionality between drivers of
> > +	  different versions of NXP ENETC PF controllers.
> > +
> > +	  If compiled as module (M), the module name is nxp-enetc-pf-common.
> > +
> >  config FSL_ENETC
> >  	tristate "ENETC PF driver"
> >  	depends on PCI_MSI
> >  	select MDIO_DEVRES
> > +	select NXP_ENETC_PF_COMMON
> >  	select FSL_ENETC_CORE
> >  	select FSL_ENETC_IERB
> >  	select FSL_ENETC_MDIO
> > diff --git a/drivers/net/ethernet/freescale/enetc/Makefile
> b/drivers/net/ethernet/freescale/enetc/Makefile
> > index 5c277910d538..b81ca462e358 100644
> > --- a/drivers/net/ethernet/freescale/enetc/Makefile
> > +++ b/drivers/net/ethernet/freescale/enetc/Makefile
> > @@ -3,6 +3,9 @@
> >  obj-$(CONFIG_FSL_ENETC_CORE) += fsl-enetc-core.o
> >  fsl-enetc-core-y := enetc.o enetc_cbdr.o enetc_ethtool.o
> >
> > +obj-$(CONFIG_NXP_ENETC_PF_COMMON) += nxp-enetc-pf-common.o
> > +nxp-enetc-pf-common-y := enetc_pf_common.o
> > +
> 
> I am not sure why you can't link enetc_pf_common.o into enetc_pf.o?
>
If we select CONFIG_FSL_ENETC=M and CONFIG_NXP_ENETC4=Y, there will
be compilation errors due to " undefined reference".

>
> >  obj-$(CONFIG_FSL_ENETC) += fsl-enetc.o
> >  fsl-enetc-y := enetc_pf.o
> >  fsl-enetc-$(CONFIG_PCI_IOV) += enetc_msg.o
> > diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.c
> b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
> > index 8f6b0bf48139..dae8be4a1607 100644
> > --- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c
> > +++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
> > @@ -33,18 +33,15 @@ static void enetc_pf_set_primary_mac_addr(struct
> enetc_hw *hw, int si,
> >  	__raw_writew(lower, hw->port + ENETC_PSIPMAR1(si));
> >  }
> >
> > -static int enetc_pf_set_mac_addr(struct net_device *ndev, void *addr)
> > +static struct phylink_pcs *enetc_pf_create_pcs(struct enetc_pf *pf,
> > +					       struct mii_bus *bus)
> >  {
> > -	struct enetc_ndev_priv *priv = netdev_priv(ndev);
> > -	struct sockaddr *saddr = addr;
> > -
> > -	if (!is_valid_ether_addr(saddr->sa_data))
> > -		return -EADDRNOTAVAIL;
> > -
> > -	eth_hw_addr_set(ndev, saddr->sa_data);
> > -	enetc_pf_set_primary_mac_addr(&priv->si->hw, 0, saddr->sa_data);
> > +	return lynx_pcs_create_mdiodev(bus, 0);
> > +}
> >
> > -	return 0;
> > +static void enetc_pf_destroy_pcs(struct phylink_pcs *pcs)
> > +{
> > +	lynx_pcs_destroy(pcs);
> >  }
> >
> >  static void enetc_set_vlan_promisc(struct enetc_hw *hw, char si_map)
> > @@ -393,56 +390,6 @@ static int enetc_pf_set_vf_spoofchk(struct
> net_device *ndev, int vf, bool en)
> >  	return 0;
> >  }
> >
> > -static int enetc_setup_mac_address(struct device_node *np, struct enetc_pf
> *pf,
> > -				   int si)
> > -{
> > -	struct device *dev = &pf->si->pdev->dev;
> > -	struct enetc_hw *hw = &pf->si->hw;
> > -	u8 mac_addr[ETH_ALEN] = { 0 };
> > -	int err;
> > -
> > -	/* (1) try to get the MAC address from the device tree */
> > -	if (np) {
> > -		err = of_get_mac_address(np, mac_addr);
> > -		if (err == -EPROBE_DEFER)
> > -			return err;
> > -	}
> > -
> > -	/* (2) bootloader supplied MAC address */
> > -	if (is_zero_ether_addr(mac_addr))
> > -		enetc_pf_get_primary_mac_addr(hw, si, mac_addr);
> > -
> > -	/* (3) choose a random one */
> > -	if (is_zero_ether_addr(mac_addr)) {
> > -		eth_random_addr(mac_addr);
> > -		dev_info(dev, "no MAC address specified for SI%d, using %pM\n",
> > -			 si, mac_addr);
> > -	}
> > -
> > -	enetc_pf_set_primary_mac_addr(hw, si, mac_addr);
> > -
> > -	return 0;
> > -}
> > -
> > -static int enetc_setup_mac_addresses(struct device_node *np,
> > -				     struct enetc_pf *pf)
> > -{
> > -	int err, i;
> > -
> > -	/* The PF might take its MAC from the device tree */
> > -	err = enetc_setup_mac_address(np, pf, 0);
> > -	if (err)
> > -		return err;
> > -
> > -	for (i = 0; i < pf->total_vfs; i++) {
> > -		err = enetc_setup_mac_address(NULL, pf, i + 1);
> > -		if (err)
> > -			return err;
> > -	}
> > -
> > -	return 0;
> > -}
> > -
> >  static void enetc_port_assign_rfs_entries(struct enetc_si *si)
> >  {
> >  	struct enetc_pf *pf = enetc_si_priv(si);
> > @@ -656,55 +603,6 @@ void enetc_msg_handle_rxmsg(struct enetc_pf *pf,
> int vf_id, u16 *status)
> >  	}
> >  }
> >
> > -#ifdef CONFIG_PCI_IOV
> > -static int enetc_sriov_configure(struct pci_dev *pdev, int num_vfs)
> > -{
> > -	struct enetc_si *si = pci_get_drvdata(pdev);
> > -	struct enetc_pf *pf = enetc_si_priv(si);
> > -	int err;
> > -
> > -	if (!num_vfs) {
> > -		enetc_msg_psi_free(pf);
> > -		kfree(pf->vf_state);
> > -		pf->num_vfs = 0;
> > -		pci_disable_sriov(pdev);
> > -	} else {
> > -		pf->num_vfs = num_vfs;
> > -
> > -		pf->vf_state = kcalloc(num_vfs, sizeof(struct enetc_vf_state),
> > -				       GFP_KERNEL);
> > -		if (!pf->vf_state) {
> > -			pf->num_vfs = 0;
> > -			return -ENOMEM;
> > -		}
> > -
> > -		err = enetc_msg_psi_init(pf);
> > -		if (err) {
> > -			dev_err(&pdev->dev, "enetc_msg_psi_init (%d)\n", err);
> > -			goto err_msg_psi;
> > -		}
> > -
> > -		err = pci_enable_sriov(pdev, num_vfs);
> > -		if (err) {
> > -			dev_err(&pdev->dev, "pci_enable_sriov err %d\n", err);
> > -			goto err_en_sriov;
> > -		}
> > -	}
> > -
> > -	return num_vfs;
> > -
> > -err_en_sriov:
> > -	enetc_msg_psi_free(pf);
> > -err_msg_psi:
> > -	kfree(pf->vf_state);
> > -	pf->num_vfs = 0;
> > -
> > -	return err;
> > -}
> > -#else
> > -#define enetc_sriov_configure(pdev, num_vfs)	(void)0
> > -#endif
> > -
> >  static int enetc_pf_set_features(struct net_device *ndev,
> >  				 netdev_features_t features)
> >  {
> > @@ -775,187 +673,6 @@ static const struct net_device_ops enetc_ndev_ops
> = {
> >  	.ndo_xdp_xmit		= enetc_xdp_xmit,
> >  };
> >
> > -static void enetc_pf_netdev_setup(struct enetc_si *si, struct net_device
> *ndev,
> > -				  const struct net_device_ops *ndev_ops)
> > -{
> > -	struct enetc_ndev_priv *priv = netdev_priv(ndev);
> > -
> > -	SET_NETDEV_DEV(ndev, &si->pdev->dev);
> > -	priv->ndev = ndev;
> > -	priv->si = si;
> > -	priv->dev = &si->pdev->dev;
> > -	si->ndev = ndev;
> > -
> > -	priv->msg_enable = (NETIF_MSG_WOL << 1) - 1;
> > -	ndev->netdev_ops = ndev_ops;
> > -	enetc_set_ethtool_ops(ndev);
> > -	ndev->watchdog_timeo = 5 * HZ;
> > -	ndev->max_mtu = ENETC_MAX_MTU;
> > -
> > -	ndev->hw_features = NETIF_F_SG | NETIF_F_RXCSUM |
> > -			    NETIF_F_HW_VLAN_CTAG_TX |
> NETIF_F_HW_VLAN_CTAG_RX |
> > -			    NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_LOOPBACK |
> > -			    NETIF_F_HW_CSUM | NETIF_F_TSO | NETIF_F_TSO6;
> > -	ndev->features = NETIF_F_HIGHDMA | NETIF_F_SG | NETIF_F_RXCSUM |
> > -			 NETIF_F_HW_VLAN_CTAG_TX |
> > -			 NETIF_F_HW_VLAN_CTAG_RX |
> > -			 NETIF_F_HW_CSUM | NETIF_F_TSO | NETIF_F_TSO6;
> > -	ndev->vlan_features = NETIF_F_SG | NETIF_F_HW_CSUM |
> > -			      NETIF_F_TSO | NETIF_F_TSO6;
> > -
> > -	if (si->num_rss)
> > -		ndev->hw_features |= NETIF_F_RXHASH;
> > -
> > -	ndev->priv_flags |= IFF_UNICAST_FLT;
> > -	ndev->xdp_features = NETDEV_XDP_ACT_BASIC |
> NETDEV_XDP_ACT_REDIRECT |
> > -			     NETDEV_XDP_ACT_NDO_XMIT |
> NETDEV_XDP_ACT_RX_SG |
> > -			     NETDEV_XDP_ACT_NDO_XMIT_SG;
> > -
> > -	if (si->hw_features & ENETC_SI_F_PSFP && !enetc_psfp_enable(priv)) {
> > -		priv->active_offloads |= ENETC_F_QCI;
> > -		ndev->features |= NETIF_F_HW_TC;
> > -		ndev->hw_features |= NETIF_F_HW_TC;
> > -	}
> > -
> > -	/* pick up primary MAC address from SI */
> > -	enetc_load_primary_mac_addr(&si->hw, ndev);
> > -}
> > -
> > -static int enetc_mdio_probe(struct enetc_pf *pf, struct device_node *np)
> > -{
> > -	struct device *dev = &pf->si->pdev->dev;
> > -	struct enetc_mdio_priv *mdio_priv;
> > -	struct mii_bus *bus;
> > -	int err;
> > -
> > -	bus = devm_mdiobus_alloc_size(dev, sizeof(*mdio_priv));
> > -	if (!bus)
> > -		return -ENOMEM;
> > -
> > -	bus->name = "Freescale ENETC MDIO Bus";
> > -	bus->read = enetc_mdio_read_c22;
> > -	bus->write = enetc_mdio_write_c22;
> > -	bus->read_c45 = enetc_mdio_read_c45;
> > -	bus->write_c45 = enetc_mdio_write_c45;
> > -	bus->parent = dev;
> > -	mdio_priv = bus->priv;
> > -	mdio_priv->hw = &pf->si->hw;
> > -	mdio_priv->mdio_base = ENETC_EMDIO_BASE;
> > -	snprintf(bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev));
> > -
> > -	err = of_mdiobus_register(bus, np);
> > -	if (err)
> > -		return dev_err_probe(dev, err, "cannot register MDIO bus\n");
> > -
> > -	pf->mdio = bus;
> > -
> > -	return 0;
> > -}
> > -
> > -static void enetc_mdio_remove(struct enetc_pf *pf)
> > -{
> > -	if (pf->mdio)
> > -		mdiobus_unregister(pf->mdio);
> > -}
> > -
> > -static int enetc_imdio_create(struct enetc_pf *pf)
> > -{
> > -	struct device *dev = &pf->si->pdev->dev;
> > -	struct enetc_mdio_priv *mdio_priv;
> > -	struct phylink_pcs *phylink_pcs;
> > -	struct mii_bus *bus;
> > -	int err;
> > -
> > -	bus = mdiobus_alloc_size(sizeof(*mdio_priv));
> > -	if (!bus)
> > -		return -ENOMEM;
> > -
> > -	bus->name = "Freescale ENETC internal MDIO Bus";
> > -	bus->read = enetc_mdio_read_c22;
> > -	bus->write = enetc_mdio_write_c22;
> > -	bus->read_c45 = enetc_mdio_read_c45;
> > -	bus->write_c45 = enetc_mdio_write_c45;
> > -	bus->parent = dev;
> > -	bus->phy_mask = ~0;
> > -	mdio_priv = bus->priv;
> > -	mdio_priv->hw = &pf->si->hw;
> > -	mdio_priv->mdio_base = ENETC_PM_IMDIO_BASE;
> > -	snprintf(bus->id, MII_BUS_ID_SIZE, "%s-imdio", dev_name(dev));
> > -
> > -	err = mdiobus_register(bus);
> > -	if (err) {
> > -		dev_err(dev, "cannot register internal MDIO bus (%d)\n", err);
> > -		goto free_mdio_bus;
> > -	}
> > -
> > -	phylink_pcs = lynx_pcs_create_mdiodev(bus, 0);
> > -	if (IS_ERR(phylink_pcs)) {
> > -		err = PTR_ERR(phylink_pcs);
> > -		dev_err(dev, "cannot create lynx pcs (%d)\n", err);
> > -		goto unregister_mdiobus;
> > -	}
> > -
> > -	pf->imdio = bus;
> > -	pf->pcs = phylink_pcs;
> > -
> > -	return 0;
> > -
> > -unregister_mdiobus:
> > -	mdiobus_unregister(bus);
> > -free_mdio_bus:
> > -	mdiobus_free(bus);
> > -	return err;
> > -}
> > -
> > -static void enetc_imdio_remove(struct enetc_pf *pf)
> > -{
> > -	if (pf->pcs)
> > -		lynx_pcs_destroy(pf->pcs);
> > -	if (pf->imdio) {
> > -		mdiobus_unregister(pf->imdio);
> > -		mdiobus_free(pf->imdio);
> > -	}
> > -}
> > -
> > -static bool enetc_port_has_pcs(struct enetc_pf *pf)
> > -{
> > -	return (pf->if_mode == PHY_INTERFACE_MODE_SGMII ||
> > -		pf->if_mode == PHY_INTERFACE_MODE_1000BASEX ||
> > -		pf->if_mode == PHY_INTERFACE_MODE_2500BASEX ||
> > -		pf->if_mode == PHY_INTERFACE_MODE_USXGMII);
> > -}
> > -
> > -static int enetc_mdiobus_create(struct enetc_pf *pf, struct device_node
> *node)
> > -{
> > -	struct device_node *mdio_np;
> > -	int err;
> > -
> > -	mdio_np = of_get_child_by_name(node, "mdio");
> > -	if (mdio_np) {
> > -		err = enetc_mdio_probe(pf, mdio_np);
> > -
> > -		of_node_put(mdio_np);
> > -		if (err)
> > -			return err;
> > -	}
> > -
> > -	if (enetc_port_has_pcs(pf)) {
> > -		err = enetc_imdio_create(pf);
> > -		if (err) {
> > -			enetc_mdio_remove(pf);
> > -			return err;
> > -		}
> > -	}
> > -
> > -	return 0;
> > -}
> > -
> > -static void enetc_mdiobus_destroy(struct enetc_pf *pf)
> > -{
> > -	enetc_mdio_remove(pf);
> > -	enetc_imdio_remove(pf);
> > -}
> > -
> >  static struct phylink_pcs *
> >  enetc_pl_mac_select_pcs(struct phylink_config *config, phy_interface_t
> iface)
> >  {
> > @@ -1101,47 +818,6 @@ static const struct phylink_mac_ops
> enetc_mac_phylink_ops = {
> >  	.mac_link_down = enetc_pl_mac_link_down,
> >  };
> >
> > -static int enetc_phylink_create(struct enetc_ndev_priv *priv,
> > -				struct device_node *node)
> > -{
> > -	struct enetc_pf *pf = enetc_si_priv(priv->si);
> > -	struct phylink *phylink;
> > -	int err;
> > -
> > -	pf->phylink_config.dev = &priv->ndev->dev;
> > -	pf->phylink_config.type = PHYLINK_NETDEV;
> > -	pf->phylink_config.mac_capabilities = MAC_ASYM_PAUSE |
> MAC_SYM_PAUSE |
> > -		MAC_10 | MAC_100 | MAC_1000 | MAC_2500FD;
> > -
> > -	__set_bit(PHY_INTERFACE_MODE_INTERNAL,
> > -		  pf->phylink_config.supported_interfaces);
> > -	__set_bit(PHY_INTERFACE_MODE_SGMII,
> > -		  pf->phylink_config.supported_interfaces);
> > -	__set_bit(PHY_INTERFACE_MODE_1000BASEX,
> > -		  pf->phylink_config.supported_interfaces);
> > -	__set_bit(PHY_INTERFACE_MODE_2500BASEX,
> > -		  pf->phylink_config.supported_interfaces);
> > -	__set_bit(PHY_INTERFACE_MODE_USXGMII,
> > -		  pf->phylink_config.supported_interfaces);
> > -	phy_interface_set_rgmii(pf->phylink_config.supported_interfaces);
> > -
> > -	phylink = phylink_create(&pf->phylink_config, of_fwnode_handle(node),
> > -				 pf->if_mode, &enetc_mac_phylink_ops);
> > -	if (IS_ERR(phylink)) {
> > -		err = PTR_ERR(phylink);
> > -		return err;
> > -	}
> > -
> > -	priv->phylink = phylink;
> > -
> > -	return 0;
> > -}
> > -
> > -static void enetc_phylink_destroy(struct enetc_ndev_priv *priv)
> > -{
> > -	phylink_destroy(priv->phylink);
> > -}
> > -
> >  /* Initialize the entire shared memory for the flow steering entries
> >   * of this port (PF + VFs)
> >   */
> > @@ -1259,6 +935,13 @@ static void enetc_psi_destroy(struct pci_dev *pdev)
> >  	enetc_pci_remove(pdev);
> >  }
> >
> > +static const struct enetc_pf_ops enetc_pf_ops = {
> > +	.set_si_primary_mac = enetc_pf_set_primary_mac_addr,
> > +	.get_si_primary_mac = enetc_pf_get_primary_mac_addr,
> > +	.create_pcs = enetc_pf_create_pcs,
> > +	.destroy_pcs = enetc_pf_destroy_pcs,
> > +};
> > +
> 
> I suppose this patch should just move functions to common.c. This involve
> addition code logic change. It is not easy to follow up to make sure your
> change is correct.
> 

Because these common interfaces are separated into a separate driver, some
changes are inevitable. I can split the patch into two parts, the first part moves
the functions into common.c, and the second part modifies common.c into a
separate driver.

> Frank
> 
> >  static int enetc_pf_probe(struct pci_dev *pdev,
> >  			  const struct pci_device_id *ent)
> >  {
> > @@ -1286,6 +969,7 @@ static int enetc_pf_probe(struct pci_dev *pdev,
> >  	pf = enetc_si_priv(si);
> >  	pf->si = si;
> >  	pf->total_vfs = pci_sriov_get_totalvfs(pdev);
> > +	enetc_pf_ops_register(pf, &enetc_pf_ops);
> >
> >  	err = enetc_setup_mac_addresses(node, pf);
> >  	if (err)
> > @@ -1338,7 +1022,7 @@ static int enetc_pf_probe(struct pci_dev *pdev,
> >  	if (err)
> >  		goto err_mdiobus_create;
> >
> > -	err = enetc_phylink_create(priv, node);
> > +	err = enetc_phylink_create(priv, node, &enetc_mac_phylink_ops);
> >  	if (err)
> >  		goto err_phylink_create;
> >
> > @@ -1422,9 +1106,7 @@ static struct pci_driver enetc_pf_driver = {
> >  	.id_table = enetc_pf_id_table,
> >  	.probe = enetc_pf_probe,
> >  	.remove = enetc_pf_remove,
> > -#ifdef CONFIG_PCI_IOV
> >  	.sriov_configure = enetc_sriov_configure,
> > -#endif
> >  };
> >  module_pci_driver(enetc_pf_driver);
> >
> > diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.h
> b/drivers/net/ethernet/freescale/enetc/enetc_pf.h
> > index c26bd66e4597..ad7dab0eb752 100644
> > --- a/drivers/net/ethernet/freescale/enetc/enetc_pf.h
> > +++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.h
> > @@ -28,6 +28,15 @@ struct enetc_vf_state {
> >  	enum enetc_vf_flags flags;
> >  };
> >
> > +struct enetc_pf;
> > +
> > +struct enetc_pf_ops {
> > +	void (*set_si_primary_mac)(struct enetc_hw *hw, int si, const u8 *addr);
> > +	void (*get_si_primary_mac)(struct enetc_hw *hw, int si, u8 *addr);
> > +	struct phylink_pcs *(*create_pcs)(struct enetc_pf *pf, struct mii_bus *bus);
> > +	void (*destroy_pcs)(struct phylink_pcs *pcs);
> > +};
> > +
> >  struct enetc_pf {
> >  	struct enetc_si *si;
> >  	int num_vfs; /* number of active VFs, after sriov_init */
> > @@ -50,6 +59,8 @@ struct enetc_pf {
> >
> >  	phy_interface_t if_mode;
> >  	struct phylink_config phylink_config;
> > +
> > +	const struct enetc_pf_ops *ops;
> >  };
> >
> >  #define phylink_to_enetc_pf(config) \
> > @@ -58,3 +69,20 @@ struct enetc_pf {
> >  int enetc_msg_psi_init(struct enetc_pf *pf);
> >  void enetc_msg_psi_free(struct enetc_pf *pf);
> >  void enetc_msg_handle_rxmsg(struct enetc_pf *pf, int mbox_id, u16
> *status);
> > +
> > +int enetc_pf_set_mac_addr(struct net_device *ndev, void *addr);
> > +int enetc_setup_mac_addresses(struct device_node *np, struct enetc_pf
> *pf);
> > +void enetc_pf_netdev_setup(struct enetc_si *si, struct net_device *ndev,
> > +			   const struct net_device_ops *ndev_ops);
> > +int enetc_mdiobus_create(struct enetc_pf *pf, struct device_node *node);
> > +void enetc_mdiobus_destroy(struct enetc_pf *pf);
> > +int enetc_phylink_create(struct enetc_ndev_priv *priv, struct device_node
> *node,
> > +			 const struct phylink_mac_ops *pl_mac_ops);
> > +void enetc_phylink_destroy(struct enetc_ndev_priv *priv);
> > +int enetc_sriov_configure(struct pci_dev *pdev, int num_vfs);
> > +
> > +static inline void enetc_pf_ops_register(struct enetc_pf *pf,
> > +					 const struct enetc_pf_ops *ops)
> > +{
> > +	pf->ops = ops;
> > +}
> > diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
> b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
> > new file mode 100644
> > index 000000000000..bbfb5c1ffd13
> > --- /dev/null
> > +++ b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
> > @@ -0,0 +1,375 @@
> > +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
> > +/* Copyright 2024 NXP */
> > +#include <linux/fsl/enetc_mdio.h>
> > +#include <linux/of_mdio.h>
> > +#include <linux/of_net.h>
> > +
> > +#include "enetc_pf.h"
> > +
> > +static int enetc_set_si_hw_addr(struct enetc_pf *pf, int si, u8 *mac_addr)
> > +{
> > +	struct enetc_hw *hw = &pf->si->hw;
> > +
> > +	if (pf->ops->set_si_primary_mac)
> > +		pf->ops->set_si_primary_mac(hw, si, mac_addr);
> > +	else
> > +		return -EOPNOTSUPP;
> > +
> > +	return 0;
> > +}
> > +
> > +int enetc_pf_set_mac_addr(struct net_device *ndev, void *addr)
> > +{
> > +	struct enetc_ndev_priv *priv = netdev_priv(ndev);
> > +	struct enetc_pf *pf = enetc_si_priv(priv->si);
> > +	struct sockaddr *saddr = addr;
> > +	int err;
> > +
> > +	if (!is_valid_ether_addr(saddr->sa_data))
> > +		return -EADDRNOTAVAIL;
> > +
> > +	err = enetc_set_si_hw_addr(pf, 0, saddr->sa_data);
> > +	if (err)
> > +		return err;
> > +
> > +	eth_hw_addr_set(ndev, saddr->sa_data);
> > +
> > +	return 0;
> > +}
> > +EXPORT_SYMBOL_GPL(enetc_pf_set_mac_addr);
> > +
> > +static int enetc_setup_mac_address(struct device_node *np, struct enetc_pf
> *pf,
> > +				   int si)
> > +{
> > +	struct device *dev = &pf->si->pdev->dev;
> > +	struct enetc_hw *hw = &pf->si->hw;
> > +	u8 mac_addr[ETH_ALEN] = { 0 };
> > +	int err;
> > +
> > +	/* (1) try to get the MAC address from the device tree */
> > +	if (np) {
> > +		err = of_get_mac_address(np, mac_addr);
> > +		if (err == -EPROBE_DEFER)
> > +			return err;
> > +	}
> > +
> > +	/* (2) bootloader supplied MAC address */
> > +	if (is_zero_ether_addr(mac_addr) && pf->ops->get_si_primary_mac)
> > +		pf->ops->get_si_primary_mac(hw, si, mac_addr);
> > +
> > +	/* (3) choose a random one */
> > +	if (is_zero_ether_addr(mac_addr)) {
> > +		eth_random_addr(mac_addr);
> > +		dev_info(dev, "no MAC address specified for SI%d, using %pM\n",
> > +			 si, mac_addr);
> > +	}
> > +
> > +	err = enetc_set_si_hw_addr(pf, si, mac_addr);
> > +	if (err)
> > +		return err;
> > +
> > +	return 0;
> > +}
> > +
> > +int enetc_setup_mac_addresses(struct device_node *np, struct enetc_pf
> *pf)
> > +{
> > +	int err, i;
> > +
> > +	/* The PF might take its MAC from the device tree */
> > +	err = enetc_setup_mac_address(np, pf, 0);
> > +	if (err)
> > +		return err;
> > +
> > +	for (i = 0; i < pf->total_vfs; i++) {
> > +		err = enetc_setup_mac_address(NULL, pf, i + 1);
> > +		if (err)
> > +			return err;
> > +	}
> > +
> > +	return 0;
> > +}
> > +EXPORT_SYMBOL_GPL(enetc_setup_mac_addresses);
> > +
> > +void enetc_pf_netdev_setup(struct enetc_si *si, struct net_device *ndev,
> > +			   const struct net_device_ops *ndev_ops)
> > +{
> > +	struct enetc_ndev_priv *priv = netdev_priv(ndev);
> > +
> > +	SET_NETDEV_DEV(ndev, &si->pdev->dev);
> > +	priv->ndev = ndev;
> > +	priv->si = si;
> > +	priv->dev = &si->pdev->dev;
> > +	si->ndev = ndev;
> > +
> > +	priv->msg_enable = (NETIF_MSG_WOL << 1) - 1;
> > +	ndev->netdev_ops = ndev_ops;
> > +	enetc_set_ethtool_ops(ndev);
> > +	ndev->watchdog_timeo = 5 * HZ;
> > +	ndev->max_mtu = ENETC_MAX_MTU;
> > +
> > +	ndev->hw_features = NETIF_F_SG | NETIF_F_RXCSUM |
> > +			    NETIF_F_HW_VLAN_CTAG_TX |
> NETIF_F_HW_VLAN_CTAG_RX |
> > +			    NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_LOOPBACK |
> > +			    NETIF_F_HW_CSUM | NETIF_F_TSO | NETIF_F_TSO6 |
> > +			    NETIF_F_GSO_UDP_L4;
> > +	ndev->features = NETIF_F_HIGHDMA | NETIF_F_SG | NETIF_F_RXCSUM |
> > +			 NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX
> |
> > +			 NETIF_F_HW_CSUM | NETIF_F_TSO | NETIF_F_TSO6 |
> > +			 NETIF_F_GSO_UDP_L4;
> > +	ndev->vlan_features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_TSO |
> > +			      NETIF_F_TSO6 | NETIF_F_GSO_UDP_L4;
> > +
> > +	if (si->num_rss)
> > +		ndev->hw_features |= NETIF_F_RXHASH;
> > +
> > +	ndev->priv_flags |= IFF_UNICAST_FLT;
> > +	ndev->xdp_features = NETDEV_XDP_ACT_BASIC |
> NETDEV_XDP_ACT_REDIRECT |
> > +			     NETDEV_XDP_ACT_NDO_XMIT |
> NETDEV_XDP_ACT_RX_SG |
> > +			     NETDEV_XDP_ACT_NDO_XMIT_SG;
> > +
> > +	if (si->hw_features & ENETC_SI_F_PSFP && !enetc_psfp_enable(priv)) {
> > +		priv->active_offloads |= ENETC_F_QCI;
> > +		ndev->features |= NETIF_F_HW_TC;
> > +		ndev->hw_features |= NETIF_F_HW_TC;
> > +	}
> > +
> > +	/* pick up primary MAC address from SI */
> > +	enetc_load_primary_mac_addr(&si->hw, ndev);
> > +}
> > +EXPORT_SYMBOL_GPL(enetc_pf_netdev_setup);
> > +
> > +static int enetc_mdio_probe(struct enetc_pf *pf, struct device_node *np)
> > +{
> > +	struct device *dev = &pf->si->pdev->dev;
> > +	struct enetc_mdio_priv *mdio_priv;
> > +	struct mii_bus *bus;
> > +	int err;
> > +
> > +	bus = devm_mdiobus_alloc_size(dev, sizeof(*mdio_priv));
> > +	if (!bus)
> > +		return -ENOMEM;
> > +
> > +	bus->name = "Freescale ENETC MDIO Bus";
> > +	bus->read = enetc_mdio_read_c22;
> > +	bus->write = enetc_mdio_write_c22;
> > +	bus->read_c45 = enetc_mdio_read_c45;
> > +	bus->write_c45 = enetc_mdio_write_c45;
> > +	bus->parent = dev;
> > +	mdio_priv = bus->priv;
> > +	mdio_priv->hw = &pf->si->hw;
> > +	mdio_priv->mdio_base = ENETC_EMDIO_BASE;
> > +	snprintf(bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev));
> > +
> > +	err = of_mdiobus_register(bus, np);
> > +	if (err)
> > +		return dev_err_probe(dev, err, "cannot register MDIO bus\n");
> > +
> > +	pf->mdio = bus;
> > +
> > +	return 0;
> > +}
> > +
> > +static void enetc_mdio_remove(struct enetc_pf *pf)
> > +{
> > +	if (pf->mdio)
> > +		mdiobus_unregister(pf->mdio);
> > +}
> > +
> > +static bool enetc_port_has_pcs(struct enetc_pf *pf)
> > +{
> > +	return (pf->if_mode == PHY_INTERFACE_MODE_SGMII ||
> > +		pf->if_mode == PHY_INTERFACE_MODE_1000BASEX ||
> > +		pf->if_mode == PHY_INTERFACE_MODE_2500BASEX ||
> > +		pf->if_mode == PHY_INTERFACE_MODE_USXGMII);
> > +}
> > +
> > +static int enetc_imdio_create(struct enetc_pf *pf)
> > +{
> > +	struct device *dev = &pf->si->pdev->dev;
> > +	struct enetc_mdio_priv *mdio_priv;
> > +	struct phylink_pcs *phylink_pcs;
> > +	struct mii_bus *bus;
> > +	int err;
> > +
> > +	if (!pf->ops->create_pcs)
> > +		return -EOPNOTSUPP;
> > +
> > +	bus = mdiobus_alloc_size(sizeof(*mdio_priv));
> > +	if (!bus)
> > +		return -ENOMEM;
> > +
> > +	bus->name = "Freescale ENETC internal MDIO Bus";
> > +	bus->read = enetc_mdio_read_c22;
> > +	bus->write = enetc_mdio_write_c22;
> > +	bus->read_c45 = enetc_mdio_read_c45;
> > +	bus->write_c45 = enetc_mdio_write_c45;
> > +	bus->parent = dev;
> > +	bus->phy_mask = ~0;
> > +	mdio_priv = bus->priv;
> > +	mdio_priv->hw = &pf->si->hw;
> > +	mdio_priv->mdio_base = ENETC_PM_IMDIO_BASE;
> > +	snprintf(bus->id, MII_BUS_ID_SIZE, "%s-imdio", dev_name(dev));
> > +
> > +	err = mdiobus_register(bus);
> > +	if (err) {
> > +		dev_err(dev, "cannot register internal MDIO bus (%d)\n", err);
> > +		goto free_mdio_bus;
> > +	}
> > +
> > +	phylink_pcs = pf->ops->create_pcs(pf, bus);
> > +	if (IS_ERR(phylink_pcs)) {
> > +		err = PTR_ERR(phylink_pcs);
> > +		dev_err(dev, "cannot create pcs (%d)\n", err);
> > +		goto unregister_mdiobus;
> > +	}
> > +
> > +	pf->imdio = bus;
> > +	pf->pcs = phylink_pcs;
> > +
> > +	return 0;
> > +
> > +unregister_mdiobus:
> > +	mdiobus_unregister(bus);
> > +free_mdio_bus:
> > +	mdiobus_free(bus);
> > +	return err;
> > +}
> > +
> > +static void enetc_imdio_remove(struct enetc_pf *pf)
> > +{
> > +	if (pf->pcs && pf->ops->destroy_pcs)
> > +		pf->ops->destroy_pcs(pf->pcs);
> > +
> > +	if (pf->imdio) {
> > +		mdiobus_unregister(pf->imdio);
> > +		mdiobus_free(pf->imdio);
> > +	}
> > +}
> > +
> > +int enetc_mdiobus_create(struct enetc_pf *pf, struct device_node *node)
> > +{
> > +	struct device_node *mdio_np;
> > +	int err;
> > +
> > +	mdio_np = of_get_child_by_name(node, "mdio");
> > +	if (mdio_np) {
> > +		err = enetc_mdio_probe(pf, mdio_np);
> > +
> > +		of_node_put(mdio_np);
> > +		if (err)
> > +			return err;
> > +	}
> > +
> > +	if (enetc_port_has_pcs(pf)) {
> > +		err = enetc_imdio_create(pf);
> > +		if (err) {
> > +			enetc_mdio_remove(pf);
> > +			return err;
> > +		}
> > +	}
> > +
> > +	return 0;
> > +}
> > +EXPORT_SYMBOL_GPL(enetc_mdiobus_create);
> > +
> > +void enetc_mdiobus_destroy(struct enetc_pf *pf)
> > +{
> > +	enetc_mdio_remove(pf);
> > +	enetc_imdio_remove(pf);
> > +}
> > +EXPORT_SYMBOL_GPL(enetc_mdiobus_destroy);
> > +
> > +int enetc_phylink_create(struct enetc_ndev_priv *priv, struct device_node
> *node,
> > +			 const struct phylink_mac_ops *pl_mac_ops)
> > +{
> > +	struct enetc_pf *pf = enetc_si_priv(priv->si);
> > +	struct phylink *phylink;
> > +	int err;
> > +
> > +	pf->phylink_config.dev = &priv->ndev->dev;
> > +	pf->phylink_config.type = PHYLINK_NETDEV;
> > +	pf->phylink_config.mac_capabilities = MAC_ASYM_PAUSE |
> MAC_SYM_PAUSE |
> > +		MAC_10 | MAC_100 | MAC_1000 | MAC_2500FD;
> > +
> > +	__set_bit(PHY_INTERFACE_MODE_INTERNAL,
> > +		  pf->phylink_config.supported_interfaces);
> > +	__set_bit(PHY_INTERFACE_MODE_SGMII,
> > +		  pf->phylink_config.supported_interfaces);
> > +	__set_bit(PHY_INTERFACE_MODE_1000BASEX,
> > +		  pf->phylink_config.supported_interfaces);
> > +	__set_bit(PHY_INTERFACE_MODE_2500BASEX,
> > +		  pf->phylink_config.supported_interfaces);
> > +	__set_bit(PHY_INTERFACE_MODE_USXGMII,
> > +		  pf->phylink_config.supported_interfaces);
> > +	phy_interface_set_rgmii(pf->phylink_config.supported_interfaces);
> > +
> > +	phylink = phylink_create(&pf->phylink_config, of_fwnode_handle(node),
> > +				 pf->if_mode, pl_mac_ops);
> > +	if (IS_ERR(phylink)) {
> > +		err = PTR_ERR(phylink);
> > +		return err;
> > +	}
> > +
> > +	priv->phylink = phylink;
> > +
> > +	return 0;
> > +}
> > +EXPORT_SYMBOL_GPL(enetc_phylink_create);
> > +
> > +void enetc_phylink_destroy(struct enetc_ndev_priv *priv)
> > +{
> > +	phylink_destroy(priv->phylink);
> > +}
> > +EXPORT_SYMBOL_GPL(enetc_phylink_destroy);
> > +
> > +int enetc_sriov_configure(struct pci_dev *pdev, int num_vfs)
> > +{
> > +	struct enetc_si *si = pci_get_drvdata(pdev);
> > +	struct enetc_pf *pf = enetc_si_priv(si);
> > +	int err;
> > +
> > +	if (!IS_ENABLED(CONFIG_PCI_IOV))
> > +		return 0;
> > +
> > +	if (!num_vfs) {
> > +		pci_disable_sriov(pdev);
> > +		enetc_msg_psi_free(pf);
> > +		kfree(pf->vf_state);
> > +		pf->num_vfs = 0;
> > +	} else {
> > +		pf->num_vfs = num_vfs;
> > +
> > +		pf->vf_state = kcalloc(num_vfs, sizeof(struct enetc_vf_state),
> > +				       GFP_KERNEL);
> > +		if (!pf->vf_state) {
> > +			pf->num_vfs = 0;
> > +			return -ENOMEM;
> > +		}
> > +
> > +		err = enetc_msg_psi_init(pf);
> > +		if (err) {
> > +			dev_err(&pdev->dev, "enetc_msg_psi_init (%d)\n", err);
> > +			goto err_msg_psi;
> > +		}
> > +
> > +		err = pci_enable_sriov(pdev, num_vfs);
> > +		if (err) {
> > +			dev_err(&pdev->dev, "pci_enable_sriov err %d\n", err);
> > +			goto err_en_sriov;
> > +		}
> > +	}
> > +
> > +	return num_vfs;
> > +
> > +err_en_sriov:
> > +	enetc_msg_psi_free(pf);
> > +err_msg_psi:
> > +	kfree(pf->vf_state);
> > +	pf->num_vfs = 0;
> > +
> > +	return err;
> > +}
> > +EXPORT_SYMBOL_GPL(enetc_sriov_configure);
> > +
> > +MODULE_DESCRIPTION("NXP ENETC PF common functionality driver");
> > +MODULE_LICENSE("Dual BSD/GPL");
> > --
> > 2.34.1
> >
kernel test robot Oct. 10, 2024, 2:16 p.m. UTC | #3
Hi Wei,

kernel test robot noticed the following build warnings:

[auto build test WARNING on net-next/main]

url:    https://github.com/intel-lab-lkp/linux/commits/Wei-Fang/dt-bindings-net-add-compatible-string-for-i-MX95-EMDIO/20241009-181113
base:   net-next/main
patch link:    https://lore.kernel.org/r/20241009095116.147412-6-wei.fang%40nxp.com
patch subject: [PATCH net-next 05/11] net: enetc: add enetc-pf-common driver support
config: m68k-allmodconfig (https://download.01.org/0day-ci/archive/20241010/202410102136.jQHZOcS4-lkp@intel.com/config)
compiler: m68k-linux-gcc (GCC) 14.1.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20241010/202410102136.jQHZOcS4-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/202410102136.jQHZOcS4-lkp@intel.com/

All warnings (new ones prefixed by >>):

   In file included from drivers/net/ethernet/freescale/enetc/enetc_pf_common.c:3:
>> include/linux/fsl/enetc_mdio.h:62:18: warning: no previous prototype for 'enetc_hw_alloc' [-Wmissing-prototypes]
      62 | struct enetc_hw *enetc_hw_alloc(struct device *dev, void __iomem *port_regs)
         |                  ^~~~~~~~~~~~~~

Kconfig warnings: (for reference only)
   WARNING: unmet direct dependencies detected for GET_FREE_REGION
   Depends on [n]: SPARSEMEM [=n]
   Selected by [m]:
   - RESOURCE_KUNIT_TEST [=m] && RUNTIME_TESTING_MENU [=y] && KUNIT [=m]


vim +/enetc_hw_alloc +62 include/linux/fsl/enetc_mdio.h

6517798dd3432a Claudiu Manoil 2020-01-06  49  
80e87442e69ba8 Andrew Lunn    2023-01-12  50  static inline int enetc_mdio_read_c22(struct mii_bus *bus, int phy_id,
80e87442e69ba8 Andrew Lunn    2023-01-12  51  				      int regnum)
6517798dd3432a Claudiu Manoil 2020-01-06  52  { return -EINVAL; }
80e87442e69ba8 Andrew Lunn    2023-01-12  53  static inline int enetc_mdio_write_c22(struct mii_bus *bus, int phy_id,
80e87442e69ba8 Andrew Lunn    2023-01-12  54  				       int regnum, u16 value)
80e87442e69ba8 Andrew Lunn    2023-01-12  55  { return -EINVAL; }
80e87442e69ba8 Andrew Lunn    2023-01-12  56  static inline int enetc_mdio_read_c45(struct mii_bus *bus, int phy_id,
80e87442e69ba8 Andrew Lunn    2023-01-12  57  				      int devad, int regnum)
80e87442e69ba8 Andrew Lunn    2023-01-12  58  { return -EINVAL; }
80e87442e69ba8 Andrew Lunn    2023-01-12  59  static inline int enetc_mdio_write_c45(struct mii_bus *bus, int phy_id,
80e87442e69ba8 Andrew Lunn    2023-01-12  60  				       int devad, int regnum, u16 value)
6517798dd3432a Claudiu Manoil 2020-01-06  61  { return -EINVAL; }
6517798dd3432a Claudiu Manoil 2020-01-06 @62  struct enetc_hw *enetc_hw_alloc(struct device *dev, void __iomem *port_regs)
6517798dd3432a Claudiu Manoil 2020-01-06  63  { return ERR_PTR(-EINVAL); }
6517798dd3432a Claudiu Manoil 2020-01-06  64
kernel test robot Oct. 10, 2024, 5:10 p.m. UTC | #4
Hi Wei,

kernel test robot noticed the following build warnings:

[auto build test WARNING on net-next/main]

url:    https://github.com/intel-lab-lkp/linux/commits/Wei-Fang/dt-bindings-net-add-compatible-string-for-i-MX95-EMDIO/20241009-181113
base:   net-next/main
patch link:    https://lore.kernel.org/r/20241009095116.147412-6-wei.fang%40nxp.com
patch subject: [PATCH net-next 05/11] net: enetc: add enetc-pf-common driver support
config: hexagon-allmodconfig (https://download.01.org/0day-ci/archive/20241011/202410110019.xUSLtcAC-lkp@intel.com/config)
compiler: clang version 20.0.0git (https://github.com/llvm/llvm-project 70e0a7e7e6a8541bcc46908c592eed561850e416)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20241011/202410110019.xUSLtcAC-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/202410110019.xUSLtcAC-lkp@intel.com/

All warnings (new ones prefixed by >>):

   In file included from drivers/net/ethernet/freescale/enetc/enetc_pf_common.c:3:
   In file included from include/linux/fsl/enetc_mdio.h:7:
   In file included from include/linux/phy.h:16:
   In file included from include/linux/ethtool.h:18:
   In file included from include/linux/if_ether.h:19:
   In file included from include/linux/skbuff.h:17:
   In file included from include/linux/bvec.h:10:
   In file included from include/linux/highmem.h:10:
   In file included from include/linux/mm.h:2213:
   include/linux/vmstat.h:518:36: warning: arithmetic between different enumeration types ('enum node_stat_item' and 'enum lru_list') [-Wenum-enum-conversion]
     518 |         return node_stat_name(NR_LRU_BASE + lru) + 3; // skip "nr_"
         |                               ~~~~~~~~~~~ ^ ~~~
   In file included from drivers/net/ethernet/freescale/enetc/enetc_pf_common.c:3:
   In file included from include/linux/fsl/enetc_mdio.h:7:
   In file included from include/linux/phy.h:16:
   In file included from include/linux/ethtool.h:18:
   In file included from include/linux/if_ether.h:19:
   In file included from include/linux/skbuff.h:17:
   In file included from include/linux/bvec.h:10:
   In file included from include/linux/highmem.h:12:
   In file included from include/linux/hardirq.h:11:
   In file included from ./arch/hexagon/include/generated/asm/hardirq.h:1:
   In file included from include/asm-generic/hardirq.h:17:
   In file included from include/linux/irq.h:20:
   In file included from include/linux/io.h:14:
   In file included from arch/hexagon/include/asm/io.h:328:
   include/asm-generic/io.h:548:31: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     548 |         val = __raw_readb(PCI_IOBASE + addr);
         |                           ~~~~~~~~~~ ^
   include/asm-generic/io.h:561:61: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     561 |         val = __le16_to_cpu((__le16 __force)__raw_readw(PCI_IOBASE + addr));
         |                                                         ~~~~~~~~~~ ^
   include/uapi/linux/byteorder/little_endian.h:37:51: note: expanded from macro '__le16_to_cpu'
      37 | #define __le16_to_cpu(x) ((__force __u16)(__le16)(x))
         |                                                   ^
   In file included from drivers/net/ethernet/freescale/enetc/enetc_pf_common.c:3:
   In file included from include/linux/fsl/enetc_mdio.h:7:
   In file included from include/linux/phy.h:16:
   In file included from include/linux/ethtool.h:18:
   In file included from include/linux/if_ether.h:19:
   In file included from include/linux/skbuff.h:17:
   In file included from include/linux/bvec.h:10:
   In file included from include/linux/highmem.h:12:
   In file included from include/linux/hardirq.h:11:
   In file included from ./arch/hexagon/include/generated/asm/hardirq.h:1:
   In file included from include/asm-generic/hardirq.h:17:
   In file included from include/linux/irq.h:20:
   In file included from include/linux/io.h:14:
   In file included from arch/hexagon/include/asm/io.h:328:
   include/asm-generic/io.h:574:61: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     574 |         val = __le32_to_cpu((__le32 __force)__raw_readl(PCI_IOBASE + addr));
         |                                                         ~~~~~~~~~~ ^
   include/uapi/linux/byteorder/little_endian.h:35:51: note: expanded from macro '__le32_to_cpu'
      35 | #define __le32_to_cpu(x) ((__force __u32)(__le32)(x))
         |                                                   ^
   In file included from drivers/net/ethernet/freescale/enetc/enetc_pf_common.c:3:
   In file included from include/linux/fsl/enetc_mdio.h:7:
   In file included from include/linux/phy.h:16:
   In file included from include/linux/ethtool.h:18:
   In file included from include/linux/if_ether.h:19:
   In file included from include/linux/skbuff.h:17:
   In file included from include/linux/bvec.h:10:
   In file included from include/linux/highmem.h:12:
   In file included from include/linux/hardirq.h:11:
   In file included from ./arch/hexagon/include/generated/asm/hardirq.h:1:
   In file included from include/asm-generic/hardirq.h:17:
   In file included from include/linux/irq.h:20:
   In file included from include/linux/io.h:14:
   In file included from arch/hexagon/include/asm/io.h:328:
   include/asm-generic/io.h:585:33: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     585 |         __raw_writeb(value, PCI_IOBASE + addr);
         |                             ~~~~~~~~~~ ^
   include/asm-generic/io.h:595:59: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     595 |         __raw_writew((u16 __force)cpu_to_le16(value), PCI_IOBASE + addr);
         |                                                       ~~~~~~~~~~ ^
   include/asm-generic/io.h:605:59: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     605 |         __raw_writel((u32 __force)cpu_to_le32(value), PCI_IOBASE + addr);
         |                                                       ~~~~~~~~~~ ^
   In file included from drivers/net/ethernet/freescale/enetc/enetc_pf_common.c:3:
>> include/linux/fsl/enetc_mdio.h:62:18: warning: no previous prototype for function 'enetc_hw_alloc' [-Wmissing-prototypes]
      62 | struct enetc_hw *enetc_hw_alloc(struct device *dev, void __iomem *port_regs)
         |                  ^
   include/linux/fsl/enetc_mdio.h:62:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
      62 | struct enetc_hw *enetc_hw_alloc(struct device *dev, void __iomem *port_regs)
         | ^
         | static 
   8 warnings generated.

Kconfig warnings: (for reference only)
   WARNING: unmet direct dependencies detected for MODVERSIONS
   Depends on [n]: MODULES [=y] && !COMPILE_TEST [=y]
   Selected by [y]:
   - RANDSTRUCT_FULL [=y] && (CC_HAS_RANDSTRUCT [=y] || GCC_PLUGINS [=n]) && MODULES [=y]
   WARNING: unmet direct dependencies detected for GET_FREE_REGION
   Depends on [n]: SPARSEMEM [=n]
   Selected by [m]:
   - RESOURCE_KUNIT_TEST [=m] && RUNTIME_TESTING_MENU [=y] && KUNIT [=m]


vim +/enetc_hw_alloc +62 include/linux/fsl/enetc_mdio.h

6517798dd3432a Claudiu Manoil 2020-01-06  49  
80e87442e69ba8 Andrew Lunn    2023-01-12  50  static inline int enetc_mdio_read_c22(struct mii_bus *bus, int phy_id,
80e87442e69ba8 Andrew Lunn    2023-01-12  51  				      int regnum)
6517798dd3432a Claudiu Manoil 2020-01-06  52  { return -EINVAL; }
80e87442e69ba8 Andrew Lunn    2023-01-12  53  static inline int enetc_mdio_write_c22(struct mii_bus *bus, int phy_id,
80e87442e69ba8 Andrew Lunn    2023-01-12  54  				       int regnum, u16 value)
80e87442e69ba8 Andrew Lunn    2023-01-12  55  { return -EINVAL; }
80e87442e69ba8 Andrew Lunn    2023-01-12  56  static inline int enetc_mdio_read_c45(struct mii_bus *bus, int phy_id,
80e87442e69ba8 Andrew Lunn    2023-01-12  57  				      int devad, int regnum)
80e87442e69ba8 Andrew Lunn    2023-01-12  58  { return -EINVAL; }
80e87442e69ba8 Andrew Lunn    2023-01-12  59  static inline int enetc_mdio_write_c45(struct mii_bus *bus, int phy_id,
80e87442e69ba8 Andrew Lunn    2023-01-12  60  				       int devad, int regnum, u16 value)
6517798dd3432a Claudiu Manoil 2020-01-06  61  { return -EINVAL; }
6517798dd3432a Claudiu Manoil 2020-01-06 @62  struct enetc_hw *enetc_hw_alloc(struct device *dev, void __iomem *port_regs)
6517798dd3432a Claudiu Manoil 2020-01-06  63  { return ERR_PTR(-EINVAL); }
6517798dd3432a Claudiu Manoil 2020-01-06  64
kernel test robot Oct. 13, 2024, 2:27 a.m. UTC | #5
Hi Wei,

kernel test robot noticed the following build errors:

[auto build test ERROR on net-next/main]

url:    https://github.com/intel-lab-lkp/linux/commits/Wei-Fang/dt-bindings-net-add-compatible-string-for-i-MX95-EMDIO/20241009-181113
base:   net-next/main
patch link:    https://lore.kernel.org/r/20241009095116.147412-6-wei.fang%40nxp.com
patch subject: [PATCH net-next 05/11] net: enetc: add enetc-pf-common driver support
config: powerpc-randconfig-r062-20241013 (https://download.01.org/0day-ci/archive/20241013/202410131001.KjFCfYWr-lkp@intel.com/config)
compiler: powerpc-linux-gcc (GCC) 14.1.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20241013/202410131001.KjFCfYWr-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/202410131001.KjFCfYWr-lkp@intel.com/

All errors (new ones prefixed by >>):

   powerpc-linux-ld: drivers/net/ethernet/freescale/enetc/enetc_pf_common.o: in function `enetc_sriov_configure':
>> drivers/net/ethernet/freescale/enetc/enetc_pf_common.c:336:(.text+0x55c): undefined reference to `enetc_msg_psi_free'
>> powerpc-linux-ld: drivers/net/ethernet/freescale/enetc/enetc_pf_common.c:349:(.text+0x5e4): undefined reference to `enetc_msg_psi_init'
>> powerpc-linux-ld: drivers/net/ethernet/freescale/enetc/enetc_pf_common.c:365:(.text+0x658): undefined reference to `enetc_msg_psi_free'
   powerpc-linux-ld: drivers/net/ethernet/freescale/enetc/enetc_pf_common.o: in function `enetc_pf_netdev_setup':
   drivers/net/ethernet/freescale/enetc/enetc_pf_common.c:106:(.text+0xb00): undefined reference to `enetc_set_ethtool_ops'


vim +336 drivers/net/ethernet/freescale/enetc/enetc_pf_common.c

   324	
   325	int enetc_sriov_configure(struct pci_dev *pdev, int num_vfs)
   326	{
   327		struct enetc_si *si = pci_get_drvdata(pdev);
   328		struct enetc_pf *pf = enetc_si_priv(si);
   329		int err;
   330	
   331		if (!IS_ENABLED(CONFIG_PCI_IOV))
   332			return 0;
   333	
   334		if (!num_vfs) {
   335			pci_disable_sriov(pdev);
 > 336			enetc_msg_psi_free(pf);
   337			kfree(pf->vf_state);
   338			pf->num_vfs = 0;
   339		} else {
   340			pf->num_vfs = num_vfs;
   341	
   342			pf->vf_state = kcalloc(num_vfs, sizeof(struct enetc_vf_state),
   343					       GFP_KERNEL);
   344			if (!pf->vf_state) {
   345				pf->num_vfs = 0;
   346				return -ENOMEM;
   347			}
   348	
 > 349			err = enetc_msg_psi_init(pf);
   350			if (err) {
   351				dev_err(&pdev->dev, "enetc_msg_psi_init (%d)\n", err);
   352				goto err_msg_psi;
   353			}
   354	
   355			err = pci_enable_sriov(pdev, num_vfs);
   356			if (err) {
   357				dev_err(&pdev->dev, "pci_enable_sriov err %d\n", err);
   358				goto err_en_sriov;
   359			}
   360		}
   361	
   362		return num_vfs;
   363	
   364	err_en_sriov:
 > 365		enetc_msg_psi_free(pf);
   366	err_msg_psi:
   367		kfree(pf->vf_state);
   368		pf->num_vfs = 0;
   369	
   370		return err;
   371	}
   372	EXPORT_SYMBOL_GPL(enetc_sriov_configure);
   373
diff mbox series

Patch

diff --git a/drivers/net/ethernet/freescale/enetc/Kconfig b/drivers/net/ethernet/freescale/enetc/Kconfig
index 51d80ea959d4..6f3306f14060 100644
--- a/drivers/net/ethernet/freescale/enetc/Kconfig
+++ b/drivers/net/ethernet/freescale/enetc/Kconfig
@@ -7,10 +7,19 @@  config FSL_ENETC_CORE
 
 	  If compiled as module (M), the module name is fsl-enetc-core.
 
+config NXP_ENETC_PF_COMMON
+	tristate "ENETC PF common functionality driver"
+	help
+	  This module supports common functionality between drivers of
+	  different versions of NXP ENETC PF controllers.
+
+	  If compiled as module (M), the module name is nxp-enetc-pf-common.
+
 config FSL_ENETC
 	tristate "ENETC PF driver"
 	depends on PCI_MSI
 	select MDIO_DEVRES
+	select NXP_ENETC_PF_COMMON
 	select FSL_ENETC_CORE
 	select FSL_ENETC_IERB
 	select FSL_ENETC_MDIO
diff --git a/drivers/net/ethernet/freescale/enetc/Makefile b/drivers/net/ethernet/freescale/enetc/Makefile
index 5c277910d538..b81ca462e358 100644
--- a/drivers/net/ethernet/freescale/enetc/Makefile
+++ b/drivers/net/ethernet/freescale/enetc/Makefile
@@ -3,6 +3,9 @@ 
 obj-$(CONFIG_FSL_ENETC_CORE) += fsl-enetc-core.o
 fsl-enetc-core-y := enetc.o enetc_cbdr.o enetc_ethtool.o
 
+obj-$(CONFIG_NXP_ENETC_PF_COMMON) += nxp-enetc-pf-common.o
+nxp-enetc-pf-common-y := enetc_pf_common.o
+
 obj-$(CONFIG_FSL_ENETC) += fsl-enetc.o
 fsl-enetc-y := enetc_pf.o
 fsl-enetc-$(CONFIG_PCI_IOV) += enetc_msg.o
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.c b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
index 8f6b0bf48139..dae8be4a1607 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
@@ -33,18 +33,15 @@  static void enetc_pf_set_primary_mac_addr(struct enetc_hw *hw, int si,
 	__raw_writew(lower, hw->port + ENETC_PSIPMAR1(si));
 }
 
-static int enetc_pf_set_mac_addr(struct net_device *ndev, void *addr)
+static struct phylink_pcs *enetc_pf_create_pcs(struct enetc_pf *pf,
+					       struct mii_bus *bus)
 {
-	struct enetc_ndev_priv *priv = netdev_priv(ndev);
-	struct sockaddr *saddr = addr;
-
-	if (!is_valid_ether_addr(saddr->sa_data))
-		return -EADDRNOTAVAIL;
-
-	eth_hw_addr_set(ndev, saddr->sa_data);
-	enetc_pf_set_primary_mac_addr(&priv->si->hw, 0, saddr->sa_data);
+	return lynx_pcs_create_mdiodev(bus, 0);
+}
 
-	return 0;
+static void enetc_pf_destroy_pcs(struct phylink_pcs *pcs)
+{
+	lynx_pcs_destroy(pcs);
 }
 
 static void enetc_set_vlan_promisc(struct enetc_hw *hw, char si_map)
@@ -393,56 +390,6 @@  static int enetc_pf_set_vf_spoofchk(struct net_device *ndev, int vf, bool en)
 	return 0;
 }
 
-static int enetc_setup_mac_address(struct device_node *np, struct enetc_pf *pf,
-				   int si)
-{
-	struct device *dev = &pf->si->pdev->dev;
-	struct enetc_hw *hw = &pf->si->hw;
-	u8 mac_addr[ETH_ALEN] = { 0 };
-	int err;
-
-	/* (1) try to get the MAC address from the device tree */
-	if (np) {
-		err = of_get_mac_address(np, mac_addr);
-		if (err == -EPROBE_DEFER)
-			return err;
-	}
-
-	/* (2) bootloader supplied MAC address */
-	if (is_zero_ether_addr(mac_addr))
-		enetc_pf_get_primary_mac_addr(hw, si, mac_addr);
-
-	/* (3) choose a random one */
-	if (is_zero_ether_addr(mac_addr)) {
-		eth_random_addr(mac_addr);
-		dev_info(dev, "no MAC address specified for SI%d, using %pM\n",
-			 si, mac_addr);
-	}
-
-	enetc_pf_set_primary_mac_addr(hw, si, mac_addr);
-
-	return 0;
-}
-
-static int enetc_setup_mac_addresses(struct device_node *np,
-				     struct enetc_pf *pf)
-{
-	int err, i;
-
-	/* The PF might take its MAC from the device tree */
-	err = enetc_setup_mac_address(np, pf, 0);
-	if (err)
-		return err;
-
-	for (i = 0; i < pf->total_vfs; i++) {
-		err = enetc_setup_mac_address(NULL, pf, i + 1);
-		if (err)
-			return err;
-	}
-
-	return 0;
-}
-
 static void enetc_port_assign_rfs_entries(struct enetc_si *si)
 {
 	struct enetc_pf *pf = enetc_si_priv(si);
@@ -656,55 +603,6 @@  void enetc_msg_handle_rxmsg(struct enetc_pf *pf, int vf_id, u16 *status)
 	}
 }
 
-#ifdef CONFIG_PCI_IOV
-static int enetc_sriov_configure(struct pci_dev *pdev, int num_vfs)
-{
-	struct enetc_si *si = pci_get_drvdata(pdev);
-	struct enetc_pf *pf = enetc_si_priv(si);
-	int err;
-
-	if (!num_vfs) {
-		enetc_msg_psi_free(pf);
-		kfree(pf->vf_state);
-		pf->num_vfs = 0;
-		pci_disable_sriov(pdev);
-	} else {
-		pf->num_vfs = num_vfs;
-
-		pf->vf_state = kcalloc(num_vfs, sizeof(struct enetc_vf_state),
-				       GFP_KERNEL);
-		if (!pf->vf_state) {
-			pf->num_vfs = 0;
-			return -ENOMEM;
-		}
-
-		err = enetc_msg_psi_init(pf);
-		if (err) {
-			dev_err(&pdev->dev, "enetc_msg_psi_init (%d)\n", err);
-			goto err_msg_psi;
-		}
-
-		err = pci_enable_sriov(pdev, num_vfs);
-		if (err) {
-			dev_err(&pdev->dev, "pci_enable_sriov err %d\n", err);
-			goto err_en_sriov;
-		}
-	}
-
-	return num_vfs;
-
-err_en_sriov:
-	enetc_msg_psi_free(pf);
-err_msg_psi:
-	kfree(pf->vf_state);
-	pf->num_vfs = 0;
-
-	return err;
-}
-#else
-#define enetc_sriov_configure(pdev, num_vfs)	(void)0
-#endif
-
 static int enetc_pf_set_features(struct net_device *ndev,
 				 netdev_features_t features)
 {
@@ -775,187 +673,6 @@  static const struct net_device_ops enetc_ndev_ops = {
 	.ndo_xdp_xmit		= enetc_xdp_xmit,
 };
 
-static void enetc_pf_netdev_setup(struct enetc_si *si, struct net_device *ndev,
-				  const struct net_device_ops *ndev_ops)
-{
-	struct enetc_ndev_priv *priv = netdev_priv(ndev);
-
-	SET_NETDEV_DEV(ndev, &si->pdev->dev);
-	priv->ndev = ndev;
-	priv->si = si;
-	priv->dev = &si->pdev->dev;
-	si->ndev = ndev;
-
-	priv->msg_enable = (NETIF_MSG_WOL << 1) - 1;
-	ndev->netdev_ops = ndev_ops;
-	enetc_set_ethtool_ops(ndev);
-	ndev->watchdog_timeo = 5 * HZ;
-	ndev->max_mtu = ENETC_MAX_MTU;
-
-	ndev->hw_features = NETIF_F_SG | NETIF_F_RXCSUM |
-			    NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX |
-			    NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_LOOPBACK |
-			    NETIF_F_HW_CSUM | NETIF_F_TSO | NETIF_F_TSO6;
-	ndev->features = NETIF_F_HIGHDMA | NETIF_F_SG | NETIF_F_RXCSUM |
-			 NETIF_F_HW_VLAN_CTAG_TX |
-			 NETIF_F_HW_VLAN_CTAG_RX |
-			 NETIF_F_HW_CSUM | NETIF_F_TSO | NETIF_F_TSO6;
-	ndev->vlan_features = NETIF_F_SG | NETIF_F_HW_CSUM |
-			      NETIF_F_TSO | NETIF_F_TSO6;
-
-	if (si->num_rss)
-		ndev->hw_features |= NETIF_F_RXHASH;
-
-	ndev->priv_flags |= IFF_UNICAST_FLT;
-	ndev->xdp_features = NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT |
-			     NETDEV_XDP_ACT_NDO_XMIT | NETDEV_XDP_ACT_RX_SG |
-			     NETDEV_XDP_ACT_NDO_XMIT_SG;
-
-	if (si->hw_features & ENETC_SI_F_PSFP && !enetc_psfp_enable(priv)) {
-		priv->active_offloads |= ENETC_F_QCI;
-		ndev->features |= NETIF_F_HW_TC;
-		ndev->hw_features |= NETIF_F_HW_TC;
-	}
-
-	/* pick up primary MAC address from SI */
-	enetc_load_primary_mac_addr(&si->hw, ndev);
-}
-
-static int enetc_mdio_probe(struct enetc_pf *pf, struct device_node *np)
-{
-	struct device *dev = &pf->si->pdev->dev;
-	struct enetc_mdio_priv *mdio_priv;
-	struct mii_bus *bus;
-	int err;
-
-	bus = devm_mdiobus_alloc_size(dev, sizeof(*mdio_priv));
-	if (!bus)
-		return -ENOMEM;
-
-	bus->name = "Freescale ENETC MDIO Bus";
-	bus->read = enetc_mdio_read_c22;
-	bus->write = enetc_mdio_write_c22;
-	bus->read_c45 = enetc_mdio_read_c45;
-	bus->write_c45 = enetc_mdio_write_c45;
-	bus->parent = dev;
-	mdio_priv = bus->priv;
-	mdio_priv->hw = &pf->si->hw;
-	mdio_priv->mdio_base = ENETC_EMDIO_BASE;
-	snprintf(bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev));
-
-	err = of_mdiobus_register(bus, np);
-	if (err)
-		return dev_err_probe(dev, err, "cannot register MDIO bus\n");
-
-	pf->mdio = bus;
-
-	return 0;
-}
-
-static void enetc_mdio_remove(struct enetc_pf *pf)
-{
-	if (pf->mdio)
-		mdiobus_unregister(pf->mdio);
-}
-
-static int enetc_imdio_create(struct enetc_pf *pf)
-{
-	struct device *dev = &pf->si->pdev->dev;
-	struct enetc_mdio_priv *mdio_priv;
-	struct phylink_pcs *phylink_pcs;
-	struct mii_bus *bus;
-	int err;
-
-	bus = mdiobus_alloc_size(sizeof(*mdio_priv));
-	if (!bus)
-		return -ENOMEM;
-
-	bus->name = "Freescale ENETC internal MDIO Bus";
-	bus->read = enetc_mdio_read_c22;
-	bus->write = enetc_mdio_write_c22;
-	bus->read_c45 = enetc_mdio_read_c45;
-	bus->write_c45 = enetc_mdio_write_c45;
-	bus->parent = dev;
-	bus->phy_mask = ~0;
-	mdio_priv = bus->priv;
-	mdio_priv->hw = &pf->si->hw;
-	mdio_priv->mdio_base = ENETC_PM_IMDIO_BASE;
-	snprintf(bus->id, MII_BUS_ID_SIZE, "%s-imdio", dev_name(dev));
-
-	err = mdiobus_register(bus);
-	if (err) {
-		dev_err(dev, "cannot register internal MDIO bus (%d)\n", err);
-		goto free_mdio_bus;
-	}
-
-	phylink_pcs = lynx_pcs_create_mdiodev(bus, 0);
-	if (IS_ERR(phylink_pcs)) {
-		err = PTR_ERR(phylink_pcs);
-		dev_err(dev, "cannot create lynx pcs (%d)\n", err);
-		goto unregister_mdiobus;
-	}
-
-	pf->imdio = bus;
-	pf->pcs = phylink_pcs;
-
-	return 0;
-
-unregister_mdiobus:
-	mdiobus_unregister(bus);
-free_mdio_bus:
-	mdiobus_free(bus);
-	return err;
-}
-
-static void enetc_imdio_remove(struct enetc_pf *pf)
-{
-	if (pf->pcs)
-		lynx_pcs_destroy(pf->pcs);
-	if (pf->imdio) {
-		mdiobus_unregister(pf->imdio);
-		mdiobus_free(pf->imdio);
-	}
-}
-
-static bool enetc_port_has_pcs(struct enetc_pf *pf)
-{
-	return (pf->if_mode == PHY_INTERFACE_MODE_SGMII ||
-		pf->if_mode == PHY_INTERFACE_MODE_1000BASEX ||
-		pf->if_mode == PHY_INTERFACE_MODE_2500BASEX ||
-		pf->if_mode == PHY_INTERFACE_MODE_USXGMII);
-}
-
-static int enetc_mdiobus_create(struct enetc_pf *pf, struct device_node *node)
-{
-	struct device_node *mdio_np;
-	int err;
-
-	mdio_np = of_get_child_by_name(node, "mdio");
-	if (mdio_np) {
-		err = enetc_mdio_probe(pf, mdio_np);
-
-		of_node_put(mdio_np);
-		if (err)
-			return err;
-	}
-
-	if (enetc_port_has_pcs(pf)) {
-		err = enetc_imdio_create(pf);
-		if (err) {
-			enetc_mdio_remove(pf);
-			return err;
-		}
-	}
-
-	return 0;
-}
-
-static void enetc_mdiobus_destroy(struct enetc_pf *pf)
-{
-	enetc_mdio_remove(pf);
-	enetc_imdio_remove(pf);
-}
-
 static struct phylink_pcs *
 enetc_pl_mac_select_pcs(struct phylink_config *config, phy_interface_t iface)
 {
@@ -1101,47 +818,6 @@  static const struct phylink_mac_ops enetc_mac_phylink_ops = {
 	.mac_link_down = enetc_pl_mac_link_down,
 };
 
-static int enetc_phylink_create(struct enetc_ndev_priv *priv,
-				struct device_node *node)
-{
-	struct enetc_pf *pf = enetc_si_priv(priv->si);
-	struct phylink *phylink;
-	int err;
-
-	pf->phylink_config.dev = &priv->ndev->dev;
-	pf->phylink_config.type = PHYLINK_NETDEV;
-	pf->phylink_config.mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE |
-		MAC_10 | MAC_100 | MAC_1000 | MAC_2500FD;
-
-	__set_bit(PHY_INTERFACE_MODE_INTERNAL,
-		  pf->phylink_config.supported_interfaces);
-	__set_bit(PHY_INTERFACE_MODE_SGMII,
-		  pf->phylink_config.supported_interfaces);
-	__set_bit(PHY_INTERFACE_MODE_1000BASEX,
-		  pf->phylink_config.supported_interfaces);
-	__set_bit(PHY_INTERFACE_MODE_2500BASEX,
-		  pf->phylink_config.supported_interfaces);
-	__set_bit(PHY_INTERFACE_MODE_USXGMII,
-		  pf->phylink_config.supported_interfaces);
-	phy_interface_set_rgmii(pf->phylink_config.supported_interfaces);
-
-	phylink = phylink_create(&pf->phylink_config, of_fwnode_handle(node),
-				 pf->if_mode, &enetc_mac_phylink_ops);
-	if (IS_ERR(phylink)) {
-		err = PTR_ERR(phylink);
-		return err;
-	}
-
-	priv->phylink = phylink;
-
-	return 0;
-}
-
-static void enetc_phylink_destroy(struct enetc_ndev_priv *priv)
-{
-	phylink_destroy(priv->phylink);
-}
-
 /* Initialize the entire shared memory for the flow steering entries
  * of this port (PF + VFs)
  */
@@ -1259,6 +935,13 @@  static void enetc_psi_destroy(struct pci_dev *pdev)
 	enetc_pci_remove(pdev);
 }
 
+static const struct enetc_pf_ops enetc_pf_ops = {
+	.set_si_primary_mac = enetc_pf_set_primary_mac_addr,
+	.get_si_primary_mac = enetc_pf_get_primary_mac_addr,
+	.create_pcs = enetc_pf_create_pcs,
+	.destroy_pcs = enetc_pf_destroy_pcs,
+};
+
 static int enetc_pf_probe(struct pci_dev *pdev,
 			  const struct pci_device_id *ent)
 {
@@ -1286,6 +969,7 @@  static int enetc_pf_probe(struct pci_dev *pdev,
 	pf = enetc_si_priv(si);
 	pf->si = si;
 	pf->total_vfs = pci_sriov_get_totalvfs(pdev);
+	enetc_pf_ops_register(pf, &enetc_pf_ops);
 
 	err = enetc_setup_mac_addresses(node, pf);
 	if (err)
@@ -1338,7 +1022,7 @@  static int enetc_pf_probe(struct pci_dev *pdev,
 	if (err)
 		goto err_mdiobus_create;
 
-	err = enetc_phylink_create(priv, node);
+	err = enetc_phylink_create(priv, node, &enetc_mac_phylink_ops);
 	if (err)
 		goto err_phylink_create;
 
@@ -1422,9 +1106,7 @@  static struct pci_driver enetc_pf_driver = {
 	.id_table = enetc_pf_id_table,
 	.probe = enetc_pf_probe,
 	.remove = enetc_pf_remove,
-#ifdef CONFIG_PCI_IOV
 	.sriov_configure = enetc_sriov_configure,
-#endif
 };
 module_pci_driver(enetc_pf_driver);
 
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.h b/drivers/net/ethernet/freescale/enetc/enetc_pf.h
index c26bd66e4597..ad7dab0eb752 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.h
@@ -28,6 +28,15 @@  struct enetc_vf_state {
 	enum enetc_vf_flags flags;
 };
 
+struct enetc_pf;
+
+struct enetc_pf_ops {
+	void (*set_si_primary_mac)(struct enetc_hw *hw, int si, const u8 *addr);
+	void (*get_si_primary_mac)(struct enetc_hw *hw, int si, u8 *addr);
+	struct phylink_pcs *(*create_pcs)(struct enetc_pf *pf, struct mii_bus *bus);
+	void (*destroy_pcs)(struct phylink_pcs *pcs);
+};
+
 struct enetc_pf {
 	struct enetc_si *si;
 	int num_vfs; /* number of active VFs, after sriov_init */
@@ -50,6 +59,8 @@  struct enetc_pf {
 
 	phy_interface_t if_mode;
 	struct phylink_config phylink_config;
+
+	const struct enetc_pf_ops *ops;
 };
 
 #define phylink_to_enetc_pf(config) \
@@ -58,3 +69,20 @@  struct enetc_pf {
 int enetc_msg_psi_init(struct enetc_pf *pf);
 void enetc_msg_psi_free(struct enetc_pf *pf);
 void enetc_msg_handle_rxmsg(struct enetc_pf *pf, int mbox_id, u16 *status);
+
+int enetc_pf_set_mac_addr(struct net_device *ndev, void *addr);
+int enetc_setup_mac_addresses(struct device_node *np, struct enetc_pf *pf);
+void enetc_pf_netdev_setup(struct enetc_si *si, struct net_device *ndev,
+			   const struct net_device_ops *ndev_ops);
+int enetc_mdiobus_create(struct enetc_pf *pf, struct device_node *node);
+void enetc_mdiobus_destroy(struct enetc_pf *pf);
+int enetc_phylink_create(struct enetc_ndev_priv *priv, struct device_node *node,
+			 const struct phylink_mac_ops *pl_mac_ops);
+void enetc_phylink_destroy(struct enetc_ndev_priv *priv);
+int enetc_sriov_configure(struct pci_dev *pdev, int num_vfs);
+
+static inline void enetc_pf_ops_register(struct enetc_pf *pf,
+					 const struct enetc_pf_ops *ops)
+{
+	pf->ops = ops;
+}
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
new file mode 100644
index 000000000000..bbfb5c1ffd13
--- /dev/null
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
@@ -0,0 +1,375 @@ 
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/* Copyright 2024 NXP */
+#include <linux/fsl/enetc_mdio.h>
+#include <linux/of_mdio.h>
+#include <linux/of_net.h>
+
+#include "enetc_pf.h"
+
+static int enetc_set_si_hw_addr(struct enetc_pf *pf, int si, u8 *mac_addr)
+{
+	struct enetc_hw *hw = &pf->si->hw;
+
+	if (pf->ops->set_si_primary_mac)
+		pf->ops->set_si_primary_mac(hw, si, mac_addr);
+	else
+		return -EOPNOTSUPP;
+
+	return 0;
+}
+
+int enetc_pf_set_mac_addr(struct net_device *ndev, void *addr)
+{
+	struct enetc_ndev_priv *priv = netdev_priv(ndev);
+	struct enetc_pf *pf = enetc_si_priv(priv->si);
+	struct sockaddr *saddr = addr;
+	int err;
+
+	if (!is_valid_ether_addr(saddr->sa_data))
+		return -EADDRNOTAVAIL;
+
+	err = enetc_set_si_hw_addr(pf, 0, saddr->sa_data);
+	if (err)
+		return err;
+
+	eth_hw_addr_set(ndev, saddr->sa_data);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(enetc_pf_set_mac_addr);
+
+static int enetc_setup_mac_address(struct device_node *np, struct enetc_pf *pf,
+				   int si)
+{
+	struct device *dev = &pf->si->pdev->dev;
+	struct enetc_hw *hw = &pf->si->hw;
+	u8 mac_addr[ETH_ALEN] = { 0 };
+	int err;
+
+	/* (1) try to get the MAC address from the device tree */
+	if (np) {
+		err = of_get_mac_address(np, mac_addr);
+		if (err == -EPROBE_DEFER)
+			return err;
+	}
+
+	/* (2) bootloader supplied MAC address */
+	if (is_zero_ether_addr(mac_addr) && pf->ops->get_si_primary_mac)
+		pf->ops->get_si_primary_mac(hw, si, mac_addr);
+
+	/* (3) choose a random one */
+	if (is_zero_ether_addr(mac_addr)) {
+		eth_random_addr(mac_addr);
+		dev_info(dev, "no MAC address specified for SI%d, using %pM\n",
+			 si, mac_addr);
+	}
+
+	err = enetc_set_si_hw_addr(pf, si, mac_addr);
+	if (err)
+		return err;
+
+	return 0;
+}
+
+int enetc_setup_mac_addresses(struct device_node *np, struct enetc_pf *pf)
+{
+	int err, i;
+
+	/* The PF might take its MAC from the device tree */
+	err = enetc_setup_mac_address(np, pf, 0);
+	if (err)
+		return err;
+
+	for (i = 0; i < pf->total_vfs; i++) {
+		err = enetc_setup_mac_address(NULL, pf, i + 1);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(enetc_setup_mac_addresses);
+
+void enetc_pf_netdev_setup(struct enetc_si *si, struct net_device *ndev,
+			   const struct net_device_ops *ndev_ops)
+{
+	struct enetc_ndev_priv *priv = netdev_priv(ndev);
+
+	SET_NETDEV_DEV(ndev, &si->pdev->dev);
+	priv->ndev = ndev;
+	priv->si = si;
+	priv->dev = &si->pdev->dev;
+	si->ndev = ndev;
+
+	priv->msg_enable = (NETIF_MSG_WOL << 1) - 1;
+	ndev->netdev_ops = ndev_ops;
+	enetc_set_ethtool_ops(ndev);
+	ndev->watchdog_timeo = 5 * HZ;
+	ndev->max_mtu = ENETC_MAX_MTU;
+
+	ndev->hw_features = NETIF_F_SG | NETIF_F_RXCSUM |
+			    NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX |
+			    NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_LOOPBACK |
+			    NETIF_F_HW_CSUM | NETIF_F_TSO | NETIF_F_TSO6 |
+			    NETIF_F_GSO_UDP_L4;
+	ndev->features = NETIF_F_HIGHDMA | NETIF_F_SG | NETIF_F_RXCSUM |
+			 NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX |
+			 NETIF_F_HW_CSUM | NETIF_F_TSO | NETIF_F_TSO6 |
+			 NETIF_F_GSO_UDP_L4;
+	ndev->vlan_features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_TSO |
+			      NETIF_F_TSO6 | NETIF_F_GSO_UDP_L4;
+
+	if (si->num_rss)
+		ndev->hw_features |= NETIF_F_RXHASH;
+
+	ndev->priv_flags |= IFF_UNICAST_FLT;
+	ndev->xdp_features = NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT |
+			     NETDEV_XDP_ACT_NDO_XMIT | NETDEV_XDP_ACT_RX_SG |
+			     NETDEV_XDP_ACT_NDO_XMIT_SG;
+
+	if (si->hw_features & ENETC_SI_F_PSFP && !enetc_psfp_enable(priv)) {
+		priv->active_offloads |= ENETC_F_QCI;
+		ndev->features |= NETIF_F_HW_TC;
+		ndev->hw_features |= NETIF_F_HW_TC;
+	}
+
+	/* pick up primary MAC address from SI */
+	enetc_load_primary_mac_addr(&si->hw, ndev);
+}
+EXPORT_SYMBOL_GPL(enetc_pf_netdev_setup);
+
+static int enetc_mdio_probe(struct enetc_pf *pf, struct device_node *np)
+{
+	struct device *dev = &pf->si->pdev->dev;
+	struct enetc_mdio_priv *mdio_priv;
+	struct mii_bus *bus;
+	int err;
+
+	bus = devm_mdiobus_alloc_size(dev, sizeof(*mdio_priv));
+	if (!bus)
+		return -ENOMEM;
+
+	bus->name = "Freescale ENETC MDIO Bus";
+	bus->read = enetc_mdio_read_c22;
+	bus->write = enetc_mdio_write_c22;
+	bus->read_c45 = enetc_mdio_read_c45;
+	bus->write_c45 = enetc_mdio_write_c45;
+	bus->parent = dev;
+	mdio_priv = bus->priv;
+	mdio_priv->hw = &pf->si->hw;
+	mdio_priv->mdio_base = ENETC_EMDIO_BASE;
+	snprintf(bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev));
+
+	err = of_mdiobus_register(bus, np);
+	if (err)
+		return dev_err_probe(dev, err, "cannot register MDIO bus\n");
+
+	pf->mdio = bus;
+
+	return 0;
+}
+
+static void enetc_mdio_remove(struct enetc_pf *pf)
+{
+	if (pf->mdio)
+		mdiobus_unregister(pf->mdio);
+}
+
+static bool enetc_port_has_pcs(struct enetc_pf *pf)
+{
+	return (pf->if_mode == PHY_INTERFACE_MODE_SGMII ||
+		pf->if_mode == PHY_INTERFACE_MODE_1000BASEX ||
+		pf->if_mode == PHY_INTERFACE_MODE_2500BASEX ||
+		pf->if_mode == PHY_INTERFACE_MODE_USXGMII);
+}
+
+static int enetc_imdio_create(struct enetc_pf *pf)
+{
+	struct device *dev = &pf->si->pdev->dev;
+	struct enetc_mdio_priv *mdio_priv;
+	struct phylink_pcs *phylink_pcs;
+	struct mii_bus *bus;
+	int err;
+
+	if (!pf->ops->create_pcs)
+		return -EOPNOTSUPP;
+
+	bus = mdiobus_alloc_size(sizeof(*mdio_priv));
+	if (!bus)
+		return -ENOMEM;
+
+	bus->name = "Freescale ENETC internal MDIO Bus";
+	bus->read = enetc_mdio_read_c22;
+	bus->write = enetc_mdio_write_c22;
+	bus->read_c45 = enetc_mdio_read_c45;
+	bus->write_c45 = enetc_mdio_write_c45;
+	bus->parent = dev;
+	bus->phy_mask = ~0;
+	mdio_priv = bus->priv;
+	mdio_priv->hw = &pf->si->hw;
+	mdio_priv->mdio_base = ENETC_PM_IMDIO_BASE;
+	snprintf(bus->id, MII_BUS_ID_SIZE, "%s-imdio", dev_name(dev));
+
+	err = mdiobus_register(bus);
+	if (err) {
+		dev_err(dev, "cannot register internal MDIO bus (%d)\n", err);
+		goto free_mdio_bus;
+	}
+
+	phylink_pcs = pf->ops->create_pcs(pf, bus);
+	if (IS_ERR(phylink_pcs)) {
+		err = PTR_ERR(phylink_pcs);
+		dev_err(dev, "cannot create pcs (%d)\n", err);
+		goto unregister_mdiobus;
+	}
+
+	pf->imdio = bus;
+	pf->pcs = phylink_pcs;
+
+	return 0;
+
+unregister_mdiobus:
+	mdiobus_unregister(bus);
+free_mdio_bus:
+	mdiobus_free(bus);
+	return err;
+}
+
+static void enetc_imdio_remove(struct enetc_pf *pf)
+{
+	if (pf->pcs && pf->ops->destroy_pcs)
+		pf->ops->destroy_pcs(pf->pcs);
+
+	if (pf->imdio) {
+		mdiobus_unregister(pf->imdio);
+		mdiobus_free(pf->imdio);
+	}
+}
+
+int enetc_mdiobus_create(struct enetc_pf *pf, struct device_node *node)
+{
+	struct device_node *mdio_np;
+	int err;
+
+	mdio_np = of_get_child_by_name(node, "mdio");
+	if (mdio_np) {
+		err = enetc_mdio_probe(pf, mdio_np);
+
+		of_node_put(mdio_np);
+		if (err)
+			return err;
+	}
+
+	if (enetc_port_has_pcs(pf)) {
+		err = enetc_imdio_create(pf);
+		if (err) {
+			enetc_mdio_remove(pf);
+			return err;
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(enetc_mdiobus_create);
+
+void enetc_mdiobus_destroy(struct enetc_pf *pf)
+{
+	enetc_mdio_remove(pf);
+	enetc_imdio_remove(pf);
+}
+EXPORT_SYMBOL_GPL(enetc_mdiobus_destroy);
+
+int enetc_phylink_create(struct enetc_ndev_priv *priv, struct device_node *node,
+			 const struct phylink_mac_ops *pl_mac_ops)
+{
+	struct enetc_pf *pf = enetc_si_priv(priv->si);
+	struct phylink *phylink;
+	int err;
+
+	pf->phylink_config.dev = &priv->ndev->dev;
+	pf->phylink_config.type = PHYLINK_NETDEV;
+	pf->phylink_config.mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE |
+		MAC_10 | MAC_100 | MAC_1000 | MAC_2500FD;
+
+	__set_bit(PHY_INTERFACE_MODE_INTERNAL,
+		  pf->phylink_config.supported_interfaces);
+	__set_bit(PHY_INTERFACE_MODE_SGMII,
+		  pf->phylink_config.supported_interfaces);
+	__set_bit(PHY_INTERFACE_MODE_1000BASEX,
+		  pf->phylink_config.supported_interfaces);
+	__set_bit(PHY_INTERFACE_MODE_2500BASEX,
+		  pf->phylink_config.supported_interfaces);
+	__set_bit(PHY_INTERFACE_MODE_USXGMII,
+		  pf->phylink_config.supported_interfaces);
+	phy_interface_set_rgmii(pf->phylink_config.supported_interfaces);
+
+	phylink = phylink_create(&pf->phylink_config, of_fwnode_handle(node),
+				 pf->if_mode, pl_mac_ops);
+	if (IS_ERR(phylink)) {
+		err = PTR_ERR(phylink);
+		return err;
+	}
+
+	priv->phylink = phylink;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(enetc_phylink_create);
+
+void enetc_phylink_destroy(struct enetc_ndev_priv *priv)
+{
+	phylink_destroy(priv->phylink);
+}
+EXPORT_SYMBOL_GPL(enetc_phylink_destroy);
+
+int enetc_sriov_configure(struct pci_dev *pdev, int num_vfs)
+{
+	struct enetc_si *si = pci_get_drvdata(pdev);
+	struct enetc_pf *pf = enetc_si_priv(si);
+	int err;
+
+	if (!IS_ENABLED(CONFIG_PCI_IOV))
+		return 0;
+
+	if (!num_vfs) {
+		pci_disable_sriov(pdev);
+		enetc_msg_psi_free(pf);
+		kfree(pf->vf_state);
+		pf->num_vfs = 0;
+	} else {
+		pf->num_vfs = num_vfs;
+
+		pf->vf_state = kcalloc(num_vfs, sizeof(struct enetc_vf_state),
+				       GFP_KERNEL);
+		if (!pf->vf_state) {
+			pf->num_vfs = 0;
+			return -ENOMEM;
+		}
+
+		err = enetc_msg_psi_init(pf);
+		if (err) {
+			dev_err(&pdev->dev, "enetc_msg_psi_init (%d)\n", err);
+			goto err_msg_psi;
+		}
+
+		err = pci_enable_sriov(pdev, num_vfs);
+		if (err) {
+			dev_err(&pdev->dev, "pci_enable_sriov err %d\n", err);
+			goto err_en_sriov;
+		}
+	}
+
+	return num_vfs;
+
+err_en_sriov:
+	enetc_msg_psi_free(pf);
+err_msg_psi:
+	kfree(pf->vf_state);
+	pf->num_vfs = 0;
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(enetc_sriov_configure);
+
+MODULE_DESCRIPTION("NXP ENETC PF common functionality driver");
+MODULE_LICENSE("Dual BSD/GPL");