Many fixes. Multicast hash filter works now. Autonegotiation with GigE
on Mac G4's now works. XXX Checksum offload still needs to be done.
This commit is contained in:
parent
d2a97e2196
commit
c1fc5d35dc
186
sys/dev/ic/gem.c
186
sys/dev/ic/gem.c
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: gem.c,v 1.14 2002/05/08 02:12:55 matt Exp $ */
|
||||
/* $NetBSD: gem.c,v 1.15 2002/05/11 00:36:02 matt Exp $ */
|
||||
|
||||
/*
|
||||
*
|
||||
|
@ -34,7 +34,7 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: gem.c,v 1.14 2002/05/08 02:12:55 matt Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: gem.c,v 1.15 2002/05/11 00:36:02 matt Exp $");
|
||||
|
||||
#include "bpfilter.h"
|
||||
|
||||
|
@ -132,7 +132,9 @@ gem_attach(sc, enaddr)
|
|||
struct ifnet *ifp = &sc->sc_ethercom.ec_if;
|
||||
struct mii_data *mii = &sc->sc_mii;
|
||||
struct mii_softc *child;
|
||||
struct ifmedia_entry *ifm;
|
||||
int i, error;
|
||||
u_int32_t v;
|
||||
|
||||
/* Make sure the chip is stopped. */
|
||||
ifp->if_softc = sc;
|
||||
|
@ -189,8 +191,9 @@ gem_attach(sc, enaddr)
|
|||
|
||||
txs = &sc->sc_txsoft[i];
|
||||
txs->txs_mbuf = NULL;
|
||||
if ((error = bus_dmamap_create(sc->sc_dmatag, MCLBYTES,
|
||||
GEM_NTXSEGS, MCLBYTES, 0, 0,
|
||||
if ((error = bus_dmamap_create(sc->sc_dmatag,
|
||||
ETHER_MAX_LEN_JUMBO, GEM_NTXSEGS,
|
||||
ETHER_MAX_LEN_JUMBO, 0, 0,
|
||||
&txs->txs_dmamap)) != 0) {
|
||||
printf("%s: unable to create tx DMA map %d, "
|
||||
"error = %d\n", sc->sc_dev.dv_xname, i, error);
|
||||
|
@ -219,9 +222,18 @@ gem_attach(sc, enaddr)
|
|||
*/
|
||||
|
||||
/* Announce ourselves. */
|
||||
printf("%s: Ethernet address %s\n", sc->sc_dev.dv_xname,
|
||||
printf("%s: Ethernet address %s", sc->sc_dev.dv_xname,
|
||||
ether_sprintf(enaddr));
|
||||
|
||||
/* Get RX FIFO size */
|
||||
sc->sc_rxfifosize = 64 *
|
||||
bus_space_read_4(sc->sc_bustag, sc->sc_h, GEM_RX_FIFO_SIZE);
|
||||
printf(", %uKB RX fifo", sc->sc_rxfifosize / 1024);
|
||||
|
||||
/* Get TX FIFO size */
|
||||
v = bus_space_read_4(sc->sc_bustag, sc->sc_h, GEM_TX_FIFO_SIZE);
|
||||
printf(", %uKB TX fifo\n", v / 16);
|
||||
|
||||
/* Initialize ifnet structure. */
|
||||
strcpy(ifp->if_xname, sc->sc_dev.dv_xname);
|
||||
ifp->if_softc = sc;
|
||||
|
@ -276,6 +288,7 @@ gem_attach(sc, enaddr)
|
|||
}
|
||||
|
||||
sc->sc_phys[child->mii_inst] = child->mii_phy;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -305,6 +318,24 @@ gem_attach(sc, enaddr)
|
|||
ifmedia_set(&sc->sc_media, IFM_ETHER|IFM_AUTO);
|
||||
}
|
||||
|
||||
/*
|
||||
* If we support GigE media, we support jumbo frames too.
|
||||
* Unless we are Apple.
|
||||
*/
|
||||
TAILQ_FOREACH(ifm, &sc->sc_media.ifm_list, ifm_list) {
|
||||
if (IFM_SUBTYPE(ifm->ifm_media) == IFM_1000_T ||
|
||||
IFM_SUBTYPE(ifm->ifm_media) == IFM_1000_SX ||
|
||||
IFM_SUBTYPE(ifm->ifm_media) == IFM_1000_LX ||
|
||||
IFM_SUBTYPE(ifm->ifm_media) == IFM_1000_CX) {
|
||||
if (sc->sc_variant != GEM_APPLE_GMAC)
|
||||
sc->sc_ethercom.ec_capabilities
|
||||
|= ETHERCAP_JUMBO_MTU;
|
||||
|
||||
sc->sc_flags |= GEM_GIGABIT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* claim 802.1q capability */
|
||||
sc->sc_ethercom.ec_capabilities |= ETHERCAP_VLAN_MTU;
|
||||
|
||||
|
@ -705,6 +736,7 @@ gem_init(struct ifnet *ifp)
|
|||
bus_space_tag_t t = sc->sc_bustag;
|
||||
bus_space_handle_t h = sc->sc_h;
|
||||
int s;
|
||||
u_int max_frame_size;
|
||||
u_int32_t v;
|
||||
|
||||
s = splnet();
|
||||
|
@ -734,10 +766,12 @@ gem_init(struct ifnet *ifp)
|
|||
|
||||
/* step 4. TX MAC registers & counters */
|
||||
gem_init_regs(sc);
|
||||
max_frame_size = max(sc->sc_ethercom.ec_if.if_mtu, ETHERMTU);
|
||||
max_frame_size += ETHER_HDR_LEN + ETHER_CRC_LEN;
|
||||
if (sc->sc_ethercom.ec_capenable & ETHERCAP_VLAN_MTU)
|
||||
max_frame_size += ETHER_VLAN_ENCAP_LEN;
|
||||
bus_space_write_4(t, h, GEM_MAC_MAC_MAX_FRAME,
|
||||
((sc->sc_ethercom.ec_capenable & ETHERCAP_VLAN_MTU) ?
|
||||
ETHER_VLAN_ENCAP_LEN + ETHER_MAX_LEN + sizeof(struct ether_header):
|
||||
ETHER_MAX_LEN + sizeof(struct ether_header)) | (0x2000<<16));
|
||||
max_frame_size|/* burst size */(0x2000<<16));
|
||||
|
||||
/* step 5. RX MAC registers & counters */
|
||||
gem_setladrf(sc);
|
||||
|
@ -782,14 +816,16 @@ gem_init(struct ifnet *ifp)
|
|||
(2<<GEM_RX_CONFIG_FBOFF_SHFT)|GEM_RX_CONFIG_RXDMA_EN|
|
||||
(0<<GEM_RX_CONFIG_CXM_START_SHFT));
|
||||
/*
|
||||
* The following value is for an OFF Threshold of about 15.5 Kbytes
|
||||
* and an ON Threshold of 4K bytes.
|
||||
* The following value is for an OFF Threshold of about 3/4 full
|
||||
* and an ON Threshold of 1/4 full.
|
||||
*/
|
||||
bus_space_write_4(t, h, GEM_RX_PAUSE_THRESH, 0xf8 | (0x40 << 12));
|
||||
bus_space_write_4(t, h, GEM_RX_BLANKING, (2<<12)|6);
|
||||
bus_space_write_4(t, h, GEM_RX_PAUSE_THRESH,
|
||||
(3 * sc->sc_rxfifosize / 256) |
|
||||
( (sc->sc_rxfifosize / 256) << 12));
|
||||
bus_space_write_4(t, h, GEM_RX_BLANKING, (6<<12)|6);
|
||||
|
||||
/* step 11. Configure Media */
|
||||
gem_mii_statchg(&sc->sc_dev);
|
||||
mii_mediachg(&sc->sc_mii);
|
||||
|
||||
/* XXXX Serial link needs a whole different setup. */
|
||||
|
||||
|
@ -827,6 +863,7 @@ gem_init_regs(struct gem_softc *sc)
|
|||
bus_space_tag_t t = sc->sc_bustag;
|
||||
bus_space_handle_t h = sc->sc_h;
|
||||
const u_char *laddr = LLADDR(ifp->if_sadl);
|
||||
u_int32_t v;
|
||||
|
||||
/* These regs are not cleared on reset */
|
||||
if (!sc->sc_inited) {
|
||||
|
@ -839,14 +876,15 @@ gem_init_regs(struct gem_softc *sc)
|
|||
bus_space_write_4(t, h, GEM_MAC_MAC_MIN_FRAME, ETHER_MIN_LEN);
|
||||
/* Max frame and max burst size */
|
||||
bus_space_write_4(t, h, GEM_MAC_MAC_MAX_FRAME,
|
||||
(ifp->if_mtu+18) | (0x2000<<16)/* Burst size */);
|
||||
ETHER_MAX_LEN | (0x2000<<16));
|
||||
|
||||
bus_space_write_4(t, h, GEM_MAC_PREAMBLE_LEN, 0x7);
|
||||
bus_space_write_4(t, h, GEM_MAC_JAM_SIZE, 0x4);
|
||||
bus_space_write_4(t, h, GEM_MAC_ATTEMPT_LIMIT, 0x10);
|
||||
/* Dunno.... */
|
||||
bus_space_write_4(t, h, GEM_MAC_CONTROL_TYPE, 0x8088);
|
||||
bus_space_write_4(t, h, GEM_MAC_RANDOM_SEED,
|
||||
((laddr[5]<<8)|laddr[4])&0x3ff);
|
||||
((laddr[5]<<8)|laddr[4])&0x3ff);
|
||||
|
||||
/* Secondary MAC addr set to 0:0:0:0:0:0 */
|
||||
bus_space_write_4(t, h, GEM_MAC_ADDR3, 0);
|
||||
|
@ -896,10 +934,24 @@ gem_init_regs(struct gem_softc *sc)
|
|||
bus_space_write_4(t, h, GEM_MAC_ADDR1, (laddr[2]<<8)|laddr[3]);
|
||||
bus_space_write_4(t, h, GEM_MAC_ADDR2, (laddr[0]<<8)|laddr[1]);
|
||||
|
||||
#if 0
|
||||
if (sc->sc_variant != APPLE_GMAC)
|
||||
return;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Enable MII outputs. Enable GMII if there is a gigabit PHY.
|
||||
*/
|
||||
sc->sc_mif_config = bus_space_read_4(t, h, 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_space_write_4(t, h, GEM_MAC_XIF_CONFIG, v);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
gem_start(ifp)
|
||||
struct ifnet *ifp;
|
||||
|
@ -948,6 +1000,13 @@ gem_start(ifp)
|
|||
*/
|
||||
if (bus_dmamap_load_mbuf(sc->sc_dmatag, dmamap, m0,
|
||||
BUS_DMA_WRITE|BUS_DMA_NOWAIT) != 0) {
|
||||
if (m0->m_pkthdr.len > MCLBYTES) {
|
||||
printf("%s: unable to allocate jumbo Tx "
|
||||
"cluster\n", sc->sc_dev.dv_xname);
|
||||
IFQ_DEQUEUE(&ifp->if_snd, m0);
|
||||
m_freem(m0);
|
||||
continue;
|
||||
}
|
||||
MGETHDR(m, M_DONTWAIT, MT_DATA);
|
||||
if (m == NULL) {
|
||||
printf("%s: unable to allocate Tx mbuf\n",
|
||||
|
@ -1636,6 +1695,7 @@ gem_mii_statchg(dev)
|
|||
v = bus_space_read_4(t, mac, GEM_MAC_XIF_CONFIG);
|
||||
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_space_read_4(t, mac, GEM_MIF_CONFIG);
|
||||
if ((sc->sc_mif_config & GEM_MIF_CONFIG_MDI1) != 0) {
|
||||
|
@ -1643,9 +1703,10 @@ gem_mii_statchg(dev)
|
|||
if ((IFM_OPTIONS(sc->sc_mii.mii_media_active) & IFM_FDX) != 0)
|
||||
/* turn on full duplex LED */
|
||||
v |= GEM_MAC_XIF_FDPLX_LED;
|
||||
else
|
||||
/* half duplex -- disable echo */
|
||||
v |= GEM_MAC_XIF_ECHO_DISABL;
|
||||
else
|
||||
/* half duplex -- disable echo */
|
||||
v |= GEM_MAC_XIF_ECHO_DISABL;
|
||||
|
||||
if (sc->sc_ethercom.ec_if.if_baudrate == IF_Mbps(1000))
|
||||
v |= GEM_MAC_XIF_GMII_MODE;
|
||||
else
|
||||
|
@ -1746,44 +1807,46 @@ void
|
|||
gem_setladrf(sc)
|
||||
struct gem_softc *sc;
|
||||
{
|
||||
struct ifnet *ifp = &sc->sc_ethercom.ec_if;
|
||||
struct ethercom *ec = &sc->sc_ethercom;
|
||||
struct ifnet *ifp = &ec->ec_if;
|
||||
struct ether_multi *enm;
|
||||
struct ether_multistep step;
|
||||
struct ethercom *ec = &sc->sc_ethercom;
|
||||
bus_space_tag_t t = sc->sc_bustag;
|
||||
bus_space_handle_t h = sc->sc_h;
|
||||
u_char *cp;
|
||||
u_int32_t crc;
|
||||
u_int32_t hash[16];
|
||||
u_int32_t v;
|
||||
int len;
|
||||
|
||||
/* Clear hash table */
|
||||
memset(hash, 0, sizeof(hash));
|
||||
int i;
|
||||
|
||||
/* Get current RX configuration */
|
||||
v = bus_space_read_4(t, h, GEM_MAC_RX_CONFIG);
|
||||
|
||||
/*
|
||||
* Turn off promiscuous mode, promiscuous group mode (all multicast),
|
||||
* and hash filter. Depending on the case, the right bit will be
|
||||
* enabled.
|
||||
*/
|
||||
v &= ~(GEM_MAC_RX_PROMISCUOUS|GEM_MAC_RX_HASH_FILTER|
|
||||
GEM_MAC_RX_PROMISC_GRP);
|
||||
|
||||
if ((ifp->if_flags & IFF_PROMISC) != 0) {
|
||||
/* Turn on promiscuous mode; turn off the hash filter */
|
||||
/* Turn on promiscuous mode */
|
||||
v |= GEM_MAC_RX_PROMISCUOUS;
|
||||
v &= ~GEM_MAC_RX_HASH_FILTER;
|
||||
ifp->if_flags |= IFF_ALLMULTI;
|
||||
goto chipit;
|
||||
}
|
||||
|
||||
/* Turn off promiscuous mode; turn on the hash filter */
|
||||
v &= ~GEM_MAC_RX_PROMISCUOUS;
|
||||
v |= GEM_MAC_RX_HASH_FILTER;
|
||||
|
||||
/*
|
||||
* Set up multicast address filter by passing all multicast addresses
|
||||
* through a crc generator, and then using the high order 6 bits as an
|
||||
* index into the 256 bit logical address filter. The high order bit
|
||||
* selects the word, while the rest of the bits select the bit within
|
||||
* the word.
|
||||
* through a crc generator, and then using the high order 8 bits as an
|
||||
* index into the 256 bit logical address filter. The high order 4
|
||||
* bits select the word, while the other 4 bits select the bit within
|
||||
* the word (where bit 0 is the MSB).
|
||||
*/
|
||||
|
||||
/* Clear hash table */
|
||||
memset(hash, 0, sizeof(hash));
|
||||
|
||||
ETHER_FIRST_MULTI(step, ec, enm);
|
||||
while (enm != NULL) {
|
||||
if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) {
|
||||
|
@ -1794,59 +1857,36 @@ gem_setladrf(sc)
|
|||
* 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.)
|
||||
* XXX use the addr filter for this
|
||||
*/
|
||||
hash[3] = hash[2] = hash[1] = hash[0] = 0xffff;
|
||||
ifp->if_flags |= IFF_ALLMULTI;
|
||||
v |= GEM_MAC_RX_PROMISC_GRP;
|
||||
goto chipit;
|
||||
}
|
||||
|
||||
cp = enm->enm_addrlo;
|
||||
crc = 0xffffffff;
|
||||
for (len = sizeof(enm->enm_addrlo); --len >= 0;) {
|
||||
int octet = *cp++;
|
||||
int i;
|
||||
/* Get the LE CRC32 of the address */
|
||||
crc = ether_crc32_le(enm->enm_addrlo, sizeof(enm->enm_addrlo));
|
||||
|
||||
#define MC_POLY_LE 0xedb88320UL /* mcast crc, little endian */
|
||||
for (i = 0; i < 8; i++) {
|
||||
if ((crc & 1) ^ (octet & 1)) {
|
||||
crc >>= 1;
|
||||
crc ^= MC_POLY_LE;
|
||||
} else {
|
||||
crc >>= 1;
|
||||
}
|
||||
octet >>= 1;
|
||||
}
|
||||
}
|
||||
/* Just want the 8 most significant bits. */
|
||||
crc >>= 24;
|
||||
|
||||
/* Set the corresponding bit in the filter. */
|
||||
hash[crc >> 4] |= 1 << (crc & 0xf);
|
||||
hash[crc >> 4] |= 1 << (15 - (crc & 15));
|
||||
|
||||
ETHER_NEXT_MULTI(step, enm);
|
||||
}
|
||||
|
||||
v |= GEM_MAC_RX_HASH_FILTER;
|
||||
ifp->if_flags &= ~IFF_ALLMULTI;
|
||||
|
||||
chipit:
|
||||
/* Now load the hash table into the chip */
|
||||
bus_space_write_4(t, h, GEM_MAC_HASH0, hash[0]);
|
||||
bus_space_write_4(t, h, GEM_MAC_HASH1, hash[1]);
|
||||
bus_space_write_4(t, h, GEM_MAC_HASH2, hash[2]);
|
||||
bus_space_write_4(t, h, GEM_MAC_HASH3, hash[3]);
|
||||
bus_space_write_4(t, h, GEM_MAC_HASH4, hash[4]);
|
||||
bus_space_write_4(t, h, GEM_MAC_HASH5, hash[5]);
|
||||
bus_space_write_4(t, h, GEM_MAC_HASH6, hash[6]);
|
||||
bus_space_write_4(t, h, GEM_MAC_HASH7, hash[7]);
|
||||
bus_space_write_4(t, h, GEM_MAC_HASH8, hash[8]);
|
||||
bus_space_write_4(t, h, GEM_MAC_HASH9, hash[9]);
|
||||
bus_space_write_4(t, h, GEM_MAC_HASH10, hash[10]);
|
||||
bus_space_write_4(t, h, GEM_MAC_HASH11, hash[11]);
|
||||
bus_space_write_4(t, h, GEM_MAC_HASH12, hash[12]);
|
||||
bus_space_write_4(t, h, GEM_MAC_HASH13, hash[13]);
|
||||
bus_space_write_4(t, h, GEM_MAC_HASH14, hash[14]);
|
||||
bus_space_write_4(t, h, GEM_MAC_HASH15, hash[15]);
|
||||
/* Now load the hash table into the chip (if we are using it) */
|
||||
for (i = 0; i < 16; i++) {
|
||||
bus_space_write_4(t, h,
|
||||
GEM_MAC_HASH0 + i * (GEM_MAC_HASH1-GEM_MAC_HASH0),
|
||||
hash[i]);
|
||||
}
|
||||
|
||||
chipit:
|
||||
bus_space_write_4(t, h, GEM_MAC_RX_CONFIG, v);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: gemreg.h,v 1.3 2002/05/08 02:12:55 matt Exp $ */
|
||||
/* $NetBSD: gemreg.h,v 1.4 2002/05/11 00:36:02 matt Exp $ */
|
||||
|
||||
/*
|
||||
*
|
||||
|
@ -204,13 +204,14 @@
|
|||
|
||||
/* GEM_RX_PAUSE_THRESH register bits -- sizes in multiples of 64 bytes */
|
||||
#define GEM_RX_PTH_XOFF_THRESH 0x000001ff
|
||||
#define GEM_RX_PTH_XON_THRESH 0x07fc0000
|
||||
#define GEM_RX_PTH_XON_THRESH 0x001ff000
|
||||
|
||||
|
||||
/* GEM_RX_BLANKING register bits */
|
||||
#define GEM_RX_BLANKING_PACKETS 0x000001ff /* Delay intr for x packets */
|
||||
#define GEM_RX_BLANKING_TIME 0x03fc0000 /* Delay intr for x ticks */
|
||||
/* One tick is 1048 PCI clocs, or 16us at 66MHz */
|
||||
#define GEM_RX_BLANKING_TIME 0x000ff000 /* Delay intr for x ticks */
|
||||
#define GEM_RX_BLANKING_TIME_SHIFT 12
|
||||
/* One tick is 2048 PCI clocks, or 16us at 66MHz */
|
||||
|
||||
|
||||
/* GEM_MAC registers */
|
||||
|
@ -475,6 +476,8 @@
|
|||
#define GEM_MII_DATAPATH_SERDES 0x00000002 /* Use PCS via 10bit interfac */
|
||||
#define GEM_MII_DATAPATH_MII 0x00000004 /* Use MII, not PCS */
|
||||
#define GEM_MII_DATAPATH_MIIOUT 0x00000008 /* enable serial output on GMII */
|
||||
#define GEM_MII_DATAPATH_BITS "\177\020" \
|
||||
"b\0SERIAL\0b\1SERDES\0b\2MII\0b\3MIIOUT\0\0"
|
||||
|
||||
|
||||
/* GEM_MII_SLINK_CONTROL reg */
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: gemvar.h,v 1.6 2002/05/08 02:12:55 matt Exp $ */
|
||||
/* $NetBSD: gemvar.h,v 1.7 2002/05/11 00:36:03 matt Exp $ */
|
||||
|
||||
/*
|
||||
*
|
||||
|
@ -130,6 +130,13 @@ struct gem_softc {
|
|||
int sc_mif_config; /* Selected MII reg setting */
|
||||
|
||||
int sc_pci; /* XXXXX -- PCI buses are LE. */
|
||||
u_int sc_variant; /* which GEM are we dealing with? */
|
||||
#define GEM_UNKNOWN 0 /* don't know */
|
||||
#define GEM_SUN_GEM 1 /* Sun GEM variant */
|
||||
#define GEM_APPLE_GMAC 2 /* Apple GMAC variant */
|
||||
|
||||
u_int sc_flags; /* */
|
||||
#define GEM_GIGABIT 0x0001 /* has a gigabit PHY */
|
||||
|
||||
void *sc_sdhook; /* shutdown hook */
|
||||
void *sc_powerhook; /* power management hook */
|
||||
|
@ -163,6 +170,7 @@ struct gem_softc {
|
|||
struct gem_txsq sc_txdirtyq; /* dirty Tx descsofts */
|
||||
|
||||
int sc_rxptr; /* next ready RX descriptor/descsoft */
|
||||
int sc_rxfifosize; /* Rx FIFO size (bytes) */
|
||||
|
||||
/* ========== */
|
||||
int sc_inited;
|
||||
|
|
Loading…
Reference in New Issue