PERFORCE change 125801 for review
Marcel Moolenaar
marcel at FreeBSD.org
Tue Aug 28 22:51:06 PDT 2007
http://perforce.freebsd.org/chv.cgi?CH=125801
Change 125801 by marcel at marcel_xcllnt on 2007/08/29 05:50:34
Various patches obtained from marius@
This compiles.
Affected files ...
.. //depot/projects/usiii/conf/NOTES#2 edit
.. //depot/projects/usiii/conf/files.sparc64#2 edit
.. //depot/projects/usiii/dev/bge/if_bge.c#2 edit
.. //depot/projects/usiii/dev/gem/if_gem.c#2 edit
.. //depot/projects/usiii/dev/gem/if_gem_pci.c#2 edit
.. //depot/projects/usiii/dev/gem/if_gemreg.h#2 edit
.. //depot/projects/usiii/dev/gem/if_gemvar.h#2 edit
.. //depot/projects/usiii/dev/pci/pci.c#2 edit
.. //depot/projects/usiii/dev/pci/pcivar.h#2 edit
.. //depot/projects/usiii/modules/Makefile#2 edit
.. //depot/projects/usiii/powerpc/conf/NOTES#2 edit
.. //depot/projects/usiii/sparc64/fhc/fhc.c#2 edit
.. //depot/projects/usiii/sparc64/fhc/fhcreg.h#2 edit
.. //depot/projects/usiii/sparc64/include/intr_machdep.h#2 edit
.. //depot/projects/usiii/sparc64/include/tlb.h#2 edit
.. //depot/projects/usiii/sparc64/pci/ofw_pcibus.c#2 edit
.. //depot/projects/usiii/sparc64/pci/psycho.c#2 edit
.. //depot/projects/usiii/sparc64/pci/psychoreg.h#2 edit
.. //depot/projects/usiii/sparc64/pci/schizo.c#1 add
.. //depot/projects/usiii/sparc64/pci/schizoreg.h#1 add
.. //depot/projects/usiii/sparc64/pci/schizovar.h#1 add
.. //depot/projects/usiii/sparc64/sbus/sbus.c#2 edit
.. //depot/projects/usiii/sparc64/sbus/sbusreg.h#2 edit
.. //depot/projects/usiii/sparc64/sparc64/cheetah.c#2 edit
.. //depot/projects/usiii/sparc64/sparc64/exception.S#2 edit
.. //depot/projects/usiii/sparc64/sparc64/intr_machdep.c#2 edit
.. //depot/projects/usiii/sparc64/sparc64/tick.c#2 edit
.. //depot/projects/usiii/sparc64/sparc64/upa.c#2 edit
Differences ...
==== //depot/projects/usiii/conf/NOTES#2 (text+ko) ====
@@ -1769,6 +1769,7 @@
# fpa: Support for the Digital DEFPA PCI FDDI. `device fddi' is also needed.
# fxp: Intel EtherExpress Pro/100B
# (hint of prefer_iomap can be done to prefer I/O instead of Mem mapping)
+# gem: Sun GEM/Sun ERI/Apple GMAC
# hme: Sun HME (Happy Meal Ethernet)
# le: AMD Am7900 LANCE and Am79C9xx PCnet
# lge: Support for PCI gigabit ethernet adapters based on the Level 1
@@ -1883,6 +1884,7 @@
device dc # DEC/Intel 21143 and various workalikes
device fxp # Intel EtherExpress PRO/100B (82557, 82558)
hint.fxp.0.prefer_iomap="0"
+device gem # Sun GEM/Sun ERI/Apple GMAC
device hme # Sun HME (Happy Meal Ethernet)
device lge # Level 1 LXT1001 gigabit Ethernet
device my # Myson Fast Ethernet (MTD80X, MTD89X)
==== //depot/projects/usiii/conf/files.sparc64#2 (text+ko) ====
@@ -85,6 +85,7 @@
sparc64/pci/ofw_pcibus.c optional pci
sparc64/pci/ofw_pci_if.m optional pci
sparc64/pci/psycho.c optional pci
+sparc64/pci/schizo.c optional pci
sparc64/sbus/dma_sbus.c optional sbus
sparc64/sbus/sbus.c optional sbus
sparc64/sbus/lsi64854.c optional sbus
==== //depot/projects/usiii/dev/bge/if_bge.c#2 (text+ko) ====
@@ -2180,14 +2180,16 @@
static int
bge_has_multiple_ports(struct bge_softc *sc)
{
- device_t dev = sc->bge_dev;
+ device_t dev, p;
u_int b, s, f, fscan;
+ dev = sc->bge_dev;
+ p = device_get_parent(device_get_parent(dev));
b = pci_get_bus(dev);
s = pci_get_slot(dev);
f = pci_get_function(dev);
for (fscan = 0; fscan <= PCI_FUNCMAX; fscan++)
- if (fscan != f && pci_find_bsf(b, s, fscan) != NULL)
+ if (fscan != f && pci_find_pbsf(p, b, s, fscan) != NULL)
return (1);
return (0);
}
==== //depot/projects/usiii/dev/gem/if_gem.c#2 (text+ko) ====
@@ -110,6 +110,7 @@
static int gem_bitwait(struct gem_softc *, bus_addr_t, u_int32_t,
u_int32_t);
static int gem_reset_rx(struct gem_softc *);
+static void gem_reset_rxdma(struct gem_softc *sc);
static int gem_reset_tx(struct gem_softc *);
static int gem_disable_rx(struct gem_softc *);
static int gem_disable_tx(struct gem_softc *);
@@ -119,6 +120,7 @@
struct mbuf *gem_get(struct gem_softc *, int, int);
static void gem_eint(struct gem_softc *, u_int);
+static void gem_pint(struct gem_softc *);
static void gem_rint(struct gem_softc *);
#ifdef GEM_RINT_TIMEOUT
static void gem_rint_timeout(void *);
@@ -149,7 +151,6 @@
struct gem_softc *sc;
{
struct ifnet *ifp;
- struct mii_softc *child;
int i, error;
u_int32_t v;
@@ -164,10 +165,7 @@
/* Make sure the chip is stopped. */
ifp->if_softc = sc;
- GEM_LOCK(sc);
- gem_stop(ifp, 0);
gem_reset(sc);
- GEM_UNLOCK(sc);
error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0,
BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
@@ -257,11 +255,74 @@
sc->sc_rxsoft[i].rxs_mbuf = NULL;
}
+ /* Bad things will happen when touching this register on ERI. */
+ if (sc->sc_variant != GEM_SUN_ERI)
+ bus_write_4(sc->sc_res[0], GEM_MII_DATAPATH_MODE,
+ GEM_MII_DATAPATH_MII);
+
gem_mifinit(sc);
- if ((error = mii_phy_probe(sc->sc_dev, &sc->sc_miibus, gem_mediachange,
- gem_mediastatus)) != 0) {
- device_printf(sc->sc_dev, "phy probe failed: %d\n", error);
+ /*
+ * Look for an external PHY.
+ */
+ error = ENXIO;
+ v = bus_read_4(sc->sc_res[0], GEM_MIF_CONFIG);
+ if ((v & GEM_MIF_CONFIG_MDI1) != 0) {
+ v |= GEM_MIF_CONFIG_PHY_SEL;
+ bus_write_4(sc->sc_res[0], GEM_MIF_CONFIG, v);
+ switch (sc->sc_variant) {
+ case GEM_SUN_ERI:
+ sc->sc_phyad = GEM_PHYAD_EXTERNAL;
+ break;
+ default:
+ sc->sc_phyad = -1;
+ break;
+ }
+ error = mii_phy_probe(sc->sc_dev, &sc->sc_miibus,
+ gem_mediachange, gem_mediastatus);
+ }
+
+ /*
+ * Fall back on an internal PHY if no external PHY was found.
+ */
+ if (error != 0 && (v & GEM_MIF_CONFIG_MDI0) != 0) {
+ v &= ~GEM_MIF_CONFIG_PHY_SEL;
+ bus_write_4(sc->sc_res[0], GEM_MIF_CONFIG, v);
+ switch (sc->sc_variant) {
+ case GEM_SUN_ERI:
+ case GEM_APPLE_K2_GMAC:
+ sc->sc_phyad = GEM_PHYAD_INTERNAL;
+ break;
+ case GEM_APPLE_GMAC:
+ sc->sc_phyad = GEM_PHYAD_EXTERNAL;
+ break;
+ default:
+ sc->sc_phyad = -1;
+ break;
+ }
+ error = mii_phy_probe(sc->sc_dev, &sc->sc_miibus,
+ gem_mediachange, gem_mediastatus);
+ }
+
+ /*
+ * Try the external PCS SERDES if we didn't find any PHYs.
+ */
+ if (error != 0 && sc->sc_variant != GEM_SUN_ERI &&
+ (v & (GEM_MIF_CONFIG_MDI0 | GEM_MIF_CONFIG_MDI1)) != 0) {
+ bus_write_4(sc->sc_res[0], GEM_MII_DATAPATH_MODE,
+ GEM_MII_DATAPATH_SERDES);
+ bus_write_4(sc->sc_res[0], GEM_MII_SLINK_CONTROL,
+ GEM_MII_SLINK_LOOPBACK | GEM_MII_SLINK_EN_SYNC_D);
+ bus_write_4(sc->sc_res[0], GEM_MII_CONFIG,
+ GEM_MII_CONFIG_ENABLE);
+ sc->sc_flags |= GEM_SERDES;
+ sc->sc_phyad = GEM_PHYAD_EXTERNAL;
+ error = mii_phy_probe(sc->sc_dev, &sc->sc_miibus,
+ gem_mediachange, gem_mediastatus);
+ }
+
+ if (error != 0) {
+ device_printf(sc->sc_dev, "PHY probe failed: %d\n", error);
goto fail_rxd;
}
sc->sc_mii = device_get_softc(sc->sc_miibus);
@@ -293,50 +354,7 @@
IFQ_SET_MAXLEN(&ifp->if_snd, GEM_TXQUEUELEN);
ifp->if_snd.ifq_drv_maxlen = GEM_TXQUEUELEN;
IFQ_SET_READY(&ifp->if_snd);
- /*
- * Walk along the list of attached MII devices and
- * establish an `MII instance' to `phy number'
- * mapping. We'll use this mapping in media change
- * requests to determine which phy to use to program
- * the MIF configuration register.
- */
- for (child = LIST_FIRST(&sc->sc_mii->mii_phys); child != NULL;
- child = LIST_NEXT(child, mii_list)) {
- /*
- * Note: we support just two PHYs: the built-in
- * internal device and an external on the MII
- * connector.
- */
- if (child->mii_phy > 1 || child->mii_inst > 1) {
- device_printf(sc->sc_dev, "cannot accomodate "
- "MII device %s at phy %d, instance %d\n",
- device_get_name(child->mii_dev),
- child->mii_phy, child->mii_inst);
- continue;
- }
- sc->sc_phys[child->mii_inst] = child->mii_phy;
- }
-
- /*
- * Now select and activate the PHY we will use.
- *
- * The order of preference is External (MDI1),
- * Internal (MDI0), Serial Link (no MII).
- */
- if (sc->sc_phys[1]) {
-#ifdef GEM_DEBUG
- printf("using external phy\n");
-#endif
- sc->sc_mif_config |= GEM_MIF_CONFIG_PHY_SEL;
- } else {
-#ifdef GEM_DEBUG
- printf("using internal phy\n");
-#endif
- sc->sc_mif_config &= ~GEM_MIF_CONFIG_PHY_SEL;
- }
- bus_write_4(sc->sc_res[0], GEM_MIF_CONFIG,
- sc->sc_mif_config);
/* Attach the interface. */
ether_ifattach(ifp, sc->sc_enaddr);
@@ -455,7 +473,7 @@
* On resume all registers have to be initialized again like
* after power-on.
*/
- sc->sc_inited = 0;
+ sc->sc_flags &= ~GEM_INITED;
if (ifp->if_flags & IFF_UP)
gem_init_locked(sc);
GEM_UNLOCK(sc);
@@ -580,7 +598,7 @@
return;
if (nsegs != 1) {
/* can't happen... */
- panic("gem_cddma_callback: bad control buffer segment count");
+ panic("%s: bad control buffer segment count", __func__);
}
sc->sc_cddma = segs[0].ds_addr;
}
@@ -698,7 +716,7 @@
callout_stop(&sc->sc_tick_ch);
#ifdef GEM_RINT_TIMEOUT
callout_stop(&sc->sc_rx_ch);
-#endif
+#endif
/* XXX - Should we reset these instead? */
gem_disable_tx(sc);
@@ -734,7 +752,7 @@
/*
* Reset the receiver
*/
-int
+static int
gem_reset_rx(sc)
struct gem_softc *sc;
{
@@ -762,6 +780,48 @@
return (0);
}
+/*
+ * Reset the receiver DMA engine.
+ *
+ * Intended to be used in case of GEM_INTR_RX_TAG_ERR, GEM_MAC_RX_OVERFLOW
+ * etc in order to reset the receiver DMA engine only and not do a full
+ * reset which amongst others also downs the link and clears the FIFOs.
+ */
+static void
+gem_reset_rxdma(struct gem_softc *sc)
+{
+ int i;
+
+ if (gem_reset_rx(sc) != 0)
+ gem_init_locked(sc);
+ for (i = 0; i < GEM_NRXDESC; i++)
+ if (sc->sc_rxsoft[i].rxs_mbuf != NULL)
+ GEM_UPDATE_RXDESC(sc, i);
+ sc->sc_rxptr = 0;
+ GEM_CDSYNC(sc, BUS_DMASYNC_PREWRITE);
+ GEM_CDSYNC(sc, BUS_DMASYNC_PREREAD);
+
+ /* NOTE: we use only 32-bit DMA addresses here. */
+ bus_write_4(sc->sc_res[0], GEM_RX_RING_PTR_HI, 0);
+ bus_write_4(sc->sc_res[0], GEM_RX_RING_PTR_LO, GEM_CDRXADDR(sc, 0));
+ bus_write_4(sc->sc_res[0], GEM_RX_KICK, GEM_NRXDESC - 4);
+ bus_write_4(sc->sc_res[0], GEM_RX_CONFIG,
+ gem_ringsize(GEM_NRXDESC /*XXX*/) |
+ ((ETHER_HDR_LEN + sizeof(struct ip)) <<
+ GEM_RX_CONFIG_CXM_START_SHFT) |
+ (GEM_THRSH_1024 << GEM_RX_CONFIG_FIFO_THRS_SHIFT) |
+ (2 << GEM_RX_CONFIG_FBOFF_SHFT));
+ bus_write_4(sc->sc_res[0], GEM_RX_BLANKING,
+ (6 << GEM_RX_BLANKING_TIME_SHIFT) | 6);
+ bus_write_4(sc->sc_res[0], GEM_RX_PAUSE_THRESH,
+ (3 * sc->sc_rxfifosize / 256) | ((sc->sc_rxfifosize / 256) << 12));
+ bus_write_4(sc->sc_res[0], GEM_RX_CONFIG,
+ bus_read_4(sc->sc_res[0], GEM_RX_CONFIG) | GEM_RX_CONFIG_RXDMA_EN);
+ bus_write_4(sc->sc_res[0], GEM_MAC_RX_MASK,
+ GEM_MAC_RX_DONE | GEM_MAC_RX_FRAME_CNT);
+ bus_write_4(sc->sc_res[0], GEM_MAC_RX_CONFIG,
+ bus_read_4(sc->sc_res[0], GEM_MAC_RX_CONFIG) | GEM_MAC_RX_ENABLE);
+}
/*
* Reset the transmitter
@@ -993,12 +1053,10 @@
/* step 8. Global Configuration & Interrupt Mask */
bus_write_4(sc->sc_res[0], GEM_INTMASK,
- ~(GEM_INTR_TX_INTME|
- GEM_INTR_TX_EMPTY|
- GEM_INTR_RX_DONE|GEM_INTR_RX_NOBUF|
- GEM_INTR_RX_TAG_ERR|GEM_INTR_PCS|
- GEM_INTR_MAC_CONTROL|GEM_INTR_MIF|
- GEM_INTR_BERR));
+ ~(GEM_INTR_TX_INTME | GEM_INTR_TX_EMPTY | GEM_INTR_RX_DONE |
+ GEM_INTR_RX_NOBUF | GEM_INTR_RX_TAG_ERR | GEM_INTR_PERR |
+ GEM_INTR_PCS | GEM_INTR_MAC_CONTROL | GEM_INTR_MIF |
+ GEM_INTR_BERR));
bus_write_4(sc->sc_res[0], GEM_MAC_RX_MASK,
GEM_MAC_RX_DONE|GEM_MAC_RX_FRAME_CNT);
bus_write_4(sc->sc_res[0], GEM_MAC_TX_MASK, 0xffff); /* XXXX */
@@ -1024,6 +1082,10 @@
bus_write_4(sc->sc_res[0], GEM_RX_CONFIG,
v|(GEM_THRSH_1024<<GEM_RX_CONFIG_FIFO_THRS_SHIFT)|
(2<<GEM_RX_CONFIG_FBOFF_SHFT)|GEM_RX_CONFIG_RXDMA_EN);
+
+ bus_write_4(sc->sc_res[0], GEM_RX_BLANKING,
+ (6 << GEM_RX_BLANKING_TIME_SHIFT) | 6);
+
/*
* The following value is for an OFF Threshold of about 3/4 full
* and an ON Threshold of 1/4 full.
@@ -1031,7 +1093,6 @@
bus_write_4(sc->sc_res[0], GEM_RX_PAUSE_THRESH,
(3 * sc->sc_rxfifosize / 256) |
( (sc->sc_rxfifosize / 256) << 12));
- bus_write_4(sc->sc_res[0], GEM_RX_BLANKING, (6<<12)|6);
/* step 11. Configure Media */
mii_mediachg(sc->sc_mii);
@@ -1205,7 +1266,7 @@
txs->txs_firstdesc = sc->sc_txnext;
nexttx = txs->txs_firstdesc;
for (seg = 0; seg < nsegs; seg++, nexttx = GEM_NEXTTX(nexttx)) {
-#ifdef GEM_DEBUG
+#ifdef GEM_DEBUG
CTR6(KTR_GEM, "%s: mapping seg %d (txd %d), len "
"%lx, addr %#lx (%#lx)", __func__, seg, nexttx,
txsegs[seg].ds_len, txsegs[seg].ds_addr,
@@ -1222,7 +1283,7 @@
}
/* set EOP on the last descriptor */
-#ifdef GEM_DEBUG
+#ifdef GEM_DEBUG
CTR3(KTR_GEM, "%s: end of packet at seg %d, tx %d", __func__, seg,
nexttx);
#endif
@@ -1230,7 +1291,7 @@
GEM_DMA_WRITE(sc, GEM_TD_END_OF_PACKET);
/* Lastly set SOP on the first descriptor */
-#ifdef GEM_DEBUG
+#ifdef GEM_DEBUG
CTR3(KTR_GEM, "%s: start of packet at seg %d, tx %d", __func__, seg,
nexttx);
#endif
@@ -1266,11 +1327,9 @@
struct gem_softc *sc;
{
const u_char *laddr = IF_LLADDR(sc->sc_ifp);
- u_int32_t v;
/* These regs are not cleared on reset */
- if (!sc->sc_inited) {
-
+ if ((sc->sc_flags & GEM_INITED) == 0) {
/* Wooo. Magic values. */
bus_write_4(sc->sc_res[0], GEM_MAC_IPG0, 0);
bus_write_4(sc->sc_res[0], GEM_MAC_IPG1, 8);
@@ -1279,8 +1338,7 @@
bus_write_4(sc->sc_res[0], GEM_MAC_MAC_MIN_FRAME, ETHER_MIN_LEN);
/* Max frame and max burst size */
bus_write_4(sc->sc_res[0], GEM_MAC_MAC_MAX_FRAME,
- (ETHER_MAX_LEN + ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN) |
- (0x2000 << 16));
+ (ETHER_MAX_LEN + ETHER_VLAN_ENCAP_LEN) | (0x2000 << 16));
bus_write_4(sc->sc_res[0], GEM_MAC_PREAMBLE_LEN, 0x7);
bus_write_4(sc->sc_res[0], GEM_MAC_JAM_SIZE, 0x4);
@@ -1308,7 +1366,7 @@
bus_write_4(sc->sc_res[0], GEM_MAC_ADR_FLT_MASK1_2, 0);
bus_write_4(sc->sc_res[0], GEM_MAC_ADR_FLT_MASK0, 0);
- sc->sc_inited = 1;
+ sc->sc_flags |= GEM_INITED;
}
/* Counters need to be zeroed */
@@ -1324,12 +1382,27 @@
bus_write_4(sc->sc_res[0], GEM_MAC_RX_CRC_ERR_CNT, 0);
bus_write_4(sc->sc_res[0], GEM_MAC_RX_CODE_VIOL, 0);
- /* Un-pause stuff */
-#if 0
+ /* Set slot time (used as pause time unit). */
+ bus_write_4(sc->sc_res[0], GEM_MAC_SLOT_TIME, 64);
+
+ /* Set XOFF pause time. */
bus_write_4(sc->sc_res[0], GEM_MAC_SEND_PAUSE_CMD, 0x1BF0);
-#else
- bus_write_4(sc->sc_res[0], GEM_MAC_SEND_PAUSE_CMD, 0);
-#endif
+
+ /*
+ * More or less magic DMA burst configuration and Apple GEM
+ * silicon bug workarounds which are both based on Linux.
+ * The former is required for at least Sun GEM in order to
+ * avoid tons of GEM_MAC_RX_OVERFLOW.
+ */
+ bus_write_4(sc->sc_res[0], GEM_CONFIG,
+ GEM_CONFIG_TXDMA_LIMIT | GEM_CONFIG_RXDMA_LIMIT |
+ GEM_CONFIG_BURST_INF | (GEM_IS_APPLE(sc) ?
+ GEM_CONFIG_RONPAULBIT | GEM_CONFIG_BUG2FIX : 0));
+ if ((bus_read_4(sc->sc_res[0], GEM_CONFIG) &
+ GEM_CONFIG_BURST_INF) == 0)
+ bus_write_4(sc->sc_res[0], GEM_CONFIG,
+ (2 << GEM_CONFIG_TXDMA_LIMIT_SHIFT) |
+ (8 << GEM_CONFIG_RXDMA_LIMIT_SHIFT));
/*
* Set the station address.
@@ -1338,17 +1411,8 @@
bus_write_4(sc->sc_res[0], GEM_MAC_ADDR1, (laddr[2]<<8)|laddr[3]);
bus_write_4(sc->sc_res[0], GEM_MAC_ADDR2, (laddr[0]<<8)|laddr[1]);
- /*
- * Enable MII outputs. Enable GMII if there is a gigabit PHY.
- */
- sc->sc_mif_config = bus_read_4(sc->sc_res[0], GEM_MIF_CONFIG);
- v = GEM_MAC_XIF_TX_MII_ENA;
- if (sc->sc_mif_config & GEM_MIF_CONFIG_MDI1) {
- v |= GEM_MAC_XIF_FDPLX_LED;
- if (sc->sc_flags & GEM_GIGABIT)
- v |= GEM_MAC_XIF_GMII_MODE;
- }
- bus_write_4(sc->sc_res[0], GEM_MAC_XIF_CONFIG, v);
+ /* Enable MII outputs. */
+ bus_write_4(sc->sc_res[0], GEM_MAC_XIF_CONFIG, GEM_MAC_XIF_TX_MII_ENA);
}
static void
@@ -1368,23 +1432,22 @@
{
struct gem_softc *sc = (struct gem_softc *)ifp->if_softc;
struct mbuf *m;
- int firsttx, ntx = 0, txmfail;
+ int ntx = 0;
if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
IFF_DRV_RUNNING)
return;
- firsttx = sc->sc_txnext;
#ifdef GEM_DEBUG
CTR4(KTR_GEM, "%s: %s: txfree %d, txnext %d",
- device_get_name(sc->sc_dev), __func__, sc->sc_txfree, firsttx);
+ device_get_name(sc->sc_dev), __func__, sc->sc_txfree,
+ sc->sc_txnext);
#endif
for (; !IFQ_DRV_IS_EMPTY(&ifp->if_snd) && sc->sc_txfree > 1;) {
IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
if (m == NULL)
break;
- txmfail = gem_load_txmbuf(sc, &m);
- if (txmfail != 0) {
+ if (gem_load_txmbuf(sc, &m) != 0) {
if (m == NULL)
break;
ifp->if_drv_flags |= IFF_DRV_OACTIVE;
@@ -1392,8 +1455,9 @@
break;
}
ntx++;
+ GEM_CDSYNC(sc, BUS_DMASYNC_PREWRITE);
/* Kick the transmitter. */
-#ifdef GEM_DEBUG
+#ifdef GEM_DEBUG
CTR3(KTR_GEM, "%s: %s: kicking tx %d",
device_get_name(sc->sc_dev), __func__, sc->sc_txnext);
#endif
@@ -1404,11 +1468,9 @@
}
if (ntx > 0) {
- GEM_CDSYNC(sc, BUS_DMASYNC_PREWRITE);
-
#ifdef GEM_DEBUG
CTR2(KTR_GEM, "%s: packets enqueued, OWN on %d",
- device_get_name(sc->sc_dev), firsttx);
+ device_get_name(sc->sc_dev), sc->sc_txnext);
#endif
/* Set a watchdog timer in case the chip flakes out. */
@@ -1507,15 +1569,13 @@
#ifdef GEM_DEBUG
CTR4(KTR_GEM, "%s: GEM_TX_STATE_MACHINE %x "
- "GEM_TX_DATA_PTR %llx "
- "GEM_TX_COMPLETION %x",
- __func__,
- bus_space_read_4(sc->sc_res[0], sc->sc_h, GEM_TX_STATE_MACHINE),
- ((long long) bus_4(sc->sc_res[0],
- GEM_TX_DATA_PTR_HI) << 32) |
- bus_read_4(sc->sc_res[0],
- GEM_TX_DATA_PTR_LO),
- bus_read_4(sc->sc_res[0], GEM_TX_COMPLETION));
+ "GEM_TX_DATA_PTR %llx "
+ "GEM_TX_COMPLETION %x",
+ __func__,
+ bus_read_4(sc->sc_res[0], GEM_TX_STATE_MACHINE),
+ ((long long) bus_read_4(sc->sc_res[0], GEM_TX_DATA_PTR_HI) << 32) |
+ bus_read_4(sc->sc_res[0], GEM_TX_DATA_PTR_LO),
+ bus_read_4(sc->sc_res[0], GEM_TX_COMPLETION));
#endif
if (progress) {
@@ -1557,11 +1617,9 @@
struct gem_softc *sc;
{
struct ifnet *ifp = sc->sc_ifp;
- struct gem_rxsoft *rxs;
struct mbuf *m;
u_int64_t rxstat;
u_int32_t rxcomp;
- int i, len, progress = 0;
#ifdef GEM_RINT_TIMEOUT
callout_stop(&sc->sc_rx_ch);
@@ -1581,12 +1639,12 @@
__func__, sc->sc_rxptr, rxcomp);
#endif
GEM_CDSYNC(sc, BUS_DMASYNC_POSTREAD);
- for (i = sc->sc_rxptr; i != rxcomp;
- i = GEM_NEXTRX(i)) {
- rxs = &sc->sc_rxsoft[i];
+ for (; sc->sc_rxptr != rxcomp;
+ sc->sc_rxptr = GEM_NEXTRX(sc->sc_rxptr)) {
+ m = sc->sc_rxsoft[sc->sc_rxptr].rxs_mbuf;
+ rxstat = GEM_DMA_READ(sc,
+ sc->sc_rxdescs[sc->sc_rxptr].gd_flags);
- rxstat = GEM_DMA_READ(sc, sc->sc_rxdescs[i].gd_flags);
-
if (rxstat & GEM_RD_OWN) {
#ifdef GEM_RINT_TIMEOUT
/*
@@ -1600,49 +1658,67 @@
callout_reset(&sc->sc_rx_ch, GEM_RXOWN_TICKS,
gem_rint_timeout, sc);
#endif
- break;
+ m = NULL;
+ goto kickit;
}
- progress++;
- ifp->if_ipackets++;
-
if (rxstat & GEM_RD_BAD_CRC) {
ifp->if_ierrors++;
device_printf(sc->sc_dev, "receive error: CRC error\n");
- GEM_INIT_RXDESC(sc, i);
- continue;
+ GEM_INIT_RXDESC(sc, sc->sc_rxptr);
+ m = NULL;
+ goto kickit;
}
#ifdef GEM_DEBUG
if (ifp->if_flags & IFF_DEBUG) {
- printf(" rxsoft %p descriptor %d: ", rxs, i);
+ printf(" rxsoft %p descriptor %d: ",
+ &sc->sc_rxsoft[sc->sc_rxptr], sc->sc_rxptr);
printf("gd_flags: 0x%016llx\t", (long long)
- GEM_DMA_READ(sc, sc->sc_rxdescs[i].gd_flags));
+ GEM_DMA_READ(sc, sc->sc_rxdescs[
+ sc->sc_rxptr].gd_flags));
printf("gd_addr: 0x%016llx\n", (long long)
- GEM_DMA_READ(sc, sc->sc_rxdescs[i].gd_addr));
+ GEM_DMA_READ(sc, sc->sc_rxdescs[
+ sc->sc_rxptr].gd_addr));
}
#endif
/*
- * No errors; receive the packet.
- */
- len = GEM_RD_BUFLEN(rxstat);
-
- /*
* Allocate a new mbuf cluster. If that fails, we are
* out of memory, and must drop the packet and recycle
* the buffer that's already attached to this descriptor.
*/
- m = rxs->rxs_mbuf;
- if (gem_add_rxbuf(sc, i) != 0) {
+ if (gem_add_rxbuf(sc, sc->sc_rxptr) != 0) {
ifp->if_ierrors++;
- GEM_INIT_RXDESC(sc, i);
+ GEM_INIT_RXDESC(sc, sc->sc_rxptr);
+ m = NULL;
+ goto kickit;
+ }
+
+kickit:
+ /*
+ * Update the RX kick register. This register has to point
+ * to the descriptor after the last valid one and must be
+ * incremented in multiples of 4 (because the DMA engine
+ * fetches/updates 4 descriptors at a time).
+ */
+ if ((sc->sc_rxptr % 4) == 0) {
+ GEM_CDSYNC(sc, BUS_DMASYNC_PREWRITE);
+ bus_write_4(sc->sc_res[0], GEM_RX_KICK,
+ (sc->sc_rxptr + GEM_NRXDESC - 4) &
+ GEM_NRXDESC_MASK);
+ }
+
+ if (m == NULL) {
+ if (rxstat & GEM_RD_OWN)
+ break;
continue;
}
+
+ ifp->if_ipackets++;
m->m_data += 2; /* We're already off by two */
-
m->m_pkthdr.rcvif = ifp;
- m->m_pkthdr.len = m->m_len = len;
+ m->m_pkthdr.len = m->m_len = GEM_RD_BUFLEN(rxstat);
if ((ifp->if_capenable & IFCAP_RXCSUM) != 0)
gem_rxcksum(m, rxstat);
@@ -1653,16 +1729,6 @@
GEM_LOCK(sc);
}
- if (progress) {
- GEM_CDSYNC(sc, BUS_DMASYNC_PREWRITE);
- /* Update the receive pointer. */
- if (i == sc->sc_rxptr) {
- device_printf(sc->sc_dev, "rint: ring wrap\n");
- }
- sc->sc_rxptr = i;
- bus_write_4(sc->sc_res[0], GEM_RX_KICK, GEM_PREVRX(i));
- }
-
#ifdef GEM_DEBUG
CTR3(KTR_GEM, "%s: done sc->rxptr %d, complete %d", __func__,
sc->sc_rxptr, bus_read_4(sc->sc_res[0], GEM_RX_COMPLETION));
@@ -1701,8 +1767,6 @@
bus_dmamap_unload(sc->sc_rdmatag, rxs->rxs_dmamap);
}
- rxs->rxs_mbuf = m;
-
error = bus_dmamap_load_mbuf_sg(sc->sc_rdmatag, rxs->rxs_dmamap,
m, segs, &nsegs, BUS_DMA_NOWAIT);
/* If nsegs is wrong then the stack is corrupt. */
@@ -1713,6 +1777,7 @@
m_freem(m);
return (ENOBUFS);
}
+ rxs->rxs_mbuf = m;
rxs->rxs_paddr = segs[0].ds_addr;
bus_dmamap_sync(sc->sc_rdmatag, rxs->rxs_dmamap, BUS_DMASYNC_PREREAD);
@@ -1730,20 +1795,40 @@
{
if ((status & GEM_INTR_MIF) != 0) {
- device_printf(sc->sc_dev, "XXXlink status changed\n");
+ device_printf(sc->sc_dev, "%s: XXXlink status changed\n",
+ __func__);
+ return;
+ }
+
+ if ((status & GEM_INTR_RX_TAG_ERR) != 0) {
+ gem_reset_rxdma(sc);
return;
}
- device_printf(sc->sc_dev, "status=%x\n", status);
+ device_printf(sc->sc_dev, "%s: status=%x\n",__func__, status);
}
+/*
+ * PCS interrupt
+ */
+static void
+gem_pint(struct gem_softc *sc)
+{
+ uint32_t status;
+ status = bus_read_4(sc->sc_res[0], GEM_MII_INTERRUP_STATUS);
+ status |= bus_read_4(sc->sc_res[0], GEM_MII_INTERRUP_STATUS);
+ if ((status & GEM_MII_INTERRUP_LINK) != 0)
+ device_printf(sc->sc_dev, "%s: link status changed\n",
+ __func__);
+}
+
void
gem_intr(v)
void *v;
{
struct gem_softc *sc = (struct gem_softc *)v;
- u_int32_t status;
+ uint32_t rxstat, status, txstat;
GEM_LOCK(sc);
status = bus_read_4(sc->sc_res[0], GEM_STATUS);
@@ -1752,19 +1837,20 @@
device_get_name(sc->sc_dev), __func__, (status>>19),
(u_int)status);
#endif
+ if ((status & GEM_INTR_PCS) != 0)
+ gem_pint(sc);
- if ((status & (GEM_INTR_RX_TAG_ERR | GEM_INTR_BERR)) != 0)
+ if ((status & GEM_INTR_ERROR) != 0)
gem_eint(sc, status);
+ if ((status & (GEM_INTR_RX_DONE | GEM_INTR_RX_NOBUF)) != 0)
+ gem_rint(sc);
+
if ((status & (GEM_INTR_TX_EMPTY | GEM_INTR_TX_INTME)) != 0)
gem_tint(sc);
- if ((status & (GEM_INTR_RX_DONE | GEM_INTR_RX_NOBUF)) != 0)
- gem_rint(sc);
-
- /* We should eventually do more than just print out error stats. */
if (status & GEM_INTR_TX_MAC) {
- int txstat = bus_read_4(sc->sc_res[0], GEM_MAC_TX_STATUS);
+ txstat = bus_read_4(sc->sc_res[0], GEM_MAC_TX_STATUS);
if (txstat & ~GEM_MAC_TX_XMIT_DONE)
device_printf(sc->sc_dev, "MAC tx fault, status %x\n",
txstat);
@@ -1772,16 +1858,22 @@
gem_init_locked(sc);
}
if (status & GEM_INTR_RX_MAC) {
- int rxstat = bus_read_4(sc->sc_res[0], GEM_MAC_RX_STATUS);
+ rxstat = bus_read_4(sc->sc_res[0], GEM_MAC_RX_STATUS);
/*
- * On some chip revisions GEM_MAC_RX_OVERFLOW happen often
- * due to a silicon bug so handle them silently.
+ * At least with GEM_SUN_GEM and some GEM_SUN_ERI
+ * revisions GEM_MAC_RX_OVERFLOW happen often due to a
+ * silicon bug so handle them silently. Moreover, it's
+ * likely that the receiver has hung so we reset it.
*/
- if (rxstat & GEM_MAC_RX_OVERFLOW)
- gem_init_locked(sc);
+ if (rxstat & GEM_MAC_RX_OVERFLOW) {
+ sc->sc_ifp->if_ierrors++;
+ gem_reset_rxdma(sc);
+ }
+#ifdef GEM_DEBUG
else if (rxstat & ~(GEM_MAC_RX_DONE | GEM_MAC_RX_FRAME_CNT))
device_printf(sc->sc_dev, "MAC rx fault, status %x\n",
rxstat);
+#endif
}
GEM_UNLOCK(sc);
}
@@ -1826,9 +1918,8 @@
{
/* Configure the MIF in frame mode */
- sc->sc_mif_config = bus_read_4(sc->sc_res[0], GEM_MIF_CONFIG);
- sc->sc_mif_config &= ~GEM_MIF_CONFIG_BB_ENA;
- bus_write_4(sc->sc_res[0], GEM_MIF_CONFIG, sc->sc_mif_config);
+ bus_write_4(sc->sc_res[0], GEM_MIF_CONFIG, bus_read_4(sc->sc_res[0],
+ GEM_MIF_CONFIG) & ~GEM_MIF_CONFIG_BB_ENA);
}
/*
@@ -1855,23 +1946,38 @@
u_int32_t v;
#ifdef GEM_DEBUG_PHY
- printf("gem_mii_readreg: phy %d reg %d\n", phy, reg);
+ printf("%s: phy %d reg %d\n", __func__, phy, reg);
#endif
-#if 0
- /* Select the desired PHY in the MIF configuration register */
- v = bus_read_4(sc->sc_res[0], GEM_MIF_CONFIG);
- /* Clear PHY select bit */
- v &= ~GEM_MIF_CONFIG_PHY_SEL;
- if (phy == GEM_PHYAD_EXTERNAL)
- /* Set PHY select bit to get at external device */
- v |= GEM_MIF_CONFIG_PHY_SEL;
- bus_write_4(sc->sc_res[0], GEM_MIF_CONFIG, v);
-#endif
+ if (sc->sc_phyad != -1 && phy != sc->sc_phyad)
+ return (0);
+
+ if ((sc->sc_flags & GEM_SERDES) != 0) {
+ switch (reg) {
+ case MII_BMCR:
+ reg = GEM_MII_CONTROL;
+ break;
+ case MII_BMSR:
+ reg = GEM_MII_STATUS;
+ break;
+ case MII_ANAR:
+ reg = GEM_MII_ANAR;
+ break;
+ case MII_ANLPAR:
+ reg = GEM_MII_ANLPAR;
+ break;
+ case MII_EXTSR:
+ return (EXTSR_1000XFDX | EXTSR_1000XHDX);
+ default:
+ return (0);
+ }
+ return (bus_read_4(sc->sc_res[0], reg));
+ }
/* Construct the frame command */
- v = (reg << GEM_MIF_REG_SHIFT) | (phy << GEM_MIF_PHY_SHIFT) |
- GEM_MIF_FRAME_READ;
+ v = GEM_MIF_FRAME_READ |
+ (phy << GEM_MIF_PHY_SHIFT) |
+ (reg << GEM_MIF_REG_SHIFT);
bus_write_4(sc->sc_res[0], GEM_MIF_FRAME, v);
for (n = 0; n < 100; n++) {
@@ -1895,23 +2001,43 @@
u_int32_t v;
#ifdef GEM_DEBUG_PHY
- printf("gem_mii_writereg: phy %d reg %d val %x\n", phy, reg, val);
+ printf("%s: phy %d reg %d val %x\n", phy, reg, val, __func__);
#endif
-#if 0
- /* Select the desired PHY in the MIF configuration register */
- v = bus_read_4(sc->sc_res[0], GEM_MIF_CONFIG);
- /* Clear PHY select bit */
- v &= ~GEM_MIF_CONFIG_PHY_SEL;
- if (phy == GEM_PHYAD_EXTERNAL)
- /* Set PHY select bit to get at external device */
- v |= GEM_MIF_CONFIG_PHY_SEL;
- bus_write_4(sc->sc_res[0], GEM_MIF_CONFIG, v);
-#endif
+ if (sc->sc_phyad != -1 && phy != sc->sc_phyad)
+ return (0);
+
+ if ((sc->sc_flags & GEM_SERDES) != 0) {
+ switch (reg) {
+ case MII_BMCR:
+ reg = GEM_MII_CONTROL;
+ break;
+ case MII_BMSR:
+ reg = GEM_MII_STATUS;
+ break;
+ case MII_ANAR:
+ reg = GEM_MII_ANAR;
+ break;
+ case MII_ANLPAR:
+ reg = GEM_MII_ANLPAR;
+ break;
+ default:
+ return (0);
+ }
+ bus_write_4(sc->sc_res[0], reg, val);
+ if (reg == GEM_MII_ANAR) {
+ bus_write_4(sc->sc_res[0], GEM_MII_SLINK_CONTROL,
+ GEM_MII_SLINK_LOOPBACK | GEM_MII_SLINK_EN_SYNC_D);
+ bus_write_4(sc->sc_res[0], GEM_MII_CONFIG,
+ GEM_MII_CONFIG_ENABLE);
+ }
+ return (0);
+ }
+
/* Construct the frame command */
- v = GEM_MIF_FRAME_WRITE |
- (phy << GEM_MIF_PHY_SHIFT) |
- (reg << GEM_MIF_REG_SHIFT) |
+ v = GEM_MIF_FRAME_WRITE |
+ (phy << GEM_MIF_PHY_SHIFT) |
+ (reg << GEM_MIF_REG_SHIFT) |
(val & GEM_MIF_FRAME_DATA);
bus_write_4(sc->sc_res[0], GEM_MIF_FRAME, v);
@@ -1931,35 +2057,49 @@
device_t dev;
{
struct gem_softc *sc = device_get_softc(dev);
+ int gigabit;
+ uint32_t rxcfg, txcfg, v;
+
#ifdef GEM_DEBUG
- int instance;
+ if ((sc->sc_ifflags & IFF_DEBUG) != 0)
+ device_printf(sc->sc_dev, "%s: status change: PHY = %d\n",
+ __func__, sc->sc_phyad);
#endif
- u_int32_t v;
-#ifdef GEM_DEBUG
- instance = IFM_INST(sc->sc_mii->mii_media.ifm_cur->ifm_media);
- if (sc->sc_debug)
- printf("gem_mii_statchg: status change: phy = %d\n",
- sc->sc_phys[instance]);
-#endif
+ switch (IFM_SUBTYPE(sc->sc_mii->mii_media_active)) {
+ case IFM_1000_SX:
+ case IFM_1000_LX:
+ case IFM_1000_CX:
+ case IFM_1000_T:
+ gigabit = 1;
+ break;
+ default:
+ gigabit = 0;
+ }
/* Set tx full duplex options */
bus_write_4(sc->sc_res[0], GEM_MAC_TX_CONFIG, 0);
DELAY(10000); /* reg must be cleared and delay before changing. */
- v = GEM_MAC_TX_ENA_IPG0|GEM_MAC_TX_NGU|GEM_MAC_TX_NGU_LIMIT|
- GEM_MAC_TX_ENABLE;
- if ((IFM_OPTIONS(sc->sc_mii->mii_media_active) & IFM_FDX) != 0) {
- v |= GEM_MAC_TX_IGN_CARRIER|GEM_MAC_TX_IGN_COLLIS;
+ rxcfg = bus_read_4(sc->sc_res[0], GEM_MAC_RX_CONFIG);
+ rxcfg &= ~GEM_MAC_RX_CARR_EXTEND;
+ txcfg = GEM_MAC_TX_ENA_IPG0 | GEM_MAC_TX_NGU | GEM_MAC_TX_NGU_LIMIT |
+ GEM_MAC_TX_ENABLE;
+ if ((IFM_OPTIONS(sc->sc_mii->mii_media_active) & IFM_FDX) != 0)
+ txcfg |= GEM_MAC_TX_IGN_CARRIER | GEM_MAC_TX_IGN_COLLIS;
+ else if (gigabit != 0) {
+ rxcfg |= GEM_MAC_RX_CARR_EXTEND;
+ txcfg |= GEM_MAC_TX_CARR_EXTEND;
}
- bus_write_4(sc->sc_res[0], GEM_MAC_TX_CONFIG, v);
+ bus_write_4(sc->sc_res[0], GEM_MAC_RX_CONFIG, rxcfg);
+ bus_write_4(sc->sc_res[0], GEM_MAC_TX_CONFIG, txcfg);
/* XIF Configuration */
v = GEM_MAC_XIF_LINK_LED;
v |= GEM_MAC_XIF_TX_MII_ENA;
/* If an external transceiver is connected, enable its MII drivers */
- sc->sc_mif_config = bus_read_4(sc->sc_res[0], GEM_MIF_CONFIG);
- if ((sc->sc_mif_config & GEM_MIF_CONFIG_MDI1) != 0) {
+ if ((bus_read_4(sc->sc_res[0], GEM_MIF_CONFIG) &
+ GEM_MIF_CONFIG_MDI1) != 0) {
/* External MII needs echo disable if half duplex. */
if ((IFM_OPTIONS(sc->sc_mii->mii_media_active) & IFM_FDX) != 0)
>>> TRUNCATED FOR MAIL (1000 lines) <<<
More information about the p4-projects
mailing list