1331722Seadler 2170654Skmacy/************************************************************************** 3170654Skmacy 4170654SkmacyCopyright (c) 2007, Chelsio Inc. 5170654SkmacyAll rights reserved. 6170654Skmacy 7170654SkmacyRedistribution and use in source and binary forms, with or without 8170654Skmacymodification, are permitted provided that the following conditions are met: 9170654Skmacy 10170654Skmacy 1. Redistributions of source code must retain the above copyright notice, 11170654Skmacy this list of conditions and the following disclaimer. 12170654Skmacy 13170654Skmacy 2. Neither the name of the Chelsio Corporation nor the names of its 14170654Skmacy contributors may be used to endorse or promote products derived from 15170654Skmacy this software without specific prior written permission. 16170654Skmacy 17170654SkmacyTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18170654SkmacyAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19170654SkmacyIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20170654SkmacyARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 21170654SkmacyLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22170654SkmacyCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23170654SkmacySUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24170654SkmacyINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25170654SkmacyCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26170654SkmacyARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27170654SkmacyPOSSIBILITY OF SUCH DAMAGE. 28170654Skmacy 29170654Skmacy***************************************************************************/ 30170654Skmacy 31170654Skmacy#include <sys/cdefs.h> 32170654Skmacy__FBSDID("$FreeBSD$"); 33170654Skmacy 34170654Skmacy#include <common/cxgb_common.h> 35170654Skmacy 36170654Skmacyenum { 37170654Skmacy ELMR_ADDR = 0, 38170654Skmacy ELMR_STAT = 1, 39170654Skmacy ELMR_DATA_LO = 2, 40170654Skmacy ELMR_DATA_HI = 3, 41170654Skmacy 42172096Skmacy ELMR_THRES0 = 0xe000, 43172096Skmacy ELMR_BW = 0xe00c, 44172096Skmacy ELMR_FIFO_SZ = 0xe00d, 45172096Skmacy ELMR_STATS = 0xf000, 46172096Skmacy 47170654Skmacy ELMR_MDIO_ADDR = 10 48170654Skmacy}; 49170654Skmacy 50170654Skmacy#define VSC_REG(block, subblock, reg) \ 51170654Skmacy ((reg) | ((subblock) << 8) | ((block) << 12)) 52170654Skmacy 53170654Skmacyint t3_elmr_blk_write(adapter_t *adap, int start, const u32 *vals, int n) 54170654Skmacy{ 55170654Skmacy int ret; 56170654Skmacy const struct mdio_ops *mo = adapter_info(adap)->mdio_ops; 57170654Skmacy 58170654Skmacy ELMR_LOCK(adap); 59170654Skmacy ret = mo->write(adap, ELMR_MDIO_ADDR, 0, ELMR_ADDR, start); 60170654Skmacy for ( ; !ret && n; n--, vals++) { 61170654Skmacy ret = mo->write(adap, ELMR_MDIO_ADDR, 0, ELMR_DATA_LO, 62170654Skmacy *vals & 0xffff); 63170654Skmacy if (!ret) 64170654Skmacy ret = mo->write(adap, ELMR_MDIO_ADDR, 0, ELMR_DATA_HI, 65170654Skmacy *vals >> 16); 66170654Skmacy } 67170654Skmacy ELMR_UNLOCK(adap); 68170654Skmacy return ret; 69170654Skmacy} 70170654Skmacy 71170654Skmacystatic int elmr_write(adapter_t *adap, int addr, u32 val) 72170654Skmacy{ 73170654Skmacy return t3_elmr_blk_write(adap, addr, &val, 1); 74170654Skmacy} 75170654Skmacy 76170654Skmacyint t3_elmr_blk_read(adapter_t *adap, int start, u32 *vals, int n) 77170654Skmacy{ 78172096Skmacy int i, ret; 79170654Skmacy unsigned int v; 80170654Skmacy const struct mdio_ops *mo = adapter_info(adap)->mdio_ops; 81170654Skmacy 82170654Skmacy ELMR_LOCK(adap); 83170654Skmacy 84170654Skmacy ret = mo->write(adap, ELMR_MDIO_ADDR, 0, ELMR_ADDR, start); 85170654Skmacy if (ret) 86170654Skmacy goto out; 87172096Skmacy 88172096Skmacy for (i = 0; i < 5; i++) { 89172096Skmacy ret = mo->read(adap, ELMR_MDIO_ADDR, 0, ELMR_STAT, &v); 90172096Skmacy if (ret) 91172096Skmacy goto out; 92172096Skmacy if (v == 1) 93172096Skmacy break; 94172096Skmacy udelay(5); 95172096Skmacy } 96170654Skmacy if (v != 1) { 97170654Skmacy ret = -ETIMEDOUT; 98170654Skmacy goto out; 99170654Skmacy } 100170654Skmacy 101170654Skmacy for ( ; !ret && n; n--, vals++) { 102170654Skmacy ret = mo->read(adap, ELMR_MDIO_ADDR, 0, ELMR_DATA_LO, vals); 103170654Skmacy if (!ret) { 104170654Skmacy ret = mo->read(adap, ELMR_MDIO_ADDR, 0, ELMR_DATA_HI, 105170654Skmacy &v); 106170654Skmacy *vals |= v << 16; 107170654Skmacy } 108170654Skmacy } 109170654Skmacyout: ELMR_UNLOCK(adap); 110170654Skmacy return ret; 111170654Skmacy} 112170654Skmacy 113170654Skmacyint t3_vsc7323_init(adapter_t *adap, int nports) 114170654Skmacy{ 115170654Skmacy static struct addr_val_pair sys_avp[] = { 116170654Skmacy { VSC_REG(7, 15, 0xf), 2 }, 117170654Skmacy { VSC_REG(7, 15, 0x19), 0xd6 }, 118170654Skmacy { VSC_REG(7, 15, 7), 0xc }, 119170654Skmacy { VSC_REG(7, 1, 0), 0x220 }, 120170654Skmacy }; 121170654Skmacy static struct addr_val_pair fifo_avp[] = { 122170654Skmacy { VSC_REG(2, 0, 0x2f), 0 }, 123170654Skmacy { VSC_REG(2, 0, 0xf), 0xa0010291 }, 124170654Skmacy { VSC_REG(2, 1, 0x2f), 1 }, 125171471Skmacy { VSC_REG(2, 1, 0xf), 0xa026301 } 126170654Skmacy }; 127170654Skmacy static struct addr_val_pair xg_avp[] = { 128170654Skmacy { VSC_REG(1, 10, 0), 0x600b }, 129171471Skmacy { VSC_REG(1, 10, 1), 0x70600 }, //QUANTA = 96*1024*8/512 130171471Skmacy { VSC_REG(1, 10, 2), 0x2710 }, 131170654Skmacy { VSC_REG(1, 10, 5), 0x65 }, 132171471Skmacy { VSC_REG(1, 10, 7), 0x23 }, 133170654Skmacy { VSC_REG(1, 10, 0x23), 0x800007bf }, 134171471Skmacy { VSC_REG(1, 10, 0x23), 0x000007bf }, 135171471Skmacy { VSC_REG(1, 10, 0x23), 0x800007bf }, 136170654Skmacy { VSC_REG(1, 10, 0x24), 4 } 137170654Skmacy }; 138170654Skmacy 139170654Skmacy int i, ret, ing_step, egr_step, ing_bot, egr_bot; 140170654Skmacy 141170654Skmacy for (i = 0; i < ARRAY_SIZE(sys_avp); i++) 142170654Skmacy if ((ret = t3_elmr_blk_write(adap, sys_avp[i].reg_addr, 143171471Skmacy &sys_avp[i].val, 1))) 144170654Skmacy return ret; 145170654Skmacy 146170654Skmacy ing_step = 0xc0 / nports; 147170654Skmacy egr_step = 0x40 / nports; 148170654Skmacy ing_bot = egr_bot = 0; 149170654Skmacy// ing_wm = ing_step * 64; 150170654Skmacy// egr_wm = egr_step * 64; 151170654Skmacy 152170654Skmacy /* {ING,EGR}_CONTROL.CLR = 1 here */ 153171471Skmacy for (i = 0; i < nports; i++) { 154171471Skmacy if ( 155171471Skmacy (ret = elmr_write(adap, VSC_REG(2, 0, 0x10 + i), 156170654Skmacy ((ing_bot + ing_step) << 16) | ing_bot)) || 157171471Skmacy (ret = elmr_write(adap, VSC_REG(2, 0, 0x40 + i), 158172096Skmacy 0x6000bc0)) || 159171471Skmacy (ret = elmr_write(adap, VSC_REG(2, 0, 0x50 + i), 1)) || 160170654Skmacy (ret = elmr_write(adap, VSC_REG(2, 1, 0x10 + i), 161170654Skmacy ((egr_bot + egr_step) << 16) | egr_bot)) || 162170654Skmacy (ret = elmr_write(adap, VSC_REG(2, 1, 0x40 + i), 163170654Skmacy 0x2000280)) || 164170654Skmacy (ret = elmr_write(adap, VSC_REG(2, 1, 0x50 + i), 0))) 165170654Skmacy return ret; 166171471Skmacy ing_bot += ing_step; 167171471Skmacy egr_bot += egr_step; 168171471Skmacy } 169170654Skmacy 170170654Skmacy for (i = 0; i < ARRAY_SIZE(fifo_avp); i++) 171170654Skmacy if ((ret = t3_elmr_blk_write(adap, fifo_avp[i].reg_addr, 172171471Skmacy &fifo_avp[i].val, 1))) 173171471Skmacy return ret; 174170654Skmacy 175170654Skmacy for (i = 0; i < ARRAY_SIZE(xg_avp); i++) 176170654Skmacy if ((ret = t3_elmr_blk_write(adap, xg_avp[i].reg_addr, 177170654Skmacy &xg_avp[i].val, 1))) 178170654Skmacy return ret; 179170654Skmacy 180170654Skmacy for (i = 0; i < nports; i++) 181170654Skmacy if ((ret = elmr_write(adap, VSC_REG(1, i, 0), 0xa59c)) || 182170654Skmacy (ret = elmr_write(adap, VSC_REG(1, i, 5), 183170654Skmacy (i << 12) | 0x63)) || 184170654Skmacy (ret = elmr_write(adap, VSC_REG(1, i, 0xb), 0x96)) || 185172096Skmacy (ret = elmr_write(adap, VSC_REG(1, i, 0x15), 0x21)) || 186172096Skmacy (ret = elmr_write(adap, ELMR_THRES0 + i, 768))) 187170654Skmacy return ret; 188172096Skmacy 189172096Skmacy if ((ret = elmr_write(adap, ELMR_BW, 7))) 190172096Skmacy return ret; 191172096Skmacy 192170654Skmacy return ret; 193170654Skmacy} 194170654Skmacy 195170654Skmacyint t3_vsc7323_set_speed_fc(adapter_t *adap, int speed, int fc, int port) 196170654Skmacy{ 197170654Skmacy int mode, clk, r; 198170654Skmacy 199170654Skmacy if (speed >= 0) { 200170654Skmacy if (speed == SPEED_10) 201170654Skmacy mode = clk = 1; 202170654Skmacy else if (speed == SPEED_100) 203170654Skmacy mode = 1, clk = 2; 204170654Skmacy else if (speed == SPEED_1000) 205170654Skmacy mode = clk = 3; 206170654Skmacy else 207170654Skmacy return -EINVAL; 208170654Skmacy 209170654Skmacy if ((r = elmr_write(adap, VSC_REG(1, port, 0), 210170654Skmacy 0xa590 | (mode << 2))) || 211170654Skmacy (r = elmr_write(adap, VSC_REG(1, port, 0xb), 212170654Skmacy 0x91 | (clk << 1))) || 213170654Skmacy (r = elmr_write(adap, VSC_REG(1, port, 0xb), 214170654Skmacy 0x90 | (clk << 1))) || 215170654Skmacy (r = elmr_write(adap, VSC_REG(1, port, 0), 216170654Skmacy 0xa593 | (mode << 2)))) 217170654Skmacy return r; 218170654Skmacy } 219170654Skmacy 220171471Skmacy r = (fc & PAUSE_RX) ? 0x60200 : 0x20200; //QUANTA = 32*1024*8/512 221170654Skmacy if (fc & PAUSE_TX) 222170654Skmacy r |= (1 << 19); 223170654Skmacy return elmr_write(adap, VSC_REG(1, port, 1), r); 224170654Skmacy} 225170654Skmacy 226170654Skmacyint t3_vsc7323_set_mtu(adapter_t *adap, unsigned int mtu, int port) 227170654Skmacy{ 228170654Skmacy return elmr_write(adap, VSC_REG(1, port, 2), mtu); 229170654Skmacy} 230170654Skmacy 231170654Skmacyint t3_vsc7323_set_addr(adapter_t *adap, u8 addr[6], int port) 232170654Skmacy{ 233170654Skmacy int ret; 234171471Skmacy 235170654Skmacy ret = elmr_write(adap, VSC_REG(1, port, 3), 236171471Skmacy (addr[0] << 16) | (addr[1] << 8) | addr[2]); 237170654Skmacy if (!ret) 238170654Skmacy ret = elmr_write(adap, VSC_REG(1, port, 4), 239171471Skmacy (addr[3] << 16) | (addr[4] << 8) | addr[5]); 240170654Skmacy return ret; 241170654Skmacy} 242170654Skmacy 243170654Skmacyint t3_vsc7323_enable(adapter_t *adap, int port, int which) 244170654Skmacy{ 245170654Skmacy int ret; 246170654Skmacy unsigned int v, orig; 247170654Skmacy 248170654Skmacy ret = t3_elmr_blk_read(adap, VSC_REG(1, port, 0), &v, 1); 249170654Skmacy if (!ret) { 250170654Skmacy orig = v; 251170654Skmacy if (which & MAC_DIRECTION_TX) 252170654Skmacy v |= 1; 253170654Skmacy if (which & MAC_DIRECTION_RX) 254170654Skmacy v |= 2; 255170654Skmacy if (v != orig) 256170654Skmacy ret = elmr_write(adap, VSC_REG(1, port, 0), v); 257170654Skmacy } 258170654Skmacy return ret; 259170654Skmacy} 260170654Skmacy 261170654Skmacyint t3_vsc7323_disable(adapter_t *adap, int port, int which) 262170654Skmacy{ 263170654Skmacy int ret; 264170654Skmacy unsigned int v, orig; 265170654Skmacy 266170654Skmacy ret = t3_elmr_blk_read(adap, VSC_REG(1, port, 0), &v, 1); 267170654Skmacy if (!ret) { 268170654Skmacy orig = v; 269170654Skmacy if (which & MAC_DIRECTION_TX) 270170654Skmacy v &= ~1; 271170654Skmacy if (which & MAC_DIRECTION_RX) 272170654Skmacy v &= ~2; 273170654Skmacy if (v != orig) 274170654Skmacy ret = elmr_write(adap, VSC_REG(1, port, 0), v); 275170654Skmacy } 276170654Skmacy return ret; 277170654Skmacy} 278170654Skmacy 279170654Skmacy#define STATS0_START 1 280170654Skmacy#define STATS1_START 0x24 281170654Skmacy#define NSTATS0 (0x1d - STATS0_START + 1) 282170654Skmacy#define NSTATS1 (0x2a - STATS1_START + 1) 283170654Skmacy 284172096Skmacy#define ELMR_STAT(port, reg) (ELMR_STATS + port * 0x40 + reg) 285172096Skmacy 286170654Skmacyconst struct mac_stats *t3_vsc7323_update_stats(struct cmac *mac) 287170654Skmacy{ 288170654Skmacy int ret; 289170654Skmacy u64 rx_ucast, tx_ucast; 290170654Skmacy u32 stats0[NSTATS0], stats1[NSTATS1]; 291170654Skmacy 292170654Skmacy ret = t3_elmr_blk_read(mac->adapter, 293172096Skmacy ELMR_STAT(mac->ext_port, STATS0_START), 294170654Skmacy stats0, NSTATS0); 295170654Skmacy if (!ret) 296170654Skmacy ret = t3_elmr_blk_read(mac->adapter, 297172096Skmacy ELMR_STAT(mac->ext_port, STATS1_START), 298170654Skmacy stats1, NSTATS1); 299170654Skmacy if (ret) 300170654Skmacy goto out; 301170654Skmacy 302170654Skmacy /* 303170654Skmacy * HW counts Rx/Tx unicast frames but we want all the frames. 304170654Skmacy */ 305170654Skmacy rx_ucast = mac->stats.rx_frames - mac->stats.rx_mcast_frames - 306170654Skmacy mac->stats.rx_bcast_frames; 307170654Skmacy rx_ucast += (u64)(stats0[6 - STATS0_START] - (u32)rx_ucast); 308170654Skmacy tx_ucast = mac->stats.tx_frames - mac->stats.tx_mcast_frames - 309170654Skmacy mac->stats.tx_bcast_frames; 310170654Skmacy tx_ucast += (u64)(stats0[27 - STATS0_START] - (u32)tx_ucast); 311170654Skmacy 312170654Skmacy#define RMON_UPDATE(mac, name, hw_stat) \ 313170654Skmacy mac->stats.name += (u64)((hw_stat) - (u32)(mac->stats.name)) 314170654Skmacy 315170654Skmacy RMON_UPDATE(mac, rx_octets, stats0[4 - STATS0_START]); 316170654Skmacy RMON_UPDATE(mac, rx_frames, stats0[6 - STATS0_START]); 317170654Skmacy RMON_UPDATE(mac, rx_frames, stats0[7 - STATS0_START]); 318170654Skmacy RMON_UPDATE(mac, rx_frames, stats0[8 - STATS0_START]); 319170654Skmacy RMON_UPDATE(mac, rx_mcast_frames, stats0[7 - STATS0_START]); 320170654Skmacy RMON_UPDATE(mac, rx_bcast_frames, stats0[8 - STATS0_START]); 321170654Skmacy RMON_UPDATE(mac, rx_fcs_errs, stats0[9 - STATS0_START]); 322170654Skmacy RMON_UPDATE(mac, rx_pause, stats0[2 - STATS0_START]); 323170654Skmacy RMON_UPDATE(mac, rx_jabber, stats0[16 - STATS0_START]); 324170654Skmacy RMON_UPDATE(mac, rx_short, stats0[11 - STATS0_START]); 325170654Skmacy RMON_UPDATE(mac, rx_symbol_errs, stats0[1 - STATS0_START]); 326170654Skmacy RMON_UPDATE(mac, rx_too_long, stats0[15 - STATS0_START]); 327170654Skmacy 328170654Skmacy RMON_UPDATE(mac, rx_frames_64, stats0[17 - STATS0_START]); 329170654Skmacy RMON_UPDATE(mac, rx_frames_65_127, stats0[18 - STATS0_START]); 330170654Skmacy RMON_UPDATE(mac, rx_frames_128_255, stats0[19 - STATS0_START]); 331170654Skmacy RMON_UPDATE(mac, rx_frames_256_511, stats0[20 - STATS0_START]); 332170654Skmacy RMON_UPDATE(mac, rx_frames_512_1023, stats0[21 - STATS0_START]); 333170654Skmacy RMON_UPDATE(mac, rx_frames_1024_1518, stats0[22 - STATS0_START]); 334170654Skmacy RMON_UPDATE(mac, rx_frames_1519_max, stats0[23 - STATS0_START]); 335170654Skmacy 336170654Skmacy RMON_UPDATE(mac, tx_octets, stats0[26 - STATS0_START]); 337170654Skmacy RMON_UPDATE(mac, tx_frames, stats0[27 - STATS0_START]); 338170654Skmacy RMON_UPDATE(mac, tx_frames, stats0[28 - STATS0_START]); 339170654Skmacy RMON_UPDATE(mac, tx_frames, stats0[29 - STATS0_START]); 340170654Skmacy RMON_UPDATE(mac, tx_mcast_frames, stats0[28 - STATS0_START]); 341170654Skmacy RMON_UPDATE(mac, tx_bcast_frames, stats0[29 - STATS0_START]); 342170654Skmacy RMON_UPDATE(mac, tx_pause, stats0[25 - STATS0_START]); 343170654Skmacy 344170654Skmacy RMON_UPDATE(mac, tx_underrun, 0); 345170654Skmacy 346170654Skmacy RMON_UPDATE(mac, tx_frames_64, stats1[36 - STATS1_START]); 347170654Skmacy RMON_UPDATE(mac, tx_frames_65_127, stats1[37 - STATS1_START]); 348170654Skmacy RMON_UPDATE(mac, tx_frames_128_255, stats1[38 - STATS1_START]); 349170654Skmacy RMON_UPDATE(mac, tx_frames_256_511, stats1[39 - STATS1_START]); 350170654Skmacy RMON_UPDATE(mac, tx_frames_512_1023, stats1[40 - STATS1_START]); 351170654Skmacy RMON_UPDATE(mac, tx_frames_1024_1518, stats1[41 - STATS1_START]); 352170654Skmacy RMON_UPDATE(mac, tx_frames_1519_max, stats1[42 - STATS1_START]); 353170654Skmacy 354170654Skmacy#undef RMON_UPDATE 355170654Skmacy 356170654Skmacy mac->stats.rx_frames = rx_ucast + mac->stats.rx_mcast_frames + 357170654Skmacy mac->stats.rx_bcast_frames; 358170654Skmacy mac->stats.tx_frames = tx_ucast + mac->stats.tx_mcast_frames + 359170654Skmacy mac->stats.tx_bcast_frames; 360170654Skmacyout: return &mac->stats; 361170654Skmacy} 362