Expand PMF_FN_* macros.
[netbsd-mini2440.git] / sys / dev / pci / cxgb_xgmac.c
blobac6e2ff9c7bc4c1236ae32e8f08d6ba3055eab5a
2 /**************************************************************************
4 Copyright (c) 2007, Chelsio Inc.
5 All rights reserved.
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>
32 #ifdef __NetBSD__
33 __KERNEL_RCSID(0, "$NetBSD: cxgb_xgmac.c,v 1.2 2007/12/11 11:25:50 lukem Exp $");
34 #endif
35 #ifdef __FreeBSD__
36 __FBSDID("$FreeBSD: src/sys/dev/cxgb/common/cxgb_xgmac.c,v 1.7 2007/09/09 01:28:03 kmacy Exp $");
37 #endif
39 #ifdef CONFIG_DEFINED
40 #include <cxgb_include.h>
41 #else
42 #ifdef __FreeBSD__
43 #include <dev/cxgb/cxgb_include.h>
44 #endif
45 #ifdef __NetBSD__
46 #include "cxgb_include.h"
47 #endif
48 #endif
50 #undef msleep
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
71 int i;
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);
80 udelay(15);
82 for (i = 0; i < ARRAY_SIZE(clear); i++) {
83 t3_set_reg_field(adap, ctrl, clear[i], 0);
84 udelay(15);
88 void t3b_pcs_reset(struct cmac *mac)
90 t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset,
91 F_PCS_RESET_, 0);
92 udelay(20);
93 t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset, 0,
94 F_PCS_RESET_);
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 }
116 u32 val;
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)) {
134 CH_ERR(adap,
135 "MAC %d XAUI SERDES CMU lock failed\n",
136 macidx(mac));
137 return -1;
139 t3_set_reg_field(adap, A_XGM_SERDES_CTRL + oft, 0,
140 F_SERDESRESET_);
141 } else
142 xaui_serdes_reset(mac);
146 if (mac->multiport) {
147 t3_write_reg(adap, A_XGM_RX_MAX_PKT_SIZE + oft,
148 MAX_FRAME_SIZE - 4);
149 t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + oft, 0,
150 F_DISPREAMBLE);
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),
155 V_TXFIFOTHRESH(64));
156 t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN);
157 t3_write_reg(adap, A_XGM_RX_CTRL + oft, F_RXEN);
160 val = F_MAC_RESET_;
161 if (is_10G(adap) || mac->multiport)
162 val |= F_PCS_RESET_;
163 else if (uses_xaui(adap))
164 val |= F_PCS_RESET_ | F_XG2G_RESET_;
165 else
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) {
170 msleep(1);
171 t3b_pcs_reset(mac);
174 memset(&mac->stats, 0, sizeof(mac->stats));
175 return 0;
178 static int t3b2_mac_reset(struct cmac *mac)
180 u32 val;
181 adapter_t *adap = mac->adapter;
182 unsigned int oft = mac->offset;
185 /* Stop egress traffic to xgm*/
186 if (!macidx(mac))
187 t3_set_reg_field(adap, A_MPS_CFG, F_PORT0ACTIVE, 0);
188 else
189 t3_set_reg_field(adap, A_MPS_CFG, F_PORT1ACTIVE, 0);
191 /* PCS in reset */
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 */
195 msleep(10);
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",
201 macidx(mac));
202 return -1;
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 */
208 val = F_MAC_RESET_;
209 if (is_10G(adap))
210 val |= F_PCS_RESET_;
211 else if (uses_xaui(adap))
212 val |= F_PCS_RESET_ | F_XG2G_RESET_;
213 else
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) {
218 msleep(1);
219 t3b_pcs_reset(mac);
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*/
226 if (!macidx(mac))
227 t3_set_reg_field(adap, A_MPS_CFG, 0, F_PORT0ACTIVE);
228 else
229 t3_set_reg_field(adap, A_MPS_CFG, 0, F_PORT1ACTIVE);
231 return 0;
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])
252 if (mac->multiport)
253 idx = mac->ext_port + idx * mac->adapter->params.nports;
254 if (idx >= mac->nucast)
255 return -EINVAL;
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);
259 return 0;
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)
270 return -EINVAL;
271 mac->nucast = n;
272 return 0;
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;
305 if (++i == 6)
306 i = 0;
308 return hash;
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;
319 else
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;
326 else {
327 u8 *addr;
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);
334 else {
335 int hash = hash_hw_addr(addr);
337 if (hash < 32)
338 hash_lo |= (1 << hash);
339 else
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);
346 return 0;
349 static int rx_fifo_hwm(int mtu)
351 int hwm;
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)
359 int hwm, lwm;
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.
367 mtu += 14;
368 if (mac->multiport)
369 mtu += 8; /* for preamble */
370 if (mtu > MAX_FRAME_SIZE - 4)
371 return -EINVAL;
372 if (mac->multiport)
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);
382 /* drain rx FIFO */
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);
388 return -EIO;
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);
393 } else
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;
414 if (is_10G(adap))
415 thres /= 10;
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);
429 return 0;
432 int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc)
434 u32 val;
435 adapter_t *adap = mac->adapter;
436 unsigned int oft = mac->offset;
438 if (duplex >= 0 && duplex != DUPLEX_FULL)
439 return -EINVAL;
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,
448 F_TXPAUSEEN);
449 return t3_vsc7323_set_speed_fc(adap, speed, fc, mac->ext_port);
451 if (speed >= 0) {
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);
460 else
461 return -EINVAL;
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);
469 if (fc & PAUSE_TX)
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);
476 return 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;
486 if (mac->multiport)
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,
500 A_TP_PIO_DATA)));
501 mac->tx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
502 A_XGM_TX_SPI4_SOP_EOP_CNT +
503 oft)));
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 +
508 oft)));
509 mac->rx_ocnt = s->rx_fifo_ovfl;
510 mac->txen = F_TXEN;
511 mac->toggle_cnt = 0;
513 if (which & MAC_DIRECTION_RX)
514 t3_write_reg(adap, A_XGM_RX_CTRL + oft, F_RXEN);
515 return 0;
518 int t3_mac_disable(struct cmac *mac, int which)
520 adapter_t *adap = mac->adapter;
522 if (mac->multiport)
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);
527 mac->txen = 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,
533 F_PCS_RESET_, 0);
534 msleep(100);
535 t3_write_reg(adap, A_XGM_RX_CTRL + mac->offset, 0);
536 if (is_10G(adap))
537 val |= F_PCS_RESET_;
538 else if (uses_xaui(adap))
539 val |= F_PCS_RESET_ | F_XG2G_RESET_;
540 else
541 val |= F_RGMII_RESET_ | F_XG2G_RESET_;
542 t3_write_reg(mac->adapter, A_XGM_RESET_CTRL + mac->offset, val);
544 return 0;
547 int t3b2_mac_watchdog_task(struct cmac *mac)
549 int status;
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);
560 } else {
561 tx_mcnt = (unsigned int)s->tx_frames;
562 rx_mcnt = (unsigned int)s->rx_frames;
564 status = 0;
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 +
571 mac->offset)));
572 if (tx_xcnt == 0) {
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,
576 A_TP_PIO_DATA)));
577 } else {
578 goto rxcheck;
580 } else {
581 mac->toggle_cnt = 0;
582 goto rxcheck;
585 if ((tx_tcnt != mac->tx_tcnt) && (mac->tx_xcnt == 0)) {
586 if (mac->toggle_cnt > 4) {
587 status = 2;
588 goto out;
589 } else {
590 status = 1;
591 goto out;
593 } else {
594 mac->toggle_cnt = 0;
595 goto rxcheck;
598 rxcheck:
599 if (rx_mcnt != mac->rx_mcnt) {
600 rx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
601 A_XGM_RX_SPI4_SOP_EOP_CNT +
602 mac->offset))) +
603 (s->rx_fifo_ovfl - mac->rx_ocnt);
604 mac->rx_ocnt = s->rx_fifo_ovfl;
605 } else
606 goto out;
608 if (mac->rx_mcnt != s->rx_frames && rx_xcnt == 0 && mac->rx_xcnt == 0) {
609 if (!mac->multiport)
610 status = 2;
611 goto out;
614 out:
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;
621 if (status == 1) {
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 */
626 mac->toggle_cnt++;
627 } else if (status == 2) {
628 t3b2_mac_reset(mac);
629 mac->toggle_cnt = 0;
631 return status;
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)
650 u32 v, lo;
652 if (mac->multiport)
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)
669 v &= 0x7fffffff;
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);
702 return &mac->stats;