summaryrefslogtreecommitdiff
path: root/sys/arch/sgi/hpc
diff options
context:
space:
mode:
authorMiod Vallat <miod@cvs.openbsd.org>2012-04-30 21:31:04 +0000
committerMiod Vallat <miod@cvs.openbsd.org>2012-04-30 21:31:04 +0000
commit7c7305753b2e61fde04a85c52ff6d5048e4c9f99 (patch)
tree2f6ef01777f0bd389af7ce8001576588a5fa7edd /sys/arch/sgi/hpc
parent30691316ceafe53afeebd9ec7dc090cd43511b4c (diff)
Add ifmedia support to sq(4).
Diffstat (limited to 'sys/arch/sgi/hpc')
-rw-r--r--sys/arch/sgi/hpc/hpc.c9
-rw-r--r--sys/arch/sgi/hpc/if_sq.c235
-rw-r--r--sys/arch/sgi/hpc/if_sqvar.h7
3 files changed, 234 insertions, 17 deletions
diff --git a/sys/arch/sgi/hpc/hpc.c b/sys/arch/sgi/hpc/hpc.c
index 3dcdd2e9c2c..73644b4d342 100644
--- a/sys/arch/sgi/hpc/hpc.c
+++ b/sys/arch/sgi/hpc/hpc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: hpc.c,v 1.10 2012/04/30 21:30:33 miod Exp $ */
+/* $OpenBSD: hpc.c,v 1.11 2012/04/30 21:31:03 miod Exp $ */
/* $NetBSD: hpc.c,v 1.66 2011/07/01 18:53:46 dyoung Exp $ */
/* $NetBSD: ioc.c,v 1.9 2011/07/01 18:53:47 dyoung Exp $ */
@@ -485,12 +485,11 @@ hpc_attach(struct device *parent, struct device *self, void *aux)
IOC_RESET_ISDN | IOC_RESET_LED_GREEN );
/*
- * Set the 10BaseT port to use UTP cable, set autoselect mode
- * for the Ethernet interface (AUI vs. TP), set the two serial
- * ports to PC mode.
+ * Set the two serial ports to PC mode.
*/
bus_space_write_4(sc->sc_ct, sc->sc_ch, IOC_BASE + IOC_WRITE,
- IOC_WRITE_ENET_AUTO | IOC_WRITE_ENET_UTP |
+ bus_space_read_4(sc->sc_ct, sc->sc_ch,
+ IOC_BASE + IOC_WRITE) |
IOC_WRITE_PC_UART2 | IOC_WRITE_PC_UART1);
/* XXX: the firmware should have taken care of this already */
diff --git a/sys/arch/sgi/hpc/if_sq.c b/sys/arch/sgi/hpc/if_sq.c
index 80907710d39..f5f0f07c448 100644
--- a/sys/arch/sgi/hpc/if_sq.c
+++ b/sys/arch/sgi/hpc/if_sq.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_sq.c,v 1.4 2012/04/15 20:40:39 miod Exp $ */
+/* $OpenBSD: if_sq.c,v 1.5 2012/04/30 21:31:03 miod Exp $ */
/* $NetBSD: if_sq.c,v 1.42 2011/07/01 18:53:47 dyoung Exp $ */
/*
@@ -78,6 +78,7 @@
#include <sgi/hpc/hpcvar.h>
#include <sgi/hpc/hpcreg.h>
+#include <sgi/hpc/iocreg.h> /* IOC_READ / IOC_WRITE */
#include <sgi/hpc/if_sqvar.h>
/*
@@ -125,6 +126,11 @@ int sq_add_rxbuf(struct sq_softc *, int);
void sq_trace_dump(struct sq_softc *);
#endif
+int sq_ifmedia_change_ip22(struct ifnet *);
+int sq_ifmedia_change_singlemedia(struct ifnet *);
+void sq_ifmedia_status_ip22(struct ifnet *, struct ifmediareq *);
+void sq_ifmedia_status_singlemedia(struct ifnet *, struct ifmediareq *);
+
const struct cfattach sq_ca = {
sizeof(struct sq_softc), sq_match, sq_attach
};
@@ -191,9 +197,11 @@ sq_attach(struct device *parent, struct device *self, void *aux)
struct sq_softc *sc = (struct sq_softc *)self;
struct hpc_attach_args *haa = aux;
struct ifnet *ifp = &sc->sc_ac.ac_if;
+ int media;
int i, rc;
sc->sc_hpct = haa->ha_st;
+ sc->sc_hpcbh = haa->ha_sh;
sc->hpc_regs = haa->hpc_regs; /* HPC register definitions */
if ((rc = bus_space_subregion(haa->ha_st, haa->ha_sh,
@@ -365,6 +373,80 @@ sq_attach(struct device *parent, struct device *self, void *aux)
IFQ_SET_MAXLEN(&ifp->if_snd, SQ_NTXDESC - 1);
ether_ifattach(ifp);
+ if (haa->hpc_regs->revision == 3) {
+ uint8_t mask, set;
+ if (/* sys_config.system_type != SGI_IP20 && */ /* implied */
+ sys_config.system_subtype == IP22_CHALLS) {
+ /*
+ * Challenge S: onboard has AUI connector only,
+ * IO+ has TP connector only.
+ */
+ if (haa->ha_base == HPC_BASE_ADDRESS_0) {
+ ifmedia_init(&sc->sc_ifmedia, 0,
+ sq_ifmedia_change_singlemedia,
+ sq_ifmedia_status_singlemedia);
+ /*
+ * Force 10Base5.
+ */
+ media = IFM_ETHER | IFM_10_5;
+ mask = IOC_WRITE_ENET_AUTO;
+ set = IOC_WRITE_ENET_AUI;
+ } else {
+ ifmedia_init(&sc->sc_ifmedia, 0,
+ sq_ifmedia_change_singlemedia,
+ sq_ifmedia_status_singlemedia);
+ /*
+ * Force 10BaseT, and set the 10BaseT port
+ * to use UTP cable.
+ */
+ media = IFM_ETHER | IFM_10_T;
+ mask = set = 0;
+ }
+ } else {
+ /*
+ * Indy, Indigo 2: onboard has AUI and TP connectors.
+ */
+ ifmedia_init(&sc->sc_ifmedia, 0,
+ sq_ifmedia_change_ip22, sq_ifmedia_status_ip22);
+ ifmedia_add(&sc->sc_ifmedia,
+ IFM_ETHER | IFM_10_5, 0, NULL);
+ ifmedia_add(&sc->sc_ifmedia,
+ IFM_ETHER | IFM_10_T, 0, NULL);
+
+ /*
+ * Force autoselect, and set the the 10BaseT port
+ * to use UTP cable.
+ */
+ media = IFM_ETHER | IFM_AUTO;
+ mask = IOC_WRITE_ENET_AUI;
+ set = IOC_WRITE_ENET_AUTO | IOC_WRITE_ENET_UTP;
+ }
+
+ if (haa->ha_base == HPC_BASE_ADDRESS_0) {
+ bus_space_write_4(haa->ha_st, haa->ha_sh,
+ IOC_BASE + IOC_WRITE,
+ (bus_space_read_4(haa->ha_st, haa->ha_sh,
+ IOC_BASE + IOC_WRITE) & ~mask) | set);
+ bus_space_barrier(haa->ha_st, haa->ha_sh,
+ IOC_BASE + IOC_WRITE, 4,
+ BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
+ }
+ } else {
+ /*
+ * HPC1/1.5: IP20 on-board, or E++: AUI connector only
+ */
+ ifmedia_init(&sc->sc_ifmedia, 0,
+ sq_ifmedia_change_singlemedia,
+ sq_ifmedia_status_singlemedia);
+ media = IFM_ETHER | IFM_10_5;
+ }
+
+ ifmedia_add(&sc->sc_ifmedia, media, 0, NULL);
+ ifmedia_set(&sc->sc_ifmedia, media);
+
+ /* supposedly connected, until TX says otherwise */
+ sc->sc_flags |= SQF_LINKUP;
+
/* Done! */
return;
@@ -418,19 +500,17 @@ sq_init(struct ifnet *ifp)
SQ_TRACE(SQ_RESET, sc, 0, 0);
- /* Set into 8003 mode, bank 0 to program ethernet address */
+ /* Set into 8003 or 80C03 mode, bank 0 to program Ethernet address */
+ if (sc->sc_type == SQ_TYPE_80C03)
+ sq_seeq_write(sc, SEEQ_TXCMD, TXCMD_ENABLE_C);
sq_seeq_write(sc, SEEQ_TXCMD, TXCMD_BANK0);
/* Now write the address */
for (i = 0; i < ETHER_ADDR_LEN; i++)
sq_seeq_write(sc, i, sc->sc_ac.ac_enaddr[i]);
- sc->sc_rxcmd =
- RXCMD_IE_CRC |
- RXCMD_IE_DRIB |
- RXCMD_IE_SHORT |
- RXCMD_IE_END |
- RXCMD_IE_GOOD;
+ sc->sc_rxcmd = RXCMD_IE_CRC | RXCMD_IE_DRIB | RXCMD_IE_SHORT |
+ RXCMD_IE_END | RXCMD_IE_GOOD;
/*
* Set the receive filter -- this will add some bits to the
@@ -440,9 +520,17 @@ sq_init(struct ifnet *ifp)
*/
sq_set_filter(sc);
+ if (sc->sc_type == SQ_TYPE_80C03) {
+ sq_seeq_write(sc, SEEQ_TXCMD, TXCMD_BANK2);
+ sq_seeq_write(sc, SEEQ_TXCTRL, 0);
+ sq_seeq_write(sc, SEEQ_TXCTRL, TXCTRL_SQE | TXCTRL_NOCARR);
+ sq_seeq_write(sc, SEEQ_TXCMD, TXCMD_BANK0);
+ }
+
/* Set up Seeq transmit command register */
- sq_seeq_write(sc, SEEQ_TXCMD,
- TXCMD_IE_UFLOW | TXCMD_IE_COLL | TXCMD_IE_16COLL | TXCMD_IE_GOOD);
+ sc->sc_txcmd =
+ TXCMD_IE_UFLOW | TXCMD_IE_COLL | TXCMD_IE_16COLL | TXCMD_IE_GOOD;
+ sq_seeq_write(sc, SEEQ_TXCMD, sc->sc_txcmd);
/* Now write the receive command register. */
sq_seeq_write(sc, SEEQ_RXCMD, sc->sc_rxcmd);
@@ -481,6 +569,7 @@ sq_set_filter(struct sq_softc *sc)
* all-multicast.
*/
if (ifp->if_flags & IFF_PROMISC) {
+ sc->sc_rxcmd &= ~RXCMD_REC_MASK;
sc->sc_rxcmd |= RXCMD_REC_ALL;
ifp->if_flags |= IFF_ALLMULTI;
return;
@@ -499,7 +588,6 @@ sq_set_filter(struct sq_softc *sc)
if (enm == NULL) {
sc->sc_rxcmd &= ~RXCMD_REC_MASK;
sc->sc_rxcmd |= RXCMD_REC_BROAD;
-
ifp->if_flags &= ~IFF_ALLMULTI;
return;
}
@@ -513,6 +601,7 @@ sq_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
{
struct sq_softc *sc = ifp->if_softc;
struct ifaddr *ifa = (struct ifaddr *)data;
+ struct ifreq *ifr = (struct ifreq *)data;
int s, error = 0;
SQ_TRACE(SQ_IOCTL, sc, 0, 0);
@@ -530,6 +619,11 @@ sq_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
#endif
break;
+ case SIOCSIFMEDIA:
+ case SIOCGIFMEDIA:
+ error = ifmedia_ioctl(ifp, ifr, &sc->sc_ifmedia, cmd);
+ break;
+
case SIOCSIFFLAGS:
if (ifp->if_flags & IFF_UP) {
if (ifp->if_flags & IFF_RUNNING)
@@ -877,6 +971,7 @@ sq_stop(struct ifnet *ifp)
}
/* Clear Seeq transmit/receive command registers */
+ sc->sc_txcmd = 0;
sq_seeq_write(sc, SEEQ_TXCMD, 0);
sq_seeq_write(sc, SEEQ_RXCMD, 0);
@@ -942,7 +1037,9 @@ sq_intr(void *arg)
{
struct sq_softc *sc = arg;
struct ifnet *ifp = &sc->sc_ac.ac_if;
+ int oldlink = sc->sc_flags & SQF_LINKUP;
uint32_t stat;
+ uint8_t sqe;
stat = sq_hpc_read(sc, sc->hpc_regs->enetr_reset);
@@ -959,6 +1056,26 @@ sq_intr(void *arg)
if ((ifp->if_flags & IFF_RUNNING) == 0)
return 0;
+ /*
+ * Check for loss of carrier detected during transmission if we
+ * can detect it.
+ */
+ if (sc->sc_type == SQ_TYPE_80C03) {
+ sqe = sq_seeq_read(sc, SEEQ_SQE) & (SQE_FLAG | SQE_NOCARR);
+ if (sqe != 0) {
+ sq_seeq_write(sc, SEEQ_TXCMD,
+ TXCMD_BANK2 | sc->sc_txcmd);
+ /* reset counters */
+ sq_seeq_write(sc, SEEQ_TXCTRL, 0);
+ sq_seeq_write(sc, SEEQ_TXCTRL,
+ TXCTRL_SQE | TXCTRL_NOCARR);
+ sq_seeq_write(sc, SEEQ_TXCMD,
+ TXCMD_BANK0 | sc->sc_txcmd);
+ if (sqe == (SQE_FLAG | SQE_NOCARR))
+ sc->sc_flags &= ~SQF_LINKUP;
+ }
+ }
+
/* Always check for received packets */
sq_rxintr(sc);
@@ -966,6 +1083,18 @@ sq_intr(void *arg)
if (sc->sc_nfreetx < SQ_NTXDESC)
sq_txintr(sc);
+ /* Notify link status change */
+ if (oldlink != (sc->sc_flags & SQF_LINKUP)) {
+ if (oldlink != 0) {
+ ifp->if_link_state = LINK_STATE_DOWN;
+ ifp->if_baudrate = 0;
+ } else {
+ ifp->if_link_state = LINK_STATE_UP;
+ ifp->if_baudrate = IF_Mbps(10);
+ }
+ if_link_state_change(ifp);
+ }
+
/*
* XXX Always claim the interrupt, even if we did nothing.
* XXX There seem to be extra interrupts when the receiver becomes
@@ -1040,6 +1169,9 @@ sq_rxintr(struct sq_softc *sc)
continue;
}
+ /* Link must be good if we have received data. */
+ sc->sc_flags |= SQF_LINKUP;
+
if (sq_add_rxbuf(sc, i) != 0) {
ifp->if_ierrors++;
bus_dmamap_sync(sc->sc_dmat, sc->sc_rxmap[i], 0,
@@ -1354,3 +1486,84 @@ sq_add_rxbuf(struct sq_softc *sc, int idx)
return 0;
}
+
+/*
+ * Media handling
+ */
+
+int
+sq_ifmedia_change_ip22(struct ifnet *ifp)
+{
+ struct sq_softc *sc = ifp->if_softc;
+ struct ifmedia *ifm = &sc->sc_ifmedia;
+ uint32_t iocw;
+
+ iocw =
+ bus_space_read_4(sc->sc_hpct, sc->sc_hpcbh, IOC_BASE + IOC_WRITE);
+
+ switch (IFM_SUBTYPE(ifm->ifm_media)) {
+ case IFM_10_5:
+ iocw &= ~IOC_WRITE_ENET_AUTO;
+ iocw |= IOC_WRITE_ENET_AUI;
+ break;
+ case IFM_10_T:
+ iocw &= ~(IOC_WRITE_ENET_AUTO | IOC_WRITE_ENET_AUI);
+ iocw |= IOC_WRITE_ENET_UTP; /* in case it cleared */
+ break;
+ default:
+ case IFM_AUTO:
+ iocw |= IOC_WRITE_ENET_AUTO;
+ break;
+ }
+
+ bus_space_write_4(sc->sc_hpct, sc->sc_hpcbh, IOC_BASE + IOC_WRITE,
+ iocw);
+ bus_space_barrier(sc->sc_hpct, sc->sc_hpcbh, IOC_BASE + IOC_WRITE, 4,
+ BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
+ return 0;
+}
+
+int
+sq_ifmedia_change_singlemedia(struct ifnet *ifp)
+{
+ return 0;
+}
+
+void
+sq_ifmedia_status_ip22(struct ifnet *ifp, struct ifmediareq *req)
+{
+ struct sq_softc *sc = ifp->if_softc;
+ uint32_t iocr, iocw;
+
+ iocw =
+ bus_space_read_4(sc->sc_hpct, sc->sc_hpcbh, IOC_BASE + IOC_WRITE);
+
+ req->ifm_status = IFM_AVALID;
+ if (sc->sc_flags & SQF_LINKUP)
+ req->ifm_status |= IFM_ACTIVE;
+ if ((iocw & IOC_WRITE_ENET_AUTO) != 0) {
+ iocr = bus_space_read_4(sc->sc_hpct, sc->sc_hpcbh,
+ IOC_BASE + IOC_READ);
+ if ((iocr & IOC_READ_ENET_LINK) != 0)
+ req->ifm_active = IFM_10_5 | IFM_ETHER;
+ else
+ req->ifm_active = IFM_10_T | IFM_ETHER;
+ } else {
+ if ((iocw & IOC_WRITE_ENET_AUI) != 0)
+ req->ifm_active = IFM_10_5 | IFM_ETHER;
+ else
+ req->ifm_active = IFM_10_T | IFM_ETHER;
+ }
+}
+
+void
+sq_ifmedia_status_singlemedia(struct ifnet *ifp, struct ifmediareq *req)
+{
+ struct sq_softc *sc = ifp->if_softc;
+ struct ifmedia *ifm = &sc->sc_ifmedia;
+
+ req->ifm_status = IFM_AVALID;
+ if (sc->sc_flags & SQF_LINKUP)
+ req->ifm_status |= IFM_ACTIVE;
+ req->ifm_active = ifm->ifm_media;
+}
diff --git a/sys/arch/sgi/hpc/if_sqvar.h b/sys/arch/sgi/hpc/if_sqvar.h
index 657025771f7..4f55053acc5 100644
--- a/sys/arch/sgi/hpc/if_sqvar.h
+++ b/sys/arch/sgi/hpc/if_sqvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_sqvar.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $OpenBSD: if_sqvar.h,v 1.2 2012/04/30 21:31:03 miod Exp $ */
/* $NetBSD: sqvar.h,v 1.12 2011/01/25 13:12:39 tsutsui Exp $ */
/*
@@ -102,6 +102,7 @@ struct sq_softc {
/* HPC registers */
bus_space_tag_t sc_hpct;
+ bus_space_handle_t sc_hpcbh; /* HPC base, for IOC access */
bus_space_handle_t sc_hpch;
/* HPC external Ethernet registers: aka Seeq 8003 registers */
@@ -112,8 +113,11 @@ struct sq_softc {
struct arpcom sc_ac;
uint8_t sc_enaddr[ETHER_ADDR_LEN];
+ struct ifmedia sc_ifmedia;
int sc_type;
+ int sc_flags;
+#define SQF_LINKUP 0x00000001
struct sq_control* sc_control;
#define sc_rxdesc sc_control->rx_desc
@@ -141,6 +145,7 @@ struct sq_softc {
bus_dmamap_t sc_txmap[SQ_NTXDESC];
struct mbuf* sc_txmbuf[SQ_NTXDESC];
+ uint8_t sc_txcmd; /* current value of TXCMD */
uint8_t sc_rxcmd; /* prototype rxcmd */
struct hpc_values *hpc_regs; /* HPC register definitions */