1167514Skmacy/************************************************************************** 2167514Skmacy 3189643SgnnCopyright (c) 2007-2009, Chelsio Inc. 4167514SkmacyAll rights reserved. 5167514Skmacy 6167514SkmacyRedistribution and use in source and binary forms, with or without 7167514Skmacymodification, are permitted provided that the following conditions are met: 8167514Skmacy 9167514Skmacy 1. Redistributions of source code must retain the above copyright notice, 10167514Skmacy this list of conditions and the following disclaimer. 11167514Skmacy 12170076Skmacy 2. Neither the name of the Chelsio Corporation nor the names of its 13167514Skmacy contributors may be used to endorse or promote products derived from 14167514Skmacy this software without specific prior written permission. 15167514Skmacy 16167514SkmacyTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17167514SkmacyAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18167514SkmacyIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19167514SkmacyARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 20167514SkmacyLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21167514SkmacyCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22167514SkmacySUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23167514SkmacyINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24167514SkmacyCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25167514SkmacyARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26167514SkmacyPOSSIBILITY OF SUCH DAMAGE. 27167514Skmacy 28167514Skmacy***************************************************************************/ 29167514Skmacy 30167514Skmacy#include <sys/cdefs.h> 31172100Skmacy__FBSDID("$FreeBSD$"); 32167514Skmacy 33170654Skmacy 34170076Skmacy#include <cxgb_include.h> 35167514Skmacy 36171471Skmacy#undef msleep 37171471Skmacy#define msleep t3_os_sleep 38170654Skmacy 39167514Skmacy/** 40167514Skmacy * t3_wait_op_done_val - wait until an operation is completed 41167514Skmacy * @adapter: the adapter performing the operation 42167514Skmacy * @reg: the register to check for completion 43167514Skmacy * @mask: a single-bit field within @reg that indicates completion 44167514Skmacy * @polarity: the value of the field when the operation is completed 45167514Skmacy * @attempts: number of check iterations 46167514Skmacy * @delay: delay in usecs between iterations 47167514Skmacy * @valp: where to store the value of the register at completion time 48167514Skmacy * 49167514Skmacy * Wait until an operation is completed by checking a bit in a register 50167514Skmacy * up to @attempts times. If @valp is not NULL the value of the register 51167514Skmacy * at the time it indicated completion is stored there. Returns 0 if the 52167514Skmacy * operation completes and -EAGAIN otherwise. 53167514Skmacy */ 54167514Skmacyint t3_wait_op_done_val(adapter_t *adapter, int reg, u32 mask, int polarity, 55167514Skmacy int attempts, int delay, u32 *valp) 56167514Skmacy{ 57167514Skmacy while (1) { 58167514Skmacy u32 val = t3_read_reg(adapter, reg); 59167514Skmacy 60167514Skmacy if (!!(val & mask) == polarity) { 61167514Skmacy if (valp) 62167514Skmacy *valp = val; 63167514Skmacy return 0; 64167514Skmacy } 65167514Skmacy if (--attempts == 0) 66167514Skmacy return -EAGAIN; 67167514Skmacy if (delay) 68167514Skmacy udelay(delay); 69167514Skmacy } 70167514Skmacy} 71167514Skmacy 72167514Skmacy/** 73167514Skmacy * t3_write_regs - write a bunch of registers 74167514Skmacy * @adapter: the adapter to program 75167514Skmacy * @p: an array of register address/register value pairs 76167514Skmacy * @n: the number of address/value pairs 77167514Skmacy * @offset: register address offset 78167514Skmacy * 79167514Skmacy * Takes an array of register address/register value pairs and writes each 80167514Skmacy * value to the corresponding register. Register addresses are adjusted 81167514Skmacy * by the supplied offset. 82167514Skmacy */ 83167514Skmacyvoid t3_write_regs(adapter_t *adapter, const struct addr_val_pair *p, int n, 84167514Skmacy unsigned int offset) 85167514Skmacy{ 86167514Skmacy while (n--) { 87167514Skmacy t3_write_reg(adapter, p->reg_addr + offset, p->val); 88167514Skmacy p++; 89167514Skmacy } 90167514Skmacy} 91167514Skmacy 92167514Skmacy/** 93167514Skmacy * t3_set_reg_field - set a register field to a value 94167514Skmacy * @adapter: the adapter to program 95167514Skmacy * @addr: the register address 96167514Skmacy * @mask: specifies the portion of the register to modify 97167514Skmacy * @val: the new value for the register field 98167514Skmacy * 99167514Skmacy * Sets a register field specified by the supplied mask to the 100167514Skmacy * given value. 101167514Skmacy */ 102167514Skmacyvoid t3_set_reg_field(adapter_t *adapter, unsigned int addr, u32 mask, u32 val) 103167514Skmacy{ 104167514Skmacy u32 v = t3_read_reg(adapter, addr) & ~mask; 105167514Skmacy 106167514Skmacy t3_write_reg(adapter, addr, v | val); 107167514Skmacy (void) t3_read_reg(adapter, addr); /* flush */ 108167514Skmacy} 109167514Skmacy 110167514Skmacy/** 111167514Skmacy * t3_read_indirect - read indirectly addressed registers 112167514Skmacy * @adap: the adapter 113167514Skmacy * @addr_reg: register holding the indirect address 114167514Skmacy * @data_reg: register holding the value of the indirect register 115167514Skmacy * @vals: where the read register values are stored 116167514Skmacy * @start_idx: index of first indirect register to read 117167514Skmacy * @nregs: how many indirect registers to read 118167514Skmacy * 119167514Skmacy * Reads registers that are accessed indirectly through an address/data 120167514Skmacy * register pair. 121167514Skmacy */ 122170654Skmacystatic void t3_read_indirect(adapter_t *adap, unsigned int addr_reg, 123167514Skmacy unsigned int data_reg, u32 *vals, unsigned int nregs, 124167514Skmacy unsigned int start_idx) 125167514Skmacy{ 126167514Skmacy while (nregs--) { 127167514Skmacy t3_write_reg(adap, addr_reg, start_idx); 128167514Skmacy *vals++ = t3_read_reg(adap, data_reg); 129167514Skmacy start_idx++; 130167514Skmacy } 131167514Skmacy} 132167514Skmacy 133167514Skmacy/** 134167514Skmacy * t3_mc7_bd_read - read from MC7 through backdoor accesses 135167514Skmacy * @mc7: identifies MC7 to read from 136167514Skmacy * @start: index of first 64-bit word to read 137167514Skmacy * @n: number of 64-bit words to read 138167514Skmacy * @buf: where to store the read result 139167514Skmacy * 140167514Skmacy * Read n 64-bit words from MC7 starting at word start, using backdoor 141167514Skmacy * accesses. 142167514Skmacy */ 143167514Skmacyint t3_mc7_bd_read(struct mc7 *mc7, unsigned int start, unsigned int n, 144167514Skmacy u64 *buf) 145167514Skmacy{ 146167514Skmacy static int shift[] = { 0, 0, 16, 24 }; 147167514Skmacy static int step[] = { 0, 32, 16, 8 }; 148167514Skmacy 149167514Skmacy unsigned int size64 = mc7->size / 8; /* # of 64-bit words */ 150167514Skmacy adapter_t *adap = mc7->adapter; 151167514Skmacy 152167514Skmacy if (start >= size64 || start + n > size64) 153167514Skmacy return -EINVAL; 154167514Skmacy 155167514Skmacy start *= (8 << mc7->width); 156167514Skmacy while (n--) { 157167514Skmacy int i; 158167514Skmacy u64 val64 = 0; 159167514Skmacy 160167514Skmacy for (i = (1 << mc7->width) - 1; i >= 0; --i) { 161167514Skmacy int attempts = 10; 162167514Skmacy u32 val; 163167514Skmacy 164167514Skmacy t3_write_reg(adap, mc7->offset + A_MC7_BD_ADDR, 165167514Skmacy start); 166167514Skmacy t3_write_reg(adap, mc7->offset + A_MC7_BD_OP, 0); 167167514Skmacy val = t3_read_reg(adap, mc7->offset + A_MC7_BD_OP); 168167514Skmacy while ((val & F_BUSY) && attempts--) 169167514Skmacy val = t3_read_reg(adap, 170167514Skmacy mc7->offset + A_MC7_BD_OP); 171167514Skmacy if (val & F_BUSY) 172167514Skmacy return -EIO; 173167514Skmacy 174167514Skmacy val = t3_read_reg(adap, mc7->offset + A_MC7_BD_DATA1); 175167514Skmacy if (mc7->width == 0) { 176167514Skmacy val64 = t3_read_reg(adap, 177167514Skmacy mc7->offset + A_MC7_BD_DATA0); 178167514Skmacy val64 |= (u64)val << 32; 179167514Skmacy } else { 180167514Skmacy if (mc7->width > 1) 181167514Skmacy val >>= shift[mc7->width]; 182167514Skmacy val64 |= (u64)val << (step[mc7->width] * i); 183167514Skmacy } 184167514Skmacy start += 8; 185167514Skmacy } 186167514Skmacy *buf++ = val64; 187167514Skmacy } 188167514Skmacy return 0; 189167514Skmacy} 190167514Skmacy 191167514Skmacy/* 192197791Snp * Low-level I2C read and write routines. These simply read and write a 193197791Snp * single byte with the option of indicating a "continue" if another operation 194197791Snp * is to be chained. Generally most code will use higher-level routines to 195197791Snp * read and write to I2C Slave Devices. 196197791Snp */ 197197791Snp#define I2C_ATTEMPTS 100 198197791Snp 199197791Snp/* 200197791Snp * Read an 8-bit value from the I2C bus. If the "chained" parameter is 201197791Snp * non-zero then a STOP bit will not be written after the read command. On 202197791Snp * error (the read timed out, etc.), a negative errno will be returned (e.g. 203197791Snp * -EAGAIN, etc.). On success, the 8-bit value read from the I2C bus is 204197791Snp * stored into the buffer *valp and the value of the I2C ACK bit is returned 205197791Snp * as a 0/1 value. 206197791Snp */ 207197791Snpint t3_i2c_read8(adapter_t *adapter, int chained, u8 *valp) 208197791Snp{ 209197791Snp int ret; 210197791Snp u32 opval; 211197791Snp MDIO_LOCK(adapter); 212197791Snp t3_write_reg(adapter, A_I2C_OP, 213197791Snp F_I2C_READ | (chained ? F_I2C_CONT : 0)); 214197791Snp ret = t3_wait_op_done_val(adapter, A_I2C_OP, F_I2C_BUSY, 0, 215197791Snp I2C_ATTEMPTS, 10, &opval); 216197791Snp if (ret >= 0) { 217197791Snp ret = ((opval & F_I2C_ACK) == F_I2C_ACK); 218197791Snp *valp = G_I2C_DATA(t3_read_reg(adapter, A_I2C_DATA)); 219197791Snp } 220197791Snp MDIO_UNLOCK(adapter); 221197791Snp return ret; 222197791Snp} 223197791Snp 224197791Snp/* 225197791Snp * Write an 8-bit value to the I2C bus. If the "chained" parameter is 226197791Snp * non-zero, then a STOP bit will not be written after the write command. On 227197791Snp * error (the write timed out, etc.), a negative errno will be returned (e.g. 228197791Snp * -EAGAIN, etc.). On success, the value of the I2C ACK bit is returned as a 229197791Snp * 0/1 value. 230197791Snp */ 231197791Snpint t3_i2c_write8(adapter_t *adapter, int chained, u8 val) 232197791Snp{ 233197791Snp int ret; 234197791Snp u32 opval; 235197791Snp MDIO_LOCK(adapter); 236197791Snp t3_write_reg(adapter, A_I2C_DATA, V_I2C_DATA(val)); 237197791Snp t3_write_reg(adapter, A_I2C_OP, 238197791Snp F_I2C_WRITE | (chained ? F_I2C_CONT : 0)); 239197791Snp ret = t3_wait_op_done_val(adapter, A_I2C_OP, F_I2C_BUSY, 0, 240197791Snp I2C_ATTEMPTS, 10, &opval); 241197791Snp if (ret >= 0) 242197791Snp ret = ((opval & F_I2C_ACK) == F_I2C_ACK); 243197791Snp MDIO_UNLOCK(adapter); 244197791Snp return ret; 245197791Snp} 246197791Snp 247197791Snp/* 248167514Skmacy * Initialize MI1. 249167514Skmacy */ 250167514Skmacystatic void mi1_init(adapter_t *adap, const struct adapter_info *ai) 251167514Skmacy{ 252167514Skmacy u32 clkdiv = adap->params.vpd.cclk / (2 * adap->params.vpd.mdc) - 1; 253189643Sgnn u32 val = F_PREEN | V_CLKDIV(clkdiv); 254167514Skmacy 255167514Skmacy t3_write_reg(adap, A_MI1_CFG, val); 256167514Skmacy} 257167514Skmacy 258170654Skmacy#define MDIO_ATTEMPTS 20 259167514Skmacy 260167514Skmacy/* 261189643Sgnn * MI1 read/write operations for clause 22 PHYs. 262167514Skmacy */ 263189643Sgnnint t3_mi1_read(adapter_t *adapter, int phy_addr, int mmd_addr, 264189643Sgnn int reg_addr, unsigned int *valp) 265167514Skmacy{ 266167514Skmacy int ret; 267167514Skmacy u32 addr = V_REGADDR(reg_addr) | V_PHYADDR(phy_addr); 268167514Skmacy 269167514Skmacy if (mmd_addr) 270167514Skmacy return -EINVAL; 271167514Skmacy 272167514Skmacy MDIO_LOCK(adapter); 273189643Sgnn t3_set_reg_field(adapter, A_MI1_CFG, V_ST(M_ST), V_ST(1)); 274167514Skmacy t3_write_reg(adapter, A_MI1_ADDR, addr); 275167514Skmacy t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(2)); 276170654Skmacy ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 10); 277167514Skmacy if (!ret) 278167514Skmacy *valp = t3_read_reg(adapter, A_MI1_DATA); 279167514Skmacy MDIO_UNLOCK(adapter); 280167514Skmacy return ret; 281167514Skmacy} 282167514Skmacy 283189643Sgnnint t3_mi1_write(adapter_t *adapter, int phy_addr, int mmd_addr, 284189643Sgnn int reg_addr, unsigned int val) 285167514Skmacy{ 286167514Skmacy int ret; 287167514Skmacy u32 addr = V_REGADDR(reg_addr) | V_PHYADDR(phy_addr); 288167514Skmacy 289167514Skmacy if (mmd_addr) 290167514Skmacy return -EINVAL; 291167514Skmacy 292167514Skmacy MDIO_LOCK(adapter); 293189643Sgnn t3_set_reg_field(adapter, A_MI1_CFG, V_ST(M_ST), V_ST(1)); 294167514Skmacy t3_write_reg(adapter, A_MI1_ADDR, addr); 295167514Skmacy t3_write_reg(adapter, A_MI1_DATA, val); 296167514Skmacy t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(1)); 297170654Skmacy ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 10); 298167514Skmacy MDIO_UNLOCK(adapter); 299167514Skmacy return ret; 300167514Skmacy} 301167514Skmacy 302167514Skmacystatic struct mdio_ops mi1_mdio_ops = { 303189643Sgnn t3_mi1_read, 304189643Sgnn t3_mi1_write 305167514Skmacy}; 306167514Skmacy 307167514Skmacy/* 308189643Sgnn * MI1 read/write operations for clause 45 PHYs. 309167514Skmacy */ 310167514Skmacystatic int mi1_ext_read(adapter_t *adapter, int phy_addr, int mmd_addr, 311167514Skmacy int reg_addr, unsigned int *valp) 312167514Skmacy{ 313167514Skmacy int ret; 314167514Skmacy u32 addr = V_REGADDR(mmd_addr) | V_PHYADDR(phy_addr); 315167514Skmacy 316167514Skmacy MDIO_LOCK(adapter); 317189643Sgnn t3_set_reg_field(adapter, A_MI1_CFG, V_ST(M_ST), 0); 318167514Skmacy t3_write_reg(adapter, A_MI1_ADDR, addr); 319167514Skmacy t3_write_reg(adapter, A_MI1_DATA, reg_addr); 320167514Skmacy t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(0)); 321170654Skmacy ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 10); 322167514Skmacy if (!ret) { 323167514Skmacy t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(3)); 324167514Skmacy ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, 325170654Skmacy MDIO_ATTEMPTS, 10); 326167514Skmacy if (!ret) 327167514Skmacy *valp = t3_read_reg(adapter, A_MI1_DATA); 328167514Skmacy } 329167514Skmacy MDIO_UNLOCK(adapter); 330167514Skmacy return ret; 331167514Skmacy} 332167514Skmacy 333167514Skmacystatic int mi1_ext_write(adapter_t *adapter, int phy_addr, int mmd_addr, 334167514Skmacy int reg_addr, unsigned int val) 335167514Skmacy{ 336167514Skmacy int ret; 337167514Skmacy u32 addr = V_REGADDR(mmd_addr) | V_PHYADDR(phy_addr); 338167514Skmacy 339167514Skmacy MDIO_LOCK(adapter); 340189643Sgnn t3_set_reg_field(adapter, A_MI1_CFG, V_ST(M_ST), 0); 341167514Skmacy t3_write_reg(adapter, A_MI1_ADDR, addr); 342167514Skmacy t3_write_reg(adapter, A_MI1_DATA, reg_addr); 343167514Skmacy t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(0)); 344170654Skmacy ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 10); 345167514Skmacy if (!ret) { 346167514Skmacy t3_write_reg(adapter, A_MI1_DATA, val); 347167514Skmacy t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(1)); 348167514Skmacy ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, 349170654Skmacy MDIO_ATTEMPTS, 10); 350167514Skmacy } 351167514Skmacy MDIO_UNLOCK(adapter); 352167514Skmacy return ret; 353167514Skmacy} 354167514Skmacy 355167514Skmacystatic struct mdio_ops mi1_mdio_ext_ops = { 356167514Skmacy mi1_ext_read, 357167514Skmacy mi1_ext_write 358167514Skmacy}; 359167514Skmacy 360167514Skmacy/** 361167514Skmacy * t3_mdio_change_bits - modify the value of a PHY register 362167514Skmacy * @phy: the PHY to operate on 363167514Skmacy * @mmd: the device address 364167514Skmacy * @reg: the register address 365167514Skmacy * @clear: what part of the register value to mask off 366167514Skmacy * @set: what part of the register value to set 367167514Skmacy * 368167514Skmacy * Changes the value of a PHY register by applying a mask to its current 369167514Skmacy * value and ORing the result with a new value. 370167514Skmacy */ 371167514Skmacyint t3_mdio_change_bits(struct cphy *phy, int mmd, int reg, unsigned int clear, 372167514Skmacy unsigned int set) 373167514Skmacy{ 374167514Skmacy int ret; 375167514Skmacy unsigned int val; 376167514Skmacy 377167514Skmacy ret = mdio_read(phy, mmd, reg, &val); 378167514Skmacy if (!ret) { 379167514Skmacy val &= ~clear; 380167514Skmacy ret = mdio_write(phy, mmd, reg, val | set); 381167514Skmacy } 382167514Skmacy return ret; 383167514Skmacy} 384167514Skmacy 385167514Skmacy/** 386167514Skmacy * t3_phy_reset - reset a PHY block 387167514Skmacy * @phy: the PHY to operate on 388167514Skmacy * @mmd: the device address of the PHY block to reset 389167514Skmacy * @wait: how long to wait for the reset to complete in 1ms increments 390167514Skmacy * 391167514Skmacy * Resets a PHY block and optionally waits for the reset to complete. 392167514Skmacy * @mmd should be 0 for 10/100/1000 PHYs and the device address to reset 393167514Skmacy * for 10G PHYs. 394167514Skmacy */ 395167514Skmacyint t3_phy_reset(struct cphy *phy, int mmd, int wait) 396167514Skmacy{ 397167514Skmacy int err; 398167514Skmacy unsigned int ctl; 399167514Skmacy 400167514Skmacy err = t3_mdio_change_bits(phy, mmd, MII_BMCR, BMCR_PDOWN, BMCR_RESET); 401167514Skmacy if (err || !wait) 402167514Skmacy return err; 403167514Skmacy 404167514Skmacy do { 405167514Skmacy err = mdio_read(phy, mmd, MII_BMCR, &ctl); 406167514Skmacy if (err) 407167514Skmacy return err; 408167514Skmacy ctl &= BMCR_RESET; 409167514Skmacy if (ctl) 410171471Skmacy msleep(1); 411167514Skmacy } while (ctl && --wait); 412167514Skmacy 413167514Skmacy return ctl ? -1 : 0; 414167514Skmacy} 415167514Skmacy 416167514Skmacy/** 417167514Skmacy * t3_phy_advertise - set the PHY advertisement registers for autoneg 418167514Skmacy * @phy: the PHY to operate on 419167514Skmacy * @advert: bitmap of capabilities the PHY should advertise 420167514Skmacy * 421167514Skmacy * Sets a 10/100/1000 PHY's advertisement registers to advertise the 422167514Skmacy * requested capabilities. 423167514Skmacy */ 424167514Skmacyint t3_phy_advertise(struct cphy *phy, unsigned int advert) 425167514Skmacy{ 426167514Skmacy int err; 427167514Skmacy unsigned int val = 0; 428167514Skmacy 429167514Skmacy err = mdio_read(phy, 0, MII_CTRL1000, &val); 430167514Skmacy if (err) 431167514Skmacy return err; 432167514Skmacy 433167514Skmacy val &= ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL); 434167514Skmacy if (advert & ADVERTISED_1000baseT_Half) 435167514Skmacy val |= ADVERTISE_1000HALF; 436167514Skmacy if (advert & ADVERTISED_1000baseT_Full) 437167514Skmacy val |= ADVERTISE_1000FULL; 438167514Skmacy 439167514Skmacy err = mdio_write(phy, 0, MII_CTRL1000, val); 440167514Skmacy if (err) 441167514Skmacy return err; 442167514Skmacy 443167514Skmacy val = 1; 444167514Skmacy if (advert & ADVERTISED_10baseT_Half) 445167514Skmacy val |= ADVERTISE_10HALF; 446167514Skmacy if (advert & ADVERTISED_10baseT_Full) 447167514Skmacy val |= ADVERTISE_10FULL; 448167514Skmacy if (advert & ADVERTISED_100baseT_Half) 449167514Skmacy val |= ADVERTISE_100HALF; 450167514Skmacy if (advert & ADVERTISED_100baseT_Full) 451167514Skmacy val |= ADVERTISE_100FULL; 452167514Skmacy if (advert & ADVERTISED_Pause) 453167514Skmacy val |= ADVERTISE_PAUSE_CAP; 454167514Skmacy if (advert & ADVERTISED_Asym_Pause) 455167514Skmacy val |= ADVERTISE_PAUSE_ASYM; 456167514Skmacy return mdio_write(phy, 0, MII_ADVERTISE, val); 457167514Skmacy} 458167514Skmacy 459167514Skmacy/** 460176472Skmacy * t3_phy_advertise_fiber - set fiber PHY advertisement register 461176472Skmacy * @phy: the PHY to operate on 462176472Skmacy * @advert: bitmap of capabilities the PHY should advertise 463176472Skmacy * 464176472Skmacy * Sets a fiber PHY's advertisement register to advertise the 465176472Skmacy * requested capabilities. 466176472Skmacy */ 467176472Skmacyint t3_phy_advertise_fiber(struct cphy *phy, unsigned int advert) 468176472Skmacy{ 469176472Skmacy unsigned int val = 0; 470176472Skmacy 471176472Skmacy if (advert & ADVERTISED_1000baseT_Half) 472176472Skmacy val |= ADVERTISE_1000XHALF; 473176472Skmacy if (advert & ADVERTISED_1000baseT_Full) 474176472Skmacy val |= ADVERTISE_1000XFULL; 475176472Skmacy if (advert & ADVERTISED_Pause) 476176472Skmacy val |= ADVERTISE_1000XPAUSE; 477176472Skmacy if (advert & ADVERTISED_Asym_Pause) 478176472Skmacy val |= ADVERTISE_1000XPSE_ASYM; 479176472Skmacy return mdio_write(phy, 0, MII_ADVERTISE, val); 480176472Skmacy} 481176472Skmacy 482176472Skmacy/** 483167514Skmacy * t3_set_phy_speed_duplex - force PHY speed and duplex 484167514Skmacy * @phy: the PHY to operate on 485167514Skmacy * @speed: requested PHY speed 486167514Skmacy * @duplex: requested PHY duplex 487167514Skmacy * 488167514Skmacy * Force a 10/100/1000 PHY's speed and duplex. This also disables 489167514Skmacy * auto-negotiation except for GigE, where auto-negotiation is mandatory. 490167514Skmacy */ 491167514Skmacyint t3_set_phy_speed_duplex(struct cphy *phy, int speed, int duplex) 492167514Skmacy{ 493167514Skmacy int err; 494167514Skmacy unsigned int ctl; 495167514Skmacy 496167514Skmacy err = mdio_read(phy, 0, MII_BMCR, &ctl); 497167514Skmacy if (err) 498167514Skmacy return err; 499167514Skmacy 500167514Skmacy if (speed >= 0) { 501167514Skmacy ctl &= ~(BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE); 502167514Skmacy if (speed == SPEED_100) 503167514Skmacy ctl |= BMCR_SPEED100; 504167514Skmacy else if (speed == SPEED_1000) 505167514Skmacy ctl |= BMCR_SPEED1000; 506167514Skmacy } 507167514Skmacy if (duplex >= 0) { 508167514Skmacy ctl &= ~(BMCR_FULLDPLX | BMCR_ANENABLE); 509167514Skmacy if (duplex == DUPLEX_FULL) 510167514Skmacy ctl |= BMCR_FULLDPLX; 511167514Skmacy } 512167514Skmacy if (ctl & BMCR_SPEED1000) /* auto-negotiation required for GigE */ 513167514Skmacy ctl |= BMCR_ANENABLE; 514167514Skmacy return mdio_write(phy, 0, MII_BMCR, ctl); 515167514Skmacy} 516167514Skmacy 517180583Skmacyint t3_phy_lasi_intr_enable(struct cphy *phy) 518180583Skmacy{ 519180583Skmacy return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 1); 520180583Skmacy} 521180583Skmacy 522180583Skmacyint t3_phy_lasi_intr_disable(struct cphy *phy) 523180583Skmacy{ 524180583Skmacy return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 0); 525180583Skmacy} 526180583Skmacy 527180583Skmacyint t3_phy_lasi_intr_clear(struct cphy *phy) 528180583Skmacy{ 529180583Skmacy u32 val; 530180583Skmacy 531180583Skmacy return mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &val); 532180583Skmacy} 533180583Skmacy 534180583Skmacyint t3_phy_lasi_intr_handler(struct cphy *phy) 535180583Skmacy{ 536180583Skmacy unsigned int status; 537180583Skmacy int err = mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &status); 538180583Skmacy 539180583Skmacy if (err) 540180583Skmacy return err; 541180583Skmacy return (status & 1) ? cphy_cause_link_change : 0; 542180583Skmacy} 543180583Skmacy 544167514Skmacystatic struct adapter_info t3_adap_info[] = { 545189643Sgnn { 1, 1, 0, 546167514Skmacy F_GPIO2_OEN | F_GPIO4_OEN | 547180583Skmacy F_GPIO2_OUT_VAL | F_GPIO4_OUT_VAL, { S_GPIO3, S_GPIO5 }, 0, 548167514Skmacy &mi1_mdio_ops, "Chelsio PE9000" }, 549189643Sgnn { 1, 1, 0, 550167514Skmacy F_GPIO2_OEN | F_GPIO4_OEN | 551180583Skmacy F_GPIO2_OUT_VAL | F_GPIO4_OUT_VAL, { S_GPIO3, S_GPIO5 }, 0, 552167514Skmacy &mi1_mdio_ops, "Chelsio T302" }, 553189643Sgnn { 1, 0, 0, 554167514Skmacy F_GPIO1_OEN | F_GPIO6_OEN | F_GPIO7_OEN | F_GPIO10_OEN | 555176472Skmacy F_GPIO11_OEN | F_GPIO1_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL, 556180583Skmacy { 0 }, SUPPORTED_10000baseT_Full | SUPPORTED_AUI, 557167514Skmacy &mi1_mdio_ext_ops, "Chelsio T310" }, 558189643Sgnn { 1, 1, 0, 559167514Skmacy F_GPIO1_OEN | F_GPIO2_OEN | F_GPIO4_OEN | F_GPIO5_OEN | F_GPIO6_OEN | 560167514Skmacy F_GPIO7_OEN | F_GPIO10_OEN | F_GPIO11_OEN | F_GPIO1_OUT_VAL | 561180583Skmacy F_GPIO5_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL, 562180583Skmacy { S_GPIO9, S_GPIO3 }, SUPPORTED_10000baseT_Full | SUPPORTED_AUI, 563167514Skmacy &mi1_mdio_ext_ops, "Chelsio T320" }, 564189643Sgnn { 4, 0, 0, 565170654Skmacy F_GPIO5_OEN | F_GPIO6_OEN | F_GPIO7_OEN | F_GPIO5_OUT_VAL | 566170654Skmacy F_GPIO6_OUT_VAL | F_GPIO7_OUT_VAL, 567180583Skmacy { S_GPIO1, S_GPIO2, S_GPIO3, S_GPIO4 }, SUPPORTED_AUI, 568170654Skmacy &mi1_mdio_ops, "Chelsio T304" }, 569185662Sgnn { 0 }, 570189643Sgnn { 1, 0, 0, 571185662Sgnn F_GPIO1_OEN | F_GPIO2_OEN | F_GPIO4_OEN | F_GPIO6_OEN | F_GPIO7_OEN | 572185662Sgnn F_GPIO10_OEN | F_GPIO1_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL, 573185662Sgnn { S_GPIO9 }, SUPPORTED_10000baseT_Full | SUPPORTED_AUI, 574197791Snp &mi1_mdio_ext_ops, "Chelsio T310" }, 575197791Snp { 1, 0, 0, 576197791Snp F_GPIO1_OEN | F_GPIO6_OEN | F_GPIO7_OEN | 577197791Snp F_GPIO1_OUT_VAL | F_GPIO6_OUT_VAL, 578197791Snp { S_GPIO9 }, SUPPORTED_10000baseT_Full | SUPPORTED_AUI, 579197791Snp &mi1_mdio_ext_ops, "Chelsio N320E-G2" }, 580167514Skmacy}; 581167514Skmacy 582167514Skmacy/* 583167514Skmacy * Return the adapter_info structure with a given index. Out-of-range indices 584167514Skmacy * return NULL. 585167514Skmacy */ 586167514Skmacyconst struct adapter_info *t3_get_adapter_info(unsigned int id) 587167514Skmacy{ 588167514Skmacy return id < ARRAY_SIZE(t3_adap_info) ? &t3_adap_info[id] : NULL; 589167514Skmacy} 590167514Skmacy 591181614Skmacystruct port_type_info { 592197791Snp int (*phy_prep)(pinfo_t *pinfo, int phy_addr, 593181614Skmacy const struct mdio_ops *ops); 594181614Skmacy}; 595181614Skmacy 596167514Skmacystatic struct port_type_info port_types[] = { 597171471Skmacy { NULL }, 598176472Skmacy { t3_ael1002_phy_prep }, 599176472Skmacy { t3_vsc8211_phy_prep }, 600176472Skmacy { t3_mv88e1xxx_phy_prep }, 601176472Skmacy { t3_xaui_direct_phy_prep }, 602180583Skmacy { t3_ael2005_phy_prep }, 603176472Skmacy { t3_qt2045_phy_prep }, 604176472Skmacy { t3_ael1006_phy_prep }, 605180583Skmacy { t3_tn1010_phy_prep }, 606197791Snp { t3_aq100x_phy_prep }, 607197791Snp { t3_ael2020_phy_prep }, 608167514Skmacy}; 609167514Skmacy 610167514Skmacy#define VPD_ENTRY(name, len) \ 611176472Skmacy u8 name##_kword[2]; u8 name##_len; u8 name##_data[len] 612167514Skmacy 613167514Skmacy/* 614167514Skmacy * Partial EEPROM Vital Product Data structure. Includes only the ID and 615167514Skmacy * VPD-R sections. 616167514Skmacy */ 617167514Skmacystruct t3_vpd { 618167514Skmacy u8 id_tag; 619167514Skmacy u8 id_len[2]; 620167514Skmacy u8 id_data[16]; 621167514Skmacy u8 vpdr_tag; 622167514Skmacy u8 vpdr_len[2]; 623167514Skmacy VPD_ENTRY(pn, 16); /* part number */ 624185157Sgnn VPD_ENTRY(ec, ECNUM_LEN); /* EC level */ 625172096Skmacy VPD_ENTRY(sn, SERNUM_LEN); /* serial number */ 626167514Skmacy VPD_ENTRY(na, 12); /* MAC address base */ 627167514Skmacy VPD_ENTRY(cclk, 6); /* core clock */ 628167514Skmacy VPD_ENTRY(mclk, 6); /* mem clock */ 629167514Skmacy VPD_ENTRY(uclk, 6); /* uP clk */ 630167514Skmacy VPD_ENTRY(mdc, 6); /* MDIO clk */ 631167514Skmacy VPD_ENTRY(mt, 2); /* mem timing */ 632167514Skmacy VPD_ENTRY(xaui0cfg, 6); /* XAUI0 config */ 633167514Skmacy VPD_ENTRY(xaui1cfg, 6); /* XAUI1 config */ 634167514Skmacy VPD_ENTRY(port0, 2); /* PHY0 complex */ 635167514Skmacy VPD_ENTRY(port1, 2); /* PHY1 complex */ 636167514Skmacy VPD_ENTRY(port2, 2); /* PHY2 complex */ 637167514Skmacy VPD_ENTRY(port3, 2); /* PHY3 complex */ 638167514Skmacy VPD_ENTRY(rv, 1); /* csum */ 639167514Skmacy u32 pad; /* for multiple-of-4 sizing and alignment */ 640167514Skmacy}; 641167514Skmacy 642181614Skmacy#define EEPROM_MAX_POLL 40 643167514Skmacy#define EEPROM_STAT_ADDR 0x4000 644167514Skmacy#define VPD_BASE 0xc00 645167514Skmacy 646167514Skmacy/** 647167514Skmacy * t3_seeprom_read - read a VPD EEPROM location 648167514Skmacy * @adapter: adapter to read 649167514Skmacy * @addr: EEPROM address 650167514Skmacy * @data: where to store the read data 651167514Skmacy * 652167514Skmacy * Read a 32-bit word from a location in VPD EEPROM using the card's PCI 653167514Skmacy * VPD ROM capability. A zero is written to the flag bit when the 654298955Spfg * address is written to the control register. The hardware device will 655167514Skmacy * set the flag to 1 when 4 bytes have been read into the data register. 656167514Skmacy */ 657167514Skmacyint t3_seeprom_read(adapter_t *adapter, u32 addr, u32 *data) 658167514Skmacy{ 659167514Skmacy u16 val; 660167514Skmacy int attempts = EEPROM_MAX_POLL; 661167514Skmacy unsigned int base = adapter->params.pci.vpd_cap_addr; 662167514Skmacy 663167514Skmacy if ((addr >= EEPROMSIZE && addr != EEPROM_STAT_ADDR) || (addr & 3)) 664167514Skmacy return -EINVAL; 665167514Skmacy 666167514Skmacy t3_os_pci_write_config_2(adapter, base + PCI_VPD_ADDR, (u16)addr); 667167514Skmacy do { 668167514Skmacy udelay(10); 669167514Skmacy t3_os_pci_read_config_2(adapter, base + PCI_VPD_ADDR, &val); 670167514Skmacy } while (!(val & PCI_VPD_ADDR_F) && --attempts); 671167514Skmacy 672167514Skmacy if (!(val & PCI_VPD_ADDR_F)) { 673167514Skmacy CH_ERR(adapter, "reading EEPROM address 0x%x failed\n", addr); 674167514Skmacy return -EIO; 675167514Skmacy } 676167514Skmacy t3_os_pci_read_config_4(adapter, base + PCI_VPD_DATA, data); 677167514Skmacy *data = le32_to_cpu(*data); 678167514Skmacy return 0; 679167514Skmacy} 680167514Skmacy 681167514Skmacy/** 682167514Skmacy * t3_seeprom_write - write a VPD EEPROM location 683167514Skmacy * @adapter: adapter to write 684167514Skmacy * @addr: EEPROM address 685167514Skmacy * @data: value to write 686167514Skmacy * 687167514Skmacy * Write a 32-bit word to a location in VPD EEPROM using the card's PCI 688167514Skmacy * VPD ROM capability. 689167514Skmacy */ 690167514Skmacyint t3_seeprom_write(adapter_t *adapter, u32 addr, u32 data) 691167514Skmacy{ 692167514Skmacy u16 val; 693167514Skmacy int attempts = EEPROM_MAX_POLL; 694167514Skmacy unsigned int base = adapter->params.pci.vpd_cap_addr; 695167514Skmacy 696167514Skmacy if ((addr >= EEPROMSIZE && addr != EEPROM_STAT_ADDR) || (addr & 3)) 697167514Skmacy return -EINVAL; 698167514Skmacy 699167514Skmacy t3_os_pci_write_config_4(adapter, base + PCI_VPD_DATA, 700167514Skmacy cpu_to_le32(data)); 701167514Skmacy t3_os_pci_write_config_2(adapter, base + PCI_VPD_ADDR, 702167514Skmacy (u16)addr | PCI_VPD_ADDR_F); 703167514Skmacy do { 704171471Skmacy msleep(1); 705167514Skmacy t3_os_pci_read_config_2(adapter, base + PCI_VPD_ADDR, &val); 706167514Skmacy } while ((val & PCI_VPD_ADDR_F) && --attempts); 707167514Skmacy 708167514Skmacy if (val & PCI_VPD_ADDR_F) { 709167514Skmacy CH_ERR(adapter, "write to EEPROM address 0x%x failed\n", addr); 710167514Skmacy return -EIO; 711167514Skmacy } 712167514Skmacy return 0; 713167514Skmacy} 714167514Skmacy 715167514Skmacy/** 716167514Skmacy * t3_seeprom_wp - enable/disable EEPROM write protection 717167514Skmacy * @adapter: the adapter 718167514Skmacy * @enable: 1 to enable write protection, 0 to disable it 719167514Skmacy * 720167514Skmacy * Enables or disables write protection on the serial EEPROM. 721167514Skmacy */ 722167514Skmacyint t3_seeprom_wp(adapter_t *adapter, int enable) 723167514Skmacy{ 724167514Skmacy return t3_seeprom_write(adapter, EEPROM_STAT_ADDR, enable ? 0xc : 0); 725167514Skmacy} 726167514Skmacy 727167514Skmacy/* 728167514Skmacy * Convert a character holding a hex digit to a number. 729167514Skmacy */ 730167514Skmacystatic unsigned int hex2int(unsigned char c) 731167514Skmacy{ 732167514Skmacy return isdigit(c) ? c - '0' : toupper(c) - 'A' + 10; 733167514Skmacy} 734167514Skmacy 735167514Skmacy/** 736197791Snp * get_desc_len - get the length of a vpd descriptor. 737197791Snp * @adapter: the adapter 738197791Snp * @offset: first byte offset of the vpd descriptor 739197791Snp * 740197791Snp * Retrieves the length of the small/large resource 741197791Snp * data type starting at offset. 742197791Snp */ 743197791Snpstatic int get_desc_len(adapter_t *adapter, u32 offset) 744197791Snp{ 745197791Snp u32 read_offset, tmp, shift, len = 0; 746197791Snp u8 tag, buf[8]; 747197791Snp int ret; 748197791Snp 749197791Snp read_offset = offset & 0xfffffffc; 750197791Snp shift = offset & 0x03; 751197791Snp 752197791Snp ret = t3_seeprom_read(adapter, read_offset, &tmp); 753197791Snp if (ret < 0) 754197791Snp return ret; 755197791Snp 756197791Snp *((u32 *)buf) = cpu_to_le32(tmp); 757197791Snp 758197791Snp tag = buf[shift]; 759197791Snp if (tag & 0x80) { 760197791Snp ret = t3_seeprom_read(adapter, read_offset + 4, &tmp); 761197791Snp if (ret < 0) 762197791Snp return ret; 763197791Snp 764197791Snp *((u32 *)(&buf[4])) = cpu_to_le32(tmp); 765197791Snp len = (buf[shift + 1] & 0xff) + 766197791Snp ((buf[shift+2] << 8) & 0xff00) + 3; 767197791Snp } else 768197791Snp len = (tag & 0x07) + 1; 769197791Snp 770197791Snp return len; 771197791Snp} 772197791Snp 773197791Snp/** 774197791Snp * is_end_tag - Check if a vpd tag is the end tag. 775197791Snp * @adapter: the adapter 776197791Snp * @offset: first byte offset of the tag 777197791Snp * 778197791Snp * Checks if the tag located at offset is the end tag. 779197791Snp */ 780197791Snpstatic int is_end_tag(adapter_t * adapter, u32 offset) 781197791Snp{ 782197791Snp u32 read_offset, shift, ret, tmp; 783197791Snp u8 buf[4]; 784197791Snp 785197791Snp read_offset = offset & 0xfffffffc; 786197791Snp shift = offset & 0x03; 787197791Snp 788197791Snp ret = t3_seeprom_read(adapter, read_offset, &tmp); 789197791Snp if (ret) 790197791Snp return ret; 791197791Snp *((u32 *)buf) = cpu_to_le32(tmp); 792197791Snp 793197791Snp if (buf[shift] == 0x78) 794197791Snp return 1; 795197791Snp else 796197791Snp return 0; 797197791Snp} 798197791Snp 799197791Snp/** 800197791Snp * t3_get_vpd_len - computes the length of a vpd structure 801197791Snp * @adapter: the adapter 802197791Snp * @vpd: contains the offset of first byte of vpd 803197791Snp * 804197791Snp * Computes the lentgh of the vpd structure starting at vpd->offset. 805197791Snp */ 806197791Snp 807197791Snpint t3_get_vpd_len(adapter_t * adapter, struct generic_vpd *vpd) 808197791Snp{ 809197791Snp u32 len=0, offset; 810197791Snp int inc, ret; 811197791Snp 812197791Snp offset = vpd->offset; 813197791Snp 814197791Snp while (offset < (vpd->offset + MAX_VPD_BYTES)) { 815197791Snp ret = is_end_tag(adapter, offset); 816197791Snp if (ret < 0) 817197791Snp return ret; 818197791Snp else if (ret == 1) 819197791Snp break; 820197791Snp 821197791Snp inc = get_desc_len(adapter, offset); 822197791Snp if (inc < 0) 823197791Snp return inc; 824197791Snp len += inc; 825197791Snp offset += inc; 826197791Snp } 827197791Snp return (len + 1); 828197791Snp} 829197791Snp 830197791Snp/** 831197791Snp * t3_read_vpd - reads the stream of bytes containing a vpd structure 832197791Snp * @adapter: the adapter 833197791Snp * @vpd: contains a buffer that would hold the stream of bytes 834197791Snp * 835197791Snp * Reads the vpd structure starting at vpd->offset into vpd->data, 836197791Snp * the length of the byte stream to read is vpd->len. 837197791Snp */ 838197791Snp 839197791Snpint t3_read_vpd(adapter_t *adapter, struct generic_vpd *vpd) 840197791Snp{ 841197791Snp u32 i, ret; 842197791Snp 843197791Snp for (i = 0; i < vpd->len; i += 4) { 844197791Snp ret = t3_seeprom_read(adapter, vpd->offset + i, 845197791Snp (u32 *) &(vpd->data[i])); 846197791Snp if (ret) 847197791Snp return ret; 848197791Snp } 849197791Snp 850197791Snp return 0; 851197791Snp} 852197791Snp 853197791Snp 854197791Snp/** 855167514Skmacy * get_vpd_params - read VPD parameters from VPD EEPROM 856167514Skmacy * @adapter: adapter to read 857167514Skmacy * @p: where to store the parameters 858167514Skmacy * 859167514Skmacy * Reads card parameters stored in VPD EEPROM. 860167514Skmacy */ 861167514Skmacystatic int get_vpd_params(adapter_t *adapter, struct vpd_params *p) 862167514Skmacy{ 863167514Skmacy int i, addr, ret; 864167514Skmacy struct t3_vpd vpd; 865167514Skmacy 866167514Skmacy /* 867167514Skmacy * Card information is normally at VPD_BASE but some early cards had 868167514Skmacy * it at 0. 869167514Skmacy */ 870167514Skmacy ret = t3_seeprom_read(adapter, VPD_BASE, (u32 *)&vpd); 871167514Skmacy if (ret) 872167514Skmacy return ret; 873167514Skmacy addr = vpd.id_tag == 0x82 ? VPD_BASE : 0; 874167514Skmacy 875167514Skmacy for (i = 0; i < sizeof(vpd); i += 4) { 876167514Skmacy ret = t3_seeprom_read(adapter, addr + i, 877167514Skmacy (u32 *)((u8 *)&vpd + i)); 878167514Skmacy if (ret) 879167514Skmacy return ret; 880167514Skmacy } 881167514Skmacy 882167514Skmacy p->cclk = simple_strtoul(vpd.cclk_data, NULL, 10); 883167514Skmacy p->mclk = simple_strtoul(vpd.mclk_data, NULL, 10); 884167514Skmacy p->uclk = simple_strtoul(vpd.uclk_data, NULL, 10); 885167514Skmacy p->mdc = simple_strtoul(vpd.mdc_data, NULL, 10); 886167514Skmacy p->mem_timing = simple_strtoul(vpd.mt_data, NULL, 10); 887172096Skmacy memcpy(p->sn, vpd.sn_data, SERNUM_LEN); 888185157Sgnn memcpy(p->ec, vpd.ec_data, ECNUM_LEN); 889167514Skmacy 890167514Skmacy /* Old eeproms didn't have port information */ 891167514Skmacy if (adapter->params.rev == 0 && !vpd.port0_data[0]) { 892167514Skmacy p->port_type[0] = uses_xaui(adapter) ? 1 : 2; 893167514Skmacy p->port_type[1] = uses_xaui(adapter) ? 6 : 2; 894167514Skmacy } else { 895167514Skmacy p->port_type[0] = (u8)hex2int(vpd.port0_data[0]); 896167514Skmacy p->port_type[1] = (u8)hex2int(vpd.port1_data[0]); 897170654Skmacy p->port_type[2] = (u8)hex2int(vpd.port2_data[0]); 898170654Skmacy p->port_type[3] = (u8)hex2int(vpd.port3_data[0]); 899167514Skmacy p->xauicfg[0] = simple_strtoul(vpd.xaui0cfg_data, NULL, 16); 900167514Skmacy p->xauicfg[1] = simple_strtoul(vpd.xaui1cfg_data, NULL, 16); 901167514Skmacy } 902167514Skmacy 903167514Skmacy for (i = 0; i < 6; i++) 904167514Skmacy p->eth_base[i] = hex2int(vpd.na_data[2 * i]) * 16 + 905167514Skmacy hex2int(vpd.na_data[2 * i + 1]); 906167514Skmacy return 0; 907167514Skmacy} 908167514Skmacy 909176472Skmacy/* BIOS boot header */ 910176472Skmacytypedef struct boot_header_s { 911176472Skmacy u8 signature[2]; /* signature */ 912176472Skmacy u8 length; /* image length (include header) */ 913176472Skmacy u8 offset[4]; /* initialization vector */ 914176472Skmacy u8 reserved[19]; /* reserved */ 915176472Skmacy u8 exheader[2]; /* offset to expansion header */ 916176472Skmacy} boot_header_t; 917176472Skmacy 918167514Skmacy/* serial flash and firmware constants */ 919167514Skmacyenum { 920167514Skmacy SF_ATTEMPTS = 5, /* max retries for SF1 operations */ 921167514Skmacy SF_SEC_SIZE = 64 * 1024, /* serial flash sector size */ 922167514Skmacy SF_SIZE = SF_SEC_SIZE * 8, /* serial flash size */ 923167514Skmacy 924167514Skmacy /* flash command opcodes */ 925167514Skmacy SF_PROG_PAGE = 2, /* program page */ 926167514Skmacy SF_WR_DISABLE = 4, /* disable writes */ 927167514Skmacy SF_RD_STATUS = 5, /* read status register */ 928167514Skmacy SF_WR_ENABLE = 6, /* enable writes */ 929167514Skmacy SF_RD_DATA_FAST = 0xb, /* read flash */ 930167514Skmacy SF_ERASE_SECTOR = 0xd8, /* erase sector */ 931167514Skmacy 932167514Skmacy FW_FLASH_BOOT_ADDR = 0x70000, /* start address of FW in flash */ 933184861Skmacy FW_VERS_ADDR = 0x7fffc, /* flash address holding FW version */ 934189643Sgnn FW_VERS_ADDR_PRE8 = 0x77ffc,/* flash address holding FW version pre8 */ 935176472Skmacy FW_MIN_SIZE = 8, /* at least version and csum */ 936176472Skmacy FW_MAX_SIZE = FW_VERS_ADDR - FW_FLASH_BOOT_ADDR, 937189643Sgnn FW_MAX_SIZE_PRE8 = FW_VERS_ADDR_PRE8 - FW_FLASH_BOOT_ADDR, 938176472Skmacy 939176472Skmacy BOOT_FLASH_BOOT_ADDR = 0x0,/* start address of boot image in flash */ 940176472Skmacy BOOT_SIGNATURE = 0xaa55, /* signature of BIOS boot ROM */ 941176472Skmacy BOOT_SIZE_INC = 512, /* image size measured in 512B chunks */ 942176472Skmacy BOOT_MIN_SIZE = sizeof(boot_header_t), /* at least basic header */ 943189643Sgnn BOOT_MAX_SIZE = 1024*BOOT_SIZE_INC /* 1 byte * length increment */ 944167514Skmacy}; 945167514Skmacy 946167514Skmacy/** 947167514Skmacy * sf1_read - read data from the serial flash 948167514Skmacy * @adapter: the adapter 949167514Skmacy * @byte_cnt: number of bytes to read 950167514Skmacy * @cont: whether another operation will be chained 951167514Skmacy * @valp: where to store the read data 952167514Skmacy * 953167514Skmacy * Reads up to 4 bytes of data from the serial flash. The location of 954167514Skmacy * the read needs to be specified prior to calling this by issuing the 955167514Skmacy * appropriate commands to the serial flash. 956167514Skmacy */ 957167514Skmacystatic int sf1_read(adapter_t *adapter, unsigned int byte_cnt, int cont, 958167514Skmacy u32 *valp) 959167514Skmacy{ 960167514Skmacy int ret; 961167514Skmacy 962167514Skmacy if (!byte_cnt || byte_cnt > 4) 963167514Skmacy return -EINVAL; 964167514Skmacy if (t3_read_reg(adapter, A_SF_OP) & F_BUSY) 965167514Skmacy return -EBUSY; 966167514Skmacy t3_write_reg(adapter, A_SF_OP, V_CONT(cont) | V_BYTECNT(byte_cnt - 1)); 967167514Skmacy ret = t3_wait_op_done(adapter, A_SF_OP, F_BUSY, 0, SF_ATTEMPTS, 10); 968167514Skmacy if (!ret) 969167514Skmacy *valp = t3_read_reg(adapter, A_SF_DATA); 970167514Skmacy return ret; 971167514Skmacy} 972167514Skmacy 973167514Skmacy/** 974167514Skmacy * sf1_write - write data to the serial flash 975167514Skmacy * @adapter: the adapter 976167514Skmacy * @byte_cnt: number of bytes to write 977167514Skmacy * @cont: whether another operation will be chained 978167514Skmacy * @val: value to write 979167514Skmacy * 980167514Skmacy * Writes up to 4 bytes of data to the serial flash. The location of 981167514Skmacy * the write needs to be specified prior to calling this by issuing the 982167514Skmacy * appropriate commands to the serial flash. 983167514Skmacy */ 984167514Skmacystatic int sf1_write(adapter_t *adapter, unsigned int byte_cnt, int cont, 985167514Skmacy u32 val) 986167514Skmacy{ 987167514Skmacy if (!byte_cnt || byte_cnt > 4) 988167514Skmacy return -EINVAL; 989167514Skmacy if (t3_read_reg(adapter, A_SF_OP) & F_BUSY) 990167514Skmacy return -EBUSY; 991167514Skmacy t3_write_reg(adapter, A_SF_DATA, val); 992167514Skmacy t3_write_reg(adapter, A_SF_OP, 993167514Skmacy V_CONT(cont) | V_BYTECNT(byte_cnt - 1) | V_OP(1)); 994167514Skmacy return t3_wait_op_done(adapter, A_SF_OP, F_BUSY, 0, SF_ATTEMPTS, 10); 995167514Skmacy} 996167514Skmacy 997167514Skmacy/** 998167514Skmacy * flash_wait_op - wait for a flash operation to complete 999167514Skmacy * @adapter: the adapter 1000167514Skmacy * @attempts: max number of polls of the status register 1001167514Skmacy * @delay: delay between polls in ms 1002167514Skmacy * 1003167514Skmacy * Wait for a flash operation to complete by polling the status register. 1004167514Skmacy */ 1005167514Skmacystatic int flash_wait_op(adapter_t *adapter, int attempts, int delay) 1006167514Skmacy{ 1007167514Skmacy int ret; 1008167514Skmacy u32 status; 1009167514Skmacy 1010167514Skmacy while (1) { 1011167514Skmacy if ((ret = sf1_write(adapter, 1, 1, SF_RD_STATUS)) != 0 || 1012167514Skmacy (ret = sf1_read(adapter, 1, 0, &status)) != 0) 1013167514Skmacy return ret; 1014167514Skmacy if (!(status & 1)) 1015167514Skmacy return 0; 1016167514Skmacy if (--attempts == 0) 1017167514Skmacy return -EAGAIN; 1018167514Skmacy if (delay) 1019171471Skmacy msleep(delay); 1020167514Skmacy } 1021167514Skmacy} 1022167514Skmacy 1023167514Skmacy/** 1024167514Skmacy * t3_read_flash - read words from serial flash 1025167514Skmacy * @adapter: the adapter 1026167514Skmacy * @addr: the start address for the read 1027167514Skmacy * @nwords: how many 32-bit words to read 1028167514Skmacy * @data: where to store the read data 1029167514Skmacy * @byte_oriented: whether to store data as bytes or as words 1030167514Skmacy * 1031167514Skmacy * Read the specified number of 32-bit words from the serial flash. 1032167514Skmacy * If @byte_oriented is set the read data is stored as a byte array 1033167514Skmacy * (i.e., big-endian), otherwise as 32-bit words in the platform's 1034298955Spfg * natural endianness. 1035167514Skmacy */ 1036167514Skmacyint t3_read_flash(adapter_t *adapter, unsigned int addr, unsigned int nwords, 1037167514Skmacy u32 *data, int byte_oriented) 1038167514Skmacy{ 1039167514Skmacy int ret; 1040167514Skmacy 1041167514Skmacy if (addr + nwords * sizeof(u32) > SF_SIZE || (addr & 3)) 1042167514Skmacy return -EINVAL; 1043167514Skmacy 1044167514Skmacy addr = swab32(addr) | SF_RD_DATA_FAST; 1045167514Skmacy 1046167514Skmacy if ((ret = sf1_write(adapter, 4, 1, addr)) != 0 || 1047167514Skmacy (ret = sf1_read(adapter, 1, 1, data)) != 0) 1048167514Skmacy return ret; 1049167514Skmacy 1050167514Skmacy for ( ; nwords; nwords--, data++) { 1051167514Skmacy ret = sf1_read(adapter, 4, nwords > 1, data); 1052167514Skmacy if (ret) 1053167514Skmacy return ret; 1054167514Skmacy if (byte_oriented) 1055167514Skmacy *data = htonl(*data); 1056167514Skmacy } 1057167514Skmacy return 0; 1058167514Skmacy} 1059167514Skmacy 1060167514Skmacy/** 1061167514Skmacy * t3_write_flash - write up to a page of data to the serial flash 1062167514Skmacy * @adapter: the adapter 1063167514Skmacy * @addr: the start address to write 1064167514Skmacy * @n: length of data to write 1065167514Skmacy * @data: the data to write 1066176472Skmacy * @byte_oriented: whether to store data as bytes or as words 1067167514Skmacy * 1068167514Skmacy * Writes up to a page of data (256 bytes) to the serial flash starting 1069167514Skmacy * at the given address. 1070176472Skmacy * If @byte_oriented is set the write data is stored as a 32-bit 1071298955Spfg * big-endian array, otherwise in the processor's native endianness. 1072189643Sgnn * 1073167514Skmacy */ 1074167514Skmacystatic int t3_write_flash(adapter_t *adapter, unsigned int addr, 1075176472Skmacy unsigned int n, const u8 *data, 1076176472Skmacy int byte_oriented) 1077167514Skmacy{ 1078167514Skmacy int ret; 1079167514Skmacy u32 buf[64]; 1080176472Skmacy unsigned int c, left, val, offset = addr & 0xff; 1081167514Skmacy 1082167514Skmacy if (addr + n > SF_SIZE || offset + n > 256) 1083167514Skmacy return -EINVAL; 1084167514Skmacy 1085167514Skmacy val = swab32(addr) | SF_PROG_PAGE; 1086167514Skmacy 1087167514Skmacy if ((ret = sf1_write(adapter, 1, 0, SF_WR_ENABLE)) != 0 || 1088167514Skmacy (ret = sf1_write(adapter, 4, 1, val)) != 0) 1089167514Skmacy return ret; 1090167514Skmacy 1091167514Skmacy for (left = n; left; left -= c) { 1092167514Skmacy c = min(left, 4U); 1093176472Skmacy val = *(const u32*)data; 1094176472Skmacy data += c; 1095176472Skmacy if (byte_oriented) 1096176472Skmacy val = htonl(val); 1097167514Skmacy 1098167514Skmacy ret = sf1_write(adapter, c, c != left, val); 1099167514Skmacy if (ret) 1100167514Skmacy return ret; 1101167514Skmacy } 1102167514Skmacy if ((ret = flash_wait_op(adapter, 5, 1)) != 0) 1103167514Skmacy return ret; 1104167514Skmacy 1105167514Skmacy /* Read the page to verify the write succeeded */ 1106176472Skmacy ret = t3_read_flash(adapter, addr & ~0xff, ARRAY_SIZE(buf), buf, 1107176472Skmacy byte_oriented); 1108167514Skmacy if (ret) 1109167514Skmacy return ret; 1110167514Skmacy 1111167514Skmacy if (memcmp(data - n, (u8 *)buf + offset, n)) 1112167514Skmacy return -EIO; 1113167514Skmacy return 0; 1114167514Skmacy} 1115167514Skmacy 1116170654Skmacy/** 1117171471Skmacy * t3_get_tp_version - read the tp sram version 1118171471Skmacy * @adapter: the adapter 1119171471Skmacy * @vers: where to place the version 1120171471Skmacy * 1121171471Skmacy * Reads the protocol sram version from sram. 1122171471Skmacy */ 1123171471Skmacyint t3_get_tp_version(adapter_t *adapter, u32 *vers) 1124171471Skmacy{ 1125171471Skmacy int ret; 1126171471Skmacy 1127171471Skmacy /* Get version loaded in SRAM */ 1128171471Skmacy t3_write_reg(adapter, A_TP_EMBED_OP_FIELD0, 0); 1129171471Skmacy ret = t3_wait_op_done(adapter, A_TP_EMBED_OP_FIELD0, 1130171471Skmacy 1, 1, 5, 1); 1131171471Skmacy if (ret) 1132171471Skmacy return ret; 1133189643Sgnn 1134171471Skmacy *vers = t3_read_reg(adapter, A_TP_EMBED_OP_FIELD1); 1135171471Skmacy 1136171471Skmacy return 0; 1137171471Skmacy} 1138171471Skmacy 1139171471Skmacy/** 1140170654Skmacy * t3_check_tpsram_version - read the tp sram version 1141170654Skmacy * @adapter: the adapter 1142170654Skmacy * 1143170654Skmacy */ 1144189643Sgnnint t3_check_tpsram_version(adapter_t *adapter) 1145170654Skmacy{ 1146170654Skmacy int ret; 1147170654Skmacy u32 vers; 1148170654Skmacy unsigned int major, minor; 1149170654Skmacy 1150176472Skmacy if (adapter->params.rev == T3_REV_A) 1151176472Skmacy return 0; 1152176472Skmacy 1153176472Skmacy 1154176472Skmacy ret = t3_get_tp_version(adapter, &vers); 1155170654Skmacy if (ret) 1156170654Skmacy return ret; 1157189643Sgnn 1158170654Skmacy vers = t3_read_reg(adapter, A_TP_EMBED_OP_FIELD1); 1159170654Skmacy 1160170654Skmacy major = G_TP_VERSION_MAJOR(vers); 1161170654Skmacy minor = G_TP_VERSION_MINOR(vers); 1162170654Skmacy 1163189643Sgnn if (major == TP_VERSION_MAJOR && minor == TP_VERSION_MINOR) 1164170654Skmacy return 0; 1165176472Skmacy else { 1166176472Skmacy CH_ERR(adapter, "found wrong TP version (%u.%u), " 1167176472Skmacy "driver compiled for version %d.%d\n", major, minor, 1168176472Skmacy TP_VERSION_MAJOR, TP_VERSION_MINOR); 1169176472Skmacy } 1170170654Skmacy return -EINVAL; 1171170654Skmacy} 1172170654Skmacy 1173170654Skmacy/** 1174189643Sgnn * t3_check_tpsram - check if provided protocol SRAM 1175170654Skmacy * is compatible with this driver 1176170654Skmacy * @adapter: the adapter 1177170654Skmacy * @tp_sram: the firmware image to write 1178170654Skmacy * @size: image size 1179170654Skmacy * 1180170654Skmacy * Checks if an adapter's tp sram is compatible with the driver. 1181170654Skmacy * Returns 0 if the versions are compatible, a negative error otherwise. 1182170654Skmacy */ 1183171471Skmacyint t3_check_tpsram(adapter_t *adapter, const u8 *tp_sram, unsigned int size) 1184170654Skmacy{ 1185170654Skmacy u32 csum; 1186170654Skmacy unsigned int i; 1187170654Skmacy const u32 *p = (const u32 *)tp_sram; 1188170654Skmacy 1189170654Skmacy /* Verify checksum */ 1190170654Skmacy for (csum = 0, i = 0; i < size / sizeof(csum); i++) 1191170654Skmacy csum += ntohl(p[i]); 1192170654Skmacy if (csum != 0xffffffff) { 1193170654Skmacy CH_ERR(adapter, "corrupted protocol SRAM image, checksum %u\n", 1194170654Skmacy csum); 1195170654Skmacy return -EINVAL; 1196170654Skmacy } 1197170654Skmacy 1198170654Skmacy return 0; 1199170654Skmacy} 1200170654Skmacy 1201167514Skmacyenum fw_version_type { 1202167514Skmacy FW_VERSION_N3, 1203167514Skmacy FW_VERSION_T3 1204167514Skmacy}; 1205167514Skmacy 1206167514Skmacy/** 1207167514Skmacy * t3_get_fw_version - read the firmware version 1208167514Skmacy * @adapter: the adapter 1209167514Skmacy * @vers: where to place the version 1210167514Skmacy * 1211189643Sgnn * Reads the FW version from flash. Note that we had to move the version 1212189643Sgnn * due to FW size. If we don't find a valid FW version in the new location 1213189643Sgnn * we fall back and read the old location. 1214167514Skmacy */ 1215167514Skmacyint t3_get_fw_version(adapter_t *adapter, u32 *vers) 1216167514Skmacy{ 1217184861Skmacy int ret = t3_read_flash(adapter, FW_VERS_ADDR, 1, vers, 0); 1218184861Skmacy if (!ret && *vers != 0xffffffff) 1219184861Skmacy return 0; 1220184861Skmacy else 1221189643Sgnn return t3_read_flash(adapter, FW_VERS_ADDR_PRE8, 1, vers, 0); 1222167514Skmacy} 1223167514Skmacy 1224167514Skmacy/** 1225167514Skmacy * t3_check_fw_version - check if the FW is compatible with this driver 1226167514Skmacy * @adapter: the adapter 1227167514Skmacy * 1228167514Skmacy * Checks if an adapter's FW is compatible with the driver. Returns 0 1229167514Skmacy * if the versions are compatible, a negative error otherwise. 1230167514Skmacy */ 1231189643Sgnnint t3_check_fw_version(adapter_t *adapter) 1232167514Skmacy{ 1233167514Skmacy int ret; 1234167514Skmacy u32 vers; 1235167514Skmacy unsigned int type, major, minor; 1236167514Skmacy 1237167514Skmacy ret = t3_get_fw_version(adapter, &vers); 1238167514Skmacy if (ret) 1239167514Skmacy return ret; 1240167514Skmacy 1241167514Skmacy type = G_FW_VERSION_TYPE(vers); 1242167514Skmacy major = G_FW_VERSION_MAJOR(vers); 1243167514Skmacy minor = G_FW_VERSION_MINOR(vers); 1244167514Skmacy 1245167746Skmacy if (type == FW_VERSION_T3 && major == FW_VERSION_MAJOR && 1246167746Skmacy minor == FW_VERSION_MINOR) 1247167514Skmacy return 0; 1248167514Skmacy 1249189643Sgnn else if (major != FW_VERSION_MAJOR || minor < FW_VERSION_MINOR) 1250176472Skmacy CH_WARN(adapter, "found old FW minor version(%u.%u), " 1251176472Skmacy "driver compiled for version %u.%u\n", major, minor, 1252176472Skmacy FW_VERSION_MAJOR, FW_VERSION_MINOR); 1253189643Sgnn else { 1254176472Skmacy CH_WARN(adapter, "found newer FW version(%u.%u), " 1255176472Skmacy "driver compiled for version %u.%u\n", major, minor, 1256176472Skmacy FW_VERSION_MAJOR, FW_VERSION_MINOR); 1257176472Skmacy return 0; 1258176472Skmacy } 1259167514Skmacy return -EINVAL; 1260167514Skmacy} 1261167514Skmacy 1262167514Skmacy/** 1263167514Skmacy * t3_flash_erase_sectors - erase a range of flash sectors 1264167514Skmacy * @adapter: the adapter 1265167514Skmacy * @start: the first sector to erase 1266167514Skmacy * @end: the last sector to erase 1267167514Skmacy * 1268167514Skmacy * Erases the sectors in the given range. 1269167514Skmacy */ 1270167514Skmacystatic int t3_flash_erase_sectors(adapter_t *adapter, int start, int end) 1271167514Skmacy{ 1272167514Skmacy while (start <= end) { 1273167514Skmacy int ret; 1274167514Skmacy 1275167514Skmacy if ((ret = sf1_write(adapter, 1, 0, SF_WR_ENABLE)) != 0 || 1276167514Skmacy (ret = sf1_write(adapter, 4, 0, 1277167514Skmacy SF_ERASE_SECTOR | (start << 8))) != 0 || 1278167514Skmacy (ret = flash_wait_op(adapter, 5, 500)) != 0) 1279167514Skmacy return ret; 1280167514Skmacy start++; 1281167514Skmacy } 1282167514Skmacy return 0; 1283167514Skmacy} 1284167514Skmacy 1285167514Skmacy/* 1286167514Skmacy * t3_load_fw - download firmware 1287167514Skmacy * @adapter: the adapter 1288170654Skmacy * @fw_data: the firmware image to write 1289167514Skmacy * @size: image size 1290167514Skmacy * 1291167514Skmacy * Write the supplied firmware image to the card's serial flash. 1292167514Skmacy * The FW image has the following sections: @size - 8 bytes of code and 1293167514Skmacy * data, followed by 4 bytes of FW version, followed by the 32-bit 1294167514Skmacy * 1's complement checksum of the whole image. 1295167514Skmacy */ 1296167514Skmacyint t3_load_fw(adapter_t *adapter, const u8 *fw_data, unsigned int size) 1297167514Skmacy{ 1298189643Sgnn u32 version, csum, fw_version_addr; 1299167514Skmacy unsigned int i; 1300167514Skmacy const u32 *p = (const u32 *)fw_data; 1301167514Skmacy int ret, addr, fw_sector = FW_FLASH_BOOT_ADDR >> 16; 1302167514Skmacy 1303170654Skmacy if ((size & 3) || size < FW_MIN_SIZE) 1304167514Skmacy return -EINVAL; 1305176472Skmacy if (size - 8 > FW_MAX_SIZE) 1306167514Skmacy return -EFBIG; 1307167514Skmacy 1308189643Sgnn version = ntohl(*(const u32 *)(fw_data + size - 8)); 1309189643Sgnn if (G_FW_VERSION_MAJOR(version) < 8) { 1310189643Sgnn 1311189643Sgnn fw_version_addr = FW_VERS_ADDR_PRE8; 1312189643Sgnn 1313189643Sgnn if (size - 8 > FW_MAX_SIZE_PRE8) 1314189643Sgnn return -EFBIG; 1315189643Sgnn } else 1316189643Sgnn fw_version_addr = FW_VERS_ADDR; 1317189643Sgnn 1318167514Skmacy for (csum = 0, i = 0; i < size / sizeof(csum); i++) 1319167514Skmacy csum += ntohl(p[i]); 1320167514Skmacy if (csum != 0xffffffff) { 1321167514Skmacy CH_ERR(adapter, "corrupted firmware image, checksum %u\n", 1322167514Skmacy csum); 1323167514Skmacy return -EINVAL; 1324167514Skmacy } 1325167514Skmacy 1326167514Skmacy ret = t3_flash_erase_sectors(adapter, fw_sector, fw_sector); 1327167514Skmacy if (ret) 1328167514Skmacy goto out; 1329167514Skmacy 1330167514Skmacy size -= 8; /* trim off version and checksum */ 1331167514Skmacy for (addr = FW_FLASH_BOOT_ADDR; size; ) { 1332167514Skmacy unsigned int chunk_size = min(size, 256U); 1333167514Skmacy 1334176472Skmacy ret = t3_write_flash(adapter, addr, chunk_size, fw_data, 1); 1335167514Skmacy if (ret) 1336167514Skmacy goto out; 1337167514Skmacy 1338167514Skmacy addr += chunk_size; 1339167514Skmacy fw_data += chunk_size; 1340167514Skmacy size -= chunk_size; 1341167514Skmacy } 1342167514Skmacy 1343189643Sgnn ret = t3_write_flash(adapter, fw_version_addr, 4, fw_data, 1); 1344167514Skmacyout: 1345167514Skmacy if (ret) 1346167514Skmacy CH_ERR(adapter, "firmware download failed, error %d\n", ret); 1347167514Skmacy return ret; 1348167514Skmacy} 1349167514Skmacy 1350176472Skmacy/* 1351176472Skmacy * t3_load_boot - download boot flash 1352176472Skmacy * @adapter: the adapter 1353176472Skmacy * @boot_data: the boot image to write 1354176472Skmacy * @size: image size 1355176472Skmacy * 1356176472Skmacy * Write the supplied boot image to the card's serial flash. 1357176472Skmacy * The boot image has the following sections: a 28-byte header and the 1358176472Skmacy * boot image. 1359176472Skmacy */ 1360176472Skmacyint t3_load_boot(adapter_t *adapter, u8 *boot_data, unsigned int size) 1361176472Skmacy{ 1362176472Skmacy boot_header_t *header = (boot_header_t *)boot_data; 1363176472Skmacy int ret; 1364176472Skmacy unsigned int addr; 1365176472Skmacy unsigned int boot_sector = BOOT_FLASH_BOOT_ADDR >> 16; 1366176472Skmacy unsigned int boot_end = (BOOT_FLASH_BOOT_ADDR + size - 1) >> 16; 1367176472Skmacy 1368176472Skmacy /* 1369176472Skmacy * Perform some primitive sanity testing to avoid accidentally 1370176472Skmacy * writing garbage over the boot sectors. We ought to check for 1371176472Skmacy * more but it's not worth it for now ... 1372176472Skmacy */ 1373176472Skmacy if (size < BOOT_MIN_SIZE || size > BOOT_MAX_SIZE) { 1374176472Skmacy CH_ERR(adapter, "boot image too small/large\n"); 1375176472Skmacy return -EFBIG; 1376176472Skmacy } 1377176472Skmacy if (le16_to_cpu(*(u16*)header->signature) != BOOT_SIGNATURE) { 1378176472Skmacy CH_ERR(adapter, "boot image missing signature\n"); 1379176472Skmacy return -EINVAL; 1380176472Skmacy } 1381176472Skmacy if (header->length * BOOT_SIZE_INC != size) { 1382176472Skmacy CH_ERR(adapter, "boot image header length != image length\n"); 1383176472Skmacy return -EINVAL; 1384176472Skmacy } 1385176472Skmacy 1386176472Skmacy ret = t3_flash_erase_sectors(adapter, boot_sector, boot_end); 1387176472Skmacy if (ret) 1388176472Skmacy goto out; 1389176472Skmacy 1390176472Skmacy for (addr = BOOT_FLASH_BOOT_ADDR; size; ) { 1391176472Skmacy unsigned int chunk_size = min(size, 256U); 1392176472Skmacy 1393176472Skmacy ret = t3_write_flash(adapter, addr, chunk_size, boot_data, 0); 1394176472Skmacy if (ret) 1395176472Skmacy goto out; 1396176472Skmacy 1397176472Skmacy addr += chunk_size; 1398176472Skmacy boot_data += chunk_size; 1399176472Skmacy size -= chunk_size; 1400176472Skmacy } 1401176472Skmacy 1402176472Skmacyout: 1403176472Skmacy if (ret) 1404176472Skmacy CH_ERR(adapter, "boot image download failed, error %d\n", ret); 1405176472Skmacy return ret; 1406176472Skmacy} 1407176472Skmacy 1408167514Skmacy#define CIM_CTL_BASE 0x2000 1409167514Skmacy 1410167514Skmacy/** 1411167514Skmacy * t3_cim_ctl_blk_read - read a block from CIM control region 1412167514Skmacy * @adap: the adapter 1413167514Skmacy * @addr: the start address within the CIM control region 1414167514Skmacy * @n: number of words to read 1415167514Skmacy * @valp: where to store the result 1416167514Skmacy * 1417167514Skmacy * Reads a block of 4-byte words from the CIM control region. 1418167514Skmacy */ 1419167514Skmacyint t3_cim_ctl_blk_read(adapter_t *adap, unsigned int addr, unsigned int n, 1420167514Skmacy unsigned int *valp) 1421167514Skmacy{ 1422167514Skmacy int ret = 0; 1423167514Skmacy 1424167514Skmacy if (t3_read_reg(adap, A_CIM_HOST_ACC_CTRL) & F_HOSTBUSY) 1425167514Skmacy return -EBUSY; 1426167514Skmacy 1427167514Skmacy for ( ; !ret && n--; addr += 4) { 1428167514Skmacy t3_write_reg(adap, A_CIM_HOST_ACC_CTRL, CIM_CTL_BASE + addr); 1429167514Skmacy ret = t3_wait_op_done(adap, A_CIM_HOST_ACC_CTRL, F_HOSTBUSY, 1430167514Skmacy 0, 5, 2); 1431167514Skmacy if (!ret) 1432167514Skmacy *valp++ = t3_read_reg(adap, A_CIM_HOST_ACC_DATA); 1433167514Skmacy } 1434167514Skmacy return ret; 1435167514Skmacy} 1436167514Skmacy 1437189643Sgnnstatic void t3_gate_rx_traffic(struct cmac *mac, u32 *rx_cfg, 1438189643Sgnn u32 *rx_hash_high, u32 *rx_hash_low) 1439189643Sgnn{ 1440189643Sgnn /* stop Rx unicast traffic */ 1441189643Sgnn t3_mac_disable_exact_filters(mac); 1442189643Sgnn 1443189643Sgnn /* stop broadcast, multicast, promiscuous mode traffic */ 1444212710Snp *rx_cfg = t3_read_reg(mac->adapter, A_XGM_RX_CFG + mac->offset); 1445212710Snp t3_set_reg_field(mac->adapter, A_XGM_RX_CFG + mac->offset, 1446189643Sgnn F_ENHASHMCAST | F_DISBCAST | F_COPYALLFRAMES, 1447189643Sgnn F_DISBCAST); 1448189643Sgnn 1449212710Snp *rx_hash_high = t3_read_reg(mac->adapter, A_XGM_RX_HASH_HIGH + 1450212710Snp mac->offset); 1451212710Snp t3_write_reg(mac->adapter, A_XGM_RX_HASH_HIGH + mac->offset, 0); 1452189643Sgnn 1453212710Snp *rx_hash_low = t3_read_reg(mac->adapter, A_XGM_RX_HASH_LOW + 1454212710Snp mac->offset); 1455212710Snp t3_write_reg(mac->adapter, A_XGM_RX_HASH_LOW + mac->offset, 0); 1456189643Sgnn 1457189643Sgnn /* Leave time to drain max RX fifo */ 1458189643Sgnn msleep(1); 1459189643Sgnn} 1460189643Sgnn 1461189643Sgnnstatic void t3_open_rx_traffic(struct cmac *mac, u32 rx_cfg, 1462189643Sgnn u32 rx_hash_high, u32 rx_hash_low) 1463189643Sgnn{ 1464189643Sgnn t3_mac_enable_exact_filters(mac); 1465212710Snp t3_set_reg_field(mac->adapter, A_XGM_RX_CFG + mac->offset, 1466189643Sgnn F_ENHASHMCAST | F_DISBCAST | F_COPYALLFRAMES, 1467189643Sgnn rx_cfg); 1468212710Snp t3_write_reg(mac->adapter, A_XGM_RX_HASH_HIGH + mac->offset, 1469212710Snp rx_hash_high); 1470212710Snp t3_write_reg(mac->adapter, A_XGM_RX_HASH_LOW + mac->offset, 1471212710Snp rx_hash_low); 1472189643Sgnn} 1473189643Sgnn 1474192540Sgnnstatic int t3_detect_link_fault(adapter_t *adapter, int port_id) 1475192540Sgnn{ 1476192540Sgnn struct port_info *pi = adap2pinfo(adapter, port_id); 1477192540Sgnn struct cmac *mac = &pi->mac; 1478192540Sgnn uint32_t rx_cfg, rx_hash_high, rx_hash_low; 1479192540Sgnn int link_fault; 1480192540Sgnn 1481192540Sgnn /* stop rx */ 1482192540Sgnn t3_gate_rx_traffic(mac, &rx_cfg, &rx_hash_high, &rx_hash_low); 1483192540Sgnn t3_write_reg(adapter, A_XGM_RX_CTRL + mac->offset, 0); 1484192540Sgnn 1485192540Sgnn /* clear status and make sure intr is enabled */ 1486192540Sgnn (void) t3_read_reg(adapter, A_XGM_INT_STATUS + mac->offset); 1487192540Sgnn t3_xgm_intr_enable(adapter, port_id); 1488192540Sgnn 1489192540Sgnn /* restart rx */ 1490192540Sgnn t3_write_reg(adapter, A_XGM_RX_CTRL + mac->offset, F_RXEN); 1491192540Sgnn t3_open_rx_traffic(mac, rx_cfg, rx_hash_high, rx_hash_low); 1492192540Sgnn 1493192540Sgnn link_fault = t3_read_reg(adapter, A_XGM_INT_STATUS + mac->offset); 1494192540Sgnn return (link_fault & F_LINKFAULTCHANGE ? 1 : 0); 1495192540Sgnn} 1496192540Sgnn 1497192540Sgnnstatic void t3_clear_faults(adapter_t *adapter, int port_id) 1498192540Sgnn{ 1499192540Sgnn struct port_info *pi = adap2pinfo(adapter, port_id); 1500192540Sgnn struct cmac *mac = &pi->mac; 1501192540Sgnn 1502192540Sgnn if (adapter->params.nports <= 2) { 1503192540Sgnn t3_xgm_intr_disable(adapter, pi->port_id); 1504192540Sgnn t3_read_reg(adapter, A_XGM_INT_STATUS + mac->offset); 1505192540Sgnn t3_write_reg(adapter, A_XGM_INT_CAUSE + mac->offset, F_XGM_INT); 1506192540Sgnn t3_set_reg_field(adapter, A_XGM_INT_ENABLE + mac->offset, 1507192540Sgnn F_XGM_INT, F_XGM_INT); 1508192540Sgnn t3_xgm_intr_enable(adapter, pi->port_id); 1509192540Sgnn } 1510192540Sgnn} 1511192540Sgnn 1512167514Skmacy/** 1513167514Skmacy * t3_link_changed - handle interface link changes 1514167514Skmacy * @adapter: the adapter 1515167514Skmacy * @port_id: the port index that changed link state 1516167514Skmacy * 1517167514Skmacy * Called when a port's link settings change to propagate the new values 1518167514Skmacy * to the associated PHY and MAC. After performing the common tasks it 1519167514Skmacy * invokes an OS-specific handler. 1520167514Skmacy */ 1521167514Skmacyvoid t3_link_changed(adapter_t *adapter, int port_id) 1522167514Skmacy{ 1523276959Snp int link_ok, speed, duplex, fc, link_fault, link_state; 1524170654Skmacy struct port_info *pi = adap2pinfo(adapter, port_id); 1525170654Skmacy struct cphy *phy = &pi->phy; 1526170654Skmacy struct cmac *mac = &pi->mac; 1527170654Skmacy struct link_config *lc = &pi->link_config; 1528167514Skmacy 1529192540Sgnn link_ok = lc->link_ok; 1530192540Sgnn speed = lc->speed; 1531192540Sgnn duplex = lc->duplex; 1532192540Sgnn fc = lc->fc; 1533192540Sgnn link_fault = 0; 1534192540Sgnn 1535276959Snp phy->ops->get_link_status(phy, &link_state, &speed, &duplex, &fc); 1536276959Snp link_ok = (link_state == PHY_LINK_UP); 1537276959Snp if (link_state != PHY_LINK_PARTIAL) 1538276959Snp phy->rst = 0; 1539276959Snp else if (++phy->rst == 3) { 1540276959Snp phy->ops->reset(phy, 0); 1541276959Snp phy->rst = 0; 1542276959Snp } 1543167514Skmacy 1544209841Snp if (link_ok == 0) 1545209841Snp pi->link_fault = LF_NO; 1546209841Snp 1547197791Snp if (lc->requested_fc & PAUSE_AUTONEG) 1548197791Snp fc &= lc->requested_fc; 1549197791Snp else 1550197791Snp fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX); 1551197791Snp 1552197791Snp /* Update mac speed before checking for link fault. */ 1553197791Snp if (link_ok && speed >= 0 && lc->autoneg == AUTONEG_ENABLE && 1554197791Snp (speed != lc->speed || duplex != lc->duplex || fc != lc->fc)) 1555197791Snp t3_mac_set_speed_duplex_fc(mac, speed, duplex, fc); 1556197791Snp 1557192540Sgnn /* 1558192540Sgnn * Check for link faults if any of these is true: 1559192540Sgnn * a) A link fault is suspected, and PHY says link ok 1560192540Sgnn * b) PHY link transitioned from down -> up 1561192540Sgnn */ 1562192540Sgnn if (adapter->params.nports <= 2 && 1563192540Sgnn ((pi->link_fault && link_ok) || (!lc->link_ok && link_ok))) { 1564189643Sgnn 1565192540Sgnn link_fault = t3_detect_link_fault(adapter, port_id); 1566192540Sgnn if (link_fault) { 1567192540Sgnn if (pi->link_fault != LF_YES) { 1568192540Sgnn mac->stats.link_faults++; 1569192540Sgnn pi->link_fault = LF_YES; 1570192540Sgnn } 1571189643Sgnn 1572211346Snp if (uses_xaui(adapter)) { 1573211346Snp if (adapter->params.rev >= T3_REV_C) 1574211346Snp t3c_pcs_force_los(mac); 1575211346Snp else 1576211346Snp t3b_pcs_reset(mac); 1577211346Snp } 1578211346Snp 1579197791Snp /* Don't report link up */ 1580192540Sgnn link_ok = 0; 1581192540Sgnn } else { 1582192540Sgnn /* clear faults here if this was a false alarm. */ 1583192540Sgnn if (pi->link_fault == LF_MAYBE && 1584192540Sgnn link_ok && lc->link_ok) 1585192540Sgnn t3_clear_faults(adapter, port_id); 1586189643Sgnn 1587192540Sgnn pi->link_fault = LF_NO; 1588189643Sgnn } 1589189643Sgnn } 1590189643Sgnn 1591180583Skmacy if (link_ok == lc->link_ok && speed == lc->speed && 1592180583Skmacy duplex == lc->duplex && fc == lc->fc) 1593180583Skmacy return; /* nothing changed */ 1594180583Skmacy 1595167514Skmacy lc->link_ok = (unsigned char)link_ok; 1596167514Skmacy lc->speed = speed < 0 ? SPEED_INVALID : speed; 1597167514Skmacy lc->duplex = duplex < 0 ? DUPLEX_INVALID : duplex; 1598197791Snp lc->fc = fc; 1599167514Skmacy 1600192540Sgnn if (link_ok) { 1601167514Skmacy 1602192540Sgnn /* down -> up, or up -> up with changed settings */ 1603167514Skmacy 1604197791Snp if (adapter->params.rev > 0 && uses_xaui(adapter)) { 1605211346Snp 1606211346Snp if (adapter->params.rev >= T3_REV_C) 1607211346Snp t3c_pcs_force_los(mac); 1608211346Snp else 1609211346Snp t3b_pcs_reset(mac); 1610211346Snp 1611192540Sgnn t3_write_reg(adapter, A_XGM_XAUI_ACT_CTRL + mac->offset, 1612192540Sgnn F_TXACTENABLE | F_RXEN); 1613192540Sgnn } 1614189643Sgnn 1615211346Snp /* disable TX FIFO drain */ 1616197791Snp t3_set_reg_field(adapter, A_XGM_TXFIFO_CFG + mac->offset, 1617197791Snp F_ENDROPPKT, 0); 1618211346Snp 1619197791Snp t3_mac_enable(mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX); 1620197791Snp t3_set_reg_field(adapter, A_XGM_STAT_CTRL + mac->offset, 1621197791Snp F_CLRSTATS, 1); 1622192540Sgnn t3_clear_faults(adapter, port_id); 1623189643Sgnn 1624192540Sgnn } else { 1625189643Sgnn 1626192540Sgnn /* up -> down */ 1627189643Sgnn 1628192540Sgnn if (adapter->params.rev > 0 && uses_xaui(adapter)) { 1629192540Sgnn t3_write_reg(adapter, 1630192540Sgnn A_XGM_XAUI_ACT_CTRL + mac->offset, 0); 1631192540Sgnn } 1632189643Sgnn 1633192540Sgnn t3_xgm_intr_disable(adapter, pi->port_id); 1634192540Sgnn if (adapter->params.nports <= 2) { 1635192540Sgnn t3_set_reg_field(adapter, 1636192540Sgnn A_XGM_INT_ENABLE + mac->offset, 1637192540Sgnn F_XGM_INT, 0); 1638189643Sgnn 1639192540Sgnn t3_mac_disable(mac, MAC_DIRECTION_RX); 1640189643Sgnn 1641211346Snp /* 1642211346Snp * Make sure Tx FIFO continues to drain, even as rxen is 1643211346Snp * left high to help detect and indicate remote faults. 1644211346Snp */ 1645211346Snp t3_set_reg_field(adapter, 1646211346Snp A_XGM_TXFIFO_CFG + mac->offset, 0, F_ENDROPPKT); 1647211346Snp t3_write_reg(adapter, A_XGM_RX_CTRL + mac->offset, 0); 1648211346Snp t3_write_reg(adapter, 1649211346Snp A_XGM_TX_CTRL + mac->offset, F_TXEN); 1650211346Snp t3_write_reg(adapter, 1651211346Snp A_XGM_RX_CTRL + mac->offset, F_RXEN); 1652211346Snp } 1653192540Sgnn } 1654189643Sgnn 1655197791Snp t3_os_link_changed(adapter, port_id, link_ok, speed, duplex, fc, 1656197791Snp mac->was_reset); 1657197791Snp mac->was_reset = 0; 1658189643Sgnn} 1659189643Sgnn 1660167514Skmacy/** 1661167514Skmacy * t3_link_start - apply link configuration to MAC/PHY 1662167514Skmacy * @phy: the PHY to setup 1663167514Skmacy * @mac: the MAC to setup 1664167514Skmacy * @lc: the requested link configuration 1665167514Skmacy * 1666167514Skmacy * Set up a port's MAC and PHY according to a desired link configuration. 1667167514Skmacy * - If the PHY can auto-negotiate first decide what to advertise, then 1668167514Skmacy * enable/disable auto-negotiation as desired, and reset. 1669167514Skmacy * - If the PHY does not auto-negotiate just reset it. 1670167514Skmacy * - If auto-negotiation is off set the MAC to the proper speed/duplex/FC, 1671167514Skmacy * otherwise do it later based on the outcome of auto-negotiation. 1672167514Skmacy */ 1673167514Skmacyint t3_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc) 1674167514Skmacy{ 1675167514Skmacy unsigned int fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX); 1676167514Skmacy 1677167514Skmacy lc->link_ok = 0; 1678167514Skmacy if (lc->supported & SUPPORTED_Autoneg) { 1679167514Skmacy lc->advertising &= ~(ADVERTISED_Asym_Pause | ADVERTISED_Pause); 1680167514Skmacy if (fc) { 1681167514Skmacy lc->advertising |= ADVERTISED_Asym_Pause; 1682167514Skmacy if (fc & PAUSE_RX) 1683167514Skmacy lc->advertising |= ADVERTISED_Pause; 1684167514Skmacy } 1685197791Snp 1686167514Skmacy phy->ops->advertise(phy, lc->advertising); 1687167514Skmacy 1688167514Skmacy if (lc->autoneg == AUTONEG_DISABLE) { 1689167514Skmacy lc->speed = lc->requested_speed; 1690167514Skmacy lc->duplex = lc->requested_duplex; 1691167514Skmacy lc->fc = (unsigned char)fc; 1692167514Skmacy t3_mac_set_speed_duplex_fc(mac, lc->speed, lc->duplex, 1693167514Skmacy fc); 1694167514Skmacy /* Also disables autoneg */ 1695167514Skmacy phy->ops->set_speed_duplex(phy, lc->speed, lc->duplex); 1696189643Sgnn /* PR 5666. Power phy up when doing an ifup */ 1697189643Sgnn if (!is_10G(phy->adapter)) 1698197791Snp phy->ops->power_down(phy, 0); 1699167514Skmacy } else 1700167514Skmacy phy->ops->autoneg_enable(phy); 1701167514Skmacy } else { 1702167514Skmacy t3_mac_set_speed_duplex_fc(mac, -1, -1, fc); 1703167514Skmacy lc->fc = (unsigned char)fc; 1704167514Skmacy phy->ops->reset(phy, 0); 1705167514Skmacy } 1706167514Skmacy return 0; 1707167514Skmacy} 1708167514Skmacy 1709167514Skmacy/** 1710167514Skmacy * t3_set_vlan_accel - control HW VLAN extraction 1711167514Skmacy * @adapter: the adapter 1712167514Skmacy * @ports: bitmap of adapter ports to operate on 1713167514Skmacy * @on: enable (1) or disable (0) HW VLAN extraction 1714167514Skmacy * 1715167514Skmacy * Enables or disables HW extraction of VLAN tags for the given port. 1716167514Skmacy */ 1717167514Skmacyvoid t3_set_vlan_accel(adapter_t *adapter, unsigned int ports, int on) 1718167514Skmacy{ 1719167514Skmacy t3_set_reg_field(adapter, A_TP_OUT_CONFIG, 1720167514Skmacy ports << S_VLANEXTRACTIONENABLE, 1721167514Skmacy on ? (ports << S_VLANEXTRACTIONENABLE) : 0); 1722167514Skmacy} 1723167514Skmacy 1724167514Skmacystruct intr_info { 1725167514Skmacy unsigned int mask; /* bits to check in interrupt status */ 1726167514Skmacy const char *msg; /* message to print or NULL */ 1727167514Skmacy short stat_idx; /* stat counter to increment or -1 */ 1728181614Skmacy unsigned short fatal; /* whether the condition reported is fatal */ 1729167514Skmacy}; 1730167514Skmacy 1731167514Skmacy/** 1732167514Skmacy * t3_handle_intr_status - table driven interrupt handler 1733167514Skmacy * @adapter: the adapter that generated the interrupt 1734167514Skmacy * @reg: the interrupt status register to process 1735167514Skmacy * @mask: a mask to apply to the interrupt status 1736167514Skmacy * @acts: table of interrupt actions 1737249582Sgabor * @stats: statistics counters tracking interrupt occurrences 1738167514Skmacy * 1739167514Skmacy * A table driven interrupt handler that applies a set of masks to an 1740167514Skmacy * interrupt status word and performs the corresponding actions if the 1741298955Spfg * interrupts described by the mask have occurred. The actions include 1742167514Skmacy * optionally printing a warning or alert message, and optionally 1743167514Skmacy * incrementing a stat counter. The table is terminated by an entry 1744167514Skmacy * specifying mask 0. Returns the number of fatal interrupt conditions. 1745167514Skmacy */ 1746167514Skmacystatic int t3_handle_intr_status(adapter_t *adapter, unsigned int reg, 1747167514Skmacy unsigned int mask, 1748167514Skmacy const struct intr_info *acts, 1749167514Skmacy unsigned long *stats) 1750167514Skmacy{ 1751167514Skmacy int fatal = 0; 1752167514Skmacy unsigned int status = t3_read_reg(adapter, reg) & mask; 1753167514Skmacy 1754167514Skmacy for ( ; acts->mask; ++acts) { 1755167514Skmacy if (!(status & acts->mask)) continue; 1756167514Skmacy if (acts->fatal) { 1757167514Skmacy fatal++; 1758167514Skmacy CH_ALERT(adapter, "%s (0x%x)\n", 1759167514Skmacy acts->msg, status & acts->mask); 1760219945Snp status &= ~acts->mask; 1761167514Skmacy } else if (acts->msg) 1762167514Skmacy CH_WARN(adapter, "%s (0x%x)\n", 1763167514Skmacy acts->msg, status & acts->mask); 1764167514Skmacy if (acts->stat_idx >= 0) 1765167514Skmacy stats[acts->stat_idx]++; 1766167514Skmacy } 1767167514Skmacy if (status) /* clear processed interrupts */ 1768167514Skmacy t3_write_reg(adapter, reg, status); 1769167514Skmacy return fatal; 1770167514Skmacy} 1771167514Skmacy 1772176472Skmacy#define SGE_INTR_MASK (F_RSPQDISABLED | \ 1773176472Skmacy F_UC_REQ_FRAMINGERROR | F_R_REQ_FRAMINGERROR | \ 1774176472Skmacy F_CPPARITYERROR | F_OCPARITYERROR | F_RCPARITYERROR | \ 1775176472Skmacy F_IRPARITYERROR | V_ITPARITYERROR(M_ITPARITYERROR) | \ 1776176472Skmacy V_FLPARITYERROR(M_FLPARITYERROR) | F_LODRBPARITYERROR | \ 1777176472Skmacy F_HIDRBPARITYERROR | F_LORCQPARITYERROR | \ 1778176472Skmacy F_HIRCQPARITYERROR) 1779167514Skmacy#define MC5_INTR_MASK (F_PARITYERR | F_ACTRGNFULL | F_UNKNOWNCMD | \ 1780167514Skmacy F_REQQPARERR | F_DISPQPARERR | F_DELACTEMPTY | \ 1781167514Skmacy F_NFASRCHFAIL) 1782167514Skmacy#define MC7_INTR_MASK (F_AE | F_UE | F_CE | V_PE(M_PE)) 1783167514Skmacy#define XGM_INTR_MASK (V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR) | \ 1784167514Skmacy V_RXFIFO_PRTY_ERR(M_RXFIFO_PRTY_ERR) | \ 1785189643Sgnn F_TXFIFO_UNDERRUN) 1786167514Skmacy#define PCIX_INTR_MASK (F_MSTDETPARERR | F_SIGTARABT | F_RCVTARABT | \ 1787167514Skmacy F_RCVMSTABT | F_SIGSYSERR | F_DETPARERR | \ 1788167514Skmacy F_SPLCMPDIS | F_UNXSPLCMP | F_RCVSPLCMPERR | \ 1789167514Skmacy F_DETCORECCERR | F_DETUNCECCERR | F_PIOPARERR | \ 1790167514Skmacy V_WFPARERR(M_WFPARERR) | V_RFPARERR(M_RFPARERR) | \ 1791167514Skmacy V_CFPARERR(M_CFPARERR) /* | V_MSIXPARERR(M_MSIXPARERR) */) 1792167514Skmacy#define PCIE_INTR_MASK (F_UNXSPLCPLERRR | F_UNXSPLCPLERRC | F_PCIE_PIOPARERR |\ 1793167514Skmacy F_PCIE_WFPARERR | F_PCIE_RFPARERR | F_PCIE_CFPARERR | \ 1794167514Skmacy /* V_PCIE_MSIXPARERR(M_PCIE_MSIXPARERR) | */ \ 1795176472Skmacy F_RETRYBUFPARERR | F_RETRYLUTPARERR | F_RXPARERR | \ 1796176472Skmacy F_TXPARERR | V_BISTERR(M_BISTERR)) 1797176472Skmacy#define ULPRX_INTR_MASK (F_PARERRDATA | F_PARERRPCMD | F_ARBPF1PERR | \ 1798176472Skmacy F_ARBPF0PERR | F_ARBFPERR | F_PCMDMUXPERR | \ 1799176472Skmacy F_DATASELFRAMEERR1 | F_DATASELFRAMEERR0) 1800176472Skmacy#define ULPTX_INTR_MASK 0xfc 1801176472Skmacy#define CPLSW_INTR_MASK (F_CIM_OP_MAP_PERR | F_TP_FRAMING_ERROR | \ 1802167514Skmacy F_SGE_FRAMING_ERROR | F_CIM_FRAMING_ERROR | \ 1803167514Skmacy F_ZERO_SWITCH_ERROR) 1804167514Skmacy#define CIM_INTR_MASK (F_BLKWRPLINT | F_BLKRDPLINT | F_BLKWRCTLINT | \ 1805167514Skmacy F_BLKRDCTLINT | F_BLKWRFLASHINT | F_BLKRDFLASHINT | \ 1806167514Skmacy F_SGLWRFLASHINT | F_WRBLKFLASHINT | F_BLKWRBOOTINT | \ 1807176472Skmacy F_FLASHRANGEINT | F_SDRAMRANGEINT | F_RSVDSPACEINT | \ 1808176472Skmacy F_DRAMPARERR | F_ICACHEPARERR | F_DCACHEPARERR | \ 1809176472Skmacy F_OBQSGEPARERR | F_OBQULPHIPARERR | F_OBQULPLOPARERR | \ 1810176472Skmacy F_IBQSGELOPARERR | F_IBQSGEHIPARERR | F_IBQULPPARERR | \ 1811176472Skmacy F_IBQTPPARERR | F_ITAGPARERR | F_DTAGPARERR) 1812167514Skmacy#define PMTX_INTR_MASK (F_ZERO_C_CMD_ERROR | ICSPI_FRM_ERR | OESPI_FRM_ERR | \ 1813167514Skmacy V_ICSPI_PAR_ERROR(M_ICSPI_PAR_ERROR) | \ 1814167514Skmacy V_OESPI_PAR_ERROR(M_OESPI_PAR_ERROR)) 1815167514Skmacy#define PMRX_INTR_MASK (F_ZERO_E_CMD_ERROR | IESPI_FRM_ERR | OCSPI_FRM_ERR | \ 1816167514Skmacy V_IESPI_PAR_ERROR(M_IESPI_PAR_ERROR) | \ 1817167514Skmacy V_OCSPI_PAR_ERROR(M_OCSPI_PAR_ERROR)) 1818167514Skmacy#define MPS_INTR_MASK (V_TX0TPPARERRENB(M_TX0TPPARERRENB) | \ 1819167514Skmacy V_TX1TPPARERRENB(M_TX1TPPARERRENB) | \ 1820167514Skmacy V_RXTPPARERRENB(M_RXTPPARERRENB) | \ 1821167514Skmacy V_MCAPARERRENB(M_MCAPARERRENB)) 1822189643Sgnn#define XGM_EXTRA_INTR_MASK (F_LINKFAULTCHANGE) 1823167514Skmacy#define PL_INTR_MASK (F_T3DBG | F_XGMAC0_0 | F_XGMAC0_1 | F_MC5A | F_PM1_TX | \ 1824167514Skmacy F_PM1_RX | F_ULP2_TX | F_ULP2_RX | F_TP1 | F_CIM | \ 1825167514Skmacy F_MC7_CM | F_MC7_PMTX | F_MC7_PMRX | F_SGE3 | F_PCIM0 | \ 1826167514Skmacy F_MPS0 | F_CPL_SWITCH) 1827167514Skmacy/* 1828167514Skmacy * Interrupt handler for the PCIX1 module. 1829167514Skmacy */ 1830167514Skmacystatic void pci_intr_handler(adapter_t *adapter) 1831167514Skmacy{ 1832167514Skmacy static struct intr_info pcix1_intr_info[] = { 1833167514Skmacy { F_MSTDETPARERR, "PCI master detected parity error", -1, 1 }, 1834167514Skmacy { F_SIGTARABT, "PCI signaled target abort", -1, 1 }, 1835167514Skmacy { F_RCVTARABT, "PCI received target abort", -1, 1 }, 1836167514Skmacy { F_RCVMSTABT, "PCI received master abort", -1, 1 }, 1837167514Skmacy { F_SIGSYSERR, "PCI signaled system error", -1, 1 }, 1838167514Skmacy { F_DETPARERR, "PCI detected parity error", -1, 1 }, 1839167514Skmacy { F_SPLCMPDIS, "PCI split completion discarded", -1, 1 }, 1840167514Skmacy { F_UNXSPLCMP, "PCI unexpected split completion error", -1, 1 }, 1841167514Skmacy { F_RCVSPLCMPERR, "PCI received split completion error", -1, 1842167514Skmacy 1 }, 1843167514Skmacy { F_DETCORECCERR, "PCI correctable ECC error", 1844167514Skmacy STAT_PCI_CORR_ECC, 0 }, 1845167514Skmacy { F_DETUNCECCERR, "PCI uncorrectable ECC error", -1, 1 }, 1846167514Skmacy { F_PIOPARERR, "PCI PIO FIFO parity error", -1, 1 }, 1847167514Skmacy { V_WFPARERR(M_WFPARERR), "PCI write FIFO parity error", -1, 1848167514Skmacy 1 }, 1849167514Skmacy { V_RFPARERR(M_RFPARERR), "PCI read FIFO parity error", -1, 1850167514Skmacy 1 }, 1851167514Skmacy { V_CFPARERR(M_CFPARERR), "PCI command FIFO parity error", -1, 1852167514Skmacy 1 }, 1853167514Skmacy { V_MSIXPARERR(M_MSIXPARERR), "PCI MSI-X table/PBA parity " 1854167514Skmacy "error", -1, 1 }, 1855167514Skmacy { 0 } 1856167514Skmacy }; 1857167514Skmacy 1858167514Skmacy if (t3_handle_intr_status(adapter, A_PCIX_INT_CAUSE, PCIX_INTR_MASK, 1859167514Skmacy pcix1_intr_info, adapter->irq_stats)) 1860167514Skmacy t3_fatal_err(adapter); 1861167514Skmacy} 1862167514Skmacy 1863167514Skmacy/* 1864167514Skmacy * Interrupt handler for the PCIE module. 1865167514Skmacy */ 1866167514Skmacystatic void pcie_intr_handler(adapter_t *adapter) 1867167514Skmacy{ 1868167514Skmacy static struct intr_info pcie_intr_info[] = { 1869167514Skmacy { F_PEXERR, "PCI PEX error", -1, 1 }, 1870167514Skmacy { F_UNXSPLCPLERRR, 1871167514Skmacy "PCI unexpected split completion DMA read error", -1, 1 }, 1872167514Skmacy { F_UNXSPLCPLERRC, 1873167514Skmacy "PCI unexpected split completion DMA command error", -1, 1 }, 1874167514Skmacy { F_PCIE_PIOPARERR, "PCI PIO FIFO parity error", -1, 1 }, 1875167514Skmacy { F_PCIE_WFPARERR, "PCI write FIFO parity error", -1, 1 }, 1876167514Skmacy { F_PCIE_RFPARERR, "PCI read FIFO parity error", -1, 1 }, 1877167514Skmacy { F_PCIE_CFPARERR, "PCI command FIFO parity error", -1, 1 }, 1878167514Skmacy { V_PCIE_MSIXPARERR(M_PCIE_MSIXPARERR), 1879167514Skmacy "PCI MSI-X table/PBA parity error", -1, 1 }, 1880176472Skmacy { F_RETRYBUFPARERR, "PCI retry buffer parity error", -1, 1 }, 1881176472Skmacy { F_RETRYLUTPARERR, "PCI retry LUT parity error", -1, 1 }, 1882176472Skmacy { F_RXPARERR, "PCI Rx parity error", -1, 1 }, 1883176472Skmacy { F_TXPARERR, "PCI Tx parity error", -1, 1 }, 1884167514Skmacy { V_BISTERR(M_BISTERR), "PCI BIST error", -1, 1 }, 1885167514Skmacy { 0 } 1886167514Skmacy }; 1887167514Skmacy 1888172096Skmacy if (t3_read_reg(adapter, A_PCIE_INT_CAUSE) & F_PEXERR) 1889172096Skmacy CH_ALERT(adapter, "PEX error code 0x%x\n", 1890172096Skmacy t3_read_reg(adapter, A_PCIE_PEX_ERR)); 1891172096Skmacy 1892167514Skmacy if (t3_handle_intr_status(adapter, A_PCIE_INT_CAUSE, PCIE_INTR_MASK, 1893167514Skmacy pcie_intr_info, adapter->irq_stats)) 1894167514Skmacy t3_fatal_err(adapter); 1895167514Skmacy} 1896167514Skmacy 1897167514Skmacy/* 1898167514Skmacy * TP interrupt handler. 1899167514Skmacy */ 1900167514Skmacystatic void tp_intr_handler(adapter_t *adapter) 1901167514Skmacy{ 1902167514Skmacy static struct intr_info tp_intr_info[] = { 1903167514Skmacy { 0xffffff, "TP parity error", -1, 1 }, 1904167514Skmacy { 0x1000000, "TP out of Rx pages", -1, 1 }, 1905167514Skmacy { 0x2000000, "TP out of Tx pages", -1, 1 }, 1906167514Skmacy { 0 } 1907167514Skmacy }; 1908176472Skmacy static struct intr_info tp_intr_info_t3c[] = { 1909176472Skmacy { 0x1fffffff, "TP parity error", -1, 1 }, 1910176472Skmacy { F_FLMRXFLSTEMPTY, "TP out of Rx pages", -1, 1 }, 1911176472Skmacy { F_FLMTXFLSTEMPTY, "TP out of Tx pages", -1, 1 }, 1912176472Skmacy { 0 } 1913176472Skmacy }; 1914167514Skmacy 1915167514Skmacy if (t3_handle_intr_status(adapter, A_TP_INT_CAUSE, 0xffffffff, 1916176472Skmacy adapter->params.rev < T3_REV_C ? 1917176472Skmacy tp_intr_info : tp_intr_info_t3c, NULL)) 1918167514Skmacy t3_fatal_err(adapter); 1919167514Skmacy} 1920167514Skmacy 1921167514Skmacy/* 1922167514Skmacy * CIM interrupt handler. 1923167514Skmacy */ 1924167514Skmacystatic void cim_intr_handler(adapter_t *adapter) 1925167514Skmacy{ 1926167514Skmacy static struct intr_info cim_intr_info[] = { 1927167514Skmacy { F_RSVDSPACEINT, "CIM reserved space write", -1, 1 }, 1928167514Skmacy { F_SDRAMRANGEINT, "CIM SDRAM address out of range", -1, 1 }, 1929167514Skmacy { F_FLASHRANGEINT, "CIM flash address out of range", -1, 1 }, 1930167514Skmacy { F_BLKWRBOOTINT, "CIM block write to boot space", -1, 1 }, 1931167514Skmacy { F_WRBLKFLASHINT, "CIM write to cached flash space", -1, 1 }, 1932167514Skmacy { F_SGLWRFLASHINT, "CIM single write to flash space", -1, 1 }, 1933167514Skmacy { F_BLKRDFLASHINT, "CIM block read from flash space", -1, 1 }, 1934167514Skmacy { F_BLKWRFLASHINT, "CIM block write to flash space", -1, 1 }, 1935167514Skmacy { F_BLKRDCTLINT, "CIM block read from CTL space", -1, 1 }, 1936167514Skmacy { F_BLKWRCTLINT, "CIM block write to CTL space", -1, 1 }, 1937167514Skmacy { F_BLKRDPLINT, "CIM block read from PL space", -1, 1 }, 1938167514Skmacy { F_BLKWRPLINT, "CIM block write to PL space", -1, 1 }, 1939176472Skmacy { F_DRAMPARERR, "CIM DRAM parity error", -1, 1 }, 1940176472Skmacy { F_ICACHEPARERR, "CIM icache parity error", -1, 1 }, 1941176472Skmacy { F_DCACHEPARERR, "CIM dcache parity error", -1, 1 }, 1942176472Skmacy { F_OBQSGEPARERR, "CIM OBQ SGE parity error", -1, 1 }, 1943176472Skmacy { F_OBQULPHIPARERR, "CIM OBQ ULPHI parity error", -1, 1 }, 1944176472Skmacy { F_OBQULPLOPARERR, "CIM OBQ ULPLO parity error", -1, 1 }, 1945176472Skmacy { F_IBQSGELOPARERR, "CIM IBQ SGELO parity error", -1, 1 }, 1946176472Skmacy { F_IBQSGEHIPARERR, "CIM IBQ SGEHI parity error", -1, 1 }, 1947176472Skmacy { F_IBQULPPARERR, "CIM IBQ ULP parity error", -1, 1 }, 1948176472Skmacy { F_IBQTPPARERR, "CIM IBQ TP parity error", -1, 1 }, 1949176472Skmacy { F_ITAGPARERR, "CIM itag parity error", -1, 1 }, 1950176472Skmacy { F_DTAGPARERR, "CIM dtag parity error", -1, 1 }, 1951167514Skmacy { 0 } 1952167514Skmacy }; 1953167514Skmacy 1954176472Skmacy if (t3_handle_intr_status(adapter, A_CIM_HOST_INT_CAUSE, CIM_INTR_MASK, 1955167514Skmacy cim_intr_info, NULL)) 1956167514Skmacy t3_fatal_err(adapter); 1957167514Skmacy} 1958167514Skmacy 1959167514Skmacy/* 1960167514Skmacy * ULP RX interrupt handler. 1961167514Skmacy */ 1962167514Skmacystatic void ulprx_intr_handler(adapter_t *adapter) 1963167514Skmacy{ 1964167514Skmacy static struct intr_info ulprx_intr_info[] = { 1965176472Skmacy { F_PARERRDATA, "ULP RX data parity error", -1, 1 }, 1966176472Skmacy { F_PARERRPCMD, "ULP RX command parity error", -1, 1 }, 1967176472Skmacy { F_ARBPF1PERR, "ULP RX ArbPF1 parity error", -1, 1 }, 1968176472Skmacy { F_ARBPF0PERR, "ULP RX ArbPF0 parity error", -1, 1 }, 1969176472Skmacy { F_ARBFPERR, "ULP RX ArbF parity error", -1, 1 }, 1970176472Skmacy { F_PCMDMUXPERR, "ULP RX PCMDMUX parity error", -1, 1 }, 1971176472Skmacy { F_DATASELFRAMEERR1, "ULP RX frame error", -1, 1 }, 1972176472Skmacy { F_DATASELFRAMEERR0, "ULP RX frame error", -1, 1 }, 1973167514Skmacy { 0 } 1974167514Skmacy }; 1975167514Skmacy 1976167514Skmacy if (t3_handle_intr_status(adapter, A_ULPRX_INT_CAUSE, 0xffffffff, 1977167514Skmacy ulprx_intr_info, NULL)) 1978167514Skmacy t3_fatal_err(adapter); 1979167514Skmacy} 1980167514Skmacy 1981167514Skmacy/* 1982167514Skmacy * ULP TX interrupt handler. 1983167514Skmacy */ 1984167514Skmacystatic void ulptx_intr_handler(adapter_t *adapter) 1985167514Skmacy{ 1986167514Skmacy static struct intr_info ulptx_intr_info[] = { 1987167514Skmacy { F_PBL_BOUND_ERR_CH0, "ULP TX channel 0 PBL out of bounds", 1988167514Skmacy STAT_ULP_CH0_PBL_OOB, 0 }, 1989167514Skmacy { F_PBL_BOUND_ERR_CH1, "ULP TX channel 1 PBL out of bounds", 1990167514Skmacy STAT_ULP_CH1_PBL_OOB, 0 }, 1991176472Skmacy { 0xfc, "ULP TX parity error", -1, 1 }, 1992167514Skmacy { 0 } 1993167514Skmacy }; 1994167514Skmacy 1995167514Skmacy if (t3_handle_intr_status(adapter, A_ULPTX_INT_CAUSE, 0xffffffff, 1996167514Skmacy ulptx_intr_info, adapter->irq_stats)) 1997167514Skmacy t3_fatal_err(adapter); 1998167514Skmacy} 1999167514Skmacy 2000167514Skmacy#define ICSPI_FRM_ERR (F_ICSPI0_FIFO2X_RX_FRAMING_ERROR | \ 2001167514Skmacy F_ICSPI1_FIFO2X_RX_FRAMING_ERROR | F_ICSPI0_RX_FRAMING_ERROR | \ 2002167514Skmacy F_ICSPI1_RX_FRAMING_ERROR | F_ICSPI0_TX_FRAMING_ERROR | \ 2003167514Skmacy F_ICSPI1_TX_FRAMING_ERROR) 2004167514Skmacy#define OESPI_FRM_ERR (F_OESPI0_RX_FRAMING_ERROR | \ 2005167514Skmacy F_OESPI1_RX_FRAMING_ERROR | F_OESPI0_TX_FRAMING_ERROR | \ 2006167514Skmacy F_OESPI1_TX_FRAMING_ERROR | F_OESPI0_OFIFO2X_TX_FRAMING_ERROR | \ 2007167514Skmacy F_OESPI1_OFIFO2X_TX_FRAMING_ERROR) 2008167514Skmacy 2009167514Skmacy/* 2010167514Skmacy * PM TX interrupt handler. 2011167514Skmacy */ 2012167514Skmacystatic void pmtx_intr_handler(adapter_t *adapter) 2013167514Skmacy{ 2014167514Skmacy static struct intr_info pmtx_intr_info[] = { 2015167514Skmacy { F_ZERO_C_CMD_ERROR, "PMTX 0-length pcmd", -1, 1 }, 2016167514Skmacy { ICSPI_FRM_ERR, "PMTX ispi framing error", -1, 1 }, 2017167514Skmacy { OESPI_FRM_ERR, "PMTX ospi framing error", -1, 1 }, 2018167514Skmacy { V_ICSPI_PAR_ERROR(M_ICSPI_PAR_ERROR), 2019167514Skmacy "PMTX ispi parity error", -1, 1 }, 2020167514Skmacy { V_OESPI_PAR_ERROR(M_OESPI_PAR_ERROR), 2021167514Skmacy "PMTX ospi parity error", -1, 1 }, 2022167514Skmacy { 0 } 2023167514Skmacy }; 2024167514Skmacy 2025167514Skmacy if (t3_handle_intr_status(adapter, A_PM1_TX_INT_CAUSE, 0xffffffff, 2026167514Skmacy pmtx_intr_info, NULL)) 2027167514Skmacy t3_fatal_err(adapter); 2028167514Skmacy} 2029167514Skmacy 2030167514Skmacy#define IESPI_FRM_ERR (F_IESPI0_FIFO2X_RX_FRAMING_ERROR | \ 2031167514Skmacy F_IESPI1_FIFO2X_RX_FRAMING_ERROR | F_IESPI0_RX_FRAMING_ERROR | \ 2032167514Skmacy F_IESPI1_RX_FRAMING_ERROR | F_IESPI0_TX_FRAMING_ERROR | \ 2033167514Skmacy F_IESPI1_TX_FRAMING_ERROR) 2034167514Skmacy#define OCSPI_FRM_ERR (F_OCSPI0_RX_FRAMING_ERROR | \ 2035167514Skmacy F_OCSPI1_RX_FRAMING_ERROR | F_OCSPI0_TX_FRAMING_ERROR | \ 2036167514Skmacy F_OCSPI1_TX_FRAMING_ERROR | F_OCSPI0_OFIFO2X_TX_FRAMING_ERROR | \ 2037167514Skmacy F_OCSPI1_OFIFO2X_TX_FRAMING_ERROR) 2038167514Skmacy 2039167514Skmacy/* 2040167514Skmacy * PM RX interrupt handler. 2041167514Skmacy */ 2042167514Skmacystatic void pmrx_intr_handler(adapter_t *adapter) 2043167514Skmacy{ 2044167514Skmacy static struct intr_info pmrx_intr_info[] = { 2045167514Skmacy { F_ZERO_E_CMD_ERROR, "PMRX 0-length pcmd", -1, 1 }, 2046167514Skmacy { IESPI_FRM_ERR, "PMRX ispi framing error", -1, 1 }, 2047167514Skmacy { OCSPI_FRM_ERR, "PMRX ospi framing error", -1, 1 }, 2048167514Skmacy { V_IESPI_PAR_ERROR(M_IESPI_PAR_ERROR), 2049167514Skmacy "PMRX ispi parity error", -1, 1 }, 2050167514Skmacy { V_OCSPI_PAR_ERROR(M_OCSPI_PAR_ERROR), 2051167514Skmacy "PMRX ospi parity error", -1, 1 }, 2052167514Skmacy { 0 } 2053167514Skmacy }; 2054167514Skmacy 2055167514Skmacy if (t3_handle_intr_status(adapter, A_PM1_RX_INT_CAUSE, 0xffffffff, 2056167514Skmacy pmrx_intr_info, NULL)) 2057167514Skmacy t3_fatal_err(adapter); 2058167514Skmacy} 2059167514Skmacy 2060167514Skmacy/* 2061167514Skmacy * CPL switch interrupt handler. 2062167514Skmacy */ 2063167514Skmacystatic void cplsw_intr_handler(adapter_t *adapter) 2064167514Skmacy{ 2065167514Skmacy static struct intr_info cplsw_intr_info[] = { 2066176472Skmacy { F_CIM_OP_MAP_PERR, "CPL switch CIM parity error", -1, 1 }, 2067176472Skmacy { F_CIM_OVFL_ERROR, "CPL switch CIM overflow", -1, 1 }, 2068167514Skmacy { F_TP_FRAMING_ERROR, "CPL switch TP framing error", -1, 1 }, 2069167514Skmacy { F_SGE_FRAMING_ERROR, "CPL switch SGE framing error", -1, 1 }, 2070167514Skmacy { F_CIM_FRAMING_ERROR, "CPL switch CIM framing error", -1, 1 }, 2071167514Skmacy { F_ZERO_SWITCH_ERROR, "CPL switch no-switch error", -1, 1 }, 2072167514Skmacy { 0 } 2073167514Skmacy }; 2074167514Skmacy 2075167514Skmacy if (t3_handle_intr_status(adapter, A_CPL_INTR_CAUSE, 0xffffffff, 2076167514Skmacy cplsw_intr_info, NULL)) 2077167514Skmacy t3_fatal_err(adapter); 2078167514Skmacy} 2079167514Skmacy 2080167514Skmacy/* 2081167514Skmacy * MPS interrupt handler. 2082167514Skmacy */ 2083167514Skmacystatic void mps_intr_handler(adapter_t *adapter) 2084167514Skmacy{ 2085167514Skmacy static struct intr_info mps_intr_info[] = { 2086167514Skmacy { 0x1ff, "MPS parity error", -1, 1 }, 2087167514Skmacy { 0 } 2088167514Skmacy }; 2089167514Skmacy 2090167514Skmacy if (t3_handle_intr_status(adapter, A_MPS_INT_CAUSE, 0xffffffff, 2091167514Skmacy mps_intr_info, NULL)) 2092167514Skmacy t3_fatal_err(adapter); 2093167514Skmacy} 2094167514Skmacy 2095167514Skmacy#define MC7_INTR_FATAL (F_UE | V_PE(M_PE) | F_AE) 2096167514Skmacy 2097167514Skmacy/* 2098167514Skmacy * MC7 interrupt handler. 2099167514Skmacy */ 2100167514Skmacystatic void mc7_intr_handler(struct mc7 *mc7) 2101167514Skmacy{ 2102167514Skmacy adapter_t *adapter = mc7->adapter; 2103167514Skmacy u32 cause = t3_read_reg(adapter, mc7->offset + A_MC7_INT_CAUSE); 2104167514Skmacy 2105167514Skmacy if (cause & F_CE) { 2106167514Skmacy mc7->stats.corr_err++; 2107167514Skmacy CH_WARN(adapter, "%s MC7 correctable error at addr 0x%x, " 2108167514Skmacy "data 0x%x 0x%x 0x%x\n", mc7->name, 2109167514Skmacy t3_read_reg(adapter, mc7->offset + A_MC7_CE_ADDR), 2110167514Skmacy t3_read_reg(adapter, mc7->offset + A_MC7_CE_DATA0), 2111167514Skmacy t3_read_reg(adapter, mc7->offset + A_MC7_CE_DATA1), 2112167514Skmacy t3_read_reg(adapter, mc7->offset + A_MC7_CE_DATA2)); 2113167514Skmacy } 2114167514Skmacy 2115167514Skmacy if (cause & F_UE) { 2116167514Skmacy mc7->stats.uncorr_err++; 2117167514Skmacy CH_ALERT(adapter, "%s MC7 uncorrectable error at addr 0x%x, " 2118167514Skmacy "data 0x%x 0x%x 0x%x\n", mc7->name, 2119167514Skmacy t3_read_reg(adapter, mc7->offset + A_MC7_UE_ADDR), 2120167514Skmacy t3_read_reg(adapter, mc7->offset + A_MC7_UE_DATA0), 2121167514Skmacy t3_read_reg(adapter, mc7->offset + A_MC7_UE_DATA1), 2122167514Skmacy t3_read_reg(adapter, mc7->offset + A_MC7_UE_DATA2)); 2123167514Skmacy } 2124167514Skmacy 2125167514Skmacy if (G_PE(cause)) { 2126167514Skmacy mc7->stats.parity_err++; 2127167514Skmacy CH_ALERT(adapter, "%s MC7 parity error 0x%x\n", 2128167514Skmacy mc7->name, G_PE(cause)); 2129167514Skmacy } 2130167514Skmacy 2131167514Skmacy if (cause & F_AE) { 2132167514Skmacy u32 addr = 0; 2133167514Skmacy 2134167514Skmacy if (adapter->params.rev > 0) 2135167514Skmacy addr = t3_read_reg(adapter, 2136167514Skmacy mc7->offset + A_MC7_ERR_ADDR); 2137167514Skmacy mc7->stats.addr_err++; 2138167514Skmacy CH_ALERT(adapter, "%s MC7 address error: 0x%x\n", 2139167514Skmacy mc7->name, addr); 2140167514Skmacy } 2141167514Skmacy 2142167514Skmacy if (cause & MC7_INTR_FATAL) 2143167514Skmacy t3_fatal_err(adapter); 2144167514Skmacy 2145167514Skmacy t3_write_reg(adapter, mc7->offset + A_MC7_INT_CAUSE, cause); 2146167514Skmacy} 2147167514Skmacy 2148167514Skmacy#define XGM_INTR_FATAL (V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR) | \ 2149167514Skmacy V_RXFIFO_PRTY_ERR(M_RXFIFO_PRTY_ERR)) 2150167514Skmacy/* 2151167514Skmacy * XGMAC interrupt handler. 2152167514Skmacy */ 2153167514Skmacystatic int mac_intr_handler(adapter_t *adap, unsigned int idx) 2154167514Skmacy{ 2155170654Skmacy u32 cause; 2156192540Sgnn struct port_info *pi; 2157170654Skmacy struct cmac *mac; 2158167514Skmacy 2159170654Skmacy idx = idx == 0 ? 0 : adapter_info(adap)->nports0; /* MAC idx -> port */ 2160192540Sgnn pi = adap2pinfo(adap, idx); 2161192540Sgnn mac = &pi->mac; 2162170654Skmacy 2163189643Sgnn /* 2164189643Sgnn * We mask out interrupt causes for which we're not taking interrupts. 2165189643Sgnn * This allows us to use polling logic to monitor some of the other 2166189643Sgnn * conditions when taking interrupts would impose too much load on the 2167189643Sgnn * system. 2168189643Sgnn */ 2169189643Sgnn cause = (t3_read_reg(adap, A_XGM_INT_CAUSE + mac->offset) 2170189643Sgnn & ~(F_RXFIFO_OVERFLOW)); 2171189643Sgnn 2172167514Skmacy if (cause & V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR)) { 2173167514Skmacy mac->stats.tx_fifo_parity_err++; 2174167514Skmacy CH_ALERT(adap, "port%d: MAC TX FIFO parity error\n", idx); 2175167514Skmacy } 2176167514Skmacy if (cause & V_RXFIFO_PRTY_ERR(M_RXFIFO_PRTY_ERR)) { 2177167514Skmacy mac->stats.rx_fifo_parity_err++; 2178167514Skmacy CH_ALERT(adap, "port%d: MAC RX FIFO parity error\n", idx); 2179167514Skmacy } 2180167514Skmacy if (cause & F_TXFIFO_UNDERRUN) 2181167514Skmacy mac->stats.tx_fifo_urun++; 2182167514Skmacy if (cause & F_RXFIFO_OVERFLOW) 2183167514Skmacy mac->stats.rx_fifo_ovfl++; 2184167514Skmacy if (cause & V_SERDES_LOS(M_SERDES_LOS)) 2185167514Skmacy mac->stats.serdes_signal_loss++; 2186167514Skmacy if (cause & F_XAUIPCSCTCERR) 2187167514Skmacy mac->stats.xaui_pcs_ctc_err++; 2188167514Skmacy if (cause & F_XAUIPCSALIGNCHANGE) 2189167514Skmacy mac->stats.xaui_pcs_align_change++; 2190209841Snp if (cause & F_XGM_INT & 2191209841Snp t3_read_reg(adap, A_XGM_INT_ENABLE + mac->offset)) { 2192209841Snp t3_set_reg_field(adap, A_XGM_INT_ENABLE + mac->offset, 2193209841Snp F_XGM_INT, 0); 2194167514Skmacy 2195192540Sgnn /* link fault suspected */ 2196192540Sgnn pi->link_fault = LF_MAYBE; 2197209841Snp t3_os_link_intr(pi); 2198189643Sgnn } 2199189643Sgnn 2200167514Skmacy if (cause & XGM_INTR_FATAL) 2201167514Skmacy t3_fatal_err(adap); 2202189643Sgnn 2203219945Snp t3_write_reg(adap, A_XGM_INT_CAUSE + mac->offset, cause); 2204167514Skmacy return cause != 0; 2205167514Skmacy} 2206167514Skmacy 2207167514Skmacy/* 2208167514Skmacy * Interrupt handler for PHY events. 2209167514Skmacy */ 2210209840Snpstatic int phy_intr_handler(adapter_t *adapter) 2211167514Skmacy{ 2212167514Skmacy u32 i, cause = t3_read_reg(adapter, A_T3DBG_INT_CAUSE); 2213167514Skmacy 2214167514Skmacy for_each_port(adapter, i) { 2215170654Skmacy struct port_info *p = adap2pinfo(adapter, i); 2216167514Skmacy 2217176472Skmacy if (!(p->phy.caps & SUPPORTED_IRQ)) 2218167514Skmacy continue; 2219167514Skmacy 2220180583Skmacy if (cause & (1 << adapter_info(adapter)->gpio_intr[i])) { 2221167514Skmacy int phy_cause = p->phy.ops->intr_handler(&p->phy); 2222167514Skmacy 2223167514Skmacy if (phy_cause & cphy_cause_link_change) 2224209841Snp t3_os_link_intr(p); 2225167514Skmacy if (phy_cause & cphy_cause_fifo_error) 2226167514Skmacy p->phy.fifo_errors++; 2227181614Skmacy if (phy_cause & cphy_cause_module_change) 2228181614Skmacy t3_os_phymod_changed(adapter, i); 2229197791Snp if (phy_cause & cphy_cause_alarm) 2230197791Snp CH_WARN(adapter, "Operation affected due to " 2231197791Snp "adverse environment. Check the spec " 2232197791Snp "sheet for corrective action."); 2233167514Skmacy } 2234167514Skmacy } 2235167514Skmacy 2236167514Skmacy t3_write_reg(adapter, A_T3DBG_INT_CAUSE, cause); 2237167514Skmacy return 0; 2238167514Skmacy} 2239167514Skmacy 2240172096Skmacy/** 2241172096Skmacy * t3_slow_intr_handler - control path interrupt handler 2242172096Skmacy * @adapter: the adapter 2243172096Skmacy * 2244172096Skmacy * T3 interrupt handler for non-data interrupt events, e.g., errors. 2245172096Skmacy * The designation 'slow' is because it involves register reads, while 2246172096Skmacy * data interrupts typically don't involve any MMIOs. 2247167514Skmacy */ 2248167514Skmacyint t3_slow_intr_handler(adapter_t *adapter) 2249167514Skmacy{ 2250167514Skmacy u32 cause = t3_read_reg(adapter, A_PL_INT_CAUSE0); 2251167514Skmacy 2252167514Skmacy cause &= adapter->slow_intr_mask; 2253167514Skmacy if (!cause) 2254167514Skmacy return 0; 2255167514Skmacy if (cause & F_PCIM0) { 2256167514Skmacy if (is_pcie(adapter)) 2257167514Skmacy pcie_intr_handler(adapter); 2258167514Skmacy else 2259167514Skmacy pci_intr_handler(adapter); 2260167514Skmacy } 2261167514Skmacy if (cause & F_SGE3) 2262167514Skmacy t3_sge_err_intr_handler(adapter); 2263167514Skmacy if (cause & F_MC7_PMRX) 2264167514Skmacy mc7_intr_handler(&adapter->pmrx); 2265167514Skmacy if (cause & F_MC7_PMTX) 2266167514Skmacy mc7_intr_handler(&adapter->pmtx); 2267167514Skmacy if (cause & F_MC7_CM) 2268167514Skmacy mc7_intr_handler(&adapter->cm); 2269167514Skmacy if (cause & F_CIM) 2270167514Skmacy cim_intr_handler(adapter); 2271167514Skmacy if (cause & F_TP1) 2272167514Skmacy tp_intr_handler(adapter); 2273167514Skmacy if (cause & F_ULP2_RX) 2274167514Skmacy ulprx_intr_handler(adapter); 2275167514Skmacy if (cause & F_ULP2_TX) 2276167514Skmacy ulptx_intr_handler(adapter); 2277167514Skmacy if (cause & F_PM1_RX) 2278167514Skmacy pmrx_intr_handler(adapter); 2279167514Skmacy if (cause & F_PM1_TX) 2280167514Skmacy pmtx_intr_handler(adapter); 2281167514Skmacy if (cause & F_CPL_SWITCH) 2282167514Skmacy cplsw_intr_handler(adapter); 2283167514Skmacy if (cause & F_MPS0) 2284167514Skmacy mps_intr_handler(adapter); 2285167514Skmacy if (cause & F_MC5A) 2286167514Skmacy t3_mc5_intr_handler(&adapter->mc5); 2287167514Skmacy if (cause & F_XGMAC0_0) 2288167514Skmacy mac_intr_handler(adapter, 0); 2289167514Skmacy if (cause & F_XGMAC0_1) 2290167514Skmacy mac_intr_handler(adapter, 1); 2291167514Skmacy if (cause & F_T3DBG) 2292209840Snp phy_intr_handler(adapter); 2293167514Skmacy 2294167514Skmacy /* Clear the interrupts just processed. */ 2295167514Skmacy t3_write_reg(adapter, A_PL_INT_CAUSE0, cause); 2296167514Skmacy (void) t3_read_reg(adapter, A_PL_INT_CAUSE0); /* flush */ 2297167514Skmacy return 1; 2298167514Skmacy} 2299167514Skmacy 2300180583Skmacystatic unsigned int calc_gpio_intr(adapter_t *adap) 2301180583Skmacy{ 2302180583Skmacy unsigned int i, gpi_intr = 0; 2303180583Skmacy 2304180583Skmacy for_each_port(adap, i) 2305180583Skmacy if ((adap2pinfo(adap, i)->phy.caps & SUPPORTED_IRQ) && 2306180583Skmacy adapter_info(adap)->gpio_intr[i]) 2307180583Skmacy gpi_intr |= 1 << adapter_info(adap)->gpio_intr[i]; 2308180583Skmacy return gpi_intr; 2309180583Skmacy} 2310180583Skmacy 2311167514Skmacy/** 2312167514Skmacy * t3_intr_enable - enable interrupts 2313167514Skmacy * @adapter: the adapter whose interrupts should be enabled 2314167514Skmacy * 2315167514Skmacy * Enable interrupts by setting the interrupt enable registers of the 2316167514Skmacy * various HW modules and then enabling the top-level interrupt 2317167514Skmacy * concentrator. 2318167514Skmacy */ 2319167514Skmacyvoid t3_intr_enable(adapter_t *adapter) 2320167514Skmacy{ 2321167514Skmacy static struct addr_val_pair intr_en_avp[] = { 2322167514Skmacy { A_MC7_INT_ENABLE, MC7_INTR_MASK }, 2323167514Skmacy { A_MC7_INT_ENABLE - MC7_PMRX_BASE_ADDR + MC7_PMTX_BASE_ADDR, 2324167514Skmacy MC7_INTR_MASK }, 2325167514Skmacy { A_MC7_INT_ENABLE - MC7_PMRX_BASE_ADDR + MC7_CM_BASE_ADDR, 2326167514Skmacy MC7_INTR_MASK }, 2327167514Skmacy { A_MC5_DB_INT_ENABLE, MC5_INTR_MASK }, 2328167514Skmacy { A_ULPRX_INT_ENABLE, ULPRX_INTR_MASK }, 2329167514Skmacy { A_PM1_TX_INT_ENABLE, PMTX_INTR_MASK }, 2330167514Skmacy { A_PM1_RX_INT_ENABLE, PMRX_INTR_MASK }, 2331167514Skmacy { A_CIM_HOST_INT_ENABLE, CIM_INTR_MASK }, 2332167514Skmacy { A_MPS_INT_ENABLE, MPS_INTR_MASK }, 2333167514Skmacy }; 2334167514Skmacy 2335167514Skmacy adapter->slow_intr_mask = PL_INTR_MASK; 2336167514Skmacy 2337167514Skmacy t3_write_regs(adapter, intr_en_avp, ARRAY_SIZE(intr_en_avp), 0); 2338176472Skmacy t3_write_reg(adapter, A_TP_INT_ENABLE, 2339176472Skmacy adapter->params.rev >= T3_REV_C ? 0x2bfffff : 0x3bfffff); 2340189643Sgnn t3_write_reg(adapter, A_SG_INT_ENABLE, SGE_INTR_MASK); 2341167514Skmacy 2342167514Skmacy if (adapter->params.rev > 0) { 2343167514Skmacy t3_write_reg(adapter, A_CPL_INTR_ENABLE, 2344167514Skmacy CPLSW_INTR_MASK | F_CIM_OVFL_ERROR); 2345167514Skmacy t3_write_reg(adapter, A_ULPTX_INT_ENABLE, 2346167514Skmacy ULPTX_INTR_MASK | F_PBL_BOUND_ERR_CH0 | 2347167514Skmacy F_PBL_BOUND_ERR_CH1); 2348167514Skmacy } else { 2349167514Skmacy t3_write_reg(adapter, A_CPL_INTR_ENABLE, CPLSW_INTR_MASK); 2350167514Skmacy t3_write_reg(adapter, A_ULPTX_INT_ENABLE, ULPTX_INTR_MASK); 2351167514Skmacy } 2352167514Skmacy 2353180583Skmacy t3_write_reg(adapter, A_T3DBG_INT_ENABLE, calc_gpio_intr(adapter)); 2354180583Skmacy 2355170654Skmacy if (is_pcie(adapter)) 2356167514Skmacy t3_write_reg(adapter, A_PCIE_INT_ENABLE, PCIE_INTR_MASK); 2357170654Skmacy else 2358167514Skmacy t3_write_reg(adapter, A_PCIX_INT_ENABLE, PCIX_INTR_MASK); 2359167514Skmacy t3_write_reg(adapter, A_PL_INT_ENABLE0, adapter->slow_intr_mask); 2360167514Skmacy (void) t3_read_reg(adapter, A_PL_INT_ENABLE0); /* flush */ 2361167514Skmacy} 2362167514Skmacy 2363167514Skmacy/** 2364167514Skmacy * t3_intr_disable - disable a card's interrupts 2365167514Skmacy * @adapter: the adapter whose interrupts should be disabled 2366167514Skmacy * 2367167514Skmacy * Disable interrupts. We only disable the top-level interrupt 2368167514Skmacy * concentrator and the SGE data interrupts. 2369167514Skmacy */ 2370167514Skmacyvoid t3_intr_disable(adapter_t *adapter) 2371167514Skmacy{ 2372167514Skmacy t3_write_reg(adapter, A_PL_INT_ENABLE0, 0); 2373167514Skmacy (void) t3_read_reg(adapter, A_PL_INT_ENABLE0); /* flush */ 2374167514Skmacy adapter->slow_intr_mask = 0; 2375167514Skmacy} 2376167514Skmacy 2377167514Skmacy/** 2378167514Skmacy * t3_intr_clear - clear all interrupts 2379167514Skmacy * @adapter: the adapter whose interrupts should be cleared 2380167514Skmacy * 2381167514Skmacy * Clears all interrupts. 2382167514Skmacy */ 2383167514Skmacyvoid t3_intr_clear(adapter_t *adapter) 2384167514Skmacy{ 2385167514Skmacy static const unsigned int cause_reg_addr[] = { 2386167514Skmacy A_SG_INT_CAUSE, 2387167514Skmacy A_SG_RSPQ_FL_STATUS, 2388167514Skmacy A_PCIX_INT_CAUSE, 2389167514Skmacy A_MC7_INT_CAUSE, 2390167514Skmacy A_MC7_INT_CAUSE - MC7_PMRX_BASE_ADDR + MC7_PMTX_BASE_ADDR, 2391167514Skmacy A_MC7_INT_CAUSE - MC7_PMRX_BASE_ADDR + MC7_CM_BASE_ADDR, 2392167514Skmacy A_CIM_HOST_INT_CAUSE, 2393167514Skmacy A_TP_INT_CAUSE, 2394167514Skmacy A_MC5_DB_INT_CAUSE, 2395167514Skmacy A_ULPRX_INT_CAUSE, 2396167514Skmacy A_ULPTX_INT_CAUSE, 2397167514Skmacy A_CPL_INTR_CAUSE, 2398167514Skmacy A_PM1_TX_INT_CAUSE, 2399167514Skmacy A_PM1_RX_INT_CAUSE, 2400167514Skmacy A_MPS_INT_CAUSE, 2401167514Skmacy A_T3DBG_INT_CAUSE, 2402167514Skmacy }; 2403167514Skmacy unsigned int i; 2404167514Skmacy 2405167514Skmacy /* Clear PHY and MAC interrupts for each port. */ 2406167514Skmacy for_each_port(adapter, i) 2407167514Skmacy t3_port_intr_clear(adapter, i); 2408167514Skmacy 2409167514Skmacy for (i = 0; i < ARRAY_SIZE(cause_reg_addr); ++i) 2410167514Skmacy t3_write_reg(adapter, cause_reg_addr[i], 0xffffffff); 2411167514Skmacy 2412172096Skmacy if (is_pcie(adapter)) 2413172096Skmacy t3_write_reg(adapter, A_PCIE_PEX_ERR, 0xffffffff); 2414167514Skmacy t3_write_reg(adapter, A_PL_INT_CAUSE0, 0xffffffff); 2415167514Skmacy (void) t3_read_reg(adapter, A_PL_INT_CAUSE0); /* flush */ 2416167514Skmacy} 2417167514Skmacy 2418189643Sgnnvoid t3_xgm_intr_enable(adapter_t *adapter, int idx) 2419189643Sgnn{ 2420189643Sgnn struct port_info *pi = adap2pinfo(adapter, idx); 2421189643Sgnn 2422189643Sgnn t3_write_reg(adapter, A_XGM_XGM_INT_ENABLE + pi->mac.offset, 2423189643Sgnn XGM_EXTRA_INTR_MASK); 2424189643Sgnn} 2425189643Sgnn 2426189643Sgnnvoid t3_xgm_intr_disable(adapter_t *adapter, int idx) 2427189643Sgnn{ 2428189643Sgnn struct port_info *pi = adap2pinfo(adapter, idx); 2429189643Sgnn 2430189643Sgnn t3_write_reg(adapter, A_XGM_XGM_INT_DISABLE + pi->mac.offset, 2431189643Sgnn 0x7ff); 2432189643Sgnn} 2433189643Sgnn 2434167514Skmacy/** 2435167514Skmacy * t3_port_intr_enable - enable port-specific interrupts 2436167514Skmacy * @adapter: associated adapter 2437167514Skmacy * @idx: index of port whose interrupts should be enabled 2438167514Skmacy * 2439167514Skmacy * Enable port-specific (i.e., MAC and PHY) interrupts for the given 2440167514Skmacy * adapter port. 2441167514Skmacy */ 2442167514Skmacyvoid t3_port_intr_enable(adapter_t *adapter, int idx) 2443167514Skmacy{ 2444170654Skmacy struct port_info *pi = adap2pinfo(adapter, idx); 2445170654Skmacy 2446170654Skmacy t3_write_reg(adapter, A_XGM_INT_ENABLE + pi->mac.offset, XGM_INTR_MASK); 2447170654Skmacy pi->phy.ops->intr_enable(&pi->phy); 2448167514Skmacy} 2449167514Skmacy 2450167514Skmacy/** 2451167514Skmacy * t3_port_intr_disable - disable port-specific interrupts 2452167514Skmacy * @adapter: associated adapter 2453167514Skmacy * @idx: index of port whose interrupts should be disabled 2454167514Skmacy * 2455167514Skmacy * Disable port-specific (i.e., MAC and PHY) interrupts for the given 2456167514Skmacy * adapter port. 2457167514Skmacy */ 2458167514Skmacyvoid t3_port_intr_disable(adapter_t *adapter, int idx) 2459167514Skmacy{ 2460170654Skmacy struct port_info *pi = adap2pinfo(adapter, idx); 2461170654Skmacy 2462170654Skmacy t3_write_reg(adapter, A_XGM_INT_ENABLE + pi->mac.offset, 0); 2463170654Skmacy pi->phy.ops->intr_disable(&pi->phy); 2464167514Skmacy} 2465167514Skmacy 2466167514Skmacy/** 2467167514Skmacy * t3_port_intr_clear - clear port-specific interrupts 2468167514Skmacy * @adapter: associated adapter 2469167514Skmacy * @idx: index of port whose interrupts to clear 2470167514Skmacy * 2471167514Skmacy * Clear port-specific (i.e., MAC and PHY) interrupts for the given 2472167514Skmacy * adapter port. 2473167514Skmacy */ 2474167514Skmacyvoid t3_port_intr_clear(adapter_t *adapter, int idx) 2475167514Skmacy{ 2476170654Skmacy struct port_info *pi = adap2pinfo(adapter, idx); 2477170654Skmacy 2478170654Skmacy t3_write_reg(adapter, A_XGM_INT_CAUSE + pi->mac.offset, 0xffffffff); 2479170654Skmacy pi->phy.ops->intr_clear(&pi->phy); 2480167514Skmacy} 2481167514Skmacy 2482172096Skmacy#define SG_CONTEXT_CMD_ATTEMPTS 100 2483172096Skmacy 2484167514Skmacy/** 2485167514Skmacy * t3_sge_write_context - write an SGE context 2486167514Skmacy * @adapter: the adapter 2487167514Skmacy * @id: the context id 2488167514Skmacy * @type: the context type 2489167514Skmacy * 2490167514Skmacy * Program an SGE context with the values already loaded in the 2491167514Skmacy * CONTEXT_DATA? registers. 2492167514Skmacy */ 2493167514Skmacystatic int t3_sge_write_context(adapter_t *adapter, unsigned int id, 2494167514Skmacy unsigned int type) 2495167514Skmacy{ 2496189643Sgnn if (type == F_RESPONSEQ) { 2497189643Sgnn /* 2498189643Sgnn * Can't write the Response Queue Context bits for 2499189643Sgnn * Interrupt Armed or the Reserve bits after the chip 2500189643Sgnn * has been initialized out of reset. Writing to these 2501189643Sgnn * bits can confuse the hardware. 2502189643Sgnn */ 2503189643Sgnn t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0xffffffff); 2504189643Sgnn t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0xffffffff); 2505189643Sgnn t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0x17ffffff); 2506189643Sgnn t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0xffffffff); 2507189643Sgnn } else { 2508189643Sgnn t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0xffffffff); 2509189643Sgnn t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0xffffffff); 2510189643Sgnn t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0xffffffff); 2511189643Sgnn t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0xffffffff); 2512189643Sgnn } 2513167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_CMD, 2514167514Skmacy V_CONTEXT_CMD_OPCODE(1) | type | V_CONTEXT(id)); 2515167514Skmacy return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, 2516172096Skmacy 0, SG_CONTEXT_CMD_ATTEMPTS, 1); 2517167514Skmacy} 2518167514Skmacy 2519189643Sgnn/** 2520189643Sgnn * clear_sge_ctxt - completely clear an SGE context 2521189643Sgnn * @adapter: the adapter 2522189643Sgnn * @id: the context id 2523189643Sgnn * @type: the context type 2524189643Sgnn * 2525189643Sgnn * Completely clear an SGE context. Used predominantly at post-reset 2526189643Sgnn * initialization. Note in particular that we don't skip writing to any 2527189643Sgnn * "sensitive bits" in the contexts the way that t3_sge_write_context() 2528189643Sgnn * does ... 2529189643Sgnn */ 2530176472Skmacystatic int clear_sge_ctxt(adapter_t *adap, unsigned int id, unsigned int type) 2531176472Skmacy{ 2532176472Skmacy t3_write_reg(adap, A_SG_CONTEXT_DATA0, 0); 2533176472Skmacy t3_write_reg(adap, A_SG_CONTEXT_DATA1, 0); 2534176472Skmacy t3_write_reg(adap, A_SG_CONTEXT_DATA2, 0); 2535176472Skmacy t3_write_reg(adap, A_SG_CONTEXT_DATA3, 0); 2536189643Sgnn t3_write_reg(adap, A_SG_CONTEXT_MASK0, 0xffffffff); 2537189643Sgnn t3_write_reg(adap, A_SG_CONTEXT_MASK1, 0xffffffff); 2538189643Sgnn t3_write_reg(adap, A_SG_CONTEXT_MASK2, 0xffffffff); 2539189643Sgnn t3_write_reg(adap, A_SG_CONTEXT_MASK3, 0xffffffff); 2540189643Sgnn t3_write_reg(adap, A_SG_CONTEXT_CMD, 2541189643Sgnn V_CONTEXT_CMD_OPCODE(1) | type | V_CONTEXT(id)); 2542189643Sgnn return t3_wait_op_done(adap, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, 2543189643Sgnn 0, SG_CONTEXT_CMD_ATTEMPTS, 1); 2544176472Skmacy} 2545176472Skmacy 2546167514Skmacy/** 2547167514Skmacy * t3_sge_init_ecntxt - initialize an SGE egress context 2548167514Skmacy * @adapter: the adapter to configure 2549167514Skmacy * @id: the context id 2550167514Skmacy * @gts_enable: whether to enable GTS for the context 2551167514Skmacy * @type: the egress context type 2552167514Skmacy * @respq: associated response queue 2553167514Skmacy * @base_addr: base address of queue 2554167514Skmacy * @size: number of queue entries 2555167514Skmacy * @token: uP token 2556167514Skmacy * @gen: initial generation value for the context 2557167514Skmacy * @cidx: consumer pointer 2558167514Skmacy * 2559167514Skmacy * Initialize an SGE egress context and make it ready for use. If the 2560167514Skmacy * platform allows concurrent context operations, the caller is 2561167514Skmacy * responsible for appropriate locking. 2562167514Skmacy */ 2563167514Skmacyint t3_sge_init_ecntxt(adapter_t *adapter, unsigned int id, int gts_enable, 2564167514Skmacy enum sge_context_type type, int respq, u64 base_addr, 2565167514Skmacy unsigned int size, unsigned int token, int gen, 2566167514Skmacy unsigned int cidx) 2567167514Skmacy{ 2568167514Skmacy unsigned int credits = type == SGE_CNTXT_OFLD ? 0 : FW_WR_NUM; 2569167514Skmacy 2570167514Skmacy if (base_addr & 0xfff) /* must be 4K aligned */ 2571167514Skmacy return -EINVAL; 2572167514Skmacy if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) 2573167514Skmacy return -EBUSY; 2574167514Skmacy 2575167514Skmacy base_addr >>= 12; 2576167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA0, V_EC_INDEX(cidx) | 2577167514Skmacy V_EC_CREDITS(credits) | V_EC_GTS(gts_enable)); 2578167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA1, V_EC_SIZE(size) | 2579167514Skmacy V_EC_BASE_LO((u32)base_addr & 0xffff)); 2580167514Skmacy base_addr >>= 16; 2581167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA2, (u32)base_addr); 2582167514Skmacy base_addr >>= 32; 2583167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA3, 2584167514Skmacy V_EC_BASE_HI((u32)base_addr & 0xf) | V_EC_RESPQ(respq) | 2585167514Skmacy V_EC_TYPE(type) | V_EC_GEN(gen) | V_EC_UP_TOKEN(token) | 2586167514Skmacy F_EC_VALID); 2587167514Skmacy return t3_sge_write_context(adapter, id, F_EGRESS); 2588167514Skmacy} 2589167514Skmacy 2590167514Skmacy/** 2591167514Skmacy * t3_sge_init_flcntxt - initialize an SGE free-buffer list context 2592167514Skmacy * @adapter: the adapter to configure 2593167514Skmacy * @id: the context id 2594167514Skmacy * @gts_enable: whether to enable GTS for the context 2595167514Skmacy * @base_addr: base address of queue 2596167514Skmacy * @size: number of queue entries 2597167514Skmacy * @bsize: size of each buffer for this queue 2598167514Skmacy * @cong_thres: threshold to signal congestion to upstream producers 2599167514Skmacy * @gen: initial generation value for the context 2600167514Skmacy * @cidx: consumer pointer 2601167514Skmacy * 2602167514Skmacy * Initialize an SGE free list context and make it ready for use. The 2603167514Skmacy * caller is responsible for ensuring only one context operation occurs 2604167514Skmacy * at a time. 2605167514Skmacy */ 2606167514Skmacyint t3_sge_init_flcntxt(adapter_t *adapter, unsigned int id, int gts_enable, 2607167514Skmacy u64 base_addr, unsigned int size, unsigned int bsize, 2608167514Skmacy unsigned int cong_thres, int gen, unsigned int cidx) 2609167514Skmacy{ 2610167514Skmacy if (base_addr & 0xfff) /* must be 4K aligned */ 2611167514Skmacy return -EINVAL; 2612167514Skmacy if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) 2613167514Skmacy return -EBUSY; 2614167514Skmacy 2615167514Skmacy base_addr >>= 12; 2616167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA0, (u32)base_addr); 2617167514Skmacy base_addr >>= 32; 2618167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA1, 2619167514Skmacy V_FL_BASE_HI((u32)base_addr) | 2620167514Skmacy V_FL_INDEX_LO(cidx & M_FL_INDEX_LO)); 2621167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA2, V_FL_SIZE(size) | 2622167514Skmacy V_FL_GEN(gen) | V_FL_INDEX_HI(cidx >> 12) | 2623167514Skmacy V_FL_ENTRY_SIZE_LO(bsize & M_FL_ENTRY_SIZE_LO)); 2624167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA3, 2625167514Skmacy V_FL_ENTRY_SIZE_HI(bsize >> (32 - S_FL_ENTRY_SIZE_LO)) | 2626167514Skmacy V_FL_CONG_THRES(cong_thres) | V_FL_GTS(gts_enable)); 2627167514Skmacy return t3_sge_write_context(adapter, id, F_FREELIST); 2628167514Skmacy} 2629167514Skmacy 2630167514Skmacy/** 2631167514Skmacy * t3_sge_init_rspcntxt - initialize an SGE response queue context 2632167514Skmacy * @adapter: the adapter to configure 2633167514Skmacy * @id: the context id 2634167514Skmacy * @irq_vec_idx: MSI-X interrupt vector index, 0 if no MSI-X, -1 if no IRQ 2635167514Skmacy * @base_addr: base address of queue 2636167514Skmacy * @size: number of queue entries 2637167514Skmacy * @fl_thres: threshold for selecting the normal or jumbo free list 2638167514Skmacy * @gen: initial generation value for the context 2639167514Skmacy * @cidx: consumer pointer 2640167514Skmacy * 2641167514Skmacy * Initialize an SGE response queue context and make it ready for use. 2642167514Skmacy * The caller is responsible for ensuring only one context operation 2643167514Skmacy * occurs at a time. 2644167514Skmacy */ 2645167514Skmacyint t3_sge_init_rspcntxt(adapter_t *adapter, unsigned int id, int irq_vec_idx, 2646167514Skmacy u64 base_addr, unsigned int size, 2647167514Skmacy unsigned int fl_thres, int gen, unsigned int cidx) 2648167514Skmacy{ 2649189643Sgnn unsigned int ctrl, intr = 0; 2650167514Skmacy 2651167514Skmacy if (base_addr & 0xfff) /* must be 4K aligned */ 2652167514Skmacy return -EINVAL; 2653167514Skmacy if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) 2654167514Skmacy return -EBUSY; 2655167514Skmacy 2656167514Skmacy base_addr >>= 12; 2657167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA0, V_CQ_SIZE(size) | 2658167514Skmacy V_CQ_INDEX(cidx)); 2659167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA1, (u32)base_addr); 2660167514Skmacy base_addr >>= 32; 2661189643Sgnn ctrl = t3_read_reg(adapter, A_SG_CONTROL); 2662189643Sgnn if ((irq_vec_idx > 0) || 2663189643Sgnn ((irq_vec_idx == 0) && !(ctrl & F_ONEINTMULTQ))) 2664189643Sgnn intr = F_RQ_INTR_EN; 2665189643Sgnn if (irq_vec_idx >= 0) 2666189643Sgnn intr |= V_RQ_MSI_VEC(irq_vec_idx); 2667167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA2, 2668167514Skmacy V_CQ_BASE_HI((u32)base_addr) | intr | V_RQ_GEN(gen)); 2669167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA3, fl_thres); 2670167514Skmacy return t3_sge_write_context(adapter, id, F_RESPONSEQ); 2671167514Skmacy} 2672167514Skmacy 2673167514Skmacy/** 2674167514Skmacy * t3_sge_init_cqcntxt - initialize an SGE completion queue context 2675167514Skmacy * @adapter: the adapter to configure 2676167514Skmacy * @id: the context id 2677167514Skmacy * @base_addr: base address of queue 2678167514Skmacy * @size: number of queue entries 2679167514Skmacy * @rspq: response queue for async notifications 2680167514Skmacy * @ovfl_mode: CQ overflow mode 2681167514Skmacy * @credits: completion queue credits 2682167514Skmacy * @credit_thres: the credit threshold 2683167514Skmacy * 2684167514Skmacy * Initialize an SGE completion queue context and make it ready for use. 2685167514Skmacy * The caller is responsible for ensuring only one context operation 2686167514Skmacy * occurs at a time. 2687167514Skmacy */ 2688167514Skmacyint t3_sge_init_cqcntxt(adapter_t *adapter, unsigned int id, u64 base_addr, 2689167514Skmacy unsigned int size, int rspq, int ovfl_mode, 2690167514Skmacy unsigned int credits, unsigned int credit_thres) 2691167514Skmacy{ 2692167514Skmacy if (base_addr & 0xfff) /* must be 4K aligned */ 2693167514Skmacy return -EINVAL; 2694167514Skmacy if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) 2695167514Skmacy return -EBUSY; 2696167514Skmacy 2697167514Skmacy base_addr >>= 12; 2698167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA0, V_CQ_SIZE(size)); 2699167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA1, (u32)base_addr); 2700167514Skmacy base_addr >>= 32; 2701167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA2, 2702167514Skmacy V_CQ_BASE_HI((u32)base_addr) | V_CQ_RSPQ(rspq) | 2703172096Skmacy V_CQ_GEN(1) | V_CQ_OVERFLOW_MODE(ovfl_mode) | 2704172096Skmacy V_CQ_ERR(ovfl_mode)); 2705167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA3, V_CQ_CREDITS(credits) | 2706167514Skmacy V_CQ_CREDIT_THRES(credit_thres)); 2707167514Skmacy return t3_sge_write_context(adapter, id, F_CQ); 2708167514Skmacy} 2709167514Skmacy 2710167514Skmacy/** 2711167514Skmacy * t3_sge_enable_ecntxt - enable/disable an SGE egress context 2712167514Skmacy * @adapter: the adapter 2713167514Skmacy * @id: the egress context id 2714167514Skmacy * @enable: enable (1) or disable (0) the context 2715167514Skmacy * 2716167514Skmacy * Enable or disable an SGE egress context. The caller is responsible for 2717167514Skmacy * ensuring only one context operation occurs at a time. 2718167514Skmacy */ 2719167514Skmacyint t3_sge_enable_ecntxt(adapter_t *adapter, unsigned int id, int enable) 2720167514Skmacy{ 2721167514Skmacy if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) 2722167514Skmacy return -EBUSY; 2723167514Skmacy 2724167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0); 2725167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0); 2726167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0); 2727167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_MASK3, F_EC_VALID); 2728167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA3, V_EC_VALID(enable)); 2729167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_CMD, 2730167514Skmacy V_CONTEXT_CMD_OPCODE(1) | F_EGRESS | V_CONTEXT(id)); 2731167514Skmacy return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, 2732172096Skmacy 0, SG_CONTEXT_CMD_ATTEMPTS, 1); 2733167514Skmacy} 2734167514Skmacy 2735167514Skmacy/** 2736167514Skmacy * t3_sge_disable_fl - disable an SGE free-buffer list 2737167514Skmacy * @adapter: the adapter 2738167514Skmacy * @id: the free list context id 2739167514Skmacy * 2740167514Skmacy * Disable an SGE free-buffer list. The caller is responsible for 2741167514Skmacy * ensuring only one context operation occurs at a time. 2742167514Skmacy */ 2743167514Skmacyint t3_sge_disable_fl(adapter_t *adapter, unsigned int id) 2744167514Skmacy{ 2745167514Skmacy if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) 2746167514Skmacy return -EBUSY; 2747167514Skmacy 2748167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0); 2749167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0); 2750167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_MASK2, V_FL_SIZE(M_FL_SIZE)); 2751167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0); 2752167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA2, 0); 2753167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_CMD, 2754167514Skmacy V_CONTEXT_CMD_OPCODE(1) | F_FREELIST | V_CONTEXT(id)); 2755167514Skmacy return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, 2756172096Skmacy 0, SG_CONTEXT_CMD_ATTEMPTS, 1); 2757167514Skmacy} 2758167514Skmacy 2759167514Skmacy/** 2760167514Skmacy * t3_sge_disable_rspcntxt - disable an SGE response queue 2761167514Skmacy * @adapter: the adapter 2762167514Skmacy * @id: the response queue context id 2763167514Skmacy * 2764167514Skmacy * Disable an SGE response queue. The caller is responsible for 2765167514Skmacy * ensuring only one context operation occurs at a time. 2766167514Skmacy */ 2767167514Skmacyint t3_sge_disable_rspcntxt(adapter_t *adapter, unsigned int id) 2768167514Skmacy{ 2769167514Skmacy if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) 2770167514Skmacy return -EBUSY; 2771167514Skmacy 2772167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_MASK0, V_CQ_SIZE(M_CQ_SIZE)); 2773167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0); 2774167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0); 2775167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0); 2776167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA0, 0); 2777167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_CMD, 2778167514Skmacy V_CONTEXT_CMD_OPCODE(1) | F_RESPONSEQ | V_CONTEXT(id)); 2779167514Skmacy return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, 2780172096Skmacy 0, SG_CONTEXT_CMD_ATTEMPTS, 1); 2781167514Skmacy} 2782167514Skmacy 2783167514Skmacy/** 2784167514Skmacy * t3_sge_disable_cqcntxt - disable an SGE completion queue 2785167514Skmacy * @adapter: the adapter 2786167514Skmacy * @id: the completion queue context id 2787167514Skmacy * 2788167514Skmacy * Disable an SGE completion queue. The caller is responsible for 2789167514Skmacy * ensuring only one context operation occurs at a time. 2790167514Skmacy */ 2791167514Skmacyint t3_sge_disable_cqcntxt(adapter_t *adapter, unsigned int id) 2792167514Skmacy{ 2793167514Skmacy if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) 2794167514Skmacy return -EBUSY; 2795167514Skmacy 2796167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_MASK0, V_CQ_SIZE(M_CQ_SIZE)); 2797167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0); 2798167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0); 2799167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0); 2800167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA0, 0); 2801167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_CMD, 2802167514Skmacy V_CONTEXT_CMD_OPCODE(1) | F_CQ | V_CONTEXT(id)); 2803167514Skmacy return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, 2804172096Skmacy 0, SG_CONTEXT_CMD_ATTEMPTS, 1); 2805167514Skmacy} 2806167514Skmacy 2807167514Skmacy/** 2808167514Skmacy * t3_sge_cqcntxt_op - perform an operation on a completion queue context 2809167514Skmacy * @adapter: the adapter 2810167514Skmacy * @id: the context id 2811167514Skmacy * @op: the operation to perform 2812172096Skmacy * @credits: credits to return to the CQ 2813167514Skmacy * 2814167514Skmacy * Perform the selected operation on an SGE completion queue context. 2815167514Skmacy * The caller is responsible for ensuring only one context operation 2816167514Skmacy * occurs at a time. 2817172096Skmacy * 2818172096Skmacy * For most operations the function returns the current HW position in 2819172096Skmacy * the completion queue. 2820167514Skmacy */ 2821167514Skmacyint t3_sge_cqcntxt_op(adapter_t *adapter, unsigned int id, unsigned int op, 2822167514Skmacy unsigned int credits) 2823167514Skmacy{ 2824167514Skmacy u32 val; 2825167514Skmacy 2826167514Skmacy if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) 2827167514Skmacy return -EBUSY; 2828167514Skmacy 2829167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA0, credits << 16); 2830167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_CMD, V_CONTEXT_CMD_OPCODE(op) | 2831167514Skmacy V_CONTEXT(id) | F_CQ); 2832167514Skmacy if (t3_wait_op_done_val(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, 2833172096Skmacy 0, SG_CONTEXT_CMD_ATTEMPTS, 1, &val)) 2834167514Skmacy return -EIO; 2835167514Skmacy 2836167514Skmacy if (op >= 2 && op < 7) { 2837167514Skmacy if (adapter->params.rev > 0) 2838167514Skmacy return G_CQ_INDEX(val); 2839167514Skmacy 2840167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_CMD, 2841167514Skmacy V_CONTEXT_CMD_OPCODE(0) | F_CQ | V_CONTEXT(id)); 2842167514Skmacy if (t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, 2843172096Skmacy F_CONTEXT_CMD_BUSY, 0, 2844172096Skmacy SG_CONTEXT_CMD_ATTEMPTS, 1)) 2845167514Skmacy return -EIO; 2846167514Skmacy return G_CQ_INDEX(t3_read_reg(adapter, A_SG_CONTEXT_DATA0)); 2847167514Skmacy } 2848167514Skmacy return 0; 2849167514Skmacy} 2850167514Skmacy 2851167514Skmacy/** 2852167514Skmacy * t3_sge_read_context - read an SGE context 2853167514Skmacy * @type: the context type 2854167514Skmacy * @adapter: the adapter 2855167514Skmacy * @id: the context id 2856167514Skmacy * @data: holds the retrieved context 2857167514Skmacy * 2858167514Skmacy * Read an SGE egress context. The caller is responsible for ensuring 2859167514Skmacy * only one context operation occurs at a time. 2860167514Skmacy */ 2861167514Skmacystatic int t3_sge_read_context(unsigned int type, adapter_t *adapter, 2862167514Skmacy unsigned int id, u32 data[4]) 2863167514Skmacy{ 2864167514Skmacy if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) 2865167514Skmacy return -EBUSY; 2866167514Skmacy 2867167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_CMD, 2868167514Skmacy V_CONTEXT_CMD_OPCODE(0) | type | V_CONTEXT(id)); 2869167514Skmacy if (t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, 0, 2870172096Skmacy SG_CONTEXT_CMD_ATTEMPTS, 1)) 2871167514Skmacy return -EIO; 2872167514Skmacy data[0] = t3_read_reg(adapter, A_SG_CONTEXT_DATA0); 2873167514Skmacy data[1] = t3_read_reg(adapter, A_SG_CONTEXT_DATA1); 2874167514Skmacy data[2] = t3_read_reg(adapter, A_SG_CONTEXT_DATA2); 2875167514Skmacy data[3] = t3_read_reg(adapter, A_SG_CONTEXT_DATA3); 2876167514Skmacy return 0; 2877167514Skmacy} 2878167514Skmacy 2879167514Skmacy/** 2880167514Skmacy * t3_sge_read_ecntxt - read an SGE egress context 2881167514Skmacy * @adapter: the adapter 2882167514Skmacy * @id: the context id 2883167514Skmacy * @data: holds the retrieved context 2884167514Skmacy * 2885167514Skmacy * Read an SGE egress context. The caller is responsible for ensuring 2886167514Skmacy * only one context operation occurs at a time. 2887167514Skmacy */ 2888167514Skmacyint t3_sge_read_ecntxt(adapter_t *adapter, unsigned int id, u32 data[4]) 2889167514Skmacy{ 2890167514Skmacy if (id >= 65536) 2891167514Skmacy return -EINVAL; 2892167514Skmacy return t3_sge_read_context(F_EGRESS, adapter, id, data); 2893167514Skmacy} 2894167514Skmacy 2895167514Skmacy/** 2896167514Skmacy * t3_sge_read_cq - read an SGE CQ context 2897167514Skmacy * @adapter: the adapter 2898167514Skmacy * @id: the context id 2899167514Skmacy * @data: holds the retrieved context 2900167514Skmacy * 2901167514Skmacy * Read an SGE CQ context. The caller is responsible for ensuring 2902167514Skmacy * only one context operation occurs at a time. 2903167514Skmacy */ 2904167514Skmacyint t3_sge_read_cq(adapter_t *adapter, unsigned int id, u32 data[4]) 2905167514Skmacy{ 2906167514Skmacy if (id >= 65536) 2907167514Skmacy return -EINVAL; 2908167514Skmacy return t3_sge_read_context(F_CQ, adapter, id, data); 2909167514Skmacy} 2910167514Skmacy 2911167514Skmacy/** 2912167514Skmacy * t3_sge_read_fl - read an SGE free-list context 2913167514Skmacy * @adapter: the adapter 2914167514Skmacy * @id: the context id 2915167514Skmacy * @data: holds the retrieved context 2916167514Skmacy * 2917167514Skmacy * Read an SGE free-list context. The caller is responsible for ensuring 2918167514Skmacy * only one context operation occurs at a time. 2919167514Skmacy */ 2920167514Skmacyint t3_sge_read_fl(adapter_t *adapter, unsigned int id, u32 data[4]) 2921167514Skmacy{ 2922167514Skmacy if (id >= SGE_QSETS * 2) 2923167514Skmacy return -EINVAL; 2924167514Skmacy return t3_sge_read_context(F_FREELIST, adapter, id, data); 2925167514Skmacy} 2926167514Skmacy 2927167514Skmacy/** 2928167514Skmacy * t3_sge_read_rspq - read an SGE response queue context 2929167514Skmacy * @adapter: the adapter 2930167514Skmacy * @id: the context id 2931167514Skmacy * @data: holds the retrieved context 2932167514Skmacy * 2933167514Skmacy * Read an SGE response queue context. The caller is responsible for 2934167514Skmacy * ensuring only one context operation occurs at a time. 2935167514Skmacy */ 2936167514Skmacyint t3_sge_read_rspq(adapter_t *adapter, unsigned int id, u32 data[4]) 2937167514Skmacy{ 2938167514Skmacy if (id >= SGE_QSETS) 2939167514Skmacy return -EINVAL; 2940167514Skmacy return t3_sge_read_context(F_RESPONSEQ, adapter, id, data); 2941167514Skmacy} 2942167514Skmacy 2943167514Skmacy/** 2944167514Skmacy * t3_config_rss - configure Rx packet steering 2945167514Skmacy * @adapter: the adapter 2946167514Skmacy * @rss_config: RSS settings (written to TP_RSS_CONFIG) 2947167514Skmacy * @cpus: values for the CPU lookup table (0xff terminated) 2948167514Skmacy * @rspq: values for the response queue lookup table (0xffff terminated) 2949167514Skmacy * 2950167514Skmacy * Programs the receive packet steering logic. @cpus and @rspq provide 2951167514Skmacy * the values for the CPU and response queue lookup tables. If they 2952167514Skmacy * provide fewer values than the size of the tables the supplied values 2953167514Skmacy * are used repeatedly until the tables are fully populated. 2954167514Skmacy */ 2955167514Skmacyvoid t3_config_rss(adapter_t *adapter, unsigned int rss_config, const u8 *cpus, 2956167514Skmacy const u16 *rspq) 2957167514Skmacy{ 2958167514Skmacy int i, j, cpu_idx = 0, q_idx = 0; 2959167514Skmacy 2960167514Skmacy if (cpus) 2961167514Skmacy for (i = 0; i < RSS_TABLE_SIZE; ++i) { 2962167514Skmacy u32 val = i << 16; 2963167514Skmacy 2964167514Skmacy for (j = 0; j < 2; ++j) { 2965167514Skmacy val |= (cpus[cpu_idx++] & 0x3f) << (8 * j); 2966167514Skmacy if (cpus[cpu_idx] == 0xff) 2967167514Skmacy cpu_idx = 0; 2968167514Skmacy } 2969167514Skmacy t3_write_reg(adapter, A_TP_RSS_LKP_TABLE, val); 2970167514Skmacy } 2971167514Skmacy 2972167514Skmacy if (rspq) 2973167514Skmacy for (i = 0; i < RSS_TABLE_SIZE; ++i) { 2974167514Skmacy t3_write_reg(adapter, A_TP_RSS_MAP_TABLE, 2975167514Skmacy (i << 16) | rspq[q_idx++]); 2976167514Skmacy if (rspq[q_idx] == 0xffff) 2977167514Skmacy q_idx = 0; 2978167514Skmacy } 2979167514Skmacy 2980167514Skmacy t3_write_reg(adapter, A_TP_RSS_CONFIG, rss_config); 2981167514Skmacy} 2982167514Skmacy 2983167514Skmacy/** 2984167514Skmacy * t3_read_rss - read the contents of the RSS tables 2985167514Skmacy * @adapter: the adapter 2986167514Skmacy * @lkup: holds the contents of the RSS lookup table 2987167514Skmacy * @map: holds the contents of the RSS map table 2988167514Skmacy * 2989167514Skmacy * Reads the contents of the receive packet steering tables. 2990167514Skmacy */ 2991167514Skmacyint t3_read_rss(adapter_t *adapter, u8 *lkup, u16 *map) 2992167514Skmacy{ 2993167514Skmacy int i; 2994167514Skmacy u32 val; 2995167514Skmacy 2996167514Skmacy if (lkup) 2997167514Skmacy for (i = 0; i < RSS_TABLE_SIZE; ++i) { 2998167514Skmacy t3_write_reg(adapter, A_TP_RSS_LKP_TABLE, 2999167514Skmacy 0xffff0000 | i); 3000167514Skmacy val = t3_read_reg(adapter, A_TP_RSS_LKP_TABLE); 3001167514Skmacy if (!(val & 0x80000000)) 3002167514Skmacy return -EAGAIN; 3003167514Skmacy *lkup++ = (u8)val; 3004167514Skmacy *lkup++ = (u8)(val >> 8); 3005167514Skmacy } 3006167514Skmacy 3007167514Skmacy if (map) 3008167514Skmacy for (i = 0; i < RSS_TABLE_SIZE; ++i) { 3009167514Skmacy t3_write_reg(adapter, A_TP_RSS_MAP_TABLE, 3010167514Skmacy 0xffff0000 | i); 3011167514Skmacy val = t3_read_reg(adapter, A_TP_RSS_MAP_TABLE); 3012167514Skmacy if (!(val & 0x80000000)) 3013167514Skmacy return -EAGAIN; 3014167514Skmacy *map++ = (u16)val; 3015167514Skmacy } 3016167514Skmacy return 0; 3017167514Skmacy} 3018167514Skmacy 3019167514Skmacy/** 3020167514Skmacy * t3_tp_set_offload_mode - put TP in NIC/offload mode 3021167514Skmacy * @adap: the adapter 3022167514Skmacy * @enable: 1 to select offload mode, 0 for regular NIC 3023167514Skmacy * 3024167514Skmacy * Switches TP to NIC/offload mode. 3025167514Skmacy */ 3026167514Skmacyvoid t3_tp_set_offload_mode(adapter_t *adap, int enable) 3027167514Skmacy{ 3028167514Skmacy if (is_offload(adap) || !enable) 3029167514Skmacy t3_set_reg_field(adap, A_TP_IN_CONFIG, F_NICMODE, 3030167514Skmacy V_NICMODE(!enable)); 3031167514Skmacy} 3032167514Skmacy 3033172096Skmacy/** 3034172096Skmacy * tp_wr_bits_indirect - set/clear bits in an indirect TP register 3035172096Skmacy * @adap: the adapter 3036172096Skmacy * @addr: the indirect TP register address 3037172096Skmacy * @mask: specifies the field within the register to modify 3038172096Skmacy * @val: new value for the field 3039172096Skmacy * 3040172096Skmacy * Sets a field of an indirect TP register to the given value. 3041172096Skmacy */ 3042171471Skmacystatic void tp_wr_bits_indirect(adapter_t *adap, unsigned int addr, 3043171471Skmacy unsigned int mask, unsigned int val) 3044171471Skmacy{ 3045171471Skmacy t3_write_reg(adap, A_TP_PIO_ADDR, addr); 3046171471Skmacy val |= t3_read_reg(adap, A_TP_PIO_DATA) & ~mask; 3047171471Skmacy t3_write_reg(adap, A_TP_PIO_DATA, val); 3048171471Skmacy} 3049171471Skmacy 3050167514Skmacy/** 3051180583Skmacy * t3_enable_filters - enable the HW filters 3052180583Skmacy * @adap: the adapter 3053180583Skmacy * 3054180583Skmacy * Enables the HW filters for NIC traffic. 3055180583Skmacy */ 3056180583Skmacyvoid t3_enable_filters(adapter_t *adap) 3057180583Skmacy{ 3058180583Skmacy t3_set_reg_field(adap, A_TP_IN_CONFIG, F_NICMODE, 0); 3059180583Skmacy t3_set_reg_field(adap, A_MC5_DB_CONFIG, 0, F_FILTEREN); 3060180583Skmacy t3_set_reg_field(adap, A_TP_GLOBAL_CONFIG, 0, V_FIVETUPLELOOKUP(3)); 3061180583Skmacy tp_wr_bits_indirect(adap, A_TP_INGRESS_CONFIG, 0, F_LOOKUPEVERYPKT); 3062180583Skmacy} 3063180583Skmacy 3064180583Skmacy/** 3065189643Sgnn * t3_disable_filters - disable the HW filters 3066189643Sgnn * @adap: the adapter 3067189643Sgnn * 3068189643Sgnn * Disables the HW filters for NIC traffic. 3069189643Sgnn */ 3070189643Sgnnvoid t3_disable_filters(adapter_t *adap) 3071189643Sgnn{ 3072189643Sgnn /* note that we don't want to revert to NIC-only mode */ 3073189643Sgnn t3_set_reg_field(adap, A_MC5_DB_CONFIG, F_FILTEREN, 0); 3074189643Sgnn t3_set_reg_field(adap, A_TP_GLOBAL_CONFIG, 3075189643Sgnn V_FIVETUPLELOOKUP(M_FIVETUPLELOOKUP), 0); 3076189643Sgnn tp_wr_bits_indirect(adap, A_TP_INGRESS_CONFIG, F_LOOKUPEVERYPKT, 0); 3077189643Sgnn} 3078189643Sgnn 3079189643Sgnn/** 3080167514Skmacy * pm_num_pages - calculate the number of pages of the payload memory 3081167514Skmacy * @mem_size: the size of the payload memory 3082167514Skmacy * @pg_size: the size of each payload memory page 3083167514Skmacy * 3084167514Skmacy * Calculate the number of pages, each of the given size, that fit in a 3085167514Skmacy * memory of the specified size, respecting the HW requirement that the 3086167514Skmacy * number of pages must be a multiple of 24. 3087167514Skmacy */ 3088167514Skmacystatic inline unsigned int pm_num_pages(unsigned int mem_size, 3089167514Skmacy unsigned int pg_size) 3090167514Skmacy{ 3091167514Skmacy unsigned int n = mem_size / pg_size; 3092167514Skmacy 3093167514Skmacy return n - n % 24; 3094167514Skmacy} 3095167514Skmacy 3096167514Skmacy#define mem_region(adap, start, size, reg) \ 3097167514Skmacy t3_write_reg((adap), A_ ## reg, (start)); \ 3098167514Skmacy start += size 3099167514Skmacy 3100172096Skmacy/** 3101167514Skmacy * partition_mem - partition memory and configure TP memory settings 3102167514Skmacy * @adap: the adapter 3103167514Skmacy * @p: the TP parameters 3104167514Skmacy * 3105167514Skmacy * Partitions context and payload memory and configures TP's memory 3106167514Skmacy * registers. 3107167514Skmacy */ 3108167514Skmacystatic void partition_mem(adapter_t *adap, const struct tp_params *p) 3109167514Skmacy{ 3110167514Skmacy unsigned int m, pstructs, tids = t3_mc5_size(&adap->mc5); 3111167514Skmacy unsigned int timers = 0, timers_shift = 22; 3112167514Skmacy 3113167514Skmacy if (adap->params.rev > 0) { 3114167514Skmacy if (tids <= 16 * 1024) { 3115167514Skmacy timers = 1; 3116167514Skmacy timers_shift = 16; 3117167514Skmacy } else if (tids <= 64 * 1024) { 3118167514Skmacy timers = 2; 3119167514Skmacy timers_shift = 18; 3120167514Skmacy } else if (tids <= 256 * 1024) { 3121167514Skmacy timers = 3; 3122167514Skmacy timers_shift = 20; 3123167514Skmacy } 3124167514Skmacy } 3125167514Skmacy 3126167514Skmacy t3_write_reg(adap, A_TP_PMM_SIZE, 3127167514Skmacy p->chan_rx_size | (p->chan_tx_size >> 16)); 3128167514Skmacy 3129167514Skmacy t3_write_reg(adap, A_TP_PMM_TX_BASE, 0); 3130167514Skmacy t3_write_reg(adap, A_TP_PMM_TX_PAGE_SIZE, p->tx_pg_size); 3131167514Skmacy t3_write_reg(adap, A_TP_PMM_TX_MAX_PAGE, p->tx_num_pgs); 3132167514Skmacy t3_set_reg_field(adap, A_TP_PARA_REG3, V_TXDATAACKIDX(M_TXDATAACKIDX), 3133167514Skmacy V_TXDATAACKIDX(fls(p->tx_pg_size) - 12)); 3134167514Skmacy 3135167514Skmacy t3_write_reg(adap, A_TP_PMM_RX_BASE, 0); 3136167514Skmacy t3_write_reg(adap, A_TP_PMM_RX_PAGE_SIZE, p->rx_pg_size); 3137167514Skmacy t3_write_reg(adap, A_TP_PMM_RX_MAX_PAGE, p->rx_num_pgs); 3138167514Skmacy 3139167514Skmacy pstructs = p->rx_num_pgs + p->tx_num_pgs; 3140167514Skmacy /* Add a bit of headroom and make multiple of 24 */ 3141167514Skmacy pstructs += 48; 3142167514Skmacy pstructs -= pstructs % 24; 3143167514Skmacy t3_write_reg(adap, A_TP_CMM_MM_MAX_PSTRUCT, pstructs); 3144167514Skmacy 3145167514Skmacy m = tids * TCB_SIZE; 3146167514Skmacy mem_region(adap, m, (64 << 10) * 64, SG_EGR_CNTX_BADDR); 3147167514Skmacy mem_region(adap, m, (64 << 10) * 64, SG_CQ_CONTEXT_BADDR); 3148167514Skmacy t3_write_reg(adap, A_TP_CMM_TIMER_BASE, V_CMTIMERMAXNUM(timers) | m); 3149167514Skmacy m += ((p->ntimer_qs - 1) << timers_shift) + (1 << 22); 3150167514Skmacy mem_region(adap, m, pstructs * 64, TP_CMM_MM_BASE); 3151167514Skmacy mem_region(adap, m, 64 * (pstructs / 24), TP_CMM_MM_PS_FLST_BASE); 3152167514Skmacy mem_region(adap, m, 64 * (p->rx_num_pgs / 24), TP_CMM_MM_RX_FLST_BASE); 3153167514Skmacy mem_region(adap, m, 64 * (p->tx_num_pgs / 24), TP_CMM_MM_TX_FLST_BASE); 3154167514Skmacy 3155167514Skmacy m = (m + 4095) & ~0xfff; 3156167514Skmacy t3_write_reg(adap, A_CIM_SDRAM_BASE_ADDR, m); 3157167514Skmacy t3_write_reg(adap, A_CIM_SDRAM_ADDR_SIZE, p->cm_size - m); 3158167514Skmacy 3159167514Skmacy tids = (p->cm_size - m - (3 << 20)) / 3072 - 32; 3160167514Skmacy m = t3_mc5_size(&adap->mc5) - adap->params.mc5.nservers - 3161167514Skmacy adap->params.mc5.nfilters - adap->params.mc5.nroutes; 3162167514Skmacy if (tids < m) 3163167514Skmacy adap->params.mc5.nservers += m - tids; 3164167514Skmacy} 3165167514Skmacy 3166167514Skmacystatic inline void tp_wr_indirect(adapter_t *adap, unsigned int addr, u32 val) 3167167514Skmacy{ 3168167514Skmacy t3_write_reg(adap, A_TP_PIO_ADDR, addr); 3169167514Skmacy t3_write_reg(adap, A_TP_PIO_DATA, val); 3170167514Skmacy} 3171167514Skmacy 3172189643Sgnnstatic inline u32 tp_rd_indirect(adapter_t *adap, unsigned int addr) 3173189643Sgnn{ 3174189643Sgnn t3_write_reg(adap, A_TP_PIO_ADDR, addr); 3175189643Sgnn return t3_read_reg(adap, A_TP_PIO_DATA); 3176189643Sgnn} 3177189643Sgnn 3178167514Skmacystatic void tp_config(adapter_t *adap, const struct tp_params *p) 3179167514Skmacy{ 3180167514Skmacy t3_write_reg(adap, A_TP_GLOBAL_CONFIG, F_TXPACINGENABLE | F_PATHMTU | 3181167514Skmacy F_IPCHECKSUMOFFLOAD | F_UDPCHECKSUMOFFLOAD | 3182167514Skmacy F_TCPCHECKSUMOFFLOAD | V_IPTTL(64)); 3183167514Skmacy t3_write_reg(adap, A_TP_TCP_OPTIONS, V_MTUDEFAULT(576) | 3184167514Skmacy F_MTUENABLE | V_WINDOWSCALEMODE(1) | 3185180583Skmacy V_TIMESTAMPSMODE(1) | V_SACKMODE(1) | V_SACKRX(1)); 3186167514Skmacy t3_write_reg(adap, A_TP_DACK_CONFIG, V_AUTOSTATE3(1) | 3187167514Skmacy V_AUTOSTATE2(1) | V_AUTOSTATE1(0) | 3188180583Skmacy V_BYTETHRESHOLD(26880) | V_MSSTHRESHOLD(2) | 3189167514Skmacy F_AUTOCAREFUL | F_AUTOENABLE | V_DACK_MODE(1)); 3190176472Skmacy t3_set_reg_field(adap, A_TP_IN_CONFIG, F_RXFBARBPRIO | F_TXFBARBPRIO, 3191167514Skmacy F_IPV6ENABLE | F_NICMODE); 3192167514Skmacy t3_write_reg(adap, A_TP_TX_RESOURCE_LIMIT, 0x18141814); 3193167514Skmacy t3_write_reg(adap, A_TP_PARA_REG4, 0x5050105); 3194170654Skmacy t3_set_reg_field(adap, A_TP_PARA_REG6, 0, 3195170654Skmacy adap->params.rev > 0 ? F_ENABLEESND : 3196170654Skmacy F_T3A_ENABLEESND); 3197167514Skmacy t3_set_reg_field(adap, A_TP_PC_CONFIG, 3198170654Skmacy F_ENABLEEPCMDAFULL, 3199170654Skmacy F_ENABLEOCSPIFULL |F_TXDEFERENABLE | F_HEARBEATDACK | 3200170654Skmacy F_TXCONGESTIONMODE | F_RXCONGESTIONMODE); 3201176472Skmacy t3_set_reg_field(adap, A_TP_PC_CONFIG2, F_CHDRAFULL, 3202176472Skmacy F_ENABLEIPV6RSS | F_ENABLENONOFDTNLSYN | 3203176472Skmacy F_ENABLEARPMISS | F_DISBLEDAPARBIT0); 3204170654Skmacy t3_write_reg(adap, A_TP_PROXY_FLOW_CNTL, 1080); 3205170654Skmacy t3_write_reg(adap, A_TP_PROXY_FLOW_CNTL, 1000); 3206167514Skmacy 3207167514Skmacy if (adap->params.rev > 0) { 3208167514Skmacy tp_wr_indirect(adap, A_TP_EGRESS_CONFIG, F_REWRITEFORCETOSIZE); 3209171471Skmacy t3_set_reg_field(adap, A_TP_PARA_REG3, 0, 3210171471Skmacy F_TXPACEAUTO | F_TXPACEAUTOSTRICT); 3211167514Skmacy t3_set_reg_field(adap, A_TP_PC_CONFIG, F_LOCKTID, F_LOCKTID); 3212171471Skmacy tp_wr_indirect(adap, A_TP_VLAN_PRI_MAP, 0xfa50); 3213171471Skmacy tp_wr_indirect(adap, A_TP_MAC_MATCH_MAP0, 0xfac688); 3214171471Skmacy tp_wr_indirect(adap, A_TP_MAC_MATCH_MAP1, 0xfac688); 3215167514Skmacy } else 3216167514Skmacy t3_set_reg_field(adap, A_TP_PARA_REG3, 0, F_TXPACEFIXED); 3217167514Skmacy 3218176472Skmacy if (adap->params.rev == T3_REV_C) 3219176472Skmacy t3_set_reg_field(adap, A_TP_PC_CONFIG, 3220176472Skmacy V_TABLELATENCYDELTA(M_TABLELATENCYDELTA), 3221176472Skmacy V_TABLELATENCYDELTA(4)); 3222176472Skmacy 3223167746Skmacy t3_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT1, 0); 3224167746Skmacy t3_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT0, 0); 3225167746Skmacy t3_write_reg(adap, A_TP_MOD_CHANNEL_WEIGHT, 0); 3226170654Skmacy t3_write_reg(adap, A_TP_MOD_RATE_LIMIT, 0xf2200000); 3227170654Skmacy 3228170654Skmacy if (adap->params.nports > 2) { 3229170654Skmacy t3_set_reg_field(adap, A_TP_PC_CONFIG2, 0, 3230180583Skmacy F_ENABLETXPORTFROMDA2 | F_ENABLETXPORTFROMDA | 3231180583Skmacy F_ENABLERXPORTFROMADDR); 3232170654Skmacy tp_wr_bits_indirect(adap, A_TP_QOS_RX_MAP_MODE, 3233170654Skmacy V_RXMAPMODE(M_RXMAPMODE), 0); 3234170654Skmacy tp_wr_indirect(adap, A_TP_INGRESS_CONFIG, V_BITPOS0(48) | 3235170654Skmacy V_BITPOS1(49) | V_BITPOS2(50) | V_BITPOS3(51) | 3236170654Skmacy F_ENABLEEXTRACT | F_ENABLEEXTRACTIONSFD | 3237170654Skmacy F_ENABLEINSERTION | F_ENABLEINSERTIONSFD); 3238170654Skmacy tp_wr_indirect(adap, A_TP_PREAMBLE_MSB, 0xfb000000); 3239170654Skmacy tp_wr_indirect(adap, A_TP_PREAMBLE_LSB, 0xd5); 3240170654Skmacy tp_wr_indirect(adap, A_TP_INTF_FROM_TX_PKT, F_INTFFROMTXPKT); 3241170654Skmacy } 3242167514Skmacy} 3243167514Skmacy 3244167514Skmacy/* TCP timer values in ms */ 3245167514Skmacy#define TP_DACK_TIMER 50 3246167514Skmacy#define TP_RTO_MIN 250 3247167514Skmacy 3248167514Skmacy/** 3249167514Skmacy * tp_set_timers - set TP timing parameters 3250167514Skmacy * @adap: the adapter to set 3251167514Skmacy * @core_clk: the core clock frequency in Hz 3252167514Skmacy * 3253167514Skmacy * Set TP's timing parameters, such as the various timer resolutions and 3254167514Skmacy * the TCP timer values. 3255167514Skmacy */ 3256167514Skmacystatic void tp_set_timers(adapter_t *adap, unsigned int core_clk) 3257167514Skmacy{ 3258170654Skmacy unsigned int tre = adap->params.tp.tre; 3259167746Skmacy unsigned int dack_re = adap->params.tp.dack_re; 3260167514Skmacy unsigned int tstamp_re = fls(core_clk / 1000); /* 1ms, at least */ 3261167514Skmacy unsigned int tps = core_clk >> tre; 3262167514Skmacy 3263167514Skmacy t3_write_reg(adap, A_TP_TIMER_RESOLUTION, V_TIMERRESOLUTION(tre) | 3264167514Skmacy V_DELAYEDACKRESOLUTION(dack_re) | 3265167514Skmacy V_TIMESTAMPRESOLUTION(tstamp_re)); 3266167514Skmacy t3_write_reg(adap, A_TP_DACK_TIMER, 3267167514Skmacy (core_clk >> dack_re) / (1000 / TP_DACK_TIMER)); 3268167514Skmacy t3_write_reg(adap, A_TP_TCP_BACKOFF_REG0, 0x3020100); 3269167514Skmacy t3_write_reg(adap, A_TP_TCP_BACKOFF_REG1, 0x7060504); 3270167514Skmacy t3_write_reg(adap, A_TP_TCP_BACKOFF_REG2, 0xb0a0908); 3271167514Skmacy t3_write_reg(adap, A_TP_TCP_BACKOFF_REG3, 0xf0e0d0c); 3272167514Skmacy t3_write_reg(adap, A_TP_SHIFT_CNT, V_SYNSHIFTMAX(6) | 3273167514Skmacy V_RXTSHIFTMAXR1(4) | V_RXTSHIFTMAXR2(15) | 3274167514Skmacy V_PERSHIFTBACKOFFMAX(8) | V_PERSHIFTMAX(8) | 3275167514Skmacy V_KEEPALIVEMAX(9)); 3276167514Skmacy 3277167514Skmacy#define SECONDS * tps 3278167514Skmacy 3279167514Skmacy t3_write_reg(adap, A_TP_MSL, 3280167514Skmacy adap->params.rev > 0 ? 0 : 2 SECONDS); 3281167514Skmacy t3_write_reg(adap, A_TP_RXT_MIN, tps / (1000 / TP_RTO_MIN)); 3282167514Skmacy t3_write_reg(adap, A_TP_RXT_MAX, 64 SECONDS); 3283167514Skmacy t3_write_reg(adap, A_TP_PERS_MIN, 5 SECONDS); 3284167514Skmacy t3_write_reg(adap, A_TP_PERS_MAX, 64 SECONDS); 3285167514Skmacy t3_write_reg(adap, A_TP_KEEP_IDLE, 7200 SECONDS); 3286167514Skmacy t3_write_reg(adap, A_TP_KEEP_INTVL, 75 SECONDS); 3287167514Skmacy t3_write_reg(adap, A_TP_INIT_SRTT, 3 SECONDS); 3288167514Skmacy t3_write_reg(adap, A_TP_FINWAIT2_TIMER, 600 SECONDS); 3289167514Skmacy 3290167514Skmacy#undef SECONDS 3291167514Skmacy} 3292167514Skmacy 3293167514Skmacy/** 3294167514Skmacy * t3_tp_set_coalescing_size - set receive coalescing size 3295167514Skmacy * @adap: the adapter 3296167514Skmacy * @size: the receive coalescing size 3297167514Skmacy * @psh: whether a set PSH bit should deliver coalesced data 3298167514Skmacy * 3299167514Skmacy * Set the receive coalescing size and PSH bit handling. 3300167514Skmacy */ 3301167514Skmacyint t3_tp_set_coalescing_size(adapter_t *adap, unsigned int size, int psh) 3302167514Skmacy{ 3303167514Skmacy u32 val; 3304167514Skmacy 3305167514Skmacy if (size > MAX_RX_COALESCING_LEN) 3306167514Skmacy return -EINVAL; 3307167514Skmacy 3308167514Skmacy val = t3_read_reg(adap, A_TP_PARA_REG3); 3309167514Skmacy val &= ~(F_RXCOALESCEENABLE | F_RXCOALESCEPSHEN); 3310167514Skmacy 3311167514Skmacy if (size) { 3312167514Skmacy val |= F_RXCOALESCEENABLE; 3313167514Skmacy if (psh) 3314167514Skmacy val |= F_RXCOALESCEPSHEN; 3315170654Skmacy size = min(MAX_RX_COALESCING_LEN, size); 3316167514Skmacy t3_write_reg(adap, A_TP_PARA_REG2, V_RXCOALESCESIZE(size) | 3317167514Skmacy V_MAXRXDATA(MAX_RX_COALESCING_LEN)); 3318167514Skmacy } 3319167514Skmacy t3_write_reg(adap, A_TP_PARA_REG3, val); 3320167514Skmacy return 0; 3321167514Skmacy} 3322167514Skmacy 3323167514Skmacy/** 3324167514Skmacy * t3_tp_set_max_rxsize - set the max receive size 3325167514Skmacy * @adap: the adapter 3326167514Skmacy * @size: the max receive size 3327167514Skmacy * 3328167514Skmacy * Set TP's max receive size. This is the limit that applies when 3329167514Skmacy * receive coalescing is disabled. 3330167514Skmacy */ 3331167514Skmacyvoid t3_tp_set_max_rxsize(adapter_t *adap, unsigned int size) 3332167514Skmacy{ 3333167514Skmacy t3_write_reg(adap, A_TP_PARA_REG7, 3334167514Skmacy V_PMMAXXFERLEN0(size) | V_PMMAXXFERLEN1(size)); 3335167514Skmacy} 3336167514Skmacy 3337167514Skmacystatic void __devinit init_mtus(unsigned short mtus[]) 3338167514Skmacy{ 3339167514Skmacy /* 3340167514Skmacy * See draft-mathis-plpmtud-00.txt for the values. The min is 88 so 3341298955Spfg * it can accommodate max size TCP/IP headers when SACK and timestamps 3342167514Skmacy * are enabled and still have at least 8 bytes of payload. 3343167514Skmacy */ 3344167514Skmacy mtus[0] = 88; 3345170654Skmacy mtus[1] = 88; 3346167746Skmacy mtus[2] = 256; 3347167746Skmacy mtus[3] = 512; 3348167746Skmacy mtus[4] = 576; 3349167514Skmacy mtus[5] = 1024; 3350167514Skmacy mtus[6] = 1280; 3351167514Skmacy mtus[7] = 1492; 3352167514Skmacy mtus[8] = 1500; 3353167514Skmacy mtus[9] = 2002; 3354167514Skmacy mtus[10] = 2048; 3355167514Skmacy mtus[11] = 4096; 3356167514Skmacy mtus[12] = 4352; 3357167514Skmacy mtus[13] = 8192; 3358167514Skmacy mtus[14] = 9000; 3359167514Skmacy mtus[15] = 9600; 3360167514Skmacy} 3361167514Skmacy 3362172096Skmacy/** 3363172096Skmacy * init_cong_ctrl - initialize congestion control parameters 3364172096Skmacy * @a: the alpha values for congestion control 3365172096Skmacy * @b: the beta values for congestion control 3366172096Skmacy * 3367172096Skmacy * Initialize the congestion control parameters. 3368167514Skmacy */ 3369167514Skmacystatic void __devinit init_cong_ctrl(unsigned short *a, unsigned short *b) 3370167514Skmacy{ 3371167514Skmacy a[0] = a[1] = a[2] = a[3] = a[4] = a[5] = a[6] = a[7] = a[8] = 1; 3372167514Skmacy a[9] = 2; 3373167514Skmacy a[10] = 3; 3374167514Skmacy a[11] = 4; 3375167514Skmacy a[12] = 5; 3376167514Skmacy a[13] = 6; 3377167514Skmacy a[14] = 7; 3378167514Skmacy a[15] = 8; 3379167514Skmacy a[16] = 9; 3380167514Skmacy a[17] = 10; 3381167514Skmacy a[18] = 14; 3382167514Skmacy a[19] = 17; 3383167514Skmacy a[20] = 21; 3384167514Skmacy a[21] = 25; 3385167514Skmacy a[22] = 30; 3386167514Skmacy a[23] = 35; 3387167514Skmacy a[24] = 45; 3388167514Skmacy a[25] = 60; 3389167514Skmacy a[26] = 80; 3390167514Skmacy a[27] = 100; 3391167514Skmacy a[28] = 200; 3392167514Skmacy a[29] = 300; 3393167514Skmacy a[30] = 400; 3394167514Skmacy a[31] = 500; 3395167514Skmacy 3396167514Skmacy b[0] = b[1] = b[2] = b[3] = b[4] = b[5] = b[6] = b[7] = b[8] = 0; 3397167514Skmacy b[9] = b[10] = 1; 3398167514Skmacy b[11] = b[12] = 2; 3399167514Skmacy b[13] = b[14] = b[15] = b[16] = 3; 3400167514Skmacy b[17] = b[18] = b[19] = b[20] = b[21] = 4; 3401167514Skmacy b[22] = b[23] = b[24] = b[25] = b[26] = b[27] = 5; 3402167514Skmacy b[28] = b[29] = 6; 3403167514Skmacy b[30] = b[31] = 7; 3404167514Skmacy} 3405167514Skmacy 3406167514Skmacy/* The minimum additive increment value for the congestion control table */ 3407167514Skmacy#define CC_MIN_INCR 2U 3408167514Skmacy 3409167514Skmacy/** 3410167514Skmacy * t3_load_mtus - write the MTU and congestion control HW tables 3411167514Skmacy * @adap: the adapter 3412167514Skmacy * @mtus: the unrestricted values for the MTU table 3413172096Skmacy * @alpha: the values for the congestion control alpha parameter 3414167514Skmacy * @beta: the values for the congestion control beta parameter 3415167514Skmacy * @mtu_cap: the maximum permitted effective MTU 3416167514Skmacy * 3417167514Skmacy * Write the MTU table with the supplied MTUs capping each at &mtu_cap. 3418167514Skmacy * Update the high-speed congestion control table with the supplied alpha, 3419167514Skmacy * beta, and MTUs. 3420167514Skmacy */ 3421167514Skmacyvoid t3_load_mtus(adapter_t *adap, unsigned short mtus[NMTUS], 3422167514Skmacy unsigned short alpha[NCCTRL_WIN], 3423167514Skmacy unsigned short beta[NCCTRL_WIN], unsigned short mtu_cap) 3424167514Skmacy{ 3425167514Skmacy static const unsigned int avg_pkts[NCCTRL_WIN] = { 3426167514Skmacy 2, 6, 10, 14, 20, 28, 40, 56, 80, 112, 160, 224, 320, 448, 640, 3427167514Skmacy 896, 1281, 1792, 2560, 3584, 5120, 7168, 10240, 14336, 20480, 3428167514Skmacy 28672, 40960, 57344, 81920, 114688, 163840, 229376 }; 3429167514Skmacy 3430167514Skmacy unsigned int i, w; 3431167514Skmacy 3432167514Skmacy for (i = 0; i < NMTUS; ++i) { 3433167514Skmacy unsigned int mtu = min(mtus[i], mtu_cap); 3434167514Skmacy unsigned int log2 = fls(mtu); 3435167514Skmacy 3436167514Skmacy if (!(mtu & ((1 << log2) >> 2))) /* round */ 3437167514Skmacy log2--; 3438167514Skmacy t3_write_reg(adap, A_TP_MTU_TABLE, 3439167514Skmacy (i << 24) | (log2 << 16) | mtu); 3440167514Skmacy 3441167514Skmacy for (w = 0; w < NCCTRL_WIN; ++w) { 3442167514Skmacy unsigned int inc; 3443167514Skmacy 3444167514Skmacy inc = max(((mtu - 40) * alpha[w]) / avg_pkts[w], 3445167514Skmacy CC_MIN_INCR); 3446167514Skmacy 3447167514Skmacy t3_write_reg(adap, A_TP_CCTRL_TABLE, (i << 21) | 3448167514Skmacy (w << 16) | (beta[w] << 13) | inc); 3449167514Skmacy } 3450167514Skmacy } 3451167514Skmacy} 3452167514Skmacy 3453167514Skmacy/** 3454167514Skmacy * t3_read_hw_mtus - returns the values in the HW MTU table 3455167514Skmacy * @adap: the adapter 3456167514Skmacy * @mtus: where to store the HW MTU values 3457167514Skmacy * 3458167514Skmacy * Reads the HW MTU table. 3459167514Skmacy */ 3460167514Skmacyvoid t3_read_hw_mtus(adapter_t *adap, unsigned short mtus[NMTUS]) 3461167514Skmacy{ 3462167514Skmacy int i; 3463167514Skmacy 3464167514Skmacy for (i = 0; i < NMTUS; ++i) { 3465167514Skmacy unsigned int val; 3466167514Skmacy 3467167514Skmacy t3_write_reg(adap, A_TP_MTU_TABLE, 0xff000000 | i); 3468167514Skmacy val = t3_read_reg(adap, A_TP_MTU_TABLE); 3469167514Skmacy mtus[i] = val & 0x3fff; 3470167514Skmacy } 3471167514Skmacy} 3472167514Skmacy 3473167514Skmacy/** 3474167514Skmacy * t3_get_cong_cntl_tab - reads the congestion control table 3475167514Skmacy * @adap: the adapter 3476167514Skmacy * @incr: where to store the alpha values 3477167514Skmacy * 3478167514Skmacy * Reads the additive increments programmed into the HW congestion 3479167514Skmacy * control table. 3480167514Skmacy */ 3481167514Skmacyvoid t3_get_cong_cntl_tab(adapter_t *adap, 3482167514Skmacy unsigned short incr[NMTUS][NCCTRL_WIN]) 3483167514Skmacy{ 3484167514Skmacy unsigned int mtu, w; 3485167514Skmacy 3486167514Skmacy for (mtu = 0; mtu < NMTUS; ++mtu) 3487167514Skmacy for (w = 0; w < NCCTRL_WIN; ++w) { 3488167514Skmacy t3_write_reg(adap, A_TP_CCTRL_TABLE, 3489167514Skmacy 0xffff0000 | (mtu << 5) | w); 3490167514Skmacy incr[mtu][w] = (unsigned short)t3_read_reg(adap, 3491167514Skmacy A_TP_CCTRL_TABLE) & 0x1fff; 3492167514Skmacy } 3493167514Skmacy} 3494167514Skmacy 3495167514Skmacy/** 3496167514Skmacy * t3_tp_get_mib_stats - read TP's MIB counters 3497167514Skmacy * @adap: the adapter 3498167514Skmacy * @tps: holds the returned counter values 3499167514Skmacy * 3500167514Skmacy * Returns the values of TP's MIB counters. 3501167514Skmacy */ 3502167514Skmacyvoid t3_tp_get_mib_stats(adapter_t *adap, struct tp_mib_stats *tps) 3503167514Skmacy{ 3504167514Skmacy t3_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_RDATA, (u32 *)tps, 3505167514Skmacy sizeof(*tps) / sizeof(u32), 0); 3506167514Skmacy} 3507167514Skmacy 3508167746Skmacy/** 3509167746Skmacy * t3_read_pace_tbl - read the pace table 3510167746Skmacy * @adap: the adapter 3511167746Skmacy * @pace_vals: holds the returned values 3512167746Skmacy * 3513167746Skmacy * Returns the values of TP's pace table in nanoseconds. 3514167746Skmacy */ 3515167746Skmacyvoid t3_read_pace_tbl(adapter_t *adap, unsigned int pace_vals[NTX_SCHED]) 3516167746Skmacy{ 3517167746Skmacy unsigned int i, tick_ns = dack_ticks_to_usec(adap, 1000); 3518167746Skmacy 3519167746Skmacy for (i = 0; i < NTX_SCHED; i++) { 3520167746Skmacy t3_write_reg(adap, A_TP_PACE_TABLE, 0xffff0000 + i); 3521167746Skmacy pace_vals[i] = t3_read_reg(adap, A_TP_PACE_TABLE) * tick_ns; 3522167746Skmacy } 3523167746Skmacy} 3524167746Skmacy 3525167746Skmacy/** 3526167746Skmacy * t3_set_pace_tbl - set the pace table 3527167746Skmacy * @adap: the adapter 3528167746Skmacy * @pace_vals: the pace values in nanoseconds 3529167746Skmacy * @start: index of the first entry in the HW pace table to set 3530167746Skmacy * @n: how many entries to set 3531167746Skmacy * 3532167746Skmacy * Sets (a subset of the) HW pace table. 3533167746Skmacy */ 3534167746Skmacyvoid t3_set_pace_tbl(adapter_t *adap, unsigned int *pace_vals, 3535167746Skmacy unsigned int start, unsigned int n) 3536167746Skmacy{ 3537167746Skmacy unsigned int tick_ns = dack_ticks_to_usec(adap, 1000); 3538167746Skmacy 3539167746Skmacy for ( ; n; n--, start++, pace_vals++) 3540167746Skmacy t3_write_reg(adap, A_TP_PACE_TABLE, (start << 16) | 3541167746Skmacy ((*pace_vals + tick_ns / 2) / tick_ns)); 3542167746Skmacy} 3543167746Skmacy 3544167514Skmacy#define ulp_region(adap, name, start, len) \ 3545167514Skmacy t3_write_reg((adap), A_ULPRX_ ## name ## _LLIMIT, (start)); \ 3546167514Skmacy t3_write_reg((adap), A_ULPRX_ ## name ## _ULIMIT, \ 3547167514Skmacy (start) + (len) - 1); \ 3548167514Skmacy start += len 3549167514Skmacy 3550167514Skmacy#define ulptx_region(adap, name, start, len) \ 3551167514Skmacy t3_write_reg((adap), A_ULPTX_ ## name ## _LLIMIT, (start)); \ 3552167514Skmacy t3_write_reg((adap), A_ULPTX_ ## name ## _ULIMIT, \ 3553167514Skmacy (start) + (len) - 1) 3554167514Skmacy 3555167514Skmacystatic void ulp_config(adapter_t *adap, const struct tp_params *p) 3556167514Skmacy{ 3557167514Skmacy unsigned int m = p->chan_rx_size; 3558167514Skmacy 3559167514Skmacy ulp_region(adap, ISCSI, m, p->chan_rx_size / 8); 3560167514Skmacy ulp_region(adap, TDDP, m, p->chan_rx_size / 8); 3561167514Skmacy ulptx_region(adap, TPT, m, p->chan_rx_size / 4); 3562167514Skmacy ulp_region(adap, STAG, m, p->chan_rx_size / 4); 3563167514Skmacy ulp_region(adap, RQ, m, p->chan_rx_size / 4); 3564167514Skmacy ulptx_region(adap, PBL, m, p->chan_rx_size / 4); 3565167514Skmacy ulp_region(adap, PBL, m, p->chan_rx_size / 4); 3566167514Skmacy t3_write_reg(adap, A_ULPRX_TDDP_TAGMASK, 0xffffffff); 3567167514Skmacy} 3568170654Skmacy 3569170654Skmacy 3570170654Skmacy/** 3571170654Skmacy * t3_set_proto_sram - set the contents of the protocol sram 3572170654Skmacy * @adapter: the adapter 3573170654Skmacy * @data: the protocol image 3574170654Skmacy * 3575170654Skmacy * Write the contents of the protocol SRAM. 3576170654Skmacy */ 3577171471Skmacyint t3_set_proto_sram(adapter_t *adap, const u8 *data) 3578170654Skmacy{ 3579170654Skmacy int i; 3580172096Skmacy const u32 *buf = (const u32 *)data; 3581170654Skmacy 3582170654Skmacy for (i = 0; i < PROTO_SRAM_LINES; i++) { 3583171471Skmacy t3_write_reg(adap, A_TP_EMBED_OP_FIELD5, cpu_to_be32(*buf++)); 3584171471Skmacy t3_write_reg(adap, A_TP_EMBED_OP_FIELD4, cpu_to_be32(*buf++)); 3585171471Skmacy t3_write_reg(adap, A_TP_EMBED_OP_FIELD3, cpu_to_be32(*buf++)); 3586171471Skmacy t3_write_reg(adap, A_TP_EMBED_OP_FIELD2, cpu_to_be32(*buf++)); 3587171471Skmacy t3_write_reg(adap, A_TP_EMBED_OP_FIELD1, cpu_to_be32(*buf++)); 3588189643Sgnn 3589170654Skmacy t3_write_reg(adap, A_TP_EMBED_OP_FIELD0, i << 1 | 1 << 31); 3590170654Skmacy if (t3_wait_op_done(adap, A_TP_EMBED_OP_FIELD0, 1, 1, 5, 1)) 3591170654Skmacy return -EIO; 3592170654Skmacy } 3593170654Skmacy return 0; 3594170654Skmacy} 3595167514Skmacy 3596172096Skmacy/** 3597172096Skmacy * t3_config_trace_filter - configure one of the tracing filters 3598172096Skmacy * @adapter: the adapter 3599172096Skmacy * @tp: the desired trace filter parameters 3600172096Skmacy * @filter_index: which filter to configure 3601172096Skmacy * @invert: if set non-matching packets are traced instead of matching ones 3602172096Skmacy * @enable: whether to enable or disable the filter 3603172096Skmacy * 3604172096Skmacy * Configures one of the tracing filters available in HW. 3605172096Skmacy */ 3606167514Skmacyvoid t3_config_trace_filter(adapter_t *adapter, const struct trace_params *tp, 3607167514Skmacy int filter_index, int invert, int enable) 3608167514Skmacy{ 3609167514Skmacy u32 addr, key[4], mask[4]; 3610167514Skmacy 3611167514Skmacy key[0] = tp->sport | (tp->sip << 16); 3612167514Skmacy key[1] = (tp->sip >> 16) | (tp->dport << 16); 3613167514Skmacy key[2] = tp->dip; 3614167514Skmacy key[3] = tp->proto | (tp->vlan << 8) | (tp->intf << 20); 3615167514Skmacy 3616167514Skmacy mask[0] = tp->sport_mask | (tp->sip_mask << 16); 3617167514Skmacy mask[1] = (tp->sip_mask >> 16) | (tp->dport_mask << 16); 3618167514Skmacy mask[2] = tp->dip_mask; 3619167514Skmacy mask[3] = tp->proto_mask | (tp->vlan_mask << 8) | (tp->intf_mask << 20); 3620167514Skmacy 3621167514Skmacy if (invert) 3622167514Skmacy key[3] |= (1 << 29); 3623167514Skmacy if (enable) 3624167514Skmacy key[3] |= (1 << 28); 3625167514Skmacy 3626167514Skmacy addr = filter_index ? A_TP_RX_TRC_KEY0 : A_TP_TX_TRC_KEY0; 3627167514Skmacy tp_wr_indirect(adapter, addr++, key[0]); 3628167514Skmacy tp_wr_indirect(adapter, addr++, mask[0]); 3629167514Skmacy tp_wr_indirect(adapter, addr++, key[1]); 3630167514Skmacy tp_wr_indirect(adapter, addr++, mask[1]); 3631167514Skmacy tp_wr_indirect(adapter, addr++, key[2]); 3632167514Skmacy tp_wr_indirect(adapter, addr++, mask[2]); 3633167514Skmacy tp_wr_indirect(adapter, addr++, key[3]); 3634167514Skmacy tp_wr_indirect(adapter, addr, mask[3]); 3635167514Skmacy (void) t3_read_reg(adapter, A_TP_PIO_DATA); 3636167514Skmacy} 3637167514Skmacy 3638167514Skmacy/** 3639189643Sgnn * t3_query_trace_filter - query a tracing filter 3640189643Sgnn * @adapter: the adapter 3641189643Sgnn * @tp: the current trace filter parameters 3642189643Sgnn * @filter_index: which filter to query 3643189643Sgnn * @inverted: non-zero if the filter is inverted 3644189643Sgnn * @enabled: non-zero if the filter is enabled 3645189643Sgnn * 3646189643Sgnn * Returns the current settings of the specified HW tracing filter. 3647189643Sgnn */ 3648189643Sgnnvoid t3_query_trace_filter(adapter_t *adapter, struct trace_params *tp, 3649189643Sgnn int filter_index, int *inverted, int *enabled) 3650189643Sgnn{ 3651189643Sgnn u32 addr, key[4], mask[4]; 3652189643Sgnn 3653189643Sgnn addr = filter_index ? A_TP_RX_TRC_KEY0 : A_TP_TX_TRC_KEY0; 3654189643Sgnn key[0] = tp_rd_indirect(adapter, addr++); 3655189643Sgnn mask[0] = tp_rd_indirect(adapter, addr++); 3656189643Sgnn key[1] = tp_rd_indirect(adapter, addr++); 3657189643Sgnn mask[1] = tp_rd_indirect(adapter, addr++); 3658189643Sgnn key[2] = tp_rd_indirect(adapter, addr++); 3659189643Sgnn mask[2] = tp_rd_indirect(adapter, addr++); 3660189643Sgnn key[3] = tp_rd_indirect(adapter, addr++); 3661189643Sgnn mask[3] = tp_rd_indirect(adapter, addr); 3662189643Sgnn 3663189643Sgnn tp->sport = key[0] & 0xffff; 3664189643Sgnn tp->sip = (key[0] >> 16) | ((key[1] & 0xffff) << 16); 3665189643Sgnn tp->dport = key[1] >> 16; 3666189643Sgnn tp->dip = key[2]; 3667189643Sgnn tp->proto = key[3] & 0xff; 3668189643Sgnn tp->vlan = key[3] >> 8; 3669189643Sgnn tp->intf = key[3] >> 20; 3670189643Sgnn 3671189643Sgnn tp->sport_mask = mask[0] & 0xffff; 3672189643Sgnn tp->sip_mask = (mask[0] >> 16) | ((mask[1] & 0xffff) << 16); 3673189643Sgnn tp->dport_mask = mask[1] >> 16; 3674189643Sgnn tp->dip_mask = mask[2]; 3675189643Sgnn tp->proto_mask = mask[3] & 0xff; 3676189643Sgnn tp->vlan_mask = mask[3] >> 8; 3677189643Sgnn tp->intf_mask = mask[3] >> 20; 3678189643Sgnn 3679189643Sgnn *inverted = key[3] & (1 << 29); 3680189643Sgnn *enabled = key[3] & (1 << 28); 3681189643Sgnn} 3682189643Sgnn 3683189643Sgnn/** 3684167514Skmacy * t3_config_sched - configure a HW traffic scheduler 3685167514Skmacy * @adap: the adapter 3686167514Skmacy * @kbps: target rate in Kbps 3687167514Skmacy * @sched: the scheduler index 3688167514Skmacy * 3689167746Skmacy * Configure a Tx HW scheduler for the target rate. 3690167514Skmacy */ 3691167514Skmacyint t3_config_sched(adapter_t *adap, unsigned int kbps, int sched) 3692167514Skmacy{ 3693167514Skmacy unsigned int v, tps, cpt, bpt, delta, mindelta = ~0; 3694167514Skmacy unsigned int clk = adap->params.vpd.cclk * 1000; 3695167514Skmacy unsigned int selected_cpt = 0, selected_bpt = 0; 3696167514Skmacy 3697167514Skmacy if (kbps > 0) { 3698167514Skmacy kbps *= 125; /* -> bytes */ 3699167514Skmacy for (cpt = 1; cpt <= 255; cpt++) { 3700167514Skmacy tps = clk / cpt; 3701167514Skmacy bpt = (kbps + tps / 2) / tps; 3702167514Skmacy if (bpt > 0 && bpt <= 255) { 3703167514Skmacy v = bpt * tps; 3704167514Skmacy delta = v >= kbps ? v - kbps : kbps - v; 3705176472Skmacy if (delta < mindelta) { 3706167514Skmacy mindelta = delta; 3707167514Skmacy selected_cpt = cpt; 3708167514Skmacy selected_bpt = bpt; 3709167514Skmacy } 3710167514Skmacy } else if (selected_cpt) 3711167514Skmacy break; 3712167514Skmacy } 3713167514Skmacy if (!selected_cpt) 3714167514Skmacy return -EINVAL; 3715167514Skmacy } 3716167514Skmacy t3_write_reg(adap, A_TP_TM_PIO_ADDR, 3717167514Skmacy A_TP_TX_MOD_Q1_Q0_RATE_LIMIT - sched / 2); 3718167514Skmacy v = t3_read_reg(adap, A_TP_TM_PIO_DATA); 3719167514Skmacy if (sched & 1) 3720167514Skmacy v = (v & 0xffff) | (selected_cpt << 16) | (selected_bpt << 24); 3721167514Skmacy else 3722167514Skmacy v = (v & 0xffff0000) | selected_cpt | (selected_bpt << 8); 3723167514Skmacy t3_write_reg(adap, A_TP_TM_PIO_DATA, v); 3724167514Skmacy return 0; 3725167514Skmacy} 3726167514Skmacy 3727167746Skmacy/** 3728167746Skmacy * t3_set_sched_ipg - set the IPG for a Tx HW packet rate scheduler 3729167746Skmacy * @adap: the adapter 3730167746Skmacy * @sched: the scheduler index 3731167746Skmacy * @ipg: the interpacket delay in tenths of nanoseconds 3732167746Skmacy * 3733167746Skmacy * Set the interpacket delay for a HW packet rate scheduler. 3734167746Skmacy */ 3735167746Skmacyint t3_set_sched_ipg(adapter_t *adap, int sched, unsigned int ipg) 3736167746Skmacy{ 3737167746Skmacy unsigned int v, addr = A_TP_TX_MOD_Q1_Q0_TIMER_SEPARATOR - sched / 2; 3738167746Skmacy 3739167746Skmacy /* convert ipg to nearest number of core clocks */ 3740167746Skmacy ipg *= core_ticks_per_usec(adap); 3741167746Skmacy ipg = (ipg + 5000) / 10000; 3742167746Skmacy if (ipg > 0xffff) 3743167746Skmacy return -EINVAL; 3744167746Skmacy 3745167746Skmacy t3_write_reg(adap, A_TP_TM_PIO_ADDR, addr); 3746167746Skmacy v = t3_read_reg(adap, A_TP_TM_PIO_DATA); 3747167746Skmacy if (sched & 1) 3748167746Skmacy v = (v & 0xffff) | (ipg << 16); 3749167746Skmacy else 3750167746Skmacy v = (v & 0xffff0000) | ipg; 3751167746Skmacy t3_write_reg(adap, A_TP_TM_PIO_DATA, v); 3752167746Skmacy t3_read_reg(adap, A_TP_TM_PIO_DATA); 3753167746Skmacy return 0; 3754167746Skmacy} 3755167746Skmacy 3756167746Skmacy/** 3757167746Skmacy * t3_get_tx_sched - get the configuration of a Tx HW traffic scheduler 3758167746Skmacy * @adap: the adapter 3759167746Skmacy * @sched: the scheduler index 3760167746Skmacy * @kbps: the byte rate in Kbps 3761167746Skmacy * @ipg: the interpacket delay in tenths of nanoseconds 3762167746Skmacy * 3763167746Skmacy * Return the current configuration of a HW Tx scheduler. 3764167746Skmacy */ 3765167746Skmacyvoid t3_get_tx_sched(adapter_t *adap, unsigned int sched, unsigned int *kbps, 3766167746Skmacy unsigned int *ipg) 3767167746Skmacy{ 3768167746Skmacy unsigned int v, addr, bpt, cpt; 3769167746Skmacy 3770167746Skmacy if (kbps) { 3771167746Skmacy addr = A_TP_TX_MOD_Q1_Q0_RATE_LIMIT - sched / 2; 3772167746Skmacy t3_write_reg(adap, A_TP_TM_PIO_ADDR, addr); 3773167746Skmacy v = t3_read_reg(adap, A_TP_TM_PIO_DATA); 3774167746Skmacy if (sched & 1) 3775167746Skmacy v >>= 16; 3776167746Skmacy bpt = (v >> 8) & 0xff; 3777167746Skmacy cpt = v & 0xff; 3778167746Skmacy if (!cpt) 3779167746Skmacy *kbps = 0; /* scheduler disabled */ 3780167746Skmacy else { 3781167746Skmacy v = (adap->params.vpd.cclk * 1000) / cpt; 3782167746Skmacy *kbps = (v * bpt) / 125; 3783167746Skmacy } 3784167746Skmacy } 3785167746Skmacy if (ipg) { 3786167746Skmacy addr = A_TP_TX_MOD_Q1_Q0_TIMER_SEPARATOR - sched / 2; 3787167746Skmacy t3_write_reg(adap, A_TP_TM_PIO_ADDR, addr); 3788167746Skmacy v = t3_read_reg(adap, A_TP_TM_PIO_DATA); 3789167746Skmacy if (sched & 1) 3790167746Skmacy v >>= 16; 3791167746Skmacy v &= 0xffff; 3792167746Skmacy *ipg = (10000 * v) / core_ticks_per_usec(adap); 3793167746Skmacy } 3794167746Skmacy} 3795167746Skmacy 3796172096Skmacy/** 3797172096Skmacy * tp_init - configure TP 3798172096Skmacy * @adap: the adapter 3799172096Skmacy * @p: TP configuration parameters 3800172096Skmacy * 3801172096Skmacy * Initializes the TP HW module. 3802172096Skmacy */ 3803167514Skmacystatic int tp_init(adapter_t *adap, const struct tp_params *p) 3804167514Skmacy{ 3805167514Skmacy int busy = 0; 3806167514Skmacy 3807167514Skmacy tp_config(adap, p); 3808167514Skmacy t3_set_vlan_accel(adap, 3, 0); 3809167514Skmacy 3810167514Skmacy if (is_offload(adap)) { 3811167514Skmacy tp_set_timers(adap, adap->params.vpd.cclk * 1000); 3812167514Skmacy t3_write_reg(adap, A_TP_RESET, F_FLSTINITENABLE); 3813167514Skmacy busy = t3_wait_op_done(adap, A_TP_RESET, F_FLSTINITENABLE, 3814167514Skmacy 0, 1000, 5); 3815167514Skmacy if (busy) 3816167514Skmacy CH_ERR(adap, "TP initialization timed out\n"); 3817167514Skmacy } 3818167514Skmacy 3819167514Skmacy if (!busy) 3820167514Skmacy t3_write_reg(adap, A_TP_RESET, F_TPRESET); 3821167514Skmacy return busy; 3822167514Skmacy} 3823167514Skmacy 3824172096Skmacy/** 3825172096Skmacy * t3_mps_set_active_ports - configure port failover 3826172096Skmacy * @adap: the adapter 3827172096Skmacy * @port_mask: bitmap of active ports 3828172096Skmacy * 3829172096Skmacy * Sets the active ports according to the supplied bitmap. 3830172096Skmacy */ 3831167514Skmacyint t3_mps_set_active_ports(adapter_t *adap, unsigned int port_mask) 3832167514Skmacy{ 3833167514Skmacy if (port_mask & ~((1 << adap->params.nports) - 1)) 3834167514Skmacy return -EINVAL; 3835167514Skmacy t3_set_reg_field(adap, A_MPS_CFG, F_PORT1ACTIVE | F_PORT0ACTIVE, 3836167514Skmacy port_mask << S_PORT0ACTIVE); 3837167514Skmacy return 0; 3838167514Skmacy} 3839167514Skmacy 3840172096Skmacy/** 3841172096Skmacy * chan_init_hw - channel-dependent HW initialization 3842172096Skmacy * @adap: the adapter 3843172096Skmacy * @chan_map: bitmap of Tx channels being used 3844172096Skmacy * 3845172096Skmacy * Perform the bits of HW initialization that are dependent on the Tx 3846172096Skmacy * channels being used. 3847167514Skmacy */ 3848170654Skmacystatic void chan_init_hw(adapter_t *adap, unsigned int chan_map) 3849167514Skmacy{ 3850167514Skmacy int i; 3851167514Skmacy 3852170654Skmacy if (chan_map != 3) { /* one channel */ 3853167514Skmacy t3_set_reg_field(adap, A_ULPRX_CTL, F_ROUND_ROBIN, 0); 3854167514Skmacy t3_set_reg_field(adap, A_ULPTX_CONFIG, F_CFG_RR_ARB, 0); 3855170654Skmacy t3_write_reg(adap, A_MPS_CFG, F_TPRXPORTEN | F_ENFORCEPKT | 3856170654Skmacy (chan_map == 1 ? F_TPTXPORT0EN | F_PORT0ACTIVE : 3857170654Skmacy F_TPTXPORT1EN | F_PORT1ACTIVE)); 3858170654Skmacy t3_write_reg(adap, A_PM1_TX_CFG, 3859170654Skmacy chan_map == 1 ? 0xffffffff : 0); 3860172096Skmacy if (chan_map == 2) 3861172096Skmacy t3_write_reg(adap, A_TP_TX_MOD_QUEUE_REQ_MAP, 3862172096Skmacy V_TX_MOD_QUEUE_REQ_MAP(0xff)); 3863172096Skmacy t3_write_reg(adap, A_TP_TX_MOD_QUE_TABLE, (12 << 16) | 0xd9c8); 3864172096Skmacy t3_write_reg(adap, A_TP_TX_MOD_QUE_TABLE, (13 << 16) | 0xfbea); 3865170654Skmacy } else { /* two channels */ 3866167514Skmacy t3_set_reg_field(adap, A_ULPRX_CTL, 0, F_ROUND_ROBIN); 3867167514Skmacy t3_set_reg_field(adap, A_ULPTX_CONFIG, 0, F_CFG_RR_ARB); 3868167514Skmacy t3_write_reg(adap, A_ULPTX_DMA_WEIGHT, 3869167514Skmacy V_D1_WEIGHT(16) | V_D0_WEIGHT(16)); 3870167514Skmacy t3_write_reg(adap, A_MPS_CFG, F_TPTXPORT0EN | F_TPTXPORT1EN | 3871167514Skmacy F_TPRXPORTEN | F_PORT0ACTIVE | F_PORT1ACTIVE | 3872167514Skmacy F_ENFORCEPKT); 3873167514Skmacy t3_write_reg(adap, A_PM1_TX_CFG, 0x80008000); 3874167514Skmacy t3_set_reg_field(adap, A_TP_PC_CONFIG, 0, F_TXTOSQUEUEMAPMODE); 3875167514Skmacy t3_write_reg(adap, A_TP_TX_MOD_QUEUE_REQ_MAP, 3876167514Skmacy V_TX_MOD_QUEUE_REQ_MAP(0xaa)); 3877167514Skmacy for (i = 0; i < 16; i++) 3878167514Skmacy t3_write_reg(adap, A_TP_TX_MOD_QUE_TABLE, 3879167514Skmacy (i << 16) | 0x1010); 3880172096Skmacy t3_write_reg(adap, A_TP_TX_MOD_QUE_TABLE, (12 << 16) | 0xba98); 3881172096Skmacy t3_write_reg(adap, A_TP_TX_MOD_QUE_TABLE, (13 << 16) | 0xfedc); 3882167514Skmacy } 3883167514Skmacy} 3884167514Skmacy 3885167514Skmacystatic int calibrate_xgm(adapter_t *adapter) 3886167514Skmacy{ 3887167514Skmacy if (uses_xaui(adapter)) { 3888167514Skmacy unsigned int v, i; 3889167514Skmacy 3890167514Skmacy for (i = 0; i < 5; ++i) { 3891167514Skmacy t3_write_reg(adapter, A_XGM_XAUI_IMP, 0); 3892167514Skmacy (void) t3_read_reg(adapter, A_XGM_XAUI_IMP); 3893171471Skmacy msleep(1); 3894167514Skmacy v = t3_read_reg(adapter, A_XGM_XAUI_IMP); 3895167514Skmacy if (!(v & (F_XGM_CALFAULT | F_CALBUSY))) { 3896167514Skmacy t3_write_reg(adapter, A_XGM_XAUI_IMP, 3897167514Skmacy V_XAUIIMP(G_CALIMP(v) >> 2)); 3898167514Skmacy return 0; 3899167514Skmacy } 3900167514Skmacy } 3901167514Skmacy CH_ERR(adapter, "MAC calibration failed\n"); 3902167514Skmacy return -1; 3903167514Skmacy } else { 3904167514Skmacy t3_write_reg(adapter, A_XGM_RGMII_IMP, 3905167514Skmacy V_RGMIIIMPPD(2) | V_RGMIIIMPPU(3)); 3906167514Skmacy t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_XGM_IMPSETUPDATE, 3907167514Skmacy F_XGM_IMPSETUPDATE); 3908167514Skmacy } 3909167514Skmacy return 0; 3910167514Skmacy} 3911167514Skmacy 3912167514Skmacystatic void calibrate_xgm_t3b(adapter_t *adapter) 3913167514Skmacy{ 3914167514Skmacy if (!uses_xaui(adapter)) { 3915167514Skmacy t3_write_reg(adapter, A_XGM_RGMII_IMP, F_CALRESET | 3916167514Skmacy F_CALUPDATE | V_RGMIIIMPPD(2) | V_RGMIIIMPPU(3)); 3917167514Skmacy t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_CALRESET, 0); 3918167514Skmacy t3_set_reg_field(adapter, A_XGM_RGMII_IMP, 0, 3919167514Skmacy F_XGM_IMPSETUPDATE); 3920167514Skmacy t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_XGM_IMPSETUPDATE, 3921167514Skmacy 0); 3922167514Skmacy t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_CALUPDATE, 0); 3923167514Skmacy t3_set_reg_field(adapter, A_XGM_RGMII_IMP, 0, F_CALUPDATE); 3924167514Skmacy } 3925167514Skmacy} 3926167514Skmacy 3927167514Skmacystruct mc7_timing_params { 3928167514Skmacy unsigned char ActToPreDly; 3929167514Skmacy unsigned char ActToRdWrDly; 3930167514Skmacy unsigned char PreCyc; 3931167514Skmacy unsigned char RefCyc[5]; 3932167514Skmacy unsigned char BkCyc; 3933167514Skmacy unsigned char WrToRdDly; 3934167514Skmacy unsigned char RdToWrDly; 3935167514Skmacy}; 3936167514Skmacy 3937167514Skmacy/* 3938167514Skmacy * Write a value to a register and check that the write completed. These 3939167514Skmacy * writes normally complete in a cycle or two, so one read should suffice. 3940167514Skmacy * The very first read exists to flush the posted write to the device. 3941167514Skmacy */ 3942167514Skmacystatic int wrreg_wait(adapter_t *adapter, unsigned int addr, u32 val) 3943167514Skmacy{ 3944167514Skmacy t3_write_reg(adapter, addr, val); 3945167514Skmacy (void) t3_read_reg(adapter, addr); /* flush */ 3946167514Skmacy if (!(t3_read_reg(adapter, addr) & F_BUSY)) 3947167514Skmacy return 0; 3948167514Skmacy CH_ERR(adapter, "write to MC7 register 0x%x timed out\n", addr); 3949167514Skmacy return -EIO; 3950167514Skmacy} 3951167514Skmacy 3952167514Skmacystatic int mc7_init(struct mc7 *mc7, unsigned int mc7_clock, int mem_type) 3953167514Skmacy{ 3954167514Skmacy static const unsigned int mc7_mode[] = { 3955167514Skmacy 0x632, 0x642, 0x652, 0x432, 0x442 3956167514Skmacy }; 3957167514Skmacy static const struct mc7_timing_params mc7_timings[] = { 3958167514Skmacy { 12, 3, 4, { 20, 28, 34, 52, 0 }, 15, 6, 4 }, 3959167514Skmacy { 12, 4, 5, { 20, 28, 34, 52, 0 }, 16, 7, 4 }, 3960167514Skmacy { 12, 5, 6, { 20, 28, 34, 52, 0 }, 17, 8, 4 }, 3961167514Skmacy { 9, 3, 4, { 15, 21, 26, 39, 0 }, 12, 6, 4 }, 3962167514Skmacy { 9, 4, 5, { 15, 21, 26, 39, 0 }, 13, 7, 4 } 3963167514Skmacy }; 3964167514Skmacy 3965167514Skmacy u32 val; 3966167514Skmacy unsigned int width, density, slow, attempts; 3967167514Skmacy adapter_t *adapter = mc7->adapter; 3968167514Skmacy const struct mc7_timing_params *p = &mc7_timings[mem_type]; 3969167514Skmacy 3970170654Skmacy if (!mc7->size) 3971169978Skmacy return 0; 3972170654Skmacy 3973167514Skmacy val = t3_read_reg(adapter, mc7->offset + A_MC7_CFG); 3974167514Skmacy slow = val & F_SLOW; 3975167514Skmacy width = G_WIDTH(val); 3976167514Skmacy density = G_DEN(val); 3977167514Skmacy 3978167514Skmacy t3_write_reg(adapter, mc7->offset + A_MC7_CFG, val | F_IFEN); 3979167514Skmacy val = t3_read_reg(adapter, mc7->offset + A_MC7_CFG); /* flush */ 3980171471Skmacy msleep(1); 3981167514Skmacy 3982167514Skmacy if (!slow) { 3983167514Skmacy t3_write_reg(adapter, mc7->offset + A_MC7_CAL, F_SGL_CAL_EN); 3984167514Skmacy (void) t3_read_reg(adapter, mc7->offset + A_MC7_CAL); 3985171471Skmacy msleep(1); 3986167514Skmacy if (t3_read_reg(adapter, mc7->offset + A_MC7_CAL) & 3987167514Skmacy (F_BUSY | F_SGL_CAL_EN | F_CAL_FAULT)) { 3988167514Skmacy CH_ERR(adapter, "%s MC7 calibration timed out\n", 3989167514Skmacy mc7->name); 3990167514Skmacy goto out_fail; 3991167514Skmacy } 3992167514Skmacy } 3993167514Skmacy 3994167514Skmacy t3_write_reg(adapter, mc7->offset + A_MC7_PARM, 3995167514Skmacy V_ACTTOPREDLY(p->ActToPreDly) | 3996167514Skmacy V_ACTTORDWRDLY(p->ActToRdWrDly) | V_PRECYC(p->PreCyc) | 3997167514Skmacy V_REFCYC(p->RefCyc[density]) | V_BKCYC(p->BkCyc) | 3998167514Skmacy V_WRTORDDLY(p->WrToRdDly) | V_RDTOWRDLY(p->RdToWrDly)); 3999167514Skmacy 4000167514Skmacy t3_write_reg(adapter, mc7->offset + A_MC7_CFG, 4001167514Skmacy val | F_CLKEN | F_TERM150); 4002167514Skmacy (void) t3_read_reg(adapter, mc7->offset + A_MC7_CFG); /* flush */ 4003167514Skmacy 4004167514Skmacy if (!slow) 4005167514Skmacy t3_set_reg_field(adapter, mc7->offset + A_MC7_DLL, F_DLLENB, 4006167514Skmacy F_DLLENB); 4007167514Skmacy udelay(1); 4008167514Skmacy 4009167514Skmacy val = slow ? 3 : 6; 4010167514Skmacy if (wrreg_wait(adapter, mc7->offset + A_MC7_PRE, 0) || 4011167514Skmacy wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE2, 0) || 4012167514Skmacy wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE3, 0) || 4013167514Skmacy wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE1, val)) 4014167514Skmacy goto out_fail; 4015167514Skmacy 4016167514Skmacy if (!slow) { 4017167514Skmacy t3_write_reg(adapter, mc7->offset + A_MC7_MODE, 0x100); 4018167514Skmacy t3_set_reg_field(adapter, mc7->offset + A_MC7_DLL, 4019167514Skmacy F_DLLRST, 0); 4020167514Skmacy udelay(5); 4021167514Skmacy } 4022167514Skmacy 4023167514Skmacy if (wrreg_wait(adapter, mc7->offset + A_MC7_PRE, 0) || 4024167514Skmacy wrreg_wait(adapter, mc7->offset + A_MC7_REF, 0) || 4025167514Skmacy wrreg_wait(adapter, mc7->offset + A_MC7_REF, 0) || 4026167514Skmacy wrreg_wait(adapter, mc7->offset + A_MC7_MODE, 4027167514Skmacy mc7_mode[mem_type]) || 4028167514Skmacy wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE1, val | 0x380) || 4029167514Skmacy wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE1, val)) 4030167514Skmacy goto out_fail; 4031167514Skmacy 4032167514Skmacy /* clock value is in KHz */ 4033167514Skmacy mc7_clock = mc7_clock * 7812 + mc7_clock / 2; /* ns */ 4034167514Skmacy mc7_clock /= 1000000; /* KHz->MHz, ns->us */ 4035167514Skmacy 4036167514Skmacy t3_write_reg(adapter, mc7->offset + A_MC7_REF, 4037167514Skmacy F_PERREFEN | V_PREREFDIV(mc7_clock)); 4038167514Skmacy (void) t3_read_reg(adapter, mc7->offset + A_MC7_REF); /* flush */ 4039167514Skmacy 4040167514Skmacy t3_write_reg(adapter, mc7->offset + A_MC7_ECC, 4041167514Skmacy F_ECCGENEN | F_ECCCHKEN); 4042167514Skmacy t3_write_reg(adapter, mc7->offset + A_MC7_BIST_DATA, 0); 4043167514Skmacy t3_write_reg(adapter, mc7->offset + A_MC7_BIST_ADDR_BEG, 0); 4044167514Skmacy t3_write_reg(adapter, mc7->offset + A_MC7_BIST_ADDR_END, 4045167514Skmacy (mc7->size << width) - 1); 4046167514Skmacy t3_write_reg(adapter, mc7->offset + A_MC7_BIST_OP, V_OP(1)); 4047167514Skmacy (void) t3_read_reg(adapter, mc7->offset + A_MC7_BIST_OP); /* flush */ 4048167514Skmacy 4049167514Skmacy attempts = 50; 4050167514Skmacy do { 4051171471Skmacy msleep(250); 4052167514Skmacy val = t3_read_reg(adapter, mc7->offset + A_MC7_BIST_OP); 4053167514Skmacy } while ((val & F_BUSY) && --attempts); 4054167514Skmacy if (val & F_BUSY) { 4055167514Skmacy CH_ERR(adapter, "%s MC7 BIST timed out\n", mc7->name); 4056167514Skmacy goto out_fail; 4057167514Skmacy } 4058167514Skmacy 4059167514Skmacy /* Enable normal memory accesses. */ 4060167514Skmacy t3_set_reg_field(adapter, mc7->offset + A_MC7_CFG, 0, F_RDY); 4061167514Skmacy return 0; 4062167514Skmacy 4063167514Skmacy out_fail: 4064167514Skmacy return -1; 4065167514Skmacy} 4066167514Skmacy 4067167514Skmacystatic void config_pcie(adapter_t *adap) 4068167514Skmacy{ 4069167514Skmacy static const u16 ack_lat[4][6] = { 4070167514Skmacy { 237, 416, 559, 1071, 2095, 4143 }, 4071167514Skmacy { 128, 217, 289, 545, 1057, 2081 }, 4072167514Skmacy { 73, 118, 154, 282, 538, 1050 }, 4073167514Skmacy { 67, 107, 86, 150, 278, 534 } 4074167514Skmacy }; 4075167514Skmacy static const u16 rpl_tmr[4][6] = { 4076167514Skmacy { 711, 1248, 1677, 3213, 6285, 12429 }, 4077167514Skmacy { 384, 651, 867, 1635, 3171, 6243 }, 4078167514Skmacy { 219, 354, 462, 846, 1614, 3150 }, 4079167514Skmacy { 201, 321, 258, 450, 834, 1602 } 4080167514Skmacy }; 4081167514Skmacy 4082197791Snp u16 val, devid; 4083167514Skmacy unsigned int log2_width, pldsize; 4084167514Skmacy unsigned int fst_trn_rx, fst_trn_tx, acklat, rpllmt; 4085167514Skmacy 4086167514Skmacy t3_os_pci_read_config_2(adap, 4087167514Skmacy adap->params.pci.pcie_cap_addr + PCI_EXP_DEVCTL, 4088167514Skmacy &val); 4089167514Skmacy pldsize = (val & PCI_EXP_DEVCTL_PAYLOAD) >> 5; 4090167514Skmacy 4091197791Snp /* 4092197791Snp * Gen2 adapter pcie bridge compatibility requires minimum 4093197791Snp * Max_Read_Request_size 4094197791Snp */ 4095197791Snp t3_os_pci_read_config_2(adap, 0x2, &devid); 4096197791Snp if (devid == 0x37) { 4097197791Snp t3_os_pci_write_config_2(adap, 4098197791Snp adap->params.pci.pcie_cap_addr + PCI_EXP_DEVCTL, 4099197791Snp val & ~PCI_EXP_DEVCTL_READRQ & ~PCI_EXP_DEVCTL_PAYLOAD); 4100197791Snp pldsize = 0; 4101197791Snp } 4102197791Snp 4103167514Skmacy t3_os_pci_read_config_2(adap, 4104167514Skmacy adap->params.pci.pcie_cap_addr + PCI_EXP_LNKCTL, 4105167514Skmacy &val); 4106167514Skmacy 4107167514Skmacy fst_trn_tx = G_NUMFSTTRNSEQ(t3_read_reg(adap, A_PCIE_PEX_CTRL0)); 4108167514Skmacy fst_trn_rx = adap->params.rev == 0 ? fst_trn_tx : 4109167514Skmacy G_NUMFSTTRNSEQRX(t3_read_reg(adap, A_PCIE_MODE)); 4110167514Skmacy log2_width = fls(adap->params.pci.width) - 1; 4111167514Skmacy acklat = ack_lat[log2_width][pldsize]; 4112167514Skmacy if (val & 1) /* check LOsEnable */ 4113167514Skmacy acklat += fst_trn_tx * 4; 4114167514Skmacy rpllmt = rpl_tmr[log2_width][pldsize] + fst_trn_rx * 4; 4115167514Skmacy 4116167514Skmacy if (adap->params.rev == 0) 4117167514Skmacy t3_set_reg_field(adap, A_PCIE_PEX_CTRL1, 4118167514Skmacy V_T3A_ACKLAT(M_T3A_ACKLAT), 4119167514Skmacy V_T3A_ACKLAT(acklat)); 4120167514Skmacy else 4121167514Skmacy t3_set_reg_field(adap, A_PCIE_PEX_CTRL1, V_ACKLAT(M_ACKLAT), 4122167514Skmacy V_ACKLAT(acklat)); 4123167514Skmacy 4124167514Skmacy t3_set_reg_field(adap, A_PCIE_PEX_CTRL0, V_REPLAYLMT(M_REPLAYLMT), 4125167514Skmacy V_REPLAYLMT(rpllmt)); 4126167514Skmacy 4127167514Skmacy t3_write_reg(adap, A_PCIE_PEX_ERR, 0xffffffff); 4128176472Skmacy t3_set_reg_field(adap, A_PCIE_CFG, 0, 4129189643Sgnn F_ENABLELINKDWNDRST | F_ENABLELINKDOWNRST | 4130176472Skmacy F_PCIE_DMASTOPEN | F_PCIE_CLIDECEN); 4131167514Skmacy} 4132167514Skmacy 4133172096Skmacy/** 4134172096Skmacy * t3_init_hw - initialize and configure T3 HW modules 4135172096Skmacy * @adapter: the adapter 4136172096Skmacy * @fw_params: initial parameters to pass to firmware (optional) 4137167514Skmacy * 4138172096Skmacy * Initialize and configure T3 HW modules. This performs the 4139172096Skmacy * initialization steps that need to be done once after a card is reset. 4140172096Skmacy * MAC and PHY initialization is handled separarely whenever a port is 4141172096Skmacy * enabled. 4142172096Skmacy * 4143172096Skmacy * @fw_params are passed to FW and their value is platform dependent. 4144172096Skmacy * Only the top 8 bits are available for use, the rest must be 0. 4145167514Skmacy */ 4146167514Skmacyint t3_init_hw(adapter_t *adapter, u32 fw_params) 4147167514Skmacy{ 4148176472Skmacy int err = -EIO, attempts, i; 4149167514Skmacy const struct vpd_params *vpd = &adapter->params.vpd; 4150167514Skmacy 4151167514Skmacy if (adapter->params.rev > 0) 4152167514Skmacy calibrate_xgm_t3b(adapter); 4153167514Skmacy else if (calibrate_xgm(adapter)) 4154167514Skmacy goto out_err; 4155167514Skmacy 4156171471Skmacy if (adapter->params.nports > 2) 4157197791Snp t3_mac_init(&adap2pinfo(adapter, 0)->mac); 4158170654Skmacy 4159167514Skmacy if (vpd->mclk) { 4160167514Skmacy partition_mem(adapter, &adapter->params.tp); 4161167514Skmacy 4162167514Skmacy if (mc7_init(&adapter->pmrx, vpd->mclk, vpd->mem_timing) || 4163167514Skmacy mc7_init(&adapter->pmtx, vpd->mclk, vpd->mem_timing) || 4164167514Skmacy mc7_init(&adapter->cm, vpd->mclk, vpd->mem_timing) || 4165167514Skmacy t3_mc5_init(&adapter->mc5, adapter->params.mc5.nservers, 4166167514Skmacy adapter->params.mc5.nfilters, 4167167514Skmacy adapter->params.mc5.nroutes)) 4168167514Skmacy goto out_err; 4169176472Skmacy 4170176472Skmacy for (i = 0; i < 32; i++) 4171176472Skmacy if (clear_sge_ctxt(adapter, i, F_CQ)) 4172176472Skmacy goto out_err; 4173167514Skmacy } 4174167514Skmacy 4175167514Skmacy if (tp_init(adapter, &adapter->params.tp)) 4176167514Skmacy goto out_err; 4177167514Skmacy 4178167514Skmacy t3_tp_set_coalescing_size(adapter, 4179167514Skmacy min(adapter->params.sge.max_pkt_size, 4180167514Skmacy MAX_RX_COALESCING_LEN), 1); 4181167514Skmacy t3_tp_set_max_rxsize(adapter, 4182167514Skmacy min(adapter->params.sge.max_pkt_size, 16384U)); 4183167514Skmacy ulp_config(adapter, &adapter->params.tp); 4184167514Skmacy if (is_pcie(adapter)) 4185167514Skmacy config_pcie(adapter); 4186167514Skmacy else 4187176472Skmacy t3_set_reg_field(adapter, A_PCIX_CFG, 0, 4188176472Skmacy F_DMASTOPEN | F_CLIDECEN); 4189167514Skmacy 4190176472Skmacy if (adapter->params.rev == T3_REV_C) 4191176472Skmacy t3_set_reg_field(adapter, A_ULPTX_CONFIG, 0, 4192176472Skmacy F_CFG_CQE_SOP_MASK); 4193176472Skmacy 4194170654Skmacy t3_write_reg(adapter, A_PM1_RX_CFG, 0xffffffff); 4195172096Skmacy t3_write_reg(adapter, A_PM1_RX_MODE, 0); 4196172096Skmacy t3_write_reg(adapter, A_PM1_TX_MODE, 0); 4197170654Skmacy chan_init_hw(adapter, adapter->params.chan_map); 4198167514Skmacy t3_sge_init(adapter, &adapter->params.sge); 4199219945Snp t3_set_reg_field(adapter, A_PL_RST, 0, F_FATALPERREN); 4200167514Skmacy 4201180583Skmacy t3_write_reg(adapter, A_T3DBG_GPIO_ACT_LOW, calc_gpio_intr(adapter)); 4202180583Skmacy 4203167514Skmacy t3_write_reg(adapter, A_CIM_HOST_ACC_DATA, vpd->uclk | fw_params); 4204167514Skmacy t3_write_reg(adapter, A_CIM_BOOT_CFG, 4205167514Skmacy V_BOOTADDR(FW_FLASH_BOOT_ADDR >> 2)); 4206167514Skmacy (void) t3_read_reg(adapter, A_CIM_BOOT_CFG); /* flush */ 4207167514Skmacy 4208176472Skmacy attempts = 100; 4209167514Skmacy do { /* wait for uP to initialize */ 4210171471Skmacy msleep(20); 4211167514Skmacy } while (t3_read_reg(adapter, A_CIM_HOST_ACC_DATA) && --attempts); 4212169978Skmacy if (!attempts) { 4213169978Skmacy CH_ERR(adapter, "uP initialization timed out\n"); 4214167514Skmacy goto out_err; 4215169978Skmacy } 4216170654Skmacy 4217167514Skmacy err = 0; 4218167514Skmacy out_err: 4219167514Skmacy return err; 4220167514Skmacy} 4221167514Skmacy 4222167514Skmacy/** 4223167514Skmacy * get_pci_mode - determine a card's PCI mode 4224167514Skmacy * @adapter: the adapter 4225167514Skmacy * @p: where to store the PCI settings 4226167514Skmacy * 4227167514Skmacy * Determines a card's PCI mode and associated parameters, such as speed 4228167514Skmacy * and width. 4229167514Skmacy */ 4230167514Skmacystatic void __devinit get_pci_mode(adapter_t *adapter, struct pci_params *p) 4231167514Skmacy{ 4232167514Skmacy static unsigned short speed_map[] = { 33, 66, 100, 133 }; 4233167514Skmacy u32 pci_mode, pcie_cap; 4234167514Skmacy 4235167514Skmacy pcie_cap = t3_os_find_pci_capability(adapter, PCI_CAP_ID_EXP); 4236167514Skmacy if (pcie_cap) { 4237167514Skmacy u16 val; 4238167514Skmacy 4239167514Skmacy p->variant = PCI_VARIANT_PCIE; 4240167514Skmacy p->pcie_cap_addr = pcie_cap; 4241167514Skmacy t3_os_pci_read_config_2(adapter, pcie_cap + PCI_EXP_LNKSTA, 4242167514Skmacy &val); 4243167514Skmacy p->width = (val >> 4) & 0x3f; 4244167514Skmacy return; 4245167514Skmacy } 4246167514Skmacy 4247167514Skmacy pci_mode = t3_read_reg(adapter, A_PCIX_MODE); 4248167514Skmacy p->speed = speed_map[G_PCLKRANGE(pci_mode)]; 4249167514Skmacy p->width = (pci_mode & F_64BIT) ? 64 : 32; 4250167514Skmacy pci_mode = G_PCIXINITPAT(pci_mode); 4251167514Skmacy if (pci_mode == 0) 4252167514Skmacy p->variant = PCI_VARIANT_PCI; 4253167514Skmacy else if (pci_mode < 4) 4254167514Skmacy p->variant = PCI_VARIANT_PCIX_MODE1_PARITY; 4255167514Skmacy else if (pci_mode < 8) 4256167514Skmacy p->variant = PCI_VARIANT_PCIX_MODE1_ECC; 4257167514Skmacy else 4258167514Skmacy p->variant = PCI_VARIANT_PCIX_266_MODE2; 4259167514Skmacy} 4260167514Skmacy 4261167514Skmacy/** 4262167514Skmacy * init_link_config - initialize a link's SW state 4263167514Skmacy * @lc: structure holding the link state 4264172096Skmacy * @caps: link capabilities 4265167514Skmacy * 4266167514Skmacy * Initializes the SW state maintained for each link, including the link's 4267167514Skmacy * capabilities and default speed/duplex/flow-control/autonegotiation 4268167514Skmacy * settings. 4269167514Skmacy */ 4270167514Skmacystatic void __devinit init_link_config(struct link_config *lc, 4271167514Skmacy unsigned int caps) 4272167514Skmacy{ 4273167514Skmacy lc->supported = caps; 4274167514Skmacy lc->requested_speed = lc->speed = SPEED_INVALID; 4275167514Skmacy lc->requested_duplex = lc->duplex = DUPLEX_INVALID; 4276167514Skmacy lc->requested_fc = lc->fc = PAUSE_RX | PAUSE_TX; 4277167514Skmacy if (lc->supported & SUPPORTED_Autoneg) { 4278167514Skmacy lc->advertising = lc->supported; 4279167514Skmacy lc->autoneg = AUTONEG_ENABLE; 4280167514Skmacy lc->requested_fc |= PAUSE_AUTONEG; 4281167514Skmacy } else { 4282167514Skmacy lc->advertising = 0; 4283167514Skmacy lc->autoneg = AUTONEG_DISABLE; 4284167514Skmacy } 4285167514Skmacy} 4286167514Skmacy 4287167514Skmacy/** 4288167514Skmacy * mc7_calc_size - calculate MC7 memory size 4289167514Skmacy * @cfg: the MC7 configuration 4290167514Skmacy * 4291167514Skmacy * Calculates the size of an MC7 memory in bytes from the value of its 4292167514Skmacy * configuration register. 4293167514Skmacy */ 4294167514Skmacystatic unsigned int __devinit mc7_calc_size(u32 cfg) 4295167514Skmacy{ 4296167514Skmacy unsigned int width = G_WIDTH(cfg); 4297167514Skmacy unsigned int banks = !!(cfg & F_BKS) + 1; 4298167514Skmacy unsigned int org = !!(cfg & F_ORG) + 1; 4299167514Skmacy unsigned int density = G_DEN(cfg); 4300167514Skmacy unsigned int MBs = ((256 << density) * banks) / (org << width); 4301167514Skmacy 4302167514Skmacy return MBs << 20; 4303167514Skmacy} 4304167514Skmacy 4305167514Skmacystatic void __devinit mc7_prep(adapter_t *adapter, struct mc7 *mc7, 4306167514Skmacy unsigned int base_addr, const char *name) 4307167514Skmacy{ 4308167514Skmacy u32 cfg; 4309167514Skmacy 4310167514Skmacy mc7->adapter = adapter; 4311167514Skmacy mc7->name = name; 4312167514Skmacy mc7->offset = base_addr - MC7_PMRX_BASE_ADDR; 4313167514Skmacy cfg = t3_read_reg(adapter, mc7->offset + A_MC7_CFG); 4314169978Skmacy mc7->size = G_DEN(cfg) == M_DEN ? 0 : mc7_calc_size(cfg); 4315167514Skmacy mc7->width = G_WIDTH(cfg); 4316167514Skmacy} 4317167514Skmacy 4318167514Skmacyvoid mac_prep(struct cmac *mac, adapter_t *adapter, int index) 4319167514Skmacy{ 4320197791Snp u16 devid; 4321197791Snp 4322167514Skmacy mac->adapter = adapter; 4323170654Skmacy mac->multiport = adapter->params.nports > 2; 4324170654Skmacy if (mac->multiport) { 4325170654Skmacy mac->ext_port = (unsigned char)index; 4326170654Skmacy mac->nucast = 8; 4327170654Skmacy } else 4328170654Skmacy mac->nucast = 1; 4329170654Skmacy 4330197791Snp /* Gen2 adapter uses VPD xauicfg[] to notify driver which MAC 4331197791Snp is connected to each port, its suppose to be using xgmac0 for both ports 4332197791Snp */ 4333197791Snp t3_os_pci_read_config_2(adapter, 0x2, &devid); 4334197791Snp 4335197791Snp if (mac->multiport || 4336197791Snp (!adapter->params.vpd.xauicfg[1] && (devid==0x37))) 4337197791Snp index = 0; 4338197791Snp 4339167514Skmacy mac->offset = (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR) * index; 4340167514Skmacy 4341167514Skmacy if (adapter->params.rev == 0 && uses_xaui(adapter)) { 4342167514Skmacy t3_write_reg(adapter, A_XGM_SERDES_CTRL + mac->offset, 4343167514Skmacy is_10G(adapter) ? 0x2901c04 : 0x2301c04); 4344167514Skmacy t3_set_reg_field(adapter, A_XGM_PORT_CFG + mac->offset, 4345167514Skmacy F_ENRGMII, 0); 4346167514Skmacy } 4347167514Skmacy} 4348167514Skmacy 4349172096Skmacy/** 4350172096Skmacy * early_hw_init - HW initialization done at card detection time 4351172096Skmacy * @adapter: the adapter 4352172096Skmacy * @ai: contains information about the adapter type and properties 4353172096Skmacy * 4354172096Skmacy * Perfoms the part of HW initialization that is done early on when the 4355172096Skmacy * driver first detecs the card. Most of the HW state is initialized 4356172096Skmacy * lazily later on when a port or an offload function are first used. 4357172096Skmacy */ 4358167514Skmacyvoid early_hw_init(adapter_t *adapter, const struct adapter_info *ai) 4359167514Skmacy{ 4360170654Skmacy u32 val = V_PORTSPEED(is_10G(adapter) || adapter->params.nports > 2 ? 4361170654Skmacy 3 : 2); 4362189643Sgnn u32 gpio_out = ai->gpio_out; 4363167514Skmacy 4364167514Skmacy mi1_init(adapter, ai); 4365167514Skmacy t3_write_reg(adapter, A_I2C_CFG, /* set for 80KHz */ 4366167514Skmacy V_I2C_CLKDIV(adapter->params.vpd.cclk / 80 - 1)); 4367167514Skmacy t3_write_reg(adapter, A_T3DBG_GPIO_EN, 4368189643Sgnn gpio_out | F_GPIO0_OEN | F_GPIO0_OUT_VAL); 4369169978Skmacy t3_write_reg(adapter, A_MC5_DB_SERVER_INDEX, 0); 4370176472Skmacy t3_write_reg(adapter, A_SG_OCO_BASE, V_BASE1(0xfff)); 4371170654Skmacy 4372167514Skmacy if (adapter->params.rev == 0 || !uses_xaui(adapter)) 4373167514Skmacy val |= F_ENRGMII; 4374167514Skmacy 4375167514Skmacy /* Enable MAC clocks so we can access the registers */ 4376167514Skmacy t3_write_reg(adapter, A_XGM_PORT_CFG, val); 4377167514Skmacy (void) t3_read_reg(adapter, A_XGM_PORT_CFG); 4378167514Skmacy 4379167514Skmacy val |= F_CLKDIVRESET_; 4380167514Skmacy t3_write_reg(adapter, A_XGM_PORT_CFG, val); 4381167514Skmacy (void) t3_read_reg(adapter, A_XGM_PORT_CFG); 4382167514Skmacy t3_write_reg(adapter, XGM_REG(A_XGM_PORT_CFG, 1), val); 4383167514Skmacy (void) t3_read_reg(adapter, A_XGM_PORT_CFG); 4384167514Skmacy} 4385167514Skmacy 4386172096Skmacy/** 4387172096Skmacy * t3_reset_adapter - reset the adapter 4388172096Skmacy * @adapter: the adapter 4389172096Skmacy * 4390172096Skmacy * Reset the adapter. 4391167514Skmacy */ 4392189643Sgnnint t3_reset_adapter(adapter_t *adapter) 4393167514Skmacy{ 4394189643Sgnn int i, save_and_restore_pcie = 4395167746Skmacy adapter->params.rev < T3_REV_B2 && is_pcie(adapter); 4396167746Skmacy uint16_t devid = 0; 4397167514Skmacy 4398167746Skmacy if (save_and_restore_pcie) 4399167514Skmacy t3_os_pci_save_state(adapter); 4400167514Skmacy t3_write_reg(adapter, A_PL_RST, F_CRSTWRM | F_CRSTWRMMODE); 4401167514Skmacy 4402167514Skmacy /* 4403167514Skmacy * Delay. Give Some time to device to reset fully. 4404167514Skmacy * XXX The delay time should be modified. 4405167514Skmacy */ 4406167514Skmacy for (i = 0; i < 10; i++) { 4407171471Skmacy msleep(50); 4408167514Skmacy t3_os_pci_read_config_2(adapter, 0x00, &devid); 4409167514Skmacy if (devid == 0x1425) 4410167514Skmacy break; 4411167514Skmacy } 4412167514Skmacy 4413167514Skmacy if (devid != 0x1425) 4414167514Skmacy return -1; 4415167514Skmacy 4416167746Skmacy if (save_and_restore_pcie) 4417167514Skmacy t3_os_pci_restore_state(adapter); 4418167514Skmacy return 0; 4419167514Skmacy} 4420167514Skmacy 4421181614Skmacystatic int init_parity(adapter_t *adap) 4422176472Skmacy{ 4423176472Skmacy int i, err, addr; 4424176472Skmacy 4425176472Skmacy if (t3_read_reg(adap, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) 4426176472Skmacy return -EBUSY; 4427176472Skmacy 4428176472Skmacy for (err = i = 0; !err && i < 16; i++) 4429176472Skmacy err = clear_sge_ctxt(adap, i, F_EGRESS); 4430176472Skmacy for (i = 0xfff0; !err && i <= 0xffff; i++) 4431176472Skmacy err = clear_sge_ctxt(adap, i, F_EGRESS); 4432176472Skmacy for (i = 0; !err && i < SGE_QSETS; i++) 4433176472Skmacy err = clear_sge_ctxt(adap, i, F_RESPONSEQ); 4434176472Skmacy if (err) 4435176472Skmacy return err; 4436176472Skmacy 4437176472Skmacy t3_write_reg(adap, A_CIM_IBQ_DBG_DATA, 0); 4438176472Skmacy for (i = 0; i < 4; i++) 4439176472Skmacy for (addr = 0; addr <= M_IBQDBGADDR; addr++) { 4440176472Skmacy t3_write_reg(adap, A_CIM_IBQ_DBG_CFG, F_IBQDBGEN | 4441176472Skmacy F_IBQDBGWR | V_IBQDBGQID(i) | 4442176472Skmacy V_IBQDBGADDR(addr)); 4443176472Skmacy err = t3_wait_op_done(adap, A_CIM_IBQ_DBG_CFG, 4444176472Skmacy F_IBQDBGBUSY, 0, 2, 1); 4445176472Skmacy if (err) 4446176472Skmacy return err; 4447176472Skmacy } 4448176472Skmacy return 0; 4449176472Skmacy} 4450176472Skmacy 4451172096Skmacy/** 4452172096Skmacy * t3_prep_adapter - prepare SW and HW for operation 4453172096Skmacy * @adapter: the adapter 4454172096Skmacy * @ai: contains information about the adapter type and properties 4455172096Skmacy * 4456172096Skmacy * Initialize adapter SW state for the various HW modules, set initial 4457172096Skmacy * values for some adapter tunables, take PHYs out of reset, and 4458172096Skmacy * initialize the MDIO interface. 4459167514Skmacy */ 4460167514Skmacyint __devinit t3_prep_adapter(adapter_t *adapter, 4461167514Skmacy const struct adapter_info *ai, int reset) 4462167514Skmacy{ 4463167514Skmacy int ret; 4464167514Skmacy unsigned int i, j = 0; 4465167514Skmacy 4466167514Skmacy get_pci_mode(adapter, &adapter->params.pci); 4467167514Skmacy 4468167514Skmacy adapter->params.info = ai; 4469170654Skmacy adapter->params.nports = ai->nports0 + ai->nports1; 4470201907Snp adapter->params.chan_map = (!!ai->nports0) | (!!ai->nports1 << 1); 4471167514Skmacy adapter->params.rev = t3_read_reg(adapter, A_PL_REV); 4472189643Sgnn 4473189643Sgnn /* 4474189643Sgnn * We used to only run the "adapter check task" once a second if 4475189643Sgnn * we had PHYs which didn't support interrupts (we would check 4476189643Sgnn * their link status once a second). Now we check other conditions 4477189643Sgnn * in that routine which would [potentially] impose a very high 4478189643Sgnn * interrupt load on the system. As such, we now always scan the 4479189643Sgnn * adapter state once a second ... 4480189643Sgnn */ 4481189643Sgnn adapter->params.linkpoll_period = 10; 4482189643Sgnn 4483171471Skmacy if (adapter->params.nports > 2) 4484171471Skmacy adapter->params.stats_update_period = VSC_STATS_ACCUM_SECS; 4485171471Skmacy else 4486171471Skmacy adapter->params.stats_update_period = is_10G(adapter) ? 4487171471Skmacy MAC_STATS_ACCUM_SECS : (MAC_STATS_ACCUM_SECS * 10); 4488167514Skmacy adapter->params.pci.vpd_cap_addr = 4489167514Skmacy t3_os_find_pci_capability(adapter, PCI_CAP_ID_VPD); 4490167514Skmacy 4491167514Skmacy ret = get_vpd_params(adapter, &adapter->params.vpd); 4492171471Skmacy if (ret < 0) 4493167514Skmacy return ret; 4494171471Skmacy 4495167514Skmacy if (reset && t3_reset_adapter(adapter)) 4496167514Skmacy return -1; 4497167514Skmacy 4498167514Skmacy if (adapter->params.vpd.mclk) { 4499167514Skmacy struct tp_params *p = &adapter->params.tp; 4500167514Skmacy 4501167514Skmacy mc7_prep(adapter, &adapter->pmrx, MC7_PMRX_BASE_ADDR, "PMRX"); 4502167514Skmacy mc7_prep(adapter, &adapter->pmtx, MC7_PMTX_BASE_ADDR, "PMTX"); 4503167514Skmacy mc7_prep(adapter, &adapter->cm, MC7_CM_BASE_ADDR, "CM"); 4504167514Skmacy 4505170654Skmacy p->nchan = adapter->params.chan_map == 3 ? 2 : 1; 4506167514Skmacy p->pmrx_size = t3_mc7_size(&adapter->pmrx); 4507167514Skmacy p->pmtx_size = t3_mc7_size(&adapter->pmtx); 4508167514Skmacy p->cm_size = t3_mc7_size(&adapter->cm); 4509167514Skmacy p->chan_rx_size = p->pmrx_size / 2; /* only 1 Rx channel */ 4510167514Skmacy p->chan_tx_size = p->pmtx_size / p->nchan; 4511167514Skmacy p->rx_pg_size = 64 * 1024; 4512167514Skmacy p->tx_pg_size = is_10G(adapter) ? 64 * 1024 : 16 * 1024; 4513167514Skmacy p->rx_num_pgs = pm_num_pages(p->chan_rx_size, p->rx_pg_size); 4514167514Skmacy p->tx_num_pgs = pm_num_pages(p->chan_tx_size, p->tx_pg_size); 4515167514Skmacy p->ntimer_qs = p->cm_size >= (128 << 20) || 4516167514Skmacy adapter->params.rev > 0 ? 12 : 6; 4517170654Skmacy p->tre = fls(adapter->params.vpd.cclk / (1000 / TP_TMR_RES)) - 4518170654Skmacy 1; 4519167746Skmacy p->dack_re = fls(adapter->params.vpd.cclk / 10) - 1; /* 100us */ 4520169978Skmacy } 4521170654Skmacy 4522169978Skmacy adapter->params.offload = t3_mc7_size(&adapter->pmrx) && 4523170654Skmacy t3_mc7_size(&adapter->pmtx) && 4524170654Skmacy t3_mc7_size(&adapter->cm); 4525167514Skmacy 4526205950Snp t3_sge_prep(adapter, &adapter->params.sge); 4527205950Snp 4528169978Skmacy if (is_offload(adapter)) { 4529167514Skmacy adapter->params.mc5.nservers = DEFAULT_NSERVERS; 4530189643Sgnn /* PR 6487. TOE and filtering are mutually exclusive */ 4531189643Sgnn adapter->params.mc5.nfilters = 0; 4532167514Skmacy adapter->params.mc5.nroutes = 0; 4533167514Skmacy t3_mc5_prep(adapter, &adapter->mc5, MC5_MODE_144_BIT); 4534167514Skmacy 4535167514Skmacy init_mtus(adapter->params.mtus); 4536167514Skmacy init_cong_ctrl(adapter->params.a_wnd, adapter->params.b_wnd); 4537167514Skmacy } 4538167514Skmacy 4539167514Skmacy early_hw_init(adapter, ai); 4540176472Skmacy ret = init_parity(adapter); 4541176472Skmacy if (ret) 4542176472Skmacy return ret; 4543167514Skmacy 4544171471Skmacy if (adapter->params.nports > 2 && 4545171471Skmacy (ret = t3_vsc7323_init(adapter, adapter->params.nports))) 4546171471Skmacy return ret; 4547171471Skmacy 4548167514Skmacy for_each_port(adapter, i) { 4549167514Skmacy u8 hw_addr[6]; 4550176472Skmacy const struct port_type_info *pti; 4551170654Skmacy struct port_info *p = adap2pinfo(adapter, i); 4552167514Skmacy 4553189643Sgnn for (;;) { 4554189643Sgnn unsigned port_type = adapter->params.vpd.port_type[j]; 4555189643Sgnn if (port_type) { 4556189643Sgnn if (port_type < ARRAY_SIZE(port_types)) { 4557189643Sgnn pti = &port_types[port_type]; 4558189643Sgnn break; 4559189643Sgnn } else 4560189643Sgnn return -EINVAL; 4561189643Sgnn } 4562189643Sgnn j++; 4563189643Sgnn if (j >= ARRAY_SIZE(adapter->params.vpd.port_type)) 4564189643Sgnn return -EINVAL; 4565189643Sgnn } 4566197791Snp ret = pti->phy_prep(p, ai->phy_base_addr + j, 4567176472Skmacy ai->mdio_ops); 4568176472Skmacy if (ret) 4569176472Skmacy return ret; 4570167514Skmacy mac_prep(&p->mac, adapter, j); 4571167514Skmacy ++j; 4572167514Skmacy 4573167514Skmacy /* 4574167514Skmacy * The VPD EEPROM stores the base Ethernet address for the 4575167514Skmacy * card. A port's address is derived from the base by adding 4576167514Skmacy * the port's index to the base's low octet. 4577167514Skmacy */ 4578167514Skmacy memcpy(hw_addr, adapter->params.vpd.eth_base, 5); 4579167514Skmacy hw_addr[5] = adapter->params.vpd.eth_base[5] + i; 4580167514Skmacy 4581167514Skmacy t3_os_set_hw_addr(adapter, i, hw_addr); 4582176472Skmacy init_link_config(&p->link_config, p->phy.caps); 4583167514Skmacy p->phy.ops->power_down(&p->phy, 1); 4584189643Sgnn 4585189643Sgnn /* 4586189643Sgnn * If the PHY doesn't support interrupts for link status 4587189643Sgnn * changes, schedule a scan of the adapter links at least 4588189643Sgnn * once a second. 4589189643Sgnn */ 4590189643Sgnn if (!(p->phy.caps & SUPPORTED_IRQ) && 4591189643Sgnn adapter->params.linkpoll_period > 10) 4592167514Skmacy adapter->params.linkpoll_period = 10; 4593167514Skmacy } 4594167514Skmacy 4595167514Skmacy return 0; 4596167514Skmacy} 4597167514Skmacy 4598181614Skmacy/** 4599181614Skmacy * t3_reinit_adapter - prepare HW for operation again 4600181614Skmacy * @adapter: the adapter 4601181614Skmacy * 4602181614Skmacy * Put HW in the same state as @t3_prep_adapter without any changes to 4603181614Skmacy * SW state. This is a cut down version of @t3_prep_adapter intended 4604181614Skmacy * to be used after events that wipe out HW state but preserve SW state, 4605181614Skmacy * e.g., EEH. The device must be reset before calling this. 4606181614Skmacy */ 4607181614Skmacyint t3_reinit_adapter(adapter_t *adap) 4608181614Skmacy{ 4609181614Skmacy unsigned int i; 4610189643Sgnn int ret, j = 0; 4611181614Skmacy 4612181614Skmacy early_hw_init(adap, adap->params.info); 4613181614Skmacy ret = init_parity(adap); 4614181614Skmacy if (ret) 4615181614Skmacy return ret; 4616181614Skmacy 4617181614Skmacy if (adap->params.nports > 2 && 4618181614Skmacy (ret = t3_vsc7323_init(adap, adap->params.nports))) 4619181614Skmacy return ret; 4620181614Skmacy 4621181614Skmacy for_each_port(adap, i) { 4622181614Skmacy const struct port_type_info *pti; 4623181614Skmacy struct port_info *p = adap2pinfo(adap, i); 4624181614Skmacy 4625189643Sgnn for (;;) { 4626189643Sgnn unsigned port_type = adap->params.vpd.port_type[j]; 4627189643Sgnn if (port_type) { 4628189643Sgnn if (port_type < ARRAY_SIZE(port_types)) { 4629189643Sgnn pti = &port_types[port_type]; 4630189643Sgnn break; 4631189643Sgnn } else 4632189643Sgnn return -EINVAL; 4633189643Sgnn } 4634189643Sgnn j++; 4635189643Sgnn if (j >= ARRAY_SIZE(adap->params.vpd.port_type)) 4636189643Sgnn return -EINVAL; 4637189643Sgnn } 4638197791Snp ret = pti->phy_prep(p, p->phy.addr, NULL); 4639181614Skmacy if (ret) 4640181614Skmacy return ret; 4641181614Skmacy p->phy.ops->power_down(&p->phy, 1); 4642181614Skmacy } 4643181614Skmacy return 0; 4644181614Skmacy} 4645181614Skmacy 4646167514Skmacyvoid t3_led_ready(adapter_t *adapter) 4647167514Skmacy{ 4648167514Skmacy t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL, 4649167514Skmacy F_GPIO0_OUT_VAL); 4650167514Skmacy} 4651167514Skmacy 4652167514Skmacyvoid t3_port_failover(adapter_t *adapter, int port) 4653167514Skmacy{ 4654167514Skmacy u32 val; 4655167514Skmacy 4656167514Skmacy val = port ? F_PORT1ACTIVE : F_PORT0ACTIVE; 4657167514Skmacy t3_set_reg_field(adapter, A_MPS_CFG, F_PORT0ACTIVE | F_PORT1ACTIVE, 4658167514Skmacy val); 4659167514Skmacy} 4660167514Skmacy 4661167514Skmacyvoid t3_failover_done(adapter_t *adapter, int port) 4662167514Skmacy{ 4663167514Skmacy t3_set_reg_field(adapter, A_MPS_CFG, F_PORT0ACTIVE | F_PORT1ACTIVE, 4664167514Skmacy F_PORT0ACTIVE | F_PORT1ACTIVE); 4665167514Skmacy} 4666167514Skmacy 4667167514Skmacyvoid t3_failover_clear(adapter_t *adapter) 4668167514Skmacy{ 4669167514Skmacy t3_set_reg_field(adapter, A_MPS_CFG, F_PORT0ACTIVE | F_PORT1ACTIVE, 4670167514Skmacy F_PORT0ACTIVE | F_PORT1ACTIVE); 4671167514Skmacy} 4672189643Sgnn 4673189643Sgnnstatic int t3_cim_hac_read(adapter_t *adapter, u32 addr, u32 *val) 4674189643Sgnn{ 4675189643Sgnn u32 v; 4676189643Sgnn 4677189643Sgnn t3_write_reg(adapter, A_CIM_HOST_ACC_CTRL, addr); 4678189643Sgnn if (t3_wait_op_done_val(adapter, A_CIM_HOST_ACC_CTRL, 4679189643Sgnn F_HOSTBUSY, 0, 10, 10, &v)) 4680189643Sgnn return -EIO; 4681189643Sgnn 4682189643Sgnn *val = t3_read_reg(adapter, A_CIM_HOST_ACC_DATA); 4683189643Sgnn 4684189643Sgnn return 0; 4685189643Sgnn} 4686189643Sgnn 4687189643Sgnnstatic int t3_cim_hac_write(adapter_t *adapter, u32 addr, u32 val) 4688189643Sgnn{ 4689189643Sgnn u32 v; 4690189643Sgnn 4691189643Sgnn t3_write_reg(adapter, A_CIM_HOST_ACC_DATA, val); 4692189643Sgnn 4693189643Sgnn addr |= F_HOSTWRITE; 4694189643Sgnn t3_write_reg(adapter, A_CIM_HOST_ACC_CTRL, addr); 4695189643Sgnn 4696189643Sgnn if (t3_wait_op_done_val(adapter, A_CIM_HOST_ACC_CTRL, 4697189643Sgnn F_HOSTBUSY, 0, 10, 5, &v)) 4698189643Sgnn return -EIO; 4699189643Sgnn return 0; 4700189643Sgnn} 4701189643Sgnn 4702189643Sgnnint t3_get_up_la(adapter_t *adapter, u32 *stopped, u32 *index, 4703189643Sgnn u32 *size, void *data) 4704189643Sgnn{ 4705189643Sgnn u32 v, *buf = data; 4706189643Sgnn int i, cnt, ret; 4707189643Sgnn 4708189643Sgnn if (*size < LA_ENTRIES * 4) 4709189643Sgnn return -EINVAL; 4710189643Sgnn 4711189643Sgnn ret = t3_cim_hac_read(adapter, LA_CTRL, &v); 4712189643Sgnn if (ret) 4713189643Sgnn goto out; 4714189643Sgnn 4715189643Sgnn *stopped = !(v & 1); 4716189643Sgnn 4717189643Sgnn /* Freeze LA */ 4718189643Sgnn if (!*stopped) { 4719189643Sgnn ret = t3_cim_hac_write(adapter, LA_CTRL, 0); 4720189643Sgnn if (ret) 4721189643Sgnn goto out; 4722189643Sgnn } 4723189643Sgnn 4724189643Sgnn for (i = 0; i < LA_ENTRIES; i++) { 4725189643Sgnn v = (i << 2) | (1 << 1); 4726189643Sgnn ret = t3_cim_hac_write(adapter, LA_CTRL, v); 4727189643Sgnn if (ret) 4728189643Sgnn goto out; 4729189643Sgnn 4730189643Sgnn ret = t3_cim_hac_read(adapter, LA_CTRL, &v); 4731189643Sgnn if (ret) 4732189643Sgnn goto out; 4733189643Sgnn 4734189643Sgnn cnt = 20; 4735189643Sgnn while ((v & (1 << 1)) && cnt) { 4736189643Sgnn udelay(5); 4737189643Sgnn --cnt; 4738189643Sgnn ret = t3_cim_hac_read(adapter, LA_CTRL, &v); 4739189643Sgnn if (ret) 4740189643Sgnn goto out; 4741189643Sgnn } 4742189643Sgnn 4743189643Sgnn if (v & (1 << 1)) 4744189643Sgnn return -EIO; 4745189643Sgnn 4746189643Sgnn ret = t3_cim_hac_read(adapter, LA_DATA, &v); 4747189643Sgnn if (ret) 4748189643Sgnn goto out; 4749189643Sgnn 4750189643Sgnn *buf++ = v; 4751189643Sgnn } 4752189643Sgnn 4753189643Sgnn ret = t3_cim_hac_read(adapter, LA_CTRL, &v); 4754189643Sgnn if (ret) 4755189643Sgnn goto out; 4756189643Sgnn 4757189643Sgnn *index = (v >> 16) + 4; 4758189643Sgnn *size = LA_ENTRIES * 4; 4759189643Sgnnout: 4760189643Sgnn /* Unfreeze LA */ 4761189643Sgnn t3_cim_hac_write(adapter, LA_CTRL, 1); 4762189643Sgnn return ret; 4763189643Sgnn} 4764189643Sgnn 4765189643Sgnnint t3_get_up_ioqs(adapter_t *adapter, u32 *size, void *data) 4766189643Sgnn{ 4767189643Sgnn u32 v, *buf = data; 4768189643Sgnn int i, j, ret; 4769189643Sgnn 4770189643Sgnn if (*size < IOQ_ENTRIES * sizeof(struct t3_ioq_entry)) 4771189643Sgnn return -EINVAL; 4772189643Sgnn 4773189643Sgnn for (i = 0; i < 4; i++) { 4774189643Sgnn ret = t3_cim_hac_read(adapter, (4 * i), &v); 4775189643Sgnn if (ret) 4776189643Sgnn goto out; 4777189643Sgnn 4778189643Sgnn *buf++ = v; 4779189643Sgnn } 4780189643Sgnn 4781189643Sgnn for (i = 0; i < IOQ_ENTRIES; i++) { 4782189643Sgnn u32 base_addr = 0x10 * (i + 1); 4783189643Sgnn 4784189643Sgnn for (j = 0; j < 4; j++) { 4785189643Sgnn ret = t3_cim_hac_read(adapter, base_addr + 4 * j, &v); 4786189643Sgnn if (ret) 4787189643Sgnn goto out; 4788189643Sgnn 4789189643Sgnn *buf++ = v; 4790189643Sgnn } 4791189643Sgnn } 4792189643Sgnn 4793189643Sgnn *size = IOQ_ENTRIES * sizeof(struct t3_ioq_entry); 4794189643Sgnn 4795189643Sgnnout: 4796189643Sgnn return ret; 4797189643Sgnn} 4798189643Sgnn 4799