summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@armlinux.org.uk>2019-01-25 20:22:16 +0000
committerRussell King <rmk+kernel@armlinux.org.uk>2019-07-09 11:44:26 +0100
commit602434f811f2e36d4e0539eb76c006a2fd2727d3 (patch)
tree260d238ef08e6477fb80f2a4acdf002e2725f8f1
parentbae46f840a41f5b56e121c27b49f4406c91f9c5f (diff)
net: phylink: support for link gpio interrupt
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(). Reviewed-by: Florian Fainelli <f.fainelli@gmail.com> Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
-rw-r--r--drivers/net/phy/phylink.c36
1 files changed, 32 insertions, 4 deletions
diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
index 1f9b1c1de778..eb1051c1a4c6 100644
--- a/drivers/net/phy/phylink.c
+++ b/drivers/net/phy/phylink.c
@@ -56,6 +56,7 @@ struct phylink {
phy_interface_t cur_interface;
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);
@@ -612,7 +613,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);
@@ -875,6 +876,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()
@@ -910,7 +920,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);
@@ -936,8 +961,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);
}