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