summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHoratiu Vultur <horatiu.vultur@microchip.com>2023-01-04 20:42:18 +0100
committerJakub Kicinski <kuba@kernel.org>2023-01-06 19:33:33 -0800
commit7abd92a5b98f33a972bd3cadf9948ce59d1c01b8 (patch)
tree2f050e05e1a5fe09f56a769daed3d6c718ce9e71
parentb466a25c930f2b7f1ed21c9eeaa553017ae78d1c (diff)
net: phy: micrel: Change handler interrupt for lan8814
The lan8814 represents a package of 4 PHYs. All of them are sharing the same interrupt line. So when a link was going down/up or a frame was timestamped, then the interrupt handler of all the PHYs was called. Which is all fine and expected but the problem is the way the handler interrupt works. Basically if one of the PHYs timestamp a frame, then all the other 3 PHYs were polling the status of the interrupt until that PHY actually cleared the interrupt by reading the timestamp. The reason of polling was in case another PHY was also timestamping a frame at the same time, it could miss this interrupt. But this is not the right approach, because it is the interrupt controller who needs to call the interrupt handlers again if the interrupt line is still active. Therefore change this such when the interrupt handler is called check only if the interrupt is for itself, otherwise just exit. In this way save CPU usage. Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com> Link: https://lore.kernel.org/r/20230104194218.3785229-1-horatiu.vultur@microchip.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
-rw-r--r--drivers/net/phy/micrel.c25
1 files changed, 8 insertions, 17 deletions
diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c
index 26ce0c5defcd..2243ad1b88e7 100644
--- a/drivers/net/phy/micrel.c
+++ b/drivers/net/phy/micrel.c
@@ -2794,13 +2794,11 @@ static void lan8814_get_rx_ts(struct kszphy_ptp_priv *ptp_priv)
} while (PTP_CAP_INFO_RX_TS_CNT_GET_(reg) > 0);
}
-static void lan8814_handle_ptp_interrupt(struct phy_device *phydev)
+static void lan8814_handle_ptp_interrupt(struct phy_device *phydev, u16 status)
{
struct kszphy_priv *priv = phydev->priv;
struct kszphy_ptp_priv *ptp_priv = &priv->ptp_priv;
- u16 status;
- status = lanphy_read_page_reg(phydev, 5, PTP_TSU_INT_STS);
if (status & PTP_TSU_INT_STS_PTP_TX_TS_EN_)
lan8814_get_tx_ts(ptp_priv);
@@ -2899,8 +2897,8 @@ static int lan8804_config_intr(struct phy_device *phydev)
static irqreturn_t lan8814_handle_interrupt(struct phy_device *phydev)
{
- int irq_status, tsu_irq_status;
int ret = IRQ_NONE;
+ int irq_status;
irq_status = phy_read(phydev, LAN8814_INTS);
if (irq_status < 0) {
@@ -2913,20 +2911,13 @@ static irqreturn_t lan8814_handle_interrupt(struct phy_device *phydev)
ret = IRQ_HANDLED;
}
- while (1) {
- tsu_irq_status = lanphy_read_page_reg(phydev, 4,
- LAN8814_INTR_STS_REG);
-
- if (tsu_irq_status > 0 &&
- (tsu_irq_status & (LAN8814_INTR_STS_REG_1588_TSU0_ |
- LAN8814_INTR_STS_REG_1588_TSU1_ |
- LAN8814_INTR_STS_REG_1588_TSU2_ |
- LAN8814_INTR_STS_REG_1588_TSU3_))) {
- lan8814_handle_ptp_interrupt(phydev);
- ret = IRQ_HANDLED;
- } else {
+ while (true) {
+ irq_status = lanphy_read_page_reg(phydev, 5, PTP_TSU_INT_STS);
+ if (!irq_status)
break;
- }
+
+ lan8814_handle_ptp_interrupt(phydev, irq_status);
+ ret = IRQ_HANDLED;
}
return ret;