Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright (c) 2005-2008 Chelsio, Inc. All rights reserved.
0003  *
0004  * This software is available to you under a choice of one of two
0005  * licenses.  You may choose to be licensed under the terms of the GNU
0006  * General Public License (GPL) Version 2, available from the file
0007  * COPYING in the main directory of this source tree, or the
0008  * OpenIB.org BSD license below:
0009  *
0010  *     Redistribution and use in source and binary forms, with or
0011  *     without modification, are permitted provided that the following
0012  *     conditions are met:
0013  *
0014  *      - Redistributions of source code must retain the above
0015  *        copyright notice, this list of conditions and the following
0016  *        disclaimer.
0017  *
0018  *      - Redistributions in binary form must reproduce the above
0019  *        copyright notice, this list of conditions and the following
0020  *        disclaimer in the documentation and/or other materials
0021  *        provided with the distribution.
0022  *
0023  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
0024  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
0025  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
0026  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
0027  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
0028  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
0029  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
0030  * SOFTWARE.
0031  */
0032 #include "common.h"
0033 #include "regs.h"
0034 
0035 /*
0036  * # of exact address filters.  The first one is used for the station address,
0037  * the rest are available for multicast addresses.
0038  */
0039 #define EXACT_ADDR_FILTERS 8
0040 
0041 static inline int macidx(const struct cmac *mac)
0042 {
0043     return mac->offset / (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR);
0044 }
0045 
0046 static void xaui_serdes_reset(struct cmac *mac)
0047 {
0048     static const unsigned int clear[] = {
0049         F_PWRDN0 | F_PWRDN1, F_RESETPLL01, F_RESET0 | F_RESET1,
0050         F_PWRDN2 | F_PWRDN3, F_RESETPLL23, F_RESET2 | F_RESET3
0051     };
0052 
0053     int i;
0054     struct adapter *adap = mac->adapter;
0055     u32 ctrl = A_XGM_SERDES_CTRL0 + mac->offset;
0056 
0057     t3_write_reg(adap, ctrl, adap->params.vpd.xauicfg[macidx(mac)] |
0058              F_RESET3 | F_RESET2 | F_RESET1 | F_RESET0 |
0059              F_PWRDN3 | F_PWRDN2 | F_PWRDN1 | F_PWRDN0 |
0060              F_RESETPLL23 | F_RESETPLL01);
0061     t3_read_reg(adap, ctrl);
0062     udelay(15);
0063 
0064     for (i = 0; i < ARRAY_SIZE(clear); i++) {
0065         t3_set_reg_field(adap, ctrl, clear[i], 0);
0066         udelay(15);
0067     }
0068 }
0069 
0070 void t3b_pcs_reset(struct cmac *mac)
0071 {
0072     t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset,
0073              F_PCS_RESET_, 0);
0074     udelay(20);
0075     t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset, 0,
0076              F_PCS_RESET_);
0077 }
0078 
0079 int t3_mac_reset(struct cmac *mac)
0080 {
0081     static const struct addr_val_pair mac_reset_avp[] = {
0082         {A_XGM_TX_CTRL, 0},
0083         {A_XGM_RX_CTRL, 0},
0084         {A_XGM_RX_CFG, F_DISPAUSEFRAMES | F_EN1536BFRAMES |
0085          F_RMFCS | F_ENJUMBO | F_ENHASHMCAST},
0086         {A_XGM_RX_HASH_LOW, 0},
0087         {A_XGM_RX_HASH_HIGH, 0},
0088         {A_XGM_RX_EXACT_MATCH_LOW_1, 0},
0089         {A_XGM_RX_EXACT_MATCH_LOW_2, 0},
0090         {A_XGM_RX_EXACT_MATCH_LOW_3, 0},
0091         {A_XGM_RX_EXACT_MATCH_LOW_4, 0},
0092         {A_XGM_RX_EXACT_MATCH_LOW_5, 0},
0093         {A_XGM_RX_EXACT_MATCH_LOW_6, 0},
0094         {A_XGM_RX_EXACT_MATCH_LOW_7, 0},
0095         {A_XGM_RX_EXACT_MATCH_LOW_8, 0},
0096         {A_XGM_STAT_CTRL, F_CLRSTATS}
0097     };
0098     u32 val;
0099     struct adapter *adap = mac->adapter;
0100     unsigned int oft = mac->offset;
0101 
0102     t3_write_reg(adap, A_XGM_RESET_CTRL + oft, F_MAC_RESET_);
0103     t3_read_reg(adap, A_XGM_RESET_CTRL + oft);  /* flush */
0104 
0105     t3_write_regs(adap, mac_reset_avp, ARRAY_SIZE(mac_reset_avp), oft);
0106     t3_set_reg_field(adap, A_XGM_RXFIFO_CFG + oft,
0107              F_RXSTRFRWRD | F_DISERRFRAMES,
0108              uses_xaui(adap) ? 0 : F_RXSTRFRWRD);
0109     t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + oft, 0, F_UNDERUNFIX);
0110 
0111     if (uses_xaui(adap)) {
0112         if (adap->params.rev == 0) {
0113             t3_set_reg_field(adap, A_XGM_SERDES_CTRL + oft, 0,
0114                      F_RXENABLE | F_TXENABLE);
0115             if (t3_wait_op_done(adap, A_XGM_SERDES_STATUS1 + oft,
0116                         F_CMULOCK, 1, 5, 2)) {
0117                 CH_ERR(adap,
0118                        "MAC %d XAUI SERDES CMU lock failed\n",
0119                        macidx(mac));
0120                 return -1;
0121             }
0122             t3_set_reg_field(adap, A_XGM_SERDES_CTRL + oft, 0,
0123                      F_SERDESRESET_);
0124         } else
0125             xaui_serdes_reset(mac);
0126     }
0127 
0128     t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + oft,
0129              V_RXMAXFRAMERSIZE(M_RXMAXFRAMERSIZE),
0130              V_RXMAXFRAMERSIZE(MAX_FRAME_SIZE) | F_RXENFRAMER);
0131     val = F_MAC_RESET_ | F_XGMAC_STOP_EN;
0132 
0133     if (is_10G(adap))
0134         val |= F_PCS_RESET_;
0135     else if (uses_xaui(adap))
0136         val |= F_PCS_RESET_ | F_XG2G_RESET_;
0137     else
0138         val |= F_RGMII_RESET_ | F_XG2G_RESET_;
0139     t3_write_reg(adap, A_XGM_RESET_CTRL + oft, val);
0140     t3_read_reg(adap, A_XGM_RESET_CTRL + oft);  /* flush */
0141     if ((val & F_PCS_RESET_) && adap->params.rev) {
0142         msleep(1);
0143         t3b_pcs_reset(mac);
0144     }
0145 
0146     memset(&mac->stats, 0, sizeof(mac->stats));
0147     return 0;
0148 }
0149 
0150 static int t3b2_mac_reset(struct cmac *mac)
0151 {
0152     struct adapter *adap = mac->adapter;
0153     unsigned int oft = mac->offset, store;
0154     int idx = macidx(mac);
0155     u32 val;
0156 
0157     if (!macidx(mac))
0158         t3_set_reg_field(adap, A_MPS_CFG, F_PORT0ACTIVE, 0);
0159     else
0160         t3_set_reg_field(adap, A_MPS_CFG, F_PORT1ACTIVE, 0);
0161 
0162     /* Stop NIC traffic to reduce the number of TXTOGGLES */
0163     t3_set_reg_field(adap, A_MPS_CFG, F_ENFORCEPKT, 0);
0164     /* Ensure TX drains */
0165     t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN, 0);
0166 
0167     t3_write_reg(adap, A_XGM_RESET_CTRL + oft, F_MAC_RESET_);
0168     t3_read_reg(adap, A_XGM_RESET_CTRL + oft);    /* flush */
0169 
0170     /* Store A_TP_TX_DROP_CFG_CH0 */
0171     t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
0172     store = t3_read_reg(adap, A_TP_TX_DROP_CFG_CH0 + idx);
0173 
0174     msleep(10);
0175 
0176     /* Change DROP_CFG to 0xc0000011 */
0177     t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
0178     t3_write_reg(adap, A_TP_PIO_DATA, 0xc0000011);
0179 
0180     /* Check for xgm Rx fifo empty */
0181     /* Increased loop count to 1000 from 5 cover 1G and 100Mbps case */
0182     if (t3_wait_op_done(adap, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT + oft,
0183                 0x80000000, 1, 1000, 2)) {
0184         CH_ERR(adap, "MAC %d Rx fifo drain failed\n",
0185                macidx(mac));
0186         return -1;
0187     }
0188 
0189     t3_write_reg(adap, A_XGM_RESET_CTRL + oft, 0);
0190     t3_read_reg(adap, A_XGM_RESET_CTRL + oft);    /* flush */
0191 
0192     val = F_MAC_RESET_;
0193     if (is_10G(adap))
0194         val |= F_PCS_RESET_;
0195     else if (uses_xaui(adap))
0196         val |= F_PCS_RESET_ | F_XG2G_RESET_;
0197     else
0198         val |= F_RGMII_RESET_ | F_XG2G_RESET_;
0199     t3_write_reg(adap, A_XGM_RESET_CTRL + oft, val);
0200     t3_read_reg(adap, A_XGM_RESET_CTRL + oft);  /* flush */
0201     if ((val & F_PCS_RESET_) && adap->params.rev) {
0202         msleep(1);
0203         t3b_pcs_reset(mac);
0204     }
0205     t3_write_reg(adap, A_XGM_RX_CFG + oft,
0206              F_DISPAUSEFRAMES | F_EN1536BFRAMES |
0207              F_RMFCS | F_ENJUMBO | F_ENHASHMCAST);
0208 
0209     /* Restore the DROP_CFG */
0210     t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
0211     t3_write_reg(adap, A_TP_PIO_DATA, store);
0212 
0213     if (!idx)
0214         t3_set_reg_field(adap, A_MPS_CFG, 0, F_PORT0ACTIVE);
0215     else
0216         t3_set_reg_field(adap, A_MPS_CFG, 0, F_PORT1ACTIVE);
0217 
0218     /* re-enable nic traffic */
0219     t3_set_reg_field(adap, A_MPS_CFG, F_ENFORCEPKT, 1);
0220 
0221     /*  Set: re-enable NIC traffic */
0222     t3_set_reg_field(adap, A_MPS_CFG, F_ENFORCEPKT, 1);
0223 
0224     return 0;
0225 }
0226 
0227 /*
0228  * Set the exact match register 'idx' to recognize the given Ethernet address.
0229  */
0230 static void set_addr_filter(struct cmac *mac, int idx, const u8 * addr)
0231 {
0232     u32 addr_lo, addr_hi;
0233     unsigned int oft = mac->offset + idx * 8;
0234 
0235     addr_lo = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0];
0236     addr_hi = (addr[5] << 8) | addr[4];
0237 
0238     t3_write_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1 + oft, addr_lo);
0239     t3_write_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_HIGH_1 + oft, addr_hi);
0240 }
0241 
0242 /* Set one of the station's unicast MAC addresses. */
0243 int t3_mac_set_address(struct cmac *mac, unsigned int idx, const u8 addr[6])
0244 {
0245     if (idx >= mac->nucast)
0246         return -EINVAL;
0247     set_addr_filter(mac, idx, addr);
0248     return 0;
0249 }
0250 
0251 /*
0252  * Specify the number of exact address filters that should be reserved for
0253  * unicast addresses.  Caller should reload the unicast and multicast addresses
0254  * after calling this.
0255  */
0256 int t3_mac_set_num_ucast(struct cmac *mac, int n)
0257 {
0258     if (n > EXACT_ADDR_FILTERS)
0259         return -EINVAL;
0260     mac->nucast = n;
0261     return 0;
0262 }
0263 
0264 void t3_mac_disable_exact_filters(struct cmac *mac)
0265 {
0266     unsigned int i, reg = mac->offset + A_XGM_RX_EXACT_MATCH_LOW_1;
0267 
0268     for (i = 0; i < EXACT_ADDR_FILTERS; i++, reg += 8) {
0269         u32 v = t3_read_reg(mac->adapter, reg);
0270         t3_write_reg(mac->adapter, reg, v);
0271     }
0272     t3_read_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1);  /* flush */
0273 }
0274 
0275 void t3_mac_enable_exact_filters(struct cmac *mac)
0276 {
0277     unsigned int i, reg = mac->offset + A_XGM_RX_EXACT_MATCH_HIGH_1;
0278 
0279     for (i = 0; i < EXACT_ADDR_FILTERS; i++, reg += 8) {
0280         u32 v = t3_read_reg(mac->adapter, reg);
0281         t3_write_reg(mac->adapter, reg, v);
0282     }
0283     t3_read_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1);  /* flush */
0284 }
0285 
0286 /* Calculate the RX hash filter index of an Ethernet address */
0287 static int hash_hw_addr(const u8 * addr)
0288 {
0289     int hash = 0, octet, bit, i = 0, c;
0290 
0291     for (octet = 0; octet < 6; ++octet)
0292         for (c = addr[octet], bit = 0; bit < 8; c >>= 1, ++bit) {
0293             hash ^= (c & 1) << i;
0294             if (++i == 6)
0295                 i = 0;
0296         }
0297     return hash;
0298 }
0299 
0300 int t3_mac_set_rx_mode(struct cmac *mac, struct net_device *dev)
0301 {
0302     u32 val, hash_lo, hash_hi;
0303     struct adapter *adap = mac->adapter;
0304     unsigned int oft = mac->offset;
0305 
0306     val = t3_read_reg(adap, A_XGM_RX_CFG + oft) & ~F_COPYALLFRAMES;
0307     if (dev->flags & IFF_PROMISC)
0308         val |= F_COPYALLFRAMES;
0309     t3_write_reg(adap, A_XGM_RX_CFG + oft, val);
0310 
0311     if (dev->flags & IFF_ALLMULTI)
0312         hash_lo = hash_hi = 0xffffffff;
0313     else {
0314         struct netdev_hw_addr *ha;
0315         int exact_addr_idx = mac->nucast;
0316 
0317         hash_lo = hash_hi = 0;
0318         netdev_for_each_mc_addr(ha, dev)
0319             if (exact_addr_idx < EXACT_ADDR_FILTERS)
0320                 set_addr_filter(mac, exact_addr_idx++,
0321                         ha->addr);
0322             else {
0323                 int hash = hash_hw_addr(ha->addr);
0324 
0325                 if (hash < 32)
0326                     hash_lo |= (1 << hash);
0327                 else
0328                     hash_hi |= (1 << (hash - 32));
0329             }
0330     }
0331 
0332     t3_write_reg(adap, A_XGM_RX_HASH_LOW + oft, hash_lo);
0333     t3_write_reg(adap, A_XGM_RX_HASH_HIGH + oft, hash_hi);
0334     return 0;
0335 }
0336 
0337 static int rx_fifo_hwm(int mtu)
0338 {
0339     int hwm;
0340 
0341     hwm = max(MAC_RXFIFO_SIZE - 3 * mtu, (MAC_RXFIFO_SIZE * 38) / 100);
0342     return min(hwm, MAC_RXFIFO_SIZE - 8192);
0343 }
0344 
0345 int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu)
0346 {
0347     int hwm, lwm, divisor;
0348     int ipg;
0349     unsigned int thres, v, reg;
0350     struct adapter *adap = mac->adapter;
0351 
0352     /*
0353      * MAX_FRAME_SIZE inludes header + FCS, mtu doesn't.  The HW max
0354      * packet size register includes header, but not FCS.
0355      */
0356     mtu += 14;
0357     if (mtu > 1536)
0358         mtu += 4;
0359 
0360     if (mtu > MAX_FRAME_SIZE - 4)
0361         return -EINVAL;
0362     t3_write_reg(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset, mtu);
0363 
0364     if (adap->params.rev >= T3_REV_B2 &&
0365         (t3_read_reg(adap, A_XGM_RX_CTRL + mac->offset) & F_RXEN)) {
0366         t3_mac_disable_exact_filters(mac);
0367         v = t3_read_reg(adap, A_XGM_RX_CFG + mac->offset);
0368         t3_set_reg_field(adap, A_XGM_RX_CFG + mac->offset,
0369                  F_ENHASHMCAST | F_COPYALLFRAMES, F_DISBCAST);
0370 
0371         reg = adap->params.rev == T3_REV_B2 ?
0372             A_XGM_RX_MAX_PKT_SIZE_ERR_CNT : A_XGM_RXFIFO_CFG;
0373 
0374         /* drain RX FIFO */
0375         if (t3_wait_op_done(adap, reg + mac->offset,
0376                     F_RXFIFO_EMPTY, 1, 20, 5)) {
0377             t3_write_reg(adap, A_XGM_RX_CFG + mac->offset, v);
0378             t3_mac_enable_exact_filters(mac);
0379             return -EIO;
0380         }
0381         t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset,
0382                  V_RXMAXPKTSIZE(M_RXMAXPKTSIZE),
0383                  V_RXMAXPKTSIZE(mtu));
0384         t3_write_reg(adap, A_XGM_RX_CFG + mac->offset, v);
0385         t3_mac_enable_exact_filters(mac);
0386     } else
0387         t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset,
0388                  V_RXMAXPKTSIZE(M_RXMAXPKTSIZE),
0389                  V_RXMAXPKTSIZE(mtu));
0390 
0391     /*
0392      * Adjust the PAUSE frame watermarks.  We always set the LWM, and the
0393      * HWM only if flow-control is enabled.
0394      */
0395     hwm = rx_fifo_hwm(mtu);
0396     lwm = min(3 * (int)mtu, MAC_RXFIFO_SIZE / 4);
0397     v = t3_read_reg(adap, A_XGM_RXFIFO_CFG + mac->offset);
0398     v &= ~V_RXFIFOPAUSELWM(M_RXFIFOPAUSELWM);
0399     v |= V_RXFIFOPAUSELWM(lwm / 8);
0400     if (G_RXFIFOPAUSEHWM(v))
0401         v = (v & ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM)) |
0402             V_RXFIFOPAUSEHWM(hwm / 8);
0403 
0404     t3_write_reg(adap, A_XGM_RXFIFO_CFG + mac->offset, v);
0405 
0406     /* Adjust the TX FIFO threshold based on the MTU */
0407     thres = (adap->params.vpd.cclk * 1000) / 15625;
0408     thres = (thres * mtu) / 1000;
0409     if (is_10G(adap))
0410         thres /= 10;
0411     thres = mtu > thres ? (mtu - thres + 7) / 8 : 0;
0412     thres = max(thres, 8U); /* need at least 8 */
0413     ipg = (adap->params.rev == T3_REV_C) ? 0 : 1;
0414     t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + mac->offset,
0415              V_TXFIFOTHRESH(M_TXFIFOTHRESH) | V_TXIPG(M_TXIPG),
0416              V_TXFIFOTHRESH(thres) | V_TXIPG(ipg));
0417 
0418     if (adap->params.rev > 0) {
0419         divisor = (adap->params.rev == T3_REV_C) ? 64 : 8;
0420         t3_write_reg(adap, A_XGM_PAUSE_TIMER + mac->offset,
0421                  (hwm - lwm) * 4 / divisor);
0422     }
0423     t3_write_reg(adap, A_XGM_TX_PAUSE_QUANTA + mac->offset,
0424              MAC_RXFIFO_SIZE * 4 * 8 / 512);
0425     return 0;
0426 }
0427 
0428 int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc)
0429 {
0430     u32 val;
0431     struct adapter *adap = mac->adapter;
0432     unsigned int oft = mac->offset;
0433 
0434     if (duplex >= 0 && duplex != DUPLEX_FULL)
0435         return -EINVAL;
0436     if (speed >= 0) {
0437         if (speed == SPEED_10)
0438             val = V_PORTSPEED(0);
0439         else if (speed == SPEED_100)
0440             val = V_PORTSPEED(1);
0441         else if (speed == SPEED_1000)
0442             val = V_PORTSPEED(2);
0443         else if (speed == SPEED_10000)
0444             val = V_PORTSPEED(3);
0445         else
0446             return -EINVAL;
0447 
0448         t3_set_reg_field(adap, A_XGM_PORT_CFG + oft,
0449                  V_PORTSPEED(M_PORTSPEED), val);
0450     }
0451 
0452     val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft);
0453     val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM);
0454     if (fc & PAUSE_TX) {
0455         u32 rx_max_pkt_size =
0456             G_RXMAXPKTSIZE(t3_read_reg(adap,
0457                            A_XGM_RX_MAX_PKT_SIZE + oft));
0458         val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(rx_max_pkt_size) / 8);
0459     }
0460     t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val);
0461 
0462     t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN,
0463              (fc & PAUSE_RX) ? F_TXPAUSEEN : 0);
0464     return 0;
0465 }
0466 
0467 int t3_mac_enable(struct cmac *mac, int which)
0468 {
0469     int idx = macidx(mac);
0470     struct adapter *adap = mac->adapter;
0471     unsigned int oft = mac->offset;
0472     struct mac_stats *s = &mac->stats;
0473 
0474     if (which & MAC_DIRECTION_TX) {
0475         t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
0476         t3_write_reg(adap, A_TP_PIO_DATA,
0477                  adap->params.rev == T3_REV_C ?
0478                  0xc4ffff01 : 0xc0ede401);
0479         t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_MODE);
0480         t3_set_reg_field(adap, A_TP_PIO_DATA, 1 << idx,
0481                  adap->params.rev == T3_REV_C ? 0 : 1 << idx);
0482 
0483         t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN);
0484 
0485         t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CNT_CH0 + idx);
0486         mac->tx_mcnt = s->tx_frames;
0487         mac->tx_tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap,
0488                             A_TP_PIO_DATA)));
0489         mac->tx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
0490                         A_XGM_TX_SPI4_SOP_EOP_CNT +
0491                         oft)));
0492         mac->rx_mcnt = s->rx_frames;
0493         mac->rx_pause = s->rx_pause;
0494         mac->rx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
0495                         A_XGM_RX_SPI4_SOP_EOP_CNT +
0496                         oft)));
0497         mac->rx_ocnt = s->rx_fifo_ovfl;
0498         mac->txen = F_TXEN;
0499         mac->toggle_cnt = 0;
0500     }
0501     if (which & MAC_DIRECTION_RX)
0502         t3_write_reg(adap, A_XGM_RX_CTRL + oft, F_RXEN);
0503     return 0;
0504 }
0505 
0506 int t3_mac_disable(struct cmac *mac, int which)
0507 {
0508     struct adapter *adap = mac->adapter;
0509 
0510     if (which & MAC_DIRECTION_TX) {
0511         t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0);
0512         mac->txen = 0;
0513     }
0514     if (which & MAC_DIRECTION_RX) {
0515         int val = F_MAC_RESET_;
0516 
0517         t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset,
0518                  F_PCS_RESET_, 0);
0519         msleep(100);
0520         t3_write_reg(adap, A_XGM_RX_CTRL + mac->offset, 0);
0521         if (is_10G(adap))
0522             val |= F_PCS_RESET_;
0523         else if (uses_xaui(adap))
0524             val |= F_PCS_RESET_ | F_XG2G_RESET_;
0525         else
0526             val |= F_RGMII_RESET_ | F_XG2G_RESET_;
0527         t3_write_reg(mac->adapter, A_XGM_RESET_CTRL + mac->offset, val);
0528     }
0529     return 0;
0530 }
0531 
0532 int t3b2_mac_watchdog_task(struct cmac *mac)
0533 {
0534     struct adapter *adap = mac->adapter;
0535     struct mac_stats *s = &mac->stats;
0536     unsigned int tx_tcnt, tx_xcnt;
0537     u64 tx_mcnt = s->tx_frames;
0538     int status;
0539 
0540     status = 0;
0541     tx_xcnt = 1;        /* By default tx_xcnt is making progress */
0542     tx_tcnt = mac->tx_tcnt; /* If tx_mcnt is progressing ignore tx_tcnt */
0543     if (tx_mcnt == mac->tx_mcnt && mac->rx_pause == s->rx_pause) {
0544         tx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
0545                         A_XGM_TX_SPI4_SOP_EOP_CNT +
0546                             mac->offset)));
0547         if (tx_xcnt == 0) {
0548             t3_write_reg(adap, A_TP_PIO_ADDR,
0549                      A_TP_TX_DROP_CNT_CH0 + macidx(mac));
0550             tx_tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap,
0551                               A_TP_PIO_DATA)));
0552         } else {
0553             goto out;
0554         }
0555     } else {
0556         mac->toggle_cnt = 0;
0557         goto out;
0558     }
0559 
0560     if ((tx_tcnt != mac->tx_tcnt) && (mac->tx_xcnt == 0)) {
0561         if (mac->toggle_cnt > 4) {
0562             status = 2;
0563             goto out;
0564         } else {
0565             status = 1;
0566             goto out;
0567         }
0568     } else {
0569         mac->toggle_cnt = 0;
0570         goto out;
0571     }
0572 
0573 out:
0574     mac->tx_tcnt = tx_tcnt;
0575     mac->tx_xcnt = tx_xcnt;
0576     mac->tx_mcnt = s->tx_frames;
0577     mac->rx_pause = s->rx_pause;
0578     if (status == 1) {
0579         t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0);
0580         t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset);  /* flush */
0581         t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, mac->txen);
0582         t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset);  /* flush */
0583         mac->toggle_cnt++;
0584     } else if (status == 2) {
0585         t3b2_mac_reset(mac);
0586         mac->toggle_cnt = 0;
0587     }
0588     return status;
0589 }
0590 
0591 /*
0592  * This function is called periodically to accumulate the current values of the
0593  * RMON counters into the port statistics.  Since the packet counters are only
0594  * 32 bits they can overflow in ~286 secs at 10G, so the function should be
0595  * called more frequently than that.  The byte counters are 45-bit wide, they
0596  * would overflow in ~7.8 hours.
0597  */
0598 const struct mac_stats *t3_mac_update_stats(struct cmac *mac)
0599 {
0600 #define RMON_READ(mac, addr) t3_read_reg(mac->adapter, addr + mac->offset)
0601 #define RMON_UPDATE(mac, name, reg) \
0602     (mac)->stats.name += (u64)RMON_READ(mac, A_XGM_STAT_##reg)
0603 #define RMON_UPDATE64(mac, name, reg_lo, reg_hi) \
0604     (mac)->stats.name += RMON_READ(mac, A_XGM_STAT_##reg_lo) + \
0605                  ((u64)RMON_READ(mac, A_XGM_STAT_##reg_hi) << 32)
0606 
0607     u32 v, lo;
0608 
0609     RMON_UPDATE64(mac, rx_octets, RX_BYTES_LOW, RX_BYTES_HIGH);
0610     RMON_UPDATE64(mac, rx_frames, RX_FRAMES_LOW, RX_FRAMES_HIGH);
0611     RMON_UPDATE(mac, rx_mcast_frames, RX_MCAST_FRAMES);
0612     RMON_UPDATE(mac, rx_bcast_frames, RX_BCAST_FRAMES);
0613     RMON_UPDATE(mac, rx_fcs_errs, RX_CRC_ERR_FRAMES);
0614     RMON_UPDATE(mac, rx_pause, RX_PAUSE_FRAMES);
0615     RMON_UPDATE(mac, rx_jabber, RX_JABBER_FRAMES);
0616     RMON_UPDATE(mac, rx_short, RX_SHORT_FRAMES);
0617     RMON_UPDATE(mac, rx_symbol_errs, RX_SYM_CODE_ERR_FRAMES);
0618 
0619     RMON_UPDATE(mac, rx_too_long, RX_OVERSIZE_FRAMES);
0620 
0621     v = RMON_READ(mac, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT);
0622     if (mac->adapter->params.rev == T3_REV_B2)
0623         v &= 0x7fffffff;
0624     mac->stats.rx_too_long += v;
0625 
0626     RMON_UPDATE(mac, rx_frames_64, RX_64B_FRAMES);
0627     RMON_UPDATE(mac, rx_frames_65_127, RX_65_127B_FRAMES);
0628     RMON_UPDATE(mac, rx_frames_128_255, RX_128_255B_FRAMES);
0629     RMON_UPDATE(mac, rx_frames_256_511, RX_256_511B_FRAMES);
0630     RMON_UPDATE(mac, rx_frames_512_1023, RX_512_1023B_FRAMES);
0631     RMON_UPDATE(mac, rx_frames_1024_1518, RX_1024_1518B_FRAMES);
0632     RMON_UPDATE(mac, rx_frames_1519_max, RX_1519_MAXB_FRAMES);
0633 
0634     RMON_UPDATE64(mac, tx_octets, TX_BYTE_LOW, TX_BYTE_HIGH);
0635     RMON_UPDATE64(mac, tx_frames, TX_FRAME_LOW, TX_FRAME_HIGH);
0636     RMON_UPDATE(mac, tx_mcast_frames, TX_MCAST);
0637     RMON_UPDATE(mac, tx_bcast_frames, TX_BCAST);
0638     RMON_UPDATE(mac, tx_pause, TX_PAUSE);
0639     /* This counts error frames in general (bad FCS, underrun, etc). */
0640     RMON_UPDATE(mac, tx_underrun, TX_ERR_FRAMES);
0641 
0642     RMON_UPDATE(mac, tx_frames_64, TX_64B_FRAMES);
0643     RMON_UPDATE(mac, tx_frames_65_127, TX_65_127B_FRAMES);
0644     RMON_UPDATE(mac, tx_frames_128_255, TX_128_255B_FRAMES);
0645     RMON_UPDATE(mac, tx_frames_256_511, TX_256_511B_FRAMES);
0646     RMON_UPDATE(mac, tx_frames_512_1023, TX_512_1023B_FRAMES);
0647     RMON_UPDATE(mac, tx_frames_1024_1518, TX_1024_1518B_FRAMES);
0648     RMON_UPDATE(mac, tx_frames_1519_max, TX_1519_MAXB_FRAMES);
0649 
0650     /* The next stat isn't clear-on-read. */
0651     t3_write_reg(mac->adapter, A_TP_MIB_INDEX, mac->offset ? 51 : 50);
0652     v = t3_read_reg(mac->adapter, A_TP_MIB_RDATA);
0653     lo = (u32) mac->stats.rx_cong_drops;
0654     mac->stats.rx_cong_drops += (u64) (v - lo);
0655 
0656     return &mac->stats;
0657 }