From 1566db0439525fc0ef29c496d73f7e984d280319 Mon Sep 17 00:00:00 2001 From: Ioana Ciornei Date: Mon, 23 Nov 2020 17:38:03 +0200 Subject: net: phy: intel-xway: implement generic .handle_interrupt() callback 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: Mathias Kresin Cc: Hauke Mehrtens Signed-off-by: Ioana Ciornei Signed-off-by: Jakub Kicinski --- drivers/net/phy/intel-xway.c | 46 +++++++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 18 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/intel-xway.c b/drivers/net/phy/intel-xway.c index b7875b36097f..1a27ae1bec5c 100644 --- a/drivers/net/phy/intel-xway.c +++ b/drivers/net/phy/intel-xway.c @@ -209,14 +209,6 @@ static int xway_gphy_ack_interrupt(struct phy_device *phydev) return (reg < 0) ? reg : 0; } -static int xway_gphy_did_interrupt(struct phy_device *phydev) -{ - int reg; - - reg = phy_read(phydev, XWAY_MDIO_ISTAT); - return reg & XWAY_MDIO_INIT_MASK; -} - static int xway_gphy_config_intr(struct phy_device *phydev) { u16 mask = 0; @@ -227,6 +219,24 @@ static int xway_gphy_config_intr(struct phy_device *phydev) return phy_write(phydev, XWAY_MDIO_IMASK, mask); } +static irqreturn_t xway_gphy_handle_interrupt(struct phy_device *phydev) +{ + int irq_status; + + irq_status = phy_read(phydev, XWAY_MDIO_ISTAT); + if (irq_status < 0) { + phy_error(phydev); + return IRQ_NONE; + } + + if (!(irq_status & XWAY_MDIO_INIT_MASK)) + return IRQ_NONE; + + phy_trigger_machine(phydev); + + return IRQ_HANDLED; +} + static struct phy_driver xway_gphy[] = { { .phy_id = PHY_ID_PHY11G_1_3, @@ -236,7 +246,7 @@ static struct phy_driver xway_gphy[] = { .config_init = xway_gphy_config_init, .config_aneg = xway_gphy14_config_aneg, .ack_interrupt = xway_gphy_ack_interrupt, - .did_interrupt = xway_gphy_did_interrupt, + .handle_interrupt = xway_gphy_handle_interrupt, .config_intr = xway_gphy_config_intr, .suspend = genphy_suspend, .resume = genphy_resume, @@ -248,7 +258,7 @@ static struct phy_driver xway_gphy[] = { .config_init = xway_gphy_config_init, .config_aneg = xway_gphy14_config_aneg, .ack_interrupt = xway_gphy_ack_interrupt, - .did_interrupt = xway_gphy_did_interrupt, + .handle_interrupt = xway_gphy_handle_interrupt, .config_intr = xway_gphy_config_intr, .suspend = genphy_suspend, .resume = genphy_resume, @@ -260,7 +270,7 @@ static struct phy_driver xway_gphy[] = { .config_init = xway_gphy_config_init, .config_aneg = xway_gphy14_config_aneg, .ack_interrupt = xway_gphy_ack_interrupt, - .did_interrupt = xway_gphy_did_interrupt, + .handle_interrupt = xway_gphy_handle_interrupt, .config_intr = xway_gphy_config_intr, .suspend = genphy_suspend, .resume = genphy_resume, @@ -272,7 +282,7 @@ static struct phy_driver xway_gphy[] = { .config_init = xway_gphy_config_init, .config_aneg = xway_gphy14_config_aneg, .ack_interrupt = xway_gphy_ack_interrupt, - .did_interrupt = xway_gphy_did_interrupt, + .handle_interrupt = xway_gphy_handle_interrupt, .config_intr = xway_gphy_config_intr, .suspend = genphy_suspend, .resume = genphy_resume, @@ -283,7 +293,7 @@ static struct phy_driver xway_gphy[] = { /* PHY_GBIT_FEATURES */ .config_init = xway_gphy_config_init, .ack_interrupt = xway_gphy_ack_interrupt, - .did_interrupt = xway_gphy_did_interrupt, + .handle_interrupt = xway_gphy_handle_interrupt, .config_intr = xway_gphy_config_intr, .suspend = genphy_suspend, .resume = genphy_resume, @@ -294,7 +304,7 @@ static struct phy_driver xway_gphy[] = { /* PHY_BASIC_FEATURES */ .config_init = xway_gphy_config_init, .ack_interrupt = xway_gphy_ack_interrupt, - .did_interrupt = xway_gphy_did_interrupt, + .handle_interrupt = xway_gphy_handle_interrupt, .config_intr = xway_gphy_config_intr, .suspend = genphy_suspend, .resume = genphy_resume, @@ -305,7 +315,7 @@ static struct phy_driver xway_gphy[] = { /* PHY_GBIT_FEATURES */ .config_init = xway_gphy_config_init, .ack_interrupt = xway_gphy_ack_interrupt, - .did_interrupt = xway_gphy_did_interrupt, + .handle_interrupt = xway_gphy_handle_interrupt, .config_intr = xway_gphy_config_intr, .suspend = genphy_suspend, .resume = genphy_resume, @@ -316,7 +326,7 @@ static struct phy_driver xway_gphy[] = { /* PHY_BASIC_FEATURES */ .config_init = xway_gphy_config_init, .ack_interrupt = xway_gphy_ack_interrupt, - .did_interrupt = xway_gphy_did_interrupt, + .handle_interrupt = xway_gphy_handle_interrupt, .config_intr = xway_gphy_config_intr, .suspend = genphy_suspend, .resume = genphy_resume, @@ -327,7 +337,7 @@ static struct phy_driver xway_gphy[] = { /* PHY_GBIT_FEATURES */ .config_init = xway_gphy_config_init, .ack_interrupt = xway_gphy_ack_interrupt, - .did_interrupt = xway_gphy_did_interrupt, + .handle_interrupt = xway_gphy_handle_interrupt, .config_intr = xway_gphy_config_intr, .suspend = genphy_suspend, .resume = genphy_resume, @@ -338,7 +348,7 @@ static struct phy_driver xway_gphy[] = { /* PHY_BASIC_FEATURES */ .config_init = xway_gphy_config_init, .ack_interrupt = xway_gphy_ack_interrupt, - .did_interrupt = xway_gphy_did_interrupt, + .handle_interrupt = xway_gphy_handle_interrupt, .config_intr = xway_gphy_config_intr, .suspend = genphy_suspend, .resume = genphy_resume, -- cgit v1.2.3 From 16c9709a75043d58ded3fb01807a6c0cd456ea49 Mon Sep 17 00:00:00 2001 From: Ioana Ciornei Date: Mon, 23 Nov 2020 17:38:04 +0200 Subject: net: phy: intel-xway: remove the use of .ack_interrupt() 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: Mathias Kresin Cc: Hauke Mehrtens Signed-off-by: Ioana Ciornei Signed-off-by: Jakub Kicinski --- drivers/net/phy/intel-xway.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/intel-xway.c b/drivers/net/phy/intel-xway.c index 1a27ae1bec5c..6eac50d4b42f 100644 --- a/drivers/net/phy/intel-xway.c +++ b/drivers/net/phy/intel-xway.c @@ -212,11 +212,24 @@ static int xway_gphy_ack_interrupt(struct phy_device *phydev) static int xway_gphy_config_intr(struct phy_device *phydev) { u16 mask = 0; + int err; + + if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { + err = xway_gphy_ack_interrupt(phydev); + if (err) + return err; - if (phydev->interrupts == PHY_INTERRUPT_ENABLED) mask = XWAY_MDIO_INIT_MASK; + err = phy_write(phydev, XWAY_MDIO_IMASK, mask); + } else { + err = phy_write(phydev, XWAY_MDIO_IMASK, mask); + if (err) + return err; + + err = xway_gphy_ack_interrupt(phydev); + } - return phy_write(phydev, XWAY_MDIO_IMASK, mask); + return err; } static irqreturn_t xway_gphy_handle_interrupt(struct phy_device *phydev) @@ -245,7 +258,6 @@ static struct phy_driver xway_gphy[] = { /* PHY_GBIT_FEATURES */ .config_init = xway_gphy_config_init, .config_aneg = xway_gphy14_config_aneg, - .ack_interrupt = xway_gphy_ack_interrupt, .handle_interrupt = xway_gphy_handle_interrupt, .config_intr = xway_gphy_config_intr, .suspend = genphy_suspend, @@ -257,7 +269,6 @@ static struct phy_driver xway_gphy[] = { /* PHY_BASIC_FEATURES */ .config_init = xway_gphy_config_init, .config_aneg = xway_gphy14_config_aneg, - .ack_interrupt = xway_gphy_ack_interrupt, .handle_interrupt = xway_gphy_handle_interrupt, .config_intr = xway_gphy_config_intr, .suspend = genphy_suspend, @@ -269,7 +280,6 @@ static struct phy_driver xway_gphy[] = { /* PHY_GBIT_FEATURES */ .config_init = xway_gphy_config_init, .config_aneg = xway_gphy14_config_aneg, - .ack_interrupt = xway_gphy_ack_interrupt, .handle_interrupt = xway_gphy_handle_interrupt, .config_intr = xway_gphy_config_intr, .suspend = genphy_suspend, @@ -281,7 +291,6 @@ static struct phy_driver xway_gphy[] = { /* PHY_BASIC_FEATURES */ .config_init = xway_gphy_config_init, .config_aneg = xway_gphy14_config_aneg, - .ack_interrupt = xway_gphy_ack_interrupt, .handle_interrupt = xway_gphy_handle_interrupt, .config_intr = xway_gphy_config_intr, .suspend = genphy_suspend, @@ -292,7 +301,6 @@ static struct phy_driver xway_gphy[] = { .name = "Intel XWAY PHY11G (PEF 7071/PEF 7072) v1.5 / v1.6", /* PHY_GBIT_FEATURES */ .config_init = xway_gphy_config_init, - .ack_interrupt = xway_gphy_ack_interrupt, .handle_interrupt = xway_gphy_handle_interrupt, .config_intr = xway_gphy_config_intr, .suspend = genphy_suspend, @@ -303,7 +311,6 @@ static struct phy_driver xway_gphy[] = { .name = "Intel XWAY PHY22F (PEF 7061) v1.5 / v1.6", /* PHY_BASIC_FEATURES */ .config_init = xway_gphy_config_init, - .ack_interrupt = xway_gphy_ack_interrupt, .handle_interrupt = xway_gphy_handle_interrupt, .config_intr = xway_gphy_config_intr, .suspend = genphy_suspend, @@ -314,7 +321,6 @@ static struct phy_driver xway_gphy[] = { .name = "Intel XWAY PHY11G (xRX v1.1 integrated)", /* PHY_GBIT_FEATURES */ .config_init = xway_gphy_config_init, - .ack_interrupt = xway_gphy_ack_interrupt, .handle_interrupt = xway_gphy_handle_interrupt, .config_intr = xway_gphy_config_intr, .suspend = genphy_suspend, @@ -325,7 +331,6 @@ static struct phy_driver xway_gphy[] = { .name = "Intel XWAY PHY22F (xRX v1.1 integrated)", /* PHY_BASIC_FEATURES */ .config_init = xway_gphy_config_init, - .ack_interrupt = xway_gphy_ack_interrupt, .handle_interrupt = xway_gphy_handle_interrupt, .config_intr = xway_gphy_config_intr, .suspend = genphy_suspend, @@ -336,7 +341,6 @@ static struct phy_driver xway_gphy[] = { .name = "Intel XWAY PHY11G (xRX v1.2 integrated)", /* PHY_GBIT_FEATURES */ .config_init = xway_gphy_config_init, - .ack_interrupt = xway_gphy_ack_interrupt, .handle_interrupt = xway_gphy_handle_interrupt, .config_intr = xway_gphy_config_intr, .suspend = genphy_suspend, @@ -347,7 +351,6 @@ static struct phy_driver xway_gphy[] = { .name = "Intel XWAY PHY22F (xRX v1.2 integrated)", /* PHY_BASIC_FEATURES */ .config_init = xway_gphy_config_init, - .ack_interrupt = xway_gphy_ack_interrupt, .handle_interrupt = xway_gphy_handle_interrupt, .config_intr = xway_gphy_config_intr, .suspend = genphy_suspend, -- cgit v1.2.3 From 25497b7f0bd90706dd697523f3e9e074641632b5 Mon Sep 17 00:00:00 2001 From: Ioana Ciornei Date: Mon, 23 Nov 2020 17:38:05 +0200 Subject: net: phy: icplus: implement generic .handle_interrupt() callback 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 Signed-off-by: Ioana Ciornei Signed-off-by: Jakub Kicinski --- drivers/net/phy/icplus.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/icplus.c b/drivers/net/phy/icplus.c index d6e8516cd146..a74ff45fa99c 100644 --- a/drivers/net/phy/icplus.c +++ b/drivers/net/phy/icplus.c @@ -285,16 +285,24 @@ static int ip101a_g_config_intr(struct phy_device *phydev) return phy_write(phydev, IP101A_G_IRQ_CONF_STATUS, val); } -static int ip101a_g_did_interrupt(struct phy_device *phydev) +static irqreturn_t ip101a_g_handle_interrupt(struct phy_device *phydev) { - int val = phy_read(phydev, IP101A_G_IRQ_CONF_STATUS); + int irq_status; - if (val < 0) - return 0; + irq_status = phy_read(phydev, IP101A_G_IRQ_CONF_STATUS); + if (irq_status < 0) { + phy_error(phydev); + return IRQ_NONE; + } + + if (!(irq_status & (IP101A_G_IRQ_SPEED_CHANGE | + IP101A_G_IRQ_DUPLEX_CHANGE | + IP101A_G_IRQ_LINK_CHANGE))) + return IRQ_NONE; + + phy_trigger_machine(phydev); - return val & (IP101A_G_IRQ_SPEED_CHANGE | - IP101A_G_IRQ_DUPLEX_CHANGE | - IP101A_G_IRQ_LINK_CHANGE); + return IRQ_HANDLED; } static int ip101a_g_ack_interrupt(struct phy_device *phydev) @@ -332,8 +340,8 @@ static struct phy_driver icplus_driver[] = { /* PHY_BASIC_FEATURES */ .probe = ip101a_g_probe, .config_intr = ip101a_g_config_intr, - .did_interrupt = ip101a_g_did_interrupt, .ack_interrupt = ip101a_g_ack_interrupt, + .handle_interrupt = ip101a_g_handle_interrupt, .config_init = &ip101a_g_config_init, .suspend = genphy_suspend, .resume = genphy_resume, -- cgit v1.2.3 From 12ae7ba3c15aa6aa1eef6deb275bbd9a812a575d Mon Sep 17 00:00:00 2001 From: Ioana Ciornei Date: Mon, 23 Nov 2020 17:38:06 +0200 Subject: net: phy: icplus: remove the use .ack_interrupt() 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 Signed-off-by: Ioana Ciornei Signed-off-by: Jakub Kicinski --- drivers/net/phy/icplus.c | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/icplus.c b/drivers/net/phy/icplus.c index a74ff45fa99c..b632947cbcdf 100644 --- a/drivers/net/phy/icplus.c +++ b/drivers/net/phy/icplus.c @@ -272,17 +272,39 @@ static int ip101a_g_config_init(struct phy_device *phydev) return phy_write(phydev, IP10XX_SPEC_CTRL_STATUS, c); } +static int ip101a_g_ack_interrupt(struct phy_device *phydev) +{ + int err = phy_read(phydev, IP101A_G_IRQ_CONF_STATUS); + + if (err < 0) + return err; + + return 0; +} + static int ip101a_g_config_intr(struct phy_device *phydev) { u16 val; + int err; + + if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { + err = ip101a_g_ack_interrupt(phydev); + if (err) + return err; - if (phydev->interrupts == PHY_INTERRUPT_ENABLED) /* INTR pin used: Speed/link/duplex will cause an interrupt */ val = IP101A_G_IRQ_PIN_USED; - else + err = phy_write(phydev, IP101A_G_IRQ_CONF_STATUS, val); + } else { val = IP101A_G_IRQ_ALL_MASK; + err = phy_write(phydev, IP101A_G_IRQ_CONF_STATUS, val); + if (err) + return err; + + err = ip101a_g_ack_interrupt(phydev); + } - return phy_write(phydev, IP101A_G_IRQ_CONF_STATUS, val); + return err; } static irqreturn_t ip101a_g_handle_interrupt(struct phy_device *phydev) @@ -305,15 +327,6 @@ static irqreturn_t ip101a_g_handle_interrupt(struct phy_device *phydev) return IRQ_HANDLED; } -static int ip101a_g_ack_interrupt(struct phy_device *phydev) -{ - int err = phy_read(phydev, IP101A_G_IRQ_CONF_STATUS); - if (err < 0) - return err; - - return 0; -} - static struct phy_driver icplus_driver[] = { { .phy_id = 0x02430d80, @@ -340,7 +353,6 @@ static struct phy_driver icplus_driver[] = { /* PHY_BASIC_FEATURES */ .probe = ip101a_g_probe, .config_intr = ip101a_g_config_intr, - .ack_interrupt = ip101a_g_ack_interrupt, .handle_interrupt = ip101a_g_handle_interrupt, .config_init = &ip101a_g_config_init, .suspend = genphy_suspend, -- cgit v1.2.3 From 6719e2be0fcfa404a885e9bf80c7e1139adf0e39 Mon Sep 17 00:00:00 2001 From: Ioana Ciornei Date: Mon, 23 Nov 2020 17:38:07 +0200 Subject: net: phy: meson-gxl: implement generic .handle_interrupt() callback 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: Jerome Brunet Cc: Neil Armstrong Signed-off-by: Ioana Ciornei Signed-off-by: Jakub Kicinski --- drivers/net/phy/meson-gxl.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/phy/meson-gxl.c b/drivers/net/phy/meson-gxl.c index e8f2ca625837..b16b1cc89165 100644 --- a/drivers/net/phy/meson-gxl.c +++ b/drivers/net/phy/meson-gxl.c @@ -222,6 +222,24 @@ static int meson_gxl_config_intr(struct phy_device *phydev) return phy_write(phydev, INTSRC_MASK, val); } +static irqreturn_t meson_gxl_handle_interrupt(struct phy_device *phydev) +{ + int irq_status; + + irq_status = phy_read(phydev, INTSRC_FLAG); + 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 struct phy_driver meson_gxl_phy[] = { { PHY_ID_MATCH_EXACT(0x01814400), @@ -233,6 +251,7 @@ static struct phy_driver meson_gxl_phy[] = { .read_status = meson_gxl_read_status, .ack_interrupt = meson_gxl_ack_interrupt, .config_intr = meson_gxl_config_intr, + .handle_interrupt = meson_gxl_handle_interrupt, .suspend = genphy_suspend, .resume = genphy_resume, }, { @@ -243,6 +262,7 @@ static struct phy_driver meson_gxl_phy[] = { .soft_reset = genphy_soft_reset, .ack_interrupt = meson_gxl_ack_interrupt, .config_intr = meson_gxl_config_intr, + .handle_interrupt = meson_gxl_handle_interrupt, .suspend = genphy_suspend, .resume = genphy_resume, }, -- cgit v1.2.3 From 84c8f773d2dc17193aba2e707338f6e107fb71e5 Mon Sep 17 00:00:00 2001 From: Ioana Ciornei Date: Mon, 23 Nov 2020 17:38:08 +0200 Subject: net: phy: meson-gxl: remove the use of .ack_callback() 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: Jerome Brunet Cc: Neil Armstrong Signed-off-by: Ioana Ciornei Signed-off-by: Jakub Kicinski --- drivers/net/phy/meson-gxl.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/meson-gxl.c b/drivers/net/phy/meson-gxl.c index b16b1cc89165..7e7904fee1d9 100644 --- a/drivers/net/phy/meson-gxl.c +++ b/drivers/net/phy/meson-gxl.c @@ -204,22 +204,27 @@ static int meson_gxl_config_intr(struct phy_device *phydev) int ret; if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { + /* Ack any pending IRQ */ + ret = meson_gxl_ack_interrupt(phydev); + if (ret) + return ret; + val = INTSRC_ANEG_PR | INTSRC_PARALLEL_FAULT | INTSRC_ANEG_LP_ACK | INTSRC_LINK_DOWN | INTSRC_REMOTE_FAULT | INTSRC_ANEG_COMPLETE; + ret = phy_write(phydev, INTSRC_MASK, val); } else { val = 0; - } + ret = phy_write(phydev, INTSRC_MASK, val); - /* Ack any pending IRQ */ - ret = meson_gxl_ack_interrupt(phydev); - if (ret) - return ret; + /* Ack any pending IRQ */ + ret = meson_gxl_ack_interrupt(phydev); + } - return phy_write(phydev, INTSRC_MASK, val); + return ret; } static irqreturn_t meson_gxl_handle_interrupt(struct phy_device *phydev) @@ -249,7 +254,6 @@ static struct phy_driver meson_gxl_phy[] = { .soft_reset = genphy_soft_reset, .config_init = meson_gxl_config_init, .read_status = meson_gxl_read_status, - .ack_interrupt = meson_gxl_ack_interrupt, .config_intr = meson_gxl_config_intr, .handle_interrupt = meson_gxl_handle_interrupt, .suspend = genphy_suspend, @@ -260,7 +264,6 @@ static struct phy_driver meson_gxl_phy[] = { /* PHY_BASIC_FEATURES */ .flags = PHY_IS_INTERNAL, .soft_reset = genphy_soft_reset, - .ack_interrupt = meson_gxl_ack_interrupt, .config_intr = meson_gxl_config_intr, .handle_interrupt = meson_gxl_handle_interrupt, .suspend = genphy_suspend, -- cgit v1.2.3 From 59ca4e58b9176989b11b1311c903b3a05e6b87a1 Mon Sep 17 00:00:00 2001 From: Ioana Ciornei Date: Mon, 23 Nov 2020 17:38:09 +0200 Subject: net: phy: micrel: implement generic .handle_interrupt() callback 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: Divya Koppera Cc: Oleksij Rempel Cc: Philippe Schenker Cc: Marek Vasut Cc: Antoine Tenart Signed-off-by: Ioana Ciornei Signed-off-by: Jakub Kicinski --- drivers/net/phy/micrel.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index a7f74b3b97af..9aa96ebd31c8 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -48,6 +48,10 @@ #define KSZPHY_INTCS_LINK_UP BIT(8) #define KSZPHY_INTCS_ALL (KSZPHY_INTCS_LINK_UP |\ KSZPHY_INTCS_LINK_DOWN) +#define KSZPHY_INTCS_LINK_DOWN_STATUS BIT(2) +#define KSZPHY_INTCS_LINK_UP_STATUS BIT(0) +#define KSZPHY_INTCS_STATUS (KSZPHY_INTCS_LINK_DOWN_STATUS |\ + KSZPHY_INTCS_LINK_UP_STATUS) /* PHY Control 1 */ #define MII_KSZPHY_CTRL_1 0x1e @@ -182,6 +186,24 @@ static int kszphy_config_intr(struct phy_device *phydev) return phy_write(phydev, MII_KSZPHY_INTCS, temp); } +static irqreturn_t kszphy_handle_interrupt(struct phy_device *phydev) +{ + int irq_status; + + irq_status = phy_read(phydev, MII_KSZPHY_INTCS); + if (irq_status < 0) { + phy_error(phydev); + return IRQ_NONE; + } + + if ((irq_status & KSZPHY_INTCS_STATUS)) + return IRQ_NONE; + + phy_trigger_machine(phydev); + + return IRQ_HANDLED; +} + static int kszphy_rmii_clk_sel(struct phy_device *phydev, bool val) { int ctrl; @@ -1162,6 +1184,7 @@ static struct phy_driver ksphy_driver[] = { .config_init = kszphy_config_init, .ack_interrupt = kszphy_ack_interrupt, .config_intr = kszphy_config_intr, + .handle_interrupt = kszphy_handle_interrupt, .suspend = genphy_suspend, .resume = genphy_resume, }, { @@ -1174,6 +1197,7 @@ static struct phy_driver ksphy_driver[] = { .config_init = kszphy_config_init, .ack_interrupt = kszphy_ack_interrupt, .config_intr = kszphy_config_intr, + .handle_interrupt = kszphy_handle_interrupt, .get_sset_count = kszphy_get_sset_count, .get_strings = kszphy_get_strings, .get_stats = kszphy_get_stats, @@ -1189,6 +1213,7 @@ static struct phy_driver ksphy_driver[] = { .config_init = kszphy_config_init, .ack_interrupt = kszphy_ack_interrupt, .config_intr = kszphy_config_intr, + .handle_interrupt = kszphy_handle_interrupt, .get_sset_count = kszphy_get_sset_count, .get_strings = kszphy_get_strings, .get_stats = kszphy_get_stats, @@ -1205,6 +1230,7 @@ static struct phy_driver ksphy_driver[] = { .config_aneg = ksz8041_config_aneg, .ack_interrupt = kszphy_ack_interrupt, .config_intr = kszphy_config_intr, + .handle_interrupt = kszphy_handle_interrupt, .get_sset_count = kszphy_get_sset_count, .get_strings = kszphy_get_strings, .get_stats = kszphy_get_stats, @@ -1220,6 +1246,7 @@ static struct phy_driver ksphy_driver[] = { .config_init = kszphy_config_init, .ack_interrupt = kszphy_ack_interrupt, .config_intr = kszphy_config_intr, + .handle_interrupt = kszphy_handle_interrupt, .get_sset_count = kszphy_get_sset_count, .get_strings = kszphy_get_strings, .get_stats = kszphy_get_stats, @@ -1233,6 +1260,7 @@ static struct phy_driver ksphy_driver[] = { .config_init = kszphy_config_init, .ack_interrupt = kszphy_ack_interrupt, .config_intr = kszphy_config_intr, + .handle_interrupt = kszphy_handle_interrupt, .get_sset_count = kszphy_get_sset_count, .get_strings = kszphy_get_strings, .get_stats = kszphy_get_stats, @@ -1249,6 +1277,7 @@ static struct phy_driver ksphy_driver[] = { .config_init = kszphy_config_init, .ack_interrupt = kszphy_ack_interrupt, .config_intr = kszphy_config_intr, + .handle_interrupt = kszphy_handle_interrupt, .get_sset_count = kszphy_get_sset_count, .get_strings = kszphy_get_strings, .get_stats = kszphy_get_stats, @@ -1264,6 +1293,7 @@ static struct phy_driver ksphy_driver[] = { .config_init = ksz8081_config_init, .ack_interrupt = kszphy_ack_interrupt, .config_intr = kszphy_config_intr, + .handle_interrupt = kszphy_handle_interrupt, .get_sset_count = kszphy_get_sset_count, .get_strings = kszphy_get_strings, .get_stats = kszphy_get_stats, @@ -1277,6 +1307,7 @@ static struct phy_driver ksphy_driver[] = { .config_init = ksz8061_config_init, .ack_interrupt = kszphy_ack_interrupt, .config_intr = kszphy_config_intr, + .handle_interrupt = kszphy_handle_interrupt, .suspend = genphy_suspend, .resume = genphy_resume, }, { @@ -1290,6 +1321,7 @@ static struct phy_driver ksphy_driver[] = { .config_init = ksz9021_config_init, .ack_interrupt = kszphy_ack_interrupt, .config_intr = kszphy_config_intr, + .handle_interrupt = kszphy_handle_interrupt, .get_sset_count = kszphy_get_sset_count, .get_strings = kszphy_get_strings, .get_stats = kszphy_get_stats, @@ -1309,6 +1341,7 @@ static struct phy_driver ksphy_driver[] = { .read_status = ksz9031_read_status, .ack_interrupt = kszphy_ack_interrupt, .config_intr = kszphy_config_intr, + .handle_interrupt = kszphy_handle_interrupt, .get_sset_count = kszphy_get_sset_count, .get_strings = kszphy_get_strings, .get_stats = kszphy_get_stats, @@ -1338,6 +1371,7 @@ static struct phy_driver ksphy_driver[] = { .read_status = genphy_read_status, .ack_interrupt = kszphy_ack_interrupt, .config_intr = kszphy_config_intr, + .handle_interrupt = kszphy_handle_interrupt, .get_sset_count = kszphy_get_sset_count, .get_strings = kszphy_get_strings, .get_stats = kszphy_get_stats, -- cgit v1.2.3 From c0c99d0cd107b86fc03ec6c49a03bd01d83b1ce7 Mon Sep 17 00:00:00 2001 From: Ioana Ciornei Date: Mon, 23 Nov 2020 17:38:10 +0200 Subject: net: phy: micrel: remove the use of .ack_interrupt() 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: Divya Koppera Cc: Oleksij Rempel Cc: Philippe Schenker Cc: Marek Vasut Cc: Antoine Tenart Signed-off-by: Ioana Ciornei Signed-off-by: Jakub Kicinski --- drivers/net/phy/micrel.c | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 9aa96ebd31c8..97f08f20630b 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -162,7 +162,7 @@ static int kszphy_ack_interrupt(struct phy_device *phydev) static int kszphy_config_intr(struct phy_device *phydev) { const struct kszphy_type *type = phydev->drv->driver_data; - int temp; + int temp, err; u16 mask; if (type && type->interrupt_level_mask) @@ -178,12 +178,23 @@ static int kszphy_config_intr(struct phy_device *phydev) phy_write(phydev, MII_KSZPHY_CTRL, temp); /* enable / disable interrupts */ - if (phydev->interrupts == PHY_INTERRUPT_ENABLED) + if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { + err = kszphy_ack_interrupt(phydev); + if (err) + return err; + temp = KSZPHY_INTCS_ALL; - else + err = phy_write(phydev, MII_KSZPHY_INTCS, temp); + } else { temp = 0; + err = phy_write(phydev, MII_KSZPHY_INTCS, temp); + if (err) + return err; + + err = kszphy_ack_interrupt(phydev); + } - return phy_write(phydev, MII_KSZPHY_INTCS, temp); + return err; } static irqreturn_t kszphy_handle_interrupt(struct phy_device *phydev) @@ -1182,7 +1193,6 @@ static struct phy_driver ksphy_driver[] = { /* PHY_BASIC_FEATURES */ .driver_data = &ks8737_type, .config_init = kszphy_config_init, - .ack_interrupt = kszphy_ack_interrupt, .config_intr = kszphy_config_intr, .handle_interrupt = kszphy_handle_interrupt, .suspend = genphy_suspend, @@ -1195,7 +1205,6 @@ static struct phy_driver ksphy_driver[] = { .driver_data = &ksz8021_type, .probe = kszphy_probe, .config_init = kszphy_config_init, - .ack_interrupt = kszphy_ack_interrupt, .config_intr = kszphy_config_intr, .handle_interrupt = kszphy_handle_interrupt, .get_sset_count = kszphy_get_sset_count, @@ -1211,7 +1220,6 @@ static struct phy_driver ksphy_driver[] = { .driver_data = &ksz8021_type, .probe = kszphy_probe, .config_init = kszphy_config_init, - .ack_interrupt = kszphy_ack_interrupt, .config_intr = kszphy_config_intr, .handle_interrupt = kszphy_handle_interrupt, .get_sset_count = kszphy_get_sset_count, @@ -1228,7 +1236,6 @@ static struct phy_driver ksphy_driver[] = { .probe = kszphy_probe, .config_init = ksz8041_config_init, .config_aneg = ksz8041_config_aneg, - .ack_interrupt = kszphy_ack_interrupt, .config_intr = kszphy_config_intr, .handle_interrupt = kszphy_handle_interrupt, .get_sset_count = kszphy_get_sset_count, @@ -1244,7 +1251,6 @@ static struct phy_driver ksphy_driver[] = { .driver_data = &ksz8041_type, .probe = kszphy_probe, .config_init = kszphy_config_init, - .ack_interrupt = kszphy_ack_interrupt, .config_intr = kszphy_config_intr, .handle_interrupt = kszphy_handle_interrupt, .get_sset_count = kszphy_get_sset_count, @@ -1258,7 +1264,6 @@ static struct phy_driver ksphy_driver[] = { .driver_data = &ksz8051_type, .probe = kszphy_probe, .config_init = kszphy_config_init, - .ack_interrupt = kszphy_ack_interrupt, .config_intr = kszphy_config_intr, .handle_interrupt = kszphy_handle_interrupt, .get_sset_count = kszphy_get_sset_count, @@ -1275,7 +1280,6 @@ static struct phy_driver ksphy_driver[] = { .driver_data = &ksz8041_type, .probe = kszphy_probe, .config_init = kszphy_config_init, - .ack_interrupt = kszphy_ack_interrupt, .config_intr = kszphy_config_intr, .handle_interrupt = kszphy_handle_interrupt, .get_sset_count = kszphy_get_sset_count, @@ -1291,7 +1295,6 @@ static struct phy_driver ksphy_driver[] = { .driver_data = &ksz8081_type, .probe = kszphy_probe, .config_init = ksz8081_config_init, - .ack_interrupt = kszphy_ack_interrupt, .config_intr = kszphy_config_intr, .handle_interrupt = kszphy_handle_interrupt, .get_sset_count = kszphy_get_sset_count, @@ -1305,7 +1308,6 @@ static struct phy_driver ksphy_driver[] = { .phy_id_mask = MICREL_PHY_ID_MASK, /* PHY_BASIC_FEATURES */ .config_init = ksz8061_config_init, - .ack_interrupt = kszphy_ack_interrupt, .config_intr = kszphy_config_intr, .handle_interrupt = kszphy_handle_interrupt, .suspend = genphy_suspend, @@ -1319,7 +1321,6 @@ static struct phy_driver ksphy_driver[] = { .probe = kszphy_probe, .get_features = ksz9031_get_features, .config_init = ksz9021_config_init, - .ack_interrupt = kszphy_ack_interrupt, .config_intr = kszphy_config_intr, .handle_interrupt = kszphy_handle_interrupt, .get_sset_count = kszphy_get_sset_count, @@ -1339,7 +1340,6 @@ static struct phy_driver ksphy_driver[] = { .config_init = ksz9031_config_init, .soft_reset = genphy_soft_reset, .read_status = ksz9031_read_status, - .ack_interrupt = kszphy_ack_interrupt, .config_intr = kszphy_config_intr, .handle_interrupt = kszphy_handle_interrupt, .get_sset_count = kszphy_get_sset_count, @@ -1369,7 +1369,6 @@ static struct phy_driver ksphy_driver[] = { .probe = kszphy_probe, .config_init = ksz9131_config_init, .read_status = genphy_read_status, - .ack_interrupt = kszphy_ack_interrupt, .config_intr = kszphy_config_intr, .handle_interrupt = kszphy_handle_interrupt, .get_sset_count = kszphy_get_sset_count, -- cgit v1.2.3 From 6571b4555dc94908f13d811898cddc5c0fa8bd71 Mon Sep 17 00:00:00 2001 From: Ioana Ciornei Date: Mon, 23 Nov 2020 17:38:11 +0200 Subject: net: phy: national: implement generic .handle_interrupt() callback 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 Signed-off-by: Jakub Kicinski --- drivers/net/phy/national.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/phy/national.c b/drivers/net/phy/national.c index a5bf0874c7d8..8c71fd66b0b1 100644 --- a/drivers/net/phy/national.c +++ b/drivers/net/phy/national.c @@ -89,6 +89,27 @@ static int ns_ack_interrupt(struct phy_device *phydev) return ret; } +static irqreturn_t ns_handle_interrupt(struct phy_device *phydev) +{ + int irq_status; + + irq_status = phy_read(phydev, DP83865_INT_STATUS); + if (irq_status < 0) { + phy_error(phydev); + return IRQ_NONE; + } + + if (!(irq_status & DP83865_INT_MASK_DEFAULT)) + return IRQ_NONE; + + /* clear the interrupt */ + phy_write(phydev, DP83865_INT_CLEAR, irq_status & ~0x7); + + phy_trigger_machine(phydev); + + return IRQ_HANDLED; +} + static void ns_giga_speed_fallback(struct phy_device *phydev, int mode) { int bmcr = phy_read(phydev, MII_BMCR); @@ -135,6 +156,7 @@ static struct phy_driver dp83865_driver[] = { { .config_init = ns_config_init, .ack_interrupt = ns_ack_interrupt, .config_intr = ns_config_intr, + .handle_interrupt = ns_handle_interrupt, } }; module_phy_driver(dp83865_driver); -- cgit v1.2.3 From a4d7742149f6a4880fa8bdf941a40c345162074c Mon Sep 17 00:00:00 2001 From: Ioana Ciornei Date: Mon, 23 Nov 2020 17:38:12 +0200 Subject: net: phy: national: remove the use of the .ack_interrupt() 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 Signed-off-by: Jakub Kicinski --- drivers/net/phy/national.c | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/national.c b/drivers/net/phy/national.c index 8c71fd66b0b1..5a8c8eb18582 100644 --- a/drivers/net/phy/national.c +++ b/drivers/net/phy/national.c @@ -63,19 +63,6 @@ static void ns_exp_write(struct phy_device *phydev, u16 reg, u8 data) phy_write(phydev, NS_EXP_MEM_DATA, data); } -static int ns_config_intr(struct phy_device *phydev) -{ - int err; - - if (phydev->interrupts == PHY_INTERRUPT_ENABLED) - err = phy_write(phydev, DP83865_INT_MASK, - DP83865_INT_MASK_DEFAULT); - else - err = phy_write(phydev, DP83865_INT_MASK, 0); - - return err; -} - static int ns_ack_interrupt(struct phy_device *phydev) { int ret = phy_read(phydev, DP83865_INT_STATUS); @@ -110,6 +97,28 @@ static irqreturn_t ns_handle_interrupt(struct phy_device *phydev) return IRQ_HANDLED; } +static int ns_config_intr(struct phy_device *phydev) +{ + int err; + + if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { + err = ns_ack_interrupt(phydev); + if (err) + return err; + + err = phy_write(phydev, DP83865_INT_MASK, + DP83865_INT_MASK_DEFAULT); + } else { + err = phy_write(phydev, DP83865_INT_MASK, 0); + if (err) + return err; + + err = ns_ack_interrupt(phydev); + } + + return err; +} + static void ns_giga_speed_fallback(struct phy_device *phydev, int mode) { int bmcr = phy_read(phydev, MII_BMCR); @@ -154,7 +163,6 @@ static struct phy_driver dp83865_driver[] = { { .name = "NatSemi DP83865", /* PHY_GBIT_FEATURES */ .config_init = ns_config_init, - .ack_interrupt = ns_ack_interrupt, .config_intr = ns_config_intr, .handle_interrupt = ns_handle_interrupt, } }; -- cgit v1.2.3 From 1d1ae3c6ca3ff49843d73852bb2a8153ce16f432 Mon Sep 17 00:00:00 2001 From: Ioana Ciornei Date: Mon, 23 Nov 2020 17:38:13 +0200 Subject: net: phy: ti: implement generic .handle_interrupt() callback 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: Dan Murphy Signed-off-by: Ioana Ciornei Signed-off-by: Jakub Kicinski --- drivers/net/phy/dp83640.c | 27 +++++++++++++++++++++++++++ drivers/net/phy/dp83822.c | 37 +++++++++++++++++++++++++++++++++++++ drivers/net/phy/dp83848.c | 33 +++++++++++++++++++++++++++++++++ drivers/net/phy/dp83867.c | 25 +++++++++++++++++++++++++ drivers/net/phy/dp83869.c | 25 +++++++++++++++++++++++++ drivers/net/phy/dp83tc811.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 191 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c index f2caccaf4408..89577f1d3576 100644 --- a/drivers/net/phy/dp83640.c +++ b/drivers/net/phy/dp83640.c @@ -50,6 +50,14 @@ #define MII_DP83640_MISR_LINK_INT_EN 0x20 #define MII_DP83640_MISR_ED_INT_EN 0x40 #define MII_DP83640_MISR_LQ_INT_EN 0x80 +#define MII_DP83640_MISR_ANC_INT 0x400 +#define MII_DP83640_MISR_DUP_INT 0x800 +#define MII_DP83640_MISR_SPD_INT 0x1000 +#define MII_DP83640_MISR_LINK_INT 0x2000 +#define MII_DP83640_MISR_INT_MASK (MII_DP83640_MISR_ANC_INT |\ + MII_DP83640_MISR_DUP_INT |\ + MII_DP83640_MISR_SPD_INT |\ + MII_DP83640_MISR_LINK_INT) /* phyter seems to miss the mark by 16 ns */ #define ADJTIME_FIX 16 @@ -1193,6 +1201,24 @@ static int dp83640_config_intr(struct phy_device *phydev) } } +static irqreturn_t dp83640_handle_interrupt(struct phy_device *phydev) +{ + int irq_status; + + irq_status = phy_read(phydev, MII_DP83640_MISR); + if (irq_status < 0) { + phy_error(phydev); + return IRQ_NONE; + } + + if (!(irq_status & MII_DP83640_MISR_INT_MASK)) + return IRQ_NONE; + + phy_trigger_machine(phydev); + + return IRQ_HANDLED; +} + static int dp83640_hwtstamp(struct mii_timestamper *mii_ts, struct ifreq *ifr) { struct dp83640_private *dp83640 = @@ -1517,6 +1543,7 @@ static struct phy_driver dp83640_driver = { .config_init = dp83640_config_init, .ack_interrupt = dp83640_ack_interrupt, .config_intr = dp83640_config_intr, + .handle_interrupt = dp83640_handle_interrupt, }; static int __init dp83640_init(void) diff --git a/drivers/net/phy/dp83822.c b/drivers/net/phy/dp83822.c index c162c9551bd1..bb512ac3f533 100644 --- a/drivers/net/phy/dp83822.c +++ b/drivers/net/phy/dp83822.c @@ -303,6 +303,41 @@ static int dp83822_config_intr(struct phy_device *phydev) return phy_write(phydev, MII_DP83822_PHYSCR, physcr_status); } +static irqreturn_t dp83822_handle_interrupt(struct phy_device *phydev) +{ + int irq_status; + + /* The MISR1 and MISR2 registers are holding the interrupt status in + * the upper half (15:8), while the lower half (7:0) is used for + * controlling the interrupt enable state of those individual interrupt + * sources. To determine the possible interrupt sources, just read the + * MISR* register and use it directly to know which interrupts have + * been enabled previously or not. + */ + irq_status = phy_read(phydev, MII_DP83822_MISR1); + if (irq_status < 0) { + phy_error(phydev); + return IRQ_NONE; + } + if (irq_status & ((irq_status & GENMASK(7, 0)) << 8)) + goto trigger_machine; + + irq_status = phy_read(phydev, MII_DP83822_MISR2); + if (irq_status < 0) { + phy_error(phydev); + return IRQ_NONE; + } + if (irq_status & ((irq_status & GENMASK(7, 0)) << 8)) + goto trigger_machine; + + return IRQ_NONE; + +trigger_machine: + phy_trigger_machine(phydev); + + return IRQ_HANDLED; +} + static int dp8382x_disable_wol(struct phy_device *phydev) { int value = DP83822_WOL_EN | DP83822_WOL_MAGIC_EN | @@ -576,6 +611,7 @@ static int dp83822_resume(struct phy_device *phydev) .set_wol = dp83822_set_wol, \ .ack_interrupt = dp83822_ack_interrupt, \ .config_intr = dp83822_config_intr, \ + .handle_interrupt = dp83822_handle_interrupt, \ .suspend = dp83822_suspend, \ .resume = dp83822_resume, \ } @@ -591,6 +627,7 @@ static int dp83822_resume(struct phy_device *phydev) .set_wol = dp83822_set_wol, \ .ack_interrupt = dp83822_ack_interrupt, \ .config_intr = dp83822_config_intr, \ + .handle_interrupt = dp83822_handle_interrupt, \ .suspend = dp83822_suspend, \ .resume = dp83822_resume, \ } diff --git a/drivers/net/phy/dp83848.c b/drivers/net/phy/dp83848.c index 54c7c1b44e4d..b707a9b27847 100644 --- a/drivers/net/phy/dp83848.c +++ b/drivers/net/phy/dp83848.c @@ -37,6 +37,20 @@ DP83848_MISR_SPD_INT_EN | \ DP83848_MISR_LINK_INT_EN) +#define DP83848_MISR_RHF_INT BIT(8) +#define DP83848_MISR_FHF_INT BIT(9) +#define DP83848_MISR_ANC_INT BIT(10) +#define DP83848_MISR_DUP_INT BIT(11) +#define DP83848_MISR_SPD_INT BIT(12) +#define DP83848_MISR_LINK_INT BIT(13) +#define DP83848_MISR_ED_INT BIT(14) + +#define DP83848_INT_MASK \ + (DP83848_MISR_ANC_INT | \ + DP83848_MISR_DUP_INT | \ + DP83848_MISR_SPD_INT | \ + DP83848_MISR_LINK_INT) + static int dp83848_ack_interrupt(struct phy_device *phydev) { int err = phy_read(phydev, DP83848_MISR); @@ -66,6 +80,24 @@ static int dp83848_config_intr(struct phy_device *phydev) return phy_write(phydev, DP83848_MICR, control); } +static irqreturn_t dp83848_handle_interrupt(struct phy_device *phydev) +{ + int irq_status; + + irq_status = phy_read(phydev, DP83848_MISR); + if (irq_status < 0) { + phy_error(phydev); + return IRQ_NONE; + } + + if (!(irq_status & DP83848_INT_MASK)) + return IRQ_NONE; + + phy_trigger_machine(phydev); + + return IRQ_HANDLED; +} + static int dp83848_config_init(struct phy_device *phydev) { int val; @@ -104,6 +136,7 @@ MODULE_DEVICE_TABLE(mdio, dp83848_tbl); /* IRQ related */ \ .ack_interrupt = dp83848_ack_interrupt, \ .config_intr = dp83848_config_intr, \ + .handle_interrupt = dp83848_handle_interrupt, \ } static struct phy_driver dp83848_driver[] = { diff --git a/drivers/net/phy/dp83867.c b/drivers/net/phy/dp83867.c index 69d3eacc2b96..aba4e4c1f75c 100644 --- a/drivers/net/phy/dp83867.c +++ b/drivers/net/phy/dp83867.c @@ -310,6 +310,30 @@ static int dp83867_config_intr(struct phy_device *phydev) return phy_write(phydev, MII_DP83867_MICR, micr_status); } +static irqreturn_t dp83867_handle_interrupt(struct phy_device *phydev) +{ + int irq_status, irq_enabled; + + irq_status = phy_read(phydev, MII_DP83867_ISR); + if (irq_status < 0) { + phy_error(phydev); + return IRQ_NONE; + } + + irq_enabled = phy_read(phydev, MII_DP83867_MICR); + 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 int dp83867_read_status(struct phy_device *phydev) { int status = phy_read(phydev, MII_DP83867_PHYSTS); @@ -827,6 +851,7 @@ static struct phy_driver dp83867_driver[] = { /* IRQ related */ .ack_interrupt = dp83867_ack_interrupt, .config_intr = dp83867_config_intr, + .handle_interrupt = dp83867_handle_interrupt, .suspend = genphy_suspend, .resume = genphy_resume, diff --git a/drivers/net/phy/dp83869.c b/drivers/net/phy/dp83869.c index cf6dec7b7d8e..487d1b8beec5 100644 --- a/drivers/net/phy/dp83869.c +++ b/drivers/net/phy/dp83869.c @@ -207,6 +207,30 @@ static int dp83869_config_intr(struct phy_device *phydev) return phy_write(phydev, MII_DP83869_MICR, micr_status); } +static irqreturn_t dp83869_handle_interrupt(struct phy_device *phydev) +{ + int irq_status, irq_enabled; + + irq_status = phy_read(phydev, MII_DP83869_ISR); + if (irq_status < 0) { + phy_error(phydev); + return IRQ_NONE; + } + + irq_enabled = phy_read(phydev, MII_DP83869_MICR); + 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 int dp83869_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol) { @@ -852,6 +876,7 @@ static struct phy_driver dp83869_driver[] = { /* IRQ related */ .ack_interrupt = dp83869_ack_interrupt, .config_intr = dp83869_config_intr, + .handle_interrupt = dp83869_handle_interrupt, .read_status = dp83869_read_status, .get_tunable = dp83869_get_tunable, diff --git a/drivers/net/phy/dp83tc811.c b/drivers/net/phy/dp83tc811.c index d73725312c7c..a93c64ac76a3 100644 --- a/drivers/net/phy/dp83tc811.c +++ b/drivers/net/phy/dp83tc811.c @@ -254,6 +254,49 @@ static int dp83811_config_intr(struct phy_device *phydev) return err; } +static irqreturn_t dp83811_handle_interrupt(struct phy_device *phydev) +{ + int irq_status; + + /* The INT_STAT registers 1, 2 and 3 are holding the interrupt status + * in the upper half (15:8), while the lower half (7:0) is used for + * controlling the interrupt enable state of those individual interrupt + * sources. To determine the possible interrupt sources, just read the + * INT_STAT* register and use it directly to know which interrupts have + * been enabled previously or not. + */ + irq_status = phy_read(phydev, MII_DP83811_INT_STAT1); + if (irq_status < 0) { + phy_error(phydev); + return IRQ_NONE; + } + if (irq_status & ((irq_status & GENMASK(7, 0)) << 8)) + goto trigger_machine; + + irq_status = phy_read(phydev, MII_DP83811_INT_STAT2); + if (irq_status < 0) { + phy_error(phydev); + return IRQ_NONE; + } + if (irq_status & ((irq_status & GENMASK(7, 0)) << 8)) + goto trigger_machine; + + irq_status = phy_read(phydev, MII_DP83811_INT_STAT3); + if (irq_status < 0) { + phy_error(phydev); + return IRQ_NONE; + } + if (irq_status & ((irq_status & GENMASK(7, 0)) << 8)) + goto trigger_machine; + + return IRQ_NONE; + +trigger_machine: + phy_trigger_machine(phydev); + + return IRQ_HANDLED; +} + static int dp83811_config_aneg(struct phy_device *phydev) { int value, err; @@ -345,6 +388,7 @@ static struct phy_driver dp83811_driver[] = { .set_wol = dp83811_set_wol, .ack_interrupt = dp83811_ack_interrupt, .config_intr = dp83811_config_intr, + .handle_interrupt = dp83811_handle_interrupt, .suspend = dp83811_suspend, .resume = dp83811_resume, }, -- cgit v1.2.3 From aa2d603ac8c0a3070e78edd4c07606ae2587754f Mon Sep 17 00:00:00 2001 From: Ioana Ciornei Date: Mon, 23 Nov 2020 17:38:14 +0200 Subject: net: phy: ti: remove the use of .ack_interrupt() 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: Dan Murphy Signed-off-by: Ioana Ciornei Signed-off-by: Jakub Kicinski --- drivers/net/phy/dp83640.c | 11 +++++++++-- drivers/net/phy/dp83822.c | 17 ----------------- drivers/net/phy/dp83848.c | 14 ++++++++++++-- drivers/net/phy/dp83867.c | 19 ++++++++++++++----- drivers/net/phy/dp83869.c | 17 +++++++++++++---- drivers/net/phy/dp83tc811.c | 9 ++++++++- 6 files changed, 56 insertions(+), 31 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c index 89577f1d3576..f1001ae1df51 100644 --- a/drivers/net/phy/dp83640.c +++ b/drivers/net/phy/dp83640.c @@ -1159,6 +1159,10 @@ static int dp83640_config_intr(struct phy_device *phydev) int err; if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { + err = dp83640_ack_interrupt(phydev); + if (err) + return err; + misr = phy_read(phydev, MII_DP83640_MISR); if (misr < 0) return misr; @@ -1197,7 +1201,11 @@ static int dp83640_config_intr(struct phy_device *phydev) MII_DP83640_MISR_DUP_INT_EN | MII_DP83640_MISR_SPD_INT_EN | MII_DP83640_MISR_LINK_INT_EN); - return phy_write(phydev, MII_DP83640_MISR, misr); + err = phy_write(phydev, MII_DP83640_MISR, misr); + if (err) + return err; + + return dp83640_ack_interrupt(phydev); } } @@ -1541,7 +1549,6 @@ static struct phy_driver dp83640_driver = { .remove = dp83640_remove, .soft_reset = dp83640_soft_reset, .config_init = dp83640_config_init, - .ack_interrupt = dp83640_ack_interrupt, .config_intr = dp83640_config_intr, .handle_interrupt = dp83640_handle_interrupt, }; diff --git a/drivers/net/phy/dp83822.c b/drivers/net/phy/dp83822.c index bb512ac3f533..fff371ca1086 100644 --- a/drivers/net/phy/dp83822.c +++ b/drivers/net/phy/dp83822.c @@ -119,21 +119,6 @@ struct dp83822_private { u16 fx_sd_enable; }; -static int dp83822_ack_interrupt(struct phy_device *phydev) -{ - int err; - - err = phy_read(phydev, MII_DP83822_MISR1); - if (err < 0) - return err; - - err = phy_read(phydev, MII_DP83822_MISR2); - if (err < 0) - return err; - - return 0; -} - static int dp83822_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol) { @@ -609,7 +594,6 @@ static int dp83822_resume(struct phy_device *phydev) .read_status = dp83822_read_status, \ .get_wol = dp83822_get_wol, \ .set_wol = dp83822_set_wol, \ - .ack_interrupt = dp83822_ack_interrupt, \ .config_intr = dp83822_config_intr, \ .handle_interrupt = dp83822_handle_interrupt, \ .suspend = dp83822_suspend, \ @@ -625,7 +609,6 @@ static int dp83822_resume(struct phy_device *phydev) .config_init = dp8382x_config_init, \ .get_wol = dp83822_get_wol, \ .set_wol = dp83822_set_wol, \ - .ack_interrupt = dp83822_ack_interrupt, \ .config_intr = dp83822_config_intr, \ .handle_interrupt = dp83822_handle_interrupt, \ .suspend = dp83822_suspend, \ diff --git a/drivers/net/phy/dp83848.c b/drivers/net/phy/dp83848.c index b707a9b27847..937061acfc61 100644 --- a/drivers/net/phy/dp83848.c +++ b/drivers/net/phy/dp83848.c @@ -67,17 +67,28 @@ static int dp83848_config_intr(struct phy_device *phydev) return control; if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { + ret = dp83848_ack_interrupt(phydev); + if (ret) + return ret; + control |= DP83848_MICR_INT_OE; control |= DP83848_MICR_INTEN; ret = phy_write(phydev, DP83848_MISR, DP83848_INT_EN_MASK); if (ret < 0) return ret; + + ret = phy_write(phydev, DP83848_MICR, control); } else { control &= ~DP83848_MICR_INTEN; + ret = phy_write(phydev, DP83848_MICR, control); + if (ret) + return ret; + + ret = dp83848_ack_interrupt(phydev); } - return phy_write(phydev, DP83848_MICR, control); + return ret; } static irqreturn_t dp83848_handle_interrupt(struct phy_device *phydev) @@ -134,7 +145,6 @@ MODULE_DEVICE_TABLE(mdio, dp83848_tbl); .resume = genphy_resume, \ \ /* IRQ related */ \ - .ack_interrupt = dp83848_ack_interrupt, \ .config_intr = dp83848_config_intr, \ .handle_interrupt = dp83848_handle_interrupt, \ } diff --git a/drivers/net/phy/dp83867.c b/drivers/net/phy/dp83867.c index aba4e4c1f75c..9bd9a5c0b1db 100644 --- a/drivers/net/phy/dp83867.c +++ b/drivers/net/phy/dp83867.c @@ -288,9 +288,13 @@ static void dp83867_get_wol(struct phy_device *phydev, static int dp83867_config_intr(struct phy_device *phydev) { - int micr_status; + int micr_status, err; if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { + err = dp83867_ack_interrupt(phydev); + if (err) + return err; + micr_status = phy_read(phydev, MII_DP83867_MICR); if (micr_status < 0) return micr_status; @@ -303,11 +307,17 @@ static int dp83867_config_intr(struct phy_device *phydev) MII_DP83867_MICR_DUP_MODE_CHNG_INT_EN | MII_DP83867_MICR_SLEEP_MODE_CHNG_INT_EN); - return phy_write(phydev, MII_DP83867_MICR, micr_status); + err = phy_write(phydev, MII_DP83867_MICR, micr_status); + } else { + micr_status = 0x0; + err = phy_write(phydev, MII_DP83867_MICR, micr_status); + if (err) + return err; + + err = dp83867_ack_interrupt(phydev); } - micr_status = 0x0; - return phy_write(phydev, MII_DP83867_MICR, micr_status); + return err; } static irqreturn_t dp83867_handle_interrupt(struct phy_device *phydev) @@ -849,7 +859,6 @@ static struct phy_driver dp83867_driver[] = { .set_wol = dp83867_set_wol, /* IRQ related */ - .ack_interrupt = dp83867_ack_interrupt, .config_intr = dp83867_config_intr, .handle_interrupt = dp83867_handle_interrupt, diff --git a/drivers/net/phy/dp83869.c b/drivers/net/phy/dp83869.c index 487d1b8beec5..b30bc142d82e 100644 --- a/drivers/net/phy/dp83869.c +++ b/drivers/net/phy/dp83869.c @@ -186,9 +186,13 @@ static int dp83869_ack_interrupt(struct phy_device *phydev) static int dp83869_config_intr(struct phy_device *phydev) { - int micr_status = 0; + int micr_status = 0, err; if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { + err = dp83869_ack_interrupt(phydev); + if (err) + return err; + micr_status = phy_read(phydev, MII_DP83869_MICR); if (micr_status < 0) return micr_status; @@ -201,10 +205,16 @@ static int dp83869_config_intr(struct phy_device *phydev) MII_DP83869_MICR_DUP_MODE_CHNG_INT_EN | MII_DP83869_MICR_SLEEP_MODE_CHNG_INT_EN); - return phy_write(phydev, MII_DP83869_MICR, micr_status); + err = phy_write(phydev, MII_DP83869_MICR, micr_status); + } else { + err = phy_write(phydev, MII_DP83869_MICR, micr_status); + if (err) + return err; + + err = dp83869_ack_interrupt(phydev); } - return phy_write(phydev, MII_DP83869_MICR, micr_status); + return err; } static irqreturn_t dp83869_handle_interrupt(struct phy_device *phydev) @@ -874,7 +884,6 @@ static struct phy_driver dp83869_driver[] = { .soft_reset = dp83869_phy_reset, /* IRQ related */ - .ack_interrupt = dp83869_ack_interrupt, .config_intr = dp83869_config_intr, .handle_interrupt = dp83869_handle_interrupt, .read_status = dp83869_read_status, diff --git a/drivers/net/phy/dp83tc811.c b/drivers/net/phy/dp83tc811.c index a93c64ac76a3..688fadffb249 100644 --- a/drivers/net/phy/dp83tc811.c +++ b/drivers/net/phy/dp83tc811.c @@ -197,6 +197,10 @@ static int dp83811_config_intr(struct phy_device *phydev) int misr_status, err; if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { + err = dp83811_ack_interrupt(phydev); + if (err) + return err; + misr_status = phy_read(phydev, MII_DP83811_INT_STAT1); if (misr_status < 0) return misr_status; @@ -249,6 +253,10 @@ static int dp83811_config_intr(struct phy_device *phydev) return err; err = phy_write(phydev, MII_DP83811_INT_STAT3, 0); + if (err < 0) + return err; + + err = dp83811_ack_interrupt(phydev); } return err; @@ -386,7 +394,6 @@ static struct phy_driver dp83811_driver[] = { .soft_reset = dp83811_phy_reset, .get_wol = dp83811_get_wol, .set_wol = dp83811_set_wol, - .ack_interrupt = dp83811_ack_interrupt, .config_intr = dp83811_config_intr, .handle_interrupt = dp83811_handle_interrupt, .suspend = dp83811_suspend, -- cgit v1.2.3 From efc3d9de7fa64433ceb962815aa16973c1b8d886 Mon Sep 17 00:00:00 2001 From: Ioana Ciornei Date: Mon, 23 Nov 2020 17:38:15 +0200 Subject: net: phy: qsemi: implement generic .handle_interrupt() callback 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 Signed-off-by: Jakub Kicinski --- drivers/net/phy/qsemi.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/phy/qsemi.c b/drivers/net/phy/qsemi.c index 1b15a991ee06..97f29ed2f0ca 100644 --- a/drivers/net/phy/qsemi.c +++ b/drivers/net/phy/qsemi.c @@ -106,6 +106,27 @@ static int qs6612_config_intr(struct phy_device *phydev) } +static irqreturn_t qs6612_handle_interrupt(struct phy_device *phydev) +{ + int irq_status; + + irq_status = phy_read(phydev, MII_QS6612_ISR); + if (irq_status < 0) { + phy_error(phydev); + return IRQ_NONE; + } + + if (!(irq_status & MII_QS6612_IMR_INIT)) + return IRQ_NONE; + + /* the interrupt source register is not self-clearing */ + qs6612_ack_interrupt(phydev); + + phy_trigger_machine(phydev); + + return IRQ_HANDLED; +} + static struct phy_driver qs6612_driver[] = { { .phy_id = 0x00181440, .name = "QS6612", @@ -114,6 +135,7 @@ static struct phy_driver qs6612_driver[] = { { .config_init = qs6612_config_init, .ack_interrupt = qs6612_ack_interrupt, .config_intr = qs6612_config_intr, + .handle_interrupt = qs6612_handle_interrupt, } }; module_phy_driver(qs6612_driver); -- cgit v1.2.3 From a1a4417458cd0b5a9b4ce574524d166f4dcd642f Mon Sep 17 00:00:00 2001 From: Ioana Ciornei Date: Mon, 23 Nov 2020 17:38:16 +0200 Subject: net: phy: qsemi: remove the use of .ack_interrupt() 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. Also, add a comment describing the multiple step interrupt acknoledgement process. Signed-off-by: Ioana Ciornei Signed-off-by: Jakub Kicinski --- drivers/net/phy/qsemi.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/qsemi.c b/drivers/net/phy/qsemi.c index 97f29ed2f0ca..d5c1aaa8236a 100644 --- a/drivers/net/phy/qsemi.c +++ b/drivers/net/phy/qsemi.c @@ -75,6 +75,10 @@ static int qs6612_ack_interrupt(struct phy_device *phydev) { int err; + /* The Interrupt Source register is not self-clearing, bits 4 and 5 are + * cleared when MII_BMSR is read and bits 1 and 3 are cleared when + * MII_EXPANSION is read + */ err = phy_read(phydev, MII_QS6612_ISR); if (err < 0) @@ -96,11 +100,22 @@ static int qs6612_ack_interrupt(struct phy_device *phydev) static int qs6612_config_intr(struct phy_device *phydev) { int err; - if (phydev->interrupts == PHY_INTERRUPT_ENABLED) + if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { + /* clear any interrupts before enabling them */ + err = qs6612_ack_interrupt(phydev); + if (err) + return err; + err = phy_write(phydev, MII_QS6612_IMR, MII_QS6612_IMR_INIT); - else + } else { err = phy_write(phydev, MII_QS6612_IMR, 0); + if (err) + return err; + + /* clear any leftover interrupts */ + err = qs6612_ack_interrupt(phydev); + } return err; @@ -133,7 +148,6 @@ static struct phy_driver qs6612_driver[] = { { .phy_id_mask = 0xfffffff0, /* PHY_BASIC_FEATURES */ .config_init = qs6612_config_init, - .ack_interrupt = qs6612_ack_interrupt, .config_intr = qs6612_config_intr, .handle_interrupt = qs6612_handle_interrupt, } }; -- cgit v1.2.3 From 6527b938426f7fa66051273568d234b1fe01a15b Mon Sep 17 00:00:00 2001 From: Ioana Ciornei Date: Mon, 23 Nov 2020 17:38:17 +0200 Subject: net: phy: remove the .did_interrupt() and .ack_interrupt() callback Now that all the PHY drivers have been migrated to directly implement the generic .handle_interrupt() callback for a seamless support of shared IRQs and all the .config_inter() implementations clear any pending interrupts, we can safely remove the two callbacks. With this patch, phylib has a proper support for shared IRQs (and not just for multi-PHY devices. A PHY driver must implement both the .handle_interrupt() and .config_intr() callbacks for the IRQs to be actually used. Signed-off-by: Ioana Ciornei Signed-off-by: Jakub Kicinski --- drivers/net/phy/phy.c | 48 ++------------------------------------------ drivers/net/phy/phy_device.c | 2 +- include/linux/phy.h | 19 ++++-------------- 3 files changed, 7 insertions(+), 62 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index dce86bad8231..45f75533c47c 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -113,23 +113,6 @@ void phy_print_status(struct phy_device *phydev) } EXPORT_SYMBOL(phy_print_status); -/** - * phy_clear_interrupt - Ack the phy device's interrupt - * @phydev: the phy_device struct - * - * If the @phydev driver has an ack_interrupt function, call it to - * ack and clear the phy device's interrupt. - * - * Returns 0 on success or < 0 on error. - */ -static int phy_clear_interrupt(struct phy_device *phydev) -{ - if (phydev->drv->ack_interrupt) - return phydev->drv->ack_interrupt(phydev); - - return 0; -} - /** * phy_config_interrupt - configure the PHY device for the requested interrupts * @phydev: the phy_device struct @@ -943,15 +926,8 @@ EXPORT_SYMBOL(phy_error); */ int phy_disable_interrupts(struct phy_device *phydev) { - int err; - /* Disable PHY interrupts */ - err = phy_config_interrupt(phydev, PHY_INTERRUPT_DISABLED); - if (err) - return err; - - /* Clear the interrupt */ - return phy_clear_interrupt(phydev); + return phy_config_interrupt(phydev, PHY_INTERRUPT_DISABLED); } /** @@ -966,22 +942,7 @@ static irqreturn_t phy_interrupt(int irq, void *phy_dat) struct phy_device *phydev = phy_dat; struct phy_driver *drv = phydev->drv; - if (drv->handle_interrupt) - return drv->handle_interrupt(phydev); - - if (drv->did_interrupt && !drv->did_interrupt(phydev)) - return IRQ_NONE; - - /* reschedule state queue work to run as soon as possible */ - phy_trigger_machine(phydev); - - /* did_interrupt() may have cleared the interrupt already */ - if (!drv->did_interrupt && phy_clear_interrupt(phydev)) { - phy_error(phydev); - return IRQ_NONE; - } - - return IRQ_HANDLED; + return drv->handle_interrupt(phydev); } /** @@ -990,11 +951,6 @@ static irqreturn_t phy_interrupt(int irq, void *phy_dat) */ static int phy_enable_interrupts(struct phy_device *phydev) { - int err = phy_clear_interrupt(phydev); - - if (err < 0) - return err; - return phy_config_interrupt(phydev, PHY_INTERRUPT_ENABLED); } diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 81f672911305..80c2e646c093 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -2826,7 +2826,7 @@ EXPORT_SYMBOL(phy_get_internal_delay); static bool phy_drv_supports_irq(struct phy_driver *phydrv) { - return phydrv->config_intr && (phydrv->ack_interrupt || phydrv->handle_interrupt); + return phydrv->config_intr && phydrv->handle_interrupt; } /** diff --git a/include/linux/phy.h b/include/linux/phy.h index 8849a00a093f..381a95732b6a 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -743,18 +743,11 @@ struct phy_driver { /** @read_status: Determines the negotiated speed and duplex */ int (*read_status)(struct phy_device *phydev); - /** @ack_interrupt: Clears any pending interrupts */ - int (*ack_interrupt)(struct phy_device *phydev); - - /** @config_intr: Enables or disables interrupts */ - int (*config_intr)(struct phy_device *phydev); - - /** - * @did_interrupt: Checks if the PHY generated an interrupt. - * For multi-PHY devices with shared PHY interrupt pin - * Set interrupt bits have to be cleared. + /** @config_intr: Enables or disables interrupts. + * It should also clear any pending interrupts prior to enabling the + * IRQs and after disabling them. */ - int (*did_interrupt)(struct phy_device *phydev); + int (*config_intr)(struct phy_device *phydev); /** @handle_interrupt: Override default interrupt handling */ irqreturn_t (*handle_interrupt)(struct phy_device *phydev); @@ -1487,10 +1480,6 @@ static inline int genphy_config_aneg(struct phy_device *phydev) return __genphy_config_aneg(phydev, false); } -static inline int genphy_no_ack_interrupt(struct phy_device *phydev) -{ - return 0; -} static inline int genphy_no_config_intr(struct phy_device *phydev) { return 0; -- cgit v1.2.3