linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH net-next v2 00/19] net: phy: add support for shared interrupts (part 1)
@ 2020-11-01 12:50 Ioana Ciornei
  2020-11-01 12:50 ` [PATCH net-next v2 01/19] net: phy: export phy_error and phy_trigger_machine Ioana Ciornei
                   ` (21 more replies)
  0 siblings, 22 replies; 31+ messages in thread
From: Ioana Ciornei @ 2020-11-01 12:50 UTC (permalink / raw)
  To: Andrew Lunn, Heiner Kallweit, Russell King, Florian Fainelli,
	Jakub Kicinski, netdev, linux-kernel
  Cc: Ioana Ciornei, Alexandru Ardelean, Andre Edich, Antoine Tenart,
	Baruch Siach, Christophe Leroy, Dan Murphy, Divya Koppera,
	Hauke Mehrtens, Jerome Brunet, Kavya Sree Kotagiri,
	Linus Walleij, Marco Felsch, Marek Vasut, Martin Blumenstingl,
	Mathias Kresin, Maxim Kochetkov, Michael Walle, Neil Armstrong,
	Nisar Sayed, Oleksij Rempel, Philippe Schenker, Willy Liu,
	Yuiko Oshino

From: Ioana Ciornei <ioana.ciornei@nxp.com>

This patch set aims to actually add support for shared interrupts in
phylib and not only for multi-PHY devices. While we are at it,
streamline the interrupt handling in phylib.

For a bit of context, at the moment, there are multiple phy_driver ops
that deal with this subject:

- .config_intr() - Enable/disable the interrupt line.

- .ack_interrupt() - Should quiesce any interrupts that may have been
  fired.  It's also used by phylib in conjunction with .config_intr() to
  clear any pending interrupts after the line was disabled, and before
  it is going to be enabled.

- .did_interrupt() - Intended for multi-PHY devices with a shared IRQ
  line and used by phylib to discern which PHY from the package was the
  one that actually fired the interrupt.

- .handle_interrupt() - Completely overrides the default interrupt
  handling logic from phylib. The PHY driver is responsible for checking
  if any interrupt was fired by the respective PHY and choose
  accordingly if it's the one that should trigger the link state machine.

From my point of view, the interrupt handling in phylib has become
somewhat confusing with all these callbacks that actually read the same
PHY register - the interrupt status.  A more streamlined approach would
be to just move the responsibility to write an interrupt handler to the
driver (as any other device driver does) and make .handle_interrupt()
the only way to deal with interrupts.

Another advantage with this approach would be that phylib would gain
support for shared IRQs between different PHY (not just multi-PHY
devices), something which at the moment would require extending every
PHY driver anyway in order to implement their .did_interrupt() callback
and duplicate the same logic as in .ack_interrupt(). The disadvantage
of making .did_interrupt() mandatory would be that we are slightly
changing the semantics of the phylib API and that would increase
confusion instead of reducing it.

What I am proposing is the following:

- As a first step, make the .ack_interrupt() callback optional so that
  we do not break any PHY driver amid the transition.

- Every PHY driver gains a .handle_interrupt() implementation that, for
  the most part, would look like below:

	irq_status = phy_read(phydev, INTR_STATUS);
	if (irq_status < 0) {
		phy_error(phydev);
		return IRQ_NONE;
	}

	if (!(irq_status & irq_mask))
		return IRQ_NONE;

	phy_trigger_machine(phydev);

	return IRQ_HANDLED;

- Remove each PHY driver's implementation of the .ack_interrupt() by
  actually taking care of quiescing any pending interrupts before
  enabling/after disabling the interrupt line.

- Finally, after all drivers have been ported, remove the
  .ack_interrupt() and .did_interrupt() callbacks from phy_driver.

This patch set is part 1 and it addresses the changes needed in phylib
and 7 PHY drivers. The rest can be found on my Github branch here:
https://github.com/IoanaCiornei/linux/commits/phylib-shared-irq

I do not have access to most of these PHY's, therefore I Cc-ed the
latest contributors to the individual PHY drivers in order to have
access, hopefully, to more regression testing.

Changes in v2:
 - Rework the .handle_interrupt() implementation for each driver so that
   only the enabled interrupts are taken into account when
   IRQ_NONE/IRQ_HANDLED it returned. The main idea is so that we avoid
   falsely blaming a device for triggering an interrupt when this is not
   the case.
   The only devices for which I was unable to make this adjustment were
   the BCM8706, BCM8727, BCMAC131 and BCM5241 since I do not have access
   to their datasheets.
 - I also updated the pseudo-code added in the cover-letter so that it's
   more clear how a .handle_interrupt() callback should look like.

Ioana Ciornei (19):
  net: phy: export phy_error and phy_trigger_machine
  net: phy: add a shutdown procedure
  net: phy: make .ack_interrupt() optional
  net: phy: at803x: implement generic .handle_interrupt() callback
  net: phy: at803x: remove the use of .ack_interrupt()
  net: phy: mscc: use phy_trigger_machine() to notify link change
  net: phy: mscc: implement generic .handle_interrupt() callback
  net: phy: mscc: remove the use of .ack_interrupt()
  net: phy: aquantia: implement generic .handle_interrupt() callback
  net: phy: aquantia: remove the use of .ack_interrupt()
  net: phy: broadcom: implement generic .handle_interrupt() callback
  net: phy: broadcom: remove use of ack_interrupt()
  net: phy: cicada: implement the generic .handle_interrupt() callback
  net: phy: cicada: remove the use of .ack_interrupt()
  net: phy: davicom: implement generic .handle_interrupt() calback
  net: phy: davicom: remove the use of .ack_interrupt()
  net: phy: add genphy_handle_interrupt_no_ack()
  net: phy: realtek: implement generic .handle_interrupt() callback
  net: phy: realtek: remove the use of .ack_interrupt()

 drivers/net/phy/aquantia_main.c  |  59 +++++++++----
 drivers/net/phy/at803x.c         |  50 +++++++++--
 drivers/net/phy/bcm-cygnus.c     |   2 +-
 drivers/net/phy/bcm-phy-lib.c    |  49 ++++++++++-
 drivers/net/phy/bcm-phy-lib.h    |   1 +
 drivers/net/phy/bcm54140.c       |  46 +++++++---
 drivers/net/phy/bcm63xx.c        |  20 +++--
 drivers/net/phy/bcm87xx.c        |  50 ++++++-----
 drivers/net/phy/broadcom.c       |  70 +++++++++++-----
 drivers/net/phy/cicada.c         |  35 +++++++-
 drivers/net/phy/davicom.c        |  63 ++++++++++----
 drivers/net/phy/mscc/mscc_main.c |  70 ++++++++--------
 drivers/net/phy/phy.c            |   6 +-
 drivers/net/phy/phy_device.c     |  23 ++++-
 drivers/net/phy/realtek.c        | 140 +++++++++++++++++++++++++++----
 include/linux/phy.h              |   3 +
 16 files changed, 529 insertions(+), 158 deletions(-)

Cc: Alexandru Ardelean <alexandru.ardelean@analog.com>
Cc: Andre Edich <andre.edich@microchip.com>
Cc: Antoine Tenart <atenart@kernel.org>
Cc: Baruch Siach <baruch@tkos.co.il>
Cc: Christophe Leroy <christophe.leroy@c-s.fr>
Cc: Dan Murphy <dmurphy@ti.com>
Cc: Divya Koppera <Divya.Koppera@microchip.com>
Cc: Florian Fainelli <f.fainelli@gmail.com>
Cc: Hauke Mehrtens <hauke@hauke-m.de>
Cc: Heiner Kallweit <hkallweit1@gmail.com>
Cc: Jerome Brunet <jbrunet@baylibre.com>
Cc: Kavya Sree Kotagiri <kavyasree.kotagiri@microchip.com>
Cc: Linus Walleij <linus.walleij@linaro.org>
Cc: Marco Felsch <m.felsch@pengutronix.de>
Cc: Marek Vasut <marex@denx.de>
Cc: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Cc: Mathias Kresin <dev@kresin.me>
Cc: Maxim Kochetkov <fido_max@inbox.ru>
Cc: Michael Walle <michael@walle.cc>
Cc: Neil Armstrong <narmstrong@baylibre.com>
Cc: Nisar Sayed <Nisar.Sayed@microchip.com>
Cc: Oleksij Rempel <o.rempel@pengutronix.de>
Cc: Philippe Schenker <philippe.schenker@toradex.com>
Cc: Willy Liu <willy.liu@realtek.com>
Cc: Yuiko Oshino <yuiko.oshino@microchip.com>

-- 
2.28.0


^ permalink raw reply	[flat|nested] 31+ messages in thread

* [PATCH net-next v2 01/19] net: phy: export phy_error and phy_trigger_machine
  2020-11-01 12:50 [PATCH net-next v2 00/19] net: phy: add support for shared interrupts (part 1) Ioana Ciornei
@ 2020-11-01 12:50 ` Ioana Ciornei
  2020-11-01 12:50 ` [PATCH net-next v2 02/19] net: phy: add a shutdown procedure Ioana Ciornei
                   ` (20 subsequent siblings)
  21 siblings, 0 replies; 31+ messages in thread
From: Ioana Ciornei @ 2020-11-01 12:50 UTC (permalink / raw)
  To: Andrew Lunn, Heiner Kallweit, Russell King, Florian Fainelli,
	Jakub Kicinski, netdev, linux-kernel
  Cc: Ioana Ciornei, Alexandru Ardelean, Andre Edich, Antoine Tenart,
	Baruch Siach, Christophe Leroy, Dan Murphy, Divya Koppera,
	Hauke Mehrtens, Jerome Brunet, Kavya Sree Kotagiri,
	Linus Walleij, Marco Felsch, Marek Vasut, Martin Blumenstingl,
	Mathias Kresin, Maxim Kochetkov, Michael Walle, Neil Armstrong,
	Nisar Sayed, Oleksij Rempel, Philippe Schenker, Willy Liu,
	Yuiko Oshino

From: Ioana Ciornei <ioana.ciornei@nxp.com>

These functions are currently used by phy_interrupt() to either signal
an error condition or to trigger the link state machine. In an attempt
to actually support shared PHY IRQs, export these two functions so that
the actual PHY drivers can use them.

Cc: Alexandru Ardelean <alexandru.ardelean@analog.com>
Cc: Andre Edich <andre.edich@microchip.com>
Cc: Antoine Tenart <atenart@kernel.org>
Cc: Baruch Siach <baruch@tkos.co.il>
Cc: Christophe Leroy <christophe.leroy@c-s.fr>
Cc: Dan Murphy <dmurphy@ti.com>
Cc: Divya Koppera <Divya.Koppera@microchip.com>
Cc: Florian Fainelli <f.fainelli@gmail.com>
Cc: Hauke Mehrtens <hauke@hauke-m.de>
Cc: Heiner Kallweit <hkallweit1@gmail.com>
Cc: Jerome Brunet <jbrunet@baylibre.com>
Cc: Kavya Sree Kotagiri <kavyasree.kotagiri@microchip.com>
Cc: Linus Walleij <linus.walleij@linaro.org>
Cc: Marco Felsch <m.felsch@pengutronix.de>
Cc: Marek Vasut <marex@denx.de>
Cc: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Cc: Mathias Kresin <dev@kresin.me>
Cc: Maxim Kochetkov <fido_max@inbox.ru>
Cc: Michael Walle <michael@walle.cc>
Cc: Neil Armstrong <narmstrong@baylibre.com>
Cc: Nisar Sayed <Nisar.Sayed@microchip.com>
Cc: Oleksij Rempel <o.rempel@pengutronix.de>
Cc: Philippe Schenker <philippe.schenker@toradex.com>
Cc: Willy Liu <willy.liu@realtek.com>
Cc: Yuiko Oshino <yuiko.oshino@microchip.com>
Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
---
Changes in v2:
 - none

 drivers/net/phy/phy.c | 6 ++++--
 include/linux/phy.h   | 2 ++
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 35525a671400..477bdf2f94df 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -493,10 +493,11 @@ EXPORT_SYMBOL(phy_queue_state_machine);
  *
  * @phydev: the phy_device struct
  */
-static void phy_trigger_machine(struct phy_device *phydev)
+void phy_trigger_machine(struct phy_device *phydev)
 {
 	phy_queue_state_machine(phydev, 0);
 }
+EXPORT_SYMBOL(phy_trigger_machine);
 
 static void phy_abort_cable_test(struct phy_device *phydev)
 {
@@ -924,7 +925,7 @@ void phy_stop_machine(struct phy_device *phydev)
  * Must not be called from interrupt context, or while the
  * phydev->lock is held.
  */
-static void phy_error(struct phy_device *phydev)
+void phy_error(struct phy_device *phydev)
 {
 	WARN_ON(1);
 
@@ -934,6 +935,7 @@ static void phy_error(struct phy_device *phydev)
 
 	phy_trigger_machine(phydev);
 }
+EXPORT_SYMBOL(phy_error);
 
 /**
  * phy_disable_interrupts - Disable the PHY interrupts from the PHY side
diff --git a/include/linux/phy.h b/include/linux/phy.h
index eb3cb1a98b45..566b39f6cd64 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -1570,8 +1570,10 @@ void phy_drivers_unregister(struct phy_driver *drv, int n);
 int phy_driver_register(struct phy_driver *new_driver, struct module *owner);
 int phy_drivers_register(struct phy_driver *new_driver, int n,
 			 struct module *owner);
+void phy_error(struct phy_device *phydev);
 void phy_state_machine(struct work_struct *work);
 void phy_queue_state_machine(struct phy_device *phydev, unsigned long jiffies);
+void phy_trigger_machine(struct phy_device *phydev);
 void phy_mac_interrupt(struct phy_device *phydev);
 void phy_start_machine(struct phy_device *phydev);
 void phy_stop_machine(struct phy_device *phydev);
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH net-next v2 02/19] net: phy: add a shutdown procedure
  2020-11-01 12:50 [PATCH net-next v2 00/19] net: phy: add support for shared interrupts (part 1) Ioana Ciornei
  2020-11-01 12:50 ` [PATCH net-next v2 01/19] net: phy: export phy_error and phy_trigger_machine Ioana Ciornei
@ 2020-11-01 12:50 ` Ioana Ciornei
  2023-08-03 18:16   ` Uwe Kleine-König
  2020-11-01 12:50 ` [PATCH net-next v2 03/19] net: phy: make .ack_interrupt() optional Ioana Ciornei
                   ` (19 subsequent siblings)
  21 siblings, 1 reply; 31+ messages in thread
From: Ioana Ciornei @ 2020-11-01 12:50 UTC (permalink / raw)
  To: Andrew Lunn, Heiner Kallweit, Russell King, Florian Fainelli,
	Jakub Kicinski, netdev, linux-kernel
  Cc: Ioana Ciornei, Alexandru Ardelean, Andre Edich, Antoine Tenart,
	Baruch Siach, Christophe Leroy, Dan Murphy, Divya Koppera,
	Hauke Mehrtens, Jerome Brunet, Kavya Sree Kotagiri,
	Linus Walleij, Marco Felsch, Marek Vasut, Martin Blumenstingl,
	Mathias Kresin, Maxim Kochetkov, Michael Walle, Neil Armstrong,
	Nisar Sayed, Oleksij Rempel, Philippe Schenker, Willy Liu,
	Yuiko Oshino

From: Ioana Ciornei <ioana.ciornei@nxp.com>

In case of a board which uses a shared IRQ we can easily end up with an
IRQ storm after a forced reboot.

For example, a 'reboot -f' will trigger a call to the .shutdown()
callbacks of all devices. Because phylib does not implement that hook,
the PHY is not quiesced, thus it can very well leave its IRQ enabled.

At the next boot, if that IRQ line is found asserted by the first PHY
driver that uses it, but _before_ the driver that is _actually_ keeping
the shared IRQ asserted is probed, the IRQ is not going to be
acknowledged, thus it will keep being fired preventing the boot process
of the kernel to continue. This is even worse when the second PHY driver
is a module.

To fix this, implement the .shutdown() callback and disable the
interrupts if these are used.

Note that we are still susceptible to IRQ storms if the previous kernel
exited with a panic or if the bootloader left the shared IRQ active, but
there is absolutely nothing we can do about these cases.

Cc: Alexandru Ardelean <alexandru.ardelean@analog.com>
Cc: Andre Edich <andre.edich@microchip.com>
Cc: Antoine Tenart <atenart@kernel.org>
Cc: Baruch Siach <baruch@tkos.co.il>
Cc: Christophe Leroy <christophe.leroy@c-s.fr>
Cc: Dan Murphy <dmurphy@ti.com>
Cc: Divya Koppera <Divya.Koppera@microchip.com>
Cc: Florian Fainelli <f.fainelli@gmail.com>
Cc: Hauke Mehrtens <hauke@hauke-m.de>
Cc: Heiner Kallweit <hkallweit1@gmail.com>
Cc: Jerome Brunet <jbrunet@baylibre.com>
Cc: Kavya Sree Kotagiri <kavyasree.kotagiri@microchip.com>
Cc: Linus Walleij <linus.walleij@linaro.org>
Cc: Marco Felsch <m.felsch@pengutronix.de>
Cc: Marek Vasut <marex@denx.de>
Cc: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Cc: Mathias Kresin <dev@kresin.me>
Cc: Maxim Kochetkov <fido_max@inbox.ru>
Cc: Michael Walle <michael@walle.cc>
Cc: Neil Armstrong <narmstrong@baylibre.com>
Cc: Nisar Sayed <Nisar.Sayed@microchip.com>
Cc: Oleksij Rempel <o.rempel@pengutronix.de>
Cc: Philippe Schenker <philippe.schenker@toradex.com>
Cc: Willy Liu <willy.liu@realtek.com>
Cc: Yuiko Oshino <yuiko.oshino@microchip.com>
Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
---
Changes in v2:
 - none

 drivers/net/phy/phy_device.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 5dab6be6fc38..413a0a2c5d51 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -2947,6 +2947,13 @@ static int phy_remove(struct device *dev)
 	return 0;
 }
 
+static void phy_shutdown(struct device *dev)
+{
+	struct phy_device *phydev = to_phy_device(dev);
+
+	phy_disable_interrupts(phydev);
+}
+
 /**
  * phy_driver_register - register a phy_driver with the PHY layer
  * @new_driver: new phy_driver to register
@@ -2970,6 +2977,7 @@ int phy_driver_register(struct phy_driver *new_driver, struct module *owner)
 	new_driver->mdiodrv.driver.bus = &mdio_bus_type;
 	new_driver->mdiodrv.driver.probe = phy_probe;
 	new_driver->mdiodrv.driver.remove = phy_remove;
+	new_driver->mdiodrv.driver.shutdown = phy_shutdown;
 	new_driver->mdiodrv.driver.owner = owner;
 	new_driver->mdiodrv.driver.probe_type = PROBE_FORCE_SYNCHRONOUS;
 
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH net-next v2 03/19] net: phy: make .ack_interrupt() optional
  2020-11-01 12:50 [PATCH net-next v2 00/19] net: phy: add support for shared interrupts (part 1) Ioana Ciornei
  2020-11-01 12:50 ` [PATCH net-next v2 01/19] net: phy: export phy_error and phy_trigger_machine Ioana Ciornei
  2020-11-01 12:50 ` [PATCH net-next v2 02/19] net: phy: add a shutdown procedure Ioana Ciornei
@ 2020-11-01 12:50 ` Ioana Ciornei
  2020-11-01 12:50 ` [PATCH net-next v2 04/19] net: phy: at803x: implement generic .handle_interrupt() callback Ioana Ciornei
                   ` (18 subsequent siblings)
  21 siblings, 0 replies; 31+ messages in thread
From: Ioana Ciornei @ 2020-11-01 12:50 UTC (permalink / raw)
  To: Andrew Lunn, Heiner Kallweit, Russell King, Florian Fainelli,
	Jakub Kicinski, netdev, linux-kernel
  Cc: Ioana Ciornei, Alexandru Ardelean, Andre Edich, Antoine Tenart,
	Baruch Siach, Christophe Leroy, Dan Murphy, Divya Koppera,
	Hauke Mehrtens, Jerome Brunet, Kavya Sree Kotagiri,
	Linus Walleij, Marco Felsch, Marek Vasut, Martin Blumenstingl,
	Mathias Kresin, Maxim Kochetkov, Michael Walle, Neil Armstrong,
	Nisar Sayed, Oleksij Rempel, Philippe Schenker, Willy Liu,
	Yuiko Oshino

From: Ioana Ciornei <ioana.ciornei@nxp.com>

As a first step into making phylib and all PHY drivers to actually
have support for shared IRQs, make the .ack_interrupt() callback
optional.

After all drivers have been moved to implement the generic
interrupt handle, the phy_drv_supports_irq() check will be
changed again to only require the .handle_interrupts() callback.

Cc: Alexandru Ardelean <alexandru.ardelean@analog.com>
Cc: Andre Edich <andre.edich@microchip.com>
Cc: Antoine Tenart <atenart@kernel.org>
Cc: Baruch Siach <baruch@tkos.co.il>
Cc: Christophe Leroy <christophe.leroy@c-s.fr>
Cc: Dan Murphy <dmurphy@ti.com>
Cc: Divya Koppera <Divya.Koppera@microchip.com>
Cc: Florian Fainelli <f.fainelli@gmail.com>
Cc: Hauke Mehrtens <hauke@hauke-m.de>
Cc: Heiner Kallweit <hkallweit1@gmail.com>
Cc: Jerome Brunet <jbrunet@baylibre.com>
Cc: Kavya Sree Kotagiri <kavyasree.kotagiri@microchip.com>
Cc: Linus Walleij <linus.walleij@linaro.org>
Cc: Marco Felsch <m.felsch@pengutronix.de>
Cc: Marek Vasut <marex@denx.de>
Cc: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Cc: Mathias Kresin <dev@kresin.me>
Cc: Maxim Kochetkov <fido_max@inbox.ru>
Cc: Michael Walle <michael@walle.cc>
Cc: Neil Armstrong <narmstrong@baylibre.com>
Cc: Nisar Sayed <Nisar.Sayed@microchip.com>
Cc: Oleksij Rempel <o.rempel@pengutronix.de>
Cc: Philippe Schenker <philippe.schenker@toradex.com>
Cc: Willy Liu <willy.liu@realtek.com>
Cc: Yuiko Oshino <yuiko.oshino@microchip.com>
Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
---
Changes in v2:
 - none

 drivers/net/phy/phy_device.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 413a0a2c5d51..f54f483d7fd6 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -2815,7 +2815,7 @@ EXPORT_SYMBOL(phy_get_internal_delay);
 
 static bool phy_drv_supports_irq(struct phy_driver *phydrv)
 {
-	return phydrv->config_intr && phydrv->ack_interrupt;
+	return phydrv->config_intr && (phydrv->ack_interrupt || phydrv->handle_interrupt);
 }
 
 /**
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH net-next v2 04/19] net: phy: at803x: implement generic .handle_interrupt() callback
  2020-11-01 12:50 [PATCH net-next v2 00/19] net: phy: add support for shared interrupts (part 1) Ioana Ciornei
                   ` (2 preceding siblings ...)
  2020-11-01 12:50 ` [PATCH net-next v2 03/19] net: phy: make .ack_interrupt() optional Ioana Ciornei
@ 2020-11-01 12:50 ` Ioana Ciornei
  2020-11-04 18:09   ` Oleksij Rempel
  2020-11-01 12:51 ` [PATCH net-next v2 05/19] net: phy: at803x: remove the use of .ack_interrupt() Ioana Ciornei
                   ` (17 subsequent siblings)
  21 siblings, 1 reply; 31+ messages in thread
From: Ioana Ciornei @ 2020-11-01 12:50 UTC (permalink / raw)
  To: Andrew Lunn, Heiner Kallweit, Russell King, Florian Fainelli,
	Jakub Kicinski, netdev, linux-kernel
  Cc: Ioana Ciornei, Oleksij Rempel, Michael Walle

From: Ioana Ciornei <ioana.ciornei@nxp.com>

In an attempt to actually support shared IRQs in phylib, we now move the
responsibility of triggering the phylib state machine or just returning
IRQ_NONE, based on the IRQ status register, to the PHY driver. Having
3 different IRQ handling callbacks (.handle_interrupt(),
.did_interrupt() and .ack_interrupt() ) is confusing so let the PHY
driver implement directly an IRQ handler like any other device driver.
Make this driver follow the new convention.

Cc: Oleksij Rempel <o.rempel@pengutronix.de>
Cc: Michael Walle <michael@walle.cc>
Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
---
Changes in v2:
 - adjust .handle_interrupt() so that we only take into account the
   enabled IRQs.

 drivers/net/phy/at803x.c | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c
index ed601a7e46a0..c7f91934cf82 100644
--- a/drivers/net/phy/at803x.c
+++ b/drivers/net/phy/at803x.c
@@ -628,6 +628,32 @@ static int at803x_config_intr(struct phy_device *phydev)
 	return err;
 }
 
+static irqreturn_t at803x_handle_interrupt(struct phy_device *phydev)
+{
+	int irq_status, int_enabled;
+
+	irq_status = phy_read(phydev, AT803X_INTR_STATUS);
+	if (irq_status < 0) {
+		phy_error(phydev);
+		return IRQ_NONE;
+	}
+
+	/* Read the current enabled interrupts */
+	int_enabled = phy_read(phydev, AT803X_INTR_ENABLE);
+	if (int_enabled < 0) {
+		phy_error(phydev);
+		return IRQ_NONE;
+	}
+
+	/* See if this was one of our enabled interrupts */
+	if (!(irq_status & int_enabled))
+		return IRQ_NONE;
+
+	phy_trigger_machine(phydev);
+
+	return IRQ_HANDLED;
+}
+
 static void at803x_link_change_notify(struct phy_device *phydev)
 {
 	/*
@@ -1064,6 +1090,7 @@ static struct phy_driver at803x_driver[] = {
 	.read_status		= at803x_read_status,
 	.ack_interrupt		= at803x_ack_interrupt,
 	.config_intr		= at803x_config_intr,
+	.handle_interrupt	= at803x_handle_interrupt,
 	.get_tunable		= at803x_get_tunable,
 	.set_tunable		= at803x_set_tunable,
 	.cable_test_start	= at803x_cable_test_start,
@@ -1084,6 +1111,7 @@ static struct phy_driver at803x_driver[] = {
 	/* PHY_BASIC_FEATURES */
 	.ack_interrupt		= at803x_ack_interrupt,
 	.config_intr		= at803x_config_intr,
+	.handle_interrupt	= at803x_handle_interrupt,
 }, {
 	/* Qualcomm Atheros AR8031/AR8033 */
 	PHY_ID_MATCH_EXACT(ATH8031_PHY_ID),
@@ -1102,6 +1130,7 @@ static struct phy_driver at803x_driver[] = {
 	.aneg_done		= at803x_aneg_done,
 	.ack_interrupt		= &at803x_ack_interrupt,
 	.config_intr		= &at803x_config_intr,
+	.handle_interrupt	= at803x_handle_interrupt,
 	.get_tunable		= at803x_get_tunable,
 	.set_tunable		= at803x_set_tunable,
 	.cable_test_start	= at803x_cable_test_start,
@@ -1122,6 +1151,7 @@ static struct phy_driver at803x_driver[] = {
 	/* PHY_BASIC_FEATURES */
 	.ack_interrupt		= at803x_ack_interrupt,
 	.config_intr		= at803x_config_intr,
+	.handle_interrupt	= at803x_handle_interrupt,
 	.cable_test_start	= at803x_cable_test_start,
 	.cable_test_get_status	= at803x_cable_test_get_status,
 }, {
@@ -1134,6 +1164,7 @@ static struct phy_driver at803x_driver[] = {
 	/* PHY_BASIC_FEATURES */
 	.ack_interrupt		= &at803x_ack_interrupt,
 	.config_intr		= &at803x_config_intr,
+	.handle_interrupt	= at803x_handle_interrupt,
 	.cable_test_start	= at803x_cable_test_start,
 	.cable_test_get_status	= at803x_cable_test_get_status,
 	.read_status		= at803x_read_status,
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH net-next v2 05/19] net: phy: at803x: remove the use of .ack_interrupt()
  2020-11-01 12:50 [PATCH net-next v2 00/19] net: phy: add support for shared interrupts (part 1) Ioana Ciornei
                   ` (3 preceding siblings ...)
  2020-11-01 12:50 ` [PATCH net-next v2 04/19] net: phy: at803x: implement generic .handle_interrupt() callback Ioana Ciornei
@ 2020-11-01 12:51 ` Ioana Ciornei
  2020-11-04 18:09   ` Oleksij Rempel
  2020-11-01 12:51 ` [PATCH net-next v2 06/19] net: phy: mscc: use phy_trigger_machine() to notify link change Ioana Ciornei
                   ` (16 subsequent siblings)
  21 siblings, 1 reply; 31+ messages in thread
From: Ioana Ciornei @ 2020-11-01 12:51 UTC (permalink / raw)
  To: Andrew Lunn, Heiner Kallweit, Russell King, Florian Fainelli,
	Jakub Kicinski, netdev, linux-kernel
  Cc: Ioana Ciornei, Oleksij Rempel, Michael Walle

From: Ioana Ciornei <ioana.ciornei@nxp.com>

In preparation of removing the .ack_interrupt() callback, we must replace
its occurrences (aka phy_clear_interrupt), from the 2 places where it is
called from (phy_enable_interrupts and phy_disable_interrupts), with
equivalent functionality.

This means that clearing interrupts now becomes something that the PHY
driver is responsible of doing, before enabling interrupts and after
clearing them. Make this driver follow the new contract.

Cc: Oleksij Rempel <o.rempel@pengutronix.de>
Cc: Michael Walle <michael@walle.cc>
Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
---
Changes in v2:
 - none

 drivers/net/phy/at803x.c | 19 ++++++++++++-------
 1 file changed, 12 insertions(+), 7 deletions(-)

diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c
index c7f91934cf82..d0b36fd6c265 100644
--- a/drivers/net/phy/at803x.c
+++ b/drivers/net/phy/at803x.c
@@ -614,6 +614,11 @@ static int at803x_config_intr(struct phy_device *phydev)
 	value = phy_read(phydev, AT803X_INTR_ENABLE);
 
 	if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
+		/* Clear any pending interrupts */
+		err = at803x_ack_interrupt(phydev);
+		if (err)
+			return err;
+
 		value |= AT803X_INTR_ENABLE_AUTONEG_ERR;
 		value |= AT803X_INTR_ENABLE_SPEED_CHANGED;
 		value |= AT803X_INTR_ENABLE_DUPLEX_CHANGED;
@@ -621,9 +626,14 @@ static int at803x_config_intr(struct phy_device *phydev)
 		value |= AT803X_INTR_ENABLE_LINK_SUCCESS;
 
 		err = phy_write(phydev, AT803X_INTR_ENABLE, value);
-	}
-	else
+	} else {
 		err = phy_write(phydev, AT803X_INTR_ENABLE, 0);
+		if (err)
+			return err;
+
+		/* Clear any pending interrupts */
+		err = at803x_ack_interrupt(phydev);
+	}
 
 	return err;
 }
@@ -1088,7 +1098,6 @@ static struct phy_driver at803x_driver[] = {
 	.resume			= at803x_resume,
 	/* PHY_GBIT_FEATURES */
 	.read_status		= at803x_read_status,
-	.ack_interrupt		= at803x_ack_interrupt,
 	.config_intr		= at803x_config_intr,
 	.handle_interrupt	= at803x_handle_interrupt,
 	.get_tunable		= at803x_get_tunable,
@@ -1109,7 +1118,6 @@ static struct phy_driver at803x_driver[] = {
 	.suspend		= at803x_suspend,
 	.resume			= at803x_resume,
 	/* PHY_BASIC_FEATURES */
-	.ack_interrupt		= at803x_ack_interrupt,
 	.config_intr		= at803x_config_intr,
 	.handle_interrupt	= at803x_handle_interrupt,
 }, {
@@ -1128,7 +1136,6 @@ static struct phy_driver at803x_driver[] = {
 	/* PHY_GBIT_FEATURES */
 	.read_status		= at803x_read_status,
 	.aneg_done		= at803x_aneg_done,
-	.ack_interrupt		= &at803x_ack_interrupt,
 	.config_intr		= &at803x_config_intr,
 	.handle_interrupt	= at803x_handle_interrupt,
 	.get_tunable		= at803x_get_tunable,
@@ -1149,7 +1156,6 @@ static struct phy_driver at803x_driver[] = {
 	.suspend		= at803x_suspend,
 	.resume			= at803x_resume,
 	/* PHY_BASIC_FEATURES */
-	.ack_interrupt		= at803x_ack_interrupt,
 	.config_intr		= at803x_config_intr,
 	.handle_interrupt	= at803x_handle_interrupt,
 	.cable_test_start	= at803x_cable_test_start,
@@ -1162,7 +1168,6 @@ static struct phy_driver at803x_driver[] = {
 	.resume			= at803x_resume,
 	.flags			= PHY_POLL_CABLE_TEST,
 	/* PHY_BASIC_FEATURES */
-	.ack_interrupt		= &at803x_ack_interrupt,
 	.config_intr		= &at803x_config_intr,
 	.handle_interrupt	= at803x_handle_interrupt,
 	.cable_test_start	= at803x_cable_test_start,
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH net-next v2 06/19] net: phy: mscc: use phy_trigger_machine() to notify link change
  2020-11-01 12:50 [PATCH net-next v2 00/19] net: phy: add support for shared interrupts (part 1) Ioana Ciornei
                   ` (4 preceding siblings ...)
  2020-11-01 12:51 ` [PATCH net-next v2 05/19] net: phy: at803x: remove the use of .ack_interrupt() Ioana Ciornei
@ 2020-11-01 12:51 ` Ioana Ciornei
  2020-11-05  0:10   ` Vladimir Oltean
  2020-11-01 12:51 ` [PATCH net-next v2 07/19] net: phy: mscc: implement generic .handle_interrupt() callback Ioana Ciornei
                   ` (15 subsequent siblings)
  21 siblings, 1 reply; 31+ messages in thread
From: Ioana Ciornei @ 2020-11-01 12:51 UTC (permalink / raw)
  To: Andrew Lunn, Heiner Kallweit, Russell King, Florian Fainelli,
	Jakub Kicinski, netdev, linux-kernel
  Cc: Ioana Ciornei

From: Ioana Ciornei <ioana.ciornei@nxp.com>

According to the comment describing the phy_mac_interrupt() function, it
it intended to be used by MAC drivers which have noticed a link change
thus its use in the mscc PHY driver is improper and, most probably, was
added just because phy_trigger_machine() was not exported.
Now that we have acces to trigger the link state machine, use directly
the phy_trigger_machine() function to notify a link change detected by
the PHY driver.

Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
---
Changes in v2:
 - none

 drivers/net/phy/mscc/mscc_main.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/phy/mscc/mscc_main.c b/drivers/net/phy/mscc/mscc_main.c
index 6bc7406a1ce7..b705121c9d26 100644
--- a/drivers/net/phy/mscc/mscc_main.c
+++ b/drivers/net/phy/mscc/mscc_main.c
@@ -1498,7 +1498,7 @@ static irqreturn_t vsc8584_handle_interrupt(struct phy_device *phydev)
 		vsc8584_handle_macsec_interrupt(phydev);
 
 	if (irq_status & MII_VSC85XX_INT_MASK_LINK_CHG)
-		phy_mac_interrupt(phydev);
+		phy_trigger_machine(phydev);
 
 	return IRQ_HANDLED;
 }
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH net-next v2 07/19] net: phy: mscc: implement generic .handle_interrupt() callback
  2020-11-01 12:50 [PATCH net-next v2 00/19] net: phy: add support for shared interrupts (part 1) Ioana Ciornei
                   ` (5 preceding siblings ...)
  2020-11-01 12:51 ` [PATCH net-next v2 06/19] net: phy: mscc: use phy_trigger_machine() to notify link change Ioana Ciornei
@ 2020-11-01 12:51 ` Ioana Ciornei
  2020-11-05  0:08   ` Vladimir Oltean
  2020-11-01 12:51 ` [PATCH net-next v2 08/19] net: phy: mscc: remove the use of .ack_interrupt() Ioana Ciornei
                   ` (14 subsequent siblings)
  21 siblings, 1 reply; 31+ messages in thread
From: Ioana Ciornei @ 2020-11-01 12:51 UTC (permalink / raw)
  To: Andrew Lunn, Heiner Kallweit, Russell King, Florian Fainelli,
	Jakub Kicinski, netdev, linux-kernel
  Cc: Ioana Ciornei

From: Ioana Ciornei <ioana.ciornei@nxp.com>

In an attempt to actually support shared IRQs in phylib, we now move the
responsibility of triggering the phylib state machine or just returning
IRQ_NONE, based on the IRQ status register, to the PHY driver. Having
3 different IRQ handling callbacks (.handle_interrupt(),
.did_interrupt() and .ack_interrupt() ) is confusing so let the PHY
driver implement directly an IRQ handler like any other device driver.
Make this driver follow the new convention.

Also, remove the .did_interrupt() callback since it's not anymore used.

Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
---
Changes in v2:
 - adjust .handle_interrupt() so that we only take into account the
   enabled IRQs.

 drivers/net/phy/mscc/mscc_main.c | 56 ++++++++++++++++----------------
 1 file changed, 28 insertions(+), 28 deletions(-)

diff --git a/drivers/net/phy/mscc/mscc_main.c b/drivers/net/phy/mscc/mscc_main.c
index b705121c9d26..48883730bf6f 100644
--- a/drivers/net/phy/mscc/mscc_main.c
+++ b/drivers/net/phy/mscc/mscc_main.c
@@ -1541,16 +1541,6 @@ static int vsc85xx_config_init(struct phy_device *phydev)
 	return 0;
 }
 
-static int vsc8584_did_interrupt(struct phy_device *phydev)
-{
-	int rc = 0;
-
-	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
-		rc = phy_read(phydev, MII_VSC85XX_INT_STATUS);
-
-	return (rc < 0) ? 0 : rc & MII_VSC85XX_INT_MASK_MASK;
-}
-
 static int vsc8514_config_pre_init(struct phy_device *phydev)
 {
 	/* These are the settings to override the silicon default
@@ -1948,6 +1938,24 @@ static int vsc85xx_config_intr(struct phy_device *phydev)
 	return rc;
 }
 
+static irqreturn_t vsc85xx_handle_interrupt(struct phy_device *phydev)
+{
+	int irq_status;
+
+	irq_status = phy_read(phydev, MII_VSC85XX_INT_STATUS);
+	if (irq_status < 0) {
+		phy_error(phydev);
+		return IRQ_NONE;
+	}
+
+	if (!(irq_status & MII_VSC85XX_INT_MASK_MASK))
+		return IRQ_NONE;
+
+	phy_trigger_machine(phydev);
+
+	return IRQ_HANDLED;
+}
+
 static int vsc85xx_config_aneg(struct phy_device *phydev)
 {
 	int rc;
@@ -2114,7 +2122,7 @@ static struct phy_driver vsc85xx_driver[] = {
 	.config_init	= &vsc85xx_config_init,
 	.config_aneg    = &vsc85xx_config_aneg,
 	.read_status	= &vsc85xx_read_status,
-	.ack_interrupt	= &vsc85xx_ack_interrupt,
+	.handle_interrupt = vsc85xx_handle_interrupt,
 	.config_intr	= &vsc85xx_config_intr,
 	.suspend	= &genphy_suspend,
 	.resume		= &genphy_resume,
@@ -2139,9 +2147,8 @@ static struct phy_driver vsc85xx_driver[] = {
 	.config_aneg    = &vsc85xx_config_aneg,
 	.aneg_done	= &genphy_aneg_done,
 	.read_status	= &vsc85xx_read_status,
-	.ack_interrupt  = &vsc85xx_ack_interrupt,
+	.handle_interrupt = vsc85xx_handle_interrupt,
 	.config_intr    = &vsc85xx_config_intr,
-	.did_interrupt  = &vsc8584_did_interrupt,
 	.suspend	= &genphy_suspend,
 	.resume		= &genphy_resume,
 	.probe		= &vsc8574_probe,
@@ -2163,7 +2170,7 @@ static struct phy_driver vsc85xx_driver[] = {
 	.config_init    = &vsc8514_config_init,
 	.config_aneg    = &vsc85xx_config_aneg,
 	.read_status	= &vsc85xx_read_status,
-	.ack_interrupt  = &vsc85xx_ack_interrupt,
+	.handle_interrupt = vsc85xx_handle_interrupt,
 	.config_intr    = &vsc85xx_config_intr,
 	.suspend	= &genphy_suspend,
 	.resume		= &genphy_resume,
@@ -2187,7 +2194,7 @@ static struct phy_driver vsc85xx_driver[] = {
 	.config_init	= &vsc85xx_config_init,
 	.config_aneg    = &vsc85xx_config_aneg,
 	.read_status	= &vsc85xx_read_status,
-	.ack_interrupt	= &vsc85xx_ack_interrupt,
+	.handle_interrupt = vsc85xx_handle_interrupt,
 	.config_intr	= &vsc85xx_config_intr,
 	.suspend	= &genphy_suspend,
 	.resume		= &genphy_resume,
@@ -2211,7 +2218,7 @@ static struct phy_driver vsc85xx_driver[] = {
 	.config_init    = &vsc85xx_config_init,
 	.config_aneg    = &vsc85xx_config_aneg,
 	.read_status	= &vsc85xx_read_status,
-	.ack_interrupt  = &vsc85xx_ack_interrupt,
+	.handle_interrupt = vsc85xx_handle_interrupt,
 	.config_intr    = &vsc85xx_config_intr,
 	.suspend	= &genphy_suspend,
 	.resume		= &genphy_resume,
@@ -2235,7 +2242,7 @@ static struct phy_driver vsc85xx_driver[] = {
 	.config_init	= &vsc85xx_config_init,
 	.config_aneg	= &vsc85xx_config_aneg,
 	.read_status	= &vsc85xx_read_status,
-	.ack_interrupt	= &vsc85xx_ack_interrupt,
+	.handle_interrupt = vsc85xx_handle_interrupt,
 	.config_intr	= &vsc85xx_config_intr,
 	.suspend	= &genphy_suspend,
 	.resume		= &genphy_resume,
@@ -2259,7 +2266,7 @@ static struct phy_driver vsc85xx_driver[] = {
 	.config_init    = &vsc85xx_config_init,
 	.config_aneg    = &vsc85xx_config_aneg,
 	.read_status	= &vsc85xx_read_status,
-	.ack_interrupt  = &vsc85xx_ack_interrupt,
+	.handle_interrupt = vsc85xx_handle_interrupt,
 	.config_intr    = &vsc85xx_config_intr,
 	.suspend	= &genphy_suspend,
 	.resume		= &genphy_resume,
@@ -2283,9 +2290,8 @@ static struct phy_driver vsc85xx_driver[] = {
 	.config_init    = &vsc8584_config_init,
 	.config_aneg    = &vsc85xx_config_aneg,
 	.read_status	= &vsc85xx_read_status,
-	.ack_interrupt  = &vsc85xx_ack_interrupt,
+	.handle_interrupt = vsc85xx_handle_interrupt,
 	.config_intr    = &vsc85xx_config_intr,
-	.did_interrupt  = &vsc8584_did_interrupt,
 	.suspend	= &genphy_suspend,
 	.resume		= &genphy_resume,
 	.probe		= &vsc8574_probe,
@@ -2308,9 +2314,8 @@ static struct phy_driver vsc85xx_driver[] = {
 	.config_init    = &vsc8584_config_init,
 	.config_aneg    = &vsc85xx_config_aneg,
 	.read_status	= &vsc85xx_read_status,
-	.ack_interrupt  = &vsc85xx_ack_interrupt,
+	.handle_interrupt = vsc85xx_handle_interrupt,
 	.config_intr    = &vsc85xx_config_intr,
-	.did_interrupt  = &vsc8584_did_interrupt,
 	.suspend	= &genphy_suspend,
 	.resume		= &genphy_resume,
 	.probe		= &vsc8584_probe,
@@ -2335,7 +2340,6 @@ static struct phy_driver vsc85xx_driver[] = {
 	.handle_interrupt = &vsc8584_handle_interrupt,
 	.ack_interrupt  = &vsc85xx_ack_interrupt,
 	.config_intr    = &vsc85xx_config_intr,
-	.did_interrupt  = &vsc8584_did_interrupt,
 	.suspend	= &genphy_suspend,
 	.resume		= &genphy_resume,
 	.probe		= &vsc8574_probe,
@@ -2359,9 +2363,8 @@ static struct phy_driver vsc85xx_driver[] = {
 	.config_aneg    = &vsc85xx_config_aneg,
 	.aneg_done	= &genphy_aneg_done,
 	.read_status	= &vsc85xx_read_status,
-	.ack_interrupt  = &vsc85xx_ack_interrupt,
+	.handle_interrupt = vsc85xx_handle_interrupt,
 	.config_intr    = &vsc85xx_config_intr,
-	.did_interrupt  = &vsc8584_did_interrupt,
 	.suspend	= &genphy_suspend,
 	.resume		= &genphy_resume,
 	.probe		= &vsc8574_probe,
@@ -2388,7 +2391,6 @@ static struct phy_driver vsc85xx_driver[] = {
 	.handle_interrupt = &vsc8584_handle_interrupt,
 	.ack_interrupt  = &vsc85xx_ack_interrupt,
 	.config_intr    = &vsc85xx_config_intr,
-	.did_interrupt  = &vsc8584_did_interrupt,
 	.suspend	= &genphy_suspend,
 	.resume		= &genphy_resume,
 	.probe		= &vsc8584_probe,
@@ -2413,7 +2415,6 @@ static struct phy_driver vsc85xx_driver[] = {
 	.handle_interrupt = &vsc8584_handle_interrupt,
 	.ack_interrupt  = &vsc85xx_ack_interrupt,
 	.config_intr    = &vsc85xx_config_intr,
-	.did_interrupt  = &vsc8584_did_interrupt,
 	.suspend	= &genphy_suspend,
 	.resume		= &genphy_resume,
 	.probe		= &vsc8584_probe,
@@ -2438,7 +2439,6 @@ static struct phy_driver vsc85xx_driver[] = {
 	.handle_interrupt = &vsc8584_handle_interrupt,
 	.ack_interrupt  = &vsc85xx_ack_interrupt,
 	.config_intr    = &vsc85xx_config_intr,
-	.did_interrupt  = &vsc8584_did_interrupt,
 	.suspend	= &genphy_suspend,
 	.resume		= &genphy_resume,
 	.probe		= &vsc8584_probe,
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH net-next v2 08/19] net: phy: mscc: remove the use of .ack_interrupt()
  2020-11-01 12:50 [PATCH net-next v2 00/19] net: phy: add support for shared interrupts (part 1) Ioana Ciornei
                   ` (6 preceding siblings ...)
  2020-11-01 12:51 ` [PATCH net-next v2 07/19] net: phy: mscc: implement generic .handle_interrupt() callback Ioana Ciornei
@ 2020-11-01 12:51 ` Ioana Ciornei
  2020-11-05  0:07   ` Vladimir Oltean
  2020-11-01 12:51 ` [PATCH net-next v2 09/19] net: phy: aquantia: implement generic .handle_interrupt() callback Ioana Ciornei
                   ` (13 subsequent siblings)
  21 siblings, 1 reply; 31+ messages in thread
From: Ioana Ciornei @ 2020-11-01 12:51 UTC (permalink / raw)
  To: Andrew Lunn, Heiner Kallweit, Russell King, Florian Fainelli,
	Jakub Kicinski, netdev, linux-kernel
  Cc: Ioana Ciornei, Antoine Tenart

From: Ioana Ciornei <ioana.ciornei@nxp.com>

In preparation of removing the .ack_interrupt() callback, we must replace
its occurrences (aka phy_clear_interrupt), from the 2 places where it is
called from (phy_enable_interrupts and phy_disable_interrupts), with
equivalent functionality.

This means that clearing interrupts now becomes something that the PHY
driver is responsible of doing, before enabling interrupts and after
clearing them. Make this driver follow the new contract.

Cc: Antoine Tenart <atenart@kernel.org>
Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
---
Changes in v2:
 - none

 drivers/net/phy/mscc/mscc_main.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/drivers/net/phy/mscc/mscc_main.c b/drivers/net/phy/mscc/mscc_main.c
index 48883730bf6f..2f2157e3deab 100644
--- a/drivers/net/phy/mscc/mscc_main.c
+++ b/drivers/net/phy/mscc/mscc_main.c
@@ -1923,6 +1923,10 @@ static int vsc85xx_config_intr(struct phy_device *phydev)
 	int rc;
 
 	if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
+		rc = vsc85xx_ack_interrupt(phydev);
+		if (rc)
+			return rc;
+
 		vsc8584_config_macsec_intr(phydev);
 		vsc8584_config_ts_intr(phydev);
 
@@ -1933,6 +1937,10 @@ static int vsc85xx_config_intr(struct phy_device *phydev)
 		if (rc < 0)
 			return rc;
 		rc = phy_read(phydev, MII_VSC85XX_INT_STATUS);
+		if (rc < 0)
+			return rc;
+
+		rc = vsc85xx_ack_interrupt(phydev);
 	}
 
 	return rc;
@@ -2338,7 +2346,6 @@ static struct phy_driver vsc85xx_driver[] = {
 	.aneg_done	= &genphy_aneg_done,
 	.read_status	= &vsc85xx_read_status,
 	.handle_interrupt = &vsc8584_handle_interrupt,
-	.ack_interrupt  = &vsc85xx_ack_interrupt,
 	.config_intr    = &vsc85xx_config_intr,
 	.suspend	= &genphy_suspend,
 	.resume		= &genphy_resume,
@@ -2389,7 +2396,6 @@ static struct phy_driver vsc85xx_driver[] = {
 	.aneg_done	= &genphy_aneg_done,
 	.read_status	= &vsc85xx_read_status,
 	.handle_interrupt = &vsc8584_handle_interrupt,
-	.ack_interrupt  = &vsc85xx_ack_interrupt,
 	.config_intr    = &vsc85xx_config_intr,
 	.suspend	= &genphy_suspend,
 	.resume		= &genphy_resume,
@@ -2413,7 +2419,6 @@ static struct phy_driver vsc85xx_driver[] = {
 	.aneg_done	= &genphy_aneg_done,
 	.read_status	= &vsc85xx_read_status,
 	.handle_interrupt = &vsc8584_handle_interrupt,
-	.ack_interrupt  = &vsc85xx_ack_interrupt,
 	.config_intr    = &vsc85xx_config_intr,
 	.suspend	= &genphy_suspend,
 	.resume		= &genphy_resume,
@@ -2437,7 +2442,6 @@ static struct phy_driver vsc85xx_driver[] = {
 	.aneg_done	= &genphy_aneg_done,
 	.read_status	= &vsc85xx_read_status,
 	.handle_interrupt = &vsc8584_handle_interrupt,
-	.ack_interrupt  = &vsc85xx_ack_interrupt,
 	.config_intr    = &vsc85xx_config_intr,
 	.suspend	= &genphy_suspend,
 	.resume		= &genphy_resume,
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH net-next v2 09/19] net: phy: aquantia: implement generic .handle_interrupt() callback
  2020-11-01 12:50 [PATCH net-next v2 00/19] net: phy: add support for shared interrupts (part 1) Ioana Ciornei
                   ` (7 preceding siblings ...)
  2020-11-01 12:51 ` [PATCH net-next v2 08/19] net: phy: mscc: remove the use of .ack_interrupt() Ioana Ciornei
@ 2020-11-01 12:51 ` Ioana Ciornei
  2020-11-01 12:51 ` [PATCH net-next v2 10/19] net: phy: aquantia: remove the use of .ack_interrupt() Ioana Ciornei
                   ` (12 subsequent siblings)
  21 siblings, 0 replies; 31+ messages in thread
From: Ioana Ciornei @ 2020-11-01 12:51 UTC (permalink / raw)
  To: Andrew Lunn, Heiner Kallweit, Russell King, Florian Fainelli,
	Jakub Kicinski, netdev, linux-kernel
  Cc: Ioana Ciornei

From: Ioana Ciornei <ioana.ciornei@nxp.com>

In an attempt to actually support shared IRQs in phylib, we now move the
responsibility of triggering the phylib state machine or just returning
IRQ_NONE, based on the IRQ status register, to the PHY driver. Having
3 different IRQ handling callbacks (.handle_interrupt(),
.did_interrupt() and .ack_interrupt() ) is confusing so let the PHY
driver implement directly an IRQ handler like any other device driver.
Make this driver follow the new convention.

Cc: Heiner Kallweit <hkallweit1@gmail.com>
Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
---
Changes in v2:
 - adjust .handle_interrupt() so that we only take into account the
   enabled IRQs.

 drivers/net/phy/aquantia_main.c | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/drivers/net/phy/aquantia_main.c b/drivers/net/phy/aquantia_main.c
index 41e7c1432497..17b33f0cb179 100644
--- a/drivers/net/phy/aquantia_main.c
+++ b/drivers/net/phy/aquantia_main.c
@@ -52,6 +52,7 @@
 #define MDIO_AN_TX_VEND_INT_STATUS1_DOWNSHIFT	BIT(1)
 
 #define MDIO_AN_TX_VEND_INT_STATUS2		0xcc01
+#define MDIO_AN_TX_VEND_INT_STATUS2_MASK	BIT(0)
 
 #define MDIO_AN_TX_VEND_INT_MASK2		0xd401
 #define MDIO_AN_TX_VEND_INT_MASK2_LINK		BIT(0)
@@ -270,6 +271,25 @@ static int aqr_ack_interrupt(struct phy_device *phydev)
 	return (reg < 0) ? reg : 0;
 }
 
+static irqreturn_t aqr_handle_interrupt(struct phy_device *phydev)
+{
+	int irq_status;
+
+	irq_status = phy_read_mmd(phydev, MDIO_MMD_AN,
+				  MDIO_AN_TX_VEND_INT_STATUS2);
+	if (irq_status < 0) {
+		phy_error(phydev);
+		return IRQ_NONE;
+	}
+
+	if (!(irq_status & MDIO_AN_TX_VEND_INT_STATUS2_MASK))
+		return IRQ_NONE;
+
+	phy_trigger_machine(phydev);
+
+	return IRQ_HANDLED;
+}
+
 static int aqr_read_status(struct phy_device *phydev)
 {
 	int val;
@@ -585,6 +605,7 @@ static struct phy_driver aqr_driver[] = {
 	.config_aneg    = aqr_config_aneg,
 	.config_intr	= aqr_config_intr,
 	.ack_interrupt	= aqr_ack_interrupt,
+	.handle_interrupt = aqr_handle_interrupt,
 	.read_status	= aqr_read_status,
 },
 {
@@ -593,6 +614,7 @@ static struct phy_driver aqr_driver[] = {
 	.config_aneg    = aqr_config_aneg,
 	.config_intr	= aqr_config_intr,
 	.ack_interrupt	= aqr_ack_interrupt,
+	.handle_interrupt = aqr_handle_interrupt,
 	.read_status	= aqr_read_status,
 },
 {
@@ -601,6 +623,7 @@ static struct phy_driver aqr_driver[] = {
 	.config_aneg    = aqr_config_aneg,
 	.config_intr	= aqr_config_intr,
 	.ack_interrupt	= aqr_ack_interrupt,
+	.handle_interrupt = aqr_handle_interrupt,
 	.read_status	= aqr_read_status,
 	.suspend	= aqr107_suspend,
 	.resume		= aqr107_resume,
@@ -611,6 +634,7 @@ static struct phy_driver aqr_driver[] = {
 	.config_aneg    = aqr_config_aneg,
 	.config_intr	= aqr_config_intr,
 	.ack_interrupt	= aqr_ack_interrupt,
+	.handle_interrupt = aqr_handle_interrupt,
 	.read_status	= aqr_read_status,
 },
 {
@@ -621,6 +645,7 @@ static struct phy_driver aqr_driver[] = {
 	.config_aneg    = aqr_config_aneg,
 	.config_intr	= aqr_config_intr,
 	.ack_interrupt	= aqr_ack_interrupt,
+	.handle_interrupt = aqr_handle_interrupt,
 	.read_status	= aqr107_read_status,
 	.get_tunable    = aqr107_get_tunable,
 	.set_tunable    = aqr107_set_tunable,
@@ -639,6 +664,7 @@ static struct phy_driver aqr_driver[] = {
 	.config_aneg    = aqr_config_aneg,
 	.config_intr	= aqr_config_intr,
 	.ack_interrupt	= aqr_ack_interrupt,
+	.handle_interrupt = aqr_handle_interrupt,
 	.read_status	= aqr107_read_status,
 	.get_tunable    = aqr107_get_tunable,
 	.set_tunable    = aqr107_set_tunable,
@@ -655,6 +681,7 @@ static struct phy_driver aqr_driver[] = {
 	.config_aneg    = aqr_config_aneg,
 	.config_intr	= aqr_config_intr,
 	.ack_interrupt	= aqr_ack_interrupt,
+	.handle_interrupt = aqr_handle_interrupt,
 	.read_status	= aqr_read_status,
 },
 };
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH net-next v2 10/19] net: phy: aquantia: remove the use of .ack_interrupt()
  2020-11-01 12:50 [PATCH net-next v2 00/19] net: phy: add support for shared interrupts (part 1) Ioana Ciornei
                   ` (8 preceding siblings ...)
  2020-11-01 12:51 ` [PATCH net-next v2 09/19] net: phy: aquantia: implement generic .handle_interrupt() callback Ioana Ciornei
@ 2020-11-01 12:51 ` Ioana Ciornei
  2020-11-01 12:51 ` [PATCH net-next v2 11/19] net: phy: broadcom: implement generic .handle_interrupt() callback Ioana Ciornei
                   ` (11 subsequent siblings)
  21 siblings, 0 replies; 31+ messages in thread
From: Ioana Ciornei @ 2020-11-01 12:51 UTC (permalink / raw)
  To: Andrew Lunn, Heiner Kallweit, Russell King, Florian Fainelli,
	Jakub Kicinski, netdev, linux-kernel
  Cc: Ioana Ciornei

From: Ioana Ciornei <ioana.ciornei@nxp.com>

In preparation of removing the .ack_interrupt() callback, we must replace
its occurrences (aka phy_clear_interrupt), from the 2 places where it is
called from (phy_enable_interrupts and phy_disable_interrupts), with
equivalent functionality.

This means that clearing interrupts now becomes something that the PHY
driver is responsible of doing, before enabling interrupts and after
clearing them. Make this driver follow the new contract.

Cc: Heiner Kallweit <hkallweit1@gmail.com>
Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
---
Changes in v2:
 - none

 drivers/net/phy/aquantia_main.c | 36 +++++++++++++++++----------------
 1 file changed, 19 insertions(+), 17 deletions(-)

diff --git a/drivers/net/phy/aquantia_main.c b/drivers/net/phy/aquantia_main.c
index 17b33f0cb179..345f70f9d39b 100644
--- a/drivers/net/phy/aquantia_main.c
+++ b/drivers/net/phy/aquantia_main.c
@@ -247,6 +247,13 @@ static int aqr_config_intr(struct phy_device *phydev)
 	bool en = phydev->interrupts == PHY_INTERRUPT_ENABLED;
 	int err;
 
+	if (en) {
+		/* Clear any pending interrupts before enabling them */
+		err = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_TX_VEND_INT_STATUS2);
+		if (err)
+			return err;
+	}
+
 	err = phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_TX_VEND_INT_MASK2,
 			    en ? MDIO_AN_TX_VEND_INT_MASK2_LINK : 0);
 	if (err < 0)
@@ -257,18 +264,20 @@ static int aqr_config_intr(struct phy_device *phydev)
 	if (err < 0)
 		return err;
 
-	return phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_INT_VEND_MASK,
-			     en ? VEND1_GLOBAL_INT_VEND_MASK_GLOBAL3 |
-			     VEND1_GLOBAL_INT_VEND_MASK_AN : 0);
-}
+	err = phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_INT_VEND_MASK,
+			    en ? VEND1_GLOBAL_INT_VEND_MASK_GLOBAL3 |
+			    VEND1_GLOBAL_INT_VEND_MASK_AN : 0);
+	if (err < 0)
+		return err;
 
-static int aqr_ack_interrupt(struct phy_device *phydev)
-{
-	int reg;
+	if (!en) {
+		/* Clear any pending interrupts after we have disabled them */
+		err = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_TX_VEND_INT_STATUS2);
+		if (err)
+			return err;
+	}
 
-	reg = phy_read_mmd(phydev, MDIO_MMD_AN,
-			   MDIO_AN_TX_VEND_INT_STATUS2);
-	return (reg < 0) ? reg : 0;
+	return 0;
 }
 
 static irqreturn_t aqr_handle_interrupt(struct phy_device *phydev)
@@ -604,7 +613,6 @@ static struct phy_driver aqr_driver[] = {
 	.name		= "Aquantia AQ1202",
 	.config_aneg    = aqr_config_aneg,
 	.config_intr	= aqr_config_intr,
-	.ack_interrupt	= aqr_ack_interrupt,
 	.handle_interrupt = aqr_handle_interrupt,
 	.read_status	= aqr_read_status,
 },
@@ -613,7 +621,6 @@ static struct phy_driver aqr_driver[] = {
 	.name		= "Aquantia AQ2104",
 	.config_aneg    = aqr_config_aneg,
 	.config_intr	= aqr_config_intr,
-	.ack_interrupt	= aqr_ack_interrupt,
 	.handle_interrupt = aqr_handle_interrupt,
 	.read_status	= aqr_read_status,
 },
@@ -622,7 +629,6 @@ static struct phy_driver aqr_driver[] = {
 	.name		= "Aquantia AQR105",
 	.config_aneg    = aqr_config_aneg,
 	.config_intr	= aqr_config_intr,
-	.ack_interrupt	= aqr_ack_interrupt,
 	.handle_interrupt = aqr_handle_interrupt,
 	.read_status	= aqr_read_status,
 	.suspend	= aqr107_suspend,
@@ -633,7 +639,6 @@ static struct phy_driver aqr_driver[] = {
 	.name		= "Aquantia AQR106",
 	.config_aneg    = aqr_config_aneg,
 	.config_intr	= aqr_config_intr,
-	.ack_interrupt	= aqr_ack_interrupt,
 	.handle_interrupt = aqr_handle_interrupt,
 	.read_status	= aqr_read_status,
 },
@@ -644,7 +649,6 @@ static struct phy_driver aqr_driver[] = {
 	.config_init	= aqr107_config_init,
 	.config_aneg    = aqr_config_aneg,
 	.config_intr	= aqr_config_intr,
-	.ack_interrupt	= aqr_ack_interrupt,
 	.handle_interrupt = aqr_handle_interrupt,
 	.read_status	= aqr107_read_status,
 	.get_tunable    = aqr107_get_tunable,
@@ -663,7 +667,6 @@ static struct phy_driver aqr_driver[] = {
 	.config_init	= aqcs109_config_init,
 	.config_aneg    = aqr_config_aneg,
 	.config_intr	= aqr_config_intr,
-	.ack_interrupt	= aqr_ack_interrupt,
 	.handle_interrupt = aqr_handle_interrupt,
 	.read_status	= aqr107_read_status,
 	.get_tunable    = aqr107_get_tunable,
@@ -680,7 +683,6 @@ static struct phy_driver aqr_driver[] = {
 	.name		= "Aquantia AQR405",
 	.config_aneg    = aqr_config_aneg,
 	.config_intr	= aqr_config_intr,
-	.ack_interrupt	= aqr_ack_interrupt,
 	.handle_interrupt = aqr_handle_interrupt,
 	.read_status	= aqr_read_status,
 },
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH net-next v2 11/19] net: phy: broadcom: implement generic .handle_interrupt() callback
  2020-11-01 12:50 [PATCH net-next v2 00/19] net: phy: add support for shared interrupts (part 1) Ioana Ciornei
                   ` (9 preceding siblings ...)
  2020-11-01 12:51 ` [PATCH net-next v2 10/19] net: phy: aquantia: remove the use of .ack_interrupt() Ioana Ciornei
@ 2020-11-01 12:51 ` Ioana Ciornei
  2020-11-01 12:51 ` [PATCH net-next v2 12/19] net: phy: broadcom: remove use of ack_interrupt() Ioana Ciornei
                   ` (10 subsequent siblings)
  21 siblings, 0 replies; 31+ messages in thread
From: Ioana Ciornei @ 2020-11-01 12:51 UTC (permalink / raw)
  To: Andrew Lunn, Heiner Kallweit, Russell King, Florian Fainelli,
	Jakub Kicinski, netdev, linux-kernel
  Cc: Ioana Ciornei, Michael Walle

From: Ioana Ciornei <ioana.ciornei@nxp.com>

In an attempt to actually support shared IRQs in phylib, we now move the
responsibility of triggering the phylib state machine or just returning
IRQ_NONE, based on the IRQ status register, to the PHY driver. Having
3 different IRQ handling callbacks (.handle_interrupt(),
.did_interrupt() and .ack_interrupt() ) is confusing so let the PHY
driver implement directly an IRQ handler like any other device driver.
Make this driver follow the new convention.

Cc: Michael Walle <michael@walle.cc>
Cc: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
---
Changes in v2:
 - Adjust .handle_interrupt() so that we only take into account the
   enabled IRQs. The BCM8706, BCM8727, BCMAC131 and BCM5241 were the
   only devices which I did not do this change since I do not have
   access to the register map.

 drivers/net/phy/bcm-cygnus.c  |  1 +
 drivers/net/phy/bcm-phy-lib.c | 31 ++++++++++++++++++++++++++++++
 drivers/net/phy/bcm-phy-lib.h |  1 +
 drivers/net/phy/bcm54140.c    | 26 ++++++++++++++++++++-----
 drivers/net/phy/bcm63xx.c     |  2 ++
 drivers/net/phy/bcm87xx.c     | 32 +++++++++++++++++++++----------
 drivers/net/phy/broadcom.c    | 36 +++++++++++++++++++++++++++++++++++
 7 files changed, 114 insertions(+), 15 deletions(-)

diff --git a/drivers/net/phy/bcm-cygnus.c b/drivers/net/phy/bcm-cygnus.c
index 9ccf28b0a04d..a236e0b8d04d 100644
--- a/drivers/net/phy/bcm-cygnus.c
+++ b/drivers/net/phy/bcm-cygnus.c
@@ -258,6 +258,7 @@ static struct phy_driver bcm_cygnus_phy_driver[] = {
 	.config_init   = bcm_cygnus_config_init,
 	.ack_interrupt = bcm_phy_ack_intr,
 	.config_intr   = bcm_phy_config_intr,
+	.handle_interrupt = bcm_phy_handle_interrupt,
 	.suspend       = genphy_suspend,
 	.resume        = bcm_cygnus_resume,
 }, {
diff --git a/drivers/net/phy/bcm-phy-lib.c b/drivers/net/phy/bcm-phy-lib.c
index ef6825b30323..c232fcfe0e20 100644
--- a/drivers/net/phy/bcm-phy-lib.c
+++ b/drivers/net/phy/bcm-phy-lib.c
@@ -196,6 +196,37 @@ int bcm_phy_config_intr(struct phy_device *phydev)
 }
 EXPORT_SYMBOL_GPL(bcm_phy_config_intr);
 
+irqreturn_t bcm_phy_handle_interrupt(struct phy_device *phydev)
+{
+	int irq_status, irq_mask;
+
+	irq_status = phy_read(phydev, MII_BCM54XX_ISR);
+	if (irq_status < 0) {
+		phy_error(phydev);
+		return IRQ_NONE;
+	}
+
+	/* If a bit from the Interrupt Mask register is set, the corresponding
+	 * bit from the Interrupt Status register is masked. So read the IMR
+	 * and then flip the bits to get the list of possible interrupt
+	 * sources.
+	 */
+	irq_mask = phy_read(phydev, MII_BCM54XX_IMR);
+	if (irq_mask < 0) {
+		phy_error(phydev);
+		return IRQ_NONE;
+	}
+	irq_mask = ~irq_mask;
+
+	if (!(irq_status & irq_mask))
+		return IRQ_NONE;
+
+	phy_trigger_machine(phydev);
+
+	return IRQ_HANDLED;
+}
+EXPORT_SYMBOL_GPL(bcm_phy_handle_interrupt);
+
 int bcm_phy_read_shadow(struct phy_device *phydev, u16 shadow)
 {
 	phy_write(phydev, MII_BCM54XX_SHD, MII_BCM54XX_SHD_VAL(shadow));
diff --git a/drivers/net/phy/bcm-phy-lib.h b/drivers/net/phy/bcm-phy-lib.h
index 237a8503c9b4..c3842f87c33b 100644
--- a/drivers/net/phy/bcm-phy-lib.h
+++ b/drivers/net/phy/bcm-phy-lib.h
@@ -63,6 +63,7 @@ int bcm_phy_modify_rdb(struct phy_device *phydev, u16 rdb, u16 mask,
 
 int bcm_phy_ack_intr(struct phy_device *phydev);
 int bcm_phy_config_intr(struct phy_device *phydev);
+irqreturn_t bcm_phy_handle_interrupt(struct phy_device *phydev);
 
 int bcm_phy_enable_apd(struct phy_device *phydev, bool dll_pwr_down);
 
diff --git a/drivers/net/phy/bcm54140.c b/drivers/net/phy/bcm54140.c
index 8998e68bb26b..36c899a88c5d 100644
--- a/drivers/net/phy/bcm54140.c
+++ b/drivers/net/phy/bcm54140.c
@@ -637,13 +637,29 @@ static int bcm54140_config_init(struct phy_device *phydev)
 				  BCM54140_RDB_C_PWR_ISOLATE, 0);
 }
 
-static int bcm54140_did_interrupt(struct phy_device *phydev)
+static irqreturn_t bcm54140_handle_interrupt(struct phy_device *phydev)
 {
-	int ret;
+	int irq_status, irq_mask;
+
+	irq_status = bcm_phy_read_rdb(phydev, BCM54140_RDB_ISR);
+	if (irq_status < 0) {
+		phy_error(phydev);
+		return IRQ_NONE;
+	}
+
+	irq_mask = bcm_phy_read_rdb(phydev, BCM54140_RDB_IMR);
+	if (irq_mask < 0) {
+		phy_error(phydev);
+		return IRQ_NONE;
+	}
+	irq_mask = ~irq_mask;
+
+	if (!(irq_status & irq_mask))
+		return IRQ_NONE;
 
-	ret = bcm_phy_read_rdb(phydev, BCM54140_RDB_ISR);
+	phy_trigger_machine(phydev);
 
-	return (ret < 0) ? 0 : ret;
+	return IRQ_HANDLED;
 }
 
 static int bcm54140_ack_intr(struct phy_device *phydev)
@@ -834,8 +850,8 @@ static struct phy_driver bcm54140_drivers[] = {
 		.flags		= PHY_POLL_CABLE_TEST,
 		.features       = PHY_GBIT_FEATURES,
 		.config_init    = bcm54140_config_init,
-		.did_interrupt	= bcm54140_did_interrupt,
 		.ack_interrupt  = bcm54140_ack_intr,
+		.handle_interrupt = bcm54140_handle_interrupt,
 		.config_intr    = bcm54140_config_intr,
 		.probe		= bcm54140_probe,
 		.suspend	= genphy_suspend,
diff --git a/drivers/net/phy/bcm63xx.c b/drivers/net/phy/bcm63xx.c
index 459fb2069c7e..818c853b6638 100644
--- a/drivers/net/phy/bcm63xx.c
+++ b/drivers/net/phy/bcm63xx.c
@@ -69,6 +69,7 @@ static struct phy_driver bcm63xx_driver[] = {
 	.config_init	= bcm63xx_config_init,
 	.ack_interrupt	= bcm_phy_ack_intr,
 	.config_intr	= bcm63xx_config_intr,
+	.handle_interrupt = bcm_phy_handle_interrupt,
 }, {
 	/* same phy as above, with just a different OUI */
 	.phy_id		= 0x002bdc00,
@@ -79,6 +80,7 @@ static struct phy_driver bcm63xx_driver[] = {
 	.config_init	= bcm63xx_config_init,
 	.ack_interrupt	= bcm_phy_ack_intr,
 	.config_intr	= bcm63xx_config_intr,
+	.handle_interrupt = bcm_phy_handle_interrupt,
 } };
 
 module_phy_driver(bcm63xx_driver);
diff --git a/drivers/net/phy/bcm87xx.c b/drivers/net/phy/bcm87xx.c
index df360e1c5069..f20cfb05ef04 100644
--- a/drivers/net/phy/bcm87xx.c
+++ b/drivers/net/phy/bcm87xx.c
@@ -153,10 +153,29 @@ static int bcm87xx_config_intr(struct phy_device *phydev)
 	return err;
 }
 
-static int bcm87xx_did_interrupt(struct phy_device *phydev)
+static irqreturn_t bcm87xx_handle_interrupt(struct phy_device *phydev)
+{
+	int irq_status;
+
+	irq_status = phy_read(phydev, BCM87XX_LASI_STATUS);
+	if (irq_status < 0) {
+		phy_error(phydev);
+		return IRQ_NONE;
+	}
+
+	if (irq_status == 0)
+		return IRQ_NONE;
+
+	phy_trigger_machine(phydev);
+
+	return IRQ_HANDLED;
+}
+
+static int bcm87xx_ack_interrupt(struct phy_device *phydev)
 {
 	int reg;
 
+	/* Reading the LASI status clears it. */
 	reg = phy_read(phydev, BCM87XX_LASI_STATUS);
 
 	if (reg < 0) {
@@ -168,13 +187,6 @@ static int bcm87xx_did_interrupt(struct phy_device *phydev)
 	return (reg & 1) != 0;
 }
 
-static int bcm87xx_ack_interrupt(struct phy_device *phydev)
-{
-	/* Reading the LASI status clears it. */
-	bcm87xx_did_interrupt(phydev);
-	return 0;
-}
-
 static int bcm8706_match_phy_device(struct phy_device *phydev)
 {
 	return phydev->c45_ids.device_ids[4] == PHY_ID_BCM8706;
@@ -196,7 +208,7 @@ static struct phy_driver bcm87xx_driver[] = {
 	.read_status	= bcm87xx_read_status,
 	.ack_interrupt	= bcm87xx_ack_interrupt,
 	.config_intr	= bcm87xx_config_intr,
-	.did_interrupt	= bcm87xx_did_interrupt,
+	.handle_interrupt = bcm87xx_handle_interrupt,
 	.match_phy_device = bcm8706_match_phy_device,
 }, {
 	.phy_id		= PHY_ID_BCM8727,
@@ -208,7 +220,7 @@ static struct phy_driver bcm87xx_driver[] = {
 	.read_status	= bcm87xx_read_status,
 	.ack_interrupt	= bcm87xx_ack_interrupt,
 	.config_intr	= bcm87xx_config_intr,
-	.did_interrupt	= bcm87xx_did_interrupt,
+	.handle_interrupt = bcm87xx_handle_interrupt,
 	.match_phy_device = bcm8727_match_phy_device,
 } };
 
diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c
index cd271de9609b..8bcdb94ef2fc 100644
--- a/drivers/net/phy/broadcom.c
+++ b/drivers/net/phy/broadcom.c
@@ -643,6 +643,24 @@ static int brcm_fet_config_intr(struct phy_device *phydev)
 	return err;
 }
 
+static irqreturn_t brcm_fet_handle_interrupt(struct phy_device *phydev)
+{
+	int irq_status;
+
+	irq_status = phy_read(phydev, MII_BRCM_FET_INTREG);
+	if (irq_status < 0) {
+		phy_error(phydev);
+		return IRQ_NONE;
+	}
+
+	if (irq_status == 0)
+		return IRQ_NONE;
+
+	phy_trigger_machine(phydev);
+
+	return IRQ_HANDLED;
+}
+
 struct bcm53xx_phy_priv {
 	u64	*stats;
 };
@@ -683,6 +701,7 @@ static struct phy_driver broadcom_drivers[] = {
 	.config_init	= bcm54xx_config_init,
 	.ack_interrupt	= bcm_phy_ack_intr,
 	.config_intr	= bcm_phy_config_intr,
+	.handle_interrupt = bcm_phy_handle_interrupt,
 }, {
 	.phy_id		= PHY_ID_BCM5421,
 	.phy_id_mask	= 0xfffffff0,
@@ -691,6 +710,7 @@ static struct phy_driver broadcom_drivers[] = {
 	.config_init	= bcm54xx_config_init,
 	.ack_interrupt	= bcm_phy_ack_intr,
 	.config_intr	= bcm_phy_config_intr,
+	.handle_interrupt = bcm_phy_handle_interrupt,
 }, {
 	.phy_id		= PHY_ID_BCM54210E,
 	.phy_id_mask	= 0xfffffff0,
@@ -699,6 +719,7 @@ static struct phy_driver broadcom_drivers[] = {
 	.config_init	= bcm54xx_config_init,
 	.ack_interrupt	= bcm_phy_ack_intr,
 	.config_intr	= bcm_phy_config_intr,
+	.handle_interrupt = bcm_phy_handle_interrupt,
 }, {
 	.phy_id		= PHY_ID_BCM5461,
 	.phy_id_mask	= 0xfffffff0,
@@ -707,6 +728,7 @@ static struct phy_driver broadcom_drivers[] = {
 	.config_init	= bcm54xx_config_init,
 	.ack_interrupt	= bcm_phy_ack_intr,
 	.config_intr	= bcm_phy_config_intr,
+	.handle_interrupt = bcm_phy_handle_interrupt,
 }, {
 	.phy_id		= PHY_ID_BCM54612E,
 	.phy_id_mask	= 0xfffffff0,
@@ -715,6 +737,7 @@ static struct phy_driver broadcom_drivers[] = {
 	.config_init	= bcm54xx_config_init,
 	.ack_interrupt	= bcm_phy_ack_intr,
 	.config_intr	= bcm_phy_config_intr,
+	.handle_interrupt = bcm_phy_handle_interrupt,
 }, {
 	.phy_id		= PHY_ID_BCM54616S,
 	.phy_id_mask	= 0xfffffff0,
@@ -724,6 +747,7 @@ static struct phy_driver broadcom_drivers[] = {
 	.config_aneg	= bcm54616s_config_aneg,
 	.ack_interrupt	= bcm_phy_ack_intr,
 	.config_intr	= bcm_phy_config_intr,
+	.handle_interrupt = bcm_phy_handle_interrupt,
 	.read_status	= bcm54616s_read_status,
 	.probe		= bcm54616s_probe,
 }, {
@@ -734,6 +758,7 @@ static struct phy_driver broadcom_drivers[] = {
 	.config_init	= bcm54xx_config_init,
 	.ack_interrupt	= bcm_phy_ack_intr,
 	.config_intr	= bcm_phy_config_intr,
+	.handle_interrupt = bcm_phy_handle_interrupt,
 	.suspend	= genphy_suspend,
 	.resume		= genphy_resume,
 }, {
@@ -745,6 +770,7 @@ static struct phy_driver broadcom_drivers[] = {
 	.config_aneg	= bcm5481_config_aneg,
 	.ack_interrupt	= bcm_phy_ack_intr,
 	.config_intr	= bcm_phy_config_intr,
+	.handle_interrupt = bcm_phy_handle_interrupt,
 }, {
 	.phy_id         = PHY_ID_BCM54810,
 	.phy_id_mask    = 0xfffffff0,
@@ -754,6 +780,7 @@ static struct phy_driver broadcom_drivers[] = {
 	.config_aneg    = bcm5481_config_aneg,
 	.ack_interrupt  = bcm_phy_ack_intr,
 	.config_intr    = bcm_phy_config_intr,
+	.handle_interrupt = bcm_phy_handle_interrupt,
 	.suspend	= genphy_suspend,
 	.resume		= bcm54xx_resume,
 }, {
@@ -765,6 +792,7 @@ static struct phy_driver broadcom_drivers[] = {
 	.config_aneg    = bcm5481_config_aneg,
 	.ack_interrupt  = bcm_phy_ack_intr,
 	.config_intr    = bcm_phy_config_intr,
+	.handle_interrupt = bcm_phy_handle_interrupt,
 	.suspend	= genphy_suspend,
 	.resume		= bcm54xx_resume,
 }, {
@@ -776,6 +804,7 @@ static struct phy_driver broadcom_drivers[] = {
 	.read_status	= bcm5482_read_status,
 	.ack_interrupt	= bcm_phy_ack_intr,
 	.config_intr	= bcm_phy_config_intr,
+	.handle_interrupt = bcm_phy_handle_interrupt,
 }, {
 	.phy_id		= PHY_ID_BCM50610,
 	.phy_id_mask	= 0xfffffff0,
@@ -784,6 +813,7 @@ static struct phy_driver broadcom_drivers[] = {
 	.config_init	= bcm54xx_config_init,
 	.ack_interrupt	= bcm_phy_ack_intr,
 	.config_intr	= bcm_phy_config_intr,
+	.handle_interrupt = bcm_phy_handle_interrupt,
 }, {
 	.phy_id		= PHY_ID_BCM50610M,
 	.phy_id_mask	= 0xfffffff0,
@@ -792,6 +822,7 @@ static struct phy_driver broadcom_drivers[] = {
 	.config_init	= bcm54xx_config_init,
 	.ack_interrupt	= bcm_phy_ack_intr,
 	.config_intr	= bcm_phy_config_intr,
+	.handle_interrupt = bcm_phy_handle_interrupt,
 }, {
 	.phy_id		= PHY_ID_BCM57780,
 	.phy_id_mask	= 0xfffffff0,
@@ -800,6 +831,7 @@ static struct phy_driver broadcom_drivers[] = {
 	.config_init	= bcm54xx_config_init,
 	.ack_interrupt	= bcm_phy_ack_intr,
 	.config_intr	= bcm_phy_config_intr,
+	.handle_interrupt = bcm_phy_handle_interrupt,
 }, {
 	.phy_id		= PHY_ID_BCMAC131,
 	.phy_id_mask	= 0xfffffff0,
@@ -808,6 +840,7 @@ static struct phy_driver broadcom_drivers[] = {
 	.config_init	= brcm_fet_config_init,
 	.ack_interrupt	= brcm_fet_ack_interrupt,
 	.config_intr	= brcm_fet_config_intr,
+	.handle_interrupt = brcm_fet_handle_interrupt,
 }, {
 	.phy_id		= PHY_ID_BCM5241,
 	.phy_id_mask	= 0xfffffff0,
@@ -816,6 +849,7 @@ static struct phy_driver broadcom_drivers[] = {
 	.config_init	= brcm_fet_config_init,
 	.ack_interrupt	= brcm_fet_ack_interrupt,
 	.config_intr	= brcm_fet_config_intr,
+	.handle_interrupt = brcm_fet_handle_interrupt,
 }, {
 	.phy_id		= PHY_ID_BCM5395,
 	.phy_id_mask	= 0xfffffff0,
@@ -839,6 +873,7 @@ static struct phy_driver broadcom_drivers[] = {
 	.config_init	= bcm54xx_config_init,
 	.ack_interrupt	= bcm_phy_ack_intr,
 	.config_intr	= bcm_phy_config_intr,
+	.handle_interrupt = bcm_phy_handle_interrupt,
 }, {
 	.phy_id         = PHY_ID_BCM89610,
 	.phy_id_mask    = 0xfffffff0,
@@ -847,6 +882,7 @@ static struct phy_driver broadcom_drivers[] = {
 	.config_init    = bcm54xx_config_init,
 	.ack_interrupt  = bcm_phy_ack_intr,
 	.config_intr    = bcm_phy_config_intr,
+	.handle_interrupt = bcm_phy_handle_interrupt,
 } };
 
 module_phy_driver(broadcom_drivers);
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH net-next v2 12/19] net: phy: broadcom: remove use of ack_interrupt()
  2020-11-01 12:50 [PATCH net-next v2 00/19] net: phy: add support for shared interrupts (part 1) Ioana Ciornei
                   ` (10 preceding siblings ...)
  2020-11-01 12:51 ` [PATCH net-next v2 11/19] net: phy: broadcom: implement generic .handle_interrupt() callback Ioana Ciornei
@ 2020-11-01 12:51 ` Ioana Ciornei
  2020-11-01 12:51 ` [PATCH net-next v2 13/19] net: phy: cicada: implement the generic .handle_interrupt() callback Ioana Ciornei
                   ` (9 subsequent siblings)
  21 siblings, 0 replies; 31+ messages in thread
From: Ioana Ciornei @ 2020-11-01 12:51 UTC (permalink / raw)
  To: Andrew Lunn, Heiner Kallweit, Russell King, Florian Fainelli,
	Jakub Kicinski, netdev, linux-kernel
  Cc: Ioana Ciornei, Michael Walle

From: Ioana Ciornei <ioana.ciornei@nxp.com>

In preparation of removing the .ack_interrupt() callback, we must replace
its occurrences (aka phy_clear_interrupt), from the 2 places where it is
called from (phy_enable_interrupts and phy_disable_interrupts), with
equivalent functionality.

This means that clearing interrupts now becomes something that the PHY
driver is responsible of doing, before enabling interrupts and after
clearing them. Make this driver follow the new contract.

Cc: Michael Walle <michael@walle.cc>
Cc: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
---
Changes in v2:
 - none

 drivers/net/phy/bcm-cygnus.c  |  1 -
 drivers/net/phy/bcm-phy-lib.c | 18 ++++++++++++++----
 drivers/net/phy/bcm54140.c    | 20 +++++++++++++++-----
 drivers/net/phy/bcm63xx.c     | 18 +++++++++++++-----
 drivers/net/phy/bcm87xx.c     | 34 +++++++++++++---------------------
 drivers/net/phy/broadcom.c    | 34 +++++++++++++---------------------
 6 files changed, 68 insertions(+), 57 deletions(-)

diff --git a/drivers/net/phy/bcm-cygnus.c b/drivers/net/phy/bcm-cygnus.c
index a236e0b8d04d..da8f7cb41b44 100644
--- a/drivers/net/phy/bcm-cygnus.c
+++ b/drivers/net/phy/bcm-cygnus.c
@@ -256,7 +256,6 @@ static struct phy_driver bcm_cygnus_phy_driver[] = {
 	.name          = "Broadcom Cygnus PHY",
 	/* PHY_GBIT_FEATURES */
 	.config_init   = bcm_cygnus_config_init,
-	.ack_interrupt = bcm_phy_ack_intr,
 	.config_intr   = bcm_phy_config_intr,
 	.handle_interrupt = bcm_phy_handle_interrupt,
 	.suspend       = genphy_suspend,
diff --git a/drivers/net/phy/bcm-phy-lib.c b/drivers/net/phy/bcm-phy-lib.c
index c232fcfe0e20..53282a6d5928 100644
--- a/drivers/net/phy/bcm-phy-lib.c
+++ b/drivers/net/phy/bcm-phy-lib.c
@@ -181,18 +181,28 @@ EXPORT_SYMBOL_GPL(bcm_phy_ack_intr);
 
 int bcm_phy_config_intr(struct phy_device *phydev)
 {
-	int reg;
+	int reg, err;
 
 	reg = phy_read(phydev, MII_BCM54XX_ECR);
 	if (reg < 0)
 		return reg;
 
-	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
+	if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
+		err = bcm_phy_ack_intr(phydev);
+		if (err)
+			return err;
+
 		reg &= ~MII_BCM54XX_ECR_IM;
-	else
+		err = phy_write(phydev, MII_BCM54XX_ECR, reg);
+	} else {
 		reg |= MII_BCM54XX_ECR_IM;
+		err = phy_write(phydev, MII_BCM54XX_ECR, reg);
+		if (err)
+			return err;
 
-	return phy_write(phydev, MII_BCM54XX_ECR, reg);
+		err = bcm_phy_ack_intr(phydev);
+	}
+	return err;
 }
 EXPORT_SYMBOL_GPL(bcm_phy_config_intr);
 
diff --git a/drivers/net/phy/bcm54140.c b/drivers/net/phy/bcm54140.c
index 36c899a88c5d..d8f3024860dc 100644
--- a/drivers/net/phy/bcm54140.c
+++ b/drivers/net/phy/bcm54140.c
@@ -681,7 +681,7 @@ static int bcm54140_config_intr(struct phy_device *phydev)
 		BCM54140_RDB_TOP_IMR_PORT0, BCM54140_RDB_TOP_IMR_PORT1,
 		BCM54140_RDB_TOP_IMR_PORT2, BCM54140_RDB_TOP_IMR_PORT3,
 	};
-	int reg;
+	int reg, err;
 
 	if (priv->port >= ARRAY_SIZE(port_to_imr_bit))
 		return -EINVAL;
@@ -690,12 +690,23 @@ static int bcm54140_config_intr(struct phy_device *phydev)
 	if (reg < 0)
 		return reg;
 
-	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
+	if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
+		err = bcm54140_ack_intr(phydev);
+		if (err)
+			return err;
+
 		reg &= ~port_to_imr_bit[priv->port];
-	else
+		err = bcm54140_base_write_rdb(phydev, BCM54140_RDB_TOP_IMR, reg);
+	} else {
 		reg |= port_to_imr_bit[priv->port];
+		err = bcm54140_base_write_rdb(phydev, BCM54140_RDB_TOP_IMR, reg);
+		if (err)
+			return err;
+
+		err = bcm54140_ack_intr(phydev);
+	}
 
-	return bcm54140_base_write_rdb(phydev, BCM54140_RDB_TOP_IMR, reg);
+	return err;
 }
 
 static int bcm54140_get_downshift(struct phy_device *phydev, u8 *data)
@@ -850,7 +861,6 @@ static struct phy_driver bcm54140_drivers[] = {
 		.flags		= PHY_POLL_CABLE_TEST,
 		.features       = PHY_GBIT_FEATURES,
 		.config_init    = bcm54140_config_init,
-		.ack_interrupt  = bcm54140_ack_intr,
 		.handle_interrupt = bcm54140_handle_interrupt,
 		.config_intr    = bcm54140_config_intr,
 		.probe		= bcm54140_probe,
diff --git a/drivers/net/phy/bcm63xx.c b/drivers/net/phy/bcm63xx.c
index 818c853b6638..0eb33be824f1 100644
--- a/drivers/net/phy/bcm63xx.c
+++ b/drivers/net/phy/bcm63xx.c
@@ -25,12 +25,22 @@ static int bcm63xx_config_intr(struct phy_device *phydev)
 	if (reg < 0)
 		return reg;
 
-	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
+	if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
+		err = bcm_phy_ack_intr(phydev);
+		if (err)
+			return err;
+
 		reg &= ~MII_BCM63XX_IR_GMASK;
-	else
+		err = phy_write(phydev, MII_BCM63XX_IR, reg);
+	} else {
 		reg |= MII_BCM63XX_IR_GMASK;
+		err = phy_write(phydev, MII_BCM63XX_IR, reg);
+		if (err)
+			return err;
+
+		err = bcm_phy_ack_intr(phydev);
+	}
 
-	err = phy_write(phydev, MII_BCM63XX_IR, reg);
 	return err;
 }
 
@@ -67,7 +77,6 @@ static struct phy_driver bcm63xx_driver[] = {
 	/* PHY_BASIC_FEATURES */
 	.flags		= PHY_IS_INTERNAL,
 	.config_init	= bcm63xx_config_init,
-	.ack_interrupt	= bcm_phy_ack_intr,
 	.config_intr	= bcm63xx_config_intr,
 	.handle_interrupt = bcm_phy_handle_interrupt,
 }, {
@@ -78,7 +87,6 @@ static struct phy_driver bcm63xx_driver[] = {
 	/* PHY_BASIC_FEATURES */
 	.flags		= PHY_IS_INTERNAL,
 	.config_init	= bcm63xx_config_init,
-	.ack_interrupt	= bcm_phy_ack_intr,
 	.config_intr	= bcm63xx_config_intr,
 	.handle_interrupt = bcm_phy_handle_interrupt,
 } };
diff --git a/drivers/net/phy/bcm87xx.c b/drivers/net/phy/bcm87xx.c
index f20cfb05ef04..4ac8fd190e9d 100644
--- a/drivers/net/phy/bcm87xx.c
+++ b/drivers/net/phy/bcm87xx.c
@@ -144,12 +144,22 @@ static int bcm87xx_config_intr(struct phy_device *phydev)
 	if (reg < 0)
 		return reg;
 
-	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
+	if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
+		err = phy_read(phydev, BCM87XX_LASI_STATUS);
+		if (err)
+			return err;
+
 		reg |= 1;
-	else
+		err = phy_write(phydev, BCM87XX_LASI_CONTROL, reg);
+	} else {
 		reg &= ~1;
+		err = phy_write(phydev, BCM87XX_LASI_CONTROL, reg);
+		if (err)
+			return err;
+
+		err = phy_read(phydev, BCM87XX_LASI_STATUS);
+	}
 
-	err = phy_write(phydev, BCM87XX_LASI_CONTROL, reg);
 	return err;
 }
 
@@ -171,22 +181,6 @@ static irqreturn_t bcm87xx_handle_interrupt(struct phy_device *phydev)
 	return IRQ_HANDLED;
 }
 
-static int bcm87xx_ack_interrupt(struct phy_device *phydev)
-{
-	int reg;
-
-	/* Reading the LASI status clears it. */
-	reg = phy_read(phydev, BCM87XX_LASI_STATUS);
-
-	if (reg < 0) {
-		phydev_err(phydev,
-			   "Error: Read of BCM87XX_LASI_STATUS failed: %d\n",
-			   reg);
-		return 0;
-	}
-	return (reg & 1) != 0;
-}
-
 static int bcm8706_match_phy_device(struct phy_device *phydev)
 {
 	return phydev->c45_ids.device_ids[4] == PHY_ID_BCM8706;
@@ -206,7 +200,6 @@ static struct phy_driver bcm87xx_driver[] = {
 	.config_init	= bcm87xx_config_init,
 	.config_aneg	= bcm87xx_config_aneg,
 	.read_status	= bcm87xx_read_status,
-	.ack_interrupt	= bcm87xx_ack_interrupt,
 	.config_intr	= bcm87xx_config_intr,
 	.handle_interrupt = bcm87xx_handle_interrupt,
 	.match_phy_device = bcm8706_match_phy_device,
@@ -218,7 +211,6 @@ static struct phy_driver bcm87xx_driver[] = {
 	.config_init	= bcm87xx_config_init,
 	.config_aneg	= bcm87xx_config_aneg,
 	.read_status	= bcm87xx_read_status,
-	.ack_interrupt	= bcm87xx_ack_interrupt,
 	.config_intr	= bcm87xx_config_intr,
 	.handle_interrupt = bcm87xx_handle_interrupt,
 	.match_phy_device = bcm8727_match_phy_device,
diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c
index 8bcdb94ef2fc..8a4ec3222168 100644
--- a/drivers/net/phy/broadcom.c
+++ b/drivers/net/phy/broadcom.c
@@ -634,12 +634,22 @@ static int brcm_fet_config_intr(struct phy_device *phydev)
 	if (reg < 0)
 		return reg;
 
-	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
+	if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
+		err = brcm_fet_ack_interrupt(phydev);
+		if (err)
+			return err;
+
 		reg &= ~MII_BRCM_FET_IR_MASK;
-	else
+		err = phy_write(phydev, MII_BRCM_FET_INTREG, reg);
+	} else {
 		reg |= MII_BRCM_FET_IR_MASK;
+		err = phy_write(phydev, MII_BRCM_FET_INTREG, reg);
+		if (err)
+			return err;
+
+		err = brcm_fet_ack_interrupt(phydev);
+	}
 
-	err = phy_write(phydev, MII_BRCM_FET_INTREG, reg);
 	return err;
 }
 
@@ -699,7 +709,6 @@ static struct phy_driver broadcom_drivers[] = {
 	.name		= "Broadcom BCM5411",
 	/* PHY_GBIT_FEATURES */
 	.config_init	= bcm54xx_config_init,
-	.ack_interrupt	= bcm_phy_ack_intr,
 	.config_intr	= bcm_phy_config_intr,
 	.handle_interrupt = bcm_phy_handle_interrupt,
 }, {
@@ -708,7 +717,6 @@ static struct phy_driver broadcom_drivers[] = {
 	.name		= "Broadcom BCM5421",
 	/* PHY_GBIT_FEATURES */
 	.config_init	= bcm54xx_config_init,
-	.ack_interrupt	= bcm_phy_ack_intr,
 	.config_intr	= bcm_phy_config_intr,
 	.handle_interrupt = bcm_phy_handle_interrupt,
 }, {
@@ -717,7 +725,6 @@ static struct phy_driver broadcom_drivers[] = {
 	.name		= "Broadcom BCM54210E",
 	/* PHY_GBIT_FEATURES */
 	.config_init	= bcm54xx_config_init,
-	.ack_interrupt	= bcm_phy_ack_intr,
 	.config_intr	= bcm_phy_config_intr,
 	.handle_interrupt = bcm_phy_handle_interrupt,
 }, {
@@ -726,7 +733,6 @@ static struct phy_driver broadcom_drivers[] = {
 	.name		= "Broadcom BCM5461",
 	/* PHY_GBIT_FEATURES */
 	.config_init	= bcm54xx_config_init,
-	.ack_interrupt	= bcm_phy_ack_intr,
 	.config_intr	= bcm_phy_config_intr,
 	.handle_interrupt = bcm_phy_handle_interrupt,
 }, {
@@ -735,7 +741,6 @@ static struct phy_driver broadcom_drivers[] = {
 	.name		= "Broadcom BCM54612E",
 	/* PHY_GBIT_FEATURES */
 	.config_init	= bcm54xx_config_init,
-	.ack_interrupt	= bcm_phy_ack_intr,
 	.config_intr	= bcm_phy_config_intr,
 	.handle_interrupt = bcm_phy_handle_interrupt,
 }, {
@@ -745,7 +750,6 @@ static struct phy_driver broadcom_drivers[] = {
 	/* PHY_GBIT_FEATURES */
 	.config_init	= bcm54xx_config_init,
 	.config_aneg	= bcm54616s_config_aneg,
-	.ack_interrupt	= bcm_phy_ack_intr,
 	.config_intr	= bcm_phy_config_intr,
 	.handle_interrupt = bcm_phy_handle_interrupt,
 	.read_status	= bcm54616s_read_status,
@@ -756,7 +760,6 @@ static struct phy_driver broadcom_drivers[] = {
 	.name		= "Broadcom BCM5464",
 	/* PHY_GBIT_FEATURES */
 	.config_init	= bcm54xx_config_init,
-	.ack_interrupt	= bcm_phy_ack_intr,
 	.config_intr	= bcm_phy_config_intr,
 	.handle_interrupt = bcm_phy_handle_interrupt,
 	.suspend	= genphy_suspend,
@@ -768,7 +771,6 @@ static struct phy_driver broadcom_drivers[] = {
 	/* PHY_GBIT_FEATURES */
 	.config_init	= bcm54xx_config_init,
 	.config_aneg	= bcm5481_config_aneg,
-	.ack_interrupt	= bcm_phy_ack_intr,
 	.config_intr	= bcm_phy_config_intr,
 	.handle_interrupt = bcm_phy_handle_interrupt,
 }, {
@@ -778,7 +780,6 @@ static struct phy_driver broadcom_drivers[] = {
 	/* PHY_GBIT_FEATURES */
 	.config_init    = bcm54xx_config_init,
 	.config_aneg    = bcm5481_config_aneg,
-	.ack_interrupt  = bcm_phy_ack_intr,
 	.config_intr    = bcm_phy_config_intr,
 	.handle_interrupt = bcm_phy_handle_interrupt,
 	.suspend	= genphy_suspend,
@@ -790,7 +791,6 @@ static struct phy_driver broadcom_drivers[] = {
 	/* PHY_GBIT_FEATURES */
 	.config_init    = bcm54811_config_init,
 	.config_aneg    = bcm5481_config_aneg,
-	.ack_interrupt  = bcm_phy_ack_intr,
 	.config_intr    = bcm_phy_config_intr,
 	.handle_interrupt = bcm_phy_handle_interrupt,
 	.suspend	= genphy_suspend,
@@ -802,7 +802,6 @@ static struct phy_driver broadcom_drivers[] = {
 	/* PHY_GBIT_FEATURES */
 	.config_init	= bcm5482_config_init,
 	.read_status	= bcm5482_read_status,
-	.ack_interrupt	= bcm_phy_ack_intr,
 	.config_intr	= bcm_phy_config_intr,
 	.handle_interrupt = bcm_phy_handle_interrupt,
 }, {
@@ -811,7 +810,6 @@ static struct phy_driver broadcom_drivers[] = {
 	.name		= "Broadcom BCM50610",
 	/* PHY_GBIT_FEATURES */
 	.config_init	= bcm54xx_config_init,
-	.ack_interrupt	= bcm_phy_ack_intr,
 	.config_intr	= bcm_phy_config_intr,
 	.handle_interrupt = bcm_phy_handle_interrupt,
 }, {
@@ -820,7 +818,6 @@ static struct phy_driver broadcom_drivers[] = {
 	.name		= "Broadcom BCM50610M",
 	/* PHY_GBIT_FEATURES */
 	.config_init	= bcm54xx_config_init,
-	.ack_interrupt	= bcm_phy_ack_intr,
 	.config_intr	= bcm_phy_config_intr,
 	.handle_interrupt = bcm_phy_handle_interrupt,
 }, {
@@ -829,7 +826,6 @@ static struct phy_driver broadcom_drivers[] = {
 	.name		= "Broadcom BCM57780",
 	/* PHY_GBIT_FEATURES */
 	.config_init	= bcm54xx_config_init,
-	.ack_interrupt	= bcm_phy_ack_intr,
 	.config_intr	= bcm_phy_config_intr,
 	.handle_interrupt = bcm_phy_handle_interrupt,
 }, {
@@ -838,7 +834,6 @@ static struct phy_driver broadcom_drivers[] = {
 	.name		= "Broadcom BCMAC131",
 	/* PHY_BASIC_FEATURES */
 	.config_init	= brcm_fet_config_init,
-	.ack_interrupt	= brcm_fet_ack_interrupt,
 	.config_intr	= brcm_fet_config_intr,
 	.handle_interrupt = brcm_fet_handle_interrupt,
 }, {
@@ -847,7 +842,6 @@ static struct phy_driver broadcom_drivers[] = {
 	.name		= "Broadcom BCM5241",
 	/* PHY_BASIC_FEATURES */
 	.config_init	= brcm_fet_config_init,
-	.ack_interrupt	= brcm_fet_ack_interrupt,
 	.config_intr	= brcm_fet_config_intr,
 	.handle_interrupt = brcm_fet_handle_interrupt,
 }, {
@@ -871,7 +865,6 @@ static struct phy_driver broadcom_drivers[] = {
 	.get_stats	= bcm53xx_phy_get_stats,
 	.probe		= bcm53xx_phy_probe,
 	.config_init	= bcm54xx_config_init,
-	.ack_interrupt	= bcm_phy_ack_intr,
 	.config_intr	= bcm_phy_config_intr,
 	.handle_interrupt = bcm_phy_handle_interrupt,
 }, {
@@ -880,7 +873,6 @@ static struct phy_driver broadcom_drivers[] = {
 	.name           = "Broadcom BCM89610",
 	/* PHY_GBIT_FEATURES */
 	.config_init    = bcm54xx_config_init,
-	.ack_interrupt  = bcm_phy_ack_intr,
 	.config_intr    = bcm_phy_config_intr,
 	.handle_interrupt = bcm_phy_handle_interrupt,
 } };
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH net-next v2 13/19] net: phy: cicada: implement the generic .handle_interrupt() callback
  2020-11-01 12:50 [PATCH net-next v2 00/19] net: phy: add support for shared interrupts (part 1) Ioana Ciornei
                   ` (11 preceding siblings ...)
  2020-11-01 12:51 ` [PATCH net-next v2 12/19] net: phy: broadcom: remove use of ack_interrupt() Ioana Ciornei
@ 2020-11-01 12:51 ` Ioana Ciornei
  2020-11-01 12:51 ` [PATCH net-next v2 14/19] net: phy: cicada: remove the use of .ack_interrupt() Ioana Ciornei
                   ` (8 subsequent siblings)
  21 siblings, 0 replies; 31+ messages in thread
From: Ioana Ciornei @ 2020-11-01 12:51 UTC (permalink / raw)
  To: Andrew Lunn, Heiner Kallweit, Russell King, Florian Fainelli,
	Jakub Kicinski, netdev, linux-kernel
  Cc: Ioana Ciornei

From: Ioana Ciornei <ioana.ciornei@nxp.com>

In an attempt to actually support shared IRQs in phylib, we now move the
responsibility of triggering the phylib state machine or just returning
IRQ_NONE, based on the IRQ status register, to the PHY driver. Having
3 different IRQ handling callbacks (.handle_interrupt(),
.did_interrupt() and .ack_interrupt() ) is confusing so let the PHY
driver implement directly an IRQ handler like any other device driver.
Make this driver follow the new convention.

Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
---
Changes in v2:
 - Adjust .handle_interrupt() so that we only take into account the
   enabled IRQs.

 drivers/net/phy/cicada.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/drivers/net/phy/cicada.c b/drivers/net/phy/cicada.c
index 9d1612a4d7e6..086c62ff5293 100644
--- a/drivers/net/phy/cicada.c
+++ b/drivers/net/phy/cicada.c
@@ -96,6 +96,24 @@ static int cis820x_config_intr(struct phy_device *phydev)
 	return err;
 }
 
+static irqreturn_t cis820x_handle_interrupt(struct phy_device *phydev)
+{
+	int irq_status;
+
+	irq_status = phy_read(phydev, MII_CIS8201_ISTAT);
+	if (irq_status < 0) {
+		phy_error(phydev);
+		return IRQ_NONE;
+	}
+
+	if (!(irq_status & MII_CIS8201_IMASK_MASK))
+		return IRQ_NONE;
+
+	phy_trigger_machine(phydev);
+
+	return IRQ_HANDLED;
+}
+
 /* Cicada 8201, a.k.a Vitesse VSC8201 */
 static struct phy_driver cis820x_driver[] = {
 {
@@ -106,6 +124,7 @@ static struct phy_driver cis820x_driver[] = {
 	.config_init	= &cis820x_config_init,
 	.ack_interrupt	= &cis820x_ack_interrupt,
 	.config_intr	= &cis820x_config_intr,
+	.handle_interrupt = &cis820x_handle_interrupt,
 }, {
 	.phy_id		= 0x000fc440,
 	.name		= "Cicada Cis8204",
@@ -114,6 +133,7 @@ static struct phy_driver cis820x_driver[] = {
 	.config_init	= &cis820x_config_init,
 	.ack_interrupt	= &cis820x_ack_interrupt,
 	.config_intr	= &cis820x_config_intr,
+	.handle_interrupt = &cis820x_handle_interrupt,
 } };
 
 module_phy_driver(cis820x_driver);
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH net-next v2 14/19] net: phy: cicada: remove the use of .ack_interrupt()
  2020-11-01 12:50 [PATCH net-next v2 00/19] net: phy: add support for shared interrupts (part 1) Ioana Ciornei
                   ` (12 preceding siblings ...)
  2020-11-01 12:51 ` [PATCH net-next v2 13/19] net: phy: cicada: implement the generic .handle_interrupt() callback Ioana Ciornei
@ 2020-11-01 12:51 ` Ioana Ciornei
  2020-11-01 12:51 ` [PATCH net-next v2 15/19] net: phy: davicom: implement generic .handle_interrupt() calback Ioana Ciornei
                   ` (7 subsequent siblings)
  21 siblings, 0 replies; 31+ messages in thread
From: Ioana Ciornei @ 2020-11-01 12:51 UTC (permalink / raw)
  To: Andrew Lunn, Heiner Kallweit, Russell King, Florian Fainelli,
	Jakub Kicinski, netdev, linux-kernel
  Cc: Ioana Ciornei

From: Ioana Ciornei <ioana.ciornei@nxp.com>

In preparation of removing the .ack_interrupt() callback, we must replace
its occurrences (aka phy_clear_interrupt), from the 2 places where it is
called from (phy_enable_interrupts and phy_disable_interrupts), with
equivalent functionality.

This means that clearing interrupts now becomes something that the PHY
driver is responsible of doing, before enabling interrupts and after
clearing them. Make this driver follow the new contract.

Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
---
Changes in v2:
 - none

 drivers/net/phy/cicada.c | 15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/drivers/net/phy/cicada.c b/drivers/net/phy/cicada.c
index 086c62ff5293..ef5f412e101f 100644
--- a/drivers/net/phy/cicada.c
+++ b/drivers/net/phy/cicada.c
@@ -87,11 +87,20 @@ static int cis820x_config_intr(struct phy_device *phydev)
 {
 	int err;
 
-	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
+	if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
+		err = cis820x_ack_interrupt(phydev);
+		if (err)
+			return err;
+
 		err = phy_write(phydev, MII_CIS8201_IMASK,
 				MII_CIS8201_IMASK_MASK);
-	else
+	} else {
 		err = phy_write(phydev, MII_CIS8201_IMASK, 0);
+		if (err)
+			return err;
+
+		err = cis820x_ack_interrupt(phydev);
+	}
 
 	return err;
 }
@@ -122,7 +131,6 @@ static struct phy_driver cis820x_driver[] = {
 	.phy_id_mask	= 0x000ffff0,
 	/* PHY_GBIT_FEATURES */
 	.config_init	= &cis820x_config_init,
-	.ack_interrupt	= &cis820x_ack_interrupt,
 	.config_intr	= &cis820x_config_intr,
 	.handle_interrupt = &cis820x_handle_interrupt,
 }, {
@@ -131,7 +139,6 @@ static struct phy_driver cis820x_driver[] = {
 	.phy_id_mask	= 0x000fffc0,
 	/* PHY_GBIT_FEATURES */
 	.config_init	= &cis820x_config_init,
-	.ack_interrupt	= &cis820x_ack_interrupt,
 	.config_intr	= &cis820x_config_intr,
 	.handle_interrupt = &cis820x_handle_interrupt,
 } };
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH net-next v2 15/19] net: phy: davicom: implement generic .handle_interrupt() calback
  2020-11-01 12:50 [PATCH net-next v2 00/19] net: phy: add support for shared interrupts (part 1) Ioana Ciornei
                   ` (13 preceding siblings ...)
  2020-11-01 12:51 ` [PATCH net-next v2 14/19] net: phy: cicada: remove the use of .ack_interrupt() Ioana Ciornei
@ 2020-11-01 12:51 ` Ioana Ciornei
  2020-11-01 12:51 ` [PATCH net-next v2 16/19] net: phy: davicom: remove the use of .ack_interrupt() Ioana Ciornei
                   ` (6 subsequent siblings)
  21 siblings, 0 replies; 31+ messages in thread
From: Ioana Ciornei @ 2020-11-01 12:51 UTC (permalink / raw)
  To: Andrew Lunn, Heiner Kallweit, Russell King, Florian Fainelli,
	Jakub Kicinski, netdev, linux-kernel
  Cc: Ioana Ciornei

From: Ioana Ciornei <ioana.ciornei@nxp.com>

In an attempt to actually support shared IRQs in phylib, we now move the
responsibility of triggering the phylib state machine or just returning
IRQ_NONE, based on the IRQ status register, to the PHY driver. Having
3 different IRQ handling callbacks (.handle_interrupt(),
.did_interrupt() and .ack_interrupt() ) is confusing so let the PHY
driver implement directly an IRQ handler like any other device driver.
Make this driver follow the new convention.

Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
---
Changes in v2:
 - Adjust .handle_interrupt() so that we only take into account the
   enabled IRQs.

 drivers/net/phy/davicom.c | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/drivers/net/phy/davicom.c b/drivers/net/phy/davicom.c
index 942f277463a4..bfa6c835070f 100644
--- a/drivers/net/phy/davicom.c
+++ b/drivers/net/phy/davicom.c
@@ -47,6 +47,10 @@
 #define MII_DM9161_INTR_STOP	\
 (MII_DM9161_INTR_DPLX_MASK | MII_DM9161_INTR_SPD_MASK \
  | MII_DM9161_INTR_LINK_MASK | MII_DM9161_INTR_MASK)
+#define MII_DM9161_INTR_CHANGE	\
+	(MII_DM9161_INTR_DPLX_CHANGE | \
+	 MII_DM9161_INTR_SPD_CHANGE | \
+	 MII_DM9161_INTR_LINK_CHANGE)
 
 /* DM9161 10BT Configuration/Status */
 #define MII_DM9161_10BTCSR	0x12
@@ -77,6 +81,24 @@ static int dm9161_config_intr(struct phy_device *phydev)
 	return temp;
 }
 
+static irqreturn_t dm9161_handle_interrupt(struct phy_device *phydev)
+{
+	int irq_status;
+
+	irq_status = phy_read(phydev, MII_DM9161_INTR);
+	if (irq_status < 0) {
+		phy_error(phydev);
+		return IRQ_NONE;
+	}
+
+	if (!(irq_status & MII_DM9161_INTR_CHANGE))
+		return IRQ_NONE;
+
+	phy_trigger_machine(phydev);
+
+	return IRQ_HANDLED;
+}
+
 static int dm9161_config_aneg(struct phy_device *phydev)
 {
 	int err;
@@ -149,6 +171,7 @@ static struct phy_driver dm91xx_driver[] = {
 	.config_aneg	= dm9161_config_aneg,
 	.ack_interrupt	= dm9161_ack_interrupt,
 	.config_intr	= dm9161_config_intr,
+	.handle_interrupt = dm9161_handle_interrupt,
 }, {
 	.phy_id		= 0x0181b8b0,
 	.name		= "Davicom DM9161B/C",
@@ -158,6 +181,7 @@ static struct phy_driver dm91xx_driver[] = {
 	.config_aneg	= dm9161_config_aneg,
 	.ack_interrupt	= dm9161_ack_interrupt,
 	.config_intr	= dm9161_config_intr,
+	.handle_interrupt = dm9161_handle_interrupt,
 }, {
 	.phy_id		= 0x0181b8a0,
 	.name		= "Davicom DM9161A",
@@ -167,6 +191,7 @@ static struct phy_driver dm91xx_driver[] = {
 	.config_aneg	= dm9161_config_aneg,
 	.ack_interrupt	= dm9161_ack_interrupt,
 	.config_intr	= dm9161_config_intr,
+	.handle_interrupt = dm9161_handle_interrupt,
 }, {
 	.phy_id		= 0x00181b80,
 	.name		= "Davicom DM9131",
@@ -174,6 +199,7 @@ static struct phy_driver dm91xx_driver[] = {
 	/* PHY_BASIC_FEATURES */
 	.ack_interrupt	= dm9161_ack_interrupt,
 	.config_intr	= dm9161_config_intr,
+	.handle_interrupt = dm9161_handle_interrupt,
 } };
 
 module_phy_driver(dm91xx_driver);
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH net-next v2 16/19] net: phy: davicom: remove the use of .ack_interrupt()
  2020-11-01 12:50 [PATCH net-next v2 00/19] net: phy: add support for shared interrupts (part 1) Ioana Ciornei
                   ` (14 preceding siblings ...)
  2020-11-01 12:51 ` [PATCH net-next v2 15/19] net: phy: davicom: implement generic .handle_interrupt() calback Ioana Ciornei
@ 2020-11-01 12:51 ` Ioana Ciornei
  2020-11-01 12:51 ` [PATCH net-next v2 17/19] net: phy: add genphy_handle_interrupt_no_ack() Ioana Ciornei
                   ` (5 subsequent siblings)
  21 siblings, 0 replies; 31+ messages in thread
From: Ioana Ciornei @ 2020-11-01 12:51 UTC (permalink / raw)
  To: Andrew Lunn, Heiner Kallweit, Russell King, Florian Fainelli,
	Jakub Kicinski, netdev, linux-kernel
  Cc: Ioana Ciornei

From: Ioana Ciornei <ioana.ciornei@nxp.com>

In preparation of removing the .ack_interrupt() callback, we must replace
its occurrences (aka phy_clear_interrupt), from the 2 places where it is
called from (phy_enable_interrupts and phy_disable_interrupts), with
equivalent functionality.

This means that clearing interrupts now becomes something that the PHY
driver is responsible of doing, before enabling interrupts and after
clearing them. Make this driver follow the new contract.

Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
---
Changes in v2:
 - none

 drivers/net/phy/davicom.c | 37 +++++++++++++++++++++----------------
 1 file changed, 21 insertions(+), 16 deletions(-)

diff --git a/drivers/net/phy/davicom.c b/drivers/net/phy/davicom.c
index bfa6c835070f..a3b3842c67e5 100644
--- a/drivers/net/phy/davicom.c
+++ b/drivers/net/phy/davicom.c
@@ -61,24 +61,40 @@ MODULE_AUTHOR("Andy Fleming");
 MODULE_LICENSE("GPL");
 
 
+static int dm9161_ack_interrupt(struct phy_device *phydev)
+{
+	int err = phy_read(phydev, MII_DM9161_INTR);
+
+	return (err < 0) ? err : 0;
+}
+
 #define DM9161_DELAY 1
 static int dm9161_config_intr(struct phy_device *phydev)
 {
-	int temp;
+	int temp, err;
 
 	temp = phy_read(phydev, MII_DM9161_INTR);
 
 	if (temp < 0)
 		return temp;
 
-	if (PHY_INTERRUPT_ENABLED == phydev->interrupts)
+	if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
+		err = dm9161_ack_interrupt(phydev);
+		if (err)
+			return err;
+
 		temp &= ~(MII_DM9161_INTR_STOP);
-	else
+		err = phy_write(phydev, MII_DM9161_INTR, temp);
+	} else {
 		temp |= MII_DM9161_INTR_STOP;
+		err = phy_write(phydev, MII_DM9161_INTR, temp);
+		if (err)
+			return err;
 
-	temp = phy_write(phydev, MII_DM9161_INTR, temp);
+		err = dm9161_ack_interrupt(phydev);
+	}
 
-	return temp;
+	return err;
 }
 
 static irqreturn_t dm9161_handle_interrupt(struct phy_device *phydev)
@@ -154,13 +170,6 @@ static int dm9161_config_init(struct phy_device *phydev)
 	return phy_write(phydev, MII_BMCR, BMCR_ANENABLE);
 }
 
-static int dm9161_ack_interrupt(struct phy_device *phydev)
-{
-	int err = phy_read(phydev, MII_DM9161_INTR);
-
-	return (err < 0) ? err : 0;
-}
-
 static struct phy_driver dm91xx_driver[] = {
 {
 	.phy_id		= 0x0181b880,
@@ -169,7 +178,6 @@ static struct phy_driver dm91xx_driver[] = {
 	/* PHY_BASIC_FEATURES */
 	.config_init	= dm9161_config_init,
 	.config_aneg	= dm9161_config_aneg,
-	.ack_interrupt	= dm9161_ack_interrupt,
 	.config_intr	= dm9161_config_intr,
 	.handle_interrupt = dm9161_handle_interrupt,
 }, {
@@ -179,7 +187,6 @@ static struct phy_driver dm91xx_driver[] = {
 	/* PHY_BASIC_FEATURES */
 	.config_init	= dm9161_config_init,
 	.config_aneg	= dm9161_config_aneg,
-	.ack_interrupt	= dm9161_ack_interrupt,
 	.config_intr	= dm9161_config_intr,
 	.handle_interrupt = dm9161_handle_interrupt,
 }, {
@@ -189,7 +196,6 @@ static struct phy_driver dm91xx_driver[] = {
 	/* PHY_BASIC_FEATURES */
 	.config_init	= dm9161_config_init,
 	.config_aneg	= dm9161_config_aneg,
-	.ack_interrupt	= dm9161_ack_interrupt,
 	.config_intr	= dm9161_config_intr,
 	.handle_interrupt = dm9161_handle_interrupt,
 }, {
@@ -197,7 +203,6 @@ static struct phy_driver dm91xx_driver[] = {
 	.name		= "Davicom DM9131",
 	.phy_id_mask	= 0x0ffffff0,
 	/* PHY_BASIC_FEATURES */
-	.ack_interrupt	= dm9161_ack_interrupt,
 	.config_intr	= dm9161_config_intr,
 	.handle_interrupt = dm9161_handle_interrupt,
 } };
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH net-next v2 17/19] net: phy: add genphy_handle_interrupt_no_ack()
  2020-11-01 12:50 [PATCH net-next v2 00/19] net: phy: add support for shared interrupts (part 1) Ioana Ciornei
                   ` (15 preceding siblings ...)
  2020-11-01 12:51 ` [PATCH net-next v2 16/19] net: phy: davicom: remove the use of .ack_interrupt() Ioana Ciornei
@ 2020-11-01 12:51 ` Ioana Ciornei
  2020-11-01 12:51 ` [PATCH net-next v2 18/19] net: phy: realtek: implement generic .handle_interrupt() callback Ioana Ciornei
                   ` (4 subsequent siblings)
  21 siblings, 0 replies; 31+ messages in thread
From: Ioana Ciornei @ 2020-11-01 12:51 UTC (permalink / raw)
  To: Andrew Lunn, Heiner Kallweit, Russell King, Florian Fainelli,
	Jakub Kicinski, netdev, linux-kernel
  Cc: Ioana Ciornei

From: Ioana Ciornei <ioana.ciornei@nxp.com>

It seems there are cases where the interrupts are handled by another
entity (ie an IRQ controller embedded inside the PHY) and do not need
any other interraction from phylib. For this kind of PHYs, like the
RTL8366RB, add the genphy_handle_interrupt_no_ack() function which just
triggers the link state machine.

Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
---
Changes in v2:
 - none

 drivers/net/phy/phy_device.c | 13 +++++++++++++
 include/linux/phy.h          |  1 +
 2 files changed, 14 insertions(+)

diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index f54f483d7fd6..e13a46c25437 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -2463,6 +2463,19 @@ int genphy_soft_reset(struct phy_device *phydev)
 }
 EXPORT_SYMBOL(genphy_soft_reset);
 
+irqreturn_t genphy_handle_interrupt_no_ack(struct phy_device *phydev)
+{
+	/* It seems there are cases where the interrupts are handled by another
+	 * entity (ie an IRQ controller embedded inside the PHY) and do not
+	 * need any other interraction from phylib. In this case, just trigger
+	 * the state machine directly.
+	 */
+	phy_trigger_machine(phydev);
+
+	return 0;
+}
+EXPORT_SYMBOL(genphy_handle_interrupt_no_ack);
+
 /**
  * genphy_read_abilities - read PHY abilities from Clause 22 registers
  * @phydev: target phy_device struct
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 566b39f6cd64..4f158d6352ae 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -1510,6 +1510,7 @@ int genphy_suspend(struct phy_device *phydev);
 int genphy_resume(struct phy_device *phydev);
 int genphy_loopback(struct phy_device *phydev, bool enable);
 int genphy_soft_reset(struct phy_device *phydev);
+irqreturn_t genphy_handle_interrupt_no_ack(struct phy_device *phydev);
 
 static inline int genphy_config_aneg(struct phy_device *phydev)
 {
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH net-next v2 18/19] net: phy: realtek: implement generic .handle_interrupt() callback
  2020-11-01 12:50 [PATCH net-next v2 00/19] net: phy: add support for shared interrupts (part 1) Ioana Ciornei
                   ` (16 preceding siblings ...)
  2020-11-01 12:51 ` [PATCH net-next v2 17/19] net: phy: add genphy_handle_interrupt_no_ack() Ioana Ciornei
@ 2020-11-01 12:51 ` Ioana Ciornei
  2020-11-01 12:51 ` [PATCH net-next v2 19/19] net: phy: realtek: remove the use of .ack_interrupt() Ioana Ciornei
                   ` (3 subsequent siblings)
  21 siblings, 0 replies; 31+ messages in thread
From: Ioana Ciornei @ 2020-11-01 12:51 UTC (permalink / raw)
  To: Andrew Lunn, Heiner Kallweit, Russell King, Florian Fainelli,
	Jakub Kicinski, netdev, linux-kernel
  Cc: Ioana Ciornei, Martin Blumenstingl, Willy Liu

From: Ioana Ciornei <ioana.ciornei@nxp.com>

In an attempt to actually support shared IRQs in phylib, we now move the
responsibility of triggering the phylib state machine or just returning
IRQ_NONE, based on the IRQ status register, to the PHY driver. Having
3 different IRQ handling callbacks (.handle_interrupt(),
.did_interrupt() and .ack_interrupt() ) is confusing so let the PHY
driver implement directly an IRQ handler like any other device driver.
Make this driver follow the new convention.

Cc: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Cc: Willy Liu <willy.liu@realtek.com>
Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
---
Changes in v2:
 - Adjust .handle_interrupt() so that we only take into account the
   enabled IRQs.

 drivers/net/phy/realtek.c | 72 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 72 insertions(+)

diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c
index fb1db713b7fb..820b4e8ef23a 100644
--- a/drivers/net/phy/realtek.c
+++ b/drivers/net/phy/realtek.c
@@ -41,6 +41,12 @@
 #define RTL8211E_RX_DELAY			BIT(11)
 
 #define RTL8201F_ISR				0x1e
+#define RTL8201F_ISR_ANERR			BIT(15)
+#define RTL8201F_ISR_DUPLEX			BIT(13)
+#define RTL8201F_ISR_LINK			BIT(11)
+#define RTL8201F_ISR_MASK			(RTL8201F_ISR_ANERR | \
+						 RTL8201F_ISR_DUPLEX | \
+						 RTL8201F_ISR_LINK)
 #define RTL8201F_IER				0x13
 
 #define RTL8366RB_POWER_SAVE			0x15
@@ -149,6 +155,66 @@ static int rtl8211f_config_intr(struct phy_device *phydev)
 	return phy_write_paged(phydev, 0xa42, RTL821x_INER, val);
 }
 
+static irqreturn_t rtl8201_handle_interrupt(struct phy_device *phydev)
+{
+	int irq_status;
+
+	irq_status = phy_read(phydev, RTL8201F_ISR);
+	if (irq_status < 0) {
+		phy_error(phydev);
+		return IRQ_NONE;
+	}
+
+	if (!(irq_status & RTL8201F_ISR_MASK))
+		return IRQ_NONE;
+
+	phy_trigger_machine(phydev);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t rtl821x_handle_interrupt(struct phy_device *phydev)
+{
+	int irq_status, irq_enabled;
+
+	irq_status = phy_read(phydev, RTL821x_INSR);
+	if (irq_status < 0) {
+		phy_error(phydev);
+		return IRQ_NONE;
+	}
+
+	irq_enabled = phy_read(phydev, RTL821x_INER);
+	if (irq_enabled < 0) {
+		phy_error(phydev);
+		return IRQ_NONE;
+	}
+
+	if (!(irq_status & irq_enabled))
+		return IRQ_NONE;
+
+	phy_trigger_machine(phydev);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t rtl8211f_handle_interrupt(struct phy_device *phydev)
+{
+	int irq_status;
+
+	irq_status = phy_read_paged(phydev, 0xa43, RTL8211F_INSR);
+	if (irq_status < 0) {
+		phy_error(phydev);
+		return IRQ_NONE;
+	}
+
+	if (!(irq_status & RTL8211F_INER_LINK_STATUS))
+		return IRQ_NONE;
+
+	phy_trigger_machine(phydev);
+
+	return IRQ_HANDLED;
+}
+
 static int rtl8211_config_aneg(struct phy_device *phydev)
 {
 	int ret;
@@ -556,6 +622,7 @@ static struct phy_driver realtek_drvs[] = {
 		.name		= "RTL8201F Fast Ethernet",
 		.ack_interrupt	= &rtl8201_ack_interrupt,
 		.config_intr	= &rtl8201_config_intr,
+		.handle_interrupt = rtl8201_handle_interrupt,
 		.suspend	= genphy_suspend,
 		.resume		= genphy_resume,
 		.read_page	= rtl821x_read_page,
@@ -582,6 +649,7 @@ static struct phy_driver realtek_drvs[] = {
 		.name		= "RTL8211B Gigabit Ethernet",
 		.ack_interrupt	= &rtl821x_ack_interrupt,
 		.config_intr	= &rtl8211b_config_intr,
+		.handle_interrupt = rtl821x_handle_interrupt,
 		.read_mmd	= &genphy_read_mmd_unsupported,
 		.write_mmd	= &genphy_write_mmd_unsupported,
 		.suspend	= rtl8211b_suspend,
@@ -601,6 +669,7 @@ static struct phy_driver realtek_drvs[] = {
 		.name		= "RTL8211DN Gigabit Ethernet",
 		.ack_interrupt	= rtl821x_ack_interrupt,
 		.config_intr	= rtl8211e_config_intr,
+		.handle_interrupt = rtl821x_handle_interrupt,
 		.suspend	= genphy_suspend,
 		.resume		= genphy_resume,
 		.read_page	= rtl821x_read_page,
@@ -611,6 +680,7 @@ static struct phy_driver realtek_drvs[] = {
 		.config_init	= &rtl8211e_config_init,
 		.ack_interrupt	= &rtl821x_ack_interrupt,
 		.config_intr	= &rtl8211e_config_intr,
+		.handle_interrupt = rtl821x_handle_interrupt,
 		.suspend	= genphy_suspend,
 		.resume		= genphy_resume,
 		.read_page	= rtl821x_read_page,
@@ -621,6 +691,7 @@ static struct phy_driver realtek_drvs[] = {
 		.config_init	= &rtl8211f_config_init,
 		.ack_interrupt	= &rtl8211f_ack_interrupt,
 		.config_intr	= &rtl8211f_config_intr,
+		.handle_interrupt = rtl8211f_handle_interrupt,
 		.suspend	= genphy_suspend,
 		.resume		= genphy_resume,
 		.read_page	= rtl821x_read_page,
@@ -670,6 +741,7 @@ static struct phy_driver realtek_drvs[] = {
 		 */
 		.ack_interrupt	= genphy_no_ack_interrupt,
 		.config_intr	= genphy_no_config_intr,
+		.handle_interrupt = genphy_handle_interrupt_no_ack,
 		.suspend	= genphy_suspend,
 		.resume		= genphy_resume,
 	},
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH net-next v2 19/19] net: phy: realtek: remove the use of .ack_interrupt()
  2020-11-01 12:50 [PATCH net-next v2 00/19] net: phy: add support for shared interrupts (part 1) Ioana Ciornei
                   ` (17 preceding siblings ...)
  2020-11-01 12:51 ` [PATCH net-next v2 18/19] net: phy: realtek: implement generic .handle_interrupt() callback Ioana Ciornei
@ 2020-11-01 12:51 ` Ioana Ciornei
  2020-11-03 16:44 ` [PATCH net-next v2 00/19] net: phy: add support for shared interrupts (part 1) Andrew Lunn
                   ` (2 subsequent siblings)
  21 siblings, 0 replies; 31+ messages in thread
From: Ioana Ciornei @ 2020-11-01 12:51 UTC (permalink / raw)
  To: Andrew Lunn, Heiner Kallweit, Russell King, Florian Fainelli,
	Jakub Kicinski, netdev, linux-kernel
  Cc: Ioana Ciornei, Martin Blumenstingl, Willy Liu

From: Ioana Ciornei <ioana.ciornei@nxp.com>

In preparation of removing the .ack_interrupt() callback, we must replace
its occurrences (aka phy_clear_interrupt), from the 2 places where it is
called from (phy_enable_interrupts and phy_disable_interrupts), with
equivalent functionality.

This means that clearing interrupts now becomes something that the PHY
driver is responsible of doing, before enabling interrupts and after
clearing them. Make this driver follow the new contract.

Cc: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Cc: Willy Liu <willy.liu@realtek.com>
Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
---
Changes in v2:
 - none

 drivers/net/phy/realtek.c | 68 ++++++++++++++++++++++++++++++---------
 1 file changed, 52 insertions(+), 16 deletions(-)

diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c
index 820b4e8ef23a..231b32118054 100644
--- a/drivers/net/phy/realtek.c
+++ b/drivers/net/phy/realtek.c
@@ -108,24 +108,45 @@ static int rtl8211f_ack_interrupt(struct phy_device *phydev)
 static int rtl8201_config_intr(struct phy_device *phydev)
 {
 	u16 val;
+	int err;
+
+	if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
+		err = rtl8201_ack_interrupt(phydev);
+		if (err)
+			return err;
 
-	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
 		val = BIT(13) | BIT(12) | BIT(11);
-	else
+		err = phy_write_paged(phydev, 0x7, RTL8201F_IER, val);
+	} else {
 		val = 0;
+		err = phy_write_paged(phydev, 0x7, RTL8201F_IER, val);
+		if (err)
+			return err;
+
+		err = rtl8201_ack_interrupt(phydev);
+	}
 
-	return phy_write_paged(phydev, 0x7, RTL8201F_IER, val);
+	return err;
 }
 
 static int rtl8211b_config_intr(struct phy_device *phydev)
 {
 	int err;
 
-	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
+	if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
+		err = rtl821x_ack_interrupt(phydev);
+		if (err)
+			return err;
+
 		err = phy_write(phydev, RTL821x_INER,
 				RTL8211B_INER_INIT);
-	else
+	} else {
 		err = phy_write(phydev, RTL821x_INER, 0);
+		if (err)
+			return err;
+
+		err = rtl821x_ack_interrupt(phydev);
+	}
 
 	return err;
 }
@@ -134,11 +155,20 @@ static int rtl8211e_config_intr(struct phy_device *phydev)
 {
 	int err;
 
-	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
+	if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
+		err = rtl821x_ack_interrupt(phydev);
+		if (err)
+			return err;
+
 		err = phy_write(phydev, RTL821x_INER,
 				RTL8211E_INER_LINK_STATUS);
-	else
+	} else {
 		err = phy_write(phydev, RTL821x_INER, 0);
+		if (err)
+			return err;
+
+		err = rtl821x_ack_interrupt(phydev);
+	}
 
 	return err;
 }
@@ -146,13 +176,25 @@ static int rtl8211e_config_intr(struct phy_device *phydev)
 static int rtl8211f_config_intr(struct phy_device *phydev)
 {
 	u16 val;
+	int err;
+
+	if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
+		err = rtl8211f_ack_interrupt(phydev);
+		if (err)
+			return err;
 
-	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
 		val = RTL8211F_INER_LINK_STATUS;
-	else
+		err = phy_write_paged(phydev, 0xa42, RTL821x_INER, val);
+	} else {
 		val = 0;
+		err = phy_write_paged(phydev, 0xa42, RTL821x_INER, val);
+		if (err)
+			return err;
 
-	return phy_write_paged(phydev, 0xa42, RTL821x_INER, val);
+		err = rtl8211f_ack_interrupt(phydev);
+	}
+
+	return err;
 }
 
 static irqreturn_t rtl8201_handle_interrupt(struct phy_device *phydev)
@@ -620,7 +662,6 @@ static struct phy_driver realtek_drvs[] = {
 	}, {
 		PHY_ID_MATCH_EXACT(0x001cc816),
 		.name		= "RTL8201F Fast Ethernet",
-		.ack_interrupt	= &rtl8201_ack_interrupt,
 		.config_intr	= &rtl8201_config_intr,
 		.handle_interrupt = rtl8201_handle_interrupt,
 		.suspend	= genphy_suspend,
@@ -647,7 +688,6 @@ static struct phy_driver realtek_drvs[] = {
 	}, {
 		PHY_ID_MATCH_EXACT(0x001cc912),
 		.name		= "RTL8211B Gigabit Ethernet",
-		.ack_interrupt	= &rtl821x_ack_interrupt,
 		.config_intr	= &rtl8211b_config_intr,
 		.handle_interrupt = rtl821x_handle_interrupt,
 		.read_mmd	= &genphy_read_mmd_unsupported,
@@ -667,7 +707,6 @@ static struct phy_driver realtek_drvs[] = {
 	}, {
 		PHY_ID_MATCH_EXACT(0x001cc914),
 		.name		= "RTL8211DN Gigabit Ethernet",
-		.ack_interrupt	= rtl821x_ack_interrupt,
 		.config_intr	= rtl8211e_config_intr,
 		.handle_interrupt = rtl821x_handle_interrupt,
 		.suspend	= genphy_suspend,
@@ -678,7 +717,6 @@ static struct phy_driver realtek_drvs[] = {
 		PHY_ID_MATCH_EXACT(0x001cc915),
 		.name		= "RTL8211E Gigabit Ethernet",
 		.config_init	= &rtl8211e_config_init,
-		.ack_interrupt	= &rtl821x_ack_interrupt,
 		.config_intr	= &rtl8211e_config_intr,
 		.handle_interrupt = rtl821x_handle_interrupt,
 		.suspend	= genphy_suspend,
@@ -689,7 +727,6 @@ static struct phy_driver realtek_drvs[] = {
 		PHY_ID_MATCH_EXACT(0x001cc916),
 		.name		= "RTL8211F Gigabit Ethernet",
 		.config_init	= &rtl8211f_config_init,
-		.ack_interrupt	= &rtl8211f_ack_interrupt,
 		.config_intr	= &rtl8211f_config_intr,
 		.handle_interrupt = rtl8211f_handle_interrupt,
 		.suspend	= genphy_suspend,
@@ -739,7 +776,6 @@ static struct phy_driver realtek_drvs[] = {
 		 * irq is requested and ACKed by reading the status register,
 		 * which is done by the irqchip code.
 		 */
-		.ack_interrupt	= genphy_no_ack_interrupt,
 		.config_intr	= genphy_no_config_intr,
 		.handle_interrupt = genphy_handle_interrupt_no_ack,
 		.suspend	= genphy_suspend,
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* Re: [PATCH net-next v2 00/19] net: phy: add support for shared interrupts (part 1)
  2020-11-01 12:50 [PATCH net-next v2 00/19] net: phy: add support for shared interrupts (part 1) Ioana Ciornei
                   ` (18 preceding siblings ...)
  2020-11-01 12:51 ` [PATCH net-next v2 19/19] net: phy: realtek: remove the use of .ack_interrupt() Ioana Ciornei
@ 2020-11-03 16:44 ` Andrew Lunn
  2020-11-03 22:53 ` Michael Walle
  2020-11-06  0:36 ` Jakub Kicinski
  21 siblings, 0 replies; 31+ messages in thread
From: Andrew Lunn @ 2020-11-03 16:44 UTC (permalink / raw)
  To: Ioana Ciornei
  Cc: Heiner Kallweit, Russell King, Florian Fainelli, Jakub Kicinski,
	netdev, linux-kernel, Ioana Ciornei, Alexandru Ardelean,
	Andre Edich, Antoine Tenart, Baruch Siach, Christophe Leroy,
	Dan Murphy, Divya Koppera, Hauke Mehrtens, Jerome Brunet,
	Kavya Sree Kotagiri, Linus Walleij, Marco Felsch, Marek Vasut,
	Martin Blumenstingl, Mathias Kresin, Maxim Kochetkov,
	Michael Walle, Neil Armstrong, Nisar Sayed, Oleksij Rempel,
	Philippe Schenker, Willy Liu, Yuiko Oshino

On Sun, Nov 01, 2020 at 02:50:55PM +0200, Ioana Ciornei wrote:
> From: Ioana Ciornei <ioana.ciornei@nxp.com>
> 
> This patch set aims to actually add support for shared interrupts in
> phylib and not only for multi-PHY devices. While we are at it,
> streamline the interrupt handling in phylib.

Hi Ioana

I did some quick testing with the Marvell PHY. This is one of the
drivers you have not changed. But it at least tests some of the core
changes.

Tested-by: Andrew Lunn <andrew@lunn.ch>

I will try to review the actual changes soon.

    Andrew

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH net-next v2 00/19] net: phy: add support for shared interrupts (part 1)
  2020-11-01 12:50 [PATCH net-next v2 00/19] net: phy: add support for shared interrupts (part 1) Ioana Ciornei
                   ` (19 preceding siblings ...)
  2020-11-03 16:44 ` [PATCH net-next v2 00/19] net: phy: add support for shared interrupts (part 1) Andrew Lunn
@ 2020-11-03 22:53 ` Michael Walle
  2020-11-06  0:36 ` Jakub Kicinski
  21 siblings, 0 replies; 31+ messages in thread
From: Michael Walle @ 2020-11-03 22:53 UTC (permalink / raw)
  To: Ioana Ciornei
  Cc: Andrew Lunn, Heiner Kallweit, Russell King, Florian Fainelli,
	Jakub Kicinski, netdev, linux-kernel, Ioana Ciornei,
	Alexandru Ardelean, Andre Edich, Antoine Tenart, Baruch Siach,
	Christophe Leroy, Dan Murphy, Divya Koppera, Hauke Mehrtens,
	Jerome Brunet, Kavya Sree Kotagiri, Linus Walleij, Marco Felsch,
	Marek Vasut, Martin Blumenstingl, Mathias Kresin,
	Maxim Kochetkov, Neil Armstrong, Nisar Sayed, Oleksij Rempel,
	Philippe Schenker, Willy Liu, Yuiko Oshino

Am 2020-11-01 13:50, schrieb Ioana Ciornei:
> From: Ioana Ciornei <ioana.ciornei@nxp.com>
> 
> This patch set aims to actually add support for shared interrupts in
> phylib and not only for multi-PHY devices. While we are at it,
> streamline the interrupt handling in phylib.

For the Broadcom BCM54140:
Tested-by: Michael Walle <michael@walle.cc>

-michael

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH net-next v2 04/19] net: phy: at803x: implement generic .handle_interrupt() callback
  2020-11-01 12:50 ` [PATCH net-next v2 04/19] net: phy: at803x: implement generic .handle_interrupt() callback Ioana Ciornei
@ 2020-11-04 18:09   ` Oleksij Rempel
  0 siblings, 0 replies; 31+ messages in thread
From: Oleksij Rempel @ 2020-11-04 18:09 UTC (permalink / raw)
  To: Ioana Ciornei
  Cc: Andrew Lunn, Heiner Kallweit, Russell King, Florian Fainelli,
	Jakub Kicinski, netdev, linux-kernel, Ioana Ciornei,
	Michael Walle

On Sun, Nov 01, 2020 at 02:50:59PM +0200, Ioana Ciornei wrote:
> From: Ioana Ciornei <ioana.ciornei@nxp.com>
> 
> In an attempt to actually support shared IRQs in phylib, we now move the
> responsibility of triggering the phylib state machine or just returning
> IRQ_NONE, based on the IRQ status register, to the PHY driver. Having
> 3 different IRQ handling callbacks (.handle_interrupt(),
> .did_interrupt() and .ack_interrupt() ) is confusing so let the PHY
> driver implement directly an IRQ handler like any other device driver.
> Make this driver follow the new convention.
> 
> Cc: Oleksij Rempel <o.rempel@pengutronix.de>
> Cc: Michael Walle <michael@walle.cc>
> Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>

Tested-by: Oleksij Rempel <o.rempel@pengutronix.de>

> ---
> Changes in v2:
>  - adjust .handle_interrupt() so that we only take into account the
>    enabled IRQs.
> 
>  drivers/net/phy/at803x.c | 31 +++++++++++++++++++++++++++++++
>  1 file changed, 31 insertions(+)
> 
> diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c
> index ed601a7e46a0..c7f91934cf82 100644
> --- a/drivers/net/phy/at803x.c
> +++ b/drivers/net/phy/at803x.c
> @@ -628,6 +628,32 @@ static int at803x_config_intr(struct phy_device *phydev)
>  	return err;
>  }
>  
> +static irqreturn_t at803x_handle_interrupt(struct phy_device *phydev)
> +{
> +	int irq_status, int_enabled;
> +
> +	irq_status = phy_read(phydev, AT803X_INTR_STATUS);
> +	if (irq_status < 0) {
> +		phy_error(phydev);
> +		return IRQ_NONE;
> +	}
> +
> +	/* Read the current enabled interrupts */
> +	int_enabled = phy_read(phydev, AT803X_INTR_ENABLE);
> +	if (int_enabled < 0) {
> +		phy_error(phydev);
> +		return IRQ_NONE;
> +	}
> +
> +	/* See if this was one of our enabled interrupts */
> +	if (!(irq_status & int_enabled))
> +		return IRQ_NONE;
> +
> +	phy_trigger_machine(phydev);
> +
> +	return IRQ_HANDLED;
> +}
> +
>  static void at803x_link_change_notify(struct phy_device *phydev)
>  {
>  	/*
> @@ -1064,6 +1090,7 @@ static struct phy_driver at803x_driver[] = {
>  	.read_status		= at803x_read_status,
>  	.ack_interrupt		= at803x_ack_interrupt,
>  	.config_intr		= at803x_config_intr,
> +	.handle_interrupt	= at803x_handle_interrupt,
>  	.get_tunable		= at803x_get_tunable,
>  	.set_tunable		= at803x_set_tunable,
>  	.cable_test_start	= at803x_cable_test_start,
> @@ -1084,6 +1111,7 @@ static struct phy_driver at803x_driver[] = {
>  	/* PHY_BASIC_FEATURES */
>  	.ack_interrupt		= at803x_ack_interrupt,
>  	.config_intr		= at803x_config_intr,
> +	.handle_interrupt	= at803x_handle_interrupt,
>  }, {
>  	/* Qualcomm Atheros AR8031/AR8033 */
>  	PHY_ID_MATCH_EXACT(ATH8031_PHY_ID),
> @@ -1102,6 +1130,7 @@ static struct phy_driver at803x_driver[] = {
>  	.aneg_done		= at803x_aneg_done,
>  	.ack_interrupt		= &at803x_ack_interrupt,
>  	.config_intr		= &at803x_config_intr,
> +	.handle_interrupt	= at803x_handle_interrupt,
>  	.get_tunable		= at803x_get_tunable,
>  	.set_tunable		= at803x_set_tunable,
>  	.cable_test_start	= at803x_cable_test_start,
> @@ -1122,6 +1151,7 @@ static struct phy_driver at803x_driver[] = {
>  	/* PHY_BASIC_FEATURES */
>  	.ack_interrupt		= at803x_ack_interrupt,
>  	.config_intr		= at803x_config_intr,
> +	.handle_interrupt	= at803x_handle_interrupt,
>  	.cable_test_start	= at803x_cable_test_start,
>  	.cable_test_get_status	= at803x_cable_test_get_status,
>  }, {
> @@ -1134,6 +1164,7 @@ static struct phy_driver at803x_driver[] = {
>  	/* PHY_BASIC_FEATURES */
>  	.ack_interrupt		= &at803x_ack_interrupt,
>  	.config_intr		= &at803x_config_intr,
> +	.handle_interrupt	= at803x_handle_interrupt,
>  	.cable_test_start	= at803x_cable_test_start,
>  	.cable_test_get_status	= at803x_cable_test_get_status,
>  	.read_status		= at803x_read_status,
> -- 
> 2.28.0
> 
> 

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH net-next v2 05/19] net: phy: at803x: remove the use of .ack_interrupt()
  2020-11-01 12:51 ` [PATCH net-next v2 05/19] net: phy: at803x: remove the use of .ack_interrupt() Ioana Ciornei
@ 2020-11-04 18:09   ` Oleksij Rempel
  0 siblings, 0 replies; 31+ messages in thread
From: Oleksij Rempel @ 2020-11-04 18:09 UTC (permalink / raw)
  To: Ioana Ciornei
  Cc: Andrew Lunn, Heiner Kallweit, Russell King, Florian Fainelli,
	Jakub Kicinski, netdev, linux-kernel, Ioana Ciornei,
	Michael Walle

On Sun, Nov 01, 2020 at 02:51:00PM +0200, Ioana Ciornei wrote:
> From: Ioana Ciornei <ioana.ciornei@nxp.com>
> 
> In preparation of removing the .ack_interrupt() callback, we must replace
> its occurrences (aka phy_clear_interrupt), from the 2 places where it is
> called from (phy_enable_interrupts and phy_disable_interrupts), with
> equivalent functionality.
> 
> This means that clearing interrupts now becomes something that the PHY
> driver is responsible of doing, before enabling interrupts and after
> clearing them. Make this driver follow the new contract.
> 
> Cc: Oleksij Rempel <o.rempel@pengutronix.de>
> Cc: Michael Walle <michael@walle.cc>
> Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>

Tested-by: Oleksij Rempel <o.rempel@pengutronix.de>

> ---
> Changes in v2:
>  - none
> 
>  drivers/net/phy/at803x.c | 19 ++++++++++++-------
>  1 file changed, 12 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c
> index c7f91934cf82..d0b36fd6c265 100644
> --- a/drivers/net/phy/at803x.c
> +++ b/drivers/net/phy/at803x.c
> @@ -614,6 +614,11 @@ static int at803x_config_intr(struct phy_device *phydev)
>  	value = phy_read(phydev, AT803X_INTR_ENABLE);
>  
>  	if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
> +		/* Clear any pending interrupts */
> +		err = at803x_ack_interrupt(phydev);
> +		if (err)
> +			return err;
> +
>  		value |= AT803X_INTR_ENABLE_AUTONEG_ERR;
>  		value |= AT803X_INTR_ENABLE_SPEED_CHANGED;
>  		value |= AT803X_INTR_ENABLE_DUPLEX_CHANGED;
> @@ -621,9 +626,14 @@ static int at803x_config_intr(struct phy_device *phydev)
>  		value |= AT803X_INTR_ENABLE_LINK_SUCCESS;
>  
>  		err = phy_write(phydev, AT803X_INTR_ENABLE, value);
> -	}
> -	else
> +	} else {
>  		err = phy_write(phydev, AT803X_INTR_ENABLE, 0);
> +		if (err)
> +			return err;
> +
> +		/* Clear any pending interrupts */
> +		err = at803x_ack_interrupt(phydev);
> +	}
>  
>  	return err;
>  }
> @@ -1088,7 +1098,6 @@ static struct phy_driver at803x_driver[] = {
>  	.resume			= at803x_resume,
>  	/* PHY_GBIT_FEATURES */
>  	.read_status		= at803x_read_status,
> -	.ack_interrupt		= at803x_ack_interrupt,
>  	.config_intr		= at803x_config_intr,
>  	.handle_interrupt	= at803x_handle_interrupt,
>  	.get_tunable		= at803x_get_tunable,
> @@ -1109,7 +1118,6 @@ static struct phy_driver at803x_driver[] = {
>  	.suspend		= at803x_suspend,
>  	.resume			= at803x_resume,
>  	/* PHY_BASIC_FEATURES */
> -	.ack_interrupt		= at803x_ack_interrupt,
>  	.config_intr		= at803x_config_intr,
>  	.handle_interrupt	= at803x_handle_interrupt,
>  }, {
> @@ -1128,7 +1136,6 @@ static struct phy_driver at803x_driver[] = {
>  	/* PHY_GBIT_FEATURES */
>  	.read_status		= at803x_read_status,
>  	.aneg_done		= at803x_aneg_done,
> -	.ack_interrupt		= &at803x_ack_interrupt,
>  	.config_intr		= &at803x_config_intr,
>  	.handle_interrupt	= at803x_handle_interrupt,
>  	.get_tunable		= at803x_get_tunable,
> @@ -1149,7 +1156,6 @@ static struct phy_driver at803x_driver[] = {
>  	.suspend		= at803x_suspend,
>  	.resume			= at803x_resume,
>  	/* PHY_BASIC_FEATURES */
> -	.ack_interrupt		= at803x_ack_interrupt,
>  	.config_intr		= at803x_config_intr,
>  	.handle_interrupt	= at803x_handle_interrupt,
>  	.cable_test_start	= at803x_cable_test_start,
> @@ -1162,7 +1168,6 @@ static struct phy_driver at803x_driver[] = {
>  	.resume			= at803x_resume,
>  	.flags			= PHY_POLL_CABLE_TEST,
>  	/* PHY_BASIC_FEATURES */
> -	.ack_interrupt		= &at803x_ack_interrupt,
>  	.config_intr		= &at803x_config_intr,
>  	.handle_interrupt	= at803x_handle_interrupt,
>  	.cable_test_start	= at803x_cable_test_start,
> -- 
> 2.28.0
> 
> 

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH net-next v2 08/19] net: phy: mscc: remove the use of .ack_interrupt()
  2020-11-01 12:51 ` [PATCH net-next v2 08/19] net: phy: mscc: remove the use of .ack_interrupt() Ioana Ciornei
@ 2020-11-05  0:07   ` Vladimir Oltean
  0 siblings, 0 replies; 31+ messages in thread
From: Vladimir Oltean @ 2020-11-05  0:07 UTC (permalink / raw)
  To: Ioana Ciornei
  Cc: Andrew Lunn, Heiner Kallweit, Russell King, Florian Fainelli,
	Jakub Kicinski, netdev, linux-kernel, Ioana Ciornei,
	Antoine Tenart

On Sun, Nov 01, 2020 at 02:51:03PM +0200, Ioana Ciornei wrote:
> From: Ioana Ciornei <ioana.ciornei@nxp.com>
> 
> In preparation of removing the .ack_interrupt() callback, we must replace
> its occurrences (aka phy_clear_interrupt), from the 2 places where it is
> called from (phy_enable_interrupts and phy_disable_interrupts), with
> equivalent functionality.
> 
> This means that clearing interrupts now becomes something that the PHY
> driver is responsible of doing, before enabling interrupts and after
> clearing them. Make this driver follow the new contract.
> 
> Cc: Antoine Tenart <atenart@kernel.org>
> Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
> ---

Tested-by: Vladimir Oltean <olteanv@gmail.com> # VSC8514

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH net-next v2 07/19] net: phy: mscc: implement generic .handle_interrupt() callback
  2020-11-01 12:51 ` [PATCH net-next v2 07/19] net: phy: mscc: implement generic .handle_interrupt() callback Ioana Ciornei
@ 2020-11-05  0:08   ` Vladimir Oltean
  0 siblings, 0 replies; 31+ messages in thread
From: Vladimir Oltean @ 2020-11-05  0:08 UTC (permalink / raw)
  To: Ioana Ciornei
  Cc: Andrew Lunn, Heiner Kallweit, Russell King, Florian Fainelli,
	Jakub Kicinski, netdev, linux-kernel, Ioana Ciornei

On Sun, Nov 01, 2020 at 02:51:02PM +0200, Ioana Ciornei wrote:
> From: Ioana Ciornei <ioana.ciornei@nxp.com>
> 
> In an attempt to actually support shared IRQs in phylib, we now move the
> responsibility of triggering the phylib state machine or just returning
> IRQ_NONE, based on the IRQ status register, to the PHY driver. Having
> 3 different IRQ handling callbacks (.handle_interrupt(),
> .did_interrupt() and .ack_interrupt() ) is confusing so let the PHY
> driver implement directly an IRQ handler like any other device driver.
> Make this driver follow the new convention.
> 
> Also, remove the .did_interrupt() callback since it's not anymore used.
> 
> Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
> ---

Tested-by: Vladimir Oltean <olteanv@gmail.com> # VSC8514

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH net-next v2 06/19] net: phy: mscc: use phy_trigger_machine() to notify link change
  2020-11-01 12:51 ` [PATCH net-next v2 06/19] net: phy: mscc: use phy_trigger_machine() to notify link change Ioana Ciornei
@ 2020-11-05  0:10   ` Vladimir Oltean
  0 siblings, 0 replies; 31+ messages in thread
From: Vladimir Oltean @ 2020-11-05  0:10 UTC (permalink / raw)
  To: Ioana Ciornei
  Cc: Andrew Lunn, Heiner Kallweit, Russell King, Florian Fainelli,
	Jakub Kicinski, netdev, linux-kernel, Ioana Ciornei

On Sun, Nov 01, 2020 at 02:51:01PM +0200, Ioana Ciornei wrote:
> From: Ioana Ciornei <ioana.ciornei@nxp.com>
> 
> According to the comment describing the phy_mac_interrupt() function, it
> it intended to be used by MAC drivers which have noticed a link change
> thus its use in the mscc PHY driver is improper and, most probably, was
> added just because phy_trigger_machine() was not exported.
> Now that we have acces to trigger the link state machine, use directly
> the phy_trigger_machine() function to notify a link change detected by
> the PHY driver.
> 
> Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
> ---

Tested-by: Vladimir Oltean <olteanv@gmail.com>

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH net-next v2 00/19] net: phy: add support for shared interrupts (part 1)
  2020-11-01 12:50 [PATCH net-next v2 00/19] net: phy: add support for shared interrupts (part 1) Ioana Ciornei
                   ` (20 preceding siblings ...)
  2020-11-03 22:53 ` Michael Walle
@ 2020-11-06  0:36 ` Jakub Kicinski
  21 siblings, 0 replies; 31+ messages in thread
From: Jakub Kicinski @ 2020-11-06  0:36 UTC (permalink / raw)
  To: Ioana Ciornei
  Cc: Andrew Lunn, Heiner Kallweit, Russell King, Florian Fainelli,
	netdev, linux-kernel, Ioana Ciornei, Alexandru Ardelean,
	Andre Edich, Antoine Tenart, Baruch Siach, Christophe Leroy,
	Dan Murphy, Divya Koppera, Hauke Mehrtens, Jerome Brunet,
	Kavya Sree Kotagiri, Linus Walleij, Marco Felsch, Marek Vasut,
	Martin Blumenstingl, Mathias Kresin, Maxim Kochetkov,
	Michael Walle, Neil Armstrong, Nisar Sayed, Oleksij Rempel,
	Philippe Schenker, Willy Liu, Yuiko Oshino

On Sun,  1 Nov 2020 14:50:55 +0200 Ioana Ciornei wrote:
> From: Ioana Ciornei <ioana.ciornei@nxp.com>
> 
> This patch set aims to actually add support for shared interrupts in
> phylib and not only for multi-PHY devices. While we are at it,
> streamline the interrupt handling in phylib.

Applied, thank you!

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH net-next v2 02/19] net: phy: add a shutdown procedure
  2020-11-01 12:50 ` [PATCH net-next v2 02/19] net: phy: add a shutdown procedure Ioana Ciornei
@ 2023-08-03 18:16   ` Uwe Kleine-König
  2023-08-03 18:24     ` Florian Fainelli
  0 siblings, 1 reply; 31+ messages in thread
From: Uwe Kleine-König @ 2023-08-03 18:16 UTC (permalink / raw)
  To: Ioana Ciornei
  Cc: Andrew Lunn, Heiner Kallweit, Russell King, Florian Fainelli,
	Jakub Kicinski, netdev, linux-kernel, Ioana Ciornei,
	Alexandru Ardelean, Andre Edich, Antoine Tenart, Baruch Siach,
	Christophe Leroy, Divya Koppera, Hauke Mehrtens, Jerome Brunet,
	Kavya Sree Kotagiri, Linus Walleij, Marco Felsch, Marek Vasut,
	Martin Blumenstingl, Mathias Kresin, Maxim Kochetkov,
	Michael Walle, Neil Armstrong, Nisar Sayed, Oleksij Rempel,
	Philippe Schenker, Willy Liu, Yuiko Oshino

[-- Attachment #1: Type: text/plain, Size: 2137 bytes --]

Hello,

this patch became commit e2f016cf775129c050d6c79483073423db15c79a and is
contained in v5.11-rc1.

It broke wake-on-lan on my NAS (an ARM machine with an Armada 370 SoC,
armada-370-netgear-rn104.dts). The used phy driver is marvell.c. I only
report it now as I just upgraded that machine from Debian 11 (with
kernel 5.10.x) to Debian 12 (with kernel 6.1.x).

Commenting out phy_disable_interrupts(...) in v6.1.41's phy_shutdown()
fixes the problem for me.

On Sun, Nov 01, 2020 at 02:50:57PM +0200, Ioana Ciornei wrote:
> In case of a board which uses a shared IRQ we can easily end up with an
> IRQ storm after a forced reboot.
> 
> For example, a 'reboot -f' will trigger a call to the .shutdown()
> callbacks of all devices. Because phylib does not implement that hook,
> the PHY is not quiesced, thus it can very well leave its IRQ enabled.
> 
> At the next boot, if that IRQ line is found asserted by the first PHY
> driver that uses it, but _before_ the driver that is _actually_ keeping
> the shared IRQ asserted is probed, the IRQ is not going to be
> acknowledged, thus it will keep being fired preventing the boot process
> of the kernel to continue. This is even worse when the second PHY driver
> is a module.
> 
> To fix this, implement the .shutdown() callback and disable the
> interrupts if these are used.

I don't know how this should interact with wake-on-lan, but I would
expect that there is a way to fix this without reintroducing the problem
fixed by this change. However I cannot say if this needs fixing in the
generic phy code or the phy driver. Any hints?
 
> Note that we are still susceptible to IRQ storms if the previous kernel
> exited with a panic or if the bootloader left the shared IRQ active, but
> there is absolutely nothing we can do about these cases.

I'd say the bootloader could handle that, knowing that for some machines
changing the bootloader isn't an option.

Best regards
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-König            |
Industrial Linux Solutions                 | https://www.pengutronix.de/ |

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH net-next v2 02/19] net: phy: add a shutdown procedure
  2023-08-03 18:16   ` Uwe Kleine-König
@ 2023-08-03 18:24     ` Florian Fainelli
  2023-08-03 18:49       ` Russell King (Oracle)
  0 siblings, 1 reply; 31+ messages in thread
From: Florian Fainelli @ 2023-08-03 18:24 UTC (permalink / raw)
  To: Uwe Kleine-König, Ioana Ciornei
  Cc: Andrew Lunn, Heiner Kallweit, Russell King, Jakub Kicinski,
	netdev, linux-kernel, Ioana Ciornei, Alexandru Ardelean,
	Andre Edich, Antoine Tenart, Baruch Siach, Christophe Leroy,
	Divya Koppera, Hauke Mehrtens, Jerome Brunet,
	Kavya Sree Kotagiri, Linus Walleij, Marco Felsch, Marek Vasut,
	Martin Blumenstingl, Mathias Kresin, Maxim Kochetkov,
	Michael Walle, Neil Armstrong, Nisar Sayed, Oleksij Rempel,
	Philippe Schenker, Willy Liu, Yuiko Oshino

On 8/3/23 11:16, Uwe Kleine-König wrote:
> Hello,
> 
> this patch became commit e2f016cf775129c050d6c79483073423db15c79a and is
> contained in v5.11-rc1.
> 
> It broke wake-on-lan on my NAS (an ARM machine with an Armada 370 SoC,
> armada-370-netgear-rn104.dts). The used phy driver is marvell.c. I only
> report it now as I just upgraded that machine from Debian 11 (with
> kernel 5.10.x) to Debian 12 (with kernel 6.1.x).
> 
> Commenting out phy_disable_interrupts(...) in v6.1.41's phy_shutdown()
> fixes the problem for me.
> 
> On Sun, Nov 01, 2020 at 02:50:57PM +0200, Ioana Ciornei wrote:
>> In case of a board which uses a shared IRQ we can easily end up with an
>> IRQ storm after a forced reboot.
>>
>> For example, a 'reboot -f' will trigger a call to the .shutdown()
>> callbacks of all devices. Because phylib does not implement that hook,
>> the PHY is not quiesced, thus it can very well leave its IRQ enabled.
>>
>> At the next boot, if that IRQ line is found asserted by the first PHY
>> driver that uses it, but _before_ the driver that is _actually_ keeping
>> the shared IRQ asserted is probed, the IRQ is not going to be
>> acknowledged, thus it will keep being fired preventing the boot process
>> of the kernel to continue. This is even worse when the second PHY driver
>> is a module.
>>
>> To fix this, implement the .shutdown() callback and disable the
>> interrupts if these are used.
> 
> I don't know how this should interact with wake-on-lan, but I would
> expect that there is a way to fix this without reintroducing the problem
> fixed by this change. However I cannot say if this needs fixing in the
> generic phy code or the phy driver. Any hints?

It depends upon what the PHY drivers and underlying hardware are capable 
and willing to do. Some PHY drivers will shutdown the TX path completely 
since you do not need that part to receive Wake-on-LAN packets and pass 
them up to the PHY and/or MAC Wake-on-LAN matching logic. This would 
invite us to let individual PHY drivers make a decision as to what they 
want to do in a .shutdown() routine that would then need to be added to 
each and every driver that wants to do something special. In the absence 
of said routine, you could default to calling phy_disable_interrupts() 
unless the PHY has WoL enabled?

phydev::wol_enabled reflects whether the PHY and/or the MAC has 
Wake-on-LAN enabled which could you could key off to "nullify" what the 
shutdown does.

>   
>> Note that we are still susceptible to IRQ storms if the previous kernel
>> exited with a panic or if the bootloader left the shared IRQ active, but
>> there is absolutely nothing we can do about these cases.
> 
> I'd say the bootloader could handle that, knowing that for some machines
> changing the bootloader isn't an option.

There is also the case of the boot loader not touching any 
PHY/MAC/networking and just booting as fast as possible to the kernel. 
It really becomes a problem that can be distributed against multiple SW 
agents to solve it, though clearly the kernel could do it too, so why 
not keep it there I guess.
-- 
Florian


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH net-next v2 02/19] net: phy: add a shutdown procedure
  2023-08-03 18:24     ` Florian Fainelli
@ 2023-08-03 18:49       ` Russell King (Oracle)
  0 siblings, 0 replies; 31+ messages in thread
From: Russell King (Oracle) @ 2023-08-03 18:49 UTC (permalink / raw)
  To: Florian Fainelli
  Cc: Uwe Kleine-König, Ioana Ciornei, Andrew Lunn,
	Heiner Kallweit, Jakub Kicinski, netdev, linux-kernel,
	Ioana Ciornei, Alexandru Ardelean, Andre Edich, Antoine Tenart,
	Baruch Siach, Christophe Leroy, Divya Koppera, Hauke Mehrtens,
	Jerome Brunet, Kavya Sree Kotagiri, Linus Walleij, Marco Felsch,
	Marek Vasut, Martin Blumenstingl, Mathias Kresin,
	Maxim Kochetkov, Michael Walle, Neil Armstrong, Nisar Sayed,
	Oleksij Rempel, Philippe Schenker, Willy Liu, Yuiko Oshino

On Thu, Aug 03, 2023 at 11:24:04AM -0700, Florian Fainelli wrote:
> On 8/3/23 11:16, Uwe Kleine-König wrote:
> > Hello,
> > 
> > this patch became commit e2f016cf775129c050d6c79483073423db15c79a and is
> > contained in v5.11-rc1.
> > 
> > It broke wake-on-lan on my NAS (an ARM machine with an Armada 370 SoC,
> > armada-370-netgear-rn104.dts). The used phy driver is marvell.c. I only
> > report it now as I just upgraded that machine from Debian 11 (with
> > kernel 5.10.x) to Debian 12 (with kernel 6.1.x).
> > 
> > Commenting out phy_disable_interrupts(...) in v6.1.41's phy_shutdown()
> > fixes the problem for me.
> > 
> > On Sun, Nov 01, 2020 at 02:50:57PM +0200, Ioana Ciornei wrote:
> > > In case of a board which uses a shared IRQ we can easily end up with an
> > > IRQ storm after a forced reboot.
> > > 
> > > For example, a 'reboot -f' will trigger a call to the .shutdown()
> > > callbacks of all devices. Because phylib does not implement that hook,
> > > the PHY is not quiesced, thus it can very well leave its IRQ enabled.
> > > 
> > > At the next boot, if that IRQ line is found asserted by the first PHY
> > > driver that uses it, but _before_ the driver that is _actually_ keeping
> > > the shared IRQ asserted is probed, the IRQ is not going to be
> > > acknowledged, thus it will keep being fired preventing the boot process
> > > of the kernel to continue. This is even worse when the second PHY driver
> > > is a module.
> > > 
> > > To fix this, implement the .shutdown() callback and disable the
> > > interrupts if these are used.
> > 
> > I don't know how this should interact with wake-on-lan, but I would
> > expect that there is a way to fix this without reintroducing the problem
> > fixed by this change. However I cannot say if this needs fixing in the
> > generic phy code or the phy driver. Any hints?
> 
> It depends upon what the PHY drivers and underlying hardware are capable and
> willing to do. Some PHY drivers will shutdown the TX path completely since
> you do not need that part to receive Wake-on-LAN packets and pass them up to
> the PHY and/or MAC Wake-on-LAN matching logic. This would invite us to let
> individual PHY drivers make a decision as to what they want to do in a
> .shutdown() routine that would then need to be added to each and every
> driver that wants to do something special. In the absence of said routine,
> you could default to calling phy_disable_interrupts() unless the PHY has WoL
> enabled?
> 
> phydev::wol_enabled reflects whether the PHY and/or the MAC has Wake-on-LAN
> enabled which could you could key off to "nullify" what the shutdown does.

If the shutdown method is being called, doesn't that imply that we're
going to be hibernating rather than suspend-to-RAM - because suspend-to
RAM doesn't involve powering down the system, whereas hibernating does.

I think the problem is that when placing the system into hibernate mode
with WoL enabled, there are PHYs which use their interrupt pin to signal
that a WoL event has happened. The problem comes with the aforementioned
commit that the core PHY code now _always_ disables interrupts on the
PHY, even if WoL is active and we're entering hibernate mode.

That's clearly the wrong thing to be doing when people expect WoL to
be able to wake their systems up from hibernate.

The more I think about it, the more I'm coming to the conclusion that
the blamed commit is wrong as it is coded today.

It also occurs to me that systems need to cope with the PHY's INT signal
being asserted through boot, because in the case of WoL-triggered resume
from hibernate mode, the PHY's INT signal will be asserted _while_ the
system is booting up (and remember, recovery from hibernate mode is
essentially no different from a normal system boot with the exception
that the kernel notices a special signature in the swap partition, and
then reloads state from there.)

So, boot has to cope properly with the PHY's interrupt being asserted
in order for WoL from hibernate to work.

It seems to me that a revert of the blamed commit is in order, and a
different approach is needed?

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!

^ permalink raw reply	[flat|nested] 31+ messages in thread

end of thread, other threads:[~2023-08-03 18:50 UTC | newest]

Thread overview: 31+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-11-01 12:50 [PATCH net-next v2 00/19] net: phy: add support for shared interrupts (part 1) Ioana Ciornei
2020-11-01 12:50 ` [PATCH net-next v2 01/19] net: phy: export phy_error and phy_trigger_machine Ioana Ciornei
2020-11-01 12:50 ` [PATCH net-next v2 02/19] net: phy: add a shutdown procedure Ioana Ciornei
2023-08-03 18:16   ` Uwe Kleine-König
2023-08-03 18:24     ` Florian Fainelli
2023-08-03 18:49       ` Russell King (Oracle)
2020-11-01 12:50 ` [PATCH net-next v2 03/19] net: phy: make .ack_interrupt() optional Ioana Ciornei
2020-11-01 12:50 ` [PATCH net-next v2 04/19] net: phy: at803x: implement generic .handle_interrupt() callback Ioana Ciornei
2020-11-04 18:09   ` Oleksij Rempel
2020-11-01 12:51 ` [PATCH net-next v2 05/19] net: phy: at803x: remove the use of .ack_interrupt() Ioana Ciornei
2020-11-04 18:09   ` Oleksij Rempel
2020-11-01 12:51 ` [PATCH net-next v2 06/19] net: phy: mscc: use phy_trigger_machine() to notify link change Ioana Ciornei
2020-11-05  0:10   ` Vladimir Oltean
2020-11-01 12:51 ` [PATCH net-next v2 07/19] net: phy: mscc: implement generic .handle_interrupt() callback Ioana Ciornei
2020-11-05  0:08   ` Vladimir Oltean
2020-11-01 12:51 ` [PATCH net-next v2 08/19] net: phy: mscc: remove the use of .ack_interrupt() Ioana Ciornei
2020-11-05  0:07   ` Vladimir Oltean
2020-11-01 12:51 ` [PATCH net-next v2 09/19] net: phy: aquantia: implement generic .handle_interrupt() callback Ioana Ciornei
2020-11-01 12:51 ` [PATCH net-next v2 10/19] net: phy: aquantia: remove the use of .ack_interrupt() Ioana Ciornei
2020-11-01 12:51 ` [PATCH net-next v2 11/19] net: phy: broadcom: implement generic .handle_interrupt() callback Ioana Ciornei
2020-11-01 12:51 ` [PATCH net-next v2 12/19] net: phy: broadcom: remove use of ack_interrupt() Ioana Ciornei
2020-11-01 12:51 ` [PATCH net-next v2 13/19] net: phy: cicada: implement the generic .handle_interrupt() callback Ioana Ciornei
2020-11-01 12:51 ` [PATCH net-next v2 14/19] net: phy: cicada: remove the use of .ack_interrupt() Ioana Ciornei
2020-11-01 12:51 ` [PATCH net-next v2 15/19] net: phy: davicom: implement generic .handle_interrupt() calback Ioana Ciornei
2020-11-01 12:51 ` [PATCH net-next v2 16/19] net: phy: davicom: remove the use of .ack_interrupt() Ioana Ciornei
2020-11-01 12:51 ` [PATCH net-next v2 17/19] net: phy: add genphy_handle_interrupt_no_ack() Ioana Ciornei
2020-11-01 12:51 ` [PATCH net-next v2 18/19] net: phy: realtek: implement generic .handle_interrupt() callback Ioana Ciornei
2020-11-01 12:51 ` [PATCH net-next v2 19/19] net: phy: realtek: remove the use of .ack_interrupt() Ioana Ciornei
2020-11-03 16:44 ` [PATCH net-next v2 00/19] net: phy: add support for shared interrupts (part 1) Andrew Lunn
2020-11-03 22:53 ` Michael Walle
2020-11-06  0:36 ` Jakub Kicinski

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).