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$");
33 #include <cxgb_include.h>
36 #define msleep t3_os_sleep
39 static inline int macidx(const struct cmac *mac)
41 return mac->offset / (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR);
44 static void xaui_serdes_reset(struct cmac *mac)
46 static const unsigned int clear[] = {
47 F_PWRDN0 | F_PWRDN1, F_RESETPLL01, F_RESET0 | F_RESET1,
48 F_PWRDN2 | F_PWRDN3, F_RESETPLL23, F_RESET2 | F_RESET3
52 adapter_t *adap = mac->adapter;
53 u32 ctrl = A_XGM_SERDES_CTRL0 + mac->offset;
55 t3_write_reg(adap, ctrl, adap->params.vpd.xauicfg[macidx(mac)] |
56 F_RESET3 | F_RESET2 | F_RESET1 | F_RESET0 |
57 F_PWRDN3 | F_PWRDN2 | F_PWRDN1 | F_PWRDN0 |
58 F_RESETPLL23 | F_RESETPLL01);
59 (void)t3_read_reg(adap, ctrl);
62 for (i = 0; i < ARRAY_SIZE(clear); i++) {
63 t3_set_reg_field(adap, ctrl, clear[i], 0);
69 * t3b_pcs_reset - reset the PCS on T3B+ adapters
70 * @mac: the XGMAC handle
72 * Reset the XGMAC PCS block on T3B+ adapters.
74 void t3b_pcs_reset(struct cmac *mac)
76 t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset,
79 t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset, 0,
84 * t3_mac_reset - reset a MAC
85 * @mac: the MAC to reset
87 * Reset the given MAC.
89 int t3_mac_reset(struct cmac *mac)
91 static struct addr_val_pair mac_reset_avp[] = {
94 { A_XGM_RX_CFG, F_DISPAUSEFRAMES | F_EN1536BFRAMES |
95 F_RMFCS | F_ENJUMBO | F_ENHASHMCAST },
96 { A_XGM_RX_HASH_LOW, 0 },
97 { A_XGM_RX_HASH_HIGH, 0 },
98 { A_XGM_RX_EXACT_MATCH_LOW_1, 0 },
99 { A_XGM_RX_EXACT_MATCH_LOW_2, 0 },
100 { A_XGM_RX_EXACT_MATCH_LOW_3, 0 },
101 { A_XGM_RX_EXACT_MATCH_LOW_4, 0 },
102 { A_XGM_RX_EXACT_MATCH_LOW_5, 0 },
103 { A_XGM_RX_EXACT_MATCH_LOW_6, 0 },
104 { A_XGM_RX_EXACT_MATCH_LOW_7, 0 },
105 { A_XGM_RX_EXACT_MATCH_LOW_8, 0 },
106 { A_XGM_STAT_CTRL, F_CLRSTATS }
109 adapter_t *adap = mac->adapter;
110 unsigned int oft = mac->offset;
112 t3_write_reg(adap, A_XGM_RESET_CTRL + oft, F_MAC_RESET_);
113 (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */
115 t3_write_regs(adap, mac_reset_avp, ARRAY_SIZE(mac_reset_avp), oft);
116 t3_set_reg_field(adap, A_XGM_RXFIFO_CFG + oft,
117 F_RXSTRFRWRD | F_DISERRFRAMES,
118 uses_xaui(adap) ? 0 : F_RXSTRFRWRD);
119 t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + oft, 0, F_UNDERUNFIX);
121 if (uses_xaui(adap)) {
122 if (adap->params.rev == 0) {
123 t3_set_reg_field(adap, A_XGM_SERDES_CTRL + oft, 0,
124 F_RXENABLE | F_TXENABLE);
125 if (t3_wait_op_done(adap, A_XGM_SERDES_STATUS1 + oft,
126 F_CMULOCK, 1, 5, 2)) {
128 "MAC %d XAUI SERDES CMU lock failed\n",
132 t3_set_reg_field(adap, A_XGM_SERDES_CTRL + oft, 0,
135 xaui_serdes_reset(mac);
139 if (mac->multiport) {
140 t3_write_reg(adap, A_XGM_RX_MAX_PKT_SIZE + oft,
142 t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + oft, 0,
144 t3_set_reg_field(adap, A_XGM_RX_CFG + oft, 0, F_COPYPREAMBLE |
145 F_ENNON802_3PREAMBLE);
146 t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + oft,
147 V_TXFIFOTHRESH(M_TXFIFOTHRESH),
149 t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN);
150 t3_write_reg(adap, A_XGM_RX_CTRL + oft, F_RXEN);
153 t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + oft,
154 V_RXMAXFRAMERSIZE(M_RXMAXFRAMERSIZE),
155 V_RXMAXFRAMERSIZE(MAX_FRAME_SIZE) | F_RXENFRAMER);
157 val = F_MAC_RESET_ | F_XGMAC_STOP_EN;
159 val |= F_XG2G_RESET_;
163 val |= F_RGMII_RESET_;
164 t3_write_reg(adap, A_XGM_RESET_CTRL + oft, val);
165 (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */
166 if ((val & F_PCS_RESET_) && adap->params.rev) {
171 memset(&mac->stats, 0, sizeof(mac->stats));
175 static int t3b2_mac_reset(struct cmac *mac)
178 adapter_t *adap = mac->adapter;
179 unsigned int oft = mac->offset;
180 int idx = macidx(mac);
183 /* Stop egress traffic to xgm*/
185 t3_set_reg_field(adap, A_MPS_CFG, F_PORT0ACTIVE, 0);
187 t3_set_reg_field(adap, A_MPS_CFG, F_PORT1ACTIVE, 0);
190 t3_write_reg(adap, A_XGM_RESET_CTRL + oft, F_MAC_RESET_);
191 (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */
193 /* Store A_TP_TX_DROP_CFG_CH0 */
194 t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
195 store = t3_read_reg(adap, A_TP_TX_DROP_CFG_CH0 + idx);
199 /* Change DROP_CFG to 0xc0000011 */
200 t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
201 t3_write_reg(adap, A_TP_PIO_DATA, 0xc0000011);
203 /* Check for xgm Rx fifo empty */
204 /* Increased loop count to 1000 from 5 cover 1G and 100Mbps case */
205 if (t3_wait_op_done(adap, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT + oft,
206 0x80000000, 1, 1000, 2)) {
207 CH_ERR(adap, "MAC %d Rx fifo drain failed\n",
212 t3_write_reg(adap, A_XGM_RESET_CTRL + oft, 0); /*MAC in reset*/
213 (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */
218 else if (uses_xaui(adap))
219 val |= F_PCS_RESET_ | F_XG2G_RESET_;
221 val |= F_RGMII_RESET_ | F_XG2G_RESET_;
222 t3_write_reg(adap, A_XGM_RESET_CTRL + oft, val);
223 (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */
224 if ((val & F_PCS_RESET_) && adap->params.rev) {
228 t3_write_reg(adap, A_XGM_RX_CFG + oft,
229 F_DISPAUSEFRAMES | F_EN1536BFRAMES |
230 F_RMFCS | F_ENJUMBO | F_ENHASHMCAST );
232 /* Restore the DROP_CFG */
233 t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
234 t3_write_reg(adap, A_TP_PIO_DATA, store);
236 /* Resume egress traffic to xgm */
238 t3_set_reg_field(adap, A_MPS_CFG, 0, F_PORT0ACTIVE);
240 t3_set_reg_field(adap, A_MPS_CFG, 0, F_PORT1ACTIVE);
246 * Set the exact match register 'idx' to recognize the given Ethernet address.
248 static void set_addr_filter(struct cmac *mac, int idx, const u8 *addr)
250 u32 addr_lo, addr_hi;
251 unsigned int oft = mac->offset + idx * 8;
253 addr_lo = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0];
254 addr_hi = (addr[5] << 8) | addr[4];
256 t3_write_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1 + oft, addr_lo);
257 t3_write_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_HIGH_1 + oft, addr_hi);
261 * t3_mac_set_address - set one of the station's unicast MAC addresses
262 * @mac: the MAC handle
263 * @idx: index of the exact address match filter to use
264 * @addr: the Ethernet address
266 * Set one of the station's unicast MAC addresses.
268 int t3_mac_set_address(struct cmac *mac, unsigned int idx, u8 addr[6])
271 idx = mac->ext_port + idx * mac->adapter->params.nports;
272 if (idx >= mac->nucast)
274 set_addr_filter(mac, idx, addr);
275 if (mac->multiport && idx < mac->adapter->params.nports)
276 t3_vsc7323_set_addr(mac->adapter, addr, idx);
281 * t3_mac_set_num_ucast - set the number of unicast addresses needed
282 * @mac: the MAC handle
283 * @n: number of unicast addresses needed
285 * Specify the number of exact address filters that should be reserved for
286 * unicast addresses. Caller should reload the unicast and multicast
287 * addresses after calling this.
289 * Generally, this is 1 with the first one used for the station address,
290 * and the rest are available for multicast addresses.
292 int t3_mac_set_num_ucast(struct cmac *mac, unsigned char n)
294 if (n > EXACT_ADDR_FILTERS)
300 static void disable_exact_filters(struct cmac *mac)
302 unsigned int i, reg = mac->offset + A_XGM_RX_EXACT_MATCH_LOW_1;
304 for (i = 0; i < EXACT_ADDR_FILTERS; i++, reg += 8) {
305 u32 v = t3_read_reg(mac->adapter, reg);
306 t3_write_reg(mac->adapter, reg, v);
308 t3_read_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1); /* flush */
311 static void enable_exact_filters(struct cmac *mac)
313 unsigned int i, reg = mac->offset + A_XGM_RX_EXACT_MATCH_HIGH_1;
315 for (i = 0; i < EXACT_ADDR_FILTERS; i++, reg += 8) {
316 u32 v = t3_read_reg(mac->adapter, reg);
317 t3_write_reg(mac->adapter, reg, v);
319 t3_read_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1); /* flush */
322 /* Calculate the RX hash filter index of an Ethernet address */
323 static int hash_hw_addr(const u8 *addr)
325 int hash = 0, octet, bit, i = 0, c;
327 for (octet = 0; octet < 6; ++octet)
328 for (c = addr[octet], bit = 0; bit < 8; c >>= 1, ++bit) {
329 hash ^= (c & 1) << i;
337 * t3_mac_set_rx_mode - set the Rx mode and address filters
338 * @mac: the MAC to configure
339 * @rm: structure containing the Rx mode and MAC addresses needed
341 * Configures the MAC Rx mode (promiscuity, etc) and exact and hash
344 int t3_mac_set_rx_mode(struct cmac *mac, struct t3_rx_mode *rm)
346 u32 hash_lo, hash_hi;
347 adapter_t *adap = mac->adapter;
348 unsigned int oft = mac->offset;
350 if (promisc_rx_mode(rm))
351 mac->promisc_map |= 1 << mac->ext_port;
353 mac->promisc_map &= ~(1 << mac->ext_port);
354 t3_set_reg_field(adap, A_XGM_RX_CFG + oft, F_COPYALLFRAMES,
355 mac->promisc_map ? F_COPYALLFRAMES : 0);
357 if (allmulti_rx_mode(rm) || mac->multiport)
358 hash_lo = hash_hi = 0xffffffff;
361 int exact_addr_idx = mac->nucast;
363 hash_lo = hash_hi = 0;
364 while ((addr = t3_get_next_mcaddr(rm)))
365 if (exact_addr_idx < EXACT_ADDR_FILTERS)
366 set_addr_filter(mac, exact_addr_idx++, addr);
368 int hash = hash_hw_addr(addr);
371 hash_lo |= (1 << hash);
373 hash_hi |= (1 << (hash - 32));
377 t3_write_reg(adap, A_XGM_RX_HASH_LOW + oft, hash_lo);
378 t3_write_reg(adap, A_XGM_RX_HASH_HIGH + oft, hash_hi);
382 static int rx_fifo_hwm(int mtu)
386 hwm = max(MAC_RXFIFO_SIZE - 3 * mtu, (MAC_RXFIFO_SIZE * 38) / 100);
387 return min(hwm, MAC_RXFIFO_SIZE - 8192);
391 * t3_mac_set_mtu - set the MAC MTU
392 * @mac: the MAC to configure
395 * Sets the MAC MTU and adjusts the FIFO PAUSE watermarks accordingly.
397 int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu)
399 int hwm, lwm, divisor;
401 unsigned int thres, v, reg;
402 adapter_t *adap = mac->adapter;
405 * MAX_FRAME_SIZE inludes header + FCS, mtu doesn't. The HW max
406 * packet size register includes header, but not FCS.
410 mtu += 8; /* for preamble */
411 if (mtu > MAX_FRAME_SIZE - 4)
414 return t3_vsc7323_set_mtu(adap, mtu - 4, mac->ext_port);
416 if (adap->params.rev >= T3_REV_B2 &&
417 (t3_read_reg(adap, A_XGM_RX_CTRL + mac->offset) & F_RXEN)) {
418 disable_exact_filters(mac);
419 v = t3_read_reg(adap, A_XGM_RX_CFG + mac->offset);
420 t3_set_reg_field(adap, A_XGM_RX_CFG + mac->offset,
421 F_ENHASHMCAST | F_COPYALLFRAMES, F_DISBCAST);
423 reg = adap->params.rev == T3_REV_B2 ?
424 A_XGM_RX_MAX_PKT_SIZE_ERR_CNT : A_XGM_RXFIFO_CFG;
427 if (t3_wait_op_done(adap, reg + mac->offset,
428 F_RXFIFO_EMPTY, 1, 20, 5)) {
429 t3_write_reg(adap, A_XGM_RX_CFG + mac->offset, v);
430 enable_exact_filters(mac);
433 t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset,
434 V_RXMAXPKTSIZE(M_RXMAXPKTSIZE),
435 V_RXMAXPKTSIZE(mtu));
436 t3_write_reg(adap, A_XGM_RX_CFG + mac->offset, v);
437 enable_exact_filters(mac);
439 t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset,
440 V_RXMAXPKTSIZE(M_RXMAXPKTSIZE),
441 V_RXMAXPKTSIZE(mtu));
443 * Adjust the PAUSE frame watermarks. We always set the LWM, and the
444 * HWM only if flow-control is enabled.
446 hwm = rx_fifo_hwm(mtu);
447 lwm = min(3 * (int) mtu, MAC_RXFIFO_SIZE /4);
448 v = t3_read_reg(adap, A_XGM_RXFIFO_CFG + mac->offset);
449 v &= ~V_RXFIFOPAUSELWM(M_RXFIFOPAUSELWM);
450 v |= V_RXFIFOPAUSELWM(lwm / 8);
451 if (G_RXFIFOPAUSEHWM(v))
452 v = (v & ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM)) |
453 V_RXFIFOPAUSEHWM(hwm / 8);
455 t3_write_reg(adap, A_XGM_RXFIFO_CFG + mac->offset, v);
457 /* Adjust the TX FIFO threshold based on the MTU */
458 thres = (adap->params.vpd.cclk * 1000) / 15625;
459 thres = (thres * mtu) / 1000;
462 thres = mtu > thres ? (mtu - thres + 7) / 8 : 0;
463 thres = max(thres, 8U); /* need at least 8 */
464 ipg = (adap->params.rev == T3_REV_C) ? 0 : 1;
465 t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + mac->offset,
466 V_TXFIFOTHRESH(M_TXFIFOTHRESH) | V_TXIPG(M_TXIPG),
467 V_TXFIFOTHRESH(thres) | V_TXIPG(ipg));
469 /* Assuming a minimum drain rate of 2.5Gbps...
471 if (adap->params.rev > 0) {
472 divisor = (adap->params.rev == T3_REV_C) ? 64 : 8;
473 t3_write_reg(adap, A_XGM_PAUSE_TIMER + mac->offset,
474 (hwm - lwm) * 4 / divisor);
476 t3_write_reg(adap, A_XGM_TX_PAUSE_QUANTA + mac->offset,
477 MAC_RXFIFO_SIZE * 4 * 8 / 512);
482 * t3_mac_set_speed_duplex_fc - set MAC speed, duplex and flow control
483 * @mac: the MAC to configure
484 * @speed: the desired speed (10/100/1000/10000)
485 * @duplex: the desired duplex
486 * @fc: desired Tx/Rx PAUSE configuration
488 * Set the MAC speed, duplex (actually only full-duplex is supported), and
489 * flow control. If a parameter value is negative the corresponding
490 * MAC setting is left at its current value.
492 int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc)
495 adapter_t *adap = mac->adapter;
496 unsigned int oft = mac->offset;
498 if (duplex >= 0 && duplex != DUPLEX_FULL)
500 if (mac->multiport) {
501 val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft);
502 val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM);
503 val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(t3_read_reg(adap,
504 A_XGM_RX_MAX_PKT_SIZE + oft)) / 8);
505 t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val);
507 t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN,
509 return t3_vsc7323_set_speed_fc(adap, speed, fc, mac->ext_port);
512 if (speed == SPEED_10)
513 val = V_PORTSPEED(0);
514 else if (speed == SPEED_100)
515 val = V_PORTSPEED(1);
516 else if (speed == SPEED_1000)
517 val = V_PORTSPEED(2);
518 else if (speed == SPEED_10000)
519 val = V_PORTSPEED(3);
523 t3_set_reg_field(adap, A_XGM_PORT_CFG + oft,
524 V_PORTSPEED(M_PORTSPEED), val);
527 val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft);
528 val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM);
530 val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(t3_read_reg(adap,
531 A_XGM_RX_MAX_PKT_SIZE + oft)) / 8);
532 t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val);
534 t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN,
535 (fc & PAUSE_RX) ? F_TXPAUSEEN : 0);
540 * t3_mac_enable - enable the MAC in the given directions
541 * @mac: the MAC to configure
542 * @which: bitmap indicating which directions to enable
544 * Enables the MAC for operation in the given directions.
545 * %MAC_DIRECTION_TX enables the Tx direction, and %MAC_DIRECTION_RX
546 * enables the Rx one.
548 int t3_mac_enable(struct cmac *mac, int which)
550 int idx = macidx(mac);
551 adapter_t *adap = mac->adapter;
552 unsigned int oft = mac->offset;
553 struct mac_stats *s = &mac->stats;
556 return t3_vsc7323_enable(adap, mac->ext_port, which);
558 if (which & MAC_DIRECTION_TX) {
559 t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
560 t3_write_reg(adap, A_TP_PIO_DATA,
561 adap->params.rev == T3_REV_C ?
562 0xc4ffff01 : 0xc0ede401);
563 t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_MODE);
564 t3_set_reg_field(adap, A_TP_PIO_DATA, 1 << idx,
565 adap->params.rev == T3_REV_C ?
568 t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN);
570 t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CNT_CH0 + idx);
571 mac->tx_mcnt = s->tx_frames;
572 mac->tx_tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap,
574 mac->tx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
575 A_XGM_TX_SPI4_SOP_EOP_CNT +
577 mac->rx_mcnt = s->rx_frames;
578 mac->rx_pause = s->rx_pause;
579 mac->rx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
580 A_XGM_RX_SPI4_SOP_EOP_CNT +
582 mac->rx_ocnt = s->rx_fifo_ovfl;
586 if (which & MAC_DIRECTION_RX)
587 t3_write_reg(adap, A_XGM_RX_CTRL + oft, F_RXEN);
592 * t3_mac_disable - disable the MAC in the given directions
593 * @mac: the MAC to configure
594 * @which: bitmap indicating which directions to disable
596 * Disables the MAC in the given directions.
597 * %MAC_DIRECTION_TX disables the Tx direction, and %MAC_DIRECTION_RX
598 * disables the Rx one.
600 int t3_mac_disable(struct cmac *mac, int which)
602 adapter_t *adap = mac->adapter;
605 return t3_vsc7323_disable(adap, mac->ext_port, which);
607 if (which & MAC_DIRECTION_TX) {
608 t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0);
611 if (which & MAC_DIRECTION_RX) {
612 int val = F_MAC_RESET_;
614 t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset,
617 t3_write_reg(adap, A_XGM_RX_CTRL + mac->offset, 0);
620 else if (uses_xaui(adap))
621 val |= F_PCS_RESET_ | F_XG2G_RESET_;
623 val |= F_RGMII_RESET_ | F_XG2G_RESET_;
624 t3_write_reg(mac->adapter, A_XGM_RESET_CTRL + mac->offset, val);
629 int t3b2_mac_watchdog_task(struct cmac *mac)
632 unsigned int tx_tcnt, tx_xcnt;
633 adapter_t *adap = mac->adapter;
634 struct mac_stats *s = &mac->stats;
635 unsigned int tx_mcnt = (unsigned int)s->tx_frames;
636 unsigned int rx_mcnt = (unsigned int)s->rx_frames;
637 unsigned int rx_xcnt;
639 if (mac->multiport) {
640 tx_mcnt = t3_read_reg(adap, A_XGM_STAT_TX_FRAME_LOW);
641 rx_mcnt = t3_read_reg(adap, A_XGM_STAT_RX_FRAMES_LOW);
643 tx_mcnt = (unsigned int)s->tx_frames;
644 rx_mcnt = (unsigned int)s->rx_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 rx_xcnt = 1; /* By default rx_xcnt is making progress*/
650 if (tx_mcnt == mac->tx_mcnt && mac->rx_pause == s->rx_pause) {
651 tx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
652 A_XGM_TX_SPI4_SOP_EOP_CNT +
655 t3_write_reg(adap, A_TP_PIO_ADDR,
656 A_TP_TX_DROP_CNT_CH0 + macidx(mac));
657 tx_tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap,
667 if ((tx_tcnt != mac->tx_tcnt) && (mac->tx_xcnt == 0)) {
668 if (mac->toggle_cnt > 4) {
681 if (rx_mcnt != mac->rx_mcnt) {
682 rx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
683 A_XGM_RX_SPI4_SOP_EOP_CNT +
685 (s->rx_fifo_ovfl - mac->rx_ocnt);
686 mac->rx_ocnt = s->rx_fifo_ovfl;
690 if (mac->rx_mcnt != s->rx_frames && rx_xcnt == 0 && mac->rx_xcnt == 0) {
697 mac->tx_tcnt = tx_tcnt;
698 mac->tx_xcnt = tx_xcnt;
699 mac->tx_mcnt = s->tx_frames;
700 mac->rx_xcnt = rx_xcnt;
701 mac->rx_mcnt = s->rx_frames;
702 mac->rx_pause = s->rx_pause;
704 t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0);
705 t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset); /* flush */
706 t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, mac->txen);
707 t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset); /* flush */
709 } else if (status == 2) {
717 * t3_mac_update_stats - accumulate MAC statistics
718 * @mac: the MAC handle
720 * This function is called periodically to accumulate the current values
721 * of the RMON counters into the port statistics. Since the packet
722 * counters are only 32 bits they can overflow in ~286 secs at 10G, so the
723 * function should be called more frequently than that. The byte counters
724 * are 45-bit wide, they would overflow in ~7.8 hours.
726 const struct mac_stats *t3_mac_update_stats(struct cmac *mac)
728 #define RMON_READ(mac, addr) t3_read_reg(mac->adapter, addr + mac->offset)
729 #define RMON_UPDATE(mac, name, reg) \
730 (mac)->stats.name += (u64)RMON_READ(mac, A_XGM_STAT_##reg)
731 #define RMON_UPDATE64(mac, name, reg_lo, reg_hi) \
732 (mac)->stats.name += RMON_READ(mac, A_XGM_STAT_##reg_lo) + \
733 ((u64)RMON_READ(mac, A_XGM_STAT_##reg_hi) << 32)
738 return t3_vsc7323_update_stats(mac);
740 RMON_UPDATE64(mac, rx_octets, RX_BYTES_LOW, RX_BYTES_HIGH);
741 RMON_UPDATE64(mac, rx_frames, RX_FRAMES_LOW, RX_FRAMES_HIGH);
742 RMON_UPDATE(mac, rx_mcast_frames, RX_MCAST_FRAMES);
743 RMON_UPDATE(mac, rx_bcast_frames, RX_BCAST_FRAMES);
744 RMON_UPDATE(mac, rx_fcs_errs, RX_CRC_ERR_FRAMES);
745 RMON_UPDATE(mac, rx_pause, RX_PAUSE_FRAMES);
746 RMON_UPDATE(mac, rx_jabber, RX_JABBER_FRAMES);
747 RMON_UPDATE(mac, rx_short, RX_SHORT_FRAMES);
748 RMON_UPDATE(mac, rx_symbol_errs, RX_SYM_CODE_ERR_FRAMES);
750 RMON_UPDATE(mac, rx_too_long, RX_OVERSIZE_FRAMES);
752 v = RMON_READ(mac, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT);
753 if (mac->adapter->params.rev == T3_REV_B2)
755 mac->stats.rx_too_long += v;
757 RMON_UPDATE(mac, rx_frames_64, RX_64B_FRAMES);
758 RMON_UPDATE(mac, rx_frames_65_127, RX_65_127B_FRAMES);
759 RMON_UPDATE(mac, rx_frames_128_255, RX_128_255B_FRAMES);
760 RMON_UPDATE(mac, rx_frames_256_511, RX_256_511B_FRAMES);
761 RMON_UPDATE(mac, rx_frames_512_1023, RX_512_1023B_FRAMES);
762 RMON_UPDATE(mac, rx_frames_1024_1518, RX_1024_1518B_FRAMES);
763 RMON_UPDATE(mac, rx_frames_1519_max, RX_1519_MAXB_FRAMES);
765 RMON_UPDATE64(mac, tx_octets, TX_BYTE_LOW, TX_BYTE_HIGH);
766 RMON_UPDATE64(mac, tx_frames, TX_FRAME_LOW, TX_FRAME_HIGH);
767 RMON_UPDATE(mac, tx_mcast_frames, TX_MCAST);
768 RMON_UPDATE(mac, tx_bcast_frames, TX_BCAST);
769 RMON_UPDATE(mac, tx_pause, TX_PAUSE);
770 /* This counts error frames in general (bad FCS, underrun, etc). */
771 RMON_UPDATE(mac, tx_underrun, TX_ERR_FRAMES);
773 RMON_UPDATE(mac, tx_frames_64, TX_64B_FRAMES);
774 RMON_UPDATE(mac, tx_frames_65_127, TX_65_127B_FRAMES);
775 RMON_UPDATE(mac, tx_frames_128_255, TX_128_255B_FRAMES);
776 RMON_UPDATE(mac, tx_frames_256_511, TX_256_511B_FRAMES);
777 RMON_UPDATE(mac, tx_frames_512_1023, TX_512_1023B_FRAMES);
778 RMON_UPDATE(mac, tx_frames_1024_1518, TX_1024_1518B_FRAMES);
779 RMON_UPDATE(mac, tx_frames_1519_max, TX_1519_MAXB_FRAMES);
781 /* The next stat isn't clear-on-read. */
782 t3_write_reg(mac->adapter, A_TP_MIB_INDEX, mac->offset ? 51 : 50);
783 v = t3_read_reg(mac->adapter, A_TP_MIB_RDATA);
784 lo = (u32)mac->stats.rx_cong_drops;
785 mac->stats.rx_cong_drops += (u64)(v - lo);