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