svn commit: r212030 - stable/7/sys/pci
Pyun YongHyeon
yongari at FreeBSD.org
Mon Aug 30 22:17:06 UTC 2010
Author: yongari
Date: Mon Aug 30 22:17:06 2010
New Revision: 212030
URL: http://svn.freebsd.org/changeset/base/212030
Log:
MFC r184515,184524,184559:
r184515:
Add RL_TWISTER_ENABLE option. This enables the magic bits to do long
cable tuning. This has helped in some installations for hardware
deployed by a former employer. Made optional because the lists aren't
full of complaints about these cards... even when they were wildly
popular.
r184524:
Fix a few typos/spelling errors in my comments from the last commit,
plus a few others that had lingered in this driver...
Submitted by: "b." bf2006a att yahoo KIBO com
r184559:
Make RL_TWISTER_ENABLE a tunable/sysctl. Eliminate it as an option.
Fix module build.
Modified:
stable/7/sys/pci/if_rl.c
stable/7/sys/pci/if_rlreg.h
Directory Properties:
stable/7/sys/ (props changed)
stable/7/sys/cddl/contrib/opensolaris/ (props changed)
stable/7/sys/contrib/dev/acpica/ (props changed)
stable/7/sys/contrib/pf/ (props changed)
Modified: stable/7/sys/pci/if_rl.c
==============================================================================
--- stable/7/sys/pci/if_rl.c Mon Aug 30 21:58:52 2010 (r212029)
+++ stable/7/sys/pci/if_rl.c Mon Aug 30 22:17:06 2010 (r212030)
@@ -96,6 +96,7 @@ __FBSDID("$FreeBSD$");
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/socket.h>
+#include <sys/sysctl.h>
#include <net/if.h>
#include <net/if_arp.h>
@@ -155,7 +156,7 @@ static struct rl_type rl_devs[] = {
{ DELTA_VENDORID, DELTA_DEVICEID_8139, RL_8139,
"Delta Electronics 8139 10/100BaseTX" },
{ ADDTRON_VENDORID, ADDTRON_DEVICEID_8139, RL_8139,
- "Addtron Technolgy 8139 10/100BaseTX" },
+ "Addtron Technology 8139 10/100BaseTX" },
{ DLINK_VENDORID, DLINK_DEVICEID_530TXPLUS, RL_8139,
"D-Link DFE-530TX+ 10/100BaseTX" },
{ DLINK_VENDORID, DLINK_DEVICEID_690TXD, RL_8139,
@@ -802,14 +803,25 @@ rl_attach(device_t dev)
struct ifnet *ifp;
struct rl_softc *sc;
struct rl_type *t;
+ struct sysctl_ctx_list *ctx;
+ struct sysctl_oid_list *children;
int error = 0, hwrev, i, pmc, rid;
int unit;
uint16_t rl_did = 0;
+ char tn[32];
sc = device_get_softc(dev);
unit = device_get_unit(dev);
sc->rl_dev = dev;
+ sc->rl_twister_enable = 0;
+ snprintf(tn, sizeof(tn), "dev.rl.%d.twister_enable", unit);
+ TUNABLE_INT_FETCH(tn, &sc->rl_twister_enable);
+ ctx = device_get_sysctl_ctx(sc->rl_dev);
+ children = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->rl_dev));
+ SYSCTL_ADD_INT(ctx, children, OID_AUTO, "twister_enable", CTLFLAG_RD,
+ &sc->rl_twister_enable, 0, "");
+
mtx_init(&sc->rl_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
MTX_DEF);
callout_init_mtx(&sc->rl_stat_callout, &sc->rl_mtx, 0);
@@ -1342,7 +1354,7 @@ rl_rxeof(struct rl_softc *sc)
RL_LOCK(sc);
}
- /* No need to sync Rx memory block as we didn't mofify it. */
+ /* No need to sync Rx memory block as we didn't modify it. */
}
/*
@@ -1408,20 +1420,142 @@ rl_txeof(struct rl_softc *sc)
}
static void
+rl_twister_update(struct rl_softc *sc)
+{
+ uint16_t linktest;
+ /*
+ * Table provided by RealTek (Kinston <shangh at realtek.com.tw>) for
+ * Linux driver. Values undocumented otherwise.
+ */
+ static const uint32_t param[4][4] = {
+ {0xcb39de43, 0xcb39ce43, 0xfb38de03, 0xcb38de43},
+ {0xcb39de43, 0xcb39ce43, 0xcb39ce83, 0xcb39ce83},
+ {0xcb39de43, 0xcb39ce43, 0xcb39ce83, 0xcb39ce83},
+ {0xbb39de43, 0xbb39ce43, 0xbb39ce83, 0xbb39ce83}
+ };
+
+ /*
+ * Tune the so-called twister registers of the RTL8139. These
+ * are used to compensate for impedance mismatches. The
+ * method for tuning these registers is undocumented and the
+ * following procedure is collected from public sources.
+ */
+ switch (sc->rl_twister)
+ {
+ case CHK_LINK:
+ /*
+ * If we have a sufficient link, then we can proceed in
+ * the state machine to the next stage. If not, then
+ * disable further tuning after writing sane defaults.
+ */
+ if (CSR_READ_2(sc, RL_CSCFG) & RL_CSCFG_LINK_OK) {
+ CSR_WRITE_2(sc, RL_CSCFG, RL_CSCFG_LINK_DOWN_OFF_CMD);
+ sc->rl_twister = FIND_ROW;
+ } else {
+ CSR_WRITE_2(sc, RL_CSCFG, RL_CSCFG_LINK_DOWN_CMD);
+ CSR_WRITE_4(sc, RL_NWAYTST, RL_NWAYTST_CBL_TEST);
+ CSR_WRITE_4(sc, RL_PARA78, RL_PARA78_DEF);
+ CSR_WRITE_4(sc, RL_PARA7C, RL_PARA7C_DEF);
+ sc->rl_twister = DONE;
+ }
+ break;
+ case FIND_ROW:
+ /*
+ * Read how long it took to see the echo to find the tuning
+ * row to use.
+ */
+ linktest = CSR_READ_2(sc, RL_CSCFG) & RL_CSCFG_STATUS;
+ if (linktest == RL_CSCFG_ROW3)
+ sc->rl_twist_row = 3;
+ else if (linktest == RL_CSCFG_ROW2)
+ sc->rl_twist_row = 2;
+ else if (linktest == RL_CSCFG_ROW1)
+ sc->rl_twist_row = 1;
+ else
+ sc->rl_twist_row = 0;
+ sc->rl_twist_col = 0;
+ sc->rl_twister = SET_PARAM;
+ break;
+ case SET_PARAM:
+ if (sc->rl_twist_col == 0)
+ CSR_WRITE_4(sc, RL_NWAYTST, RL_NWAYTST_RESET);
+ CSR_WRITE_4(sc, RL_PARA7C,
+ param[sc->rl_twist_row][sc->rl_twist_col]);
+ if (++sc->rl_twist_col == 4) {
+ if (sc->rl_twist_row == 3)
+ sc->rl_twister = RECHK_LONG;
+ else
+ sc->rl_twister = DONE;
+ }
+ break;
+ case RECHK_LONG:
+ /*
+ * For long cables, we have to double check to make sure we
+ * don't mistune.
+ */
+ linktest = CSR_READ_2(sc, RL_CSCFG) & RL_CSCFG_STATUS;
+ if (linktest == RL_CSCFG_ROW3)
+ sc->rl_twister = DONE;
+ else {
+ CSR_WRITE_4(sc, RL_PARA7C, RL_PARA7C_RETUNE);
+ sc->rl_twister = RETUNE;
+ }
+ break;
+ case RETUNE:
+ /* Retune for a shorter cable (try column 2) */
+ CSR_WRITE_4(sc, RL_NWAYTST, RL_NWAYTST_CBL_TEST);
+ CSR_WRITE_4(sc, RL_PARA78, RL_PARA78_DEF);
+ CSR_WRITE_4(sc, RL_PARA7C, RL_PARA7C_DEF);
+ CSR_WRITE_4(sc, RL_NWAYTST, RL_NWAYTST_RESET);
+ sc->rl_twist_row--;
+ sc->rl_twist_col = 0;
+ sc->rl_twister = SET_PARAM;
+ break;
+
+ case DONE:
+ break;
+ }
+
+}
+
+static void
rl_tick(void *xsc)
{
struct rl_softc *sc = xsc;
struct mii_data *mii;
+ int ticks;
RL_LOCK_ASSERT(sc);
+ /*
+ * If we're doing the twister cable calibration, then we need to defer
+ * watchdog timeouts. This is a no-op in normal operations, but
+ * can falsely trigger when the cable calibration takes a while and
+ * there was traffic ready to go when rl was started.
+ *
+ * We don't defer mii_tick since that updates the mii status, which
+ * helps the twister process, at least according to similar patches
+ * for the Linux driver I found online while doing the fixes. Worst
+ * case is a few extra mii reads during calibration.
+ */
mii = device_get_softc(sc->rl_miibus);
mii_tick(mii);
if ((sc->rl_flags & RL_FLAG_LINK) == 0)
rl_miibus_statchg(sc->rl_dev);
+ if (sc->rl_twister_enable) {
+ if (sc->rl_twister == DONE)
+ rl_watchdog(sc);
+ else
+ rl_twister_update(sc);
+ if (sc->rl_twister == DONE)
+ ticks = hz;
+ else
+ ticks = hz / 10;
+ } else {
+ rl_watchdog(sc);
+ ticks = hz;
+ }
- rl_watchdog(sc);
-
- callout_reset(&sc->rl_stat_callout, hz, rl_tick, sc);
+ callout_reset(&sc->rl_stat_callout, ticks, rl_tick, sc);
}
#ifdef DEVICE_POLLING
@@ -1550,7 +1684,7 @@ rl_encap(struct rl_softc *sc, struct mbu
if (padlen > 0) {
/*
- * Make security concious people happy: zero out the
+ * Make security-conscious people happy: zero out the
* bytes in the pad area, since we don't know what
* this mbuf cluster buffer's previous user might
* have left in it.
@@ -1669,6 +1803,15 @@ rl_init_locked(struct rl_softc *sc)
rl_stop(sc);
rl_reset(sc);
+ if (sc->rl_twister_enable) {
+ /*
+ * Reset twister register tuning state. The twister
+ * registers and their tuning are undocumented, but
+ * are necessary to cope with bad links. rl_twister =
+ * DONE here will disable this entirely.
+ */
+ sc->rl_twister = CHK_LINK;
+ }
/*
* Init our MAC address. Even though the chipset
Modified: stable/7/sys/pci/if_rlreg.h
==============================================================================
--- stable/7/sys/pci/if_rlreg.h Mon Aug 30 21:58:52 2010 (r212029)
+++ stable/7/sys/pci/if_rlreg.h Mon Aug 30 22:17:06 2010 (r212030)
@@ -319,6 +319,27 @@
#define RL_CMD_STOPREQ 0x0080
/*
+ * Twister register values. These are completely undocumented and derived
+ * from public sources.
+ */
+#define RL_CSCFG_LINK_OK 0x0400
+#define RL_CSCFG_CHANGE 0x0800
+#define RL_CSCFG_STATUS 0xf000
+#define RL_CSCFG_ROW3 0x7000
+#define RL_CSCFG_ROW2 0x3000
+#define RL_CSCFG_ROW1 0x1000
+#define RL_CSCFG_LINK_DOWN_OFF_CMD 0x03c0
+#define RL_CSCFG_LINK_DOWN_CMD 0xf3c0
+
+#define RL_NWAYTST_RESET 0
+#define RL_NWAYTST_CBL_TEST 0x20
+
+#define RL_PARA78 0x78
+#define RL_PARA78_DEF 0x78fa8388
+#define RL_PARA7C 0x7C
+#define RL_PARA7C_DEF 0xcb38de43
+#define RL_PARA7C_RETUNE 0xfb38de03
+/*
* EEPROM control register
*/
#define RL_EE_DATAOUT 0x01 /* Data out */
@@ -819,6 +840,8 @@ struct rl_list_data {
bus_addr_t rl_tx_list_addr;
};
+enum rl_twist { DONE, CHK_LINK, FIND_ROW, SET_PARAM, RECHK_LONG, RETUNE };
+
struct rl_softc {
struct ifnet *rl_ifp; /* interface info */
bus_space_handle_t rl_bhandle; /* bus space handle */
@@ -847,6 +870,10 @@ struct rl_softc {
uint32_t rl_rxlenmask;
int rl_testmode;
int rl_if_flags;
+ int rl_twister_enable;
+ enum rl_twist rl_twister;
+ int rl_twist_row;
+ int rl_twist_col;
int suspended; /* 0 = normal 1 = suspended */
#ifdef DEVICE_POLLING
int rxcycles;
More information about the svn-src-stable-7
mailing list