1 /**************************************************************************
3 Copyright (c) 2007-2009 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);
189 /* This will reduce the number of TXTOGGLES */
190 /* Clear: to stop the NIC traffic */
191 t3_set_reg_field(adap, A_MPS_CFG, F_ENFORCEPKT, 0);
192 /* Ensure TX drains */
193 t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN, 0);
196 t3_write_reg(adap, A_XGM_RESET_CTRL + oft, F_MAC_RESET_);
197 (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */
199 /* Store A_TP_TX_DROP_CFG_CH0 */
200 t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
201 store = t3_read_reg(adap, A_TP_TX_DROP_CFG_CH0 + idx);
205 /* Change DROP_CFG to 0xc0000011 */
206 t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
207 t3_write_reg(adap, A_TP_PIO_DATA, 0xc0000011);
209 /* Check for xgm Rx fifo empty */
210 /* Increased loop count to 1000 from 5 cover 1G and 100Mbps case */
211 if (t3_wait_op_done(adap, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT + oft,
212 0x80000000, 1, 1000, 2)) {
213 CH_ERR(adap, "MAC %d Rx fifo drain failed\n",
218 t3_write_reg(adap, A_XGM_RESET_CTRL + oft, 0); /*MAC in reset*/
219 (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */
224 else if (uses_xaui(adap))
225 val |= F_PCS_RESET_ | F_XG2G_RESET_;
227 val |= F_RGMII_RESET_ | F_XG2G_RESET_;
228 t3_write_reg(adap, A_XGM_RESET_CTRL + oft, val);
229 (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */
230 if ((val & F_PCS_RESET_) && adap->params.rev) {
234 t3_write_reg(adap, A_XGM_RX_CFG + oft,
235 F_DISPAUSEFRAMES | F_EN1536BFRAMES |
236 F_RMFCS | F_ENJUMBO | F_ENHASHMCAST );
238 /* Restore the DROP_CFG */
239 t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
240 t3_write_reg(adap, A_TP_PIO_DATA, store);
242 /* Resume egress traffic to xgm */
244 t3_set_reg_field(adap, A_MPS_CFG, 0, F_PORT0ACTIVE);
246 t3_set_reg_field(adap, A_MPS_CFG, 0, F_PORT1ACTIVE);
248 /* Set: re-enable NIC traffic */
249 t3_set_reg_field(adap, A_MPS_CFG, F_ENFORCEPKT, 1);
255 * Set the exact match register 'idx' to recognize the given Ethernet address.
257 static void set_addr_filter(struct cmac *mac, int idx, const u8 *addr)
259 u32 addr_lo, addr_hi;
260 unsigned int oft = mac->offset + idx * 8;
262 addr_lo = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0];
263 addr_hi = (addr[5] << 8) | addr[4];
265 t3_write_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1 + oft, addr_lo);
266 t3_write_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_HIGH_1 + oft, addr_hi);
270 * t3_mac_set_address - set one of the station's unicast MAC addresses
271 * @mac: the MAC handle
272 * @idx: index of the exact address match filter to use
273 * @addr: the Ethernet address
275 * Set one of the station's unicast MAC addresses.
277 int t3_mac_set_address(struct cmac *mac, unsigned int idx, u8 addr[6])
280 idx = mac->ext_port + idx * mac->adapter->params.nports;
281 if (idx >= mac->nucast)
283 set_addr_filter(mac, idx, addr);
284 if (mac->multiport && idx < mac->adapter->params.nports)
285 t3_vsc7323_set_addr(mac->adapter, addr, idx);
290 * t3_mac_set_num_ucast - set the number of unicast addresses needed
291 * @mac: the MAC handle
292 * @n: number of unicast addresses needed
294 * Specify the number of exact address filters that should be reserved for
295 * unicast addresses. Caller should reload the unicast and multicast
296 * addresses after calling this.
298 * Generally, this is 1 with the first one used for the station address,
299 * and the rest are available for multicast addresses.
301 int t3_mac_set_num_ucast(struct cmac *mac, unsigned char n)
303 if (n > EXACT_ADDR_FILTERS)
309 void t3_mac_disable_exact_filters(struct cmac *mac)
311 unsigned int i, reg = mac->offset + A_XGM_RX_EXACT_MATCH_LOW_1;
313 for (i = 0; i < EXACT_ADDR_FILTERS; i++, reg += 8) {
314 u32 v = t3_read_reg(mac->adapter, reg);
315 t3_write_reg(mac->adapter, reg, v);
317 t3_read_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1); /* flush */
320 void t3_mac_enable_exact_filters(struct cmac *mac)
322 unsigned int i, reg = mac->offset + A_XGM_RX_EXACT_MATCH_HIGH_1;
324 for (i = 0; i < EXACT_ADDR_FILTERS; i++, reg += 8) {
325 u32 v = t3_read_reg(mac->adapter, reg);
326 t3_write_reg(mac->adapter, reg, v);
328 t3_read_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1); /* flush */
331 /* Calculate the RX hash filter index of an Ethernet address */
332 static int hash_hw_addr(const u8 *addr)
334 int hash = 0, octet, bit, i = 0, c;
336 for (octet = 0; octet < 6; ++octet)
337 for (c = addr[octet], bit = 0; bit < 8; c >>= 1, ++bit) {
338 hash ^= (c & 1) << i;
346 * t3_mac_set_rx_mode - set the Rx mode and address filters
347 * @mac: the MAC to configure
348 * @rm: structure containing the Rx mode and MAC addresses needed
350 * Configures the MAC Rx mode (promiscuity, etc) and exact and hash
353 int t3_mac_set_rx_mode(struct cmac *mac, struct t3_rx_mode *rm)
355 u32 hash_lo, hash_hi;
356 adapter_t *adap = mac->adapter;
357 unsigned int oft = mac->offset;
359 if (promisc_rx_mode(rm))
360 mac->promisc_map |= 1 << mac->ext_port;
362 mac->promisc_map &= ~(1 << mac->ext_port);
363 t3_set_reg_field(adap, A_XGM_RX_CFG + oft, F_COPYALLFRAMES,
364 mac->promisc_map ? F_COPYALLFRAMES : 0);
366 if (allmulti_rx_mode(rm) || mac->multiport)
367 hash_lo = hash_hi = 0xffffffff;
370 int exact_addr_idx = mac->nucast;
372 hash_lo = hash_hi = 0;
373 while ((addr = t3_get_next_mcaddr(rm)))
374 if (exact_addr_idx < EXACT_ADDR_FILTERS)
375 set_addr_filter(mac, exact_addr_idx++, addr);
377 int hash = hash_hw_addr(addr);
380 hash_lo |= (1 << hash);
382 hash_hi |= (1 << (hash - 32));
386 t3_write_reg(adap, A_XGM_RX_HASH_LOW + oft, hash_lo);
387 t3_write_reg(adap, A_XGM_RX_HASH_HIGH + oft, hash_hi);
391 static int rx_fifo_hwm(int mtu)
395 hwm = max(MAC_RXFIFO_SIZE - 3 * mtu, (MAC_RXFIFO_SIZE * 38) / 100);
396 return min(hwm, MAC_RXFIFO_SIZE - 8192);
400 * t3_mac_set_mtu - set the MAC MTU
401 * @mac: the MAC to configure
404 * Sets the MAC MTU and adjusts the FIFO PAUSE watermarks accordingly.
406 int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu)
408 int hwm, lwm, divisor;
410 unsigned int thres, v, reg;
411 adapter_t *adap = mac->adapter;
414 * MAX_FRAME_SIZE inludes header + FCS, mtu doesn't. The HW max
415 * packet size register includes header, but not FCS.
419 mtu += 8; /* for preamble */
420 if (mtu > MAX_FRAME_SIZE - 4)
423 return t3_vsc7323_set_mtu(adap, mtu - 4, mac->ext_port);
425 if (adap->params.rev >= T3_REV_B2 &&
426 (t3_read_reg(adap, A_XGM_RX_CTRL + mac->offset) & F_RXEN)) {
427 t3_mac_disable_exact_filters(mac);
428 v = t3_read_reg(adap, A_XGM_RX_CFG + mac->offset);
429 t3_set_reg_field(adap, A_XGM_RX_CFG + mac->offset,
430 F_ENHASHMCAST | F_COPYALLFRAMES, F_DISBCAST);
432 reg = adap->params.rev == T3_REV_B2 ?
433 A_XGM_RX_MAX_PKT_SIZE_ERR_CNT : A_XGM_RXFIFO_CFG;
436 if (t3_wait_op_done(adap, reg + mac->offset,
437 F_RXFIFO_EMPTY, 1, 20, 5)) {
438 t3_write_reg(adap, A_XGM_RX_CFG + mac->offset, v);
439 t3_mac_enable_exact_filters(mac);
442 t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset,
443 V_RXMAXPKTSIZE(M_RXMAXPKTSIZE),
444 V_RXMAXPKTSIZE(mtu));
445 t3_write_reg(adap, A_XGM_RX_CFG + mac->offset, v);
446 t3_mac_enable_exact_filters(mac);
448 t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset,
449 V_RXMAXPKTSIZE(M_RXMAXPKTSIZE),
450 V_RXMAXPKTSIZE(mtu));
452 * Adjust the PAUSE frame watermarks. We always set the LWM, and the
453 * HWM only if flow-control is enabled.
455 hwm = rx_fifo_hwm(mtu);
456 lwm = min(3 * (int) mtu, MAC_RXFIFO_SIZE /4);
457 v = t3_read_reg(adap, A_XGM_RXFIFO_CFG + mac->offset);
458 v &= ~V_RXFIFOPAUSELWM(M_RXFIFOPAUSELWM);
459 v |= V_RXFIFOPAUSELWM(lwm / 8);
460 if (G_RXFIFOPAUSEHWM(v))
461 v = (v & ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM)) |
462 V_RXFIFOPAUSEHWM(hwm / 8);
464 t3_write_reg(adap, A_XGM_RXFIFO_CFG + mac->offset, v);
466 /* Adjust the TX FIFO threshold based on the MTU */
467 thres = (adap->params.vpd.cclk * 1000) / 15625;
468 thres = (thres * mtu) / 1000;
471 thres = mtu > thres ? (mtu - thres + 7) / 8 : 0;
472 thres = max(thres, 8U); /* need at least 8 */
473 ipg = (adap->params.rev == T3_REV_C) ? 0 : 1;
474 t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + mac->offset,
475 V_TXFIFOTHRESH(M_TXFIFOTHRESH) | V_TXIPG(M_TXIPG),
476 V_TXFIFOTHRESH(thres) | V_TXIPG(ipg));
478 /* Assuming a minimum drain rate of 2.5Gbps...
480 if (adap->params.rev > 0) {
481 divisor = (adap->params.rev == T3_REV_C) ? 64 : 8;
482 t3_write_reg(adap, A_XGM_PAUSE_TIMER + mac->offset,
483 (hwm - lwm) * 4 / divisor);
485 t3_write_reg(adap, A_XGM_TX_PAUSE_QUANTA + mac->offset,
486 MAC_RXFIFO_SIZE * 4 * 8 / 512);
491 * t3_mac_set_speed_duplex_fc - set MAC speed, duplex and flow control
492 * @mac: the MAC to configure
493 * @speed: the desired speed (10/100/1000/10000)
494 * @duplex: the desired duplex
495 * @fc: desired Tx/Rx PAUSE configuration
497 * Set the MAC speed, duplex (actually only full-duplex is supported), and
498 * flow control. If a parameter value is negative the corresponding
499 * MAC setting is left at its current value.
501 int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc)
504 adapter_t *adap = mac->adapter;
505 unsigned int oft = mac->offset;
507 if (duplex >= 0 && duplex != DUPLEX_FULL)
509 if (mac->multiport) {
510 val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft);
511 val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM);
512 val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(t3_read_reg(adap,
513 A_XGM_RX_MAX_PKT_SIZE + oft)) / 8);
514 t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val);
516 t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN,
518 return t3_vsc7323_set_speed_fc(adap, speed, fc, mac->ext_port);
521 if (speed == SPEED_10)
522 val = V_PORTSPEED(0);
523 else if (speed == SPEED_100)
524 val = V_PORTSPEED(1);
525 else if (speed == SPEED_1000)
526 val = V_PORTSPEED(2);
527 else if (speed == SPEED_10000)
528 val = V_PORTSPEED(3);
532 t3_set_reg_field(adap, A_XGM_PORT_CFG + oft,
533 V_PORTSPEED(M_PORTSPEED), val);
536 val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft);
537 val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM);
539 val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(t3_read_reg(adap,
540 A_XGM_RX_MAX_PKT_SIZE + oft)) / 8);
541 t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val);
543 t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN,
544 (fc & PAUSE_RX) ? F_TXPAUSEEN : 0);
549 * t3_mac_enable - enable the MAC in the given directions
550 * @mac: the MAC to configure
551 * @which: bitmap indicating which directions to enable
553 * Enables the MAC for operation in the given directions.
554 * %MAC_DIRECTION_TX enables the Tx direction, and %MAC_DIRECTION_RX
555 * enables the Rx one.
557 int t3_mac_enable(struct cmac *mac, int which)
559 int idx = macidx(mac);
560 adapter_t *adap = mac->adapter;
561 unsigned int oft = mac->offset;
562 struct mac_stats *s = &mac->stats;
565 return t3_vsc7323_enable(adap, mac->ext_port, which);
567 if (which & MAC_DIRECTION_TX) {
568 t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
569 t3_write_reg(adap, A_TP_PIO_DATA,
570 adap->params.rev == T3_REV_C ?
571 0xc4ffff01 : 0xc0ede401);
572 t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_MODE);
573 t3_set_reg_field(adap, A_TP_PIO_DATA, 1 << idx,
574 adap->params.rev == T3_REV_C ?
577 t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN);
579 t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CNT_CH0 + idx);
580 mac->tx_mcnt = s->tx_frames;
581 mac->tx_tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap,
583 mac->tx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
584 A_XGM_TX_SPI4_SOP_EOP_CNT +
586 mac->rx_mcnt = s->rx_frames;
587 mac->rx_pause = s->rx_pause;
588 mac->rx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
589 A_XGM_RX_SPI4_SOP_EOP_CNT +
591 mac->rx_ocnt = s->rx_fifo_ovfl;
595 if (which & MAC_DIRECTION_RX)
596 t3_write_reg(adap, A_XGM_RX_CTRL + oft, F_RXEN);
601 * t3_mac_disable - disable the MAC in the given directions
602 * @mac: the MAC to configure
603 * @which: bitmap indicating which directions to disable
605 * Disables the MAC in the given directions.
606 * %MAC_DIRECTION_TX disables the Tx direction, and %MAC_DIRECTION_RX
607 * disables the Rx one.
609 int t3_mac_disable(struct cmac *mac, int which)
611 adapter_t *adap = mac->adapter;
614 return t3_vsc7323_disable(adap, mac->ext_port, which);
616 if (which & MAC_DIRECTION_TX) {
617 t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0);
620 if (which & MAC_DIRECTION_RX) {
621 int val = F_MAC_RESET_;
623 t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset,
626 t3_write_reg(adap, A_XGM_RX_CTRL + mac->offset, 0);
629 else if (uses_xaui(adap))
630 val |= F_PCS_RESET_ | F_XG2G_RESET_;
632 val |= F_RGMII_RESET_ | F_XG2G_RESET_;
633 t3_write_reg(mac->adapter, A_XGM_RESET_CTRL + mac->offset, val);
638 int t3b2_mac_watchdog_task(struct cmac *mac)
641 unsigned int tx_tcnt, tx_xcnt;
642 adapter_t *adap = mac->adapter;
643 struct mac_stats *s = &mac->stats;
644 u64 tx_mcnt = s->tx_frames;
647 tx_mcnt = t3_read_reg(adap, A_XGM_STAT_TX_FRAME_LOW);
650 tx_xcnt = 1; /* By default tx_xcnt is making progress*/
651 tx_tcnt = mac->tx_tcnt; /* If tx_mcnt is progressing ignore tx_tcnt*/
652 if (tx_mcnt == mac->tx_mcnt && mac->rx_pause == s->rx_pause) {
653 tx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
654 A_XGM_TX_SPI4_SOP_EOP_CNT +
657 t3_write_reg(adap, A_TP_PIO_ADDR,
658 A_TP_TX_DROP_CNT_CH0 + macidx(mac));
659 tx_tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap,
669 if ((tx_tcnt != mac->tx_tcnt) && (mac->tx_xcnt == 0)) {
670 if (mac->toggle_cnt > 4) {
683 mac->tx_tcnt = tx_tcnt;
684 mac->tx_xcnt = tx_xcnt;
685 mac->tx_mcnt = s->tx_frames;
686 mac->rx_pause = s->rx_pause;
688 t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0);
689 t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset); /* flush */
690 t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, mac->txen);
691 t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset); /* flush */
693 } else if (status == 2) {
701 * t3_mac_update_stats - accumulate MAC statistics
702 * @mac: the MAC handle
704 * This function is called periodically to accumulate the current values
705 * of the RMON counters into the port statistics. Since the packet
706 * counters are only 32 bits they can overflow in ~286 secs at 10G, so the
707 * function should be called more frequently than that. The byte counters
708 * are 45-bit wide, they would overflow in ~7.8 hours.
710 const struct mac_stats *t3_mac_update_stats(struct cmac *mac)
712 #define RMON_READ(mac, addr) t3_read_reg(mac->adapter, addr + mac->offset)
713 #define RMON_UPDATE(mac, name, reg) \
714 (mac)->stats.name += (u64)RMON_READ(mac, A_XGM_STAT_##reg)
715 #define RMON_UPDATE64(mac, name, reg_lo, reg_hi) \
716 (mac)->stats.name += RMON_READ(mac, A_XGM_STAT_##reg_lo) + \
717 ((u64)RMON_READ(mac, A_XGM_STAT_##reg_hi) << 32)
722 return t3_vsc7323_update_stats(mac);
724 RMON_UPDATE64(mac, rx_octets, RX_BYTES_LOW, RX_BYTES_HIGH);
725 RMON_UPDATE64(mac, rx_frames, RX_FRAMES_LOW, RX_FRAMES_HIGH);
726 RMON_UPDATE(mac, rx_mcast_frames, RX_MCAST_FRAMES);
727 RMON_UPDATE(mac, rx_bcast_frames, RX_BCAST_FRAMES);
728 RMON_UPDATE(mac, rx_fcs_errs, RX_CRC_ERR_FRAMES);
729 RMON_UPDATE(mac, rx_pause, RX_PAUSE_FRAMES);
730 RMON_UPDATE(mac, rx_jabber, RX_JABBER_FRAMES);
731 RMON_UPDATE(mac, rx_short, RX_SHORT_FRAMES);
732 RMON_UPDATE(mac, rx_symbol_errs, RX_SYM_CODE_ERR_FRAMES);
734 RMON_UPDATE(mac, rx_too_long, RX_OVERSIZE_FRAMES);
736 v = RMON_READ(mac, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT);
737 if (mac->adapter->params.rev == T3_REV_B2)
739 mac->stats.rx_too_long += v;
741 RMON_UPDATE(mac, rx_frames_64, RX_64B_FRAMES);
742 RMON_UPDATE(mac, rx_frames_65_127, RX_65_127B_FRAMES);
743 RMON_UPDATE(mac, rx_frames_128_255, RX_128_255B_FRAMES);
744 RMON_UPDATE(mac, rx_frames_256_511, RX_256_511B_FRAMES);
745 RMON_UPDATE(mac, rx_frames_512_1023, RX_512_1023B_FRAMES);
746 RMON_UPDATE(mac, rx_frames_1024_1518, RX_1024_1518B_FRAMES);
747 RMON_UPDATE(mac, rx_frames_1519_max, RX_1519_MAXB_FRAMES);
749 RMON_UPDATE64(mac, tx_octets, TX_BYTE_LOW, TX_BYTE_HIGH);
750 RMON_UPDATE64(mac, tx_frames, TX_FRAME_LOW, TX_FRAME_HIGH);
751 RMON_UPDATE(mac, tx_mcast_frames, TX_MCAST);
752 RMON_UPDATE(mac, tx_bcast_frames, TX_BCAST);
753 RMON_UPDATE(mac, tx_pause, TX_PAUSE);
754 /* This counts error frames in general (bad FCS, underrun, etc). */
755 RMON_UPDATE(mac, tx_underrun, TX_ERR_FRAMES);
757 RMON_UPDATE(mac, tx_frames_64, TX_64B_FRAMES);
758 RMON_UPDATE(mac, tx_frames_65_127, TX_65_127B_FRAMES);
759 RMON_UPDATE(mac, tx_frames_128_255, TX_128_255B_FRAMES);
760 RMON_UPDATE(mac, tx_frames_256_511, TX_256_511B_FRAMES);
761 RMON_UPDATE(mac, tx_frames_512_1023, TX_512_1023B_FRAMES);
762 RMON_UPDATE(mac, tx_frames_1024_1518, TX_1024_1518B_FRAMES);
763 RMON_UPDATE(mac, tx_frames_1519_max, TX_1519_MAXB_FRAMES);
765 /* The next stat isn't clear-on-read. */
766 t3_write_reg(mac->adapter, A_TP_MIB_INDEX, mac->offset ? 51 : 50);
767 v = t3_read_reg(mac->adapter, A_TP_MIB_RDATA);
768 lo = (u32)mac->stats.rx_cong_drops;
769 mac->stats.rx_cong_drops += (u64)(v - lo);