summaryrefslogtreecommitdiff
path: root/sys/dev/pci/if_tht.c
diff options
context:
space:
mode:
authorDavid Gwynne <dlg@cvs.openbsd.org>2007-04-18 07:00:12 +0000
committerDavid Gwynne <dlg@cvs.openbsd.org>2007-04-18 07:00:12 +0000
commit0afd8e7d8b66f4659f215abf10eff899b31c6db7 (patch)
tree06d6d8ae5d1681940ecb97b8d94a3a459cf903ea /sys/dev/pci/if_tht.c
parentc0045be9a9be1162e613fc555dd38ed99a120df3 (diff)
implement the software reset of a port as per the specification
Diffstat (limited to 'sys/dev/pci/if_tht.c')
-rw-r--r--sys/dev/pci/if_tht.c82
1 files changed, 80 insertions, 2 deletions
diff --git a/sys/dev/pci/if_tht.c b/sys/dev/pci/if_tht.c
index 7a932cce974..68257451f40 100644
--- a/sys/dev/pci/if_tht.c
+++ b/sys/dev/pci/if_tht.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_tht.c,v 1.21 2007/04/18 06:57:14 dlg Exp $ */
+/* $OpenBSD: if_tht.c,v 1.22 2007/04/18 07:00:11 dlg Exp $ */
/*
* Copyright (c) 2007 David Gwynne <dlg@openbsd.org>
@@ -290,12 +290,17 @@ struct tht_attach_args {
};
/* port operations */
+void tht_read_lladdr(struct tht_softc *);
+int tht_sw_reset(struct tht_softc *);
+
+/* interface operations */
int tht_ioctl(struct ifnet *, u_long, caddr_t);
void tht_start(struct ifnet *);
void tht_watchdog(struct ifnet *);
+
+/* ifmedia operations */
int tht_media_change(struct ifnet *);
void tht_media_status(struct ifnet *, struct ifmediareq *);
-void tht_read_lladdr(struct tht_softc *);
/* bus space operations */
u_int32_t tht_read(struct tht_softc *, bus_size_t);
@@ -547,6 +552,79 @@ tht_read_lladdr(struct tht_softc *sc)
sc->sc_lladdr[i] = swap16(tht_read(sc, r[i]));
}
+#define tht_swrst_set(_s, _r) tht_write((_s), (_r), 0x1)
+#define tht_swrst_clr(_s, _r) tht_write((_s), (_r), 0x0)
+int
+tht_sw_reset(struct tht_softc *sc)
+{
+ int i;
+
+ /* this follows SW Reset process in 8.8 of the doco */
+
+ /* 1. disable rx */
+ tht_clr(sc, THT_REG_RX_FLT, THT_REG_RX_FLT_OSEN);
+
+ /* 2. initiate port disable */
+ tht_swrst_set(sc, THT_REG_DIS_PRT);
+
+ /* 3. initiate queue disable */
+ tht_swrst_set(sc, THT_REG_DIS_QU_0);
+ tht_swrst_set(sc, THT_REG_DIS_QU_1);
+
+ /* 4. wait for successful finish of previous tasks */
+ if (!tht_wait_set(sc, THT_REG_RST_PRT, THT_REG_RST_PRT_ACTIVE, 1000)) {
+ printf("%s: port reset didnt become active\n", DEVNAME(sc));
+ return (1);
+ }
+
+ /* 5. Reset interrupt registers */
+ tht_write(sc, THT_REG_IMR, 0x0); /* 5.a */
+ tht_read(sc, THT_REG_ISR); /* 5.b */
+ for (i = 0; i < THT_NQUEUES; i++) {
+ tht_write(sc, THT_REG_RDINTCM(i), 0x0); /* 5.c/5.d */
+ tht_write(sc, THT_REG_TDINTCM(i), 0x0); /* 5.e */
+ }
+
+ /* 6. initiate queue reset */
+ tht_swrst_set(sc, THT_REG_RST_QU_0);
+ tht_swrst_set(sc, THT_REG_RST_QU_1);
+
+ /* 7. initiate port reset */
+ tht_swrst_set(sc, THT_REG_RST_PRT);
+
+ /* 8. clear txt/rxf/rxd/txf read and write ptrs */
+ for (i = 0; i < THT_NQUEUES; i++) {
+ tht_write(sc, THT_REG_TXT_RPTR(i), 0);
+ tht_write(sc, THT_REG_RXF_RPTR(i), 0);
+ tht_write(sc, THT_REG_RXD_RPTR(i), 0);
+ tht_write(sc, THT_REG_TXF_RPTR(i), 0);
+
+ tht_write(sc, THT_REG_TXT_WPTR(i), 0);
+ tht_write(sc, THT_REG_RXF_WPTR(i), 0);
+ tht_write(sc, THT_REG_RXD_WPTR(i), 0);
+ tht_write(sc, THT_REG_TXF_WPTR(i), 0);
+ }
+
+ /* 9. unset port disable */
+ tht_swrst_clr(sc, THT_REG_DIS_PRT);
+
+ /* 10. unset queue disable */
+ tht_swrst_clr(sc, THT_REG_DIS_QU_0);
+ tht_swrst_clr(sc, THT_REG_DIS_QU_1);
+
+ /* 11. unset queue reset */
+ tht_swrst_clr(sc, THT_REG_RST_QU_0);
+ tht_swrst_clr(sc, THT_REG_RST_QU_1);
+
+ /* 12. unset port reset */
+ tht_swrst_clr(sc, THT_REG_RST_PRT);
+
+ /* 13. enable rx */
+ tht_set(sc, THT_REG_RX_FLT, THT_REG_RX_FLT_OSEN);
+
+ return (0);
+}
+
u_int32_t
tht_read(struct tht_softc *sc, bus_size_t r)
{