diff options
author | Martin Blumenstingl <martin.blumenstingl@googlemail.com> | 2018-11-18 22:23:58 +0100 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-11-19 01:16:20 +0100 |
commit | f7e290fbeb336421ba6237548b693c9afb4d75fa (patch) | |
tree | 18ad7ffc5439aaaa0cc9e92f8ec633c3716ca81d /drivers/net/phy/icplus.c | |
parent | net: phy: icplus: rename IP101A_G_NO_IRQ to IP101A_G_IRQ_ALL_MASK (diff) | |
download | linux-f7e290fbeb336421ba6237548b693c9afb4d75fa.tar.xz linux-f7e290fbeb336421ba6237548b693c9afb4d75fa.zip |
net: phy: icplus: implement .did_interrupt for IP101A/G
The IP101A_G_IRQ_CONF_STATUS register has bits to detect which
interrupts have fired. Implement the .did_interrupt callback to let the
PHY core know whether the interrupt was for this specific PHY.
This is useful for debugging interrupt problems with 32-pin IP101GR PHYs
where the interrupt line is shared with the RX_ERR (receive error
status) signal. The default values are:
- RX_ERR is enabled by default (LOW means that there is no receive
error)
- the PHY's interrupt line is configured "active low" by default
Without any additional changes there is a flood of interrupts if the
RX_ERR/INTR32 signal is configured in RX_ERR mode (which is the
default). Having a did_interrupt ensures that the PHY core returns
IRQ_NONE instead of endlessly triggering the PHY state machine.
Additionally the kernel will report this after a while:
irq 28: nobody cared (try booting with the "irqpoll" option)
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/phy/icplus.c')
-rw-r--r-- | drivers/net/phy/icplus.c | 16 |
1 files changed, 16 insertions, 0 deletions
diff --git a/drivers/net/phy/icplus.c b/drivers/net/phy/icplus.c index c9489ec77cef..3dc8bbbe746b 100644 --- a/drivers/net/phy/icplus.c +++ b/drivers/net/phy/icplus.c @@ -44,6 +44,9 @@ MODULE_LICENSE("GPL"); #define IP101A_G_IRQ_CONF_STATUS 0x11 /* Conf Info IRQ & Status Reg */ #define IP101A_G_IRQ_PIN_USED BIT(15) /* INTR pin used */ #define IP101A_G_IRQ_ALL_MASK BIT(11) /* IRQ's inactive */ +#define IP101A_G_IRQ_SPEED_CHANGE BIT(2) +#define IP101A_G_IRQ_DUPLEX_CHANGE BIT(1) +#define IP101A_G_IRQ_LINK_CHANGE BIT(0) static int ip175c_config_init(struct phy_device *phydev) { @@ -209,6 +212,18 @@ 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) +{ + int val = phy_read(phydev, IP101A_G_IRQ_CONF_STATUS); + + if (val < 0) + return 0; + + return val & (IP101A_G_IRQ_SPEED_CHANGE | + IP101A_G_IRQ_DUPLEX_CHANGE | + IP101A_G_IRQ_LINK_CHANGE); +} + static int ip101a_g_ack_interrupt(struct phy_device *phydev) { int err = phy_read(phydev, IP101A_G_IRQ_CONF_STATUS); @@ -243,6 +258,7 @@ static struct phy_driver icplus_driver[] = { .phy_id_mask = 0x0ffffff0, .features = PHY_BASIC_FEATURES, .config_intr = ip101a_g_config_intr, + .did_interrupt = ip101a_g_did_interrupt, .ack_interrupt = ip101a_g_ack_interrupt, .config_init = &ip101a_g_config_init, .suspend = genphy_suspend, |