summaryrefslogtreecommitdiff
path: root/sys/dev/pci
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/pci')
-rw-r--r--sys/dev/pci/if_sis.c240
-rw-r--r--sys/dev/pci/if_sisreg.h26
2 files changed, 238 insertions, 28 deletions
diff --git a/sys/dev/pci/if_sis.c b/sys/dev/pci/if_sis.c
index 78997e1e062..b5a9bfaa2de 100644
--- a/sys/dev/pci/if_sis.c
+++ b/sys/dev/pci/if_sis.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_sis.c,v 1.3 2000/02/15 02:28:14 jason Exp $ */
+/* $OpenBSD: if_sis.c,v 1.4 2000/07/06 19:12:12 aaron Exp $ */
/*
* Copyright (c) 1997, 1998, 1999
* Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved.
@@ -30,7 +30,7 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*
- * $FreeBSD: src/sys/pci/if_sis.c,v 1.13 1999/09/25 17:29:01 wpaul Exp $
+ * $FreeBSD: src/sys/pci/if_sis.c,v 1.17 2000/07/06 06:02:04 wpaul Exp $
*/
/*
@@ -120,6 +120,7 @@ void sis_watchdog __P((struct ifnet *));
int sis_ifmedia_upd __P((struct ifnet *));
void sis_ifmedia_sts __P((struct ifnet *, struct ifmediareq *));
+u_int16_t sis_reverse __P((u_int16_t));
void sis_delay __P((struct sis_softc *));
void sis_eeprom_idle __P((struct sis_softc *));
void sis_eeprom_putbyte __P((struct sis_softc *, int));
@@ -130,8 +131,9 @@ int sis_miibus_readreg __P((struct device *, int, int));
void sis_miibus_writereg __P((struct device *, int, int, int));
void sis_miibus_statchg __P((struct device *));
-void sis_setmulti __P((struct sis_softc *));
-u_int32_t sis_calchash __P((caddr_t));
+void sis_setmulti_sis __P((struct sis_softc *));
+void sis_setmulti_ns __P((struct sis_softc *));
+u_int32_t sis_crc __P((struct sis_softc *, caddr_t));
void sis_reset __P((struct sis_softc *));
int sis_list_rx_init __P((struct sis_softc *));
int sis_list_tx_init __P((struct sis_softc *));
@@ -150,6 +152,21 @@ int sis_list_tx_init __P((struct sis_softc *));
#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.
+ */
+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);
+}
+
void sis_delay(sc)
struct sis_softc *sc;
{
@@ -233,9 +250,9 @@ 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);
/*
@@ -294,7 +311,26 @@ int sis_miibus_readreg(self, phy, reg)
int phy, reg;
{
struct sis_softc *sc = (struct sis_softc *)self;
- int i, val;
+ int i, val = 0;
+
+ 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);
@@ -327,6 +363,13 @@ void sis_miibus_writereg(self, phy, reg, data)
struct sis_softc *sc = (struct sis_softc *)self;
int i;
+ if (sc->sis_type == SIS_TYPE_83815) {
+ if (phy != 0)
+ return;
+ CSR_WRITE_4(sc, NS_BMCR + (reg * 4), data);
+ return;
+ }
+
if (sc->sis_type == SIS_TYPE_900 && phy != 0)
return;
@@ -366,7 +409,8 @@ void sis_miibus_statchg(self)
return;
}
-u_int32_t sis_calchash(addr)
+u_int32_t sis_crc(sc, addr)
+ struct sis_softc *sc;
caddr_t addr;
{
u_int32_t crc, carry;
@@ -387,11 +431,69 @@ 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);
}
-void sis_setmulti(sc)
+void sis_setmulti_ns(sc)
+ struct sis_softc *sc;
+{
+ struct ifnet *ifp;
+ struct arpcom *ac = &sc->arpcom;
+ struct ether_multi *enm;
+ struct ether_multistep step;
+ 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);
+ }
+
+ ETHER_FIRST_MULTI(step, ac, enm);
+ while (enm != NULL) {
+ h = sis_crc(sc, enm->enm_addrlo);
+ 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));
+ ETHER_NEXT_MULTI(step, enm);
+ }
+
+ CSR_WRITE_4(sc, SIS_RXFILT_CTL, filtsave);
+
+ return;
+}
+
+void sis_setmulti_sis(sc)
struct sis_softc *sc;
{
struct ifnet *ifp;
@@ -420,7 +522,7 @@ void sis_setmulti(sc)
/* now program new ones */
ETHER_FIRST_MULTI(step, ac, enm);
while (enm != NULL) {
- h = sis_calchash(enm->enm_addrlo);
+ h = sis_crc(sc, enm->enm_addrlo);
CSR_WRITE_4(sc, SIS_RXFILT_CTL, (4 + (h >> 4)) << 16);
SIS_SETBIT(sc, SIS_RXFILT_DATA, (1 << (h & 0xF)));
ETHER_NEXT_MULTI(step, enm);
@@ -462,7 +564,8 @@ int sis_probe(parent, match, aux)
{
struct pci_attach_args *pa = (struct pci_attach_args *)aux;
- if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_SIS)
+ if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_SIS &&
+ PCI_VENDOR(pa->pa_id) != PCI_VENDOR_NS)
return(0);
switch (PCI_PRODUCT(pa->pa_id)) {
@@ -470,6 +573,8 @@ int sis_probe(parent, match, aux)
return(1);
case PCI_PRODUCT_SIS_7016:
return(1);
+ case PCI_PRODUCT_NS_DP83815:
+ return(1);
}
return(0);
@@ -497,7 +602,20 @@ void sis_attach(parent, self, aux)
s = splimp();
sc->sis_unit = sc->sc_dev.dv_unit;
- sc->sis_type = SIS_TYPE_900;
+
+ switch (PCI_PRODUCT(pa->pa_id)) {
+ case PCI_PRODUCT_SIS_900:
+ sc->sis_type = SIS_TYPE_900;
+ break;
+ case PCI_PRODUCT_SIS_7016:
+ sc->sis_type = SIS_TYPE_7016;
+ break;
+ case PCI_PRODUCT_NS_DP83815:
+ sc->sis_type = SIS_TYPE_83815;
+ break;
+ default:
+ break;
+ }
/*
* Handle power management nonsense.
@@ -590,10 +708,51 @@ void sis_attach(parent, self, aux)
/*
* Get station address from the EEPROM.
*/
- sis_read_eeprom(sc, (caddr_t)&sc->arpcom.ac_enaddr, SIS_EE_NODEADDR,3,0);
+ switch (PCI_VENDOR(pa->pa_id)) {
+ case PCI_VENDOR_NS:
+ /*
+ * 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], sc->arpcom.ac_enaddr,
+ ETHER_ADDR_LEN);
+ }
+ break;
+ case PCI_VENDOR_SIS:
+ default:
+ sis_read_eeprom(sc, (caddr_t)&sc->arpcom.ac_enaddr,
+ SIS_EE_NODEADDR, 3, 0);
+ break;
+ }
printf(" address %s\n", ether_sprintf(sc->arpcom.ac_enaddr));
-
+
sc->sis_ldata_ptr = malloc(sizeof(struct sis_list_data) + 8,
M_DEVBUF, M_NOWAIT);
if (sc->sis_ldata_ptr == NULL) {
@@ -1096,15 +1255,27 @@ void sis_init(xsc)
mii = &sc->sc_mii;
/* 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) {
@@ -1120,6 +1291,17 @@ 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);
@@ -1139,7 +1321,10 @@ 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);
@@ -1266,7 +1451,10 @@ int sis_ioctl(ifp, command, data)
* Multicast list has changed; set the hardware
* filter accordingly.
*/
- sis_setmulti(sc);
+ if (sc->sis_type == SIS_TYPE_83815)
+ sis_setmulti_ns(sc);
+ else
+ sis_setmulti_sis(sc);
error = 0;
}
break;
diff --git a/sys/dev/pci/if_sisreg.h b/sys/dev/pci/if_sisreg.h
index 910f42b5ff2..f27ad80c364 100644
--- a/sys/dev/pci/if_sisreg.h
+++ b/sys/dev/pci/if_sisreg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_sisreg.h,v 1.1 1999/12/04 20:27:37 aaron Exp $ */
+/* $OpenBSD: if_sisreg.h,v 1.2 2000/07/06 19:12:12 aaron Exp $ */
/*
* Copyright (c) 1997, 1998, 1999
* Bill Paul <wpaul@ee.columbia.edu>. All rights reserved.
@@ -30,7 +30,7 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*
- * $FreeBSD: src/sys/pci/if_sisreg.h,v 1.1 1999/09/05 21:00:59 wpaul Exp $
+ * $FreeBSD: src/sys/pci/if_sisreg.h,v 1.2 2000/07/06 06:02:04 wpaul Exp $
*/
/*
@@ -75,6 +75,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
@@ -101,6 +111,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
@@ -221,6 +232,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
@@ -238,6 +252,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.
@@ -331,6 +352,7 @@ struct sis_type {
#define SIS_TYPE_900 1
#define SIS_TYPE_7016 2
+#define SIS_TYPE_83815 3
struct sis_softc {
struct device sc_dev; /* generic device structure */