cxgb_t3_hw.c revision 181614
1167514Skmacy/************************************************************************** 2167514Skmacy 3167514SkmacyCopyright (c) 2007, 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: head/sys/dev/cxgb/common/cxgb_t3_hw.c 181614 2008-08-11 23:01:34Z kmacy $"); 32167514Skmacy 33170654Skmacy 34170076Skmacy#ifdef CONFIG_DEFINED 35170076Skmacy#include <cxgb_include.h> 36170076Skmacy#else 37170076Skmacy#include <dev/cxgb/cxgb_include.h> 38170076Skmacy#endif 39167514Skmacy 40171471Skmacy#undef msleep 41171471Skmacy#define msleep t3_os_sleep 42170654Skmacy 43167514Skmacy/** 44167514Skmacy * t3_wait_op_done_val - wait until an operation is completed 45167514Skmacy * @adapter: the adapter performing the operation 46167514Skmacy * @reg: the register to check for completion 47167514Skmacy * @mask: a single-bit field within @reg that indicates completion 48167514Skmacy * @polarity: the value of the field when the operation is completed 49167514Skmacy * @attempts: number of check iterations 50167514Skmacy * @delay: delay in usecs between iterations 51167514Skmacy * @valp: where to store the value of the register at completion time 52167514Skmacy * 53167514Skmacy * Wait until an operation is completed by checking a bit in a register 54167514Skmacy * up to @attempts times. If @valp is not NULL the value of the register 55167514Skmacy * at the time it indicated completion is stored there. Returns 0 if the 56167514Skmacy * operation completes and -EAGAIN otherwise. 57167514Skmacy */ 58167514Skmacyint t3_wait_op_done_val(adapter_t *adapter, int reg, u32 mask, int polarity, 59167514Skmacy int attempts, int delay, u32 *valp) 60167514Skmacy{ 61167514Skmacy while (1) { 62167514Skmacy u32 val = t3_read_reg(adapter, reg); 63167514Skmacy 64167514Skmacy if (!!(val & mask) == polarity) { 65167514Skmacy if (valp) 66167514Skmacy *valp = val; 67167514Skmacy return 0; 68167514Skmacy } 69167514Skmacy if (--attempts == 0) 70167514Skmacy return -EAGAIN; 71167514Skmacy if (delay) 72167514Skmacy udelay(delay); 73167514Skmacy } 74167514Skmacy} 75167514Skmacy 76167514Skmacy/** 77167514Skmacy * t3_write_regs - write a bunch of registers 78167514Skmacy * @adapter: the adapter to program 79167514Skmacy * @p: an array of register address/register value pairs 80167514Skmacy * @n: the number of address/value pairs 81167514Skmacy * @offset: register address offset 82167514Skmacy * 83167514Skmacy * Takes an array of register address/register value pairs and writes each 84167514Skmacy * value to the corresponding register. Register addresses are adjusted 85167514Skmacy * by the supplied offset. 86167514Skmacy */ 87167514Skmacyvoid t3_write_regs(adapter_t *adapter, const struct addr_val_pair *p, int n, 88167514Skmacy unsigned int offset) 89167514Skmacy{ 90167514Skmacy while (n--) { 91167514Skmacy t3_write_reg(adapter, p->reg_addr + offset, p->val); 92167514Skmacy p++; 93167514Skmacy } 94167514Skmacy} 95167514Skmacy 96167514Skmacy/** 97167514Skmacy * t3_set_reg_field - set a register field to a value 98167514Skmacy * @adapter: the adapter to program 99167514Skmacy * @addr: the register address 100167514Skmacy * @mask: specifies the portion of the register to modify 101167514Skmacy * @val: the new value for the register field 102167514Skmacy * 103167514Skmacy * Sets a register field specified by the supplied mask to the 104167514Skmacy * given value. 105167514Skmacy */ 106167514Skmacyvoid t3_set_reg_field(adapter_t *adapter, unsigned int addr, u32 mask, u32 val) 107167514Skmacy{ 108167514Skmacy u32 v = t3_read_reg(adapter, addr) & ~mask; 109167514Skmacy 110167514Skmacy t3_write_reg(adapter, addr, v | val); 111167514Skmacy (void) t3_read_reg(adapter, addr); /* flush */ 112167514Skmacy} 113167514Skmacy 114167514Skmacy/** 115167514Skmacy * t3_read_indirect - read indirectly addressed registers 116167514Skmacy * @adap: the adapter 117167514Skmacy * @addr_reg: register holding the indirect address 118167514Skmacy * @data_reg: register holding the value of the indirect register 119167514Skmacy * @vals: where the read register values are stored 120167514Skmacy * @start_idx: index of first indirect register to read 121167514Skmacy * @nregs: how many indirect registers to read 122167514Skmacy * 123167514Skmacy * Reads registers that are accessed indirectly through an address/data 124167514Skmacy * register pair. 125167514Skmacy */ 126170654Skmacystatic void t3_read_indirect(adapter_t *adap, unsigned int addr_reg, 127167514Skmacy unsigned int data_reg, u32 *vals, unsigned int nregs, 128167514Skmacy unsigned int start_idx) 129167514Skmacy{ 130167514Skmacy while (nregs--) { 131167514Skmacy t3_write_reg(adap, addr_reg, start_idx); 132167514Skmacy *vals++ = t3_read_reg(adap, data_reg); 133167514Skmacy start_idx++; 134167514Skmacy } 135167514Skmacy} 136167514Skmacy 137167514Skmacy/** 138167514Skmacy * t3_mc7_bd_read - read from MC7 through backdoor accesses 139167514Skmacy * @mc7: identifies MC7 to read from 140167514Skmacy * @start: index of first 64-bit word to read 141167514Skmacy * @n: number of 64-bit words to read 142167514Skmacy * @buf: where to store the read result 143167514Skmacy * 144167514Skmacy * Read n 64-bit words from MC7 starting at word start, using backdoor 145167514Skmacy * accesses. 146167514Skmacy */ 147167514Skmacyint t3_mc7_bd_read(struct mc7 *mc7, unsigned int start, unsigned int n, 148167514Skmacy u64 *buf) 149167514Skmacy{ 150167514Skmacy static int shift[] = { 0, 0, 16, 24 }; 151167514Skmacy static int step[] = { 0, 32, 16, 8 }; 152167514Skmacy 153167514Skmacy unsigned int size64 = mc7->size / 8; /* # of 64-bit words */ 154167514Skmacy adapter_t *adap = mc7->adapter; 155167514Skmacy 156167514Skmacy if (start >= size64 || start + n > size64) 157167514Skmacy return -EINVAL; 158167514Skmacy 159167514Skmacy start *= (8 << mc7->width); 160167514Skmacy while (n--) { 161167514Skmacy int i; 162167514Skmacy u64 val64 = 0; 163167514Skmacy 164167514Skmacy for (i = (1 << mc7->width) - 1; i >= 0; --i) { 165167514Skmacy int attempts = 10; 166167514Skmacy u32 val; 167167514Skmacy 168167514Skmacy t3_write_reg(adap, mc7->offset + A_MC7_BD_ADDR, 169167514Skmacy start); 170167514Skmacy t3_write_reg(adap, mc7->offset + A_MC7_BD_OP, 0); 171167514Skmacy val = t3_read_reg(adap, mc7->offset + A_MC7_BD_OP); 172167514Skmacy while ((val & F_BUSY) && attempts--) 173167514Skmacy val = t3_read_reg(adap, 174167514Skmacy mc7->offset + A_MC7_BD_OP); 175167514Skmacy if (val & F_BUSY) 176167514Skmacy return -EIO; 177167514Skmacy 178167514Skmacy val = t3_read_reg(adap, mc7->offset + A_MC7_BD_DATA1); 179167514Skmacy if (mc7->width == 0) { 180167514Skmacy val64 = t3_read_reg(adap, 181167514Skmacy mc7->offset + A_MC7_BD_DATA0); 182167514Skmacy val64 |= (u64)val << 32; 183167514Skmacy } else { 184167514Skmacy if (mc7->width > 1) 185167514Skmacy val >>= shift[mc7->width]; 186167514Skmacy val64 |= (u64)val << (step[mc7->width] * i); 187167514Skmacy } 188167514Skmacy start += 8; 189167514Skmacy } 190167514Skmacy *buf++ = val64; 191167514Skmacy } 192167514Skmacy return 0; 193167514Skmacy} 194167514Skmacy 195167514Skmacy/* 196167514Skmacy * Initialize MI1. 197167514Skmacy */ 198167514Skmacystatic void mi1_init(adapter_t *adap, const struct adapter_info *ai) 199167514Skmacy{ 200167514Skmacy u32 clkdiv = adap->params.vpd.cclk / (2 * adap->params.vpd.mdc) - 1; 201167514Skmacy u32 val = F_PREEN | V_MDIINV(ai->mdiinv) | V_MDIEN(ai->mdien) | 202167514Skmacy V_CLKDIV(clkdiv); 203167514Skmacy 204167514Skmacy if (!(ai->caps & SUPPORTED_10000baseT_Full)) 205167514Skmacy val |= V_ST(1); 206167514Skmacy t3_write_reg(adap, A_MI1_CFG, val); 207167514Skmacy} 208167514Skmacy 209170654Skmacy#define MDIO_ATTEMPTS 20 210167514Skmacy 211167514Skmacy/* 212167514Skmacy * MI1 read/write operations for direct-addressed PHYs. 213167514Skmacy */ 214167514Skmacystatic int mi1_read(adapter_t *adapter, int phy_addr, int mmd_addr, 215167514Skmacy int reg_addr, unsigned int *valp) 216167514Skmacy{ 217167514Skmacy int ret; 218167514Skmacy u32 addr = V_REGADDR(reg_addr) | V_PHYADDR(phy_addr); 219167514Skmacy 220167514Skmacy if (mmd_addr) 221167514Skmacy return -EINVAL; 222167514Skmacy 223167514Skmacy MDIO_LOCK(adapter); 224167514Skmacy t3_write_reg(adapter, A_MI1_ADDR, addr); 225167514Skmacy t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(2)); 226170654Skmacy ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 10); 227167514Skmacy if (!ret) 228167514Skmacy *valp = t3_read_reg(adapter, A_MI1_DATA); 229167514Skmacy MDIO_UNLOCK(adapter); 230167514Skmacy return ret; 231167514Skmacy} 232167514Skmacy 233167514Skmacystatic int mi1_write(adapter_t *adapter, int phy_addr, int mmd_addr, 234167514Skmacy int reg_addr, unsigned int val) 235167514Skmacy{ 236167514Skmacy int ret; 237167514Skmacy u32 addr = V_REGADDR(reg_addr) | V_PHYADDR(phy_addr); 238167514Skmacy 239167514Skmacy if (mmd_addr) 240167514Skmacy return -EINVAL; 241167514Skmacy 242167514Skmacy MDIO_LOCK(adapter); 243167514Skmacy t3_write_reg(adapter, A_MI1_ADDR, addr); 244167514Skmacy t3_write_reg(adapter, A_MI1_DATA, val); 245167514Skmacy t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(1)); 246170654Skmacy ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 10); 247167514Skmacy MDIO_UNLOCK(adapter); 248167514Skmacy return ret; 249167514Skmacy} 250167514Skmacy 251167514Skmacystatic struct mdio_ops mi1_mdio_ops = { 252167514Skmacy mi1_read, 253167514Skmacy mi1_write 254167514Skmacy}; 255167514Skmacy 256167514Skmacy/* 257167514Skmacy * MI1 read/write operations for indirect-addressed PHYs. 258167514Skmacy */ 259167514Skmacystatic int mi1_ext_read(adapter_t *adapter, int phy_addr, int mmd_addr, 260167514Skmacy int reg_addr, unsigned int *valp) 261167514Skmacy{ 262167514Skmacy int ret; 263167514Skmacy u32 addr = V_REGADDR(mmd_addr) | V_PHYADDR(phy_addr); 264167514Skmacy 265167514Skmacy MDIO_LOCK(adapter); 266167514Skmacy t3_write_reg(adapter, A_MI1_ADDR, addr); 267167514Skmacy t3_write_reg(adapter, A_MI1_DATA, reg_addr); 268167514Skmacy t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(0)); 269170654Skmacy ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 10); 270167514Skmacy if (!ret) { 271167514Skmacy t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(3)); 272167514Skmacy ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, 273170654Skmacy MDIO_ATTEMPTS, 10); 274167514Skmacy if (!ret) 275167514Skmacy *valp = t3_read_reg(adapter, A_MI1_DATA); 276167514Skmacy } 277167514Skmacy MDIO_UNLOCK(adapter); 278167514Skmacy return ret; 279167514Skmacy} 280167514Skmacy 281167514Skmacystatic int mi1_ext_write(adapter_t *adapter, int phy_addr, int mmd_addr, 282167514Skmacy int reg_addr, unsigned int val) 283167514Skmacy{ 284167514Skmacy int ret; 285167514Skmacy u32 addr = V_REGADDR(mmd_addr) | V_PHYADDR(phy_addr); 286167514Skmacy 287167514Skmacy MDIO_LOCK(adapter); 288167514Skmacy t3_write_reg(adapter, A_MI1_ADDR, addr); 289167514Skmacy t3_write_reg(adapter, A_MI1_DATA, reg_addr); 290167514Skmacy t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(0)); 291170654Skmacy ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 10); 292167514Skmacy if (!ret) { 293167514Skmacy t3_write_reg(adapter, A_MI1_DATA, val); 294167514Skmacy t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(1)); 295167514Skmacy ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, 296170654Skmacy MDIO_ATTEMPTS, 10); 297167514Skmacy } 298167514Skmacy MDIO_UNLOCK(adapter); 299167514Skmacy return ret; 300167514Skmacy} 301167514Skmacy 302167514Skmacystatic struct mdio_ops mi1_mdio_ext_ops = { 303167514Skmacy mi1_ext_read, 304167514Skmacy mi1_ext_write 305167514Skmacy}; 306167514Skmacy 307167514Skmacy/** 308167514Skmacy * t3_mdio_change_bits - modify the value of a PHY register 309167514Skmacy * @phy: the PHY to operate on 310167514Skmacy * @mmd: the device address 311167514Skmacy * @reg: the register address 312167514Skmacy * @clear: what part of the register value to mask off 313167514Skmacy * @set: what part of the register value to set 314167514Skmacy * 315167514Skmacy * Changes the value of a PHY register by applying a mask to its current 316167514Skmacy * value and ORing the result with a new value. 317167514Skmacy */ 318167514Skmacyint t3_mdio_change_bits(struct cphy *phy, int mmd, int reg, unsigned int clear, 319167514Skmacy unsigned int set) 320167514Skmacy{ 321167514Skmacy int ret; 322167514Skmacy unsigned int val; 323167514Skmacy 324167514Skmacy ret = mdio_read(phy, mmd, reg, &val); 325167514Skmacy if (!ret) { 326167514Skmacy val &= ~clear; 327167514Skmacy ret = mdio_write(phy, mmd, reg, val | set); 328167514Skmacy } 329167514Skmacy return ret; 330167514Skmacy} 331167514Skmacy 332167514Skmacy/** 333167514Skmacy * t3_phy_reset - reset a PHY block 334167514Skmacy * @phy: the PHY to operate on 335167514Skmacy * @mmd: the device address of the PHY block to reset 336167514Skmacy * @wait: how long to wait for the reset to complete in 1ms increments 337167514Skmacy * 338167514Skmacy * Resets a PHY block and optionally waits for the reset to complete. 339167514Skmacy * @mmd should be 0 for 10/100/1000 PHYs and the device address to reset 340167514Skmacy * for 10G PHYs. 341167514Skmacy */ 342167514Skmacyint t3_phy_reset(struct cphy *phy, int mmd, int wait) 343167514Skmacy{ 344167514Skmacy int err; 345167514Skmacy unsigned int ctl; 346167514Skmacy 347167514Skmacy err = t3_mdio_change_bits(phy, mmd, MII_BMCR, BMCR_PDOWN, BMCR_RESET); 348167514Skmacy if (err || !wait) 349167514Skmacy return err; 350167514Skmacy 351167514Skmacy do { 352167514Skmacy err = mdio_read(phy, mmd, MII_BMCR, &ctl); 353167514Skmacy if (err) 354167514Skmacy return err; 355167514Skmacy ctl &= BMCR_RESET; 356167514Skmacy if (ctl) 357171471Skmacy msleep(1); 358167514Skmacy } while (ctl && --wait); 359167514Skmacy 360167514Skmacy return ctl ? -1 : 0; 361167514Skmacy} 362167514Skmacy 363167514Skmacy/** 364167514Skmacy * t3_phy_advertise - set the PHY advertisement registers for autoneg 365167514Skmacy * @phy: the PHY to operate on 366167514Skmacy * @advert: bitmap of capabilities the PHY should advertise 367167514Skmacy * 368167514Skmacy * Sets a 10/100/1000 PHY's advertisement registers to advertise the 369167514Skmacy * requested capabilities. 370167514Skmacy */ 371167514Skmacyint t3_phy_advertise(struct cphy *phy, unsigned int advert) 372167514Skmacy{ 373167514Skmacy int err; 374167514Skmacy unsigned int val = 0; 375167514Skmacy 376167514Skmacy err = mdio_read(phy, 0, MII_CTRL1000, &val); 377167514Skmacy if (err) 378167514Skmacy return err; 379167514Skmacy 380167514Skmacy val &= ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL); 381167514Skmacy if (advert & ADVERTISED_1000baseT_Half) 382167514Skmacy val |= ADVERTISE_1000HALF; 383167514Skmacy if (advert & ADVERTISED_1000baseT_Full) 384167514Skmacy val |= ADVERTISE_1000FULL; 385167514Skmacy 386167514Skmacy err = mdio_write(phy, 0, MII_CTRL1000, val); 387167514Skmacy if (err) 388167514Skmacy return err; 389167514Skmacy 390167514Skmacy val = 1; 391167514Skmacy if (advert & ADVERTISED_10baseT_Half) 392167514Skmacy val |= ADVERTISE_10HALF; 393167514Skmacy if (advert & ADVERTISED_10baseT_Full) 394167514Skmacy val |= ADVERTISE_10FULL; 395167514Skmacy if (advert & ADVERTISED_100baseT_Half) 396167514Skmacy val |= ADVERTISE_100HALF; 397167514Skmacy if (advert & ADVERTISED_100baseT_Full) 398167514Skmacy val |= ADVERTISE_100FULL; 399167514Skmacy if (advert & ADVERTISED_Pause) 400167514Skmacy val |= ADVERTISE_PAUSE_CAP; 401167514Skmacy if (advert & ADVERTISED_Asym_Pause) 402167514Skmacy val |= ADVERTISE_PAUSE_ASYM; 403167514Skmacy return mdio_write(phy, 0, MII_ADVERTISE, val); 404167514Skmacy} 405167514Skmacy 406167514Skmacy/** 407176472Skmacy * t3_phy_advertise_fiber - set fiber PHY advertisement register 408176472Skmacy * @phy: the PHY to operate on 409176472Skmacy * @advert: bitmap of capabilities the PHY should advertise 410176472Skmacy * 411176472Skmacy * Sets a fiber PHY's advertisement register to advertise the 412176472Skmacy * requested capabilities. 413176472Skmacy */ 414176472Skmacyint t3_phy_advertise_fiber(struct cphy *phy, unsigned int advert) 415176472Skmacy{ 416176472Skmacy unsigned int val = 0; 417176472Skmacy 418176472Skmacy if (advert & ADVERTISED_1000baseT_Half) 419176472Skmacy val |= ADVERTISE_1000XHALF; 420176472Skmacy if (advert & ADVERTISED_1000baseT_Full) 421176472Skmacy val |= ADVERTISE_1000XFULL; 422176472Skmacy if (advert & ADVERTISED_Pause) 423176472Skmacy val |= ADVERTISE_1000XPAUSE; 424176472Skmacy if (advert & ADVERTISED_Asym_Pause) 425176472Skmacy val |= ADVERTISE_1000XPSE_ASYM; 426176472Skmacy return mdio_write(phy, 0, MII_ADVERTISE, val); 427176472Skmacy} 428176472Skmacy 429176472Skmacy/** 430167514Skmacy * t3_set_phy_speed_duplex - force PHY speed and duplex 431167514Skmacy * @phy: the PHY to operate on 432167514Skmacy * @speed: requested PHY speed 433167514Skmacy * @duplex: requested PHY duplex 434167514Skmacy * 435167514Skmacy * Force a 10/100/1000 PHY's speed and duplex. This also disables 436167514Skmacy * auto-negotiation except for GigE, where auto-negotiation is mandatory. 437167514Skmacy */ 438167514Skmacyint t3_set_phy_speed_duplex(struct cphy *phy, int speed, int duplex) 439167514Skmacy{ 440167514Skmacy int err; 441167514Skmacy unsigned int ctl; 442167514Skmacy 443167514Skmacy err = mdio_read(phy, 0, MII_BMCR, &ctl); 444167514Skmacy if (err) 445167514Skmacy return err; 446167514Skmacy 447167514Skmacy if (speed >= 0) { 448167514Skmacy ctl &= ~(BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE); 449167514Skmacy if (speed == SPEED_100) 450167514Skmacy ctl |= BMCR_SPEED100; 451167514Skmacy else if (speed == SPEED_1000) 452167514Skmacy ctl |= BMCR_SPEED1000; 453167514Skmacy } 454167514Skmacy if (duplex >= 0) { 455167514Skmacy ctl &= ~(BMCR_FULLDPLX | BMCR_ANENABLE); 456167514Skmacy if (duplex == DUPLEX_FULL) 457167514Skmacy ctl |= BMCR_FULLDPLX; 458167514Skmacy } 459167514Skmacy if (ctl & BMCR_SPEED1000) /* auto-negotiation required for GigE */ 460167514Skmacy ctl |= BMCR_ANENABLE; 461167514Skmacy return mdio_write(phy, 0, MII_BMCR, ctl); 462167514Skmacy} 463167514Skmacy 464180583Skmacyint t3_phy_lasi_intr_enable(struct cphy *phy) 465180583Skmacy{ 466180583Skmacy return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 1); 467180583Skmacy} 468180583Skmacy 469180583Skmacyint t3_phy_lasi_intr_disable(struct cphy *phy) 470180583Skmacy{ 471180583Skmacy return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 0); 472180583Skmacy} 473180583Skmacy 474180583Skmacyint t3_phy_lasi_intr_clear(struct cphy *phy) 475180583Skmacy{ 476180583Skmacy u32 val; 477180583Skmacy 478180583Skmacy return mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &val); 479180583Skmacy} 480180583Skmacy 481180583Skmacyint t3_phy_lasi_intr_handler(struct cphy *phy) 482180583Skmacy{ 483180583Skmacy unsigned int status; 484180583Skmacy int err = mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &status); 485180583Skmacy 486180583Skmacy if (err) 487180583Skmacy return err; 488180583Skmacy return (status & 1) ? cphy_cause_link_change : 0; 489180583Skmacy} 490180583Skmacy 491167514Skmacystatic struct adapter_info t3_adap_info[] = { 492170654Skmacy { 1, 1, 0, 0, 0, 493167514Skmacy F_GPIO2_OEN | F_GPIO4_OEN | 494180583Skmacy F_GPIO2_OUT_VAL | F_GPIO4_OUT_VAL, { S_GPIO3, S_GPIO5 }, 0, 495167514Skmacy &mi1_mdio_ops, "Chelsio PE9000" }, 496170654Skmacy { 1, 1, 0, 0, 0, 497167514Skmacy F_GPIO2_OEN | F_GPIO4_OEN | 498180583Skmacy F_GPIO2_OUT_VAL | F_GPIO4_OUT_VAL, { S_GPIO3, S_GPIO5 }, 0, 499167514Skmacy &mi1_mdio_ops, "Chelsio T302" }, 500170654Skmacy { 1, 0, 0, 0, 0, 501167514Skmacy F_GPIO1_OEN | F_GPIO6_OEN | F_GPIO7_OEN | F_GPIO10_OEN | 502176472Skmacy F_GPIO11_OEN | F_GPIO1_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL, 503180583Skmacy { 0 }, SUPPORTED_10000baseT_Full | SUPPORTED_AUI, 504167514Skmacy &mi1_mdio_ext_ops, "Chelsio T310" }, 505170654Skmacy { 1, 1, 0, 0, 0, 506167514Skmacy F_GPIO1_OEN | F_GPIO2_OEN | F_GPIO4_OEN | F_GPIO5_OEN | F_GPIO6_OEN | 507167514Skmacy F_GPIO7_OEN | F_GPIO10_OEN | F_GPIO11_OEN | F_GPIO1_OUT_VAL | 508180583Skmacy F_GPIO5_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL, 509180583Skmacy { S_GPIO9, S_GPIO3 }, SUPPORTED_10000baseT_Full | SUPPORTED_AUI, 510167514Skmacy &mi1_mdio_ext_ops, "Chelsio T320" }, 511170654Skmacy { 4, 0, 0, 0, 0, 512170654Skmacy F_GPIO5_OEN | F_GPIO6_OEN | F_GPIO7_OEN | F_GPIO5_OUT_VAL | 513170654Skmacy F_GPIO6_OUT_VAL | F_GPIO7_OUT_VAL, 514180583Skmacy { S_GPIO1, S_GPIO2, S_GPIO3, S_GPIO4 }, SUPPORTED_AUI, 515170654Skmacy &mi1_mdio_ops, "Chelsio T304" }, 516167514Skmacy}; 517167514Skmacy 518167514Skmacy/* 519167514Skmacy * Return the adapter_info structure with a given index. Out-of-range indices 520167514Skmacy * return NULL. 521167514Skmacy */ 522167514Skmacyconst struct adapter_info *t3_get_adapter_info(unsigned int id) 523167514Skmacy{ 524167514Skmacy return id < ARRAY_SIZE(t3_adap_info) ? &t3_adap_info[id] : NULL; 525167514Skmacy} 526167514Skmacy 527181614Skmacystruct port_type_info { 528181614Skmacy int (*phy_prep)(struct cphy *phy, adapter_t *adapter, int phy_addr, 529181614Skmacy const struct mdio_ops *ops); 530181614Skmacy}; 531181614Skmacy 532167514Skmacystatic struct port_type_info port_types[] = { 533171471Skmacy { NULL }, 534176472Skmacy { t3_ael1002_phy_prep }, 535176472Skmacy { t3_vsc8211_phy_prep }, 536176472Skmacy { t3_mv88e1xxx_phy_prep }, 537176472Skmacy { t3_xaui_direct_phy_prep }, 538180583Skmacy { t3_ael2005_phy_prep }, 539176472Skmacy { t3_qt2045_phy_prep }, 540176472Skmacy { t3_ael1006_phy_prep }, 541180583Skmacy { t3_tn1010_phy_prep }, 542167514Skmacy}; 543167514Skmacy 544167514Skmacy#define VPD_ENTRY(name, len) \ 545176472Skmacy u8 name##_kword[2]; u8 name##_len; u8 name##_data[len] 546167514Skmacy 547167514Skmacy/* 548167514Skmacy * Partial EEPROM Vital Product Data structure. Includes only the ID and 549167514Skmacy * VPD-R sections. 550167514Skmacy */ 551167514Skmacystruct t3_vpd { 552167514Skmacy u8 id_tag; 553167514Skmacy u8 id_len[2]; 554167514Skmacy u8 id_data[16]; 555167514Skmacy u8 vpdr_tag; 556167514Skmacy u8 vpdr_len[2]; 557167514Skmacy VPD_ENTRY(pn, 16); /* part number */ 558167514Skmacy VPD_ENTRY(ec, 16); /* EC level */ 559172096Skmacy VPD_ENTRY(sn, SERNUM_LEN); /* serial number */ 560167514Skmacy VPD_ENTRY(na, 12); /* MAC address base */ 561167514Skmacy VPD_ENTRY(cclk, 6); /* core clock */ 562167514Skmacy VPD_ENTRY(mclk, 6); /* mem clock */ 563167514Skmacy VPD_ENTRY(uclk, 6); /* uP clk */ 564167514Skmacy VPD_ENTRY(mdc, 6); /* MDIO clk */ 565167514Skmacy VPD_ENTRY(mt, 2); /* mem timing */ 566167514Skmacy VPD_ENTRY(xaui0cfg, 6); /* XAUI0 config */ 567167514Skmacy VPD_ENTRY(xaui1cfg, 6); /* XAUI1 config */ 568167514Skmacy VPD_ENTRY(port0, 2); /* PHY0 complex */ 569167514Skmacy VPD_ENTRY(port1, 2); /* PHY1 complex */ 570167514Skmacy VPD_ENTRY(port2, 2); /* PHY2 complex */ 571167514Skmacy VPD_ENTRY(port3, 2); /* PHY3 complex */ 572167514Skmacy VPD_ENTRY(rv, 1); /* csum */ 573167514Skmacy u32 pad; /* for multiple-of-4 sizing and alignment */ 574167514Skmacy}; 575167514Skmacy 576181614Skmacy#define EEPROM_MAX_POLL 40 577167514Skmacy#define EEPROM_STAT_ADDR 0x4000 578167514Skmacy#define VPD_BASE 0xc00 579167514Skmacy 580167514Skmacy/** 581167514Skmacy * t3_seeprom_read - read a VPD EEPROM location 582167514Skmacy * @adapter: adapter to read 583167514Skmacy * @addr: EEPROM address 584167514Skmacy * @data: where to store the read data 585167514Skmacy * 586167514Skmacy * Read a 32-bit word from a location in VPD EEPROM using the card's PCI 587167514Skmacy * VPD ROM capability. A zero is written to the flag bit when the 588167514Skmacy * addres is written to the control register. The hardware device will 589167514Skmacy * set the flag to 1 when 4 bytes have been read into the data register. 590167514Skmacy */ 591167514Skmacyint t3_seeprom_read(adapter_t *adapter, u32 addr, u32 *data) 592167514Skmacy{ 593167514Skmacy u16 val; 594167514Skmacy int attempts = EEPROM_MAX_POLL; 595167514Skmacy unsigned int base = adapter->params.pci.vpd_cap_addr; 596167514Skmacy 597167514Skmacy if ((addr >= EEPROMSIZE && addr != EEPROM_STAT_ADDR) || (addr & 3)) 598167514Skmacy return -EINVAL; 599167514Skmacy 600167514Skmacy t3_os_pci_write_config_2(adapter, base + PCI_VPD_ADDR, (u16)addr); 601167514Skmacy do { 602167514Skmacy udelay(10); 603167514Skmacy t3_os_pci_read_config_2(adapter, base + PCI_VPD_ADDR, &val); 604167514Skmacy } while (!(val & PCI_VPD_ADDR_F) && --attempts); 605167514Skmacy 606167514Skmacy if (!(val & PCI_VPD_ADDR_F)) { 607167514Skmacy CH_ERR(adapter, "reading EEPROM address 0x%x failed\n", addr); 608167514Skmacy return -EIO; 609167514Skmacy } 610167514Skmacy t3_os_pci_read_config_4(adapter, base + PCI_VPD_DATA, data); 611167514Skmacy *data = le32_to_cpu(*data); 612167514Skmacy return 0; 613167514Skmacy} 614167514Skmacy 615167514Skmacy/** 616167514Skmacy * t3_seeprom_write - write a VPD EEPROM location 617167514Skmacy * @adapter: adapter to write 618167514Skmacy * @addr: EEPROM address 619167514Skmacy * @data: value to write 620167514Skmacy * 621167514Skmacy * Write a 32-bit word to a location in VPD EEPROM using the card's PCI 622167514Skmacy * VPD ROM capability. 623167514Skmacy */ 624167514Skmacyint t3_seeprom_write(adapter_t *adapter, u32 addr, u32 data) 625167514Skmacy{ 626167514Skmacy u16 val; 627167514Skmacy int attempts = EEPROM_MAX_POLL; 628167514Skmacy unsigned int base = adapter->params.pci.vpd_cap_addr; 629167514Skmacy 630167514Skmacy if ((addr >= EEPROMSIZE && addr != EEPROM_STAT_ADDR) || (addr & 3)) 631167514Skmacy return -EINVAL; 632167514Skmacy 633167514Skmacy t3_os_pci_write_config_4(adapter, base + PCI_VPD_DATA, 634167514Skmacy cpu_to_le32(data)); 635167514Skmacy t3_os_pci_write_config_2(adapter, base + PCI_VPD_ADDR, 636167514Skmacy (u16)addr | PCI_VPD_ADDR_F); 637167514Skmacy do { 638171471Skmacy msleep(1); 639167514Skmacy t3_os_pci_read_config_2(adapter, base + PCI_VPD_ADDR, &val); 640167514Skmacy } while ((val & PCI_VPD_ADDR_F) && --attempts); 641167514Skmacy 642167514Skmacy if (val & PCI_VPD_ADDR_F) { 643167514Skmacy CH_ERR(adapter, "write to EEPROM address 0x%x failed\n", addr); 644167514Skmacy return -EIO; 645167514Skmacy } 646167514Skmacy return 0; 647167514Skmacy} 648167514Skmacy 649167514Skmacy/** 650167514Skmacy * t3_seeprom_wp - enable/disable EEPROM write protection 651167514Skmacy * @adapter: the adapter 652167514Skmacy * @enable: 1 to enable write protection, 0 to disable it 653167514Skmacy * 654167514Skmacy * Enables or disables write protection on the serial EEPROM. 655167514Skmacy */ 656167514Skmacyint t3_seeprom_wp(adapter_t *adapter, int enable) 657167514Skmacy{ 658167514Skmacy return t3_seeprom_write(adapter, EEPROM_STAT_ADDR, enable ? 0xc : 0); 659167514Skmacy} 660167514Skmacy 661167514Skmacy/* 662167514Skmacy * Convert a character holding a hex digit to a number. 663167514Skmacy */ 664167514Skmacystatic unsigned int hex2int(unsigned char c) 665167514Skmacy{ 666167514Skmacy return isdigit(c) ? c - '0' : toupper(c) - 'A' + 10; 667167514Skmacy} 668167514Skmacy 669167514Skmacy/** 670167514Skmacy * get_vpd_params - read VPD parameters from VPD EEPROM 671167514Skmacy * @adapter: adapter to read 672167514Skmacy * @p: where to store the parameters 673167514Skmacy * 674167514Skmacy * Reads card parameters stored in VPD EEPROM. 675167514Skmacy */ 676167514Skmacystatic int get_vpd_params(adapter_t *adapter, struct vpd_params *p) 677167514Skmacy{ 678167514Skmacy int i, addr, ret; 679167514Skmacy struct t3_vpd vpd; 680167514Skmacy 681167514Skmacy /* 682167514Skmacy * Card information is normally at VPD_BASE but some early cards had 683167514Skmacy * it at 0. 684167514Skmacy */ 685167514Skmacy ret = t3_seeprom_read(adapter, VPD_BASE, (u32 *)&vpd); 686167514Skmacy if (ret) 687167514Skmacy return ret; 688167514Skmacy addr = vpd.id_tag == 0x82 ? VPD_BASE : 0; 689167514Skmacy 690167514Skmacy for (i = 0; i < sizeof(vpd); i += 4) { 691167514Skmacy ret = t3_seeprom_read(adapter, addr + i, 692167514Skmacy (u32 *)((u8 *)&vpd + i)); 693167514Skmacy if (ret) 694167514Skmacy return ret; 695167514Skmacy } 696167514Skmacy 697167514Skmacy p->cclk = simple_strtoul(vpd.cclk_data, NULL, 10); 698167514Skmacy p->mclk = simple_strtoul(vpd.mclk_data, NULL, 10); 699167514Skmacy p->uclk = simple_strtoul(vpd.uclk_data, NULL, 10); 700167514Skmacy p->mdc = simple_strtoul(vpd.mdc_data, NULL, 10); 701167514Skmacy p->mem_timing = simple_strtoul(vpd.mt_data, NULL, 10); 702172096Skmacy memcpy(p->sn, vpd.sn_data, SERNUM_LEN); 703167514Skmacy 704167514Skmacy /* Old eeproms didn't have port information */ 705167514Skmacy if (adapter->params.rev == 0 && !vpd.port0_data[0]) { 706167514Skmacy p->port_type[0] = uses_xaui(adapter) ? 1 : 2; 707167514Skmacy p->port_type[1] = uses_xaui(adapter) ? 6 : 2; 708167514Skmacy } else { 709167514Skmacy p->port_type[0] = (u8)hex2int(vpd.port0_data[0]); 710167514Skmacy p->port_type[1] = (u8)hex2int(vpd.port1_data[0]); 711170654Skmacy p->port_type[2] = (u8)hex2int(vpd.port2_data[0]); 712170654Skmacy p->port_type[3] = (u8)hex2int(vpd.port3_data[0]); 713167514Skmacy p->xauicfg[0] = simple_strtoul(vpd.xaui0cfg_data, NULL, 16); 714167514Skmacy p->xauicfg[1] = simple_strtoul(vpd.xaui1cfg_data, NULL, 16); 715167514Skmacy } 716167514Skmacy 717167514Skmacy for (i = 0; i < 6; i++) 718167514Skmacy p->eth_base[i] = hex2int(vpd.na_data[2 * i]) * 16 + 719167514Skmacy hex2int(vpd.na_data[2 * i + 1]); 720167514Skmacy return 0; 721167514Skmacy} 722167514Skmacy 723176472Skmacy/* BIOS boot header */ 724176472Skmacytypedef struct boot_header_s { 725176472Skmacy u8 signature[2]; /* signature */ 726176472Skmacy u8 length; /* image length (include header) */ 727176472Skmacy u8 offset[4]; /* initialization vector */ 728176472Skmacy u8 reserved[19]; /* reserved */ 729176472Skmacy u8 exheader[2]; /* offset to expansion header */ 730176472Skmacy} boot_header_t; 731176472Skmacy 732167514Skmacy/* serial flash and firmware constants */ 733167514Skmacyenum { 734167514Skmacy SF_ATTEMPTS = 5, /* max retries for SF1 operations */ 735167514Skmacy SF_SEC_SIZE = 64 * 1024, /* serial flash sector size */ 736167514Skmacy SF_SIZE = SF_SEC_SIZE * 8, /* serial flash size */ 737167514Skmacy 738167514Skmacy /* flash command opcodes */ 739167514Skmacy SF_PROG_PAGE = 2, /* program page */ 740167514Skmacy SF_WR_DISABLE = 4, /* disable writes */ 741167514Skmacy SF_RD_STATUS = 5, /* read status register */ 742167514Skmacy SF_WR_ENABLE = 6, /* enable writes */ 743167514Skmacy SF_RD_DATA_FAST = 0xb, /* read flash */ 744167514Skmacy SF_ERASE_SECTOR = 0xd8, /* erase sector */ 745167514Skmacy 746167514Skmacy FW_FLASH_BOOT_ADDR = 0x70000, /* start address of FW in flash */ 747167746Skmacy FW_VERS_ADDR = 0x77ffc, /* flash address holding FW version */ 748176472Skmacy FW_MIN_SIZE = 8, /* at least version and csum */ 749176472Skmacy FW_MAX_SIZE = FW_VERS_ADDR - FW_FLASH_BOOT_ADDR, 750176472Skmacy 751176472Skmacy BOOT_FLASH_BOOT_ADDR = 0x0,/* start address of boot image in flash */ 752176472Skmacy BOOT_SIGNATURE = 0xaa55, /* signature of BIOS boot ROM */ 753176472Skmacy BOOT_SIZE_INC = 512, /* image size measured in 512B chunks */ 754176472Skmacy BOOT_MIN_SIZE = sizeof(boot_header_t), /* at least basic header */ 755176472Skmacy BOOT_MAX_SIZE = 0xff*BOOT_SIZE_INC /* 1 byte * length increment */ 756167514Skmacy}; 757167514Skmacy 758167514Skmacy/** 759167514Skmacy * sf1_read - read data from the serial flash 760167514Skmacy * @adapter: the adapter 761167514Skmacy * @byte_cnt: number of bytes to read 762167514Skmacy * @cont: whether another operation will be chained 763167514Skmacy * @valp: where to store the read data 764167514Skmacy * 765167514Skmacy * Reads up to 4 bytes of data from the serial flash. The location of 766167514Skmacy * the read needs to be specified prior to calling this by issuing the 767167514Skmacy * appropriate commands to the serial flash. 768167514Skmacy */ 769167514Skmacystatic int sf1_read(adapter_t *adapter, unsigned int byte_cnt, int cont, 770167514Skmacy u32 *valp) 771167514Skmacy{ 772167514Skmacy int ret; 773167514Skmacy 774167514Skmacy if (!byte_cnt || byte_cnt > 4) 775167514Skmacy return -EINVAL; 776167514Skmacy if (t3_read_reg(adapter, A_SF_OP) & F_BUSY) 777167514Skmacy return -EBUSY; 778167514Skmacy t3_write_reg(adapter, A_SF_OP, V_CONT(cont) | V_BYTECNT(byte_cnt - 1)); 779167514Skmacy ret = t3_wait_op_done(adapter, A_SF_OP, F_BUSY, 0, SF_ATTEMPTS, 10); 780167514Skmacy if (!ret) 781167514Skmacy *valp = t3_read_reg(adapter, A_SF_DATA); 782167514Skmacy return ret; 783167514Skmacy} 784167514Skmacy 785167514Skmacy/** 786167514Skmacy * sf1_write - write data to the serial flash 787167514Skmacy * @adapter: the adapter 788167514Skmacy * @byte_cnt: number of bytes to write 789167514Skmacy * @cont: whether another operation will be chained 790167514Skmacy * @val: value to write 791167514Skmacy * 792167514Skmacy * Writes up to 4 bytes of data to the serial flash. The location of 793167514Skmacy * the write needs to be specified prior to calling this by issuing the 794167514Skmacy * appropriate commands to the serial flash. 795167514Skmacy */ 796167514Skmacystatic int sf1_write(adapter_t *adapter, unsigned int byte_cnt, int cont, 797167514Skmacy u32 val) 798167514Skmacy{ 799167514Skmacy if (!byte_cnt || byte_cnt > 4) 800167514Skmacy return -EINVAL; 801167514Skmacy if (t3_read_reg(adapter, A_SF_OP) & F_BUSY) 802167514Skmacy return -EBUSY; 803167514Skmacy t3_write_reg(adapter, A_SF_DATA, val); 804167514Skmacy t3_write_reg(adapter, A_SF_OP, 805167514Skmacy V_CONT(cont) | V_BYTECNT(byte_cnt - 1) | V_OP(1)); 806167514Skmacy return t3_wait_op_done(adapter, A_SF_OP, F_BUSY, 0, SF_ATTEMPTS, 10); 807167514Skmacy} 808167514Skmacy 809167514Skmacy/** 810167514Skmacy * flash_wait_op - wait for a flash operation to complete 811167514Skmacy * @adapter: the adapter 812167514Skmacy * @attempts: max number of polls of the status register 813167514Skmacy * @delay: delay between polls in ms 814167514Skmacy * 815167514Skmacy * Wait for a flash operation to complete by polling the status register. 816167514Skmacy */ 817167514Skmacystatic int flash_wait_op(adapter_t *adapter, int attempts, int delay) 818167514Skmacy{ 819167514Skmacy int ret; 820167514Skmacy u32 status; 821167514Skmacy 822167514Skmacy while (1) { 823167514Skmacy if ((ret = sf1_write(adapter, 1, 1, SF_RD_STATUS)) != 0 || 824167514Skmacy (ret = sf1_read(adapter, 1, 0, &status)) != 0) 825167514Skmacy return ret; 826167514Skmacy if (!(status & 1)) 827167514Skmacy return 0; 828167514Skmacy if (--attempts == 0) 829167514Skmacy return -EAGAIN; 830167514Skmacy if (delay) 831171471Skmacy msleep(delay); 832167514Skmacy } 833167514Skmacy} 834167514Skmacy 835167514Skmacy/** 836167514Skmacy * t3_read_flash - read words from serial flash 837167514Skmacy * @adapter: the adapter 838167514Skmacy * @addr: the start address for the read 839167514Skmacy * @nwords: how many 32-bit words to read 840167514Skmacy * @data: where to store the read data 841167514Skmacy * @byte_oriented: whether to store data as bytes or as words 842167514Skmacy * 843167514Skmacy * Read the specified number of 32-bit words from the serial flash. 844167514Skmacy * If @byte_oriented is set the read data is stored as a byte array 845167514Skmacy * (i.e., big-endian), otherwise as 32-bit words in the platform's 846167514Skmacy * natural endianess. 847167514Skmacy */ 848167514Skmacyint t3_read_flash(adapter_t *adapter, unsigned int addr, unsigned int nwords, 849167514Skmacy u32 *data, int byte_oriented) 850167514Skmacy{ 851167514Skmacy int ret; 852167514Skmacy 853167514Skmacy if (addr + nwords * sizeof(u32) > SF_SIZE || (addr & 3)) 854167514Skmacy return -EINVAL; 855167514Skmacy 856167514Skmacy addr = swab32(addr) | SF_RD_DATA_FAST; 857167514Skmacy 858167514Skmacy if ((ret = sf1_write(adapter, 4, 1, addr)) != 0 || 859167514Skmacy (ret = sf1_read(adapter, 1, 1, data)) != 0) 860167514Skmacy return ret; 861167514Skmacy 862167514Skmacy for ( ; nwords; nwords--, data++) { 863167514Skmacy ret = sf1_read(adapter, 4, nwords > 1, data); 864167514Skmacy if (ret) 865167514Skmacy return ret; 866167514Skmacy if (byte_oriented) 867167514Skmacy *data = htonl(*data); 868167514Skmacy } 869167514Skmacy return 0; 870167514Skmacy} 871167514Skmacy 872167514Skmacy/** 873167514Skmacy * t3_write_flash - write up to a page of data to the serial flash 874167514Skmacy * @adapter: the adapter 875167514Skmacy * @addr: the start address to write 876167514Skmacy * @n: length of data to write 877167514Skmacy * @data: the data to write 878176472Skmacy * @byte_oriented: whether to store data as bytes or as words 879167514Skmacy * 880167514Skmacy * Writes up to a page of data (256 bytes) to the serial flash starting 881167514Skmacy * at the given address. 882176472Skmacy * If @byte_oriented is set the write data is stored as a 32-bit 883176472Skmacy * big-endian array, otherwise in the processor's native endianess. 884176472Skmacy * 885167514Skmacy */ 886167514Skmacystatic int t3_write_flash(adapter_t *adapter, unsigned int addr, 887176472Skmacy unsigned int n, const u8 *data, 888176472Skmacy int byte_oriented) 889167514Skmacy{ 890167514Skmacy int ret; 891167514Skmacy u32 buf[64]; 892176472Skmacy unsigned int c, left, val, offset = addr & 0xff; 893167514Skmacy 894167514Skmacy if (addr + n > SF_SIZE || offset + n > 256) 895167514Skmacy return -EINVAL; 896167514Skmacy 897167514Skmacy val = swab32(addr) | SF_PROG_PAGE; 898167514Skmacy 899167514Skmacy if ((ret = sf1_write(adapter, 1, 0, SF_WR_ENABLE)) != 0 || 900167514Skmacy (ret = sf1_write(adapter, 4, 1, val)) != 0) 901167514Skmacy return ret; 902167514Skmacy 903167514Skmacy for (left = n; left; left -= c) { 904167514Skmacy c = min(left, 4U); 905176472Skmacy val = *(const u32*)data; 906176472Skmacy data += c; 907176472Skmacy if (byte_oriented) 908176472Skmacy val = htonl(val); 909167514Skmacy 910167514Skmacy ret = sf1_write(adapter, c, c != left, val); 911167514Skmacy if (ret) 912167514Skmacy return ret; 913167514Skmacy } 914167514Skmacy if ((ret = flash_wait_op(adapter, 5, 1)) != 0) 915167514Skmacy return ret; 916167514Skmacy 917167514Skmacy /* Read the page to verify the write succeeded */ 918176472Skmacy ret = t3_read_flash(adapter, addr & ~0xff, ARRAY_SIZE(buf), buf, 919176472Skmacy byte_oriented); 920167514Skmacy if (ret) 921167514Skmacy return ret; 922167514Skmacy 923167514Skmacy if (memcmp(data - n, (u8 *)buf + offset, n)) 924167514Skmacy return -EIO; 925167514Skmacy return 0; 926167514Skmacy} 927167514Skmacy 928170654Skmacy/** 929171471Skmacy * t3_get_tp_version - read the tp sram version 930171471Skmacy * @adapter: the adapter 931171471Skmacy * @vers: where to place the version 932171471Skmacy * 933171471Skmacy * Reads the protocol sram version from sram. 934171471Skmacy */ 935171471Skmacyint t3_get_tp_version(adapter_t *adapter, u32 *vers) 936171471Skmacy{ 937171471Skmacy int ret; 938171471Skmacy 939171471Skmacy /* Get version loaded in SRAM */ 940171471Skmacy t3_write_reg(adapter, A_TP_EMBED_OP_FIELD0, 0); 941171471Skmacy ret = t3_wait_op_done(adapter, A_TP_EMBED_OP_FIELD0, 942171471Skmacy 1, 1, 5, 1); 943171471Skmacy if (ret) 944171471Skmacy return ret; 945171471Skmacy 946171471Skmacy *vers = t3_read_reg(adapter, A_TP_EMBED_OP_FIELD1); 947171471Skmacy 948171471Skmacy return 0; 949171471Skmacy} 950171471Skmacy 951171471Skmacy/** 952170654Skmacy * t3_check_tpsram_version - read the tp sram version 953170654Skmacy * @adapter: the adapter 954170654Skmacy * 955170654Skmacy */ 956176472Skmacyint t3_check_tpsram_version(adapter_t *adapter, int *must_load) 957170654Skmacy{ 958170654Skmacy int ret; 959170654Skmacy u32 vers; 960170654Skmacy unsigned int major, minor; 961170654Skmacy 962176472Skmacy if (adapter->params.rev == T3_REV_A) 963176472Skmacy return 0; 964176472Skmacy 965176472Skmacy *must_load = 1; 966176472Skmacy 967176472Skmacy ret = t3_get_tp_version(adapter, &vers); 968170654Skmacy if (ret) 969170654Skmacy return ret; 970170654Skmacy 971170654Skmacy vers = t3_read_reg(adapter, A_TP_EMBED_OP_FIELD1); 972170654Skmacy 973170654Skmacy major = G_TP_VERSION_MAJOR(vers); 974170654Skmacy minor = G_TP_VERSION_MINOR(vers); 975170654Skmacy 976170654Skmacy if (major == TP_VERSION_MAJOR && minor == TP_VERSION_MINOR) 977170654Skmacy return 0; 978170654Skmacy 979176472Skmacy if (major != TP_VERSION_MAJOR) 980176472Skmacy CH_ERR(adapter, "found wrong TP version (%u.%u), " 981176472Skmacy "driver needs version %d.%d\n", major, minor, 982176472Skmacy TP_VERSION_MAJOR, TP_VERSION_MINOR); 983176472Skmacy else { 984176472Skmacy *must_load = 0; 985176472Skmacy CH_ERR(adapter, "found wrong TP version (%u.%u), " 986176472Skmacy "driver compiled for version %d.%d\n", major, minor, 987176472Skmacy TP_VERSION_MAJOR, TP_VERSION_MINOR); 988176472Skmacy } 989170654Skmacy return -EINVAL; 990170654Skmacy} 991170654Skmacy 992170654Skmacy/** 993170654Skmacy * t3_check_tpsram - check if provided protocol SRAM 994170654Skmacy * is compatible with this driver 995170654Skmacy * @adapter: the adapter 996170654Skmacy * @tp_sram: the firmware image to write 997170654Skmacy * @size: image size 998170654Skmacy * 999170654Skmacy * Checks if an adapter's tp sram is compatible with the driver. 1000170654Skmacy * Returns 0 if the versions are compatible, a negative error otherwise. 1001170654Skmacy */ 1002171471Skmacyint t3_check_tpsram(adapter_t *adapter, const u8 *tp_sram, unsigned int size) 1003170654Skmacy{ 1004170654Skmacy u32 csum; 1005170654Skmacy unsigned int i; 1006170654Skmacy const u32 *p = (const u32 *)tp_sram; 1007170654Skmacy 1008170654Skmacy /* Verify checksum */ 1009170654Skmacy for (csum = 0, i = 0; i < size / sizeof(csum); i++) 1010170654Skmacy csum += ntohl(p[i]); 1011170654Skmacy if (csum != 0xffffffff) { 1012170654Skmacy CH_ERR(adapter, "corrupted protocol SRAM image, checksum %u\n", 1013170654Skmacy csum); 1014170654Skmacy return -EINVAL; 1015170654Skmacy } 1016170654Skmacy 1017170654Skmacy return 0; 1018170654Skmacy} 1019170654Skmacy 1020167514Skmacyenum fw_version_type { 1021167514Skmacy FW_VERSION_N3, 1022167514Skmacy FW_VERSION_T3 1023167514Skmacy}; 1024167514Skmacy 1025167514Skmacy/** 1026167514Skmacy * t3_get_fw_version - read the firmware version 1027167514Skmacy * @adapter: the adapter 1028167514Skmacy * @vers: where to place the version 1029167514Skmacy * 1030167514Skmacy * Reads the FW version from flash. 1031167514Skmacy */ 1032167514Skmacyint t3_get_fw_version(adapter_t *adapter, u32 *vers) 1033167514Skmacy{ 1034167514Skmacy return t3_read_flash(adapter, FW_VERS_ADDR, 1, vers, 0); 1035167514Skmacy} 1036167514Skmacy 1037167514Skmacy/** 1038167514Skmacy * t3_check_fw_version - check if the FW is compatible with this driver 1039167514Skmacy * @adapter: the adapter 1040167514Skmacy * 1041167514Skmacy * Checks if an adapter's FW is compatible with the driver. Returns 0 1042167514Skmacy * if the versions are compatible, a negative error otherwise. 1043167514Skmacy */ 1044176472Skmacyint t3_check_fw_version(adapter_t *adapter, int *must_load) 1045167514Skmacy{ 1046167514Skmacy int ret; 1047167514Skmacy u32 vers; 1048167514Skmacy unsigned int type, major, minor; 1049167514Skmacy 1050176472Skmacy *must_load = 1; 1051167514Skmacy ret = t3_get_fw_version(adapter, &vers); 1052167514Skmacy if (ret) 1053167514Skmacy return ret; 1054167514Skmacy 1055167514Skmacy type = G_FW_VERSION_TYPE(vers); 1056167514Skmacy major = G_FW_VERSION_MAJOR(vers); 1057167514Skmacy minor = G_FW_VERSION_MINOR(vers); 1058167514Skmacy 1059167746Skmacy if (type == FW_VERSION_T3 && major == FW_VERSION_MAJOR && 1060167746Skmacy minor == FW_VERSION_MINOR) 1061167514Skmacy return 0; 1062167514Skmacy 1063176472Skmacy if (major != FW_VERSION_MAJOR) 1064176472Skmacy CH_ERR(adapter, "found wrong FW version(%u.%u), " 1065176472Skmacy "driver needs version %u.%u\n", major, minor, 1066176472Skmacy FW_VERSION_MAJOR, FW_VERSION_MINOR); 1067176472Skmacy else if ((int)minor < FW_VERSION_MINOR) { 1068176472Skmacy *must_load = 0; 1069176472Skmacy CH_WARN(adapter, "found old FW minor version(%u.%u), " 1070176472Skmacy "driver compiled for version %u.%u\n", major, minor, 1071176472Skmacy FW_VERSION_MAJOR, FW_VERSION_MINOR); 1072176472Skmacy } else { 1073176472Skmacy CH_WARN(adapter, "found newer FW version(%u.%u), " 1074176472Skmacy "driver compiled for version %u.%u\n", major, minor, 1075176472Skmacy FW_VERSION_MAJOR, FW_VERSION_MINOR); 1076176472Skmacy return 0; 1077176472Skmacy } 1078167514Skmacy return -EINVAL; 1079167514Skmacy} 1080167514Skmacy 1081167514Skmacy/** 1082167514Skmacy * t3_flash_erase_sectors - erase a range of flash sectors 1083167514Skmacy * @adapter: the adapter 1084167514Skmacy * @start: the first sector to erase 1085167514Skmacy * @end: the last sector to erase 1086167514Skmacy * 1087167514Skmacy * Erases the sectors in the given range. 1088167514Skmacy */ 1089167514Skmacystatic int t3_flash_erase_sectors(adapter_t *adapter, int start, int end) 1090167514Skmacy{ 1091167514Skmacy while (start <= end) { 1092167514Skmacy int ret; 1093167514Skmacy 1094167514Skmacy if ((ret = sf1_write(adapter, 1, 0, SF_WR_ENABLE)) != 0 || 1095167514Skmacy (ret = sf1_write(adapter, 4, 0, 1096167514Skmacy SF_ERASE_SECTOR | (start << 8))) != 0 || 1097167514Skmacy (ret = flash_wait_op(adapter, 5, 500)) != 0) 1098167514Skmacy return ret; 1099167514Skmacy start++; 1100167514Skmacy } 1101167514Skmacy return 0; 1102167514Skmacy} 1103167514Skmacy 1104167514Skmacy/* 1105167514Skmacy * t3_load_fw - download firmware 1106167514Skmacy * @adapter: the adapter 1107170654Skmacy * @fw_data: the firmware image to write 1108167514Skmacy * @size: image size 1109167514Skmacy * 1110167514Skmacy * Write the supplied firmware image to the card's serial flash. 1111167514Skmacy * The FW image has the following sections: @size - 8 bytes of code and 1112167514Skmacy * data, followed by 4 bytes of FW version, followed by the 32-bit 1113167514Skmacy * 1's complement checksum of the whole image. 1114167514Skmacy */ 1115167514Skmacyint t3_load_fw(adapter_t *adapter, const u8 *fw_data, unsigned int size) 1116167514Skmacy{ 1117167514Skmacy u32 csum; 1118167514Skmacy unsigned int i; 1119167514Skmacy const u32 *p = (const u32 *)fw_data; 1120167514Skmacy int ret, addr, fw_sector = FW_FLASH_BOOT_ADDR >> 16; 1121167514Skmacy 1122170654Skmacy if ((size & 3) || size < FW_MIN_SIZE) 1123167514Skmacy return -EINVAL; 1124176472Skmacy if (size - 8 > FW_MAX_SIZE) 1125167514Skmacy return -EFBIG; 1126167514Skmacy 1127167514Skmacy for (csum = 0, i = 0; i < size / sizeof(csum); i++) 1128167514Skmacy csum += ntohl(p[i]); 1129167514Skmacy if (csum != 0xffffffff) { 1130167514Skmacy CH_ERR(adapter, "corrupted firmware image, checksum %u\n", 1131167514Skmacy csum); 1132167514Skmacy return -EINVAL; 1133167514Skmacy } 1134167514Skmacy 1135167514Skmacy ret = t3_flash_erase_sectors(adapter, fw_sector, fw_sector); 1136167514Skmacy if (ret) 1137167514Skmacy goto out; 1138167514Skmacy 1139167514Skmacy size -= 8; /* trim off version and checksum */ 1140167514Skmacy for (addr = FW_FLASH_BOOT_ADDR; size; ) { 1141167514Skmacy unsigned int chunk_size = min(size, 256U); 1142167514Skmacy 1143176472Skmacy ret = t3_write_flash(adapter, addr, chunk_size, fw_data, 1); 1144167514Skmacy if (ret) 1145167514Skmacy goto out; 1146167514Skmacy 1147167514Skmacy addr += chunk_size; 1148167514Skmacy fw_data += chunk_size; 1149167514Skmacy size -= chunk_size; 1150167514Skmacy } 1151167514Skmacy 1152176472Skmacy ret = t3_write_flash(adapter, FW_VERS_ADDR, 4, fw_data, 1); 1153167514Skmacyout: 1154167514Skmacy if (ret) 1155167514Skmacy CH_ERR(adapter, "firmware download failed, error %d\n", ret); 1156167514Skmacy return ret; 1157167514Skmacy} 1158167514Skmacy 1159176472Skmacy/* 1160176472Skmacy * t3_load_boot - download boot flash 1161176472Skmacy * @adapter: the adapter 1162176472Skmacy * @boot_data: the boot image to write 1163176472Skmacy * @size: image size 1164176472Skmacy * 1165176472Skmacy * Write the supplied boot image to the card's serial flash. 1166176472Skmacy * The boot image has the following sections: a 28-byte header and the 1167176472Skmacy * boot image. 1168176472Skmacy */ 1169176472Skmacyint t3_load_boot(adapter_t *adapter, u8 *boot_data, unsigned int size) 1170176472Skmacy{ 1171176472Skmacy boot_header_t *header = (boot_header_t *)boot_data; 1172176472Skmacy int ret; 1173176472Skmacy unsigned int addr; 1174176472Skmacy unsigned int boot_sector = BOOT_FLASH_BOOT_ADDR >> 16; 1175176472Skmacy unsigned int boot_end = (BOOT_FLASH_BOOT_ADDR + size - 1) >> 16; 1176176472Skmacy 1177176472Skmacy /* 1178176472Skmacy * Perform some primitive sanity testing to avoid accidentally 1179176472Skmacy * writing garbage over the boot sectors. We ought to check for 1180176472Skmacy * more but it's not worth it for now ... 1181176472Skmacy */ 1182176472Skmacy if (size < BOOT_MIN_SIZE || size > BOOT_MAX_SIZE) { 1183176472Skmacy CH_ERR(adapter, "boot image too small/large\n"); 1184176472Skmacy return -EFBIG; 1185176472Skmacy } 1186176472Skmacy if (le16_to_cpu(*(u16*)header->signature) != BOOT_SIGNATURE) { 1187176472Skmacy CH_ERR(adapter, "boot image missing signature\n"); 1188176472Skmacy return -EINVAL; 1189176472Skmacy } 1190176472Skmacy if (header->length * BOOT_SIZE_INC != size) { 1191176472Skmacy CH_ERR(adapter, "boot image header length != image length\n"); 1192176472Skmacy return -EINVAL; 1193176472Skmacy } 1194176472Skmacy 1195176472Skmacy ret = t3_flash_erase_sectors(adapter, boot_sector, boot_end); 1196176472Skmacy if (ret) 1197176472Skmacy goto out; 1198176472Skmacy 1199176472Skmacy for (addr = BOOT_FLASH_BOOT_ADDR; size; ) { 1200176472Skmacy unsigned int chunk_size = min(size, 256U); 1201176472Skmacy 1202176472Skmacy ret = t3_write_flash(adapter, addr, chunk_size, boot_data, 0); 1203176472Skmacy if (ret) 1204176472Skmacy goto out; 1205176472Skmacy 1206176472Skmacy addr += chunk_size; 1207176472Skmacy boot_data += chunk_size; 1208176472Skmacy size -= chunk_size; 1209176472Skmacy } 1210176472Skmacy 1211176472Skmacyout: 1212176472Skmacy if (ret) 1213176472Skmacy CH_ERR(adapter, "boot image download failed, error %d\n", ret); 1214176472Skmacy return ret; 1215176472Skmacy} 1216176472Skmacy 1217167514Skmacy#define CIM_CTL_BASE 0x2000 1218167514Skmacy 1219167514Skmacy/** 1220167514Skmacy * t3_cim_ctl_blk_read - read a block from CIM control region 1221167514Skmacy * @adap: the adapter 1222167514Skmacy * @addr: the start address within the CIM control region 1223167514Skmacy * @n: number of words to read 1224167514Skmacy * @valp: where to store the result 1225167514Skmacy * 1226167514Skmacy * Reads a block of 4-byte words from the CIM control region. 1227167514Skmacy */ 1228167514Skmacyint t3_cim_ctl_blk_read(adapter_t *adap, unsigned int addr, unsigned int n, 1229167514Skmacy unsigned int *valp) 1230167514Skmacy{ 1231167514Skmacy int ret = 0; 1232167514Skmacy 1233167514Skmacy if (t3_read_reg(adap, A_CIM_HOST_ACC_CTRL) & F_HOSTBUSY) 1234167514Skmacy return -EBUSY; 1235167514Skmacy 1236167514Skmacy for ( ; !ret && n--; addr += 4) { 1237167514Skmacy t3_write_reg(adap, A_CIM_HOST_ACC_CTRL, CIM_CTL_BASE + addr); 1238167514Skmacy ret = t3_wait_op_done(adap, A_CIM_HOST_ACC_CTRL, F_HOSTBUSY, 1239167514Skmacy 0, 5, 2); 1240167514Skmacy if (!ret) 1241167514Skmacy *valp++ = t3_read_reg(adap, A_CIM_HOST_ACC_DATA); 1242167514Skmacy } 1243167514Skmacy return ret; 1244167514Skmacy} 1245167514Skmacy 1246167514Skmacy/** 1247167514Skmacy * t3_link_changed - handle interface link changes 1248167514Skmacy * @adapter: the adapter 1249167514Skmacy * @port_id: the port index that changed link state 1250167514Skmacy * 1251167514Skmacy * Called when a port's link settings change to propagate the new values 1252167514Skmacy * to the associated PHY and MAC. After performing the common tasks it 1253167514Skmacy * invokes an OS-specific handler. 1254167514Skmacy */ 1255167514Skmacyvoid t3_link_changed(adapter_t *adapter, int port_id) 1256167514Skmacy{ 1257167514Skmacy int link_ok, speed, duplex, fc; 1258170654Skmacy struct port_info *pi = adap2pinfo(adapter, port_id); 1259170654Skmacy struct cphy *phy = &pi->phy; 1260170654Skmacy struct cmac *mac = &pi->mac; 1261170654Skmacy struct link_config *lc = &pi->link_config; 1262167514Skmacy 1263167514Skmacy phy->ops->get_link_status(phy, &link_ok, &speed, &duplex, &fc); 1264167514Skmacy 1265180583Skmacy if (lc->requested_fc & PAUSE_AUTONEG) 1266180583Skmacy fc &= lc->requested_fc; 1267180583Skmacy else 1268180583Skmacy fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX); 1269180583Skmacy 1270180583Skmacy if (link_ok == lc->link_ok && speed == lc->speed && 1271180583Skmacy duplex == lc->duplex && fc == lc->fc) 1272180583Skmacy return; /* nothing changed */ 1273180583Skmacy 1274167514Skmacy if (link_ok != lc->link_ok && adapter->params.rev > 0 && 1275167514Skmacy uses_xaui(adapter)) { 1276167514Skmacy if (link_ok) 1277167514Skmacy t3b_pcs_reset(mac); 1278167514Skmacy t3_write_reg(adapter, A_XGM_XAUI_ACT_CTRL + mac->offset, 1279167514Skmacy link_ok ? F_TXACTENABLE | F_RXEN : 0); 1280167514Skmacy } 1281167514Skmacy lc->link_ok = (unsigned char)link_ok; 1282167514Skmacy lc->speed = speed < 0 ? SPEED_INVALID : speed; 1283167514Skmacy lc->duplex = duplex < 0 ? DUPLEX_INVALID : duplex; 1284167514Skmacy 1285167514Skmacy if (link_ok && speed >= 0 && lc->autoneg == AUTONEG_ENABLE) { 1286167514Skmacy /* Set MAC speed, duplex, and flow control to match PHY. */ 1287167514Skmacy t3_mac_set_speed_duplex_fc(mac, speed, duplex, fc); 1288167514Skmacy lc->fc = (unsigned char)fc; 1289167514Skmacy } 1290167514Skmacy 1291167514Skmacy t3_os_link_changed(adapter, port_id, link_ok, speed, duplex, fc); 1292167514Skmacy} 1293167514Skmacy 1294167514Skmacy/** 1295167514Skmacy * t3_link_start - apply link configuration to MAC/PHY 1296167514Skmacy * @phy: the PHY to setup 1297167514Skmacy * @mac: the MAC to setup 1298167514Skmacy * @lc: the requested link configuration 1299167514Skmacy * 1300167514Skmacy * Set up a port's MAC and PHY according to a desired link configuration. 1301167514Skmacy * - If the PHY can auto-negotiate first decide what to advertise, then 1302167514Skmacy * enable/disable auto-negotiation as desired, and reset. 1303167514Skmacy * - If the PHY does not auto-negotiate just reset it. 1304167514Skmacy * - If auto-negotiation is off set the MAC to the proper speed/duplex/FC, 1305167514Skmacy * otherwise do it later based on the outcome of auto-negotiation. 1306167514Skmacy */ 1307167514Skmacyint t3_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc) 1308167514Skmacy{ 1309167514Skmacy unsigned int fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX); 1310167514Skmacy 1311167514Skmacy lc->link_ok = 0; 1312167514Skmacy if (lc->supported & SUPPORTED_Autoneg) { 1313167514Skmacy lc->advertising &= ~(ADVERTISED_Asym_Pause | ADVERTISED_Pause); 1314167514Skmacy if (fc) { 1315167514Skmacy lc->advertising |= ADVERTISED_Asym_Pause; 1316167514Skmacy if (fc & PAUSE_RX) 1317167514Skmacy lc->advertising |= ADVERTISED_Pause; 1318167514Skmacy } 1319167514Skmacy phy->ops->advertise(phy, lc->advertising); 1320167514Skmacy 1321167514Skmacy if (lc->autoneg == AUTONEG_DISABLE) { 1322167514Skmacy lc->speed = lc->requested_speed; 1323167514Skmacy lc->duplex = lc->requested_duplex; 1324167514Skmacy lc->fc = (unsigned char)fc; 1325167514Skmacy t3_mac_set_speed_duplex_fc(mac, lc->speed, lc->duplex, 1326167514Skmacy fc); 1327167514Skmacy /* Also disables autoneg */ 1328167514Skmacy phy->ops->set_speed_duplex(phy, lc->speed, lc->duplex); 1329167514Skmacy } else 1330167514Skmacy phy->ops->autoneg_enable(phy); 1331167514Skmacy } else { 1332167514Skmacy t3_mac_set_speed_duplex_fc(mac, -1, -1, fc); 1333167514Skmacy lc->fc = (unsigned char)fc; 1334167514Skmacy phy->ops->reset(phy, 0); 1335167514Skmacy } 1336167514Skmacy return 0; 1337167514Skmacy} 1338167514Skmacy 1339167514Skmacy/** 1340167514Skmacy * t3_set_vlan_accel - control HW VLAN extraction 1341167514Skmacy * @adapter: the adapter 1342167514Skmacy * @ports: bitmap of adapter ports to operate on 1343167514Skmacy * @on: enable (1) or disable (0) HW VLAN extraction 1344167514Skmacy * 1345167514Skmacy * Enables or disables HW extraction of VLAN tags for the given port. 1346167514Skmacy */ 1347167514Skmacyvoid t3_set_vlan_accel(adapter_t *adapter, unsigned int ports, int on) 1348167514Skmacy{ 1349167514Skmacy t3_set_reg_field(adapter, A_TP_OUT_CONFIG, 1350167514Skmacy ports << S_VLANEXTRACTIONENABLE, 1351167514Skmacy on ? (ports << S_VLANEXTRACTIONENABLE) : 0); 1352167514Skmacy} 1353167514Skmacy 1354167514Skmacystruct intr_info { 1355167514Skmacy unsigned int mask; /* bits to check in interrupt status */ 1356167514Skmacy const char *msg; /* message to print or NULL */ 1357167514Skmacy short stat_idx; /* stat counter to increment or -1 */ 1358181614Skmacy unsigned short fatal; /* whether the condition reported is fatal */ 1359167514Skmacy}; 1360167514Skmacy 1361167514Skmacy/** 1362167514Skmacy * t3_handle_intr_status - table driven interrupt handler 1363167514Skmacy * @adapter: the adapter that generated the interrupt 1364167514Skmacy * @reg: the interrupt status register to process 1365167514Skmacy * @mask: a mask to apply to the interrupt status 1366167514Skmacy * @acts: table of interrupt actions 1367167514Skmacy * @stats: statistics counters tracking interrupt occurences 1368167514Skmacy * 1369167514Skmacy * A table driven interrupt handler that applies a set of masks to an 1370167514Skmacy * interrupt status word and performs the corresponding actions if the 1371167514Skmacy * interrupts described by the mask have occured. The actions include 1372167514Skmacy * optionally printing a warning or alert message, and optionally 1373167514Skmacy * incrementing a stat counter. The table is terminated by an entry 1374167514Skmacy * specifying mask 0. Returns the number of fatal interrupt conditions. 1375167514Skmacy */ 1376167514Skmacystatic int t3_handle_intr_status(adapter_t *adapter, unsigned int reg, 1377167514Skmacy unsigned int mask, 1378167514Skmacy const struct intr_info *acts, 1379167514Skmacy unsigned long *stats) 1380167514Skmacy{ 1381167514Skmacy int fatal = 0; 1382167514Skmacy unsigned int status = t3_read_reg(adapter, reg) & mask; 1383167514Skmacy 1384167514Skmacy for ( ; acts->mask; ++acts) { 1385167514Skmacy if (!(status & acts->mask)) continue; 1386167514Skmacy if (acts->fatal) { 1387167514Skmacy fatal++; 1388167514Skmacy CH_ALERT(adapter, "%s (0x%x)\n", 1389167514Skmacy acts->msg, status & acts->mask); 1390167514Skmacy } else if (acts->msg) 1391167514Skmacy CH_WARN(adapter, "%s (0x%x)\n", 1392167514Skmacy acts->msg, status & acts->mask); 1393167514Skmacy if (acts->stat_idx >= 0) 1394167514Skmacy stats[acts->stat_idx]++; 1395167514Skmacy } 1396167514Skmacy if (status) /* clear processed interrupts */ 1397167514Skmacy t3_write_reg(adapter, reg, status); 1398167514Skmacy return fatal; 1399167514Skmacy} 1400167514Skmacy 1401176472Skmacy#define SGE_INTR_MASK (F_RSPQDISABLED | \ 1402176472Skmacy F_UC_REQ_FRAMINGERROR | F_R_REQ_FRAMINGERROR | \ 1403176472Skmacy F_CPPARITYERROR | F_OCPARITYERROR | F_RCPARITYERROR | \ 1404176472Skmacy F_IRPARITYERROR | V_ITPARITYERROR(M_ITPARITYERROR) | \ 1405176472Skmacy V_FLPARITYERROR(M_FLPARITYERROR) | F_LODRBPARITYERROR | \ 1406176472Skmacy F_HIDRBPARITYERROR | F_LORCQPARITYERROR | \ 1407176472Skmacy F_HIRCQPARITYERROR) 1408167514Skmacy#define MC5_INTR_MASK (F_PARITYERR | F_ACTRGNFULL | F_UNKNOWNCMD | \ 1409167514Skmacy F_REQQPARERR | F_DISPQPARERR | F_DELACTEMPTY | \ 1410167514Skmacy F_NFASRCHFAIL) 1411167514Skmacy#define MC7_INTR_MASK (F_AE | F_UE | F_CE | V_PE(M_PE)) 1412167514Skmacy#define XGM_INTR_MASK (V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR) | \ 1413167514Skmacy V_RXFIFO_PRTY_ERR(M_RXFIFO_PRTY_ERR) | \ 1414167514Skmacy F_TXFIFO_UNDERRUN | F_RXFIFO_OVERFLOW) 1415167514Skmacy#define PCIX_INTR_MASK (F_MSTDETPARERR | F_SIGTARABT | F_RCVTARABT | \ 1416167514Skmacy F_RCVMSTABT | F_SIGSYSERR | F_DETPARERR | \ 1417167514Skmacy F_SPLCMPDIS | F_UNXSPLCMP | F_RCVSPLCMPERR | \ 1418167514Skmacy F_DETCORECCERR | F_DETUNCECCERR | F_PIOPARERR | \ 1419167514Skmacy V_WFPARERR(M_WFPARERR) | V_RFPARERR(M_RFPARERR) | \ 1420167514Skmacy V_CFPARERR(M_CFPARERR) /* | V_MSIXPARERR(M_MSIXPARERR) */) 1421167514Skmacy#define PCIE_INTR_MASK (F_UNXSPLCPLERRR | F_UNXSPLCPLERRC | F_PCIE_PIOPARERR |\ 1422167514Skmacy F_PCIE_WFPARERR | F_PCIE_RFPARERR | F_PCIE_CFPARERR | \ 1423167514Skmacy /* V_PCIE_MSIXPARERR(M_PCIE_MSIXPARERR) | */ \ 1424176472Skmacy F_RETRYBUFPARERR | F_RETRYLUTPARERR | F_RXPARERR | \ 1425176472Skmacy F_TXPARERR | V_BISTERR(M_BISTERR)) 1426176472Skmacy#define ULPRX_INTR_MASK (F_PARERRDATA | F_PARERRPCMD | F_ARBPF1PERR | \ 1427176472Skmacy F_ARBPF0PERR | F_ARBFPERR | F_PCMDMUXPERR | \ 1428176472Skmacy F_DATASELFRAMEERR1 | F_DATASELFRAMEERR0) 1429176472Skmacy#define ULPTX_INTR_MASK 0xfc 1430176472Skmacy#define CPLSW_INTR_MASK (F_CIM_OP_MAP_PERR | F_TP_FRAMING_ERROR | \ 1431167514Skmacy F_SGE_FRAMING_ERROR | F_CIM_FRAMING_ERROR | \ 1432167514Skmacy F_ZERO_SWITCH_ERROR) 1433167514Skmacy#define CIM_INTR_MASK (F_BLKWRPLINT | F_BLKRDPLINT | F_BLKWRCTLINT | \ 1434167514Skmacy F_BLKRDCTLINT | F_BLKWRFLASHINT | F_BLKRDFLASHINT | \ 1435167514Skmacy F_SGLWRFLASHINT | F_WRBLKFLASHINT | F_BLKWRBOOTINT | \ 1436176472Skmacy F_FLASHRANGEINT | F_SDRAMRANGEINT | F_RSVDSPACEINT | \ 1437176472Skmacy F_DRAMPARERR | F_ICACHEPARERR | F_DCACHEPARERR | \ 1438176472Skmacy F_OBQSGEPARERR | F_OBQULPHIPARERR | F_OBQULPLOPARERR | \ 1439176472Skmacy F_IBQSGELOPARERR | F_IBQSGEHIPARERR | F_IBQULPPARERR | \ 1440176472Skmacy F_IBQTPPARERR | F_ITAGPARERR | F_DTAGPARERR) 1441167514Skmacy#define PMTX_INTR_MASK (F_ZERO_C_CMD_ERROR | ICSPI_FRM_ERR | OESPI_FRM_ERR | \ 1442167514Skmacy V_ICSPI_PAR_ERROR(M_ICSPI_PAR_ERROR) | \ 1443167514Skmacy V_OESPI_PAR_ERROR(M_OESPI_PAR_ERROR)) 1444167514Skmacy#define PMRX_INTR_MASK (F_ZERO_E_CMD_ERROR | IESPI_FRM_ERR | OCSPI_FRM_ERR | \ 1445167514Skmacy V_IESPI_PAR_ERROR(M_IESPI_PAR_ERROR) | \ 1446167514Skmacy V_OCSPI_PAR_ERROR(M_OCSPI_PAR_ERROR)) 1447167514Skmacy#define MPS_INTR_MASK (V_TX0TPPARERRENB(M_TX0TPPARERRENB) | \ 1448167514Skmacy V_TX1TPPARERRENB(M_TX1TPPARERRENB) | \ 1449167514Skmacy V_RXTPPARERRENB(M_RXTPPARERRENB) | \ 1450167514Skmacy V_MCAPARERRENB(M_MCAPARERRENB)) 1451167514Skmacy#define PL_INTR_MASK (F_T3DBG | F_XGMAC0_0 | F_XGMAC0_1 | F_MC5A | F_PM1_TX | \ 1452167514Skmacy F_PM1_RX | F_ULP2_TX | F_ULP2_RX | F_TP1 | F_CIM | \ 1453167514Skmacy F_MC7_CM | F_MC7_PMTX | F_MC7_PMRX | F_SGE3 | F_PCIM0 | \ 1454167514Skmacy F_MPS0 | F_CPL_SWITCH) 1455167514Skmacy 1456167514Skmacy/* 1457167514Skmacy * Interrupt handler for the PCIX1 module. 1458167514Skmacy */ 1459167514Skmacystatic void pci_intr_handler(adapter_t *adapter) 1460167514Skmacy{ 1461167514Skmacy static struct intr_info pcix1_intr_info[] = { 1462167514Skmacy { F_MSTDETPARERR, "PCI master detected parity error", -1, 1 }, 1463167514Skmacy { F_SIGTARABT, "PCI signaled target abort", -1, 1 }, 1464167514Skmacy { F_RCVTARABT, "PCI received target abort", -1, 1 }, 1465167514Skmacy { F_RCVMSTABT, "PCI received master abort", -1, 1 }, 1466167514Skmacy { F_SIGSYSERR, "PCI signaled system error", -1, 1 }, 1467167514Skmacy { F_DETPARERR, "PCI detected parity error", -1, 1 }, 1468167514Skmacy { F_SPLCMPDIS, "PCI split completion discarded", -1, 1 }, 1469167514Skmacy { F_UNXSPLCMP, "PCI unexpected split completion error", -1, 1 }, 1470167514Skmacy { F_RCVSPLCMPERR, "PCI received split completion error", -1, 1471167514Skmacy 1 }, 1472167514Skmacy { F_DETCORECCERR, "PCI correctable ECC error", 1473167514Skmacy STAT_PCI_CORR_ECC, 0 }, 1474167514Skmacy { F_DETUNCECCERR, "PCI uncorrectable ECC error", -1, 1 }, 1475167514Skmacy { F_PIOPARERR, "PCI PIO FIFO parity error", -1, 1 }, 1476167514Skmacy { V_WFPARERR(M_WFPARERR), "PCI write FIFO parity error", -1, 1477167514Skmacy 1 }, 1478167514Skmacy { V_RFPARERR(M_RFPARERR), "PCI read FIFO parity error", -1, 1479167514Skmacy 1 }, 1480167514Skmacy { V_CFPARERR(M_CFPARERR), "PCI command FIFO parity error", -1, 1481167514Skmacy 1 }, 1482167514Skmacy { V_MSIXPARERR(M_MSIXPARERR), "PCI MSI-X table/PBA parity " 1483167514Skmacy "error", -1, 1 }, 1484167514Skmacy { 0 } 1485167514Skmacy }; 1486167514Skmacy 1487167514Skmacy if (t3_handle_intr_status(adapter, A_PCIX_INT_CAUSE, PCIX_INTR_MASK, 1488167514Skmacy pcix1_intr_info, adapter->irq_stats)) 1489167514Skmacy t3_fatal_err(adapter); 1490167514Skmacy} 1491167514Skmacy 1492167514Skmacy/* 1493167514Skmacy * Interrupt handler for the PCIE module. 1494167514Skmacy */ 1495167514Skmacystatic void pcie_intr_handler(adapter_t *adapter) 1496167514Skmacy{ 1497167514Skmacy static struct intr_info pcie_intr_info[] = { 1498167514Skmacy { F_PEXERR, "PCI PEX error", -1, 1 }, 1499167514Skmacy { F_UNXSPLCPLERRR, 1500167514Skmacy "PCI unexpected split completion DMA read error", -1, 1 }, 1501167514Skmacy { F_UNXSPLCPLERRC, 1502167514Skmacy "PCI unexpected split completion DMA command error", -1, 1 }, 1503167514Skmacy { F_PCIE_PIOPARERR, "PCI PIO FIFO parity error", -1, 1 }, 1504167514Skmacy { F_PCIE_WFPARERR, "PCI write FIFO parity error", -1, 1 }, 1505167514Skmacy { F_PCIE_RFPARERR, "PCI read FIFO parity error", -1, 1 }, 1506167514Skmacy { F_PCIE_CFPARERR, "PCI command FIFO parity error", -1, 1 }, 1507167514Skmacy { V_PCIE_MSIXPARERR(M_PCIE_MSIXPARERR), 1508167514Skmacy "PCI MSI-X table/PBA parity error", -1, 1 }, 1509176472Skmacy { F_RETRYBUFPARERR, "PCI retry buffer parity error", -1, 1 }, 1510176472Skmacy { F_RETRYLUTPARERR, "PCI retry LUT parity error", -1, 1 }, 1511176472Skmacy { F_RXPARERR, "PCI Rx parity error", -1, 1 }, 1512176472Skmacy { F_TXPARERR, "PCI Tx parity error", -1, 1 }, 1513167514Skmacy { V_BISTERR(M_BISTERR), "PCI BIST error", -1, 1 }, 1514167514Skmacy { 0 } 1515167514Skmacy }; 1516167514Skmacy 1517172096Skmacy if (t3_read_reg(adapter, A_PCIE_INT_CAUSE) & F_PEXERR) 1518172096Skmacy CH_ALERT(adapter, "PEX error code 0x%x\n", 1519172096Skmacy t3_read_reg(adapter, A_PCIE_PEX_ERR)); 1520172096Skmacy 1521167514Skmacy if (t3_handle_intr_status(adapter, A_PCIE_INT_CAUSE, PCIE_INTR_MASK, 1522167514Skmacy pcie_intr_info, adapter->irq_stats)) 1523167514Skmacy t3_fatal_err(adapter); 1524167514Skmacy} 1525167514Skmacy 1526167514Skmacy/* 1527167514Skmacy * TP interrupt handler. 1528167514Skmacy */ 1529167514Skmacystatic void tp_intr_handler(adapter_t *adapter) 1530167514Skmacy{ 1531167514Skmacy static struct intr_info tp_intr_info[] = { 1532167514Skmacy { 0xffffff, "TP parity error", -1, 1 }, 1533167514Skmacy { 0x1000000, "TP out of Rx pages", -1, 1 }, 1534167514Skmacy { 0x2000000, "TP out of Tx pages", -1, 1 }, 1535167514Skmacy { 0 } 1536167514Skmacy }; 1537176472Skmacy static struct intr_info tp_intr_info_t3c[] = { 1538176472Skmacy { 0x1fffffff, "TP parity error", -1, 1 }, 1539176472Skmacy { F_FLMRXFLSTEMPTY, "TP out of Rx pages", -1, 1 }, 1540176472Skmacy { F_FLMTXFLSTEMPTY, "TP out of Tx pages", -1, 1 }, 1541176472Skmacy { 0 } 1542176472Skmacy }; 1543167514Skmacy 1544167514Skmacy if (t3_handle_intr_status(adapter, A_TP_INT_CAUSE, 0xffffffff, 1545176472Skmacy adapter->params.rev < T3_REV_C ? 1546176472Skmacy tp_intr_info : tp_intr_info_t3c, NULL)) 1547167514Skmacy t3_fatal_err(adapter); 1548167514Skmacy} 1549167514Skmacy 1550167514Skmacy/* 1551167514Skmacy * CIM interrupt handler. 1552167514Skmacy */ 1553167514Skmacystatic void cim_intr_handler(adapter_t *adapter) 1554167514Skmacy{ 1555167514Skmacy static struct intr_info cim_intr_info[] = { 1556167514Skmacy { F_RSVDSPACEINT, "CIM reserved space write", -1, 1 }, 1557167514Skmacy { F_SDRAMRANGEINT, "CIM SDRAM address out of range", -1, 1 }, 1558167514Skmacy { F_FLASHRANGEINT, "CIM flash address out of range", -1, 1 }, 1559167514Skmacy { F_BLKWRBOOTINT, "CIM block write to boot space", -1, 1 }, 1560167514Skmacy { F_WRBLKFLASHINT, "CIM write to cached flash space", -1, 1 }, 1561167514Skmacy { F_SGLWRFLASHINT, "CIM single write to flash space", -1, 1 }, 1562167514Skmacy { F_BLKRDFLASHINT, "CIM block read from flash space", -1, 1 }, 1563167514Skmacy { F_BLKWRFLASHINT, "CIM block write to flash space", -1, 1 }, 1564167514Skmacy { F_BLKRDCTLINT, "CIM block read from CTL space", -1, 1 }, 1565167514Skmacy { F_BLKWRCTLINT, "CIM block write to CTL space", -1, 1 }, 1566167514Skmacy { F_BLKRDPLINT, "CIM block read from PL space", -1, 1 }, 1567167514Skmacy { F_BLKWRPLINT, "CIM block write to PL space", -1, 1 }, 1568176472Skmacy { F_DRAMPARERR, "CIM DRAM parity error", -1, 1 }, 1569176472Skmacy { F_ICACHEPARERR, "CIM icache parity error", -1, 1 }, 1570176472Skmacy { F_DCACHEPARERR, "CIM dcache parity error", -1, 1 }, 1571176472Skmacy { F_OBQSGEPARERR, "CIM OBQ SGE parity error", -1, 1 }, 1572176472Skmacy { F_OBQULPHIPARERR, "CIM OBQ ULPHI parity error", -1, 1 }, 1573176472Skmacy { F_OBQULPLOPARERR, "CIM OBQ ULPLO parity error", -1, 1 }, 1574176472Skmacy { F_IBQSGELOPARERR, "CIM IBQ SGELO parity error", -1, 1 }, 1575176472Skmacy { F_IBQSGEHIPARERR, "CIM IBQ SGEHI parity error", -1, 1 }, 1576176472Skmacy { F_IBQULPPARERR, "CIM IBQ ULP parity error", -1, 1 }, 1577176472Skmacy { F_IBQTPPARERR, "CIM IBQ TP parity error", -1, 1 }, 1578176472Skmacy { F_ITAGPARERR, "CIM itag parity error", -1, 1 }, 1579176472Skmacy { F_DTAGPARERR, "CIM dtag parity error", -1, 1 }, 1580167514Skmacy { 0 } 1581167514Skmacy }; 1582167514Skmacy 1583176472Skmacy if (t3_handle_intr_status(adapter, A_CIM_HOST_INT_CAUSE, CIM_INTR_MASK, 1584167514Skmacy cim_intr_info, NULL)) 1585167514Skmacy t3_fatal_err(adapter); 1586167514Skmacy} 1587167514Skmacy 1588167514Skmacy/* 1589167514Skmacy * ULP RX interrupt handler. 1590167514Skmacy */ 1591167514Skmacystatic void ulprx_intr_handler(adapter_t *adapter) 1592167514Skmacy{ 1593167514Skmacy static struct intr_info ulprx_intr_info[] = { 1594176472Skmacy { F_PARERRDATA, "ULP RX data parity error", -1, 1 }, 1595176472Skmacy { F_PARERRPCMD, "ULP RX command parity error", -1, 1 }, 1596176472Skmacy { F_ARBPF1PERR, "ULP RX ArbPF1 parity error", -1, 1 }, 1597176472Skmacy { F_ARBPF0PERR, "ULP RX ArbPF0 parity error", -1, 1 }, 1598176472Skmacy { F_ARBFPERR, "ULP RX ArbF parity error", -1, 1 }, 1599176472Skmacy { F_PCMDMUXPERR, "ULP RX PCMDMUX parity error", -1, 1 }, 1600176472Skmacy { F_DATASELFRAMEERR1, "ULP RX frame error", -1, 1 }, 1601176472Skmacy { F_DATASELFRAMEERR0, "ULP RX frame error", -1, 1 }, 1602167514Skmacy { 0 } 1603167514Skmacy }; 1604167514Skmacy 1605167514Skmacy if (t3_handle_intr_status(adapter, A_ULPRX_INT_CAUSE, 0xffffffff, 1606167514Skmacy ulprx_intr_info, NULL)) 1607167514Skmacy t3_fatal_err(adapter); 1608167514Skmacy} 1609167514Skmacy 1610167514Skmacy/* 1611167514Skmacy * ULP TX interrupt handler. 1612167514Skmacy */ 1613167514Skmacystatic void ulptx_intr_handler(adapter_t *adapter) 1614167514Skmacy{ 1615167514Skmacy static struct intr_info ulptx_intr_info[] = { 1616167514Skmacy { F_PBL_BOUND_ERR_CH0, "ULP TX channel 0 PBL out of bounds", 1617167514Skmacy STAT_ULP_CH0_PBL_OOB, 0 }, 1618167514Skmacy { F_PBL_BOUND_ERR_CH1, "ULP TX channel 1 PBL out of bounds", 1619167514Skmacy STAT_ULP_CH1_PBL_OOB, 0 }, 1620176472Skmacy { 0xfc, "ULP TX parity error", -1, 1 }, 1621167514Skmacy { 0 } 1622167514Skmacy }; 1623167514Skmacy 1624167514Skmacy if (t3_handle_intr_status(adapter, A_ULPTX_INT_CAUSE, 0xffffffff, 1625167514Skmacy ulptx_intr_info, adapter->irq_stats)) 1626167514Skmacy t3_fatal_err(adapter); 1627167514Skmacy} 1628167514Skmacy 1629167514Skmacy#define ICSPI_FRM_ERR (F_ICSPI0_FIFO2X_RX_FRAMING_ERROR | \ 1630167514Skmacy F_ICSPI1_FIFO2X_RX_FRAMING_ERROR | F_ICSPI0_RX_FRAMING_ERROR | \ 1631167514Skmacy F_ICSPI1_RX_FRAMING_ERROR | F_ICSPI0_TX_FRAMING_ERROR | \ 1632167514Skmacy F_ICSPI1_TX_FRAMING_ERROR) 1633167514Skmacy#define OESPI_FRM_ERR (F_OESPI0_RX_FRAMING_ERROR | \ 1634167514Skmacy F_OESPI1_RX_FRAMING_ERROR | F_OESPI0_TX_FRAMING_ERROR | \ 1635167514Skmacy F_OESPI1_TX_FRAMING_ERROR | F_OESPI0_OFIFO2X_TX_FRAMING_ERROR | \ 1636167514Skmacy F_OESPI1_OFIFO2X_TX_FRAMING_ERROR) 1637167514Skmacy 1638167514Skmacy/* 1639167514Skmacy * PM TX interrupt handler. 1640167514Skmacy */ 1641167514Skmacystatic void pmtx_intr_handler(adapter_t *adapter) 1642167514Skmacy{ 1643167514Skmacy static struct intr_info pmtx_intr_info[] = { 1644167514Skmacy { F_ZERO_C_CMD_ERROR, "PMTX 0-length pcmd", -1, 1 }, 1645167514Skmacy { ICSPI_FRM_ERR, "PMTX ispi framing error", -1, 1 }, 1646167514Skmacy { OESPI_FRM_ERR, "PMTX ospi framing error", -1, 1 }, 1647167514Skmacy { V_ICSPI_PAR_ERROR(M_ICSPI_PAR_ERROR), 1648167514Skmacy "PMTX ispi parity error", -1, 1 }, 1649167514Skmacy { V_OESPI_PAR_ERROR(M_OESPI_PAR_ERROR), 1650167514Skmacy "PMTX ospi parity error", -1, 1 }, 1651167514Skmacy { 0 } 1652167514Skmacy }; 1653167514Skmacy 1654167514Skmacy if (t3_handle_intr_status(adapter, A_PM1_TX_INT_CAUSE, 0xffffffff, 1655167514Skmacy pmtx_intr_info, NULL)) 1656167514Skmacy t3_fatal_err(adapter); 1657167514Skmacy} 1658167514Skmacy 1659167514Skmacy#define IESPI_FRM_ERR (F_IESPI0_FIFO2X_RX_FRAMING_ERROR | \ 1660167514Skmacy F_IESPI1_FIFO2X_RX_FRAMING_ERROR | F_IESPI0_RX_FRAMING_ERROR | \ 1661167514Skmacy F_IESPI1_RX_FRAMING_ERROR | F_IESPI0_TX_FRAMING_ERROR | \ 1662167514Skmacy F_IESPI1_TX_FRAMING_ERROR) 1663167514Skmacy#define OCSPI_FRM_ERR (F_OCSPI0_RX_FRAMING_ERROR | \ 1664167514Skmacy F_OCSPI1_RX_FRAMING_ERROR | F_OCSPI0_TX_FRAMING_ERROR | \ 1665167514Skmacy F_OCSPI1_TX_FRAMING_ERROR | F_OCSPI0_OFIFO2X_TX_FRAMING_ERROR | \ 1666167514Skmacy F_OCSPI1_OFIFO2X_TX_FRAMING_ERROR) 1667167514Skmacy 1668167514Skmacy/* 1669167514Skmacy * PM RX interrupt handler. 1670167514Skmacy */ 1671167514Skmacystatic void pmrx_intr_handler(adapter_t *adapter) 1672167514Skmacy{ 1673167514Skmacy static struct intr_info pmrx_intr_info[] = { 1674167514Skmacy { F_ZERO_E_CMD_ERROR, "PMRX 0-length pcmd", -1, 1 }, 1675167514Skmacy { IESPI_FRM_ERR, "PMRX ispi framing error", -1, 1 }, 1676167514Skmacy { OCSPI_FRM_ERR, "PMRX ospi framing error", -1, 1 }, 1677167514Skmacy { V_IESPI_PAR_ERROR(M_IESPI_PAR_ERROR), 1678167514Skmacy "PMRX ispi parity error", -1, 1 }, 1679167514Skmacy { V_OCSPI_PAR_ERROR(M_OCSPI_PAR_ERROR), 1680167514Skmacy "PMRX ospi parity error", -1, 1 }, 1681167514Skmacy { 0 } 1682167514Skmacy }; 1683167514Skmacy 1684167514Skmacy if (t3_handle_intr_status(adapter, A_PM1_RX_INT_CAUSE, 0xffffffff, 1685167514Skmacy pmrx_intr_info, NULL)) 1686167514Skmacy t3_fatal_err(adapter); 1687167514Skmacy} 1688167514Skmacy 1689167514Skmacy/* 1690167514Skmacy * CPL switch interrupt handler. 1691167514Skmacy */ 1692167514Skmacystatic void cplsw_intr_handler(adapter_t *adapter) 1693167514Skmacy{ 1694167514Skmacy static struct intr_info cplsw_intr_info[] = { 1695176472Skmacy { F_CIM_OP_MAP_PERR, "CPL switch CIM parity error", -1, 1 }, 1696176472Skmacy { F_CIM_OVFL_ERROR, "CPL switch CIM overflow", -1, 1 }, 1697167514Skmacy { F_TP_FRAMING_ERROR, "CPL switch TP framing error", -1, 1 }, 1698167514Skmacy { F_SGE_FRAMING_ERROR, "CPL switch SGE framing error", -1, 1 }, 1699167514Skmacy { F_CIM_FRAMING_ERROR, "CPL switch CIM framing error", -1, 1 }, 1700167514Skmacy { F_ZERO_SWITCH_ERROR, "CPL switch no-switch error", -1, 1 }, 1701167514Skmacy { 0 } 1702167514Skmacy }; 1703167514Skmacy 1704167514Skmacy if (t3_handle_intr_status(adapter, A_CPL_INTR_CAUSE, 0xffffffff, 1705167514Skmacy cplsw_intr_info, NULL)) 1706167514Skmacy t3_fatal_err(adapter); 1707167514Skmacy} 1708167514Skmacy 1709167514Skmacy/* 1710167514Skmacy * MPS interrupt handler. 1711167514Skmacy */ 1712167514Skmacystatic void mps_intr_handler(adapter_t *adapter) 1713167514Skmacy{ 1714167514Skmacy static struct intr_info mps_intr_info[] = { 1715167514Skmacy { 0x1ff, "MPS parity error", -1, 1 }, 1716167514Skmacy { 0 } 1717167514Skmacy }; 1718167514Skmacy 1719167514Skmacy if (t3_handle_intr_status(adapter, A_MPS_INT_CAUSE, 0xffffffff, 1720167514Skmacy mps_intr_info, NULL)) 1721167514Skmacy t3_fatal_err(adapter); 1722167514Skmacy} 1723167514Skmacy 1724167514Skmacy#define MC7_INTR_FATAL (F_UE | V_PE(M_PE) | F_AE) 1725167514Skmacy 1726167514Skmacy/* 1727167514Skmacy * MC7 interrupt handler. 1728167514Skmacy */ 1729167514Skmacystatic void mc7_intr_handler(struct mc7 *mc7) 1730167514Skmacy{ 1731167514Skmacy adapter_t *adapter = mc7->adapter; 1732167514Skmacy u32 cause = t3_read_reg(adapter, mc7->offset + A_MC7_INT_CAUSE); 1733167514Skmacy 1734167514Skmacy if (cause & F_CE) { 1735167514Skmacy mc7->stats.corr_err++; 1736167514Skmacy CH_WARN(adapter, "%s MC7 correctable error at addr 0x%x, " 1737167514Skmacy "data 0x%x 0x%x 0x%x\n", mc7->name, 1738167514Skmacy t3_read_reg(adapter, mc7->offset + A_MC7_CE_ADDR), 1739167514Skmacy t3_read_reg(adapter, mc7->offset + A_MC7_CE_DATA0), 1740167514Skmacy t3_read_reg(adapter, mc7->offset + A_MC7_CE_DATA1), 1741167514Skmacy t3_read_reg(adapter, mc7->offset + A_MC7_CE_DATA2)); 1742167514Skmacy } 1743167514Skmacy 1744167514Skmacy if (cause & F_UE) { 1745167514Skmacy mc7->stats.uncorr_err++; 1746167514Skmacy CH_ALERT(adapter, "%s MC7 uncorrectable error at addr 0x%x, " 1747167514Skmacy "data 0x%x 0x%x 0x%x\n", mc7->name, 1748167514Skmacy t3_read_reg(adapter, mc7->offset + A_MC7_UE_ADDR), 1749167514Skmacy t3_read_reg(adapter, mc7->offset + A_MC7_UE_DATA0), 1750167514Skmacy t3_read_reg(adapter, mc7->offset + A_MC7_UE_DATA1), 1751167514Skmacy t3_read_reg(adapter, mc7->offset + A_MC7_UE_DATA2)); 1752167514Skmacy } 1753167514Skmacy 1754167514Skmacy if (G_PE(cause)) { 1755167514Skmacy mc7->stats.parity_err++; 1756167514Skmacy CH_ALERT(adapter, "%s MC7 parity error 0x%x\n", 1757167514Skmacy mc7->name, G_PE(cause)); 1758167514Skmacy } 1759167514Skmacy 1760167514Skmacy if (cause & F_AE) { 1761167514Skmacy u32 addr = 0; 1762167514Skmacy 1763167514Skmacy if (adapter->params.rev > 0) 1764167514Skmacy addr = t3_read_reg(adapter, 1765167514Skmacy mc7->offset + A_MC7_ERR_ADDR); 1766167514Skmacy mc7->stats.addr_err++; 1767167514Skmacy CH_ALERT(adapter, "%s MC7 address error: 0x%x\n", 1768167514Skmacy mc7->name, addr); 1769167514Skmacy } 1770167514Skmacy 1771167514Skmacy if (cause & MC7_INTR_FATAL) 1772167514Skmacy t3_fatal_err(adapter); 1773167514Skmacy 1774167514Skmacy t3_write_reg(adapter, mc7->offset + A_MC7_INT_CAUSE, cause); 1775167514Skmacy} 1776167514Skmacy 1777167514Skmacy#define XGM_INTR_FATAL (V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR) | \ 1778167514Skmacy V_RXFIFO_PRTY_ERR(M_RXFIFO_PRTY_ERR)) 1779167514Skmacy/* 1780167514Skmacy * XGMAC interrupt handler. 1781167514Skmacy */ 1782167514Skmacystatic int mac_intr_handler(adapter_t *adap, unsigned int idx) 1783167514Skmacy{ 1784170654Skmacy u32 cause; 1785170654Skmacy struct cmac *mac; 1786167514Skmacy 1787170654Skmacy idx = idx == 0 ? 0 : adapter_info(adap)->nports0; /* MAC idx -> port */ 1788170654Skmacy mac = &adap2pinfo(adap, idx)->mac; 1789170654Skmacy cause = t3_read_reg(adap, A_XGM_INT_CAUSE + mac->offset); 1790170654Skmacy 1791167514Skmacy if (cause & V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR)) { 1792167514Skmacy mac->stats.tx_fifo_parity_err++; 1793167514Skmacy CH_ALERT(adap, "port%d: MAC TX FIFO parity error\n", idx); 1794167514Skmacy } 1795167514Skmacy if (cause & V_RXFIFO_PRTY_ERR(M_RXFIFO_PRTY_ERR)) { 1796167514Skmacy mac->stats.rx_fifo_parity_err++; 1797167514Skmacy CH_ALERT(adap, "port%d: MAC RX FIFO parity error\n", idx); 1798167514Skmacy } 1799167514Skmacy if (cause & F_TXFIFO_UNDERRUN) 1800167514Skmacy mac->stats.tx_fifo_urun++; 1801167514Skmacy if (cause & F_RXFIFO_OVERFLOW) 1802167514Skmacy mac->stats.rx_fifo_ovfl++; 1803167514Skmacy if (cause & V_SERDES_LOS(M_SERDES_LOS)) 1804167514Skmacy mac->stats.serdes_signal_loss++; 1805167514Skmacy if (cause & F_XAUIPCSCTCERR) 1806167514Skmacy mac->stats.xaui_pcs_ctc_err++; 1807167514Skmacy if (cause & F_XAUIPCSALIGNCHANGE) 1808167514Skmacy mac->stats.xaui_pcs_align_change++; 1809167514Skmacy 1810167514Skmacy t3_write_reg(adap, A_XGM_INT_CAUSE + mac->offset, cause); 1811167514Skmacy if (cause & XGM_INTR_FATAL) 1812167514Skmacy t3_fatal_err(adap); 1813167514Skmacy return cause != 0; 1814167514Skmacy} 1815167514Skmacy 1816167514Skmacy/* 1817167514Skmacy * Interrupt handler for PHY events. 1818167514Skmacy */ 1819167514Skmacyint t3_phy_intr_handler(adapter_t *adapter) 1820167514Skmacy{ 1821167514Skmacy u32 i, cause = t3_read_reg(adapter, A_T3DBG_INT_CAUSE); 1822167514Skmacy 1823167514Skmacy for_each_port(adapter, i) { 1824170654Skmacy struct port_info *p = adap2pinfo(adapter, i); 1825167514Skmacy 1826176472Skmacy if (!(p->phy.caps & SUPPORTED_IRQ)) 1827167514Skmacy continue; 1828167514Skmacy 1829180583Skmacy if (cause & (1 << adapter_info(adapter)->gpio_intr[i])) { 1830167514Skmacy int phy_cause = p->phy.ops->intr_handler(&p->phy); 1831167514Skmacy 1832167514Skmacy if (phy_cause & cphy_cause_link_change) 1833167514Skmacy t3_link_changed(adapter, i); 1834167514Skmacy if (phy_cause & cphy_cause_fifo_error) 1835167514Skmacy p->phy.fifo_errors++; 1836181614Skmacy if (phy_cause & cphy_cause_module_change) 1837181614Skmacy t3_os_phymod_changed(adapter, i); 1838167514Skmacy } 1839167514Skmacy } 1840167514Skmacy 1841167514Skmacy t3_write_reg(adapter, A_T3DBG_INT_CAUSE, cause); 1842167514Skmacy return 0; 1843167514Skmacy} 1844167514Skmacy 1845172096Skmacy/** 1846172096Skmacy * t3_slow_intr_handler - control path interrupt handler 1847172096Skmacy * @adapter: the adapter 1848172096Skmacy * 1849172096Skmacy * T3 interrupt handler for non-data interrupt events, e.g., errors. 1850172096Skmacy * The designation 'slow' is because it involves register reads, while 1851172096Skmacy * data interrupts typically don't involve any MMIOs. 1852167514Skmacy */ 1853167514Skmacyint t3_slow_intr_handler(adapter_t *adapter) 1854167514Skmacy{ 1855167514Skmacy u32 cause = t3_read_reg(adapter, A_PL_INT_CAUSE0); 1856167514Skmacy 1857167514Skmacy cause &= adapter->slow_intr_mask; 1858167514Skmacy if (!cause) 1859167514Skmacy return 0; 1860167514Skmacy if (cause & F_PCIM0) { 1861167514Skmacy if (is_pcie(adapter)) 1862167514Skmacy pcie_intr_handler(adapter); 1863167514Skmacy else 1864167514Skmacy pci_intr_handler(adapter); 1865167514Skmacy } 1866167514Skmacy if (cause & F_SGE3) 1867167514Skmacy t3_sge_err_intr_handler(adapter); 1868167514Skmacy if (cause & F_MC7_PMRX) 1869167514Skmacy mc7_intr_handler(&adapter->pmrx); 1870167514Skmacy if (cause & F_MC7_PMTX) 1871167514Skmacy mc7_intr_handler(&adapter->pmtx); 1872167514Skmacy if (cause & F_MC7_CM) 1873167514Skmacy mc7_intr_handler(&adapter->cm); 1874167514Skmacy if (cause & F_CIM) 1875167514Skmacy cim_intr_handler(adapter); 1876167514Skmacy if (cause & F_TP1) 1877167514Skmacy tp_intr_handler(adapter); 1878167514Skmacy if (cause & F_ULP2_RX) 1879167514Skmacy ulprx_intr_handler(adapter); 1880167514Skmacy if (cause & F_ULP2_TX) 1881167514Skmacy ulptx_intr_handler(adapter); 1882167514Skmacy if (cause & F_PM1_RX) 1883167514Skmacy pmrx_intr_handler(adapter); 1884167514Skmacy if (cause & F_PM1_TX) 1885167514Skmacy pmtx_intr_handler(adapter); 1886167514Skmacy if (cause & F_CPL_SWITCH) 1887167514Skmacy cplsw_intr_handler(adapter); 1888167514Skmacy if (cause & F_MPS0) 1889167514Skmacy mps_intr_handler(adapter); 1890167514Skmacy if (cause & F_MC5A) 1891167514Skmacy t3_mc5_intr_handler(&adapter->mc5); 1892167514Skmacy if (cause & F_XGMAC0_0) 1893167514Skmacy mac_intr_handler(adapter, 0); 1894167514Skmacy if (cause & F_XGMAC0_1) 1895167514Skmacy mac_intr_handler(adapter, 1); 1896167514Skmacy if (cause & F_T3DBG) 1897167514Skmacy t3_os_ext_intr_handler(adapter); 1898167514Skmacy 1899167514Skmacy /* Clear the interrupts just processed. */ 1900167514Skmacy t3_write_reg(adapter, A_PL_INT_CAUSE0, cause); 1901167514Skmacy (void) t3_read_reg(adapter, A_PL_INT_CAUSE0); /* flush */ 1902167514Skmacy return 1; 1903167514Skmacy} 1904167514Skmacy 1905180583Skmacystatic unsigned int calc_gpio_intr(adapter_t *adap) 1906180583Skmacy{ 1907180583Skmacy unsigned int i, gpi_intr = 0; 1908180583Skmacy 1909180583Skmacy for_each_port(adap, i) 1910180583Skmacy if ((adap2pinfo(adap, i)->phy.caps & SUPPORTED_IRQ) && 1911180583Skmacy adapter_info(adap)->gpio_intr[i]) 1912180583Skmacy gpi_intr |= 1 << adapter_info(adap)->gpio_intr[i]; 1913180583Skmacy return gpi_intr; 1914180583Skmacy} 1915180583Skmacy 1916167514Skmacy/** 1917167514Skmacy * t3_intr_enable - enable interrupts 1918167514Skmacy * @adapter: the adapter whose interrupts should be enabled 1919167514Skmacy * 1920167514Skmacy * Enable interrupts by setting the interrupt enable registers of the 1921167514Skmacy * various HW modules and then enabling the top-level interrupt 1922167514Skmacy * concentrator. 1923167514Skmacy */ 1924167514Skmacyvoid t3_intr_enable(adapter_t *adapter) 1925167514Skmacy{ 1926167514Skmacy static struct addr_val_pair intr_en_avp[] = { 1927167514Skmacy { A_MC7_INT_ENABLE, MC7_INTR_MASK }, 1928167514Skmacy { A_MC7_INT_ENABLE - MC7_PMRX_BASE_ADDR + MC7_PMTX_BASE_ADDR, 1929167514Skmacy MC7_INTR_MASK }, 1930167514Skmacy { A_MC7_INT_ENABLE - MC7_PMRX_BASE_ADDR + MC7_CM_BASE_ADDR, 1931167514Skmacy MC7_INTR_MASK }, 1932167514Skmacy { A_MC5_DB_INT_ENABLE, MC5_INTR_MASK }, 1933167514Skmacy { A_ULPRX_INT_ENABLE, ULPRX_INTR_MASK }, 1934167514Skmacy { A_PM1_TX_INT_ENABLE, PMTX_INTR_MASK }, 1935167514Skmacy { A_PM1_RX_INT_ENABLE, PMRX_INTR_MASK }, 1936167514Skmacy { A_CIM_HOST_INT_ENABLE, CIM_INTR_MASK }, 1937167514Skmacy { A_MPS_INT_ENABLE, MPS_INTR_MASK }, 1938167514Skmacy }; 1939167514Skmacy 1940167514Skmacy adapter->slow_intr_mask = PL_INTR_MASK; 1941167514Skmacy 1942167514Skmacy t3_write_regs(adapter, intr_en_avp, ARRAY_SIZE(intr_en_avp), 0); 1943176472Skmacy t3_write_reg(adapter, A_TP_INT_ENABLE, 1944176472Skmacy adapter->params.rev >= T3_REV_C ? 0x2bfffff : 0x3bfffff); 1945181614Skmacy t3_write_reg(adapter, A_SG_INT_ENABLE, 1946181614Skmacy adapter->params.rev >= T3_REV_C ? 1947181614Skmacy SGE_INTR_MASK | F_FLEMPTY : SGE_INTR_MASK); 1948167514Skmacy 1949167514Skmacy if (adapter->params.rev > 0) { 1950167514Skmacy t3_write_reg(adapter, A_CPL_INTR_ENABLE, 1951167514Skmacy CPLSW_INTR_MASK | F_CIM_OVFL_ERROR); 1952167514Skmacy t3_write_reg(adapter, A_ULPTX_INT_ENABLE, 1953167514Skmacy ULPTX_INTR_MASK | F_PBL_BOUND_ERR_CH0 | 1954167514Skmacy F_PBL_BOUND_ERR_CH1); 1955167514Skmacy } else { 1956167514Skmacy t3_write_reg(adapter, A_CPL_INTR_ENABLE, CPLSW_INTR_MASK); 1957167514Skmacy t3_write_reg(adapter, A_ULPTX_INT_ENABLE, ULPTX_INTR_MASK); 1958167514Skmacy } 1959167514Skmacy 1960180583Skmacy t3_write_reg(adapter, A_T3DBG_INT_ENABLE, calc_gpio_intr(adapter)); 1961180583Skmacy 1962170654Skmacy if (is_pcie(adapter)) 1963167514Skmacy t3_write_reg(adapter, A_PCIE_INT_ENABLE, PCIE_INTR_MASK); 1964170654Skmacy else 1965167514Skmacy t3_write_reg(adapter, A_PCIX_INT_ENABLE, PCIX_INTR_MASK); 1966167514Skmacy t3_write_reg(adapter, A_PL_INT_ENABLE0, adapter->slow_intr_mask); 1967167514Skmacy (void) t3_read_reg(adapter, A_PL_INT_ENABLE0); /* flush */ 1968167514Skmacy} 1969167514Skmacy 1970167514Skmacy/** 1971167514Skmacy * t3_intr_disable - disable a card's interrupts 1972167514Skmacy * @adapter: the adapter whose interrupts should be disabled 1973167514Skmacy * 1974167514Skmacy * Disable interrupts. We only disable the top-level interrupt 1975167514Skmacy * concentrator and the SGE data interrupts. 1976167514Skmacy */ 1977167514Skmacyvoid t3_intr_disable(adapter_t *adapter) 1978167514Skmacy{ 1979167514Skmacy t3_write_reg(adapter, A_PL_INT_ENABLE0, 0); 1980167514Skmacy (void) t3_read_reg(adapter, A_PL_INT_ENABLE0); /* flush */ 1981167514Skmacy adapter->slow_intr_mask = 0; 1982167514Skmacy} 1983167514Skmacy 1984167514Skmacy/** 1985167514Skmacy * t3_intr_clear - clear all interrupts 1986167514Skmacy * @adapter: the adapter whose interrupts should be cleared 1987167514Skmacy * 1988167514Skmacy * Clears all interrupts. 1989167514Skmacy */ 1990167514Skmacyvoid t3_intr_clear(adapter_t *adapter) 1991167514Skmacy{ 1992167514Skmacy static const unsigned int cause_reg_addr[] = { 1993167514Skmacy A_SG_INT_CAUSE, 1994167514Skmacy A_SG_RSPQ_FL_STATUS, 1995167514Skmacy A_PCIX_INT_CAUSE, 1996167514Skmacy A_MC7_INT_CAUSE, 1997167514Skmacy A_MC7_INT_CAUSE - MC7_PMRX_BASE_ADDR + MC7_PMTX_BASE_ADDR, 1998167514Skmacy A_MC7_INT_CAUSE - MC7_PMRX_BASE_ADDR + MC7_CM_BASE_ADDR, 1999167514Skmacy A_CIM_HOST_INT_CAUSE, 2000167514Skmacy A_TP_INT_CAUSE, 2001167514Skmacy A_MC5_DB_INT_CAUSE, 2002167514Skmacy A_ULPRX_INT_CAUSE, 2003167514Skmacy A_ULPTX_INT_CAUSE, 2004167514Skmacy A_CPL_INTR_CAUSE, 2005167514Skmacy A_PM1_TX_INT_CAUSE, 2006167514Skmacy A_PM1_RX_INT_CAUSE, 2007167514Skmacy A_MPS_INT_CAUSE, 2008167514Skmacy A_T3DBG_INT_CAUSE, 2009167514Skmacy }; 2010167514Skmacy unsigned int i; 2011167514Skmacy 2012167514Skmacy /* Clear PHY and MAC interrupts for each port. */ 2013167514Skmacy for_each_port(adapter, i) 2014167514Skmacy t3_port_intr_clear(adapter, i); 2015167514Skmacy 2016167514Skmacy for (i = 0; i < ARRAY_SIZE(cause_reg_addr); ++i) 2017167514Skmacy t3_write_reg(adapter, cause_reg_addr[i], 0xffffffff); 2018167514Skmacy 2019172096Skmacy if (is_pcie(adapter)) 2020172096Skmacy t3_write_reg(adapter, A_PCIE_PEX_ERR, 0xffffffff); 2021167514Skmacy t3_write_reg(adapter, A_PL_INT_CAUSE0, 0xffffffff); 2022167514Skmacy (void) t3_read_reg(adapter, A_PL_INT_CAUSE0); /* flush */ 2023167514Skmacy} 2024167514Skmacy 2025167514Skmacy/** 2026167514Skmacy * t3_port_intr_enable - enable port-specific interrupts 2027167514Skmacy * @adapter: associated adapter 2028167514Skmacy * @idx: index of port whose interrupts should be enabled 2029167514Skmacy * 2030167514Skmacy * Enable port-specific (i.e., MAC and PHY) interrupts for the given 2031167514Skmacy * adapter port. 2032167514Skmacy */ 2033167514Skmacyvoid t3_port_intr_enable(adapter_t *adapter, int idx) 2034167514Skmacy{ 2035170654Skmacy struct port_info *pi = adap2pinfo(adapter, idx); 2036170654Skmacy 2037170654Skmacy t3_write_reg(adapter, A_XGM_INT_ENABLE + pi->mac.offset, XGM_INTR_MASK); 2038170654Skmacy pi->phy.ops->intr_enable(&pi->phy); 2039167514Skmacy} 2040167514Skmacy 2041167514Skmacy/** 2042167514Skmacy * t3_port_intr_disable - disable port-specific interrupts 2043167514Skmacy * @adapter: associated adapter 2044167514Skmacy * @idx: index of port whose interrupts should be disabled 2045167514Skmacy * 2046167514Skmacy * Disable port-specific (i.e., MAC and PHY) interrupts for the given 2047167514Skmacy * adapter port. 2048167514Skmacy */ 2049167514Skmacyvoid t3_port_intr_disable(adapter_t *adapter, int idx) 2050167514Skmacy{ 2051170654Skmacy struct port_info *pi = adap2pinfo(adapter, idx); 2052170654Skmacy 2053170654Skmacy t3_write_reg(adapter, A_XGM_INT_ENABLE + pi->mac.offset, 0); 2054170654Skmacy pi->phy.ops->intr_disable(&pi->phy); 2055167514Skmacy} 2056167514Skmacy 2057167514Skmacy/** 2058167514Skmacy * t3_port_intr_clear - clear port-specific interrupts 2059167514Skmacy * @adapter: associated adapter 2060167514Skmacy * @idx: index of port whose interrupts to clear 2061167514Skmacy * 2062167514Skmacy * Clear port-specific (i.e., MAC and PHY) interrupts for the given 2063167514Skmacy * adapter port. 2064167514Skmacy */ 2065167514Skmacyvoid t3_port_intr_clear(adapter_t *adapter, int idx) 2066167514Skmacy{ 2067170654Skmacy struct port_info *pi = adap2pinfo(adapter, idx); 2068170654Skmacy 2069170654Skmacy t3_write_reg(adapter, A_XGM_INT_CAUSE + pi->mac.offset, 0xffffffff); 2070170654Skmacy pi->phy.ops->intr_clear(&pi->phy); 2071167514Skmacy} 2072167514Skmacy 2073172096Skmacy#define SG_CONTEXT_CMD_ATTEMPTS 100 2074172096Skmacy 2075167514Skmacy/** 2076167514Skmacy * t3_sge_write_context - write an SGE context 2077167514Skmacy * @adapter: the adapter 2078167514Skmacy * @id: the context id 2079167514Skmacy * @type: the context type 2080167514Skmacy * 2081167514Skmacy * Program an SGE context with the values already loaded in the 2082167514Skmacy * CONTEXT_DATA? registers. 2083167514Skmacy */ 2084167514Skmacystatic int t3_sge_write_context(adapter_t *adapter, unsigned int id, 2085167514Skmacy unsigned int type) 2086167514Skmacy{ 2087167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0xffffffff); 2088167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0xffffffff); 2089167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0xffffffff); 2090167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0xffffffff); 2091167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_CMD, 2092167514Skmacy V_CONTEXT_CMD_OPCODE(1) | type | V_CONTEXT(id)); 2093167514Skmacy return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, 2094172096Skmacy 0, SG_CONTEXT_CMD_ATTEMPTS, 1); 2095167514Skmacy} 2096167514Skmacy 2097176472Skmacystatic int clear_sge_ctxt(adapter_t *adap, unsigned int id, unsigned int type) 2098176472Skmacy{ 2099176472Skmacy t3_write_reg(adap, A_SG_CONTEXT_DATA0, 0); 2100176472Skmacy t3_write_reg(adap, A_SG_CONTEXT_DATA1, 0); 2101176472Skmacy t3_write_reg(adap, A_SG_CONTEXT_DATA2, 0); 2102176472Skmacy t3_write_reg(adap, A_SG_CONTEXT_DATA3, 0); 2103176472Skmacy return t3_sge_write_context(adap, id, type); 2104176472Skmacy} 2105176472Skmacy 2106167514Skmacy/** 2107167514Skmacy * t3_sge_init_ecntxt - initialize an SGE egress context 2108167514Skmacy * @adapter: the adapter to configure 2109167514Skmacy * @id: the context id 2110167514Skmacy * @gts_enable: whether to enable GTS for the context 2111167514Skmacy * @type: the egress context type 2112167514Skmacy * @respq: associated response queue 2113167514Skmacy * @base_addr: base address of queue 2114167514Skmacy * @size: number of queue entries 2115167514Skmacy * @token: uP token 2116167514Skmacy * @gen: initial generation value for the context 2117167514Skmacy * @cidx: consumer pointer 2118167514Skmacy * 2119167514Skmacy * Initialize an SGE egress context and make it ready for use. If the 2120167514Skmacy * platform allows concurrent context operations, the caller is 2121167514Skmacy * responsible for appropriate locking. 2122167514Skmacy */ 2123167514Skmacyint t3_sge_init_ecntxt(adapter_t *adapter, unsigned int id, int gts_enable, 2124167514Skmacy enum sge_context_type type, int respq, u64 base_addr, 2125167514Skmacy unsigned int size, unsigned int token, int gen, 2126167514Skmacy unsigned int cidx) 2127167514Skmacy{ 2128167514Skmacy unsigned int credits = type == SGE_CNTXT_OFLD ? 0 : FW_WR_NUM; 2129167514Skmacy 2130167514Skmacy if (base_addr & 0xfff) /* must be 4K aligned */ 2131167514Skmacy return -EINVAL; 2132167514Skmacy if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) 2133167514Skmacy return -EBUSY; 2134167514Skmacy 2135167514Skmacy base_addr >>= 12; 2136167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA0, V_EC_INDEX(cidx) | 2137167514Skmacy V_EC_CREDITS(credits) | V_EC_GTS(gts_enable)); 2138167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA1, V_EC_SIZE(size) | 2139167514Skmacy V_EC_BASE_LO((u32)base_addr & 0xffff)); 2140167514Skmacy base_addr >>= 16; 2141167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA2, (u32)base_addr); 2142167514Skmacy base_addr >>= 32; 2143167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA3, 2144167514Skmacy V_EC_BASE_HI((u32)base_addr & 0xf) | V_EC_RESPQ(respq) | 2145167514Skmacy V_EC_TYPE(type) | V_EC_GEN(gen) | V_EC_UP_TOKEN(token) | 2146167514Skmacy F_EC_VALID); 2147167514Skmacy return t3_sge_write_context(adapter, id, F_EGRESS); 2148167514Skmacy} 2149167514Skmacy 2150167514Skmacy/** 2151167514Skmacy * t3_sge_init_flcntxt - initialize an SGE free-buffer list context 2152167514Skmacy * @adapter: the adapter to configure 2153167514Skmacy * @id: the context id 2154167514Skmacy * @gts_enable: whether to enable GTS for the context 2155167514Skmacy * @base_addr: base address of queue 2156167514Skmacy * @size: number of queue entries 2157167514Skmacy * @bsize: size of each buffer for this queue 2158167514Skmacy * @cong_thres: threshold to signal congestion to upstream producers 2159167514Skmacy * @gen: initial generation value for the context 2160167514Skmacy * @cidx: consumer pointer 2161167514Skmacy * 2162167514Skmacy * Initialize an SGE free list context and make it ready for use. The 2163167514Skmacy * caller is responsible for ensuring only one context operation occurs 2164167514Skmacy * at a time. 2165167514Skmacy */ 2166167514Skmacyint t3_sge_init_flcntxt(adapter_t *adapter, unsigned int id, int gts_enable, 2167167514Skmacy u64 base_addr, unsigned int size, unsigned int bsize, 2168167514Skmacy unsigned int cong_thres, int gen, unsigned int cidx) 2169167514Skmacy{ 2170167514Skmacy if (base_addr & 0xfff) /* must be 4K aligned */ 2171167514Skmacy return -EINVAL; 2172167514Skmacy if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) 2173167514Skmacy return -EBUSY; 2174167514Skmacy 2175167514Skmacy base_addr >>= 12; 2176167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA0, (u32)base_addr); 2177167514Skmacy base_addr >>= 32; 2178167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA1, 2179167514Skmacy V_FL_BASE_HI((u32)base_addr) | 2180167514Skmacy V_FL_INDEX_LO(cidx & M_FL_INDEX_LO)); 2181167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA2, V_FL_SIZE(size) | 2182167514Skmacy V_FL_GEN(gen) | V_FL_INDEX_HI(cidx >> 12) | 2183167514Skmacy V_FL_ENTRY_SIZE_LO(bsize & M_FL_ENTRY_SIZE_LO)); 2184167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA3, 2185167514Skmacy V_FL_ENTRY_SIZE_HI(bsize >> (32 - S_FL_ENTRY_SIZE_LO)) | 2186167514Skmacy V_FL_CONG_THRES(cong_thres) | V_FL_GTS(gts_enable)); 2187167514Skmacy return t3_sge_write_context(adapter, id, F_FREELIST); 2188167514Skmacy} 2189167514Skmacy 2190167514Skmacy/** 2191167514Skmacy * t3_sge_init_rspcntxt - initialize an SGE response queue context 2192167514Skmacy * @adapter: the adapter to configure 2193167514Skmacy * @id: the context id 2194167514Skmacy * @irq_vec_idx: MSI-X interrupt vector index, 0 if no MSI-X, -1 if no IRQ 2195167514Skmacy * @base_addr: base address of queue 2196167514Skmacy * @size: number of queue entries 2197167514Skmacy * @fl_thres: threshold for selecting the normal or jumbo free list 2198167514Skmacy * @gen: initial generation value for the context 2199167514Skmacy * @cidx: consumer pointer 2200167514Skmacy * 2201167514Skmacy * Initialize an SGE response queue context and make it ready for use. 2202167514Skmacy * The caller is responsible for ensuring only one context operation 2203167514Skmacy * occurs at a time. 2204167514Skmacy */ 2205167514Skmacyint t3_sge_init_rspcntxt(adapter_t *adapter, unsigned int id, int irq_vec_idx, 2206167514Skmacy u64 base_addr, unsigned int size, 2207167514Skmacy unsigned int fl_thres, int gen, unsigned int cidx) 2208167514Skmacy{ 2209167514Skmacy unsigned int intr = 0; 2210167514Skmacy 2211167514Skmacy if (base_addr & 0xfff) /* must be 4K aligned */ 2212167514Skmacy return -EINVAL; 2213167514Skmacy if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) 2214167514Skmacy return -EBUSY; 2215167514Skmacy 2216167514Skmacy base_addr >>= 12; 2217167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA0, V_CQ_SIZE(size) | 2218167514Skmacy V_CQ_INDEX(cidx)); 2219167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA1, (u32)base_addr); 2220167514Skmacy base_addr >>= 32; 2221167514Skmacy if (irq_vec_idx >= 0) 2222167514Skmacy intr = V_RQ_MSI_VEC(irq_vec_idx) | F_RQ_INTR_EN; 2223167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA2, 2224167514Skmacy V_CQ_BASE_HI((u32)base_addr) | intr | V_RQ_GEN(gen)); 2225167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA3, fl_thres); 2226167514Skmacy return t3_sge_write_context(adapter, id, F_RESPONSEQ); 2227167514Skmacy} 2228167514Skmacy 2229167514Skmacy/** 2230167514Skmacy * t3_sge_init_cqcntxt - initialize an SGE completion queue context 2231167514Skmacy * @adapter: the adapter to configure 2232167514Skmacy * @id: the context id 2233167514Skmacy * @base_addr: base address of queue 2234167514Skmacy * @size: number of queue entries 2235167514Skmacy * @rspq: response queue for async notifications 2236167514Skmacy * @ovfl_mode: CQ overflow mode 2237167514Skmacy * @credits: completion queue credits 2238167514Skmacy * @credit_thres: the credit threshold 2239167514Skmacy * 2240167514Skmacy * Initialize an SGE completion queue context and make it ready for use. 2241167514Skmacy * The caller is responsible for ensuring only one context operation 2242167514Skmacy * occurs at a time. 2243167514Skmacy */ 2244167514Skmacyint t3_sge_init_cqcntxt(adapter_t *adapter, unsigned int id, u64 base_addr, 2245167514Skmacy unsigned int size, int rspq, int ovfl_mode, 2246167514Skmacy unsigned int credits, unsigned int credit_thres) 2247167514Skmacy{ 2248167514Skmacy if (base_addr & 0xfff) /* must be 4K aligned */ 2249167514Skmacy return -EINVAL; 2250167514Skmacy if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) 2251167514Skmacy return -EBUSY; 2252167514Skmacy 2253167514Skmacy base_addr >>= 12; 2254167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA0, V_CQ_SIZE(size)); 2255167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA1, (u32)base_addr); 2256167514Skmacy base_addr >>= 32; 2257167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA2, 2258167514Skmacy V_CQ_BASE_HI((u32)base_addr) | V_CQ_RSPQ(rspq) | 2259172096Skmacy V_CQ_GEN(1) | V_CQ_OVERFLOW_MODE(ovfl_mode) | 2260172096Skmacy V_CQ_ERR(ovfl_mode)); 2261167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA3, V_CQ_CREDITS(credits) | 2262167514Skmacy V_CQ_CREDIT_THRES(credit_thres)); 2263167514Skmacy return t3_sge_write_context(adapter, id, F_CQ); 2264167514Skmacy} 2265167514Skmacy 2266167514Skmacy/** 2267167514Skmacy * t3_sge_enable_ecntxt - enable/disable an SGE egress context 2268167514Skmacy * @adapter: the adapter 2269167514Skmacy * @id: the egress context id 2270167514Skmacy * @enable: enable (1) or disable (0) the context 2271167514Skmacy * 2272167514Skmacy * Enable or disable an SGE egress context. The caller is responsible for 2273167514Skmacy * ensuring only one context operation occurs at a time. 2274167514Skmacy */ 2275167514Skmacyint t3_sge_enable_ecntxt(adapter_t *adapter, unsigned int id, int enable) 2276167514Skmacy{ 2277167514Skmacy if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) 2278167514Skmacy return -EBUSY; 2279167514Skmacy 2280167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0); 2281167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0); 2282167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0); 2283167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_MASK3, F_EC_VALID); 2284167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA3, V_EC_VALID(enable)); 2285167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_CMD, 2286167514Skmacy V_CONTEXT_CMD_OPCODE(1) | F_EGRESS | V_CONTEXT(id)); 2287167514Skmacy return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, 2288172096Skmacy 0, SG_CONTEXT_CMD_ATTEMPTS, 1); 2289167514Skmacy} 2290167514Skmacy 2291167514Skmacy/** 2292167514Skmacy * t3_sge_disable_fl - disable an SGE free-buffer list 2293167514Skmacy * @adapter: the adapter 2294167514Skmacy * @id: the free list context id 2295167514Skmacy * 2296167514Skmacy * Disable an SGE free-buffer list. The caller is responsible for 2297167514Skmacy * ensuring only one context operation occurs at a time. 2298167514Skmacy */ 2299167514Skmacyint t3_sge_disable_fl(adapter_t *adapter, unsigned int id) 2300167514Skmacy{ 2301167514Skmacy if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) 2302167514Skmacy return -EBUSY; 2303167514Skmacy 2304167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0); 2305167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0); 2306167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_MASK2, V_FL_SIZE(M_FL_SIZE)); 2307167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0); 2308167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA2, 0); 2309167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_CMD, 2310167514Skmacy V_CONTEXT_CMD_OPCODE(1) | F_FREELIST | V_CONTEXT(id)); 2311167514Skmacy return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, 2312172096Skmacy 0, SG_CONTEXT_CMD_ATTEMPTS, 1); 2313167514Skmacy} 2314167514Skmacy 2315167514Skmacy/** 2316167514Skmacy * t3_sge_disable_rspcntxt - disable an SGE response queue 2317167514Skmacy * @adapter: the adapter 2318167514Skmacy * @id: the response queue context id 2319167514Skmacy * 2320167514Skmacy * Disable an SGE response queue. The caller is responsible for 2321167514Skmacy * ensuring only one context operation occurs at a time. 2322167514Skmacy */ 2323167514Skmacyint t3_sge_disable_rspcntxt(adapter_t *adapter, unsigned int id) 2324167514Skmacy{ 2325167514Skmacy if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) 2326167514Skmacy return -EBUSY; 2327167514Skmacy 2328167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_MASK0, V_CQ_SIZE(M_CQ_SIZE)); 2329167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0); 2330167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0); 2331167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0); 2332167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA0, 0); 2333167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_CMD, 2334167514Skmacy V_CONTEXT_CMD_OPCODE(1) | F_RESPONSEQ | V_CONTEXT(id)); 2335167514Skmacy return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, 2336172096Skmacy 0, SG_CONTEXT_CMD_ATTEMPTS, 1); 2337167514Skmacy} 2338167514Skmacy 2339167514Skmacy/** 2340167514Skmacy * t3_sge_disable_cqcntxt - disable an SGE completion queue 2341167514Skmacy * @adapter: the adapter 2342167514Skmacy * @id: the completion queue context id 2343167514Skmacy * 2344167514Skmacy * Disable an SGE completion queue. The caller is responsible for 2345167514Skmacy * ensuring only one context operation occurs at a time. 2346167514Skmacy */ 2347167514Skmacyint t3_sge_disable_cqcntxt(adapter_t *adapter, unsigned int id) 2348167514Skmacy{ 2349167514Skmacy if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) 2350167514Skmacy return -EBUSY; 2351167514Skmacy 2352167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_MASK0, V_CQ_SIZE(M_CQ_SIZE)); 2353167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0); 2354167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0); 2355167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0); 2356167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA0, 0); 2357167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_CMD, 2358167514Skmacy V_CONTEXT_CMD_OPCODE(1) | F_CQ | V_CONTEXT(id)); 2359167514Skmacy return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, 2360172096Skmacy 0, SG_CONTEXT_CMD_ATTEMPTS, 1); 2361167514Skmacy} 2362167514Skmacy 2363167514Skmacy/** 2364167514Skmacy * t3_sge_cqcntxt_op - perform an operation on a completion queue context 2365167514Skmacy * @adapter: the adapter 2366167514Skmacy * @id: the context id 2367167514Skmacy * @op: the operation to perform 2368172096Skmacy * @credits: credits to return to the CQ 2369167514Skmacy * 2370167514Skmacy * Perform the selected operation on an SGE completion queue context. 2371167514Skmacy * The caller is responsible for ensuring only one context operation 2372167514Skmacy * occurs at a time. 2373172096Skmacy * 2374172096Skmacy * For most operations the function returns the current HW position in 2375172096Skmacy * the completion queue. 2376167514Skmacy */ 2377167514Skmacyint t3_sge_cqcntxt_op(adapter_t *adapter, unsigned int id, unsigned int op, 2378167514Skmacy unsigned int credits) 2379167514Skmacy{ 2380167514Skmacy u32 val; 2381167514Skmacy 2382167514Skmacy if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) 2383167514Skmacy return -EBUSY; 2384167514Skmacy 2385167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_DATA0, credits << 16); 2386167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_CMD, V_CONTEXT_CMD_OPCODE(op) | 2387167514Skmacy V_CONTEXT(id) | F_CQ); 2388167514Skmacy if (t3_wait_op_done_val(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, 2389172096Skmacy 0, SG_CONTEXT_CMD_ATTEMPTS, 1, &val)) 2390167514Skmacy return -EIO; 2391167514Skmacy 2392167514Skmacy if (op >= 2 && op < 7) { 2393167514Skmacy if (adapter->params.rev > 0) 2394167514Skmacy return G_CQ_INDEX(val); 2395167514Skmacy 2396167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_CMD, 2397167514Skmacy V_CONTEXT_CMD_OPCODE(0) | F_CQ | V_CONTEXT(id)); 2398167514Skmacy if (t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, 2399172096Skmacy F_CONTEXT_CMD_BUSY, 0, 2400172096Skmacy SG_CONTEXT_CMD_ATTEMPTS, 1)) 2401167514Skmacy return -EIO; 2402167514Skmacy return G_CQ_INDEX(t3_read_reg(adapter, A_SG_CONTEXT_DATA0)); 2403167514Skmacy } 2404167514Skmacy return 0; 2405167514Skmacy} 2406167514Skmacy 2407167514Skmacy/** 2408167514Skmacy * t3_sge_read_context - read an SGE context 2409167514Skmacy * @type: the context type 2410167514Skmacy * @adapter: the adapter 2411167514Skmacy * @id: the context id 2412167514Skmacy * @data: holds the retrieved context 2413167514Skmacy * 2414167514Skmacy * Read an SGE egress context. The caller is responsible for ensuring 2415167514Skmacy * only one context operation occurs at a time. 2416167514Skmacy */ 2417167514Skmacystatic int t3_sge_read_context(unsigned int type, adapter_t *adapter, 2418167514Skmacy unsigned int id, u32 data[4]) 2419167514Skmacy{ 2420167514Skmacy if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) 2421167514Skmacy return -EBUSY; 2422167514Skmacy 2423167514Skmacy t3_write_reg(adapter, A_SG_CONTEXT_CMD, 2424167514Skmacy V_CONTEXT_CMD_OPCODE(0) | type | V_CONTEXT(id)); 2425167514Skmacy if (t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, 0, 2426172096Skmacy SG_CONTEXT_CMD_ATTEMPTS, 1)) 2427167514Skmacy return -EIO; 2428167514Skmacy data[0] = t3_read_reg(adapter, A_SG_CONTEXT_DATA0); 2429167514Skmacy data[1] = t3_read_reg(adapter, A_SG_CONTEXT_DATA1); 2430167514Skmacy data[2] = t3_read_reg(adapter, A_SG_CONTEXT_DATA2); 2431167514Skmacy data[3] = t3_read_reg(adapter, A_SG_CONTEXT_DATA3); 2432167514Skmacy return 0; 2433167514Skmacy} 2434167514Skmacy 2435167514Skmacy/** 2436167514Skmacy * t3_sge_read_ecntxt - read an SGE egress context 2437167514Skmacy * @adapter: the adapter 2438167514Skmacy * @id: the context id 2439167514Skmacy * @data: holds the retrieved context 2440167514Skmacy * 2441167514Skmacy * Read an SGE egress context. The caller is responsible for ensuring 2442167514Skmacy * only one context operation occurs at a time. 2443167514Skmacy */ 2444167514Skmacyint t3_sge_read_ecntxt(adapter_t *adapter, unsigned int id, u32 data[4]) 2445167514Skmacy{ 2446167514Skmacy if (id >= 65536) 2447167514Skmacy return -EINVAL; 2448167514Skmacy return t3_sge_read_context(F_EGRESS, adapter, id, data); 2449167514Skmacy} 2450167514Skmacy 2451167514Skmacy/** 2452167514Skmacy * t3_sge_read_cq - read an SGE CQ context 2453167514Skmacy * @adapter: the adapter 2454167514Skmacy * @id: the context id 2455167514Skmacy * @data: holds the retrieved context 2456167514Skmacy * 2457167514Skmacy * Read an SGE CQ context. The caller is responsible for ensuring 2458167514Skmacy * only one context operation occurs at a time. 2459167514Skmacy */ 2460167514Skmacyint t3_sge_read_cq(adapter_t *adapter, unsigned int id, u32 data[4]) 2461167514Skmacy{ 2462167514Skmacy if (id >= 65536) 2463167514Skmacy return -EINVAL; 2464167514Skmacy return t3_sge_read_context(F_CQ, adapter, id, data); 2465167514Skmacy} 2466167514Skmacy 2467167514Skmacy/** 2468167514Skmacy * t3_sge_read_fl - read an SGE free-list context 2469167514Skmacy * @adapter: the adapter 2470167514Skmacy * @id: the context id 2471167514Skmacy * @data: holds the retrieved context 2472167514Skmacy * 2473167514Skmacy * Read an SGE free-list context. The caller is responsible for ensuring 2474167514Skmacy * only one context operation occurs at a time. 2475167514Skmacy */ 2476167514Skmacyint t3_sge_read_fl(adapter_t *adapter, unsigned int id, u32 data[4]) 2477167514Skmacy{ 2478167514Skmacy if (id >= SGE_QSETS * 2) 2479167514Skmacy return -EINVAL; 2480167514Skmacy return t3_sge_read_context(F_FREELIST, adapter, id, data); 2481167514Skmacy} 2482167514Skmacy 2483167514Skmacy/** 2484167514Skmacy * t3_sge_read_rspq - read an SGE response queue context 2485167514Skmacy * @adapter: the adapter 2486167514Skmacy * @id: the context id 2487167514Skmacy * @data: holds the retrieved context 2488167514Skmacy * 2489167514Skmacy * Read an SGE response queue context. The caller is responsible for 2490167514Skmacy * ensuring only one context operation occurs at a time. 2491167514Skmacy */ 2492167514Skmacyint t3_sge_read_rspq(adapter_t *adapter, unsigned int id, u32 data[4]) 2493167514Skmacy{ 2494167514Skmacy if (id >= SGE_QSETS) 2495167514Skmacy return -EINVAL; 2496167514Skmacy return t3_sge_read_context(F_RESPONSEQ, adapter, id, data); 2497167514Skmacy} 2498167514Skmacy 2499167514Skmacy/** 2500167514Skmacy * t3_config_rss - configure Rx packet steering 2501167514Skmacy * @adapter: the adapter 2502167514Skmacy * @rss_config: RSS settings (written to TP_RSS_CONFIG) 2503167514Skmacy * @cpus: values for the CPU lookup table (0xff terminated) 2504167514Skmacy * @rspq: values for the response queue lookup table (0xffff terminated) 2505167514Skmacy * 2506167514Skmacy * Programs the receive packet steering logic. @cpus and @rspq provide 2507167514Skmacy * the values for the CPU and response queue lookup tables. If they 2508167514Skmacy * provide fewer values than the size of the tables the supplied values 2509167514Skmacy * are used repeatedly until the tables are fully populated. 2510167514Skmacy */ 2511167514Skmacyvoid t3_config_rss(adapter_t *adapter, unsigned int rss_config, const u8 *cpus, 2512167514Skmacy const u16 *rspq) 2513167514Skmacy{ 2514167514Skmacy int i, j, cpu_idx = 0, q_idx = 0; 2515167514Skmacy 2516167514Skmacy if (cpus) 2517167514Skmacy for (i = 0; i < RSS_TABLE_SIZE; ++i) { 2518167514Skmacy u32 val = i << 16; 2519167514Skmacy 2520167514Skmacy for (j = 0; j < 2; ++j) { 2521167514Skmacy val |= (cpus[cpu_idx++] & 0x3f) << (8 * j); 2522167514Skmacy if (cpus[cpu_idx] == 0xff) 2523167514Skmacy cpu_idx = 0; 2524167514Skmacy } 2525167514Skmacy t3_write_reg(adapter, A_TP_RSS_LKP_TABLE, val); 2526167514Skmacy } 2527167514Skmacy 2528167514Skmacy if (rspq) 2529167514Skmacy for (i = 0; i < RSS_TABLE_SIZE; ++i) { 2530167514Skmacy t3_write_reg(adapter, A_TP_RSS_MAP_TABLE, 2531167514Skmacy (i << 16) | rspq[q_idx++]); 2532167514Skmacy if (rspq[q_idx] == 0xffff) 2533167514Skmacy q_idx = 0; 2534167514Skmacy } 2535167514Skmacy 2536167514Skmacy t3_write_reg(adapter, A_TP_RSS_CONFIG, rss_config); 2537167514Skmacy} 2538167514Skmacy 2539167514Skmacy/** 2540167514Skmacy * t3_read_rss - read the contents of the RSS tables 2541167514Skmacy * @adapter: the adapter 2542167514Skmacy * @lkup: holds the contents of the RSS lookup table 2543167514Skmacy * @map: holds the contents of the RSS map table 2544167514Skmacy * 2545167514Skmacy * Reads the contents of the receive packet steering tables. 2546167514Skmacy */ 2547167514Skmacyint t3_read_rss(adapter_t *adapter, u8 *lkup, u16 *map) 2548167514Skmacy{ 2549167514Skmacy int i; 2550167514Skmacy u32 val; 2551167514Skmacy 2552167514Skmacy if (lkup) 2553167514Skmacy for (i = 0; i < RSS_TABLE_SIZE; ++i) { 2554167514Skmacy t3_write_reg(adapter, A_TP_RSS_LKP_TABLE, 2555167514Skmacy 0xffff0000 | i); 2556167514Skmacy val = t3_read_reg(adapter, A_TP_RSS_LKP_TABLE); 2557167514Skmacy if (!(val & 0x80000000)) 2558167514Skmacy return -EAGAIN; 2559167514Skmacy *lkup++ = (u8)val; 2560167514Skmacy *lkup++ = (u8)(val >> 8); 2561167514Skmacy } 2562167514Skmacy 2563167514Skmacy if (map) 2564167514Skmacy for (i = 0; i < RSS_TABLE_SIZE; ++i) { 2565167514Skmacy t3_write_reg(adapter, A_TP_RSS_MAP_TABLE, 2566167514Skmacy 0xffff0000 | i); 2567167514Skmacy val = t3_read_reg(adapter, A_TP_RSS_MAP_TABLE); 2568167514Skmacy if (!(val & 0x80000000)) 2569167514Skmacy return -EAGAIN; 2570167514Skmacy *map++ = (u16)val; 2571167514Skmacy } 2572167514Skmacy return 0; 2573167514Skmacy} 2574167514Skmacy 2575167514Skmacy/** 2576167514Skmacy * t3_tp_set_offload_mode - put TP in NIC/offload mode 2577167514Skmacy * @adap: the adapter 2578167514Skmacy * @enable: 1 to select offload mode, 0 for regular NIC 2579167514Skmacy * 2580167514Skmacy * Switches TP to NIC/offload mode. 2581167514Skmacy */ 2582167514Skmacyvoid t3_tp_set_offload_mode(adapter_t *adap, int enable) 2583167514Skmacy{ 2584167514Skmacy if (is_offload(adap) || !enable) 2585167514Skmacy t3_set_reg_field(adap, A_TP_IN_CONFIG, F_NICMODE, 2586167514Skmacy V_NICMODE(!enable)); 2587167514Skmacy} 2588167514Skmacy 2589172096Skmacy/** 2590172096Skmacy * tp_wr_bits_indirect - set/clear bits in an indirect TP register 2591172096Skmacy * @adap: the adapter 2592172096Skmacy * @addr: the indirect TP register address 2593172096Skmacy * @mask: specifies the field within the register to modify 2594172096Skmacy * @val: new value for the field 2595172096Skmacy * 2596172096Skmacy * Sets a field of an indirect TP register to the given value. 2597172096Skmacy */ 2598171471Skmacystatic void tp_wr_bits_indirect(adapter_t *adap, unsigned int addr, 2599171471Skmacy unsigned int mask, unsigned int val) 2600171471Skmacy{ 2601171471Skmacy t3_write_reg(adap, A_TP_PIO_ADDR, addr); 2602171471Skmacy val |= t3_read_reg(adap, A_TP_PIO_DATA) & ~mask; 2603171471Skmacy t3_write_reg(adap, A_TP_PIO_DATA, val); 2604171471Skmacy} 2605171471Skmacy 2606167514Skmacy/** 2607180583Skmacy * t3_enable_filters - enable the HW filters 2608180583Skmacy * @adap: the adapter 2609180583Skmacy * 2610180583Skmacy * Enables the HW filters for NIC traffic. 2611180583Skmacy */ 2612180583Skmacyvoid t3_enable_filters(adapter_t *adap) 2613180583Skmacy{ 2614180583Skmacy t3_set_reg_field(adap, A_TP_IN_CONFIG, F_NICMODE, 0); 2615180583Skmacy t3_set_reg_field(adap, A_MC5_DB_CONFIG, 0, F_FILTEREN); 2616180583Skmacy t3_set_reg_field(adap, A_TP_GLOBAL_CONFIG, 0, V_FIVETUPLELOOKUP(3)); 2617180583Skmacy tp_wr_bits_indirect(adap, A_TP_INGRESS_CONFIG, 0, F_LOOKUPEVERYPKT); 2618180583Skmacy} 2619180583Skmacy 2620180583Skmacy/** 2621167514Skmacy * pm_num_pages - calculate the number of pages of the payload memory 2622167514Skmacy * @mem_size: the size of the payload memory 2623167514Skmacy * @pg_size: the size of each payload memory page 2624167514Skmacy * 2625167514Skmacy * Calculate the number of pages, each of the given size, that fit in a 2626167514Skmacy * memory of the specified size, respecting the HW requirement that the 2627167514Skmacy * number of pages must be a multiple of 24. 2628167514Skmacy */ 2629167514Skmacystatic inline unsigned int pm_num_pages(unsigned int mem_size, 2630167514Skmacy unsigned int pg_size) 2631167514Skmacy{ 2632167514Skmacy unsigned int n = mem_size / pg_size; 2633167514Skmacy 2634167514Skmacy return n - n % 24; 2635167514Skmacy} 2636167514Skmacy 2637167514Skmacy#define mem_region(adap, start, size, reg) \ 2638167514Skmacy t3_write_reg((adap), A_ ## reg, (start)); \ 2639167514Skmacy start += size 2640167514Skmacy 2641172096Skmacy/** 2642167514Skmacy * partition_mem - partition memory and configure TP memory settings 2643167514Skmacy * @adap: the adapter 2644167514Skmacy * @p: the TP parameters 2645167514Skmacy * 2646167514Skmacy * Partitions context and payload memory and configures TP's memory 2647167514Skmacy * registers. 2648167514Skmacy */ 2649167514Skmacystatic void partition_mem(adapter_t *adap, const struct tp_params *p) 2650167514Skmacy{ 2651167514Skmacy unsigned int m, pstructs, tids = t3_mc5_size(&adap->mc5); 2652167514Skmacy unsigned int timers = 0, timers_shift = 22; 2653167514Skmacy 2654167514Skmacy if (adap->params.rev > 0) { 2655167514Skmacy if (tids <= 16 * 1024) { 2656167514Skmacy timers = 1; 2657167514Skmacy timers_shift = 16; 2658167514Skmacy } else if (tids <= 64 * 1024) { 2659167514Skmacy timers = 2; 2660167514Skmacy timers_shift = 18; 2661167514Skmacy } else if (tids <= 256 * 1024) { 2662167514Skmacy timers = 3; 2663167514Skmacy timers_shift = 20; 2664167514Skmacy } 2665167514Skmacy } 2666167514Skmacy 2667167514Skmacy t3_write_reg(adap, A_TP_PMM_SIZE, 2668167514Skmacy p->chan_rx_size | (p->chan_tx_size >> 16)); 2669167514Skmacy 2670167514Skmacy t3_write_reg(adap, A_TP_PMM_TX_BASE, 0); 2671167514Skmacy t3_write_reg(adap, A_TP_PMM_TX_PAGE_SIZE, p->tx_pg_size); 2672167514Skmacy t3_write_reg(adap, A_TP_PMM_TX_MAX_PAGE, p->tx_num_pgs); 2673167514Skmacy t3_set_reg_field(adap, A_TP_PARA_REG3, V_TXDATAACKIDX(M_TXDATAACKIDX), 2674167514Skmacy V_TXDATAACKIDX(fls(p->tx_pg_size) - 12)); 2675167514Skmacy 2676167514Skmacy t3_write_reg(adap, A_TP_PMM_RX_BASE, 0); 2677167514Skmacy t3_write_reg(adap, A_TP_PMM_RX_PAGE_SIZE, p->rx_pg_size); 2678167514Skmacy t3_write_reg(adap, A_TP_PMM_RX_MAX_PAGE, p->rx_num_pgs); 2679167514Skmacy 2680167514Skmacy pstructs = p->rx_num_pgs + p->tx_num_pgs; 2681167514Skmacy /* Add a bit of headroom and make multiple of 24 */ 2682167514Skmacy pstructs += 48; 2683167514Skmacy pstructs -= pstructs % 24; 2684167514Skmacy t3_write_reg(adap, A_TP_CMM_MM_MAX_PSTRUCT, pstructs); 2685167514Skmacy 2686167514Skmacy m = tids * TCB_SIZE; 2687167514Skmacy mem_region(adap, m, (64 << 10) * 64, SG_EGR_CNTX_BADDR); 2688167514Skmacy mem_region(adap, m, (64 << 10) * 64, SG_CQ_CONTEXT_BADDR); 2689167514Skmacy t3_write_reg(adap, A_TP_CMM_TIMER_BASE, V_CMTIMERMAXNUM(timers) | m); 2690167514Skmacy m += ((p->ntimer_qs - 1) << timers_shift) + (1 << 22); 2691167514Skmacy mem_region(adap, m, pstructs * 64, TP_CMM_MM_BASE); 2692167514Skmacy mem_region(adap, m, 64 * (pstructs / 24), TP_CMM_MM_PS_FLST_BASE); 2693167514Skmacy mem_region(adap, m, 64 * (p->rx_num_pgs / 24), TP_CMM_MM_RX_FLST_BASE); 2694167514Skmacy mem_region(adap, m, 64 * (p->tx_num_pgs / 24), TP_CMM_MM_TX_FLST_BASE); 2695167514Skmacy 2696167514Skmacy m = (m + 4095) & ~0xfff; 2697167514Skmacy t3_write_reg(adap, A_CIM_SDRAM_BASE_ADDR, m); 2698167514Skmacy t3_write_reg(adap, A_CIM_SDRAM_ADDR_SIZE, p->cm_size - m); 2699167514Skmacy 2700167514Skmacy tids = (p->cm_size - m - (3 << 20)) / 3072 - 32; 2701167514Skmacy m = t3_mc5_size(&adap->mc5) - adap->params.mc5.nservers - 2702167514Skmacy adap->params.mc5.nfilters - adap->params.mc5.nroutes; 2703167514Skmacy if (tids < m) 2704167514Skmacy adap->params.mc5.nservers += m - tids; 2705167514Skmacy} 2706167514Skmacy 2707167514Skmacystatic inline void tp_wr_indirect(adapter_t *adap, unsigned int addr, u32 val) 2708167514Skmacy{ 2709167514Skmacy t3_write_reg(adap, A_TP_PIO_ADDR, addr); 2710167514Skmacy t3_write_reg(adap, A_TP_PIO_DATA, val); 2711167514Skmacy} 2712167514Skmacy 2713167514Skmacystatic void tp_config(adapter_t *adap, const struct tp_params *p) 2714167514Skmacy{ 2715167514Skmacy t3_write_reg(adap, A_TP_GLOBAL_CONFIG, F_TXPACINGENABLE | F_PATHMTU | 2716167514Skmacy F_IPCHECKSUMOFFLOAD | F_UDPCHECKSUMOFFLOAD | 2717167514Skmacy F_TCPCHECKSUMOFFLOAD | V_IPTTL(64)); 2718167514Skmacy t3_write_reg(adap, A_TP_TCP_OPTIONS, V_MTUDEFAULT(576) | 2719167514Skmacy F_MTUENABLE | V_WINDOWSCALEMODE(1) | 2720180583Skmacy V_TIMESTAMPSMODE(1) | V_SACKMODE(1) | V_SACKRX(1)); 2721167514Skmacy t3_write_reg(adap, A_TP_DACK_CONFIG, V_AUTOSTATE3(1) | 2722167514Skmacy V_AUTOSTATE2(1) | V_AUTOSTATE1(0) | 2723180583Skmacy V_BYTETHRESHOLD(26880) | V_MSSTHRESHOLD(2) | 2724167514Skmacy F_AUTOCAREFUL | F_AUTOENABLE | V_DACK_MODE(1)); 2725176472Skmacy t3_set_reg_field(adap, A_TP_IN_CONFIG, F_RXFBARBPRIO | F_TXFBARBPRIO, 2726167514Skmacy F_IPV6ENABLE | F_NICMODE); 2727167514Skmacy t3_write_reg(adap, A_TP_TX_RESOURCE_LIMIT, 0x18141814); 2728167514Skmacy t3_write_reg(adap, A_TP_PARA_REG4, 0x5050105); 2729170654Skmacy t3_set_reg_field(adap, A_TP_PARA_REG6, 0, 2730170654Skmacy adap->params.rev > 0 ? F_ENABLEESND : 2731170654Skmacy F_T3A_ENABLEESND); 2732167514Skmacy t3_set_reg_field(adap, A_TP_PC_CONFIG, 2733170654Skmacy F_ENABLEEPCMDAFULL, 2734170654Skmacy F_ENABLEOCSPIFULL |F_TXDEFERENABLE | F_HEARBEATDACK | 2735170654Skmacy F_TXCONGESTIONMODE | F_RXCONGESTIONMODE); 2736176472Skmacy t3_set_reg_field(adap, A_TP_PC_CONFIG2, F_CHDRAFULL, 2737176472Skmacy F_ENABLEIPV6RSS | F_ENABLENONOFDTNLSYN | 2738176472Skmacy F_ENABLEARPMISS | F_DISBLEDAPARBIT0); 2739170654Skmacy t3_write_reg(adap, A_TP_PROXY_FLOW_CNTL, 1080); 2740170654Skmacy t3_write_reg(adap, A_TP_PROXY_FLOW_CNTL, 1000); 2741167514Skmacy 2742167514Skmacy if (adap->params.rev > 0) { 2743167514Skmacy tp_wr_indirect(adap, A_TP_EGRESS_CONFIG, F_REWRITEFORCETOSIZE); 2744171471Skmacy t3_set_reg_field(adap, A_TP_PARA_REG3, 0, 2745171471Skmacy F_TXPACEAUTO | F_TXPACEAUTOSTRICT); 2746167514Skmacy t3_set_reg_field(adap, A_TP_PC_CONFIG, F_LOCKTID, F_LOCKTID); 2747171471Skmacy tp_wr_indirect(adap, A_TP_VLAN_PRI_MAP, 0xfa50); 2748171471Skmacy tp_wr_indirect(adap, A_TP_MAC_MATCH_MAP0, 0xfac688); 2749171471Skmacy tp_wr_indirect(adap, A_TP_MAC_MATCH_MAP1, 0xfac688); 2750167514Skmacy } else 2751167514Skmacy t3_set_reg_field(adap, A_TP_PARA_REG3, 0, F_TXPACEFIXED); 2752167514Skmacy 2753176472Skmacy if (adap->params.rev == T3_REV_C) 2754176472Skmacy t3_set_reg_field(adap, A_TP_PC_CONFIG, 2755176472Skmacy V_TABLELATENCYDELTA(M_TABLELATENCYDELTA), 2756176472Skmacy V_TABLELATENCYDELTA(4)); 2757176472Skmacy 2758167746Skmacy t3_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT1, 0); 2759167746Skmacy t3_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT0, 0); 2760167746Skmacy t3_write_reg(adap, A_TP_MOD_CHANNEL_WEIGHT, 0); 2761170654Skmacy t3_write_reg(adap, A_TP_MOD_RATE_LIMIT, 0xf2200000); 2762170654Skmacy 2763170654Skmacy if (adap->params.nports > 2) { 2764170654Skmacy t3_set_reg_field(adap, A_TP_PC_CONFIG2, 0, 2765180583Skmacy F_ENABLETXPORTFROMDA2 | F_ENABLETXPORTFROMDA | 2766180583Skmacy F_ENABLERXPORTFROMADDR); 2767170654Skmacy tp_wr_bits_indirect(adap, A_TP_QOS_RX_MAP_MODE, 2768170654Skmacy V_RXMAPMODE(M_RXMAPMODE), 0); 2769170654Skmacy tp_wr_indirect(adap, A_TP_INGRESS_CONFIG, V_BITPOS0(48) | 2770170654Skmacy V_BITPOS1(49) | V_BITPOS2(50) | V_BITPOS3(51) | 2771170654Skmacy F_ENABLEEXTRACT | F_ENABLEEXTRACTIONSFD | 2772170654Skmacy F_ENABLEINSERTION | F_ENABLEINSERTIONSFD); 2773170654Skmacy tp_wr_indirect(adap, A_TP_PREAMBLE_MSB, 0xfb000000); 2774170654Skmacy tp_wr_indirect(adap, A_TP_PREAMBLE_LSB, 0xd5); 2775170654Skmacy tp_wr_indirect(adap, A_TP_INTF_FROM_TX_PKT, F_INTFFROMTXPKT); 2776170654Skmacy } 2777167514Skmacy} 2778167514Skmacy 2779167514Skmacy/* TCP timer values in ms */ 2780167514Skmacy#define TP_DACK_TIMER 50 2781167514Skmacy#define TP_RTO_MIN 250 2782167514Skmacy 2783167514Skmacy/** 2784167514Skmacy * tp_set_timers - set TP timing parameters 2785167514Skmacy * @adap: the adapter to set 2786167514Skmacy * @core_clk: the core clock frequency in Hz 2787167514Skmacy * 2788167514Skmacy * Set TP's timing parameters, such as the various timer resolutions and 2789167514Skmacy * the TCP timer values. 2790167514Skmacy */ 2791167514Skmacystatic void tp_set_timers(adapter_t *adap, unsigned int core_clk) 2792167514Skmacy{ 2793170654Skmacy unsigned int tre = adap->params.tp.tre; 2794167746Skmacy unsigned int dack_re = adap->params.tp.dack_re; 2795167514Skmacy unsigned int tstamp_re = fls(core_clk / 1000); /* 1ms, at least */ 2796167514Skmacy unsigned int tps = core_clk >> tre; 2797167514Skmacy 2798167514Skmacy t3_write_reg(adap, A_TP_TIMER_RESOLUTION, V_TIMERRESOLUTION(tre) | 2799167514Skmacy V_DELAYEDACKRESOLUTION(dack_re) | 2800167514Skmacy V_TIMESTAMPRESOLUTION(tstamp_re)); 2801167514Skmacy t3_write_reg(adap, A_TP_DACK_TIMER, 2802167514Skmacy (core_clk >> dack_re) / (1000 / TP_DACK_TIMER)); 2803167514Skmacy t3_write_reg(adap, A_TP_TCP_BACKOFF_REG0, 0x3020100); 2804167514Skmacy t3_write_reg(adap, A_TP_TCP_BACKOFF_REG1, 0x7060504); 2805167514Skmacy t3_write_reg(adap, A_TP_TCP_BACKOFF_REG2, 0xb0a0908); 2806167514Skmacy t3_write_reg(adap, A_TP_TCP_BACKOFF_REG3, 0xf0e0d0c); 2807167514Skmacy t3_write_reg(adap, A_TP_SHIFT_CNT, V_SYNSHIFTMAX(6) | 2808167514Skmacy V_RXTSHIFTMAXR1(4) | V_RXTSHIFTMAXR2(15) | 2809167514Skmacy V_PERSHIFTBACKOFFMAX(8) | V_PERSHIFTMAX(8) | 2810167514Skmacy V_KEEPALIVEMAX(9)); 2811167514Skmacy 2812167514Skmacy#define SECONDS * tps 2813167514Skmacy 2814167514Skmacy t3_write_reg(adap, A_TP_MSL, 2815167514Skmacy adap->params.rev > 0 ? 0 : 2 SECONDS); 2816167514Skmacy t3_write_reg(adap, A_TP_RXT_MIN, tps / (1000 / TP_RTO_MIN)); 2817167514Skmacy t3_write_reg(adap, A_TP_RXT_MAX, 64 SECONDS); 2818167514Skmacy t3_write_reg(adap, A_TP_PERS_MIN, 5 SECONDS); 2819167514Skmacy t3_write_reg(adap, A_TP_PERS_MAX, 64 SECONDS); 2820167514Skmacy t3_write_reg(adap, A_TP_KEEP_IDLE, 7200 SECONDS); 2821167514Skmacy t3_write_reg(adap, A_TP_KEEP_INTVL, 75 SECONDS); 2822167514Skmacy t3_write_reg(adap, A_TP_INIT_SRTT, 3 SECONDS); 2823167514Skmacy t3_write_reg(adap, A_TP_FINWAIT2_TIMER, 600 SECONDS); 2824167514Skmacy 2825167514Skmacy#undef SECONDS 2826167514Skmacy} 2827167514Skmacy 2828167514Skmacy#ifdef CONFIG_CHELSIO_T3_CORE 2829167514Skmacy/** 2830167514Skmacy * t3_tp_set_coalescing_size - set receive coalescing size 2831167514Skmacy * @adap: the adapter 2832167514Skmacy * @size: the receive coalescing size 2833167514Skmacy * @psh: whether a set PSH bit should deliver coalesced data 2834167514Skmacy * 2835167514Skmacy * Set the receive coalescing size and PSH bit handling. 2836167514Skmacy */ 2837167514Skmacyint t3_tp_set_coalescing_size(adapter_t *adap, unsigned int size, int psh) 2838167514Skmacy{ 2839167514Skmacy u32 val; 2840167514Skmacy 2841167514Skmacy if (size > MAX_RX_COALESCING_LEN) 2842167514Skmacy return -EINVAL; 2843167514Skmacy 2844167514Skmacy val = t3_read_reg(adap, A_TP_PARA_REG3); 2845167514Skmacy val &= ~(F_RXCOALESCEENABLE | F_RXCOALESCEPSHEN); 2846167514Skmacy 2847167514Skmacy if (size) { 2848167514Skmacy val |= F_RXCOALESCEENABLE; 2849167514Skmacy if (psh) 2850167514Skmacy val |= F_RXCOALESCEPSHEN; 2851170654Skmacy size = min(MAX_RX_COALESCING_LEN, size); 2852167514Skmacy t3_write_reg(adap, A_TP_PARA_REG2, V_RXCOALESCESIZE(size) | 2853167514Skmacy V_MAXRXDATA(MAX_RX_COALESCING_LEN)); 2854167514Skmacy } 2855167514Skmacy t3_write_reg(adap, A_TP_PARA_REG3, val); 2856167514Skmacy return 0; 2857167514Skmacy} 2858167514Skmacy 2859167514Skmacy/** 2860167514Skmacy * t3_tp_set_max_rxsize - set the max receive size 2861167514Skmacy * @adap: the adapter 2862167514Skmacy * @size: the max receive size 2863167514Skmacy * 2864167514Skmacy * Set TP's max receive size. This is the limit that applies when 2865167514Skmacy * receive coalescing is disabled. 2866167514Skmacy */ 2867167514Skmacyvoid t3_tp_set_max_rxsize(adapter_t *adap, unsigned int size) 2868167514Skmacy{ 2869167514Skmacy t3_write_reg(adap, A_TP_PARA_REG7, 2870167514Skmacy V_PMMAXXFERLEN0(size) | V_PMMAXXFERLEN1(size)); 2871167514Skmacy} 2872167514Skmacy 2873167514Skmacystatic void __devinit init_mtus(unsigned short mtus[]) 2874167514Skmacy{ 2875167514Skmacy /* 2876167514Skmacy * See draft-mathis-plpmtud-00.txt for the values. The min is 88 so 2877167514Skmacy * it can accomodate max size TCP/IP headers when SACK and timestamps 2878167514Skmacy * are enabled and still have at least 8 bytes of payload. 2879167514Skmacy */ 2880167514Skmacy mtus[0] = 88; 2881170654Skmacy mtus[1] = 88; 2882167746Skmacy mtus[2] = 256; 2883167746Skmacy mtus[3] = 512; 2884167746Skmacy mtus[4] = 576; 2885167514Skmacy mtus[5] = 1024; 2886167514Skmacy mtus[6] = 1280; 2887167514Skmacy mtus[7] = 1492; 2888167514Skmacy mtus[8] = 1500; 2889167514Skmacy mtus[9] = 2002; 2890167514Skmacy mtus[10] = 2048; 2891167514Skmacy mtus[11] = 4096; 2892167514Skmacy mtus[12] = 4352; 2893167514Skmacy mtus[13] = 8192; 2894167514Skmacy mtus[14] = 9000; 2895167514Skmacy mtus[15] = 9600; 2896167514Skmacy} 2897167514Skmacy 2898172096Skmacy/** 2899172096Skmacy * init_cong_ctrl - initialize congestion control parameters 2900172096Skmacy * @a: the alpha values for congestion control 2901172096Skmacy * @b: the beta values for congestion control 2902172096Skmacy * 2903172096Skmacy * Initialize the congestion control parameters. 2904167514Skmacy */ 2905167514Skmacystatic void __devinit init_cong_ctrl(unsigned short *a, unsigned short *b) 2906167514Skmacy{ 2907167514Skmacy a[0] = a[1] = a[2] = a[3] = a[4] = a[5] = a[6] = a[7] = a[8] = 1; 2908167514Skmacy a[9] = 2; 2909167514Skmacy a[10] = 3; 2910167514Skmacy a[11] = 4; 2911167514Skmacy a[12] = 5; 2912167514Skmacy a[13] = 6; 2913167514Skmacy a[14] = 7; 2914167514Skmacy a[15] = 8; 2915167514Skmacy a[16] = 9; 2916167514Skmacy a[17] = 10; 2917167514Skmacy a[18] = 14; 2918167514Skmacy a[19] = 17; 2919167514Skmacy a[20] = 21; 2920167514Skmacy a[21] = 25; 2921167514Skmacy a[22] = 30; 2922167514Skmacy a[23] = 35; 2923167514Skmacy a[24] = 45; 2924167514Skmacy a[25] = 60; 2925167514Skmacy a[26] = 80; 2926167514Skmacy a[27] = 100; 2927167514Skmacy a[28] = 200; 2928167514Skmacy a[29] = 300; 2929167514Skmacy a[30] = 400; 2930167514Skmacy a[31] = 500; 2931167514Skmacy 2932167514Skmacy b[0] = b[1] = b[2] = b[3] = b[4] = b[5] = b[6] = b[7] = b[8] = 0; 2933167514Skmacy b[9] = b[10] = 1; 2934167514Skmacy b[11] = b[12] = 2; 2935167514Skmacy b[13] = b[14] = b[15] = b[16] = 3; 2936167514Skmacy b[17] = b[18] = b[19] = b[20] = b[21] = 4; 2937167514Skmacy b[22] = b[23] = b[24] = b[25] = b[26] = b[27] = 5; 2938167514Skmacy b[28] = b[29] = 6; 2939167514Skmacy b[30] = b[31] = 7; 2940167514Skmacy} 2941167514Skmacy 2942167514Skmacy/* The minimum additive increment value for the congestion control table */ 2943167514Skmacy#define CC_MIN_INCR 2U 2944167514Skmacy 2945167514Skmacy/** 2946167514Skmacy * t3_load_mtus - write the MTU and congestion control HW tables 2947167514Skmacy * @adap: the adapter 2948167514Skmacy * @mtus: the unrestricted values for the MTU table 2949172096Skmacy * @alpha: the values for the congestion control alpha parameter 2950167514Skmacy * @beta: the values for the congestion control beta parameter 2951167514Skmacy * @mtu_cap: the maximum permitted effective MTU 2952167514Skmacy * 2953167514Skmacy * Write the MTU table with the supplied MTUs capping each at &mtu_cap. 2954167514Skmacy * Update the high-speed congestion control table with the supplied alpha, 2955167514Skmacy * beta, and MTUs. 2956167514Skmacy */ 2957167514Skmacyvoid t3_load_mtus(adapter_t *adap, unsigned short mtus[NMTUS], 2958167514Skmacy unsigned short alpha[NCCTRL_WIN], 2959167514Skmacy unsigned short beta[NCCTRL_WIN], unsigned short mtu_cap) 2960167514Skmacy{ 2961167514Skmacy static const unsigned int avg_pkts[NCCTRL_WIN] = { 2962167514Skmacy 2, 6, 10, 14, 20, 28, 40, 56, 80, 112, 160, 224, 320, 448, 640, 2963167514Skmacy 896, 1281, 1792, 2560, 3584, 5120, 7168, 10240, 14336, 20480, 2964167514Skmacy 28672, 40960, 57344, 81920, 114688, 163840, 229376 }; 2965167514Skmacy 2966167514Skmacy unsigned int i, w; 2967167514Skmacy 2968167514Skmacy for (i = 0; i < NMTUS; ++i) { 2969167514Skmacy unsigned int mtu = min(mtus[i], mtu_cap); 2970167514Skmacy unsigned int log2 = fls(mtu); 2971167514Skmacy 2972167514Skmacy if (!(mtu & ((1 << log2) >> 2))) /* round */ 2973167514Skmacy log2--; 2974167514Skmacy t3_write_reg(adap, A_TP_MTU_TABLE, 2975167514Skmacy (i << 24) | (log2 << 16) | mtu); 2976167514Skmacy 2977167514Skmacy for (w = 0; w < NCCTRL_WIN; ++w) { 2978167514Skmacy unsigned int inc; 2979167514Skmacy 2980167514Skmacy inc = max(((mtu - 40) * alpha[w]) / avg_pkts[w], 2981167514Skmacy CC_MIN_INCR); 2982167514Skmacy 2983167514Skmacy t3_write_reg(adap, A_TP_CCTRL_TABLE, (i << 21) | 2984167514Skmacy (w << 16) | (beta[w] << 13) | inc); 2985167514Skmacy } 2986167514Skmacy } 2987167514Skmacy} 2988167514Skmacy 2989167514Skmacy/** 2990167514Skmacy * t3_read_hw_mtus - returns the values in the HW MTU table 2991167514Skmacy * @adap: the adapter 2992167514Skmacy * @mtus: where to store the HW MTU values 2993167514Skmacy * 2994167514Skmacy * Reads the HW MTU table. 2995167514Skmacy */ 2996167514Skmacyvoid t3_read_hw_mtus(adapter_t *adap, unsigned short mtus[NMTUS]) 2997167514Skmacy{ 2998167514Skmacy int i; 2999167514Skmacy 3000167514Skmacy for (i = 0; i < NMTUS; ++i) { 3001167514Skmacy unsigned int val; 3002167514Skmacy 3003167514Skmacy t3_write_reg(adap, A_TP_MTU_TABLE, 0xff000000 | i); 3004167514Skmacy val = t3_read_reg(adap, A_TP_MTU_TABLE); 3005167514Skmacy mtus[i] = val & 0x3fff; 3006167514Skmacy } 3007167514Skmacy} 3008167514Skmacy 3009167514Skmacy/** 3010167514Skmacy * t3_get_cong_cntl_tab - reads the congestion control table 3011167514Skmacy * @adap: the adapter 3012167514Skmacy * @incr: where to store the alpha values 3013167514Skmacy * 3014167514Skmacy * Reads the additive increments programmed into the HW congestion 3015167514Skmacy * control table. 3016167514Skmacy */ 3017167514Skmacyvoid t3_get_cong_cntl_tab(adapter_t *adap, 3018167514Skmacy unsigned short incr[NMTUS][NCCTRL_WIN]) 3019167514Skmacy{ 3020167514Skmacy unsigned int mtu, w; 3021167514Skmacy 3022167514Skmacy for (mtu = 0; mtu < NMTUS; ++mtu) 3023167514Skmacy for (w = 0; w < NCCTRL_WIN; ++w) { 3024167514Skmacy t3_write_reg(adap, A_TP_CCTRL_TABLE, 3025167514Skmacy 0xffff0000 | (mtu << 5) | w); 3026167514Skmacy incr[mtu][w] = (unsigned short)t3_read_reg(adap, 3027167514Skmacy A_TP_CCTRL_TABLE) & 0x1fff; 3028167514Skmacy } 3029167514Skmacy} 3030167514Skmacy 3031167514Skmacy/** 3032167514Skmacy * t3_tp_get_mib_stats - read TP's MIB counters 3033167514Skmacy * @adap: the adapter 3034167514Skmacy * @tps: holds the returned counter values 3035167514Skmacy * 3036167514Skmacy * Returns the values of TP's MIB counters. 3037167514Skmacy */ 3038167514Skmacyvoid t3_tp_get_mib_stats(adapter_t *adap, struct tp_mib_stats *tps) 3039167514Skmacy{ 3040167514Skmacy t3_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_RDATA, (u32 *)tps, 3041167514Skmacy sizeof(*tps) / sizeof(u32), 0); 3042167514Skmacy} 3043167514Skmacy 3044167746Skmacy/** 3045167746Skmacy * t3_read_pace_tbl - read the pace table 3046167746Skmacy * @adap: the adapter 3047167746Skmacy * @pace_vals: holds the returned values 3048167746Skmacy * 3049167746Skmacy * Returns the values of TP's pace table in nanoseconds. 3050167746Skmacy */ 3051167746Skmacyvoid t3_read_pace_tbl(adapter_t *adap, unsigned int pace_vals[NTX_SCHED]) 3052167746Skmacy{ 3053167746Skmacy unsigned int i, tick_ns = dack_ticks_to_usec(adap, 1000); 3054167746Skmacy 3055167746Skmacy for (i = 0; i < NTX_SCHED; i++) { 3056167746Skmacy t3_write_reg(adap, A_TP_PACE_TABLE, 0xffff0000 + i); 3057167746Skmacy pace_vals[i] = t3_read_reg(adap, A_TP_PACE_TABLE) * tick_ns; 3058167746Skmacy } 3059167746Skmacy} 3060167746Skmacy 3061167746Skmacy/** 3062167746Skmacy * t3_set_pace_tbl - set the pace table 3063167746Skmacy * @adap: the adapter 3064167746Skmacy * @pace_vals: the pace values in nanoseconds 3065167746Skmacy * @start: index of the first entry in the HW pace table to set 3066167746Skmacy * @n: how many entries to set 3067167746Skmacy * 3068167746Skmacy * Sets (a subset of the) HW pace table. 3069167746Skmacy */ 3070167746Skmacyvoid t3_set_pace_tbl(adapter_t *adap, unsigned int *pace_vals, 3071167746Skmacy unsigned int start, unsigned int n) 3072167746Skmacy{ 3073167746Skmacy unsigned int tick_ns = dack_ticks_to_usec(adap, 1000); 3074167746Skmacy 3075167746Skmacy for ( ; n; n--, start++, pace_vals++) 3076167746Skmacy t3_write_reg(adap, A_TP_PACE_TABLE, (start << 16) | 3077167746Skmacy ((*pace_vals + tick_ns / 2) / tick_ns)); 3078167746Skmacy} 3079167746Skmacy 3080167514Skmacy#define ulp_region(adap, name, start, len) \ 3081167514Skmacy t3_write_reg((adap), A_ULPRX_ ## name ## _LLIMIT, (start)); \ 3082167514Skmacy t3_write_reg((adap), A_ULPRX_ ## name ## _ULIMIT, \ 3083167514Skmacy (start) + (len) - 1); \ 3084167514Skmacy start += len 3085167514Skmacy 3086167514Skmacy#define ulptx_region(adap, name, start, len) \ 3087167514Skmacy t3_write_reg((adap), A_ULPTX_ ## name ## _LLIMIT, (start)); \ 3088167514Skmacy t3_write_reg((adap), A_ULPTX_ ## name ## _ULIMIT, \ 3089167514Skmacy (start) + (len) - 1) 3090167514Skmacy 3091167514Skmacystatic void ulp_config(adapter_t *adap, const struct tp_params *p) 3092167514Skmacy{ 3093167514Skmacy unsigned int m = p->chan_rx_size; 3094167514Skmacy 3095167514Skmacy ulp_region(adap, ISCSI, m, p->chan_rx_size / 8); 3096167514Skmacy ulp_region(adap, TDDP, m, p->chan_rx_size / 8); 3097167514Skmacy ulptx_region(adap, TPT, m, p->chan_rx_size / 4); 3098167514Skmacy ulp_region(adap, STAG, m, p->chan_rx_size / 4); 3099167514Skmacy ulp_region(adap, RQ, m, p->chan_rx_size / 4); 3100167514Skmacy ulptx_region(adap, PBL, m, p->chan_rx_size / 4); 3101167514Skmacy ulp_region(adap, PBL, m, p->chan_rx_size / 4); 3102167514Skmacy t3_write_reg(adap, A_ULPRX_TDDP_TAGMASK, 0xffffffff); 3103167514Skmacy} 3104170654Skmacy 3105170654Skmacy 3106170654Skmacy/** 3107170654Skmacy * t3_set_proto_sram - set the contents of the protocol sram 3108170654Skmacy * @adapter: the adapter 3109170654Skmacy * @data: the protocol image 3110170654Skmacy * 3111170654Skmacy * Write the contents of the protocol SRAM. 3112170654Skmacy */ 3113171471Skmacyint t3_set_proto_sram(adapter_t *adap, const u8 *data) 3114170654Skmacy{ 3115170654Skmacy int i; 3116172096Skmacy const u32 *buf = (const u32 *)data; 3117170654Skmacy 3118170654Skmacy for (i = 0; i < PROTO_SRAM_LINES; i++) { 3119171471Skmacy t3_write_reg(adap, A_TP_EMBED_OP_FIELD5, cpu_to_be32(*buf++)); 3120171471Skmacy t3_write_reg(adap, A_TP_EMBED_OP_FIELD4, cpu_to_be32(*buf++)); 3121171471Skmacy t3_write_reg(adap, A_TP_EMBED_OP_FIELD3, cpu_to_be32(*buf++)); 3122171471Skmacy t3_write_reg(adap, A_TP_EMBED_OP_FIELD2, cpu_to_be32(*buf++)); 3123171471Skmacy t3_write_reg(adap, A_TP_EMBED_OP_FIELD1, cpu_to_be32(*buf++)); 3124170654Skmacy 3125170654Skmacy t3_write_reg(adap, A_TP_EMBED_OP_FIELD0, i << 1 | 1 << 31); 3126170654Skmacy if (t3_wait_op_done(adap, A_TP_EMBED_OP_FIELD0, 1, 1, 5, 1)) 3127170654Skmacy return -EIO; 3128170654Skmacy } 3129170654Skmacy return 0; 3130170654Skmacy} 3131167514Skmacy#endif 3132167514Skmacy 3133172096Skmacy/** 3134172096Skmacy * t3_config_trace_filter - configure one of the tracing filters 3135172096Skmacy * @adapter: the adapter 3136172096Skmacy * @tp: the desired trace filter parameters 3137172096Skmacy * @filter_index: which filter to configure 3138172096Skmacy * @invert: if set non-matching packets are traced instead of matching ones 3139172096Skmacy * @enable: whether to enable or disable the filter 3140172096Skmacy * 3141172096Skmacy * Configures one of the tracing filters available in HW. 3142172096Skmacy */ 3143167514Skmacyvoid t3_config_trace_filter(adapter_t *adapter, const struct trace_params *tp, 3144167514Skmacy int filter_index, int invert, int enable) 3145167514Skmacy{ 3146167514Skmacy u32 addr, key[4], mask[4]; 3147167514Skmacy 3148167514Skmacy key[0] = tp->sport | (tp->sip << 16); 3149167514Skmacy key[1] = (tp->sip >> 16) | (tp->dport << 16); 3150167514Skmacy key[2] = tp->dip; 3151167514Skmacy key[3] = tp->proto | (tp->vlan << 8) | (tp->intf << 20); 3152167514Skmacy 3153167514Skmacy mask[0] = tp->sport_mask | (tp->sip_mask << 16); 3154167514Skmacy mask[1] = (tp->sip_mask >> 16) | (tp->dport_mask << 16); 3155167514Skmacy mask[2] = tp->dip_mask; 3156167514Skmacy mask[3] = tp->proto_mask | (tp->vlan_mask << 8) | (tp->intf_mask << 20); 3157167514Skmacy 3158167514Skmacy if (invert) 3159167514Skmacy key[3] |= (1 << 29); 3160167514Skmacy if (enable) 3161167514Skmacy key[3] |= (1 << 28); 3162167514Skmacy 3163167514Skmacy addr = filter_index ? A_TP_RX_TRC_KEY0 : A_TP_TX_TRC_KEY0; 3164167514Skmacy tp_wr_indirect(adapter, addr++, key[0]); 3165167514Skmacy tp_wr_indirect(adapter, addr++, mask[0]); 3166167514Skmacy tp_wr_indirect(adapter, addr++, key[1]); 3167167514Skmacy tp_wr_indirect(adapter, addr++, mask[1]); 3168167514Skmacy tp_wr_indirect(adapter, addr++, key[2]); 3169167514Skmacy tp_wr_indirect(adapter, addr++, mask[2]); 3170167514Skmacy tp_wr_indirect(adapter, addr++, key[3]); 3171167514Skmacy tp_wr_indirect(adapter, addr, mask[3]); 3172167514Skmacy (void) t3_read_reg(adapter, A_TP_PIO_DATA); 3173167514Skmacy} 3174167514Skmacy 3175167514Skmacy/** 3176167514Skmacy * t3_config_sched - configure a HW traffic scheduler 3177167514Skmacy * @adap: the adapter 3178167514Skmacy * @kbps: target rate in Kbps 3179167514Skmacy * @sched: the scheduler index 3180167514Skmacy * 3181167746Skmacy * Configure a Tx HW scheduler for the target rate. 3182167514Skmacy */ 3183167514Skmacyint t3_config_sched(adapter_t *adap, unsigned int kbps, int sched) 3184167514Skmacy{ 3185167514Skmacy unsigned int v, tps, cpt, bpt, delta, mindelta = ~0; 3186167514Skmacy unsigned int clk = adap->params.vpd.cclk * 1000; 3187167514Skmacy unsigned int selected_cpt = 0, selected_bpt = 0; 3188167514Skmacy 3189167514Skmacy if (kbps > 0) { 3190167514Skmacy kbps *= 125; /* -> bytes */ 3191167514Skmacy for (cpt = 1; cpt <= 255; cpt++) { 3192167514Skmacy tps = clk / cpt; 3193167514Skmacy bpt = (kbps + tps / 2) / tps; 3194167514Skmacy if (bpt > 0 && bpt <= 255) { 3195167514Skmacy v = bpt * tps; 3196167514Skmacy delta = v >= kbps ? v - kbps : kbps - v; 3197176472Skmacy if (delta < mindelta) { 3198167514Skmacy mindelta = delta; 3199167514Skmacy selected_cpt = cpt; 3200167514Skmacy selected_bpt = bpt; 3201167514Skmacy } 3202167514Skmacy } else if (selected_cpt) 3203167514Skmacy break; 3204167514Skmacy } 3205167514Skmacy if (!selected_cpt) 3206167514Skmacy return -EINVAL; 3207167514Skmacy } 3208167514Skmacy t3_write_reg(adap, A_TP_TM_PIO_ADDR, 3209167514Skmacy A_TP_TX_MOD_Q1_Q0_RATE_LIMIT - sched / 2); 3210167514Skmacy v = t3_read_reg(adap, A_TP_TM_PIO_DATA); 3211167514Skmacy if (sched & 1) 3212167514Skmacy v = (v & 0xffff) | (selected_cpt << 16) | (selected_bpt << 24); 3213167514Skmacy else 3214167514Skmacy v = (v & 0xffff0000) | selected_cpt | (selected_bpt << 8); 3215167514Skmacy t3_write_reg(adap, A_TP_TM_PIO_DATA, v); 3216167514Skmacy return 0; 3217167514Skmacy} 3218167514Skmacy 3219167746Skmacy/** 3220167746Skmacy * t3_set_sched_ipg - set the IPG for a Tx HW packet rate scheduler 3221167746Skmacy * @adap: the adapter 3222167746Skmacy * @sched: the scheduler index 3223167746Skmacy * @ipg: the interpacket delay in tenths of nanoseconds 3224167746Skmacy * 3225167746Skmacy * Set the interpacket delay for a HW packet rate scheduler. 3226167746Skmacy */ 3227167746Skmacyint t3_set_sched_ipg(adapter_t *adap, int sched, unsigned int ipg) 3228167746Skmacy{ 3229167746Skmacy unsigned int v, addr = A_TP_TX_MOD_Q1_Q0_TIMER_SEPARATOR - sched / 2; 3230167746Skmacy 3231167746Skmacy /* convert ipg to nearest number of core clocks */ 3232167746Skmacy ipg *= core_ticks_per_usec(adap); 3233167746Skmacy ipg = (ipg + 5000) / 10000; 3234167746Skmacy if (ipg > 0xffff) 3235167746Skmacy return -EINVAL; 3236167746Skmacy 3237167746Skmacy t3_write_reg(adap, A_TP_TM_PIO_ADDR, addr); 3238167746Skmacy v = t3_read_reg(adap, A_TP_TM_PIO_DATA); 3239167746Skmacy if (sched & 1) 3240167746Skmacy v = (v & 0xffff) | (ipg << 16); 3241167746Skmacy else 3242167746Skmacy v = (v & 0xffff0000) | ipg; 3243167746Skmacy t3_write_reg(adap, A_TP_TM_PIO_DATA, v); 3244167746Skmacy t3_read_reg(adap, A_TP_TM_PIO_DATA); 3245167746Skmacy return 0; 3246167746Skmacy} 3247167746Skmacy 3248167746Skmacy/** 3249167746Skmacy * t3_get_tx_sched - get the configuration of a Tx HW traffic scheduler 3250167746Skmacy * @adap: the adapter 3251167746Skmacy * @sched: the scheduler index 3252167746Skmacy * @kbps: the byte rate in Kbps 3253167746Skmacy * @ipg: the interpacket delay in tenths of nanoseconds 3254167746Skmacy * 3255167746Skmacy * Return the current configuration of a HW Tx scheduler. 3256167746Skmacy */ 3257167746Skmacyvoid t3_get_tx_sched(adapter_t *adap, unsigned int sched, unsigned int *kbps, 3258167746Skmacy unsigned int *ipg) 3259167746Skmacy{ 3260167746Skmacy unsigned int v, addr, bpt, cpt; 3261167746Skmacy 3262167746Skmacy if (kbps) { 3263167746Skmacy addr = A_TP_TX_MOD_Q1_Q0_RATE_LIMIT - sched / 2; 3264167746Skmacy t3_write_reg(adap, A_TP_TM_PIO_ADDR, addr); 3265167746Skmacy v = t3_read_reg(adap, A_TP_TM_PIO_DATA); 3266167746Skmacy if (sched & 1) 3267167746Skmacy v >>= 16; 3268167746Skmacy bpt = (v >> 8) & 0xff; 3269167746Skmacy cpt = v & 0xff; 3270167746Skmacy if (!cpt) 3271167746Skmacy *kbps = 0; /* scheduler disabled */ 3272167746Skmacy else { 3273167746Skmacy v = (adap->params.vpd.cclk * 1000) / cpt; 3274167746Skmacy *kbps = (v * bpt) / 125; 3275167746Skmacy } 3276167746Skmacy } 3277167746Skmacy if (ipg) { 3278167746Skmacy addr = A_TP_TX_MOD_Q1_Q0_TIMER_SEPARATOR - sched / 2; 3279167746Skmacy t3_write_reg(adap, A_TP_TM_PIO_ADDR, addr); 3280167746Skmacy v = t3_read_reg(adap, A_TP_TM_PIO_DATA); 3281167746Skmacy if (sched & 1) 3282167746Skmacy v >>= 16; 3283167746Skmacy v &= 0xffff; 3284167746Skmacy *ipg = (10000 * v) / core_ticks_per_usec(adap); 3285167746Skmacy } 3286167746Skmacy} 3287167746Skmacy 3288172096Skmacy/** 3289172096Skmacy * tp_init - configure TP 3290172096Skmacy * @adap: the adapter 3291172096Skmacy * @p: TP configuration parameters 3292172096Skmacy * 3293172096Skmacy * Initializes the TP HW module. 3294172096Skmacy */ 3295167514Skmacystatic int tp_init(adapter_t *adap, const struct tp_params *p) 3296167514Skmacy{ 3297167514Skmacy int busy = 0; 3298167514Skmacy 3299167514Skmacy tp_config(adap, p); 3300167514Skmacy t3_set_vlan_accel(adap, 3, 0); 3301167514Skmacy 3302167514Skmacy if (is_offload(adap)) { 3303167514Skmacy tp_set_timers(adap, adap->params.vpd.cclk * 1000); 3304167514Skmacy t3_write_reg(adap, A_TP_RESET, F_FLSTINITENABLE); 3305167514Skmacy busy = t3_wait_op_done(adap, A_TP_RESET, F_FLSTINITENABLE, 3306167514Skmacy 0, 1000, 5); 3307167514Skmacy if (busy) 3308167514Skmacy CH_ERR(adap, "TP initialization timed out\n"); 3309167514Skmacy } 3310167514Skmacy 3311167514Skmacy if (!busy) 3312167514Skmacy t3_write_reg(adap, A_TP_RESET, F_TPRESET); 3313167514Skmacy return busy; 3314167514Skmacy} 3315167514Skmacy 3316172096Skmacy/** 3317172096Skmacy * t3_mps_set_active_ports - configure port failover 3318172096Skmacy * @adap: the adapter 3319172096Skmacy * @port_mask: bitmap of active ports 3320172096Skmacy * 3321172096Skmacy * Sets the active ports according to the supplied bitmap. 3322172096Skmacy */ 3323167514Skmacyint t3_mps_set_active_ports(adapter_t *adap, unsigned int port_mask) 3324167514Skmacy{ 3325167514Skmacy if (port_mask & ~((1 << adap->params.nports) - 1)) 3326167514Skmacy return -EINVAL; 3327167514Skmacy t3_set_reg_field(adap, A_MPS_CFG, F_PORT1ACTIVE | F_PORT0ACTIVE, 3328167514Skmacy port_mask << S_PORT0ACTIVE); 3329167514Skmacy return 0; 3330167514Skmacy} 3331167514Skmacy 3332172096Skmacy/** 3333172096Skmacy * chan_init_hw - channel-dependent HW initialization 3334172096Skmacy * @adap: the adapter 3335172096Skmacy * @chan_map: bitmap of Tx channels being used 3336172096Skmacy * 3337172096Skmacy * Perform the bits of HW initialization that are dependent on the Tx 3338172096Skmacy * channels being used. 3339167514Skmacy */ 3340170654Skmacystatic void chan_init_hw(adapter_t *adap, unsigned int chan_map) 3341167514Skmacy{ 3342167514Skmacy int i; 3343167514Skmacy 3344170654Skmacy if (chan_map != 3) { /* one channel */ 3345167514Skmacy t3_set_reg_field(adap, A_ULPRX_CTL, F_ROUND_ROBIN, 0); 3346167514Skmacy t3_set_reg_field(adap, A_ULPTX_CONFIG, F_CFG_RR_ARB, 0); 3347170654Skmacy t3_write_reg(adap, A_MPS_CFG, F_TPRXPORTEN | F_ENFORCEPKT | 3348170654Skmacy (chan_map == 1 ? F_TPTXPORT0EN | F_PORT0ACTIVE : 3349170654Skmacy F_TPTXPORT1EN | F_PORT1ACTIVE)); 3350170654Skmacy t3_write_reg(adap, A_PM1_TX_CFG, 3351170654Skmacy chan_map == 1 ? 0xffffffff : 0); 3352172096Skmacy if (chan_map == 2) 3353172096Skmacy t3_write_reg(adap, A_TP_TX_MOD_QUEUE_REQ_MAP, 3354172096Skmacy V_TX_MOD_QUEUE_REQ_MAP(0xff)); 3355172096Skmacy t3_write_reg(adap, A_TP_TX_MOD_QUE_TABLE, (12 << 16) | 0xd9c8); 3356172096Skmacy t3_write_reg(adap, A_TP_TX_MOD_QUE_TABLE, (13 << 16) | 0xfbea); 3357170654Skmacy } else { /* two channels */ 3358167514Skmacy t3_set_reg_field(adap, A_ULPRX_CTL, 0, F_ROUND_ROBIN); 3359167514Skmacy t3_set_reg_field(adap, A_ULPTX_CONFIG, 0, F_CFG_RR_ARB); 3360167514Skmacy t3_write_reg(adap, A_ULPTX_DMA_WEIGHT, 3361167514Skmacy V_D1_WEIGHT(16) | V_D0_WEIGHT(16)); 3362167514Skmacy t3_write_reg(adap, A_MPS_CFG, F_TPTXPORT0EN | F_TPTXPORT1EN | 3363167514Skmacy F_TPRXPORTEN | F_PORT0ACTIVE | F_PORT1ACTIVE | 3364167514Skmacy F_ENFORCEPKT); 3365167514Skmacy t3_write_reg(adap, A_PM1_TX_CFG, 0x80008000); 3366167514Skmacy t3_set_reg_field(adap, A_TP_PC_CONFIG, 0, F_TXTOSQUEUEMAPMODE); 3367167514Skmacy t3_write_reg(adap, A_TP_TX_MOD_QUEUE_REQ_MAP, 3368167514Skmacy V_TX_MOD_QUEUE_REQ_MAP(0xaa)); 3369167514Skmacy for (i = 0; i < 16; i++) 3370167514Skmacy t3_write_reg(adap, A_TP_TX_MOD_QUE_TABLE, 3371167514Skmacy (i << 16) | 0x1010); 3372172096Skmacy t3_write_reg(adap, A_TP_TX_MOD_QUE_TABLE, (12 << 16) | 0xba98); 3373172096Skmacy t3_write_reg(adap, A_TP_TX_MOD_QUE_TABLE, (13 << 16) | 0xfedc); 3374167514Skmacy } 3375167514Skmacy} 3376167514Skmacy 3377167514Skmacystatic int calibrate_xgm(adapter_t *adapter) 3378167514Skmacy{ 3379167514Skmacy if (uses_xaui(adapter)) { 3380167514Skmacy unsigned int v, i; 3381167514Skmacy 3382167514Skmacy for (i = 0; i < 5; ++i) { 3383167514Skmacy t3_write_reg(adapter, A_XGM_XAUI_IMP, 0); 3384167514Skmacy (void) t3_read_reg(adapter, A_XGM_XAUI_IMP); 3385171471Skmacy msleep(1); 3386167514Skmacy v = t3_read_reg(adapter, A_XGM_XAUI_IMP); 3387167514Skmacy if (!(v & (F_XGM_CALFAULT | F_CALBUSY))) { 3388167514Skmacy t3_write_reg(adapter, A_XGM_XAUI_IMP, 3389167514Skmacy V_XAUIIMP(G_CALIMP(v) >> 2)); 3390167514Skmacy return 0; 3391167514Skmacy } 3392167514Skmacy } 3393167514Skmacy CH_ERR(adapter, "MAC calibration failed\n"); 3394167514Skmacy return -1; 3395167514Skmacy } else { 3396167514Skmacy t3_write_reg(adapter, A_XGM_RGMII_IMP, 3397167514Skmacy V_RGMIIIMPPD(2) | V_RGMIIIMPPU(3)); 3398167514Skmacy t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_XGM_IMPSETUPDATE, 3399167514Skmacy F_XGM_IMPSETUPDATE); 3400167514Skmacy } 3401167514Skmacy return 0; 3402167514Skmacy} 3403167514Skmacy 3404167514Skmacystatic void calibrate_xgm_t3b(adapter_t *adapter) 3405167514Skmacy{ 3406167514Skmacy if (!uses_xaui(adapter)) { 3407167514Skmacy t3_write_reg(adapter, A_XGM_RGMII_IMP, F_CALRESET | 3408167514Skmacy F_CALUPDATE | V_RGMIIIMPPD(2) | V_RGMIIIMPPU(3)); 3409167514Skmacy t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_CALRESET, 0); 3410167514Skmacy t3_set_reg_field(adapter, A_XGM_RGMII_IMP, 0, 3411167514Skmacy F_XGM_IMPSETUPDATE); 3412167514Skmacy t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_XGM_IMPSETUPDATE, 3413167514Skmacy 0); 3414167514Skmacy t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_CALUPDATE, 0); 3415167514Skmacy t3_set_reg_field(adapter, A_XGM_RGMII_IMP, 0, F_CALUPDATE); 3416167514Skmacy } 3417167514Skmacy} 3418167514Skmacy 3419167514Skmacystruct mc7_timing_params { 3420167514Skmacy unsigned char ActToPreDly; 3421167514Skmacy unsigned char ActToRdWrDly; 3422167514Skmacy unsigned char PreCyc; 3423167514Skmacy unsigned char RefCyc[5]; 3424167514Skmacy unsigned char BkCyc; 3425167514Skmacy unsigned char WrToRdDly; 3426167514Skmacy unsigned char RdToWrDly; 3427167514Skmacy}; 3428167514Skmacy 3429167514Skmacy/* 3430167514Skmacy * Write a value to a register and check that the write completed. These 3431167514Skmacy * writes normally complete in a cycle or two, so one read should suffice. 3432167514Skmacy * The very first read exists to flush the posted write to the device. 3433167514Skmacy */ 3434167514Skmacystatic int wrreg_wait(adapter_t *adapter, unsigned int addr, u32 val) 3435167514Skmacy{ 3436167514Skmacy t3_write_reg(adapter, addr, val); 3437167514Skmacy (void) t3_read_reg(adapter, addr); /* flush */ 3438167514Skmacy if (!(t3_read_reg(adapter, addr) & F_BUSY)) 3439167514Skmacy return 0; 3440167514Skmacy CH_ERR(adapter, "write to MC7 register 0x%x timed out\n", addr); 3441167514Skmacy return -EIO; 3442167514Skmacy} 3443167514Skmacy 3444167514Skmacystatic int mc7_init(struct mc7 *mc7, unsigned int mc7_clock, int mem_type) 3445167514Skmacy{ 3446167514Skmacy static const unsigned int mc7_mode[] = { 3447167514Skmacy 0x632, 0x642, 0x652, 0x432, 0x442 3448167514Skmacy }; 3449167514Skmacy static const struct mc7_timing_params mc7_timings[] = { 3450167514Skmacy { 12, 3, 4, { 20, 28, 34, 52, 0 }, 15, 6, 4 }, 3451167514Skmacy { 12, 4, 5, { 20, 28, 34, 52, 0 }, 16, 7, 4 }, 3452167514Skmacy { 12, 5, 6, { 20, 28, 34, 52, 0 }, 17, 8, 4 }, 3453167514Skmacy { 9, 3, 4, { 15, 21, 26, 39, 0 }, 12, 6, 4 }, 3454167514Skmacy { 9, 4, 5, { 15, 21, 26, 39, 0 }, 13, 7, 4 } 3455167514Skmacy }; 3456167514Skmacy 3457167514Skmacy u32 val; 3458167514Skmacy unsigned int width, density, slow, attempts; 3459167514Skmacy adapter_t *adapter = mc7->adapter; 3460167514Skmacy const struct mc7_timing_params *p = &mc7_timings[mem_type]; 3461167514Skmacy 3462170654Skmacy if (!mc7->size) 3463169978Skmacy return 0; 3464170654Skmacy 3465167514Skmacy val = t3_read_reg(adapter, mc7->offset + A_MC7_CFG); 3466167514Skmacy slow = val & F_SLOW; 3467167514Skmacy width = G_WIDTH(val); 3468167514Skmacy density = G_DEN(val); 3469167514Skmacy 3470167514Skmacy t3_write_reg(adapter, mc7->offset + A_MC7_CFG, val | F_IFEN); 3471167514Skmacy val = t3_read_reg(adapter, mc7->offset + A_MC7_CFG); /* flush */ 3472171471Skmacy msleep(1); 3473167514Skmacy 3474167514Skmacy if (!slow) { 3475167514Skmacy t3_write_reg(adapter, mc7->offset + A_MC7_CAL, F_SGL_CAL_EN); 3476167514Skmacy (void) t3_read_reg(adapter, mc7->offset + A_MC7_CAL); 3477171471Skmacy msleep(1); 3478167514Skmacy if (t3_read_reg(adapter, mc7->offset + A_MC7_CAL) & 3479167514Skmacy (F_BUSY | F_SGL_CAL_EN | F_CAL_FAULT)) { 3480167514Skmacy CH_ERR(adapter, "%s MC7 calibration timed out\n", 3481167514Skmacy mc7->name); 3482167514Skmacy goto out_fail; 3483167514Skmacy } 3484167514Skmacy } 3485167514Skmacy 3486167514Skmacy t3_write_reg(adapter, mc7->offset + A_MC7_PARM, 3487167514Skmacy V_ACTTOPREDLY(p->ActToPreDly) | 3488167514Skmacy V_ACTTORDWRDLY(p->ActToRdWrDly) | V_PRECYC(p->PreCyc) | 3489167514Skmacy V_REFCYC(p->RefCyc[density]) | V_BKCYC(p->BkCyc) | 3490167514Skmacy V_WRTORDDLY(p->WrToRdDly) | V_RDTOWRDLY(p->RdToWrDly)); 3491167514Skmacy 3492167514Skmacy t3_write_reg(adapter, mc7->offset + A_MC7_CFG, 3493167514Skmacy val | F_CLKEN | F_TERM150); 3494167514Skmacy (void) t3_read_reg(adapter, mc7->offset + A_MC7_CFG); /* flush */ 3495167514Skmacy 3496167514Skmacy if (!slow) 3497167514Skmacy t3_set_reg_field(adapter, mc7->offset + A_MC7_DLL, F_DLLENB, 3498167514Skmacy F_DLLENB); 3499167514Skmacy udelay(1); 3500167514Skmacy 3501167514Skmacy val = slow ? 3 : 6; 3502167514Skmacy if (wrreg_wait(adapter, mc7->offset + A_MC7_PRE, 0) || 3503167514Skmacy wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE2, 0) || 3504167514Skmacy wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE3, 0) || 3505167514Skmacy wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE1, val)) 3506167514Skmacy goto out_fail; 3507167514Skmacy 3508167514Skmacy if (!slow) { 3509167514Skmacy t3_write_reg(adapter, mc7->offset + A_MC7_MODE, 0x100); 3510167514Skmacy t3_set_reg_field(adapter, mc7->offset + A_MC7_DLL, 3511167514Skmacy F_DLLRST, 0); 3512167514Skmacy udelay(5); 3513167514Skmacy } 3514167514Skmacy 3515167514Skmacy if (wrreg_wait(adapter, mc7->offset + A_MC7_PRE, 0) || 3516167514Skmacy wrreg_wait(adapter, mc7->offset + A_MC7_REF, 0) || 3517167514Skmacy wrreg_wait(adapter, mc7->offset + A_MC7_REF, 0) || 3518167514Skmacy wrreg_wait(adapter, mc7->offset + A_MC7_MODE, 3519167514Skmacy mc7_mode[mem_type]) || 3520167514Skmacy wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE1, val | 0x380) || 3521167514Skmacy wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE1, val)) 3522167514Skmacy goto out_fail; 3523167514Skmacy 3524167514Skmacy /* clock value is in KHz */ 3525167514Skmacy mc7_clock = mc7_clock * 7812 + mc7_clock / 2; /* ns */ 3526167514Skmacy mc7_clock /= 1000000; /* KHz->MHz, ns->us */ 3527167514Skmacy 3528167514Skmacy t3_write_reg(adapter, mc7->offset + A_MC7_REF, 3529167514Skmacy F_PERREFEN | V_PREREFDIV(mc7_clock)); 3530167514Skmacy (void) t3_read_reg(adapter, mc7->offset + A_MC7_REF); /* flush */ 3531167514Skmacy 3532167514Skmacy t3_write_reg(adapter, mc7->offset + A_MC7_ECC, 3533167514Skmacy F_ECCGENEN | F_ECCCHKEN); 3534167514Skmacy t3_write_reg(adapter, mc7->offset + A_MC7_BIST_DATA, 0); 3535167514Skmacy t3_write_reg(adapter, mc7->offset + A_MC7_BIST_ADDR_BEG, 0); 3536167514Skmacy t3_write_reg(adapter, mc7->offset + A_MC7_BIST_ADDR_END, 3537167514Skmacy (mc7->size << width) - 1); 3538167514Skmacy t3_write_reg(adapter, mc7->offset + A_MC7_BIST_OP, V_OP(1)); 3539167514Skmacy (void) t3_read_reg(adapter, mc7->offset + A_MC7_BIST_OP); /* flush */ 3540167514Skmacy 3541167514Skmacy attempts = 50; 3542167514Skmacy do { 3543171471Skmacy msleep(250); 3544167514Skmacy val = t3_read_reg(adapter, mc7->offset + A_MC7_BIST_OP); 3545167514Skmacy } while ((val & F_BUSY) && --attempts); 3546167514Skmacy if (val & F_BUSY) { 3547167514Skmacy CH_ERR(adapter, "%s MC7 BIST timed out\n", mc7->name); 3548167514Skmacy goto out_fail; 3549167514Skmacy } 3550167514Skmacy 3551167514Skmacy /* Enable normal memory accesses. */ 3552167514Skmacy t3_set_reg_field(adapter, mc7->offset + A_MC7_CFG, 0, F_RDY); 3553167514Skmacy return 0; 3554167514Skmacy 3555167514Skmacy out_fail: 3556167514Skmacy return -1; 3557167514Skmacy} 3558167514Skmacy 3559167514Skmacystatic void config_pcie(adapter_t *adap) 3560167514Skmacy{ 3561167514Skmacy static const u16 ack_lat[4][6] = { 3562167514Skmacy { 237, 416, 559, 1071, 2095, 4143 }, 3563167514Skmacy { 128, 217, 289, 545, 1057, 2081 }, 3564167514Skmacy { 73, 118, 154, 282, 538, 1050 }, 3565167514Skmacy { 67, 107, 86, 150, 278, 534 } 3566167514Skmacy }; 3567167514Skmacy static const u16 rpl_tmr[4][6] = { 3568167514Skmacy { 711, 1248, 1677, 3213, 6285, 12429 }, 3569167514Skmacy { 384, 651, 867, 1635, 3171, 6243 }, 3570167514Skmacy { 219, 354, 462, 846, 1614, 3150 }, 3571167514Skmacy { 201, 321, 258, 450, 834, 1602 } 3572167514Skmacy }; 3573167514Skmacy 3574167514Skmacy u16 val; 3575167514Skmacy unsigned int log2_width, pldsize; 3576167514Skmacy unsigned int fst_trn_rx, fst_trn_tx, acklat, rpllmt; 3577167514Skmacy 3578167514Skmacy t3_os_pci_read_config_2(adap, 3579167514Skmacy adap->params.pci.pcie_cap_addr + PCI_EXP_DEVCTL, 3580167514Skmacy &val); 3581167514Skmacy pldsize = (val & PCI_EXP_DEVCTL_PAYLOAD) >> 5; 3582167514Skmacy 3583167514Skmacy t3_os_pci_read_config_2(adap, 3584167514Skmacy adap->params.pci.pcie_cap_addr + PCI_EXP_LNKCTL, 3585167514Skmacy &val); 3586167514Skmacy 3587167514Skmacy fst_trn_tx = G_NUMFSTTRNSEQ(t3_read_reg(adap, A_PCIE_PEX_CTRL0)); 3588167514Skmacy fst_trn_rx = adap->params.rev == 0 ? fst_trn_tx : 3589167514Skmacy G_NUMFSTTRNSEQRX(t3_read_reg(adap, A_PCIE_MODE)); 3590167514Skmacy log2_width = fls(adap->params.pci.width) - 1; 3591167514Skmacy acklat = ack_lat[log2_width][pldsize]; 3592167514Skmacy if (val & 1) /* check LOsEnable */ 3593167514Skmacy acklat += fst_trn_tx * 4; 3594167514Skmacy rpllmt = rpl_tmr[log2_width][pldsize] + fst_trn_rx * 4; 3595167514Skmacy 3596167514Skmacy if (adap->params.rev == 0) 3597167514Skmacy t3_set_reg_field(adap, A_PCIE_PEX_CTRL1, 3598167514Skmacy V_T3A_ACKLAT(M_T3A_ACKLAT), 3599167514Skmacy V_T3A_ACKLAT(acklat)); 3600167514Skmacy else 3601167514Skmacy t3_set_reg_field(adap, A_PCIE_PEX_CTRL1, V_ACKLAT(M_ACKLAT), 3602167514Skmacy V_ACKLAT(acklat)); 3603167514Skmacy 3604167514Skmacy t3_set_reg_field(adap, A_PCIE_PEX_CTRL0, V_REPLAYLMT(M_REPLAYLMT), 3605167514Skmacy V_REPLAYLMT(rpllmt)); 3606167514Skmacy 3607167514Skmacy t3_write_reg(adap, A_PCIE_PEX_ERR, 0xffffffff); 3608176472Skmacy t3_set_reg_field(adap, A_PCIE_CFG, 0, 3609176472Skmacy F_PCIE_DMASTOPEN | F_PCIE_CLIDECEN); 3610167514Skmacy} 3611167514Skmacy 3612172096Skmacy/** 3613172096Skmacy * t3_init_hw - initialize and configure T3 HW modules 3614172096Skmacy * @adapter: the adapter 3615172096Skmacy * @fw_params: initial parameters to pass to firmware (optional) 3616167514Skmacy * 3617172096Skmacy * Initialize and configure T3 HW modules. This performs the 3618172096Skmacy * initialization steps that need to be done once after a card is reset. 3619172096Skmacy * MAC and PHY initialization is handled separarely whenever a port is 3620172096Skmacy * enabled. 3621172096Skmacy * 3622172096Skmacy * @fw_params are passed to FW and their value is platform dependent. 3623172096Skmacy * Only the top 8 bits are available for use, the rest must be 0. 3624167514Skmacy */ 3625167514Skmacyint t3_init_hw(adapter_t *adapter, u32 fw_params) 3626167514Skmacy{ 3627176472Skmacy int err = -EIO, attempts, i; 3628167514Skmacy const struct vpd_params *vpd = &adapter->params.vpd; 3629167514Skmacy 3630167514Skmacy if (adapter->params.rev > 0) 3631167514Skmacy calibrate_xgm_t3b(adapter); 3632167514Skmacy else if (calibrate_xgm(adapter)) 3633167514Skmacy goto out_err; 3634167514Skmacy 3635171471Skmacy if (adapter->params.nports > 2) 3636170654Skmacy t3_mac_reset(&adap2pinfo(adapter, 0)->mac); 3637170654Skmacy 3638167514Skmacy if (vpd->mclk) { 3639167514Skmacy partition_mem(adapter, &adapter->params.tp); 3640167514Skmacy 3641167514Skmacy if (mc7_init(&adapter->pmrx, vpd->mclk, vpd->mem_timing) || 3642167514Skmacy mc7_init(&adapter->pmtx, vpd->mclk, vpd->mem_timing) || 3643167514Skmacy mc7_init(&adapter->cm, vpd->mclk, vpd->mem_timing) || 3644167514Skmacy t3_mc5_init(&adapter->mc5, adapter->params.mc5.nservers, 3645167514Skmacy adapter->params.mc5.nfilters, 3646167514Skmacy adapter->params.mc5.nroutes)) 3647167514Skmacy goto out_err; 3648176472Skmacy 3649176472Skmacy for (i = 0; i < 32; i++) 3650176472Skmacy if (clear_sge_ctxt(adapter, i, F_CQ)) 3651176472Skmacy goto out_err; 3652167514Skmacy } 3653167514Skmacy 3654167514Skmacy if (tp_init(adapter, &adapter->params.tp)) 3655167514Skmacy goto out_err; 3656167514Skmacy 3657167514Skmacy#ifdef CONFIG_CHELSIO_T3_CORE 3658167514Skmacy t3_tp_set_coalescing_size(adapter, 3659167514Skmacy min(adapter->params.sge.max_pkt_size, 3660167514Skmacy MAX_RX_COALESCING_LEN), 1); 3661167514Skmacy t3_tp_set_max_rxsize(adapter, 3662167514Skmacy min(adapter->params.sge.max_pkt_size, 16384U)); 3663167514Skmacy ulp_config(adapter, &adapter->params.tp); 3664167514Skmacy#endif 3665167514Skmacy if (is_pcie(adapter)) 3666167514Skmacy config_pcie(adapter); 3667167514Skmacy else 3668176472Skmacy t3_set_reg_field(adapter, A_PCIX_CFG, 0, 3669176472Skmacy F_DMASTOPEN | F_CLIDECEN); 3670167514Skmacy 3671176472Skmacy if (adapter->params.rev == T3_REV_C) 3672176472Skmacy t3_set_reg_field(adapter, A_ULPTX_CONFIG, 0, 3673176472Skmacy F_CFG_CQE_SOP_MASK); 3674176472Skmacy 3675170654Skmacy t3_write_reg(adapter, A_PM1_RX_CFG, 0xffffffff); 3676172096Skmacy t3_write_reg(adapter, A_PM1_RX_MODE, 0); 3677172096Skmacy t3_write_reg(adapter, A_PM1_TX_MODE, 0); 3678170654Skmacy chan_init_hw(adapter, adapter->params.chan_map); 3679167514Skmacy t3_sge_init(adapter, &adapter->params.sge); 3680167514Skmacy 3681180583Skmacy t3_write_reg(adapter, A_T3DBG_GPIO_ACT_LOW, calc_gpio_intr(adapter)); 3682180583Skmacy 3683167514Skmacy t3_write_reg(adapter, A_CIM_HOST_ACC_DATA, vpd->uclk | fw_params); 3684167514Skmacy t3_write_reg(adapter, A_CIM_BOOT_CFG, 3685167514Skmacy V_BOOTADDR(FW_FLASH_BOOT_ADDR >> 2)); 3686167514Skmacy (void) t3_read_reg(adapter, A_CIM_BOOT_CFG); /* flush */ 3687167514Skmacy 3688176472Skmacy attempts = 100; 3689167514Skmacy do { /* wait for uP to initialize */ 3690171471Skmacy msleep(20); 3691167514Skmacy } while (t3_read_reg(adapter, A_CIM_HOST_ACC_DATA) && --attempts); 3692169978Skmacy if (!attempts) { 3693169978Skmacy CH_ERR(adapter, "uP initialization timed out\n"); 3694167514Skmacy goto out_err; 3695169978Skmacy } 3696170654Skmacy 3697167514Skmacy err = 0; 3698167514Skmacy out_err: 3699167514Skmacy return err; 3700167514Skmacy} 3701167514Skmacy 3702167514Skmacy/** 3703167514Skmacy * get_pci_mode - determine a card's PCI mode 3704167514Skmacy * @adapter: the adapter 3705167514Skmacy * @p: where to store the PCI settings 3706167514Skmacy * 3707167514Skmacy * Determines a card's PCI mode and associated parameters, such as speed 3708167514Skmacy * and width. 3709167514Skmacy */ 3710167514Skmacystatic void __devinit get_pci_mode(adapter_t *adapter, struct pci_params *p) 3711167514Skmacy{ 3712167514Skmacy static unsigned short speed_map[] = { 33, 66, 100, 133 }; 3713167514Skmacy u32 pci_mode, pcie_cap; 3714167514Skmacy 3715167514Skmacy pcie_cap = t3_os_find_pci_capability(adapter, PCI_CAP_ID_EXP); 3716167514Skmacy if (pcie_cap) { 3717167514Skmacy u16 val; 3718167514Skmacy 3719167514Skmacy p->variant = PCI_VARIANT_PCIE; 3720167514Skmacy p->pcie_cap_addr = pcie_cap; 3721167514Skmacy t3_os_pci_read_config_2(adapter, pcie_cap + PCI_EXP_LNKSTA, 3722167514Skmacy &val); 3723167514Skmacy p->width = (val >> 4) & 0x3f; 3724167514Skmacy return; 3725167514Skmacy } 3726167514Skmacy 3727167514Skmacy pci_mode = t3_read_reg(adapter, A_PCIX_MODE); 3728167514Skmacy p->speed = speed_map[G_PCLKRANGE(pci_mode)]; 3729167514Skmacy p->width = (pci_mode & F_64BIT) ? 64 : 32; 3730167514Skmacy pci_mode = G_PCIXINITPAT(pci_mode); 3731167514Skmacy if (pci_mode == 0) 3732167514Skmacy p->variant = PCI_VARIANT_PCI; 3733167514Skmacy else if (pci_mode < 4) 3734167514Skmacy p->variant = PCI_VARIANT_PCIX_MODE1_PARITY; 3735167514Skmacy else if (pci_mode < 8) 3736167514Skmacy p->variant = PCI_VARIANT_PCIX_MODE1_ECC; 3737167514Skmacy else 3738167514Skmacy p->variant = PCI_VARIANT_PCIX_266_MODE2; 3739167514Skmacy} 3740167514Skmacy 3741167514Skmacy/** 3742167514Skmacy * init_link_config - initialize a link's SW state 3743167514Skmacy * @lc: structure holding the link state 3744172096Skmacy * @caps: link capabilities 3745167514Skmacy * 3746167514Skmacy * Initializes the SW state maintained for each link, including the link's 3747167514Skmacy * capabilities and default speed/duplex/flow-control/autonegotiation 3748167514Skmacy * settings. 3749167514Skmacy */ 3750167514Skmacystatic void __devinit init_link_config(struct link_config *lc, 3751167514Skmacy unsigned int caps) 3752167514Skmacy{ 3753167514Skmacy lc->supported = caps; 3754167514Skmacy lc->requested_speed = lc->speed = SPEED_INVALID; 3755167514Skmacy lc->requested_duplex = lc->duplex = DUPLEX_INVALID; 3756167514Skmacy lc->requested_fc = lc->fc = PAUSE_RX | PAUSE_TX; 3757167514Skmacy if (lc->supported & SUPPORTED_Autoneg) { 3758167514Skmacy lc->advertising = lc->supported; 3759167514Skmacy lc->autoneg = AUTONEG_ENABLE; 3760167514Skmacy lc->requested_fc |= PAUSE_AUTONEG; 3761167514Skmacy } else { 3762167514Skmacy lc->advertising = 0; 3763167514Skmacy lc->autoneg = AUTONEG_DISABLE; 3764167514Skmacy } 3765167514Skmacy} 3766167514Skmacy 3767167514Skmacy/** 3768167514Skmacy * mc7_calc_size - calculate MC7 memory size 3769167514Skmacy * @cfg: the MC7 configuration 3770167514Skmacy * 3771167514Skmacy * Calculates the size of an MC7 memory in bytes from the value of its 3772167514Skmacy * configuration register. 3773167514Skmacy */ 3774167514Skmacystatic unsigned int __devinit mc7_calc_size(u32 cfg) 3775167514Skmacy{ 3776167514Skmacy unsigned int width = G_WIDTH(cfg); 3777167514Skmacy unsigned int banks = !!(cfg & F_BKS) + 1; 3778167514Skmacy unsigned int org = !!(cfg & F_ORG) + 1; 3779167514Skmacy unsigned int density = G_DEN(cfg); 3780167514Skmacy unsigned int MBs = ((256 << density) * banks) / (org << width); 3781167514Skmacy 3782167514Skmacy return MBs << 20; 3783167514Skmacy} 3784167514Skmacy 3785167514Skmacystatic void __devinit mc7_prep(adapter_t *adapter, struct mc7 *mc7, 3786167514Skmacy unsigned int base_addr, const char *name) 3787167514Skmacy{ 3788167514Skmacy u32 cfg; 3789167514Skmacy 3790167514Skmacy mc7->adapter = adapter; 3791167514Skmacy mc7->name = name; 3792167514Skmacy mc7->offset = base_addr - MC7_PMRX_BASE_ADDR; 3793167514Skmacy cfg = t3_read_reg(adapter, mc7->offset + A_MC7_CFG); 3794169978Skmacy mc7->size = G_DEN(cfg) == M_DEN ? 0 : mc7_calc_size(cfg); 3795167514Skmacy mc7->width = G_WIDTH(cfg); 3796167514Skmacy} 3797167514Skmacy 3798167514Skmacyvoid mac_prep(struct cmac *mac, adapter_t *adapter, int index) 3799167514Skmacy{ 3800167514Skmacy mac->adapter = adapter; 3801170654Skmacy mac->multiport = adapter->params.nports > 2; 3802170654Skmacy if (mac->multiport) { 3803170654Skmacy mac->ext_port = (unsigned char)index; 3804170654Skmacy mac->nucast = 8; 3805170654Skmacy index = 0; 3806170654Skmacy } else 3807170654Skmacy mac->nucast = 1; 3808170654Skmacy 3809167514Skmacy mac->offset = (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR) * index; 3810167514Skmacy 3811167514Skmacy if (adapter->params.rev == 0 && uses_xaui(adapter)) { 3812167514Skmacy t3_write_reg(adapter, A_XGM_SERDES_CTRL + mac->offset, 3813167514Skmacy is_10G(adapter) ? 0x2901c04 : 0x2301c04); 3814167514Skmacy t3_set_reg_field(adapter, A_XGM_PORT_CFG + mac->offset, 3815167514Skmacy F_ENRGMII, 0); 3816167514Skmacy } 3817167514Skmacy} 3818167514Skmacy 3819172096Skmacy/** 3820172096Skmacy * early_hw_init - HW initialization done at card detection time 3821172096Skmacy * @adapter: the adapter 3822172096Skmacy * @ai: contains information about the adapter type and properties 3823172096Skmacy * 3824172096Skmacy * Perfoms the part of HW initialization that is done early on when the 3825172096Skmacy * driver first detecs the card. Most of the HW state is initialized 3826172096Skmacy * lazily later on when a port or an offload function are first used. 3827172096Skmacy */ 3828167514Skmacyvoid early_hw_init(adapter_t *adapter, const struct adapter_info *ai) 3829167514Skmacy{ 3830170654Skmacy u32 val = V_PORTSPEED(is_10G(adapter) || adapter->params.nports > 2 ? 3831170654Skmacy 3 : 2); 3832167514Skmacy 3833167514Skmacy mi1_init(adapter, ai); 3834167514Skmacy t3_write_reg(adapter, A_I2C_CFG, /* set for 80KHz */ 3835167514Skmacy V_I2C_CLKDIV(adapter->params.vpd.cclk / 80 - 1)); 3836167514Skmacy t3_write_reg(adapter, A_T3DBG_GPIO_EN, 3837167514Skmacy ai->gpio_out | F_GPIO0_OEN | F_GPIO0_OUT_VAL); 3838169978Skmacy t3_write_reg(adapter, A_MC5_DB_SERVER_INDEX, 0); 3839176472Skmacy t3_write_reg(adapter, A_SG_OCO_BASE, V_BASE1(0xfff)); 3840170654Skmacy 3841167514Skmacy if (adapter->params.rev == 0 || !uses_xaui(adapter)) 3842167514Skmacy val |= F_ENRGMII; 3843167514Skmacy 3844167514Skmacy /* Enable MAC clocks so we can access the registers */ 3845167514Skmacy t3_write_reg(adapter, A_XGM_PORT_CFG, val); 3846167514Skmacy (void) t3_read_reg(adapter, A_XGM_PORT_CFG); 3847167514Skmacy 3848167514Skmacy val |= F_CLKDIVRESET_; 3849167514Skmacy t3_write_reg(adapter, A_XGM_PORT_CFG, val); 3850167514Skmacy (void) t3_read_reg(adapter, A_XGM_PORT_CFG); 3851167514Skmacy t3_write_reg(adapter, XGM_REG(A_XGM_PORT_CFG, 1), val); 3852167514Skmacy (void) t3_read_reg(adapter, A_XGM_PORT_CFG); 3853167514Skmacy} 3854167514Skmacy 3855172096Skmacy/** 3856172096Skmacy * t3_reset_adapter - reset the adapter 3857172096Skmacy * @adapter: the adapter 3858172096Skmacy * 3859172096Skmacy * Reset the adapter. 3860167514Skmacy */ 3861170654Skmacystatic int t3_reset_adapter(adapter_t *adapter) 3862167514Skmacy{ 3863170654Skmacy int i, save_and_restore_pcie = 3864167746Skmacy adapter->params.rev < T3_REV_B2 && is_pcie(adapter); 3865167746Skmacy uint16_t devid = 0; 3866167514Skmacy 3867167746Skmacy if (save_and_restore_pcie) 3868167514Skmacy t3_os_pci_save_state(adapter); 3869167514Skmacy t3_write_reg(adapter, A_PL_RST, F_CRSTWRM | F_CRSTWRMMODE); 3870167514Skmacy 3871167514Skmacy /* 3872167514Skmacy * Delay. Give Some time to device to reset fully. 3873167514Skmacy * XXX The delay time should be modified. 3874167514Skmacy */ 3875167514Skmacy for (i = 0; i < 10; i++) { 3876171471Skmacy msleep(50); 3877167514Skmacy t3_os_pci_read_config_2(adapter, 0x00, &devid); 3878167514Skmacy if (devid == 0x1425) 3879167514Skmacy break; 3880167514Skmacy } 3881167514Skmacy 3882167514Skmacy if (devid != 0x1425) 3883167514Skmacy return -1; 3884167514Skmacy 3885167746Skmacy if (save_and_restore_pcie) 3886167514Skmacy t3_os_pci_restore_state(adapter); 3887167514Skmacy return 0; 3888167514Skmacy} 3889167514Skmacy 3890181614Skmacystatic int init_parity(adapter_t *adap) 3891176472Skmacy{ 3892176472Skmacy int i, err, addr; 3893176472Skmacy 3894176472Skmacy if (t3_read_reg(adap, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) 3895176472Skmacy return -EBUSY; 3896176472Skmacy 3897176472Skmacy for (err = i = 0; !err && i < 16; i++) 3898176472Skmacy err = clear_sge_ctxt(adap, i, F_EGRESS); 3899176472Skmacy for (i = 0xfff0; !err && i <= 0xffff; i++) 3900176472Skmacy err = clear_sge_ctxt(adap, i, F_EGRESS); 3901176472Skmacy for (i = 0; !err && i < SGE_QSETS; i++) 3902176472Skmacy err = clear_sge_ctxt(adap, i, F_RESPONSEQ); 3903176472Skmacy if (err) 3904176472Skmacy return err; 3905176472Skmacy 3906176472Skmacy t3_write_reg(adap, A_CIM_IBQ_DBG_DATA, 0); 3907176472Skmacy for (i = 0; i < 4; i++) 3908176472Skmacy for (addr = 0; addr <= M_IBQDBGADDR; addr++) { 3909176472Skmacy t3_write_reg(adap, A_CIM_IBQ_DBG_CFG, F_IBQDBGEN | 3910176472Skmacy F_IBQDBGWR | V_IBQDBGQID(i) | 3911176472Skmacy V_IBQDBGADDR(addr)); 3912176472Skmacy err = t3_wait_op_done(adap, A_CIM_IBQ_DBG_CFG, 3913176472Skmacy F_IBQDBGBUSY, 0, 2, 1); 3914176472Skmacy if (err) 3915176472Skmacy return err; 3916176472Skmacy } 3917176472Skmacy return 0; 3918176472Skmacy} 3919176472Skmacy 3920172096Skmacy/** 3921172096Skmacy * t3_prep_adapter - prepare SW and HW for operation 3922172096Skmacy * @adapter: the adapter 3923172096Skmacy * @ai: contains information about the adapter type and properties 3924172096Skmacy * 3925172096Skmacy * Initialize adapter SW state for the various HW modules, set initial 3926172096Skmacy * values for some adapter tunables, take PHYs out of reset, and 3927172096Skmacy * initialize the MDIO interface. 3928167514Skmacy */ 3929167514Skmacyint __devinit t3_prep_adapter(adapter_t *adapter, 3930167514Skmacy const struct adapter_info *ai, int reset) 3931167514Skmacy{ 3932167514Skmacy int ret; 3933167514Skmacy unsigned int i, j = 0; 3934167514Skmacy 3935167514Skmacy get_pci_mode(adapter, &adapter->params.pci); 3936167514Skmacy 3937167514Skmacy adapter->params.info = ai; 3938170654Skmacy adapter->params.nports = ai->nports0 + ai->nports1; 3939170654Skmacy adapter->params.chan_map = !!ai->nports0 | (!!ai->nports1 << 1); 3940167514Skmacy adapter->params.rev = t3_read_reg(adapter, A_PL_REV); 3941167514Skmacy adapter->params.linkpoll_period = 0; 3942171471Skmacy if (adapter->params.nports > 2) 3943171471Skmacy adapter->params.stats_update_period = VSC_STATS_ACCUM_SECS; 3944171471Skmacy else 3945171471Skmacy adapter->params.stats_update_period = is_10G(adapter) ? 3946171471Skmacy MAC_STATS_ACCUM_SECS : (MAC_STATS_ACCUM_SECS * 10); 3947167514Skmacy adapter->params.pci.vpd_cap_addr = 3948167514Skmacy t3_os_find_pci_capability(adapter, PCI_CAP_ID_VPD); 3949167514Skmacy 3950167514Skmacy ret = get_vpd_params(adapter, &adapter->params.vpd); 3951171471Skmacy if (ret < 0) 3952167514Skmacy return ret; 3953171471Skmacy 3954167514Skmacy if (reset && t3_reset_adapter(adapter)) 3955167514Skmacy return -1; 3956167514Skmacy 3957167514Skmacy t3_sge_prep(adapter, &adapter->params.sge); 3958167514Skmacy 3959167514Skmacy if (adapter->params.vpd.mclk) { 3960167514Skmacy struct tp_params *p = &adapter->params.tp; 3961167514Skmacy 3962167514Skmacy mc7_prep(adapter, &adapter->pmrx, MC7_PMRX_BASE_ADDR, "PMRX"); 3963167514Skmacy mc7_prep(adapter, &adapter->pmtx, MC7_PMTX_BASE_ADDR, "PMTX"); 3964167514Skmacy mc7_prep(adapter, &adapter->cm, MC7_CM_BASE_ADDR, "CM"); 3965167514Skmacy 3966170654Skmacy p->nchan = adapter->params.chan_map == 3 ? 2 : 1; 3967167514Skmacy p->pmrx_size = t3_mc7_size(&adapter->pmrx); 3968167514Skmacy p->pmtx_size = t3_mc7_size(&adapter->pmtx); 3969167514Skmacy p->cm_size = t3_mc7_size(&adapter->cm); 3970167514Skmacy p->chan_rx_size = p->pmrx_size / 2; /* only 1 Rx channel */ 3971167514Skmacy p->chan_tx_size = p->pmtx_size / p->nchan; 3972167514Skmacy p->rx_pg_size = 64 * 1024; 3973167514Skmacy p->tx_pg_size = is_10G(adapter) ? 64 * 1024 : 16 * 1024; 3974167514Skmacy p->rx_num_pgs = pm_num_pages(p->chan_rx_size, p->rx_pg_size); 3975167514Skmacy p->tx_num_pgs = pm_num_pages(p->chan_tx_size, p->tx_pg_size); 3976167514Skmacy p->ntimer_qs = p->cm_size >= (128 << 20) || 3977167514Skmacy adapter->params.rev > 0 ? 12 : 6; 3978170654Skmacy p->tre = fls(adapter->params.vpd.cclk / (1000 / TP_TMR_RES)) - 3979170654Skmacy 1; 3980167746Skmacy p->dack_re = fls(adapter->params.vpd.cclk / 10) - 1; /* 100us */ 3981169978Skmacy } 3982170654Skmacy 3983169978Skmacy adapter->params.offload = t3_mc7_size(&adapter->pmrx) && 3984170654Skmacy t3_mc7_size(&adapter->pmtx) && 3985170654Skmacy t3_mc7_size(&adapter->cm); 3986167514Skmacy 3987169978Skmacy if (is_offload(adapter)) { 3988167514Skmacy adapter->params.mc5.nservers = DEFAULT_NSERVERS; 3989167514Skmacy adapter->params.mc5.nfilters = adapter->params.rev > 0 ? 3990167514Skmacy DEFAULT_NFILTERS : 0; 3991167514Skmacy adapter->params.mc5.nroutes = 0; 3992167514Skmacy t3_mc5_prep(adapter, &adapter->mc5, MC5_MODE_144_BIT); 3993167514Skmacy 3994167514Skmacy#ifdef CONFIG_CHELSIO_T3_CORE 3995167514Skmacy init_mtus(adapter->params.mtus); 3996167514Skmacy init_cong_ctrl(adapter->params.a_wnd, adapter->params.b_wnd); 3997167514Skmacy#endif 3998167514Skmacy } 3999167514Skmacy 4000167514Skmacy early_hw_init(adapter, ai); 4001176472Skmacy ret = init_parity(adapter); 4002176472Skmacy if (ret) 4003176472Skmacy return ret; 4004167514Skmacy 4005171471Skmacy if (adapter->params.nports > 2 && 4006171471Skmacy (ret = t3_vsc7323_init(adapter, adapter->params.nports))) 4007171471Skmacy return ret; 4008171471Skmacy 4009167514Skmacy for_each_port(adapter, i) { 4010167514Skmacy u8 hw_addr[6]; 4011176472Skmacy const struct port_type_info *pti; 4012170654Skmacy struct port_info *p = adap2pinfo(adapter, i); 4013167514Skmacy 4014171471Skmacy while (!adapter->params.vpd.port_type[j]) 4015167514Skmacy ++j; 4016167514Skmacy 4017176472Skmacy pti = &port_types[adapter->params.vpd.port_type[j]]; 4018176472Skmacy ret = pti->phy_prep(&p->phy, adapter, ai->phy_base_addr + j, 4019176472Skmacy ai->mdio_ops); 4020176472Skmacy if (ret) 4021176472Skmacy return ret; 4022167514Skmacy mac_prep(&p->mac, adapter, j); 4023167514Skmacy ++j; 4024167514Skmacy 4025167514Skmacy /* 4026167514Skmacy * The VPD EEPROM stores the base Ethernet address for the 4027167514Skmacy * card. A port's address is derived from the base by adding 4028167514Skmacy * the port's index to the base's low octet. 4029167514Skmacy */ 4030167514Skmacy memcpy(hw_addr, adapter->params.vpd.eth_base, 5); 4031167514Skmacy hw_addr[5] = adapter->params.vpd.eth_base[5] + i; 4032167514Skmacy 4033167514Skmacy t3_os_set_hw_addr(adapter, i, hw_addr); 4034176472Skmacy init_link_config(&p->link_config, p->phy.caps); 4035167514Skmacy p->phy.ops->power_down(&p->phy, 1); 4036176472Skmacy if (!(p->phy.caps & SUPPORTED_IRQ)) 4037167514Skmacy adapter->params.linkpoll_period = 10; 4038167514Skmacy } 4039167514Skmacy 4040167514Skmacy return 0; 4041167514Skmacy} 4042167514Skmacy 4043181614Skmacy/** 4044181614Skmacy * t3_reinit_adapter - prepare HW for operation again 4045181614Skmacy * @adapter: the adapter 4046181614Skmacy * 4047181614Skmacy * Put HW in the same state as @t3_prep_adapter without any changes to 4048181614Skmacy * SW state. This is a cut down version of @t3_prep_adapter intended 4049181614Skmacy * to be used after events that wipe out HW state but preserve SW state, 4050181614Skmacy * e.g., EEH. The device must be reset before calling this. 4051181614Skmacy */ 4052181614Skmacyint t3_reinit_adapter(adapter_t *adap) 4053181614Skmacy{ 4054181614Skmacy unsigned int i; 4055181614Skmacy int ret, j = -1; 4056181614Skmacy 4057181614Skmacy early_hw_init(adap, adap->params.info); 4058181614Skmacy ret = init_parity(adap); 4059181614Skmacy if (ret) 4060181614Skmacy return ret; 4061181614Skmacy 4062181614Skmacy if (adap->params.nports > 2 && 4063181614Skmacy (ret = t3_vsc7323_init(adap, adap->params.nports))) 4064181614Skmacy return ret; 4065181614Skmacy 4066181614Skmacy for_each_port(adap, i) { 4067181614Skmacy const struct port_type_info *pti; 4068181614Skmacy struct port_info *p = adap2pinfo(adap, i); 4069181614Skmacy 4070181614Skmacy while (!adap->params.vpd.port_type[++j]) 4071181614Skmacy ; 4072181614Skmacy 4073181614Skmacy pti = &port_types[adap->params.vpd.port_type[j]]; 4074181614Skmacy ret = pti->phy_prep(&p->phy, adap, p->phy.addr, NULL); 4075181614Skmacy if (ret) 4076181614Skmacy return ret; 4077181614Skmacy p->phy.ops->power_down(&p->phy, 1); 4078181614Skmacy } 4079181614Skmacy return 0; 4080181614Skmacy} 4081181614Skmacy 4082167514Skmacyvoid t3_led_ready(adapter_t *adapter) 4083167514Skmacy{ 4084167514Skmacy t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL, 4085167514Skmacy F_GPIO0_OUT_VAL); 4086167514Skmacy} 4087167514Skmacy 4088167514Skmacyvoid t3_port_failover(adapter_t *adapter, int port) 4089167514Skmacy{ 4090167514Skmacy u32 val; 4091167514Skmacy 4092167514Skmacy val = port ? F_PORT1ACTIVE : F_PORT0ACTIVE; 4093167514Skmacy t3_set_reg_field(adapter, A_MPS_CFG, F_PORT0ACTIVE | F_PORT1ACTIVE, 4094167514Skmacy val); 4095167514Skmacy} 4096167514Skmacy 4097167514Skmacyvoid t3_failover_done(adapter_t *adapter, int port) 4098167514Skmacy{ 4099167514Skmacy t3_set_reg_field(adapter, A_MPS_CFG, F_PORT0ACTIVE | F_PORT1ACTIVE, 4100167514Skmacy F_PORT0ACTIVE | F_PORT1ACTIVE); 4101167514Skmacy} 4102167514Skmacy 4103167514Skmacyvoid t3_failover_clear(adapter_t *adapter) 4104167514Skmacy{ 4105167514Skmacy t3_set_reg_field(adapter, A_MPS_CFG, F_PORT0ACTIVE | F_PORT1ACTIVE, 4106167514Skmacy F_PORT0ACTIVE | F_PORT1ACTIVE); 4107167514Skmacy} 4108