diff --git a/sys/dev/ic/tulip.c b/sys/dev/ic/tulip.c index 47ae52f3d929..b6a3044415ba 100644 --- a/sys/dev/ic/tulip.c +++ b/sys/dev/ic/tulip.c @@ -1,4 +1,4 @@ -/* $NetBSD: tulip.c,v 1.136 2005/03/23 13:24:47 wiz Exp $ */ +/* $NetBSD: tulip.c,v 1.137 2005/06/23 23:51:41 rpaulo Exp $ */ /*- * Copyright (c) 1998, 1999, 2000, 2002 The NetBSD Foundation, Inc. @@ -43,7 +43,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: tulip.c,v 1.136 2005/03/23 13:24:47 wiz Exp $"); +__KERNEL_RCSID(0, "$NetBSD: tulip.c,v 1.137 2005/06/23 23:51:41 rpaulo Exp $"); #include "bpfilter.h" @@ -116,6 +116,7 @@ void tlp_power(int, void *); void tlp_filter_setup(struct tulip_softc *); void tlp_winb_filter_setup(struct tulip_softc *); void tlp_al981_filter_setup(struct tulip_softc *); +void tlp_asix_filter_setup(struct tulip_softc *); void tlp_rxintr(struct tulip_softc *); void tlp_txintr(struct tulip_softc *); @@ -141,6 +142,7 @@ void tlp_2114x_preinit(struct tulip_softc *); void tlp_2114x_mii_preinit(struct tulip_softc *); void tlp_pnic_preinit(struct tulip_softc *); void tlp_dm9102_preinit(struct tulip_softc *); +void tlp_asix_preinit(struct tulip_softc *); void tlp_21140_reset(struct tulip_softc *); void tlp_21142_reset(struct tulip_softc *); @@ -241,6 +243,11 @@ tlp_attach(sc, enaddr) sc->sc_filter_setup = tlp_al981_filter_setup; break; + case TULIP_CHIP_AX88140: + case TULIP_CHIP_AX88141: + sc->sc_filter_setup = tlp_asix_filter_setup; + break; + default: sc->sc_filter_setup = tlp_filter_setup; break; @@ -360,6 +367,16 @@ tlp_attach(sc, enaddr) sc->sc_txthresh = TXTH_DM9102_SF; break; + case TULIP_CHIP_AX88140: + case TULIP_CHIP_AX88141: + /* + * Run these chips in ring mode. + */ + sc->sc_tdctl_ch = 0; + sc->sc_tdctl_er = TDCTL_ER; + sc->sc_preinit = tlp_asix_preinit; + break; + default: /* * Default to running in ring mode. @@ -434,6 +451,8 @@ tlp_attach(sc, enaddr) case TULIP_CHIP_X3201_3: case TULIP_CHIP_DM9102: case TULIP_CHIP_DM9102A: + case TULIP_CHIP_AX88140: + case TULIP_CHIP_AX88141: sc->sc_ntxsegs = 1; break; @@ -1579,11 +1598,14 @@ tlp_reset(sc) TULIP_WRITE(sc, CSR_BUSMODE, BUSMODE_SWR); /* - * Xircom clone doesn't bring itself out of reset automatically. + * Xircom and ASIX clones don't bring themselves out of + * reset automatically. * Instead, we have to wait at least 50 PCI cycles, and then * clear SWR. */ - if (sc->sc_chip == TULIP_CHIP_X3201_3) { + if (sc->sc_chip == TULIP_CHIP_X3201_3 || + sc->sc_chip == TULIP_CHIP_AX88140 || + sc->sc_chip == TULIP_CHIP_AX88141) { delay(10); TULIP_WRITE(sc, CSR_BUSMODE, 0); } @@ -1684,6 +1706,12 @@ tlp_init(ifp) if (sc->sc_maxburst == 0) sc->sc_maxburst = 16; break; + + case TULIP_CHIP_AX88140: + case TULIP_CHIP_AX88141: + if (sc->sc_maxburst == 0) + sc->sc_maxburst = 16; + break; default: /* Nothing. */ @@ -1915,6 +1943,26 @@ tlp_init(ifp) reg = enaddr[4] | (enaddr[5] << 8); bus_space_write_4(sc->sc_st, sc->sc_sh, CSR_ADM_PAR1, reg); + break; + } + + case TULIP_CHIP_AX88140: + case TULIP_CHIP_AX88141: + { + u_int32_t reg; + u_int8_t *enaddr = LLADDR(ifp->if_sadl); + + reg = enaddr[0] | + (enaddr[1] << 8) | + (enaddr[2] << 16) | + (enaddr[3] << 24); + TULIP_WRITE(sc, CSR_AX_FILTIDX, AX_FILTIDX_PAR0); + TULIP_WRITE(sc, CSR_AX_FILTDATA, reg); + + reg = enaddr[4] | (enaddr[5] << 8); + TULIP_WRITE(sc, CSR_AX_FILTIDX, AX_FILTIDX_PAR1); + TULIP_WRITE(sc, CSR_AX_FILTDATA, reg); + break; } default: @@ -2979,6 +3027,78 @@ tlp_al981_filter_setup(sc) sc->sc_dev.dv_xname)); } +/* + * tlp_asix_filter_setup: + * + * Set the ASIX AX8814x recieve filter. + */ +void +tlp_asix_filter_setup(sc) + struct tulip_softc *sc; +{ + struct ethercom *ec = &sc->sc_ethercom; + struct ifnet *ifp = &sc->sc_ethercom.ec_if; + struct ether_multi *enm; + struct ether_multistep step; + u_int32_t hash, mchash[2]; + + DPRINTF(sc, ("%s: tlp_asix_filter_setup: sc_flags 0x%08x\n", + sc->sc_dev.dv_xname, sc->sc_flags)); + + sc->sc_opmode &= ~(OPMODE_PM|OPMODE_AX_RB|OPMODE_PR); + + if (ifp->if_flags & IFF_MULTICAST) + sc->sc_opmode |= OPMODE_PM; + + if (ifp->if_flags & IFF_BROADCAST) + sc->sc_opmode |= OPMODE_AX_RB; + + if (ifp->if_flags & IFF_PROMISC) { + sc->sc_opmode |= OPMODE_PR; + goto allmulti; + } + + mchash[0] = mchash[1] = 0; + + ETHER_FIRST_MULTI(step, ec, enm); + while (enm != NULL) { + if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) { + /* + * We must listen to a range of multicast addresses. + * For now, just accept all multicasts, rather than + * trying to set only those filter bits needed to match + * the range. (At this time, the only use of address + * ranges is for IP multicast routing, for which the + * range is big enough to require all bits set.) + */ + goto allmulti; + } + hash = (ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN) >> 26) + & 0x3f; + if (hash < 32) + mchash[0] |= (1 << hash); + else + mchash[1] |= (1 << (hash - 32)); + ETHER_NEXT_MULTI(step, enm); + } + ifp->if_flags &= ~IFF_ALLMULTI; + goto setit; + +allmulti: + ifp->if_flags |= IFF_ALLMULTI; + mchash[0] = mchash[1] = 0xffffffff; + +setit: + TULIP_WRITE(sc, CSR_AX_FILTIDX, AX_FILTIDX_MAR0); + TULIP_WRITE(sc, CSR_AX_FILTDATA, mchash[0]); + TULIP_WRITE(sc, CSR_AX_FILTIDX, AX_FILTIDX_MAR1); + TULIP_WRITE(sc, CSR_AX_FILTDATA, mchash[1]); + TULIP_WRITE(sc, CSR_OPMODE, sc->sc_opmode); + DPRINTF(sc, ("%s: tlp_asix_filter_setup: returning\n", + sc->sc_dev.dv_xname)); +} + + /* * tlp_idle: * @@ -3065,9 +3185,18 @@ tlp_idle(sc, bits) if ((csr & ackmask) != ackmask) { if ((bits & OPMODE_ST) != 0 && (csr & STATUS_TPS) == 0 && (csr & STATUS_TS) != STATUS_TS_STOPPED) { - printf("%s: transmit process failed to idle: " - "state %s\n", sc->sc_dev.dv_xname, - tx_state_names[(csr & STATUS_TS) >> 20]); + switch (sc->sc_chip) { + case TULIP_CHIP_AX88140: + case TULIP_CHIP_AX88141: + /* + * Filter the message out on noisy chips. + */ + break; + default: + printf("%s: transmit process failed to idle: " + "state %s\n", sc->sc_dev.dv_xname, + tx_state_names[(csr & STATUS_TS) >> 20]); + } } if ((bits & OPMODE_SR) != 0 && (csr & STATUS_RPS) == 0 && (csr & STATUS_RS) != STATUS_RS_STOPPED) { @@ -3543,6 +3672,30 @@ tlp_pnic_preinit(sc) } } +/* + * tlp_asix_preinit: + * + * Pre-init function for the ASIX chipsets. + */ +void +tlp_asix_preinit(sc) + struct tulip_softc *sc; +{ + + switch (sc->sc_chip) { + case TULIP_CHIP_AX88140: + case TULIP_CHIP_AX88141: + /* XXX Handle PHY. */ + sc->sc_opmode |= OPMODE_HBD|OPMODE_PS; + break; + default: + /* Nothing */ + break; + } + + TULIP_WRITE(sc, CSR_OPMODE, sc->sc_opmode); +} + /* * tlp_dm9102_preinit: * @@ -6095,3 +6248,83 @@ tlp_dm9102_tmsw_setmedia(sc) /* XXX HomePNA on DM9102A. */ return (tlp_mii_setmedia(sc)); } + +/* + * ASIX AX88140A/AX88141 media switch. Internal PHY or MII. + */ + +void tlp_asix_tmsw_init(struct tulip_softc *); +void tlp_asix_tmsw_getmedia(struct tulip_softc *, struct ifmediareq *); +int tlp_asix_tmsw_setmedia(struct tulip_softc *); + +const struct tulip_mediasw tlp_asix_mediasw = { + tlp_asix_tmsw_init, tlp_asix_tmsw_getmedia, + tlp_asix_tmsw_setmedia +}; + +void +tlp_asix_tmsw_init(sc) + struct tulip_softc *sc; +{ + struct ifnet *ifp = &sc->sc_ethercom.ec_if; + u_int32_t opmode; + + sc->sc_mii.mii_ifp = ifp; + sc->sc_mii.mii_readreg = tlp_bitbang_mii_readreg; + sc->sc_mii.mii_writereg = tlp_bitbang_mii_writereg; + sc->sc_mii.mii_statchg = sc->sc_statchg; + ifmedia_init(&sc->sc_mii.mii_media, 0, tlp_mediachange, + tlp_mediastatus); + + /* + * Configure OPMODE properly for the internal MII interface. + */ + switch (sc->sc_chip) { + case TULIP_CHIP_AX88140: + case TULIP_CHIP_AX88141: + opmode = OPMODE_HBD|OPMODE_PS; + break; + default: + opmode = 0; + break; + } + + TULIP_WRITE(sc, CSR_OPMODE, opmode); + + /* Now, probe the internal MII for the internal PHY. */ + mii_attach(&sc->sc_dev, &sc->sc_mii, 0xffffffff, MII_PHY_ANY, + MII_OFFSET_ANY, 0); + + /* XXX Figure how to handle the PHY. */ + + if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL) { + ifmedia_add(&sc->sc_mii.mii_media, IFM_ETHER|IFM_NONE, 0, NULL); + ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_NONE); + } else { + sc->sc_flags |= TULIPF_HAS_MII; + sc->sc_tick = tlp_mii_tick; + ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_AUTO); + } + + +} + +void +tlp_asix_tmsw_getmedia(sc, ifmr) + struct tulip_softc *sc; + struct ifmediareq *ifmr; +{ + + /* XXX PHY handling. */ + tlp_mii_getmedia(sc, ifmr); +} + +int +tlp_asix_tmsw_setmedia(sc) + struct tulip_softc *sc; +{ + + /* XXX PHY handling. */ + return (tlp_mii_setmedia(sc)); +} + diff --git a/sys/dev/ic/tulipreg.h b/sys/dev/ic/tulipreg.h index 8b845b790f8f..752498274860 100644 --- a/sys/dev/ic/tulipreg.h +++ b/sys/dev/ic/tulipreg.h @@ -1,4 +1,4 @@ -/* $NetBSD: tulipreg.h,v 1.30 2005/02/27 00:27:03 perry Exp $ */ +/* $NetBSD: tulipreg.h,v 1.31 2005/06/23 23:51:42 rpaulo Exp $ */ /*- * Copyright (c) 1999, 2000 The NetBSD Foundation, Inc. @@ -139,10 +139,19 @@ * - There seems to be an interrupt logic bug, requiring * that interrupts be disabled on the chip during the * interrupt handler. + * + * - ASIX AX88140 + * + * 21433 clone with a few differences: + * + * - Specific broadcast bit in the OPMODE register. + * - Transmit buffer must be 32-bit aligned. + * - The BUSMODE_SWR bit is not self-clearing. + * - External 10BaseT PHY or 10/100 MII. * * Some of the clone chips have different registers, and some have * different bits in the same registers. These will be denoted by - * PMAC, PNICII, PNIC, DM, WINB, and ADM in the register/bit names. + * PMAC, PNICII, PNIC, DM, WINB, ADM and AX in the register/bit names. */ /* @@ -437,6 +446,7 @@ struct tulip_desc { * Winbond 89C040F * Xircom X3201-3 * Davicom DM9102 (buggy BUSMODE register) + * ASIX AX88140 */ #define BUSMODE_TAP_NONE 0x00000000 /* no auto-polling */ #define BUSMODE_TAP_200us 0x00020000 /* 200 uS */ @@ -585,6 +595,7 @@ struct tulip_desc { #define OPMODE_PM 0x00000080 /* pass all multicast */ #define OPMODE_WINB_AEP 0x00000080 /* accept error packet */ #define OPMODE_FKD 0x00000100 /* flaky oscillator disable */ +#define OPMODE_AX_RB 0x00000100 /* recieve broadcast packets */ #define OPMODE_FD 0x00000200 /* full-duplex mode */ #define OPMODE_OM 0x00000c00 /* operating mode */ #define OPMODE_OM_NORMAL 0x00000000 /* normal mode */ @@ -1539,4 +1550,20 @@ struct tulip_desc { #define CSR_DM_SFDR TULIP_CSR14 /* See 21143 SIAGEN register */ +/* + * ASIX AX88140A and AX88141 registers. + */ + +/* CSR13 - Filtering Index */ +#define CSR_AX_FILTIDX TULIP_CSR13 + +/* CSR14 - Filtering data */ +#define CSR_AX_FILTDATA TULIP_CSR14 + +/* Filtering Index values */ +#define AX_FILTIDX_PAR0 0x00000000 +#define AX_FILTIDX_PAR1 0x00000001 +#define AX_FILTIDX_MAR0 0x00000002 +#define AX_FILTIDX_MAR1 0x00000003 + #endif /* _DEV_IC_TULIPREG_H_ */ diff --git a/sys/dev/ic/tulipvar.h b/sys/dev/ic/tulipvar.h index 0b568dc83f60..868247545f91 100644 --- a/sys/dev/ic/tulipvar.h +++ b/sys/dev/ic/tulipvar.h @@ -1,4 +1,4 @@ -/* $NetBSD: tulipvar.h,v 1.54 2005/02/27 00:27:03 perry Exp $ */ +/* $NetBSD: tulipvar.h,v 1.55 2005/06/23 23:51:42 rpaulo Exp $ */ /*- * Copyright (c) 1998, 1999, 2000 The NetBSD Foundation, Inc. @@ -595,6 +595,7 @@ extern const struct tulip_mediasw tlp_pmac_mediasw; extern const struct tulip_mediasw tlp_al981_mediasw; extern const struct tulip_mediasw tlp_an985_mediasw; extern const struct tulip_mediasw tlp_dm9102_mediasw; +extern const struct tulip_mediasw tlp_asix_mediasw; void tlp_attach(struct tulip_softc *, const u_int8_t *); int tlp_activate(struct device *, enum devact); diff --git a/sys/dev/pci/if_tlp_pci.c b/sys/dev/pci/if_tlp_pci.c index 2a0d094fc995..2c9523237be1 100644 --- a/sys/dev/pci/if_tlp_pci.c +++ b/sys/dev/pci/if_tlp_pci.c @@ -1,4 +1,4 @@ -/* $NetBSD: if_tlp_pci.c,v 1.79 2005/06/13 16:37:38 tron Exp $ */ +/* $NetBSD: if_tlp_pci.c,v 1.80 2005/06/23 23:51:41 rpaulo Exp $ */ /*- * Copyright (c) 1998, 1999, 2000, 2002 The NetBSD Foundation, Inc. @@ -43,7 +43,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: if_tlp_pci.c,v 1.79 2005/06/13 16:37:38 tron Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_tlp_pci.c,v 1.80 2005/06/23 23:51:41 rpaulo Exp $"); #include #include @@ -169,10 +169,8 @@ static const struct tulip_pci_product { { PCI_VENDOR_3COM, PCI_PRODUCT_3COM_3C910SOHOB, TULIP_CHIP_AN985 }, -#if 0 { PCI_VENDOR_ASIX, PCI_PRODUCT_ASIX_AX88140A, TULIP_CHIP_AX88140 }, -#endif { 0, 0, TULIP_CHIP_INVALID }, @@ -486,6 +484,8 @@ tlp_pci_attach(struct device *parent, struct device *self, void *aux) case TULIP_CHIP_MX98725: case TULIP_CHIP_DM9102: case TULIP_CHIP_DM9102A: + case TULIP_CHIP_AX88140: + case TULIP_CHIP_AX88141: /* * Clear the "sleep mode" bit in the CFDA register. */ @@ -930,6 +930,21 @@ tlp_pci_attach(struct device *parent, struct device *self, void *aux) sc->sc_mediasw = &tlp_dm9102_mediasw; break; + case TULIP_CHIP_AX88140: + case TULIP_CHIP_AX88141: + /* + * ASIX AX88140/AX88141 Ethernet Address is located at offset + * 20 of the SROM. + */ + memcpy(enaddr, &sc->sc_srom[20], ETHER_ADDR_LEN); + + /* + * ASIX AX88140A/AX88141 chip can have a built-in PHY or + * an external MII interface. + */ + sc->sc_mediasw = &tlp_asix_mediasw; + break; + default: cant_cope: printf("%s: sorry, unable to handle your board\n",