From e2f49ebf076060ca0bc87c59da336c3d2fa55f6a Mon Sep 17 00:00:00 2001 From: bz Date: Thu, 17 Mar 2005 14:23:13 +0000 Subject: [PATCH] * Lower interrupt moderation timer 200->100. Obtained from: NetBSD if_sk.c rev. 1.11 * Make interrupt moderation configurable via sysctl/tuneable. PR: kern/41220 Approved by: rwatson (mentor) --- sys/dev/sk/if_sk.c | 61 ++++++++++++++++++++++++++++++++++++++++++- sys/dev/sk/if_skreg.h | 5 ++++ sys/pci/if_sk.c | 61 ++++++++++++++++++++++++++++++++++++++++++- sys/pci/if_skreg.h | 5 ++++ 4 files changed, 130 insertions(+), 2 deletions(-) diff --git a/sys/dev/sk/if_sk.c b/sys/dev/sk/if_sk.c index 39c0f8ada108..16e0c417b4d6 100644 --- a/sys/dev/sk/if_sk.c +++ b/sys/dev/sk/if_sk.c @@ -94,6 +94,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -241,6 +242,9 @@ static void sk_setfilt(struct sk_if_softc *, caddr_t, int); static void sk_setmulti(struct sk_if_softc *); static void sk_setpromisc(struct sk_if_softc *); +static int sysctl_int_range(SYSCTL_HANDLER_ARGS, int low, int high); +static int sysctl_hw_sk_int_mod(SYSCTL_HANDLER_ARGS); + #ifdef SK_USEIOSPACE #define SK_RES SYS_RES_IOPORT #define SK_RID SK_PCI_LOIO @@ -1307,7 +1311,9 @@ sk_reset(sc) * register represents 18.825ns, so to specify a timeout in * microseconds, we have to multiply by 54. */ - sk_win_write_4(sc, SK_IMTIMERINIT, SK_IM_USECS(200)); + printf("skc%d: interrupt moderation is %d us\n", + sc->sk_unit, sc->sk_int_mod); + sk_win_write_4(sc, SK_IMTIMERINIT, SK_IM_USECS(sc->sk_int_mod)); sk_win_write_4(sc, SK_IMMR, SK_ISR_TX1_S_EOF|SK_ISR_TX2_S_EOF| SK_ISR_RX1_EOF|SK_ISR_RX2_EOF); sk_win_write_1(sc, SK_IMTIMERCTL, SK_IMCTL_START); @@ -1577,6 +1583,25 @@ skc_attach(dev) goto fail; } + SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), + SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), + OID_AUTO, "int_mod", CTLTYPE_INT|CTLFLAG_RW, + &sc->sk_int_mod, 0, sysctl_hw_sk_int_mod, "I", + "SK interrupt moderation"); + + /* Pull in device tunables. */ + sc->sk_int_mod = SK_IM_DEFAULT; + error = resource_int_value(device_get_name(dev), unit, + "int_mod", &sc->sk_int_mod); + if (error == 0) { + if (sc->sk_int_mod < SK_IM_MIN || + sc->sk_int_mod > SK_IM_MAX) { + printf("skc%d: int_mod value out of range; " + "using default: %d\n", unit, SK_IM_DEFAULT); + sc->sk_int_mod = SK_IM_DEFAULT; + } + } + /* Reset the adapter. */ sk_reset(sc); @@ -2648,6 +2673,7 @@ sk_init(xsc) struct ifnet *ifp; struct mii_data *mii; u_int16_t reg; + u_int32_t imr; SK_IF_LOCK(sc_if); @@ -2745,6 +2771,16 @@ sk_init(xsc) } sk_init_tx_ring(sc_if); + /* Set interrupt moderation if changed via sysctl. */ + /* SK_LOCK(sc); */ + imr = sk_win_read_4(sc, SK_IMTIMERINIT); + if (imr != SK_IM_USECS(sc->sk_int_mod)) { + sk_win_write_4(sc, SK_IMTIMERINIT, SK_IM_USECS(sc->sk_int_mod)); + printf("skc%d: interrupt moderation is %d us\n", + sc->sk_unit, sc->sk_int_mod); + } + /* SK_UNLOCK(sc); */ + /* Configure interrupt handling */ CSR_READ_4(sc, SK_ISSR); if (sc_if->sk_port == SK_PORT_A) @@ -2864,3 +2900,26 @@ sk_stop(sc_if) SK_IF_UNLOCK(sc_if); return; } + +static int +sysctl_int_range(SYSCTL_HANDLER_ARGS, int low, int high) +{ + int error, value; + + if (!arg1) + return (EINVAL); + value = *(int *)arg1; + error = sysctl_handle_int(oidp, &value, 0, req); + if (error || !req->newptr) + return (error); + if (value < low || value > high) + return (EINVAL); + *(int *)arg1 = value; + return (0); +} + +static int +sysctl_hw_sk_int_mod(SYSCTL_HANDLER_ARGS) +{ + return (sysctl_int_range(oidp, arg1, arg2, req, SK_IM_MIN, SK_IM_MAX)); +} diff --git a/sys/dev/sk/if_skreg.h b/sys/dev/sk/if_skreg.h index 44d31c3680a2..46e9f1e8a647 100644 --- a/sys/dev/sk/if_skreg.h +++ b/sys/dev/sk/if_skreg.h @@ -376,6 +376,10 @@ #define SK_IMTIMER_TICKS 54 #define SK_IM_USECS(x) ((x) * SK_IMTIMER_TICKS) +#define SK_IM_MIN 10 +#define SK_IM_DEFAULT 100 +#define SK_IM_MAX 10000 + /* * The SK_EPROM0 register contains a byte that describes the * amount of SRAM mounted on the NIC. The value also tells if @@ -1442,6 +1446,7 @@ struct sk_softc { u_int32_t sk_ramsize; /* amount of RAM on NIC */ u_int32_t sk_pmd; /* physical media type */ u_int32_t sk_intrmask; + int sk_int_mod; struct sk_if_softc *sk_if[2]; device_t sk_devs[2]; struct mtx sk_mtx; diff --git a/sys/pci/if_sk.c b/sys/pci/if_sk.c index 39c0f8ada108..16e0c417b4d6 100644 --- a/sys/pci/if_sk.c +++ b/sys/pci/if_sk.c @@ -94,6 +94,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -241,6 +242,9 @@ static void sk_setfilt(struct sk_if_softc *, caddr_t, int); static void sk_setmulti(struct sk_if_softc *); static void sk_setpromisc(struct sk_if_softc *); +static int sysctl_int_range(SYSCTL_HANDLER_ARGS, int low, int high); +static int sysctl_hw_sk_int_mod(SYSCTL_HANDLER_ARGS); + #ifdef SK_USEIOSPACE #define SK_RES SYS_RES_IOPORT #define SK_RID SK_PCI_LOIO @@ -1307,7 +1311,9 @@ sk_reset(sc) * register represents 18.825ns, so to specify a timeout in * microseconds, we have to multiply by 54. */ - sk_win_write_4(sc, SK_IMTIMERINIT, SK_IM_USECS(200)); + printf("skc%d: interrupt moderation is %d us\n", + sc->sk_unit, sc->sk_int_mod); + sk_win_write_4(sc, SK_IMTIMERINIT, SK_IM_USECS(sc->sk_int_mod)); sk_win_write_4(sc, SK_IMMR, SK_ISR_TX1_S_EOF|SK_ISR_TX2_S_EOF| SK_ISR_RX1_EOF|SK_ISR_RX2_EOF); sk_win_write_1(sc, SK_IMTIMERCTL, SK_IMCTL_START); @@ -1577,6 +1583,25 @@ skc_attach(dev) goto fail; } + SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), + SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), + OID_AUTO, "int_mod", CTLTYPE_INT|CTLFLAG_RW, + &sc->sk_int_mod, 0, sysctl_hw_sk_int_mod, "I", + "SK interrupt moderation"); + + /* Pull in device tunables. */ + sc->sk_int_mod = SK_IM_DEFAULT; + error = resource_int_value(device_get_name(dev), unit, + "int_mod", &sc->sk_int_mod); + if (error == 0) { + if (sc->sk_int_mod < SK_IM_MIN || + sc->sk_int_mod > SK_IM_MAX) { + printf("skc%d: int_mod value out of range; " + "using default: %d\n", unit, SK_IM_DEFAULT); + sc->sk_int_mod = SK_IM_DEFAULT; + } + } + /* Reset the adapter. */ sk_reset(sc); @@ -2648,6 +2673,7 @@ sk_init(xsc) struct ifnet *ifp; struct mii_data *mii; u_int16_t reg; + u_int32_t imr; SK_IF_LOCK(sc_if); @@ -2745,6 +2771,16 @@ sk_init(xsc) } sk_init_tx_ring(sc_if); + /* Set interrupt moderation if changed via sysctl. */ + /* SK_LOCK(sc); */ + imr = sk_win_read_4(sc, SK_IMTIMERINIT); + if (imr != SK_IM_USECS(sc->sk_int_mod)) { + sk_win_write_4(sc, SK_IMTIMERINIT, SK_IM_USECS(sc->sk_int_mod)); + printf("skc%d: interrupt moderation is %d us\n", + sc->sk_unit, sc->sk_int_mod); + } + /* SK_UNLOCK(sc); */ + /* Configure interrupt handling */ CSR_READ_4(sc, SK_ISSR); if (sc_if->sk_port == SK_PORT_A) @@ -2864,3 +2900,26 @@ sk_stop(sc_if) SK_IF_UNLOCK(sc_if); return; } + +static int +sysctl_int_range(SYSCTL_HANDLER_ARGS, int low, int high) +{ + int error, value; + + if (!arg1) + return (EINVAL); + value = *(int *)arg1; + error = sysctl_handle_int(oidp, &value, 0, req); + if (error || !req->newptr) + return (error); + if (value < low || value > high) + return (EINVAL); + *(int *)arg1 = value; + return (0); +} + +static int +sysctl_hw_sk_int_mod(SYSCTL_HANDLER_ARGS) +{ + return (sysctl_int_range(oidp, arg1, arg2, req, SK_IM_MIN, SK_IM_MAX)); +} diff --git a/sys/pci/if_skreg.h b/sys/pci/if_skreg.h index 44d31c3680a2..46e9f1e8a647 100644 --- a/sys/pci/if_skreg.h +++ b/sys/pci/if_skreg.h @@ -376,6 +376,10 @@ #define SK_IMTIMER_TICKS 54 #define SK_IM_USECS(x) ((x) * SK_IMTIMER_TICKS) +#define SK_IM_MIN 10 +#define SK_IM_DEFAULT 100 +#define SK_IM_MAX 10000 + /* * The SK_EPROM0 register contains a byte that describes the * amount of SRAM mounted on the NIC. The value also tells if @@ -1442,6 +1446,7 @@ struct sk_softc { u_int32_t sk_ramsize; /* amount of RAM on NIC */ u_int32_t sk_pmd; /* physical media type */ u_int32_t sk_intrmask; + int sk_int_mod; struct sk_if_softc *sk_if[2]; device_t sk_devs[2]; struct mtx sk_mtx;