Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 2 Jan 2012 23:38:03 +0000 (UTC)
From:      Pyun YongHyeon <yongari@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org
Subject:   svn commit: r229337 - in stable/8/sys: conf dev/dc
Message-ID:  <201201022338.q02Nc3gQ093746@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: yongari
Date: Mon Jan  2 23:38:03 2012
New Revision: 229337
URL: http://svn.freebsd.org/changeset/base/229337

Log:
  MFC r226701:
    Add support for ALi/ULi, now NVIDIA, M5261/M5263 PCI FastEthernet
    controller which is found on ULi M1563 South Bridge & M1689 Bridge.
    These controllers look like a tulip clone.
    M5263 controller does not support MII bitbang so use DC_ROM
    register to access MII registers.  Like other tulip variants, ULi
    controller uses a setup frame to configure RX filter and uses new
    setup frame format.  It's not clear to me whether the controller
    supports a hash based multicast filtering so this patch uses 14
    perfect multicast filter to filter multicast frames.  If number of
    multicast addresses is greater than 14, controller is put into a
    mode that receives all multicast frames.
    Due to lack of access to M5261, this change was not tested with
    M5261 but it probably works.  Many thanks to Marco who provided
    remote access to M5263.
  
    Tested by:	Marco Steinbach <coco <> executive-computing dot de>,
  		Martin MATO <martin.mato <> orange dot fr>

Modified:
  stable/8/sys/dev/dc/if_dc.c
  stable/8/sys/dev/dc/if_dcreg.h
Directory Properties:
  stable/8/sys/   (props changed)
  stable/8/sys/amd64/include/xen/   (props changed)
  stable/8/sys/cddl/contrib/opensolaris/   (props changed)
  stable/8/sys/conf/ldscript.mips.octeon1.32   (props changed)
  stable/8/sys/conf/ldscript.mips.octeon1.64   (props changed)
  stable/8/sys/contrib/dev/acpica/   (props changed)
  stable/8/sys/contrib/pf/   (props changed)

Modified: stable/8/sys/dev/dc/if_dc.c
==============================================================================
--- stable/8/sys/dev/dc/if_dc.c	Mon Jan  2 23:35:18 2012	(r229336)
+++ stable/8/sys/dev/dc/if_dc.c	Mon Jan  2 23:38:03 2012	(r229337)
@@ -225,6 +225,10 @@ static const struct dc_type const dc_dev
 		"Linksys PCMPC200 CardBus 10/100" },
 	{ DC_DEVID(DC_VENDORID_LINKSYS, DC_DEVICEID_PCMPC200_AB09), 0,
 		"Linksys PCMPC200 CardBus 10/100" },
+	{ DC_DEVID(DC_VENDORID_ULI, DC_DEVICEID_M5261), 0,
+		"ULi M5261 FastEthernet" },
+	{ DC_DEVID(DC_VENDORID_ULI, DC_DEVICEID_M5263), 0,
+		"ULi M5263 FastEthernet" },
 	{ 0, 0, NULL }
 };
 
@@ -281,6 +285,7 @@ static uint32_t dc_mchash_be(const uint8
 static void dc_setfilt_21143(struct dc_softc *);
 static void dc_setfilt_asix(struct dc_softc *);
 static void dc_setfilt_admtek(struct dc_softc *);
+static void dc_setfilt_uli(struct dc_softc *);
 static void dc_setfilt_xircom(struct dc_softc *);
 
 static void dc_setfilt(struct dc_softc *);
@@ -701,6 +706,23 @@ dc_miibus_readreg(device_t dev, int phy,
 		return (0);
 	}
 
+	if (sc->dc_type == DC_TYPE_ULI_M5263) {
+		CSR_WRITE_4(sc, DC_ROM,
+		    ((phy << DC_ULI_PHY_ADDR_SHIFT) & DC_ULI_PHY_ADDR_MASK) |
+		    ((reg << DC_ULI_PHY_REG_SHIFT) & DC_ULI_PHY_REG_MASK) |
+		    DC_ULI_PHY_OP_READ);
+		for (i = 0; i < DC_TIMEOUT; i++) {
+			DELAY(1);
+			rval = CSR_READ_4(sc, DC_ROM);
+			if ((rval & DC_ULI_PHY_OP_DONE) != 0) {
+				return (rval & DC_ULI_PHY_DATA_MASK);
+			}
+		}
+		if (i == DC_TIMEOUT)
+			device_printf(dev, "phy read timed out\n");
+		return (0);
+	}
+
 	if (DC_IS_COMET(sc)) {
 		switch (reg) {
 		case MII_BMCR:
@@ -766,6 +788,16 @@ dc_miibus_writereg(device_t dev, int phy
 		return (0);
 	}
 
+	if (sc->dc_type == DC_TYPE_ULI_M5263) {
+		CSR_WRITE_4(sc, DC_ROM,
+		    ((phy << DC_ULI_PHY_ADDR_SHIFT) & DC_ULI_PHY_ADDR_MASK) |
+		    ((reg << DC_ULI_PHY_REG_SHIFT) & DC_ULI_PHY_REG_MASK) |
+		    ((data << DC_ULI_PHY_DATA_SHIFT) & DC_ULI_PHY_DATA_MASK) |
+		    DC_ULI_PHY_OP_WRITE);
+		DELAY(1);
+		return (0);
+	}
+
 	if (DC_IS_COMET(sc)) {
 		switch (reg) {
 		case MII_BMCR:
@@ -1149,6 +1181,97 @@ dc_setfilt_asix(struct dc_softc *sc)
 }
 
 static void
+dc_setfilt_uli(struct dc_softc *sc)
+{
+	uint8_t eaddr[ETHER_ADDR_LEN];
+	struct ifnet *ifp;
+	struct ifmultiaddr *ifma;
+	struct dc_desc *sframe;
+	uint32_t filter, *sp;
+	uint8_t *ma;
+	int i, mcnt;
+
+	ifp = sc->dc_ifp;
+
+	i = sc->dc_cdata.dc_tx_prod;
+	DC_INC(sc->dc_cdata.dc_tx_prod, DC_TX_LIST_CNT);
+	sc->dc_cdata.dc_tx_cnt++;
+	sframe = &sc->dc_ldata.dc_tx_list[i];
+	sp = sc->dc_cdata.dc_sbuf;
+	bzero(sp, DC_SFRAME_LEN);
+
+	sframe->dc_data = htole32(DC_ADDR_LO(sc->dc_saddr));
+	sframe->dc_ctl = htole32(DC_SFRAME_LEN | DC_TXCTL_SETUP |
+	    DC_TXCTL_TLINK | DC_FILTER_PERFECT | DC_TXCTL_FINT);
+
+	sc->dc_cdata.dc_tx_chain[i] = (struct mbuf *)sc->dc_cdata.dc_sbuf;
+
+	/* Set station address. */
+	bcopy(IF_LLADDR(sc->dc_ifp), eaddr, ETHER_ADDR_LEN);
+	*sp++ = DC_SP_MAC(eaddr[1] << 8 | eaddr[0]);
+	*sp++ = DC_SP_MAC(eaddr[3] << 8 | eaddr[2]);
+	*sp++ = DC_SP_MAC(eaddr[5] << 8 | eaddr[4]);
+
+	/* Set broadcast address. */
+	*sp++ = DC_SP_MAC(0xFFFF);
+	*sp++ = DC_SP_MAC(0xFFFF);
+	*sp++ = DC_SP_MAC(0xFFFF);
+
+	/* Extract current filter configuration. */
+	filter = CSR_READ_4(sc, DC_NETCFG);
+	filter &= ~(DC_NETCFG_RX_PROMISC | DC_NETCFG_RX_ALLMULTI);
+
+	/* Now build perfect filters. */
+	mcnt = 0;
+	if_maddr_rlock(ifp);
+	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
+		if (ifma->ifma_addr->sa_family != AF_LINK)
+			continue;
+		if (mcnt >= DC_ULI_FILTER_NPERF) {
+			filter |= DC_NETCFG_RX_ALLMULTI;
+			break;
+		}
+		ma = LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
+		*sp++ = DC_SP_MAC(ma[1] << 8 | ma[0]);
+		*sp++ = DC_SP_MAC(ma[3] << 8 | ma[2]);
+		*sp++ = DC_SP_MAC(ma[5] << 8 | ma[4]);
+		mcnt++;
+	}
+	if_maddr_runlock(ifp);
+
+	for (; mcnt < DC_ULI_FILTER_NPERF; mcnt++) {
+		*sp++ = DC_SP_MAC(0xFFFF);
+		*sp++ = DC_SP_MAC(0xFFFF);
+		*sp++ = DC_SP_MAC(0xFFFF);
+	}
+
+	if (filter & (DC_NETCFG_TX_ON | DC_NETCFG_RX_ON))
+		CSR_WRITE_4(sc, DC_NETCFG,
+		    filter & ~(DC_NETCFG_TX_ON | DC_NETCFG_RX_ON));
+	if (ifp->if_flags & IFF_PROMISC)
+		filter |= DC_NETCFG_RX_PROMISC | DC_NETCFG_RX_ALLMULTI;
+	if (ifp->if_flags & IFF_ALLMULTI)
+		filter |= DC_NETCFG_RX_ALLMULTI;
+	CSR_WRITE_4(sc, DC_NETCFG,
+	    filter & ~(DC_NETCFG_TX_ON | DC_NETCFG_RX_ON));
+	if (filter & (DC_NETCFG_TX_ON | DC_NETCFG_RX_ON))
+		CSR_WRITE_4(sc, DC_NETCFG, filter);
+
+	sframe->dc_status = htole32(DC_TXSTAT_OWN);
+	bus_dmamap_sync(sc->dc_tx_ltag, sc->dc_tx_lmap, BUS_DMASYNC_PREREAD |
+	    BUS_DMASYNC_PREWRITE);
+	bus_dmamap_sync(sc->dc_stag, sc->dc_smap, BUS_DMASYNC_PREWRITE);
+	CSR_WRITE_4(sc, DC_TXSTART, 0xFFFFFFFF);
+
+	/*
+	 * Wait some time...
+	 */
+	DELAY(1000);
+
+	sc->dc_wdog_timer = 5;
+}
+
+static void
 dc_setfilt_xircom(struct dc_softc *sc)
 {
 	uint16_t eaddr[(ETHER_ADDR_LEN+1)/2];
@@ -1236,6 +1359,9 @@ dc_setfilt(struct dc_softc *sc)
 	if (DC_IS_ADMTEK(sc))
 		dc_setfilt_admtek(sc);
 
+	if (DC_IS_ULI(sc))
+		dc_setfilt_uli(sc);
+
 	if (DC_IS_XIRCOM(sc))
 		dc_setfilt_xircom(sc);
 }
@@ -1404,7 +1530,7 @@ dc_reset(struct dc_softc *sc)
 	}
 
 	if (DC_IS_ASIX(sc) || DC_IS_ADMTEK(sc) || DC_IS_CONEXANT(sc) ||
-	    DC_IS_XIRCOM(sc) || DC_IS_INTEL(sc)) {
+	    DC_IS_XIRCOM(sc) || DC_IS_INTEL(sc) || DC_IS_ULI(sc)) {
 		DELAY(10000);
 		DC_CLRBIT(sc, DC_BUSCTL, DC_BUSCTL_RESET);
 		i = 0;
@@ -1616,7 +1742,7 @@ dc_read_srom(struct dc_softc *sc, int bi
 	int size;
 
 	size = DC_ROM_SIZE(bits);
-	sc->dc_srom = malloc(size, M_DEVBUF, M_NOWAIT);
+	sc->dc_srom = malloc(size, M_DEVBUF, M_NOWAIT | M_ZERO);
 	if (sc->dc_srom == NULL) {
 		device_printf(sc->dc_dev, "Could not allocate SROM buffer\n");
 		return (ENOMEM);
@@ -1910,7 +2036,8 @@ dc_attach(device_t dev)
 	struct ifnet *ifp;
 	struct dc_mediainfo *m;
 	uint32_t reg, revision;
-	int error, mac_offset, phy, rid, tmp;
+	uint16_t *srom;
+	int error, mac_offset, n, phy, rid, tmp;
 	uint8_t *mac;
 
 	sc = device_get_softc(dev);
@@ -2090,6 +2217,21 @@ dc_attach(device_t dev)
 		if (error != 0)
 			goto fail;
 		break;
+	case DC_DEVID(DC_VENDORID_ULI, DC_DEVICEID_M5261):
+	case DC_DEVID(DC_VENDORID_ULI, DC_DEVICEID_M5263):
+		if (sc->dc_info->dc_devid ==
+		    DC_DEVID(DC_VENDORID_ULI, DC_DEVICEID_M5261))
+			sc->dc_type = DC_TYPE_ULI_M5261;
+		else
+			sc->dc_type = DC_TYPE_ULI_M5263;
+		/* TX buffers should be aligned on 4 byte boundary. */
+		sc->dc_flags |= DC_TX_INTR_ALWAYS | DC_TX_COALESCE |
+		    DC_TX_ALIGN;
+		sc->dc_pmode = DC_PMODE_MII;
+		error = dc_read_srom(sc, sc->dc_romwidth);
+		if (error != 0)
+			goto fail;
+		break;
 	default:
 		device_printf(dev, "unknown device: %x\n",
 		    sc->dc_info->dc_devid);
@@ -2187,6 +2329,33 @@ dc_attach(device_t dev)
 		}
 		bcopy(mac, eaddr, ETHER_ADDR_LEN);
 		break;
+	case DC_TYPE_ULI_M5261:
+	case DC_TYPE_ULI_M5263:
+		srom = (uint16_t *)sc->dc_srom;
+		if (srom == NULL || *srom == 0xFFFF || *srom == 0) {
+			/*
+			 * No valid SROM present, read station address
+			 * from ID Table.
+			 */
+			device_printf(dev,
+			    "Reading station address from ID Table.\n");
+			CSR_WRITE_4(sc, DC_BUSCTL, 0x10000);
+			CSR_WRITE_4(sc, DC_SIARESET, 0x01C0);
+			CSR_WRITE_4(sc, DC_10BTCTRL, 0x0000);
+			CSR_WRITE_4(sc, DC_10BTCTRL, 0x0010);
+			CSR_WRITE_4(sc, DC_10BTCTRL, 0x0000);
+			CSR_WRITE_4(sc, DC_SIARESET, 0x0000);
+			CSR_WRITE_4(sc, DC_SIARESET, 0x01B0);
+			mac = (uint8_t *)eaddr;
+			for (n = 0; n < ETHER_ADDR_LEN; n++)
+				mac[n] = (uint8_t)CSR_READ_4(sc, DC_10BTCTRL);
+			CSR_WRITE_4(sc, DC_SIARESET, 0x0000);
+			CSR_WRITE_4(sc, DC_BUSCTL, 0x0000);
+			DELAY(10);
+		} else
+			dc_read_eeprom(sc, (caddr_t)&eaddr, DC_EE_NODEADDR, 3,
+			    0);
+		break;
 	default:
 		dc_read_eeprom(sc, (caddr_t)&eaddr, DC_EE_NODEADDR, 3, 0);
 		break;
@@ -3463,7 +3632,7 @@ dc_init_locked(struct dc_softc *sc)
 	/*
 	 * Set cache alignment and burst length.
 	 */
-	if (DC_IS_ASIX(sc) || DC_IS_DAVICOM(sc))
+	if (DC_IS_ASIX(sc) || DC_IS_DAVICOM(sc) || DC_IS_ULI(sc))
 		CSR_WRITE_4(sc, DC_BUSCTL, 0);
 	else
 		CSR_WRITE_4(sc, DC_BUSCTL, DC_BUSCTL_MRME | DC_BUSCTL_MRLE);
@@ -3576,6 +3745,11 @@ dc_init_locked(struct dc_softc *sc)
 	CSR_WRITE_4(sc, DC_IMR, DC_INTRS);
 	CSR_WRITE_4(sc, DC_ISR, 0xFFFFFFFF);
 
+	/* Initialize TX jabber and RX watchdog timer. */
+	if (DC_IS_ULI(sc))
+		CSR_WRITE_4(sc, DC_WATCHDOG, DC_WDOG_JABBERCLK |
+		    DC_WDOG_HOSTUNJAB);
+
 	/* Enable transmitter. */
 	DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_TX_ON);
 

Modified: stable/8/sys/dev/dc/if_dcreg.h
==============================================================================
--- stable/8/sys/dev/dc/if_dcreg.h	Mon Jan  2 23:35:18 2012	(r229336)
+++ stable/8/sys/dev/dc/if_dcreg.h	Mon Jan  2 23:38:03 2012	(r229337)
@@ -78,6 +78,8 @@
 #define	DC_TYPE_PNIC		0xA	/* 82c168/82c169 PNIC I */
 #define	DC_TYPE_XIRCOM		0xB	/* Xircom X3201 */
 #define	DC_TYPE_CONEXANT	0xC	/* Conexant LANfinity RS7112 */
+#define	DC_TYPE_ULI_M5261	0xD	/* ALi/ULi M5261 */
+#define	DC_TYPE_ULI_M5263	0xE	/* ALi/ULi M5263 */
 
 #define	DC_IS_MACRONIX(x)			\
 	(x->dc_type == DC_TYPE_98713 ||		\
@@ -88,6 +90,10 @@
 	(x->dc_type == DC_TYPE_AL981 ||		\
 	 x->dc_type == DC_TYPE_AN983)
 
+#define	DC_IS_ULI(x)				\
+	(x->dc_type == DC_TYPE_ULI_M5261 ||	\
+	 x->dc_type == DC_TYPE_ULI_M5263)
+
 #define	DC_IS_INTEL(x)		(x->dc_type == DC_TYPE_21143)
 #define	DC_IS_ASIX(x)		(x->dc_type == DC_TYPE_ASIX)
 #define	DC_IS_COMET(x)		(x->dc_type == DC_TYPE_AL981)
@@ -707,6 +713,23 @@ struct dc_type {
 
 /* End of CONEXANT specific registers */
 
+/*
+ * ULi M5263 specific registers.
+ */
+#define	DC_ULI_FILTER_NPERF	14
+
+#define	DC_ULI_PHY_DATA_MASK	0x0000FFFF
+#define	DC_ULI_PHY_REG_MASK	0x001F0000
+#define	DC_ULI_PHY_ADDR_MASK	0x03E00000
+#define	DC_ULI_PHY_OP_WRITE	0x04000000
+#define	DC_ULI_PHY_OP_READ	0x08000000
+#define	DC_ULI_PHY_OP_DONE	0x10000000
+
+#define	DC_ULI_PHY_DATA_SHIFT	0
+#define	DC_ULI_PHY_REG_SHIFT	16
+#define	DC_ULI_PHY_ADDR_SHIFT	21
+
+/* End of ULi M5263 specific registers */
 
 struct dc_softc {
 	struct ifnet		*dc_ifp;	/* interface info */
@@ -1014,6 +1037,17 @@ struct dc_softc {
 #define	DC_DEVICEID_PCMPC200_AB08	0xab08
 #define	DC_DEVICEID_PCMPC200_AB09	0xab09
 
+/*
+ * ULi vendor ID.
+ */
+#define	DC_VENDORID_ULI		0x10b9
+
+/*
+ * ULi device IDs.
+ */
+#define	DC_DEVICEID_M5261	0x5261
+#define	DC_DEVICEID_M5263	0x5263
+
 #define	DC_DEVID(vendor, device)	((device) << 16 | (vendor))
 
 /*



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201201022338.q02Nc3gQ093746>