Network device driver issues.

classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

Network device driver issues.

Alok Barsode
Hello,
I am porting freeBSD 4.10 to a embedded board.
The board has 2 Three speed Ethernet Controller and a
Cicada PHY.
I have implemented a pseudo-bus (called mpcbus) which
attaches itself to nexus.
i plan to attach all the devices to the mpcbus. (i
will be calling the IDENTIFY function for each
device-driver).All the devices are memory
mapped.
Now i have 2 TSEC(Three-Speed Ethernet Controller)on
the board(say TSEC0 and TSEC1).
During the IDENTIFY routine, should the function
BUS_ADD_CHILD() called twice ,once for each TSEC?

I also dont what the PHY to be configured sepatately.
(I right now dont want any "mii" stuff) I will
configure the PHY manually. is this fine
with the freeBSD point of view? I dont understand the
struct xxx_mii_frame.
i am looking at the National Semiconductor
DP83820/DP83821 gigabit
ethernet driver (i.e /dev/nge/if_nge.c)

 The frame structure is:
struct nge_mii_frame {
         u_int8_t                mii_stdelim;
         u_int8_t                mii_opcode;
         u_int8_t                mii_phyaddr;
         u_int8_t                mii_regaddr;
         u_int8_t                mii_turnaround;
         u_int16_t               mii_data;
 };All the drivers use this kind of frame structure.
Is this a generic one? how does one use it?

is there a simple driver i can look at? or a simple
tutorial on network drivers?
the National Semiconductor driver is a bit complex.

Thanks,
alok.

__________________________________________________
Do You Yahoo!?
Tired of spam?  Yahoo! Mail has the best spam protection around
http://mail.yahoo.com 
_______________________________________________
[hidden email] mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-new-bus
To unsubscribe, send any mail to "[hidden email]"
Reply | Threaded
Open this post in threaded view
|

Re: Network device driver issues.

Warner Losh
In message: <[hidden email]>
            Alok Barsode <[hidden email]> writes:
: Hello,
: I am porting freeBSD 4.10 to a embedded board.
: The board has 2 Three speed Ethernet Controller and a
: Cicada PHY.
: I have implemented a pseudo-bus (called mpcbus) which
: attaches itself to nexus.
: i plan to attach all the devices to the mpcbus. (i
: will be calling the IDENTIFY function for each
: device-driver).All the devices are memory
: mapped.
: Now i have 2 TSEC(Three-Speed Ethernet Controller)on
: the board(say TSEC0 and TSEC1).
: During the IDENTIFY routine, should the function
: BUS_ADD_CHILD() called twice ,once for each TSEC?

Yes, that would work.  Actaully, you need to write a more real bus
that adds the children, but short of that, calling bus_add_child would
be a short-term workaround.

: I also dont what the PHY to be configured sepatately.
: (I right now dont want any "mii" stuff) I will
: configure the PHY manually. is this fine
: with the freeBSD point of view?

: I dont understand the
: struct xxx_mii_frame.
: i am looking at the National Semiconductor
: DP83820/DP83821 gigabit
: ethernet driver (i.e /dev/nge/if_nge.c)
:
:  The frame structure is:
: struct nge_mii_frame {
:          u_int8_t                mii_stdelim;
:          u_int8_t                mii_opcode;
:          u_int8_t                mii_phyaddr;
:          u_int8_t                mii_regaddr;
:          u_int8_t                mii_turnaround;
:          u_int16_t               mii_data;
:  };All the drivers use this kind of frame structure.
: Is this a generic one? how does one use it?

That looks like it might be left over from ports to other OSes.  What
you are seeing in the nge driver is that it is reading/writing the
registers and doing the transactions in a rather long way.  It is best
viewed as bitbanging the information out.

: is there a simple driver i can look at? or a simple
: tutorial on network drivers?
: the National Semiconductor driver is a bit complex.

Generally, one just lets the MII bus do its thing.  If you look at the
if_ate driver, you can see this in operation:

#include <dev/mii/mii.h>
#include <dev/mii/miivar.h>
...
#include "miibus_if.h"
...
/* in softc */
        device_t miibus; /* My child miibus */
...

after allocating the ifp:
        if (mii_phy_probe(dev, &sc->miibus, ate_ifmedia_upd, ate_ifmedia_sts)) {
                device_printf(dev, "Cannot find my PHY.\n");
                err = ENXIO;
                goto out;
        }
...
/*
 * Change media according to request.
 */
static int
ate_ifmedia_upd(struct ifnet *ifp)
{
        struct ate_softc *sc = ifp->if_softc;
        struct mii_data *mii;

        mii = device_get_softc(sc->miibus);
        ATE_LOCK(sc);
        mii_mediachg(mii);
        ATE_UNLOCK(sc);
        return (0);
}

/*
 * Notify the world which media we're using.
 */
static void
ate_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
{
        struct ate_softc *sc = ifp->if_softc;
        struct mii_data *mii;

        mii = device_get_softc(sc->miibus);
        ATE_LOCK(sc);
        mii_pollstat(mii);
        ifmr->ifm_active = mii->mii_media_active;
        ifmr->ifm_status = mii->mii_media_status;
        ATE_UNLOCK(sc);
}

static void
ate_tick(void *xsc)
{
        struct ate_softc *sc = xsc;
        struct mii_data *mii;
        int active;

        /*
         * The KB920x boot loader tests ETH_SR & ETH_SR_LINK and will ask
         * the MII if there's a link if this bit is clear.  Not sure if we
         * should do the same thing here or not.
         */
        ATE_ASSERT_LOCKED(sc);
        if (sc->miibus != NULL) {
                mii = device_get_softc(sc->miibus);
                active = mii->mii_media_active;
                mii_tick(mii);
                if (mii->mii_media_status & IFM_ACTIVE &&
                     active != mii->mii_media_active) {
                        /*
                         * The speed and full/half-duplex state needs
                         * to be reflected in the ETH_CFG register, it
                         * seems.
                         */
                        if (IFM_SUBTYPE(mii->mii_media_active) == IFM_10_T)
                                WR4(sc, ETH_CFG, RD4(sc, ETH_CFG) &
                                    ~ETH_CFG_SPD);
                        else
                                WR4(sc, ETH_CFG, RD4(sc, ETH_CFG) |
                                    ETH_CFG_SPD);
                        if (mii->mii_media_active & IFM_FDX)
                                WR4(sc, ETH_CFG, RD4(sc, ETH_CFG) |
                                    ETH_CFG_FD);
                        else
                                WR4(sc, ETH_CFG, RD4(sc, ETH_CFG) &
                                    ~ETH_CFG_FD);
                }
        }
...
        /*
         * Schedule another timeout one second from now.
         */
        callout_reset(&sc->tick_ch, hz, ate_tick, sc);
}

At the end of the if_init routine, you need to start the ticker:

        callout_reset(&sc->tick_ch, hz, ate_tick, sc);

You also need to implement the read/write regitser stuff

Add this to your device's method table:

        /* MII interface */
        DEVMETHOD(miibus_readreg, ate_miibus_readreg),
        DEVMETHOD(miibus_writereg, ate_miibus_writereg),

For comparison, here's the ate read/write routines:

/*
 * MII bus support routines.
 */
static int
ate_miibus_readreg(device_t dev, int phy, int reg)
{
        struct ate_softc *sc;
        int val;

        /*
         * XXX if we implement agressive power savings, then we need
         * XXX to make sure that the clock to the emac is on here
         */

        if (phy != 0)
                return (0xffff);
        sc = device_get_softc(dev);
        DELAY(1); /* Hangs w/o this delay really 30.5us atm */
        WR4(sc, ETH_MAN, ETH_MAN_REG_RD(phy, reg));
        while ((RD4(sc, ETH_SR) & ETH_SR_IDLE) == 0)
                continue;
        val = RD4(sc, ETH_MAN) & ETH_MAN_VALUE_MASK;

        return (val);
}

static void
ate_miibus_writereg(device_t dev, int phy, int reg, int data)
{
        struct ate_softc *sc;
       
        /*
         * XXX if we implement agressive power savings, then we need
         * XXX to make sure that the clock to the emac is on here
         */

        sc = device_get_softc(dev);
        WR4(sc, ETH_MAN, ETH_MAN_REG_WR(phy, reg, data));
        while ((RD4(sc, ETH_SR) & ETH_SR_IDLE) == 0)
                continue;
        return;
}

The ate hardware does the bit-banging for you...

FreeBSD doesn't directly program the PHY.  Your driver still needs to
do that, as illustrated above.  This just takes the drudgery out of
it.

Warner
_______________________________________________
[hidden email] mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-new-bus
To unsubscribe, send any mail to "[hidden email]"