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 654167514Skmacy * addres 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 1034167514Skmacy * natural endianess. 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 1071176472Skmacy * big-endian array, otherwise in the processor's native endianess. 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{ 1523197791Snp int link_ok, speed, duplex, fc, link_fault; 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 1535167514Skmacy phy->ops->get_link_status(phy, &link_ok, &speed, &duplex, &fc); 1536167514Skmacy 1537209841Snp if (link_ok == 0) 1538209841Snp pi->link_fault = LF_NO; 1539209841Snp 1540197791Snp if (lc->requested_fc & PAUSE_AUTONEG) 1541197791Snp fc &= lc->requested_fc; 1542197791Snp else 1543197791Snp fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX); 1544197791Snp 1545197791Snp /* Update mac speed before checking for link fault. */ 1546197791Snp if (link_ok && speed >= 0 && lc->autoneg == AUTONEG_ENABLE && 1547197791Snp (speed != lc->speed || duplex != lc->duplex || fc != lc->fc)) 1548197791Snp t3_mac_set_speed_duplex_fc(mac, speed, duplex, fc); 1549197791Snp 1550192540Sgnn /* 1551192540Sgnn * Check for link faults if any of these is true: 1552192540Sgnn * a) A link fault is suspected, and PHY says link ok 1553192540Sgnn * b) PHY link transitioned from down -> up 1554192540Sgnn */ 1555192540Sgnn if (adapter->params.nports <= 2 && 1556192540Sgnn ((pi->link_fault && link_ok) || (!lc->link_ok && link_ok))) { 1557189643Sgnn 1558192540Sgnn link_fault = t3_detect_link_fault(adapter, port_id); 1559192540Sgnn if (link_fault) { 1560192540Sgnn if (pi->link_fault != LF_YES) { 1561192540Sgnn mac->stats.link_faults++; 1562192540Sgnn pi->link_fault = LF_YES; 1563192540Sgnn } 1564189643Sgnn 1565211346Snp if (uses_xaui(adapter)) { 1566211346Snp if (adapter->params.rev >= T3_REV_C) 1567211346Snp t3c_pcs_force_los(mac); 1568211346Snp else 1569211346Snp t3b_pcs_reset(mac); 1570211346Snp } 1571211346Snp 1572197791Snp /* Don't report link up */ 1573192540Sgnn link_ok = 0; 1574192540Sgnn } else { 1575192540Sgnn /* clear faults here if this was a false alarm. */ 1576192540Sgnn if (pi->link_fault == LF_MAYBE && 1577192540Sgnn link_ok && lc->link_ok) 1578192540Sgnn t3_clear_faults(adapter, port_id); 1579189643Sgnn 1580192540Sgnn pi->link_fault = LF_NO; 1581189643Sgnn } 1582189643Sgnn } 1583189643Sgnn 1584180583Skmacy if (link_ok == lc->link_ok && speed == lc->speed && 1585180583Skmacy duplex == lc->duplex && fc == lc->fc) 1586180583Skmacy return; /* nothing changed */ 1587180583Skmacy 1588167514Skmacy lc->link_ok = (unsigned char)link_ok; 1589167514Skmacy lc->speed = speed < 0 ? SPEED_INVALID : speed; 1590167514Skmacy lc->duplex = duplex < 0 ? DUPLEX_INVALID : duplex; 1591197791Snp lc->fc = fc; 1592167514Skmacy 1593192540Sgnn if (link_ok) { 1594167514Skmacy 1595192540Sgnn /* down -> up, or up -> up with changed settings */ 1596167514Skmacy 1597197791Snp if (adapter->params.rev > 0 && uses_xaui(adapter)) { 1598211346Snp 1599211346Snp if (adapter->params.rev >= T3_REV_C) 1600211346Snp t3c_pcs_force_los(mac); 1601211346Snp else 1602211346Snp t3b_pcs_reset(mac); 1603211346Snp 1604192540Sgnn t3_write_reg(adapter, A_XGM_XAUI_ACT_CTRL + mac->offset, 1605192540Sgnn F_TXACTENABLE | F_RXEN); 1606192540Sgnn } 1607189643Sgnn 1608211346Snp /* disable TX FIFO drain */ 1609197791Snp t3_set_reg_field(adapter, A_XGM_TXFIFO_CFG + mac->offset, 1610197791Snp F_ENDROPPKT, 0); 1611211346Snp 1612197791Snp t3_mac_enable(mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX); 1613197791Snp t3_set_reg_field(adapter, A_XGM_STAT_CTRL + mac->offset, 1614197791Snp F_CLRSTATS, 1); 1615192540Sgnn t3_clear_faults(adapter, port_id); 1616189643Sgnn 1617192540Sgnn } else { 1618189643Sgnn 1619192540Sgnn /* up -> down */ 1620189643Sgnn 1621192540Sgnn if (adapter->params.rev > 0 && uses_xaui(adapter)) { 1622192540Sgnn t3_write_reg(adapter, 1623192540Sgnn A_XGM_XAUI_ACT_CTRL + mac->offset, 0); 1624192540Sgnn } 1625189643Sgnn 1626192540Sgnn t3_xgm_intr_disable(adapter, pi->port_id); 1627192540Sgnn if (adapter->params.nports <= 2) { 1628192540Sgnn t3_set_reg_field(adapter, 1629192540Sgnn A_XGM_INT_ENABLE + mac->offset, 1630192540Sgnn F_XGM_INT, 0); 1631189643Sgnn 1632192540Sgnn t3_mac_disable(mac, MAC_DIRECTION_RX); 1633189643Sgnn 1634211346Snp /* 1635211346Snp * Make sure Tx FIFO continues to drain, even as rxen is 1636211346Snp * left high to help detect and indicate remote faults. 1637211346Snp */ 1638211346Snp t3_set_reg_field(adapter, 1639211346Snp A_XGM_TXFIFO_CFG + mac->offset, 0, F_ENDROPPKT); 1640211346Snp t3_write_reg(adapter, A_XGM_RX_CTRL + mac->offset, 0); 1641211346Snp t3_write_reg(adapter, 1642211346Snp A_XGM_TX_CTRL + mac->offset, F_TXEN); 1643211346Snp t3_write_reg(adapter, 1644211346Snp A_XGM_RX_CTRL + mac->offset, F_RXEN); 1645211346Snp } 1646192540Sgnn } 1647189643Sgnn 1648197791Snp t3_os_link_changed(adapter, port_id, link_ok, speed, duplex, fc, 1649197791Snp mac->was_reset); 1650197791Snp mac->was_reset = 0; 1651189643Sgnn} 1652189643Sgnn 1653167514Skmacy/** 1654167514Skmacy * t3_link_start - apply link configuration to MAC/PHY 1655167514Skmacy * @phy: the PHY to setup 1656167514Skmacy * @mac: the MAC to setup 1657167514Skmacy * @lc: the requested link configuration 1658167514Skmacy * 1659167514Skmacy * Set up a port's MAC and PHY according to a desired link configuration. 1660167514Skmacy * - If the PHY can auto-negotiate first decide what to advertise, then 1661167514Skmacy * enable/disable auto-negotiation as desired, and reset. 1662167514Skmacy * - If the PHY does not auto-negotiate just reset it. 1663167514Skmacy * - If auto-negotiation is off set the MAC to the proper speed/duplex/FC, 1664167514Skmacy * otherwise do it later based on the outcome of auto-negotiation. 1665167514Skmacy */ 1666167514Skmacyint t3_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc) 1667167514Skmacy{ 1668167514Skmacy unsigned int fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX); 1669167514Skmacy 1670167514Skmacy lc->link_ok = 0; 1671167514Skmacy if (lc->supported & SUPPORTED_Autoneg) { 1672167514Skmacy lc->advertising &= ~(ADVERTISED_Asym_Pause | ADVERTISED_Pause); 1673167514Skmacy if (fc) { 1674167514Skmacy lc->advertising |= ADVERTISED_Asym_Pause; 1675167514Skmacy if (fc & PAUSE_RX) 1676167514Skmacy lc->advertising |= ADVERTISED_Pause; 1677167514Skmacy } 1678197791Snp 1679167514Skmacy phy->ops->advertise(phy, lc->advertising); 1680167514Skmacy 1681167514Skmacy if (lc->autoneg == AUTONEG_DISABLE) { 1682167514Skmacy lc->speed = lc->requested_speed; 1683167514Skmacy lc->duplex = lc->requested_duplex; 1684167514Skmacy lc->fc = (unsigned char)fc; 1685167514Skmacy t3_mac_set_speed_duplex_fc(mac, lc->speed, lc->duplex, 1686167514Skmacy fc); 1687167514Skmacy /* Also disables autoneg */ 1688167514Skmacy phy->ops->set_speed_duplex(phy, lc->speed, lc->duplex); 1689189643Sgnn /* PR 5666. Power phy up when doing an ifup */ 1690189643Sgnn if (!is_10G(phy->adapter)) 1691197791Snp phy->ops->power_down(phy, 0); 1692167514Skmacy } else 1693167514Skmacy phy->ops->autoneg_enable(phy); 1694167514Skmacy } else { 1695167514Skmacy t3_mac_set_speed_duplex_fc(mac, -1, -1, fc); 1696167514Skmacy lc->fc = (unsigned char)fc; 1697167514Skmacy phy->ops->reset(phy, 0); 1698167514Skmacy } 1699167514Skmacy return 0; 1700167514Skmacy} 1701167514Skmacy 1702167514Skmacy/** 1703167514Skmacy * t3_set_vlan_accel - control HW VLAN extraction 1704167514Skmacy * @adapter: the adapter 1705167514Skmacy * @ports: bitmap of adapter ports to operate on 1706167514Skmacy * @on: enable (1) or disable (0) HW VLAN extraction 1707167514Skmacy * 1708167514Skmacy * Enables or disables HW extraction of VLAN tags for the given port. 1709167514Skmacy */ 1710167514Skmacyvoid t3_set_vlan_accel(adapter_t *adapter, unsigned int ports, int on) 1711167514Skmacy{ 1712167514Skmacy t3_set_reg_field(adapter, A_TP_OUT_CONFIG, 1713167514Skmacy ports << S_VLANEXTRACTIONENABLE, 1714167514Skmacy on ? (ports << S_VLANEXTRACTIONENABLE) : 0); 1715167514Skmacy} 1716167514Skmacy 1717167514Skmacystruct intr_info { 1718167514Skmacy unsigned int mask; /* bits to check in interrupt status */ 1719167514Skmacy const char *msg; /* message to print or NULL */ 1720167514Skmacy short stat_idx; /* stat counter to increment or -1 */ 1721181614Skmacy unsigned short fatal; /* whether the condition reported is fatal */ 1722167514Skmacy}; 1723167514Skmacy 1724167514Skmacy/** 1725167514Skmacy * t3_handle_intr_status - table driven interrupt handler 1726167514Skmacy * @adapter: the adapter that generated the interrupt 1727167514Skmacy * @reg: the interrupt status register to process 1728167514Skmacy * @mask: a mask to apply to the interrupt status 1729167514Skmacy * @acts: table of interrupt actions 1730167514Skmacy * @stats: statistics counters tracking interrupt occurences 1731167514Skmacy * 1732167514Skmacy * A table driven interrupt handler that applies a set of masks to an 1733167514Skmacy * interrupt status word and performs the corresponding actions if the 1734167514Skmacy * interrupts described by the mask have occured. The actions include 1735167514Skmacy * optionally printing a warning or alert message, and optionally 1736167514Skmacy * incrementing a stat counter. The table is terminated by an entry 1737167514Skmacy * specifying mask 0. Returns the number of fatal interrupt conditions. 1738167514Skmacy */ 1739167514Skmacystatic int t3_handle_intr_status(adapter_t *adapter, unsigned int reg, 1740167514Skmacy unsigned int mask, 1741167514Skmacy const struct intr_info *acts, 1742167514Skmacy unsigned long *stats) 1743167514Skmacy{ 1744167514Skmacy int fatal = 0; 1745167514Skmacy unsigned int status = t3_read_reg(adapter, reg) & mask; 1746167514Skmacy 1747167514Skmacy for ( ; acts->mask; ++acts) { 1748167514Skmacy if (!(status & acts->mask)) continue; 1749167514Skmacy if (acts->fatal) { 1750167514Skmacy fatal++; 1751167514Skmacy CH_ALERT(adapter, "%s (0x%x)\n", 1752167514Skmacy acts->msg, status & acts->mask); 1753219945Snp status &= ~acts->mask; 1754167514Skmacy } else if (acts->msg) 1755167514Skmacy CH_WARN(adapter, "%s (0x%x)\n", 1756167514Skmacy acts->msg, status & acts->mask); 1757167514Skmacy if (acts->stat_idx >= 0) 1758167514Skmacy stats[acts->stat_idx]++; 1759167514Skmacy } 1760167514Skmacy if (status) /* clear processed interrupts */ 1761167514Skmacy t3_write_reg(adapter, reg, status); 1762167514Skmacy return fatal; 1763167514Skmacy} 1764167514Skmacy 1765176472Skmacy#define SGE_INTR_MASK (F_RSPQDISABLED | \ 1766176472Skmacy F_UC_REQ_FRAMINGERROR | F_R_REQ_FRAMINGERROR | \ 1767176472Skmacy F_CPPARITYERROR | F_OCPARITYERROR | F_RCPARITYERROR | \ 1768176472Skmacy F_IRPARITYERROR | V_ITPARITYERROR(M_ITPARITYERROR) | \ 1769176472Skmacy V_FLPARITYERROR(M_FLPARITYERROR) | F_LODRBPARITYERROR | \ 1770176472Skmacy F_HIDRBPARITYERROR | F_LORCQPARITYERROR | \ 1771176472Skmacy F_HIRCQPARITYERROR) 1772167514Skmacy#define MC5_INTR_MASK (F_PARITYERR | F_ACTRGNFULL | F_UNKNOWNCMD | \ 1773167514Skmacy F_REQQPARERR | F_DISPQPARERR | F_DELACTEMPTY | \ 1774167514Skmacy F_NFASRCHFAIL) 1775167514Skmacy#define MC7_INTR_MASK (F_AE | F_UE | F_CE | V_PE(M_PE)) 1776167514Skmacy#define XGM_INTR_MASK (V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR) | \ 1777167514Skmacy V_RXFIFO_PRTY_ERR(M_RXFIFO_PRTY_ERR) | \ 1778189643Sgnn F_TXFIFO_UNDERRUN) 1779167514Skmacy#define PCIX_INTR_MASK (F_MSTDETPARERR | F_SIGTARABT | F_RCVTARABT | \ 1780167514Skmacy F_RCVMSTABT | F_SIGSYSERR | F_DETPARERR | \ 1781167514Skmacy F_SPLCMPDIS | F_UNXSPLCMP | F_RCVSPLCMPERR | \ 1782167514Skmacy F_DETCORECCERR | F_DETUNCECCERR | F_PIOPARERR | \ 1783167514Skmacy V_WFPARERR(M_WFPARERR) | V_RFPARERR(M_RFPARERR) | \ 1784167514Skmacy V_CFPARERR(M_CFPARERR) /* | V_MSIXPARERR(M_MSIXPARERR) */) 1785167514Skmacy#define PCIE_INTR_MASK (F_UNXSPLCPLERRR | F_UNXSPLCPLERRC | F_PCIE_PIOPARERR |\ 1786167514Skmacy F_PCIE_WFPARERR | F_PCIE_RFPARERR | F_PCIE_CFPARERR | \ 1787167514Skmacy /* V_PCIE_MSIXPARERR(M_PCIE_MSIXPARERR) | */ \ 1788176472Skmacy F_RETRYBUFPARERR | F_RETRYLUTPARERR | F_RXPARERR | \ 1789176472Skmacy F_TXPARERR | V_BISTERR(M_BISTERR)) 1790176472Skmacy#define ULPRX_INTR_MASK (F_PARERRDATA | F_PARERRPCMD | F_ARBPF1PERR | \ 1791176472Skmacy F_ARBPF0PERR | F_ARBFPERR | F_PCMDMUXPERR | \ 1792176472Skmacy F_DATASELFRAMEERR1 | F_DATASELFRAMEERR0) 1793176472Skmacy#define ULPTX_INTR_MASK 0xfc 1794176472Skmacy#define CPLSW_INTR_MASK (F_CIM_OP_MAP_PERR | F_TP_FRAMING_ERROR | \ 1795167514Skmacy F_SGE_FRAMING_ERROR | F_CIM_FRAMING_ERROR | \ 1796167514Skmacy F_ZERO_SWITCH_ERROR) 1797167514Skmacy#define CIM_INTR_MASK (F_BLKWRPLINT | F_BLKRDPLINT | F_BLKWRCTLINT | \ 1798167514Skmacy F_BLKRDCTLINT | F_BLKWRFLASHINT | F_BLKRDFLASHINT | \ 1799167514Skmacy F_SGLWRFLASHINT | F_WRBLKFLASHINT | F_BLKWRBOOTINT | \ 1800176472Skmacy F_FLASHRANGEINT | F_SDRAMRANGEINT | F_RSVDSPACEINT | \ 1801176472Skmacy F_DRAMPARERR | F_ICACHEPARERR | F_DCACHEPARERR | \ 1802176472Skmacy F_OBQSGEPARERR | F_OBQULPHIPARERR | F_OBQULPLOPARERR | \ 1803176472Skmacy F_IBQSGELOPARERR | F_IBQSGEHIPARERR | F_IBQULPPARERR | \ 1804176472Skmacy F_IBQTPPARERR | F_ITAGPARERR | F_DTAGPARERR) 1805167514Skmacy#define PMTX_INTR_MASK (F_ZERO_C_CMD_ERROR | ICSPI_FRM_ERR | OESPI_FRM_ERR | \ 1806167514Skmacy V_ICSPI_PAR_ERROR(M_ICSPI_PAR_ERROR) | \ 1807167514Skmacy V_OESPI_PAR_ERROR(M_OESPI_PAR_ERROR)) 1808167514Skmacy#define PMRX_INTR_MASK (F_ZERO_E_CMD_ERROR | IESPI_FRM_ERR | OCSPI_FRM_ERR | \ 1809167514Skmacy V_IESPI_PAR_ERROR(M_IESPI_PAR_ERROR) | \ 1810167514Skmacy V_OCSPI_PAR_ERROR(M_OCSPI_PAR_ERROR)) 1811167514Skmacy#define MPS_INTR_MASK (V_TX0TPPARERRENB(M_TX0TPPARERRENB) | \ 1812167514Skmacy V_TX1TPPARERRENB(M_TX1TPPARERRENB) | \ 1813167514Skmacy V_RXTPPARERRENB(M_RXTPPARERRENB) | \ 1814167514Skmacy V_MCAPARERRENB(M_MCAPARERRENB)) 1815189643Sgnn#define XGM_EXTRA_INTR_MASK (F_LINKFAULTCHANGE) 1816167514Skmacy#define PL_INTR_MASK (F_T3DBG | F_XGMAC0_0 | F_XGMAC0_1 | F_MC5A | F_PM1_TX | \ 1817167514Skmacy F_PM1_RX | F_ULP2_TX | F_ULP2_RX | F_TP1 | F_CIM | \ 1818167514Skmacy F_MC7_CM | F_MC7_PMTX | F_MC7_PMRX | F_SGE3 | F_PCIM0 | \ 1819167514Skmacy F_MPS0 | F_CPL_SWITCH) 1820167514Skmacy/* 1821167514Skmacy * Interrupt handler for the PCIX1 module. 1822167514Skmacy */ 1823167514Skmacystatic void pci_intr_handler(adapter_t *adapter) 1824167514Skmacy{ 1825167514Skmacy static struct intr_info pcix1_intr_info[] = { 1826167514Skmacy { F_MSTDETPARERR, "PCI master detected parity error", -1, 1 }, 1827167514Skmacy { F_SIGTARABT, "PCI signaled target abort", -1, 1 }, 1828167514Skmacy { F_RCVTARABT, "PCI received target abort", -1, 1 }, 1829167514Skmacy { F_RCVMSTABT, "PCI received master abort", -1, 1 }, 1830167514Skmacy { F_SIGSYSERR, "PCI signaled system error", -1, 1 }, 1831167514Skmacy { F_DETPARERR, "PCI detected parity error", -1, 1 }, 1832167514Skmacy { F_SPLCMPDIS, "PCI split completion discarded", -1, 1 }, 1833167514Skmacy { F_UNXSPLCMP, "PCI unexpected split completion error", -1, 1 }, 1834167514Skmacy { F_RCVSPLCMPERR, "PCI received split completion error", -1, 1835167514Skmacy 1 }, 1836167514Skmacy { F_DETCORECCERR, "PCI correctable ECC error", 1837167514Skmacy STAT_PCI_CORR_ECC, 0 }, 1838167514Skmacy { F_DETUNCECCERR, "PCI uncorrectable ECC error", -1, 1 }, 1839167514Skmacy { F_PIOPARERR, "PCI PIO FIFO parity error", -1, 1 }, 1840167514Skmacy { V_WFPARERR(M_WFPARERR), "PCI write FIFO parity error", -1, 1841167514Skmacy 1 }, 1842167514Skmacy { V_RFPARERR(M_RFPARERR), "PCI read FIFO parity error", -1, 1843167514Skmacy 1 }, 1844167514Skmacy { V_CFPARERR(M_CFPARERR), "PCI command FIFO parity error", -1, 1845167514Skmacy 1 }, 1846167514Skmacy { V_MSIXPARERR(M_MSIXPARERR), "PCI MSI-X table/PBA parity " 1847167514Skmacy "error", -1, 1 }, 1848167514Skmacy { 0 } 1849167514Skmacy }; 1850167514Skmacy 1851167514Skmacy if (t3_handle_intr_status(adapter, A_PCIX_INT_CAUSE, PCIX_INTR_MASK, 1852167514Skmacy pcix1_intr_info, adapter->irq_stats)) 1853167514Skmacy t3_fatal_err(adapter); 1854167514Skmacy} 1855167514Skmacy 1856167514Skmacy/* 1857167514Skmacy * Interrupt handler for the PCIE module. 1858167514Skmacy */ 1859167514Skmacystatic void pcie_intr_handler(adapter_t *adapter) 1860167514Skmacy{ 1861167514Skmacy static struct intr_info pcie_intr_info[] = { 1862167514Skmacy { F_PEXERR, "PCI PEX error", -1, 1 }, 1863167514Skmacy { F_UNXSPLCPLERRR, 1864167514Skmacy "PCI unexpected split completion DMA read error", -1, 1 }, 1865167514Skmacy { F_UNXSPLCPLERRC, 1866167514Skmacy "PCI unexpected split completion DMA command error", -1, 1 }, 1867167514Skmacy { F_PCIE_PIOPARERR, "PCI PIO FIFO parity error", -1, 1 }, 1868167514Skmacy { F_PCIE_WFPARERR, "PCI write FIFO parity error", -1, 1 }, 1869167514Skmacy { F_PCIE_RFPARERR, "PCI read FIFO parity error", -1, 1 }, 1870167514Skmacy { F_PCIE_CFPARERR, "PCI command FIFO parity error", -1, 1 }, 1871167514Skmacy { V_PCIE_MSIXPARERR(M_PCIE_MSIXPARERR), 1872167514Skmacy "PCI MSI-X table/PBA parity error", -1, 1 }, 1873176472Skmacy { F_RETRYBUFPARERR, "PCI retry buffer parity error", -1, 1 }, 1874176472Skmacy { F_RETRYLUTPARERR, "PCI retry LUT parity error", -1, 1 }, 1875176472Skmacy { F_RXPARERR, "PCI Rx parity error", -1, 1 }, 1876176472Skmacy { F_TXPARERR, "PCI Tx parity error", -1, 1 }, 1877167514Skmacy { V_BISTERR(M_BISTERR), "PCI BIST error", -1, 1 }, 1878167514Skmacy { 0 } 1879167514Skmacy }; 1880167514Skmacy 1881172096Skmacy if (t3_read_reg(adapter, A_PCIE_INT_CAUSE) & F_PEXERR) 1882172096Skmacy CH_ALERT(adapter, "PEX error code 0x%x\n", 1883172096Skmacy t3_read_reg(adapter, A_PCIE_PEX_ERR)); 1884172096Skmacy 1885167514Skmacy if (t3_handle_intr_status(adapter, A_PCIE_INT_CAUSE, PCIE_INTR_MASK, 1886167514Skmacy pcie_intr_info, adapter->irq_stats)) 1887167514Skmacy t3_fatal_err(adapter); 1888167514Skmacy} 1889167514Skmacy 1890167514Skmacy/* 1891167514Skmacy * TP interrupt handler. 1892167514Skmacy */ 1893167514Skmacystatic void tp_intr_handler(adapter_t *adapter) 1894167514Skmacy{ 1895167514Skmacy static struct intr_info tp_intr_info[] = { 1896167514Skmacy { 0xffffff, "TP parity error", -1, 1 }, 1897167514Skmacy { 0x1000000, "TP out of Rx pages", -1, 1 }, 1898167514Skmacy { 0x2000000, "TP out of Tx pages", -1, 1 }, 1899167514Skmacy { 0 } 1900167514Skmacy }; 1901176472Skmacy static struct intr_info tp_intr_info_t3c[] = { 1902176472Skmacy { 0x1fffffff, "TP parity error", -1, 1 }, 1903176472Skmacy { F_FLMRXFLSTEMPTY, "TP out of Rx pages", -1, 1 }, 1904176472Skmacy { F_FLMTXFLSTEMPTY, "TP out of Tx pages", -1, 1 }, 1905176472Skmacy { 0 } 1906176472Skmacy }; 1907167514Skmacy 1908167514Skmacy if (t3_handle_intr_status(adapter, A_TP_INT_CAUSE, 0xffffffff, 1909176472Skmacy adapter->params.rev < T3_REV_C ? 1910176472Skmacy tp_intr_info : tp_intr_info_t3c, NULL)) 1911167514Skmacy t3_fatal_err(adapter); 1912167514Skmacy} 1913167514Skmacy 1914167514Skmacy/* 1915167514Skmacy * CIM interrupt handler. 1916167514Skmacy */ 1917167514Skmacystatic void cim_intr_handler(adapter_t *adapter) 1918167514Skmacy{ 1919167514Skmacy static struct intr_info cim_intr_info[] = { 1920167514Skmacy { F_RSVDSPACEINT, "CIM reserved space write", -1, 1 }, 1921167514Skmacy { F_SDRAMRANGEINT, "CIM SDRAM address out of range", -1, 1 }, 1922167514Skmacy { F_FLASHRANGEINT, "CIM flash address out of range", -1, 1 }, 1923167514Skmacy { F_BLKWRBOOTINT, "CIM block write to boot space", -1, 1 }, 1924167514Skmacy { F_WRBLKFLASHINT, "CIM write to cached flash space", -1, 1 }, 1925167514Skmacy { F_SGLWRFLASHINT, "CIM single write to flash space", -1, 1 }, 1926167514Skmacy { F_BLKRDFLASHINT, "CIM block read from flash space", -1, 1 }, 1927167514Skmacy { F_BLKWRFLASHINT, "CIM block write to flash space", -1, 1 }, 1928167514Skmacy { F_BLKRDCTLINT, "CIM block read from CTL space", -1, 1 }, 1929167514Skmacy { F_BLKWRCTLINT, "CIM block write to CTL space", -1, 1 }, 1930167514Skmacy { F_BLKRDPLINT, "CIM block read from PL space", -1, 1 }, 1931167514Skmacy { F_BLKWRPLINT, "CIM block write to PL space", -1, 1 }, 1932176472Skmacy { F_DRAMPARERR, "CIM DRAM parity error", -1, 1 }, 1933176472Skmacy { F_ICACHEPARERR, "CIM icache parity error", -1, 1 }, 1934176472Skmacy { F_DCACHEPARERR, "CIM dcache parity error", -1, 1 }, 1935176472Skmacy { F_OBQSGEPARERR, "CIM OBQ SGE parity error", -1, 1 }, 1936176472Skmacy { F_OBQULPHIPARERR, "CIM OBQ ULPHI parity error", -1, 1 }, 1937176472Skmacy { F_OBQULPLOPARERR, "CIM OBQ ULPLO parity error", -1, 1 }, 1938176472Skmacy { F_IBQSGELOPARERR, "CIM IBQ SGELO parity error", -1, 1 }, 1939176472Skmacy { F_IBQSGEHIPARERR, "CIM IBQ SGEHI parity error", -1, 1 }, 1940176472Skmacy { F_IBQULPPARERR, "CIM IBQ ULP parity error", -1, 1 }, 1941176472Skmacy { F_IBQTPPARERR, "CIM IBQ TP parity error", -1, 1 }, 1942176472Skmacy { F_ITAGPARERR, "CIM itag parity error", -1, 1 }, 1943176472Skmacy { F_DTAGPARERR, "CIM dtag parity error", -1, 1 }, 1944167514Skmacy { 0 } 1945167514Skmacy }; 1946167514Skmacy 1947176472Skmacy if (t3_handle_intr_status(adapter, A_CIM_HOST_INT_CAUSE, CIM_INTR_MASK, 1948167514Skmacy cim_intr_info, NULL)) 1949167514Skmacy t3_fatal_err(adapter); 1950167514Skmacy} 1951167514Skmacy 1952167514Skmacy/* 1953167514Skmacy * ULP RX interrupt handler. 1954167514Skmacy */ 1955167514Skmacystatic void ulprx_intr_handler(adapter_t *adapter) 1956167514Skmacy{ 1957167514Skmacy static struct intr_info ulprx_intr_info[] = { 1958176472Skmacy { F_PARERRDATA, "ULP RX data parity error", -1, 1 }, 1959176472Skmacy { F_PARERRPCMD, "ULP RX command parity error", -1, 1 }, 1960176472Skmacy { F_ARBPF1PERR, "ULP RX ArbPF1 parity error", -1, 1 }, 1961176472Skmacy { F_ARBPF0PERR, "ULP RX ArbPF0 parity error", -1, 1 }, 1962176472Skmacy { F_ARBFPERR, "ULP RX ArbF parity error", -1, 1 }, 1963176472Skmacy { F_PCMDMUXPERR, "ULP RX PCMDMUX parity error", -1, 1 }, 1964176472Skmacy { F_DATASELFRAMEERR1, "ULP RX frame error", -1, 1 }, 1965176472Skmacy { F_DATASELFRAMEERR0, "ULP RX frame error", -1, 1 }, 1966167514Skmacy { 0 } 1967167514Skmacy }; 1968167514Skmacy 1969167514Skmacy if (t3_handle_intr_status(adapter, A_ULPRX_INT_CAUSE, 0xffffffff, 1970167514Skmacy ulprx_intr_info, NULL)) 1971167514Skmacy t3_fatal_err(adapter); 1972167514Skmacy} 1973167514Skmacy 1974167514Skmacy/* 1975167514Skmacy * ULP TX interrupt handler. 1976167514Skmacy */ 1977167514Skmacystatic void ulptx_intr_handler(adapter_t *adapter) 1978167514Skmacy{ 1979167514Skmacy static struct intr_info ulptx_intr_info[] = { 1980167514Skmacy { F_PBL_BOUND_ERR_CH0, "ULP TX channel 0 PBL out of bounds", 1981167514Skmacy STAT_ULP_CH0_PBL_OOB, 0 }, 1982167514Skmacy { F_PBL_BOUND_ERR_CH1, "ULP TX channel 1 PBL out of bounds", 1983167514Skmacy STAT_ULP_CH1_PBL_OOB, 0 }, 1984176472Skmacy { 0xfc, "ULP TX parity error", -1, 1 }, 1985167514Skmacy { 0 } 1986167514Skmacy }; 1987167514Skmacy 1988167514Skmacy if (t3_handle_intr_status(adapter, A_ULPTX_INT_CAUSE, 0xffffffff, 1989167514Skmacy ulptx_intr_info, adapter->irq_stats)) 1990167514Skmacy t3_fatal_err(adapter); 1991167514Skmacy} 1992167514Skmacy 1993167514Skmacy#define ICSPI_FRM_ERR (F_ICSPI0_FIFO2X_RX_FRAMING_ERROR | \ 1994167514Skmacy F_ICSPI1_FIFO2X_RX_FRAMING_ERROR | F_ICSPI0_RX_FRAMING_ERROR | \ 1995167514Skmacy F_ICSPI1_RX_FRAMING_ERROR | F_ICSPI0_TX_FRAMING_ERROR | \ 1996167514Skmacy F_ICSPI1_TX_FRAMING_ERROR) 1997167514Skmacy#define OESPI_FRM_ERR (F_OESPI0_RX_FRAMING_ERROR | \ 1998167514Skmacy F_OESPI1_RX_FRAMING_ERROR | F_OESPI0_TX_FRAMING_ERROR | \ 1999167514Skmacy F_OESPI1_TX_FRAMING_ERROR | F_OESPI0_OFIFO2X_TX_FRAMING_ERROR | \ 2000167514Skmacy F_OESPI1_OFIFO2X_TX_FRAMING_ERROR) 2001167514Skmacy 2002167514Skmacy/* 2003167514Skmacy * PM TX interrupt handler. 2004167514Skmacy */ 2005167514Skmacystatic void pmtx_intr_handler(adapter_t *adapter) 2006167514Skmacy{ 2007167514Skmacy static struct intr_info pmtx_intr_info[] = { 2008167514Skmacy { F_ZERO_C_CMD_ERROR, "PMTX 0-length pcmd", -1, 1 }, 2009167514Skmacy { ICSPI_FRM_ERR, "PMTX ispi framing error", -1, 1 }, 2010167514Skmacy { OESPI_FRM_ERR, "PMTX ospi framing error", -1, 1 }, 2011167514Skmacy { V_ICSPI_PAR_ERROR(M_ICSPI_PAR_ERROR), 2012167514Skmacy "PMTX ispi parity error", -1, 1 }, 2013167514Skmacy { V_OESPI_PAR_ERROR(M_OESPI_PAR_ERROR), 2014167514Skmacy "PMTX ospi parity error", -1, 1 }, 2015167514Skmacy { 0 } 2016167514Skmacy }; 2017167514Skmacy 2018167514Skmacy if (t3_handle_intr_status(adapter, A_PM1_TX_INT_CAUSE, 0xffffffff, 2019167514Skmacy pmtx_intr_info, NULL)) 2020167514Skmacy t3_fatal_err(adapter); 2021167514Skmacy} 2022167514Skmacy 2023167514Skmacy#define IESPI_FRM_ERR (F_IESPI0_FIFO2X_RX_FRAMING_ERROR | \ 2024167514Skmacy F_IESPI1_FIFO2X_RX_FRAMING_ERROR | F_IESPI0_RX_FRAMING_ERROR | \ 2025167514Skmacy F_IESPI1_RX_FRAMING_ERROR | F_IESPI0_TX_FRAMING_ERROR | \ 2026167514Skmacy F_IESPI1_TX_FRAMING_ERROR) 2027167514Skmacy#define OCSPI_FRM_ERR (F_OCSPI0_RX_FRAMING_ERROR | \ 2028167514Skmacy F_OCSPI1_RX_FRAMING_ERROR | F_OCSPI0_TX_FRAMING_ERROR | \ 2029167514Skmacy F_OCSPI1_TX_FRAMING_ERROR | F_OCSPI0_OFIFO2X_TX_FRAMING_ERROR | \ 2030167514Skmacy F_OCSPI1_OFIFO2X_TX_FRAMING_ERROR) 2031167514Skmacy 2032167514Skmacy/* 2033167514Skmacy * PM RX interrupt handler. 2034167514Skmacy */ 2035167514Skmacystatic void pmrx_intr_handler(adapter_t *adapter) 2036167514Skmacy{ 2037167514Skmacy static struct intr_info pmrx_intr_info[] = { 2038167514Skmacy { F_ZERO_E_CMD_ERROR, "PMRX 0-length pcmd", -1, 1 }, 2039167514Skmacy { IESPI_FRM_ERR, "PMRX ispi framing error", -1, 1 }, 2040167514Skmacy { OCSPI_FRM_ERR, "PMRX ospi framing error", -1, 1 }, 2041167514Skmacy { V_IESPI_PAR_ERROR(M_IESPI_PAR_ERROR), 2042167514Skmacy "PMRX ispi parity error", -1, 1 }, 2043167514Skmacy { V_OCSPI_PAR_ERROR(M_OCSPI_PAR_ERROR), 2044167514Skmacy "PMRX ospi parity error", -1, 1 }, 2045167514Skmacy { 0 } 2046167514Skmacy }; 2047167514Skmacy 2048167514Skmacy if (t3_handle_intr_status(adapter, A_PM1_RX_INT_CAUSE, 0xffffffff, 2049167514Skmacy pmrx_intr_info, NULL)) 2050167514Skmacy t3_fatal_err(adapter); 2051167514Skmacy} 2052167514Skmacy 2053167514Skmacy/* 2054167514Skmacy * CPL switch interrupt handler. 2055167514Skmacy */ 2056167514Skmacystatic void cplsw_intr_handler(adapter_t *adapter) 2057167514Skmacy{ 2058167514Skmacy static struct intr_info cplsw_intr_info[] = { 2059176472Skmacy { F_CIM_OP_MAP_PERR, "CPL switch CIM parity error", -1, 1 }, 2060176472Skmacy { F_CIM_OVFL_ERROR, "CPL switch CIM overflow", -1, 1 }, 2061167514Skmacy { F_TP_FRAMING_ERROR, "CPL switch TP framing error", -1, 1 }, 2062167514Skmacy { F_SGE_FRAMING_ERROR, "CPL switch SGE framing error", -1, 1 }, 2063167514Skmacy { F_CIM_FRAMING_ERROR, "CPL switch CIM framing error", -1, 1 }, 2064167514Skmacy { F_ZERO_SWITCH_ERROR, "CPL switch no-switch error", -1, 1 }, 2065167514Skmacy { 0 } 2066167514Skmacy }; 2067167514Skmacy 2068167514Skmacy if (t3_handle_intr_status(adapter, A_CPL_INTR_CAUSE, 0xffffffff, 2069167514Skmacy cplsw_intr_info, NULL)) 2070167514Skmacy t3_fatal_err(adapter); 2071167514Skmacy} 2072167514Skmacy 2073167514Skmacy/* 2074167514Skmacy * MPS interrupt handler. 2075167514Skmacy */ 2076167514Skmacystatic void mps_intr_handler(adapter_t *adapter) 2077167514Skmacy{ 2078167514Skmacy static struct intr_info mps_intr_info[] = { 2079167514Skmacy { 0x1ff, "MPS parity error", -1, 1 }, 2080167514Skmacy { 0 } 2081167514Skmacy }; 2082167514Skmacy 2083167514Skmacy if (t3_handle_intr_status(adapter, A_MPS_INT_CAUSE, 0xffffffff, 2084167514Skmacy mps_intr_info, NULL)) 2085167514Skmacy t3_fatal_err(adapter); 2086167514Skmacy} 2087167514Skmacy 2088167514Skmacy#define MC7_INTR_FATAL (F_UE | V_PE(M_PE) | F_AE) 2089167514Skmacy 2090167514Skmacy/* 2091167514Skmacy * MC7 interrupt handler. 2092167514Skmacy */ 2093167514Skmacystatic void mc7_intr_handler(struct mc7 *mc7) 2094167514Skmacy{ 2095167514Skmacy adapter_t *adapter = mc7->adapter; 2096167514Skmacy u32 cause = t3_read_reg(adapter, mc7->offset + A_MC7_INT_CAUSE); 2097167514Skmacy 2098167514Skmacy if (cause & F_CE) { 2099167514Skmacy mc7->stats.corr_err++; 2100167514Skmacy CH_WARN(adapter, "%s MC7 correctable error at addr 0x%x, " 2101167514Skmacy "data 0x%x 0x%x 0x%x\n", mc7->name, 2102167514Skmacy t3_read_reg(adapter, mc7->offset + A_MC7_CE_ADDR), 2103167514Skmacy t3_read_reg(adapter, mc7->offset + A_MC7_CE_DATA0), 2104167514Skmacy t3_read_reg(adapter, mc7->offset + A_MC7_CE_DATA1), 2105167514Skmacy t3_read_reg(adapter, mc7->offset + A_MC7_CE_DATA2)); 2106167514Skmacy } 2107167514Skmacy 2108167514Skmacy if (cause & F_UE) { 2109167514Skmacy mc7->stats.uncorr_err++; 2110167514Skmacy CH_ALERT(adapter, "%s MC7 uncorrectable error at addr 0x%x, " 2111167514Skmacy "data 0x%x 0x%x 0x%x\n", mc7->name, 2112167514Skmacy t3_read_reg(adapter, mc7->offset + A_MC7_UE_ADDR), 2113167514Skmacy t3_read_reg(adapter, mc7->offset + A_MC7_UE_DATA0), 2114167514Skmacy t3_read_reg(adapter, mc7->offset + A_MC7_UE_DATA1), 2115167514Skmacy t3_read_reg(adapter, mc7->offset + A_MC7_UE_DATA2)); 2116167514Skmacy } 2117167514Skmacy 2118167514Skmacy if (G_PE(cause)) { 2119167514Skmacy mc7->stats.parity_err++; 2120167514Skmacy CH_ALERT(adapter, "%s MC7 parity error 0x%x\n", 2121167514Skmacy mc7->name, G_PE(cause)); 2122167514Skmacy } 2123167514Skmacy 2124167514Skmacy if (cause & F_AE) { 2125167514Skmacy u32 addr = 0; 2126167514Skmacy 2127167514Skmacy if (adapter->params.rev > 0) 2128167514Skmacy addr = t3_read_reg(adapter, 2129167514Skmacy mc7->offset + A_MC7_ERR_ADDR); 2130167514Skmacy mc7->stats.addr_err++; 2131167514Skmacy CH_ALERT(adapter, "%s MC7 address error: 0x%x\n", 2132167514Skmacy mc7->name, addr); 2133167514Skmacy } 2134167514Skmacy 2135167514Skmacy if (cause & MC7_INTR_FATAL) 2136167514Skmacy t3_fatal_err(adapter); 2137167514Skmacy 2138167514Skmacy t3_write_reg(adapter, mc7->offset + A_MC7_INT_CAUSE, cause); 2139167514Skmacy} 2140167514Skmacy 2141167514Skmacy#define XGM_INTR_FATAL (V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR) | \ 2142167514Skmacy V_RXFIFO_PRTY_ERR(M_RXFIFO_PRTY_ERR)) 2143167514Skmacy/* 2144167514Skmacy * XGMAC interrupt handler. 2145167514Skmacy */ 2146167514Skmacystatic int mac_intr_handler(adapter_t *adap, unsigned int idx) 2147167514Skmacy{ 2148170654Skmacy u32 cause; 2149192540Sgnn struct port_info *pi; 2150170654Skmacy struct cmac *mac; 2151167514Skmacy 2152170654Skmacy idx = idx == 0 ? 0 : adapter_info(adap)->nports0; /* MAC idx -> port */ 2153192540Sgnn pi = adap2pinfo(adap, idx); 2154192540Sgnn mac = &pi->mac; 2155170654Skmacy 2156189643Sgnn /* 2157189643Sgnn * We mask out interrupt causes for which we're not taking interrupts. 2158189643Sgnn * This allows us to use polling logic to monitor some of the other 2159189643Sgnn * conditions when taking interrupts would impose too much load on the 2160189643Sgnn * system. 2161189643Sgnn */ 2162189643Sgnn cause = (t3_read_reg(adap, A_XGM_INT_CAUSE + mac->offset) 2163189643Sgnn & ~(F_RXFIFO_OVERFLOW)); 2164189643Sgnn 2165167514Skmacy if (cause & V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR)) { 2166167514Skmacy mac->stats.tx_fifo_parity_err++; 2167167514Skmacy CH_ALERT(adap, "port%d: MAC TX FIFO parity error\n", idx); 2168167514Skmacy } 2169167514Skmacy if (cause & V_RXFIFO_PRTY_ERR(M_RXFIFO_PRTY_ERR)) { 2170167514Skmacy mac->stats.rx_fifo_parity_err++; 2171167514Skmacy CH_ALERT(adap, "port%d: MAC RX FIFO parity error\n", idx); 2172167514Skmacy } 2173167514Skmacy if (cause & F_TXFIFO_UNDERRUN) 2174167514Skmacy mac->stats.tx_fifo_urun++; 2175167514Skmacy if (cause & F_RXFIFO_OVERFLOW) 2176167514Skmacy mac->stats.rx_fifo_ovfl++; 2177167514Skmacy if (cause & V_SERDES_LOS(M_SERDES_LOS)) 2178167514Skmacy mac->stats.serdes_signal_loss++; 2179167514Skmacy if (cause & F_XAUIPCSCTCERR) 2180167514Skmacy mac->stats.xaui_pcs_ctc_err++; 2181167514Skmacy if (cause & F_XAUIPCSALIGNCHANGE) 2182167514Skmacy mac->stats.xaui_pcs_align_change++; 2183209841Snp if (cause & F_XGM_INT & 2184209841Snp t3_read_reg(adap, A_XGM_INT_ENABLE + mac->offset)) { 2185209841Snp t3_set_reg_field(adap, A_XGM_INT_ENABLE + mac->offset, 2186209841Snp F_XGM_INT, 0); 2187167514Skmacy 2188192540Sgnn /* link fault suspected */ 2189192540Sgnn pi->link_fault = LF_MAYBE; 2190209841Snp t3_os_link_intr(pi); 2191189643Sgnn } 2192189643Sgnn 2193167514Skmacy if (cause & XGM_INTR_FATAL) 2194167514Skmacy t3_fatal_err(adap); 2195189643Sgnn 2196219945Snp t3_write_reg(adap, A_XGM_INT_CAUSE + mac->offset, cause); 2197167514Skmacy return cause != 0; 2198167514Skmacy} 2199167514Skmacy 2200167514Skmacy/* 2201167514Skmacy * Interrupt handler for PHY events. 2202167514Skmacy */ 2203209840Snpstatic int phy_intr_handler(adapter_t *adapter) 2204167514Skmacy{ 2205167514Skmacy u32 i, cause = t3_read_reg(adapter, A_T3DBG_INT_CAUSE); 2206167514Skmacy 2207167514Skmacy for_each_port(adapter, i) { 2208170654Skmacy struct port_info *p = adap2pinfo(adapter, i); 2209167514Skmacy 2210176472Skmacy if (!(p->phy.caps & SUPPORTED_IRQ)) 2211167514Skmacy continue; 2212167514Skmacy 2213180583Skmacy if (cause & (1 << adapter_info(adapter)->gpio_intr[i])) { 2214167514Skmacy int phy_cause = p->phy.ops->intr_handler(&p->phy); 2215167514Skmacy 2216167514Skmacy if (phy_cause & cphy_cause_link_change) 2217209841Snp t3_os_link_intr(p); 2218167514Skmacy if (phy_cause & cphy_cause_fifo_error) 2219167514Skmacy p->phy.fifo_errors++; 2220181614Skmacy if (phy_cause & cphy_cause_module_change) 2221181614Skmacy t3_os_phymod_changed(adapter, i); 2222197791Snp if (phy_cause & cphy_cause_alarm) 2223197791Snp CH_WARN(adapter, "Operation affected due to " 2224197791Snp "adverse environment. Check the spec " 2225197791Snp "sheet for corrective action."); 2226167514Skmacy } 2227167514Skmacy } 2228167514Skmacy 2229167514Skmacy t3_write_reg(adapter, A_T3DBG_INT_CAUSE, cause); 2230167514Skmacy return 0; 2231167514Skmacy} 2232167514Skmacy 2233172096Skmacy/** 2234172096Skmacy * t3_slow_intr_handler - control path interrupt handler 2235172096Skmacy * @adapter: the adapter 2236172096Skmacy * 2237172096Skmacy * T3 interrupt handler for non-data interrupt events, e.g., errors. 2238172096Skmacy * The designation 'slow' is because it involves register reads, while 2239172096Skmacy * data interrupts typically don't involve any MMIOs. 2240167514Skmacy */ 2241167514Skmacyint t3_slow_intr_handler(adapter_t *adapter) 2242167514Skmacy{ 2243167514Skmacy u32 cause = t3_read_reg(adapter, A_PL_INT_CAUSE0); 2244167514Skmacy 2245167514Skmacy cause &= adapter->slow_intr_mask; 2246167514Skmacy if (!cause) 2247167514Skmacy return 0; 2248167514Skmacy if (cause & F_PCIM0) { 2249167514Skmacy if (is_pcie(adapter)) 2250167514Skmacy pcie_intr_handler(adapter); 2251167514Skmacy else 2252167514Skmacy pci_intr_handler(adapter); 2253167514Skmacy } 2254167514Skmacy if (cause & F_SGE3) 2255167514Skmacy t3_sge_err_intr_handler(adapter); 2256167514Skmacy if (cause & F_MC7_PMRX) 2257167514Skmacy mc7_intr_handler(&adapter->pmrx); 2258167514Skmacy if (cause & F_MC7_PMTX) 2259167514Skmacy mc7_intr_handler(&adapter->pmtx); 2260167514Skmacy if (cause & F_MC7_CM) 2261167514Skmacy mc7_intr_handler(&adapter->cm); 2262167514Skmacy if (cause & F_CIM) 2263167514Skmacy cim_intr_handler(adapter); 2264167514Skmacy if (cause & F_TP1) 2265167514Skmacy tp_intr_handler(adapter); 2266167514Skmacy if (cause & F_ULP2_RX) 2267167514Skmacy ulprx_intr_handler(adapter); 2268167514Skmacy if (cause & F_ULP2_TX) 2269167514Skmacy ulptx_intr_handler(adapter); 2270167514Skmacy if (cause & F_PM1_RX) 2271167514Skmacy pmrx_intr_handler(adapter); 2272167514Skmacy if (cause & F_PM1_TX) 2273167514Skmacy pmtx_intr_handler(adapter); 2274167514Skmacy if (cause & F_CPL_SWITCH) 2275167514Skmacy cplsw_intr_handler(adapter); 2276167514Skmacy if (cause & F_MPS0) 2277167514Skmacy mps_intr_handler(adapter); 2278167514Skmacy if (cause & F_MC5A) 2279167514Skmacy t3_mc5_intr_handler(&adapter->mc5); 2280167514Skmacy if (cause & F_XGMAC0_0) 2281167514Skmacy mac_intr_handler(adapter, 0); 2282167514Skmacy if (cause & F_XGMAC0_1) 2283167514Skmacy mac_intr_handler(adapter, 1); 2284167514Skmacy if (cause & F_T3DBG) 2285209840Snp phy_intr_handler(adapter); 2286167514Skmacy 2287167514Skmacy /* Clear the interrupts just processed. */ 2288167514Skmacy t3_write_reg(adapter, A_PL_INT_CAUSE0, cause); 2289167514Skmacy (void) t3_read_reg(adapter, A_PL_INT_CAUSE0); /* flush */ 2290167514Skmacy return 1; 2291167514Skmacy} 2292167514Skmacy 2293180583Skmacystatic unsigned int calc_gpio_intr(adapter_t *adap) 2294180583Skmacy{ 2295180583Skmacy unsigned int i, gpi_intr = 0; 2296180583Skmacy 2297180583Skmacy for_each_port(adap, i) 2298180583Skmacy if ((adap2pinfo(adap, i)->phy.caps & SUPPORTED_IRQ) && 2299180583Skmacy adapter_info(adap)->gpio_intr[i]) 2300180583Skmacy gpi_intr |= 1 << adapter_info(adap)->gpio_intr[i]; 2301180583Skmacy return gpi_intr; 2302180583Skmacy} 2303180583Skmacy 2304167514Skmacy/** 2305167514Skmacy * t3_intr_enable - enable interrupts 2306167514Skmacy * @adapter: the adapter whose interrupts should be enabled 2307167514Skmacy * 2308167514Skmacy * Enable interrupts by setting the interrupt enable registers of the 2309167514Skmacy * various HW modules and then enabling the top-level interrupt 2310167514Skmacy * concentrator. 2311167514Skmacy */ 2312167514Skmacyvoid t3_intr_enable(adapter_t *adapter) 2313167514Skmacy{ 2314167514Skmacy static struct addr_val_pair intr_en_avp[] = { 2315167514Skmacy { A_MC7_INT_ENABLE, MC7_INTR_MASK }, 2316167514Skmacy { A_MC7_INT_ENABLE - MC7_PMRX_BASE_ADDR + MC7_PMTX_BASE_ADDR, 2317167514Skmacy MC7_INTR_MASK }, 2318167514Skmacy { A_MC7_INT_ENABLE - MC7_PMRX_BASE_ADDR + MC7_CM_BASE_ADDR, 2319167514Skmacy MC7_INTR_MASK }, 2320167514Skmacy { A_MC5_DB_INT_ENABLE, MC5_INTR_MASK }, 2321167514Skmacy { A_ULPRX_INT_ENABLE, ULPRX_INTR_MASK }, 2322167514Skmacy { A_PM1_TX_INT_ENABLE, PMTX_INTR_MASK }, 2323167514Skmacy { A_PM1_RX_INT_ENABLE, PMRX_INTR_MASK }, 2324167514Skmacy { A_CIM_HOST_INT_ENABLE, CIM_INTR_MASK }, 2325167514Skmacy { A_MPS_INT_ENABLE, MPS_INTR_MASK }, 2326167514Skmacy }; 2327167514Skmacy 2328167514Skmacy adapter->slow_intr_mask = PL_INTR_MASK; 2329167514Skmacy 2330167514Skmacy t3_write_regs(adapter, intr_en_avp, ARRAY_SIZE(intr_en_avp), 0); 2331176472Skmacy t3_write_reg(adapter, A_TP_INT_ENABLE, 2332176472Skmacy adapter->params.rev >= T3_REV_C ? 0x2bfffff : 0x3bfffff); 2333189643Sgnn t3_write_reg(adapter, A_SG_INT_ENABLE, SGE_INTR_MASK); 2334167514Skmacy 2335167514Skmacy if (adapter->params.rev > 0) { 2336167514Skmacy t3_write_reg(adapter, A_CPL_INTR_ENABLE, 2337167514Skmacy CPLSW_INTR_MASK | F_CIM_OVFL_ERROR); 2338167514Skmacy t3_write_reg(adapter, A_ULPTX_INT_ENABLE, 2339167514Skmacy ULPTX_INTR_MASK | F_PBL_BOUND_ERR_CH0 | 2340167514Skmacy F_PBL_BOUND_ERR_CH1); 2341167514Skmacy } else { 2342167514Skmacy t3_write_reg(adapter, A_CPL_INTR_ENABLE, CPLSW_INTR_MASK); 2343167514Skmacy t3_write_reg(adapter, A_ULPTX_INT_ENABLE, ULPTX_INTR_MASK); 2344167514Skmacy } 2345167514Skmacy 2346180583Skmacy t3_write_reg(adapter, A_T3DBG_INT_ENABLE, calc_gpio_intr(adapter)); 2347180583Skmacy 2348170654Skmacy if (is_pcie(adapter)) 2349167514Skmacy t3_write_reg(adapter, A_PCIE_INT_ENABLE, PCIE_INTR_MASK); 2350170654Skmacy else 2351167514Skmacy t3_write_reg(adapter, A_PCIX_INT_ENABLE, PCIX_INTR_MASK); 2352167514Skmacy t3_write_reg(adapter, A_PL_INT_ENABLE0, adapter->slow_intr_mask); 2353167514Skmacy (void) t3_read_reg(adapter, A_PL_INT_ENABLE0); /* flush */ 2354167514Skmacy} 2355167514Skmacy 2356167514Skmacy/** 2357167514Skmacy * t3_intr_disable - disable a card's interrupts 2358167514Skmacy * @adapter: the adapter whose interrupts should be disabled 2359167514Skmacy * 2360167514Skmacy * Disable interrupts. We only disable the top-level interrupt 2361167514Skmacy * concentrator and the SGE data interrupts. 2362167514Skmacy */ 2363167514Skmacyvoid t3_intr_disable(adapter_t *adapter) 2364167514Skmacy{ 2365167514Skmacy t3_write_reg(adapter, A_PL_INT_ENABLE0, 0); 2366167514Skmacy (void) t3_read_reg(adapter, A_PL_INT_ENABLE0); /* flush */ 2367167514Skmacy adapter->slow_intr_mask = 0; 2368167514Skmacy} 2369167514Skmacy 2370167514Skmacy/** 2371167514Skmacy * t3_intr_clear - clear all interrupts 2372167514Skmacy * @adapter: the adapter whose interrupts should be cleared 2373167514Skmacy * 2374167514Skmacy * Clears all interrupts. 2375167514Skmacy */ 2376167514Skmacyvoid t3_intr_clear(adapter_t *adapter) 2377167514Skmacy{ 2378167514Skmacy static const unsigned int cause_reg_addr[] = { 2379167514Skmacy A_SG_INT_CAUSE, 2380167514Skmacy A_SG_RSPQ_FL_STATUS, 2381167514Skmacy A_PCIX_INT_CAUSE, 2382167514Skmacy A_MC7_INT_CAUSE, 2383167514Skmacy A_MC7_INT_CAUSE - MC7_PMRX_BASE_ADDR + MC7_PMTX_BASE_ADDR, 2384167514Skmacy A_MC7_INT_CAUSE - MC7_PMRX_BASE_ADDR + MC7_CM_BASE_ADDR, 2385167514Skmacy A_CIM_HOST_INT_CAUSE, 2386167514Skmacy A_TP_INT_CAUSE, 2387167514Skmacy A_MC5_DB_INT_CAUSE, 2388167514Skmacy A_ULPRX_INT_CAUSE, 2389167514Skmacy A_ULPTX_INT_CAUSE, 2390167514Skmacy A_CPL_INTR_CAUSE, 2391167514Skmacy A_PM1_TX_INT_CAUSE, 2392167514Skmacy A_PM1_RX_INT_CAUSE, 2393167514Skmacy A_MPS_INT_CAUSE, 2394167514Skmacy A_T3DBG_INT_CAUSE, 2395167514Skmacy }; 2396167514Skmacy unsigned int i; 2397167514Skmacy 2398167514Skmacy /* Clear PHY and MAC interrupts for each port. */ 2399167514Skmacy for_each_port(adapter, i) 2400167514Skmacy t3_port_intr_clear(adapter, i); 2401167514Skmacy 2402167514Skmacy for (i = 0; i < ARRAY_SIZE(cause_reg_addr); ++i) 2403167514Skmacy t3_write_reg(adapter, cause_reg_addr[i], 0xffffffff); 2404167514Skmacy 2405172096Skmacy if (is_pcie(adapter)) 2406172096Skmacy t3_write_reg(adapter, A_PCIE_PEX_ERR, 0xffffffff); 2407167514Skmacy t3_write_reg(adapter, A_PL_INT_CAUSE0, 0xffffffff); 2408167514Skmacy (void) t3_read_reg(adapter, A_PL_INT_CAUSE0); /* flush */ 2409167514Skmacy} 2410167514Skmacy 2411189643Sgnnvoid t3_xgm_intr_enable(adapter_t *adapter, int idx) 2412189643Sgnn{ 2413189643Sgnn struct port_info *pi = adap2pinfo(adapter, idx); 2414189643Sgnn 2415189643Sgnn t3_write_reg(adapter, A_XGM_XGM_INT_ENABLE + pi->mac.offset, 2416189643Sgnn XGM_EXTRA_INTR_MASK); 2417189643Sgnn} 2418189643Sgnn 2419189643Sgnnvoid t3_xgm_intr_disable(adapter_t *adapter, int idx) 2420189643Sgnn{ 2421189643Sgnn struct port_info *pi = adap2pinfo(adapter, idx); 2422189643Sgnn 2423189643Sgnn t3_write_reg(adapter, A_XGM_XGM_INT_DISABLE + pi->mac.offset, 2424189643Sgnn 0x7ff); 2425189643Sgnn} 2426189643Sgnn 2427167514Skmacy/** 2428167514Skmacy * t3_port_intr_enable - enable port-specific interrupts 2429167514Skmacy * @adapter: associated adapter 2430167514Skmacy * @idx: index of port whose interrupts should be enabled 2431167514Skmacy * 2432167514Skmacy * Enable port-specific (i.e., MAC and PHY) interrupts for the given 2433167514Skmacy * adapter port. 2434167514Skmacy */ 2435167514Skmacyvoid t3_port_intr_enable(adapter_t *adapter, int idx) 2436167514Skmacy{ 2437170654Skmacy struct port_info *pi = adap2pinfo(adapter, idx); 2438170654Skmacy 2439170654Skmacy t3_write_reg(adapter, A_XGM_INT_ENABLE + pi->mac.offset, XGM_INTR_MASK); 2440170654Skmacy pi->phy.ops->intr_enable(&pi->phy); 2441167514Skmacy} 2442167514Skmacy 2443167514Skmacy/** 2444167514Skmacy * t3_port_intr_disable - disable port-specific interrupts 2445167514Skmacy * @adapter: associated adapter 2446167514Skmacy * @idx: index of port whose interrupts should be disabled 2447167514Skmacy * 2448167514Skmacy * Disable port-specific (i.e., MAC and PHY) interrupts for the given 2449167514Skmacy * adapter port. 2450167514Skmacy */ 2451167514Skmacyvoid t3_port_intr_disable(adapter_t *adapter, int idx) 2452167514Skmacy{ 2453170654Skmacy struct port_info *pi = adap2pinfo(adapter, idx); 2454170654Skmacy 2455170654Skmacy t3_write_reg(adapter, A_XGM_INT_ENABLE + pi->mac.offset, 0); 2456170654Skmacy pi->phy.ops->intr_disable(&pi->phy); 2457167514Skmacy} 2458167514Skmacy 2459167514Skmacy/** 2460167514Skmacy * t3_port_intr_clear - clear port-specific interrupts 2461167514Skmacy * @adapter: associated adapter 2462167514Skmacy * @idx: index of port whose interrupts to clear 2463167514Skmacy * 2464167514Skmacy * Clear port-specific (i.e., MAC and PHY) interrupts for the given 2465167514Skmacy * adapter port. 2466167514Skmacy */ 2467167514Skmacyvoid t3_port_intr_clear(adapter_t *adapter, int idx) 2468167514Skmacy{ 2469170654Skmacy struct port_info *pi = adap2pinfo(adapter, idx); 2470170654Skmacy 2471170654Skmacy t3_write_reg(adapter, A_XGM_INT_CAUSE + pi->mac.offset, 0xffffffff); 2472170654Skmacy pi->phy.ops->intr_clear(&pi->phy); 2473167514Skmacy} 2474167514Skmacy 2475172096Skmacy#define SG_CONTEXT_CMD_ATTEMPTS 100 2476172096Skmacy 2477167514Skmacy/** 2478167514Skmacy * t3_sge_write_context - write an SGE context 2479167514Skmacy * @adapter: the adapter 2480167514Skmacy * @id: the context id 2481167514Skmacy * @type: the context type 2482167514Skmacy * 2483167514Skmacy * Program an SGE context with the values already loaded in the 2484167514Skmacy * CONTEXT_DATA? registers. 2485167514Skmacy */ 2486167514Skmacystatic int t3_sge_write_context(adapter_t *adapter, unsigned int id, 2487167514Skmacy unsigned int type) 2488167514Skmacy{ 2489189643Sgnn if (type == F_RESPONSEQ) { 2490189643Sgnn /* 2491189643Sgnn * Can't write the Response Queue Context bits for 2492189643Sgnn * Interrupt Armed or the Reserve bits after the chip 2493189643Sgnn * has been initialized out of reset. Writing to these 2494189643Sgnn * bits can confuse the hardware. 2495189643Sgnn */ 2496189643Sgnn t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0xffffffff); 2497189643Sgnn t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0xffffffff); 2498189643Sgnn t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0x17ffffff); 2499189643Sgnn t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0xffffffff); 2500189643Sgnn } else { 2501189643Sgnn t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0xffffffff); 2502189643Sgnn t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0xffffffff); 2503189643Sgnn t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0xffffffff); 2504189643Sgnn t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0xffffffff); 2505189643Sgnn } 2506167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_CMD, 2507167514Skmacy V_CONTEXT_CMD_OPCODE(1) | type | V_CONTEXT(id)); 2508167514Skmacy return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, 2509172096Skmacy 0, SG_CONTEXT_CMD_ATTEMPTS, 1); 2510167514Skmacy} 2511167514Skmacy 2512189643Sgnn/** 2513189643Sgnn * clear_sge_ctxt - completely clear an SGE context 2514189643Sgnn * @adapter: the adapter 2515189643Sgnn * @id: the context id 2516189643Sgnn * @type: the context type 2517189643Sgnn * 2518189643Sgnn * Completely clear an SGE context. Used predominantly at post-reset 2519189643Sgnn * initialization. Note in particular that we don't skip writing to any 2520189643Sgnn * "sensitive bits" in the contexts the way that t3_sge_write_context() 2521189643Sgnn * does ... 2522189643Sgnn */ 2523176472Skmacystatic int clear_sge_ctxt(adapter_t *adap, unsigned int id, unsigned int type) 2524176472Skmacy{ 2525176472Skmacy t3_write_reg(adap, A_SG_CONTEXT_DATA0, 0); 2526176472Skmacy t3_write_reg(adap, A_SG_CONTEXT_DATA1, 0); 2527176472Skmacy t3_write_reg(adap, A_SG_CONTEXT_DATA2, 0); 2528176472Skmacy t3_write_reg(adap, A_SG_CONTEXT_DATA3, 0); 2529189643Sgnn t3_write_reg(adap, A_SG_CONTEXT_MASK0, 0xffffffff); 2530189643Sgnn t3_write_reg(adap, A_SG_CONTEXT_MASK1, 0xffffffff); 2531189643Sgnn t3_write_reg(adap, A_SG_CONTEXT_MASK2, 0xffffffff); 2532189643Sgnn t3_write_reg(adap, A_SG_CONTEXT_MASK3, 0xffffffff); 2533189643Sgnn t3_write_reg(adap, A_SG_CONTEXT_CMD, 2534189643Sgnn V_CONTEXT_CMD_OPCODE(1) | type | V_CONTEXT(id)); 2535189643Sgnn return t3_wait_op_done(adap, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, 2536189643Sgnn 0, SG_CONTEXT_CMD_ATTEMPTS, 1); 2537176472Skmacy} 2538176472Skmacy 2539167514Skmacy/** 2540167514Skmacy * t3_sge_init_ecntxt - initialize an SGE egress context 2541167514Skmacy * @adapter: the adapter to configure 2542167514Skmacy * @id: the context id 2543167514Skmacy * @gts_enable: whether to enable GTS for the context 2544167514Skmacy * @type: the egress context type 2545167514Skmacy * @respq: associated response queue 2546167514Skmacy * @base_addr: base address of queue 2547167514Skmacy * @size: number of queue entries 2548167514Skmacy * @token: uP token 2549167514Skmacy * @gen: initial generation value for the context 2550167514Skmacy * @cidx: consumer pointer 2551167514Skmacy * 2552167514Skmacy * Initialize an SGE egress context and make it ready for use. If the 2553167514Skmacy * platform allows concurrent context operations, the caller is 2554167514Skmacy * responsible for appropriate locking. 2555167514Skmacy */ 2556167514Skmacyint t3_sge_init_ecntxt(adapter_t *adapter, unsigned int id, int gts_enable, 2557167514Skmacy enum sge_context_type type, int respq, u64 base_addr, 2558167514Skmacy unsigned int size, unsigned int token, int gen, 2559167514Skmacy unsigned int cidx) 2560167514Skmacy{ 2561167514Skmacy unsigned int credits = type == SGE_CNTXT_OFLD ? 0 : FW_WR_NUM; 2562167514Skmacy 2563167514Skmacy if (base_addr & 0xfff) /* must be 4K aligned */ 2564167514Skmacy return -EINVAL; 2565167514Skmacy if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) 2566167514Skmacy return -EBUSY; 2567167514Skmacy 2568167514Skmacy base_addr >>= 12; 2569167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA0, V_EC_INDEX(cidx) | 2570167514Skmacy V_EC_CREDITS(credits) | V_EC_GTS(gts_enable)); 2571167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA1, V_EC_SIZE(size) | 2572167514Skmacy V_EC_BASE_LO((u32)base_addr & 0xffff)); 2573167514Skmacy base_addr >>= 16; 2574167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA2, (u32)base_addr); 2575167514Skmacy base_addr >>= 32; 2576167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA3, 2577167514Skmacy V_EC_BASE_HI((u32)base_addr & 0xf) | V_EC_RESPQ(respq) | 2578167514Skmacy V_EC_TYPE(type) | V_EC_GEN(gen) | V_EC_UP_TOKEN(token) | 2579167514Skmacy F_EC_VALID); 2580167514Skmacy return t3_sge_write_context(adapter, id, F_EGRESS); 2581167514Skmacy} 2582167514Skmacy 2583167514Skmacy/** 2584167514Skmacy * t3_sge_init_flcntxt - initialize an SGE free-buffer list context 2585167514Skmacy * @adapter: the adapter to configure 2586167514Skmacy * @id: the context id 2587167514Skmacy * @gts_enable: whether to enable GTS for the context 2588167514Skmacy * @base_addr: base address of queue 2589167514Skmacy * @size: number of queue entries 2590167514Skmacy * @bsize: size of each buffer for this queue 2591167514Skmacy * @cong_thres: threshold to signal congestion to upstream producers 2592167514Skmacy * @gen: initial generation value for the context 2593167514Skmacy * @cidx: consumer pointer 2594167514Skmacy * 2595167514Skmacy * Initialize an SGE free list context and make it ready for use. The 2596167514Skmacy * caller is responsible for ensuring only one context operation occurs 2597167514Skmacy * at a time. 2598167514Skmacy */ 2599167514Skmacyint t3_sge_init_flcntxt(adapter_t *adapter, unsigned int id, int gts_enable, 2600167514Skmacy u64 base_addr, unsigned int size, unsigned int bsize, 2601167514Skmacy unsigned int cong_thres, int gen, unsigned int cidx) 2602167514Skmacy{ 2603167514Skmacy if (base_addr & 0xfff) /* must be 4K aligned */ 2604167514Skmacy return -EINVAL; 2605167514Skmacy if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) 2606167514Skmacy return -EBUSY; 2607167514Skmacy 2608167514Skmacy base_addr >>= 12; 2609167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA0, (u32)base_addr); 2610167514Skmacy base_addr >>= 32; 2611167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA1, 2612167514Skmacy V_FL_BASE_HI((u32)base_addr) | 2613167514Skmacy V_FL_INDEX_LO(cidx & M_FL_INDEX_LO)); 2614167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA2, V_FL_SIZE(size) | 2615167514Skmacy V_FL_GEN(gen) | V_FL_INDEX_HI(cidx >> 12) | 2616167514Skmacy V_FL_ENTRY_SIZE_LO(bsize & M_FL_ENTRY_SIZE_LO)); 2617167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA3, 2618167514Skmacy V_FL_ENTRY_SIZE_HI(bsize >> (32 - S_FL_ENTRY_SIZE_LO)) | 2619167514Skmacy V_FL_CONG_THRES(cong_thres) | V_FL_GTS(gts_enable)); 2620167514Skmacy return t3_sge_write_context(adapter, id, F_FREELIST); 2621167514Skmacy} 2622167514Skmacy 2623167514Skmacy/** 2624167514Skmacy * t3_sge_init_rspcntxt - initialize an SGE response queue context 2625167514Skmacy * @adapter: the adapter to configure 2626167514Skmacy * @id: the context id 2627167514Skmacy * @irq_vec_idx: MSI-X interrupt vector index, 0 if no MSI-X, -1 if no IRQ 2628167514Skmacy * @base_addr: base address of queue 2629167514Skmacy * @size: number of queue entries 2630167514Skmacy * @fl_thres: threshold for selecting the normal or jumbo free list 2631167514Skmacy * @gen: initial generation value for the context 2632167514Skmacy * @cidx: consumer pointer 2633167514Skmacy * 2634167514Skmacy * Initialize an SGE response queue context and make it ready for use. 2635167514Skmacy * The caller is responsible for ensuring only one context operation 2636167514Skmacy * occurs at a time. 2637167514Skmacy */ 2638167514Skmacyint t3_sge_init_rspcntxt(adapter_t *adapter, unsigned int id, int irq_vec_idx, 2639167514Skmacy u64 base_addr, unsigned int size, 2640167514Skmacy unsigned int fl_thres, int gen, unsigned int cidx) 2641167514Skmacy{ 2642189643Sgnn unsigned int ctrl, intr = 0; 2643167514Skmacy 2644167514Skmacy if (base_addr & 0xfff) /* must be 4K aligned */ 2645167514Skmacy return -EINVAL; 2646167514Skmacy if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) 2647167514Skmacy return -EBUSY; 2648167514Skmacy 2649167514Skmacy base_addr >>= 12; 2650167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA0, V_CQ_SIZE(size) | 2651167514Skmacy V_CQ_INDEX(cidx)); 2652167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA1, (u32)base_addr); 2653167514Skmacy base_addr >>= 32; 2654189643Sgnn ctrl = t3_read_reg(adapter, A_SG_CONTROL); 2655189643Sgnn if ((irq_vec_idx > 0) || 2656189643Sgnn ((irq_vec_idx == 0) && !(ctrl & F_ONEINTMULTQ))) 2657189643Sgnn intr = F_RQ_INTR_EN; 2658189643Sgnn if (irq_vec_idx >= 0) 2659189643Sgnn intr |= V_RQ_MSI_VEC(irq_vec_idx); 2660167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA2, 2661167514Skmacy V_CQ_BASE_HI((u32)base_addr) | intr | V_RQ_GEN(gen)); 2662167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA3, fl_thres); 2663167514Skmacy return t3_sge_write_context(adapter, id, F_RESPONSEQ); 2664167514Skmacy} 2665167514Skmacy 2666167514Skmacy/** 2667167514Skmacy * t3_sge_init_cqcntxt - initialize an SGE completion queue context 2668167514Skmacy * @adapter: the adapter to configure 2669167514Skmacy * @id: the context id 2670167514Skmacy * @base_addr: base address of queue 2671167514Skmacy * @size: number of queue entries 2672167514Skmacy * @rspq: response queue for async notifications 2673167514Skmacy * @ovfl_mode: CQ overflow mode 2674167514Skmacy * @credits: completion queue credits 2675167514Skmacy * @credit_thres: the credit threshold 2676167514Skmacy * 2677167514Skmacy * Initialize an SGE completion queue context and make it ready for use. 2678167514Skmacy * The caller is responsible for ensuring only one context operation 2679167514Skmacy * occurs at a time. 2680167514Skmacy */ 2681167514Skmacyint t3_sge_init_cqcntxt(adapter_t *adapter, unsigned int id, u64 base_addr, 2682167514Skmacy unsigned int size, int rspq, int ovfl_mode, 2683167514Skmacy unsigned int credits, unsigned int credit_thres) 2684167514Skmacy{ 2685167514Skmacy if (base_addr & 0xfff) /* must be 4K aligned */ 2686167514Skmacy return -EINVAL; 2687167514Skmacy if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) 2688167514Skmacy return -EBUSY; 2689167514Skmacy 2690167514Skmacy base_addr >>= 12; 2691167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA0, V_CQ_SIZE(size)); 2692167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA1, (u32)base_addr); 2693167514Skmacy base_addr >>= 32; 2694167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA2, 2695167514Skmacy V_CQ_BASE_HI((u32)base_addr) | V_CQ_RSPQ(rspq) | 2696172096Skmacy V_CQ_GEN(1) | V_CQ_OVERFLOW_MODE(ovfl_mode) | 2697172096Skmacy V_CQ_ERR(ovfl_mode)); 2698167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA3, V_CQ_CREDITS(credits) | 2699167514Skmacy V_CQ_CREDIT_THRES(credit_thres)); 2700167514Skmacy return t3_sge_write_context(adapter, id, F_CQ); 2701167514Skmacy} 2702167514Skmacy 2703167514Skmacy/** 2704167514Skmacy * t3_sge_enable_ecntxt - enable/disable an SGE egress context 2705167514Skmacy * @adapter: the adapter 2706167514Skmacy * @id: the egress context id 2707167514Skmacy * @enable: enable (1) or disable (0) the context 2708167514Skmacy * 2709167514Skmacy * Enable or disable an SGE egress context. The caller is responsible for 2710167514Skmacy * ensuring only one context operation occurs at a time. 2711167514Skmacy */ 2712167514Skmacyint t3_sge_enable_ecntxt(adapter_t *adapter, unsigned int id, int enable) 2713167514Skmacy{ 2714167514Skmacy if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) 2715167514Skmacy return -EBUSY; 2716167514Skmacy 2717167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0); 2718167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0); 2719167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0); 2720167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_MASK3, F_EC_VALID); 2721167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA3, V_EC_VALID(enable)); 2722167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_CMD, 2723167514Skmacy V_CONTEXT_CMD_OPCODE(1) | F_EGRESS | V_CONTEXT(id)); 2724167514Skmacy return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, 2725172096Skmacy 0, SG_CONTEXT_CMD_ATTEMPTS, 1); 2726167514Skmacy} 2727167514Skmacy 2728167514Skmacy/** 2729167514Skmacy * t3_sge_disable_fl - disable an SGE free-buffer list 2730167514Skmacy * @adapter: the adapter 2731167514Skmacy * @id: the free list context id 2732167514Skmacy * 2733167514Skmacy * Disable an SGE free-buffer list. The caller is responsible for 2734167514Skmacy * ensuring only one context operation occurs at a time. 2735167514Skmacy */ 2736167514Skmacyint t3_sge_disable_fl(adapter_t *adapter, unsigned int id) 2737167514Skmacy{ 2738167514Skmacy if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) 2739167514Skmacy return -EBUSY; 2740167514Skmacy 2741167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0); 2742167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0); 2743167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_MASK2, V_FL_SIZE(M_FL_SIZE)); 2744167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0); 2745167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA2, 0); 2746167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_CMD, 2747167514Skmacy V_CONTEXT_CMD_OPCODE(1) | F_FREELIST | V_CONTEXT(id)); 2748167514Skmacy return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, 2749172096Skmacy 0, SG_CONTEXT_CMD_ATTEMPTS, 1); 2750167514Skmacy} 2751167514Skmacy 2752167514Skmacy/** 2753167514Skmacy * t3_sge_disable_rspcntxt - disable an SGE response queue 2754167514Skmacy * @adapter: the adapter 2755167514Skmacy * @id: the response queue context id 2756167514Skmacy * 2757167514Skmacy * Disable an SGE response queue. The caller is responsible for 2758167514Skmacy * ensuring only one context operation occurs at a time. 2759167514Skmacy */ 2760167514Skmacyint t3_sge_disable_rspcntxt(adapter_t *adapter, unsigned int id) 2761167514Skmacy{ 2762167514Skmacy if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) 2763167514Skmacy return -EBUSY; 2764167514Skmacy 2765167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_MASK0, V_CQ_SIZE(M_CQ_SIZE)); 2766167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0); 2767167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0); 2768167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0); 2769167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA0, 0); 2770167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_CMD, 2771167514Skmacy V_CONTEXT_CMD_OPCODE(1) | F_RESPONSEQ | V_CONTEXT(id)); 2772167514Skmacy return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, 2773172096Skmacy 0, SG_CONTEXT_CMD_ATTEMPTS, 1); 2774167514Skmacy} 2775167514Skmacy 2776167514Skmacy/** 2777167514Skmacy * t3_sge_disable_cqcntxt - disable an SGE completion queue 2778167514Skmacy * @adapter: the adapter 2779167514Skmacy * @id: the completion queue context id 2780167514Skmacy * 2781167514Skmacy * Disable an SGE completion queue. The caller is responsible for 2782167514Skmacy * ensuring only one context operation occurs at a time. 2783167514Skmacy */ 2784167514Skmacyint t3_sge_disable_cqcntxt(adapter_t *adapter, unsigned int id) 2785167514Skmacy{ 2786167514Skmacy if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) 2787167514Skmacy return -EBUSY; 2788167514Skmacy 2789167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_MASK0, V_CQ_SIZE(M_CQ_SIZE)); 2790167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0); 2791167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0); 2792167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0); 2793167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA0, 0); 2794167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_CMD, 2795167514Skmacy V_CONTEXT_CMD_OPCODE(1) | F_CQ | V_CONTEXT(id)); 2796167514Skmacy return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, 2797172096Skmacy 0, SG_CONTEXT_CMD_ATTEMPTS, 1); 2798167514Skmacy} 2799167514Skmacy 2800167514Skmacy/** 2801167514Skmacy * t3_sge_cqcntxt_op - perform an operation on a completion queue context 2802167514Skmacy * @adapter: the adapter 2803167514Skmacy * @id: the context id 2804167514Skmacy * @op: the operation to perform 2805172096Skmacy * @credits: credits to return to the CQ 2806167514Skmacy * 2807167514Skmacy * Perform the selected operation on an SGE completion queue context. 2808167514Skmacy * The caller is responsible for ensuring only one context operation 2809167514Skmacy * occurs at a time. 2810172096Skmacy * 2811172096Skmacy * For most operations the function returns the current HW position in 2812172096Skmacy * the completion queue. 2813167514Skmacy */ 2814167514Skmacyint t3_sge_cqcntxt_op(adapter_t *adapter, unsigned int id, unsigned int op, 2815167514Skmacy unsigned int credits) 2816167514Skmacy{ 2817167514Skmacy u32 val; 2818167514Skmacy 2819167514Skmacy if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) 2820167514Skmacy return -EBUSY; 2821167514Skmacy 2822167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA0, credits << 16); 2823167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_CMD, V_CONTEXT_CMD_OPCODE(op) | 2824167514Skmacy V_CONTEXT(id) | F_CQ); 2825167514Skmacy if (t3_wait_op_done_val(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, 2826172096Skmacy 0, SG_CONTEXT_CMD_ATTEMPTS, 1, &val)) 2827167514Skmacy return -EIO; 2828167514Skmacy 2829167514Skmacy if (op >= 2 && op < 7) { 2830167514Skmacy if (adapter->params.rev > 0) 2831167514Skmacy return G_CQ_INDEX(val); 2832167514Skmacy 2833167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_CMD, 2834167514Skmacy V_CONTEXT_CMD_OPCODE(0) | F_CQ | V_CONTEXT(id)); 2835167514Skmacy if (t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, 2836172096Skmacy F_CONTEXT_CMD_BUSY, 0, 2837172096Skmacy SG_CONTEXT_CMD_ATTEMPTS, 1)) 2838167514Skmacy return -EIO; 2839167514Skmacy return G_CQ_INDEX(t3_read_reg(adapter, A_SG_CONTEXT_DATA0)); 2840167514Skmacy } 2841167514Skmacy return 0; 2842167514Skmacy} 2843167514Skmacy 2844167514Skmacy/** 2845167514Skmacy * t3_sge_read_context - read an SGE context 2846167514Skmacy * @type: the context type 2847167514Skmacy * @adapter: the adapter 2848167514Skmacy * @id: the context id 2849167514Skmacy * @data: holds the retrieved context 2850167514Skmacy * 2851167514Skmacy * Read an SGE egress context. The caller is responsible for ensuring 2852167514Skmacy * only one context operation occurs at a time. 2853167514Skmacy */ 2854167514Skmacystatic int t3_sge_read_context(unsigned int type, adapter_t *adapter, 2855167514Skmacy unsigned int id, u32 data[4]) 2856167514Skmacy{ 2857167514Skmacy if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) 2858167514Skmacy return -EBUSY; 2859167514Skmacy 2860167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_CMD, 2861167514Skmacy V_CONTEXT_CMD_OPCODE(0) | type | V_CONTEXT(id)); 2862167514Skmacy if (t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, 0, 2863172096Skmacy SG_CONTEXT_CMD_ATTEMPTS, 1)) 2864167514Skmacy return -EIO; 2865167514Skmacy data[0] = t3_read_reg(adapter, A_SG_CONTEXT_DATA0); 2866167514Skmacy data[1] = t3_read_reg(adapter, A_SG_CONTEXT_DATA1); 2867167514Skmacy data[2] = t3_read_reg(adapter, A_SG_CONTEXT_DATA2); 2868167514Skmacy data[3] = t3_read_reg(adapter, A_SG_CONTEXT_DATA3); 2869167514Skmacy return 0; 2870167514Skmacy} 2871167514Skmacy 2872167514Skmacy/** 2873167514Skmacy * t3_sge_read_ecntxt - read an SGE egress context 2874167514Skmacy * @adapter: the adapter 2875167514Skmacy * @id: the context id 2876167514Skmacy * @data: holds the retrieved context 2877167514Skmacy * 2878167514Skmacy * Read an SGE egress context. The caller is responsible for ensuring 2879167514Skmacy * only one context operation occurs at a time. 2880167514Skmacy */ 2881167514Skmacyint t3_sge_read_ecntxt(adapter_t *adapter, unsigned int id, u32 data[4]) 2882167514Skmacy{ 2883167514Skmacy if (id >= 65536) 2884167514Skmacy return -EINVAL; 2885167514Skmacy return t3_sge_read_context(F_EGRESS, adapter, id, data); 2886167514Skmacy} 2887167514Skmacy 2888167514Skmacy/** 2889167514Skmacy * t3_sge_read_cq - read an SGE CQ context 2890167514Skmacy * @adapter: the adapter 2891167514Skmacy * @id: the context id 2892167514Skmacy * @data: holds the retrieved context 2893167514Skmacy * 2894167514Skmacy * Read an SGE CQ context. The caller is responsible for ensuring 2895167514Skmacy * only one context operation occurs at a time. 2896167514Skmacy */ 2897167514Skmacyint t3_sge_read_cq(adapter_t *adapter, unsigned int id, u32 data[4]) 2898167514Skmacy{ 2899167514Skmacy if (id >= 65536) 2900167514Skmacy return -EINVAL; 2901167514Skmacy return t3_sge_read_context(F_CQ, adapter, id, data); 2902167514Skmacy} 2903167514Skmacy 2904167514Skmacy/** 2905167514Skmacy * t3_sge_read_fl - read an SGE free-list context 2906167514Skmacy * @adapter: the adapter 2907167514Skmacy * @id: the context id 2908167514Skmacy * @data: holds the retrieved context 2909167514Skmacy * 2910167514Skmacy * Read an SGE free-list context. The caller is responsible for ensuring 2911167514Skmacy * only one context operation occurs at a time. 2912167514Skmacy */ 2913167514Skmacyint t3_sge_read_fl(adapter_t *adapter, unsigned int id, u32 data[4]) 2914167514Skmacy{ 2915167514Skmacy if (id >= SGE_QSETS * 2) 2916167514Skmacy return -EINVAL; 2917167514Skmacy return t3_sge_read_context(F_FREELIST, adapter, id, data); 2918167514Skmacy} 2919167514Skmacy 2920167514Skmacy/** 2921167514Skmacy * t3_sge_read_rspq - read an SGE response queue context 2922167514Skmacy * @adapter: the adapter 2923167514Skmacy * @id: the context id 2924167514Skmacy * @data: holds the retrieved context 2925167514Skmacy * 2926167514Skmacy * Read an SGE response queue context. The caller is responsible for 2927167514Skmacy * ensuring only one context operation occurs at a time. 2928167514Skmacy */ 2929167514Skmacyint t3_sge_read_rspq(adapter_t *adapter, unsigned int id, u32 data[4]) 2930167514Skmacy{ 2931167514Skmacy if (id >= SGE_QSETS) 2932167514Skmacy return -EINVAL; 2933167514Skmacy return t3_sge_read_context(F_RESPONSEQ, adapter, id, data); 2934167514Skmacy} 2935167514Skmacy 2936167514Skmacy/** 2937167514Skmacy * t3_config_rss - configure Rx packet steering 2938167514Skmacy * @adapter: the adapter 2939167514Skmacy * @rss_config: RSS settings (written to TP_RSS_CONFIG) 2940167514Skmacy * @cpus: values for the CPU lookup table (0xff terminated) 2941167514Skmacy * @rspq: values for the response queue lookup table (0xffff terminated) 2942167514Skmacy * 2943167514Skmacy * Programs the receive packet steering logic. @cpus and @rspq provide 2944167514Skmacy * the values for the CPU and response queue lookup tables. If they 2945167514Skmacy * provide fewer values than the size of the tables the supplied values 2946167514Skmacy * are used repeatedly until the tables are fully populated. 2947167514Skmacy */ 2948167514Skmacyvoid t3_config_rss(adapter_t *adapter, unsigned int rss_config, const u8 *cpus, 2949167514Skmacy const u16 *rspq) 2950167514Skmacy{ 2951167514Skmacy int i, j, cpu_idx = 0, q_idx = 0; 2952167514Skmacy 2953167514Skmacy if (cpus) 2954167514Skmacy for (i = 0; i < RSS_TABLE_SIZE; ++i) { 2955167514Skmacy u32 val = i << 16; 2956167514Skmacy 2957167514Skmacy for (j = 0; j < 2; ++j) { 2958167514Skmacy val |= (cpus[cpu_idx++] & 0x3f) << (8 * j); 2959167514Skmacy if (cpus[cpu_idx] == 0xff) 2960167514Skmacy cpu_idx = 0; 2961167514Skmacy } 2962167514Skmacy t3_write_reg(adapter, A_TP_RSS_LKP_TABLE, val); 2963167514Skmacy } 2964167514Skmacy 2965167514Skmacy if (rspq) 2966167514Skmacy for (i = 0; i < RSS_TABLE_SIZE; ++i) { 2967167514Skmacy t3_write_reg(adapter, A_TP_RSS_MAP_TABLE, 2968167514Skmacy (i << 16) | rspq[q_idx++]); 2969167514Skmacy if (rspq[q_idx] == 0xffff) 2970167514Skmacy q_idx = 0; 2971167514Skmacy } 2972167514Skmacy 2973167514Skmacy t3_write_reg(adapter, A_TP_RSS_CONFIG, rss_config); 2974167514Skmacy} 2975167514Skmacy 2976167514Skmacy/** 2977167514Skmacy * t3_read_rss - read the contents of the RSS tables 2978167514Skmacy * @adapter: the adapter 2979167514Skmacy * @lkup: holds the contents of the RSS lookup table 2980167514Skmacy * @map: holds the contents of the RSS map table 2981167514Skmacy * 2982167514Skmacy * Reads the contents of the receive packet steering tables. 2983167514Skmacy */ 2984167514Skmacyint t3_read_rss(adapter_t *adapter, u8 *lkup, u16 *map) 2985167514Skmacy{ 2986167514Skmacy int i; 2987167514Skmacy u32 val; 2988167514Skmacy 2989167514Skmacy if (lkup) 2990167514Skmacy for (i = 0; i < RSS_TABLE_SIZE; ++i) { 2991167514Skmacy t3_write_reg(adapter, A_TP_RSS_LKP_TABLE, 2992167514Skmacy 0xffff0000 | i); 2993167514Skmacy val = t3_read_reg(adapter, A_TP_RSS_LKP_TABLE); 2994167514Skmacy if (!(val & 0x80000000)) 2995167514Skmacy return -EAGAIN; 2996167514Skmacy *lkup++ = (u8)val; 2997167514Skmacy *lkup++ = (u8)(val >> 8); 2998167514Skmacy } 2999167514Skmacy 3000167514Skmacy if (map) 3001167514Skmacy for (i = 0; i < RSS_TABLE_SIZE; ++i) { 3002167514Skmacy t3_write_reg(adapter, A_TP_RSS_MAP_TABLE, 3003167514Skmacy 0xffff0000 | i); 3004167514Skmacy val = t3_read_reg(adapter, A_TP_RSS_MAP_TABLE); 3005167514Skmacy if (!(val & 0x80000000)) 3006167514Skmacy return -EAGAIN; 3007167514Skmacy *map++ = (u16)val; 3008167514Skmacy } 3009167514Skmacy return 0; 3010167514Skmacy} 3011167514Skmacy 3012167514Skmacy/** 3013167514Skmacy * t3_tp_set_offload_mode - put TP in NIC/offload mode 3014167514Skmacy * @adap: the adapter 3015167514Skmacy * @enable: 1 to select offload mode, 0 for regular NIC 3016167514Skmacy * 3017167514Skmacy * Switches TP to NIC/offload mode. 3018167514Skmacy */ 3019167514Skmacyvoid t3_tp_set_offload_mode(adapter_t *adap, int enable) 3020167514Skmacy{ 3021167514Skmacy if (is_offload(adap) || !enable) 3022167514Skmacy t3_set_reg_field(adap, A_TP_IN_CONFIG, F_NICMODE, 3023167514Skmacy V_NICMODE(!enable)); 3024167514Skmacy} 3025167514Skmacy 3026172096Skmacy/** 3027172096Skmacy * tp_wr_bits_indirect - set/clear bits in an indirect TP register 3028172096Skmacy * @adap: the adapter 3029172096Skmacy * @addr: the indirect TP register address 3030172096Skmacy * @mask: specifies the field within the register to modify 3031172096Skmacy * @val: new value for the field 3032172096Skmacy * 3033172096Skmacy * Sets a field of an indirect TP register to the given value. 3034172096Skmacy */ 3035171471Skmacystatic void tp_wr_bits_indirect(adapter_t *adap, unsigned int addr, 3036171471Skmacy unsigned int mask, unsigned int val) 3037171471Skmacy{ 3038171471Skmacy t3_write_reg(adap, A_TP_PIO_ADDR, addr); 3039171471Skmacy val |= t3_read_reg(adap, A_TP_PIO_DATA) & ~mask; 3040171471Skmacy t3_write_reg(adap, A_TP_PIO_DATA, val); 3041171471Skmacy} 3042171471Skmacy 3043167514Skmacy/** 3044180583Skmacy * t3_enable_filters - enable the HW filters 3045180583Skmacy * @adap: the adapter 3046180583Skmacy * 3047180583Skmacy * Enables the HW filters for NIC traffic. 3048180583Skmacy */ 3049180583Skmacyvoid t3_enable_filters(adapter_t *adap) 3050180583Skmacy{ 3051180583Skmacy t3_set_reg_field(adap, A_TP_IN_CONFIG, F_NICMODE, 0); 3052180583Skmacy t3_set_reg_field(adap, A_MC5_DB_CONFIG, 0, F_FILTEREN); 3053180583Skmacy t3_set_reg_field(adap, A_TP_GLOBAL_CONFIG, 0, V_FIVETUPLELOOKUP(3)); 3054180583Skmacy tp_wr_bits_indirect(adap, A_TP_INGRESS_CONFIG, 0, F_LOOKUPEVERYPKT); 3055180583Skmacy} 3056180583Skmacy 3057180583Skmacy/** 3058189643Sgnn * t3_disable_filters - disable the HW filters 3059189643Sgnn * @adap: the adapter 3060189643Sgnn * 3061189643Sgnn * Disables the HW filters for NIC traffic. 3062189643Sgnn */ 3063189643Sgnnvoid t3_disable_filters(adapter_t *adap) 3064189643Sgnn{ 3065189643Sgnn /* note that we don't want to revert to NIC-only mode */ 3066189643Sgnn t3_set_reg_field(adap, A_MC5_DB_CONFIG, F_FILTEREN, 0); 3067189643Sgnn t3_set_reg_field(adap, A_TP_GLOBAL_CONFIG, 3068189643Sgnn V_FIVETUPLELOOKUP(M_FIVETUPLELOOKUP), 0); 3069189643Sgnn tp_wr_bits_indirect(adap, A_TP_INGRESS_CONFIG, F_LOOKUPEVERYPKT, 0); 3070189643Sgnn} 3071189643Sgnn 3072189643Sgnn/** 3073167514Skmacy * pm_num_pages - calculate the number of pages of the payload memory 3074167514Skmacy * @mem_size: the size of the payload memory 3075167514Skmacy * @pg_size: the size of each payload memory page 3076167514Skmacy * 3077167514Skmacy * Calculate the number of pages, each of the given size, that fit in a 3078167514Skmacy * memory of the specified size, respecting the HW requirement that the 3079167514Skmacy * number of pages must be a multiple of 24. 3080167514Skmacy */ 3081167514Skmacystatic inline unsigned int pm_num_pages(unsigned int mem_size, 3082167514Skmacy unsigned int pg_size) 3083167514Skmacy{ 3084167514Skmacy unsigned int n = mem_size / pg_size; 3085167514Skmacy 3086167514Skmacy return n - n % 24; 3087167514Skmacy} 3088167514Skmacy 3089167514Skmacy#define mem_region(adap, start, size, reg) \ 3090167514Skmacy t3_write_reg((adap), A_ ## reg, (start)); \ 3091167514Skmacy start += size 3092167514Skmacy 3093172096Skmacy/** 3094167514Skmacy * partition_mem - partition memory and configure TP memory settings 3095167514Skmacy * @adap: the adapter 3096167514Skmacy * @p: the TP parameters 3097167514Skmacy * 3098167514Skmacy * Partitions context and payload memory and configures TP's memory 3099167514Skmacy * registers. 3100167514Skmacy */ 3101167514Skmacystatic void partition_mem(adapter_t *adap, const struct tp_params *p) 3102167514Skmacy{ 3103167514Skmacy unsigned int m, pstructs, tids = t3_mc5_size(&adap->mc5); 3104167514Skmacy unsigned int timers = 0, timers_shift = 22; 3105167514Skmacy 3106167514Skmacy if (adap->params.rev > 0) { 3107167514Skmacy if (tids <= 16 * 1024) { 3108167514Skmacy timers = 1; 3109167514Skmacy timers_shift = 16; 3110167514Skmacy } else if (tids <= 64 * 1024) { 3111167514Skmacy timers = 2; 3112167514Skmacy timers_shift = 18; 3113167514Skmacy } else if (tids <= 256 * 1024) { 3114167514Skmacy timers = 3; 3115167514Skmacy timers_shift = 20; 3116167514Skmacy } 3117167514Skmacy } 3118167514Skmacy 3119167514Skmacy t3_write_reg(adap, A_TP_PMM_SIZE, 3120167514Skmacy p->chan_rx_size | (p->chan_tx_size >> 16)); 3121167514Skmacy 3122167514Skmacy t3_write_reg(adap, A_TP_PMM_TX_BASE, 0); 3123167514Skmacy t3_write_reg(adap, A_TP_PMM_TX_PAGE_SIZE, p->tx_pg_size); 3124167514Skmacy t3_write_reg(adap, A_TP_PMM_TX_MAX_PAGE, p->tx_num_pgs); 3125167514Skmacy t3_set_reg_field(adap, A_TP_PARA_REG3, V_TXDATAACKIDX(M_TXDATAACKIDX), 3126167514Skmacy V_TXDATAACKIDX(fls(p->tx_pg_size) - 12)); 3127167514Skmacy 3128167514Skmacy t3_write_reg(adap, A_TP_PMM_RX_BASE, 0); 3129167514Skmacy t3_write_reg(adap, A_TP_PMM_RX_PAGE_SIZE, p->rx_pg_size); 3130167514Skmacy t3_write_reg(adap, A_TP_PMM_RX_MAX_PAGE, p->rx_num_pgs); 3131167514Skmacy 3132167514Skmacy pstructs = p->rx_num_pgs + p->tx_num_pgs; 3133167514Skmacy /* Add a bit of headroom and make multiple of 24 */ 3134167514Skmacy pstructs += 48; 3135167514Skmacy pstructs -= pstructs % 24; 3136167514Skmacy t3_write_reg(adap, A_TP_CMM_MM_MAX_PSTRUCT, pstructs); 3137167514Skmacy 3138167514Skmacy m = tids * TCB_SIZE; 3139167514Skmacy mem_region(adap, m, (64 << 10) * 64, SG_EGR_CNTX_BADDR); 3140167514Skmacy mem_region(adap, m, (64 << 10) * 64, SG_CQ_CONTEXT_BADDR); 3141167514Skmacy t3_write_reg(adap, A_TP_CMM_TIMER_BASE, V_CMTIMERMAXNUM(timers) | m); 3142167514Skmacy m += ((p->ntimer_qs - 1) << timers_shift) + (1 << 22); 3143167514Skmacy mem_region(adap, m, pstructs * 64, TP_CMM_MM_BASE); 3144167514Skmacy mem_region(adap, m, 64 * (pstructs / 24), TP_CMM_MM_PS_FLST_BASE); 3145167514Skmacy mem_region(adap, m, 64 * (p->rx_num_pgs / 24), TP_CMM_MM_RX_FLST_BASE); 3146167514Skmacy mem_region(adap, m, 64 * (p->tx_num_pgs / 24), TP_CMM_MM_TX_FLST_BASE); 3147167514Skmacy 3148167514Skmacy m = (m + 4095) & ~0xfff; 3149167514Skmacy t3_write_reg(adap, A_CIM_SDRAM_BASE_ADDR, m); 3150167514Skmacy t3_write_reg(adap, A_CIM_SDRAM_ADDR_SIZE, p->cm_size - m); 3151167514Skmacy 3152167514Skmacy tids = (p->cm_size - m - (3 << 20)) / 3072 - 32; 3153167514Skmacy m = t3_mc5_size(&adap->mc5) - adap->params.mc5.nservers - 3154167514Skmacy adap->params.mc5.nfilters - adap->params.mc5.nroutes; 3155167514Skmacy if (tids < m) 3156167514Skmacy adap->params.mc5.nservers += m - tids; 3157167514Skmacy} 3158167514Skmacy 3159167514Skmacystatic inline void tp_wr_indirect(adapter_t *adap, unsigned int addr, u32 val) 3160167514Skmacy{ 3161167514Skmacy t3_write_reg(adap, A_TP_PIO_ADDR, addr); 3162167514Skmacy t3_write_reg(adap, A_TP_PIO_DATA, val); 3163167514Skmacy} 3164167514Skmacy 3165189643Sgnnstatic inline u32 tp_rd_indirect(adapter_t *adap, unsigned int addr) 3166189643Sgnn{ 3167189643Sgnn t3_write_reg(adap, A_TP_PIO_ADDR, addr); 3168189643Sgnn return t3_read_reg(adap, A_TP_PIO_DATA); 3169189643Sgnn} 3170189643Sgnn 3171167514Skmacystatic void tp_config(adapter_t *adap, const struct tp_params *p) 3172167514Skmacy{ 3173167514Skmacy t3_write_reg(adap, A_TP_GLOBAL_CONFIG, F_TXPACINGENABLE | F_PATHMTU | 3174167514Skmacy F_IPCHECKSUMOFFLOAD | F_UDPCHECKSUMOFFLOAD | 3175167514Skmacy F_TCPCHECKSUMOFFLOAD | V_IPTTL(64)); 3176167514Skmacy t3_write_reg(adap, A_TP_TCP_OPTIONS, V_MTUDEFAULT(576) | 3177167514Skmacy F_MTUENABLE | V_WINDOWSCALEMODE(1) | 3178180583Skmacy V_TIMESTAMPSMODE(1) | V_SACKMODE(1) | V_SACKRX(1)); 3179167514Skmacy t3_write_reg(adap, A_TP_DACK_CONFIG, V_AUTOSTATE3(1) | 3180167514Skmacy V_AUTOSTATE2(1) | V_AUTOSTATE1(0) | 3181180583Skmacy V_BYTETHRESHOLD(26880) | V_MSSTHRESHOLD(2) | 3182167514Skmacy F_AUTOCAREFUL | F_AUTOENABLE | V_DACK_MODE(1)); 3183176472Skmacy t3_set_reg_field(adap, A_TP_IN_CONFIG, F_RXFBARBPRIO | F_TXFBARBPRIO, 3184167514Skmacy F_IPV6ENABLE | F_NICMODE); 3185167514Skmacy t3_write_reg(adap, A_TP_TX_RESOURCE_LIMIT, 0x18141814); 3186167514Skmacy t3_write_reg(adap, A_TP_PARA_REG4, 0x5050105); 3187170654Skmacy t3_set_reg_field(adap, A_TP_PARA_REG6, 0, 3188170654Skmacy adap->params.rev > 0 ? F_ENABLEESND : 3189170654Skmacy F_T3A_ENABLEESND); 3190167514Skmacy t3_set_reg_field(adap, A_TP_PC_CONFIG, 3191170654Skmacy F_ENABLEEPCMDAFULL, 3192170654Skmacy F_ENABLEOCSPIFULL |F_TXDEFERENABLE | F_HEARBEATDACK | 3193170654Skmacy F_TXCONGESTIONMODE | F_RXCONGESTIONMODE); 3194176472Skmacy t3_set_reg_field(adap, A_TP_PC_CONFIG2, F_CHDRAFULL, 3195176472Skmacy F_ENABLEIPV6RSS | F_ENABLENONOFDTNLSYN | 3196176472Skmacy F_ENABLEARPMISS | F_DISBLEDAPARBIT0); 3197170654Skmacy t3_write_reg(adap, A_TP_PROXY_FLOW_CNTL, 1080); 3198170654Skmacy t3_write_reg(adap, A_TP_PROXY_FLOW_CNTL, 1000); 3199167514Skmacy 3200167514Skmacy if (adap->params.rev > 0) { 3201167514Skmacy tp_wr_indirect(adap, A_TP_EGRESS_CONFIG, F_REWRITEFORCETOSIZE); 3202171471Skmacy t3_set_reg_field(adap, A_TP_PARA_REG3, 0, 3203171471Skmacy F_TXPACEAUTO | F_TXPACEAUTOSTRICT); 3204167514Skmacy t3_set_reg_field(adap, A_TP_PC_CONFIG, F_LOCKTID, F_LOCKTID); 3205171471Skmacy tp_wr_indirect(adap, A_TP_VLAN_PRI_MAP, 0xfa50); 3206171471Skmacy tp_wr_indirect(adap, A_TP_MAC_MATCH_MAP0, 0xfac688); 3207171471Skmacy tp_wr_indirect(adap, A_TP_MAC_MATCH_MAP1, 0xfac688); 3208167514Skmacy } else 3209167514Skmacy t3_set_reg_field(adap, A_TP_PARA_REG3, 0, F_TXPACEFIXED); 3210167514Skmacy 3211176472Skmacy if (adap->params.rev == T3_REV_C) 3212176472Skmacy t3_set_reg_field(adap, A_TP_PC_CONFIG, 3213176472Skmacy V_TABLELATENCYDELTA(M_TABLELATENCYDELTA), 3214176472Skmacy V_TABLELATENCYDELTA(4)); 3215176472Skmacy 3216167746Skmacy t3_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT1, 0); 3217167746Skmacy t3_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT0, 0); 3218167746Skmacy t3_write_reg(adap, A_TP_MOD_CHANNEL_WEIGHT, 0); 3219170654Skmacy t3_write_reg(adap, A_TP_MOD_RATE_LIMIT, 0xf2200000); 3220170654Skmacy 3221170654Skmacy if (adap->params.nports > 2) { 3222170654Skmacy t3_set_reg_field(adap, A_TP_PC_CONFIG2, 0, 3223180583Skmacy F_ENABLETXPORTFROMDA2 | F_ENABLETXPORTFROMDA | 3224180583Skmacy F_ENABLERXPORTFROMADDR); 3225170654Skmacy tp_wr_bits_indirect(adap, A_TP_QOS_RX_MAP_MODE, 3226170654Skmacy V_RXMAPMODE(M_RXMAPMODE), 0); 3227170654Skmacy tp_wr_indirect(adap, A_TP_INGRESS_CONFIG, V_BITPOS0(48) | 3228170654Skmacy V_BITPOS1(49) | V_BITPOS2(50) | V_BITPOS3(51) | 3229170654Skmacy F_ENABLEEXTRACT | F_ENABLEEXTRACTIONSFD | 3230170654Skmacy F_ENABLEINSERTION | F_ENABLEINSERTIONSFD); 3231170654Skmacy tp_wr_indirect(adap, A_TP_PREAMBLE_MSB, 0xfb000000); 3232170654Skmacy tp_wr_indirect(adap, A_TP_PREAMBLE_LSB, 0xd5); 3233170654Skmacy tp_wr_indirect(adap, A_TP_INTF_FROM_TX_PKT, F_INTFFROMTXPKT); 3234170654Skmacy } 3235167514Skmacy} 3236167514Skmacy 3237167514Skmacy/* TCP timer values in ms */ 3238167514Skmacy#define TP_DACK_TIMER 50 3239167514Skmacy#define TP_RTO_MIN 250 3240167514Skmacy 3241167514Skmacy/** 3242167514Skmacy * tp_set_timers - set TP timing parameters 3243167514Skmacy * @adap: the adapter to set 3244167514Skmacy * @core_clk: the core clock frequency in Hz 3245167514Skmacy * 3246167514Skmacy * Set TP's timing parameters, such as the various timer resolutions and 3247167514Skmacy * the TCP timer values. 3248167514Skmacy */ 3249167514Skmacystatic void tp_set_timers(adapter_t *adap, unsigned int core_clk) 3250167514Skmacy{ 3251170654Skmacy unsigned int tre = adap->params.tp.tre; 3252167746Skmacy unsigned int dack_re = adap->params.tp.dack_re; 3253167514Skmacy unsigned int tstamp_re = fls(core_clk / 1000); /* 1ms, at least */ 3254167514Skmacy unsigned int tps = core_clk >> tre; 3255167514Skmacy 3256167514Skmacy t3_write_reg(adap, A_TP_TIMER_RESOLUTION, V_TIMERRESOLUTION(tre) | 3257167514Skmacy V_DELAYEDACKRESOLUTION(dack_re) | 3258167514Skmacy V_TIMESTAMPRESOLUTION(tstamp_re)); 3259167514Skmacy t3_write_reg(adap, A_TP_DACK_TIMER, 3260167514Skmacy (core_clk >> dack_re) / (1000 / TP_DACK_TIMER)); 3261167514Skmacy t3_write_reg(adap, A_TP_TCP_BACKOFF_REG0, 0x3020100); 3262167514Skmacy t3_write_reg(adap, A_TP_TCP_BACKOFF_REG1, 0x7060504); 3263167514Skmacy t3_write_reg(adap, A_TP_TCP_BACKOFF_REG2, 0xb0a0908); 3264167514Skmacy t3_write_reg(adap, A_TP_TCP_BACKOFF_REG3, 0xf0e0d0c); 3265167514Skmacy t3_write_reg(adap, A_TP_SHIFT_CNT, V_SYNSHIFTMAX(6) | 3266167514Skmacy V_RXTSHIFTMAXR1(4) | V_RXTSHIFTMAXR2(15) | 3267167514Skmacy V_PERSHIFTBACKOFFMAX(8) | V_PERSHIFTMAX(8) | 3268167514Skmacy V_KEEPALIVEMAX(9)); 3269167514Skmacy 3270167514Skmacy#define SECONDS * tps 3271167514Skmacy 3272167514Skmacy t3_write_reg(adap, A_TP_MSL, 3273167514Skmacy adap->params.rev > 0 ? 0 : 2 SECONDS); 3274167514Skmacy t3_write_reg(adap, A_TP_RXT_MIN, tps / (1000 / TP_RTO_MIN)); 3275167514Skmacy t3_write_reg(adap, A_TP_RXT_MAX, 64 SECONDS); 3276167514Skmacy t3_write_reg(adap, A_TP_PERS_MIN, 5 SECONDS); 3277167514Skmacy t3_write_reg(adap, A_TP_PERS_MAX, 64 SECONDS); 3278167514Skmacy t3_write_reg(adap, A_TP_KEEP_IDLE, 7200 SECONDS); 3279167514Skmacy t3_write_reg(adap, A_TP_KEEP_INTVL, 75 SECONDS); 3280167514Skmacy t3_write_reg(adap, A_TP_INIT_SRTT, 3 SECONDS); 3281167514Skmacy t3_write_reg(adap, A_TP_FINWAIT2_TIMER, 600 SECONDS); 3282167514Skmacy 3283167514Skmacy#undef SECONDS 3284167514Skmacy} 3285167514Skmacy 3286167514Skmacy/** 3287167514Skmacy * t3_tp_set_coalescing_size - set receive coalescing size 3288167514Skmacy * @adap: the adapter 3289167514Skmacy * @size: the receive coalescing size 3290167514Skmacy * @psh: whether a set PSH bit should deliver coalesced data 3291167514Skmacy * 3292167514Skmacy * Set the receive coalescing size and PSH bit handling. 3293167514Skmacy */ 3294167514Skmacyint t3_tp_set_coalescing_size(adapter_t *adap, unsigned int size, int psh) 3295167514Skmacy{ 3296167514Skmacy u32 val; 3297167514Skmacy 3298167514Skmacy if (size > MAX_RX_COALESCING_LEN) 3299167514Skmacy return -EINVAL; 3300167514Skmacy 3301167514Skmacy val = t3_read_reg(adap, A_TP_PARA_REG3); 3302167514Skmacy val &= ~(F_RXCOALESCEENABLE | F_RXCOALESCEPSHEN); 3303167514Skmacy 3304167514Skmacy if (size) { 3305167514Skmacy val |= F_RXCOALESCEENABLE; 3306167514Skmacy if (psh) 3307167514Skmacy val |= F_RXCOALESCEPSHEN; 3308170654Skmacy size = min(MAX_RX_COALESCING_LEN, size); 3309167514Skmacy t3_write_reg(adap, A_TP_PARA_REG2, V_RXCOALESCESIZE(size) | 3310167514Skmacy V_MAXRXDATA(MAX_RX_COALESCING_LEN)); 3311167514Skmacy } 3312167514Skmacy t3_write_reg(adap, A_TP_PARA_REG3, val); 3313167514Skmacy return 0; 3314167514Skmacy} 3315167514Skmacy 3316167514Skmacy/** 3317167514Skmacy * t3_tp_set_max_rxsize - set the max receive size 3318167514Skmacy * @adap: the adapter 3319167514Skmacy * @size: the max receive size 3320167514Skmacy * 3321167514Skmacy * Set TP's max receive size. This is the limit that applies when 3322167514Skmacy * receive coalescing is disabled. 3323167514Skmacy */ 3324167514Skmacyvoid t3_tp_set_max_rxsize(adapter_t *adap, unsigned int size) 3325167514Skmacy{ 3326167514Skmacy t3_write_reg(adap, A_TP_PARA_REG7, 3327167514Skmacy V_PMMAXXFERLEN0(size) | V_PMMAXXFERLEN1(size)); 3328167514Skmacy} 3329167514Skmacy 3330167514Skmacystatic void __devinit init_mtus(unsigned short mtus[]) 3331167514Skmacy{ 3332167514Skmacy /* 3333167514Skmacy * See draft-mathis-plpmtud-00.txt for the values. The min is 88 so 3334167514Skmacy * it can accomodate max size TCP/IP headers when SACK and timestamps 3335167514Skmacy * are enabled and still have at least 8 bytes of payload. 3336167514Skmacy */ 3337167514Skmacy mtus[0] = 88; 3338170654Skmacy mtus[1] = 88; 3339167746Skmacy mtus[2] = 256; 3340167746Skmacy mtus[3] = 512; 3341167746Skmacy mtus[4] = 576; 3342167514Skmacy mtus[5] = 1024; 3343167514Skmacy mtus[6] = 1280; 3344167514Skmacy mtus[7] = 1492; 3345167514Skmacy mtus[8] = 1500; 3346167514Skmacy mtus[9] = 2002; 3347167514Skmacy mtus[10] = 2048; 3348167514Skmacy mtus[11] = 4096; 3349167514Skmacy mtus[12] = 4352; 3350167514Skmacy mtus[13] = 8192; 3351167514Skmacy mtus[14] = 9000; 3352167514Skmacy mtus[15] = 9600; 3353167514Skmacy} 3354167514Skmacy 3355172096Skmacy/** 3356172096Skmacy * init_cong_ctrl - initialize congestion control parameters 3357172096Skmacy * @a: the alpha values for congestion control 3358172096Skmacy * @b: the beta values for congestion control 3359172096Skmacy * 3360172096Skmacy * Initialize the congestion control parameters. 3361167514Skmacy */ 3362167514Skmacystatic void __devinit init_cong_ctrl(unsigned short *a, unsigned short *b) 3363167514Skmacy{ 3364167514Skmacy a[0] = a[1] = a[2] = a[3] = a[4] = a[5] = a[6] = a[7] = a[8] = 1; 3365167514Skmacy a[9] = 2; 3366167514Skmacy a[10] = 3; 3367167514Skmacy a[11] = 4; 3368167514Skmacy a[12] = 5; 3369167514Skmacy a[13] = 6; 3370167514Skmacy a[14] = 7; 3371167514Skmacy a[15] = 8; 3372167514Skmacy a[16] = 9; 3373167514Skmacy a[17] = 10; 3374167514Skmacy a[18] = 14; 3375167514Skmacy a[19] = 17; 3376167514Skmacy a[20] = 21; 3377167514Skmacy a[21] = 25; 3378167514Skmacy a[22] = 30; 3379167514Skmacy a[23] = 35; 3380167514Skmacy a[24] = 45; 3381167514Skmacy a[25] = 60; 3382167514Skmacy a[26] = 80; 3383167514Skmacy a[27] = 100; 3384167514Skmacy a[28] = 200; 3385167514Skmacy a[29] = 300; 3386167514Skmacy a[30] = 400; 3387167514Skmacy a[31] = 500; 3388167514Skmacy 3389167514Skmacy b[0] = b[1] = b[2] = b[3] = b[4] = b[5] = b[6] = b[7] = b[8] = 0; 3390167514Skmacy b[9] = b[10] = 1; 3391167514Skmacy b[11] = b[12] = 2; 3392167514Skmacy b[13] = b[14] = b[15] = b[16] = 3; 3393167514Skmacy b[17] = b[18] = b[19] = b[20] = b[21] = 4; 3394167514Skmacy b[22] = b[23] = b[24] = b[25] = b[26] = b[27] = 5; 3395167514Skmacy b[28] = b[29] = 6; 3396167514Skmacy b[30] = b[31] = 7; 3397167514Skmacy} 3398167514Skmacy 3399167514Skmacy/* The minimum additive increment value for the congestion control table */ 3400167514Skmacy#define CC_MIN_INCR 2U 3401167514Skmacy 3402167514Skmacy/** 3403167514Skmacy * t3_load_mtus - write the MTU and congestion control HW tables 3404167514Skmacy * @adap: the adapter 3405167514Skmacy * @mtus: the unrestricted values for the MTU table 3406172096Skmacy * @alpha: the values for the congestion control alpha parameter 3407167514Skmacy * @beta: the values for the congestion control beta parameter 3408167514Skmacy * @mtu_cap: the maximum permitted effective MTU 3409167514Skmacy * 3410167514Skmacy * Write the MTU table with the supplied MTUs capping each at &mtu_cap. 3411167514Skmacy * Update the high-speed congestion control table with the supplied alpha, 3412167514Skmacy * beta, and MTUs. 3413167514Skmacy */ 3414167514Skmacyvoid t3_load_mtus(adapter_t *adap, unsigned short mtus[NMTUS], 3415167514Skmacy unsigned short alpha[NCCTRL_WIN], 3416167514Skmacy unsigned short beta[NCCTRL_WIN], unsigned short mtu_cap) 3417167514Skmacy{ 3418167514Skmacy static const unsigned int avg_pkts[NCCTRL_WIN] = { 3419167514Skmacy 2, 6, 10, 14, 20, 28, 40, 56, 80, 112, 160, 224, 320, 448, 640, 3420167514Skmacy 896, 1281, 1792, 2560, 3584, 5120, 7168, 10240, 14336, 20480, 3421167514Skmacy 28672, 40960, 57344, 81920, 114688, 163840, 229376 }; 3422167514Skmacy 3423167514Skmacy unsigned int i, w; 3424167514Skmacy 3425167514Skmacy for (i = 0; i < NMTUS; ++i) { 3426167514Skmacy unsigned int mtu = min(mtus[i], mtu_cap); 3427167514Skmacy unsigned int log2 = fls(mtu); 3428167514Skmacy 3429167514Skmacy if (!(mtu & ((1 << log2) >> 2))) /* round */ 3430167514Skmacy log2--; 3431167514Skmacy t3_write_reg(adap, A_TP_MTU_TABLE, 3432167514Skmacy (i << 24) | (log2 << 16) | mtu); 3433167514Skmacy 3434167514Skmacy for (w = 0; w < NCCTRL_WIN; ++w) { 3435167514Skmacy unsigned int inc; 3436167514Skmacy 3437167514Skmacy inc = max(((mtu - 40) * alpha[w]) / avg_pkts[w], 3438167514Skmacy CC_MIN_INCR); 3439167514Skmacy 3440167514Skmacy t3_write_reg(adap, A_TP_CCTRL_TABLE, (i << 21) | 3441167514Skmacy (w << 16) | (beta[w] << 13) | inc); 3442167514Skmacy } 3443167514Skmacy } 3444167514Skmacy} 3445167514Skmacy 3446167514Skmacy/** 3447167514Skmacy * t3_read_hw_mtus - returns the values in the HW MTU table 3448167514Skmacy * @adap: the adapter 3449167514Skmacy * @mtus: where to store the HW MTU values 3450167514Skmacy * 3451167514Skmacy * Reads the HW MTU table. 3452167514Skmacy */ 3453167514Skmacyvoid t3_read_hw_mtus(adapter_t *adap, unsigned short mtus[NMTUS]) 3454167514Skmacy{ 3455167514Skmacy int i; 3456167514Skmacy 3457167514Skmacy for (i = 0; i < NMTUS; ++i) { 3458167514Skmacy unsigned int val; 3459167514Skmacy 3460167514Skmacy t3_write_reg(adap, A_TP_MTU_TABLE, 0xff000000 | i); 3461167514Skmacy val = t3_read_reg(adap, A_TP_MTU_TABLE); 3462167514Skmacy mtus[i] = val & 0x3fff; 3463167514Skmacy } 3464167514Skmacy} 3465167514Skmacy 3466167514Skmacy/** 3467167514Skmacy * t3_get_cong_cntl_tab - reads the congestion control table 3468167514Skmacy * @adap: the adapter 3469167514Skmacy * @incr: where to store the alpha values 3470167514Skmacy * 3471167514Skmacy * Reads the additive increments programmed into the HW congestion 3472167514Skmacy * control table. 3473167514Skmacy */ 3474167514Skmacyvoid t3_get_cong_cntl_tab(adapter_t *adap, 3475167514Skmacy unsigned short incr[NMTUS][NCCTRL_WIN]) 3476167514Skmacy{ 3477167514Skmacy unsigned int mtu, w; 3478167514Skmacy 3479167514Skmacy for (mtu = 0; mtu < NMTUS; ++mtu) 3480167514Skmacy for (w = 0; w < NCCTRL_WIN; ++w) { 3481167514Skmacy t3_write_reg(adap, A_TP_CCTRL_TABLE, 3482167514Skmacy 0xffff0000 | (mtu << 5) | w); 3483167514Skmacy incr[mtu][w] = (unsigned short)t3_read_reg(adap, 3484167514Skmacy A_TP_CCTRL_TABLE) & 0x1fff; 3485167514Skmacy } 3486167514Skmacy} 3487167514Skmacy 3488167514Skmacy/** 3489167514Skmacy * t3_tp_get_mib_stats - read TP's MIB counters 3490167514Skmacy * @adap: the adapter 3491167514Skmacy * @tps: holds the returned counter values 3492167514Skmacy * 3493167514Skmacy * Returns the values of TP's MIB counters. 3494167514Skmacy */ 3495167514Skmacyvoid t3_tp_get_mib_stats(adapter_t *adap, struct tp_mib_stats *tps) 3496167514Skmacy{ 3497167514Skmacy t3_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_RDATA, (u32 *)tps, 3498167514Skmacy sizeof(*tps) / sizeof(u32), 0); 3499167514Skmacy} 3500167514Skmacy 3501167746Skmacy/** 3502167746Skmacy * t3_read_pace_tbl - read the pace table 3503167746Skmacy * @adap: the adapter 3504167746Skmacy * @pace_vals: holds the returned values 3505167746Skmacy * 3506167746Skmacy * Returns the values of TP's pace table in nanoseconds. 3507167746Skmacy */ 3508167746Skmacyvoid t3_read_pace_tbl(adapter_t *adap, unsigned int pace_vals[NTX_SCHED]) 3509167746Skmacy{ 3510167746Skmacy unsigned int i, tick_ns = dack_ticks_to_usec(adap, 1000); 3511167746Skmacy 3512167746Skmacy for (i = 0; i < NTX_SCHED; i++) { 3513167746Skmacy t3_write_reg(adap, A_TP_PACE_TABLE, 0xffff0000 + i); 3514167746Skmacy pace_vals[i] = t3_read_reg(adap, A_TP_PACE_TABLE) * tick_ns; 3515167746Skmacy } 3516167746Skmacy} 3517167746Skmacy 3518167746Skmacy/** 3519167746Skmacy * t3_set_pace_tbl - set the pace table 3520167746Skmacy * @adap: the adapter 3521167746Skmacy * @pace_vals: the pace values in nanoseconds 3522167746Skmacy * @start: index of the first entry in the HW pace table to set 3523167746Skmacy * @n: how many entries to set 3524167746Skmacy * 3525167746Skmacy * Sets (a subset of the) HW pace table. 3526167746Skmacy */ 3527167746Skmacyvoid t3_set_pace_tbl(adapter_t *adap, unsigned int *pace_vals, 3528167746Skmacy unsigned int start, unsigned int n) 3529167746Skmacy{ 3530167746Skmacy unsigned int tick_ns = dack_ticks_to_usec(adap, 1000); 3531167746Skmacy 3532167746Skmacy for ( ; n; n--, start++, pace_vals++) 3533167746Skmacy t3_write_reg(adap, A_TP_PACE_TABLE, (start << 16) | 3534167746Skmacy ((*pace_vals + tick_ns / 2) / tick_ns)); 3535167746Skmacy} 3536167746Skmacy 3537167514Skmacy#define ulp_region(adap, name, start, len) \ 3538167514Skmacy t3_write_reg((adap), A_ULPRX_ ## name ## _LLIMIT, (start)); \ 3539167514Skmacy t3_write_reg((adap), A_ULPRX_ ## name ## _ULIMIT, \ 3540167514Skmacy (start) + (len) - 1); \ 3541167514Skmacy start += len 3542167514Skmacy 3543167514Skmacy#define ulptx_region(adap, name, start, len) \ 3544167514Skmacy t3_write_reg((adap), A_ULPTX_ ## name ## _LLIMIT, (start)); \ 3545167514Skmacy t3_write_reg((adap), A_ULPTX_ ## name ## _ULIMIT, \ 3546167514Skmacy (start) + (len) - 1) 3547167514Skmacy 3548167514Skmacystatic void ulp_config(adapter_t *adap, const struct tp_params *p) 3549167514Skmacy{ 3550167514Skmacy unsigned int m = p->chan_rx_size; 3551167514Skmacy 3552167514Skmacy ulp_region(adap, ISCSI, m, p->chan_rx_size / 8); 3553167514Skmacy ulp_region(adap, TDDP, m, p->chan_rx_size / 8); 3554167514Skmacy ulptx_region(adap, TPT, m, p->chan_rx_size / 4); 3555167514Skmacy ulp_region(adap, STAG, m, p->chan_rx_size / 4); 3556167514Skmacy ulp_region(adap, RQ, m, p->chan_rx_size / 4); 3557167514Skmacy ulptx_region(adap, PBL, m, p->chan_rx_size / 4); 3558167514Skmacy ulp_region(adap, PBL, m, p->chan_rx_size / 4); 3559167514Skmacy t3_write_reg(adap, A_ULPRX_TDDP_TAGMASK, 0xffffffff); 3560167514Skmacy} 3561170654Skmacy 3562170654Skmacy 3563170654Skmacy/** 3564170654Skmacy * t3_set_proto_sram - set the contents of the protocol sram 3565170654Skmacy * @adapter: the adapter 3566170654Skmacy * @data: the protocol image 3567170654Skmacy * 3568170654Skmacy * Write the contents of the protocol SRAM. 3569170654Skmacy */ 3570171471Skmacyint t3_set_proto_sram(adapter_t *adap, const u8 *data) 3571170654Skmacy{ 3572170654Skmacy int i; 3573172096Skmacy const u32 *buf = (const u32 *)data; 3574170654Skmacy 3575170654Skmacy for (i = 0; i < PROTO_SRAM_LINES; i++) { 3576171471Skmacy t3_write_reg(adap, A_TP_EMBED_OP_FIELD5, cpu_to_be32(*buf++)); 3577171471Skmacy t3_write_reg(adap, A_TP_EMBED_OP_FIELD4, cpu_to_be32(*buf++)); 3578171471Skmacy t3_write_reg(adap, A_TP_EMBED_OP_FIELD3, cpu_to_be32(*buf++)); 3579171471Skmacy t3_write_reg(adap, A_TP_EMBED_OP_FIELD2, cpu_to_be32(*buf++)); 3580171471Skmacy t3_write_reg(adap, A_TP_EMBED_OP_FIELD1, cpu_to_be32(*buf++)); 3581189643Sgnn 3582170654Skmacy t3_write_reg(adap, A_TP_EMBED_OP_FIELD0, i << 1 | 1 << 31); 3583170654Skmacy if (t3_wait_op_done(adap, A_TP_EMBED_OP_FIELD0, 1, 1, 5, 1)) 3584170654Skmacy return -EIO; 3585170654Skmacy } 3586170654Skmacy return 0; 3587170654Skmacy} 3588167514Skmacy 3589172096Skmacy/** 3590172096Skmacy * t3_config_trace_filter - configure one of the tracing filters 3591172096Skmacy * @adapter: the adapter 3592172096Skmacy * @tp: the desired trace filter parameters 3593172096Skmacy * @filter_index: which filter to configure 3594172096Skmacy * @invert: if set non-matching packets are traced instead of matching ones 3595172096Skmacy * @enable: whether to enable or disable the filter 3596172096Skmacy * 3597172096Skmacy * Configures one of the tracing filters available in HW. 3598172096Skmacy */ 3599167514Skmacyvoid t3_config_trace_filter(adapter_t *adapter, const struct trace_params *tp, 3600167514Skmacy int filter_index, int invert, int enable) 3601167514Skmacy{ 3602167514Skmacy u32 addr, key[4], mask[4]; 3603167514Skmacy 3604167514Skmacy key[0] = tp->sport | (tp->sip << 16); 3605167514Skmacy key[1] = (tp->sip >> 16) | (tp->dport << 16); 3606167514Skmacy key[2] = tp->dip; 3607167514Skmacy key[3] = tp->proto | (tp->vlan << 8) | (tp->intf << 20); 3608167514Skmacy 3609167514Skmacy mask[0] = tp->sport_mask | (tp->sip_mask << 16); 3610167514Skmacy mask[1] = (tp->sip_mask >> 16) | (tp->dport_mask << 16); 3611167514Skmacy mask[2] = tp->dip_mask; 3612167514Skmacy mask[3] = tp->proto_mask | (tp->vlan_mask << 8) | (tp->intf_mask << 20); 3613167514Skmacy 3614167514Skmacy if (invert) 3615167514Skmacy key[3] |= (1 << 29); 3616167514Skmacy if (enable) 3617167514Skmacy key[3] |= (1 << 28); 3618167514Skmacy 3619167514Skmacy addr = filter_index ? A_TP_RX_TRC_KEY0 : A_TP_TX_TRC_KEY0; 3620167514Skmacy tp_wr_indirect(adapter, addr++, key[0]); 3621167514Skmacy tp_wr_indirect(adapter, addr++, mask[0]); 3622167514Skmacy tp_wr_indirect(adapter, addr++, key[1]); 3623167514Skmacy tp_wr_indirect(adapter, addr++, mask[1]); 3624167514Skmacy tp_wr_indirect(adapter, addr++, key[2]); 3625167514Skmacy tp_wr_indirect(adapter, addr++, mask[2]); 3626167514Skmacy tp_wr_indirect(adapter, addr++, key[3]); 3627167514Skmacy tp_wr_indirect(adapter, addr, mask[3]); 3628167514Skmacy (void) t3_read_reg(adapter, A_TP_PIO_DATA); 3629167514Skmacy} 3630167514Skmacy 3631167514Skmacy/** 3632189643Sgnn * t3_query_trace_filter - query a tracing filter 3633189643Sgnn * @adapter: the adapter 3634189643Sgnn * @tp: the current trace filter parameters 3635189643Sgnn * @filter_index: which filter to query 3636189643Sgnn * @inverted: non-zero if the filter is inverted 3637189643Sgnn * @enabled: non-zero if the filter is enabled 3638189643Sgnn * 3639189643Sgnn * Returns the current settings of the specified HW tracing filter. 3640189643Sgnn */ 3641189643Sgnnvoid t3_query_trace_filter(adapter_t *adapter, struct trace_params *tp, 3642189643Sgnn int filter_index, int *inverted, int *enabled) 3643189643Sgnn{ 3644189643Sgnn u32 addr, key[4], mask[4]; 3645189643Sgnn 3646189643Sgnn addr = filter_index ? A_TP_RX_TRC_KEY0 : A_TP_TX_TRC_KEY0; 3647189643Sgnn key[0] = tp_rd_indirect(adapter, addr++); 3648189643Sgnn mask[0] = tp_rd_indirect(adapter, addr++); 3649189643Sgnn key[1] = tp_rd_indirect(adapter, addr++); 3650189643Sgnn mask[1] = tp_rd_indirect(adapter, addr++); 3651189643Sgnn key[2] = tp_rd_indirect(adapter, addr++); 3652189643Sgnn mask[2] = tp_rd_indirect(adapter, addr++); 3653189643Sgnn key[3] = tp_rd_indirect(adapter, addr++); 3654189643Sgnn mask[3] = tp_rd_indirect(adapter, addr); 3655189643Sgnn 3656189643Sgnn tp->sport = key[0] & 0xffff; 3657189643Sgnn tp->sip = (key[0] >> 16) | ((key[1] & 0xffff) << 16); 3658189643Sgnn tp->dport = key[1] >> 16; 3659189643Sgnn tp->dip = key[2]; 3660189643Sgnn tp->proto = key[3] & 0xff; 3661189643Sgnn tp->vlan = key[3] >> 8; 3662189643Sgnn tp->intf = key[3] >> 20; 3663189643Sgnn 3664189643Sgnn tp->sport_mask = mask[0] & 0xffff; 3665189643Sgnn tp->sip_mask = (mask[0] >> 16) | ((mask[1] & 0xffff) << 16); 3666189643Sgnn tp->dport_mask = mask[1] >> 16; 3667189643Sgnn tp->dip_mask = mask[2]; 3668189643Sgnn tp->proto_mask = mask[3] & 0xff; 3669189643Sgnn tp->vlan_mask = mask[3] >> 8; 3670189643Sgnn tp->intf_mask = mask[3] >> 20; 3671189643Sgnn 3672189643Sgnn *inverted = key[3] & (1 << 29); 3673189643Sgnn *enabled = key[3] & (1 << 28); 3674189643Sgnn} 3675189643Sgnn 3676189643Sgnn/** 3677167514Skmacy * t3_config_sched - configure a HW traffic scheduler 3678167514Skmacy * @adap: the adapter 3679167514Skmacy * @kbps: target rate in Kbps 3680167514Skmacy * @sched: the scheduler index 3681167514Skmacy * 3682167746Skmacy * Configure a Tx HW scheduler for the target rate. 3683167514Skmacy */ 3684167514Skmacyint t3_config_sched(adapter_t *adap, unsigned int kbps, int sched) 3685167514Skmacy{ 3686167514Skmacy unsigned int v, tps, cpt, bpt, delta, mindelta = ~0; 3687167514Skmacy unsigned int clk = adap->params.vpd.cclk * 1000; 3688167514Skmacy unsigned int selected_cpt = 0, selected_bpt = 0; 3689167514Skmacy 3690167514Skmacy if (kbps > 0) { 3691167514Skmacy kbps *= 125; /* -> bytes */ 3692167514Skmacy for (cpt = 1; cpt <= 255; cpt++) { 3693167514Skmacy tps = clk / cpt; 3694167514Skmacy bpt = (kbps + tps / 2) / tps; 3695167514Skmacy if (bpt > 0 && bpt <= 255) { 3696167514Skmacy v = bpt * tps; 3697167514Skmacy delta = v >= kbps ? v - kbps : kbps - v; 3698176472Skmacy if (delta < mindelta) { 3699167514Skmacy mindelta = delta; 3700167514Skmacy selected_cpt = cpt; 3701167514Skmacy selected_bpt = bpt; 3702167514Skmacy } 3703167514Skmacy } else if (selected_cpt) 3704167514Skmacy break; 3705167514Skmacy } 3706167514Skmacy if (!selected_cpt) 3707167514Skmacy return -EINVAL; 3708167514Skmacy } 3709167514Skmacy t3_write_reg(adap, A_TP_TM_PIO_ADDR, 3710167514Skmacy A_TP_TX_MOD_Q1_Q0_RATE_LIMIT - sched / 2); 3711167514Skmacy v = t3_read_reg(adap, A_TP_TM_PIO_DATA); 3712167514Skmacy if (sched & 1) 3713167514Skmacy v = (v & 0xffff) | (selected_cpt << 16) | (selected_bpt << 24); 3714167514Skmacy else 3715167514Skmacy v = (v & 0xffff0000) | selected_cpt | (selected_bpt << 8); 3716167514Skmacy t3_write_reg(adap, A_TP_TM_PIO_DATA, v); 3717167514Skmacy return 0; 3718167514Skmacy} 3719167514Skmacy 3720167746Skmacy/** 3721167746Skmacy * t3_set_sched_ipg - set the IPG for a Tx HW packet rate scheduler 3722167746Skmacy * @adap: the adapter 3723167746Skmacy * @sched: the scheduler index 3724167746Skmacy * @ipg: the interpacket delay in tenths of nanoseconds 3725167746Skmacy * 3726167746Skmacy * Set the interpacket delay for a HW packet rate scheduler. 3727167746Skmacy */ 3728167746Skmacyint t3_set_sched_ipg(adapter_t *adap, int sched, unsigned int ipg) 3729167746Skmacy{ 3730167746Skmacy unsigned int v, addr = A_TP_TX_MOD_Q1_Q0_TIMER_SEPARATOR - sched / 2; 3731167746Skmacy 3732167746Skmacy /* convert ipg to nearest number of core clocks */ 3733167746Skmacy ipg *= core_ticks_per_usec(adap); 3734167746Skmacy ipg = (ipg + 5000) / 10000; 3735167746Skmacy if (ipg > 0xffff) 3736167746Skmacy return -EINVAL; 3737167746Skmacy 3738167746Skmacy t3_write_reg(adap, A_TP_TM_PIO_ADDR, addr); 3739167746Skmacy v = t3_read_reg(adap, A_TP_TM_PIO_DATA); 3740167746Skmacy if (sched & 1) 3741167746Skmacy v = (v & 0xffff) | (ipg << 16); 3742167746Skmacy else 3743167746Skmacy v = (v & 0xffff0000) | ipg; 3744167746Skmacy t3_write_reg(adap, A_TP_TM_PIO_DATA, v); 3745167746Skmacy t3_read_reg(adap, A_TP_TM_PIO_DATA); 3746167746Skmacy return 0; 3747167746Skmacy} 3748167746Skmacy 3749167746Skmacy/** 3750167746Skmacy * t3_get_tx_sched - get the configuration of a Tx HW traffic scheduler 3751167746Skmacy * @adap: the adapter 3752167746Skmacy * @sched: the scheduler index 3753167746Skmacy * @kbps: the byte rate in Kbps 3754167746Skmacy * @ipg: the interpacket delay in tenths of nanoseconds 3755167746Skmacy * 3756167746Skmacy * Return the current configuration of a HW Tx scheduler. 3757167746Skmacy */ 3758167746Skmacyvoid t3_get_tx_sched(adapter_t *adap, unsigned int sched, unsigned int *kbps, 3759167746Skmacy unsigned int *ipg) 3760167746Skmacy{ 3761167746Skmacy unsigned int v, addr, bpt, cpt; 3762167746Skmacy 3763167746Skmacy if (kbps) { 3764167746Skmacy addr = A_TP_TX_MOD_Q1_Q0_RATE_LIMIT - sched / 2; 3765167746Skmacy t3_write_reg(adap, A_TP_TM_PIO_ADDR, addr); 3766167746Skmacy v = t3_read_reg(adap, A_TP_TM_PIO_DATA); 3767167746Skmacy if (sched & 1) 3768167746Skmacy v >>= 16; 3769167746Skmacy bpt = (v >> 8) & 0xff; 3770167746Skmacy cpt = v & 0xff; 3771167746Skmacy if (!cpt) 3772167746Skmacy *kbps = 0; /* scheduler disabled */ 3773167746Skmacy else { 3774167746Skmacy v = (adap->params.vpd.cclk * 1000) / cpt; 3775167746Skmacy *kbps = (v * bpt) / 125; 3776167746Skmacy } 3777167746Skmacy } 3778167746Skmacy if (ipg) { 3779167746Skmacy addr = A_TP_TX_MOD_Q1_Q0_TIMER_SEPARATOR - sched / 2; 3780167746Skmacy t3_write_reg(adap, A_TP_TM_PIO_ADDR, addr); 3781167746Skmacy v = t3_read_reg(adap, A_TP_TM_PIO_DATA); 3782167746Skmacy if (sched & 1) 3783167746Skmacy v >>= 16; 3784167746Skmacy v &= 0xffff; 3785167746Skmacy *ipg = (10000 * v) / core_ticks_per_usec(adap); 3786167746Skmacy } 3787167746Skmacy} 3788167746Skmacy 3789172096Skmacy/** 3790172096Skmacy * tp_init - configure TP 3791172096Skmacy * @adap: the adapter 3792172096Skmacy * @p: TP configuration parameters 3793172096Skmacy * 3794172096Skmacy * Initializes the TP HW module. 3795172096Skmacy */ 3796167514Skmacystatic int tp_init(adapter_t *adap, const struct tp_params *p) 3797167514Skmacy{ 3798167514Skmacy int busy = 0; 3799167514Skmacy 3800167514Skmacy tp_config(adap, p); 3801167514Skmacy t3_set_vlan_accel(adap, 3, 0); 3802167514Skmacy 3803167514Skmacy if (is_offload(adap)) { 3804167514Skmacy tp_set_timers(adap, adap->params.vpd.cclk * 1000); 3805167514Skmacy t3_write_reg(adap, A_TP_RESET, F_FLSTINITENABLE); 3806167514Skmacy busy = t3_wait_op_done(adap, A_TP_RESET, F_FLSTINITENABLE, 3807167514Skmacy 0, 1000, 5); 3808167514Skmacy if (busy) 3809167514Skmacy CH_ERR(adap, "TP initialization timed out\n"); 3810167514Skmacy } 3811167514Skmacy 3812167514Skmacy if (!busy) 3813167514Skmacy t3_write_reg(adap, A_TP_RESET, F_TPRESET); 3814167514Skmacy return busy; 3815167514Skmacy} 3816167514Skmacy 3817172096Skmacy/** 3818172096Skmacy * t3_mps_set_active_ports - configure port failover 3819172096Skmacy * @adap: the adapter 3820172096Skmacy * @port_mask: bitmap of active ports 3821172096Skmacy * 3822172096Skmacy * Sets the active ports according to the supplied bitmap. 3823172096Skmacy */ 3824167514Skmacyint t3_mps_set_active_ports(adapter_t *adap, unsigned int port_mask) 3825167514Skmacy{ 3826167514Skmacy if (port_mask & ~((1 << adap->params.nports) - 1)) 3827167514Skmacy return -EINVAL; 3828167514Skmacy t3_set_reg_field(adap, A_MPS_CFG, F_PORT1ACTIVE | F_PORT0ACTIVE, 3829167514Skmacy port_mask << S_PORT0ACTIVE); 3830167514Skmacy return 0; 3831167514Skmacy} 3832167514Skmacy 3833172096Skmacy/** 3834172096Skmacy * chan_init_hw - channel-dependent HW initialization 3835172096Skmacy * @adap: the adapter 3836172096Skmacy * @chan_map: bitmap of Tx channels being used 3837172096Skmacy * 3838172096Skmacy * Perform the bits of HW initialization that are dependent on the Tx 3839172096Skmacy * channels being used. 3840167514Skmacy */ 3841170654Skmacystatic void chan_init_hw(adapter_t *adap, unsigned int chan_map) 3842167514Skmacy{ 3843167514Skmacy int i; 3844167514Skmacy 3845170654Skmacy if (chan_map != 3) { /* one channel */ 3846167514Skmacy t3_set_reg_field(adap, A_ULPRX_CTL, F_ROUND_ROBIN, 0); 3847167514Skmacy t3_set_reg_field(adap, A_ULPTX_CONFIG, F_CFG_RR_ARB, 0); 3848170654Skmacy t3_write_reg(adap, A_MPS_CFG, F_TPRXPORTEN | F_ENFORCEPKT | 3849170654Skmacy (chan_map == 1 ? F_TPTXPORT0EN | F_PORT0ACTIVE : 3850170654Skmacy F_TPTXPORT1EN | F_PORT1ACTIVE)); 3851170654Skmacy t3_write_reg(adap, A_PM1_TX_CFG, 3852170654Skmacy chan_map == 1 ? 0xffffffff : 0); 3853172096Skmacy if (chan_map == 2) 3854172096Skmacy t3_write_reg(adap, A_TP_TX_MOD_QUEUE_REQ_MAP, 3855172096Skmacy V_TX_MOD_QUEUE_REQ_MAP(0xff)); 3856172096Skmacy t3_write_reg(adap, A_TP_TX_MOD_QUE_TABLE, (12 << 16) | 0xd9c8); 3857172096Skmacy t3_write_reg(adap, A_TP_TX_MOD_QUE_TABLE, (13 << 16) | 0xfbea); 3858170654Skmacy } else { /* two channels */ 3859167514Skmacy t3_set_reg_field(adap, A_ULPRX_CTL, 0, F_ROUND_ROBIN); 3860167514Skmacy t3_set_reg_field(adap, A_ULPTX_CONFIG, 0, F_CFG_RR_ARB); 3861167514Skmacy t3_write_reg(adap, A_ULPTX_DMA_WEIGHT, 3862167514Skmacy V_D1_WEIGHT(16) | V_D0_WEIGHT(16)); 3863167514Skmacy t3_write_reg(adap, A_MPS_CFG, F_TPTXPORT0EN | F_TPTXPORT1EN | 3864167514Skmacy F_TPRXPORTEN | F_PORT0ACTIVE | F_PORT1ACTIVE | 3865167514Skmacy F_ENFORCEPKT); 3866167514Skmacy t3_write_reg(adap, A_PM1_TX_CFG, 0x80008000); 3867167514Skmacy t3_set_reg_field(adap, A_TP_PC_CONFIG, 0, F_TXTOSQUEUEMAPMODE); 3868167514Skmacy t3_write_reg(adap, A_TP_TX_MOD_QUEUE_REQ_MAP, 3869167514Skmacy V_TX_MOD_QUEUE_REQ_MAP(0xaa)); 3870167514Skmacy for (i = 0; i < 16; i++) 3871167514Skmacy t3_write_reg(adap, A_TP_TX_MOD_QUE_TABLE, 3872167514Skmacy (i << 16) | 0x1010); 3873172096Skmacy t3_write_reg(adap, A_TP_TX_MOD_QUE_TABLE, (12 << 16) | 0xba98); 3874172096Skmacy t3_write_reg(adap, A_TP_TX_MOD_QUE_TABLE, (13 << 16) | 0xfedc); 3875167514Skmacy } 3876167514Skmacy} 3877167514Skmacy 3878167514Skmacystatic int calibrate_xgm(adapter_t *adapter) 3879167514Skmacy{ 3880167514Skmacy if (uses_xaui(adapter)) { 3881167514Skmacy unsigned int v, i; 3882167514Skmacy 3883167514Skmacy for (i = 0; i < 5; ++i) { 3884167514Skmacy t3_write_reg(adapter, A_XGM_XAUI_IMP, 0); 3885167514Skmacy (void) t3_read_reg(adapter, A_XGM_XAUI_IMP); 3886171471Skmacy msleep(1); 3887167514Skmacy v = t3_read_reg(adapter, A_XGM_XAUI_IMP); 3888167514Skmacy if (!(v & (F_XGM_CALFAULT | F_CALBUSY))) { 3889167514Skmacy t3_write_reg(adapter, A_XGM_XAUI_IMP, 3890167514Skmacy V_XAUIIMP(G_CALIMP(v) >> 2)); 3891167514Skmacy return 0; 3892167514Skmacy } 3893167514Skmacy } 3894167514Skmacy CH_ERR(adapter, "MAC calibration failed\n"); 3895167514Skmacy return -1; 3896167514Skmacy } else { 3897167514Skmacy t3_write_reg(adapter, A_XGM_RGMII_IMP, 3898167514Skmacy V_RGMIIIMPPD(2) | V_RGMIIIMPPU(3)); 3899167514Skmacy t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_XGM_IMPSETUPDATE, 3900167514Skmacy F_XGM_IMPSETUPDATE); 3901167514Skmacy } 3902167514Skmacy return 0; 3903167514Skmacy} 3904167514Skmacy 3905167514Skmacystatic void calibrate_xgm_t3b(adapter_t *adapter) 3906167514Skmacy{ 3907167514Skmacy if (!uses_xaui(adapter)) { 3908167514Skmacy t3_write_reg(adapter, A_XGM_RGMII_IMP, F_CALRESET | 3909167514Skmacy F_CALUPDATE | V_RGMIIIMPPD(2) | V_RGMIIIMPPU(3)); 3910167514Skmacy t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_CALRESET, 0); 3911167514Skmacy t3_set_reg_field(adapter, A_XGM_RGMII_IMP, 0, 3912167514Skmacy F_XGM_IMPSETUPDATE); 3913167514Skmacy t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_XGM_IMPSETUPDATE, 3914167514Skmacy 0); 3915167514Skmacy t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_CALUPDATE, 0); 3916167514Skmacy t3_set_reg_field(adapter, A_XGM_RGMII_IMP, 0, F_CALUPDATE); 3917167514Skmacy } 3918167514Skmacy} 3919167514Skmacy 3920167514Skmacystruct mc7_timing_params { 3921167514Skmacy unsigned char ActToPreDly; 3922167514Skmacy unsigned char ActToRdWrDly; 3923167514Skmacy unsigned char PreCyc; 3924167514Skmacy unsigned char RefCyc[5]; 3925167514Skmacy unsigned char BkCyc; 3926167514Skmacy unsigned char WrToRdDly; 3927167514Skmacy unsigned char RdToWrDly; 3928167514Skmacy}; 3929167514Skmacy 3930167514Skmacy/* 3931167514Skmacy * Write a value to a register and check that the write completed. These 3932167514Skmacy * writes normally complete in a cycle or two, so one read should suffice. 3933167514Skmacy * The very first read exists to flush the posted write to the device. 3934167514Skmacy */ 3935167514Skmacystatic int wrreg_wait(adapter_t *adapter, unsigned int addr, u32 val) 3936167514Skmacy{ 3937167514Skmacy t3_write_reg(adapter, addr, val); 3938167514Skmacy (void) t3_read_reg(adapter, addr); /* flush */ 3939167514Skmacy if (!(t3_read_reg(adapter, addr) & F_BUSY)) 3940167514Skmacy return 0; 3941167514Skmacy CH_ERR(adapter, "write to MC7 register 0x%x timed out\n", addr); 3942167514Skmacy return -EIO; 3943167514Skmacy} 3944167514Skmacy 3945167514Skmacystatic int mc7_init(struct mc7 *mc7, unsigned int mc7_clock, int mem_type) 3946167514Skmacy{ 3947167514Skmacy static const unsigned int mc7_mode[] = { 3948167514Skmacy 0x632, 0x642, 0x652, 0x432, 0x442 3949167514Skmacy }; 3950167514Skmacy static const struct mc7_timing_params mc7_timings[] = { 3951167514Skmacy { 12, 3, 4, { 20, 28, 34, 52, 0 }, 15, 6, 4 }, 3952167514Skmacy { 12, 4, 5, { 20, 28, 34, 52, 0 }, 16, 7, 4 }, 3953167514Skmacy { 12, 5, 6, { 20, 28, 34, 52, 0 }, 17, 8, 4 }, 3954167514Skmacy { 9, 3, 4, { 15, 21, 26, 39, 0 }, 12, 6, 4 }, 3955167514Skmacy { 9, 4, 5, { 15, 21, 26, 39, 0 }, 13, 7, 4 } 3956167514Skmacy }; 3957167514Skmacy 3958167514Skmacy u32 val; 3959167514Skmacy unsigned int width, density, slow, attempts; 3960167514Skmacy adapter_t *adapter = mc7->adapter; 3961167514Skmacy const struct mc7_timing_params *p = &mc7_timings[mem_type]; 3962167514Skmacy 3963170654Skmacy if (!mc7->size) 3964169978Skmacy return 0; 3965170654Skmacy 3966167514Skmacy val = t3_read_reg(adapter, mc7->offset + A_MC7_CFG); 3967167514Skmacy slow = val & F_SLOW; 3968167514Skmacy width = G_WIDTH(val); 3969167514Skmacy density = G_DEN(val); 3970167514Skmacy 3971167514Skmacy t3_write_reg(adapter, mc7->offset + A_MC7_CFG, val | F_IFEN); 3972167514Skmacy val = t3_read_reg(adapter, mc7->offset + A_MC7_CFG); /* flush */ 3973171471Skmacy msleep(1); 3974167514Skmacy 3975167514Skmacy if (!slow) { 3976167514Skmacy t3_write_reg(adapter, mc7->offset + A_MC7_CAL, F_SGL_CAL_EN); 3977167514Skmacy (void) t3_read_reg(adapter, mc7->offset + A_MC7_CAL); 3978171471Skmacy msleep(1); 3979167514Skmacy if (t3_read_reg(adapter, mc7->offset + A_MC7_CAL) & 3980167514Skmacy (F_BUSY | F_SGL_CAL_EN | F_CAL_FAULT)) { 3981167514Skmacy CH_ERR(adapter, "%s MC7 calibration timed out\n", 3982167514Skmacy mc7->name); 3983167514Skmacy goto out_fail; 3984167514Skmacy } 3985167514Skmacy } 3986167514Skmacy 3987167514Skmacy t3_write_reg(adapter, mc7->offset + A_MC7_PARM, 3988167514Skmacy V_ACTTOPREDLY(p->ActToPreDly) | 3989167514Skmacy V_ACTTORDWRDLY(p->ActToRdWrDly) | V_PRECYC(p->PreCyc) | 3990167514Skmacy V_REFCYC(p->RefCyc[density]) | V_BKCYC(p->BkCyc) | 3991167514Skmacy V_WRTORDDLY(p->WrToRdDly) | V_RDTOWRDLY(p->RdToWrDly)); 3992167514Skmacy 3993167514Skmacy t3_write_reg(adapter, mc7->offset + A_MC7_CFG, 3994167514Skmacy val | F_CLKEN | F_TERM150); 3995167514Skmacy (void) t3_read_reg(adapter, mc7->offset + A_MC7_CFG); /* flush */ 3996167514Skmacy 3997167514Skmacy if (!slow) 3998167514Skmacy t3_set_reg_field(adapter, mc7->offset + A_MC7_DLL, F_DLLENB, 3999167514Skmacy F_DLLENB); 4000167514Skmacy udelay(1); 4001167514Skmacy 4002167514Skmacy val = slow ? 3 : 6; 4003167514Skmacy if (wrreg_wait(adapter, mc7->offset + A_MC7_PRE, 0) || 4004167514Skmacy wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE2, 0) || 4005167514Skmacy wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE3, 0) || 4006167514Skmacy wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE1, val)) 4007167514Skmacy goto out_fail; 4008167514Skmacy 4009167514Skmacy if (!slow) { 4010167514Skmacy t3_write_reg(adapter, mc7->offset + A_MC7_MODE, 0x100); 4011167514Skmacy t3_set_reg_field(adapter, mc7->offset + A_MC7_DLL, 4012167514Skmacy F_DLLRST, 0); 4013167514Skmacy udelay(5); 4014167514Skmacy } 4015167514Skmacy 4016167514Skmacy if (wrreg_wait(adapter, mc7->offset + A_MC7_PRE, 0) || 4017167514Skmacy wrreg_wait(adapter, mc7->offset + A_MC7_REF, 0) || 4018167514Skmacy wrreg_wait(adapter, mc7->offset + A_MC7_REF, 0) || 4019167514Skmacy wrreg_wait(adapter, mc7->offset + A_MC7_MODE, 4020167514Skmacy mc7_mode[mem_type]) || 4021167514Skmacy wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE1, val | 0x380) || 4022167514Skmacy wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE1, val)) 4023167514Skmacy goto out_fail; 4024167514Skmacy 4025167514Skmacy /* clock value is in KHz */ 4026167514Skmacy mc7_clock = mc7_clock * 7812 + mc7_clock / 2; /* ns */ 4027167514Skmacy mc7_clock /= 1000000; /* KHz->MHz, ns->us */ 4028167514Skmacy 4029167514Skmacy t3_write_reg(adapter, mc7->offset + A_MC7_REF, 4030167514Skmacy F_PERREFEN | V_PREREFDIV(mc7_clock)); 4031167514Skmacy (void) t3_read_reg(adapter, mc7->offset + A_MC7_REF); /* flush */ 4032167514Skmacy 4033167514Skmacy t3_write_reg(adapter, mc7->offset + A_MC7_ECC, 4034167514Skmacy F_ECCGENEN | F_ECCCHKEN); 4035167514Skmacy t3_write_reg(adapter, mc7->offset + A_MC7_BIST_DATA, 0); 4036167514Skmacy t3_write_reg(adapter, mc7->offset + A_MC7_BIST_ADDR_BEG, 0); 4037167514Skmacy t3_write_reg(adapter, mc7->offset + A_MC7_BIST_ADDR_END, 4038167514Skmacy (mc7->size << width) - 1); 4039167514Skmacy t3_write_reg(adapter, mc7->offset + A_MC7_BIST_OP, V_OP(1)); 4040167514Skmacy (void) t3_read_reg(adapter, mc7->offset + A_MC7_BIST_OP); /* flush */ 4041167514Skmacy 4042167514Skmacy attempts = 50; 4043167514Skmacy do { 4044171471Skmacy msleep(250); 4045167514Skmacy val = t3_read_reg(adapter, mc7->offset + A_MC7_BIST_OP); 4046167514Skmacy } while ((val & F_BUSY) && --attempts); 4047167514Skmacy if (val & F_BUSY) { 4048167514Skmacy CH_ERR(adapter, "%s MC7 BIST timed out\n", mc7->name); 4049167514Skmacy goto out_fail; 4050167514Skmacy } 4051167514Skmacy 4052167514Skmacy /* Enable normal memory accesses. */ 4053167514Skmacy t3_set_reg_field(adapter, mc7->offset + A_MC7_CFG, 0, F_RDY); 4054167514Skmacy return 0; 4055167514Skmacy 4056167514Skmacy out_fail: 4057167514Skmacy return -1; 4058167514Skmacy} 4059167514Skmacy 4060167514Skmacystatic void config_pcie(adapter_t *adap) 4061167514Skmacy{ 4062167514Skmacy static const u16 ack_lat[4][6] = { 4063167514Skmacy { 237, 416, 559, 1071, 2095, 4143 }, 4064167514Skmacy { 128, 217, 289, 545, 1057, 2081 }, 4065167514Skmacy { 73, 118, 154, 282, 538, 1050 }, 4066167514Skmacy { 67, 107, 86, 150, 278, 534 } 4067167514Skmacy }; 4068167514Skmacy static const u16 rpl_tmr[4][6] = { 4069167514Skmacy { 711, 1248, 1677, 3213, 6285, 12429 }, 4070167514Skmacy { 384, 651, 867, 1635, 3171, 6243 }, 4071167514Skmacy { 219, 354, 462, 846, 1614, 3150 }, 4072167514Skmacy { 201, 321, 258, 450, 834, 1602 } 4073167514Skmacy }; 4074167514Skmacy 4075197791Snp u16 val, devid; 4076167514Skmacy unsigned int log2_width, pldsize; 4077167514Skmacy unsigned int fst_trn_rx, fst_trn_tx, acklat, rpllmt; 4078167514Skmacy 4079167514Skmacy t3_os_pci_read_config_2(adap, 4080167514Skmacy adap->params.pci.pcie_cap_addr + PCI_EXP_DEVCTL, 4081167514Skmacy &val); 4082167514Skmacy pldsize = (val & PCI_EXP_DEVCTL_PAYLOAD) >> 5; 4083167514Skmacy 4084197791Snp /* 4085197791Snp * Gen2 adapter pcie bridge compatibility requires minimum 4086197791Snp * Max_Read_Request_size 4087197791Snp */ 4088197791Snp t3_os_pci_read_config_2(adap, 0x2, &devid); 4089197791Snp if (devid == 0x37) { 4090197791Snp t3_os_pci_write_config_2(adap, 4091197791Snp adap->params.pci.pcie_cap_addr + PCI_EXP_DEVCTL, 4092197791Snp val & ~PCI_EXP_DEVCTL_READRQ & ~PCI_EXP_DEVCTL_PAYLOAD); 4093197791Snp pldsize = 0; 4094197791Snp } 4095197791Snp 4096167514Skmacy t3_os_pci_read_config_2(adap, 4097167514Skmacy adap->params.pci.pcie_cap_addr + PCI_EXP_LNKCTL, 4098167514Skmacy &val); 4099167514Skmacy 4100167514Skmacy fst_trn_tx = G_NUMFSTTRNSEQ(t3_read_reg(adap, A_PCIE_PEX_CTRL0)); 4101167514Skmacy fst_trn_rx = adap->params.rev == 0 ? fst_trn_tx : 4102167514Skmacy G_NUMFSTTRNSEQRX(t3_read_reg(adap, A_PCIE_MODE)); 4103167514Skmacy log2_width = fls(adap->params.pci.width) - 1; 4104167514Skmacy acklat = ack_lat[log2_width][pldsize]; 4105167514Skmacy if (val & 1) /* check LOsEnable */ 4106167514Skmacy acklat += fst_trn_tx * 4; 4107167514Skmacy rpllmt = rpl_tmr[log2_width][pldsize] + fst_trn_rx * 4; 4108167514Skmacy 4109167514Skmacy if (adap->params.rev == 0) 4110167514Skmacy t3_set_reg_field(adap, A_PCIE_PEX_CTRL1, 4111167514Skmacy V_T3A_ACKLAT(M_T3A_ACKLAT), 4112167514Skmacy V_T3A_ACKLAT(acklat)); 4113167514Skmacy else 4114167514Skmacy t3_set_reg_field(adap, A_PCIE_PEX_CTRL1, V_ACKLAT(M_ACKLAT), 4115167514Skmacy V_ACKLAT(acklat)); 4116167514Skmacy 4117167514Skmacy t3_set_reg_field(adap, A_PCIE_PEX_CTRL0, V_REPLAYLMT(M_REPLAYLMT), 4118167514Skmacy V_REPLAYLMT(rpllmt)); 4119167514Skmacy 4120167514Skmacy t3_write_reg(adap, A_PCIE_PEX_ERR, 0xffffffff); 4121176472Skmacy t3_set_reg_field(adap, A_PCIE_CFG, 0, 4122189643Sgnn F_ENABLELINKDWNDRST | F_ENABLELINKDOWNRST | 4123176472Skmacy F_PCIE_DMASTOPEN | F_PCIE_CLIDECEN); 4124167514Skmacy} 4125167514Skmacy 4126172096Skmacy/** 4127172096Skmacy * t3_init_hw - initialize and configure T3 HW modules 4128172096Skmacy * @adapter: the adapter 4129172096Skmacy * @fw_params: initial parameters to pass to firmware (optional) 4130167514Skmacy * 4131172096Skmacy * Initialize and configure T3 HW modules. This performs the 4132172096Skmacy * initialization steps that need to be done once after a card is reset. 4133172096Skmacy * MAC and PHY initialization is handled separarely whenever a port is 4134172096Skmacy * enabled. 4135172096Skmacy * 4136172096Skmacy * @fw_params are passed to FW and their value is platform dependent. 4137172096Skmacy * Only the top 8 bits are available for use, the rest must be 0. 4138167514Skmacy */ 4139167514Skmacyint t3_init_hw(adapter_t *adapter, u32 fw_params) 4140167514Skmacy{ 4141176472Skmacy int err = -EIO, attempts, i; 4142167514Skmacy const struct vpd_params *vpd = &adapter->params.vpd; 4143167514Skmacy 4144167514Skmacy if (adapter->params.rev > 0) 4145167514Skmacy calibrate_xgm_t3b(adapter); 4146167514Skmacy else if (calibrate_xgm(adapter)) 4147167514Skmacy goto out_err; 4148167514Skmacy 4149171471Skmacy if (adapter->params.nports > 2) 4150197791Snp t3_mac_init(&adap2pinfo(adapter, 0)->mac); 4151170654Skmacy 4152167514Skmacy if (vpd->mclk) { 4153167514Skmacy partition_mem(adapter, &adapter->params.tp); 4154167514Skmacy 4155167514Skmacy if (mc7_init(&adapter->pmrx, vpd->mclk, vpd->mem_timing) || 4156167514Skmacy mc7_init(&adapter->pmtx, vpd->mclk, vpd->mem_timing) || 4157167514Skmacy mc7_init(&adapter->cm, vpd->mclk, vpd->mem_timing) || 4158167514Skmacy t3_mc5_init(&adapter->mc5, adapter->params.mc5.nservers, 4159167514Skmacy adapter->params.mc5.nfilters, 4160167514Skmacy adapter->params.mc5.nroutes)) 4161167514Skmacy goto out_err; 4162176472Skmacy 4163176472Skmacy for (i = 0; i < 32; i++) 4164176472Skmacy if (clear_sge_ctxt(adapter, i, F_CQ)) 4165176472Skmacy goto out_err; 4166167514Skmacy } 4167167514Skmacy 4168167514Skmacy if (tp_init(adapter, &adapter->params.tp)) 4169167514Skmacy goto out_err; 4170167514Skmacy 4171167514Skmacy t3_tp_set_coalescing_size(adapter, 4172167514Skmacy min(adapter->params.sge.max_pkt_size, 4173167514Skmacy MAX_RX_COALESCING_LEN), 1); 4174167514Skmacy t3_tp_set_max_rxsize(adapter, 4175167514Skmacy min(adapter->params.sge.max_pkt_size, 16384U)); 4176167514Skmacy ulp_config(adapter, &adapter->params.tp); 4177167514Skmacy if (is_pcie(adapter)) 4178167514Skmacy config_pcie(adapter); 4179167514Skmacy else 4180176472Skmacy t3_set_reg_field(adapter, A_PCIX_CFG, 0, 4181176472Skmacy F_DMASTOPEN | F_CLIDECEN); 4182167514Skmacy 4183176472Skmacy if (adapter->params.rev == T3_REV_C) 4184176472Skmacy t3_set_reg_field(adapter, A_ULPTX_CONFIG, 0, 4185176472Skmacy F_CFG_CQE_SOP_MASK); 4186176472Skmacy 4187170654Skmacy t3_write_reg(adapter, A_PM1_RX_CFG, 0xffffffff); 4188172096Skmacy t3_write_reg(adapter, A_PM1_RX_MODE, 0); 4189172096Skmacy t3_write_reg(adapter, A_PM1_TX_MODE, 0); 4190170654Skmacy chan_init_hw(adapter, adapter->params.chan_map); 4191167514Skmacy t3_sge_init(adapter, &adapter->params.sge); 4192219945Snp t3_set_reg_field(adapter, A_PL_RST, 0, F_FATALPERREN); 4193167514Skmacy 4194180583Skmacy t3_write_reg(adapter, A_T3DBG_GPIO_ACT_LOW, calc_gpio_intr(adapter)); 4195180583Skmacy 4196167514Skmacy t3_write_reg(adapter, A_CIM_HOST_ACC_DATA, vpd->uclk | fw_params); 4197167514Skmacy t3_write_reg(adapter, A_CIM_BOOT_CFG, 4198167514Skmacy V_BOOTADDR(FW_FLASH_BOOT_ADDR >> 2)); 4199167514Skmacy (void) t3_read_reg(adapter, A_CIM_BOOT_CFG); /* flush */ 4200167514Skmacy 4201176472Skmacy attempts = 100; 4202167514Skmacy do { /* wait for uP to initialize */ 4203171471Skmacy msleep(20); 4204167514Skmacy } while (t3_read_reg(adapter, A_CIM_HOST_ACC_DATA) && --attempts); 4205169978Skmacy if (!attempts) { 4206169978Skmacy CH_ERR(adapter, "uP initialization timed out\n"); 4207167514Skmacy goto out_err; 4208169978Skmacy } 4209170654Skmacy 4210167514Skmacy err = 0; 4211167514Skmacy out_err: 4212167514Skmacy return err; 4213167514Skmacy} 4214167514Skmacy 4215167514Skmacy/** 4216167514Skmacy * get_pci_mode - determine a card's PCI mode 4217167514Skmacy * @adapter: the adapter 4218167514Skmacy * @p: where to store the PCI settings 4219167514Skmacy * 4220167514Skmacy * Determines a card's PCI mode and associated parameters, such as speed 4221167514Skmacy * and width. 4222167514Skmacy */ 4223167514Skmacystatic void __devinit get_pci_mode(adapter_t *adapter, struct pci_params *p) 4224167514Skmacy{ 4225167514Skmacy static unsigned short speed_map[] = { 33, 66, 100, 133 }; 4226167514Skmacy u32 pci_mode, pcie_cap; 4227167514Skmacy 4228167514Skmacy pcie_cap = t3_os_find_pci_capability(adapter, PCI_CAP_ID_EXP); 4229167514Skmacy if (pcie_cap) { 4230167514Skmacy u16 val; 4231167514Skmacy 4232167514Skmacy p->variant = PCI_VARIANT_PCIE; 4233167514Skmacy p->pcie_cap_addr = pcie_cap; 4234167514Skmacy t3_os_pci_read_config_2(adapter, pcie_cap + PCI_EXP_LNKSTA, 4235167514Skmacy &val); 4236167514Skmacy p->width = (val >> 4) & 0x3f; 4237167514Skmacy return; 4238167514Skmacy } 4239167514Skmacy 4240167514Skmacy pci_mode = t3_read_reg(adapter, A_PCIX_MODE); 4241167514Skmacy p->speed = speed_map[G_PCLKRANGE(pci_mode)]; 4242167514Skmacy p->width = (pci_mode & F_64BIT) ? 64 : 32; 4243167514Skmacy pci_mode = G_PCIXINITPAT(pci_mode); 4244167514Skmacy if (pci_mode == 0) 4245167514Skmacy p->variant = PCI_VARIANT_PCI; 4246167514Skmacy else if (pci_mode < 4) 4247167514Skmacy p->variant = PCI_VARIANT_PCIX_MODE1_PARITY; 4248167514Skmacy else if (pci_mode < 8) 4249167514Skmacy p->variant = PCI_VARIANT_PCIX_MODE1_ECC; 4250167514Skmacy else 4251167514Skmacy p->variant = PCI_VARIANT_PCIX_266_MODE2; 4252167514Skmacy} 4253167514Skmacy 4254167514Skmacy/** 4255167514Skmacy * init_link_config - initialize a link's SW state 4256167514Skmacy * @lc: structure holding the link state 4257172096Skmacy * @caps: link capabilities 4258167514Skmacy * 4259167514Skmacy * Initializes the SW state maintained for each link, including the link's 4260167514Skmacy * capabilities and default speed/duplex/flow-control/autonegotiation 4261167514Skmacy * settings. 4262167514Skmacy */ 4263167514Skmacystatic void __devinit init_link_config(struct link_config *lc, 4264167514Skmacy unsigned int caps) 4265167514Skmacy{ 4266167514Skmacy lc->supported = caps; 4267167514Skmacy lc->requested_speed = lc->speed = SPEED_INVALID; 4268167514Skmacy lc->requested_duplex = lc->duplex = DUPLEX_INVALID; 4269167514Skmacy lc->requested_fc = lc->fc = PAUSE_RX | PAUSE_TX; 4270167514Skmacy if (lc->supported & SUPPORTED_Autoneg) { 4271167514Skmacy lc->advertising = lc->supported; 4272167514Skmacy lc->autoneg = AUTONEG_ENABLE; 4273167514Skmacy lc->requested_fc |= PAUSE_AUTONEG; 4274167514Skmacy } else { 4275167514Skmacy lc->advertising = 0; 4276167514Skmacy lc->autoneg = AUTONEG_DISABLE; 4277167514Skmacy } 4278167514Skmacy} 4279167514Skmacy 4280167514Skmacy/** 4281167514Skmacy * mc7_calc_size - calculate MC7 memory size 4282167514Skmacy * @cfg: the MC7 configuration 4283167514Skmacy * 4284167514Skmacy * Calculates the size of an MC7 memory in bytes from the value of its 4285167514Skmacy * configuration register. 4286167514Skmacy */ 4287167514Skmacystatic unsigned int __devinit mc7_calc_size(u32 cfg) 4288167514Skmacy{ 4289167514Skmacy unsigned int width = G_WIDTH(cfg); 4290167514Skmacy unsigned int banks = !!(cfg & F_BKS) + 1; 4291167514Skmacy unsigned int org = !!(cfg & F_ORG) + 1; 4292167514Skmacy unsigned int density = G_DEN(cfg); 4293167514Skmacy unsigned int MBs = ((256 << density) * banks) / (org << width); 4294167514Skmacy 4295167514Skmacy return MBs << 20; 4296167514Skmacy} 4297167514Skmacy 4298167514Skmacystatic void __devinit mc7_prep(adapter_t *adapter, struct mc7 *mc7, 4299167514Skmacy unsigned int base_addr, const char *name) 4300167514Skmacy{ 4301167514Skmacy u32 cfg; 4302167514Skmacy 4303167514Skmacy mc7->adapter = adapter; 4304167514Skmacy mc7->name = name; 4305167514Skmacy mc7->offset = base_addr - MC7_PMRX_BASE_ADDR; 4306167514Skmacy cfg = t3_read_reg(adapter, mc7->offset + A_MC7_CFG); 4307169978Skmacy mc7->size = G_DEN(cfg) == M_DEN ? 0 : mc7_calc_size(cfg); 4308167514Skmacy mc7->width = G_WIDTH(cfg); 4309167514Skmacy} 4310167514Skmacy 4311167514Skmacyvoid mac_prep(struct cmac *mac, adapter_t *adapter, int index) 4312167514Skmacy{ 4313197791Snp u16 devid; 4314197791Snp 4315167514Skmacy mac->adapter = adapter; 4316170654Skmacy mac->multiport = adapter->params.nports > 2; 4317170654Skmacy if (mac->multiport) { 4318170654Skmacy mac->ext_port = (unsigned char)index; 4319170654Skmacy mac->nucast = 8; 4320170654Skmacy } else 4321170654Skmacy mac->nucast = 1; 4322170654Skmacy 4323197791Snp /* Gen2 adapter uses VPD xauicfg[] to notify driver which MAC 4324197791Snp is connected to each port, its suppose to be using xgmac0 for both ports 4325197791Snp */ 4326197791Snp t3_os_pci_read_config_2(adapter, 0x2, &devid); 4327197791Snp 4328197791Snp if (mac->multiport || 4329197791Snp (!adapter->params.vpd.xauicfg[1] && (devid==0x37))) 4330197791Snp index = 0; 4331197791Snp 4332167514Skmacy mac->offset = (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR) * index; 4333167514Skmacy 4334167514Skmacy if (adapter->params.rev == 0 && uses_xaui(adapter)) { 4335167514Skmacy t3_write_reg(adapter, A_XGM_SERDES_CTRL + mac->offset, 4336167514Skmacy is_10G(adapter) ? 0x2901c04 : 0x2301c04); 4337167514Skmacy t3_set_reg_field(adapter, A_XGM_PORT_CFG + mac->offset, 4338167514Skmacy F_ENRGMII, 0); 4339167514Skmacy } 4340167514Skmacy} 4341167514Skmacy 4342172096Skmacy/** 4343172096Skmacy * early_hw_init - HW initialization done at card detection time 4344172096Skmacy * @adapter: the adapter 4345172096Skmacy * @ai: contains information about the adapter type and properties 4346172096Skmacy * 4347172096Skmacy * Perfoms the part of HW initialization that is done early on when the 4348172096Skmacy * driver first detecs the card. Most of the HW state is initialized 4349172096Skmacy * lazily later on when a port or an offload function are first used. 4350172096Skmacy */ 4351167514Skmacyvoid early_hw_init(adapter_t *adapter, const struct adapter_info *ai) 4352167514Skmacy{ 4353170654Skmacy u32 val = V_PORTSPEED(is_10G(adapter) || adapter->params.nports > 2 ? 4354170654Skmacy 3 : 2); 4355189643Sgnn u32 gpio_out = ai->gpio_out; 4356167514Skmacy 4357167514Skmacy mi1_init(adapter, ai); 4358167514Skmacy t3_write_reg(adapter, A_I2C_CFG, /* set for 80KHz */ 4359167514Skmacy V_I2C_CLKDIV(adapter->params.vpd.cclk / 80 - 1)); 4360167514Skmacy t3_write_reg(adapter, A_T3DBG_GPIO_EN, 4361189643Sgnn gpio_out | F_GPIO0_OEN | F_GPIO0_OUT_VAL); 4362169978Skmacy t3_write_reg(adapter, A_MC5_DB_SERVER_INDEX, 0); 4363176472Skmacy t3_write_reg(adapter, A_SG_OCO_BASE, V_BASE1(0xfff)); 4364170654Skmacy 4365167514Skmacy if (adapter->params.rev == 0 || !uses_xaui(adapter)) 4366167514Skmacy val |= F_ENRGMII; 4367167514Skmacy 4368167514Skmacy /* Enable MAC clocks so we can access the registers */ 4369167514Skmacy t3_write_reg(adapter, A_XGM_PORT_CFG, val); 4370167514Skmacy (void) t3_read_reg(adapter, A_XGM_PORT_CFG); 4371167514Skmacy 4372167514Skmacy val |= F_CLKDIVRESET_; 4373167514Skmacy t3_write_reg(adapter, A_XGM_PORT_CFG, val); 4374167514Skmacy (void) t3_read_reg(adapter, A_XGM_PORT_CFG); 4375167514Skmacy t3_write_reg(adapter, XGM_REG(A_XGM_PORT_CFG, 1), val); 4376167514Skmacy (void) t3_read_reg(adapter, A_XGM_PORT_CFG); 4377167514Skmacy} 4378167514Skmacy 4379172096Skmacy/** 4380172096Skmacy * t3_reset_adapter - reset the adapter 4381172096Skmacy * @adapter: the adapter 4382172096Skmacy * 4383172096Skmacy * Reset the adapter. 4384167514Skmacy */ 4385189643Sgnnint t3_reset_adapter(adapter_t *adapter) 4386167514Skmacy{ 4387189643Sgnn int i, save_and_restore_pcie = 4388167746Skmacy adapter->params.rev < T3_REV_B2 && is_pcie(adapter); 4389167746Skmacy uint16_t devid = 0; 4390167514Skmacy 4391167746Skmacy if (save_and_restore_pcie) 4392167514Skmacy t3_os_pci_save_state(adapter); 4393167514Skmacy t3_write_reg(adapter, A_PL_RST, F_CRSTWRM | F_CRSTWRMMODE); 4394167514Skmacy 4395167514Skmacy /* 4396167514Skmacy * Delay. Give Some time to device to reset fully. 4397167514Skmacy * XXX The delay time should be modified. 4398167514Skmacy */ 4399167514Skmacy for (i = 0; i < 10; i++) { 4400171471Skmacy msleep(50); 4401167514Skmacy t3_os_pci_read_config_2(adapter, 0x00, &devid); 4402167514Skmacy if (devid == 0x1425) 4403167514Skmacy break; 4404167514Skmacy } 4405167514Skmacy 4406167514Skmacy if (devid != 0x1425) 4407167514Skmacy return -1; 4408167514Skmacy 4409167746Skmacy if (save_and_restore_pcie) 4410167514Skmacy t3_os_pci_restore_state(adapter); 4411167514Skmacy return 0; 4412167514Skmacy} 4413167514Skmacy 4414181614Skmacystatic int init_parity(adapter_t *adap) 4415176472Skmacy{ 4416176472Skmacy int i, err, addr; 4417176472Skmacy 4418176472Skmacy if (t3_read_reg(adap, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) 4419176472Skmacy return -EBUSY; 4420176472Skmacy 4421176472Skmacy for (err = i = 0; !err && i < 16; i++) 4422176472Skmacy err = clear_sge_ctxt(adap, i, F_EGRESS); 4423176472Skmacy for (i = 0xfff0; !err && i <= 0xffff; i++) 4424176472Skmacy err = clear_sge_ctxt(adap, i, F_EGRESS); 4425176472Skmacy for (i = 0; !err && i < SGE_QSETS; i++) 4426176472Skmacy err = clear_sge_ctxt(adap, i, F_RESPONSEQ); 4427176472Skmacy if (err) 4428176472Skmacy return err; 4429176472Skmacy 4430176472Skmacy t3_write_reg(adap, A_CIM_IBQ_DBG_DATA, 0); 4431176472Skmacy for (i = 0; i < 4; i++) 4432176472Skmacy for (addr = 0; addr <= M_IBQDBGADDR; addr++) { 4433176472Skmacy t3_write_reg(adap, A_CIM_IBQ_DBG_CFG, F_IBQDBGEN | 4434176472Skmacy F_IBQDBGWR | V_IBQDBGQID(i) | 4435176472Skmacy V_IBQDBGADDR(addr)); 4436176472Skmacy err = t3_wait_op_done(adap, A_CIM_IBQ_DBG_CFG, 4437176472Skmacy F_IBQDBGBUSY, 0, 2, 1); 4438176472Skmacy if (err) 4439176472Skmacy return err; 4440176472Skmacy } 4441176472Skmacy return 0; 4442176472Skmacy} 4443176472Skmacy 4444172096Skmacy/** 4445172096Skmacy * t3_prep_adapter - prepare SW and HW for operation 4446172096Skmacy * @adapter: the adapter 4447172096Skmacy * @ai: contains information about the adapter type and properties 4448172096Skmacy * 4449172096Skmacy * Initialize adapter SW state for the various HW modules, set initial 4450172096Skmacy * values for some adapter tunables, take PHYs out of reset, and 4451172096Skmacy * initialize the MDIO interface. 4452167514Skmacy */ 4453167514Skmacyint __devinit t3_prep_adapter(adapter_t *adapter, 4454167514Skmacy const struct adapter_info *ai, int reset) 4455167514Skmacy{ 4456167514Skmacy int ret; 4457167514Skmacy unsigned int i, j = 0; 4458167514Skmacy 4459167514Skmacy get_pci_mode(adapter, &adapter->params.pci); 4460167514Skmacy 4461167514Skmacy adapter->params.info = ai; 4462170654Skmacy adapter->params.nports = ai->nports0 + ai->nports1; 4463201907Snp adapter->params.chan_map = (!!ai->nports0) | (!!ai->nports1 << 1); 4464167514Skmacy adapter->params.rev = t3_read_reg(adapter, A_PL_REV); 4465189643Sgnn 4466189643Sgnn /* 4467189643Sgnn * We used to only run the "adapter check task" once a second if 4468189643Sgnn * we had PHYs which didn't support interrupts (we would check 4469189643Sgnn * their link status once a second). Now we check other conditions 4470189643Sgnn * in that routine which would [potentially] impose a very high 4471189643Sgnn * interrupt load on the system. As such, we now always scan the 4472189643Sgnn * adapter state once a second ... 4473189643Sgnn */ 4474189643Sgnn adapter->params.linkpoll_period = 10; 4475189643Sgnn 4476171471Skmacy if (adapter->params.nports > 2) 4477171471Skmacy adapter->params.stats_update_period = VSC_STATS_ACCUM_SECS; 4478171471Skmacy else 4479171471Skmacy adapter->params.stats_update_period = is_10G(adapter) ? 4480171471Skmacy MAC_STATS_ACCUM_SECS : (MAC_STATS_ACCUM_SECS * 10); 4481167514Skmacy adapter->params.pci.vpd_cap_addr = 4482167514Skmacy t3_os_find_pci_capability(adapter, PCI_CAP_ID_VPD); 4483167514Skmacy 4484167514Skmacy ret = get_vpd_params(adapter, &adapter->params.vpd); 4485171471Skmacy if (ret < 0) 4486167514Skmacy return ret; 4487171471Skmacy 4488167514Skmacy if (reset && t3_reset_adapter(adapter)) 4489167514Skmacy return -1; 4490167514Skmacy 4491167514Skmacy if (adapter->params.vpd.mclk) { 4492167514Skmacy struct tp_params *p = &adapter->params.tp; 4493167514Skmacy 4494167514Skmacy mc7_prep(adapter, &adapter->pmrx, MC7_PMRX_BASE_ADDR, "PMRX"); 4495167514Skmacy mc7_prep(adapter, &adapter->pmtx, MC7_PMTX_BASE_ADDR, "PMTX"); 4496167514Skmacy mc7_prep(adapter, &adapter->cm, MC7_CM_BASE_ADDR, "CM"); 4497167514Skmacy 4498170654Skmacy p->nchan = adapter->params.chan_map == 3 ? 2 : 1; 4499167514Skmacy p->pmrx_size = t3_mc7_size(&adapter->pmrx); 4500167514Skmacy p->pmtx_size = t3_mc7_size(&adapter->pmtx); 4501167514Skmacy p->cm_size = t3_mc7_size(&adapter->cm); 4502167514Skmacy p->chan_rx_size = p->pmrx_size / 2; /* only 1 Rx channel */ 4503167514Skmacy p->chan_tx_size = p->pmtx_size / p->nchan; 4504167514Skmacy p->rx_pg_size = 64 * 1024; 4505167514Skmacy p->tx_pg_size = is_10G(adapter) ? 64 * 1024 : 16 * 1024; 4506167514Skmacy p->rx_num_pgs = pm_num_pages(p->chan_rx_size, p->rx_pg_size); 4507167514Skmacy p->tx_num_pgs = pm_num_pages(p->chan_tx_size, p->tx_pg_size); 4508167514Skmacy p->ntimer_qs = p->cm_size >= (128 << 20) || 4509167514Skmacy adapter->params.rev > 0 ? 12 : 6; 4510170654Skmacy p->tre = fls(adapter->params.vpd.cclk / (1000 / TP_TMR_RES)) - 4511170654Skmacy 1; 4512167746Skmacy p->dack_re = fls(adapter->params.vpd.cclk / 10) - 1; /* 100us */ 4513169978Skmacy } 4514170654Skmacy 4515169978Skmacy adapter->params.offload = t3_mc7_size(&adapter->pmrx) && 4516170654Skmacy t3_mc7_size(&adapter->pmtx) && 4517170654Skmacy t3_mc7_size(&adapter->cm); 4518167514Skmacy 4519205950Snp t3_sge_prep(adapter, &adapter->params.sge); 4520205950Snp 4521169978Skmacy if (is_offload(adapter)) { 4522167514Skmacy adapter->params.mc5.nservers = DEFAULT_NSERVERS; 4523189643Sgnn /* PR 6487. TOE and filtering are mutually exclusive */ 4524189643Sgnn adapter->params.mc5.nfilters = 0; 4525167514Skmacy adapter->params.mc5.nroutes = 0; 4526167514Skmacy t3_mc5_prep(adapter, &adapter->mc5, MC5_MODE_144_BIT); 4527167514Skmacy 4528167514Skmacy init_mtus(adapter->params.mtus); 4529167514Skmacy init_cong_ctrl(adapter->params.a_wnd, adapter->params.b_wnd); 4530167514Skmacy } 4531167514Skmacy 4532167514Skmacy early_hw_init(adapter, ai); 4533176472Skmacy ret = init_parity(adapter); 4534176472Skmacy if (ret) 4535176472Skmacy return ret; 4536167514Skmacy 4537171471Skmacy if (adapter->params.nports > 2 && 4538171471Skmacy (ret = t3_vsc7323_init(adapter, adapter->params.nports))) 4539171471Skmacy return ret; 4540171471Skmacy 4541167514Skmacy for_each_port(adapter, i) { 4542167514Skmacy u8 hw_addr[6]; 4543176472Skmacy const struct port_type_info *pti; 4544170654Skmacy struct port_info *p = adap2pinfo(adapter, i); 4545167514Skmacy 4546189643Sgnn for (;;) { 4547189643Sgnn unsigned port_type = adapter->params.vpd.port_type[j]; 4548189643Sgnn if (port_type) { 4549189643Sgnn if (port_type < ARRAY_SIZE(port_types)) { 4550189643Sgnn pti = &port_types[port_type]; 4551189643Sgnn break; 4552189643Sgnn } else 4553189643Sgnn return -EINVAL; 4554189643Sgnn } 4555189643Sgnn j++; 4556189643Sgnn if (j >= ARRAY_SIZE(adapter->params.vpd.port_type)) 4557189643Sgnn return -EINVAL; 4558189643Sgnn } 4559197791Snp ret = pti->phy_prep(p, ai->phy_base_addr + j, 4560176472Skmacy ai->mdio_ops); 4561176472Skmacy if (ret) 4562176472Skmacy return ret; 4563167514Skmacy mac_prep(&p->mac, adapter, j); 4564167514Skmacy ++j; 4565167514Skmacy 4566167514Skmacy /* 4567167514Skmacy * The VPD EEPROM stores the base Ethernet address for the 4568167514Skmacy * card. A port's address is derived from the base by adding 4569167514Skmacy * the port's index to the base's low octet. 4570167514Skmacy */ 4571167514Skmacy memcpy(hw_addr, adapter->params.vpd.eth_base, 5); 4572167514Skmacy hw_addr[5] = adapter->params.vpd.eth_base[5] + i; 4573167514Skmacy 4574167514Skmacy t3_os_set_hw_addr(adapter, i, hw_addr); 4575176472Skmacy init_link_config(&p->link_config, p->phy.caps); 4576167514Skmacy p->phy.ops->power_down(&p->phy, 1); 4577189643Sgnn 4578189643Sgnn /* 4579189643Sgnn * If the PHY doesn't support interrupts for link status 4580189643Sgnn * changes, schedule a scan of the adapter links at least 4581189643Sgnn * once a second. 4582189643Sgnn */ 4583189643Sgnn if (!(p->phy.caps & SUPPORTED_IRQ) && 4584189643Sgnn adapter->params.linkpoll_period > 10) 4585167514Skmacy adapter->params.linkpoll_period = 10; 4586167514Skmacy } 4587167514Skmacy 4588167514Skmacy return 0; 4589167514Skmacy} 4590167514Skmacy 4591181614Skmacy/** 4592181614Skmacy * t3_reinit_adapter - prepare HW for operation again 4593181614Skmacy * @adapter: the adapter 4594181614Skmacy * 4595181614Skmacy * Put HW in the same state as @t3_prep_adapter without any changes to 4596181614Skmacy * SW state. This is a cut down version of @t3_prep_adapter intended 4597181614Skmacy * to be used after events that wipe out HW state but preserve SW state, 4598181614Skmacy * e.g., EEH. The device must be reset before calling this. 4599181614Skmacy */ 4600181614Skmacyint t3_reinit_adapter(adapter_t *adap) 4601181614Skmacy{ 4602181614Skmacy unsigned int i; 4603189643Sgnn int ret, j = 0; 4604181614Skmacy 4605181614Skmacy early_hw_init(adap, adap->params.info); 4606181614Skmacy ret = init_parity(adap); 4607181614Skmacy if (ret) 4608181614Skmacy return ret; 4609181614Skmacy 4610181614Skmacy if (adap->params.nports > 2 && 4611181614Skmacy (ret = t3_vsc7323_init(adap, adap->params.nports))) 4612181614Skmacy return ret; 4613181614Skmacy 4614181614Skmacy for_each_port(adap, i) { 4615181614Skmacy const struct port_type_info *pti; 4616181614Skmacy struct port_info *p = adap2pinfo(adap, i); 4617181614Skmacy 4618189643Sgnn for (;;) { 4619189643Sgnn unsigned port_type = adap->params.vpd.port_type[j]; 4620189643Sgnn if (port_type) { 4621189643Sgnn if (port_type < ARRAY_SIZE(port_types)) { 4622189643Sgnn pti = &port_types[port_type]; 4623189643Sgnn break; 4624189643Sgnn } else 4625189643Sgnn return -EINVAL; 4626189643Sgnn } 4627189643Sgnn j++; 4628189643Sgnn if (j >= ARRAY_SIZE(adap->params.vpd.port_type)) 4629189643Sgnn return -EINVAL; 4630189643Sgnn } 4631197791Snp ret = pti->phy_prep(p, p->phy.addr, NULL); 4632181614Skmacy if (ret) 4633181614Skmacy return ret; 4634181614Skmacy p->phy.ops->power_down(&p->phy, 1); 4635181614Skmacy } 4636181614Skmacy return 0; 4637181614Skmacy} 4638181614Skmacy 4639167514Skmacyvoid t3_led_ready(adapter_t *adapter) 4640167514Skmacy{ 4641167514Skmacy t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL, 4642167514Skmacy F_GPIO0_OUT_VAL); 4643167514Skmacy} 4644167514Skmacy 4645167514Skmacyvoid t3_port_failover(adapter_t *adapter, int port) 4646167514Skmacy{ 4647167514Skmacy u32 val; 4648167514Skmacy 4649167514Skmacy val = port ? F_PORT1ACTIVE : F_PORT0ACTIVE; 4650167514Skmacy t3_set_reg_field(adapter, A_MPS_CFG, F_PORT0ACTIVE | F_PORT1ACTIVE, 4651167514Skmacy val); 4652167514Skmacy} 4653167514Skmacy 4654167514Skmacyvoid t3_failover_done(adapter_t *adapter, int port) 4655167514Skmacy{ 4656167514Skmacy t3_set_reg_field(adapter, A_MPS_CFG, F_PORT0ACTIVE | F_PORT1ACTIVE, 4657167514Skmacy F_PORT0ACTIVE | F_PORT1ACTIVE); 4658167514Skmacy} 4659167514Skmacy 4660167514Skmacyvoid t3_failover_clear(adapter_t *adapter) 4661167514Skmacy{ 4662167514Skmacy t3_set_reg_field(adapter, A_MPS_CFG, F_PORT0ACTIVE | F_PORT1ACTIVE, 4663167514Skmacy F_PORT0ACTIVE | F_PORT1ACTIVE); 4664167514Skmacy} 4665189643Sgnn 4666189643Sgnnstatic int t3_cim_hac_read(adapter_t *adapter, u32 addr, u32 *val) 4667189643Sgnn{ 4668189643Sgnn u32 v; 4669189643Sgnn 4670189643Sgnn t3_write_reg(adapter, A_CIM_HOST_ACC_CTRL, addr); 4671189643Sgnn if (t3_wait_op_done_val(adapter, A_CIM_HOST_ACC_CTRL, 4672189643Sgnn F_HOSTBUSY, 0, 10, 10, &v)) 4673189643Sgnn return -EIO; 4674189643Sgnn 4675189643Sgnn *val = t3_read_reg(adapter, A_CIM_HOST_ACC_DATA); 4676189643Sgnn 4677189643Sgnn return 0; 4678189643Sgnn} 4679189643Sgnn 4680189643Sgnnstatic int t3_cim_hac_write(adapter_t *adapter, u32 addr, u32 val) 4681189643Sgnn{ 4682189643Sgnn u32 v; 4683189643Sgnn 4684189643Sgnn t3_write_reg(adapter, A_CIM_HOST_ACC_DATA, val); 4685189643Sgnn 4686189643Sgnn addr |= F_HOSTWRITE; 4687189643Sgnn t3_write_reg(adapter, A_CIM_HOST_ACC_CTRL, addr); 4688189643Sgnn 4689189643Sgnn if (t3_wait_op_done_val(adapter, A_CIM_HOST_ACC_CTRL, 4690189643Sgnn F_HOSTBUSY, 0, 10, 5, &v)) 4691189643Sgnn return -EIO; 4692189643Sgnn return 0; 4693189643Sgnn} 4694189643Sgnn 4695189643Sgnnint t3_get_up_la(adapter_t *adapter, u32 *stopped, u32 *index, 4696189643Sgnn u32 *size, void *data) 4697189643Sgnn{ 4698189643Sgnn u32 v, *buf = data; 4699189643Sgnn int i, cnt, ret; 4700189643Sgnn 4701189643Sgnn if (*size < LA_ENTRIES * 4) 4702189643Sgnn return -EINVAL; 4703189643Sgnn 4704189643Sgnn ret = t3_cim_hac_read(adapter, LA_CTRL, &v); 4705189643Sgnn if (ret) 4706189643Sgnn goto out; 4707189643Sgnn 4708189643Sgnn *stopped = !(v & 1); 4709189643Sgnn 4710189643Sgnn /* Freeze LA */ 4711189643Sgnn if (!*stopped) { 4712189643Sgnn ret = t3_cim_hac_write(adapter, LA_CTRL, 0); 4713189643Sgnn if (ret) 4714189643Sgnn goto out; 4715189643Sgnn } 4716189643Sgnn 4717189643Sgnn for (i = 0; i < LA_ENTRIES; i++) { 4718189643Sgnn v = (i << 2) | (1 << 1); 4719189643Sgnn ret = t3_cim_hac_write(adapter, LA_CTRL, v); 4720189643Sgnn if (ret) 4721189643Sgnn goto out; 4722189643Sgnn 4723189643Sgnn ret = t3_cim_hac_read(adapter, LA_CTRL, &v); 4724189643Sgnn if (ret) 4725189643Sgnn goto out; 4726189643Sgnn 4727189643Sgnn cnt = 20; 4728189643Sgnn while ((v & (1 << 1)) && cnt) { 4729189643Sgnn udelay(5); 4730189643Sgnn --cnt; 4731189643Sgnn ret = t3_cim_hac_read(adapter, LA_CTRL, &v); 4732189643Sgnn if (ret) 4733189643Sgnn goto out; 4734189643Sgnn } 4735189643Sgnn 4736189643Sgnn if (v & (1 << 1)) 4737189643Sgnn return -EIO; 4738189643Sgnn 4739189643Sgnn ret = t3_cim_hac_read(adapter, LA_DATA, &v); 4740189643Sgnn if (ret) 4741189643Sgnn goto out; 4742189643Sgnn 4743189643Sgnn *buf++ = v; 4744189643Sgnn } 4745189643Sgnn 4746189643Sgnn ret = t3_cim_hac_read(adapter, LA_CTRL, &v); 4747189643Sgnn if (ret) 4748189643Sgnn goto out; 4749189643Sgnn 4750189643Sgnn *index = (v >> 16) + 4; 4751189643Sgnn *size = LA_ENTRIES * 4; 4752189643Sgnnout: 4753189643Sgnn /* Unfreeze LA */ 4754189643Sgnn t3_cim_hac_write(adapter, LA_CTRL, 1); 4755189643Sgnn return ret; 4756189643Sgnn} 4757189643Sgnn 4758189643Sgnnint t3_get_up_ioqs(adapter_t *adapter, u32 *size, void *data) 4759189643Sgnn{ 4760189643Sgnn u32 v, *buf = data; 4761189643Sgnn int i, j, ret; 4762189643Sgnn 4763189643Sgnn if (*size < IOQ_ENTRIES * sizeof(struct t3_ioq_entry)) 4764189643Sgnn return -EINVAL; 4765189643Sgnn 4766189643Sgnn for (i = 0; i < 4; i++) { 4767189643Sgnn ret = t3_cim_hac_read(adapter, (4 * i), &v); 4768189643Sgnn if (ret) 4769189643Sgnn goto out; 4770189643Sgnn 4771189643Sgnn *buf++ = v; 4772189643Sgnn } 4773189643Sgnn 4774189643Sgnn for (i = 0; i < IOQ_ENTRIES; i++) { 4775189643Sgnn u32 base_addr = 0x10 * (i + 1); 4776189643Sgnn 4777189643Sgnn for (j = 0; j < 4; j++) { 4778189643Sgnn ret = t3_cim_hac_read(adapter, base_addr + 4 * j, &v); 4779189643Sgnn if (ret) 4780189643Sgnn goto out; 4781189643Sgnn 4782189643Sgnn *buf++ = v; 4783189643Sgnn } 4784189643Sgnn } 4785189643Sgnn 4786189643Sgnn *size = IOQ_ENTRIES * sizeof(struct t3_ioq_entry); 4787189643Sgnn 4788189643Sgnnout: 4789189643Sgnn return ret; 4790189643Sgnn} 4791189643Sgnn 4792