summaryrefslogtreecommitdiffstats
path: root/sys/dev/xl
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/dev/xl
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/dev/xl')
-rw-r--r--sys/dev/xl/if_xl.c205
-rw-r--r--sys/dev/xl/if_xlreg.h32
2 files changed, 58 insertions, 179 deletions
diff --git a/sys/dev/xl/if_xl.c b/sys/dev/xl/if_xl.c
index e09e434..b774e7f 100644
--- a/sys/dev/xl/if_xl.c
+++ b/sys/dev/xl/if_xl.c
@@ -127,6 +127,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>
@@ -160,7 +161,7 @@ MODULE_DEPEND(xl, miibus, 1, 1, 1);
/*
* Various supported device vendors/types and their names.
*/
-static const struct xl_type xl_devs[] = {
+static const struct xl_type const xl_devs[] = {
{ TC_VENDORID, TC_DEVICEID_BOOMERANG_10BT,
"3Com 3c900-TPO Etherlink XL" },
{ TC_VENDORID, TC_DEVICEID_BOOMERANG_10BT_COMBO,
@@ -258,10 +259,6 @@ static void xl_ifmedia_sts(struct ifnet *, struct ifmediareq *);
static int xl_eeprom_wait(struct xl_softc *);
static int xl_read_eeprom(struct xl_softc *, caddr_t, int, int, int);
-static void xl_mii_sync(struct xl_softc *);
-static void xl_mii_send(struct xl_softc *, u_int32_t, int);
-static int xl_mii_readreg(struct xl_softc *, struct xl_mii_frame *);
-static int xl_mii_writereg(struct xl_softc *, struct xl_mii_frame *);
static void xl_rxfilter(struct xl_softc *);
static void xl_rxfilter_90x(struct xl_softc *);
@@ -286,6 +283,24 @@ static int xl_miibus_writereg(device_t, int, int, int);
static void xl_miibus_statchg(device_t);
static void xl_miibus_mediainit(device_t);
+/*
+ * MII bit-bang glue
+ */
+static uint32_t xl_mii_bitbang_read(device_t);
+static void xl_mii_bitbang_write(device_t, uint32_t);
+
+static const struct mii_bitbang_ops xl_mii_bitbang_ops = {
+ xl_mii_bitbang_read,
+ xl_mii_bitbang_write,
+ {
+ XL_MII_DATA, /* MII_BIT_MDO */
+ XL_MII_DATA, /* MII_BIT_MDI */
+ XL_MII_CLK, /* MII_BIT_MDC */
+ XL_MII_DIR, /* MII_BIT_DIR_HOST_PHY */
+ 0, /* MII_BIT_DIR_PHY_HOST */
+ }
+};
+
static device_method_t xl_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, xl_probe),
@@ -359,194 +374,66 @@ xl_wait(struct xl_softc *sc)
* some chips/CPUs/processor speeds/bus speeds/etc but not
* with others.
*/
-#define MII_SET(x) \
- CSR_WRITE_2(sc, XL_W4_PHY_MGMT, \
- CSR_READ_2(sc, XL_W4_PHY_MGMT) | (x))
-
-#define MII_CLR(x) \
- CSR_WRITE_2(sc, XL_W4_PHY_MGMT, \
- CSR_READ_2(sc, XL_W4_PHY_MGMT) & ~(x))
-
-/*
- * Sync the PHYs by setting data bit and strobing the clock 32 times.
- */
-static void
-xl_mii_sync(struct xl_softc *sc)
-{
- register int i;
-
- XL_SEL_WIN(4);
- MII_SET(XL_MII_DIR|XL_MII_DATA);
-
- for (i = 0; i < 32; i++) {
- MII_SET(XL_MII_CLK);
- MII_SET(XL_MII_DATA);
- MII_SET(XL_MII_DATA);
- MII_CLR(XL_MII_CLK);
- MII_SET(XL_MII_DATA);
- MII_SET(XL_MII_DATA);
- }
-}
/*
- * Clock a series of bits through the MII.
+ * Read the MII serial port for the MII bit-bang module.
*/
-static void
-xl_mii_send(struct xl_softc *sc, u_int32_t bits, int cnt)
+static uint32_t
+xl_mii_bitbang_read(device_t dev)
{
- int i;
-
- XL_SEL_WIN(4);
- MII_CLR(XL_MII_CLK);
-
- for (i = (0x1 << (cnt - 1)); i; i >>= 1) {
- if (bits & i) {
- MII_SET(XL_MII_DATA);
- } else {
- MII_CLR(XL_MII_DATA);
- }
- MII_CLR(XL_MII_CLK);
- MII_SET(XL_MII_CLK);
- }
-}
-
-/*
- * Read an PHY register through the MII.
- */
-static int
-xl_mii_readreg(struct xl_softc *sc, struct xl_mii_frame *frame)
-{
- int i, ack;
-
- /* Set up frame for RX. */
- frame->mii_stdelim = XL_MII_STARTDELIM;
- frame->mii_opcode = XL_MII_READOP;
- frame->mii_turnaround = 0;
- frame->mii_data = 0;
-
- /* Select register window 4. */
- XL_SEL_WIN(4);
-
- CSR_WRITE_2(sc, XL_W4_PHY_MGMT, 0);
- /* Turn on data xmit. */
- MII_SET(XL_MII_DIR);
-
- xl_mii_sync(sc);
-
- /* Send command/address info. */
- xl_mii_send(sc, frame->mii_stdelim, 2);
- xl_mii_send(sc, frame->mii_opcode, 2);
- xl_mii_send(sc, frame->mii_phyaddr, 5);
- xl_mii_send(sc, frame->mii_regaddr, 5);
-
- /* Idle bit */
- MII_CLR((XL_MII_CLK|XL_MII_DATA));
- MII_SET(XL_MII_CLK);
-
- /* Turn off xmit. */
- MII_CLR(XL_MII_DIR);
-
- /* Check for ack */
- MII_CLR(XL_MII_CLK);
- ack = CSR_READ_2(sc, XL_W4_PHY_MGMT) & XL_MII_DATA;
- MII_SET(XL_MII_CLK);
-
- /*
- * 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(XL_MII_CLK);
- MII_SET(XL_MII_CLK);
- }
- goto fail;
- }
+ struct xl_softc *sc;
+ uint32_t val;
- for (i = 0x8000; i; i >>= 1) {
- MII_CLR(XL_MII_CLK);
- if (!ack) {
- if (CSR_READ_2(sc, XL_W4_PHY_MGMT) & XL_MII_DATA)
- frame->mii_data |= i;
- }
- MII_SET(XL_MII_CLK);
- }
+ sc = device_get_softc(dev);
-fail:
- MII_CLR(XL_MII_CLK);
- MII_SET(XL_MII_CLK);
+ /* We're already in window 4. */
+ val = CSR_READ_2(sc, XL_W4_PHY_MGMT);
+ CSR_BARRIER(sc, XL_W4_PHY_MGMT, 2,
+ 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
-xl_mii_writereg(struct xl_softc *sc, struct xl_mii_frame *frame)
+static void
+xl_mii_bitbang_write(device_t dev, uint32_t val)
{
+ struct xl_softc *sc;
- /* Set up frame for TX. */
- frame->mii_stdelim = XL_MII_STARTDELIM;
- frame->mii_opcode = XL_MII_WRITEOP;
- frame->mii_turnaround = XL_MII_TURNAROUND;
-
- /* Select the window 4. */
- XL_SEL_WIN(4);
-
- /* Turn on data output. */
- MII_SET(XL_MII_DIR);
-
- xl_mii_sync(sc);
-
- xl_mii_send(sc, frame->mii_stdelim, 2);
- xl_mii_send(sc, frame->mii_opcode, 2);
- xl_mii_send(sc, frame->mii_phyaddr, 5);
- xl_mii_send(sc, frame->mii_regaddr, 5);
- xl_mii_send(sc, frame->mii_turnaround, 2);
- xl_mii_send(sc, frame->mii_data, 16);
-
- /* Idle bit. */
- MII_SET(XL_MII_CLK);
- MII_CLR(XL_MII_CLK);
-
- /* Turn off xmit. */
- MII_CLR(XL_MII_DIR);
+ sc = device_get_softc(dev);
- return (0);
+ /* We're already in window 4. */
+ CSR_WRITE_2(sc, XL_W4_PHY_MGMT, val);
+ CSR_BARRIER(sc, XL_W4_PHY_MGMT, 2,
+ BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
}
static int
xl_miibus_readreg(device_t dev, int phy, int reg)
{
struct xl_softc *sc;
- struct xl_mii_frame frame;
sc = device_get_softc(dev);
- bzero((char *)&frame, sizeof(frame));
- frame.mii_phyaddr = phy;
- frame.mii_regaddr = reg;
-
- xl_mii_readreg(sc, &frame);
+ /* Select the window 4. */
+ XL_SEL_WIN(4);
- return (frame.mii_data);
+ return (mii_bitbang_readreg(dev, &xl_mii_bitbang_ops, phy, reg));
}
static int
xl_miibus_writereg(device_t dev, int phy, int reg, int data)
{
struct xl_softc *sc;
- struct xl_mii_frame frame;
sc = device_get_softc(dev);
- bzero((char *)&frame, sizeof(frame));
- frame.mii_phyaddr = phy;
- frame.mii_regaddr = reg;
- frame.mii_data = data;
+ /* Select the window 4. */
+ XL_SEL_WIN(4);
- xl_mii_writereg(sc, &frame);
+ mii_bitbang_writereg(dev, &xl_mii_bitbang_ops, phy, reg, data);
return (0);
}
diff --git a/sys/dev/xl/if_xlreg.h b/sys/dev/xl/if_xlreg.h
index f5494f5..b27e038 100644
--- a/sys/dev/xl/if_xlreg.h
+++ b/sys/dev/xl/if_xlreg.h
@@ -556,27 +556,10 @@ struct xl_chain_data {
struct xl_type {
u_int16_t xl_vid;
u_int16_t xl_did;
- char *xl_name;
-};
-
-struct xl_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;
+ const char *xl_name;
};
/*
- * MII constants
- */
-#define XL_MII_STARTDELIM 0x01
-#define XL_MII_READOP 0x02
-#define XL_MII_WRITEOP 0x01
-#define XL_MII_TURNAROUND 0x02
-
-/*
* The 3C905B adapters implement a few features that we want to
* take advantage of, namely the multicast hash filter. With older
* chips, you only have the option of turning on reception of all
@@ -680,8 +663,17 @@ struct xl_stats {
#define CSR_READ_1(sc, reg) \
bus_space_read_1(sc->xl_btag, sc->xl_bhandle, reg)
-#define XL_SEL_WIN(x) \
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_WINSEL | x)
+#define CSR_BARRIER(sc, reg, length, flags) \
+ bus_space_barrier(sc->xl_btag, sc->xl_bhandle, reg, length, flags)
+
+#define XL_SEL_WIN(x) do { \
+ CSR_BARRIER(sc, XL_COMMAND, 2, \
+ BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); \
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_WINSEL | x); \
+ CSR_BARRIER(sc, XL_COMMAND, 2, \
+ BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); \
+} while (0)
+
#define XL_TIMEOUT 1000
/*
OpenPOWER on IntegriCloud