1 /**************************************************************************
2
3 Copyright (c) 2007, Chelsio Inc.
4 All rights reserved.
5
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions are met:
8
9 1. Redistributions of source code must retain the above copyright notice,
10 this list of conditions and the following disclaimer.
11
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.
15
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.
27
28 ***************************************************************************/
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD: releng/6.4/sys/dev/cxgb/common/cxgb_xgmac.c 174319 2007-12-05 22:05:49Z kmacy $");
32
33 #ifdef CONFIG_DEFINED
34 #include <cxgb_include.h>
35 #else
36 #include <dev/cxgb/cxgb_include.h>
37 #endif
38
39 #undef msleep
40 #define msleep t3_os_sleep
41
42 /*
43 * # of exact address filters. The first one is used for the station address,
44 * the rest are available for multicast addresses.
45 */
46 #define EXACT_ADDR_FILTERS 8
47
48 static inline int macidx(const struct cmac *mac)
49 {
50 return mac->offset / (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR);
51 }
52
53 static void xaui_serdes_reset(struct cmac *mac)
54 {
55 static const unsigned int clear[] = {
56 F_PWRDN0 | F_PWRDN1, F_RESETPLL01, F_RESET0 | F_RESET1,
57 F_PWRDN2 | F_PWRDN3, F_RESETPLL23, F_RESET2 | F_RESET3
58 };
59
60 int i;
61 adapter_t *adap = mac->adapter;
62 u32 ctrl = A_XGM_SERDES_CTRL0 + mac->offset;
63
64 t3_write_reg(adap, ctrl, adap->params.vpd.xauicfg[macidx(mac)] |
65 F_RESET3 | F_RESET2 | F_RESET1 | F_RESET0 |
66 F_PWRDN3 | F_PWRDN2 | F_PWRDN1 | F_PWRDN0 |
67 F_RESETPLL23 | F_RESETPLL01);
68 (void)t3_read_reg(adap, ctrl);
69 udelay(15);
70
71 for (i = 0; i < ARRAY_SIZE(clear); i++) {
72 t3_set_reg_field(adap, ctrl, clear[i], 0);
73 udelay(15);
74 }
75 }
76
77 void t3b_pcs_reset(struct cmac *mac)
78 {
79 t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset,
80 F_PCS_RESET_, 0);
81 udelay(20);
82 t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset, 0,
83 F_PCS_RESET_);
84 }
85
86 int t3_mac_reset(struct cmac *mac)
87 {
88 static struct addr_val_pair mac_reset_avp[] = {
89 { A_XGM_TX_CTRL, 0 },
90 { A_XGM_RX_CTRL, 0 },
91 { A_XGM_RX_CFG, F_DISPAUSEFRAMES | F_EN1536BFRAMES |
92 F_RMFCS | F_ENJUMBO | F_ENHASHMCAST },
93 { A_XGM_RX_HASH_LOW, 0 },
94 { A_XGM_RX_HASH_HIGH, 0 },
95 { A_XGM_RX_EXACT_MATCH_LOW_1, 0 },
96 { A_XGM_RX_EXACT_MATCH_LOW_2, 0 },
97 { A_XGM_RX_EXACT_MATCH_LOW_3, 0 },
98 { A_XGM_RX_EXACT_MATCH_LOW_4, 0 },
99 { A_XGM_RX_EXACT_MATCH_LOW_5, 0 },
100 { A_XGM_RX_EXACT_MATCH_LOW_6, 0 },
101 { A_XGM_RX_EXACT_MATCH_LOW_7, 0 },
102 { A_XGM_RX_EXACT_MATCH_LOW_8, 0 },
103 { A_XGM_STAT_CTRL, F_CLRSTATS }
104 };
105 u32 val;
106 adapter_t *adap = mac->adapter;
107 unsigned int oft = mac->offset;
108
109 t3_write_reg(adap, A_XGM_RESET_CTRL + oft, F_MAC_RESET_);
110 (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */
111
112 t3_write_regs(adap, mac_reset_avp, ARRAY_SIZE(mac_reset_avp), oft);
113 t3_set_reg_field(adap, A_XGM_RXFIFO_CFG + oft,
114 F_RXSTRFRWRD | F_DISERRFRAMES,
115 uses_xaui(adap) ? 0 : F_RXSTRFRWRD);
116
117 if (uses_xaui(adap)) {
118 if (adap->params.rev == 0) {
119 t3_set_reg_field(adap, A_XGM_SERDES_CTRL + oft, 0,
120 F_RXENABLE | F_TXENABLE);
121 if (t3_wait_op_done(adap, A_XGM_SERDES_STATUS1 + oft,
122 F_CMULOCK, 1, 5, 2)) {
123 CH_ERR(adap,
124 "MAC %d XAUI SERDES CMU lock failed\n",
125 macidx(mac));
126 return -1;
127 }
128 t3_set_reg_field(adap, A_XGM_SERDES_CTRL + oft, 0,
129 F_SERDESRESET_);
130 } else
131 xaui_serdes_reset(mac);
132 }
133
134
135 if (mac->multiport) {
136 t3_write_reg(adap, A_XGM_RX_MAX_PKT_SIZE + oft,
137 MAX_FRAME_SIZE - 4);
138 t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + oft, 0,
139 F_DISPREAMBLE);
140 t3_set_reg_field(adap, A_XGM_RX_CFG + oft, 0, F_COPYPREAMBLE |
141 F_ENNON802_3PREAMBLE);
142 t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + oft,
143 V_TXFIFOTHRESH(M_TXFIFOTHRESH),
144 V_TXFIFOTHRESH(64));
145 t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN);
146 t3_write_reg(adap, A_XGM_RX_CTRL + oft, F_RXEN);
147 }
148
149 val = F_MAC_RESET_;
150 if (is_10G(adap) || mac->multiport)
151 val |= F_PCS_RESET_;
152 else if (uses_xaui(adap))
153 val |= F_PCS_RESET_ | F_XG2G_RESET_;
154 else
155 val |= F_RGMII_RESET_ | F_XG2G_RESET_;
156 t3_write_reg(adap, A_XGM_RESET_CTRL + oft, val);
157 (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */
158 if ((val & F_PCS_RESET_) && adap->params.rev) {
159 msleep(1);
160 t3b_pcs_reset(mac);
161 }
162
163 memset(&mac->stats, 0, sizeof(mac->stats));
164 return 0;
165 }
166
167 static int t3b2_mac_reset(struct cmac *mac)
168 {
169 u32 val;
170 adapter_t *adap = mac->adapter;
171 unsigned int oft = mac->offset;
172
173
174 /* Stop egress traffic to xgm*/
175 if (!macidx(mac))
176 t3_set_reg_field(adap, A_MPS_CFG, F_PORT0ACTIVE, 0);
177 else
178 t3_set_reg_field(adap, A_MPS_CFG, F_PORT1ACTIVE, 0);
179
180 /* PCS in reset */
181 t3_write_reg(adap, A_XGM_RESET_CTRL + oft, F_MAC_RESET_);
182 (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */
183
184 msleep(10);
185
186 /* Check for xgm Rx fifo empty */
187 if (t3_wait_op_done(adap, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT + oft,
188 0x80000000, 1, 5, 2)) {
189 CH_ERR(adap, "MAC %d Rx fifo drain failed\n",
190 macidx(mac));
191 return -1;
192 }
193
194 t3_write_reg(adap, A_XGM_RESET_CTRL + oft, 0); /*MAC in reset*/
195 (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */
196
197 val = F_MAC_RESET_;
198 if (is_10G(adap))
199 val |= F_PCS_RESET_;
200 else if (uses_xaui(adap))
201 val |= F_PCS_RESET_ | F_XG2G_RESET_;
202 else
203 val |= F_RGMII_RESET_ | F_XG2G_RESET_;
204 t3_write_reg(adap, A_XGM_RESET_CTRL + oft, val);
205 (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */
206 if ((val & F_PCS_RESET_) && adap->params.rev) {
207 msleep(1);
208 t3b_pcs_reset(mac);
209 }
210 t3_write_reg(adap, A_XGM_RX_CFG + oft,
211 F_DISPAUSEFRAMES | F_EN1536BFRAMES |
212 F_RMFCS | F_ENJUMBO | F_ENHASHMCAST );
213
214 /*Resume egress traffic to xgm*/
215 if (!macidx(mac))
216 t3_set_reg_field(adap, A_MPS_CFG, 0, F_PORT0ACTIVE);
217 else
218 t3_set_reg_field(adap, A_MPS_CFG, 0, F_PORT1ACTIVE);
219
220 return 0;
221 }
222
223 /*
224 * Set the exact match register 'idx' to recognize the given Ethernet address.
225 */
226 static void set_addr_filter(struct cmac *mac, int idx, const u8 *addr)
227 {
228 u32 addr_lo, addr_hi;
229 unsigned int oft = mac->offset + idx * 8;
230
231 addr_lo = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0];
232 addr_hi = (addr[5] << 8) | addr[4];
233
234 t3_write_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1 + oft, addr_lo);
235 t3_write_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_HIGH_1 + oft, addr_hi);
236 }
237
238 /* Set one of the station's unicast MAC addresses. */
239 int t3_mac_set_address(struct cmac *mac, unsigned int idx, u8 addr[6])
240 {
241 if (mac->multiport)
242 idx = mac->ext_port + idx * mac->adapter->params.nports;
243 if (idx >= mac->nucast)
244 return -EINVAL;
245 set_addr_filter(mac, idx, addr);
246 if (mac->multiport && idx < mac->adapter->params.nports)
247 t3_vsc7323_set_addr(mac->adapter, addr, idx);
248 return 0;
249 }
250
251 /*
252 * Specify the number of exact address filters that should be reserved for
253 * unicast addresses. Caller should reload the unicast and multicast addresses
254 * after calling this.
255 */
256 int t3_mac_set_num_ucast(struct cmac *mac, unsigned char n)
257 {
258 if (n > EXACT_ADDR_FILTERS)
259 return -EINVAL;
260 mac->nucast = n;
261 return 0;
262 }
263
264 static void disable_exact_filters(struct cmac *mac)
265 {
266 unsigned int i, reg = mac->offset + A_XGM_RX_EXACT_MATCH_LOW_1;
267
268 for (i = 0; i < EXACT_ADDR_FILTERS; i++, reg += 8) {
269 u32 v = t3_read_reg(mac->adapter, reg);
270 t3_write_reg(mac->adapter, reg, v);
271 }
272 t3_read_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1); /* flush */
273 }
274
275 static void enable_exact_filters(struct cmac *mac)
276 {
277 unsigned int i, reg = mac->offset + A_XGM_RX_EXACT_MATCH_HIGH_1;
278
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);
282 }
283 t3_read_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1); /* flush */
284 }
285
286 /* Calculate the RX hash filter index of an Ethernet address */
287 static int hash_hw_addr(const u8 *addr)
288 {
289 int hash = 0, octet, bit, i = 0, c;
290
291 for (octet = 0; octet < 6; ++octet)
292 for (c = addr[octet], bit = 0; bit < 8; c >>= 1, ++bit) {
293 hash ^= (c & 1) << i;
294 if (++i == 6)
295 i = 0;
296 }
297 return hash;
298 }
299
300 int t3_mac_set_rx_mode(struct cmac *mac, struct t3_rx_mode *rm)
301 {
302 u32 hash_lo, hash_hi;
303 adapter_t *adap = mac->adapter;
304 unsigned int oft = mac->offset;
305
306 if (promisc_rx_mode(rm))
307 mac->promisc_map |= 1 << mac->ext_port;
308 else
309 mac->promisc_map &= ~(1 << mac->ext_port);
310 t3_set_reg_field(adap, A_XGM_RX_CFG + oft, F_COPYALLFRAMES,
311 mac->promisc_map ? F_COPYALLFRAMES : 0);
312
313 if (allmulti_rx_mode(rm) || mac->multiport)
314 hash_lo = hash_hi = 0xffffffff;
315 else {
316 u8 *addr;
317 int exact_addr_idx = mac->nucast;
318
319 hash_lo = hash_hi = 0;
320 while ((addr = t3_get_next_mcaddr(rm)))
321 if (exact_addr_idx < EXACT_ADDR_FILTERS)
322 set_addr_filter(mac, exact_addr_idx++, addr);
323 else {
324 int hash = hash_hw_addr(addr);
325
326 if (hash < 32)
327 hash_lo |= (1 << hash);
328 else
329 hash_hi |= (1 << (hash - 32));
330 }
331 }
332
333 t3_write_reg(adap, A_XGM_RX_HASH_LOW + oft, hash_lo);
334 t3_write_reg(adap, A_XGM_RX_HASH_HIGH + oft, hash_hi);
335 return 0;
336 }
337
338 static int rx_fifo_hwm(int mtu)
339 {
340 int hwm;
341
342 hwm = max(MAC_RXFIFO_SIZE - 3 * mtu, (MAC_RXFIFO_SIZE * 38) / 100);
343 return min(hwm, MAC_RXFIFO_SIZE - 8192);
344 }
345
346 int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu)
347 {
348 int hwm, lwm;
349 unsigned int thres, v;
350 adapter_t *adap = mac->adapter;
351
352 /*
353 * MAX_FRAME_SIZE inludes header + FCS, mtu doesn't. The HW max
354 * packet size register includes header, but not FCS.
355 */
356 mtu += 14;
357 if (mac->multiport)
358 mtu += 8; /* for preamble */
359 if (mtu > MAX_FRAME_SIZE - 4)
360 return -EINVAL;
361 if (mac->multiport)
362 return t3_vsc7323_set_mtu(adap, mtu - 4, mac->ext_port);
363
364 if (adap->params.rev == T3_REV_B2 &&
365 (t3_read_reg(adap, A_XGM_RX_CTRL + mac->offset) & F_RXEN)) {
366 disable_exact_filters(mac);
367 v = t3_read_reg(adap, A_XGM_RX_CFG + mac->offset);
368 t3_set_reg_field(adap, A_XGM_RX_CFG + mac->offset,
369 F_ENHASHMCAST | F_COPYALLFRAMES, F_DISBCAST);
370
371 /* drain rx FIFO */
372 if (t3_wait_op_done(adap,
373 A_XGM_RX_MAX_PKT_SIZE_ERR_CNT + mac->offset,
374 1 << 31, 1, 20, 5)) {
375 t3_write_reg(adap, A_XGM_RX_CFG + mac->offset, v);
376 enable_exact_filters(mac);
377 return -EIO;
378 }
379 t3_write_reg(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset, mtu);
380 t3_write_reg(adap, A_XGM_RX_CFG + mac->offset, v);
381 enable_exact_filters(mac);
382 } else
383 t3_write_reg(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset, mtu);
384
385 /*
386 * Adjust the PAUSE frame watermarks. We always set the LWM, and the
387 * HWM only if flow-control is enabled.
388 */
389 hwm = rx_fifo_hwm(mtu);
390 lwm = min(3 * (int) mtu, MAC_RXFIFO_SIZE /4);
391 v = t3_read_reg(adap, A_XGM_RXFIFO_CFG + mac->offset);
392 v &= ~V_RXFIFOPAUSELWM(M_RXFIFOPAUSELWM);
393 v |= V_RXFIFOPAUSELWM(lwm / 8);
394 if (G_RXFIFOPAUSEHWM(v))
395 v = (v & ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM)) |
396 V_RXFIFOPAUSEHWM(hwm / 8);
397
398 t3_write_reg(adap, A_XGM_RXFIFO_CFG + mac->offset, v);
399
400 /* Adjust the TX FIFO threshold based on the MTU */
401 thres = (adap->params.vpd.cclk * 1000) / 15625;
402 thres = (thres * mtu) / 1000;
403 if (is_10G(adap))
404 thres /= 10;
405 thres = mtu > thres ? (mtu - thres + 7) / 8 : 0;
406 thres = max(thres, 8U); /* need at least 8 */
407 t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + mac->offset,
408 V_TXFIFOTHRESH(M_TXFIFOTHRESH) | V_TXIPG(M_TXIPG),
409 V_TXFIFOTHRESH(thres) | V_TXIPG(1));
410
411 /* Assuming a minimum drain rate of 2.5Gbps...
412 */
413 if (adap->params.rev > 0)
414 t3_write_reg(adap, A_XGM_PAUSE_TIMER + mac->offset,
415 (hwm - lwm) * 4 / 8);
416 t3_write_reg(adap, A_XGM_TX_PAUSE_QUANTA + mac->offset,
417 MAC_RXFIFO_SIZE * 4 * 8 / 512);
418 return 0;
419 }
420
421 int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc)
422 {
423 u32 val;
424 adapter_t *adap = mac->adapter;
425 unsigned int oft = mac->offset;
426
427 if (duplex >= 0 && duplex != DUPLEX_FULL)
428 return -EINVAL;
429 if (mac->multiport) {
430 val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft);
431 val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM);
432 val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(t3_read_reg(adap,
433 A_XGM_RX_MAX_PKT_SIZE + oft)) / 8);
434 t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val);
435
436 t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN,
437 F_TXPAUSEEN);
438 return t3_vsc7323_set_speed_fc(adap, speed, fc, mac->ext_port);
439 }
440 if (speed >= 0) {
441 if (speed == SPEED_10)
442 val = V_PORTSPEED(0);
443 else if (speed == SPEED_100)
444 val = V_PORTSPEED(1);
445 else if (speed == SPEED_1000)
446 val = V_PORTSPEED(2);
447 else if (speed == SPEED_10000)
448 val = V_PORTSPEED(3);
449 else
450 return -EINVAL;
451
452 t3_set_reg_field(adap, A_XGM_PORT_CFG + oft,
453 V_PORTSPEED(M_PORTSPEED), val);
454 }
455
456 val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft);
457 val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM);
458 if (fc & PAUSE_TX)
459 val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(t3_read_reg(adap,
460 A_XGM_RX_MAX_PKT_SIZE + oft)) / 8);
461 t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val);
462
463 t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN,
464 (fc & PAUSE_RX) ? F_TXPAUSEEN : 0);
465 return 0;
466 }
467
468 int t3_mac_enable(struct cmac *mac, int which)
469 {
470 int idx = macidx(mac);
471 adapter_t *adap = mac->adapter;
472 unsigned int oft = mac->offset;
473 struct mac_stats *s = &mac->stats;
474
475 if (mac->multiport)
476 return t3_vsc7323_enable(adap, mac->ext_port, which);
477
478 if (which & MAC_DIRECTION_TX) {
479 t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
480 t3_write_reg(adap, A_TP_PIO_DATA, 0xc0ede401);
481 t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_MODE);
482 t3_set_reg_field(adap, A_TP_PIO_DATA, 1 << idx, 1 << idx);
483
484 t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN);
485
486 t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CNT_CH0 + idx);
487 mac->tx_mcnt = s->tx_frames;
488 mac->tx_tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap,
489 A_TP_PIO_DATA)));
490 mac->tx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
491 A_XGM_TX_SPI4_SOP_EOP_CNT +
492 oft)));
493 mac->rx_mcnt = s->rx_frames;
494 mac->rx_pause = s->rx_pause;
495 mac->rx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
496 A_XGM_RX_SPI4_SOP_EOP_CNT +
497 oft)));
498 mac->rx_ocnt = s->rx_fifo_ovfl;
499 mac->txen = F_TXEN;
500 mac->toggle_cnt = 0;
501 }
502 if (which & MAC_DIRECTION_RX)
503 t3_write_reg(adap, A_XGM_RX_CTRL + oft, F_RXEN);
504 return 0;
505 }
506
507 int t3_mac_disable(struct cmac *mac, int which)
508 {
509 adapter_t *adap = mac->adapter;
510
511 if (mac->multiport)
512 return t3_vsc7323_disable(adap, mac->ext_port, which);
513
514 if (which & MAC_DIRECTION_TX) {
515 t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0);
516 mac->txen = 0;
517 }
518 if (which & MAC_DIRECTION_RX) {
519 int val = F_MAC_RESET_;
520
521 t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset,
522 F_PCS_RESET_, 0);
523 msleep(100);
524 t3_write_reg(adap, A_XGM_RX_CTRL + mac->offset, 0);
525 if (is_10G(adap))
526 val |= F_PCS_RESET_;
527 else if (uses_xaui(adap))
528 val |= F_PCS_RESET_ | F_XG2G_RESET_;
529 else
530 val |= F_RGMII_RESET_ | F_XG2G_RESET_;
531 t3_write_reg(mac->adapter, A_XGM_RESET_CTRL + mac->offset, val);
532 }
533 return 0;
534 }
535
536 int t3b2_mac_watchdog_task(struct cmac *mac)
537 {
538 int status;
539 unsigned int tx_tcnt, tx_xcnt;
540 adapter_t *adap = mac->adapter;
541 struct mac_stats *s = &mac->stats;
542 unsigned int tx_mcnt = (unsigned int)s->tx_frames;
543 unsigned int rx_mcnt = (unsigned int)s->rx_frames;
544 unsigned int rx_xcnt;
545
546 if (mac->multiport) {
547 tx_mcnt = t3_read_reg(adap, A_XGM_STAT_TX_FRAME_LOW);
548 rx_mcnt = t3_read_reg(adap, A_XGM_STAT_RX_FRAMES_LOW);
549 } else {
550 tx_mcnt = (unsigned int)s->tx_frames;
551 rx_mcnt = (unsigned int)s->rx_frames;
552 }
553 status = 0;
554 tx_xcnt = 1; /* By default tx_xcnt is making progress*/
555 tx_tcnt = mac->tx_tcnt; /* If tx_mcnt is progressing ignore tx_tcnt*/
556 rx_xcnt = 1; /* By default rx_xcnt is making progress*/
557 if (tx_mcnt == mac->tx_mcnt && mac->rx_pause == s->rx_pause) {
558 tx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
559 A_XGM_TX_SPI4_SOP_EOP_CNT +
560 mac->offset)));
561 if (tx_xcnt == 0) {
562 t3_write_reg(adap, A_TP_PIO_ADDR,
563 A_TP_TX_DROP_CNT_CH0 + macidx(mac));
564 tx_tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap,
565 A_TP_PIO_DATA)));
566 } else {
567 goto rxcheck;
568 }
569 } else {
570 mac->toggle_cnt = 0;
571 goto rxcheck;
572 }
573
574 if ((tx_tcnt != mac->tx_tcnt) && (mac->tx_xcnt == 0)) {
575 if (mac->toggle_cnt > 4) {
576 status = 2;
577 goto out;
578 } else {
579 status = 1;
580 goto out;
581 }
582 } else {
583 mac->toggle_cnt = 0;
584 goto rxcheck;
585 }
586
587 rxcheck:
588 if (rx_mcnt != mac->rx_mcnt) {
589 rx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
590 A_XGM_RX_SPI4_SOP_EOP_CNT +
591 mac->offset))) +
592 (s->rx_fifo_ovfl - mac->rx_ocnt);
593 mac->rx_ocnt = s->rx_fifo_ovfl;
594 } else
595 goto out;
596
597 if (mac->rx_mcnt != s->rx_frames && rx_xcnt == 0 && mac->rx_xcnt == 0) {
598 if (!mac->multiport)
599 status = 2;
600 goto out;
601 }
602
603 out:
604 mac->tx_tcnt = tx_tcnt;
605 mac->tx_xcnt = tx_xcnt;
606 mac->tx_mcnt = s->tx_frames;
607 mac->rx_xcnt = rx_xcnt;
608 mac->rx_mcnt = s->rx_frames;
609 mac->rx_pause = s->rx_pause;
610 if (status == 1) {
611 t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0);
612 t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset); /* flush */
613 t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, mac->txen);
614 t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset); /* flush */
615 mac->toggle_cnt++;
616 } else if (status == 2) {
617 t3b2_mac_reset(mac);
618 mac->toggle_cnt = 0;
619 }
620 return status;
621 }
622
623 /*
624 * This function is called periodically to accumulate the current values of the
625 * RMON counters into the port statistics. Since the packet counters are only
626 * 32 bits they can overflow in ~286 secs at 10G, so the function should be
627 * called more frequently than that. The byte counters are 45-bit wide, they
628 * would overflow in ~7.8 hours.
629 */
630 const struct mac_stats *t3_mac_update_stats(struct cmac *mac)
631 {
632 #define RMON_READ(mac, addr) t3_read_reg(mac->adapter, addr + mac->offset)
633 #define RMON_UPDATE(mac, name, reg) \
634 (mac)->stats.name += (u64)RMON_READ(mac, A_XGM_STAT_##reg)
635 #define RMON_UPDATE64(mac, name, reg_lo, reg_hi) \
636 (mac)->stats.name += RMON_READ(mac, A_XGM_STAT_##reg_lo) + \
637 ((u64)RMON_READ(mac, A_XGM_STAT_##reg_hi) << 32)
638
639 u32 v, lo;
640
641 if (mac->multiport)
642 return t3_vsc7323_update_stats(mac);
643
644 RMON_UPDATE64(mac, rx_octets, RX_BYTES_LOW, RX_BYTES_HIGH);
645 RMON_UPDATE64(mac, rx_frames, RX_FRAMES_LOW, RX_FRAMES_HIGH);
646 RMON_UPDATE(mac, rx_mcast_frames, RX_MCAST_FRAMES);
647 RMON_UPDATE(mac, rx_bcast_frames, RX_BCAST_FRAMES);
648 RMON_UPDATE(mac, rx_fcs_errs, RX_CRC_ERR_FRAMES);
649 RMON_UPDATE(mac, rx_pause, RX_PAUSE_FRAMES);
650 RMON_UPDATE(mac, rx_jabber, RX_JABBER_FRAMES);
651 RMON_UPDATE(mac, rx_short, RX_SHORT_FRAMES);
652 RMON_UPDATE(mac, rx_symbol_errs, RX_SYM_CODE_ERR_FRAMES);
653
654 RMON_UPDATE(mac, rx_too_long, RX_OVERSIZE_FRAMES);
655
656 v = RMON_READ(mac, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT);
657 if (mac->adapter->params.rev == T3_REV_B2)
658 v &= 0x7fffffff;
659 mac->stats.rx_too_long += v;
660
661 RMON_UPDATE(mac, rx_frames_64, RX_64B_FRAMES);
662 RMON_UPDATE(mac, rx_frames_65_127, RX_65_127B_FRAMES);
663 RMON_UPDATE(mac, rx_frames_128_255, RX_128_255B_FRAMES);
664 RMON_UPDATE(mac, rx_frames_256_511, RX_256_511B_FRAMES);
665 RMON_UPDATE(mac, rx_frames_512_1023, RX_512_1023B_FRAMES);
666 RMON_UPDATE(mac, rx_frames_1024_1518, RX_1024_1518B_FRAMES);
667 RMON_UPDATE(mac, rx_frames_1519_max, RX_1519_MAXB_FRAMES);
668
669 RMON_UPDATE64(mac, tx_octets, TX_BYTE_LOW, TX_BYTE_HIGH);
670 RMON_UPDATE64(mac, tx_frames, TX_FRAME_LOW, TX_FRAME_HIGH);
671 RMON_UPDATE(mac, tx_mcast_frames, TX_MCAST);
672 RMON_UPDATE(mac, tx_bcast_frames, TX_BCAST);
673 RMON_UPDATE(mac, tx_pause, TX_PAUSE);
674 /* This counts error frames in general (bad FCS, underrun, etc). */
675 RMON_UPDATE(mac, tx_underrun, TX_ERR_FRAMES);
676
677 RMON_UPDATE(mac, tx_frames_64, TX_64B_FRAMES);
678 RMON_UPDATE(mac, tx_frames_65_127, TX_65_127B_FRAMES);
679 RMON_UPDATE(mac, tx_frames_128_255, TX_128_255B_FRAMES);
680 RMON_UPDATE(mac, tx_frames_256_511, TX_256_511B_FRAMES);
681 RMON_UPDATE(mac, tx_frames_512_1023, TX_512_1023B_FRAMES);
682 RMON_UPDATE(mac, tx_frames_1024_1518, TX_1024_1518B_FRAMES);
683 RMON_UPDATE(mac, tx_frames_1519_max, TX_1519_MAXB_FRAMES);
684
685 /* The next stat isn't clear-on-read. */
686 t3_write_reg(mac->adapter, A_TP_MIB_INDEX, mac->offset ? 51 : 50);
687 v = t3_read_reg(mac->adapter, A_TP_MIB_RDATA);
688 lo = (u32)mac->stats.rx_cong_drops;
689 mac->stats.rx_cong_drops += (u64)(v - lo);
690
691 return &mac->stats;
692 }
Cache object: 5a75993b2bbbb5507bcabd33b8c89931
|