summaryrefslogtreecommitdiffstats
path: root/sys/dev/nge
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/nge
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/nge')
-rw-r--r--sys/dev/nge/if_nge.c230
-rw-r--r--sys/dev/nge/if_ngereg.h24
2 files changed, 51 insertions, 203 deletions
diff --git a/sys/dev/nge/if_nge.c b/sys/dev/nge/if_nge.c
index db20ad2..3d7ad63 100644
--- a/sys/dev/nge/if_nge.c
+++ b/sys/dev/nge/if_nge.c
@@ -117,6 +117,7 @@ __FBSDID("$FreeBSD$");
#include <net/if_vlan_var.h>
#include <dev/mii/mii.h>
+#include <dev/mii/mii_bitbang.h>
#include <dev/mii/miivar.h>
#include <dev/pci/pcireg.h>
@@ -138,7 +139,7 @@ MODULE_DEPEND(nge, miibus, 1, 1, 1);
/*
* Various supported device vendors/types and their names.
*/
-static struct nge_type nge_devs[] = {
+static const struct nge_type const nge_devs[] = {
{ NGE_VENDORID, NGE_DEVICEID,
"National Semiconductor Gigabit Ethernet" },
{ 0, 0, NULL }
@@ -180,11 +181,6 @@ static void nge_eeprom_putbyte(struct nge_softc *, int);
static void nge_eeprom_getword(struct nge_softc *, int, uint16_t *);
static void nge_read_eeprom(struct nge_softc *, caddr_t, int, int);
-static void nge_mii_sync(struct nge_softc *);
-static void nge_mii_send(struct nge_softc *, uint32_t, int);
-static int nge_mii_readreg(struct nge_softc *, struct nge_mii_frame *);
-static int nge_mii_writereg(struct nge_softc *, struct nge_mii_frame *);
-
static int nge_miibus_readreg(device_t, int, int);
static int nge_miibus_writereg(device_t, int, int, int);
static void nge_miibus_statchg(device_t);
@@ -200,6 +196,24 @@ static void nge_sysctl_node(struct nge_softc *);
static int sysctl_int_range(SYSCTL_HANDLER_ARGS, int, int);
static int sysctl_hw_nge_int_holdoff(SYSCTL_HANDLER_ARGS);
+/*
+ * MII bit-bang glue
+ */
+static uint32_t nge_mii_bitbang_read(device_t);
+static void nge_mii_bitbang_write(device_t, uint32_t);
+
+static const struct mii_bitbang_ops nge_mii_bitbang_ops = {
+ nge_mii_bitbang_read,
+ nge_mii_bitbang_write,
+ {
+ NGE_MEAR_MII_DATA, /* MII_BIT_MDO */
+ NGE_MEAR_MII_DATA, /* MII_BIT_MDI */
+ NGE_MEAR_MII_CLK, /* MII_BIT_MDC */
+ NGE_MEAR_MII_DIR, /* MII_BIT_DIR_HOST_PHY */
+ 0, /* MII_BIT_DIR_PHY_HOST */
+ }
+};
+
static device_method_t nge_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, nge_probe),
@@ -366,180 +380,42 @@ nge_read_eeprom(struct nge_softc *sc, caddr_t dest, int off, int cnt)
}
/*
- * Sync the PHYs by setting data bit and strobing the clock 32 times.
- */
-static void
-nge_mii_sync(struct nge_softc *sc)
-{
- int i;
-
- SIO_SET(NGE_MEAR_MII_DIR|NGE_MEAR_MII_DATA);
-
- for (i = 0; i < 32; i++) {
- SIO_SET(NGE_MEAR_MII_CLK);
- DELAY(1);
- SIO_CLR(NGE_MEAR_MII_CLK);
- DELAY(1);
- }
-}
-
-/*
- * Clock a series of bits through the MII.
- */
-static void
-nge_mii_send(struct nge_softc *sc, uint32_t bits, int cnt)
-{
- int i;
-
- SIO_CLR(NGE_MEAR_MII_CLK);
-
- for (i = (0x1 << (cnt - 1)); i; i >>= 1) {
- if (bits & i) {
- SIO_SET(NGE_MEAR_MII_DATA);
- } else {
- SIO_CLR(NGE_MEAR_MII_DATA);
- }
- DELAY(1);
- SIO_CLR(NGE_MEAR_MII_CLK);
- DELAY(1);
- SIO_SET(NGE_MEAR_MII_CLK);
- }
-}
-
-/*
- * Read an PHY register through the MII.
+ * Read the MII serial port for the MII bit-bang module.
*/
-static int
-nge_mii_readreg(struct nge_softc *sc, struct nge_mii_frame *frame)
+static uint32_t
+nge_mii_bitbang_read(device_t dev)
{
- int i, ack;
-
- /*
- * Set up frame for RX.
- */
- frame->mii_stdelim = NGE_MII_STARTDELIM;
- frame->mii_opcode = NGE_MII_READOP;
- frame->mii_turnaround = 0;
- frame->mii_data = 0;
-
- CSR_WRITE_4(sc, NGE_MEAR, 0);
-
- /*
- * Turn on data xmit.
- */
- SIO_SET(NGE_MEAR_MII_DIR);
-
- nge_mii_sync(sc);
-
- /*
- * Send command/address info.
- */
- nge_mii_send(sc, frame->mii_stdelim, 2);
- nge_mii_send(sc, frame->mii_opcode, 2);
- nge_mii_send(sc, frame->mii_phyaddr, 5);
- nge_mii_send(sc, frame->mii_regaddr, 5);
-
- /* Idle bit */
- SIO_CLR((NGE_MEAR_MII_CLK|NGE_MEAR_MII_DATA));
- DELAY(1);
- SIO_SET(NGE_MEAR_MII_CLK);
- DELAY(1);
-
- /* Turn off xmit. */
- SIO_CLR(NGE_MEAR_MII_DIR);
- /* Check for ack */
- SIO_CLR(NGE_MEAR_MII_CLK);
- DELAY(1);
- ack = CSR_READ_4(sc, NGE_MEAR) & NGE_MEAR_MII_DATA;
- SIO_SET(NGE_MEAR_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++) {
- SIO_CLR(NGE_MEAR_MII_CLK);
- DELAY(1);
- SIO_SET(NGE_MEAR_MII_CLK);
- DELAY(1);
- }
- goto fail;
- }
-
- for (i = 0x8000; i; i >>= 1) {
- SIO_CLR(NGE_MEAR_MII_CLK);
- DELAY(1);
- if (!ack) {
- if (CSR_READ_4(sc, NGE_MEAR) & NGE_MEAR_MII_DATA)
- frame->mii_data |= i;
- DELAY(1);
- }
- SIO_SET(NGE_MEAR_MII_CLK);
- DELAY(1);
- }
+ struct nge_softc *sc;
+ uint32_t val;
-fail:
+ sc = device_get_softc(dev);
- SIO_CLR(NGE_MEAR_MII_CLK);
- DELAY(1);
- SIO_SET(NGE_MEAR_MII_CLK);
- DELAY(1);
+ val = CSR_READ_4(sc, NGE_MEAR);
+ CSR_BARRIER_4(sc, NGE_MEAR,
+ BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
- if (ack)
- return (1);
- return (0);
+ return (val);
}
/*
- * Write to a PHY register through the MII.
+ * Write the MII serial port for the MII bit-bang module.
*/
-static int
-nge_mii_writereg(struct nge_softc *sc, struct nge_mii_frame *frame)
+static void
+nge_mii_bitbang_write(device_t dev, uint32_t val)
{
+ struct nge_softc *sc;
- /*
- * Set up frame for TX.
- */
-
- frame->mii_stdelim = NGE_MII_STARTDELIM;
- frame->mii_opcode = NGE_MII_WRITEOP;
- frame->mii_turnaround = NGE_MII_TURNAROUND;
-
- /*
- * Turn on data output.
- */
- SIO_SET(NGE_MEAR_MII_DIR);
-
- nge_mii_sync(sc);
-
- nge_mii_send(sc, frame->mii_stdelim, 2);
- nge_mii_send(sc, frame->mii_opcode, 2);
- nge_mii_send(sc, frame->mii_phyaddr, 5);
- nge_mii_send(sc, frame->mii_regaddr, 5);
- nge_mii_send(sc, frame->mii_turnaround, 2);
- nge_mii_send(sc, frame->mii_data, 16);
-
- /* Idle bit. */
- SIO_SET(NGE_MEAR_MII_CLK);
- DELAY(1);
- SIO_CLR(NGE_MEAR_MII_CLK);
- DELAY(1);
-
- /*
- * Turn off xmit.
- */
- SIO_CLR(NGE_MEAR_MII_DIR);
+ sc = device_get_softc(dev);
- return (0);
+ CSR_WRITE_4(sc, NGE_MEAR, val);
+ CSR_BARRIER_4(sc, NGE_MEAR,
+ BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
}
static int
nge_miibus_readreg(device_t dev, int phy, int reg)
{
struct nge_softc *sc;
- struct nge_mii_frame frame;
int rv;
sc = device_get_softc(dev);
@@ -583,20 +459,13 @@ nge_miibus_readreg(device_t dev, int phy, int reg)
return (CSR_READ_4(sc, reg));
}
- bzero((char *)&frame, sizeof(frame));
-
- frame.mii_phyaddr = phy;
- frame.mii_regaddr = reg;
- nge_mii_readreg(sc, &frame);
-
- return (frame.mii_data);
+ return (mii_bitbang_readreg(dev, &nge_mii_bitbang_ops, phy, reg));
}
static int
nge_miibus_writereg(device_t dev, int phy, int reg, int data)
{
struct nge_softc *sc;
- struct nge_mii_frame frame;
sc = device_get_softc(dev);
if ((sc->nge_flags & NGE_FLAG_TBI) != 0) {
@@ -633,12 +502,7 @@ nge_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;
- nge_mii_writereg(sc, &frame);
+ mii_bitbang_writereg(dev, &nge_mii_bitbang_ops, phy, reg, data);
return (0);
}
@@ -813,7 +677,7 @@ nge_rxfilter(struct nge_softc *sc)
rxfilt = CSR_READ_4(sc, NGE_RXFILT_CTL);
rxfilt &= ~NGE_RXFILTCTL_ENABLE;
CSR_WRITE_4(sc, NGE_RXFILT_CTL, rxfilt);
- CSR_BARRIER_WRITE_4(sc, NGE_RXFILT_CTL);
+ CSR_BARRIER_4(sc, NGE_RXFILT_CTL, BUS_SPACE_BARRIER_WRITE);
rxfilt &= ~(NGE_RXFILTCTL_ALLMULTI | NGE_RXFILTCTL_ALLPHYS);
rxfilt &= ~NGE_RXFILTCTL_BROAD;
@@ -882,7 +746,7 @@ done:
/* Turn the receive filter on. */
rxfilt |= NGE_RXFILTCTL_ENABLE;
CSR_WRITE_4(sc, NGE_RXFILT_CTL, rxfilt);
- CSR_BARRIER_WRITE_4(sc, NGE_RXFILT_CTL);
+ CSR_BARRIER_4(sc, NGE_RXFILT_CTL, BUS_SPACE_BARRIER_WRITE);
}
static void
@@ -932,7 +796,7 @@ nge_reset(struct nge_softc *sc)
static int
nge_probe(device_t dev)
{
- struct nge_type *t;
+ const struct nge_type *t;
t = nge_devs;
@@ -2216,7 +2080,7 @@ nge_init_locked(struct nge_softc *sc)
/* Disable Rx filter prior to programming Rx filter. */
CSR_WRITE_4(sc, NGE_RXFILT_CTL, 0);
- CSR_BARRIER_WRITE_4(sc, NGE_RXFILT_CTL);
+ CSR_BARRIER_4(sc, NGE_RXFILT_CTL, BUS_SPACE_BARRIER_WRITE);
mii = device_get_softc(sc->nge_miibus);
@@ -2704,12 +2568,12 @@ nge_wol(struct nge_softc *sc)
* (i.e. Silent Rx mode.)
*/
CSR_WRITE_4(sc, NGE_RX_LISTPTR_HI, 0);
- CSR_BARRIER_WRITE_4(sc, NGE_RX_LISTPTR_HI);
+ CSR_BARRIER_4(sc, NGE_RX_LISTPTR_HI, BUS_SPACE_BARRIER_WRITE);
CSR_WRITE_4(sc, NGE_RX_LISTPTR_LO, 0);
- CSR_BARRIER_WRITE_4(sc, NGE_RX_LISTPTR_LO);
+ CSR_BARRIER_4(sc, NGE_RX_LISTPTR_LO, BUS_SPACE_BARRIER_WRITE);
/* Enable Rx again. */
NGE_SETBIT(sc, NGE_CSR, NGE_CSR_RX_ENABLE);
- CSR_BARRIER_WRITE_4(sc, NGE_CSR);
+ CSR_BARRIER_4(sc, NGE_CSR, BUS_SPACE_BARRIER_WRITE);
/* Configure WOL events. */
reg = 0;
diff --git a/sys/dev/nge/if_ngereg.h b/sys/dev/nge/if_ngereg.h
index 4ad1bf9..9df0d92 100644
--- a/sys/dev/nge/if_ngereg.h
+++ b/sys/dev/nge/if_ngereg.h
@@ -611,26 +611,9 @@ struct nge_ring_data {
struct nge_type {
uint16_t nge_vid;
uint16_t nge_did;
- char *nge_name;
+ const char *nge_name;
};
-struct nge_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 NGE_MII_STARTDELIM 0x01
-#define NGE_MII_READOP 0x02
-#define NGE_MII_WRITEOP 0x01
-#define NGE_MII_TURNAROUND 0x02
-
#define NGE_JUMBO_FRAMELEN 9022
#define NGE_JUMBO_MTU \
(NGE_JUMBO_FRAMELEN - sizeof(struct ether_vlan_header) - ETHER_CRC_LEN)
@@ -691,8 +674,9 @@ struct nge_softc {
*/
#define CSR_WRITE_4(sc, reg, val) \
bus_write_4((sc)->nge_res, reg, val)
-#define CSR_BARRIER_WRITE_4(sc, reg) \
- bus_barrier((sc)->nge_res, reg, 4, BUS_SPACE_BARRIER_WRITE)
+
+#define CSR_BARRIER_4(sc, reg, flags) \
+ bus_barrier((sc)->nge_res, reg, 4, flags)
#define CSR_READ_4(sc, reg) \
bus_read_4((sc)->nge_res, reg)
OpenPOWER on IntegriCloud