Home | History | Annotate | Line # | Download | only in cxgb
cxgb_xgmac.c revision 1.1.2.2
      1  1.1.2.2  uebayasi 
      2  1.1.2.2  uebayasi /**************************************************************************
      3  1.1.2.2  uebayasi 
      4  1.1.2.2  uebayasi Copyright (c) 2007, Chelsio Inc.
      5  1.1.2.2  uebayasi All rights reserved.
      6  1.1.2.2  uebayasi 
      7  1.1.2.2  uebayasi Redistribution and use in source and binary forms, with or without
      8  1.1.2.2  uebayasi modification, are permitted provided that the following conditions are met:
      9  1.1.2.2  uebayasi 
     10  1.1.2.2  uebayasi  1. Redistributions of source code must retain the above copyright notice,
     11  1.1.2.2  uebayasi     this list of conditions and the following disclaimer.
     12  1.1.2.2  uebayasi 
     13  1.1.2.2  uebayasi  2. Neither the name of the Chelsio Corporation nor the names of its
     14  1.1.2.2  uebayasi     contributors may be used to endorse or promote products derived from
     15  1.1.2.2  uebayasi     this software without specific prior written permission.
     16  1.1.2.2  uebayasi 
     17  1.1.2.2  uebayasi THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     18  1.1.2.2  uebayasi AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     19  1.1.2.2  uebayasi IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     20  1.1.2.2  uebayasi ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
     21  1.1.2.2  uebayasi LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     22  1.1.2.2  uebayasi CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     23  1.1.2.2  uebayasi SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     24  1.1.2.2  uebayasi INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     25  1.1.2.2  uebayasi CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     26  1.1.2.2  uebayasi ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     27  1.1.2.2  uebayasi POSSIBILITY OF SUCH DAMAGE.
     28  1.1.2.2  uebayasi 
     29  1.1.2.2  uebayasi ***************************************************************************/
     30  1.1.2.2  uebayasi 
     31  1.1.2.2  uebayasi #include <sys/cdefs.h>
     32  1.1.2.2  uebayasi __KERNEL_RCSID(0, "$NetBSD: cxgb_xgmac.c,v 1.1.2.2 2010/04/30 14:43:45 uebayasi Exp $");
     33  1.1.2.2  uebayasi 
     34  1.1.2.2  uebayasi #ifdef CONFIG_DEFINED
     35  1.1.2.2  uebayasi #include <cxgb_include.h>
     36  1.1.2.2  uebayasi #else
     37  1.1.2.2  uebayasi #include "cxgb_include.h"
     38  1.1.2.2  uebayasi #endif
     39  1.1.2.2  uebayasi 
     40  1.1.2.2  uebayasi #undef msleep
     41  1.1.2.2  uebayasi #define msleep t3_os_sleep
     42  1.1.2.2  uebayasi 
     43  1.1.2.2  uebayasi /*
     44  1.1.2.2  uebayasi  * # of exact address filters.  The first one is used for the station address,
     45  1.1.2.2  uebayasi  * the rest are available for multicast addresses.
     46  1.1.2.2  uebayasi  */
     47  1.1.2.2  uebayasi #define EXACT_ADDR_FILTERS 8
     48  1.1.2.2  uebayasi 
     49  1.1.2.2  uebayasi static inline int macidx(const struct cmac *mac)
     50  1.1.2.2  uebayasi {
     51  1.1.2.2  uebayasi     return mac->offset / (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR);
     52  1.1.2.2  uebayasi }
     53  1.1.2.2  uebayasi 
     54  1.1.2.2  uebayasi static void xaui_serdes_reset(struct cmac *mac)
     55  1.1.2.2  uebayasi {
     56  1.1.2.2  uebayasi     static const unsigned int clear[] = {
     57  1.1.2.2  uebayasi         F_PWRDN0 | F_PWRDN1,    F_RESETPLL01,    F_RESET0 | F_RESET1,
     58  1.1.2.2  uebayasi             F_PWRDN2 | F_PWRDN3,    F_RESETPLL23,    F_RESET2 | F_RESET3
     59  1.1.2.2  uebayasi     };
     60  1.1.2.2  uebayasi 
     61  1.1.2.2  uebayasi     int i;
     62  1.1.2.2  uebayasi     adapter_t *adap = mac->adapter;
     63  1.1.2.2  uebayasi     u32 ctrl = A_XGM_SERDES_CTRL0 + mac->offset;
     64  1.1.2.2  uebayasi 
     65  1.1.2.2  uebayasi     t3_write_reg(adap, ctrl, adap->params.vpd.xauicfg[macidx(mac)] |
     66  1.1.2.2  uebayasi              F_RESET3 | F_RESET2 | F_RESET1 | F_RESET0 |
     67  1.1.2.2  uebayasi              F_PWRDN3 | F_PWRDN2 | F_PWRDN1 | F_PWRDN0 |
     68  1.1.2.2  uebayasi              F_RESETPLL23 | F_RESETPLL01);
     69  1.1.2.2  uebayasi     (void)t3_read_reg(adap, ctrl);
     70  1.1.2.2  uebayasi     udelay(15);
     71  1.1.2.2  uebayasi 
     72  1.1.2.2  uebayasi     for (i = 0; i < ARRAY_SIZE(clear); i++) {
     73  1.1.2.2  uebayasi         t3_set_reg_field(adap, ctrl, clear[i], 0);
     74  1.1.2.2  uebayasi         udelay(15);
     75  1.1.2.2  uebayasi     }
     76  1.1.2.2  uebayasi }
     77  1.1.2.2  uebayasi 
     78  1.1.2.2  uebayasi void t3b_pcs_reset(struct cmac *mac)
     79  1.1.2.2  uebayasi {
     80  1.1.2.2  uebayasi     t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset,
     81  1.1.2.2  uebayasi              F_PCS_RESET_, 0);
     82  1.1.2.2  uebayasi     udelay(20);
     83  1.1.2.2  uebayasi     t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset, 0,
     84  1.1.2.2  uebayasi              F_PCS_RESET_);
     85  1.1.2.2  uebayasi }
     86  1.1.2.2  uebayasi 
     87  1.1.2.2  uebayasi int t3_mac_reset(struct cmac *mac)
     88  1.1.2.2  uebayasi {
     89  1.1.2.2  uebayasi     static struct addr_val_pair mac_reset_avp[] = {
     90  1.1.2.2  uebayasi         { A_XGM_TX_CTRL, 0 },
     91  1.1.2.2  uebayasi         { A_XGM_RX_CTRL, 0 },
     92  1.1.2.2  uebayasi         { A_XGM_RX_CFG, F_DISPAUSEFRAMES | F_EN1536BFRAMES |
     93  1.1.2.2  uebayasi                         F_RMFCS | F_ENJUMBO | F_ENHASHMCAST },
     94  1.1.2.2  uebayasi         { A_XGM_RX_HASH_LOW, 0 },
     95  1.1.2.2  uebayasi         { A_XGM_RX_HASH_HIGH, 0 },
     96  1.1.2.2  uebayasi         { A_XGM_RX_EXACT_MATCH_LOW_1, 0 },
     97  1.1.2.2  uebayasi         { A_XGM_RX_EXACT_MATCH_LOW_2, 0 },
     98  1.1.2.2  uebayasi         { A_XGM_RX_EXACT_MATCH_LOW_3, 0 },
     99  1.1.2.2  uebayasi         { A_XGM_RX_EXACT_MATCH_LOW_4, 0 },
    100  1.1.2.2  uebayasi         { A_XGM_RX_EXACT_MATCH_LOW_5, 0 },
    101  1.1.2.2  uebayasi         { A_XGM_RX_EXACT_MATCH_LOW_6, 0 },
    102  1.1.2.2  uebayasi         { A_XGM_RX_EXACT_MATCH_LOW_7, 0 },
    103  1.1.2.2  uebayasi         { A_XGM_RX_EXACT_MATCH_LOW_8, 0 },
    104  1.1.2.2  uebayasi         { A_XGM_STAT_CTRL, F_CLRSTATS }
    105  1.1.2.2  uebayasi     };
    106  1.1.2.2  uebayasi     u32 val;
    107  1.1.2.2  uebayasi     adapter_t *adap = mac->adapter;
    108  1.1.2.2  uebayasi     unsigned int oft = mac->offset;
    109  1.1.2.2  uebayasi 
    110  1.1.2.2  uebayasi     t3_write_reg(adap, A_XGM_RESET_CTRL + oft, F_MAC_RESET_);
    111  1.1.2.2  uebayasi     (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft);    /* flush */
    112  1.1.2.2  uebayasi 
    113  1.1.2.2  uebayasi     t3_write_regs(adap, mac_reset_avp, ARRAY_SIZE(mac_reset_avp), oft);
    114  1.1.2.2  uebayasi     t3_set_reg_field(adap, A_XGM_RXFIFO_CFG + oft,
    115  1.1.2.2  uebayasi              F_RXSTRFRWRD | F_DISERRFRAMES,
    116  1.1.2.2  uebayasi              uses_xaui(adap) ? 0 : F_RXSTRFRWRD);
    117  1.1.2.2  uebayasi 
    118  1.1.2.2  uebayasi     if (uses_xaui(adap)) {
    119  1.1.2.2  uebayasi         if (adap->params.rev == 0) {
    120  1.1.2.2  uebayasi             t3_set_reg_field(adap, A_XGM_SERDES_CTRL + oft, 0,
    121  1.1.2.2  uebayasi                      F_RXENABLE | F_TXENABLE);
    122  1.1.2.2  uebayasi             if (t3_wait_op_done(adap, A_XGM_SERDES_STATUS1 + oft,
    123  1.1.2.2  uebayasi                         F_CMULOCK, 1, 5, 2)) {
    124  1.1.2.2  uebayasi                 CH_ERR(adap,
    125  1.1.2.2  uebayasi                        "MAC %d XAUI SERDES CMU lock failed\n",
    126  1.1.2.2  uebayasi                        macidx(mac));
    127  1.1.2.2  uebayasi                 return -1;
    128  1.1.2.2  uebayasi             }
    129  1.1.2.2  uebayasi             t3_set_reg_field(adap, A_XGM_SERDES_CTRL + oft, 0,
    130  1.1.2.2  uebayasi                      F_SERDESRESET_);
    131  1.1.2.2  uebayasi         } else
    132  1.1.2.2  uebayasi             xaui_serdes_reset(mac);
    133  1.1.2.2  uebayasi     }
    134  1.1.2.2  uebayasi 
    135  1.1.2.2  uebayasi 
    136  1.1.2.2  uebayasi     if (mac->multiport) {
    137  1.1.2.2  uebayasi         t3_write_reg(adap, A_XGM_RX_MAX_PKT_SIZE + oft,
    138  1.1.2.2  uebayasi                  MAX_FRAME_SIZE - 4);
    139  1.1.2.2  uebayasi         t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + oft, 0,
    140  1.1.2.2  uebayasi                  F_DISPREAMBLE);
    141  1.1.2.2  uebayasi         t3_set_reg_field(adap, A_XGM_RX_CFG + oft, 0, F_COPYPREAMBLE |
    142  1.1.2.2  uebayasi                  F_ENNON802_3PREAMBLE);
    143  1.1.2.2  uebayasi         t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + oft,
    144  1.1.2.2  uebayasi                  V_TXFIFOTHRESH(M_TXFIFOTHRESH),
    145  1.1.2.2  uebayasi                  V_TXFIFOTHRESH(64));
    146  1.1.2.2  uebayasi         t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN);
    147  1.1.2.2  uebayasi         t3_write_reg(adap, A_XGM_RX_CTRL + oft, F_RXEN);
    148  1.1.2.2  uebayasi     }
    149  1.1.2.2  uebayasi 
    150  1.1.2.2  uebayasi     val = F_MAC_RESET_;
    151  1.1.2.2  uebayasi     if (is_10G(adap) || mac->multiport)
    152  1.1.2.2  uebayasi         val |= F_PCS_RESET_;
    153  1.1.2.2  uebayasi     else if (uses_xaui(adap))
    154  1.1.2.2  uebayasi         val |= F_PCS_RESET_ | F_XG2G_RESET_;
    155  1.1.2.2  uebayasi     else
    156  1.1.2.2  uebayasi         val |= F_RGMII_RESET_ | F_XG2G_RESET_;
    157  1.1.2.2  uebayasi     t3_write_reg(adap, A_XGM_RESET_CTRL + oft, val);
    158  1.1.2.2  uebayasi     (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft);  /* flush */
    159  1.1.2.2  uebayasi     if ((val & F_PCS_RESET_) && adap->params.rev) {
    160  1.1.2.2  uebayasi         msleep(1);
    161  1.1.2.2  uebayasi         t3b_pcs_reset(mac);
    162  1.1.2.2  uebayasi     }
    163  1.1.2.2  uebayasi 
    164  1.1.2.2  uebayasi     memset(&mac->stats, 0, sizeof(mac->stats));
    165  1.1.2.2  uebayasi     return 0;
    166  1.1.2.2  uebayasi }
    167  1.1.2.2  uebayasi 
    168  1.1.2.2  uebayasi static int t3b2_mac_reset(struct cmac *mac)
    169  1.1.2.2  uebayasi {
    170  1.1.2.2  uebayasi     u32 val;
    171  1.1.2.2  uebayasi     adapter_t *adap = mac->adapter;
    172  1.1.2.2  uebayasi     unsigned int oft = mac->offset;
    173  1.1.2.2  uebayasi 
    174  1.1.2.2  uebayasi 
    175  1.1.2.2  uebayasi     /* Stop egress traffic to xgm*/
    176  1.1.2.2  uebayasi     if (!macidx(mac))
    177  1.1.2.2  uebayasi         t3_set_reg_field(adap, A_MPS_CFG, F_PORT0ACTIVE, 0);
    178  1.1.2.2  uebayasi     else
    179  1.1.2.2  uebayasi         t3_set_reg_field(adap, A_MPS_CFG, F_PORT1ACTIVE, 0);
    180  1.1.2.2  uebayasi 
    181  1.1.2.2  uebayasi     /* PCS in reset */
    182  1.1.2.2  uebayasi     t3_write_reg(adap, A_XGM_RESET_CTRL + oft, F_MAC_RESET_);
    183  1.1.2.2  uebayasi     (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft);    /* flush */
    184  1.1.2.2  uebayasi 
    185  1.1.2.2  uebayasi     msleep(10);
    186  1.1.2.2  uebayasi 
    187  1.1.2.2  uebayasi     /* Check for xgm Rx fifo empty */
    188  1.1.2.2  uebayasi     if (t3_wait_op_done(adap, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT + oft,
    189  1.1.2.2  uebayasi                 0x80000000, 1, 5, 2)) {
    190  1.1.2.2  uebayasi         CH_ERR(adap, "MAC %d Rx fifo drain failed\n",
    191  1.1.2.2  uebayasi                macidx(mac));
    192  1.1.2.2  uebayasi         return -1;
    193  1.1.2.2  uebayasi     }
    194  1.1.2.2  uebayasi 
    195  1.1.2.2  uebayasi     t3_write_reg(adap, A_XGM_RESET_CTRL + oft, 0); /*MAC in reset*/
    196  1.1.2.2  uebayasi     (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft);    /* flush */
    197  1.1.2.2  uebayasi 
    198  1.1.2.2  uebayasi     val = F_MAC_RESET_;
    199  1.1.2.2  uebayasi     if (is_10G(adap))
    200  1.1.2.2  uebayasi         val |= F_PCS_RESET_;
    201  1.1.2.2  uebayasi     else if (uses_xaui(adap))
    202  1.1.2.2  uebayasi         val |= F_PCS_RESET_ | F_XG2G_RESET_;
    203  1.1.2.2  uebayasi     else
    204  1.1.2.2  uebayasi         val |= F_RGMII_RESET_ | F_XG2G_RESET_;
    205  1.1.2.2  uebayasi     t3_write_reg(adap, A_XGM_RESET_CTRL + oft, val);
    206  1.1.2.2  uebayasi     (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft);  /* flush */
    207  1.1.2.2  uebayasi     if ((val & F_PCS_RESET_) && adap->params.rev) {
    208  1.1.2.2  uebayasi         msleep(1);
    209  1.1.2.2  uebayasi         t3b_pcs_reset(mac);
    210  1.1.2.2  uebayasi     }
    211  1.1.2.2  uebayasi     t3_write_reg(adap, A_XGM_RX_CFG + oft,
    212  1.1.2.2  uebayasi          F_DISPAUSEFRAMES | F_EN1536BFRAMES |
    213  1.1.2.2  uebayasi                         F_RMFCS | F_ENJUMBO | F_ENHASHMCAST );
    214  1.1.2.2  uebayasi 
    215  1.1.2.2  uebayasi     /*Resume egress traffic to xgm*/
    216  1.1.2.2  uebayasi     if (!macidx(mac))
    217  1.1.2.2  uebayasi         t3_set_reg_field(adap, A_MPS_CFG, 0, F_PORT0ACTIVE);
    218  1.1.2.2  uebayasi     else
    219  1.1.2.2  uebayasi         t3_set_reg_field(adap, A_MPS_CFG, 0, F_PORT1ACTIVE);
    220  1.1.2.2  uebayasi 
    221  1.1.2.2  uebayasi     return 0;
    222  1.1.2.2  uebayasi }
    223  1.1.2.2  uebayasi 
    224  1.1.2.2  uebayasi /*
    225  1.1.2.2  uebayasi  * Set the exact match register 'idx' to recognize the given Ethernet address.
    226  1.1.2.2  uebayasi  */
    227  1.1.2.2  uebayasi static void set_addr_filter(struct cmac *mac, int idx, const u8 *addr)
    228  1.1.2.2  uebayasi {
    229  1.1.2.2  uebayasi     u32 addr_lo, addr_hi;
    230  1.1.2.2  uebayasi     unsigned int oft = mac->offset + idx * 8;
    231  1.1.2.2  uebayasi 
    232  1.1.2.2  uebayasi     addr_lo = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0];
    233  1.1.2.2  uebayasi     addr_hi = (addr[5] << 8) | addr[4];
    234  1.1.2.2  uebayasi 
    235  1.1.2.2  uebayasi     t3_write_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1 + oft, addr_lo);
    236  1.1.2.2  uebayasi     t3_write_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_HIGH_1 + oft, addr_hi);
    237  1.1.2.2  uebayasi }
    238  1.1.2.2  uebayasi 
    239  1.1.2.2  uebayasi /* Set one of the station's unicast MAC addresses. */
    240  1.1.2.2  uebayasi int t3_mac_set_address(struct cmac *mac, unsigned int idx, u8 addr[6])
    241  1.1.2.2  uebayasi {
    242  1.1.2.2  uebayasi     if (mac->multiport)
    243  1.1.2.2  uebayasi         idx = mac->ext_port + idx * mac->adapter->params.nports;
    244  1.1.2.2  uebayasi     if (idx >= mac->nucast)
    245  1.1.2.2  uebayasi         return -EINVAL;
    246  1.1.2.2  uebayasi     set_addr_filter(mac, idx, addr);
    247  1.1.2.2  uebayasi     if (mac->multiport && idx < mac->adapter->params.nports)
    248  1.1.2.2  uebayasi         t3_vsc7323_set_addr(mac->adapter, addr, idx);
    249  1.1.2.2  uebayasi     return 0;
    250  1.1.2.2  uebayasi }
    251  1.1.2.2  uebayasi 
    252  1.1.2.2  uebayasi /*
    253  1.1.2.2  uebayasi  * Specify the number of exact address filters that should be reserved for
    254  1.1.2.2  uebayasi  * unicast addresses.  Caller should reload the unicast and multicast addresses
    255  1.1.2.2  uebayasi  * after calling this.
    256  1.1.2.2  uebayasi  */
    257  1.1.2.2  uebayasi int t3_mac_set_num_ucast(struct cmac *mac, unsigned char n)
    258  1.1.2.2  uebayasi {
    259  1.1.2.2  uebayasi     if (n > EXACT_ADDR_FILTERS)
    260  1.1.2.2  uebayasi         return -EINVAL;
    261  1.1.2.2  uebayasi     mac->nucast = n;
    262  1.1.2.2  uebayasi     return 0;
    263  1.1.2.2  uebayasi }
    264  1.1.2.2  uebayasi 
    265  1.1.2.2  uebayasi static void disable_exact_filters(struct cmac *mac)
    266  1.1.2.2  uebayasi {
    267  1.1.2.2  uebayasi     unsigned int i, reg = mac->offset + A_XGM_RX_EXACT_MATCH_LOW_1;
    268  1.1.2.2  uebayasi 
    269  1.1.2.2  uebayasi     for (i = 0; i < EXACT_ADDR_FILTERS; i++, reg += 8) {
    270  1.1.2.2  uebayasi         u32 v = t3_read_reg(mac->adapter, reg);
    271  1.1.2.2  uebayasi         t3_write_reg(mac->adapter, reg, v);
    272  1.1.2.2  uebayasi     }
    273  1.1.2.2  uebayasi     t3_read_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1); /* flush */
    274  1.1.2.2  uebayasi }
    275  1.1.2.2  uebayasi 
    276  1.1.2.2  uebayasi static void enable_exact_filters(struct cmac *mac)
    277  1.1.2.2  uebayasi {
    278  1.1.2.2  uebayasi     unsigned int i, reg = mac->offset + A_XGM_RX_EXACT_MATCH_HIGH_1;
    279  1.1.2.2  uebayasi 
    280  1.1.2.2  uebayasi     for (i = 0; i < EXACT_ADDR_FILTERS; i++, reg += 8) {
    281  1.1.2.2  uebayasi         u32 v = t3_read_reg(mac->adapter, reg);
    282  1.1.2.2  uebayasi         t3_write_reg(mac->adapter, reg, v);
    283  1.1.2.2  uebayasi     }
    284  1.1.2.2  uebayasi     t3_read_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1); /* flush */
    285  1.1.2.2  uebayasi }
    286  1.1.2.2  uebayasi 
    287  1.1.2.2  uebayasi /* Calculate the RX hash filter index of an Ethernet address */
    288  1.1.2.2  uebayasi static int hash_hw_addr(const u8 *addr)
    289  1.1.2.2  uebayasi {
    290  1.1.2.2  uebayasi     int hash = 0, octet, bit, i = 0, c;
    291  1.1.2.2  uebayasi 
    292  1.1.2.2  uebayasi     for (octet = 0; octet < 6; ++octet)
    293  1.1.2.2  uebayasi         for (c = addr[octet], bit = 0; bit < 8; c >>= 1, ++bit) {
    294  1.1.2.2  uebayasi             hash ^= (c & 1) << i;
    295  1.1.2.2  uebayasi             if (++i == 6)
    296  1.1.2.2  uebayasi                 i = 0;
    297  1.1.2.2  uebayasi         }
    298  1.1.2.2  uebayasi     return hash;
    299  1.1.2.2  uebayasi }
    300  1.1.2.2  uebayasi 
    301  1.1.2.2  uebayasi int t3_mac_set_rx_mode(struct cmac *mac, struct t3_rx_mode *rm)
    302  1.1.2.2  uebayasi {
    303  1.1.2.2  uebayasi     u32 hash_lo, hash_hi;
    304  1.1.2.2  uebayasi     adapter_t *adap = mac->adapter;
    305  1.1.2.2  uebayasi     unsigned int oft = mac->offset;
    306  1.1.2.2  uebayasi 
    307  1.1.2.2  uebayasi     if (promisc_rx_mode(rm))
    308  1.1.2.2  uebayasi         mac->promisc_map |= 1 << mac->ext_port;
    309  1.1.2.2  uebayasi     else
    310  1.1.2.2  uebayasi         mac->promisc_map &= ~(1 << mac->ext_port);
    311  1.1.2.2  uebayasi     t3_set_reg_field(adap, A_XGM_RX_CFG + oft, F_COPYALLFRAMES,
    312  1.1.2.2  uebayasi              mac->promisc_map ? F_COPYALLFRAMES : 0);
    313  1.1.2.2  uebayasi 
    314  1.1.2.2  uebayasi     if (allmulti_rx_mode(rm) || mac->multiport)
    315  1.1.2.2  uebayasi         hash_lo = hash_hi = 0xffffffff;
    316  1.1.2.2  uebayasi     else {
    317  1.1.2.2  uebayasi         u8 *addr;
    318  1.1.2.2  uebayasi         int exact_addr_idx = mac->nucast;
    319  1.1.2.2  uebayasi 
    320  1.1.2.2  uebayasi         hash_lo = hash_hi = 0;
    321  1.1.2.2  uebayasi         while ((addr = t3_get_next_mcaddr(rm)))
    322  1.1.2.2  uebayasi             if (exact_addr_idx < EXACT_ADDR_FILTERS)
    323  1.1.2.2  uebayasi                 set_addr_filter(mac, exact_addr_idx++, addr);
    324  1.1.2.2  uebayasi             else {
    325  1.1.2.2  uebayasi                 int hash = hash_hw_addr(addr);
    326  1.1.2.2  uebayasi 
    327  1.1.2.2  uebayasi                 if (hash < 32)
    328  1.1.2.2  uebayasi                     hash_lo |= (1 << hash);
    329  1.1.2.2  uebayasi                 else
    330  1.1.2.2  uebayasi                     hash_hi |= (1 << (hash - 32));
    331  1.1.2.2  uebayasi             }
    332  1.1.2.2  uebayasi     }
    333  1.1.2.2  uebayasi 
    334  1.1.2.2  uebayasi     t3_write_reg(adap, A_XGM_RX_HASH_LOW + oft, hash_lo);
    335  1.1.2.2  uebayasi     t3_write_reg(adap, A_XGM_RX_HASH_HIGH + oft, hash_hi);
    336  1.1.2.2  uebayasi     return 0;
    337  1.1.2.2  uebayasi }
    338  1.1.2.2  uebayasi 
    339  1.1.2.2  uebayasi static int rx_fifo_hwm(int mtu)
    340  1.1.2.2  uebayasi {
    341  1.1.2.2  uebayasi     int hwm;
    342  1.1.2.2  uebayasi 
    343  1.1.2.2  uebayasi     hwm = max(MAC_RXFIFO_SIZE - 3 * mtu, (MAC_RXFIFO_SIZE * 38) / 100);
    344  1.1.2.2  uebayasi     return min(hwm, MAC_RXFIFO_SIZE - 8192);
    345  1.1.2.2  uebayasi }
    346  1.1.2.2  uebayasi 
    347  1.1.2.2  uebayasi int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu)
    348  1.1.2.2  uebayasi {
    349  1.1.2.2  uebayasi     int hwm, lwm;
    350  1.1.2.2  uebayasi     unsigned int thres, v;
    351  1.1.2.2  uebayasi     adapter_t *adap = mac->adapter;
    352  1.1.2.2  uebayasi 
    353  1.1.2.2  uebayasi     /*
    354  1.1.2.2  uebayasi      * MAX_FRAME_SIZE inludes header + FCS, mtu doesn't.  The HW max
    355  1.1.2.2  uebayasi      * packet size register includes header, but not FCS.
    356  1.1.2.2  uebayasi      */
    357  1.1.2.2  uebayasi     mtu += 14;
    358  1.1.2.2  uebayasi     if (mac->multiport)
    359  1.1.2.2  uebayasi         mtu += 8;                             /* for preamble */
    360  1.1.2.2  uebayasi     if (mtu > MAX_FRAME_SIZE - 4)
    361  1.1.2.2  uebayasi         return -EINVAL;
    362  1.1.2.2  uebayasi     if (mac->multiport)
    363  1.1.2.2  uebayasi         return t3_vsc7323_set_mtu(adap, mtu - 4, mac->ext_port);
    364  1.1.2.2  uebayasi 
    365  1.1.2.2  uebayasi     if (adap->params.rev == T3_REV_B2 &&
    366  1.1.2.2  uebayasi         (t3_read_reg(adap, A_XGM_RX_CTRL + mac->offset) & F_RXEN)) {
    367  1.1.2.2  uebayasi         disable_exact_filters(mac);
    368  1.1.2.2  uebayasi         v = t3_read_reg(adap, A_XGM_RX_CFG + mac->offset);
    369  1.1.2.2  uebayasi         t3_set_reg_field(adap, A_XGM_RX_CFG + mac->offset,
    370  1.1.2.2  uebayasi                  F_ENHASHMCAST | F_COPYALLFRAMES, F_DISBCAST);
    371  1.1.2.2  uebayasi 
    372  1.1.2.2  uebayasi         /* drain rx FIFO */
    373  1.1.2.2  uebayasi         if (t3_wait_op_done(adap,
    374  1.1.2.2  uebayasi                     A_XGM_RX_MAX_PKT_SIZE_ERR_CNT + mac->offset,
    375  1.1.2.2  uebayasi                     1 << 31, 1, 20, 5)) {
    376  1.1.2.2  uebayasi             t3_write_reg(adap, A_XGM_RX_CFG + mac->offset, v);
    377  1.1.2.2  uebayasi             enable_exact_filters(mac);
    378  1.1.2.2  uebayasi             return -EIO;
    379  1.1.2.2  uebayasi         }
    380  1.1.2.2  uebayasi         t3_write_reg(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset, mtu);
    381  1.1.2.2  uebayasi         t3_write_reg(adap, A_XGM_RX_CFG + mac->offset, v);
    382  1.1.2.2  uebayasi         enable_exact_filters(mac);
    383  1.1.2.2  uebayasi     } else
    384  1.1.2.2  uebayasi         t3_write_reg(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset, mtu);
    385  1.1.2.2  uebayasi 
    386  1.1.2.2  uebayasi     /*
    387  1.1.2.2  uebayasi      * Adjust the PAUSE frame watermarks.  We always set the LWM, and the
    388  1.1.2.2  uebayasi      * HWM only if flow-control is enabled.
    389  1.1.2.2  uebayasi      */
    390  1.1.2.2  uebayasi     hwm = rx_fifo_hwm(mtu);
    391  1.1.2.2  uebayasi     lwm = min(3 * (int) mtu, MAC_RXFIFO_SIZE /4);
    392  1.1.2.2  uebayasi     v = t3_read_reg(adap, A_XGM_RXFIFO_CFG + mac->offset);
    393  1.1.2.2  uebayasi     v &= ~V_RXFIFOPAUSELWM(M_RXFIFOPAUSELWM);
    394  1.1.2.2  uebayasi     v |= V_RXFIFOPAUSELWM(lwm / 8);
    395  1.1.2.2  uebayasi     if (G_RXFIFOPAUSEHWM(v))
    396  1.1.2.2  uebayasi         v = (v & ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM)) |
    397  1.1.2.2  uebayasi             V_RXFIFOPAUSEHWM(hwm / 8);
    398  1.1.2.2  uebayasi 
    399  1.1.2.2  uebayasi     t3_write_reg(adap, A_XGM_RXFIFO_CFG + mac->offset, v);
    400  1.1.2.2  uebayasi 
    401  1.1.2.2  uebayasi     /* Adjust the TX FIFO threshold based on the MTU */
    402  1.1.2.2  uebayasi     thres = (adap->params.vpd.cclk * 1000) / 15625;
    403  1.1.2.2  uebayasi     thres = (thres * mtu) / 1000;
    404  1.1.2.2  uebayasi     if (is_10G(adap))
    405  1.1.2.2  uebayasi         thres /= 10;
    406  1.1.2.2  uebayasi     thres = mtu > thres ? (mtu - thres + 7) / 8 : 0;
    407  1.1.2.2  uebayasi     thres = max(thres, 8U);                          /* need at least 8 */
    408  1.1.2.2  uebayasi     t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + mac->offset,
    409  1.1.2.2  uebayasi              V_TXFIFOTHRESH(M_TXFIFOTHRESH) | V_TXIPG(M_TXIPG),
    410  1.1.2.2  uebayasi              V_TXFIFOTHRESH(thres) | V_TXIPG(1));
    411  1.1.2.2  uebayasi 
    412  1.1.2.2  uebayasi     /* Assuming a minimum drain rate of 2.5Gbps...
    413  1.1.2.2  uebayasi      */
    414  1.1.2.2  uebayasi     if (adap->params.rev > 0)
    415  1.1.2.2  uebayasi         t3_write_reg(adap, A_XGM_PAUSE_TIMER + mac->offset,
    416  1.1.2.2  uebayasi                  (hwm - lwm) * 4 / 8);
    417  1.1.2.2  uebayasi     t3_write_reg(adap, A_XGM_TX_PAUSE_QUANTA + mac->offset,
    418  1.1.2.2  uebayasi              MAC_RXFIFO_SIZE * 4 * 8 / 512);
    419  1.1.2.2  uebayasi     return 0;
    420  1.1.2.2  uebayasi }
    421  1.1.2.2  uebayasi 
    422  1.1.2.2  uebayasi int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc)
    423  1.1.2.2  uebayasi {
    424  1.1.2.2  uebayasi     u32 val;
    425  1.1.2.2  uebayasi     adapter_t *adap = mac->adapter;
    426  1.1.2.2  uebayasi     unsigned int oft = mac->offset;
    427  1.1.2.2  uebayasi 
    428  1.1.2.2  uebayasi     if (duplex >= 0 && duplex != DUPLEX_FULL)
    429  1.1.2.2  uebayasi         return -EINVAL;
    430  1.1.2.2  uebayasi     if (mac->multiport) {
    431  1.1.2.2  uebayasi         val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft);
    432  1.1.2.2  uebayasi         val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM);
    433  1.1.2.2  uebayasi         val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(t3_read_reg(adap,
    434  1.1.2.2  uebayasi                     A_XGM_RX_MAX_PKT_SIZE + oft)) / 8);
    435  1.1.2.2  uebayasi         t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val);
    436  1.1.2.2  uebayasi 
    437  1.1.2.2  uebayasi         t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN,
    438  1.1.2.2  uebayasi                     F_TXPAUSEEN);
    439  1.1.2.2  uebayasi         return t3_vsc7323_set_speed_fc(adap, speed, fc, mac->ext_port);
    440  1.1.2.2  uebayasi     }
    441  1.1.2.2  uebayasi     if (speed >= 0) {
    442  1.1.2.2  uebayasi         if (speed == SPEED_10)
    443  1.1.2.2  uebayasi             val = V_PORTSPEED(0);
    444  1.1.2.2  uebayasi         else if (speed == SPEED_100)
    445  1.1.2.2  uebayasi             val = V_PORTSPEED(1);
    446  1.1.2.2  uebayasi         else if (speed == SPEED_1000)
    447  1.1.2.2  uebayasi             val = V_PORTSPEED(2);
    448  1.1.2.2  uebayasi         else if (speed == SPEED_10000)
    449  1.1.2.2  uebayasi             val = V_PORTSPEED(3);
    450  1.1.2.2  uebayasi         else
    451  1.1.2.2  uebayasi             return -EINVAL;
    452  1.1.2.2  uebayasi 
    453  1.1.2.2  uebayasi         t3_set_reg_field(adap, A_XGM_PORT_CFG + oft,
    454  1.1.2.2  uebayasi                  V_PORTSPEED(M_PORTSPEED), val);
    455  1.1.2.2  uebayasi     }
    456  1.1.2.2  uebayasi 
    457  1.1.2.2  uebayasi     val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft);
    458  1.1.2.2  uebayasi     val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM);
    459  1.1.2.2  uebayasi     if (fc & PAUSE_TX)
    460  1.1.2.2  uebayasi         val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(t3_read_reg(adap,
    461  1.1.2.2  uebayasi                     A_XGM_RX_MAX_PKT_SIZE + oft)) / 8);
    462  1.1.2.2  uebayasi     t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val);
    463  1.1.2.2  uebayasi 
    464  1.1.2.2  uebayasi     t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN,
    465  1.1.2.2  uebayasi             (fc & PAUSE_RX) ? F_TXPAUSEEN : 0);
    466  1.1.2.2  uebayasi     return 0;
    467  1.1.2.2  uebayasi }
    468  1.1.2.2  uebayasi 
    469  1.1.2.2  uebayasi int t3_mac_enable(struct cmac *mac, int which)
    470  1.1.2.2  uebayasi {
    471  1.1.2.2  uebayasi     int idx = macidx(mac);
    472  1.1.2.2  uebayasi     adapter_t *adap = mac->adapter;
    473  1.1.2.2  uebayasi     unsigned int oft = mac->offset;
    474  1.1.2.2  uebayasi     struct mac_stats *s = &mac->stats;
    475  1.1.2.2  uebayasi 
    476  1.1.2.2  uebayasi     if (mac->multiport)
    477  1.1.2.2  uebayasi         return t3_vsc7323_enable(adap, mac->ext_port, which);
    478  1.1.2.2  uebayasi 
    479  1.1.2.2  uebayasi     if (which & MAC_DIRECTION_TX) {
    480  1.1.2.2  uebayasi         t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
    481  1.1.2.2  uebayasi         t3_write_reg(adap, A_TP_PIO_DATA, 0xc0ede401);
    482  1.1.2.2  uebayasi         t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_MODE);
    483  1.1.2.2  uebayasi         t3_set_reg_field(adap, A_TP_PIO_DATA, 1 << idx, 1 << idx);
    484  1.1.2.2  uebayasi 
    485  1.1.2.2  uebayasi         t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN);
    486  1.1.2.2  uebayasi 
    487  1.1.2.2  uebayasi         t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CNT_CH0 + idx);
    488  1.1.2.2  uebayasi         mac->tx_mcnt = s->tx_frames;
    489  1.1.2.2  uebayasi         mac->tx_tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap,
    490  1.1.2.2  uebayasi                                    A_TP_PIO_DATA)));
    491  1.1.2.2  uebayasi         mac->tx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
    492  1.1.2.2  uebayasi                         A_XGM_TX_SPI4_SOP_EOP_CNT +
    493  1.1.2.2  uebayasi                         oft)));
    494  1.1.2.2  uebayasi         mac->rx_mcnt = s->rx_frames;
    495  1.1.2.2  uebayasi         mac->rx_pause = s->rx_pause;
    496  1.1.2.2  uebayasi         mac->rx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
    497  1.1.2.2  uebayasi                         A_XGM_RX_SPI4_SOP_EOP_CNT +
    498  1.1.2.2  uebayasi                         oft)));
    499  1.1.2.2  uebayasi         mac->rx_ocnt = s->rx_fifo_ovfl;
    500  1.1.2.2  uebayasi         mac->txen = F_TXEN;
    501  1.1.2.2  uebayasi         mac->toggle_cnt = 0;
    502  1.1.2.2  uebayasi     }
    503  1.1.2.2  uebayasi     if (which & MAC_DIRECTION_RX)
    504  1.1.2.2  uebayasi         t3_write_reg(adap, A_XGM_RX_CTRL + oft, F_RXEN);
    505  1.1.2.2  uebayasi     return 0;
    506  1.1.2.2  uebayasi }
    507  1.1.2.2  uebayasi 
    508  1.1.2.2  uebayasi int t3_mac_disable(struct cmac *mac, int which)
    509  1.1.2.2  uebayasi {
    510  1.1.2.2  uebayasi     adapter_t *adap = mac->adapter;
    511  1.1.2.2  uebayasi 
    512  1.1.2.2  uebayasi     if (mac->multiport)
    513  1.1.2.2  uebayasi         return t3_vsc7323_disable(adap, mac->ext_port, which);
    514  1.1.2.2  uebayasi 
    515  1.1.2.2  uebayasi     if (which & MAC_DIRECTION_TX) {
    516  1.1.2.2  uebayasi         t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0);
    517  1.1.2.2  uebayasi         mac->txen = 0;
    518  1.1.2.2  uebayasi     }
    519  1.1.2.2  uebayasi     if (which & MAC_DIRECTION_RX) {
    520  1.1.2.2  uebayasi         int val = F_MAC_RESET_;
    521  1.1.2.2  uebayasi 
    522  1.1.2.2  uebayasi         t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset,
    523  1.1.2.2  uebayasi                  F_PCS_RESET_, 0);
    524  1.1.2.2  uebayasi         msleep(100);
    525  1.1.2.2  uebayasi         t3_write_reg(adap, A_XGM_RX_CTRL + mac->offset, 0);
    526  1.1.2.2  uebayasi         if (is_10G(adap))
    527  1.1.2.2  uebayasi             val |= F_PCS_RESET_;
    528  1.1.2.2  uebayasi         else if (uses_xaui(adap))
    529  1.1.2.2  uebayasi             val |= F_PCS_RESET_ | F_XG2G_RESET_;
    530  1.1.2.2  uebayasi         else
    531  1.1.2.2  uebayasi             val |= F_RGMII_RESET_ | F_XG2G_RESET_;
    532  1.1.2.2  uebayasi         t3_write_reg(mac->adapter, A_XGM_RESET_CTRL + mac->offset, val);
    533  1.1.2.2  uebayasi     }
    534  1.1.2.2  uebayasi     return 0;
    535  1.1.2.2  uebayasi }
    536  1.1.2.2  uebayasi 
    537  1.1.2.2  uebayasi int t3b2_mac_watchdog_task(struct cmac *mac)
    538  1.1.2.2  uebayasi {
    539  1.1.2.2  uebayasi     int status;
    540  1.1.2.2  uebayasi     unsigned int tx_tcnt, tx_xcnt;
    541  1.1.2.2  uebayasi     adapter_t *adap = mac->adapter;
    542  1.1.2.2  uebayasi     struct mac_stats *s = &mac->stats;
    543  1.1.2.2  uebayasi     unsigned int tx_mcnt = (unsigned int)s->tx_frames;
    544  1.1.2.2  uebayasi     unsigned int rx_mcnt = (unsigned int)s->rx_frames;
    545  1.1.2.2  uebayasi     unsigned int rx_xcnt;
    546  1.1.2.2  uebayasi 
    547  1.1.2.2  uebayasi     if (mac->multiport) {
    548  1.1.2.2  uebayasi       tx_mcnt = t3_read_reg(adap, A_XGM_STAT_TX_FRAME_LOW);
    549  1.1.2.2  uebayasi       rx_mcnt = t3_read_reg(adap, A_XGM_STAT_RX_FRAMES_LOW);
    550  1.1.2.2  uebayasi     } else {
    551  1.1.2.2  uebayasi       tx_mcnt = (unsigned int)s->tx_frames;
    552  1.1.2.2  uebayasi       rx_mcnt = (unsigned int)s->rx_frames;
    553  1.1.2.2  uebayasi     }
    554  1.1.2.2  uebayasi     status = 0;
    555  1.1.2.2  uebayasi     tx_xcnt = 1; /* By default tx_xcnt is making progress*/
    556  1.1.2.2  uebayasi     tx_tcnt = mac->tx_tcnt; /* If tx_mcnt is progressing ignore tx_tcnt*/
    557  1.1.2.2  uebayasi     rx_xcnt = 1; /* By default rx_xcnt is making progress*/
    558  1.1.2.2  uebayasi     if (tx_mcnt == mac->tx_mcnt && mac->rx_pause == s->rx_pause) {
    559  1.1.2.2  uebayasi         tx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
    560  1.1.2.2  uebayasi                         A_XGM_TX_SPI4_SOP_EOP_CNT +
    561  1.1.2.2  uebayasi                             mac->offset)));
    562  1.1.2.2  uebayasi         if (tx_xcnt == 0) {
    563  1.1.2.2  uebayasi             t3_write_reg(adap, A_TP_PIO_ADDR,
    564  1.1.2.2  uebayasi                     A_TP_TX_DROP_CNT_CH0 + macidx(mac));
    565  1.1.2.2  uebayasi             tx_tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap,
    566  1.1.2.2  uebayasi                     A_TP_PIO_DATA)));
    567  1.1.2.2  uebayasi         } else {
    568  1.1.2.2  uebayasi             goto rxcheck;
    569  1.1.2.2  uebayasi         }
    570  1.1.2.2  uebayasi     } else {
    571  1.1.2.2  uebayasi         mac->toggle_cnt = 0;
    572  1.1.2.2  uebayasi         goto rxcheck;
    573  1.1.2.2  uebayasi     }
    574  1.1.2.2  uebayasi 
    575  1.1.2.2  uebayasi     if ((tx_tcnt != mac->tx_tcnt) && (mac->tx_xcnt == 0)) {
    576  1.1.2.2  uebayasi         if (mac->toggle_cnt > 4) {
    577  1.1.2.2  uebayasi             status = 2;
    578  1.1.2.2  uebayasi             goto out;
    579  1.1.2.2  uebayasi         } else {
    580  1.1.2.2  uebayasi             status = 1;
    581  1.1.2.2  uebayasi             goto out;
    582  1.1.2.2  uebayasi         }
    583  1.1.2.2  uebayasi     } else {
    584  1.1.2.2  uebayasi         mac->toggle_cnt = 0;
    585  1.1.2.2  uebayasi         goto rxcheck;
    586  1.1.2.2  uebayasi     }
    587  1.1.2.2  uebayasi 
    588  1.1.2.2  uebayasi rxcheck:
    589  1.1.2.2  uebayasi     if (rx_mcnt != mac->rx_mcnt) {
    590  1.1.2.2  uebayasi         rx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
    591  1.1.2.2  uebayasi                         A_XGM_RX_SPI4_SOP_EOP_CNT +
    592  1.1.2.2  uebayasi                         mac->offset))) +
    593  1.1.2.2  uebayasi                         (s->rx_fifo_ovfl - mac->rx_ocnt);
    594  1.1.2.2  uebayasi         mac->rx_ocnt = s->rx_fifo_ovfl;
    595  1.1.2.2  uebayasi     } else
    596  1.1.2.2  uebayasi         goto out;
    597  1.1.2.2  uebayasi 
    598  1.1.2.2  uebayasi     if (mac->rx_mcnt != s->rx_frames && rx_xcnt == 0 && mac->rx_xcnt == 0) {
    599  1.1.2.2  uebayasi         if (!mac->multiport)
    600  1.1.2.2  uebayasi           status = 2;
    601  1.1.2.2  uebayasi         goto out;
    602  1.1.2.2  uebayasi     }
    603  1.1.2.2  uebayasi 
    604  1.1.2.2  uebayasi out:
    605  1.1.2.2  uebayasi     mac->tx_tcnt = tx_tcnt;
    606  1.1.2.2  uebayasi     mac->tx_xcnt = tx_xcnt;
    607  1.1.2.2  uebayasi     mac->tx_mcnt = s->tx_frames;
    608  1.1.2.2  uebayasi     mac->rx_xcnt = rx_xcnt;
    609  1.1.2.2  uebayasi     mac->rx_mcnt = s->rx_frames;
    610  1.1.2.2  uebayasi     mac->rx_pause = s->rx_pause;
    611  1.1.2.2  uebayasi     if (status == 1) {
    612  1.1.2.2  uebayasi         t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0);
    613  1.1.2.2  uebayasi         t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset);  /* flush */
    614  1.1.2.2  uebayasi         t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, mac->txen);
    615  1.1.2.2  uebayasi         t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset);  /* flush */
    616  1.1.2.2  uebayasi         mac->toggle_cnt++;
    617  1.1.2.2  uebayasi     } else if (status == 2) {
    618  1.1.2.2  uebayasi         t3b2_mac_reset(mac);
    619  1.1.2.2  uebayasi         mac->toggle_cnt = 0;
    620  1.1.2.2  uebayasi     }
    621  1.1.2.2  uebayasi     return status;
    622  1.1.2.2  uebayasi }
    623  1.1.2.2  uebayasi 
    624  1.1.2.2  uebayasi /*
    625  1.1.2.2  uebayasi  * This function is called periodically to accumulate the current values of the
    626  1.1.2.2  uebayasi  * RMON counters into the port statistics.  Since the packet counters are only
    627  1.1.2.2  uebayasi  * 32 bits they can overflow in ~286 secs at 10G, so the function should be
    628  1.1.2.2  uebayasi  * called more frequently than that.  The byte counters are 45-bit wide, they
    629  1.1.2.2  uebayasi  * would overflow in ~7.8 hours.
    630  1.1.2.2  uebayasi  */
    631  1.1.2.2  uebayasi const struct mac_stats *t3_mac_update_stats(struct cmac *mac)
    632  1.1.2.2  uebayasi {
    633  1.1.2.2  uebayasi #define RMON_READ(mac, addr) t3_read_reg(mac->adapter, addr + mac->offset)
    634  1.1.2.2  uebayasi #define RMON_UPDATE(mac, name, reg) \
    635  1.1.2.2  uebayasi     (mac)->stats.name += (u64)RMON_READ(mac, A_XGM_STAT_##reg)
    636  1.1.2.2  uebayasi #define RMON_UPDATE64(mac, name, reg_lo, reg_hi) \
    637  1.1.2.2  uebayasi     (mac)->stats.name += RMON_READ(mac, A_XGM_STAT_##reg_lo) + \
    638  1.1.2.2  uebayasi                  ((u64)RMON_READ(mac, A_XGM_STAT_##reg_hi) << 32)
    639  1.1.2.2  uebayasi 
    640  1.1.2.2  uebayasi     u32 v, lo;
    641  1.1.2.2  uebayasi 
    642  1.1.2.2  uebayasi     if (mac->multiport)
    643  1.1.2.2  uebayasi         return t3_vsc7323_update_stats(mac);
    644  1.1.2.2  uebayasi 
    645  1.1.2.2  uebayasi     RMON_UPDATE64(mac, rx_octets, RX_BYTES_LOW, RX_BYTES_HIGH);
    646  1.1.2.2  uebayasi     RMON_UPDATE64(mac, rx_frames, RX_FRAMES_LOW, RX_FRAMES_HIGH);
    647  1.1.2.2  uebayasi     RMON_UPDATE(mac, rx_mcast_frames, RX_MCAST_FRAMES);
    648  1.1.2.2  uebayasi     RMON_UPDATE(mac, rx_bcast_frames, RX_BCAST_FRAMES);
    649  1.1.2.2  uebayasi     RMON_UPDATE(mac, rx_fcs_errs, RX_CRC_ERR_FRAMES);
    650  1.1.2.2  uebayasi     RMON_UPDATE(mac, rx_pause, RX_PAUSE_FRAMES);
    651  1.1.2.2  uebayasi     RMON_UPDATE(mac, rx_jabber, RX_JABBER_FRAMES);
    652  1.1.2.2  uebayasi     RMON_UPDATE(mac, rx_short, RX_SHORT_FRAMES);
    653  1.1.2.2  uebayasi     RMON_UPDATE(mac, rx_symbol_errs, RX_SYM_CODE_ERR_FRAMES);
    654  1.1.2.2  uebayasi 
    655  1.1.2.2  uebayasi     RMON_UPDATE(mac, rx_too_long, RX_OVERSIZE_FRAMES);
    656  1.1.2.2  uebayasi 
    657  1.1.2.2  uebayasi     v = RMON_READ(mac, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT);
    658  1.1.2.2  uebayasi     if (mac->adapter->params.rev == T3_REV_B2)
    659  1.1.2.2  uebayasi         v &= 0x7fffffff;
    660  1.1.2.2  uebayasi     mac->stats.rx_too_long += v;
    661  1.1.2.2  uebayasi 
    662  1.1.2.2  uebayasi     RMON_UPDATE(mac, rx_frames_64,        RX_64B_FRAMES);
    663  1.1.2.2  uebayasi     RMON_UPDATE(mac, rx_frames_65_127,    RX_65_127B_FRAMES);
    664  1.1.2.2  uebayasi     RMON_UPDATE(mac, rx_frames_128_255,   RX_128_255B_FRAMES);
    665  1.1.2.2  uebayasi     RMON_UPDATE(mac, rx_frames_256_511,   RX_256_511B_FRAMES);
    666  1.1.2.2  uebayasi     RMON_UPDATE(mac, rx_frames_512_1023,  RX_512_1023B_FRAMES);
    667  1.1.2.2  uebayasi     RMON_UPDATE(mac, rx_frames_1024_1518, RX_1024_1518B_FRAMES);
    668  1.1.2.2  uebayasi     RMON_UPDATE(mac, rx_frames_1519_max,  RX_1519_MAXB_FRAMES);
    669  1.1.2.2  uebayasi 
    670  1.1.2.2  uebayasi     RMON_UPDATE64(mac, tx_octets, TX_BYTE_LOW, TX_BYTE_HIGH);
    671  1.1.2.2  uebayasi     RMON_UPDATE64(mac, tx_frames, TX_FRAME_LOW, TX_FRAME_HIGH);
    672  1.1.2.2  uebayasi     RMON_UPDATE(mac, tx_mcast_frames, TX_MCAST);
    673  1.1.2.2  uebayasi     RMON_UPDATE(mac, tx_bcast_frames, TX_BCAST);
    674  1.1.2.2  uebayasi     RMON_UPDATE(mac, tx_pause, TX_PAUSE);
    675  1.1.2.2  uebayasi     /* This counts error frames in general (bad FCS, underrun, etc). */
    676  1.1.2.2  uebayasi     RMON_UPDATE(mac, tx_underrun, TX_ERR_FRAMES);
    677  1.1.2.2  uebayasi 
    678  1.1.2.2  uebayasi     RMON_UPDATE(mac, tx_frames_64,        TX_64B_FRAMES);
    679  1.1.2.2  uebayasi     RMON_UPDATE(mac, tx_frames_65_127,    TX_65_127B_FRAMES);
    680  1.1.2.2  uebayasi     RMON_UPDATE(mac, tx_frames_128_255,   TX_128_255B_FRAMES);
    681  1.1.2.2  uebayasi     RMON_UPDATE(mac, tx_frames_256_511,   TX_256_511B_FRAMES);
    682  1.1.2.2  uebayasi     RMON_UPDATE(mac, tx_frames_512_1023,  TX_512_1023B_FRAMES);
    683  1.1.2.2  uebayasi     RMON_UPDATE(mac, tx_frames_1024_1518, TX_1024_1518B_FRAMES);
    684  1.1.2.2  uebayasi     RMON_UPDATE(mac, tx_frames_1519_max,  TX_1519_MAXB_FRAMES);
    685  1.1.2.2  uebayasi 
    686  1.1.2.2  uebayasi     /* The next stat isn't clear-on-read. */
    687  1.1.2.2  uebayasi     t3_write_reg(mac->adapter, A_TP_MIB_INDEX, mac->offset ? 51 : 50);
    688  1.1.2.2  uebayasi     v = t3_read_reg(mac->adapter, A_TP_MIB_RDATA);
    689  1.1.2.2  uebayasi     lo = (u32)mac->stats.rx_cong_drops;
    690  1.1.2.2  uebayasi     mac->stats.rx_cong_drops += (u64)(v - lo);
    691  1.1.2.2  uebayasi 
    692  1.1.2.2  uebayasi     return &mac->stats;
    693  1.1.2.2  uebayasi }
    694