diff options
author | semenu <semenu@FreeBSD.org> | 2001-02-07 20:11:02 +0000 |
---|---|---|
committer | semenu <semenu@FreeBSD.org> | 2001-02-07 20:11:02 +0000 |
commit | b3d64495b94dc135a232b4fba8d12f9cc7ee4e7d (patch) | |
tree | 9545682391ebfb6f593f78e12b6bbc2a79e84a2e /sys/dev | |
parent | e472dcaec284f55073806b3253159e12983c9fbf (diff) | |
download | FreeBSD-src-b3d64495b94dc135a232b4fba8d12f9cc7ee4e7d.zip FreeBSD-src-b3d64495b94dc135a232b4fba8d12f9cc7ee4e7d.tar.gz |
Add support for SMC9432FTX card, possibly othe fiber optic SMC9432 family
cards will work too.
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/tx/if_tx.c | 205 | ||||
-rw-r--r-- | sys/dev/tx/if_txreg.h | 27 | ||||
-rw-r--r-- | sys/dev/tx/if_txvar.h | 27 |
3 files changed, 216 insertions, 43 deletions
diff --git a/sys/dev/tx/if_tx.c b/sys/dev/tx/if_tx.c index 934b943..b16ac50 100644 --- a/sys/dev/tx/if_tx.c +++ b/sys/dev/tx/if_tx.c @@ -75,6 +75,9 @@ #include <dev/mii/mii.h> #include <dev/mii/miivar.h> +#include <dev/mii/miidevs.h> + +#include <dev/mii/lxtphyreg.h> #include "miibus_if.h" @@ -116,6 +119,8 @@ #include <dev/mii/mii.h> #include <dev/mii/miivar.h> +#include <dev/mii/miidevs.h> +#include <dev/mii/lxtphyreg.h> #include <dev/pci/pcivar.h> #include <dev/pci/pcireg.h> @@ -546,7 +551,7 @@ epic_freebsd_attach(dev) if( ' ' == (u_int8_t)tmp ) break; printf("%c",(u_int8_t)tmp); } - printf ("\n"); + printf("\n"); /* Attach to OS's managers */ ether_ifattach(ifp, ETHER_BPF_SUPPORTED); @@ -779,14 +784,24 @@ epic_common_attach(sc) /* Set defaults */ sc->tx_threshold = TRANSMIT_THRESHOLD; sc->txcon = TXCON_DEFAULT; + sc->miicfg = MIICFG_SMI_ENABLE; + sc->phyid = EPIC_UNKN_PHY; + sc->serinst = -1; + + /* Fetch card id */ + sc->cardvend = pci_read_config(sc->dev, PCIR_SUBVEND_0, 2); + sc->cardid = pci_read_config(sc->dev, PCIR_SUBDEV_0, 2); + + if (sc->cardvend != SMC_VENDORID) + printf(EPIC_FORMAT ": unknown card vendor 0x%04x\n", EPIC_ARGS(sc), sc->cardvend); return 0; } /* * This is if_start handler. It takes mbufs from if_snd queue - * and quque them for transmit, one by one, until TX ring become full - * or quque become empty. + * and queue them for transmit, one by one, until TX ring become full + * or queue become empty. */ static void epic_ifstart(ifp) @@ -1127,39 +1142,124 @@ epic_ifmedia_upd(ifp) epic_softc_t *sc; struct mii_data *mii; struct ifmedia *ifm; + struct mii_softc *miisc; + int cfg, media; sc = ifp->if_softc; mii = device_get_softc(sc->miibus); ifm = &mii->mii_media; + media = ifm->ifm_cur->ifm_media; /* Do not do anything if interface is not up */ if(!(ifp->if_flags & IFF_UP)) return (0); - if((IFM_INST(ifm->ifm_cur->ifm_media) == mii->mii_instance) && - (IFM_SUBTYPE(ifm->ifm_cur->ifm_media) == IFM_10_2)) { - /* Call this, to isolate (and powerdown ?) all PHYs */ - mii_mediachg(mii); + /* + * Lookup current selected PHY + */ + if (IFM_INST(media) == sc->serinst) { + sc->phyid = EPIC_SERIAL; + sc->physc = NULL; + } else { + /* If we're not selecting serial interface, select MII mode */ + sc->miicfg &= ~MIICFG_SERIAL_ENABLE; + CSR_WRITE_4(sc, MIICFG, sc->miicfg); - /* Select BNC */ - CSR_WRITE_4(sc, MIICFG, MIICFG_SERIAL_ENABLE | - MIICFG_694_ENABLE | MIICFG_SMI_ENABLE); + dprintf((EPIC_FORMAT ": MII selected\n", EPIC_ARGS(sc))); - /* Update txcon register */ - epic_miibus_statchg(sc->dev); + /* Default to unknown PHY */ + sc->phyid = EPIC_UNKN_PHY; - return (0); - } else if(IFM_INST(ifm->ifm_cur->ifm_media) < mii->mii_instance) { - /* Select MII */ - CSR_WRITE_4(sc, MIICFG, MIICFG_SMI_ENABLE); + /* Lookup selected PHY */ + for (miisc = LIST_FIRST(&mii->mii_phys); miisc != NULL; + miisc = LIST_NEXT(miisc, mii_list)) { + if (IFM_INST(media) == miisc->mii_inst) { + sc->physc = miisc; + break; + } + } - /* Give it to miibus... */ - mii_mediachg(mii); + /* Identify selected PHY */ + if (sc->physc) { + int id1, id2, model, oui; - return (0); + id1 = PHY_READ(sc->physc, MII_PHYIDR1); + id2 = PHY_READ(sc->physc, MII_PHYIDR2); + + oui = MII_OUI(id1, id2); + model = MII_MODEL(id2); + switch (oui) { + case MII_OUI_QUALSEMI: + if (model == MII_MODEL_QUALSEMI_QS6612) + sc->phyid = EPIC_QS6612_PHY; + break; + case MII_OUI_xxALTIMA: + if (model == MII_MODEL_xxALTIMA_AC101) + sc->phyid = EPIC_AC101_PHY; + break; + case MII_OUI_xxLEVEL1: + if (model == MII_MODEL_xxLEVEL1_LXT970) + sc->phyid = EPIC_LXT970_PHY; + break; + } + } + } + + /* + * Do PHY specific card setup + */ + + /* Call this, to isolate all not selected PHYs and + * set up selected + */ + mii_mediachg(mii); + + /* Do our own setup */ + switch (sc->phyid) { + case EPIC_QS6612_PHY: + break; + case EPIC_AC101_PHY: + /* We have to powerup fiber tranceivers */ + if (IFM_SUBTYPE(media) == IFM_100_FX) + sc->miicfg |= MIICFG_694_ENABLE; + else + sc->miicfg &= ~MIICFG_694_ENABLE; + CSR_WRITE_4(sc, MIICFG, sc->miicfg); + + break; + case EPIC_LXT970_PHY: + /* We have to powerup fiber tranceivers */ + cfg = PHY_READ(sc->physc, MII_LXTPHY_CONFIG); + if (IFM_SUBTYPE(media) == IFM_100_FX) + cfg |= CONFIG_LEDC1 | CONFIG_LEDC0; + else + cfg &= ~(CONFIG_LEDC1 | CONFIG_LEDC0); + PHY_WRITE(sc->physc, MII_LXTPHY_CONFIG, cfg); + + break; + case EPIC_SERIAL: + /* Select serial PHY, (10base2/BNC usually) */ + sc->miicfg |= MIICFG_694_ENABLE | MIICFG_SERIAL_ENABLE; + CSR_WRITE_4(sc, MIICFG, sc->miicfg); + + /* There is no driver to fill this */ + mii->mii_media_active = media; + mii->mii_media_status = 0; + + /* We need to call this manualy as i wasn't called + * in mii_mediachg() + */ + epic_miibus_statchg(sc->dev); + + dprintf((EPIC_FORMAT ": SERIAL selected\n", EPIC_ARGS(sc))); + + break; + default: + printf(EPIC_FORMAT ": ERROR! Unknown PHY selected\n", EPIC_ARGS(sc)); + return (EINVAL); } - return(EINVAL); + return(0); } /* @@ -1178,6 +1278,7 @@ epic_ifmedia_sts(ifp, ifmr) mii = device_get_softc(sc->miibus); ifm = &mii->mii_media; + /* Nothing should be selected if interface is down */ if(!(ifp->if_flags & IFF_UP)) { ifmr->ifm_active = IFM_NONE; ifmr->ifm_status = 0; @@ -1185,18 +1286,13 @@ epic_ifmedia_sts(ifp, ifmr) return; } - if((IFM_INST(ifm->ifm_cur->ifm_media) == mii->mii_instance) && - (IFM_SUBTYPE(ifm->ifm_cur->ifm_media) == IFM_10_2)) { - ifmr->ifm_active = ifm->ifm_cur->ifm_media; - ifmr->ifm_status = 0; - } else if(IFM_INST(ifm->ifm_cur->ifm_media) < mii->mii_instance) { + /* Call underlying pollstat, if not serial PHY */ + if (sc->phyid != EPIC_SERIAL) mii_pollstat(mii); - ifmr->ifm_active = mii->mii_media_active; - ifmr->ifm_status = mii->mii_media_status; - } else { - ifmr->ifm_active = IFM_NONE; - ifmr->ifm_status = 0; - } + + /* Simply copy media info */ + ifmr->ifm_active = mii->mii_media_active; + ifmr->ifm_status = mii->mii_media_status; return; } @@ -1210,20 +1306,34 @@ epic_miibus_statchg(dev) { epic_softc_t *sc; struct mii_data *mii; + int media; sc = device_get_softc(dev); mii = device_get_softc(sc->miibus); + media = mii->mii_media_active; sc->txcon &= ~(TXCON_LOOPBACK_MODE | TXCON_FULL_DUPLEX); - /* - * If we are in full-duplex mode or loopback operation, + /* If we are in full-duplex mode or loopback operation, * we need to decouple receiver and transmitter. */ - if (mii->mii_media_active & (IFM_FDX | IFM_LOOP)) + if (IFM_OPTIONS(media) & (IFM_FDX | IFM_LOOP)) sc->txcon |= TXCON_FULL_DUPLEX; - if (IFM_SUBTYPE(mii->mii_media_active) == IFM_100_TX) + /* On some cards we need manualy set fullduplex led */ + if (sc->cardid == SMC9432FTX || + sc->cardid == SMC9432FTX_SC) { + if (IFM_OPTIONS(media) & IFM_FDX) + sc->miicfg |= MIICFG_694_ENABLE; + else + sc->miicfg &= ~MIICFG_694_ENABLE; + + CSR_WRITE_4(sc, MIICFG, sc->miicfg); + } + + /* Update baudrate */ + if (IFM_SUBTYPE(media) == IFM_100_TX && + IFM_SUBTYPE(media) == IFM_100_FX) sc->sc_if.if_baudrate = 100000000; else sc->sc_if.if_baudrate = 10000000; @@ -1233,22 +1343,32 @@ epic_miibus_statchg(dev) return; } -static void epic_miibus_mediainit(dev) +static void +epic_miibus_mediainit(dev) device_t dev; { epic_softc_t *sc; struct mii_data *mii; struct ifmedia *ifm; int media; - + sc = device_get_softc(dev); mii = device_get_softc(sc->miibus); ifm = &mii->mii_media; + /* Add Serial Media Interface if present, this applies to + * SMC9432BTX serie + */ if(CSR_READ_4(sc, MIICFG) & MIICFG_PHY_PRESENT) { - media = IFM_MAKEWORD(IFM_ETHER, IFM_10_2, 0, mii->mii_instance); - printf(EPIC_FORMAT ": serial PHY detected (10Base2/BNC)\n",EPIC_ARGS(sc)); + /* Store its instance */ + sc->serinst = mii->mii_instance++; + + /* Add as 10base2/BNC media */ + media = IFM_MAKEWORD(IFM_ETHER, IFM_10_2, 0, sc->serinst); ifmedia_add(ifm, media, 0, NULL); + + /* Report to user */ + printf(EPIC_FORMAT ": serial PHY detected (10Base2/BNC)\n",EPIC_ARGS(sc)); } return; @@ -1317,10 +1437,13 @@ epic_init(sc) /* Enable interrupts by setting the interrupt mask. */ CSR_WRITE_4( sc, INTMASK, - INTSTAT_RCC | INTSTAT_RQE | INTSTAT_OVW | INTSTAT_RXE | - INTSTAT_TXC | INTSTAT_TCC | INTSTAT_TQE | INTSTAT_TXU | + INTSTAT_RCC | /* INTSTAT_RQE | INTSTAT_OVW | INTSTAT_RXE | */ + /* INTSTAT_TXC | */ INTSTAT_TCC | INTSTAT_TQE | INTSTAT_TXU | INTSTAT_FATAL); + /* Acknowledge all pending interrupts */ + CSR_WRITE_4(sc, INTSTAT, CSR_READ_4(sc, INTSTAT)); + /* Enable interrupts, set for PCI read multiple and etc */ CSR_WRITE_4( sc, GENCTL, GENCTL_ENABLE_INTERRUPT | GENCTL_MEMORY_READ_MULTIPLE | diff --git a/sys/dev/tx/if_txreg.h b/sys/dev/tx/if_txreg.h index 6e7dd86..f8d1e16 100644 --- a/sys/dev/tx/if_txreg.h +++ b/sys/dev/tx/if_txreg.h @@ -257,6 +257,26 @@ struct epic_tx_buffer { * epic_rx_desc, epic_tx_desc, epic_frag_list - must be aligned on dword */ +/* PHY, known by tx driver */ +#define EPIC_UNKN_PHY 0x0000 +#define EPIC_QS6612_PHY 0x0001 +#define EPIC_AC101_PHY 0x0002 +#define EPIC_LXT970_PHY 0x0003 +#define EPIC_SERIAL 0x0004 + +#define SMC9432DMT 0xA010 +#define SMC9432TX 0xA011 +#define SMC9032TXM 0xA012 +#define SMC9032TX 0xA013 +#define SMC9432TXPWR 0xA014 +#define SMC9432BTX 0xA015 +#define SMC9432FTX 0xA016 +#define SMC9432FTX_SC 0xA017 +#define SMC9432TX_XG_ADHOC 0xA020 +#define SMC9434TX_XG_ADHOC 0xA021 +#define SMC9432FTX_ADHOC 0xA022 +#define SMC9432BTX1 0xA024 + /* Driver status structure */ typedef struct { struct arpcom arpcom; @@ -288,11 +308,16 @@ typedef struct { u_int32_t flags; u_int32_t tx_threshold; u_int32_t txcon; - u_int32_t phyid; + u_int32_t miicfg; u_int32_t cur_tx; u_int32_t cur_rx; u_int32_t dirty_tx; u_int32_t pending_txs; + u_int16_t cardvend; + u_int16_t cardid; + struct mii_softc *physc; + u_int32_t phyid; + int serinst; void *pool; } epic_softc_t; diff --git a/sys/dev/tx/if_txvar.h b/sys/dev/tx/if_txvar.h index 6e7dd86..f8d1e16 100644 --- a/sys/dev/tx/if_txvar.h +++ b/sys/dev/tx/if_txvar.h @@ -257,6 +257,26 @@ struct epic_tx_buffer { * epic_rx_desc, epic_tx_desc, epic_frag_list - must be aligned on dword */ +/* PHY, known by tx driver */ +#define EPIC_UNKN_PHY 0x0000 +#define EPIC_QS6612_PHY 0x0001 +#define EPIC_AC101_PHY 0x0002 +#define EPIC_LXT970_PHY 0x0003 +#define EPIC_SERIAL 0x0004 + +#define SMC9432DMT 0xA010 +#define SMC9432TX 0xA011 +#define SMC9032TXM 0xA012 +#define SMC9032TX 0xA013 +#define SMC9432TXPWR 0xA014 +#define SMC9432BTX 0xA015 +#define SMC9432FTX 0xA016 +#define SMC9432FTX_SC 0xA017 +#define SMC9432TX_XG_ADHOC 0xA020 +#define SMC9434TX_XG_ADHOC 0xA021 +#define SMC9432FTX_ADHOC 0xA022 +#define SMC9432BTX1 0xA024 + /* Driver status structure */ typedef struct { struct arpcom arpcom; @@ -288,11 +308,16 @@ typedef struct { u_int32_t flags; u_int32_t tx_threshold; u_int32_t txcon; - u_int32_t phyid; + u_int32_t miicfg; u_int32_t cur_tx; u_int32_t cur_rx; u_int32_t dirty_tx; u_int32_t pending_txs; + u_int16_t cardvend; + u_int16_t cardid; + struct mii_softc *physc; + u_int32_t phyid; + int serinst; void *pool; } epic_softc_t; |