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 SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3 
    4 Copyright (c) 2007-2009 Chelsio Inc.
    5 All rights reserved.
    6 
    7 Redistribution and use in source and binary forms, with or without
    8 modification, are permitted provided that the following conditions are met:
    9 
   10  1. Redistributions of source code must retain the above copyright notice,
   11     this list of conditions and the following disclaimer.
   12 
   13  2. Neither the name of the Chelsio Corporation nor the names of its
   14     contributors may be used to endorse or promote products derived from
   15     this software without specific prior written permission.
   16 
   17 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   18 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   19 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   20 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
   21 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   22 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   23 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   24 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   25 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   26 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   27 POSSIBILITY OF SUCH DAMAGE.
   28 
   29 ***************************************************************************/
   30 
   31 #include <sys/cdefs.h>
   32 __FBSDID("$FreeBSD$");
   33 
   34 #include <cxgb_include.h>
   35 
   36 #undef msleep
   37 #define msleep t3_os_sleep
   38 
   39 
   40 static inline int macidx(const struct cmac *mac)
   41 {
   42         return mac->offset / (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR);
   43 }
   44 
   45 /*
   46  * Returns a reasonable A_XGM_RESET_CTRL value for the mac specified.
   47  */
   48 static inline int xgm_reset_ctrl(const struct cmac *mac)
   49 {
   50         adapter_t *adap = mac->adapter;
   51         int val = F_MAC_RESET_ | F_XGMAC_STOP_EN;
   52 
   53         if (is_10G(adap)) {
   54                 int cfg = t3_read_reg(adap, A_XGM_PORT_CFG + mac->offset);
   55 
   56                 val |= F_PCS_RESET_;
   57                 if (G_PORTSPEED(cfg) != 3)      /* not running at 10G */
   58                         val |= F_XG2G_RESET_;
   59         } else if (uses_xaui(adap))
   60                 val |= F_PCS_RESET_ | F_XG2G_RESET_;
   61         else
   62                 val |= F_RGMII_RESET_ | F_XG2G_RESET_;
   63 
   64         return (val);
   65 }
   66 
   67 static void xaui_serdes_reset(struct cmac *mac)
   68 {
   69         static const unsigned int clear[] = {
   70                 F_PWRDN0 | F_PWRDN1,    F_RESETPLL01,    F_RESET0 | F_RESET1,
   71                 F_PWRDN2 | F_PWRDN3,    F_RESETPLL23,    F_RESET2 | F_RESET3
   72         };
   73 
   74         int i;
   75         adapter_t *adap = mac->adapter;
   76         u32 ctrl = A_XGM_SERDES_CTRL0 + mac->offset;
   77 
   78         t3_write_reg(adap, ctrl, adap->params.vpd.xauicfg[macidx(mac)] |
   79                      F_RESET3 | F_RESET2 | F_RESET1 | F_RESET0 |
   80                      F_PWRDN3 | F_PWRDN2 | F_PWRDN1 | F_PWRDN0 |
   81                      F_RESETPLL23 | F_RESETPLL01);
   82         (void)t3_read_reg(adap, ctrl);
   83         udelay(15);
   84 
   85         for (i = 0; i < ARRAY_SIZE(clear); i++) {
   86                 t3_set_reg_field(adap, ctrl, clear[i], 0);
   87                 udelay(15);
   88         }
   89 }
   90 
   91 /**
   92  *      t3b_pcs_reset - reset the PCS on T3B+ adapters
   93  *      @mac: the XGMAC handle
   94  *
   95  *      Reset the XGMAC PCS block on T3B+ adapters.
   96  */
   97 void t3b_pcs_reset(struct cmac *mac)
   98 {
   99         t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset,
  100                          F_PCS_RESET_, 0);
  101 
  102         /* No delay required */
  103 
  104         t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset, 0,
  105                          F_PCS_RESET_);
  106 }
  107 
  108 void t3c_pcs_force_los(struct cmac *mac)
  109 {
  110         t3_set_reg_field(mac->adapter, A_XGM_SERDES_STAT0 + mac->offset,
  111             F_LOWSIGFORCEEN0 | F_LOWSIGFORCEVALUE0,
  112             F_LOWSIGFORCEEN0 | F_LOWSIGFORCEVALUE0);
  113         t3_set_reg_field(mac->adapter, A_XGM_SERDES_STAT1 + mac->offset,
  114             F_LOWSIGFORCEEN1 | F_LOWSIGFORCEVALUE1,
  115             F_LOWSIGFORCEEN1 | F_LOWSIGFORCEVALUE1);
  116         t3_set_reg_field(mac->adapter, A_XGM_SERDES_STAT2 + mac->offset,
  117             F_LOWSIGFORCEEN2 | F_LOWSIGFORCEVALUE2,
  118             F_LOWSIGFORCEEN2 | F_LOWSIGFORCEVALUE2);
  119         t3_set_reg_field(mac->adapter, A_XGM_SERDES_STAT3 + mac->offset,
  120             F_LOWSIGFORCEEN3 | F_LOWSIGFORCEVALUE3,
  121             F_LOWSIGFORCEEN3 | F_LOWSIGFORCEVALUE3);
  122 
  123         /* No delay required */
  124 
  125         t3_set_reg_field(mac->adapter, A_XGM_SERDES_STAT0 + mac->offset,
  126             F_LOWSIGFORCEEN0, 0);
  127         t3_set_reg_field(mac->adapter, A_XGM_SERDES_STAT1 + mac->offset,
  128             F_LOWSIGFORCEEN1, 0);
  129         t3_set_reg_field(mac->adapter, A_XGM_SERDES_STAT2 + mac->offset,
  130             F_LOWSIGFORCEEN2, 0);
  131         t3_set_reg_field(mac->adapter, A_XGM_SERDES_STAT3 + mac->offset,
  132             F_LOWSIGFORCEEN3, 0);
  133 }
  134 
  135 /**
  136  *      t3_mac_init - initialize a MAC
  137  *      @mac: the MAC to initialize
  138  *
  139  *      Initialize the given MAC.
  140  */
  141 int t3_mac_init(struct cmac *mac)
  142 {
  143         static struct addr_val_pair mac_reset_avp[] = {
  144                 { A_XGM_TX_CTRL, 0 },
  145                 { A_XGM_RX_CTRL, 0 },
  146                 { A_XGM_RX_CFG, F_DISPAUSEFRAMES | F_EN1536BFRAMES |
  147                                 F_RMFCS | F_ENJUMBO | F_ENHASHMCAST },
  148                 { A_XGM_RX_HASH_LOW, 0 },
  149                 { A_XGM_RX_HASH_HIGH, 0 },
  150                 { A_XGM_RX_EXACT_MATCH_LOW_1, 0 },
  151                 { A_XGM_RX_EXACT_MATCH_LOW_2, 0 },
  152                 { A_XGM_RX_EXACT_MATCH_LOW_3, 0 },
  153                 { A_XGM_RX_EXACT_MATCH_LOW_4, 0 },
  154                 { A_XGM_RX_EXACT_MATCH_LOW_5, 0 },
  155                 { A_XGM_RX_EXACT_MATCH_LOW_6, 0 },
  156                 { A_XGM_RX_EXACT_MATCH_LOW_7, 0 },
  157                 { A_XGM_RX_EXACT_MATCH_LOW_8, 0 },
  158                 { A_XGM_STAT_CTRL, F_CLRSTATS }
  159         };
  160         u32 val;
  161         adapter_t *adap = mac->adapter;
  162         unsigned int oft = mac->offset;
  163 
  164         t3_write_reg(adap, A_XGM_RESET_CTRL + oft, F_MAC_RESET_);
  165         (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft);    /* flush */
  166 
  167         t3_write_regs(adap, mac_reset_avp, ARRAY_SIZE(mac_reset_avp), oft);
  168         t3_set_reg_field(adap, A_XGM_RXFIFO_CFG + oft,
  169                          F_RXSTRFRWRD | F_DISERRFRAMES,
  170                          uses_xaui(adap) ? 0 : F_RXSTRFRWRD);
  171         t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + oft, 0, F_UNDERUNFIX);
  172 
  173         if (uses_xaui(adap)) {
  174                 if (adap->params.rev == 0) {
  175                         t3_set_reg_field(adap, A_XGM_SERDES_CTRL + oft, 0,
  176                                          F_RXENABLE | F_TXENABLE);
  177                         if (t3_wait_op_done(adap, A_XGM_SERDES_STATUS1 + oft,
  178                                             F_CMULOCK, 1, 5, 2)) {
  179                                 CH_ERR(adap,
  180                                        "MAC %d XAUI SERDES CMU lock failed\n",
  181                                        macidx(mac));
  182                                 return -1;
  183                         }
  184                         t3_set_reg_field(adap, A_XGM_SERDES_CTRL + oft, 0,
  185                                          F_SERDESRESET_);
  186                 } else
  187                         xaui_serdes_reset(mac);
  188         }
  189 
  190 
  191         if (mac->multiport) {
  192                 t3_write_reg(adap, A_XGM_RX_MAX_PKT_SIZE + oft,
  193                              V_RXMAXPKTSIZE(MAX_FRAME_SIZE - 4));
  194                 t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + oft, 0,
  195                                  F_DISPREAMBLE);
  196                 t3_set_reg_field(adap, A_XGM_RX_CFG + oft, 0, F_COPYPREAMBLE |
  197                                  F_ENNON802_3PREAMBLE);
  198                 t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + oft,
  199                                  V_TXFIFOTHRESH(M_TXFIFOTHRESH),
  200                                  V_TXFIFOTHRESH(64));
  201                 t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN);
  202                 t3_write_reg(adap, A_XGM_RX_CTRL + oft, F_RXEN);
  203         }
  204 
  205         t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + oft,
  206                          V_RXMAXFRAMERSIZE(M_RXMAXFRAMERSIZE),
  207                          V_RXMAXFRAMERSIZE(MAX_FRAME_SIZE) | F_RXENFRAMER);
  208 
  209         val = xgm_reset_ctrl(mac);
  210         t3_write_reg(adap, A_XGM_RESET_CTRL + oft, val);
  211         (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft);  /* flush */
  212         if ((val & F_PCS_RESET_) && adap->params.rev) {
  213                 msleep(1);
  214                 t3b_pcs_reset(mac);
  215         }
  216 
  217         memset(&mac->stats, 0, sizeof(mac->stats));
  218         return 0;
  219 }
  220 
  221 static int t3_mac_reset(struct cmac *mac, int portspeed)
  222 {
  223         u32 val, store_mps;
  224         adapter_t *adap = mac->adapter;
  225         unsigned int oft = mac->offset;
  226         int idx = macidx(mac);
  227         unsigned int store;
  228 
  229         /* Stop egress traffic to xgm*/
  230         store_mps = t3_read_reg(adap, A_MPS_CFG);
  231         if (!idx)
  232                 t3_set_reg_field(adap, A_MPS_CFG, F_PORT0ACTIVE, 0);
  233         else
  234                 t3_set_reg_field(adap, A_MPS_CFG, F_PORT1ACTIVE, 0);
  235 
  236         /* This will reduce the number of TXTOGGLES */
  237         /* Clear: to stop the NIC traffic */
  238         t3_set_reg_field(adap, A_MPS_CFG, F_ENFORCEPKT, 0);
  239         /* Ensure TX drains */
  240         t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN, 0);
  241 
  242         /* PCS in reset */
  243         t3_write_reg(adap, A_XGM_RESET_CTRL + oft, F_MAC_RESET_);
  244         (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft);    /* flush */
  245 
  246         /* Store A_TP_TX_DROP_CFG_CH0 */
  247         t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
  248         store = t3_read_reg(adap, A_TP_PIO_DATA);
  249 
  250         msleep(10);
  251 
  252         /* Change DROP_CFG to 0xc0000011 */
  253         t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
  254         t3_write_reg(adap, A_TP_PIO_DATA, 0xc0000011);
  255 
  256         /* Check for xgm Rx fifo empty */
  257         /* Increased loop count to 1000 from 5 cover 1G and 100Mbps case */
  258         if (t3_wait_op_done(adap, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT + oft,
  259                             0x80000000, 1, 1000, 2) && portspeed < 0) {
  260                 CH_ERR(adap, "MAC %d Rx fifo drain failed\n", idx);
  261                 return -1;
  262         }
  263 
  264         if (portspeed >= 0) {
  265                 u32 intr = t3_read_reg(adap, A_XGM_INT_ENABLE + oft);
  266 
  267                 /*
  268                  * safespeedchange: wipes out pretty much all XGMAC registers.
  269                  */
  270 
  271                 t3_set_reg_field(adap, A_XGM_PORT_CFG + oft,
  272                     V_PORTSPEED(M_PORTSPEED) | F_SAFESPEEDCHANGE,
  273                     portspeed | F_SAFESPEEDCHANGE);
  274                 (void) t3_read_reg(adap, A_XGM_PORT_CFG + oft);
  275                 t3_set_reg_field(adap, A_XGM_PORT_CFG + oft,
  276                     F_SAFESPEEDCHANGE, 0);
  277                 (void) t3_read_reg(adap, A_XGM_PORT_CFG + oft);
  278                 t3_mac_init(mac);
  279                 
  280                 t3_write_reg(adap, A_XGM_INT_ENABLE + oft, intr);
  281         } else {
  282 
  283                 t3_write_reg(adap, A_XGM_RESET_CTRL + oft, 0); /*MAC in reset*/
  284                 (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft);    /* flush */
  285 
  286                 val = xgm_reset_ctrl(mac);
  287                 t3_write_reg(adap, A_XGM_RESET_CTRL + oft, val);
  288                 (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft);  /* flush */
  289                 if ((val & F_PCS_RESET_) && adap->params.rev) {
  290                         msleep(1);
  291                         t3b_pcs_reset(mac);
  292                 }
  293                 t3_write_reg(adap, A_XGM_RX_CFG + oft,
  294                          F_DISPAUSEFRAMES | F_EN1536BFRAMES |
  295                                         F_RMFCS | F_ENJUMBO | F_ENHASHMCAST );
  296         }
  297 
  298         /* Restore the DROP_CFG */
  299         t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
  300         t3_write_reg(adap, A_TP_PIO_DATA, store);
  301 
  302         /* Resume egress traffic to xgm */
  303         t3_set_reg_field(adap, A_MPS_CFG, F_PORT1ACTIVE | F_PORT0ACTIVE,
  304                          store_mps);
  305 
  306         /*  Set: re-enable NIC traffic */
  307         t3_set_reg_field(adap, A_MPS_CFG, F_ENFORCEPKT, F_ENFORCEPKT);
  308 
  309         return 0;
  310 }
  311 
  312 /*
  313  * Set the exact match register 'idx' to recognize the given Ethernet address.
  314  */
  315 static void set_addr_filter(struct cmac *mac, int idx, const u8 *addr)
  316 {
  317         u32 addr_lo, addr_hi;
  318         unsigned int oft = mac->offset + idx * 8;
  319 
  320         addr_lo = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0];
  321         addr_hi = (addr[5] << 8) | addr[4];
  322 
  323         t3_write_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1 + oft, addr_lo);
  324         t3_write_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_HIGH_1 + oft, addr_hi);
  325 }
  326 
  327 /**
  328  *      t3_mac_set_address - set one of the station's unicast MAC addresses
  329  *      @mac: the MAC handle
  330  *      @idx: index of the exact address match filter to use
  331  *      @addr: the Ethernet address
  332  *
  333  *      Set one of the station's unicast MAC addresses.
  334  */
  335 int t3_mac_set_address(struct cmac *mac, unsigned int idx, u8 addr[6])
  336 {
  337         if (mac->multiport)
  338                 idx = mac->ext_port + idx * mac->adapter->params.nports;
  339         if (idx >= mac->nucast)
  340                 return -EINVAL;
  341         set_addr_filter(mac, idx, addr);
  342         if (mac->multiport && idx < mac->adapter->params.nports)
  343                 t3_vsc7323_set_addr(mac->adapter, addr, idx);
  344         return 0;
  345 }
  346 
  347 /**
  348  *      t3_mac_set_num_ucast - set the number of unicast addresses needed
  349  *      @mac: the MAC handle
  350  *      @n: number of unicast addresses needed
  351  *
  352  *      Specify the number of exact address filters that should be reserved for
  353  *      unicast addresses.  Caller should reload the unicast and multicast
  354  *      addresses after calling this.
  355  *
  356  *      Generally, this is 1 with the first one used for the station address,
  357  *      and the rest are available for multicast addresses.
  358  */
  359 int t3_mac_set_num_ucast(struct cmac *mac, unsigned char n)
  360 {
  361         if (n > EXACT_ADDR_FILTERS)
  362                 return -EINVAL;
  363         mac->nucast = n;
  364         return 0;
  365 }
  366 
  367 void t3_mac_disable_exact_filters(struct cmac *mac)
  368 {
  369         unsigned int i, reg = mac->offset + A_XGM_RX_EXACT_MATCH_LOW_1;
  370 
  371         for (i = 0; i < EXACT_ADDR_FILTERS; i++, reg += 8) {
  372                 u32 v = t3_read_reg(mac->adapter, reg);
  373                 t3_write_reg(mac->adapter, reg, v);
  374         }
  375         t3_read_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1); /* flush */
  376 }
  377 
  378 void t3_mac_enable_exact_filters(struct cmac *mac)
  379 {
  380         unsigned int i, reg = mac->offset + A_XGM_RX_EXACT_MATCH_HIGH_1;
  381 
  382         for (i = 0; i < EXACT_ADDR_FILTERS; i++, reg += 8) {
  383                 u32 v = t3_read_reg(mac->adapter, reg);
  384                 t3_write_reg(mac->adapter, reg, v);
  385         }
  386         t3_read_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1); /* flush */
  387 }
  388 
  389 /* Calculate the RX hash filter index of an Ethernet address */
  390 static int hash_hw_addr(const u8 *addr)
  391 {
  392         int hash = 0, octet, bit, i = 0, c;
  393 
  394         for (octet = 0; octet < 6; ++octet)
  395                 for (c = addr[octet], bit = 0; bit < 8; c >>= 1, ++bit) {
  396                         hash ^= (c & 1) << i;
  397                         if (++i == 6)
  398                                 i = 0;
  399                 }
  400         return hash;
  401 }
  402 
  403 /**
  404  *      t3_mac_set_rx_mode - set the Rx mode and address filters
  405  *      @mac: the MAC to configure
  406  *      @rm: structure containing the Rx mode and MAC addresses needed
  407  *
  408  *      Configures the MAC Rx mode (promiscuity, etc) and exact and hash
  409  *      address filters.
  410  */
  411 struct t3_mcaddr_ctx {
  412         struct cmac *mac;
  413         u32 hash_lo, hash_hi;
  414 };
  415 
  416 static u_int
  417 t3_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt)
  418 {
  419         struct t3_mcaddr_ctx *ctx = arg;
  420         int hash;
  421 
  422         if (ctx->mac->nucast + cnt < EXACT_ADDR_FILTERS)
  423                 set_addr_filter(ctx->mac, ctx->mac->nucast + cnt, LLADDR(sdl));
  424         else {
  425                 hash = hash_hw_addr(LLADDR(sdl));
  426                 if (hash < 32)
  427                         ctx->hash_lo |= (1 << hash);
  428                 else
  429                         ctx->hash_hi |= (1 << (hash - 32));
  430         }
  431         return (1);
  432 }
  433 
  434 int t3_mac_set_rx_mode(struct cmac *mac, struct t3_rx_mode *rm)
  435 {
  436         struct t3_mcaddr_ctx ctx;
  437         adapter_t *adap = mac->adapter;
  438         unsigned int oft = mac->offset;
  439 
  440         if (promisc_rx_mode(rm))
  441                 mac->promisc_map |= 1 << mac->ext_port;
  442         else
  443                 mac->promisc_map &= ~(1 << mac->ext_port);
  444         t3_set_reg_field(adap, A_XGM_RX_CFG + oft, F_COPYALLFRAMES,
  445                          mac->promisc_map ? F_COPYALLFRAMES : 0);
  446 
  447         if (allmulti_rx_mode(rm) || mac->multiport)
  448                 ctx.hash_lo = ctx.hash_hi = 0xffffffff;
  449         else {
  450                 ctx.mac = mac;
  451                 ctx.hash_lo = ctx.hash_hi = 0;
  452                 if_foreach_llmaddr(rm->port->ifp, t3_hash_maddr, &ctx);
  453         }
  454 
  455         t3_write_reg(adap, A_XGM_RX_HASH_LOW + oft, ctx.hash_lo);
  456         t3_write_reg(adap, A_XGM_RX_HASH_HIGH + oft, ctx.hash_hi);
  457         return 0;
  458 }
  459 
  460 static int rx_fifo_hwm(int mtu)
  461 {
  462         int hwm;
  463 
  464         hwm = max(MAC_RXFIFO_SIZE - 3 * mtu, (MAC_RXFIFO_SIZE * 38) / 100);
  465         return min(hwm, MAC_RXFIFO_SIZE - 8192);
  466 }
  467 
  468 /**
  469  *      t3_mac_set_mtu - set the MAC MTU
  470  *      @mac: the MAC to configure
  471  *      @mtu: the MTU
  472  *
  473  *      Sets the MAC MTU and adjusts the FIFO PAUSE watermarks accordingly.
  474  */
  475 int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu)
  476 {
  477         int hwm, lwm;
  478         int ipg;
  479         unsigned int thres, v, reg;
  480         adapter_t *adap = mac->adapter;
  481         unsigned port_type = adap->params.vpd.port_type[macidx(mac)];
  482         unsigned int orig_mtu=mtu;
  483 
  484         /*
  485          * MAX_FRAME_SIZE inludes header + FCS, mtu doesn't.  The HW max
  486          * packet size register includes header, but not FCS.
  487          */
  488         mtu += 14;
  489         if (mac->multiport)
  490                 mtu += 8;                             /* for preamble */
  491         if (mtu > MAX_FRAME_SIZE - 4)
  492                 return -EINVAL;
  493         if (mac->multiport)
  494                 return t3_vsc7323_set_mtu(adap, mtu - 4, mac->ext_port);
  495 
  496         /* Modify the TX and RX fifo depth only if the card has a vsc8211 phy */
  497         if (port_type == 2) {
  498                 int err = t3_vsc8211_fifo_depth(adap,orig_mtu,macidx(mac));
  499 
  500                 if (err)
  501                         return err;
  502         }
  503 
  504         if (adap->params.rev >= T3_REV_B2 &&
  505             (t3_read_reg(adap, A_XGM_RX_CTRL + mac->offset) & F_RXEN)) {
  506                 t3_mac_disable_exact_filters(mac);
  507                 v = t3_read_reg(adap, A_XGM_RX_CFG + mac->offset);
  508                 t3_set_reg_field(adap, A_XGM_RX_CFG + mac->offset,
  509                                  F_ENHASHMCAST | F_COPYALLFRAMES, F_DISBCAST);
  510 
  511                 reg = adap->params.rev == T3_REV_B2 ?
  512                         A_XGM_RX_MAX_PKT_SIZE_ERR_CNT : A_XGM_RXFIFO_CFG;
  513 
  514                 /* drain RX FIFO */
  515                 if (t3_wait_op_done(adap, reg + mac->offset,
  516                                     F_RXFIFO_EMPTY, 1, 20, 5)) {
  517                         t3_write_reg(adap, A_XGM_RX_CFG + mac->offset, v);
  518                         t3_mac_enable_exact_filters(mac);
  519                         return -EIO;
  520                 }
  521                 t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset,
  522                                  V_RXMAXPKTSIZE(M_RXMAXPKTSIZE),
  523                                  V_RXMAXPKTSIZE(mtu));
  524                 t3_write_reg(adap, A_XGM_RX_CFG + mac->offset, v);
  525                 t3_mac_enable_exact_filters(mac);
  526         } else
  527                 t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset,
  528                                  V_RXMAXPKTSIZE(M_RXMAXPKTSIZE),
  529                                  V_RXMAXPKTSIZE(mtu));
  530         /*
  531          * Adjust the PAUSE frame watermarks.  We always set the LWM, and the
  532          * HWM only if flow-control is enabled.
  533          */
  534         hwm = rx_fifo_hwm(mtu);
  535         lwm = min(3 * (int) mtu, MAC_RXFIFO_SIZE /4);
  536         v = t3_read_reg(adap, A_XGM_RXFIFO_CFG + mac->offset);
  537         v &= ~V_RXFIFOPAUSELWM(M_RXFIFOPAUSELWM);
  538         v |= V_RXFIFOPAUSELWM(lwm / 8);
  539         if (G_RXFIFOPAUSEHWM(v))
  540                 v = (v & ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM)) |
  541                     V_RXFIFOPAUSEHWM(hwm / 8);
  542 
  543         t3_write_reg(adap, A_XGM_RXFIFO_CFG + mac->offset, v);
  544 
  545         /* Adjust the TX FIFO threshold based on the MTU */
  546         thres = (adap->params.vpd.cclk * 1000) / 15625;
  547         thres = (thres * mtu) / 1000;
  548         if (is_10G(adap))
  549                 thres /= 10;
  550         thres = mtu > thres ? (mtu - thres + 7) / 8 : 0;
  551         thres = max(thres, 8U);                          /* need at least 8 */
  552         ipg = (port_type == 9 || adap->params.rev != T3_REV_C) ? 1 : 0;
  553         t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + mac->offset,
  554                          V_TXFIFOTHRESH(M_TXFIFOTHRESH) | V_TXIPG(M_TXIPG),
  555                          V_TXFIFOTHRESH(thres) | V_TXIPG(ipg));
  556         return 0;
  557 }
  558 
  559 /**
  560  *      t3_mac_set_speed_duplex_fc - set MAC speed, duplex and flow control
  561  *      @mac: the MAC to configure
  562  *      @speed: the desired speed (10/100/1000/10000)
  563  *      @duplex: the desired duplex
  564  *      @fc: desired Tx/Rx PAUSE configuration
  565  *
  566  *      Set the MAC speed, duplex (actually only full-duplex is supported), and
  567  *      flow control.  If a parameter value is negative the corresponding
  568  *      MAC setting is left at its current value.
  569  */
  570 int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc)
  571 {
  572         u32 val;
  573         adapter_t *adap = mac->adapter;
  574         unsigned int oft = mac->offset;
  575         unsigned int pause_bits;
  576 
  577         if (duplex >= 0 && duplex != DUPLEX_FULL)
  578                 return -EINVAL;
  579 
  580         pause_bits = MAC_RXFIFO_SIZE * 4 * 8;
  581         t3_write_reg(adap, A_XGM_TX_PAUSE_QUANTA + mac->offset,
  582                      pause_bits / 512);
  583         t3_write_reg(adap, A_XGM_PAUSE_TIMER + mac->offset,
  584                      (pause_bits >> (adap->params.rev == T3_REV_C ? 10 : 7)));
  585 
  586         if (mac->multiport) {
  587                 u32 rx_max_pkt_size =
  588                     G_RXMAXPKTSIZE(t3_read_reg(adap,
  589                                                A_XGM_RX_MAX_PKT_SIZE + oft));
  590                 val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft);
  591                 val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM);
  592                 val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(rx_max_pkt_size) / 8);
  593                 t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val);
  594                 t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN,
  595                                         F_TXPAUSEEN);
  596 
  597                 return t3_vsc7323_set_speed_fc(adap, speed, fc, mac->ext_port);
  598         }
  599         if (speed >= 0) {
  600                 if (speed == SPEED_10)
  601                         val = V_PORTSPEED(0);
  602                 else if (speed == SPEED_100)
  603                         val = V_PORTSPEED(1);
  604                 else if (speed == SPEED_1000)
  605                         val = V_PORTSPEED(2);
  606                 else if (speed == SPEED_10000)
  607                         val = V_PORTSPEED(3);
  608                 else
  609                         return -EINVAL;
  610 
  611                 if (!uses_xaui(adap)) /* T302 */
  612                         t3_set_reg_field(adap, A_XGM_PORT_CFG + oft,
  613                             V_PORTSPEED(M_PORTSPEED), val);
  614                 else {
  615                         u32 old = t3_read_reg(adap, A_XGM_PORT_CFG + oft);
  616 
  617                         if ((old & V_PORTSPEED(M_PORTSPEED)) != val) {
  618                                 t3_mac_reset(mac, val);
  619                                 mac->was_reset = 1;
  620                         }
  621                 }
  622         }
  623 
  624         val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft);
  625         val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM);
  626         if (fc & PAUSE_TX) {
  627                 u32 rx_max_pkt_size =
  628                     G_RXMAXPKTSIZE(t3_read_reg(adap,
  629                                                A_XGM_RX_MAX_PKT_SIZE + oft));
  630                 val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(rx_max_pkt_size) / 8);
  631         }
  632         t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val);
  633 
  634         t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN,
  635                         (fc & PAUSE_RX) ? F_TXPAUSEEN : 0);
  636         return 0;
  637 }
  638 
  639 /**
  640  *      t3_mac_enable - enable the MAC in the given directions
  641  *      @mac: the MAC to configure
  642  *      @which: bitmap indicating which directions to enable
  643  *
  644  *      Enables the MAC for operation in the given directions.
  645  *      %MAC_DIRECTION_TX enables the Tx direction, and %MAC_DIRECTION_RX
  646  *      enables the Rx one.
  647  */
  648 int t3_mac_enable(struct cmac *mac, int which)
  649 {
  650         int idx = macidx(mac);
  651         adapter_t *adap = mac->adapter;
  652         unsigned int oft = mac->offset;
  653         struct mac_stats *s = &mac->stats;
  654 
  655         if (mac->multiport)
  656                 return t3_vsc7323_enable(adap, mac->ext_port, which);
  657 
  658         if (which & MAC_DIRECTION_TX) {
  659                 t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
  660                 t3_write_reg(adap, A_TP_PIO_DATA,
  661                              adap->params.rev == T3_REV_C ?
  662                              0xc4ffff01 : 0xc0ede401);
  663                 t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_MODE);
  664                 t3_set_reg_field(adap, A_TP_PIO_DATA, 1 << idx,
  665                                  adap->params.rev == T3_REV_C ?
  666                                  0 : 1 << idx);
  667 
  668                 t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN);
  669 
  670                 t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CNT_CH0 + idx);
  671                 mac->tx_mcnt = s->tx_frames;
  672                 mac->tx_tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap,
  673                                                                A_TP_PIO_DATA)));
  674                 mac->tx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
  675                                                 A_XGM_TX_SPI4_SOP_EOP_CNT +
  676                                                 oft)));
  677                 mac->rx_mcnt = s->rx_frames;
  678                 mac->rx_pause = s->rx_pause;
  679                 mac->rx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
  680                                                 A_XGM_RX_SPI4_SOP_EOP_CNT +
  681                                                 oft)));
  682                 mac->rx_ocnt = s->rx_fifo_ovfl;
  683                 mac->txen = F_TXEN;
  684                 mac->toggle_cnt = 0;
  685         }
  686         if (which & MAC_DIRECTION_RX)
  687                 t3_write_reg(adap, A_XGM_RX_CTRL + oft, F_RXEN);
  688         return 0;
  689 }
  690 
  691 /**
  692  *      t3_mac_disable - disable the MAC in the given directions
  693  *      @mac: the MAC to configure
  694  *      @which: bitmap indicating which directions to disable
  695  *
  696  *      Disables the MAC in the given directions.
  697  *      %MAC_DIRECTION_TX disables the Tx direction, and %MAC_DIRECTION_RX
  698  *      disables the Rx one.
  699  */
  700 int t3_mac_disable(struct cmac *mac, int which)
  701 {
  702         adapter_t *adap = mac->adapter;
  703 
  704         if (mac->multiport)
  705                 return t3_vsc7323_disable(adap, mac->ext_port, which);
  706 
  707         if (which & MAC_DIRECTION_TX) {
  708                 t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0);
  709                 mac->txen = 0;
  710         }
  711         if (which & MAC_DIRECTION_RX) {
  712                 int val = xgm_reset_ctrl(mac);
  713 
  714                 t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset,
  715                                  F_PCS_RESET_, 0);
  716                 msleep(100);
  717                 t3_write_reg(adap, A_XGM_RX_CTRL + mac->offset, 0);
  718                 t3_write_reg(mac->adapter, A_XGM_RESET_CTRL + mac->offset, val);
  719         }
  720         return 0;
  721 }
  722 
  723 int t3b2_mac_watchdog_task(struct cmac *mac)
  724 {
  725         int status;
  726         unsigned int tx_tcnt, tx_xcnt;
  727         adapter_t *adap = mac->adapter;
  728         struct mac_stats *s = &mac->stats;
  729         u64 tx_mcnt = s->tx_frames;
  730 
  731         if (mac->multiport)
  732                 tx_mcnt = t3_read_reg(adap, A_XGM_STAT_TX_FRAME_LOW);
  733 
  734         status = 0;
  735         tx_xcnt = 1; /* By default tx_xcnt is making progress*/
  736         tx_tcnt = mac->tx_tcnt; /* If tx_mcnt is progressing ignore tx_tcnt*/
  737         if (tx_mcnt == mac->tx_mcnt && mac->rx_pause == s->rx_pause) {
  738                 u32 cfg, active, enforcepkt;
  739 
  740                 tx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
  741                                                       A_XGM_TX_SPI4_SOP_EOP_CNT +
  742                                                       mac->offset)));
  743                 cfg = t3_read_reg(adap, A_MPS_CFG);
  744                 active = macidx(mac) ? cfg & F_PORT1ACTIVE : cfg & F_PORT0ACTIVE;
  745                 enforcepkt = cfg & F_ENFORCEPKT;        
  746                 if (active && enforcepkt && (tx_xcnt == 0)) {
  747                         t3_write_reg(adap, A_TP_PIO_ADDR,
  748                                 A_TP_TX_DROP_CNT_CH0 + macidx(mac));
  749                         tx_tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap,
  750                                 A_TP_PIO_DATA)));
  751                 } else
  752                         goto out;
  753 
  754         } else {
  755                 mac->toggle_cnt = 0;
  756                 goto out;
  757         }
  758 
  759         if ((tx_tcnt != mac->tx_tcnt) && (mac->tx_xcnt == 0)) {
  760                 if (mac->toggle_cnt > 4) {
  761                         status = 2;
  762                         goto out;
  763                 } else {
  764                         status = 1;
  765                         goto out;
  766                 }
  767         } else {
  768                 mac->toggle_cnt = 0;
  769                 goto out;
  770         }
  771 
  772 out:
  773         mac->tx_tcnt = tx_tcnt;
  774         mac->tx_xcnt = tx_xcnt;
  775         mac->tx_mcnt = s->tx_frames;
  776         mac->rx_pause = s->rx_pause;
  777         if (status == 1) {
  778                 t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0);
  779                 t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset);  /* flush */
  780                 t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, mac->txen);
  781                 t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset);  /* flush */
  782                 mac->toggle_cnt++;
  783         } else if (status == 2) {
  784                 t3_mac_reset(mac, -1);
  785                 mac->toggle_cnt = 0;
  786         }
  787         return status;
  788 }
  789 
  790 /**
  791  *      t3_mac_update_stats - accumulate MAC statistics
  792  *      @mac: the MAC handle
  793  *
  794  *      This function is called periodically to accumulate the current values
  795  *      of the RMON counters into the port statistics.  Since the packet
  796  *      counters are only 32 bits they can overflow in ~286 secs at 10G, so the
  797  *      function should be called more frequently than that.  The byte counters
  798  *      are 45-bit wide, they would overflow in ~7.8 hours.
  799  */
  800 const struct mac_stats *t3_mac_update_stats(struct cmac *mac)
  801 {
  802 #define RMON_READ(mac, addr) t3_read_reg(mac->adapter, addr + mac->offset)
  803 #define RMON_UPDATE(mac, name, reg) \
  804         (mac)->stats.name += (u64)RMON_READ(mac, A_XGM_STAT_##reg)
  805 #define RMON_UPDATE64(mac, name, reg_lo, reg_hi) \
  806         (mac)->stats.name += RMON_READ(mac, A_XGM_STAT_##reg_lo) + \
  807                              ((u64)RMON_READ(mac, A_XGM_STAT_##reg_hi) << 32)
  808 
  809         u32 v, lo;
  810 
  811         if (mac->multiport)
  812                 return t3_vsc7323_update_stats(mac);
  813 
  814         RMON_UPDATE64(mac, rx_octets, RX_BYTES_LOW, RX_BYTES_HIGH);
  815         RMON_UPDATE64(mac, rx_frames, RX_FRAMES_LOW, RX_FRAMES_HIGH);
  816         RMON_UPDATE(mac, rx_mcast_frames, RX_MCAST_FRAMES);
  817         RMON_UPDATE(mac, rx_bcast_frames, RX_BCAST_FRAMES);
  818         RMON_UPDATE(mac, rx_fcs_errs, RX_CRC_ERR_FRAMES);
  819         RMON_UPDATE(mac, rx_pause, RX_PAUSE_FRAMES);
  820         RMON_UPDATE(mac, rx_jabber, RX_JABBER_FRAMES);
  821         RMON_UPDATE(mac, rx_short, RX_SHORT_FRAMES);
  822         RMON_UPDATE(mac, rx_symbol_errs, RX_SYM_CODE_ERR_FRAMES);
  823 
  824         RMON_UPDATE(mac, rx_too_long, RX_OVERSIZE_FRAMES);
  825 
  826         v = RMON_READ(mac, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT);
  827         if (mac->adapter->params.rev == T3_REV_B2)
  828                 v &= 0x7fffffff;
  829         mac->stats.rx_too_long += v;
  830 
  831         RMON_UPDATE(mac, rx_frames_64,        RX_64B_FRAMES);
  832         RMON_UPDATE(mac, rx_frames_65_127,    RX_65_127B_FRAMES);
  833         RMON_UPDATE(mac, rx_frames_128_255,   RX_128_255B_FRAMES);
  834         RMON_UPDATE(mac, rx_frames_256_511,   RX_256_511B_FRAMES);
  835         RMON_UPDATE(mac, rx_frames_512_1023,  RX_512_1023B_FRAMES);
  836         RMON_UPDATE(mac, rx_frames_1024_1518, RX_1024_1518B_FRAMES);
  837         RMON_UPDATE(mac, rx_frames_1519_max,  RX_1519_MAXB_FRAMES);
  838 
  839         RMON_UPDATE64(mac, tx_octets, TX_BYTE_LOW, TX_BYTE_HIGH);
  840         RMON_UPDATE64(mac, tx_frames, TX_FRAME_LOW, TX_FRAME_HIGH);
  841         RMON_UPDATE(mac, tx_mcast_frames, TX_MCAST);
  842         RMON_UPDATE(mac, tx_bcast_frames, TX_BCAST);
  843         RMON_UPDATE(mac, tx_pause, TX_PAUSE);
  844         /* This counts error frames in general (bad FCS, underrun, etc). */
  845         RMON_UPDATE(mac, tx_underrun, TX_ERR_FRAMES);
  846 
  847         RMON_UPDATE(mac, tx_frames_64,        TX_64B_FRAMES);
  848         RMON_UPDATE(mac, tx_frames_65_127,    TX_65_127B_FRAMES);
  849         RMON_UPDATE(mac, tx_frames_128_255,   TX_128_255B_FRAMES);
  850         RMON_UPDATE(mac, tx_frames_256_511,   TX_256_511B_FRAMES);
  851         RMON_UPDATE(mac, tx_frames_512_1023,  TX_512_1023B_FRAMES);
  852         RMON_UPDATE(mac, tx_frames_1024_1518, TX_1024_1518B_FRAMES);
  853         RMON_UPDATE(mac, tx_frames_1519_max,  TX_1519_MAXB_FRAMES);
  854 
  855         /* The next stat isn't clear-on-read. */
  856         t3_write_reg(mac->adapter, A_TP_MIB_INDEX, mac->offset ? 51 : 50);
  857         v = t3_read_reg(mac->adapter, A_TP_MIB_RDATA);
  858         lo = (u32)mac->stats.rx_cong_drops;
  859         mac->stats.rx_cong_drops += (u64)(v - lo);
  860 
  861         return &mac->stats;
  862 }

Cache object: a5caaa92c18a135837a869c2f0f157d3


[ 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.