From owner-svn-src-head@FreeBSD.ORG Fri Oct 31 23:24:14 2008 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 88E011065670; Fri, 31 Oct 2008 23:24:14 +0000 (UTC) (envelope-from imp@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 77DBD8FC13; Fri, 31 Oct 2008 23:24:14 +0000 (UTC) (envelope-from imp@FreeBSD.org) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id m9VNOE4u093400; Fri, 31 Oct 2008 23:24:14 GMT (envelope-from imp@svn.freebsd.org) Received: (from imp@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id m9VNOE88093395; Fri, 31 Oct 2008 23:24:14 GMT (envelope-from imp@svn.freebsd.org) Message-Id: <200810312324.m9VNOE88093395@svn.freebsd.org> From: Warner Losh Date: Fri, 31 Oct 2008 23:24:14 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r184515 - in head/sys: conf modules/rl pci X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 31 Oct 2008 23:24:14 -0000 Author: imp Date: Fri Oct 31 23:24:13 2008 New Revision: 184515 URL: http://svn.freebsd.org/changeset/base/184515 Log: 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. Reviewed by: attilio@, jhb@, trhodes@ (all an older version of the patch) Modified: head/sys/conf/options head/sys/modules/rl/Makefile head/sys/pci/if_rl.c head/sys/pci/if_rlreg.h Modified: head/sys/conf/options ============================================================================== --- head/sys/conf/options Fri Oct 31 18:40:35 2008 (r184514) +++ head/sys/conf/options Fri Oct 31 23:24:13 2008 (r184515) @@ -672,6 +672,9 @@ ED_SIC opt_ed.h # bce driver BCE_DEBUG opt_bce.h +# rl driver +RL_TWISTER_ENABLE opt_rl.h + SOCKBUF_DEBUG opt_global.h # options for ubsec driver Modified: head/sys/modules/rl/Makefile ============================================================================== --- head/sys/modules/rl/Makefile Fri Oct 31 18:40:35 2008 (r184514) +++ head/sys/modules/rl/Makefile Fri Oct 31 23:24:13 2008 (r184515) @@ -3,7 +3,7 @@ .PATH: ${.CURDIR}/../../pci KMOD= if_rl -SRCS= if_rl.c device_if.h bus_if.h pci_if.h +SRCS= if_rl.c device_if.h bus_if.h pci_if.h opt_rl.h SRCS+= miibus_if.h .include Modified: head/sys/pci/if_rl.c ============================================================================== --- head/sys/pci/if_rl.c Fri Oct 31 18:40:35 2008 (r184514) +++ head/sys/pci/if_rl.c Fri Oct 31 23:24:13 2008 (r184515) @@ -85,6 +85,7 @@ __FBSDID("$FreeBSD$"); #ifdef HAVE_KERNEL_OPTION_HEADERS #include "opt_device_polling.h" +#include "opt_rl.h" #endif #include @@ -1383,19 +1384,143 @@ rl_txeof(struct rl_softc *sc) sc->rl_watchdog_timer = 0; } +#ifdef RL_TWISTER_ENABLE +static void +rl_twister_update(struct rl_softc *sc) +{ + uint16_t linktest; + /* + * Table provided by RealTek (Kinston ) 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 impendence mismatches. The + * method for tuning these registes is undocumented and the + * following proceedure is collected from public sources. + */ + switch (sc->rl_twister) + { + case CHK_LINK: + /* + * If we have a sufficent 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; + } + +} +#endif + 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); - +#ifdef 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; +#endif - callout_reset(&sc->rl_stat_callout, hz, rl_tick, sc); + callout_reset(&sc->rl_stat_callout, ticks, rl_tick, sc); } #ifdef DEVICE_POLLING @@ -1643,6 +1768,14 @@ rl_init_locked(struct rl_softc *sc) rl_stop(sc); rl_reset(sc); +#ifdef 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; +#endif /* * Init our MAC address. Even though the chipset Modified: head/sys/pci/if_rlreg.h ============================================================================== --- head/sys/pci/if_rlreg.h Fri Oct 31 18:40:35 2008 (r184514) +++ head/sys/pci/if_rlreg.h Fri Oct 31 23:24:13 2008 (r184515) @@ -309,6 +309,27 @@ #define RL_CMD_RESET 0x0010 /* + * 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 */ @@ -809,6 +830,10 @@ struct rl_list_data { bus_addr_t rl_tx_list_addr; }; +#ifdef RL_TWISTER_ENABLE +enum rl_twist { DONE, CHK_LINK, FIND_ROW, SET_PARAM, RECHK_LONG, RETUNE }; +#endif + struct rl_softc { struct ifnet *rl_ifp; /* interface info */ bus_space_handle_t rl_bhandle; /* bus space handle */ @@ -837,6 +862,11 @@ struct rl_softc { uint32_t rl_rxlenmask; int rl_testmode; int rl_if_flags; +#ifdef RL_TWISTER_ENABLE + enum rl_twist rl_twister; + int rl_twist_row; + int rl_twist_col; +#endif int suspended; /* 0 = normal 1 = suspended */ #ifdef DEVICE_POLLING int rxcycles;