diff mbox series

[SRU,J:linux-bluefield,v2,1/1] UBUNTU: SAUCE: mlxbf-gige: support fixed phy for Bobcat

Message ID 20240226175641.21215-2-asmaa@nvidia.com
State New
Headers show
Series UBUNTU: SAUCE: mlxbf-gige: support fixed phy for Bobcat | expand

Commit Message

Asmaa Mnebhi Feb. 26, 2024, 5:56 p.m. UTC
BugLink: https://bugs.launchpad.net/bugs/2054845

There is no external PHY connected to the OOB MAC on the Bobcat
board and no access to the MDIO bus. The OOB MAC is directly connected
to the Marvell switch. So support a "fake PHY" and simulate an MDIO bus.

If "fixed-link" property is supported in the ACPI table, register the
fixed PHY driver.

Signed-off-by: Asmaa Mnebhi <asmaa@nvidia.com>
Reviewed-by: David Thompson <davthompson@nvidia.com>
---
 .../ethernet/mellanox/mlxbf_gige/mlxbf_gige.h |  2 -
 .../mellanox/mlxbf_gige/mlxbf_gige_main.c     | 62 ++++++++++++++++---
 2 files changed, 53 insertions(+), 11 deletions(-)

Comments

Bartlomiej Zolnierkiewicz Feb. 27, 2024, 2:49 p.m. UTC | #1
Acked-by: Bartlomiej Zolnierkiewicz <bartlomiej.zolnierkiewicz@canonical.com>

On Mon, Feb 26, 2024 at 7:01 PM Asmaa Mnebhi <asmaa@nvidia.com> wrote:
>
> BugLink: https://bugs.launchpad.net/bugs/2054845
>
> There is no external PHY connected to the OOB MAC on the Bobcat
> board and no access to the MDIO bus. The OOB MAC is directly connected
> to the Marvell switch. So support a "fake PHY" and simulate an MDIO bus.
>
> If "fixed-link" property is supported in the ACPI table, register the
> fixed PHY driver.
>
> Signed-off-by: Asmaa Mnebhi <asmaa@nvidia.com>
> Reviewed-by: David Thompson <davthompson@nvidia.com>
> ---
>  .../ethernet/mellanox/mlxbf_gige/mlxbf_gige.h |  2 -
>  .../mellanox/mlxbf_gige/mlxbf_gige_main.c     | 62 ++++++++++++++++---
>  2 files changed, 53 insertions(+), 11 deletions(-)
>
> diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h
> index a453b9cd9033..a85823a64d94 100644
> --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h
> +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h
> @@ -175,8 +175,6 @@ enum mlxbf_gige_res {
>  int mlxbf_gige_mdio_probe(struct platform_device *pdev,
>                           struct mlxbf_gige *priv);
>  void mlxbf_gige_mdio_remove(struct mlxbf_gige *priv);
> -irqreturn_t mlxbf_gige_mdio_handle_phy_interrupt(int irq, void *dev_id);
> -void mlxbf_gige_mdio_enable_phy_int(struct mlxbf_gige *priv);
>
>  void mlxbf_gige_set_mac_rx_filter(struct mlxbf_gige *priv,
>                                   unsigned int index, u64 dmac);
> diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c
> index c0da9c05b12a..74ef75e00739 100644
> --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c
> +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c
> @@ -13,6 +13,7 @@
>  #include <linux/iopoll.h>
>  #include <linux/module.h>
>  #include <linux/phy.h>
> +#include <linux/phy_fixed.h>
>  #include <linux/platform_device.h>
>  #include <linux/skbuff.h>
>
> @@ -364,6 +365,7 @@ static struct mlxbf_gige_link_cfg mlxbf_gige_link_cfgs[] = {
>
>  static int mlxbf_gige_probe(struct platform_device *pdev)
>  {
> +       struct fixed_phy_status fphy_status = {};
>         struct phy_device *phydev;
>         struct net_device *netdev;
>         struct mlxbf_gige *priv;
> @@ -428,16 +430,53 @@ static int mlxbf_gige_probe(struct platform_device *pdev)
>         priv->rx_irq = platform_get_irq(pdev, MLXBF_GIGE_RECEIVE_PKT_INTR_IDX);
>         priv->llu_plu_irq = platform_get_irq(pdev, MLXBF_GIGE_LLU_PLU_INTR_IDX);
>
> -       phy_irq = acpi_dev_gpio_irq_get_by(ACPI_COMPANION(&pdev->dev), "phy-gpios", 0);
> -       if (phy_irq < 0) {
> -               dev_err(&pdev->dev, "Error getting PHY irq. Use polling instead");
> +       if (device_property_read_bool(&pdev->dev, "fixed-link")) {
> +               fphy_status.link = 1;
> +               err = device_property_read_u32(&pdev->dev, "full-duplex", &fphy_status.duplex);
> +               if (err) {
> +                       dev_err(&pdev->dev, "Failed to get duplex\n");
> +                       err = -EINVAL;
> +                       goto out;
> +               }
> +               err = device_property_read_u32(&pdev->dev, "speed", &fphy_status.speed);
> +               if (err) {
> +                       dev_err(&pdev->dev, "Failed to get speed\n");
> +                       err = -EINVAL;
> +                       goto out;
> +               }
> +               err = device_property_read_u32(&pdev->dev, "pause", &fphy_status.pause);
> +               if (err) {
> +                       dev_err(&pdev->dev, "Failed to get pause\n");
> +                       err = -EINVAL;
> +                       goto out;
> +               }
> +               err = device_property_read_u32(&pdev->dev, "asym-pause", &fphy_status.asym_pause);
> +               if (err) {
> +                       dev_err(&pdev->dev, "Failed to get asym-pause\n");
> +                       err = -EINVAL;
> +                       goto out;
> +               }
> +
> +               phydev = fixed_phy_register(PHY_POLL, &fphy_status, NULL);
> +               if (IS_ERR(phydev)) {
> +                       dev_err(&pdev->dev, "Failed to register fixed PHY device\n");
> +                       err = PTR_ERR(phydev);
> +                       goto out;
> +               }
> +
>                 phy_irq = PHY_POLL;
> -       }
> +       } else {
> +               phy_irq = acpi_dev_gpio_irq_get_by(ACPI_COMPANION(&pdev->dev), "phy-gpios", 0);
> +               if (phy_irq < 0) {
> +                       dev_err(&pdev->dev, "Error getting PHY irq. Use polling instead");
> +                       phy_irq = PHY_POLL;
> +               }
>
> -       phydev = phy_find_first(priv->mdiobus);
> -       if (!phydev) {
> -               err = -ENODEV;
> -               goto out;
> +               phydev = phy_find_first(priv->mdiobus);
> +               if (!phydev) {
> +                       err = -ENODEV;
> +                       goto out;
> +               }
>         }
>
>         addr = phydev->mdio.addr;
> @@ -474,9 +513,14 @@ static int mlxbf_gige_probe(struct platform_device *pdev)
>  static int mlxbf_gige_remove(struct platform_device *pdev)
>  {
>         struct mlxbf_gige *priv = platform_get_drvdata(pdev);
> +       struct phy_device *phydev = priv->netdev->phydev;
>
>         unregister_netdev(priv->netdev);
> -       phy_disconnect(priv->netdev->phydev);
> +       phy_disconnect(phydev);
> +
> +       if (phy_is_pseudo_fixed_link(phydev))
> +               fixed_phy_unregister(phydev);
> +
>         mlxbf_gige_mdio_remove(priv);
>         platform_set_drvdata(pdev, NULL);
>
diff mbox series

Patch

diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h
index a453b9cd9033..a85823a64d94 100644
--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h
+++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h
@@ -175,8 +175,6 @@  enum mlxbf_gige_res {
 int mlxbf_gige_mdio_probe(struct platform_device *pdev,
 			  struct mlxbf_gige *priv);
 void mlxbf_gige_mdio_remove(struct mlxbf_gige *priv);
-irqreturn_t mlxbf_gige_mdio_handle_phy_interrupt(int irq, void *dev_id);
-void mlxbf_gige_mdio_enable_phy_int(struct mlxbf_gige *priv);
 
 void mlxbf_gige_set_mac_rx_filter(struct mlxbf_gige *priv,
 				  unsigned int index, u64 dmac);
diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c
index c0da9c05b12a..74ef75e00739 100644
--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c
+++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c
@@ -13,6 +13,7 @@ 
 #include <linux/iopoll.h>
 #include <linux/module.h>
 #include <linux/phy.h>
+#include <linux/phy_fixed.h>
 #include <linux/platform_device.h>
 #include <linux/skbuff.h>
 
@@ -364,6 +365,7 @@  static struct mlxbf_gige_link_cfg mlxbf_gige_link_cfgs[] = {
 
 static int mlxbf_gige_probe(struct platform_device *pdev)
 {
+	struct fixed_phy_status fphy_status = {};
 	struct phy_device *phydev;
 	struct net_device *netdev;
 	struct mlxbf_gige *priv;
@@ -428,16 +430,53 @@  static int mlxbf_gige_probe(struct platform_device *pdev)
 	priv->rx_irq = platform_get_irq(pdev, MLXBF_GIGE_RECEIVE_PKT_INTR_IDX);
 	priv->llu_plu_irq = platform_get_irq(pdev, MLXBF_GIGE_LLU_PLU_INTR_IDX);
 
-	phy_irq = acpi_dev_gpio_irq_get_by(ACPI_COMPANION(&pdev->dev), "phy-gpios", 0);
-	if (phy_irq < 0) {
-		dev_err(&pdev->dev, "Error getting PHY irq. Use polling instead");
+	if (device_property_read_bool(&pdev->dev, "fixed-link")) {
+		fphy_status.link = 1;
+		err = device_property_read_u32(&pdev->dev, "full-duplex", &fphy_status.duplex);
+		if (err) {
+			dev_err(&pdev->dev, "Failed to get duplex\n");
+			err = -EINVAL;
+			goto out;
+		}
+		err = device_property_read_u32(&pdev->dev, "speed", &fphy_status.speed);
+		if (err) {
+			dev_err(&pdev->dev, "Failed to get speed\n");
+			err = -EINVAL;
+			goto out;
+		}
+		err = device_property_read_u32(&pdev->dev, "pause", &fphy_status.pause);
+		if (err) {
+			dev_err(&pdev->dev, "Failed to get pause\n");
+			err = -EINVAL;
+			goto out;
+		}
+		err = device_property_read_u32(&pdev->dev, "asym-pause", &fphy_status.asym_pause);
+		if (err) {
+			dev_err(&pdev->dev, "Failed to get asym-pause\n");
+			err = -EINVAL;
+			goto out;
+		}
+
+		phydev = fixed_phy_register(PHY_POLL, &fphy_status, NULL);
+		if (IS_ERR(phydev)) {
+			dev_err(&pdev->dev, "Failed to register fixed PHY device\n");
+			err = PTR_ERR(phydev);
+			goto out;
+		}
+
 		phy_irq = PHY_POLL;
-	}
+	} else {
+		phy_irq = acpi_dev_gpio_irq_get_by(ACPI_COMPANION(&pdev->dev), "phy-gpios", 0);
+		if (phy_irq < 0) {
+			dev_err(&pdev->dev, "Error getting PHY irq. Use polling instead");
+			phy_irq = PHY_POLL;
+		}
 
-	phydev = phy_find_first(priv->mdiobus);
-	if (!phydev) {
-		err = -ENODEV;
-		goto out;
+		phydev = phy_find_first(priv->mdiobus);
+		if (!phydev) {
+			err = -ENODEV;
+			goto out;
+		}
 	}
 
 	addr = phydev->mdio.addr;
@@ -474,9 +513,14 @@  static int mlxbf_gige_probe(struct platform_device *pdev)
 static int mlxbf_gige_remove(struct platform_device *pdev)
 {
 	struct mlxbf_gige *priv = platform_get_drvdata(pdev);
+	struct phy_device *phydev = priv->netdev->phydev;
 
 	unregister_netdev(priv->netdev);
-	phy_disconnect(priv->netdev->phydev);
+	phy_disconnect(phydev);
+
+	if (phy_is_pseudo_fixed_link(phydev))
+		fixed_phy_unregister(phydev);
+
 	mlxbf_gige_mdio_remove(priv);
 	platform_set_drvdata(pdev, NULL);