summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorriz <riz@NetBSD.org>2006-02-14 00:19:17 +0000
committerriz <riz@NetBSD.org>2006-02-14 00:19:17 +0000
commita4163a9fe4da25977d82d1569eca4d02aeeb77ee (patch)
treeb1b6956e91604c5bd8a08b0ddc26669928f91820 /sys/dev
parentc842fab210caa224b02ec1857687ea5f2241736b (diff)
Not all chips supported by this driver use the same interrupt moderation
timer frequency; Take this into account. Information gathered from the sk98lin driver for Linux, from Marvell. Also add sysctl support for changing the interrupt moderation timer at runtime; each board is controlled independently. Discussed on tech-net beginning in November 2005.
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/pci/if_sk.c165
-rw-r--r--sys/dev/pci/if_skreg.h20
-rw-r--r--sys/dev/pci/if_skvar.h5
3 files changed, 172 insertions, 18 deletions
diff --git a/sys/dev/pci/if_sk.c b/sys/dev/pci/if_sk.c
index 0eb846b6048..2bfc67f8091 100644
--- a/sys/dev/pci/if_sk.c
+++ b/sys/dev/pci/if_sk.c
@@ -1,4 +1,4 @@
-/* $NetBSD: if_sk.c,v 1.19 2006/02/11 13:04:44 rpaulo Exp $ */
+/* $NetBSD: if_sk.c,v 1.20 2006/02/14 00:19:17 riz Exp $ */
/*-
* Copyright (c) 2003 The NetBSD Foundation, Inc.
@@ -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 @@ void sk_vpd_read_res(struct sk_softc *,
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 @@ void sk_dump_bytes(const char *, int);
#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 @@ sk_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
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 @@ void sk_reset(struct sk_softc *sc)
/* 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 @@ skc_attach(struct device *parent, struct device *self, void *aux)
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 @@ skc_attach(struct device *parent, struct device *self, void *aux)
/* 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 @@ sk_intr(void *xsc)
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 @@ sk_init(struct ifnet *ifp)
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 @@ sk_init(struct ifnet *ifp)
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 @@ sk_stop(struct ifnet *ifp, int disable)
{
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 @@ sk_dump_mbuf(struct mbuf *m)
}
}
#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);
+}
diff --git a/sys/dev/pci/if_skreg.h b/sys/dev/pci/if_skreg.h
index 5af05914b7f..b5e3156f061 100644
--- a/sys/dev/pci/if_skreg.h
+++ b/sys/dev/pci/if_skreg.h
@@ -1,4 +1,4 @@
-/* $NetBSD: if_skreg.h,v 1.5 2005/12/11 12:22:49 christos Exp $ */
+/* $NetBSD: if_skreg.h,v 1.6 2006/02/14 00:19:17 riz Exp $ */
/*-
* Copyright (c) 2003 The NetBSD Foundation, Inc.
@@ -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
diff --git a/sys/dev/pci/if_skvar.h b/sys/dev/pci/if_skvar.h
index 524898669fe..5459942e5a5 100644
--- a/sys/dev/pci/if_skvar.h
+++ b/sys/dev/pci/if_skvar.h
@@ -1,4 +1,4 @@
-/* $NetBSD: if_skvar.h,v 1.8 2006/02/11 13:04:44 rpaulo Exp $ */
+/* $NetBSD: if_skvar.h,v 1.9 2006/02/14 00:19:17 riz Exp $ */
/*-
* Copyright (c) 2003 The NetBSD Foundation, Inc.
@@ -212,6 +212,9 @@ 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;
+ 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