summaryrefslogtreecommitdiffstats
path: root/sys/pci
diff options
context:
space:
mode:
authorsemenu <semenu@FreeBSD.org>2001-02-07 20:11:02 +0000
committersemenu <semenu@FreeBSD.org>2001-02-07 20:11:02 +0000
commitb3d64495b94dc135a232b4fba8d12f9cc7ee4e7d (patch)
tree9545682391ebfb6f593f78e12b6bbc2a79e84a2e /sys/pci
parente472dcaec284f55073806b3253159e12983c9fbf (diff)
downloadFreeBSD-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/pci')
-rw-r--r--sys/pci/if_tx.c205
-rw-r--r--sys/pci/if_txvar.h27
2 files changed, 190 insertions, 42 deletions
diff --git a/sys/pci/if_tx.c b/sys/pci/if_tx.c
index 934b943..b16ac50 100644
--- a/sys/pci/if_tx.c
+++ b/sys/pci/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/pci/if_txvar.h b/sys/pci/if_txvar.h
index 6e7dd86..f8d1e16 100644
--- a/sys/pci/if_txvar.h
+++ b/sys/pci/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;
OpenPOWER on IntegriCloud