Add support for the National Semiconductor DP83815 fast ethernet

controller chip. This chip is currently being used on the NetGear
FA312-TX adapter, which I guess is a replacement for the FA310-TX
(PNIC-based).

I added support for this chip by modifying the sis driver since
the SiS 900 and the NS DP83815 have almost the same programming
interface (the RX filter programming and PHY access methods are
different, but the general configuration, DMA scheme and register
layout are identical).

I would have had this done a lot sooner, but getting the damn MAC
address out of the EEPROM proved to be more complicated than expected.
This commit is contained in:
Bill Paul 2000-07-06 06:02:04 +00:00
parent 18c8a61a47
commit 95674596b9
6 changed files with 256 additions and 23 deletions

View File

@ -526,6 +526,9 @@ NICs including the following:
Silicon Integrated Systems SiS 900 and SiS 7016 PCI fast ethernet NICs
National Semiconductor DP83815 fast ethernet NICs including the following:
NetGear FA312-TX
Sundance Technologies ST201 PCI fast ethernet NICs including
the following:
D-Link DFE-550TX

View File

@ -71,6 +71,8 @@ POSIX.1b Shared Memory Objects are now supported. The implementation
uses regular files, but automatically enables the MAP_NOSYNC flag
when they are mmap(2)ed.
Added support for PCI ethernet adapters based on the National Semiconductor
DP83815 chipset, including the NetGear FA312-TX.
1.2. SECURITY FIXES
-------------------
@ -289,6 +291,9 @@ NICs including the following:
Silicon Integrated Systems SiS 900 and SiS 7016 PCI fast ethernet NICs
National Semiconductor DP83815 fast ethernet NICs including the following:
NetGear FA312-TX
Sundance Technologies ST201 PCI fast ethernet NICs including
the following:
D-Link DFE-550TX

View File

@ -75,6 +75,9 @@ POSIX.1b Shared Memory Objects are now supported. The implementation
uses regular files, but automatically enables the MAP_NOSYNC flag
when they are mmap(2)ed.
Added support for PCI ethernet adapters based on the National Semiconductor
DP83815 chipset, including the NetGear FA312-TX.
1.2. SECURITY FIXES
-------------------
@ -308,6 +311,9 @@ NICs including the following:
Silicon Integrated Systems SiS 900 and SiS 7016 PCI fast ethernet NICs
National Semiconductor DP83815 fast ethernet NICs including the following:
NetGear FA312-TX
Sundance Technologies ST201 PCI fast ethernet NICs including
the following:
D-Link DFE-550TX

View File

@ -36,7 +36,7 @@
.Sh NAME
.Nm sis
.Nd
Silicon Integrated Systems fast ethernet device driver
SiS 900, SiS 7016 and NS DP83815 fast ethernet device driver
.Sh SYNOPSIS
.Cd "device miibus"
.Cd "device sis"
@ -45,7 +45,9 @@ The
.Nm
driver provides support for PCI ethernet adapters and embedded
controllers based on the Silicon Integrated Systems SiS 900
and SiS 7016 fast ethernet controller chips.
and SiS 7016 fast ethernet controller chips, as well as support
for adapters based on the National Semiconductor DP83815 (MacPhyter)
PCI ethernet controller chip, including the Netgear FA312-TX.
.Pp
The SiS 900 is a 100Mbps ethernet MAC and MII-compliant transceiver
in a single package.
@ -57,6 +59,11 @@ to be attached to its MII interface.
The SiS 900 and SiS 7016 both have a 128-bit multicast hash filter
and a single perfect filter entry for the station address.
.Pp
The NS DP83815 is also a 100Mbps ethernet MAC with integrated PHY.
The NatSemi chip and the SiS 900 share many of the same features and
a fairly similar programming interface, hence both chips are supported
by the same driver.
.Pp
The
.Nm
driver supports the following media types:
@ -147,6 +154,10 @@ the card should be configured correctly.
.%T SiS 900 and SiS 7016 datasheets
.%O http://www.sis.com.tw
.Re
.Rs
.%T NatSemi DP83815 datasheet
.%O http://www.national.com
.Re
.Sh HISTORY
The
.Nm

View File

@ -106,6 +106,7 @@ static const char rcsid[] =
static struct sis_type sis_devs[] = {
{ SIS_VENDORID, SIS_DEVICEID_900, "SiS 900 10/100BaseTX" },
{ SIS_VENDORID, SIS_DEVICEID_7016, "SiS 7016 10/100BaseTX" },
{ NS_VENDORID, NS_DEVICEID_DP83815, "NatSemi DP83815 10/100BaseTX" },
{ 0, 0, NULL }
};
@ -132,6 +133,7 @@ static void sis_shutdown __P((device_t));
static int sis_ifmedia_upd __P((struct ifnet *));
static void sis_ifmedia_sts __P((struct ifnet *, struct ifmediareq *));
static u_int16_t sis_reverse __P((u_int16_t));
static void sis_delay __P((struct sis_softc *));
static void sis_eeprom_idle __P((struct sis_softc *));
static void sis_eeprom_putbyte __P((struct sis_softc *, int));
@ -142,8 +144,9 @@ static int sis_miibus_readreg __P((device_t, int, int));
static int sis_miibus_writereg __P((device_t, int, int, int));
static void sis_miibus_statchg __P((device_t));
static void sis_setmulti __P((struct sis_softc *));
static u_int32_t sis_calchash __P((caddr_t));
static void sis_setmulti_sis __P((struct sis_softc *));
static void sis_setmulti_ns __P((struct sis_softc *));
static u_int32_t sis_crc __P((struct sis_softc *, caddr_t));
static void sis_reset __P((struct sis_softc *));
static int sis_list_rx_init __P((struct sis_softc *));
static int sis_list_tx_init __P((struct sis_softc *));
@ -200,6 +203,21 @@ DRIVER_MODULE(miibus, sis, miibus_driver, miibus_devclass, 0, 0);
#define SIO_CLR(x) \
CSR_WRITE_4(sc, SIS_EECTL, CSR_READ_4(sc, SIS_EECTL) & ~x)
/*
* Routine to reverse the bits in a word. Stolen almost
* verbatim from /usr/games/fortune.
*/
static u_int16_t sis_reverse(n)
u_int16_t n;
{
n = ((n >> 1) & 0x5555) | ((n << 1) & 0xaaaa);
n = ((n >> 2) & 0x3333) | ((n << 2) & 0xcccc);
n = ((n >> 4) & 0x0f0f) | ((n << 4) & 0xf0f0);
n = ((n >> 8) & 0x00ff) | ((n << 8) & 0xff00);
return(n);
}
static void sis_delay(sc)
struct sis_softc *sc;
{
@ -283,9 +301,9 @@ static void sis_eeprom_getword(sc, addr, dest)
/* Enter EEPROM access mode. */
sis_delay(sc);
SIO_SET(SIS_EECTL_CSEL);
SIO_CLR(SIS_EECTL_CLK);
sis_delay(sc);
SIO_SET(SIS_EECTL_CLK);
SIO_SET(SIS_EECTL_CSEL);
sis_delay(sc);
/*
@ -344,10 +362,29 @@ static int sis_miibus_readreg(dev, phy, reg)
int phy, reg;
{
struct sis_softc *sc;
int i, val;
int i, val = 0;
sc = device_get_softc(dev);
if (sc->sis_type == SIS_TYPE_83815) {
if (phy != 0)
return(0);
/*
* The NatSemi chip can take a while after
* a reset to come ready, during which the BMSR
* returns a value of 0. This is *never* supposed
* to happen: some of the BMSR bits are meant to
* be hardwired in the on position, and this can
* confuse the miibus code a bit during the probe
* and attach phase. So we make an effort to check
* for this condition and wait for it to clear.
*/
if (!CSR_READ_4(sc, NS_BMSR))
DELAY(1000);
val = CSR_READ_4(sc, NS_BMCR + (reg * 4));
return(val);
}
if (sc->sis_type == SIS_TYPE_900 && phy != 0)
return(0);
@ -381,6 +418,16 @@ static int sis_miibus_writereg(dev, phy, reg, data)
sc = device_get_softc(dev);
if (sc->sis_type == SIS_TYPE_83815) {
if (phy != 0)
return(0);
CSR_WRITE_4(sc, NS_BMCR + (reg * 4), data);
return(0);
}
if (sc->sis_type == SIS_TYPE_900 && phy != 0)
return(0);
if (sc->sis_type == SIS_TYPE_900 && phy != 0)
return(0);
@ -421,7 +468,8 @@ static void sis_miibus_statchg(dev)
return;
}
static u_int32_t sis_calchash(addr)
static u_int32_t sis_crc(sc, addr)
struct sis_softc *sc;
caddr_t addr;
{
u_int32_t crc, carry;
@ -442,11 +490,68 @@ static u_int32_t sis_calchash(addr)
}
}
/* return the filter bit position */
/*
* return the filter bit position
*
* The NatSemi chip has a 512-bit filter, which is
* different than the SiS, so we special-case it.
*/
if (sc->sis_type == SIS_TYPE_83815)
return((crc >> 23) & 0x1FF);
return((crc >> 25) & 0x0000007F);
}
static void sis_setmulti(sc)
static void sis_setmulti_ns(sc)
struct sis_softc *sc;
{
struct ifnet *ifp;
struct ifmultiaddr *ifma;
u_int32_t h = 0, i, filtsave;
int bit, index;
ifp = &sc->arpcom.ac_if;
if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
SIS_CLRBIT(sc, SIS_RXFILT_CTL, NS_RXFILTCTL_MCHASH);
SIS_SETBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_ALLMULTI);
return;
}
/*
* We have to explicitly enable the multicast hash table
* on the NatSemi chip if we want to use it, which we do.
*/
SIS_SETBIT(sc, SIS_RXFILT_CTL, NS_RXFILTCTL_MCHASH);
SIS_CLRBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_ALLMULTI);
filtsave = CSR_READ_4(sc, SIS_RXFILT_CTL);
/* first, zot all the existing hash bits */
for (i = 0; i < 32; i++) {
CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_FMEM_LO + (i*2));
CSR_WRITE_4(sc, SIS_RXFILT_DATA, 0);
}
for (ifma = ifp->if_multiaddrs.lh_first; ifma != NULL;
ifma = ifma->ifma_link.le_next) {
if (ifma->ifma_addr->sa_family != AF_LINK)
continue;
h = sis_crc(sc, LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
index = h >> 3;
bit = h & 0x1F;
CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_FMEM_LO + index);
if (bit > 0xF)
bit -= 0x10;
SIS_SETBIT(sc, SIS_RXFILT_DATA, (1 << bit));
}
CSR_WRITE_4(sc, SIS_RXFILT_CTL, filtsave);
return;
}
static void sis_setmulti_sis(sc)
struct sis_softc *sc;
{
struct ifnet *ifp;
@ -475,7 +580,7 @@ static void sis_setmulti(sc)
ifma = ifma->ifma_link.le_next) {
if (ifma->ifma_addr->sa_family != AF_LINK)
continue;
h = sis_calchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
h = sis_crc(sc, LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
CSR_WRITE_4(sc, SIS_RXFILT_CTL, (4 + (h >> 4)) << 16);
SIS_SETBIT(sc, SIS_RXFILT_DATA, (1 << (h & 0xF)));
}
@ -552,6 +657,8 @@ static int sis_attach(dev)
sc->sis_type = SIS_TYPE_900;
if (pci_get_device(dev) == SIS_DEVICEID_7016)
sc->sis_type = SIS_TYPE_7016;
if (pci_get_vendor(dev) == NS_VENDORID)
sc->sis_type = SIS_TYPE_83815;
/*
* Handle power management nonsense.
@ -645,7 +752,47 @@ static int sis_attach(dev)
/*
* Get station address from the EEPROM.
*/
sis_read_eeprom(sc, (caddr_t)&eaddr, SIS_EE_NODEADDR, 3, 0);
switch (pci_get_vendor(dev)) {
case NS_VENDORID:
/*
* Reading the MAC address out of the EEPROM on
* the NatSemi chip takes a bit more work than
* you'd expect. The address spans 4 16-bit words,
* with the first word containing only a single bit.
* You have to shift everything over one bit to
* get it aligned properly. Also, the bits are
* stored backwards (the LSB is really the MSB,
* and so on) so you have to reverse them in order
* to get the MAC address into the form we want.
* Why? Who the hell knows.
*/
{
u_int16_t tmp[4];
sis_read_eeprom(sc, (caddr_t)&tmp,
NS_EE_NODEADDR, 4, 0);
/* Shift everything over one bit. */
tmp[3] = tmp[3] >> 1;
tmp[3] |= tmp[2] >> 15;
tmp[2] = tmp[2] >> 1;
tmp[2] |= tmp[1] >> 15;
tmp[1] = tmp[1] >> 1;
tmp[1] |= tmp[0] >> 15;
/* Now reverse all the bits. */
tmp[3] = sis_reverse(tmp[3]);
tmp[2] = sis_reverse(tmp[2]);
tmp[1] = sis_reverse(tmp[1]);
bcopy((char *)&tmp[1], eaddr, ETHER_ADDR_LEN);
}
break;
case SIS_VENDORID:
default:
sis_read_eeprom(sc, (caddr_t)&eaddr, SIS_EE_NODEADDR, 3, 0);
break;
}
/*
* A SiS chip was detected. Inform the world.
@ -1183,15 +1330,27 @@ static void sis_init(xsc)
mii = device_get_softc(sc->sis_miibus);
/* Set MAC address */
CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR0);
CSR_WRITE_4(sc, SIS_RXFILT_DATA,
((u_int16_t *)sc->arpcom.ac_enaddr)[0]);
CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR1);
CSR_WRITE_4(sc, SIS_RXFILT_DATA,
((u_int16_t *)sc->arpcom.ac_enaddr)[1]);
CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR2);
CSR_WRITE_4(sc, SIS_RXFILT_DATA,
((u_int16_t *)sc->arpcom.ac_enaddr)[2]);
if (sc->sis_type == SIS_TYPE_83815) {
CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_PAR0);
CSR_WRITE_4(sc, SIS_RXFILT_DATA,
((u_int16_t *)sc->arpcom.ac_enaddr)[0]);
CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_PAR1);
CSR_WRITE_4(sc, SIS_RXFILT_DATA,
((u_int16_t *)sc->arpcom.ac_enaddr)[1]);
CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_PAR2);
CSR_WRITE_4(sc, SIS_RXFILT_DATA,
((u_int16_t *)sc->arpcom.ac_enaddr)[2]);
} else {
CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR0);
CSR_WRITE_4(sc, SIS_RXFILT_DATA,
((u_int16_t *)sc->arpcom.ac_enaddr)[0]);
CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR1);
CSR_WRITE_4(sc, SIS_RXFILT_DATA,
((u_int16_t *)sc->arpcom.ac_enaddr)[1]);
CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR2);
CSR_WRITE_4(sc, SIS_RXFILT_DATA,
((u_int16_t *)sc->arpcom.ac_enaddr)[2]);
}
/* Init circular RX list. */
if (sis_list_rx_init(sc) == ENOBUFS) {
@ -1207,6 +1366,17 @@ static void sis_init(xsc)
*/
sis_list_tx_init(sc);
/*
* For the NatSemi chip, we have to explicitly enable the
* reception of ARP frames, as well as turn on the 'perfect
* match' filter where we store the station address, otherwise
* we won't receive unicasts meant for this host.
*/
if (sc->sis_type == SIS_TYPE_83815) {
SIS_SETBIT(sc, SIS_RXFILT_CTL, NS_RXFILTCTL_ARP);
SIS_SETBIT(sc, SIS_RXFILT_CTL, NS_RXFILTCTL_PERFECT);
}
/* If we want promiscuous mode, set the allframes bit. */
if (ifp->if_flags & IFF_PROMISC) {
SIS_SETBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_ALLPHYS);
@ -1226,7 +1396,10 @@ static void sis_init(xsc)
/*
* Load the multicast filter.
*/
sis_setmulti(sc);
if (sc->sis_type == SIS_TYPE_83815)
sis_setmulti_ns(sc);
else
sis_setmulti_sis(sc);
/* Turn the receive filter on */
SIS_SETBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_ENABLE);
@ -1331,7 +1504,10 @@ static int sis_ioctl(ifp, command, data)
break;
case SIOCADDMULTI:
case SIOCDELMULTI:
sis_setmulti(sc);
if (sc->sis_type == SIS_TYPE_83815)
sis_setmulti_ns(sc);
else
sis_setmulti_sis(sc);
error = 0;
break;
case SIOCGIFMEDIA:

View File

@ -74,6 +74,16 @@
#define SIS_TIMEUNIT 0xA4
#define SIS_GPIO 0xB8
/* NS DP83815 registers */
#define NS_BMCR 0x80
#define NS_BMSR 0x84
#define NS_PHYIDR1 0x88
#define NS_PHYIDR2 0x8C
#define NS_ANAR 0x90
#define NS_ANLPAR 0x94
#define NS_ANER 0x98
#define NS_ANNPTR 0x9C
#define SIS_CSR_TX_ENABLE 0x00000001
#define SIS_CSR_TX_DISABLE 0x00000002
#define SIS_CSR_RX_ENABLE 0x00000004
@ -100,6 +110,7 @@
#define SIS_EECMD_ERASE 0x1c0
#define SIS_EE_NODEADDR 0x8
#define NS_EE_NODEADDR 0x6
#define SIS_PCICTL_SRAMADDR 0x0000001F
#define SIS_PCICTL_RAMTSTENB 0x00000020
@ -220,6 +231,9 @@
(SIS_RXCFG_DRAIN(64)|SIS_RXDMA_256BYTES)
#define SIS_RXFILTCTL_ADDR 0x000F0000
#define NS_RXFILTCTL_MCHASH 0x00200000
#define NS_RXFILTCTL_ARP 0x00400000
#define NS_RXFILTCTL_PERFECT 0x08000000
#define SIS_RXFILTCTL_ALLPHYS 0x10000000
#define SIS_RXFILTCTL_ALLMULTI 0x20000000
#define SIS_RXFILTCTL_BROAD 0x40000000
@ -237,6 +251,13 @@
#define SIS_FILTADDR_MAR6 0x000A0000
#define SIS_FILTADDR_MAR7 0x000B0000
#define NS_FILTADDR_PAR0 0x00000000
#define NS_FILTADDR_PAR1 0x00000002
#define NS_FILTADDR_PAR2 0x00000004
#define NS_FILTADDR_FMEM_LO 0x00000200
#define NS_FILTADDR_FMEM_HI 0x000003FE
/*
* DMA descriptor structures. The first part of the descriptor
* is the hardware descriptor format, which is just three longwords.
@ -322,6 +343,16 @@ struct sis_ring_data {
#define SIS_DEVICEID_900 0x0900
#define SIS_DEVICEID_7016 0x7016
/*
* NatSemi vendor ID
*/
#define NS_VENDORID 0x100B
/*
* DP83815 device ID
*/
#define NS_DEVICEID_DP83815 0x0020
struct sis_type {
u_int16_t sis_vid;
u_int16_t sis_did;
@ -330,6 +361,7 @@ struct sis_type {
#define SIS_TYPE_900 1
#define SIS_TYPE_7016 2
#define SIS_TYPE_83815 3
struct sis_softc {
struct arpcom arpcom; /* interface info */