The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/cxgb/common/cxgb_xgmac.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 5a75993b2bbbb5507bcabd33b8c89931


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.