summaryrefslogtreecommitdiffstats
path: root/sys/pci/if_ti.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/pci/if_ti.c')
-rw-r--r--sys/pci/if_ti.c87
1 files changed, 70 insertions, 17 deletions
diff --git a/sys/pci/if_ti.c b/sys/pci/if_ti.c
index 358a3f0..8d373ef 100644
--- a/sys/pci/if_ti.c
+++ b/sys/pci/if_ti.c
@@ -136,6 +136,8 @@ static const char rcsid[] =
static struct ti_type ti_devs[] = {
{ ALT_VENDORID, ALT_DEVICEID_ACENIC,
"Alteon AceNIC Gigabit Ethernet" },
+ { ALT_VENDORID, ALT_DEVICEID_ACENIC_COPPER,
+ "Alteon AceNIC 1000baseTX Gigabit Ethernet" },
{ TC_VENDORID, TC_DEVICEID_3C985,
"3Com 3c985-SX Gigabit Ethernet" },
{ NG_VENDORID, NG_DEVICEID_GA620,
@@ -946,7 +948,7 @@ static int ti_init_rx_ring_jumbo(sc)
register int i;
struct ti_cmd_desc cmd;
- for (i = 0; i < (TI_JSLOTS - 20); i++) {
+ for (i = 0; i < TI_JUMBO_RX_RING_CNT; i++) {
if (ti_newbuf_jumbo(sc, i, NULL) == ENOBUFS)
return(ENOBUFS);
};
@@ -1688,6 +1690,17 @@ static int ti_attach(dev)
goto fail;
}
+ /*
+ * We really need a better way to tell a 1000baseTX card
+ * from a 1000baseSX one, since in theory there could be
+ * OEMed 1000baseTX cards from lame vendors who aren't
+ * clever enough to change the PCI ID. For the moment
+ * though, the AceNIC is the only copper card available.
+ */
+ if (pci_get_vendor(dev) == ALT_VENDORID &&
+ pci_get_device(dev) == ALT_DEVICEID_ACENIC_COPPER)
+ sc->ti_copper = 1;
+
/* Set default tuneable values. */
sc->ti_stat_ticks = 2 * TI_TICKS_PER_SEC;
sc->ti_rx_coal_ticks = TI_TICKS_PER_SEC / 5000;
@@ -1712,12 +1725,30 @@ static int ti_attach(dev)
/* Set up ifmedia support. */
ifmedia_init(&sc->ifmedia, IFM_IMASK, ti_ifmedia_upd, ti_ifmedia_sts);
- ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_FL, 0, NULL);
- ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_FL|IFM_FDX, 0, NULL);
- ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_FX, 0, NULL);
- ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_FX|IFM_FDX, 0, NULL);
- ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_1000_SX, 0, NULL);
- ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_1000_SX|IFM_FDX, 0, NULL);
+ if (sc->ti_copper) {
+ /*
+ * Copper cards allow manual 10/100 mode selection,
+ * but not manual 1000baseTX mode selection. Why?
+ * Becuase currently there's no way to specify the
+ * master/slave setting through the firmware interface,
+ * so Alteon decided to just bag it and handle it
+ * via autonegotiation.
+ */
+ ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T, 0, NULL);
+ ifmedia_add(&sc->ifmedia,
+ IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL);
+ ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_TX, 0, NULL);
+ ifmedia_add(&sc->ifmedia,
+ IFM_ETHER|IFM_100_TX|IFM_FDX, 0, NULL);
+ ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_1000_TX, 0, NULL);
+ ifmedia_add(&sc->ifmedia,
+ IFM_ETHER|IFM_1000_TX|IFM_FDX, 0, NULL);
+ } else {
+ /* Fiber cards don't support 10/100 modes. */
+ ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_1000_SX, 0, NULL);
+ ifmedia_add(&sc->ifmedia,
+ IFM_ETHER|IFM_1000_SX|IFM_FDX, 0, NULL);
+ }
ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL);
ifmedia_set(&sc->ifmedia, IFM_ETHER|IFM_AUTO);
@@ -2297,17 +2328,24 @@ static int ti_ifmedia_upd(ifp)
TI_CMD_CODE_NEGOTIATE_BOTH, 0);
break;
case IFM_1000_SX:
+ case IFM_1000_TX:
CSR_WRITE_4(sc, TI_GCR_GLINK, TI_GLNK_PREF|TI_GLNK_1000MB|
- TI_GLNK_FULL_DUPLEX|TI_GLNK_RX_FLOWCTL_Y|TI_GLNK_ENB);
+ TI_GLNK_RX_FLOWCTL_Y|TI_GLNK_ENB);
CSR_WRITE_4(sc, TI_GCR_LINK, 0);
+ if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX) {
+ TI_SETBIT(sc, TI_GCR_GLINK, TI_GLNK_FULL_DUPLEX);
+ }
TI_DO_CMD(TI_CMD_LINK_NEGOTIATION,
TI_CMD_CODE_NEGOTIATE_GIGABIT, 0);
break;
case IFM_100_FX:
case IFM_10_FL:
+ case IFM_100_TX:
+ case IFM_10_T:
CSR_WRITE_4(sc, TI_GCR_GLINK, 0);
CSR_WRITE_4(sc, TI_GCR_LINK, TI_LNK_ENB|TI_LNK_PREF);
- if (IFM_SUBTYPE(ifm->ifm_media) == IFM_100_FX) {
+ if (IFM_SUBTYPE(ifm->ifm_media) == IFM_100_FX ||
+ IFM_SUBTYPE(ifm->ifm_media) == IFM_100_TX) {
TI_SETBIT(sc, TI_GCR_LINK, TI_LNK_100MB);
} else {
TI_SETBIT(sc, TI_GCR_LINK, TI_LNK_10MB);
@@ -2333,6 +2371,7 @@ static void ti_ifmedia_sts(ifp, ifmr)
struct ifmediareq *ifmr;
{
struct ti_softc *sc;
+ u_int32_t media = 0;
sc = ifp->if_softc;
@@ -2344,15 +2383,29 @@ static void ti_ifmedia_sts(ifp, ifmr)
ifmr->ifm_status |= IFM_ACTIVE;
- if (sc->ti_linkstat == TI_EV_CODE_GIG_LINK_UP)
- ifmr->ifm_active |= IFM_1000_SX|IFM_FDX;
- else if (sc->ti_linkstat == TI_EV_CODE_LINK_UP) {
- u_int32_t media;
+ if (sc->ti_linkstat == TI_EV_CODE_GIG_LINK_UP) {
+ media = CSR_READ_4(sc, TI_GCR_GLINK_STAT);
+ if (sc->ti_copper)
+ ifmr->ifm_active |= IFM_1000_TX;
+ else
+ ifmr->ifm_active |= IFM_1000_SX;
+ if (media & TI_GLNK_FULL_DUPLEX)
+ ifmr->ifm_active |= IFM_FDX;
+ else
+ ifmr->ifm_active |= IFM_HDX;
+ } else if (sc->ti_linkstat == TI_EV_CODE_LINK_UP) {
media = CSR_READ_4(sc, TI_GCR_LINK_STAT);
- if (media & TI_LNK_100MB)
- ifmr->ifm_active |= IFM_100_FX;
- if (media & TI_LNK_10MB)
- ifmr->ifm_active |= IFM_10_FL;
+ if (sc->ti_copper) {
+ if (media & TI_LNK_100MB)
+ ifmr->ifm_active |= IFM_100_TX;
+ if (media & TI_LNK_10MB)
+ ifmr->ifm_active |= IFM_10_T;
+ } else {
+ if (media & TI_LNK_100MB)
+ ifmr->ifm_active |= IFM_100_FX;
+ if (media & TI_LNK_10MB)
+ ifmr->ifm_active |= IFM_10_FL;
+ }
if (media & TI_LNK_FULL_DUPLEX)
ifmr->ifm_active |= IFM_FDX;
if (media & TI_LNK_HALF_DUPLEX)
OpenPOWER on IntegriCloud