diff mbox series

[net-next,1/4] net: phylink: support for link gpio interrupt

Message ID E1hSk6y-0000vs-Pj@rmk-PC.armlinux.org.uk
State Deferred
Delegated to: David Miller
Headers show
Series phylink/sfp updates | expand

Commit Message

Russell King (Oracle) May 20, 2019, 3:22 p.m. UTC
Add support for using GPIO interrupts with a fixed-link GPIO rather than
polling the GPIO every second and invoking the phylink resolution.  This
avoids unnecessary calls to mac_config().

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
 drivers/net/phy/phylink.c | 36 ++++++++++++++++++++++++++++++++----
 1 file changed, 32 insertions(+), 4 deletions(-)

Comments

Florian Fainelli May 20, 2019, 6:22 p.m. UTC | #1
On 5/20/19 8:22 AM, Russell King wrote:
> Add support for using GPIO interrupts with a fixed-link GPIO rather than
> polling the GPIO every second and invoking the phylink resolution.  This
> avoids unnecessary calls to mac_config().
> 
> Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>

Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>

Just one comment, see below:

[snip]

> -	if (pl->link_an_mode == MLO_AN_FIXED && !IS_ERR(pl->link_gpio))
> -		del_timer_sync(&pl->link_poll);
> +	del_timer_sync(&pl->link_poll);

Removing a timer that was only set-up if pl->link_an_mode ==
MLO_AN_FIXED probably does not hurt, but this breaks symmetry a bit here.
Russell King (Oracle) May 20, 2019, 6:31 p.m. UTC | #2
On Mon, May 20, 2019 at 11:22:21AM -0700, Florian Fainelli wrote:
> On 5/20/19 8:22 AM, Russell King wrote:
> > Add support for using GPIO interrupts with a fixed-link GPIO rather than
> > polling the GPIO every second and invoking the phylink resolution.  This
> > avoids unnecessary calls to mac_config().
> > 
> > Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
> 
> Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
> 
> Just one comment, see below:
> 
> [snip]
> 
> > -	if (pl->link_an_mode == MLO_AN_FIXED && !IS_ERR(pl->link_gpio))
> > -		del_timer_sync(&pl->link_poll);
> > +	del_timer_sync(&pl->link_poll);
> 
> Removing a timer that was only set-up if pl->link_an_mode ==
> MLO_AN_FIXED probably does not hurt, but this breaks symmetry a bit here.

The reason for this change is because that is no longer the only case
that the timer would be running.  The timer will be running if either
of the following are true:

1. We are in fixed mode, and we have a get_fixed_state function
   registered.
2. We are in fixed mode, and have a GPIO, but are unable to get an
   interrupt for it.

It's way simpler and less error-prone to just delete the timer here,
rather than trying to keep track of whether we armed it.
diff mbox series

Patch

diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
index 74983593834b..bdee5f307a7f 100644
--- a/drivers/net/phy/phylink.c
+++ b/drivers/net/phy/phylink.c
@@ -52,6 +52,7 @@  struct phylink {
 	/* The link configuration settings */
 	struct phylink_link_state link_config;
 	struct gpio_desc *link_gpio;
+	unsigned int link_irq;
 	struct timer_list link_poll;
 	void (*get_fixed_state)(struct net_device *dev,
 				struct phylink_link_state *s);
@@ -608,7 +609,7 @@  void phylink_destroy(struct phylink *pl)
 {
 	if (pl->sfp_bus)
 		sfp_unregister_upstream(pl->sfp_bus);
-	if (!IS_ERR_OR_NULL(pl->link_gpio))
+	if (pl->link_gpio)
 		gpiod_put(pl->link_gpio);
 
 	cancel_work_sync(&pl->resolve);
@@ -871,6 +872,15 @@  void phylink_mac_change(struct phylink *pl, bool up)
 }
 EXPORT_SYMBOL_GPL(phylink_mac_change);
 
+static irqreturn_t phylink_link_handler(int irq, void *data)
+{
+	struct phylink *pl = data;
+
+	phylink_run_resolve(pl);
+
+	return IRQ_HANDLED;
+}
+
 /**
  * phylink_start() - start a phylink instance
  * @pl: a pointer to a &struct phylink returned from phylink_create()
@@ -906,7 +916,22 @@  void phylink_start(struct phylink *pl)
 	clear_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state);
 	phylink_run_resolve(pl);
 
-	if (pl->link_an_mode == MLO_AN_FIXED && !IS_ERR(pl->link_gpio))
+	if (pl->link_an_mode == MLO_AN_FIXED && pl->link_gpio) {
+		int irq = gpiod_to_irq(pl->link_gpio);
+
+		if (irq > 0) {
+			if (!request_irq(irq, phylink_link_handler,
+					 IRQF_TRIGGER_RISING |
+					 IRQF_TRIGGER_FALLING,
+					 "netdev link", pl))
+				pl->link_irq = irq;
+			else
+				irq = 0;
+		}
+		if (irq <= 0)
+			mod_timer(&pl->link_poll, jiffies + HZ);
+	}
+	if (pl->link_an_mode == MLO_AN_FIXED && pl->get_fixed_state)
 		mod_timer(&pl->link_poll, jiffies + HZ);
 	if (pl->sfp_bus)
 		sfp_upstream_start(pl->sfp_bus);
@@ -932,8 +957,11 @@  void phylink_stop(struct phylink *pl)
 		phy_stop(pl->phydev);
 	if (pl->sfp_bus)
 		sfp_upstream_stop(pl->sfp_bus);
-	if (pl->link_an_mode == MLO_AN_FIXED && !IS_ERR(pl->link_gpio))
-		del_timer_sync(&pl->link_poll);
+	del_timer_sync(&pl->link_poll);
+	if (pl->link_irq) {
+		free_irq(pl->link_irq, pl);
+		pl->link_irq = 0;
+	}
 
 	phylink_run_resolve_and_disable(pl, PHYLINK_DISABLE_STOPPED);
 }