summaryrefslogtreecommitdiff
path: root/sys/arch/sparc/dev/be.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/arch/sparc/dev/be.c')
-rw-r--r--sys/arch/sparc/dev/be.c769
1 files changed, 680 insertions, 89 deletions
diff --git a/sys/arch/sparc/dev/be.c b/sys/arch/sparc/dev/be.c
index b2cafbfafb7..83aaa8453f1 100644
--- a/sys/arch/sparc/dev/be.c
+++ b/sys/arch/sparc/dev/be.c
@@ -1,7 +1,8 @@
-/* $OpenBSD: be.c,v 1.5 1998/07/11 05:47:36 deraadt Exp $ */
+/* $OpenBSD: be.c,v 1.6 1998/08/26 05:00:51 jason Exp $ */
/*
- * Copyright (c) 1998 Theo de Raadt. All rights reserved.
+ * Copyright (c) 1998 Theo de Raadt and Jason L. Wright.
+ * All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -11,13 +12,13 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
+ * 3. The name of the authors may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
@@ -70,19 +71,29 @@ int bematch __P((struct device *, void *, void *));
void beattach __P((struct device *, struct device *, void *));
void beinit __P((struct besoftc *));
-void be_meminit __P((struct besoftc *));
void bestart __P((struct ifnet *));
void bestop __P((struct besoftc *));
void bewatchdog __P((struct ifnet *));
int beioctl __P((struct ifnet *, u_long, caddr_t));
+void bereset __P((struct besoftc *sc));
int beintr __P((void *));
-int betint __P((struct besoftc *));
int berint __P((struct besoftc *));
-int beqint __P((struct besoftc *));
-int beeint __P((struct besoftc *));
+int betint __P((struct besoftc *));
+int beqint __P((struct besoftc *, u_int32_t));
+int beeint __P((struct besoftc *, u_int32_t));
+int be_put __P((struct besoftc *, int, struct mbuf *));
+void be_read __P((struct besoftc *, int, int));
+struct mbuf * be_get __P((struct besoftc *, int, int));
+
+void be_tcvr_idle __P((struct besoftc *sc));
void be_tcvr_init __P((struct besoftc *sc));
void be_tcvr_setspeed __P((struct besoftc *sc));
+void be_tcvr_write __P((struct besoftc *sc, u_int8_t reg, u_int16_t val));
+void be_tcvr_write_bit __P((struct besoftc *sc, int bit));
+int be_tcvr_read_bit1 __P((struct besoftc *sc));
+int be_tcvr_read_bit2 __P((struct besoftc *sc));
+int be_tcvr_read __P((struct besoftc *sc, u_int8_t reg));
struct cfdriver be_cd = {
NULL, "be", DV_IFNET
@@ -125,9 +136,10 @@ beattach(parent, self, aux)
pri = ca->ca_ra.ra_intr[0].int_pri;
sc->sc_rev = getpropint(ca->ca_ra.ra_node, "board-version", -1);
- sc->sc_cr = mapiodev(ca->ca_ra.ra_reg, 0, sizeof(struct be_cregs));
+ sc->sc_cr = mapiodev(&ca->ca_ra.ra_reg[0], 0, sizeof(struct be_cregs));
sc->sc_br = mapiodev(&ca->ca_ra.ra_reg[1], 0, sizeof(struct be_bregs));
sc->sc_tr = mapiodev(&ca->ca_ra.ra_reg[2], 0, sizeof(struct be_tregs));
+ sc->sc_qec = qec;
sc->sc_qr = qec->sc_regs;
bestop(sc);
@@ -182,11 +194,9 @@ void
bestart(ifp)
struct ifnet *ifp;
{
-printf("start\n");
-#if 0
- struct besoftc *sc = ifp->if_softc;
+ struct besoftc *sc = (struct besoftc *)ifp->if_softc;
struct mbuf *m;
- int bix;
+ int bix, len;
if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
return;
@@ -194,11 +204,10 @@ printf("start\n");
bix = sc->sc_last_td;
for (;;) {
- /* XXX TODO: Some magic */
-
IF_DEQUEUE(&ifp->if_snd, m);
if (m == 0)
break;
+
#if NBPFILTER > 0
/*
* If BPF is listening on this interface, let it see the
@@ -208,24 +217,29 @@ printf("start\n");
bpf_mtap(ifp->if_bpf, m);
#endif
- /* XXX TODO
+ /*
* Copy the mbuf chain into the transmit buffer.
*/
- /* XXX TODO
+ len = be_put(sc, bix, m);
+
+ /*
* Initialize transmit registers and start transmission
*/
+ sc->sc_desc->be_txd[bix].tx_flags =
+ BE_TXD_OWN | BE_TXD_SOP | BE_TXD_EOP |
+ (len & BE_TXD_LENGTH);
+ sc->sc_cr->ctrl = BE_CR_CTRL_TWAKEUP;
- if (++bix == TX_RING_SIZE)
+ if (++bix == BE_TX_RING_SIZE)
bix = 0;
- if (++sc->sc_no_td == TX_RING_SIZE) {
+ if (++sc->sc_no_td == BE_TX_RING_SIZE) {
ifp->if_flags |= IFF_OACTIVE;
break;
}
}
sc->sc_last_td = bix;
-#endif
}
void
@@ -245,20 +259,31 @@ bestop(sc)
DELAY(20);
}
+/*
+ * Reset interface.
+ */
+void
+bereset(sc)
+ struct besoftc *sc;
+{
+ int s;
+
+ s = splnet();
+ bestop(sc);
+ beinit(sc);
+ splx(s);
+}
+
void
bewatchdog(ifp)
struct ifnet *ifp;
{
-printf("watchdog\n");
-
-#if 0
struct besoftc *sc = ifp->if_softc;
log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
++sc->sc_arpcom.ac_if.if_oerrors;
bereset(sc);
-#endif
}
int
@@ -266,50 +291,227 @@ beintr(v)
void *v;
{
struct besoftc *sc = (struct besoftc *)v;
- u_int32_t why;
+ u_int32_t whyq, whyb, whyc;
int r = 0;
- why = sc->sc_qr->stat;
+ whyq = sc->sc_qr->stat; /* qec status */
+ whyc = sc->sc_cr->stat; /* be channel status */
+ whyb = sc->sc_br->stat; /* be status */
+
+ if (whyq & QEC_STAT_BM)
+ r |= beeint(sc, whyb);
+
+ if (whyq & QEC_STAT_ER)
+ r |= beqint(sc, whyc);
- if (why & QEC_STAT_TX)
+ if (whyq & QEC_STAT_TX && whyc & BE_CR_STAT_TXIRQ)
r |= betint(sc);
- if (why & QEC_STAT_RX)
+
+ if (whyq & QEC_STAT_RX && whyc & BE_CR_STAT_RXIRQ)
r |= berint(sc);
- if (why & QEC_STAT_BM)
- r |= beqint(sc);
- if (why & QEC_STAT_ER)
- r |= beeint(sc);
- if (r)
- printf("%s: intr: why=%08x\n", sc->sc_dev.dv_xname, why);
+
return (r);
}
+/*
+ * QEC Interrupt.
+ */
int
-betint(sc)
+beqint(sc, why)
struct besoftc *sc;
+ u_int32_t why;
{
- return (0);
+ int r = 0, rst = 0;
+
+ if (why & BE_CR_STAT_TXIRQ)
+ r |= 1;
+ if (why & BE_CR_STAT_RXIRQ)
+ r |= 1;
+
+ if (why & BE_CR_STAT_BERROR) {
+ r |= 1;
+ rst = 1;
+ printf("%s: bigmac error\n", sc->sc_dev.dv_xname);
+ }
+
+ if (why & BE_CR_STAT_TXDERR) {
+ r |= 1;
+ rst = 1;
+ printf("%s: bogus tx descriptor\n", sc->sc_dev.dv_xname);
+ }
+
+ if (why & (BE_CR_STAT_TXLERR | BE_CR_STAT_TXPERR | BE_CR_STAT_TXSERR)) {
+ r |= 1;
+ rst = 1;
+ printf("%s: tx dma error ( ", sc->sc_dev.dv_xname);
+ if (why & BE_CR_STAT_TXLERR)
+ printf("Late ");
+ if (why & BE_CR_STAT_TXPERR)
+ printf("Parity ");
+ if (why & BE_CR_STAT_TXSERR)
+ printf("Generic ");
+ printf(")\n");
+ }
+
+ if (why & BE_CR_STAT_RXDROP) {
+ r |= 1;
+ rst = 1;
+ printf("%s: out of rx descriptors\n", sc->sc_dev.dv_xname);
+ }
+
+ if (why & BE_CR_STAT_RXSMALL) {
+ r |= 1;
+ rst = 1;
+ printf("%s: rx descriptor too small\n", sc->sc_dev.dv_xname);
+ }
+
+ if (why & (BE_CR_STAT_RXLERR | BE_CR_STAT_RXPERR | BE_CR_STAT_RXSERR)) {
+ r |= 1;
+ rst = 1;
+ printf("%s: rx dma error ( ", sc->sc_dev.dv_xname);
+ if (why & BE_CR_STAT_RXLERR)
+ printf("Late ");
+ if (why & BE_CR_STAT_RXPERR)
+ printf("Parity ");
+ if (why & BE_CR_STAT_RXSERR)
+ printf("Generic ");
+ printf(")\n");
+ }
+
+ if (!r) {
+ rst = 1;
+ printf("%s: unexpected error interrupt %08x\n",
+ sc->sc_dev.dv_xname, why);
+ }
+
+ if (rst) {
+ printf("%s: resetting\n", sc->sc_dev.dv_xname);
+ bereset(sc);
+ }
+
+ return r;
}
+/*
+ * Error interrupt.
+ */
int
-berint(sc)
+beeint(sc, why)
struct besoftc *sc;
+ u_int32_t why;
{
- return (0);
+ int r = 0, rst = 0;
+
+ if (why & BE_BR_STAT_RFIFOVF) {
+ r |= 1;
+ rst = 1;
+ printf("%s: receive fifo overrun\n", sc->sc_dev.dv_xname);
+ }
+ if (why & BE_BR_STAT_TFIFO_UND) {
+ r |= 1;
+ rst = 1;
+ printf("%s: transmit fifo underrun\n", sc->sc_dev.dv_xname);
+ }
+ if (why & BE_BR_STAT_MAXPKTERR) {
+ r |= 1;
+ rst = 1;
+ printf("%s: max packet size error\n", sc->sc_dev.dv_xname);
+ }
+ if (why & BE_BR_STAT_DTIMEXP) {
+ r |= 1;
+ printf("%s: defer timer expired\n", sc->sc_dev.dv_xname);
+ }
+
+ if (!r) {
+ rst = 1;
+ printf("%s: unexpected error interrupt %08x\n",
+ sc->sc_dev.dv_xname, why);
+ }
+
+ if (rst) {
+ printf("%s: resetting\n", sc->sc_dev.dv_xname);
+ bereset(sc);
+ }
+
+ return r;
}
+/*
+ * Transmit interrupt.
+ */
int
-beqint(sc)
+betint(sc)
struct besoftc *sc;
{
- return (0);
+ struct ifnet *ifp = &sc->sc_arpcom.ac_if;
+ int bix;
+ struct be_txd txd;
+
+ bix = sc->sc_first_td;
+
+ for (;;) {
+ if (sc->sc_no_td <= 0)
+ break;
+
+ bcopy(&sc->sc_desc->be_txd[bix], &txd, sizeof(txd));
+
+ if (txd.tx_flags & BE_TXD_OWN)
+ break;
+
+ ifp->if_flags &= ~IFF_OACTIVE;
+ ifp->if_opackets++;
+
+ if (++bix == BE_TX_RING_SIZE)
+ bix = 0;
+
+ --sc->sc_no_td;
+ }
+
+ sc->sc_first_td = bix;
+
+ bestart(ifp);
+
+ if (sc->sc_no_td == 0)
+ ifp->if_timer = 0;
+
+ return 1;
}
+/*
+ * Receive interrupt.
+ */
int
-beeint(sc)
+berint(sc)
struct besoftc *sc;
{
- return (0);
+ int bix, len;
+ struct be_rxd rxd;
+
+ bix = sc->sc_last_rd;
+
+ /*
+ * Process all buffers with valid data.
+ */
+ for (;;) {
+ bcopy(&sc->sc_desc->be_rxd[bix], &rxd, sizeof(rxd));
+
+ if (rxd.rx_flags & BE_RXD_OWN)
+ break;
+
+ len = rxd.rx_flags & BE_RXD_LENGTH;
+ be_read(sc, bix, len);
+
+ rxd.rx_flags = BE_RXD_OWN | (BE_PKT_BUF_SZ & BE_RXD_LENGTH);
+
+ bcopy(&rxd, &sc->sc_desc->be_rxd[bix], sizeof(rxd));
+
+ if (++bix == BE_RX_RING_SIZE)
+ bix = 0;
+ }
+
+ sc->sc_last_rd = bix;
+
+ return 1;
}
int
@@ -422,18 +624,6 @@ beioctl(ifp, cmd, data)
}
void
-be_tcvr_init(sc)
- struct besoftc *sc;
-{
-}
-
-void
-be_tcvr_setspeed(sc)
- struct besoftc *sc;
-{
-}
-
-void
beinit(sc)
struct besoftc *sc;
{
@@ -441,13 +631,15 @@ beinit(sc)
int s = splimp();
int i;
- bestop(sc);
+ qec_reset(sc->sc_qec);
- /* init QEC */
+ /*
+ * init QEC: 'be' specific initializations
+ */
sc->sc_qr->msize = sc->sc_memsize;
sc->sc_qr->rsize = sc->sc_memsize / 2;
sc->sc_qr->tsize = sc->sc_memsize / 2;
- sc->sc_qr->psize = 2048;
+ sc->sc_qr->psize = QEC_PSIZE_2048;
if (sc->sc_burst & SBUS_BURST_64)
i = QEC_CTRL_B64;
else if (sc->sc_burst & SBUS_BURST_32)
@@ -456,28 +648,31 @@ beinit(sc)
i = QEC_CTRL_B16;
sc->sc_qr->ctrl = QEC_CTRL_BMODE | i;
- /* Allocate memory if not done yet */
- if (sc->sc_desc_dva == NULL)
- sc->sc_desc_dva = (struct be_desc *)dvma_malloc(
- sizeof(struct be_desc), &sc->sc_desc, M_NOWAIT);
- if (sc->sc_bufs_dva == NULL)
- sc->sc_bufs_dva = (struct be_bufs *)dvma_malloc(
- sizeof(struct be_bufs), &sc->sc_bufs, M_NOWAIT);
-
- /* chain descriptors into buffers */
- sc->sc_txnew = 0;
- sc->sc_rxnew = 0;
- sc->sc_txold = 0;
- sc->sc_rxold = 0;
- for (i = 0; i < RX_RING_SIZE; i++) {
- sc->sc_desc->be_rxd[i].rx_addr =
- (u_int32_t)&sc->sc_bufs_dva->rx_buf[i][0];
- sc->sc_desc->be_rxd[i].rx_flags = 0;
- }
- for (i = 0; i < TX_RING_SIZE; i++) {
- sc->sc_desc->be_txd[i].tx_addr = 0;
+ /*
+ * Allocate descriptor ring and buffers, if not already done
+ */
+ if (sc->sc_desc == NULL)
+ sc->sc_desc_dva = (struct be_desc *) dvma_malloc(
+ sizeof(struct be_desc), &sc->sc_desc, M_NOWAIT);
+ if (sc->sc_bufs == NULL)
+ sc->sc_bufs_dva = (struct be_bufs *) dvma_malloc(
+ sizeof(struct be_bufs), &sc->sc_bufs, M_NOWAIT);
+
+ for (i = 0; i < BE_TX_RING_SIZE; i++) {
+ sc->sc_desc->be_txd[i].tx_addr =
+ (u_int32_t) &sc->sc_bufs_dva->tx_buf[i][0];
sc->sc_desc->be_txd[i].tx_flags = 0;
}
+ for (i = 0; i < BE_RX_RING_SIZE; i++) {
+ sc->sc_desc->be_rxd[i].rx_addr =
+ (u_int32_t) &sc->sc_bufs_dva->rx_buf[i][0];
+ sc->sc_desc->be_rxd[i].rx_flags =
+ BE_RXD_OWN |
+ (BE_PKT_BUF_SZ & BE_RXD_LENGTH);
+ }
+
+ sc->sc_first_td = sc->sc_last_td = sc->sc_no_td = 0;
+ sc->sc_last_rd = 0;
be_tcvr_init(sc);
be_tcvr_setspeed(sc);
@@ -496,23 +691,38 @@ beinit(sc)
sc->sc_br->htable1 = 0;
sc->sc_br->htable0 = 0;
- sc->sc_br->rx_cfg = BE_RXCFG_HENABLE | BE_RXCFG_FIFO;
+ sc->sc_br->rx_cfg = BE_BR_RXCFG_HENABLE | BE_BR_RXCFG_FIFO;
DELAY(20);
- sc->sc_br->tx_cfg = BE_TXCFG_FIFO;
+ sc->sc_br->tx_cfg = BE_BR_TXCFG_FIFO;
sc->sc_br->rand_seed = 0xbd;
- sc->sc_br->xif_cfg = BE_XCFG_ODENABLE | BE_XCFG_RESV;
+ sc->sc_br->xif_cfg = BE_BR_XCFG_ODENABLE | BE_BR_XCFG_RESV;
- sc->sc_cr->rxds = (u_int32_t)&sc->sc_desc_dva->be_rxd[0];
- sc->sc_cr->txds = (u_int32_t)&sc->sc_desc_dva->be_txd[0];
+ sc->sc_cr->rxds = (u_int32_t) &sc->sc_desc_dva->be_rxd[0];
+ sc->sc_cr->txds = (u_int32_t) &sc->sc_desc_dva->be_txd[0];
sc->sc_cr->rxwbufptr = 0;
sc->sc_cr->rxrbufptr = 0;
- sc->sc_cr->txwbufptr = sc->sc_memsize;
- sc->sc_cr->txrbufptr = sc->sc_memsize;
-
- sc->sc_br->imask = 0;
+ sc->sc_cr->txwbufptr = sc->sc_qr->tsize;
+ sc->sc_cr->txrbufptr = sc->sc_qr->tsize;
+
+ /*
+ * Turn off counter expiration interrupts as well as
+ * 'gotframe' and 'sentframe'
+ */
+ sc->sc_br->imask = BE_BR_IMASK_GOTFRAME |
+ BE_BR_IMASK_RCNTEXP |
+ BE_BR_IMASK_ACNTEXP |
+ BE_BR_IMASK_CCNTEXP |
+ BE_BR_IMASK_LCNTEXP |
+ BE_BR_IMASK_CVCNTEXP |
+ BE_BR_IMASK_NCNTEXP |
+ BE_BR_IMASK_ECNTEXP |
+ BE_BR_IMASK_LCCNTEXP |
+ BE_BR_IMASK_LCNTEXP |
+ BE_BR_IMASK_LCNTEXP |
+ BE_BR_IMASK_SENTFRAME;
sc->sc_cr->rimask = 0;
sc->sc_cr->timask = 0;
@@ -523,10 +733,391 @@ beinit(sc)
sc->sc_cr->ccnt = 0;
- sc->sc_br->tx_cfg |= BE_TXCFG_ENABLE;
- sc->sc_br->rx_cfg |= BE_RXCFG_ENABLE;
+ sc->sc_br->tx_cfg |= BE_BR_TXCFG_ENABLE;
+ sc->sc_br->rx_cfg |= BE_BR_RXCFG_ENABLE;
ifp->if_flags |= IFF_RUNNING;
ifp->if_flags &= ~IFF_OACTIVE;
splx(s);
}
+
+void
+be_tcvr_setspeed(sc)
+ struct besoftc *sc;
+{
+ int x;
+
+ be_tcvr_write(sc, PHY_BMCR, 0);
+ x = be_tcvr_read(sc, PHY_BMSR);
+}
+
+/*
+ * Set the tcvr to an idle state
+ */
+void
+be_tcvr_idle(sc)
+ struct besoftc *sc;
+{
+ struct be_tregs *tr = sc->sc_tr;
+ volatile u_int32_t x;
+ int i = 20;
+
+ while (i--) {
+ tr->mgmt_pal = MGMT_PAL_INT_MDIO | MGMT_PAL_EXT_MDIO |
+ MGMT_PAL_OENAB;
+ x = tr->mgmt_pal;
+ tr->mgmt_pal = MGMT_PAL_INT_MDIO | MGMT_PAL_EXT_MDIO |
+ MGMT_PAL_OENAB | MGMT_PAL_DCLOCK;
+ x = tr->mgmt_pal;
+ }
+}
+
+/*
+ * Initialize the transceiver and figure out whether we're using the
+ * external or internal one.
+ */
+void
+be_tcvr_init(sc)
+ struct besoftc *sc;
+{
+ volatile u_int32_t x;
+ struct be_tregs *tr = sc->sc_tr;
+
+ be_tcvr_idle(sc);
+
+ if (sc->sc_rev != 1) {
+ printf("%s: rev %d PAL not supported.\n",
+ sc->sc_dev.dv_xname,
+ sc->sc_rev);
+ return;
+ }
+
+ tr->mgmt_pal = MGMT_PAL_INT_MDIO | MGMT_PAL_EXT_MDIO | MGMT_PAL_DCLOCK;
+ x = tr->mgmt_pal;
+
+ tr->mgmt_pal = MGMT_PAL_INT_MDIO | MGMT_PAL_EXT_MDIO;
+ x = tr->mgmt_pal;
+ DELAY(200);
+
+ if (tr->mgmt_pal & MGMT_PAL_EXT_MDIO) {
+ sc->sc_tcvr_type = BE_TCVR_EXTERNAL;
+ tr->tcvr_pal = ~(TCVR_PAL_EXTLBACK | TCVR_PAL_MSENSE |
+ TCVR_PAL_LTENABLE);
+ x = tr->tcvr_pal;
+ }
+ else if (tr->mgmt_pal & MGMT_PAL_INT_MDIO) {
+ sc->sc_tcvr_type = BE_TCVR_INTERNAL;
+ tr->tcvr_pal = ~(TCVR_PAL_EXTLBACK | TCVR_PAL_MSENSE |
+ TCVR_PAL_LTENABLE | TCVR_PAL_SERIAL);
+ x = tr->tcvr_pal;
+ }
+ else {
+ printf("%s: no internal or external transceiver found.\n",
+ sc->sc_dev.dv_xname);
+ }
+}
+
+int
+be_tcvr_read(sc, reg)
+ struct besoftc *sc;
+ u_int8_t reg;
+{
+ int phy, i;
+ u_int32_t ret = 0;
+
+ if (sc->sc_tcvr_type == BE_TCVR_INTERNAL)
+ phy = BE_PHY_INTERNAL;
+ else if (sc->sc_tcvr_type == BE_TCVR_EXTERNAL)
+ phy = BE_PHY_EXTERNAL;
+ else {
+ printf("%s: invalid tcvr type\n", sc->sc_dev.dv_xname);
+ return BE_TCVR_READ_INVALID;
+ }
+
+ be_tcvr_idle(sc);
+
+ be_tcvr_write_bit(sc, 0);
+ be_tcvr_write_bit(sc, 1);
+ be_tcvr_write_bit(sc, 1);
+ be_tcvr_write_bit(sc, 0);
+
+ for (i = 4; i >= 0; i--)
+ be_tcvr_write_bit(sc, (phy >> i) & 1);
+
+ for (i = 4; i >= 0; i--)
+ be_tcvr_write_bit(sc, (reg >> i) & 1);
+
+ if (sc->sc_tcvr_type == BE_TCVR_EXTERNAL) {
+ (void) be_tcvr_read_bit2(sc);
+ (void) be_tcvr_read_bit2(sc);
+
+ for (i = 15; i >= 0; i--) {
+ int b;
+
+ b = be_tcvr_read_bit2(sc);
+ ret |= (b & 1) << i;
+ }
+
+ (void) be_tcvr_read_bit2(sc);
+ (void) be_tcvr_read_bit2(sc);
+ (void) be_tcvr_read_bit2(sc);
+ }
+ else {
+ (void) be_tcvr_read_bit1(sc);
+ (void) be_tcvr_read_bit1(sc);
+
+ for (i = 15; i >= 0; i--) {
+ int b;
+
+ b = be_tcvr_read_bit1(sc);
+ ret |= (b & 1) << i;
+ }
+
+ (void) be_tcvr_read_bit1(sc);
+ (void) be_tcvr_read_bit1(sc);
+ (void) be_tcvr_read_bit1(sc);
+ }
+ return ret;
+}
+
+int
+be_tcvr_read_bit1(sc)
+ struct besoftc *sc;
+{
+ volatile u_int32_t x;
+ struct be_tregs *tr = sc->sc_tr;
+ int ret = 0;
+
+ if (sc->sc_tcvr_type == BE_TCVR_INTERNAL) {
+ tr->mgmt_pal = MGMT_PAL_EXT_MDIO;
+ x = tr->mgmt_pal;
+ tr->mgmt_pal = MGMT_PAL_EXT_MDIO | MGMT_PAL_DCLOCK;
+ x = tr->mgmt_pal;
+ DELAY(20);
+ ret = (tr->mgmt_pal & MGMT_PAL_INT_MDIO) >> 3;
+ } else if (sc->sc_tcvr_type == BE_TCVR_EXTERNAL) {
+ tr->mgmt_pal = MGMT_PAL_INT_MDIO;
+ x = tr->mgmt_pal;
+ tr->mgmt_pal = MGMT_PAL_INT_MDIO | MGMT_PAL_DCLOCK;
+ x = tr->mgmt_pal;
+ DELAY(20);
+ ret = (tr->mgmt_pal & MGMT_PAL_EXT_MDIO) >> 2;
+ } else {
+ printf("%s: invalid tcvr type\n", sc->sc_dev.dv_xname);
+ }
+ return (ret & 1);
+}
+
+int
+be_tcvr_read_bit2(sc)
+ struct besoftc *sc;
+{
+ volatile u_int32_t x;
+ struct be_tregs *tr = sc->sc_tr;
+ int ret = 0;
+
+ if (sc->sc_tcvr_type == BE_TCVR_INTERNAL) {
+ tr->mgmt_pal = MGMT_PAL_EXT_MDIO;
+ x = tr->mgmt_pal;
+ DELAY(20);
+ ret = (tr->mgmt_pal & MGMT_PAL_INT_MDIO) >> 3;
+ tr->mgmt_pal = MGMT_PAL_EXT_MDIO | MGMT_PAL_DCLOCK;
+ x = tr->mgmt_pal;
+ } else if (sc->sc_tcvr_type == BE_TCVR_EXTERNAL) {
+ tr->mgmt_pal = MGMT_PAL_INT_MDIO;
+ x = tr->mgmt_pal;
+ DELAY(20);
+ ret = (tr->mgmt_pal & MGMT_PAL_EXT_MDIO) >> 2;
+ tr->mgmt_pal = MGMT_PAL_INT_MDIO | MGMT_PAL_DCLOCK;
+ x = tr->mgmt_pal;
+ } else {
+ printf("%s: invalid tcvr type\n", sc->sc_dev.dv_xname);
+ }
+ return ret;
+}
+
+void
+be_tcvr_write(sc, reg, val)
+ struct besoftc *sc;
+ u_int8_t reg;
+ u_int16_t val;
+{
+ int phy, i;
+
+ if (sc->sc_tcvr_type == BE_TCVR_INTERNAL)
+ phy = BE_PHY_INTERNAL;
+ else if (sc->sc_tcvr_type == BE_TCVR_EXTERNAL)
+ phy = BE_PHY_EXTERNAL;
+ else {
+ printf("%s: invalid tcvr type\n", sc->sc_dev.dv_xname);
+ return;
+ }
+
+ be_tcvr_idle(sc);
+
+ be_tcvr_write_bit(sc, 0);
+ be_tcvr_write_bit(sc, 1);
+ be_tcvr_write_bit(sc, 0);
+ be_tcvr_write_bit(sc, 1);
+
+ for (i = 4; i >= 0; i--)
+ be_tcvr_write_bit(sc, (phy >> i) & 1);
+
+ for (i = 4; i >= 0; i--)
+ be_tcvr_write_bit(sc, (reg >> i) & 1);
+
+ be_tcvr_write_bit(sc, 1);
+ be_tcvr_write_bit(sc, 0);
+
+ for (i = 15; i >= 0; i--)
+ be_tcvr_write_bit(sc, (val >> i) & 1);
+}
+
+void
+be_tcvr_write_bit(sc, bit)
+ struct besoftc *sc;
+ int bit;
+{
+ volatile u_int32_t x;
+
+ if (sc->sc_tcvr_type == BE_TCVR_INTERNAL) {
+ bit = ((bit & 1) << 3) | MGMT_PAL_OENAB | MGMT_PAL_EXT_MDIO;
+ sc->sc_tr->mgmt_pal = bit;
+ x = sc->sc_tr->mgmt_pal;
+ sc->sc_tr->mgmt_pal = bit | MGMT_PAL_DCLOCK;
+ x = sc->sc_tr->mgmt_pal;
+ } else {
+ bit = ((bit & 1) << 2) | MGMT_PAL_OENAB | MGMT_PAL_INT_MDIO;
+ sc->sc_tr->mgmt_pal = bit;
+ x = sc->sc_tr->mgmt_pal;
+ sc->sc_tr->mgmt_pal = bit | MGMT_PAL_DCLOCK;
+ x = sc->sc_tr->mgmt_pal;
+ }
+}
+
+/*
+ * Routine to copy from mbuf chain to transmit buffer in
+ * network buffer memory.
+ */
+int
+be_put(sc, idx, m)
+ struct besoftc *sc;
+ int idx;
+ struct mbuf *m;
+{
+ struct mbuf *n;
+ int len, tlen = 0, boff = 0;
+
+ for (; m; m = n) {
+ len = m->m_len;
+ if (len == 0) {
+ MFREE(m, n);
+ continue;
+ }
+ bcopy(mtod(m, caddr_t), &sc->sc_bufs->tx_buf[idx][boff], len);
+ boff += len;
+ tlen += len;
+ MFREE(m, n);
+ }
+ return tlen;
+}
+
+/*
+ * Pass a packet to the higher levels.
+ */
+void
+be_read(sc, idx, len)
+ struct besoftc *sc;
+ int idx, len;
+{
+ struct ifnet *ifp = &sc->sc_arpcom.ac_if;
+ struct ether_header *eh;
+ struct mbuf *m;
+
+ if (len <= sizeof(struct ether_header) ||
+ len > ETHERMTU + sizeof(struct ether_header)) {
+
+ printf("%s: invalid packet size %d; dropping\n",
+ ifp->if_xname, len);
+
+ ifp->if_ierrors++;
+ return;
+ }
+
+ /*
+ * Pull packet off interface.
+ */
+ m = be_get(sc, idx, len);
+ if (m == NULL) {
+ ifp->if_ierrors++;
+ return;
+ }
+ ifp->if_ipackets++;
+
+ /* We assume that the header fit entirely in one mbuf. */
+ eh = mtod(m, struct ether_header *);
+
+#if NBPFILTER > 0
+ /*
+ * Check if there's a BPF listener on this interface.
+ * If so, hand off the raw packet to BPF.
+ */
+ if (ifp->if_bpf)
+ bpf_mtap(ifp->if_bpf, m);
+#endif
+ /* Pass the packet up, with the ether header sort-of removed. */
+ m_adj(m, sizeof(struct ether_header));
+ ether_input(ifp, eh, m);
+}
+
+/*
+ * Pull data off an interface.
+ * Len is the length of data, with local net header stripped.
+ * We copy the data into mbufs. When full cluster sized units are present,
+ * we copy into clusters.
+ */
+struct mbuf *
+be_get(sc, idx, totlen)
+ struct besoftc *sc;
+ int idx, totlen;
+{
+ struct ifnet *ifp = &sc->sc_arpcom.ac_if;
+ struct mbuf *m;
+ struct mbuf *top, **mp;
+ int len, pad, boff = 0;
+
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m == NULL)
+ return (NULL);
+ m->m_pkthdr.rcvif = ifp;
+ m->m_pkthdr.len = totlen;
+ pad = ALIGN(sizeof(struct ether_header)) - sizeof(struct ether_header);
+ m->m_data += pad;
+ len = MHLEN - pad;
+ top = NULL;
+ mp = &top;
+
+ while (totlen > 0) {
+ if (top) {
+ MGET(m, M_DONTWAIT, MT_DATA);
+ if (m == NULL) {
+ m_freem(top);
+ return NULL;
+ }
+ len = MLEN;
+ }
+ if (top && totlen >= MINCLSIZE) {
+ MCLGET(m, M_DONTWAIT);
+ if (m->m_flags & M_EXT)
+ len = MCLBYTES;
+ }
+ m->m_len = len = min(totlen, len);
+ bcopy(&sc->sc_bufs->rx_buf[idx][boff], mtod(m, caddr_t), len);
+ boff += len;
+ totlen -= len;
+ *mp = m;
+ mp = &m->m_next;
+ }
+
+ return (top);
+}