summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrad Smith <brad@cvs.openbsd.org>2004-11-16 14:41:48 +0000
committerBrad Smith <brad@cvs.openbsd.org>2004-11-16 14:41:48 +0000
commit1788bde8f096de74d4e10097ebcb19da6f6946f5 (patch)
tree9a9caa58afb15a534bcb25c5b025a61c76b8e2d3
parent54e319ef100dd9d311a288a77020ce6ffdfe5cb1 (diff)
Fix tx queue (slist can be corrupted when tx interrupts hit within tx_encap).
From NetBSD ok henning@ mcbride@
-rw-r--r--sys/dev/pci/if_sk.c142
1 files changed, 114 insertions, 28 deletions
diff --git a/sys/dev/pci/if_sk.c b/sys/dev/pci/if_sk.c
index 956aef26c9f..bf1a5f39ffa 100644
--- a/sys/dev/pci/if_sk.c
+++ b/sys/dev/pci/if_sk.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_sk.c,v 1.48 2004/11/11 19:08:00 brad Exp $ */
+/* $OpenBSD: if_sk.c,v 1.49 2004/11/16 14:41:47 brad Exp $ */
/*
* Copyright (c) 1997, 1998, 1999, 2000
@@ -381,7 +381,7 @@ sk_vpd_read(struct sk_softc *sc)
sc->sk_vpd_readonly = malloc(res.vr_len, M_DEVBUF, M_NOWAIT);
if (sc->sk_vpd_readonly == NULL)
panic("sk_vpd_read");
- for (i = 0; i < res.vr_len + 1; i++)
+ for (i = 0; i < res.vr_len; i++)
sc->sk_vpd_readonly[i] = sk_vpd_readbyte(sc, i + pos);
}
@@ -594,6 +594,8 @@ sk_setmulti(struct sk_if_softc *sc_if)
SK_XM_WRITE_4(sc_if, XM_MAR2, 0);
break;
case SK_YUKON:
+ case SK_YUKON_LITE:
+ case SK_YUKON_LP:
SK_YU_WRITE_2(sc_if, YUKON_MCAH1, 0);
SK_YU_WRITE_2(sc_if, YUKON_MCAH2, 0);
SK_YU_WRITE_2(sc_if, YUKON_MCAH3, 0);
@@ -632,6 +634,8 @@ allmulti:
break;
case SK_YUKON:
+ case SK_YUKON_LITE:
+ case SK_YUKON_LP:
h = sk_yukon_hash(enm->enm_addrlo);
break;
}
@@ -653,6 +657,8 @@ allmulti:
SK_XM_WRITE_4(sc_if, XM_MAR2, hashes[1]);
break;
case SK_YUKON:
+ case SK_YUKON_LITE:
+ case SK_YUKON_LP:
SK_YU_WRITE_2(sc_if, YUKON_MCAH1, hashes[0] & 0xffff);
SK_YU_WRITE_2(sc_if, YUKON_MCAH2, (hashes[0] >> 16) & 0xffff);
SK_YU_WRITE_2(sc_if, YUKON_MCAH3, hashes[1] & 0xffff);
@@ -1005,6 +1011,8 @@ sk_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
XM_MODE_RX_PROMISC);
break;
case SK_YUKON:
+ case SK_YUKON_LITE:
+ case SK_YUKON_LP:
SK_YU_CLRBIT_2(sc_if, YUKON_RCR,
YU_RCR_UFLEN | YU_RCR_MUFLEN);
break;
@@ -1019,6 +1027,8 @@ sk_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
XM_MODE_RX_PROMISC);
break;
case SK_YUKON:
+ case SK_YUKON_LITE:
+ case SK_YUKON_LP:
SK_YU_SETBIT_2(sc_if, YUKON_RCR,
YU_RCR_UFLEN | YU_RCR_MUFLEN);
break;
@@ -1084,14 +1094,14 @@ void sk_reset(struct sk_softc *sc)
CSR_WRITE_2(sc, SK_CSR, SK_CSR_SW_RESET);
CSR_WRITE_2(sc, SK_CSR, SK_CSR_MASTER_RESET);
- if (sc->sk_type == SK_YUKON)
+ if (SK_YUKON_FAMILY(sc->sk_type))
CSR_WRITE_2(sc, SK_LINK_CTRL, SK_LINK_RESET_SET);
DELAY(1000);
CSR_WRITE_2(sc, SK_CSR, SK_CSR_SW_UNRESET);
DELAY(2);
CSR_WRITE_2(sc, SK_CSR, SK_CSR_MASTER_UNRESET);
- if (sc->sk_type == SK_YUKON)
+ if (SK_YUKON_FAMILY(sc->sk_type))
CSR_WRITE_2(sc, SK_LINK_CTRL, SK_LINK_RESET_CLEAR);
DPRINTFN(2, ("sk_reset: sk_csr=%x\n", CSR_READ_2(sc, SK_CSR)));
@@ -1294,6 +1304,8 @@ sk_attach(struct device *parent, struct device *self, void *aux)
sk_init_xmac(sc_if);
break;
case SK_YUKON:
+ case SK_YUKON_LITE:
+ case SK_YUKON_LP:
sk_init_yukon(sc_if);
break;
default:
@@ -1311,6 +1323,8 @@ sk_attach(struct device *parent, struct device *self, void *aux)
sc_if->sk_mii.mii_statchg = sk_xmac_miibus_statchg;
break;
case SK_YUKON:
+ case SK_YUKON_LITE:
+ case SK_YUKON_LP:
sc_if->sk_mii.mii_readreg = sk_marv_miibus_readreg;
sc_if->sk_mii.mii_writereg = sk_marv_miibus_writereg;
sc_if->sk_mii.mii_statchg = sk_marv_miibus_statchg;
@@ -1379,6 +1393,7 @@ skc_attach(struct device *parent, struct device *self, void *aux)
bus_size_t iosize;
int s;
u_int32_t command;
+ char *revstr;
DPRINTFN(2, ("begin skc_attach\n"));
@@ -1419,28 +1434,6 @@ skc_attach(struct device *parent, struct device *self, void *aux)
*/
command = pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
-#define SK_MK_ID(vnd,prd) \
- (((vnd) << PCI_VENDOR_SHIFT) | ((prd) << PCI_PRODUCT_SHIFT))
-
- switch (pa->pa_id) {
- case SK_MK_ID(PCI_VENDOR_SCHNEIDERKOCH, PCI_PRODUCT_SCHNEIDERKOCH_GE):
- sc->sk_type = SK_GENESIS;
- break;
- case SK_MK_ID(PCI_VENDOR_3COM, PCI_PRODUCT_3COM_3C940):
- case SK_MK_ID(PCI_VENDOR_DLINK, PCI_PRODUCT_DLINK_DGE530T):
- case SK_MK_ID(PCI_VENDOR_LINKSYS, PCI_PRODUCT_LINKSYS_EG1032):
- case SK_MK_ID(PCI_VENDOR_LINKSYS, PCI_PRODUCT_LINKSYS_EG1064):
- case SK_MK_ID(PCI_VENDOR_MARVELL, PCI_PRODUCT_MARVELL_SK_V2):
- case SK_MK_ID(PCI_VENDOR_MARVELL, PCI_PRODUCT_MARVELL_SK_V2_BELKIN):
- case SK_MK_ID(PCI_VENDOR_SCHNEIDERKOCH, PCI_PRODUCT_SCHNEIDERKOCH_SK9821v2):
- sc->sk_type = SK_YUKON;
- break;
- default:
- printf(": unknown device!\n");
- goto fail;
- }
-#undef SK_MK_ID
-
#ifdef SK_USEIOSPACE
if (!(command & PCI_COMMAND_IO_ENABLE)) {
printf(": failed to enable I/O ports!\n");
@@ -1477,6 +1470,14 @@ skc_attach(struct device *parent, struct device *self, void *aux)
#endif
sc->sc_dmatag = pa->pa_dmat;
+ sc->sk_type = sk_win_read_1(sc, SK_CHIPVER);
+ sc->sk_rev = (sk_win_read_1(sc, SK_CONFIG) >> 4);
+
+ /* bail out here if chip is not recognized */
+ if ( sc->sk_type != SK_GENESIS && ! SK_YUKON_FAMILY(sc->sk_type)) {
+ printf("%s: unknown chip type\n",sc->sk_dev.dv_xname);
+ goto fail;
+ }
DPRINTFN(2, ("skc_attach: allocate interrupt\n"));
/* Allocate interrupt */
@@ -1558,8 +1559,89 @@ skc_attach(struct device *parent, struct device *self, void *aux)
goto fail;
}
+ /* determine whether to name it with VPD or just make it up */
+ /* Marvell Yukon VPD's can freqently be bogus */
+ switch (pa->pa_id) {
+ case PCI_ID_CODE(PCI_VENDOR_SCHNEIDERKOCH,
+ PCI_PRODUCT_SCHNEIDERKOCH_GE):
+ case PCI_PRODUCT_SCHNEIDERKOCH_SK9821v2:
+ case PCI_PRODUCT_3COM_3C940:
+ case PCI_PRODUCT_DLINK_DGE530T:
+ case PCI_PRODUCT_LINKSYS_EG1032:
+ case PCI_PRODUCT_LINKSYS_EG1064:
+ case PCI_ID_CODE(PCI_VENDOR_SCHNEIDERKOCH,
+ PCI_PRODUCT_SCHNEIDERKOCH_SK9821v2):
+ case PCI_ID_CODE(PCI_VENDOR_3COM,PCI_PRODUCT_3COM_3C940):
+ case PCI_ID_CODE(PCI_VENDOR_DLINK,PCI_PRODUCT_DLINK_DGE530T):
+ case PCI_ID_CODE(PCI_VENDOR_LINKSYS,PCI_PRODUCT_LINKSYS_EG1032):
+ case PCI_ID_CODE(PCI_VENDOR_LINKSYS,PCI_PRODUCT_LINKSYS_EG1064):
+ sc->sk_name = sc->sk_vpd_prodname;
+ break;
+ case PCI_ID_CODE(PCI_VENDOR_MARVELL,PCI_PRODUCT_MARVELL_SK_V2):
+ case PCI_ID_CODE(PCI_VENDOR_MARVELL,PCI_PRODUCT_MARVELL_SK_V2_BELKIN):
+ /* whoops Yukon VPD prodname bears no resemblance to reality */
+ switch (sc->sk_type) {
+ case SK_GENESIS:
+ sc->sk_name = sc->sk_vpd_prodname;
+ break;
+ case SK_YUKON:
+ sc->sk_name = "Marvell Yukon Gigabit Ethernet";
+ break;
+ case SK_YUKON_LITE:
+ sc->sk_name = "Marvell Yukon Lite Gigabit Ethernet";
+ break;
+ case SK_YUKON_LP:
+ sc->sk_name = "Marvell Yukon LP Gigabit Ethernet";
+ break;
+ default:
+ sc->sk_name = "Marvell Yukon (Unknown) Gigabit Ethernet";
+ }
+
+ /* Yukon Lite Rev A0 needs special test, from sk98lin driver */
+ if ( sc->sk_type == SK_YUKON ) {
+ uint32_t flashaddr;
+ uint8_t testbyte;
+
+ flashaddr = sk_win_read_4(sc,SK_EP_ADDR);
+
+ /* test Flash-Address Register */
+ sk_win_write_1(sc,SK_EP_ADDR+3, 0xff);
+ testbyte = sk_win_read_1(sc, SK_EP_ADDR+3);
+
+ if (testbyte != 0) {
+ /* This is a Yukon Lite Rev A0 */
+ sc->sk_type = SK_YUKON_LITE;
+ sc->sk_rev = SK_YUKON_LITE_REV_A0;
+ /* restore Flash-Address Register */
+ sk_win_write_4(sc,SK_EP_ADDR,flashaddr);
+ }
+ }
+ break;
+ default:
+ sc->sk_name = "Unkown Marvell";
+ }
+
+ if ( sc->sk_type == SK_YUKON_LITE ) {
+ switch (sc->sk_rev) {
+ case SK_YUKON_LITE_REV_A0:
+ revstr = "A0";
+ break;
+ case SK_YUKON_LITE_REV_A1:
+ revstr = "A1";
+ break;
+ case SK_YUKON_LITE_REV_A3:
+ revstr = "A3";
+ break;
+ default:
+ revstr = "";
+ }
+ } else {
+ revstr = "";
+ }
+
/* Announce the product name. */
- printf("%s: %s\n", sc->sk_dev.dv_xname, sc->sk_vpd_prodname);
+ printf("%s: %s rev. %s(0x%x)\n", sc->sk_dev.dv_xname,
+ sc->sk_name, revstr, sc->sk_rev);
skca.skc_port = SK_PORT_A;
(void)config_found(&sc->sk_dev, &skca, skcprint);
@@ -2506,6 +2588,8 @@ sk_init(void *xsc_if)
sk_init_xmac(sc_if);
break;
case SK_YUKON:
+ case SK_YUKON_LITE:
+ case SK_YUKON_LP:
sk_init_yukon(sc_if);
break;
}
@@ -2591,7 +2675,7 @@ sk_init(void *xsc_if)
XM_MMUCMD_TX_ENB|XM_MMUCMD_RX_ENB);
}
- if (sc->sk_type == SK_YUKON) {
+ if (SK_YUKON_FAMILY(sc->sk_type)) {
u_int16_t reg = SK_YU_READ_2(sc_if, YUKON_GPCR);
reg |= YU_GPCR_TXEN | YU_GPCR_RXEN;
reg &= ~(YU_GPCR_SPEED_EN | YU_GPCR_DPLX_EN);
@@ -2640,6 +2724,8 @@ sk_stop(struct sk_if_softc *sc_if)
SK_IF_WRITE_4(sc_if, 0, SK_RXF1_CTL, SK_FIFO_RESET);
break;
case SK_YUKON:
+ case SK_YUKON_LITE:
+ case SK_YUKON_LP:
SK_IF_WRITE_1(sc_if,0, SK_RXMF1_CTRL_TEST, SK_RFCTL_RESET_SET);
SK_IF_WRITE_1(sc_if,0, SK_TXMF1_CTRL_TEST, SK_TFCTL_RESET_SET);
break;