2 /**************************************************************************
4 Copyright (c) 2007, Chelsio Inc.
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
10 1. Redistributions of source code must retain the above copyright notice,
11 this list of conditions and the following disclaimer.
13 2. Neither the name of the Chelsio Corporation nor the names of its
14 contributors may be used to endorse or promote products derived from
15 this software without specific prior written permission.
17 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 POSSIBILITY OF SUCH DAMAGE.
29 ***************************************************************************/
31 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: cxgb_xgmac.c,v 1.2 2007/12/11 11:25:50 lukem Exp $");
36 __FBSDID("$FreeBSD: src/sys/dev/cxgb/common/cxgb_xgmac.c,v 1.7 2007/09/09 01:28:03 kmacy Exp $");
40 #include <cxgb_include.h>
43 #include <dev/cxgb/cxgb_include.h>
46 #include "cxgb_include.h"
51 #define msleep t3_os_sleep
54 * # of exact address filters. The first one is used for the station address,
55 * the rest are available for multicast addresses.
57 #define EXACT_ADDR_FILTERS 8
59 static inline int macidx(const struct cmac
*mac
)
61 return mac
->offset
/ (XGMAC0_1_BASE_ADDR
- XGMAC0_0_BASE_ADDR
);
64 static void xaui_serdes_reset(struct cmac
*mac
)
66 static const unsigned int clear
[] = {
67 F_PWRDN0
| F_PWRDN1
, F_RESETPLL01
, F_RESET0
| F_RESET1
,
68 F_PWRDN2
| F_PWRDN3
, F_RESETPLL23
, F_RESET2
| F_RESET3
72 adapter_t
*adap
= mac
->adapter
;
73 u32 ctrl
= A_XGM_SERDES_CTRL0
+ mac
->offset
;
75 t3_write_reg(adap
, ctrl
, adap
->params
.vpd
.xauicfg
[macidx(mac
)] |
76 F_RESET3
| F_RESET2
| F_RESET1
| F_RESET0
|
77 F_PWRDN3
| F_PWRDN2
| F_PWRDN1
| F_PWRDN0
|
78 F_RESETPLL23
| F_RESETPLL01
);
79 (void)t3_read_reg(adap
, ctrl
);
82 for (i
= 0; i
< ARRAY_SIZE(clear
); i
++) {
83 t3_set_reg_field(adap
, ctrl
, clear
[i
], 0);
88 void t3b_pcs_reset(struct cmac
*mac
)
90 t3_set_reg_field(mac
->adapter
, A_XGM_RESET_CTRL
+ mac
->offset
,
93 t3_set_reg_field(mac
->adapter
, A_XGM_RESET_CTRL
+ mac
->offset
, 0,
97 int t3_mac_reset(struct cmac
*mac
)
99 static struct addr_val_pair mac_reset_avp
[] = {
100 { A_XGM_TX_CTRL
, 0 },
101 { A_XGM_RX_CTRL
, 0 },
102 { A_XGM_RX_CFG
, F_DISPAUSEFRAMES
| F_EN1536BFRAMES
|
103 F_RMFCS
| F_ENJUMBO
| F_ENHASHMCAST
},
104 { A_XGM_RX_HASH_LOW
, 0 },
105 { A_XGM_RX_HASH_HIGH
, 0 },
106 { A_XGM_RX_EXACT_MATCH_LOW_1
, 0 },
107 { A_XGM_RX_EXACT_MATCH_LOW_2
, 0 },
108 { A_XGM_RX_EXACT_MATCH_LOW_3
, 0 },
109 { A_XGM_RX_EXACT_MATCH_LOW_4
, 0 },
110 { A_XGM_RX_EXACT_MATCH_LOW_5
, 0 },
111 { A_XGM_RX_EXACT_MATCH_LOW_6
, 0 },
112 { A_XGM_RX_EXACT_MATCH_LOW_7
, 0 },
113 { A_XGM_RX_EXACT_MATCH_LOW_8
, 0 },
114 { A_XGM_STAT_CTRL
, F_CLRSTATS
}
117 adapter_t
*adap
= mac
->adapter
;
118 unsigned int oft
= mac
->offset
;
120 t3_write_reg(adap
, A_XGM_RESET_CTRL
+ oft
, F_MAC_RESET_
);
121 (void) t3_read_reg(adap
, A_XGM_RESET_CTRL
+ oft
); /* flush */
123 t3_write_regs(adap
, mac_reset_avp
, ARRAY_SIZE(mac_reset_avp
), oft
);
124 t3_set_reg_field(adap
, A_XGM_RXFIFO_CFG
+ oft
,
125 F_RXSTRFRWRD
| F_DISERRFRAMES
,
126 uses_xaui(adap
) ? 0 : F_RXSTRFRWRD
);
128 if (uses_xaui(adap
)) {
129 if (adap
->params
.rev
== 0) {
130 t3_set_reg_field(adap
, A_XGM_SERDES_CTRL
+ oft
, 0,
131 F_RXENABLE
| F_TXENABLE
);
132 if (t3_wait_op_done(adap
, A_XGM_SERDES_STATUS1
+ oft
,
133 F_CMULOCK
, 1, 5, 2)) {
135 "MAC %d XAUI SERDES CMU lock failed\n",
139 t3_set_reg_field(adap
, A_XGM_SERDES_CTRL
+ oft
, 0,
142 xaui_serdes_reset(mac
);
146 if (mac
->multiport
) {
147 t3_write_reg(adap
, A_XGM_RX_MAX_PKT_SIZE
+ oft
,
149 t3_set_reg_field(adap
, A_XGM_TXFIFO_CFG
+ oft
, 0,
151 t3_set_reg_field(adap
, A_XGM_RX_CFG
+ oft
, 0, F_COPYPREAMBLE
|
152 F_ENNON802_3PREAMBLE
);
153 t3_set_reg_field(adap
, A_XGM_TXFIFO_CFG
+ oft
,
154 V_TXFIFOTHRESH(M_TXFIFOTHRESH
),
156 t3_write_reg(adap
, A_XGM_TX_CTRL
+ oft
, F_TXEN
);
157 t3_write_reg(adap
, A_XGM_RX_CTRL
+ oft
, F_RXEN
);
161 if (is_10G(adap
) || mac
->multiport
)
163 else if (uses_xaui(adap
))
164 val
|= F_PCS_RESET_
| F_XG2G_RESET_
;
166 val
|= F_RGMII_RESET_
| F_XG2G_RESET_
;
167 t3_write_reg(adap
, A_XGM_RESET_CTRL
+ oft
, val
);
168 (void) t3_read_reg(adap
, A_XGM_RESET_CTRL
+ oft
); /* flush */
169 if ((val
& F_PCS_RESET_
) && adap
->params
.rev
) {
174 memset(&mac
->stats
, 0, sizeof(mac
->stats
));
178 static int t3b2_mac_reset(struct cmac
*mac
)
181 adapter_t
*adap
= mac
->adapter
;
182 unsigned int oft
= mac
->offset
;
185 /* Stop egress traffic to xgm*/
187 t3_set_reg_field(adap
, A_MPS_CFG
, F_PORT0ACTIVE
, 0);
189 t3_set_reg_field(adap
, A_MPS_CFG
, F_PORT1ACTIVE
, 0);
192 t3_write_reg(adap
, A_XGM_RESET_CTRL
+ oft
, F_MAC_RESET_
);
193 (void) t3_read_reg(adap
, A_XGM_RESET_CTRL
+ oft
); /* flush */
197 /* Check for xgm Rx fifo empty */
198 if (t3_wait_op_done(adap
, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT
+ oft
,
199 0x80000000, 1, 5, 2)) {
200 CH_ERR(adap
, "MAC %d Rx fifo drain failed\n",
205 t3_write_reg(adap
, A_XGM_RESET_CTRL
+ oft
, 0); /*MAC in reset*/
206 (void) t3_read_reg(adap
, A_XGM_RESET_CTRL
+ oft
); /* flush */
211 else if (uses_xaui(adap
))
212 val
|= F_PCS_RESET_
| F_XG2G_RESET_
;
214 val
|= F_RGMII_RESET_
| F_XG2G_RESET_
;
215 t3_write_reg(adap
, A_XGM_RESET_CTRL
+ oft
, val
);
216 (void) t3_read_reg(adap
, A_XGM_RESET_CTRL
+ oft
); /* flush */
217 if ((val
& F_PCS_RESET_
) && adap
->params
.rev
) {
221 t3_write_reg(adap
, A_XGM_RX_CFG
+ oft
,
222 F_DISPAUSEFRAMES
| F_EN1536BFRAMES
|
223 F_RMFCS
| F_ENJUMBO
| F_ENHASHMCAST
);
225 /*Resume egress traffic to xgm*/
227 t3_set_reg_field(adap
, A_MPS_CFG
, 0, F_PORT0ACTIVE
);
229 t3_set_reg_field(adap
, A_MPS_CFG
, 0, F_PORT1ACTIVE
);
235 * Set the exact match register 'idx' to recognize the given Ethernet address.
237 static void set_addr_filter(struct cmac
*mac
, int idx
, const u8
*addr
)
239 u32 addr_lo
, addr_hi
;
240 unsigned int oft
= mac
->offset
+ idx
* 8;
242 addr_lo
= (addr
[3] << 24) | (addr
[2] << 16) | (addr
[1] << 8) | addr
[0];
243 addr_hi
= (addr
[5] << 8) | addr
[4];
245 t3_write_reg(mac
->adapter
, A_XGM_RX_EXACT_MATCH_LOW_1
+ oft
, addr_lo
);
246 t3_write_reg(mac
->adapter
, A_XGM_RX_EXACT_MATCH_HIGH_1
+ oft
, addr_hi
);
249 /* Set one of the station's unicast MAC addresses. */
250 int t3_mac_set_address(struct cmac
*mac
, unsigned int idx
, u8 addr
[6])
253 idx
= mac
->ext_port
+ idx
* mac
->adapter
->params
.nports
;
254 if (idx
>= mac
->nucast
)
256 set_addr_filter(mac
, idx
, addr
);
257 if (mac
->multiport
&& idx
< mac
->adapter
->params
.nports
)
258 t3_vsc7323_set_addr(mac
->adapter
, addr
, idx
);
263 * Specify the number of exact address filters that should be reserved for
264 * unicast addresses. Caller should reload the unicast and multicast addresses
265 * after calling this.
267 int t3_mac_set_num_ucast(struct cmac
*mac
, unsigned char n
)
269 if (n
> EXACT_ADDR_FILTERS
)
275 static void disable_exact_filters(struct cmac
*mac
)
277 unsigned int i
, reg
= mac
->offset
+ A_XGM_RX_EXACT_MATCH_LOW_1
;
279 for (i
= 0; i
< EXACT_ADDR_FILTERS
; i
++, reg
+= 8) {
280 u32 v
= t3_read_reg(mac
->adapter
, reg
);
281 t3_write_reg(mac
->adapter
, reg
, v
);
283 t3_read_reg(mac
->adapter
, A_XGM_RX_EXACT_MATCH_LOW_1
); /* flush */
286 static void enable_exact_filters(struct cmac
*mac
)
288 unsigned int i
, reg
= mac
->offset
+ A_XGM_RX_EXACT_MATCH_HIGH_1
;
290 for (i
= 0; i
< EXACT_ADDR_FILTERS
; i
++, reg
+= 8) {
291 u32 v
= t3_read_reg(mac
->adapter
, reg
);
292 t3_write_reg(mac
->adapter
, reg
, v
);
294 t3_read_reg(mac
->adapter
, A_XGM_RX_EXACT_MATCH_LOW_1
); /* flush */
297 /* Calculate the RX hash filter index of an Ethernet address */
298 static int hash_hw_addr(const u8
*addr
)
300 int hash
= 0, octet
, bit
, i
= 0, c
;
302 for (octet
= 0; octet
< 6; ++octet
)
303 for (c
= addr
[octet
], bit
= 0; bit
< 8; c
>>= 1, ++bit
) {
304 hash
^= (c
& 1) << i
;
311 int t3_mac_set_rx_mode(struct cmac
*mac
, struct t3_rx_mode
*rm
)
313 u32 hash_lo
, hash_hi
;
314 adapter_t
*adap
= mac
->adapter
;
315 unsigned int oft
= mac
->offset
;
317 if (promisc_rx_mode(rm
))
318 mac
->promisc_map
|= 1 << mac
->ext_port
;
320 mac
->promisc_map
&= ~(1 << mac
->ext_port
);
321 t3_set_reg_field(adap
, A_XGM_RX_CFG
+ oft
, F_COPYALLFRAMES
,
322 mac
->promisc_map
? F_COPYALLFRAMES
: 0);
324 if (allmulti_rx_mode(rm
) || mac
->multiport
)
325 hash_lo
= hash_hi
= 0xffffffff;
328 int exact_addr_idx
= mac
->nucast
;
330 hash_lo
= hash_hi
= 0;
331 while ((addr
= t3_get_next_mcaddr(rm
)))
332 if (exact_addr_idx
< EXACT_ADDR_FILTERS
)
333 set_addr_filter(mac
, exact_addr_idx
++, addr
);
335 int hash
= hash_hw_addr(addr
);
338 hash_lo
|= (1 << hash
);
340 hash_hi
|= (1 << (hash
- 32));
344 t3_write_reg(adap
, A_XGM_RX_HASH_LOW
+ oft
, hash_lo
);
345 t3_write_reg(adap
, A_XGM_RX_HASH_HIGH
+ oft
, hash_hi
);
349 static int rx_fifo_hwm(int mtu
)
353 hwm
= max(MAC_RXFIFO_SIZE
- 3 * mtu
, (MAC_RXFIFO_SIZE
* 38) / 100);
354 return min(hwm
, MAC_RXFIFO_SIZE
- 8192);
357 int t3_mac_set_mtu(struct cmac
*mac
, unsigned int mtu
)
360 unsigned int thres
, v
;
361 adapter_t
*adap
= mac
->adapter
;
364 * MAX_FRAME_SIZE inludes header + FCS, mtu doesn't. The HW max
365 * packet size register includes header, but not FCS.
369 mtu
+= 8; /* for preamble */
370 if (mtu
> MAX_FRAME_SIZE
- 4)
373 return t3_vsc7323_set_mtu(adap
, mtu
- 4, mac
->ext_port
);
375 if (adap
->params
.rev
== T3_REV_B2
&&
376 (t3_read_reg(adap
, A_XGM_RX_CTRL
+ mac
->offset
) & F_RXEN
)) {
377 disable_exact_filters(mac
);
378 v
= t3_read_reg(adap
, A_XGM_RX_CFG
+ mac
->offset
);
379 t3_set_reg_field(adap
, A_XGM_RX_CFG
+ mac
->offset
,
380 F_ENHASHMCAST
| F_COPYALLFRAMES
, F_DISBCAST
);
383 if (t3_wait_op_done(adap
,
384 A_XGM_RX_MAX_PKT_SIZE_ERR_CNT
+ mac
->offset
,
385 1 << 31, 1, 20, 5)) {
386 t3_write_reg(adap
, A_XGM_RX_CFG
+ mac
->offset
, v
);
387 enable_exact_filters(mac
);
390 t3_write_reg(adap
, A_XGM_RX_MAX_PKT_SIZE
+ mac
->offset
, mtu
);
391 t3_write_reg(adap
, A_XGM_RX_CFG
+ mac
->offset
, v
);
392 enable_exact_filters(mac
);
394 t3_write_reg(adap
, A_XGM_RX_MAX_PKT_SIZE
+ mac
->offset
, mtu
);
397 * Adjust the PAUSE frame watermarks. We always set the LWM, and the
398 * HWM only if flow-control is enabled.
400 hwm
= rx_fifo_hwm(mtu
);
401 lwm
= min(3 * (int) mtu
, MAC_RXFIFO_SIZE
/4);
402 v
= t3_read_reg(adap
, A_XGM_RXFIFO_CFG
+ mac
->offset
);
403 v
&= ~V_RXFIFOPAUSELWM(M_RXFIFOPAUSELWM
);
404 v
|= V_RXFIFOPAUSELWM(lwm
/ 8);
405 if (G_RXFIFOPAUSEHWM(v
))
406 v
= (v
& ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM
)) |
407 V_RXFIFOPAUSEHWM(hwm
/ 8);
409 t3_write_reg(adap
, A_XGM_RXFIFO_CFG
+ mac
->offset
, v
);
411 /* Adjust the TX FIFO threshold based on the MTU */
412 thres
= (adap
->params
.vpd
.cclk
* 1000) / 15625;
413 thres
= (thres
* mtu
) / 1000;
416 thres
= mtu
> thres
? (mtu
- thres
+ 7) / 8 : 0;
417 thres
= max(thres
, 8U); /* need at least 8 */
418 t3_set_reg_field(adap
, A_XGM_TXFIFO_CFG
+ mac
->offset
,
419 V_TXFIFOTHRESH(M_TXFIFOTHRESH
) | V_TXIPG(M_TXIPG
),
420 V_TXFIFOTHRESH(thres
) | V_TXIPG(1));
422 /* Assuming a minimum drain rate of 2.5Gbps...
424 if (adap
->params
.rev
> 0)
425 t3_write_reg(adap
, A_XGM_PAUSE_TIMER
+ mac
->offset
,
426 (hwm
- lwm
) * 4 / 8);
427 t3_write_reg(adap
, A_XGM_TX_PAUSE_QUANTA
+ mac
->offset
,
428 MAC_RXFIFO_SIZE
* 4 * 8 / 512);
432 int t3_mac_set_speed_duplex_fc(struct cmac
*mac
, int speed
, int duplex
, int fc
)
435 adapter_t
*adap
= mac
->adapter
;
436 unsigned int oft
= mac
->offset
;
438 if (duplex
>= 0 && duplex
!= DUPLEX_FULL
)
440 if (mac
->multiport
) {
441 val
= t3_read_reg(adap
, A_XGM_RXFIFO_CFG
+ oft
);
442 val
&= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM
);
443 val
|= V_RXFIFOPAUSEHWM(rx_fifo_hwm(t3_read_reg(adap
,
444 A_XGM_RX_MAX_PKT_SIZE
+ oft
)) / 8);
445 t3_write_reg(adap
, A_XGM_RXFIFO_CFG
+ oft
, val
);
447 t3_set_reg_field(adap
, A_XGM_TX_CFG
+ oft
, F_TXPAUSEEN
,
449 return t3_vsc7323_set_speed_fc(adap
, speed
, fc
, mac
->ext_port
);
452 if (speed
== SPEED_10
)
453 val
= V_PORTSPEED(0);
454 else if (speed
== SPEED_100
)
455 val
= V_PORTSPEED(1);
456 else if (speed
== SPEED_1000
)
457 val
= V_PORTSPEED(2);
458 else if (speed
== SPEED_10000
)
459 val
= V_PORTSPEED(3);
463 t3_set_reg_field(adap
, A_XGM_PORT_CFG
+ oft
,
464 V_PORTSPEED(M_PORTSPEED
), val
);
467 val
= t3_read_reg(adap
, A_XGM_RXFIFO_CFG
+ oft
);
468 val
&= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM
);
470 val
|= V_RXFIFOPAUSEHWM(rx_fifo_hwm(t3_read_reg(adap
,
471 A_XGM_RX_MAX_PKT_SIZE
+ oft
)) / 8);
472 t3_write_reg(adap
, A_XGM_RXFIFO_CFG
+ oft
, val
);
474 t3_set_reg_field(adap
, A_XGM_TX_CFG
+ oft
, F_TXPAUSEEN
,
475 (fc
& PAUSE_RX
) ? F_TXPAUSEEN
: 0);
479 int t3_mac_enable(struct cmac
*mac
, int which
)
481 int idx
= macidx(mac
);
482 adapter_t
*adap
= mac
->adapter
;
483 unsigned int oft
= mac
->offset
;
484 struct mac_stats
*s
= &mac
->stats
;
487 return t3_vsc7323_enable(adap
, mac
->ext_port
, which
);
489 if (which
& MAC_DIRECTION_TX
) {
490 t3_write_reg(adap
, A_TP_PIO_ADDR
, A_TP_TX_DROP_CFG_CH0
+ idx
);
491 t3_write_reg(adap
, A_TP_PIO_DATA
, 0xc0ede401);
492 t3_write_reg(adap
, A_TP_PIO_ADDR
, A_TP_TX_DROP_MODE
);
493 t3_set_reg_field(adap
, A_TP_PIO_DATA
, 1 << idx
, 1 << idx
);
495 t3_write_reg(adap
, A_XGM_TX_CTRL
+ oft
, F_TXEN
);
497 t3_write_reg(adap
, A_TP_PIO_ADDR
, A_TP_TX_DROP_CNT_CH0
+ idx
);
498 mac
->tx_mcnt
= s
->tx_frames
;
499 mac
->tx_tcnt
= (G_TXDROPCNTCH0RCVD(t3_read_reg(adap
,
501 mac
->tx_xcnt
= (G_TXSPI4SOPCNT(t3_read_reg(adap
,
502 A_XGM_TX_SPI4_SOP_EOP_CNT
+
504 mac
->rx_mcnt
= s
->rx_frames
;
505 mac
->rx_pause
= s
->rx_pause
;
506 mac
->rx_xcnt
= (G_TXSPI4SOPCNT(t3_read_reg(adap
,
507 A_XGM_RX_SPI4_SOP_EOP_CNT
+
509 mac
->rx_ocnt
= s
->rx_fifo_ovfl
;
513 if (which
& MAC_DIRECTION_RX
)
514 t3_write_reg(adap
, A_XGM_RX_CTRL
+ oft
, F_RXEN
);
518 int t3_mac_disable(struct cmac
*mac
, int which
)
520 adapter_t
*adap
= mac
->adapter
;
523 return t3_vsc7323_disable(adap
, mac
->ext_port
, which
);
525 if (which
& MAC_DIRECTION_TX
) {
526 t3_write_reg(adap
, A_XGM_TX_CTRL
+ mac
->offset
, 0);
529 if (which
& MAC_DIRECTION_RX
) {
530 int val
= F_MAC_RESET_
;
532 t3_set_reg_field(mac
->adapter
, A_XGM_RESET_CTRL
+ mac
->offset
,
535 t3_write_reg(adap
, A_XGM_RX_CTRL
+ mac
->offset
, 0);
538 else if (uses_xaui(adap
))
539 val
|= F_PCS_RESET_
| F_XG2G_RESET_
;
541 val
|= F_RGMII_RESET_
| F_XG2G_RESET_
;
542 t3_write_reg(mac
->adapter
, A_XGM_RESET_CTRL
+ mac
->offset
, val
);
547 int t3b2_mac_watchdog_task(struct cmac
*mac
)
550 unsigned int tx_tcnt
, tx_xcnt
;
551 adapter_t
*adap
= mac
->adapter
;
552 struct mac_stats
*s
= &mac
->stats
;
553 unsigned int tx_mcnt
= (unsigned int)s
->tx_frames
;
554 unsigned int rx_mcnt
= (unsigned int)s
->rx_frames
;
555 unsigned int rx_xcnt
;
557 if (mac
->multiport
) {
558 tx_mcnt
= t3_read_reg(adap
, A_XGM_STAT_TX_FRAME_LOW
);
559 rx_mcnt
= t3_read_reg(adap
, A_XGM_STAT_RX_FRAMES_LOW
);
561 tx_mcnt
= (unsigned int)s
->tx_frames
;
562 rx_mcnt
= (unsigned int)s
->rx_frames
;
565 tx_xcnt
= 1; /* By default tx_xcnt is making progress*/
566 tx_tcnt
= mac
->tx_tcnt
; /* If tx_mcnt is progressing ignore tx_tcnt*/
567 rx_xcnt
= 1; /* By default rx_xcnt is making progress*/
568 if (tx_mcnt
== mac
->tx_mcnt
&& mac
->rx_pause
== s
->rx_pause
) {
569 tx_xcnt
= (G_TXSPI4SOPCNT(t3_read_reg(adap
,
570 A_XGM_TX_SPI4_SOP_EOP_CNT
+
573 t3_write_reg(adap
, A_TP_PIO_ADDR
,
574 A_TP_TX_DROP_CNT_CH0
+ macidx(mac
));
575 tx_tcnt
= (G_TXDROPCNTCH0RCVD(t3_read_reg(adap
,
585 if ((tx_tcnt
!= mac
->tx_tcnt
) && (mac
->tx_xcnt
== 0)) {
586 if (mac
->toggle_cnt
> 4) {
599 if (rx_mcnt
!= mac
->rx_mcnt
) {
600 rx_xcnt
= (G_TXSPI4SOPCNT(t3_read_reg(adap
,
601 A_XGM_RX_SPI4_SOP_EOP_CNT
+
603 (s
->rx_fifo_ovfl
- mac
->rx_ocnt
);
604 mac
->rx_ocnt
= s
->rx_fifo_ovfl
;
608 if (mac
->rx_mcnt
!= s
->rx_frames
&& rx_xcnt
== 0 && mac
->rx_xcnt
== 0) {
615 mac
->tx_tcnt
= tx_tcnt
;
616 mac
->tx_xcnt
= tx_xcnt
;
617 mac
->tx_mcnt
= s
->tx_frames
;
618 mac
->rx_xcnt
= rx_xcnt
;
619 mac
->rx_mcnt
= s
->rx_frames
;
620 mac
->rx_pause
= s
->rx_pause
;
622 t3_write_reg(adap
, A_XGM_TX_CTRL
+ mac
->offset
, 0);
623 t3_read_reg(adap
, A_XGM_TX_CTRL
+ mac
->offset
); /* flush */
624 t3_write_reg(adap
, A_XGM_TX_CTRL
+ mac
->offset
, mac
->txen
);
625 t3_read_reg(adap
, A_XGM_TX_CTRL
+ mac
->offset
); /* flush */
627 } else if (status
== 2) {
635 * This function is called periodically to accumulate the current values of the
636 * RMON counters into the port statistics. Since the packet counters are only
637 * 32 bits they can overflow in ~286 secs at 10G, so the function should be
638 * called more frequently than that. The byte counters are 45-bit wide, they
639 * would overflow in ~7.8 hours.
641 const struct mac_stats
*t3_mac_update_stats(struct cmac
*mac
)
643 #define RMON_READ(mac, addr) t3_read_reg(mac->adapter, addr + mac->offset)
644 #define RMON_UPDATE(mac, name, reg) \
645 (mac)->stats.name += (u64)RMON_READ(mac, A_XGM_STAT_##reg)
646 #define RMON_UPDATE64(mac, name, reg_lo, reg_hi) \
647 (mac)->stats.name += RMON_READ(mac, A_XGM_STAT_##reg_lo) + \
648 ((u64)RMON_READ(mac, A_XGM_STAT_##reg_hi) << 32)
653 return t3_vsc7323_update_stats(mac
);
655 RMON_UPDATE64(mac
, rx_octets
, RX_BYTES_LOW
, RX_BYTES_HIGH
);
656 RMON_UPDATE64(mac
, rx_frames
, RX_FRAMES_LOW
, RX_FRAMES_HIGH
);
657 RMON_UPDATE(mac
, rx_mcast_frames
, RX_MCAST_FRAMES
);
658 RMON_UPDATE(mac
, rx_bcast_frames
, RX_BCAST_FRAMES
);
659 RMON_UPDATE(mac
, rx_fcs_errs
, RX_CRC_ERR_FRAMES
);
660 RMON_UPDATE(mac
, rx_pause
, RX_PAUSE_FRAMES
);
661 RMON_UPDATE(mac
, rx_jabber
, RX_JABBER_FRAMES
);
662 RMON_UPDATE(mac
, rx_short
, RX_SHORT_FRAMES
);
663 RMON_UPDATE(mac
, rx_symbol_errs
, RX_SYM_CODE_ERR_FRAMES
);
665 RMON_UPDATE(mac
, rx_too_long
, RX_OVERSIZE_FRAMES
);
667 v
= RMON_READ(mac
, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT
);
668 if (mac
->adapter
->params
.rev
== T3_REV_B2
)
670 mac
->stats
.rx_too_long
+= v
;
672 RMON_UPDATE(mac
, rx_frames_64
, RX_64B_FRAMES
);
673 RMON_UPDATE(mac
, rx_frames_65_127
, RX_65_127B_FRAMES
);
674 RMON_UPDATE(mac
, rx_frames_128_255
, RX_128_255B_FRAMES
);
675 RMON_UPDATE(mac
, rx_frames_256_511
, RX_256_511B_FRAMES
);
676 RMON_UPDATE(mac
, rx_frames_512_1023
, RX_512_1023B_FRAMES
);
677 RMON_UPDATE(mac
, rx_frames_1024_1518
, RX_1024_1518B_FRAMES
);
678 RMON_UPDATE(mac
, rx_frames_1519_max
, RX_1519_MAXB_FRAMES
);
680 RMON_UPDATE64(mac
, tx_octets
, TX_BYTE_LOW
, TX_BYTE_HIGH
);
681 RMON_UPDATE64(mac
, tx_frames
, TX_FRAME_LOW
, TX_FRAME_HIGH
);
682 RMON_UPDATE(mac
, tx_mcast_frames
, TX_MCAST
);
683 RMON_UPDATE(mac
, tx_bcast_frames
, TX_BCAST
);
684 RMON_UPDATE(mac
, tx_pause
, TX_PAUSE
);
685 /* This counts error frames in general (bad FCS, underrun, etc). */
686 RMON_UPDATE(mac
, tx_underrun
, TX_ERR_FRAMES
);
688 RMON_UPDATE(mac
, tx_frames_64
, TX_64B_FRAMES
);
689 RMON_UPDATE(mac
, tx_frames_65_127
, TX_65_127B_FRAMES
);
690 RMON_UPDATE(mac
, tx_frames_128_255
, TX_128_255B_FRAMES
);
691 RMON_UPDATE(mac
, tx_frames_256_511
, TX_256_511B_FRAMES
);
692 RMON_UPDATE(mac
, tx_frames_512_1023
, TX_512_1023B_FRAMES
);
693 RMON_UPDATE(mac
, tx_frames_1024_1518
, TX_1024_1518B_FRAMES
);
694 RMON_UPDATE(mac
, tx_frames_1519_max
, TX_1519_MAXB_FRAMES
);
696 /* The next stat isn't clear-on-read. */
697 t3_write_reg(mac
->adapter
, A_TP_MIB_INDEX
, mac
->offset
? 51 : 50);
698 v
= t3_read_reg(mac
->adapter
, A_TP_MIB_RDATA
);
699 lo
= (u32
)mac
->stats
.rx_cong_drops
;
700 mac
->stats
.rx_cong_drops
+= (u64
)(v
- lo
);