Date: Mon, 25 Aug 2008 00:23:16 -0600 (MDT) From: "M. Warner Losh" <imp@bsdimp.com> To: net@freebsd.org, arch@freebsd.org Subject: Code review Message-ID: <20080825.002316.-1548243307.imp@bsdimp.com>
next in thread | raw e-mail | index | archive | help
----Next_Part(Mon_Aug_25_00_23_16_2008_044)-- Content-Type: Text/Plain; charset=us-ascii Content-Transfer-Encoding: 7bit I did this a few years ago when trying to track down a problem with some realtek network chips that I was having problems with at Timing Solutions. I'd like to get this into the tree, since it was helpful then. Comments? Warner ----Next_Part(Mon_Aug_25_00_23_16_2008_044)-- Content-Type: Text/Plain; charset=us-ascii Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="rl.diff" diff -ur src/sys/pci/if_rl.c newcard/src/sys/pci/if_rl.c --- src/sys/pci/if_rl.c 2008-08-23 22:21:15.000000000 -0600 +++ newcard/src/sys/pci/if_rl.c 2008-08-23 22:26:09.000000000 -0600 @@ -1253,18 +1253,120 @@ } static void +rl_twister_update(struct rl_softc *sc) +{ + uint16_t linktest; + 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; + } + +} + +static void rl_tick(void *xsc) { struct rl_softc *sc = xsc; struct mii_data *mii; + int ticks; RL_LOCK_ASSERT(sc); mii = device_get_softc(sc->rl_miibus); mii_tick(mii); + if (sc->rl_twister != DONE) + rl_twister_update(sc); + if (sc->rl_twister != DONE) + ticks = hz / 10; + else + 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 @@ -1490,6 +1592,13 @@ rl_stop(sc); /* + * 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 * documentation doesn't mention it, we need to enter "Config * register write enable" mode to modify the ID registers. diff -ur src/sys/pci/if_rlreg.h newcard/src/sys/pci/if_rlreg.h --- src/sys/pci/if_rlreg.h 2008-08-23 22:21:15.000000000 -0600 +++ newcard/src/sys/pci/if_rlreg.h 2008-08-23 22:26:09.000000000 -0600 @@ -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 */ @@ -801,6 +822,8 @@ 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 */ @@ -830,6 +853,9 @@ uint32_t rl_rxlenmask; int rl_testmode; int rl_if_flags; + enum rl_twist rl_twister; + int rl_twist_row; + int rl_twist_col; int suspended; /* 0 = normal 1 = suspended */ #ifdef DEVICE_POLLING int rxcycles; @@ -850,6 +876,8 @@ #define RL_FLAG_LINK 0x8000 }; + + #define RL_LOCK(_sc) mtx_lock(&(_sc)->rl_mtx) #define RL_UNLOCK(_sc) mtx_unlock(&(_sc)->rl_mtx) #define RL_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->rl_mtx, MA_OWNED) ----Next_Part(Mon_Aug_25_00_23_16_2008_044)----
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20080825.002316.-1548243307.imp>