Index: if_sk.c =================================================================== RCS file: /cvsroot/src/sys/dev/pci/if_sk.c,v retrieving revision 1.19 diff -u -r1.19 if_sk.c --- if_sk.c 11 Feb 2006 13:04:44 -0000 1.19 +++ if_sk.c 13 Feb 2006 19:59:14 -0000 @@ -134,6 +134,7 @@ #include #include #include +#include #include #include @@ -201,6 +202,8 @@ struct vpd_res *, int); void sk_vpd_read(struct sk_softc *); +void sk_update_int_mod(struct sk_softc *); + int sk_xmac_miibus_readreg(struct device *, int, int); void sk_xmac_miibus_writereg(struct device *, int, int, int); void sk_xmac_miibus_statchg(struct device *); @@ -247,6 +250,9 @@ #define SK_WIN_CLRBIT_2(sc, reg, x) \ sk_win_write_2(sc, reg, sk_win_read_2(sc, reg) & ~x) +static int sk_sysctl_handler(SYSCTLFN_PROTO); +static int sk_root_num; + /* supported device vendors */ static const struct sk_product { pci_vendor_id_t sk_vendor; @@ -952,6 +958,39 @@ return(error); } +void +sk_update_int_mod(struct sk_softc *sc) +{ + u_int32_t sk_imtimer_ticks; + + /* + * Configure interrupt moderation. The moderation timer + * defers interrupts specified in the interrupt moderation + * timer mask based on the timeout specified in the interrupt + * moderation timer init register. Each bit in the timer + * register represents one tick, so to specify a timeout in + * microseconds, we have to multiply by the correct number of + * ticks-per-microsecond. + */ + switch (sc->sk_type) { + case SK_GENESIS: + sk_imtimer_ticks = SK_IMTIMER_TICKS_GENESIS; + break; + case SK_YUKON_EC: + sk_imtimer_ticks = SK_IMTIMER_TICKS_YUKON_EC; + break; + default: + sk_imtimer_ticks = SK_IMTIMER_TICKS_YUKON; + } + aprint_verbose("%s: interrupt moderation is %d us\n", + sc->sk_dev.dv_xname, 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); + sc->sk_int_mod_pending = 0; +} + /* * Lookup: Check the PCI vendor and device, and return a pointer to * The structure if the IDs match against our list. @@ -1030,18 +1069,7 @@ /* Enable RAM interface */ sk_win_write_4(sc, SK_RAMCTL, SK_RAMCTL_UNRESET); - /* - * Configure interrupt moderation. The moderation timer - * defers interrupts specified in the interrupt moderation - * timer mask based on the timeout specified in the interrupt - * moderation timer init register. Each bit in the timer - * 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(100)); - 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); + sk_update_int_mod(sc); } int @@ -1351,9 +1379,10 @@ const char *intrstr = NULL; bus_addr_t iobase; bus_size_t iosize; - int s; + int s, rc, sk_nodenum; u_int32_t command; const char *revstr; + const struct sysctlnode *node; DPRINTFN(2, ("begin skc_attach\n")); @@ -1627,6 +1656,36 @@ /* Turn on the 'driver is loaded' LED. */ CSR_WRITE_2(sc, SK_LED, SK_LED_GREEN_ON); + /* skc sysctl setup */ + + sc->sk_int_mod = SK_IM_DEFAULT; + sc->sk_int_mod_pending = 0; + + if ((rc = sysctl_createv(&sc->sk_clog, 0, NULL, &node, + 0, CTLTYPE_NODE, sc->sk_dev.dv_xname, + SYSCTL_DESCR("skc per-controller controls"), + NULL, 0, NULL, 0, CTL_HW, sk_root_num, CTL_CREATE, + CTL_EOL)) != 0) { + aprint_normal("%s: couldn't create sysctl node\n", + sc->sk_dev.dv_xname); + goto fail; + } + + sk_nodenum = node->sysctl_num; + + /* interrupt moderation time in usecs */ + if ((rc = sysctl_createv(&sc->sk_clog, 0, NULL, &node, + CTLFLAG_READWRITE, + CTLTYPE_INT, "int_mod", + SYSCTL_DESCR("sk interrupt moderation timer"), + sk_sysctl_handler, 0, sc, + 0, CTL_HW, sk_root_num, sk_nodenum, CTL_CREATE, + CTL_EOL)) != 0) { + aprint_normal("%s: couldn't create int_mod sysctl node\n", + sc->sk_dev.dv_xname); + goto fail; + } + fail: splx(s); } @@ -2179,6 +2238,9 @@ rnd_add_uint32(&sc->rnd_source, status); #endif + if (sc->sk_int_mod_pending) + sk_update_int_mod(sc); + return (claimed); } @@ -2490,6 +2552,7 @@ struct sk_softc *sc = sc_if->sk_softc; struct mii_data *mii = &sc_if->sk_mii; int s; + u_int32_t imr, sk_imtimer_ticks; DPRINTFN(1, ("sk_init\n")); @@ -2592,6 +2655,25 @@ return(ENOBUFS); } + /* Set interrupt moderation if changed via sysctl. */ + switch (sc->sk_type) { + case SK_GENESIS: + sk_imtimer_ticks = SK_IMTIMER_TICKS_GENESIS; + break; + case SK_YUKON_EC: + sk_imtimer_ticks = SK_IMTIMER_TICKS_YUKON_EC; + break; + default: + sk_imtimer_ticks = SK_IMTIMER_TICKS_YUKON; + } + 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)); + aprint_verbose("%s: interrupt moderation is %d us\n", + sc->sk_dev.dv_xname, sc->sk_int_mod); + } + /* Configure interrupt handling */ CSR_READ_4(sc, SK_ISSR); if (sc_if->sk_port == SK_PORT_A) @@ -2633,6 +2715,7 @@ { struct sk_if_softc *sc_if = ifp->if_softc; struct sk_softc *sc = sc_if->sk_softc; + //struct sk_txmap_entry *dma; int i; DPRINTFN(1, ("sk_stop\n")); @@ -2794,3 +2877,57 @@ } } #endif + +static int +sk_sysctl_handler(SYSCTLFN_ARGS) +{ + int error, t; + struct sysctlnode node; + struct sk_softc *sc; + + node = *rnode; + sc = node.sysctl_data; + t = sc->sk_int_mod; + node.sysctl_data = &t; + error = sysctl_lookup(SYSCTLFN_CALL(&node)); + if (error || newp == NULL) + return (error); + + if (t < SK_IM_MIN || t > SK_IM_MAX) + return (EINVAL); + + /* update the softc with sysctl-changed value, and mark + for hardware update */ + sc->sk_int_mod = t; + sc->sk_int_mod_pending = 1; + return (0); +} + +/* + * Set up sysctl(3) MIB, hw.sk.* - Individual controllers will be + * set up in skc_attach() + */ +SYSCTL_SETUP(sysctl_sk, "sysctl sk subtree setup") +{ + int rc; + const struct sysctlnode *node; + + if ((rc = sysctl_createv(clog, 0, NULL, NULL, + 0, CTLTYPE_NODE, "hw", NULL, + NULL, 0, NULL, 0, CTL_HW, CTL_EOL)) != 0) { + goto err; + } + + if ((rc = sysctl_createv(clog, 0, NULL, &node, + 0, CTLTYPE_NODE, "sk", + SYSCTL_DESCR("sk interface controls"), + NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL)) != 0) { + goto err; + } + + sk_root_num = node->sysctl_num; + return; + +err: + printf("%s: syctl_createv failed (rc = %d)\n", __func__, rc); +} Index: if_skreg.h =================================================================== RCS file: /cvsroot/src/sys/dev/pci/if_skreg.h,v retrieving revision 1.5 diff -u -r1.5 if_skreg.h --- if_skreg.h 11 Dec 2005 12:22:49 -0000 1.5 +++ if_skreg.h 13 Feb 2006 19:59:24 -0000 @@ -357,18 +357,32 @@ #define SK_YUKON 0xB0 #define SK_YUKON_LITE 0xB1 #define SK_YUKON_LP 0xB2 +#define SK_YUKON_XL 0xB3 +#define SK_YUKON_EC_U 0xB4 +#define SK_YUKON_EC 0xB6 +#define SK_YUKON_FE 0xB7 #define SK_YUKON_FAMILY(x) ((x) & 0xB0) /* known revisions in SK_CONFIG */ #define SK_YUKON_LITE_REV_A0 0x0 /* invented, see test in skc_attach */ #define SK_YUKON_LITE_REV_A1 0x3 #define SK_YUKON_LITE_REV_A3 0x7 +#define SK_YUKON_EC_REV_A1 0x0 +#define SK_YUKON_EC_REV_A2 0x1 +#define SK_YUKON_EC_REV_A3 0x2 + #define SK_IMCTL_STOP 0x02 #define SK_IMCTL_START 0x04 -#define SK_IMTIMER_TICKS 54 -#define SK_IM_USECS(x) ((x) * SK_IMTIMER_TICKS) - +/* Number of ticks per usec for interrupt moderation */ +#define SK_IMTIMER_TICKS_GENESIS 54 +#define SK_IMTIMER_TICKS_YUKON 78 +#define SK_IMTIMER_TICKS_YUKON_EC 125 +#define SK_IM_USECS(x) ((x) * sk_imtimer_ticks) + +#define SK_IM_MIN 0 +#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 Index: if_skvar.h =================================================================== RCS file: /cvsroot/src/sys/dev/pci/if_skvar.h,v retrieving revision 1.8 diff -u -r1.8 if_skvar.h --- if_skvar.h 11 Feb 2006 13:04:44 -0000 1.8 +++ if_skvar.h 13 Feb 2006 19:59:30 -0000 @@ -212,6 +212,9 @@ u_int32_t sk_ramsize; /* amount of RAM on NIC */ u_int32_t sk_pmd; /* physical media type */ u_int32_t sk_intrmask; + struct sysctllog *sk_clog; + int sk_int_mod; + int sk_int_mod_pending; bus_dma_tag_t sc_dmatag; struct sk_if_softc *sk_if[2]; #if NRND > 0