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

Cache object: dc567988700cc570336d4ef5cd5c4c9f


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