RE: [PATCH v3 1/2] gpio: mlxbf2: Introduce IRQ support
From: Asmaa Mnebhi <asmaa@nvidia.com>
Date: 2021-09-28 15:02:13
Also in:
linux-acpi, linux-gpio, lkml
So the PHY is level based. The PHY is combing multiple interrupt sources into one external interrupt. If any of those internal interrupt sources are active, the external interrupt is active. If there are > multiple active sources at once, the interrupt stays low, until they are all cleared. This means there is not an edge per interrupt. There is one edge when the first internal source occurs, and no more edges, > even if there are more internal interrupts.
The general flow in the PHY interrupt handler is to read the interrupt status register, which tells you which internal interrupts have fired. You then address these internal interrupts one by one.
In KSZ9031, Register MII_KSZPHY_INTCS=0x1B reports all interrupt events and clear on read. So if there are 4 different interrupts, once it is read once, all 4 clear at once. The micrel.c driver has defined ack_interrupt to read the above reg and is called every time the interrupt handler phy_interrupt is called. So in this case, we should be good. The code flow in our case would look like this: - 2 interrupt sources (for example, link down followed by link up) set in MII_KSZPHY_INTCS - interrupt handler (phy_interrupt) reads MII_KSZPHY_INT which automatically clears both interrupts - another internal source triggers and sets the register. - The second edge will be caught accordingly by the GPIO.
This can take some time, MDIO is a slow bus etc. While handling these interrupt sources, it could be another internal interrupt source triggers. This new internal interrupt source keeps the external interrupt active. But there has not been an edge, since the interrupt handler is still clearing the sources which caused the first interrupt. With level interrupts, this is not an issue. When the interrupt handler exits, the interrupt is re-enabled. Since it is still active, due to the unhandled internal interrupt sources, the level interrupt immediately fires again. the handler then sees this new interrupt and handles it. At that point the level interrupt goes inactive.