From patchwork Fri Jul 9 19:08:21 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Asmaa Mnebhi X-Patchwork-Id: 1503329 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=) Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4GM2lc63LZz9sPf; Sat, 10 Jul 2021 05:09:32 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1m1vsM-0003ZR-VH; Fri, 09 Jul 2021 19:09:27 +0000 Received: from mail-il-dmz.mellanox.com ([193.47.165.129] helo=mellanox.co.il) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1m1vrs-0003D8-SG for kernel-team@lists.ubuntu.com; Fri, 09 Jul 2021 19:08:57 +0000 Received: from Internal Mail-Server by MTLPINE1 (envelope-from asmaa@mellanox.com) with SMTP; 9 Jul 2021 22:08:54 +0300 Received: from farm-0002.mtbu.labs.mlnx (farm-0002.mtbu.labs.mlnx [10.15.2.32]) by mtbu-labmailer.labs.mlnx (8.14.4/8.14.4) with ESMTP id 169J8rHZ030229; Fri, 9 Jul 2021 15:08:53 -0400 Received: (from asmaa@localhost) by farm-0002.mtbu.labs.mlnx (8.14.7/8.13.8/Submit) id 169J8rlB005467; Fri, 9 Jul 2021 15:08:53 -0400 From: Asmaa Mnebhi To: kernel-team@lists.ubuntu.com Subject: [SRU][F][PULL][PATCH v2 14/23] Revert "UBUNTU: SAUCE: Address upstream comments from patch v6 for PHY driver" Date: Fri, 9 Jul 2021 15:08:21 -0400 Message-Id: <20210709190830.5405-15-asmaa@nvidia.com> X-Mailer: git-send-email 2.30.1 In-Reply-To: <20210709190830.5405-1-asmaa@nvidia.com> References: <20210709190830.5405-1-asmaa@nvidia.com> MIME-Version: 1.0 X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: asmaa@nvidia.com, davthompson@nvidia.com Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" BugLink: https://bugs.launchpad.net/bugs/1934923 This reverts commit e65518a6eeb7dc24198700b1ec7e96ffdeab2b46. Signed-off-by: Asmaa Mnebhi --- .../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 @@ -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 @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include @@ -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__