enable interrupt coalescing.
authordlg <dlg@openbsd.org>
Sun, 5 Jun 2022 02:54:18 +0000 (02:54 +0000)
committerdlg <dlg@openbsd.org>
Sun, 5 Jun 2022 02:54:18 +0000 (02:54 +0000)
mvneta only supports coalescing tx completions by count, so this
uses the txmit value or half the ring as the threshold, whichever
is lower.

rx coalescing has a threshold on the number of packets, and a max
time it will wait before interrupting. however, it also has a
threshold for how many spare/empty descriptors there are on the
ring too. we use this latter threshold to have the chip interrupt
as soon as it uses the allocation that the rx ring moderation has
granted, and then first two to otherwise rate limit rx to about 4k
interrupts per second.

ok patrick@

sys/dev/fdt/if_mvneta.c

index a61e685..2339ca8 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: if_mvneta.c,v 1.25 2022/06/01 08:19:15 dlg Exp $      */
+/*     $OpenBSD: if_mvneta.c,v 1.26 2022/06/05 02:54:18 dlg Exp $      */
 /*     $NetBSD: if_mvneta.c,v 1.41 2015/04/15 10:15:40 hsuenaga Exp $  */
 /*
  * Copyright (c) 2007, 2008, 2013 KIYOHARA Takashi
@@ -137,6 +137,8 @@ struct mvneta_softc {
        bus_dma_tag_t sc_dmat;
        void *sc_ih;
 
+       uint64_t                sc_clk_freq;
+
        struct arpcom sc_ac;
 #define sc_enaddr sc_ac.ac_enaddr
        struct mii_data sc_mii;
@@ -453,6 +455,7 @@ mvneta_attach(struct device *parent, struct device *self, void *aux)
        sc->sc_node = faa->fa_node;
 
        clock_enable(faa->fa_node, NULL);
+       sc->sc_clk_freq = clock_get_frequency_idx(faa->fa_node, 0);
 
        pinctrl_byname(faa->fa_node, "default");
 
@@ -837,7 +840,7 @@ mvneta_intr(void *arg)
        if (ic & MVNETA_PRXTXTI_TBTCQ(0))
                mvneta_tx_proc(sc);
 
-       if (ic & MVNETA_PRXTXTI_RBICTAPQ(0))
+       if (ISSET(ic, MVNETA_PRXTXTI_RBICTAPQ(0) | MVNETA_PRXTXTI_RDTAQ(0)))
                mvneta_rx_proc(sc);
 
        return 1;
@@ -1134,7 +1137,24 @@ mvneta_up(struct mvneta_softc *sc)
        MVNETA_WRITE(sc, MVNETA_PRXDQA(0), MVNETA_DMA_DVA(sc->sc_rxring));
        MVNETA_WRITE(sc, MVNETA_PRXDQS(0), MVNETA_RX_RING_CNT |
            ((MCLBYTES >> 3) << 19));
-       MVNETA_WRITE(sc, MVNETA_PRXDQTH(0), 0);
+
+       if (sc->sc_clk_freq != 0) {
+               /*
+                * Use the Non Occupied Descriptors Threshold to
+                * interrupt when the descriptors granted by rxr are
+                * used up, otherwise wait until the RX Interrupt
+                * Time Threshold is reached.
+                */
+               MVNETA_WRITE(sc, MVNETA_PRXDQTH(0),
+                   MVNETA_PRXDQTH_ODT(MVNETA_RX_RING_CNT) |
+                   MVNETA_PRXDQTH_NODT(2));
+               MVNETA_WRITE(sc, MVNETA_PRXITTH(0), sc->sc_clk_freq / 4000);
+       } else {
+               /* Time based moderation is hard without a clock */
+               MVNETA_WRITE(sc, MVNETA_PRXDQTH(0), 0);
+               MVNETA_WRITE(sc, MVNETA_PRXITTH(0), 0);
+       }
+
        MVNETA_WRITE(sc, MVNETA_PRXC(0), 0);
 
        /* Set Tx queue bandwidth. */
@@ -1144,7 +1164,8 @@ mvneta_up(struct mvneta_softc *sc)
        /* Set Tx descriptor ring data. */
        MVNETA_WRITE(sc, MVNETA_PTXDQA(0), MVNETA_DMA_DVA(sc->sc_txring));
        MVNETA_WRITE(sc, MVNETA_PTXDQS(0),
-           MVNETA_PTXDQS_DQS(MVNETA_TX_RING_CNT));
+           MVNETA_PTXDQS_DQS(MVNETA_TX_RING_CNT) |
+           MVNETA_PTXDQS_TBT(MIN(MVNETA_TX_RING_CNT / 2, ifp->if_txmit)));
 
        sc->sc_rx_prod = sc->sc_rx_cons = 0;
 
@@ -1178,7 +1199,8 @@ mvneta_up(struct mvneta_softc *sc)
 
        /* Enable interrupt masks */
        MVNETA_WRITE(sc, MVNETA_PRXTXTIM, MVNETA_PRXTXTI_RBICTAPQ(0) |
-           MVNETA_PRXTXTI_TBTCQ(0) | MVNETA_PRXTXTI_PMISCICSUMMARY);
+           MVNETA_PRXTXTI_TBTCQ(0) | MVNETA_PRXTXTI_RDTAQ(0) |
+           MVNETA_PRXTXTI_PMISCICSUMMARY);
        MVNETA_WRITE(sc, MVNETA_PMIM, MVNETA_PMI_PHYSTATUSCHNG |
            MVNETA_PMI_LINKCHANGE | MVNETA_PMI_PSCSYNCCHNG);