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