summaryrefslogtreecommitdiff
path: root/sys/arch/sgi/hpc
diff options
context:
space:
mode:
authorMiod Vallat <miod@cvs.openbsd.org>2012-04-08 22:08:26 +0000
committerMiod Vallat <miod@cvs.openbsd.org>2012-04-08 22:08:26 +0000
commit41d3aa859474ac82bb5d3ca7b5863d96271008fb (patch)
treea622e97c86f265e647c3a7454510229d365ef406 /sys/arch/sgi/hpc
parent2cecc3b1a143f7ade6e4ccc41cbdc9a57787b5ad (diff)
Be more careful when reprogramming the sq(4) DMA and PIO timing parameters;
the current logic can be traced back to DaveM's intership at SGI in 1996, and are adequate for the hardware he had access to. However, ``recent'' Indigo2 and Indy systems are fit with a faster (33MHz instead of 25MHz) GIO64 bus, which need different timing parameters, and guess what? The PROM knows the right values to set. Since programming these timing registers was apparently only necessary for the Challenge S second interface: 1) only reprogram those registers on an IP24 (Indy, Challenge S) system. 2) pick proper values depending upon the actual GIO64 bus speed. Item #1 fixes Ethernet operation on Indigo2 (at least my teal R4400SC). Item #2 fixes Ethernet operation on my R5000SC Indy. For the record, programming unoptimal value caused `TX DMA underrun' errors (documented as `can't happen' in the HPC3 documentation, oh the irony), which could be reproduced reliably with ypbind(8).
Diffstat (limited to 'sys/arch/sgi/hpc')
-rw-r--r--sys/arch/sgi/hpc/hpc.c58
-rw-r--r--sys/arch/sgi/hpc/hpcvar.h3
-rw-r--r--sys/arch/sgi/hpc/if_sq.c78
-rw-r--r--sys/arch/sgi/hpc/iocreg.h9
4 files changed, 99 insertions, 49 deletions
diff --git a/sys/arch/sgi/hpc/hpc.c b/sys/arch/sgi/hpc/hpc.c
index 88d8f471eb8..6014fa33ce8 100644
--- a/sys/arch/sgi/hpc/hpc.c
+++ b/sys/arch/sgi/hpc/hpc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: hpc.c,v 1.4 2012/04/05 21:46:43 miod Exp $ */
+/* $OpenBSD: hpc.c,v 1.5 2012/04/08 22:08:25 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 $ */
@@ -196,13 +196,13 @@ static const struct hpc_device hpc3_devices[] = {
{ "zs", /* serial 0/1 duart 0 */
HPC_BASE_ADDRESS_0,
/* XXX Magic numbers */
- HPC3_PBUS_CH6_DEVREGS + IOC_SERIAL_REGS, 0,
+ IOC_BASE + IOC_SERIAL_REGS, 0,
24 + 5,
HPCDEV_IP22 | HPCDEV_IP24 },
{ "pckbc", /* Indigo2/Indy ps2 keyboard/mouse controller */
HPC_BASE_ADDRESS_0,
- HPC3_PBUS_CH6_DEVREGS + IOC_KB_REGS, 0,
+ IOC_BASE + IOC_KB_REGS, 0,
24 + 4,
HPCDEV_IP22 | HPCDEV_IP24 },
@@ -238,13 +238,13 @@ static const struct hpc_device hpc3_devices[] = {
{ "pione", /* Indigo2/Indy/Challenge S/Challenge M onboard pport */
HPC_BASE_ADDRESS_0,
- HPC3_PBUS_CH6_DEVREGS + IOC_PLP_REGS, 0,
+ IOC_BASE + IOC_PLP_REGS, 0,
5,
HPCDEV_IP22 | HPCDEV_IP24 },
{ "panel", /* Indy front panel */
HPC_BASE_ADDRESS_0,
- HPC3_PBUS_CH6_DEVREGS + IOC_PANEL, 0,
+ IOC_BASE + IOC_PANEL, 0,
9,
HPCDEV_IP24 },
@@ -407,7 +407,7 @@ struct cfdriver hpc_cd = {
NULL, "hpc", DV_DULL
};
-void hpc_space_barrier(bus_space_tag_t, bus_space_handle_t, bus_size_t,
+void hpc_space_barrier(bus_space_tag_t, bus_space_handle_t, bus_size_t,
bus_size_t, int);
int
@@ -430,10 +430,12 @@ hpc_attach(struct device *parent, struct device *self, void *aux)
struct gio_attach_args* ga = aux;
struct hpc_attach_args ha;
const struct hpc_device *hd;
+ struct hpc_values *hv;
uint32_t dummy;
uint32_t hpctype;
int isonboard;
int isioplus;
+ int giofast;
int sysmask = 0;
sc->sc_base = ga->ga_addr;
@@ -573,7 +575,41 @@ hpc_attach(struct device *parent, struct device *self, void *aux)
if (hpctype == 3)
sc->sc_hpc_bus_space._space_barrier = hpc_space_barrier;
- hd = hpctype == 3 ? hpc3_devices : hpc1_devices;
+ if (hpctype == 3) {
+ hd = hpc3_devices;
+ hv = &hpc3_values;
+
+ if (isonboard) {
+ if (sys_config.system_subtype == IP22_INDIGO2) {
+ /* wild guess */
+ giofast = 1;
+ } else {
+ /*
+ * According to IRIX hpc3.h, the fast GIO bit
+ * is active high, but the register value has
+ * been found to be 0xf8 on slow GIO systems
+ * and 0xf1 on fast ones, which tends to prove
+ * the opposite...
+ */
+ if (bus_space_read_4(sc->sc_ct, sc->sc_ch,
+ IOC_BASE + IOC_GCREG) & IOC_GCREG_GIO_33MHZ)
+ giofast = 0;
+ else
+ giofast = 1;
+ }
+ } else {
+ /*
+ * XXX should IO+ Mezzanine use the same settings as
+ * XXX the onboard HPC3?
+ */
+ giofast = 0;
+ }
+ } else {
+ hd = hpc1_devices;
+ hv = &hpc1_values;
+ hv->revision = hpctype;
+ giofast = 0;
+ }
for (; hd->hd_name != NULL; hd++) {
if (!(hd->hd_sysmask & sysmask) || hd->hd_base != sc->sc_base)
continue;
@@ -586,11 +622,8 @@ hpc_attach(struct device *parent, struct device *self, void *aux)
ha.ha_st = &sc->sc_hpc_bus_space;
ha.ha_sh = sc->sc_ch;
ha.ha_dmat = sc->sc_dmat;
- if (hpctype == 3)
- ha.hpc_regs = &hpc3_values;
- else
- ha.hpc_regs = &hpc1_values;
- ha.hpc_regs->revision = hpctype;
+ ha.hpc_regs = hv;
+ ha.ha_giofast = giofast;
/*
* XXX On hpc@gio boards such as the E++, this will cause
@@ -619,6 +652,7 @@ hpc_attach(struct device *parent, struct device *self, void *aux)
ha.ha_sh = sc->sc_ch;
ha.ha_dmat = sc->sc_dmat;
ha.hpc_regs = NULL;
+ ha.ha_giofast = giofast;
config_found_sm(self, &ha, hpc_print, hpc_submatch);
diff --git a/sys/arch/sgi/hpc/hpcvar.h b/sys/arch/sgi/hpc/hpcvar.h
index 488940404e7..0debe5fd001 100644
--- a/sys/arch/sgi/hpc/hpcvar.h
+++ b/sys/arch/sgi/hpc/hpcvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: hpcvar.h,v 1.2 2012/04/05 21:45:51 miod Exp $ */
+/* $OpenBSD: hpcvar.h,v 1.3 2012/04/08 22:08:25 miod Exp $ */
/* $NetBSD: hpcvar.h,v 1.12 2011/01/25 12:21:04 tsutsui Exp $ */
/*
@@ -103,6 +103,7 @@ struct hpc_attach_args {
bus_dma_tag_t ha_dmat; /* HPC DMA tag */
struct hpc_values *hpc_regs; /* HPC register definitions */
+ int ha_giofast; /* GIO bus speed */
uint8_t hpc_eeprom[256];/* HPC eeprom contents */
};
diff --git a/sys/arch/sgi/hpc/if_sq.c b/sys/arch/sgi/hpc/if_sq.c
index 5a5e02d1d2b..259aa1ad178 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.2 2012/04/05 21:45:51 miod Exp $ */
+/* $OpenBSD: if_sq.c,v 1.3 2012/04/08 22:08:25 miod Exp $ */
/* $NetBSD: if_sq.c,v 1.42 2011/07/01 18:53:47 dyoung Exp $ */
/*
@@ -72,6 +72,7 @@
#include <machine/cpu.h> /* guarded_read_4 */
#include <machine/intr.h>
#include <mips64/arcbios.h> /* bios_enaddr */
+#include <sgi/sgi/ip22.h>
#include <sgi/localbus/intvar.h>
#include <dev/ic/seeq8003reg.h>
@@ -98,7 +99,7 @@
* the correct thing?
*/
-#if defined(SQ_DEBUG)
+#ifdef SQ_DEBUG
int sq_debug = 0;
#define SQ_DPRINTF(x) do { if (sq_debug) printf x; } while (0)
#else
@@ -294,6 +295,44 @@ sq_attach(struct device *parent, struct device *self, void *aux)
goto fail_6;
}
+ /*
+ * Set up HPC ethernet PIO and DMA configurations.
+ *
+ * The PROM appears to do most of this for the onboard HPC3, but
+ * not for the Challenge S's IOPLUS chip. We copy how the onboard
+ * chip is configured and assume that it's correct for both.
+ */
+ if (haa->hpc_regs->revision == 3 &&
+ sys_config.system_subtype != IP22_INDIGO2) {
+ uint32_t dmareg, pioreg;
+
+ if (haa->ha_giofast) {
+ pioreg =
+ HPC3_ENETR_PIOCFG_P1(1) |
+ HPC3_ENETR_PIOCFG_P2(5) |
+ HPC3_ENETR_PIOCFG_P3(0);
+ dmareg =
+ HPC3_ENETR_DMACFG_D1(5) |
+ HPC3_ENETR_DMACFG_D2(1) |
+ HPC3_ENETR_DMACFG_D3(0);
+ } else {
+ pioreg =
+ HPC3_ENETR_PIOCFG_P1(1) |
+ HPC3_ENETR_PIOCFG_P2(6) |
+ HPC3_ENETR_PIOCFG_P3(1);
+ dmareg =
+ HPC3_ENETR_DMACFG_D1(6) |
+ HPC3_ENETR_DMACFG_D2(2) |
+ HPC3_ENETR_DMACFG_D3(0);
+ }
+ dmareg |= HPC3_ENETR_DMACFG_FIX_RXDC |
+ HPC3_ENETR_DMACFG_FIX_INTR | HPC3_ENETR_DMACFG_FIX_EOP |
+ HPC3_ENETR_DMACFG_TIMEOUT;
+
+ sq_hpc_write(sc, HPC3_ENETR_PIOCFG, pioreg);
+ sq_hpc_write(sc, HPC3_ENETR_DMACFG, dmareg);
+ }
+
/* Reset the chip to a known state. */
sq_reset(sc);
@@ -409,34 +448,6 @@ sq_init(struct ifnet *ifp)
/* Now write the receive command register. */
sq_seeq_write(sc, SEEQ_RXCMD, sc->sc_rxcmd);
- /*
- * Set up HPC ethernet PIO and DMA configurations.
- *
- * The PROM appears to do most of this for the onboard HPC3, but
- * not for the Challenge S's IOPLUS chip. We copy how the onboard
- * chip is configured and assume that it's correct for both.
- */
- if (sc->hpc_regs->revision == 3) {
- uint32_t dmareg, pioreg;
-
- pioreg =
- HPC3_ENETR_PIOCFG_P1(1) |
- HPC3_ENETR_PIOCFG_P2(6) |
- HPC3_ENETR_PIOCFG_P3(1);
-
- dmareg =
- HPC3_ENETR_DMACFG_D1(6) |
- HPC3_ENETR_DMACFG_D2(2) |
- HPC3_ENETR_DMACFG_D3(0) |
- HPC3_ENETR_DMACFG_FIX_RXDC |
- HPC3_ENETR_DMACFG_FIX_INTR |
- HPC3_ENETR_DMACFG_FIX_EOP |
- HPC3_ENETR_DMACFG_TIMEOUT;
-
- sq_hpc_write(sc, HPC3_ENETR_PIOCFG, pioreg);
- sq_hpc_write(sc, HPC3_ENETR_DMACFG, dmareg);
- }
-
/* Pass the start of the receive ring to the HPC */
sq_hpc_write(sc, sc->hpc_regs->enetr_ndbp, SQ_CDRXADDR(sc, 0));
@@ -764,7 +775,7 @@ sq_start(struct ifnet *ifp)
* descriptor.
*
* HPC1_HDD_CTL_INTR will generate an interrupt on
- * HPC1. HPC3 requires HPC3_HDD_CTL_EOPACKET in
+ * HPC1. HPC3 requires HPC3_HDD_CTL_EOCHAIN in
* addition to HPC3_HDD_CTL_INTR to interrupt.
*/
KASSERT(lasttx != -1);
@@ -1124,8 +1135,9 @@ sq_txintr(struct sq_softc *sc)
}
if (status & TXSTAT_16COLL) {
- printf("%s: max collisions reached\n",
- sc->sc_dev.dv_xname);
+ if (ifp->if_flags & IFF_DEBUG)
+ printf("%s: max collisions reached\n",
+ sc->sc_dev.dv_xname);
ifp->if_oerrors++;
ifp->if_collisions += 16;
}
diff --git a/sys/arch/sgi/hpc/iocreg.h b/sys/arch/sgi/hpc/iocreg.h
index 274454e4ddf..ca5eace2939 100644
--- a/sys/arch/sgi/hpc/iocreg.h
+++ b/sys/arch/sgi/hpc/iocreg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: iocreg.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $OpenBSD: iocreg.h,v 1.2 2012/04/08 22:08:25 miod Exp $ */
/* $NetBSD: iocreg.h,v 1.2 2005/12/11 12:18:53 christos Exp $ */
/*
@@ -72,6 +72,7 @@
#define IOC_GCSEL 0x48 /* General select register */
#define IOC_GCREG 0x4c /* General control register */
+#define IOC_GCREG_GIO_33MHZ 0x08
#define IOC_PANEL 0x50 /* Front Panel register */
#define IOC_PANEL_POWER_STATE 0x01
@@ -102,7 +103,8 @@
#define IOC_DMASEL_SERIAL_6MHZ 0x10
#define IOC_DMASEL_SERIAL_EXTERNAL 0x20
-#define IOC_RESET 0x70 /* Reset register */
+#define IOC_RESET 0x70 /* Reset (IP24) / Write 1 (IP22)
+ register */
#define IOC_RESET_PARALLEL 0x01
#define IOC_RESET_PCKBC 0x02
#define IOC_RESET_EISA 0x04
@@ -111,7 +113,8 @@
#define IOC_RESET_LED_RED 0x20
#define IOC_RESET_LED_ORANGE 0x40
-#define IOC_WRITE 0x78 /* Write register */
+#define IOC_WRITE 0x78 /* Write (IP24) / Write 2 (IP22)
+ register */
#define IOC_WRITE_ENET_NTH 0x01
#define IOC_WRITE_ENET_UTP 0x02
#define IOC_WRITE_ENET_AUI 0x04