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 <sys/device.h>
 #include <sys/queue.h>
 #include <sys/callout.h>
+#include <sys/sysctl.h>
 
 #include <net/if.h>
 #include <net/if_dl.h>
@@ -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
