1 /**************************************************************************
3 Copyright (c) 2007, Chelsio Inc.
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions are met:
9 1. Redistributions of source code must retain the above copyright notice,
10 this list of conditions and the following disclaimer.
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.
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.
28 ***************************************************************************/
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
34 #include <cxgb_include.h>
36 #include <dev/cxgb/cxgb_include.h>
40 #define msleep t3_os_sleep
43 static inline int macidx(const struct cmac *mac)
45 return mac->offset / (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR);
48 static void xaui_serdes_reset(struct cmac *mac)
50 static const unsigned int clear[] = {
51 F_PWRDN0 | F_PWRDN1, F_RESETPLL01, F_RESET0 | F_RESET1,
52 F_PWRDN2 | F_PWRDN3, F_RESETPLL23, F_RESET2 | F_RESET3
56 adapter_t *adap = mac->adapter;
57 u32 ctrl = A_XGM_SERDES_CTRL0 + mac->offset;
59 t3_write_reg(adap, ctrl, adap->params.vpd.xauicfg[macidx(mac)] |
60 F_RESET3 | F_RESET2 | F_RESET1 | F_RESET0 |
61 F_PWRDN3 | F_PWRDN2 | F_PWRDN1 | F_PWRDN0 |
62 F_RESETPLL23 | F_RESETPLL01);
63 (void)t3_read_reg(adap, ctrl);
66 for (i = 0; i < ARRAY_SIZE(clear); i++) {
67 t3_set_reg_field(adap, ctrl, clear[i], 0);
73 * t3b_pcs_reset - reset the PCS on T3B+ adapters
74 * @mac: the XGMAC handle
76 * Reset the XGMAC PCS block on T3B+ adapters.
78 void t3b_pcs_reset(struct cmac *mac)
80 t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset,
83 t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset, 0,
88 * t3_mac_reset - reset a MAC
89 * @mac: the MAC to reset
91 * Reset the given MAC.
93 int t3_mac_reset(struct cmac *mac)
95 static struct addr_val_pair mac_reset_avp[] = {
98 { A_XGM_RX_CFG, F_DISPAUSEFRAMES | F_EN1536BFRAMES |
99 F_RMFCS | F_ENJUMBO | F_ENHASHMCAST },
100 { A_XGM_RX_HASH_LOW, 0 },
101 { A_XGM_RX_HASH_HIGH, 0 },
102 { A_XGM_RX_EXACT_MATCH_LOW_1, 0 },
103 { A_XGM_RX_EXACT_MATCH_LOW_2, 0 },
104 { A_XGM_RX_EXACT_MATCH_LOW_3, 0 },
105 { A_XGM_RX_EXACT_MATCH_LOW_4, 0 },
106 { A_XGM_RX_EXACT_MATCH_LOW_5, 0 },
107 { A_XGM_RX_EXACT_MATCH_LOW_6, 0 },
108 { A_XGM_RX_EXACT_MATCH_LOW_7, 0 },
109 { A_XGM_RX_EXACT_MATCH_LOW_8, 0 },
110 { A_XGM_STAT_CTRL, F_CLRSTATS }
113 adapter_t *adap = mac->adapter;
114 unsigned int oft = mac->offset;
116 t3_write_reg(adap, A_XGM_RESET_CTRL + oft, F_MAC_RESET_);
117 (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */
119 t3_write_regs(adap, mac_reset_avp, ARRAY_SIZE(mac_reset_avp), oft);
120 t3_set_reg_field(adap, A_XGM_RXFIFO_CFG + oft,
121 F_RXSTRFRWRD | F_DISERRFRAMES,
122 uses_xaui(adap) ? 0 : F_RXSTRFRWRD);
123 t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + oft, 0, F_UNDERUNFIX);
125 if (uses_xaui(adap)) {
126 if (adap->params.rev == 0) {
127 t3_set_reg_field(adap, A_XGM_SERDES_CTRL + oft, 0,
128 F_RXENABLE | F_TXENABLE);
129 if (t3_wait_op_done(adap, A_XGM_SERDES_STATUS1 + oft,
130 F_CMULOCK, 1, 5, 2)) {
132 "MAC %d XAUI SERDES CMU lock failed\n",
136 t3_set_reg_field(adap, A_XGM_SERDES_CTRL + oft, 0,
139 xaui_serdes_reset(mac);
143 if (mac->multiport) {
144 t3_write_reg(adap, A_XGM_RX_MAX_PKT_SIZE + oft,
146 t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + oft, 0,
148 t3_set_reg_field(adap, A_XGM_RX_CFG + oft, 0, F_COPYPREAMBLE |
149 F_ENNON802_3PREAMBLE);
150 t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + oft,
151 V_TXFIFOTHRESH(M_TXFIFOTHRESH),
153 t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN);
154 t3_write_reg(adap, A_XGM_RX_CTRL + oft, F_RXEN);
157 t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + oft,
158 V_RXMAXFRAMERSIZE(M_RXMAXFRAMERSIZE),
159 V_RXMAXFRAMERSIZE(MAX_FRAME_SIZE) | F_RXENFRAMER);
161 val = F_MAC_RESET_ | F_XGMAC_STOP_EN;
163 val |= F_XG2G_RESET_;
167 val |= F_RGMII_RESET_;
168 t3_write_reg(adap, A_XGM_RESET_CTRL + oft, val);
169 (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */
170 if ((val & F_PCS_RESET_) && adap->params.rev) {
175 memset(&mac->stats, 0, sizeof(mac->stats));
179 static int t3b2_mac_reset(struct cmac *mac)
182 adapter_t *adap = mac->adapter;
183 unsigned int oft = mac->offset;
184 int idx = macidx(mac);
187 /* Stop egress traffic to xgm*/
189 t3_set_reg_field(adap, A_MPS_CFG, F_PORT0ACTIVE, 0);
191 t3_set_reg_field(adap, A_MPS_CFG, F_PORT1ACTIVE, 0);
194 t3_write_reg(adap, A_XGM_RESET_CTRL + oft, F_MAC_RESET_);
195 (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */
197 /* Store A_TP_TX_DROP_CFG_CH0 */
198 t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
199 store = t3_read_reg(adap, A_TP_TX_DROP_CFG_CH0 + idx);
203 /* Change DROP_CFG to 0xc0000011 */
204 t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
205 t3_write_reg(adap, A_TP_PIO_DATA, 0xc0000011);
207 /* Check for xgm Rx fifo empty */
208 /* Increased loop count to 1000 from 5 cover 1G and 100Mbps case */
209 if (t3_wait_op_done(adap, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT + oft,
210 0x80000000, 1, 1000, 2)) {
211 CH_ERR(adap, "MAC %d Rx fifo drain failed\n",
216 t3_write_reg(adap, A_XGM_RESET_CTRL + oft, 0); /*MAC in reset*/
217 (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */
222 else if (uses_xaui(adap))
223 val |= F_PCS_RESET_ | F_XG2G_RESET_;
225 val |= F_RGMII_RESET_ | F_XG2G_RESET_;
226 t3_write_reg(adap, A_XGM_RESET_CTRL + oft, val);
227 (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */
228 if ((val & F_PCS_RESET_) && adap->params.rev) {
232 t3_write_reg(adap, A_XGM_RX_CFG + oft,
233 F_DISPAUSEFRAMES | F_EN1536BFRAMES |
234 F_RMFCS | F_ENJUMBO | F_ENHASHMCAST );
236 /* Restore the DROP_CFG */
237 t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
238 t3_write_reg(adap, A_TP_PIO_DATA, store);
240 /* Resume egress traffic to xgm */
242 t3_set_reg_field(adap, A_MPS_CFG, 0, F_PORT0ACTIVE);
244 t3_set_reg_field(adap, A_MPS_CFG, 0, F_PORT1ACTIVE);
250 * Set the exact match register 'idx' to recognize the given Ethernet address.
252 static void set_addr_filter(struct cmac *mac, int idx, const u8 *addr)
254 u32 addr_lo, addr_hi;
255 unsigned int oft = mac->offset + idx * 8;
257 addr_lo = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0];
258 addr_hi = (addr[5] << 8) | addr[4];
260 t3_write_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1 + oft, addr_lo);
261 t3_write_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_HIGH_1 + oft, addr_hi);
265 * t3_mac_set_address - set one of the station's unicast MAC addresses
266 * @mac: the MAC handle
267 * @idx: index of the exact address match filter to use
268 * @addr: the Ethernet address
270 * Set one of the station's unicast MAC addresses.
272 int t3_mac_set_address(struct cmac *mac, unsigned int idx, u8 addr[6])
275 idx = mac->ext_port + idx * mac->adapter->params.nports;
276 if (idx >= mac->nucast)
278 set_addr_filter(mac, idx, addr);
279 if (mac->multiport && idx < mac->adapter->params.nports)
280 t3_vsc7323_set_addr(mac->adapter, addr, idx);
285 * t3_mac_set_num_ucast - set the number of unicast addresses needed
286 * @mac: the MAC handle
287 * @n: number of unicast addresses needed
289 * Specify the number of exact address filters that should be reserved for
290 * unicast addresses. Caller should reload the unicast and multicast
291 * addresses after calling this.
293 * Generally, this is 1 with the first one used for the station address,
294 * and the rest are available for multicast addresses.
296 int t3_mac_set_num_ucast(struct cmac *mac, unsigned char n)
298 if (n > EXACT_ADDR_FILTERS)
304 static void disable_exact_filters(struct cmac *mac)
306 unsigned int i, reg = mac->offset + A_XGM_RX_EXACT_MATCH_LOW_1;
308 for (i = 0; i < EXACT_ADDR_FILTERS; i++, reg += 8) {
309 u32 v = t3_read_reg(mac->adapter, reg);
310 t3_write_reg(mac->adapter, reg, v);
312 t3_read_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1); /* flush */
315 static void enable_exact_filters(struct cmac *mac)
317 unsigned int i, reg = mac->offset + A_XGM_RX_EXACT_MATCH_HIGH_1;
319 for (i = 0; i < EXACT_ADDR_FILTERS; i++, reg += 8) {
320 u32 v = t3_read_reg(mac->adapter, reg);
321 t3_write_reg(mac->adapter, reg, v);
323 t3_read_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1); /* flush */
326 /* Calculate the RX hash filter index of an Ethernet address */
327 static int hash_hw_addr(const u8 *addr)
329 int hash = 0, octet, bit, i = 0, c;
331 for (octet = 0; octet < 6; ++octet)
332 for (c = addr[octet], bit = 0; bit < 8; c >>= 1, ++bit) {
333 hash ^= (c & 1) << i;
341 * t3_mac_set_rx_mode - set the Rx mode and address filters
342 * @mac: the MAC to configure
343 * @rm: structure containing the Rx mode and MAC addresses needed
345 * Configures the MAC Rx mode (promiscuity, etc) and exact and hash
348 int t3_mac_set_rx_mode(struct cmac *mac, struct t3_rx_mode *rm)
350 u32 hash_lo, hash_hi;
351 adapter_t *adap = mac->adapter;
352 unsigned int oft = mac->offset;
354 if (promisc_rx_mode(rm))
355 mac->promisc_map |= 1 << mac->ext_port;
357 mac->promisc_map &= ~(1 << mac->ext_port);
358 t3_set_reg_field(adap, A_XGM_RX_CFG + oft, F_COPYALLFRAMES,
359 mac->promisc_map ? F_COPYALLFRAMES : 0);
361 if (allmulti_rx_mode(rm) || mac->multiport)
362 hash_lo = hash_hi = 0xffffffff;
365 int exact_addr_idx = mac->nucast;
367 hash_lo = hash_hi = 0;
368 while ((addr = t3_get_next_mcaddr(rm)))
369 if (exact_addr_idx < EXACT_ADDR_FILTERS)
370 set_addr_filter(mac, exact_addr_idx++, addr);
372 int hash = hash_hw_addr(addr);
375 hash_lo |= (1 << hash);
377 hash_hi |= (1 << (hash - 32));
381 t3_write_reg(adap, A_XGM_RX_HASH_LOW + oft, hash_lo);
382 t3_write_reg(adap, A_XGM_RX_HASH_HIGH + oft, hash_hi);
386 static int rx_fifo_hwm(int mtu)
390 hwm = max(MAC_RXFIFO_SIZE - 3 * mtu, (MAC_RXFIFO_SIZE * 38) / 100);
391 return min(hwm, MAC_RXFIFO_SIZE - 8192);
395 * t3_mac_set_mtu - set the MAC MTU
396 * @mac: the MAC to configure
399 * Sets the MAC MTU and adjusts the FIFO PAUSE watermarks accordingly.
401 int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu)
403 int hwm, lwm, divisor;
405 unsigned int thres, v, reg;
406 adapter_t *adap = mac->adapter;
409 * MAX_FRAME_SIZE inludes header + FCS, mtu doesn't. The HW max
410 * packet size register includes header, but not FCS.
414 mtu += 8; /* for preamble */
415 if (mtu > MAX_FRAME_SIZE - 4)
418 return t3_vsc7323_set_mtu(adap, mtu - 4, mac->ext_port);
420 if (adap->params.rev >= T3_REV_B2 &&
421 (t3_read_reg(adap, A_XGM_RX_CTRL + mac->offset) & F_RXEN)) {
422 disable_exact_filters(mac);
423 v = t3_read_reg(adap, A_XGM_RX_CFG + mac->offset);
424 t3_set_reg_field(adap, A_XGM_RX_CFG + mac->offset,
425 F_ENHASHMCAST | F_COPYALLFRAMES, F_DISBCAST);
427 reg = adap->params.rev == T3_REV_B2 ?
428 A_XGM_RX_MAX_PKT_SIZE_ERR_CNT : A_XGM_RXFIFO_CFG;
431 if (t3_wait_op_done(adap, reg + mac->offset,
432 F_RXFIFO_EMPTY, 1, 20, 5)) {
433 t3_write_reg(adap, A_XGM_RX_CFG + mac->offset, v);
434 enable_exact_filters(mac);
437 t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset,
438 V_RXMAXPKTSIZE(M_RXMAXPKTSIZE),
439 V_RXMAXPKTSIZE(mtu));
440 t3_write_reg(adap, A_XGM_RX_CFG + mac->offset, v);
441 enable_exact_filters(mac);
443 t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset,
444 V_RXMAXPKTSIZE(M_RXMAXPKTSIZE),
445 V_RXMAXPKTSIZE(mtu));
447 * Adjust the PAUSE frame watermarks. We always set the LWM, and the
448 * HWM only if flow-control is enabled.
450 hwm = rx_fifo_hwm(mtu);
451 lwm = min(3 * (int) mtu, MAC_RXFIFO_SIZE /4);
452 v = t3_read_reg(adap, A_XGM_RXFIFO_CFG + mac->offset);
453 v &= ~V_RXFIFOPAUSELWM(M_RXFIFOPAUSELWM);
454 v |= V_RXFIFOPAUSELWM(lwm / 8);
455 if (G_RXFIFOPAUSEHWM(v))
456 v = (v & ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM)) |
457 V_RXFIFOPAUSEHWM(hwm / 8);
459 t3_write_reg(adap, A_XGM_RXFIFO_CFG + mac->offset, v);
461 /* Adjust the TX FIFO threshold based on the MTU */
462 thres = (adap->params.vpd.cclk * 1000) / 15625;
463 thres = (thres * mtu) / 1000;
466 thres = mtu > thres ? (mtu - thres + 7) / 8 : 0;
467 thres = max(thres, 8U); /* need at least 8 */
468 ipg = (adap->params.rev == T3_REV_C) ? 0 : 1;
469 t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + mac->offset,
470 V_TXFIFOTHRESH(M_TXFIFOTHRESH) | V_TXIPG(M_TXIPG),
471 V_TXFIFOTHRESH(thres) | V_TXIPG(ipg));
473 /* Assuming a minimum drain rate of 2.5Gbps...
475 if (adap->params.rev > 0) {
476 divisor = (adap->params.rev == T3_REV_C) ? 64 : 8;
477 t3_write_reg(adap, A_XGM_PAUSE_TIMER + mac->offset,
478 (hwm - lwm) * 4 / divisor);
480 t3_write_reg(adap, A_XGM_TX_PAUSE_QUANTA + mac->offset,
481 MAC_RXFIFO_SIZE * 4 * 8 / 512);
486 * t3_mac_set_speed_duplex_fc - set MAC speed, duplex and flow control
487 * @mac: the MAC to configure
488 * @speed: the desired speed (10/100/1000/10000)
489 * @duplex: the desired duplex
490 * @fc: desired Tx/Rx PAUSE configuration
492 * Set the MAC speed, duplex (actually only full-duplex is supported), and
493 * flow control. If a parameter value is negative the corresponding
494 * MAC setting is left at its current value.
496 int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc)
499 adapter_t *adap = mac->adapter;
500 unsigned int oft = mac->offset;
502 if (duplex >= 0 && duplex != DUPLEX_FULL)
504 if (mac->multiport) {
505 val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft);
506 val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM);
507 val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(t3_read_reg(adap,
508 A_XGM_RX_MAX_PKT_SIZE + oft)) / 8);
509 t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val);
511 t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN,
513 return t3_vsc7323_set_speed_fc(adap, speed, fc, mac->ext_port);
516 if (speed == SPEED_10)
517 val = V_PORTSPEED(0);
518 else if (speed == SPEED_100)
519 val = V_PORTSPEED(1);
520 else if (speed == SPEED_1000)
521 val = V_PORTSPEED(2);
522 else if (speed == SPEED_10000)
523 val = V_PORTSPEED(3);
527 t3_set_reg_field(adap, A_XGM_PORT_CFG + oft,
528 V_PORTSPEED(M_PORTSPEED), val);
531 val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft);
532 val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM);
534 val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(t3_read_reg(adap,
535 A_XGM_RX_MAX_PKT_SIZE + oft)) / 8);
536 t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val);
538 t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN,
539 (fc & PAUSE_RX) ? F_TXPAUSEEN : 0);
544 * t3_mac_enable - enable the MAC in the given directions
545 * @mac: the MAC to configure
546 * @which: bitmap indicating which directions to enable
548 * Enables the MAC for operation in the given directions.
549 * %MAC_DIRECTION_TX enables the Tx direction, and %MAC_DIRECTION_RX
550 * enables the Rx one.
552 int t3_mac_enable(struct cmac *mac, int which)
554 int idx = macidx(mac);
555 adapter_t *adap = mac->adapter;
556 unsigned int oft = mac->offset;
557 struct mac_stats *s = &mac->stats;
560 return t3_vsc7323_enable(adap, mac->ext_port, which);
562 if (which & MAC_DIRECTION_TX) {
563 t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
564 t3_write_reg(adap, A_TP_PIO_DATA,
565 adap->params.rev == T3_REV_C ?
566 0xc4ffff01 : 0xc0ede401);
567 t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_MODE);
568 t3_set_reg_field(adap, A_TP_PIO_DATA, 1 << idx,
569 adap->params.rev == T3_REV_C ?
572 t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN);
574 t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CNT_CH0 + idx);
575 mac->tx_mcnt = s->tx_frames;
576 mac->tx_tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap,
578 mac->tx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
579 A_XGM_TX_SPI4_SOP_EOP_CNT +
581 mac->rx_mcnt = s->rx_frames;
582 mac->rx_pause = s->rx_pause;
583 mac->rx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
584 A_XGM_RX_SPI4_SOP_EOP_CNT +
586 mac->rx_ocnt = s->rx_fifo_ovfl;
590 if (which & MAC_DIRECTION_RX)
591 t3_write_reg(adap, A_XGM_RX_CTRL + oft, F_RXEN);
596 * t3_mac_disable - disable the MAC in the given directions
597 * @mac: the MAC to configure
598 * @which: bitmap indicating which directions to disable
600 * Disables the MAC in the given directions.
601 * %MAC_DIRECTION_TX disables the Tx direction, and %MAC_DIRECTION_RX
602 * disables the Rx one.
604 int t3_mac_disable(struct cmac *mac, int which)
606 adapter_t *adap = mac->adapter;
609 return t3_vsc7323_disable(adap, mac->ext_port, which);
611 if (which & MAC_DIRECTION_TX) {
612 t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0);
615 if (which & MAC_DIRECTION_RX) {
616 int val = F_MAC_RESET_;
618 t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset,
621 t3_write_reg(adap, A_XGM_RX_CTRL + mac->offset, 0);
624 else if (uses_xaui(adap))
625 val |= F_PCS_RESET_ | F_XG2G_RESET_;
627 val |= F_RGMII_RESET_ | F_XG2G_RESET_;
628 t3_write_reg(mac->adapter, A_XGM_RESET_CTRL + mac->offset, val);
633 int t3b2_mac_watchdog_task(struct cmac *mac)
636 unsigned int tx_tcnt, tx_xcnt;
637 adapter_t *adap = mac->adapter;
638 struct mac_stats *s = &mac->stats;
639 unsigned int tx_mcnt = (unsigned int)s->tx_frames;
641 if (mac->multiport) {
642 tx_mcnt = t3_read_reg(adap, A_XGM_STAT_TX_FRAME_LOW);
644 tx_mcnt = (unsigned int)s->tx_frames;
647 tx_xcnt = 1; /* By default tx_xcnt is making progress*/
648 tx_tcnt = mac->tx_tcnt; /* If tx_mcnt is progressing ignore tx_tcnt*/
649 if (tx_mcnt == mac->tx_mcnt && mac->rx_pause == s->rx_pause) {
650 tx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
651 A_XGM_TX_SPI4_SOP_EOP_CNT +
654 t3_write_reg(adap, A_TP_PIO_ADDR,
655 A_TP_TX_DROP_CNT_CH0 + macidx(mac));
656 tx_tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap,
666 if ((tx_tcnt != mac->tx_tcnt) && (mac->tx_xcnt == 0)) {
667 if (mac->toggle_cnt > 4) {
680 mac->tx_tcnt = tx_tcnt;
681 mac->tx_xcnt = tx_xcnt;
682 mac->tx_mcnt = s->tx_frames;
683 mac->rx_pause = s->rx_pause;
685 t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0);
686 t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset); /* flush */
687 t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, mac->txen);
688 t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset); /* flush */
690 } else if (status == 2) {
698 * t3_mac_update_stats - accumulate MAC statistics
699 * @mac: the MAC handle
701 * This function is called periodically to accumulate the current values
702 * of the RMON counters into the port statistics. Since the packet
703 * counters are only 32 bits they can overflow in ~286 secs at 10G, so the
704 * function should be called more frequently than that. The byte counters
705 * are 45-bit wide, they would overflow in ~7.8 hours.
707 const struct mac_stats *t3_mac_update_stats(struct cmac *mac)
709 #define RMON_READ(mac, addr) t3_read_reg(mac->adapter, addr + mac->offset)
710 #define RMON_UPDATE(mac, name, reg) \
711 (mac)->stats.name += (u64)RMON_READ(mac, A_XGM_STAT_##reg)
712 #define RMON_UPDATE64(mac, name, reg_lo, reg_hi) \
713 (mac)->stats.name += RMON_READ(mac, A_XGM_STAT_##reg_lo) + \
714 ((u64)RMON_READ(mac, A_XGM_STAT_##reg_hi) << 32)
719 return t3_vsc7323_update_stats(mac);
721 RMON_UPDATE64(mac, rx_octets, RX_BYTES_LOW, RX_BYTES_HIGH);
722 RMON_UPDATE64(mac, rx_frames, RX_FRAMES_LOW, RX_FRAMES_HIGH);
723 RMON_UPDATE(mac, rx_mcast_frames, RX_MCAST_FRAMES);
724 RMON_UPDATE(mac, rx_bcast_frames, RX_BCAST_FRAMES);
725 RMON_UPDATE(mac, rx_fcs_errs, RX_CRC_ERR_FRAMES);
726 RMON_UPDATE(mac, rx_pause, RX_PAUSE_FRAMES);
727 RMON_UPDATE(mac, rx_jabber, RX_JABBER_FRAMES);
728 RMON_UPDATE(mac, rx_short, RX_SHORT_FRAMES);
729 RMON_UPDATE(mac, rx_symbol_errs, RX_SYM_CODE_ERR_FRAMES);
731 RMON_UPDATE(mac, rx_too_long, RX_OVERSIZE_FRAMES);
733 v = RMON_READ(mac, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT);
734 if (mac->adapter->params.rev == T3_REV_B2)
736 mac->stats.rx_too_long += v;
738 RMON_UPDATE(mac, rx_frames_64, RX_64B_FRAMES);
739 RMON_UPDATE(mac, rx_frames_65_127, RX_65_127B_FRAMES);
740 RMON_UPDATE(mac, rx_frames_128_255, RX_128_255B_FRAMES);
741 RMON_UPDATE(mac, rx_frames_256_511, RX_256_511B_FRAMES);
742 RMON_UPDATE(mac, rx_frames_512_1023, RX_512_1023B_FRAMES);
743 RMON_UPDATE(mac, rx_frames_1024_1518, RX_1024_1518B_FRAMES);
744 RMON_UPDATE(mac, rx_frames_1519_max, RX_1519_MAXB_FRAMES);
746 RMON_UPDATE64(mac, tx_octets, TX_BYTE_LOW, TX_BYTE_HIGH);
747 RMON_UPDATE64(mac, tx_frames, TX_FRAME_LOW, TX_FRAME_HIGH);
748 RMON_UPDATE(mac, tx_mcast_frames, TX_MCAST);
749 RMON_UPDATE(mac, tx_bcast_frames, TX_BCAST);
750 RMON_UPDATE(mac, tx_pause, TX_PAUSE);
751 /* This counts error frames in general (bad FCS, underrun, etc). */
752 RMON_UPDATE(mac, tx_underrun, TX_ERR_FRAMES);
754 RMON_UPDATE(mac, tx_frames_64, TX_64B_FRAMES);
755 RMON_UPDATE(mac, tx_frames_65_127, TX_65_127B_FRAMES);
756 RMON_UPDATE(mac, tx_frames_128_255, TX_128_255B_FRAMES);
757 RMON_UPDATE(mac, tx_frames_256_511, TX_256_511B_FRAMES);
758 RMON_UPDATE(mac, tx_frames_512_1023, TX_512_1023B_FRAMES);
759 RMON_UPDATE(mac, tx_frames_1024_1518, TX_1024_1518B_FRAMES);
760 RMON_UPDATE(mac, tx_frames_1519_max, TX_1519_MAXB_FRAMES);
762 /* The next stat isn't clear-on-read. */
763 t3_write_reg(mac->adapter, A_TP_MIB_INDEX, mac->offset ? 51 : 50);
764 v = t3_read_reg(mac->adapter, A_TP_MIB_RDATA);
765 lo = (u32)mac->stats.rx_cong_drops;
766 mac->stats.rx_cong_drops += (u64)(v - lo);