From nobody Thu Sep 24 23:33:27 2026 Received: from esa.microchip.iphmx.com (esa.microchip.iphmx.com [68.232.154.123]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 979903DEFE2; Fri, 18 Sep 2026 14:33:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=68.232.154.123 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789741998; cv=none; b=XI1EngxVxNEaXq+75+s88ZAM3Z1nRXcIvozTI1VVn6eHJoujZDQ5mIGg80I2l3lc6UTXti44fZiJPRi4mo/rEJ/+fmjV5braTVvk9GgGZm2z9F28S+stZsxe1ZuAmtmQ2iEVcV89wrvFZVVtcqBxfSDB3fEPrVTZqUMFk1Qy3Rk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789741998; c=relaxed/simple; bh=nowrGPImW60NJh5SJPfOQT+NuCyRWOuREJ5ST3tON+I=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=u1VRNZqlFArd33YHB+el+XkUuh4FadlwMiU+nvE4VJGl2DGCM+wlaAE3dqJ0tTlXdqMmR1Q8oLuhwkENRA7Mg/4FnBr9sVrFYlAN1Nwg7vRxRr88ecTw39em9sPyNMMafEyoeB+/WIRyToEvWdIamfQNOFJGOKKBpXt3VnB7vtk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=microchip.com; spf=pass smtp.mailfrom=microchip.com; dkim=pass (2048-bit key) header.d=microchip.com header.i=@microchip.com header.b=BTrcFSTW; arc=none smtp.client-ip=68.232.154.123 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=microchip.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=microchip.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=microchip.com header.i=@microchip.com header.b="BTrcFSTW" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1789741996; x=1821277996; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=nowrGPImW60NJh5SJPfOQT+NuCyRWOuREJ5ST3tON+I=; b=BTrcFSTWWzXKdIDDhWVfGGwp86+S3pA8cviPQa0llmD+TzicBNMGiPFO L1zHCYEQGuav074SJcJjkebpMiVLQ8MCKZKi42lUxjPb3r3AaUVWzj+6Z zBuOJOKrRjyiEt1RVWKOlzZvb+irgENivnq6hB71OB04TsbF/tyT8e/BW FYeDJmAIh7cZgUZ4UVvCHYeK7lVdoU5mxnJP/cj22Dk4hbPbhc5CrqCht mIfoyhKjp6HnE3+QFUdB3/JC7CXLsUokYIT9bBigoO+5t+Mr8K4ZcxbCc V6AwbA/rfu/oWdW/6c/zWJ1wWWb52S3ZsNFhxmgzWbp9ZgMRsXGUtNhCc w==; X-CSE-ConnectionGUID: U6LChHbFQWizlUL0pkJVpg== X-CSE-MsgGUID: oClejNADSTuClErrztdE3g== X-IronPort-AV: E=Sophos;i="6.27,109,1787036400"; d="scan'208";a="230930419" X-Amp-Result: SKIPPED(no attachment in message) Received: from unknown (HELO email.microchip.com) ([170.129.1.10]) by esa6.microchip.iphmx.com with ESMTP/TLS/ECDHE-RSA-AES128-GCM-SHA256; 18 Sep 2026 07:33:15 -0700 Received: from chn-vm-ex01.mchp-main.com (10.10.85.143) by chn-vm-ex02.mchp-main.com (10.10.85.144) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.58; Fri, 18 Sep 2026 07:33:15 -0700 Received: from che-ll-i17164.microchip.com (10.10.85.11) by chn-vm-ex01.mchp-main.com (10.10.85.143) with Microsoft SMTP Server id 15.1.2507.58 via Frontend Transport; Fri, 18 Sep 2026 07:33:10 -0700 From: Parthiban Veerasooran To: , , , , , , CC: , , , , Parthiban Veerasooran Subject: [PATCH net-next v3 1/4] net: phy: microchip_t1s: fix collision detection on PLCA status change Date: Fri, 18 Sep 2026 20:02:59 +0530 Message-ID: <20260918143302.76909-2-parthiban.veerasooran@microchip.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260918143302.76909-1-parthiban.veerasooran@microchip.com> References: <20260918143302.76909-1-parthiban.veerasooran@microchip.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" lan86xx_plca_set_cfg() only adjusted collision detection on explicit ethtool PLCA changes, missing the autonomous online/offline transitions the PHY performs based on BEACON availability. When PLCA went offline, collision detection stayed disabled, leaving CSMA/CD running unprotected. Fix this by monitoring the PLCA Status Changed (PSTC) interrupt. lan86xx_config_intr() enables/disables PSTCM in IMSK1; lan86xx_handle_interrupt() reads live PLCA status on each interrupt and toggles CDEN in COL_DET_CTRL0 accordingly. CDEN is re-synced against current PLCA status right after unmasking PSTCM, since a transition during the masked window is otherwise silently dropped by the STS1 read-to-clear. lan86xx_read_clear_sts1() and lan86xx_set_intr_mask() factor out the shared STS1/IMSK1 sequences; both are reused by the Rev.D0 handling added later in this series. Wired to LAN867X Rev.B1, C1, C2 and LAN865X Rev.B0/B1. Rev.D0 needs separate handling (follow-on patch). Boards without a routed interrupt (phydev->irq =3D=3D PHY_POLL, including LAN865X until later patches) keep the static CDEN write in lan86xx_plca_set_cfg() as a baseline, with the known limitation that autonomous transitions between ethtool calls aren't tracked there. Fixes: 78341049fbcd ("net: phy: microchip_t1s: configure collision detectio= n based on PLCA mode") Signed-off-by: Parthiban Veerasooran --- drivers/net/phy/microchip_t1s.c | 142 +++++++++++++++++++++++++++++++- 1 file changed, 139 insertions(+), 3 deletions(-) diff --git a/drivers/net/phy/microchip_t1s.c b/drivers/net/phy/microchip_t1= s.c index 73c23d311d72..3333e4801aae 100644 --- a/drivers/net/phy/microchip_t1s.c +++ b/drivers/net/phy/microchip_t1s.c @@ -27,6 +27,14 @@ #define LAN865X_REG_CFGPARAM_CTRL 0x00DA #define LAN865X_REG_STS2 0x0019 =20 +/* PHY interrupt status and mask registers (MDIO_MMD_VEND2). The status bi= ts + * are read-to-clear; a mask bit is enabled by writing 0. + */ +#define LAN86XX_REG_STS1 0x0018 +#define LAN86XX_REG_IMSK1 0x001C + +#define LAN86XX_STS1_PLCA_STS_CHANGED BIT(11) + /* Collision Detector Control 0 Register */ #define LAN86XX_REG_COL_DET_CTRL0 0x0087 #define COL_DET_CTRL0_ENABLE_BIT_MASK BIT(15) @@ -458,14 +466,29 @@ static int lan86xx_plca_set_cfg(struct phy_device *ph= ydev, if (ret) return ret; =20 - if (plca_cfg->enabled) + /* phylib dispatches handle_interrupt() only for PHYs with a real IRQ + * number (phy_interrupt_is_valid()). For PHY_POLL and PHY_MAC_INTERRUPT + * handle_interrupt() is never called, so apply the static CDEN write + * here as a baseline on every ethtool PLCA reconfiguration. The + * limitation is that autonomous PLCA mode transitions between ethtool + * reconfigurations are not tracked on such boards. + */ + if (phy_interrupt_is_valid(phydev)) + return 0; + + if (plca_cfg->enabled > 0) return phy_modify_mmd(phydev, MDIO_MMD_VEND2, LAN86XX_REG_COL_DET_CTRL0, COL_DET_CTRL0_ENABLE_BIT_MASK, COL_DET_DISABLE); =20 - return phy_modify_mmd(phydev, MDIO_MMD_VEND2, LAN86XX_REG_COL_DET_CTRL0, - COL_DET_CTRL0_ENABLE_BIT_MASK, COL_DET_ENABLE); + if (plca_cfg->enabled =3D=3D 0) + return phy_modify_mmd(phydev, MDIO_MMD_VEND2, + LAN86XX_REG_COL_DET_CTRL0, + COL_DET_CTRL0_ENABLE_BIT_MASK, + COL_DET_ENABLE); + + return 0; } =20 static int lan867x_revd0_config_init(struct phy_device *phydev) @@ -506,6 +529,111 @@ static int lan86xx_read_status(struct phy_device *phy= dev) return 0; } =20 +/* Read LAN86XX_REG_STS1, which clears the latched status bits on read. */ +static int lan86xx_read_clear_sts1(struct phy_device *phydev) +{ + return phy_read_mmd(phydev, MDIO_MMD_VEND2, LAN86XX_REG_STS1); +} + +/* Mask (mask bit =3D 1) or unmask (mask bit =3D 0) the given STS1 bits in + * IMSK1. + */ +static int lan86xx_set_intr_mask(struct phy_device *phydev, u16 mask, + bool enable) +{ + if (enable) + /* A mask bit of 0 enables the corresponding interrupt. */ + return phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2, + LAN86XX_REG_IMSK1, mask); + + return phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, LAN86XX_REG_IMSK1, + mask); +} + +static int lan86xx_config_intr(struct phy_device *phydev) +{ + struct phy_plca_status plca_st; + int ret; + + if (phydev->interrupts =3D=3D PHY_INTERRUPT_ENABLED) { + /* Read to clear any pending status before enabling. */ + ret =3D lan86xx_read_clear_sts1(phydev); + if (ret < 0) + return ret; + + /* STS1 may have cleared a PSTC event that occurred while the + * interrupt was masked, so synchronize CDEN with the current + * PLCA state before enabling PSTC. + */ + ret =3D genphy_c45_plca_get_status(phydev, &plca_st); + if (ret < 0) + return ret; + + ret =3D phy_modify_mmd(phydev, MDIO_MMD_VEND2, + LAN86XX_REG_COL_DET_CTRL0, + COL_DET_CTRL0_ENABLE_BIT_MASK, + plca_st.pst ? COL_DET_DISABLE : + COL_DET_ENABLE); + if (ret) + return ret; + + return lan86xx_set_intr_mask(phydev, + LAN86XX_STS1_PLCA_STS_CHANGED, + true); + } + + ret =3D lan86xx_set_intr_mask(phydev, LAN86XX_STS1_PLCA_STS_CHANGED, + false); + if (ret) + return ret; + + /* Read to clear any pending status after disabling. */ + ret =3D lan86xx_read_clear_sts1(phydev); + return ret < 0 ? ret : 0; +} + +static irqreturn_t lan86xx_handle_interrupt(struct phy_device *phydev) +{ + struct phy_plca_status plca_st; + irqreturn_t ret_irq =3D IRQ_NONE; + int sts1, ret; + + /* Reading the status register clears the latched event bits. */ + sts1 =3D lan86xx_read_clear_sts1(phydev); + if (sts1 < 0) { + phy_error(phydev); + return IRQ_NONE; + } + + if (sts1 & LAN86XX_STS1_PLCA_STS_CHANGED) { + ret =3D genphy_c45_plca_get_status(phydev, &plca_st); + if (ret < 0) { + phy_error(phydev); + return IRQ_NONE; + } + + /* AN1760/AN1699: disable collision detection in PLCA mode to + * improve signal quality; re-enable it in CSMA/CD mode. + * + * https://www.microchip.com/en-us/application-notes/an1760 + * https://www.microchip.com/en-us/application-notes/an1699 + */ + ret =3D phy_modify_mmd(phydev, MDIO_MMD_VEND2, + LAN86XX_REG_COL_DET_CTRL0, + COL_DET_CTRL0_ENABLE_BIT_MASK, + plca_st.pst ? COL_DET_DISABLE : + COL_DET_ENABLE); + if (ret < 0) { + phy_error(phydev); + return IRQ_NONE; + } + + ret_irq =3D IRQ_HANDLED; + } + + return ret_irq; +} + static struct phy_driver microchip_t1s_driver[] =3D { { PHY_ID_MATCH_EXACT(PHY_ID_LAN867X_REVB1), @@ -513,6 +641,8 @@ static struct phy_driver microchip_t1s_driver[] =3D { .features =3D PHY_BASIC_T1S_P2MP_FEATURES, .config_init =3D lan867x_revb1_config_init, .read_status =3D lan86xx_read_status, + .config_intr =3D lan86xx_config_intr, + .handle_interrupt =3D lan86xx_handle_interrupt, .get_plca_cfg =3D genphy_c45_plca_get_cfg, .set_plca_cfg =3D genphy_c45_plca_set_cfg, .get_plca_status =3D genphy_c45_plca_get_status, @@ -523,6 +653,8 @@ static struct phy_driver microchip_t1s_driver[] =3D { .features =3D PHY_BASIC_T1S_P2MP_FEATURES, .config_init =3D lan867x_revc_config_init, .read_status =3D lan86xx_read_status, + .config_intr =3D lan86xx_config_intr, + .handle_interrupt =3D lan86xx_handle_interrupt, .get_plca_cfg =3D genphy_c45_plca_get_cfg, .set_plca_cfg =3D lan86xx_plca_set_cfg, .get_plca_status =3D genphy_c45_plca_get_status, @@ -533,6 +665,8 @@ static struct phy_driver microchip_t1s_driver[] =3D { .features =3D PHY_BASIC_T1S_P2MP_FEATURES, .config_init =3D lan867x_revc_config_init, .read_status =3D lan86xx_read_status, + .config_intr =3D lan86xx_config_intr, + .handle_interrupt =3D lan86xx_handle_interrupt, .get_plca_cfg =3D genphy_c45_plca_get_cfg, .set_plca_cfg =3D lan86xx_plca_set_cfg, .get_plca_status =3D genphy_c45_plca_get_status, @@ -556,6 +690,8 @@ static struct phy_driver microchip_t1s_driver[] =3D { .features =3D PHY_BASIC_T1S_P2MP_FEATURES, .config_init =3D lan865x_revb_config_init, .read_status =3D lan86xx_read_status, + .config_intr =3D lan86xx_config_intr, + .handle_interrupt =3D lan86xx_handle_interrupt, .read_mmd =3D genphy_read_mmd_c45, .write_mmd =3D genphy_write_mmd_c45, .get_plca_cfg =3D genphy_c45_plca_get_cfg, --=20 2.43.0 From nobody Thu Sep 24 23:33:27 2026 Received: from esa.microchip.iphmx.com (esa.microchip.iphmx.com [68.232.153.233]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2EC9949D587; Fri, 18 Sep 2026 14:33:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=68.232.153.233 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789742004; cv=none; b=ZzIwUwPqbPNS7tzdqDQuGNpJmwuV9P38cMjA5szEp9dST2+k5U+eI9qakdFy1NRSh011UmOxh7NkVA9YqDO1m5CDfpJkX4NRgAc87BEGK31yxj9r4ro6pcwR089tNfZ7CrpyB4hKp9auCPZb7Mljy8NINGUkW8mmhvbLLzGi29Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789742004; c=relaxed/simple; bh=kOMyXulWsJvv7WEbdxT53eYJ3BjsEMEi5erNBhvQZZ0=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=klL7k8itVQ6c+hUsexCpufNYSOTNsz3ZeUEJq18TifGrjxvHFHjc04M03ftCG5ILfIKPXQM/ymXXQuCvo2x9IBloky3nfiSFysKtHxg63/6/drVC65KZt2jnYKrZ2TIEEd2/6+fEgl6wWEycGzrzly3oJjE6tlCZYAj6jukIIVg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=microchip.com; spf=pass smtp.mailfrom=microchip.com; dkim=pass (2048-bit key) header.d=microchip.com header.i=@microchip.com header.b=VwjhgDDF; arc=none smtp.client-ip=68.232.153.233 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=microchip.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=microchip.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=microchip.com header.i=@microchip.com header.b="VwjhgDDF" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1789742001; x=1821278001; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=kOMyXulWsJvv7WEbdxT53eYJ3BjsEMEi5erNBhvQZZ0=; b=VwjhgDDF5Jph9lKkYFQWpKmybyZ4TXfbWLMj5szzurvbwHc3w6uZN5pZ tbsm45GQDX6HGEo3mhZiIARbvc9FupZG48F9vXX7xZIQGSmbrRRIOiwZv sCEBUd9OccpaF+aEirvGf1WJ/cVcx7XYffpaPepxGxmF5ju3ltbZOLaHB m+OmkCWyI4m7bw35YhWXl5f8wbnUtjUWlE02mL5q83JpMtHkHSaUDc449 hpu2DkbQK5EavKbDOCLSyiIAZJip7aozr1oCNlrKcSPo7KCuQefoMm4Bx uPbX1CRLilY5Ls4S41ptWfd2RhHbPctzb0V7C9BVh3xJbiT0P4XFk84+k A==; X-CSE-ConnectionGUID: dz8rexjhRT22p0eHFAuehw== X-CSE-MsgGUID: fBg8lOWqSem32f1AslMIfg== X-IronPort-AV: E=Sophos;i="6.27,109,1787036400"; d="scan'208";a="63811296" X-Amp-Result: SKIPPED(no attachment in message) Received: from unknown (HELO email.microchip.com) ([170.129.1.10]) by esa3.microchip.iphmx.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 18 Sep 2026 07:33:21 -0700 Received: from chn-vm-ex01.mchp-main.com (10.10.87.71) by chn-vm-ex3.mchp-main.com (10.10.87.32) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.2.2562.49; Fri, 18 Sep 2026 07:33:19 -0700 Received: from che-ll-i17164.microchip.com (10.10.85.11) by chn-vm-ex01.mchp-main.com (10.10.85.143) with Microsoft SMTP Server id 15.1.2507.58 via Frontend Transport; Fri, 18 Sep 2026 07:33:15 -0700 From: Parthiban Veerasooran To: , , , , , , CC: , , , , Parthiban Veerasooran Subject: [PATCH net-next v3 2/4] net: ethernet: oa_tc6: deliver the PHY interrupt to phylib Date: Fri, 18 Sep 2026 20:03:00 +0530 Message-ID: <20260918143302.76909-3-parthiban.veerasooran@microchip.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260918143302.76909-1-parthiban.veerasooran@microchip.com> References: <20260918143302.76909-1-parthiban.veerasooran@microchip.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The OA TC6 standard defines PHY interrupt delivery via the SPI status register as optional. The PHY has no dedicated interrupt line in that case; its interrupt is signalled through the MAC-PHY SPI interface, but phy_mac_interrupt() can't make the PHY driver read and acknowledge its own status registers. Expose it to phylib instead as a nested virtual IRQ, gated by a new OA_TC6_PHY_INT quirk flag for drivers that route PHY interrupts in-band. When set, a nested virtual IRQ is created in oa_tc6_mdiobus_register() before mdiobus_register(), and all mii_bus->irq[] entries are populated with it so phy_device_create() picks it up regardless of MDIO address. Teardown is integrated into oa_tc6_mdiobus_unregister(). A custom irq_chip (oa_tc6_phy_irq_chip) implements mask/unmask via irq_bus_lock/irq_bus_sync_unlock, writing the mask bit to hardware over SPI. The interrupt starts masked (hardware reset default) and is only unmasked when phylib requests it, so disabling the nested IRQ actually masks the hardware source too, preventing interrupt storms. Dispatch is deferred to a workqueue rather than run synchronously from the threaded IRQ: phy_interrupt() takes phydev->lock and PHY handle_interrupt() issues synchronous SPI transfers, either of which would otherwise stall the single thread pumping every TX/RX data chunk. PHYINT is level triggered and stays asserted until acked, so a no-op reschedule on an already-pending work item can't lose or duplicate an event. Select IRQ_DOMAIN in Kconfig for the irq_domain APIs used here. Prerequisite for "net: phy: microchip_t1s: fix collision detection on PLCA status change" (Fixes: 78341049fbcd) to fully cover the LAN865X internal PHY. Signed-off-by: Parthiban Veerasooran --- drivers/net/ethernet/Kconfig | 1 + drivers/net/ethernet/oa_tc6.c | 145 ++++++++++++++++++++++++++++++++++ include/linux/oa_tc6.h | 3 + 3 files changed, 149 insertions(+) diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig index 8581ccba1505..ea2161232a17 100644 --- a/drivers/net/ethernet/Kconfig +++ b/drivers/net/ethernet/Kconfig @@ -150,6 +150,7 @@ config OA_TC6 tristate "OPEN Alliance TC6 10BASE-T1x MAC-PHY support" if COMPILE_TEST depends on SPI select PHYLIB + select IRQ_DOMAIN help This library implements OPEN Alliance TC6 10BASE-T1x MAC-PHY Serial Interface protocol for supporting 10BASE-T1x MAC-PHYs. diff --git a/drivers/net/ethernet/oa_tc6.c b/drivers/net/ethernet/oa_tc6.c index 6fcc5f561d56..b4a95155e924 100644 --- a/drivers/net/ethernet/oa_tc6.c +++ b/drivers/net/ethernet/oa_tc6.c @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include #include #include @@ -70,6 +72,11 @@ struct oa_tc6 { struct phy_device *phydev; struct mii_bus *mdiobus; struct spi_device *spi; + struct mutex phy_irq_lock; /* Serialises irq_bus_lock/sync_unlock */ + bool phy_irq_masked; /* Shadow of OA_TC6_INT_MASK0_PHY_INT_MASK */ + struct irq_domain *phy_irq_domain; + int phy_virq; + struct work_struct phy_irq_work; struct mutex spi_ctrl_lock; /* Protects spi control transfer */ spinlock_t tx_skb_lock; /* Protects tx skb handling */ void *spi_ctrl_tx_buf; @@ -528,6 +535,114 @@ int oa_tc6_mdiobus_write_c45(struct mii_bus *bus, int= addr, int devnum, } EXPORT_SYMBOL_GPL(oa_tc6_mdiobus_write_c45); =20 +static void oa_tc6_phy_irq_work(struct work_struct *work) +{ + struct oa_tc6 *tc6 =3D container_of(work, struct oa_tc6, phy_irq_work); + + /* Dispatched off the SPI chunk-processing thread so that + * phy_interrupt() taking phydev->lock and issuing synchronous SPI + * control transfers from PHY handle_interrupt() cannot stall the single + * thread pumping TX/RX data chunks. + */ + handle_nested_irq(tc6->phy_virq); +} + +static void oa_tc6_phy_irq_mask(struct irq_data *irqd) +{ + struct oa_tc6 *tc6 =3D irq_data_get_irq_chip_data(irqd); + + tc6->phy_irq_masked =3D true; +} + +static void oa_tc6_phy_irq_unmask(struct irq_data *irqd) +{ + struct oa_tc6 *tc6 =3D irq_data_get_irq_chip_data(irqd); + + tc6->phy_irq_masked =3D false; +} + +static void oa_tc6_phy_irq_bus_lock(struct irq_data *irqd) +{ + struct oa_tc6 *tc6 =3D irq_data_get_irq_chip_data(irqd); + + mutex_lock(&tc6->phy_irq_lock); +} + +static void oa_tc6_phy_irq_bus_sync_unlock(struct irq_data *irqd) +{ + struct oa_tc6 *tc6 =3D irq_data_get_irq_chip_data(irqd); + u32 regval; + int ret; + + ret =3D oa_tc6_read_register(tc6, OA_TC6_REG_INT_MASK0, ®val); + if (ret) { + dev_err(&tc6->spi->dev, "Failed to read INT_MASK0: %d\n", ret); + goto unlock; + } + + if (tc6->phy_irq_masked) + regval |=3D OA_TC6_INT_MASK0_PHY_INT_MASK; + else + regval &=3D ~OA_TC6_INT_MASK0_PHY_INT_MASK; + + ret =3D oa_tc6_write_register(tc6, OA_TC6_REG_INT_MASK0, regval); + if (ret) + dev_err(&tc6->spi->dev, "Failed to write INT_MASK0: %d\n", ret); + +unlock: + mutex_unlock(&tc6->phy_irq_lock); +} + +static struct irq_chip oa_tc6_phy_irq_chip =3D { + .name =3D "oa_tc6_phy", + .irq_mask =3D oa_tc6_phy_irq_mask, + .irq_unmask =3D oa_tc6_phy_irq_unmask, + .irq_bus_lock =3D oa_tc6_phy_irq_bus_lock, + .irq_bus_sync_unlock =3D oa_tc6_phy_irq_bus_sync_unlock, +}; + +static int oa_tc6_phy_irq_map(struct irq_domain *domain, unsigned int irq, + irq_hw_number_t hwirq) +{ + irq_set_chip_data(irq, domain->host_data); + irq_set_chip_and_handler(irq, &oa_tc6_phy_irq_chip, handle_simple_irq); + irq_set_nested_thread(irq, true); + irq_set_noprobe(irq); + + return 0; +} + +static const struct irq_domain_ops oa_tc6_phy_irq_domain_ops =3D { + .map =3D oa_tc6_phy_irq_map, +}; + +static int oa_tc6_phy_irq_setup(struct oa_tc6 *tc6) +{ + INIT_WORK(&tc6->phy_irq_work, oa_tc6_phy_irq_work); + + tc6->phy_irq_domain =3D + irq_domain_create_linear(NULL, 1, + &oa_tc6_phy_irq_domain_ops, tc6); + if (!tc6->phy_irq_domain) + return -ENOMEM; + + tc6->phy_virq =3D irq_create_mapping(tc6->phy_irq_domain, 0); + tc6->phy_irq_masked =3D true; + if (!tc6->phy_virq) { + irq_domain_remove(tc6->phy_irq_domain); + return -ENOMEM; + } + + return 0; +} + +static void oa_tc6_phy_irq_teardown(struct oa_tc6 *tc6) +{ + cancel_work_sync(&tc6->phy_irq_work); + irq_dispose_mapping(tc6->phy_virq); + irq_domain_remove(tc6->phy_irq_domain); +} + static int oa_tc6_mdiobus_register(struct oa_tc6 *tc6) { int ret; @@ -559,9 +674,25 @@ static int oa_tc6_mdiobus_register(struct oa_tc6 *tc6) snprintf(tc6->mdiobus->id, ARRAY_SIZE(tc6->mdiobus->id), "%s", dev_name(&tc6->spi->dev)); =20 + if (tc6->quirk_flags & OA_TC6_PHY_INT) { + ret =3D oa_tc6_phy_irq_setup(tc6); + if (ret) { + mdiobus_free(tc6->mdiobus); + return ret; + } + /* Populate all irq[] entries before registration so + * phy_device_create() picks up the virtual IRQ regardless of + * the PHY's MDIO address. + */ + for (int i =3D 0; i < PHY_MAX_ADDR; i++) + tc6->mdiobus->irq[i] =3D tc6->phy_virq; + } + ret =3D mdiobus_register(tc6->mdiobus); if (ret) { netdev_err(tc6->netdev, "Could not register MDIO bus\n"); + if (tc6->quirk_flags & OA_TC6_PHY_INT) + oa_tc6_phy_irq_teardown(tc6); mdiobus_free(tc6->mdiobus); return ret; } @@ -572,6 +703,8 @@ static int oa_tc6_mdiobus_register(struct oa_tc6 *tc6) static void oa_tc6_mdiobus_unregister(struct oa_tc6 *tc6) { mdiobus_unregister(tc6->mdiobus); + if (tc6->quirk_flags & OA_TC6_PHY_INT) + oa_tc6_phy_irq_teardown(tc6); mdiobus_free(tc6->mdiobus); } =20 @@ -810,6 +943,17 @@ static int oa_tc6_process_extended_status(struct oa_tc= 6 *tc6) return ret; } =20 + /* Dispatch the PHY interrupt to phylib via the nested virtual IRQ so + * the PHY driver reads and acknowledges its status. This is deferred + * to a workqueue rather than dispatched synchronously here, since + * phy_interrupt() takes phydev->lock and PHY handle_interrupt() issues + * synchronous SPI control transfers, which would otherwise block this + * thread. + */ + if ((tc6->quirk_flags & OA_TC6_PHY_INT) && + FIELD_GET(OA_TC6_STATUS0_PHY_INT, value)) + schedule_work(&tc6->phy_irq_work); + if (FIELD_GET(OA_TC6_STATUS0_RX_BUFFER_OVERFLOW_ERROR, value)) { oa_tc6_look_for_new_frame(tc6); net_err_ratelimited("%s: Receive buffer overflow error\n", @@ -1468,6 +1612,7 @@ struct oa_tc6 *oa_tc6_init(struct spi_device *spi, st= ruct net_device *netdev, tc6->spi =3D spi; tc6->netdev =3D netdev; SET_NETDEV_DEV(netdev, &spi->dev); + mutex_init(&tc6->phy_irq_lock); mutex_init(&tc6->spi_ctrl_lock); spin_lock_init(&tc6->tx_skb_lock); =20 diff --git a/include/linux/oa_tc6.h b/include/linux/oa_tc6.h index 27f652d4920b..1c8cc263c5e5 100644 --- a/include/linux/oa_tc6.h +++ b/include/linux/oa_tc6.h @@ -30,6 +30,7 @@ =20 /* Status Register #0 */ #define OA_TC6_REG_STATUS0 0x0008 +#define OA_TC6_STATUS0_PHY_INT BIT(7) #define OA_TC6_STATUS0_RESETC BIT(6) /* Reset Complete */ #define OA_TC6_STATUS0_HEADER_ERROR BIT(5) #define OA_TC6_STATUS0_LOSS_OF_FRAME_ERROR BIT(4) @@ -43,6 +44,7 @@ =20 /* Interrupt Mask Register #0 */ #define OA_TC6_REG_INT_MASK0 0x000C +#define OA_TC6_INT_MASK0_PHY_INT_MASK BIT(7) #define OA_TC6_INT_MASK0_HEADER_ERR_MASK BIT(5) #define OA_TC6_INT_MASK0_LOSS_OF_FRAME_ERR_MASK BIT(4) #define OA_TC6_INT_MASK0_RX_BUFFER_OVERFLOW_ERR_MASK BIT(3) @@ -68,6 +70,7 @@ struct oa_tc6; =20 enum oa_tc6_quirk_flag { OA_TC6_BROKEN_PHY =3D BIT(0), + OA_TC6_PHY_INT =3D BIT(1), }; =20 struct oa_tc6_quirks { --=20 2.43.0 From nobody Thu Sep 24 23:33:27 2026 Received: from esa.microchip.iphmx.com (esa.microchip.iphmx.com [68.232.154.123]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 64FF93BF67A; Fri, 18 Sep 2026 14:33:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=68.232.154.123 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789742007; cv=none; b=Ekgn+hVm/AC0QgOEQm5u7o44c1reUDnKrl1G2lDI+3FxETJ1rEhOEDnb6Z23Yt05YlQFxoqWu8qF2DFnNcHEsLlGjC35NI1mNuMVYc1E/aqAZ4YRzvT1fV5mz15B8OKIAM4ahIZuqa4c+kS/A5Y6ApvvTclTYH7uKafyvcF6IKE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789742007; c=relaxed/simple; bh=NCowSd3P7qx8s6nC/FhxgE0HdwSDbaiO8q8/eY2PSjg=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=XTSVxa/FHKThM66Ie2D1SpjVzposJB32PcmRheSu+VChDQNDFchFu4vgjcL3rle/if0659VdWp3s3FgiRzwJ6luNq++x5GzIbAWkh8n0YCokJhMriZj83hGHS9Jyv4YKCYsO2SI1p9gpf4o41v8BimAwClrVffR+teITJ46WYjA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=microchip.com; spf=pass smtp.mailfrom=microchip.com; dkim=pass (2048-bit key) header.d=microchip.com header.i=@microchip.com header.b=VtnZUJPO; arc=none smtp.client-ip=68.232.154.123 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=microchip.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=microchip.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=microchip.com header.i=@microchip.com header.b="VtnZUJPO" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1789742005; x=1821278005; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=NCowSd3P7qx8s6nC/FhxgE0HdwSDbaiO8q8/eY2PSjg=; b=VtnZUJPOdUJfXzv6f3yylC5N12skCM/tO+lluqCsv16oBznTSunAVUpK TYwjJw+B++vZ0HCrACO1hLeV8TuvnAiAq9mHFkKv1g5p7QYOLEiIQi2p6 mBkHD+uDkgIxAKRMB7ujA8Qq6LcFqujXg0Wz5cUaLy/HxJYB0/wBZBfQ8 zjRxnmp5luLDUJbfXvZywRgvwTjk+6OZxvQ9yvfBQfZyBMHxsT/K5svoX ib+rOpNeFjsxFBc1IrZ36B+Kc7198IViZkFdL7SLFu5fDB/iLuFvGSbrm GxD04J65rjeMJxfoko5npcBcV38Ek3oC6LkU2TaMs4dfyLkeWlAnONKYI g==; X-CSE-ConnectionGUID: xUPNpqYGQCePtL1y3X+2eA== X-CSE-MsgGUID: AmliRLZhQAa/UoRfTz2lEA== X-IronPort-AV: E=Sophos;i="6.27,109,1787036400"; d="scan'208";a="64127951" X-Amp-Result: SKIPPED(no attachment in message) Received: from unknown (HELO email.microchip.com) ([170.129.1.10]) by esa2.microchip.iphmx.com with ESMTP/TLS/ECDHE-RSA-AES128-GCM-SHA256; 18 Sep 2026 07:33:24 -0700 Received: from chn-vm-ex01.mchp-main.com (10.10.85.143) by chn-vm-ex02.mchp-main.com (10.10.85.144) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.58; Fri, 18 Sep 2026 07:33:24 -0700 Received: from che-ll-i17164.microchip.com (10.10.85.11) by chn-vm-ex01.mchp-main.com (10.10.85.143) with Microsoft SMTP Server id 15.1.2507.58 via Frontend Transport; Fri, 18 Sep 2026 07:33:20 -0700 From: Parthiban Veerasooran To: , , , , , , CC: , , , , Parthiban Veerasooran Subject: [PATCH net-next v3 3/4] microchip: lan865x: enable PHY interrupt via virtual IRQ Date: Fri, 18 Sep 2026 20:03:01 +0530 Message-ID: <20260918143302.76909-4-parthiban.veerasooran@microchip.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260918143302.76909-1-parthiban.veerasooran@microchip.com> References: <20260918143302.76909-1-parthiban.veerasooran@microchip.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The LAN865X integrates the PHY directly into the MAC-PHY SPI device. The PHY has no dedicated interrupt line; its interrupt is always delivered as the PHYINT bit in STATUS0. Pass the OA_TC6_PHY_INT quirk flag to oa_tc6_init() to enable the virtual IRQ infrastructure. This lets phylib operate in interrupt mode and drives the PHY driver's config_intr/handle_interrupt callbacks for the LAN865X internal PHY. This completes the collision-detection fix started in "net: phy: microchip_t1s: fix collision detection on PLCA status change"; without this patch (and its prerequisite, "net: ethernet: oa_tc6: deliver the PHY interrupt to phylib"), LAN865X stays on that commit's static CDEN fallback instead of tracking PLCA transitions dynamically. lan865x_revb_fixup_registers[] does not program COL_DET_CTRL0 (0x0087), so CDEN correctness relies on that bit's hardware reset default together with lan86xx_handle_interrupt() tracking every subsequent PLCA transition via the PSTC interrupt this patch enables. Fixes: 78341049fbcd ("net: phy: microchip_t1s: configure collision detectio= n based on PLCA mode") Signed-off-by: Parthiban Veerasooran --- drivers/net/ethernet/microchip/lan865x/lan865x.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/microchip/lan865x/lan865x.c b/drivers/net= /ethernet/microchip/lan865x/lan865x.c index 26a2761332a5..043a3dc3f965 100644 --- a/drivers/net/ethernet/microchip/lan865x/lan865x.c +++ b/drivers/net/ethernet/microchip/lan865x/lan865x.c @@ -332,6 +332,7 @@ static const struct net_device_ops lan865x_netdev_ops = =3D { =20 static int lan865x_probe(struct spi_device *spi) { + struct oa_tc6_quirks tc6_quirks =3D {}; struct net_device *netdev; struct lan865x_priv *priv; int ret; @@ -346,7 +347,8 @@ static int lan865x_probe(struct spi_device *spi) spi_set_drvdata(spi, priv); INIT_WORK(&priv->multicast_work, lan865x_multicast_work_handler); =20 - priv->tc6 =3D oa_tc6_init(spi, netdev, NULL); + tc6_quirks.quirk_flags =3D OA_TC6_PHY_INT; + priv->tc6 =3D oa_tc6_init(spi, netdev, &tc6_quirks); if (!priv->tc6) { ret =3D -ENODEV; goto free_netdev; --=20 2.43.0 From nobody Thu Sep 24 23:33:27 2026 Received: from esa.microchip.iphmx.com (esa.microchip.iphmx.com [68.232.154.123]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0E1923BF67A; Fri, 18 Sep 2026 14:33:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=68.232.154.123 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789742012; cv=none; b=oC6RbGoBhQQGpOhzmk2D9RCcoxzrGXKgYHCZ5Ire5Y7RaQ6H6oF+TzYsHJF92/Q+Kgm7jtfLwww0R6aPABhtOqF1GzLkU29GkMObnbpVMCR3yilu7ksB/ePpgznUXpHMsHAO1m/pAfkCUnfkAoadzXpcNB7/QxIHkQXAQ3amGUA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789742012; c=relaxed/simple; bh=CEtPt1OIVJcWvrM0vYC4+5MnARffVyTm+wgu61bIFE4=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=FuiX5YgylO6rHJac7zdXA1QM+h1d6ydcmTuw4WrmafS8EeIaNrc4w0ffUEcVx0LxtpQCpuaFRegHcHE5SRnrTHnwiII9frd1MWtlo+FF2iZB5CLveTrEkonQF1t44qwlDh9N/R7l9GkaJYRmdqz/tIMudX8w0hUAXVjwtUEUx3k= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=microchip.com; spf=pass smtp.mailfrom=microchip.com; dkim=pass (2048-bit key) header.d=microchip.com header.i=@microchip.com header.b=b6lbPAYz; arc=none smtp.client-ip=68.232.154.123 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=microchip.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=microchip.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=microchip.com header.i=@microchip.com header.b="b6lbPAYz" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1789742010; x=1821278010; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=CEtPt1OIVJcWvrM0vYC4+5MnARffVyTm+wgu61bIFE4=; b=b6lbPAYzKvOz5cNCYeivfLiw3vy7na6BWQkdLnUkhTqefoddZORftqgb 4sRrKo5ttpeQhJgrECThCU3ELRIdrz63/U5IhmqrhR+FnPbzJjx3/DiEw YxxzUBx2/FvkSt1Cb3fuSYIpwTU/cC4/61A/SII6758q0OPK8/b3yz4tg aVCTNgco1KZUzhKbaYbbjdHzrFyGB15OfvHhhbuF+3tm97FSH2J3NfMOW yzbnW5uRndESNzAC0JVgmUR3snAPlOPA9xRWA0YW1hFgkI+bwGvJ3zueC ivMM2ysEpHteElBcUo4s8OMYyNREASJhZmIKTlWhyD+fQCVsb0gteboj8 w==; X-CSE-ConnectionGUID: 1HRGPZFjQ6mjKILVpT+Pbw== X-CSE-MsgGUID: EhJJPUtZRmC8+L+b5RRXRw== X-IronPort-AV: E=Sophos;i="6.27,109,1787036400"; d="scan'208";a="62883842" X-Amp-Result: SKIPPED(no attachment in message) Received: from unknown (HELO email.microchip.com) ([170.129.1.10]) by esa4.microchip.iphmx.com with ESMTP/TLS/ECDHE-RSA-AES128-GCM-SHA256; 18 Sep 2026 07:33:29 -0700 Received: from chn-vm-ex01.mchp-main.com (10.10.85.143) by chn-vm-ex02.mchp-main.com (10.10.85.144) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.58; Fri, 18 Sep 2026 07:33:28 -0700 Received: from che-ll-i17164.microchip.com (10.10.85.11) by chn-vm-ex01.mchp-main.com (10.10.85.143) with Microsoft SMTP Server id 15.1.2507.58 via Frontend Transport; Fri, 18 Sep 2026 07:33:24 -0700 From: Parthiban Veerasooran To: , , , , , , CC: , , , , Parthiban Veerasooran Subject: [PATCH net-next v3 4/4] net: phy: microchip_t1s: fix collision detection for LAN867X Rev.D0 Date: Fri, 18 Sep 2026 20:03:02 +0530 Message-ID: <20260918143302.76909-5-parthiban.veerasooran@microchip.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260918143302.76909-1-parthiban.veerasooran@microchip.com> References: <20260918143302.76909-1-parthiban.veerasooran@microchip.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" LAN867X Rev.D0 adds a Collision Counting and MAC Forwarding Control field (CCMFC, bits 10:9) in COL_DET_CTRL0 (0x0087). Set to the OA default (0x1), the hardware autonomously gates collision forwarding based on live PLCA_Status, removing the delay a software-driven CDEN toggle had on older revisions. The PSTC interrupt handler for Rev.D0 therefore only needs to update the link status selection on each PLCA transition. Configure CCMFC to the OA default in lan867x_revd0_config_init(). Add lan867x_revd0_handle_interrupt() for two events: Link Status Change triggers the phylib state machine; PLCA Status Change re-reads the PLCA config and updates the link status selection. Rev.D0 can also be configured (PRSCTL1, 0x0035, bit 10) to autonomously fall back to CSMA/CD when no BEACON is seen. When that's active, the PHY's own hardware transition already handles CSMA/CD correctly, so driving link status from PLCA_Status reports nothing meaningful. Force the semaphore (forced-active) source whenever fallback is enabled; only when fallback is disabled - the PHY stays pinned to PLCA mode - does tracking PLCA_Status serve its purpose. Wire up .config_intr/.handle_interrupt for Rev.D0 via a dedicated lan867x_revd0_config_intr(), reusing the STS1/IMSK1 helpers from the other LAN86XX PHYs. Fixes: e7e756779afa ("net: phy: microchip_t1s: add support for Microchip LA= N867X Rev.D0 PHY") Signed-off-by: Parthiban Veerasooran --- drivers/net/phy/microchip_t1s.c | 169 +++++++++++++++++++++++++++++++- 1 file changed, 164 insertions(+), 5 deletions(-) diff --git a/drivers/net/phy/microchip_t1s.c b/drivers/net/phy/microchip_t1= s.c index 3333e4801aae..a69ad6ce1d8a 100644 --- a/drivers/net/phy/microchip_t1s.c +++ b/drivers/net/phy/microchip_t1s.c @@ -20,7 +20,8 @@ =20 #define LAN867X_REG_STS2 0x0019 =20 -#define LAN867x_RESET_COMPLETE_STS BIT(11) +#define LAN86XX_STS1_LINK_STS_CHANGED BIT(13) +#define LAN867x_RESET_COMPLETE_STS BIT(11) =20 #define LAN865X_REG_CFGPARAM_ADDR 0x00D8 #define LAN865X_REG_CFGPARAM_DATA 0x00D9 @@ -40,6 +41,17 @@ #define COL_DET_CTRL0_ENABLE_BIT_MASK BIT(15) #define COL_DET_ENABLE BIT(15) #define COL_DET_DISABLE 0x0000 +#define COL_DET_CTRL0_CCMFC_MASK GENMASK(10, 9) +/* OA default: collisions gated by PLCA_Status in hardware */ +#define COL_DET_CTRL0_CCMFC_OA_DEFAULT BIT(9) + +/* PLCA Reconciliation Sublayer Control 1 Register (PRSCTL1). Bit 10 + * controls whether the PHY autonomously falls back to CSMA/CD mode when + * no BEACON is observed while PLCA is enabled, versus staying pinned to + * PLCA mode regardless of BEACON presence. + */ +#define LAN867X_REG_PRSCTL1 0x0035 +#define PRSCTL1_PLCA_FALLB_TO_CSMACD_EN BIT(10) =20 /* LAN8670/1/2 Rev.D0 Link Status Selection Register */ #define LAN867X_REG_LINK_STATUS_CTRL 0x0012 @@ -438,6 +450,40 @@ static int lan867x_revd0_link_active_selection(struct = phy_device *phydev, LAN867X_REG_LINK_STATUS_CTRL, value); } =20 +static int lan867x_revd0_fallback_to_csmacd(struct phy_device *phydev) +{ + int ret; + + ret =3D phy_read_mmd(phydev, MDIO_MMD_VEND2, LAN867X_REG_PRSCTL1); + if (ret < 0) + return ret; + + return !!(ret & PRSCTL1_PLCA_FALLB_TO_CSMACD_EN); +} + +/* When the PHY autonomously falls back to CSMA/CD once BEACONs stop (PRSC= TL1 + * bit 10 set), the hardware fallback already provides correct CSMA/CD + * operation; selecting link status from PLCA_STATUS in that case reports + * nothing meaningful, since the PHY may already be running CSMA/CD regard= less + * of the stale PLCA_STATUS value. Force the semaphore (forced-active) sou= rce + * in that case instead. Only when fallback is disabled - the PHY is pinned + * to PLCA mode - does tracking PLCA_STATUS serve its intended purpose. + */ +static int lan867x_revd0_update_link_selection(struct phy_device *phydev, + bool plca_operational) +{ + int fallback; + + fallback =3D lan867x_revd0_fallback_to_csmacd(phydev); + if (fallback < 0) + return fallback; + + if (fallback) + return lan867x_revd0_link_active_selection(phydev, false); + + return lan867x_revd0_link_active_selection(phydev, plca_operational); +} + /* As per LAN8650/1 Rev.B0/B1 AN1760 (Revision F (DS60001760G - June 2024)= ) and * LAN8670/1/2 Rev.C1/C2 AN1699 (Revision E (DS60001699F - June 2024)), un= der * normal operation, the device should be operated in PLCA mode. Disabling @@ -446,6 +492,11 @@ static int lan867x_revd0_link_active_selection(struct = phy_device *phydev, * distortion cause poor signal quality. Collision detection must be re-en= abled * if the device is configured to operate in CSMA/CD mode. * + * LAN867X Rev.D0 has autonomous collision detection gating via CCMFC and + * does not toggle CDEN in the interrupt handler. CDEN remains permanently + * enabled in config_init(), so no software-driven CDEN toggling is needed + * here. + * * AN1760: https://www.microchip.com/en-us/application-notes/an1760 * AN1699: https://www.microchip.com/en-us/application-notes/an1699 */ @@ -454,9 +505,12 @@ static int lan86xx_plca_set_cfg(struct phy_device *phy= dev, { int ret; =20 - /* Link status selection must be configured for LAN8670/1/2 Rev.D0 */ - if (phydev->phy_id =3D=3D PHY_ID_LAN867X_REVD0) { - ret =3D lan867x_revd0_link_active_selection(phydev, + /* Link status selection must be configured for LAN8670/1/2 Rev.D0. + * Only update link status selection if enabled is explicitly specified + * (not -1, which means "don't change"). + */ + if (phydev->phy_id =3D=3D PHY_ID_LAN867X_REVD0 && plca_cfg->enabled !=3D = -1) { + ret =3D lan867x_revd0_update_link_selection(phydev, plca_cfg->enabled); if (ret) return ret; @@ -472,8 +526,12 @@ static int lan86xx_plca_set_cfg(struct phy_device *phy= dev, * here as a baseline on every ethtool PLCA reconfiguration. The * limitation is that autonomous PLCA mode transitions between ethtool * reconfigurations are not tracked on such boards. + * + * LAN867X Rev.D0 has autonomous collision detection via CCMFC, so skip + * the software CDEN toggling for that revision. */ - if (phy_interrupt_is_valid(phydev)) + if (phy_interrupt_is_valid(phydev) || + phydev->phy_id =3D=3D PHY_ID_LAN867X_REVD0) return 0; =20 if (plca_cfg->enabled > 0) @@ -507,6 +565,20 @@ static int lan867x_revd0_config_init(struct phy_device= *phydev) return ret; } =20 + /* AN1699: Configure CCMFC (Collision Counting and MAC Forwarding + * Control) to OA default (0x1) so that the hardware autonomously gates + * collision forwarding to the MAC based on the live PLCA_Status: + * collisions are neither counted nor forwarded when PLCA_Status is OK, + * and are counted/forwarded when not OK. This eliminates the need for + * software-driven CDEN toggling. CDEN is enabled by default and remains + * permanently enabled for Rev.D0. + */ + ret =3D phy_modify_mmd(phydev, MDIO_MMD_VEND2, LAN86XX_REG_COL_DET_CTRL0, + COL_DET_CTRL0_CCMFC_MASK, + COL_DET_CTRL0_CCMFC_OA_DEFAULT); + if (ret) + return ret; + /* Initially the PHY will be in CSMA/CD mode by default. So it is * required to set the link always active as it doesn't support * autoneg. @@ -634,6 +706,91 @@ static irqreturn_t lan86xx_handle_interrupt(struct phy= _device *phydev) return ret_irq; } =20 +static int lan867x_revd0_config_intr(struct phy_device *phydev) +{ + u16 mask =3D LAN86XX_STS1_PLCA_STS_CHANGED | + LAN86XX_STS1_LINK_STS_CHANGED; + struct phy_plca_cfg plca_cfg; + int sts1, ret; + + if (phydev->interrupts =3D=3D PHY_INTERRUPT_ENABLED) { + /* Read to clear any pending status before enabling. */ + sts1 =3D lan86xx_read_clear_sts1(phydev); + if (sts1 < 0) + return sts1; + + if (sts1 & LAN86XX_STS1_LINK_STS_CHANGED) + phy_trigger_machine(phydev); + + /* STS1 may have cleared a pending PSTC while masked, and a + * missed PSTC leaves no trace to key off, so unconditionally + * resync the link-status-selection source from the current + * PLCA enable state and fallback configuration. CDEN is + * never touched here - see lan867x_revd0_config_init(). + */ + ret =3D genphy_c45_plca_get_cfg(phydev, &plca_cfg); + if (ret < 0) + return ret; + + ret =3D lan867x_revd0_update_link_selection(phydev, + plca_cfg.enabled); + if (ret < 0) + return ret; + + return lan86xx_set_intr_mask(phydev, mask, true); + } + + ret =3D lan86xx_set_intr_mask(phydev, mask, false); + if (ret) + return ret; + + /* Read to clear any pending status after disabling. */ + ret =3D lan86xx_read_clear_sts1(phydev); + return ret < 0 ? ret : 0; +} + +static irqreturn_t lan867x_revd0_handle_interrupt(struct phy_device *phyde= v) +{ + irqreturn_t ret_irq =3D IRQ_NONE; + struct phy_plca_cfg plca_cfg; + int sts1, ret; + + sts1 =3D lan86xx_read_clear_sts1(phydev); + if (sts1 < 0) { + phy_error(phydev); + return IRQ_NONE; + } + + if (sts1 & LAN86XX_STS1_LINK_STS_CHANGED) { + phy_trigger_machine(phydev); + ret_irq =3D IRQ_HANDLED; + } + + if (sts1 & LAN86XX_STS1_PLCA_STS_CHANGED) { + ret =3D genphy_c45_plca_get_cfg(phydev, &plca_cfg); + if (ret < 0) { + phy_error(phydev); + return IRQ_NONE; + } + + /* lan867x_revd0_update_link_selection() drives the selection + * source from the configured PLCA enable state, forcing + * semaphore mode instead whenever autonomous fallback to + * CSMA/CD is configured (see PRSCTL1 above). + */ + ret =3D lan867x_revd0_update_link_selection(phydev, + plca_cfg.enabled); + if (ret < 0) { + phy_error(phydev); + return IRQ_NONE; + } + + ret_irq =3D IRQ_HANDLED; + } + + return ret_irq; +} + static struct phy_driver microchip_t1s_driver[] =3D { { PHY_ID_MATCH_EXACT(PHY_ID_LAN867X_REVB1), @@ -676,6 +833,8 @@ static struct phy_driver microchip_t1s_driver[] =3D { .name =3D "LAN867X Rev.D0", .features =3D PHY_BASIC_T1S_P2MP_FEATURES, .config_init =3D lan867x_revd0_config_init, + .config_intr =3D lan867x_revd0_config_intr, + .handle_interrupt =3D lan867x_revd0_handle_interrupt, .get_plca_cfg =3D genphy_c45_plca_get_cfg, .set_plca_cfg =3D lan86xx_plca_set_cfg, .get_plca_status =3D genphy_c45_plca_get_status, --=20 2.43.0