[SRU][F][PULL][PATCH v2 14/23] Revert "UBUNTU: SAUCE: Address upstream comments from patch v6 for PHY driver"
Asmaa Mnebhi
asmaa at nvidia.com
Fri Jul 9 19:08:21 UTC 2021
BugLink: https://bugs.launchpad.net/bugs/1934923
This reverts commit e65518a6eeb7dc24198700b1ec7e96ffdeab2b46.
Signed-off-by: Asmaa Mnebhi <asmaa at nvidia.com>
---
.../net/ethernet/mellanox/mlxbf_gige/Kconfig | 2 +-
.../net/ethernet/mellanox/mlxbf_gige/Makefile | 2 +-
.../ethernet/mellanox/mlxbf_gige/mlxbf_gige.h | 10 +-
.../mellanox/mlxbf_gige/mlxbf_gige_main.c | 103 ++-------
.../mellanox/mlxbf_gige/mlxbf_gige_mdio.c | 208 ++++++++++++++----
.../mellanox/mlxbf_gige/mlxbf_gige_regs.h | 4 +-
6 files changed, 192 insertions(+), 137 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/Kconfig b/drivers/net/ethernet/mellanox/mlxbf_gige/Kconfig
index 41c7a8997190..73c5d74081ee 100644
--- a/drivers/net/ethernet/mellanox/mlxbf_gige/Kconfig
+++ b/drivers/net/ethernet/mellanox/mlxbf_gige/Kconfig
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause
+# SPDX-License-Identifier: GPL-2.0-only OR Linux-OpenIB
#
# Mellanox GigE driver configuration
#
diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/Makefile b/drivers/net/ethernet/mellanox/mlxbf_gige/Makefile
index e99fc19ac819..f6be6c692093 100644
--- a/drivers/net/ethernet/mellanox/mlxbf_gige/Makefile
+++ b/drivers/net/ethernet/mellanox/mlxbf_gige/Makefile
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause
+# SPDX-License-Identifier: GPL-2.0-only OR Linux-OpenIB
obj-$(CONFIG_MLXBF_GIGE) += mlxbf_gige.o
diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h
index 63e07e60108d..f89199d562ad 100644
--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h
+++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h
@@ -1,10 +1,10 @@
-/* SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause */
+/* SPDX-License-Identifier: GPL-2.0-only OR Linux-OpenIB */
/* Header file for Gigabit Ethernet driver for Mellanox BlueField SoC
* - this file contains software data structures and any chip-specific
* data structures (e.g. TX WQE format) that are memory resident.
*
- * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
+ * Copyright (c) 2020 Mellanox Technologies Ltd.
*/
#ifndef __MLXBF_GIGE_H__
@@ -101,13 +101,9 @@ struct mlxbf_gige {
int error_irq;
int rx_irq;
int llu_plu_irq;
- int phy_irq;
bool promisc_enabled;
struct napi_struct napi;
struct mlxbf_gige_stats stats;
- u32 tx_pause;
- u32 rx_pause;
- u32 aneg_pause;
};
/* Rx Work Queue Element definitions */
@@ -155,6 +151,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);
+irqreturn_t mlxbf_gige_mdio_handle_phy_interrupt(struct mlxbf_gige *priv);
#endif /* !defined(__MLXBF_GIGE_H__) */
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 0fd540bc50f7..d650e9c0a57f 100644
--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c
+++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c
@@ -1,8 +1,8 @@
-// SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause
+// SPDX-License-Identifier: GPL-2.0-only OR Linux-OpenIB
/* Gigabit Ethernet driver for Mellanox BlueField SoC
*
- * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
+ * Copyright (c) 2020 Mellanox Technologies Ltd.
*/
#include <linux/acpi.h>
@@ -18,7 +18,7 @@
#include "mlxbf_gige_regs.h"
#define DRV_NAME "mlxbf_gige"
-#define DRV_VERSION "1.3"
+#define DRV_VERSION "1.2"
static void mlxbf_gige_set_mac_rx_filter(struct mlxbf_gige *priv,
unsigned int index, u64 dmac)
@@ -474,11 +474,9 @@ static void mlxbf_gige_get_ethtool_stats(struct net_device *netdev,
static void mlxbf_gige_get_pauseparam(struct net_device *netdev,
struct ethtool_pauseparam *pause)
{
- struct mlxbf_gige *priv = netdev_priv(netdev);
-
- pause->autoneg = priv->aneg_pause;
- pause->rx_pause = priv->tx_pause;
- pause->tx_pause = priv->rx_pause;
+ pause->autoneg = AUTONEG_ENABLE;
+ pause->rx_pause = 1;
+ pause->tx_pause = 1;
}
static const struct ethtool_ops mlxbf_gige_ethtool_ops = {
@@ -496,6 +494,20 @@ static const struct ethtool_ops mlxbf_gige_ethtool_ops = {
.get_link_ksettings = phy_ethtool_get_link_ksettings,
};
+static void mlxbf_gige_handle_link_change(struct net_device *netdev)
+{
+ struct mlxbf_gige *priv = netdev_priv(netdev);
+ struct phy_device *phydev = netdev->phydev;
+ irqreturn_t ret;
+
+ ret = mlxbf_gige_mdio_handle_phy_interrupt(priv);
+ if (ret != IRQ_HANDLED)
+ return;
+
+ /* print new link status only if the interrupt came from the PHY */
+ phy_print_status(phydev);
+}
+
/* Start of struct net_device_ops functions */
static irqreturn_t mlxbf_gige_error_intr(int irq, void *dev_id)
{
@@ -789,15 +801,6 @@ static int mlxbf_gige_request_irqs(struct mlxbf_gige *priv)
return err;
}
- err = request_threaded_irq(priv->phy_irq, NULL,
- mlxbf_gige_mdio_handle_phy_interrupt,
- IRQF_ONESHOT | IRQF_SHARED, "mlxbf_gige_phy",
- priv);
- if (err) {
- dev_err(priv->dev, "Request phy_irq failure\n");
- return err;
- }
-
return 0;
}
@@ -806,7 +809,6 @@ static void mlxbf_gige_free_irqs(struct mlxbf_gige *priv)
devm_free_irq(priv->dev, priv->error_irq, priv);
devm_free_irq(priv->dev, priv->rx_irq, priv);
devm_free_irq(priv->dev, priv->llu_plu_irq, priv);
- free_irq(priv->phy_irq, priv);
}
static void mlxbf_gige_cache_stats(struct mlxbf_gige *priv)
@@ -848,38 +850,6 @@ static void mlxbf_gige_clean_port(struct mlxbf_gige *priv)
writeq(control, priv->base + MLXBF_GIGE_CONTROL);
}
-static int mlxbf_gige_phy_enable_interrupt(struct phy_device *phydev)
-{
- int ret = 0;
-
- if (phydev->drv->ack_interrupt)
- ret = phydev->drv->ack_interrupt(phydev);
- if (ret < 0)
- return ret;
-
- phydev->interrupts = PHY_INTERRUPT_ENABLED;
- if (phydev->drv->config_intr)
- ret = phydev->drv->config_intr(phydev);
-
- return ret;
-}
-
-static int mlxbf_gige_phy_disable_interrupt(struct phy_device *phydev)
-{
- int ret = 0;
-
- if (phydev->drv->ack_interrupt)
- ret = phydev->drv->ack_interrupt(phydev);
- if (ret < 0)
- return ret;
-
- phydev->interrupts = PHY_INTERRUPT_DISABLED;
- if (phydev->drv->config_intr)
- ret = phydev->drv->config_intr(phydev);
-
- return ret;
-}
-
static int mlxbf_gige_open(struct net_device *netdev)
{
struct mlxbf_gige *priv = netdev_priv(netdev);
@@ -900,14 +870,6 @@ static int mlxbf_gige_open(struct net_device *netdev)
return err;
phy_start(phydev);
- /* Always make sure interrupts are enabled since phy_start calls
- * __phy_resume which may reset the PHY interrupt control reg.
- * __phy_resume only reenables the interrupts if
- * phydev->irq != IRQ_IGNORE_INTERRUPT.
- */
- err = mlxbf_gige_phy_enable_interrupt(phydev);
- if (err)
- return err;
/* Set bits in INT_EN that we care about */
int_en = MLXBF_GIGE_INT_EN_HW_ACCESS_ERROR |
@@ -932,8 +894,8 @@ static int mlxbf_gige_stop(struct net_device *netdev)
netif_napi_del(&priv->napi);
mlxbf_gige_free_irqs(priv);
- phy_stop(netdev->phydev);
- mlxbf_gige_phy_disable_interrupt(netdev->phydev);
+ if (netdev->phydev)
+ phy_stop(netdev->phydev);
mlxbf_gige_rx_deinit(priv);
mlxbf_gige_tx_deinit(priv);
@@ -1111,12 +1073,6 @@ static void mlxbf_gige_initial_mac(struct mlxbf_gige *priv)
local_mac);
}
-static void mlxbf_gige_adjust_link(struct net_device *netdev)
-{
- /* Only one speed and one duplex supported */
- return;
-}
-
static int mlxbf_gige_probe(struct platform_device *pdev)
{
struct phy_device *phydev;
@@ -1130,7 +1086,6 @@ static int mlxbf_gige_probe(struct platform_device *pdev)
void __iomem *base;
u64 control;
int err = 0;
- int addr;
mac_res = platform_get_resource(pdev, IORESOURCE_MEM, MLXBF_GIGE_RES_MAC);
if (!mac_res)
@@ -1202,21 +1157,16 @@ static int mlxbf_gige_probe(struct platform_device *pdev)
priv->error_irq = platform_get_irq(pdev, MLXBF_GIGE_ERROR_INTR_IDX);
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);
- priv->phy_irq = platform_get_irq(pdev, MLXBF_GIGE_PHY_INT_N);
phydev = phy_find_first(priv->mdiobus);
if (!phydev)
- return -ENODEV;
-
- addr = phydev->mdio.addr;
- phydev->irq = priv->mdiobus->irq[addr] = PHY_IGNORE_INTERRUPT;
+ return -EIO;
/* Sets netdev->phydev to phydev; which will eventually
* be used in ioctl calls.
- * Cannot pass NULL handler.
*/
err = phy_connect_direct(netdev, phydev,
- mlxbf_gige_adjust_link,
+ mlxbf_gige_handle_link_change,
PHY_INTERFACE_MODE_GMII);
if (err) {
dev_err(&pdev->dev, "Could not attach to PHY\n");
@@ -1233,11 +1183,6 @@ static int mlxbf_gige_probe(struct platform_device *pdev)
/* MAC supports symmetric flow control */
phy_support_sym_pause(phydev);
- /* Enable pause */
- priv->rx_pause = phydev->pause;
- priv->tx_pause = phydev->pause;
- priv->aneg_pause = AUTONEG_ENABLE;
-
/* Display information about attached PHY device */
phy_attached_info(phydev);
diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c
index 464bfac9a650..7a225036ab59 100644
--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c
+++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c
@@ -1,7 +1,7 @@
-// SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause
+// SPDX-License-Identifier: GPL-2.0-only OR Linux-OpenIB
/* MDIO support for Mellanox GigE driver
*
- * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
+ * Copyright (c) 2020 Mellanox Technologies Ltd.
*/
#include <linux/acpi.h>
@@ -10,7 +10,6 @@
#include <linux/device.h>
#include <linux/err.h>
#include <linux/io.h>
-#include <linux/iopoll.h>
#include <linux/ioport.h>
#include <linux/irqreturn.h>
#include <linux/jiffies.h>
@@ -22,6 +21,9 @@
#include "mlxbf_gige.h"
+#define MLXBF_GIGE_MDIO_POLL_BUSY_TIMEOUT 100 /* ms */
+#define MLXBF_GIGE_MDIO_POLL_DELAY_USEC 100 /* us */
+
#define MLXBF_GIGE_MDIO_GW_OFFSET 0x0
#define MLXBF_GIGE_MDIO_CFG_OFFSET 0x4
@@ -32,6 +34,8 @@
/* Busy bit is set by software and cleared by hardware */
#define MLXBF_GIGE_MDIO_SET_BUSY 0x1
+/* Lock bit should be set/cleared by software */
+#define MLXBF_GIGE_MDIO_SET_LOCK 0x1
/* MDIO GW register bits */
#define MLXBF_GIGE_MDIO_GW_AD_MASK GENMASK(15, 0)
@@ -40,6 +44,7 @@
#define MLXBF_GIGE_MDIO_GW_OPCODE_MASK GENMASK(27, 26)
#define MLXBF_GIGE_MDIO_GW_ST1_MASK GENMASK(28, 28)
#define MLXBF_GIGE_MDIO_GW_BUSY_MASK GENMASK(30, 30)
+#define MLXBF_GIGE_MDIO_GW_LOCK_MASK GENMASK(31, 31)
/* MDIO config register bits */
#define MLXBF_GIGE_MDIO_CFG_MDIO_MODE_MASK GENMASK(1, 0)
@@ -63,13 +68,20 @@
#define MLXBF_GIGE_MDIO_PERIOD (((MLXBF_GIGE_MDC_CLK_NS * MLXBF_GIGE_I1CLK_MHZ / 1000) / 2) - 1)
-#define MLXBF_GIGE_MDIO_CFG_VAL (FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_MODE_MASK, 1) | \
- FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO3_3_MASK, 1) | \
- FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_FULL_DRIVE_MASK, 1) | \
- FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDC_PERIOD_MASK, \
- MLXBF_GIGE_MDIO_PERIOD) | \
- FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_IN_SAMP_MASK, 6) | \
- FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_OUT_SAMP_MASK, 13))
+/* PHY should operate in master mode only */
+#define MLXBF_GIGE_MDIO_MODE_MASTER 1
+
+/* PHY input voltage has to be 3.3V */
+#define MLXBF_GIGE_MDIO3_3 1
+
+/* Operate in full drive mode */
+#define MLXBF_GIGE_MDIO_FULL_DRIVE 1
+
+/* 6 cycles before the i1clk (core clock) rising edge that triggers the mdc */
+#define MLXBF_GIGE_MDIO_IN_SAMP 6
+
+/* 13 cycles after the i1clk (core clock) rising edge that triggers the mdc */
+#define MLXBF_GIGE_MDIO_OUT_SAMP 13
/* The PHY interrupt line is shared with other interrupt lines such
* as GPIO and SMBus. So use YU registers to determine whether the
@@ -87,10 +99,6 @@
#define MLXBF_GIGE_GPIO_CAUSE_OR_CLRCAUSE 0x98
#define MLXBF_GIGE_GPIO12_BIT 12
-#define MLXBF_GIGE_CAUSE_OR_CAUSE_EVTEN0_MASK BIT(MLXBF_GIGE_GPIO12_BIT)
-#define MLXBF_GIGE_CAUSE_OR_EVTEN0_MASK BIT(MLXBF_GIGE_GPIO12_BIT)
-#define MLXBF_GIGE_CAUSE_FALL_EN_MASK BIT(MLXBF_GIGE_GPIO12_BIT)
-#define MLXBF_GIGE_CAUSE_OR_CLRCAUSE_MASK BIT(MLXBF_GIGE_GPIO12_BIT)
static u32 mlxbf_gige_mdio_create_cmd(u16 data, int phy_add,
int phy_reg, u32 opcode)
@@ -106,36 +114,65 @@ static u32 mlxbf_gige_mdio_create_cmd(u16 data, int phy_add,
gw_reg |= FIELD_PREP(MLXBF_GIGE_MDIO_GW_BUSY_MASK,
MLXBF_GIGE_MDIO_SET_BUSY);
+ /* Hold the lock until the read/write is completed so that no other
+ * program accesses the mdio bus.
+ */
+ gw_reg |= FIELD_PREP(MLXBF_GIGE_MDIO_GW_LOCK_MASK,
+ MLXBF_GIGE_MDIO_SET_LOCK);
+
return gw_reg;
}
+static int mlxbf_gige_mdio_poll_bit(struct mlxbf_gige *priv, u32 bit_mask)
+{
+ unsigned long timeout;
+ u32 val;
+
+ timeout = jiffies + msecs_to_jiffies(MLXBF_GIGE_MDIO_POLL_BUSY_TIMEOUT);
+ do {
+ val = readl(priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET);
+ if (!(val & bit_mask))
+ return 0;
+ udelay(MLXBF_GIGE_MDIO_POLL_DELAY_USEC);
+ } while (time_before(jiffies, timeout));
+
+ return -ETIME;
+}
+
static int mlxbf_gige_mdio_read(struct mii_bus *bus, int phy_add, int phy_reg)
{
struct mlxbf_gige *priv = bus->priv;
u32 cmd;
- int ret;
- u32 val;
+ u32 ret;
- if (phy_reg & MII_ADDR_C45)
- return -EOPNOTSUPP;
+ /* If the lock is held by something else, drop the request.
+ * If the lock is cleared, that means the busy bit was cleared.
+ */
+ ret = mlxbf_gige_mdio_poll_bit(priv, MLXBF_GIGE_MDIO_GW_LOCK_MASK);
+ if (ret)
+ return -EBUSY;
/* Send mdio read request */
cmd = mlxbf_gige_mdio_create_cmd(0, phy_add, phy_reg, MLXBF_GIGE_MDIO_CL22_READ);
writel(cmd, priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET);
- ret = readl_poll_timeout_atomic(priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET,
- val, !(val & MLXBF_GIGE_MDIO_GW_BUSY_MASK), 100, 1000000);
-
+ ret = mlxbf_gige_mdio_poll_bit(priv, MLXBF_GIGE_MDIO_GW_BUSY_MASK);
if (ret) {
writel(0, priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET);
- return ret;
+ return -EBUSY;
}
ret = readl(priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET);
/* Only return ad bits of the gw register */
ret &= MLXBF_GIGE_MDIO_GW_AD_MASK;
+ /* To release the YU MDIO lock, clear gw register,
+ * so that the YU does not confuse this write with a new
+ * MDIO read/write request.
+ */
+ writel(0, priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET);
+
return ret;
}
@@ -145,10 +182,13 @@ static int mlxbf_gige_mdio_write(struct mii_bus *bus, int phy_add,
struct mlxbf_gige *priv = bus->priv;
u32 cmd;
int ret;
- u32 temp;
- if (phy_reg & MII_ADDR_C45)
- return -EOPNOTSUPP;
+ /* If the lock is held by something else, drop the request.
+ * If the lock is cleared, that means the busy bit was cleared.
+ */
+ ret = mlxbf_gige_mdio_poll_bit(priv, MLXBF_GIGE_MDIO_GW_LOCK_MASK);
+ if (ret)
+ return -EBUSY;
/* Send mdio write request */
cmd = mlxbf_gige_mdio_create_cmd(val, phy_add, phy_reg,
@@ -156,8 +196,13 @@ static int mlxbf_gige_mdio_write(struct mii_bus *bus, int phy_add,
writel(cmd, priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET);
/* If the poll timed out, drop the request */
- ret = readl_poll_timeout_atomic(priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET,
- temp, !(temp & MLXBF_GIGE_MDIO_GW_BUSY_MASK), 100, 1000000);
+ ret = mlxbf_gige_mdio_poll_bit(priv, MLXBF_GIGE_MDIO_GW_BUSY_MASK);
+
+ /* To release the YU MDIO lock, clear gw register,
+ * so that the YU does not confuse this write as a new
+ * MDIO read/write request.
+ */
+ writel(0, priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET);
return ret;
}
@@ -169,7 +214,7 @@ static void mlxbf_gige_mdio_disable_phy_int(struct mlxbf_gige *priv)
spin_lock_irqsave(&priv->gpio_lock, flags);
val = readl(priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_EVTEN0);
- val &= ~MLXBF_GIGE_CAUSE_OR_EVTEN0_MASK;
+ val &= ~priv->phy_int_gpio_mask;
writel(val, priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_EVTEN0);
spin_unlock_irqrestore(&priv->gpio_lock, flags);
}
@@ -185,13 +230,13 @@ static void mlxbf_gige_mdio_enable_phy_int(struct mlxbf_gige *priv)
* state goes low.
*/
val = readl(priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_FALL_EN);
- val |= MLXBF_GIGE_CAUSE_FALL_EN_MASK;
+ val |= priv->phy_int_gpio_mask;
writel(val, priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_FALL_EN);
/* Enable PHY interrupt by setting the priority level */
val = readl(priv->gpio_io +
MLXBF_GIGE_GPIO_CAUSE_OR_EVTEN0);
- val |= MLXBF_GIGE_CAUSE_OR_EVTEN0_MASK;
+ val |= priv->phy_int_gpio_mask;
writel(val, priv->gpio_io +
MLXBF_GIGE_GPIO_CAUSE_OR_EVTEN0);
spin_unlock_irqrestore(&priv->gpio_lock, flags);
@@ -200,25 +245,33 @@ static void mlxbf_gige_mdio_enable_phy_int(struct mlxbf_gige *priv)
/* Interrupt handler is called from mlxbf_gige_main.c
* driver whenever a phy interrupt is received.
*/
-irqreturn_t mlxbf_gige_mdio_handle_phy_interrupt(int irq, void *dev_id)
+irqreturn_t mlxbf_gige_mdio_handle_phy_interrupt(struct mlxbf_gige *priv)
{
- struct phy_device *phydev;
- struct mlxbf_gige *priv;
u32 val;
- priv = dev_id;
- phydev = priv->netdev->phydev;
+ /* The YU interrupt is shared between SMBus and GPIOs.
+ * So first, determine whether this is a GPIO interrupt.
+ */
+ val = readl(priv->cause_rsh_coalesce0_io);
+ if (!MLXBF_GIGE_GPIO_CAUSE_IRQ_IS_SET(val)) {
+ /* Nothing to do here, not a GPIO interrupt */
+ return IRQ_NONE;
+ }
+ /* Then determine which gpio register this interrupt is for.
+ * Return if the interrupt is not for gpio block 0.
+ */
+ val = readl(priv->cause_gpio_arm_coalesce0_io);
+ if (!(val & MLXBF_GIGE_GPIO_BLOCK0_MASK))
+ return IRQ_NONE;
- /* Check if this interrupt is from PHY device.
+ /* Finally check if this interrupt is from PHY device.
* Return if it is not.
*/
val = readl(priv->gpio_io +
MLXBF_GIGE_GPIO_CAUSE_OR_CAUSE_EVTEN0);
- if (!(val & MLXBF_GIGE_CAUSE_OR_CAUSE_EVTEN0_MASK))
+ if (!(val & priv->phy_int_gpio_mask))
return IRQ_NONE;
- phy_mac_interrupt(phydev);
-
/* Clear interrupt when done, otherwise, no further interrupt
* will be triggered.
* Writing 0x1 to the clear cause register also clears the
@@ -228,22 +281,67 @@ irqreturn_t mlxbf_gige_mdio_handle_phy_interrupt(int irq, void *dev_id)
*/
val = readl(priv->gpio_io +
MLXBF_GIGE_GPIO_CAUSE_OR_CLRCAUSE);
- val |= MLXBF_GIGE_CAUSE_OR_CLRCAUSE_MASK;
+ val |= priv->phy_int_gpio_mask;
writel(val, priv->gpio_io +
MLXBF_GIGE_GPIO_CAUSE_OR_CLRCAUSE);
- /* Make sure to clear the PHY device interrupt */
- if (phydev->drv->ack_interrupt)
- phydev->drv->ack_interrupt(phydev);
-
return IRQ_HANDLED;
}
+static void mlxbf_gige_mdio_init_config(struct mlxbf_gige *priv)
+{
+ struct device *dev = priv->dev;
+ u32 mdio_full_drive;
+ u32 mdio_out_sample;
+ u32 mdio_in_sample;
+ u32 mdio_voltage;
+ u32 mdc_period;
+ u32 mdio_mode;
+ u32 mdio_cfg;
+ int ret;
+
+ ret = device_property_read_u32(dev, "mdio-mode", &mdio_mode);
+ if (ret < 0)
+ mdio_mode = MLXBF_GIGE_MDIO_MODE_MASTER;
+
+ ret = device_property_read_u32(dev, "mdio-voltage", &mdio_voltage);
+ if (ret < 0)
+ mdio_voltage = MLXBF_GIGE_MDIO3_3;
+
+ ret = device_property_read_u32(dev, "mdio-full-drive", &mdio_full_drive);
+ if (ret < 0)
+ mdio_full_drive = MLXBF_GIGE_MDIO_FULL_DRIVE;
+
+ ret = device_property_read_u32(dev, "mdc-period", &mdc_period);
+ if (ret < 0)
+ mdc_period = MLXBF_GIGE_MDIO_PERIOD;
+
+ ret = device_property_read_u32(dev, "mdio-in-sample", &mdio_in_sample);
+ if (ret < 0)
+ mdio_in_sample = MLXBF_GIGE_MDIO_IN_SAMP;
+
+ ret = device_property_read_u32(dev, "mdio-out-sample", &mdio_out_sample);
+ if (ret < 0)
+ mdio_out_sample = MLXBF_GIGE_MDIO_OUT_SAMP;
+
+ mdio_cfg = FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_MODE_MASK, mdio_mode) |
+ FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO3_3_MASK, mdio_voltage) |
+ FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_FULL_DRIVE_MASK, mdio_full_drive) |
+ FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDC_PERIOD_MASK, mdc_period) |
+ FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_IN_SAMP_MASK, mdio_in_sample) |
+ FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_OUT_SAMP_MASK, mdio_out_sample);
+
+ writel(mdio_cfg, priv->mdio_io + MLXBF_GIGE_MDIO_CFG_OFFSET);
+}
+
int mlxbf_gige_mdio_probe(struct platform_device *pdev, struct mlxbf_gige *priv)
{
struct device *dev = &pdev->dev;
struct resource *res;
+ u32 phy_int_gpio;
+ u32 phy_addr;
int ret;
+ int irq;
res = platform_get_resource(pdev, IORESOURCE_MEM, MLXBF_GIGE_RES_MDIO9);
if (!res)
@@ -281,9 +379,12 @@ int mlxbf_gige_mdio_probe(struct platform_device *pdev, struct mlxbf_gige *priv)
if (!priv->cause_gpio_arm_coalesce0_io)
return -ENOMEM;
- /* Configure mdio parameters */
- writel(MLXBF_GIGE_MDIO_CFG_VAL,
- priv->mdio_io + MLXBF_GIGE_MDIO_CFG_OFFSET);
+ mlxbf_gige_mdio_init_config(priv);
+
+ ret = device_property_read_u32(dev, "phy-int-gpio", &phy_int_gpio);
+ if (ret < 0)
+ phy_int_gpio = MLXBF_GIGE_GPIO12_BIT;
+ priv->phy_int_gpio_mask = BIT(phy_int_gpio);
mlxbf_gige_mdio_enable_phy_int(priv);
@@ -301,6 +402,19 @@ int mlxbf_gige_mdio_probe(struct platform_device *pdev, struct mlxbf_gige *priv)
snprintf(priv->mdiobus->id, MII_BUS_ID_SIZE, "%s",
dev_name(dev));
+ ret = device_property_read_u32(dev, "phy-addr", &phy_addr);
+ if (ret < 0)
+ phy_addr = MLXBF_GIGE_MDIO_DEFAULT_PHY_ADDR;
+
+ irq = platform_get_irq(pdev, MLXBF_GIGE_PHY_INT_N);
+ if (irq < 0) {
+ dev_err(dev, "Failed to retrieve irq 0x%x\n", irq);
+ return -ENODEV;
+ }
+ priv->mdiobus->irq[phy_addr] = PHY_POLL;
+
+ /* Auto probe PHY at the corresponding address */
+ priv->mdiobus->phy_mask = ~(1 << phy_addr);
ret = mdiobus_register(priv->mdiobus);
if (ret)
dev_err(dev, "Failed to register MDIO bus\n");
diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h
index 06e3c7145bbd..9c7af820c197 100644
--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h
+++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h
@@ -1,8 +1,8 @@
-/* SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause */
+/* SPDX-License-Identifier: GPL-2.0-only OR Linux-OpenIB */
/* Header file for Mellanox BlueField GigE register defines
*
- * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
+ * Copyright (c) 2020 Mellanox Technologies Ltd.
*/
#ifndef __MLXBF_GIGE_REGS_H__
--
2.30.1
More information about the kernel-team
mailing list