Page MenuHomeFreeBSD

D58227.diff
No OneTemporary

D58227.diff

diff --git a/sys/arm64/rockchip/rk_gpio.c b/sys/arm64/rockchip/rk_gpio.c
--- a/sys/arm64/rockchip/rk_gpio.c
+++ b/sys/arm64/rockchip/rk_gpio.c
@@ -219,13 +219,30 @@
RK_GPIO_LOCK(sc);
status = rk_gpio_read_4(sc, RK_GPIO_INT_STATUS);
- rk_gpio_write_4(sc, RK_GPIO_PORTA_EOI, status);
RK_GPIO_UNLOCK(sc);
while (status) {
int pin = ffs(status) - 1;
+ bool is_level;
status &= ~(1 << pin);
+
+ /*
+ * Edge-triggered latches must be cleared before dispatch so a
+ * new edge during the handler still registers a new IRQ.
+ * Level-triggered latches must be cleared AFTER the consumer
+ * has deasserted the source line, otherwise the latch
+ * immediately re-arms and we storm. Edge EOI here; level EOI
+ * is deferred to pic_post_filter or pic_pre_ithread.
+ */
+ is_level = (sc->isrcs[pin].mode &
+ (GPIO_INTR_LEVEL_LOW | GPIO_INTR_LEVEL_HIGH)) != 0;
+ if (!is_level) {
+ RK_GPIO_LOCK(sc);
+ rk_gpio_write_4(sc, RK_GPIO_PORTA_EOI, 1u << pin);
+ RK_GPIO_UNLOCK(sc);
+ }
+
if (intr_isrc_dispatch(RK_GPIO_ISRC(sc, pin), tf)) {
/*
* Pin asserted but no consumer is registered for it
@@ -235,14 +252,19 @@
* messages per second. Mask the pin's IRQ at the
* controller and disable further dispatches; if a
* consumer attaches later it will re-enable through
- * pic_enable_intr / rk_gpio_pic_enable_intr.
+ * pic_enable_intr / rk_gpio_pic_enable_intr. For
+ * level pins also EOI now -- there is no consumer
+ * to drive the source low.
*/
RK_GPIO_LOCK(sc);
rk_gpio_write_bit(sc, RK_GPIO_INTMASK, pin, 1);
rk_gpio_write_bit(sc, RK_GPIO_INTEN, pin, 0);
+ if (is_level)
+ rk_gpio_write_4(sc, RK_GPIO_PORTA_EOI,
+ 1u << pin);
RK_GPIO_UNLOCK(sc);
device_printf(sc->sc_dev,
- "Interrupt pin=%d unhandled — masked\n", pin);
+ "Interrupt pin=%d unhandled -- masked\n", pin);
continue;
}
@@ -906,21 +928,39 @@
RK_GPIO_UNLOCK(sc);
}
-/*
- * Called by INTRNG before delivering to the ithread. Mask the source
- * so it cannot re-fire during the ithread window -- without this,
- * level-low IRQs (e.g. FUSB302 INT_N) re-trigger continuously and
- * starve the ithread (~210 kHz storm observed via dtrace).
- * Re-unmasked in pic_post_ithread() once the ithread acks the source.
- */
+static void
+rk_pic_post_filter(device_t dev, struct intr_irqsrc *isrc)
+{
+ struct rk_gpio_softc *sc = device_get_softc(dev);
+ struct rk_pin_irqsrc *rkisrc = (struct rk_pin_irqsrc *)isrc;
+
+ /*
+ * Edge-triggered interrupts were cleared in rk_gpio_intr(); nothing
+ * further to do.
+ */
+ if ((rkisrc->mode & (GPIO_INTR_LEVEL_LOW | GPIO_INTR_LEVEL_HIGH)) == 0)
+ return;
+
+ /* Ack/clear the interrupt. */
+ RK_GPIO_LOCK(sc);
+ rk_gpio_write_4(sc, RK_GPIO_PORTA_EOI, 1u << rkisrc->irq);
+ RK_GPIO_UNLOCK(sc);
+}
+
static void
rk_pic_pre_ithread(device_t dev, struct intr_irqsrc *isrc)
{
struct rk_gpio_softc *sc = device_get_softc(dev);
struct rk_pin_irqsrc *rkisrc = (struct rk_pin_irqsrc *)isrc;
+ /*
+ * Prepare to run the threaded handler -- first, mask the interrupt;
+ * then, ack/clear the (level-triggered) source.
+ */
RK_GPIO_LOCK(sc);
rk_gpio_write_bit(sc, RK_GPIO_INTMASK, rkisrc->irq, 1);
+ if ((rkisrc->mode & (GPIO_INTR_LEVEL_LOW | GPIO_INTR_LEVEL_HIGH)) != 0)
+ rk_gpio_write_4(sc, RK_GPIO_PORTA_EOI, 1u << rkisrc->irq);
RK_GPIO_UNLOCK(sc);
}
@@ -930,6 +970,10 @@
struct rk_gpio_softc *sc = device_get_softc(dev);
struct rk_pin_irqsrc *rkisrc = (struct rk_pin_irqsrc *)isrc;
+ /*
+ * Execution of the threaded handler is complete -- unmask the
+ * interrupt.
+ */
RK_GPIO_LOCK(sc);
rk_gpio_write_bit(sc, RK_GPIO_INTMASK, rkisrc->irq, 0);
RK_GPIO_UNLOCK(sc);
@@ -965,6 +1009,7 @@
DEVMETHOD(pic_teardown_intr, rk_pic_teardown_intr),
DEVMETHOD(pic_disable_intr, rk_pic_disable_intr),
DEVMETHOD(pic_enable_intr, rk_pic_enable_intr),
+ DEVMETHOD(pic_post_filter, rk_pic_post_filter),
DEVMETHOD(pic_pre_ithread, rk_pic_pre_ithread),
DEVMETHOD(pic_post_ithread, rk_pic_post_ithread),

File Metadata

Mime Type
text/plain
Expires
Sat, Jul 18, 11:13 PM (7 h, 41 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
35105245
Default Alt Text
D58227.diff (3 KB)

Event Timeline