Message ID | 20240118104341.10832-1-andre.werner@systec-electronic.com |
---|---|
State | New |
Headers |
Return-Path: <linux-kernel+bounces-30012-ouuuleilei=gmail.com@vger.kernel.org> Delivered-To: ouuuleilei@gmail.com Received: by 2002:a05:7301:2bc4:b0:101:a8e8:374 with SMTP id hx4csp256116dyb; Thu, 18 Jan 2024 02:50:52 -0800 (PST) X-Google-Smtp-Source: AGHT+IFPZah551OZJMd6m0dwTWFcneAl4h++NvKQBkLqA2G7YYLUuDvSjOIDkZZH1zQCkZkLdIDG X-Received: by 2002:a05:6a20:7012:b0:19a:3647:7185 with SMTP id h18-20020a056a20701200b0019a36477185mr458773pza.61.1705575052293; Thu, 18 Jan 2024 02:50:52 -0800 (PST) Received: from sy.mirrors.kernel.org (sy.mirrors.kernel.org. [2604:1380:40f1:3f00::1]) by mx.google.com with ESMTPS id l10-20020a170902f68a00b001d703a78940si1222175plg.257.2024.01.18.02.50.51 for <ouuuleilei@gmail.com> (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 18 Jan 2024 02:50:52 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel+bounces-30012-ouuuleilei=gmail.com@vger.kernel.org designates 2604:1380:40f1:3f00::1 as permitted sender) client-ip=2604:1380:40f1:3f00::1; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@systec-electronic.com header.s=B34D3B04-5DC7-11EE-83E3-4D8CAB78E8CD header.b=jweTdpNd; arc=fail (body hash mismatch); spf=pass (google.com: domain of linux-kernel+bounces-30012-ouuuleilei=gmail.com@vger.kernel.org designates 2604:1380:40f1:3f00::1 as permitted sender) smtp.mailfrom="linux-kernel+bounces-30012-ouuuleilei=gmail.com@vger.kernel.org" Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by sy.mirrors.kernel.org (Postfix) with ESMTPS id 63C9FB23D82 for <ouuuleilei@gmail.com>; Thu, 18 Jan 2024 10:50:44 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 38136241E9; Thu, 18 Jan 2024 10:50:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=systec-electronic.com header.i=@systec-electronic.com header.b="jweTdpNd" Received: from mail.systec-electronic.com (mail.systec-electronic.com [77.220.239.22]) (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 6218022F06; Thu, 18 Jan 2024 10:50:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=77.220.239.22 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1705575022; cv=none; b=uePK3Mg5xV6eRNlUYBMi1bqFR9C5VFBC6pLfmBDqHu+9rB+UudS+cwEQMx45l+YSeNI255IKJtlydtymN4hJOk4p9j0G9l1K3uDmY17KPloki20Ri5wQZ7J9NcvpvGwJ4/bWhai8Q0tUUWLqPVgTzQUdtGWEr5cLlSqo5fACyqU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1705575022; c=relaxed/simple; bh=hDDXvdoNu8vOBXyjictCiicouiBYP0yBck+Nijapc7A=; h=Received:Received:Received:DKIM-Filter:DKIM-Signature: X-Virus-Scanned:Received:Received:From:To:Cc:Subject:Date: Message-ID:X-Mailer:MIME-Version:Content-Transfer-Encoding; b=kTc/bUcpr5BBREXWoSNSZkHkIt6CwWiEMhA88OmVuBYdNIyWm0Av6aVMHsEtUHDrhLX/Sv0tDV6iQca/oC5OY+eDniuIQ+LzWrxZUTEv7H0vo5r3z+aN+igEnG0XOentxXCDG38id6EDkEMEaJpIEgePR7TRXQCtnW8eOSUqEKk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=systec-electronic.com; spf=pass smtp.mailfrom=systec-electronic.com; dkim=pass (2048-bit key) header.d=systec-electronic.com header.i=@systec-electronic.com header.b=jweTdpNd; arc=none smtp.client-ip=77.220.239.22 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=systec-electronic.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=systec-electronic.com Received: from localhost (localhost.localdomain [127.0.0.1]) by mail.systec-electronic.com (Postfix) with ESMTP id 0935B9400107; Thu, 18 Jan 2024 11:43:46 +0100 (CET) Received: from mail.systec-electronic.com ([127.0.0.1]) by localhost (mail.systec-electronic.com [127.0.0.1]) (amavis, port 10032) with ESMTP id kmPasBcjk7Jn; Thu, 18 Jan 2024 11:43:45 +0100 (CET) Received: from localhost (localhost.localdomain [127.0.0.1]) by mail.systec-electronic.com (Postfix) with ESMTP id D50E0941A5CF; Thu, 18 Jan 2024 11:43:45 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.10.3 mail.systec-electronic.com D50E0941A5CF DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=systec-electronic.com; s=B34D3B04-5DC7-11EE-83E3-4D8CAB78E8CD; t=1705574625; bh=WxeGf6vaj1r+8COYX0/cdjukb0tx7B8JYxC+WAtqHa0=; h=From:To:Date:Message-ID:MIME-Version; b=jweTdpNdDn+ajwP/fyZNxaw16T2I+A0f+HsXVCiLa0RmlDN5BV7ZKJJEojjIdF2i/ 3h9eSv7UAOOQmPSeCmz37EClt4Urbt8H/JKY8cLjL6+yxMuzBZ1aVXG+ZZ0cdgC7X+ HvX0n+m0UtTlSq17Jb3IpZUUDWGFv+TnVmXdZRf+b7XCXvkN9EoYRRfsACnVJoIaUV +nblJVNJQ6QxuQ1GR0yt4WV0E4fjY8b279Gpfe1CYOSX4yUV0AuZ7pMpycUFf3adN0 t5xsOZ8fzm/GJIPl8CB56tTlmm39Q8QzY+93gLz99AT68jFU6J+mVbB6JyObmCqyw0 kgSv2fffF1GYQ== X-Virus-Scanned: amavis at systec-electronic.com Received: from mail.systec-electronic.com ([127.0.0.1]) by localhost (mail.systec-electronic.com [127.0.0.1]) (amavis, port 10026) with ESMTP id km2frKiTSdy9; Thu, 18 Jan 2024 11:43:45 +0100 (CET) Received: from ws-565760.systec.local (unknown [212.185.67.148]) by mail.systec-electronic.com (Postfix) with ESMTPSA id 822909400107; Thu, 18 Jan 2024 11:43:45 +0100 (CET) From: Andre Werner <andre.werner@systec-electronic.com> To: andrew@lunn.ch, hkallweit1@gmail.com, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com Cc: linux@armlinux.org.uk, netdev@vger.kernel.org, linux-kernel@vger.kernel.org, Andre Werner <andre.werner@systec-electronic.com> Subject: [PATCH] net: phy: adin1100: Fix nullptr exception for phy interrupts Date: Thu, 18 Jan 2024 11:43:41 +0100 Message-ID: <20240118104341.10832-1-andre.werner@systec-electronic.com> X-Mailer: git-send-email 2.43.0 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: <linux-kernel.vger.kernel.org> List-Subscribe: <mailto:linux-kernel+subscribe@vger.kernel.org> List-Unsubscribe: <mailto:linux-kernel+unsubscribe@vger.kernel.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1788425065600670850 X-GMAIL-MSGID: 1788425065600670850 |
Series |
net: phy: adin1100: Fix nullptr exception for phy interrupts
|
|
Commit Message
Andre Werner
Jan. 18, 2024, 10:43 a.m. UTC
If using ADIN1100 as an external phy, e.g. in combination with
"smsc95xx", we ran into nullptr exception by creating a link.
In our case the "smsc95xx" does not check for an available interrupt handler
on external phy driver to use poll instead of interrupts if no handler is
available. So we decide to implement a small handler in the phy driver
to support other MACs as well.
I update the driver to add an interrupt handler because libphy
does not check if their is a interrupt handler available either.
There are several interrupts maskable at the phy, but only link change interrupts
are handled by the driver yet.
We tested the combination "smsc95xx" and "adin1100" with Linux Kernel 6.69
and Linux Kernel 6.1.0, respectively.
Signed-off-by: Andre Werner <andre.werner@systec-electronic.com>
---
drivers/net/phy/adin1100.c | 58 ++++++++++++++++++++++++++++++++++++++
1 file changed, 58 insertions(+)
Comments
On Thu, Jan 18, 2024 at 11:43:41AM +0100, Andre Werner wrote: > If using ADIN1100 as an external phy, e.g. in combination with > "smsc95xx", we ran into nullptr exception by creating a link. > > In our case the "smsc95xx" does not check for an available interrupt handler > on external phy driver to use poll instead of interrupts if no handler is > available. So we decide to implement a small handler in the phy driver > to support other MACs as well. > > I update the driver to add an interrupt handler because libphy > does not check if their is a interrupt handler available either. > > There are several interrupts maskable at the phy, but only link change interrupts > are handled by the driver yet. > > We tested the combination "smsc95xx" and "adin1100" with Linux Kernel 6.6.9 > and Linux Kernel 6.1.0, respectively. Hi Andre A few different things.... Please could you give more details of the null pointer exception. phylib should test if the needed methods have been implemented in the PHY driver, and not tried to use interrupts when they are missing. It should of polled the PHY. So i would like to understand what went wrong. Maybe we have a phylib core bug we should be fixing. Or a bug in the smsc95xx driver. Please take a read of https://www.kernel.org/doc/html/latest/process/maintainer-netdev.html Patches like this should be against net-next, not 6.6.9 etc. Also, net-next is currently closed due to the merge window being open. Its fine to post patches, but please mark them RFC until the merge window is over. The patch itself looks O.K, but i would make the commit message more formal. You can add additional comments under the --- which will not become part of the git history. Andrew
On Thu, Jan 18, 2024 at 06:36:16PM +0100, Heiner Kallweit wrote: > On 18.01.2024 17:53, Andrew Lunn wrote: > > On Thu, Jan 18, 2024 at 11:43:41AM +0100, Andre Werner wrote: > >> If using ADIN1100 as an external phy, e.g. in combination with > >> "smsc95xx", we ran into nullptr exception by creating a link. > >> > >> In our case the "smsc95xx" does not check for an available interrupt handler > >> on external phy driver to use poll instead of interrupts if no handler is > >> available. So we decide to implement a small handler in the phy driver > >> to support other MACs as well. > >> > >> I update the driver to add an interrupt handler because libphy > >> does not check if their is a interrupt handler available either. > >> > >> There are several interrupts maskable at the phy, but only link change interrupts > >> are handled by the driver yet. > >> > >> We tested the combination "smsc95xx" and "adin1100" with Linux Kernel 6.6.9 > >> and Linux Kernel 6.1.0, respectively. > > > > Hi Andre > > > > A few different things.... > > > > Please could you give more details of the null pointer > > exception. phylib should test if the needed methods have been > > implemented in the PHY driver, and not tried to use interrupts when > > they are missing. It should of polled the PHY. So i would like to > > understand what went wrong. Maybe we have a phylib core bug we should > > be fixing. Or a bug in the smsc95xx driver. > > > Seems to be a bug in smsc95xx. The following is the relevant code piece. > > ret = mdiobus_register(pdata->mdiobus); > if (ret) { > netdev_err(dev->net, "Could not register MDIO bus\n"); > goto free_mdio; > } > > pdata->phydev = phy_find_first(pdata->mdiobus); > if (!pdata->phydev) { > netdev_err(dev->net, "no PHY found\n"); > ret = -ENODEV; > goto unregister_mdio; > } > > pdata->phydev->irq = phy_irq; > > The interrupt is set too late, after phy_probe(), where we have this: > > if (!phy_drv_supports_irq(phydrv) && phy_interrupt_is_valid(phydev)) > phydev->irq = PHY_POLL; > > So we would have two steps: > 1. Fix the smsc95xx bug (as the same issue could occur with another PHY type) Its not so nice to fix. Normally you would do something like: pdata->mdiobus->priv = dev; pdata->mdiobus->read = smsc95xx_mdiobus_read; pdata->mdiobus->write = smsc95xx_mdiobus_write; pdata->mdiobus->reset = smsc95xx_mdiobus_reset; pdata->mdiobus->name = "smsc95xx-mdiobus"; pdata->mdiobus->parent = &dev->udev->dev; snprintf(pdata->mdiobus->id, ARRAY_SIZE(pdata->mdiobus->id), "usb-%03d:%03d", dev->udev->bus->busnum, dev->udev->devnum); pdata->mdiobus->irq[X] = phy_irq; ret = mdiobus_register(pdata->mdiobus); By setting pdata->mdiobus->irq[X] before registering the PHY, the irq number gets passed to the phydev->irq very early on. If everything is O.K, interrupts are then used. However, because of the use of phy_find_first(), we have no idea what address on the bus the PHY is using. So we don't know which member of irq[] to set. Its not ideal, but one solution is to set them all. However, a better solution is to perform the validation again in phy_attach_direct(). Add a second: if (!phy_drv_supports_irq(phydrv) && phy_interrupt_is_valid(phydev)) phydev->irq = PHY_POLL; which will force phydev->irq back to polling. Andrew
On 18.01.2024 21:09, Andrew Lunn wrote: > On Thu, Jan 18, 2024 at 06:36:16PM +0100, Heiner Kallweit wrote: >> On 18.01.2024 17:53, Andrew Lunn wrote: >>> On Thu, Jan 18, 2024 at 11:43:41AM +0100, Andre Werner wrote: >>>> If using ADIN1100 as an external phy, e.g. in combination with >>>> "smsc95xx", we ran into nullptr exception by creating a link. >>>> >>>> In our case the "smsc95xx" does not check for an available interrupt handler >>>> on external phy driver to use poll instead of interrupts if no handler is >>>> available. So we decide to implement a small handler in the phy driver >>>> to support other MACs as well. >>>> >>>> I update the driver to add an interrupt handler because libphy >>>> does not check if their is a interrupt handler available either. >>>> >>>> There are several interrupts maskable at the phy, but only link change interrupts >>>> are handled by the driver yet. >>>> >>>> We tested the combination "smsc95xx" and "adin1100" with Linux Kernel 6.6.9 >>>> and Linux Kernel 6.1.0, respectively. >>> >>> Hi Andre >>> >>> A few different things.... >>> >>> Please could you give more details of the null pointer >>> exception. phylib should test if the needed methods have been >>> implemented in the PHY driver, and not tried to use interrupts when >>> they are missing. It should of polled the PHY. So i would like to >>> understand what went wrong. Maybe we have a phylib core bug we should >>> be fixing. Or a bug in the smsc95xx driver. >>> >> Seems to be a bug in smsc95xx. The following is the relevant code piece. >> >> ret = mdiobus_register(pdata->mdiobus); >> if (ret) { >> netdev_err(dev->net, "Could not register MDIO bus\n"); >> goto free_mdio; >> } >> >> pdata->phydev = phy_find_first(pdata->mdiobus); >> if (!pdata->phydev) { >> netdev_err(dev->net, "no PHY found\n"); >> ret = -ENODEV; >> goto unregister_mdio; >> } >> >> pdata->phydev->irq = phy_irq; >> >> The interrupt is set too late, after phy_probe(), where we have this: >> >> if (!phy_drv_supports_irq(phydrv) && phy_interrupt_is_valid(phydev)) >> phydev->irq = PHY_POLL; >> >> So we would have two steps: >> 1. Fix the smsc95xx bug (as the same issue could occur with another PHY type) > > Its not so nice to fix. > > Normally you would do something like: > > pdata->mdiobus->priv = dev; > pdata->mdiobus->read = smsc95xx_mdiobus_read; > pdata->mdiobus->write = smsc95xx_mdiobus_write; > pdata->mdiobus->reset = smsc95xx_mdiobus_reset; > pdata->mdiobus->name = "smsc95xx-mdiobus"; > pdata->mdiobus->parent = &dev->udev->dev; > > snprintf(pdata->mdiobus->id, ARRAY_SIZE(pdata->mdiobus->id), > "usb-%03d:%03d", dev->udev->bus->busnum, dev->udev->devnum); > > pdata->mdiobus->irq[X] = phy_irq; > > ret = mdiobus_register(pdata->mdiobus); > > By setting pdata->mdiobus->irq[X] before registering the PHY, the irq > number gets passed to the phydev->irq very early on. If everything is > O.K, interrupts are then used. > > However, because of the use of phy_find_first(), we have no idea what > address on the bus the PHY is using. So we don't know which member of > irq[] to set. Its not ideal, but one solution is to set them all. > > However, a better solution is to perform the validation again in > phy_attach_direct(). Add a second: > > if (!phy_drv_supports_irq(phydrv) && phy_interrupt_is_valid(phydev)) > phydev->irq = PHY_POLL; > This would save us here, but can't prevent that phydev->irq may be set even later. I think, ideally nobody should ever access phydev->irq directly. There should be a setter which performs the needed checks. But it may be a longer journey to make parts of struct phy_device private to phylib. > which will force phydev->irq back to polling. > > Andrew Heiner
On Thu, 18 Jan 2024, Russell King (Oracle) wrote: > In addition to Andrew's comments: > > On Thu, Jan 18, 2024 at 11:43:41AM +0100, Andre Werner wrote: >> +static int adin_config_intr(struct phy_device *phydev) >> +{ >> + int ret, regval; >> + >> + ret = adin_phy_ack_intr(phydev); >> + >> + if (ret) >> + return ret; >> + >> + regval = phy_read_mmd(phydev, MDIO_MMD_VEND2, ADIN_PHY_SUBSYS_IRQ_MASK); >> + if (regval < 0) >> + return regval; >> + >> + if (phydev->interrupts == PHY_INTERRUPT_ENABLED) >> + regval |= ADIN_LINK_STAT_CHNG_IRQ_EN; >> + else >> + regval &= ~ADIN_LINK_STAT_CHNG_IRQ_EN; >> + >> + ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, >> + ADIN_PHY_SUBSYS_IRQ_MASK, >> + regval); >> + return ret; > > u16 irq_mask; > > if (phydev->interrupts == PHY_INTERRUPT_ENABLED) > irq_mask = ADIN_LINK_STAT_CHNG_IRQ_EN; > else > irq_mask = 0; Unfortunately, I can not do this, because that phy ask for read-modify-write access to registers and some bits in this register are already set after reset and should not being modified. > > return phy_modify_mmd(phydev, MDIO_MMD_VEND2, > ADIN_PHY_SUBSYS_IRQ_MASK, > ADIN_LINK_STAT_CHNG_IRQ_EN, irq_mask); > >> +} >> + >> +static irqreturn_t adin_phy_handle_interrupt(struct phy_device *phydev) >> +{ >> + int irq_status; >> + >> + irq_status = phy_read_mmd(phydev, MDIO_MMD_VEND2, ADIN_PHY_SUBSYS_IRQ_STATUS); > > Probably want to wrap this - if you're going to bother wrapping your > phy_write_mmd() above because it overflows 80 columns, then please do > so consistently. Done. > > Thanks. > > -- > RMK's Patch system: https://www.armlinux.org.uk/developer/patches/ > FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last! >
On Thu, 18 Jan 2024, Heiner Kallweit wrote: > On 18.01.2024 21:09, Andrew Lunn wrote: >> On Thu, Jan 18, 2024 at 06:36:16PM +0100, Heiner Kallweit wrote: >>> On 18.01.2024 17:53, Andrew Lunn wrote: >>>> On Thu, Jan 18, 2024 at 11:43:41AM +0100, Andre Werner wrote: >>>>> If using ADIN1100 as an external phy, e.g. in combination with >>>>> "smsc95xx", we ran into nullptr exception by creating a link. >>>>> >>>>> In our case the "smsc95xx" does not check for an available interrupt handler >>>>> on external phy driver to use poll instead of interrupts if no handler is >>>>> available. So we decide to implement a small handler in the phy driver >>>>> to support other MACs as well. >>>>> >>>>> I update the driver to add an interrupt handler because libphy >>>>> does not check if their is a interrupt handler available either. >>>>> >>>>> There are several interrupts maskable at the phy, but only link change interrupts >>>>> are handled by the driver yet. >>>>> >>>>> We tested the combination "smsc95xx" and "adin1100" with Linux Kernel 6.6.9 >>>>> and Linux Kernel 6.1.0, respectively. >>>> >>>> Hi Andre >>>> >>>> A few different things.... >>>> >>>> Please could you give more details of the null pointer >>>> exception. phylib should test if the needed methods have been >>>> implemented in the PHY driver, and not tried to use interrupts when >>>> they are missing. It should of polled the PHY. So i would like to >>>> understand what went wrong. Maybe we have a phylib core bug we should >>>> be fixing. Or a bug in the smsc95xx driver. >>>> >>> Seems to be a bug in smsc95xx. The following is the relevant code piece. >>> >>> ret = mdiobus_register(pdata->mdiobus); >>> if (ret) { >>> netdev_err(dev->net, "Could not register MDIO bus\n"); >>> goto free_mdio; >>> } >>> >>> pdata->phydev = phy_find_first(pdata->mdiobus); >>> if (!pdata->phydev) { >>> netdev_err(dev->net, "no PHY found\n"); >>> ret = -ENODEV; >>> goto unregister_mdio; >>> } >>> >>> pdata->phydev->irq = phy_irq; >>> >>> The interrupt is set too late, after phy_probe(), where we have this: >>> >>> if (!phy_drv_supports_irq(phydrv) && phy_interrupt_is_valid(phydev)) >>> phydev->irq = PHY_POLL; >>> >>> So we would have two steps: >>> 1. Fix the smsc95xx bug (as the same issue could occur with another PHY type) >> >> Its not so nice to fix. >> >> Normally you would do something like: >> >> pdata->mdiobus->priv = dev; >> pdata->mdiobus->read = smsc95xx_mdiobus_read; >> pdata->mdiobus->write = smsc95xx_mdiobus_write; >> pdata->mdiobus->reset = smsc95xx_mdiobus_reset; >> pdata->mdiobus->name = "smsc95xx-mdiobus"; >> pdata->mdiobus->parent = &dev->udev->dev; >> >> snprintf(pdata->mdiobus->id, ARRAY_SIZE(pdata->mdiobus->id), >> "usb-%03d:%03d", dev->udev->bus->busnum, dev->udev->devnum); >> >> pdata->mdiobus->irq[X] = phy_irq; >> >> ret = mdiobus_register(pdata->mdiobus); >> >> By setting pdata->mdiobus->irq[X] before registering the PHY, the irq >> number gets passed to the phydev->irq very early on. If everything is >> O.K, interrupts are then used. >> >> However, because of the use of phy_find_first(), we have no idea what >> address on the bus the PHY is using. So we don't know which member of >> irq[] to set. Its not ideal, but one solution is to set them all. >> >> However, a better solution is to perform the validation again in >> phy_attach_direct(). Add a second: >> >> if (!phy_drv_supports_irq(phydrv) && phy_interrupt_is_valid(phydev)) >> phydev->irq = PHY_POLL; I add this check into phy_device.c-> phy_attach_direct as a work around for now. I will send a new patch set to net-next as suggested. >> > This would save us here, but can't prevent that phydev->irq may be set > even later. I think, ideally nobody should ever access phydev->irq directly. > There should be a setter which performs the needed checks. > But it may be a longer journey to make parts of struct phy_device private > to phylib. > >> which will force phydev->irq back to polling. >> >> Andrew > > Heiner > Regards, Andre
diff --git a/drivers/net/phy/adin1100.c b/drivers/net/phy/adin1100.c index 7619d6185801..ed8a7e6250cf 100644 --- a/drivers/net/phy/adin1100.c +++ b/drivers/net/phy/adin1100.c @@ -18,6 +18,12 @@ #define PHY_ID_ADIN1110 0x0283bc91 #define PHY_ID_ADIN2111 0x0283bca1 +#define ADIN_PHY_SUBSYS_IRQ_MASK 0x0021 +#define ADIN_LINK_STAT_CHNG_IRQ_EN BIT(1) + +#define ADIN_PHY_SUBSYS_IRQ_STATUS 0x0011 +#define ADIN_LINK_STAT_CHNG BIT(1) + #define ADIN_FORCED_MODE 0x8000 #define ADIN_FORCED_MODE_EN BIT(0) @@ -136,6 +142,56 @@ static int adin_config_aneg(struct phy_device *phydev) return genphy_c45_config_aneg(phydev); } +static int adin_phy_ack_intr(struct phy_device *phydev) +{ + /* Clear pending interrupts */ + int rc = phy_read_mmd(phydev, MDIO_MMD_VEND2, ADIN_PHY_SUBSYS_IRQ_STATUS); + + return rc < 0 ? rc : 0; +} + +static int adin_config_intr(struct phy_device *phydev) +{ + int ret, regval; + + ret = adin_phy_ack_intr(phydev); + + if (ret) + return ret; + + regval = phy_read_mmd(phydev, MDIO_MMD_VEND2, ADIN_PHY_SUBSYS_IRQ_MASK); + if (regval < 0) + return regval; + + if (phydev->interrupts == PHY_INTERRUPT_ENABLED) + regval |= ADIN_LINK_STAT_CHNG_IRQ_EN; + else + regval &= ~ADIN_LINK_STAT_CHNG_IRQ_EN; + + ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, + ADIN_PHY_SUBSYS_IRQ_MASK, + regval); + return ret; +} + +static irqreturn_t adin_phy_handle_interrupt(struct phy_device *phydev) +{ + int irq_status; + + irq_status = phy_read_mmd(phydev, MDIO_MMD_VEND2, ADIN_PHY_SUBSYS_IRQ_STATUS); + if (irq_status < 0) { + phy_error(phydev); + return IRQ_NONE; + } + + if (!(irq_status & ADIN_LINK_STAT_CHNG)) + return IRQ_NONE; + + phy_trigger_machine(phydev); + + return IRQ_HANDLED; +} + static int adin_set_powerdown_mode(struct phy_device *phydev, bool en) { int ret; @@ -275,6 +331,8 @@ static struct phy_driver adin_driver[] = { .probe = adin_probe, .config_aneg = adin_config_aneg, .read_status = adin_read_status, + .config_intr = adin_config_intr, + .handle_interrupt = adin_phy_handle_interrupt, .set_loopback = adin_set_loopback, .suspend = adin_suspend, .resume = adin_resume,