Date: Mon, 30 Aug 2010 22:17:06 +0000 (UTC) From: Pyun YongHyeon <yongari@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-7@freebsd.org Subject: svn commit: r212030 - stable/7/sys/pci Message-ID: <201008302217.o7UMH6ci009336@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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@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;
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201008302217.o7UMH6ci009336>