summaryrefslogtreecommitdiffstats
path: root/sys/pci/if_rl.c
diff options
context:
space:
mode:
authormarius <marius@FreeBSD.org>2011-11-01 16:13:59 +0000
committermarius <marius@FreeBSD.org>2011-11-01 16:13:59 +0000
commitb4610d98b0096971fd87d53d90c40f4da7db34e2 (patch)
treead9ba266ea9f21e3bb8157cdc1c2c7c8b1a6b9a3 /sys/pci/if_rl.c
parentd08a02f709c03ad61dd57d1fa39412d6de62189d (diff)
downloadFreeBSD-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.c227
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;
OpenPOWER on IntegriCloud