diff options
author | marius <marius@FreeBSD.org> | 2011-11-01 16:13:59 +0000 |
---|---|---|
committer | marius <marius@FreeBSD.org> | 2011-11-01 16:13:59 +0000 |
commit | b4610d98b0096971fd87d53d90c40f4da7db34e2 (patch) | |
tree | ad9ba266ea9f21e3bb8157cdc1c2c7c8b1a6b9a3 /sys/pci/if_rl.c | |
parent | d08a02f709c03ad61dd57d1fa39412d6de62189d (diff) | |
download | FreeBSD-src-b4610d98b0096971fd87d53d90c40f4da7db34e2.zip FreeBSD-src-b4610d98b0096971fd87d53d90c40f4da7db34e2.tar.gz |
- Import the common MII bitbang'ing code from NetBSD and convert drivers to
take advantage of it instead of duplicating it. This reduces the size of
the i386 GENERIC kernel by about 4k. The only potential in-tree user left
unconverted is xe(4), which generally should be changed to use miibus(4)
instead of implementing PHY handling on its own, as otherwise it makes not
much sense to add a dependency on miibus(4)/mii_bitbang(4) to xe(4) just
for the MII bitbang'ing code. The common MII bitbang'ing code also is
useful in the embedded space for using GPIO pins to implement MII access.
- Based on lessons learnt with dc(4) (see r185750), add bus barriers to the
MII bitbang read and write functions of the other drivers converted in
order to ensure the intended ordering. Given that register access via an
index register as well as register bank/window switching is subject to the
same problem, also add bus barriers to the respective functions of smc(4),
tl(4) and xl(4).
- Sprinkle some const.
Thanks to the following testers:
Andrew Bliznak (nge(4)), nwhitehorn@ (bm(4)), yongari@ (sis(4) and ste(4))
Thanks to Hans-Joerg Sirtl for supplying hardware to test stge(4).
Reviewed by: yongari (subset of drivers)
Obtained from: NetBSD (partially)
Diffstat (limited to 'sys/pci/if_rl.c')
-rw-r--r-- | sys/pci/if_rl.c | 227 |
1 files changed, 46 insertions, 181 deletions
diff --git a/sys/pci/if_rl.c b/sys/pci/if_rl.c index 87c2fc8..19b84d2 100644 --- a/sys/pci/if_rl.c +++ b/sys/pci/if_rl.c @@ -113,6 +113,7 @@ __FBSDID("$FreeBSD$"); #include <sys/rman.h> #include <dev/mii/mii.h> +#include <dev/mii/mii_bitbang.h> #include <dev/mii/miivar.h> #include <dev/pci/pcireg.h> @@ -130,7 +131,7 @@ MODULE_DEPEND(rl, miibus, 1, 1, 1); /* * Various supported device vendors/types and their names. */ -static struct rl_type rl_devs[] = { +static const struct rl_type const rl_devs[] = { { RT_VENDORID, RT_DEVICEID_8129, RL_8129, "RealTek 8129 10/100BaseTX" }, { RT_VENDORID, RT_DEVICEID_8139, RL_8139, @@ -187,10 +188,6 @@ static int rl_ioctl(struct ifnet *, u_long, caddr_t); static void rl_intr(void *); static void rl_init(void *); static void rl_init_locked(struct rl_softc *sc); -static void rl_mii_send(struct rl_softc *, uint32_t, int); -static void rl_mii_sync(struct rl_softc *); -static int rl_mii_readreg(struct rl_softc *, struct rl_mii_frame *); -static int rl_mii_writereg(struct rl_softc *, struct rl_mii_frame *); static int rl_miibus_readreg(device_t, int, int); static void rl_miibus_statchg(device_t); static int rl_miibus_writereg(device_t, int, int, int); @@ -215,6 +212,24 @@ static void rl_watchdog(struct rl_softc *); static void rl_setwol(struct rl_softc *); static void rl_clrwol(struct rl_softc *); +/* + * MII bit-bang glue + */ +static uint32_t rl_mii_bitbang_read(device_t); +static void rl_mii_bitbang_write(device_t, uint32_t); + +static const struct mii_bitbang_ops rl_mii_bitbang_ops = { + rl_mii_bitbang_read, + rl_mii_bitbang_write, + { + RL_MII_DATAOUT, /* MII_BIT_MDO */ + RL_MII_DATAIN, /* MII_BIT_MDI */ + RL_MII_CLK, /* MII_BIT_MDC */ + RL_MII_DIR, /* MII_BIT_DIR_HOST_PHY */ + 0, /* MII_BIT_DIR_PHY_HOST */ + } +}; + static device_method_t rl_methods[] = { /* Device interface */ DEVMETHOD(device_probe, rl_probe), @@ -340,181 +355,43 @@ rl_read_eeprom(struct rl_softc *sc, uint8_t *dest, int off, int cnt, int swap) } /* - * MII access routines are provided for the 8129, which - * doesn't have a built-in PHY. For the 8139, we fake things - * up by diverting rl_phy_readreg()/rl_phy_writereg() to the - * direct access PHY registers. - */ -#define MII_SET(x) \ - CSR_WRITE_1(sc, RL_MII, \ - CSR_READ_1(sc, RL_MII) | (x)) - -#define MII_CLR(x) \ - CSR_WRITE_1(sc, RL_MII, \ - CSR_READ_1(sc, RL_MII) & ~(x)) - -/* - * Sync the PHYs by setting data bit and strobing the clock 32 times. - */ -static void -rl_mii_sync(struct rl_softc *sc) -{ - register int i; - - MII_SET(RL_MII_DIR|RL_MII_DATAOUT); - - for (i = 0; i < 32; i++) { - MII_SET(RL_MII_CLK); - DELAY(1); - MII_CLR(RL_MII_CLK); - DELAY(1); - } -} - -/* - * Clock a series of bits through the MII. + * Read the MII serial port for the MII bit-bang module. */ -static void -rl_mii_send(struct rl_softc *sc, uint32_t bits, int cnt) +static uint32_t +rl_mii_bitbang_read(device_t dev) { - int i; - - MII_CLR(RL_MII_CLK); + struct rl_softc *sc; + uint32_t val; - for (i = (0x1 << (cnt - 1)); i; i >>= 1) { - if (bits & i) { - MII_SET(RL_MII_DATAOUT); - } else { - MII_CLR(RL_MII_DATAOUT); - } - DELAY(1); - MII_CLR(RL_MII_CLK); - DELAY(1); - MII_SET(RL_MII_CLK); - } -} - -/* - * Read an PHY register through the MII. - */ -static int -rl_mii_readreg(struct rl_softc *sc, struct rl_mii_frame *frame) -{ - int i, ack; - - /* Set up frame for RX. */ - frame->mii_stdelim = RL_MII_STARTDELIM; - frame->mii_opcode = RL_MII_READOP; - frame->mii_turnaround = 0; - frame->mii_data = 0; - - CSR_WRITE_2(sc, RL_MII, 0); - - /* Turn on data xmit. */ - MII_SET(RL_MII_DIR); - - rl_mii_sync(sc); - - /* Send command/address info. */ - rl_mii_send(sc, frame->mii_stdelim, 2); - rl_mii_send(sc, frame->mii_opcode, 2); - rl_mii_send(sc, frame->mii_phyaddr, 5); - rl_mii_send(sc, frame->mii_regaddr, 5); - - /* Idle bit */ - MII_CLR((RL_MII_CLK|RL_MII_DATAOUT)); - DELAY(1); - MII_SET(RL_MII_CLK); - DELAY(1); - - /* Turn off xmit. */ - MII_CLR(RL_MII_DIR); - - /* Check for ack */ - MII_CLR(RL_MII_CLK); - DELAY(1); - ack = CSR_READ_2(sc, RL_MII) & RL_MII_DATAIN; - MII_SET(RL_MII_CLK); - DELAY(1); - - /* - * Now try reading data bits. If the ack failed, we still - * need to clock through 16 cycles to keep the PHY(s) in sync. - */ - if (ack) { - for(i = 0; i < 16; i++) { - MII_CLR(RL_MII_CLK); - DELAY(1); - MII_SET(RL_MII_CLK); - DELAY(1); - } - goto fail; - } - - for (i = 0x8000; i; i >>= 1) { - MII_CLR(RL_MII_CLK); - DELAY(1); - if (!ack) { - if (CSR_READ_2(sc, RL_MII) & RL_MII_DATAIN) - frame->mii_data |= i; - DELAY(1); - } - MII_SET(RL_MII_CLK); - DELAY(1); - } + sc = device_get_softc(dev); -fail: - MII_CLR(RL_MII_CLK); - DELAY(1); - MII_SET(RL_MII_CLK); - DELAY(1); + val = CSR_READ_1(sc, RL_MII); + CSR_BARRIER(sc, RL_MII, 1, + BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); - return (ack ? 1 : 0); + return (val); } /* - * Write to a PHY register through the MII. + * Write the MII serial port for the MII bit-bang module. */ -static int -rl_mii_writereg(struct rl_softc *sc, struct rl_mii_frame *frame) +static void +rl_mii_bitbang_write(device_t dev, uint32_t val) { + struct rl_softc *sc; - /* Set up frame for TX. */ - frame->mii_stdelim = RL_MII_STARTDELIM; - frame->mii_opcode = RL_MII_WRITEOP; - frame->mii_turnaround = RL_MII_TURNAROUND; - - /* Turn on data output. */ - MII_SET(RL_MII_DIR); - - rl_mii_sync(sc); - - rl_mii_send(sc, frame->mii_stdelim, 2); - rl_mii_send(sc, frame->mii_opcode, 2); - rl_mii_send(sc, frame->mii_phyaddr, 5); - rl_mii_send(sc, frame->mii_regaddr, 5); - rl_mii_send(sc, frame->mii_turnaround, 2); - rl_mii_send(sc, frame->mii_data, 16); - - /* Idle bit. */ - MII_SET(RL_MII_CLK); - DELAY(1); - MII_CLR(RL_MII_CLK); - DELAY(1); - - /* Turn off xmit. */ - MII_CLR(RL_MII_DIR); + sc = device_get_softc(dev); - return (0); + CSR_WRITE_1(sc, RL_MII, val); + CSR_BARRIER(sc, RL_MII, 1, + BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); } static int rl_miibus_readreg(device_t dev, int phy, int reg) { struct rl_softc *sc; - struct rl_mii_frame frame; - uint16_t rval = 0; - uint16_t rl8139_reg = 0; + uint16_t rl8139_reg; sc = device_get_softc(dev); @@ -545,30 +422,22 @@ rl_miibus_readreg(device_t dev, int phy, int reg) * us the results of parallel detection. */ case RL_MEDIASTAT: - rval = CSR_READ_1(sc, RL_MEDIASTAT); - return (rval); + return (CSR_READ_1(sc, RL_MEDIASTAT)); default: device_printf(sc->rl_dev, "bad phy register\n"); return (0); } - rval = CSR_READ_2(sc, rl8139_reg); - return (rval); + return (CSR_READ_2(sc, rl8139_reg)); } - bzero((char *)&frame, sizeof(frame)); - frame.mii_phyaddr = phy; - frame.mii_regaddr = reg; - rl_mii_readreg(sc, &frame); - - return (frame.mii_data); + return (mii_bitbang_readreg(dev, &rl_mii_bitbang_ops, phy, reg)); } static int rl_miibus_writereg(device_t dev, int phy, int reg, int data) { struct rl_softc *sc; - struct rl_mii_frame frame; - uint16_t rl8139_reg = 0; + uint16_t rl8139_reg; sc = device_get_softc(dev); @@ -601,11 +470,7 @@ rl_miibus_writereg(device_t dev, int phy, int reg, int data) return (0); } - bzero((char *)&frame, sizeof(frame)); - frame.mii_phyaddr = phy; - frame.mii_regaddr = reg; - frame.mii_data = data; - rl_mii_writereg(sc, &frame); + mii_bitbang_writereg(dev, &rl_mii_bitbang_ops, phy, reg, data); return (0); } @@ -719,7 +584,7 @@ rl_reset(struct rl_softc *sc) static int rl_probe(device_t dev) { - struct rl_type *t; + const struct rl_type *t; uint16_t devid, revid, vendor; int i; @@ -773,7 +638,7 @@ rl_attach(device_t dev) uint16_t as[3]; struct ifnet *ifp; struct rl_softc *sc; - struct rl_type *t; + const struct rl_type *t; struct sysctl_ctx_list *ctx; struct sysctl_oid_list *children; int error = 0, hwrev, i, phy, pmc, rid; |