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

Cache object: 1c31d7640034037f9e773e79a873f5be


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