From owner-p4-projects@FreeBSD.ORG Wed Aug 29 05:51:06 2007 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id BFD6B16A421; Wed, 29 Aug 2007 05:51:05 +0000 (UTC) Delivered-To: perforce@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 932A316A41A for ; Wed, 29 Aug 2007 05:51:05 +0000 (UTC) (envelope-from marcel@freebsd.org) Received: from repoman.freebsd.org (repoman.freebsd.org [IPv6:2001:4f8:fff6::29]) by mx1.freebsd.org (Postfix) with ESMTP id 891F313C46A for ; Wed, 29 Aug 2007 05:51:05 +0000 (UTC) (envelope-from marcel@freebsd.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.1/8.14.1) with ESMTP id l7T5p5qa001650 for ; Wed, 29 Aug 2007 05:51:05 GMT (envelope-from marcel@freebsd.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.1/8.14.1/Submit) id l7T5p3TO001643 for perforce@freebsd.org; Wed, 29 Aug 2007 05:51:03 GMT (envelope-from marcel@freebsd.org) Date: Wed, 29 Aug 2007 05:51:03 GMT Message-Id: <200708290551.l7T5p3TO001643@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to marcel@freebsd.org using -f From: Marcel Moolenaar To: Perforce Change Reviews Cc: Subject: PERFORCE change 125801 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 29 Aug 2007 05:51:06 -0000 http://perforce.freebsd.org/chv.cgi?CH=125801 Change 125801 by marcel@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<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) <<<