summaryrefslogtreecommitdiffstats
path: root/sys/dev/stge
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/stge
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/stge')
-rw-r--r--sys/dev/stge/if_stge.c236
-rw-r--r--sys/dev/stge/if_stgereg.h20
2 files changed, 50 insertions, 206 deletions
diff --git a/sys/dev/stge/if_stge.c b/sys/dev/stge/if_stge.c
index 5058a4d..b18da27 100644
--- a/sys/dev/stge/if_stge.c
+++ b/sys/dev/stge/if_stge.c
@@ -67,6 +67,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>
@@ -86,11 +87,11 @@ MODULE_DEPEND(stge, miibus, 1, 1, 1);
/*
* Devices supported by this driver.
*/
-static struct stge_product {
+static const struct stge_product {
uint16_t stge_vendorid;
uint16_t stge_deviceid;
const char *stge_name;
-} stge_products[] = {
+} const stge_products[] = {
{ VENDOR_SUNDANCETI, DEVICEID_SUNDANCETI_ST1023,
"Sundance ST-1023 Gigabit Ethernet" },
@@ -160,10 +161,6 @@ static int stge_newbuf(struct stge_softc *, int);
static __inline struct mbuf *stge_fixup_rx(struct stge_softc *, struct mbuf *);
#endif
-static void stge_mii_sync(struct stge_softc *);
-static void stge_mii_send(struct stge_softc *, uint32_t, int);
-static int stge_mii_readreg(struct stge_softc *, struct stge_mii_frame *);
-static int stge_mii_writereg(struct stge_softc *, struct stge_mii_frame *);
static int stge_miibus_readreg(device_t, int, int);
static int stge_miibus_writereg(device_t, int, int, int);
static void stge_miibus_statchg(device_t);
@@ -185,6 +182,24 @@ static int sysctl_int_range(SYSCTL_HANDLER_ARGS, int, int);
static int sysctl_hw_stge_rxint_nframe(SYSCTL_HANDLER_ARGS);
static int sysctl_hw_stge_rxint_dmawait(SYSCTL_HANDLER_ARGS);
+/*
+ * MII bit-bang glue
+ */
+static uint32_t stge_mii_bitbang_read(device_t);
+static void stge_mii_bitbang_write(device_t, uint32_t);
+
+static const struct mii_bitbang_ops stge_mii_bitbang_ops = {
+ stge_mii_bitbang_read,
+ stge_mii_bitbang_write,
+ {
+ PC_MgmtData, /* MII_BIT_MDO */
+ PC_MgmtData, /* MII_BIT_MDI */
+ PC_MgmtClk, /* MII_BIT_MDC */
+ PC_MgmtDir, /* MII_BIT_DIR_HOST_PHY */
+ 0, /* MII_BIT_DIR_PHY_HOST */
+ }
+};
+
static device_method_t stge_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, stge_probe),
@@ -225,176 +240,40 @@ static struct resource_spec stge_res_spec_mem[] = {
{ -1, 0, 0 }
};
-#define MII_SET(x) \
- CSR_WRITE_1(sc, STGE_PhyCtrl, CSR_READ_1(sc, STGE_PhyCtrl) | (x))
-#define MII_CLR(x) \
- CSR_WRITE_1(sc, STGE_PhyCtrl, CSR_READ_1(sc, STGE_PhyCtrl) & ~(x))
-
/*
- * Sync the PHYs by setting data bit and strobing the clock 32 times.
+ * stge_mii_bitbang_read: [mii bit-bang interface function]
+ *
+ * Read the MII serial port for the MII bit-bang module.
*/
-static void
-stge_mii_sync(struct stge_softc *sc)
+static uint32_t
+stge_mii_bitbang_read(device_t dev)
{
- int i;
+ struct stge_softc *sc;
+ uint32_t val;
- MII_SET(PC_MgmtDir | PC_MgmtData);
+ sc = device_get_softc(dev);
- for (i = 0; i < 32; i++) {
- MII_SET(PC_MgmtClk);
- DELAY(1);
- MII_CLR(PC_MgmtClk);
- DELAY(1);
- }
+ val = CSR_READ_1(sc, STGE_PhyCtrl);
+ CSR_BARRIER(sc, STGE_PhyCtrl, 1,
+ BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
+ return (val);
}
/*
- * Clock a series of bits through the MII.
+ * stge_mii_bitbang_write: [mii big-bang interface function]
+ *
+ * Write the MII serial port for the MII bit-bang module.
*/
static void
-stge_mii_send(struct stge_softc *sc, uint32_t bits, int cnt)
-{
- int i;
-
- MII_CLR(PC_MgmtClk);
-
- for (i = (0x1 << (cnt - 1)); i; i >>= 1) {
- if (bits & i)
- MII_SET(PC_MgmtData);
- else
- MII_CLR(PC_MgmtData);
- DELAY(1);
- MII_CLR(PC_MgmtClk);
- DELAY(1);
- MII_SET(PC_MgmtClk);
- }
-}
-
-/*
- * Read an PHY register through the MII.
- */
-static int
-stge_mii_readreg(struct stge_softc *sc, struct stge_mii_frame *frame)
+stge_mii_bitbang_write(device_t dev, uint32_t val)
{
- int i, ack;
-
- /*
- * Set up frame for RX.
- */
- frame->mii_stdelim = STGE_MII_STARTDELIM;
- frame->mii_opcode = STGE_MII_READOP;
- frame->mii_turnaround = 0;
- frame->mii_data = 0;
-
- CSR_WRITE_1(sc, STGE_PhyCtrl, 0 | sc->sc_PhyCtrl);
- /*
- * Turn on data xmit.
- */
- MII_SET(PC_MgmtDir);
-
- stge_mii_sync(sc);
-
- /*
- * Send command/address info.
- */
- stge_mii_send(sc, frame->mii_stdelim, 2);
- stge_mii_send(sc, frame->mii_opcode, 2);
- stge_mii_send(sc, frame->mii_phyaddr, 5);
- stge_mii_send(sc, frame->mii_regaddr, 5);
-
- /* Turn off xmit. */
- MII_CLR(PC_MgmtDir);
-
- /* Idle bit */
- MII_CLR((PC_MgmtClk | PC_MgmtData));
- DELAY(1);
- MII_SET(PC_MgmtClk);
- DELAY(1);
-
- /* Check for ack */
- MII_CLR(PC_MgmtClk);
- DELAY(1);
- ack = CSR_READ_1(sc, STGE_PhyCtrl) & PC_MgmtData;
- MII_SET(PC_MgmtClk);
- 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(PC_MgmtClk);
- DELAY(1);
- MII_SET(PC_MgmtClk);
- DELAY(1);
- }
- goto fail;
- }
-
- for (i = 0x8000; i; i >>= 1) {
- MII_CLR(PC_MgmtClk);
- DELAY(1);
- if (!ack) {
- if (CSR_READ_1(sc, STGE_PhyCtrl) & PC_MgmtData)
- frame->mii_data |= i;
- DELAY(1);
- }
- MII_SET(PC_MgmtClk);
- DELAY(1);
- }
-
-fail:
- MII_CLR(PC_MgmtClk);
- DELAY(1);
- MII_SET(PC_MgmtClk);
- DELAY(1);
-
- if (ack)
- return(1);
- return(0);
-}
-
-/*
- * Write to a PHY register through the MII.
- */
-static int
-stge_mii_writereg(struct stge_softc *sc, struct stge_mii_frame *frame)
-{
-
- /*
- * Set up frame for TX.
- */
- frame->mii_stdelim = STGE_MII_STARTDELIM;
- frame->mii_opcode = STGE_MII_WRITEOP;
- frame->mii_turnaround = STGE_MII_TURNAROUND;
-
- /*
- * Turn on data output.
- */
- MII_SET(PC_MgmtDir);
-
- stge_mii_sync(sc);
-
- stge_mii_send(sc, frame->mii_stdelim, 2);
- stge_mii_send(sc, frame->mii_opcode, 2);
- stge_mii_send(sc, frame->mii_phyaddr, 5);
- stge_mii_send(sc, frame->mii_regaddr, 5);
- stge_mii_send(sc, frame->mii_turnaround, 2);
- stge_mii_send(sc, frame->mii_data, 16);
-
- /* Idle bit. */
- MII_SET(PC_MgmtClk);
- DELAY(1);
- MII_CLR(PC_MgmtClk);
- DELAY(1);
+ struct stge_softc *sc;
- /*
- * Turn off xmit.
- */
- MII_CLR(PC_MgmtDir);
+ sc = device_get_softc(dev);
- return(0);
+ CSR_WRITE_1(sc, STGE_PhyCtrl, val);
+ CSR_BARRIER(sc, STGE_PhyCtrl, 1,
+ BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
}
/*
@@ -406,8 +285,7 @@ static int
stge_miibus_readreg(device_t dev, int phy, int reg)
{
struct stge_softc *sc;
- struct stge_mii_frame frame;
- int error;
+ int error, val;
sc = device_get_softc(dev);
@@ -418,21 +296,11 @@ stge_miibus_readreg(device_t dev, int phy, int reg)
STGE_MII_UNLOCK(sc);
return (error);
}
- bzero(&frame, sizeof(frame));
- frame.mii_phyaddr = phy;
- frame.mii_regaddr = reg;
STGE_MII_LOCK(sc);
- error = stge_mii_readreg(sc, &frame);
+ val = mii_bitbang_readreg(dev, &stge_mii_bitbang_ops, phy, reg);
STGE_MII_UNLOCK(sc);
-
- if (error != 0) {
- /* Don't show errors for PHY probe request */
- if (reg != 1)
- device_printf(sc->sc_dev, "phy read fail\n");
- return (0);
- }
- return (frame.mii_data);
+ return (val);
}
/*
@@ -444,22 +312,12 @@ static int
stge_miibus_writereg(device_t dev, int phy, int reg, int val)
{
struct stge_softc *sc;
- struct stge_mii_frame frame;
- int error;
sc = device_get_softc(dev);
- bzero(&frame, sizeof(frame));
- frame.mii_phyaddr = phy;
- frame.mii_regaddr = reg;
- frame.mii_data = val;
-
STGE_MII_LOCK(sc);
- error = stge_mii_writereg(sc, &frame);
+ mii_bitbang_writereg(dev, &stge_mii_bitbang_ops, phy, reg, val);
STGE_MII_UNLOCK(sc);
-
- if (error != 0)
- device_printf(sc->sc_dev, "phy write fail\n");
return (0);
}
@@ -550,7 +408,7 @@ stge_read_eeprom(struct stge_softc *sc, int offset, uint16_t *data)
static int
stge_probe(device_t dev)
{
- struct stge_product *sp;
+ const struct stge_product *sp;
int i;
uint16_t vendor, devid;
diff --git a/sys/dev/stge/if_stgereg.h b/sys/dev/stge/if_stgereg.h
index 6ecbdf9..f14142a 100644
--- a/sys/dev/stge/if_stgereg.h
+++ b/sys/dev/stge/if_stgereg.h
@@ -99,6 +99,9 @@
#define CSR_READ_1(_sc, reg) \
bus_read_1((_sc)->sc_res[0], (reg))
+#define CSR_BARRIER(_sc, reg, length, flags) \
+ bus_barrier((_sc)->sc_res[0], reg, length, flags)
+
/*
* TC9021 buffer fragment descriptor.
*/
@@ -677,23 +680,6 @@ do { \
#define STGE_TIMEOUT 1000
-struct stge_mii_frame {
- uint8_t mii_stdelim;
- uint8_t mii_opcode;
- uint8_t mii_phyaddr;
- uint8_t mii_regaddr;
- uint8_t mii_turnaround;
- uint16_t mii_data;
-};
-
-/*
- * MII constants
- */
-#define STGE_MII_STARTDELIM 0x01
-#define STGE_MII_READOP 0x02
-#define STGE_MII_WRITEOP 0x01
-#define STGE_MII_TURNAROUND 0x02
-
#define STGE_RESET_NONE 0x00
#define STGE_RESET_TX 0x01
#define STGE_RESET_RX 0x02
OpenPOWER on IntegriCloud