From owner-svn-src-all@FreeBSD.ORG Mon Oct 24 20:48:02 2011 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 9EFF4106566C; Mon, 24 Oct 2011 20:48:02 +0000 (UTC) (envelope-from yongari@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 8E1368FC08; Mon, 24 Oct 2011 20:48:02 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.4/8.14.4) with ESMTP id p9OKm2EA062066; Mon, 24 Oct 2011 20:48:02 GMT (envelope-from yongari@svn.freebsd.org) Received: (from yongari@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id p9OKm21o062063; Mon, 24 Oct 2011 20:48:02 GMT (envelope-from yongari@svn.freebsd.org) Message-Id: <201110242048.p9OKm21o062063@svn.freebsd.org> From: Pyun YongHyeon Date: Mon, 24 Oct 2011 20:48:02 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r226701 - head/sys/dev/dc X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 24 Oct 2011 20:48:02 -0000 Author: yongari Date: Mon Oct 24 20:48:02 2011 New Revision: 226701 URL: http://svn.freebsd.org/changeset/base/226701 Log: 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 executive-computing dot de>, Martin MATO orange dot fr> Modified: head/sys/dev/dc/if_dc.c head/sys/dev/dc/if_dcreg.h Modified: head/sys/dev/dc/if_dc.c ============================================================================== --- head/sys/dev/dc/if_dc.c Mon Oct 24 20:41:31 2011 (r226700) +++ head/sys/dev/dc/if_dc.c Mon Oct 24 20:48:02 2011 (r226701) @@ -224,6 +224,10 @@ static const struct dc_type dc_devs[] = "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 } }; @@ -286,6 +290,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 *); @@ -828,6 +833,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: @@ -898,6 +920,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: @@ -1285,6 +1317,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]; @@ -1372,6 +1495,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); } @@ -1540,7 +1666,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; @@ -1752,7 +1878,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); @@ -2046,7 +2172,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); @@ -2226,6 +2353,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); @@ -2323,6 +2465,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; @@ -3599,7 +3768,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); @@ -3712,6 +3881,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: head/sys/dev/dc/if_dcreg.h ============================================================================== --- head/sys/dev/dc/if_dcreg.h Mon Oct 24 20:41:31 2011 (r226700) +++ head/sys/dev/dc/if_dcreg.h Mon Oct 24 20:48:02 2011 (r226701) @@ -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) @@ -725,6 +731,23 @@ struct dc_mii_frame { /* 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 */ @@ -1032,6 +1055,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)) /*