summaryrefslogtreecommitdiffstats
path: root/sys/pci
diff options
context:
space:
mode:
authorjon <jon@FreeBSD.org>2000-10-19 08:34:32 +0000
committerjon <jon@FreeBSD.org>2000-10-19 08:34:32 +0000
commit4580b26b321a7db757880cf45873ce30aa10fd27 (patch)
treecff7f58d8da222e806bc63d80206f2c95b70295c /sys/pci
parente3c86757f4279913a9a3eaa797fdcc8c2b9dba4f (diff)
downloadFreeBSD-src-4580b26b321a7db757880cf45873ce30aa10fd27.zip
FreeBSD-src-4580b26b321a7db757880cf45873ce30aa10fd27.tar.gz
NEWCARD/Cardbus -
This commit adds support for Xircom X3201 based cardbus cards. Support for the TDK 78Q2120 MII is also added. IBM Etherjet, Intel and Xircom cards uses these chips. Note that as a result of this commit, some Intel/DEC 21143 based cardbus cards will also attach, but not get link. That is being looked at.
Diffstat (limited to 'sys/pci')
-rw-r--r--sys/pci/if_dc.c183
-rw-r--r--sys/pci/if_dcreg.h33
2 files changed, 207 insertions, 9 deletions
diff --git a/sys/pci/if_dc.c b/sys/pci/if_dc.c
index 6a437a4..84538e4 100644
--- a/sys/pci/if_dc.c
+++ b/sys/pci/if_dc.c
@@ -45,6 +45,7 @@
* ADMtek AN985 (www.admtek.com.tw)
* Davicom DM9100, DM9102, DM9102A (www.davicom8.com)
* Accton EN1217 (www.accton.com)
+ * Xircom X3201 (www.xircom.com)
*
* Datasheets for the 21143 are available at developer.intel.com.
* Datasheets for the clone parts can be found at their respective sites.
@@ -179,6 +180,8 @@ static struct dc_type dc_devs[] = {
"82c169 PNIC 10/100BaseTX" },
{ DC_VENDORID_ACCTON, DC_DEVICEID_EN1217,
"Accton EN1217 10/100BaseTX" },
+ { DC_VENDORID_XIRCOM, DC_DEVICEID_X3201,
+ "Xircom X3201 10/100BaseTX" },
{ 0, 0, NULL }
};
@@ -212,6 +215,8 @@ static void dc_eeprom_putbyte __P((struct dc_softc *, int));
static void dc_eeprom_getword __P((struct dc_softc *, int, u_int16_t *));
static void dc_eeprom_getword_pnic
__P((struct dc_softc *, int, u_int16_t *));
+static void dc_eeprom_getword_xircom
+ __P((struct dc_softc *, int, u_int16_t *));
static void dc_read_eeprom __P((struct dc_softc *, caddr_t, int,
int, int));
@@ -232,6 +237,7 @@ static u_int32_t dc_crc_be __P((caddr_t));
static void dc_setfilt_21143 __P((struct dc_softc *));
static void dc_setfilt_asix __P((struct dc_softc *));
static void dc_setfilt_admtek __P((struct dc_softc *));
+static void dc_setfilt_xircom __P((struct dc_softc *));
static void dc_setfilt __P((struct dc_softc *));
@@ -284,6 +290,7 @@ static driver_t dc_driver = {
static devclass_t dc_devclass;
+DRIVER_MODULE(if_dc, cardbus, dc_driver, dc_devclass, 0, 0);
DRIVER_MODULE(if_dc, pci, dc_driver, dc_devclass, 0, 0);
DRIVER_MODULE(miibus, dc, miibus_driver, miibus_devclass, 0, 0);
@@ -402,6 +409,29 @@ static void dc_eeprom_getword_pnic(sc, addr, dest)
/*
* Read a word of data stored in the EEPROM at address 'addr.'
+ * The Xircom X3201 has its own non-standard way to read
+ * the EEPROM, too.
+ */
+static void dc_eeprom_getword_xircom(sc, addr, dest)
+ struct dc_softc *sc;
+ int addr;
+ u_int16_t *dest;
+{
+ SIO_SET(DC_SIO_ROMSEL | DC_SIO_ROMCTL_READ);
+
+ addr *= 2;
+ CSR_WRITE_4(sc, DC_ROM, addr | 0x160);
+ *dest = (u_int16_t)CSR_READ_4(sc, DC_SIO)&0xff;
+ addr += 1;
+ CSR_WRITE_4(sc, DC_ROM, addr | 0x160);
+ *dest |= ((u_int16_t)CSR_READ_4(sc, DC_SIO)&0xff) << 8;
+
+ SIO_CLR(DC_SIO_ROMSEL | DC_SIO_ROMCTL_READ);
+ return;
+}
+
+/*
+ * Read a word of data stored in the EEPROM at address 'addr.'
*/
static void dc_eeprom_getword(sc, addr, dest)
struct dc_softc *sc;
@@ -466,6 +496,8 @@ static void dc_read_eeprom(sc, dest, off, cnt, swap)
for (i = 0; i < cnt; i++) {
if (DC_IS_PNIC(sc))
dc_eeprom_getword_pnic(sc, off + i, &word);
+ else if (DC_IS_XIRCOM(sc))
+ dc_eeprom_getword_xircom(sc, off + i, &word);
else
dc_eeprom_getword(sc, off + i, &word);
ptr = (u_int16_t *)(dest + (i * 2));
@@ -922,6 +954,15 @@ static u_int32_t dc_crc_le(sc, addr)
if (sc->dc_flags & DC_64BIT_HASH)
return (crc & ((1 << DC_BITS_64) - 1));
+ /* Xircom's hash filtering table is different (read: weird) */
+ /* Xircom uses the LEAST significant bits */
+ if (DC_IS_XIRCOM(sc)) {
+ if ((crc & 0x180) == 0x180)
+ return (crc & 0x0F) + (crc & 0x70)*3 + (14 << 4);
+ else
+ return (crc & 0x1F) + ((crc>>1) & 0xF0)*3 + (12 << 4);
+ }
+
return (crc & ((1 << DC_BITS_512) - 1));
}
@@ -1158,6 +1199,76 @@ void dc_setfilt_asix(sc)
return;
}
+void dc_setfilt_xircom(sc)
+ struct dc_softc *sc;
+{
+ struct dc_desc *sframe;
+ u_int32_t h, *sp;
+ struct ifmultiaddr *ifma;
+ struct ifnet *ifp;
+ int i;
+
+ ifp = &sc->arpcom.ac_if;
+ DC_CLRBIT(sc, DC_NETCFG, (DC_NETCFG_TX_ON|DC_NETCFG_RX_ON));
+
+ 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 = (u_int32_t *)&sc->dc_cdata.dc_sbuf;
+ bzero((char *)sp, DC_SFRAME_LEN);
+
+ sframe->dc_data = vtophys(&sc->dc_cdata.dc_sbuf);
+ sframe->dc_ctl = DC_SFRAME_LEN | DC_TXCTL_SETUP | DC_TXCTL_TLINK |
+ DC_FILTER_HASHPERF | DC_TXCTL_FINT;
+
+ sc->dc_cdata.dc_tx_chain[i] = (struct mbuf *)&sc->dc_cdata.dc_sbuf;
+
+ /* If we want promiscuous mode, set the allframes bit. */
+ if (ifp->if_flags & IFF_PROMISC)
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_PROMISC);
+ else
+ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_RX_PROMISC);
+
+ if (ifp->if_flags & IFF_ALLMULTI)
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI);
+ else
+ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI);
+
+ 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 = dc_crc_le(sc, LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
+ sp[h >> 4] |= 1 << (h & 0xF);
+ }
+
+ if (ifp->if_flags & IFF_BROADCAST) {
+ h = dc_crc_le(sc, (caddr_t)&etherbroadcastaddr);
+ sp[h >> 4] |= 1 << (h & 0xF);
+ }
+
+ /* Set our MAC address */
+ sp[0] = ((u_int16_t *)sc->arpcom.ac_enaddr)[0];
+ sp[1] = ((u_int16_t *)sc->arpcom.ac_enaddr)[1];
+ sp[2] = ((u_int16_t *)sc->arpcom.ac_enaddr)[2];
+
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_TX_ON);
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_ON);
+ ifp->if_flags |= IFF_RUNNING;
+ sframe->dc_status = DC_TXSTAT_OWN;
+ CSR_WRITE_4(sc, DC_TXSTART, 0xFFFFFFFF);
+
+ /*
+ * wait some time...
+ */
+ DELAY(1000);
+
+ ifp->if_timer = 5;
+
+ return;
+}
+
static void dc_setfilt(sc)
struct dc_softc *sc;
{
@@ -1171,7 +1282,10 @@ static void dc_setfilt(sc)
if (DC_IS_ADMTEK(sc))
dc_setfilt_admtek(sc);
- return;
+ if (DC_IS_XIRCOM(sc))
+ dc_setfilt_xircom(sc);
+
+ return;
}
/*
@@ -1338,7 +1452,7 @@ static void dc_reset(sc)
break;
}
- if (DC_IS_ASIX(sc) || DC_IS_ADMTEK(sc)) {
+ if (DC_IS_ASIX(sc) || DC_IS_ADMTEK(sc) || DC_IS_XIRCOM(sc) || DC_IS_INTEL(sc)) {
DELAY(10000);
DC_CLRBIT(sc, DC_BUSCTL, DC_BUSCTL_RESET);
i = 0;
@@ -1788,6 +1902,14 @@ static int dc_attach(dev)
sc->dc_flags |= DC_REDUCED_MII_POLL;
sc->dc_pmode = DC_PMODE_MII;
break;
+ case DC_DEVICEID_X3201:
+ sc->dc_type = DC_TYPE_XIRCOM;
+ sc->dc_flags |= DC_TX_INTR_ALWAYS | DC_TX_COALESCE;
+ /*
+ * We don't actually need to coalesce, but we're doing
+ * it to obtain a double word aligned buffer.
+ */
+ break;
default:
printf("dc%d: unknown device: %x\n", sc->dc_unit,
sc->dc_info->dc_did);
@@ -1805,7 +1927,7 @@ static int dc_attach(dev)
dc_reset(sc);
/* Take 21143 out of snooze mode */
- if (DC_IS_INTEL(sc)) {
+ if (DC_IS_INTEL(sc) || DC_IS_XIRCOM(sc)) {
command = pci_read_config(dev, DC_PCI_CFDD, 4);
command &= ~(DC_CFDD_SNOOZE_MODE|DC_CFDD_SLEEP_MODE);
pci_write_config(dev, DC_PCI_CFDD, command, 4);
@@ -1852,6 +1974,9 @@ static int dc_attach(dev)
case DC_TYPE_AN985:
dc_read_eeprom(sc, (caddr_t)&eaddr, DC_AL_EE_NODEADDR, 3, 0);
break;
+ case DC_TYPE_XIRCOM:
+ dc_read_eeprom(sc, (caddr_t)&eaddr, 3, 3, 0);
+ break;
default:
dc_read_eeprom(sc, (caddr_t)&eaddr, DC_EE_NODEADDR, 3, 0);
break;
@@ -1883,6 +2008,7 @@ static int dc_attach(dev)
ifp->if_softc = sc;
ifp->if_unit = unit;
ifp->if_name = "dc";
+ /* XXX: bleah, MTU gets overwritten in ether_ifattach() */
ifp->if_mtu = ETHERMTU;
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
ifp->if_ioctl = dc_ioctl;
@@ -1937,6 +2063,19 @@ static int dc_attach(dev)
goto fail;
}
+ if (DC_IS_XIRCOM(sc)) {
+ /*
+ * setup General Purpose Port mode and data so the tulip
+ * can talk to the MII.
+ */
+ CSR_WRITE_4(sc, DC_SIAGP, DC_SIAGP_WRITE_EN | DC_SIAGP_INT1_EN |
+ DC_SIAGP_MD_GP2_OUTPUT | DC_SIAGP_MD_GP0_OUTPUT);
+ DELAY(10);
+ CSR_WRITE_4(sc, DC_SIAGP, DC_SIAGP_INT1_EN |
+ DC_SIAGP_MD_GP2_OUTPUT | DC_SIAGP_MD_GP0_OUTPUT);
+ DELAY(10);
+ }
+
/*
* Call MI attach routine.
*/
@@ -2420,11 +2559,23 @@ static void dc_txeof(sc)
continue;
}
- if (/*sc->dc_type == DC_TYPE_21143 &&*/
- sc->dc_pmode == DC_PMODE_MII &&
- ((txstat & 0xFFFF) & ~(DC_TXSTAT_ERRSUM|
- DC_TXSTAT_NOCARRIER|DC_TXSTAT_CARRLOST)))
- txstat &= ~DC_TXSTAT_ERRSUM;
+ if (DC_IS_XIRCOM(sc)) {
+ /*
+ * XXX: Why does my Xircom taunt me so?
+ * For some reason it likes setting the CARRLOST flag
+ * even when the carrier is there. wtf?!? */
+ if (/*sc->dc_type == DC_TYPE_21143 &&*/
+ sc->dc_pmode == DC_PMODE_MII &&
+ ((txstat & 0xFFFF) & ~(DC_TXSTAT_ERRSUM|
+ DC_TXSTAT_NOCARRIER)))
+ txstat &= ~DC_TXSTAT_ERRSUM;
+ } else {
+ if (/*sc->dc_type == DC_TYPE_21143 &&*/
+ sc->dc_pmode == DC_PMODE_MII &&
+ ((txstat & 0xFFFF) & ~(DC_TXSTAT_ERRSUM|
+ DC_TXSTAT_NOCARRIER|DC_TXSTAT_CARRLOST)))
+ txstat &= ~DC_TXSTAT_ERRSUM;
+ }
if (txstat & DC_TXSTAT_ERRSUM) {
ifp->if_oerrors++;
@@ -2557,7 +2708,8 @@ static void dc_intr(arg)
/* Disable interrupts. */
CSR_WRITE_4(sc, DC_IMR, 0x00000000);
- while((status = CSR_READ_4(sc, DC_ISR)) & DC_INTRS) {
+ while(((status = CSR_READ_4(sc, DC_ISR)) & DC_INTRS)
+ && status != 0xFFFFFFFF) {
CSR_WRITE_4(sc, DC_ISR, status);
@@ -2883,6 +3035,19 @@ static void dc_init(xsc)
DC_SETBIT(sc, DC_MX_MAGICPACKET, DC_MX_MAGIC_98715);
}
+ if (DC_IS_XIRCOM(sc)) {
+ /*
+ * setup General Purpose Port mode and data so the tulip
+ * can talk to the MII.
+ */
+ CSR_WRITE_4(sc, DC_SIAGP, DC_SIAGP_WRITE_EN | DC_SIAGP_INT1_EN |
+ DC_SIAGP_MD_GP2_OUTPUT | DC_SIAGP_MD_GP0_OUTPUT);
+ DELAY(10);
+ CSR_WRITE_4(sc, DC_SIAGP, DC_SIAGP_INT1_EN |
+ DC_SIAGP_MD_GP2_OUTPUT | DC_SIAGP_MD_GP0_OUTPUT);
+ DELAY(10);
+ }
+
DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_TX_THRESH);
DC_SETBIT(sc, DC_NETCFG, DC_TXTHRESH_72BYTES);
diff --git a/sys/pci/if_dcreg.h b/sys/pci/if_dcreg.h
index e72d8b4..f36d6b3 100644
--- a/sys/pci/if_dcreg.h
+++ b/sys/pci/if_dcreg.h
@@ -52,6 +52,7 @@
#define DC_SIARESET 0x68 /* SIA connectivity */
#define DC_10BTCTRL 0x70 /* SIA transmit and receive */
#define DC_WATCHDOG 0x78 /* SIA and general purpose port */
+#define DC_SIAGP 0x78 /* SIA and general purpose port (X3201) */
/*
* There are two general 'types' of MX chips that we need to be
@@ -75,6 +76,7 @@
#define DC_TYPE_DM9102 0x8 /* Davicom DM9102 */
#define DC_TYPE_PNICII 0x9 /* 82c115 PNIC II */
#define DC_TYPE_PNIC 0xA /* 82c168/82c169 PNIC I */
+#define DC_TYPE_XIRCOM 0xB /* Xircom X3201 */
#define DC_IS_MACRONIX(x) \
(x->dc_type == DC_TYPE_98713 || \
@@ -92,6 +94,7 @@
#define DC_IS_DAVICOM(x) (x->dc_type == DC_TYPE_DM9102)
#define DC_IS_PNICII(x) (x->dc_type == DC_TYPE_PNICII)
#define DC_IS_PNIC(x) (x->dc_type == DC_TYPE_PNIC)
+#define DC_IS_XIRCOM(x) (x->dc_type == DC_TYPE_XIRCOM)
/* MII/symbol mode port types */
#define DC_PMODE_MII 0x1
@@ -349,6 +352,25 @@
#define DC_WDOG_CTLWREN 0x08000000
/*
+ * SIA and General Purpose Port register (X3201)
+ */
+#define DC_SIAGP_RXMATCH 0x40000000
+#define DC_SIAGP_INT1 0x20000000
+#define DC_SIAGP_INT0 0x10000000
+#define DC_SIAGP_WRITE_EN 0x08000000
+#define DC_SIAGP_RXMATCH_EN 0x04000000
+#define DC_SIAGP_INT1_EN 0x02000000
+#define DC_SIAGP_INT0_EN 0x01000000
+#define DC_SIAGP_LED3 0x00800000
+#define DC_SIAGP_LED2 0x00400000
+#define DC_SIAGP_LED1 0x00200000
+#define DC_SIAGP_LED0 0x00100000
+#define DC_SIAGP_MD_GP3_OUTPUT 0x00080000
+#define DC_SIAGP_MD_GP2_OUTPUT 0x00040000
+#define DC_SIAGP_MD_GP1_OUTPUT 0x00020000
+#define DC_SIAGP_MD_GP0_OUTPUT 0x00010000
+
+/*
* Size of a setup frame.
*/
#define DC_SFRAME_LEN 192
@@ -834,6 +856,17 @@ struct dc_softc {
#define DC_DEVICEID_EN1217 0x1217
/*
+ * Xircom vendor ID
+ */
+#define DC_VENDORID_XIRCOM 0x115d
+
+/*
+ * Xircom device IDs.
+ */
+#define DC_DEVICEID_X3201 0x0003
+
+
+/*
* PCI low memory base and low I/O base register, and
* other PCI registers.
*/
OpenPOWER on IntegriCloud