1 /**************************************************************************
2
3 Copyright (c) 2007-2009 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/8.1/sys/dev/cxgb/common/cxgb_xgmac.c 200175 2009-12-06 01:45:55Z np $");
32
33 #include <cxgb_include.h>
34
35 #undef msleep
36 #define msleep t3_os_sleep
37
38
39 static inline int macidx(const struct cmac *mac)
40 {
41 return mac->offset / (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR);
42 }
43
44 /*
45 * Returns a reasonable A_XGM_RESET_CTRL value for the mac specified.
46 */
47 static inline int xgm_reset_ctrl(const struct cmac *mac)
48 {
49 adapter_t *adap = mac->adapter;
50 int val = F_MAC_RESET_ | F_XGMAC_STOP_EN;
51
52 if (is_10G(adap)) {
53 int cfg = t3_read_reg(adap, A_XGM_PORT_CFG + mac->offset);
54
55 val |= F_PCS_RESET_;
56 if (G_PORTSPEED(cfg) != 3) /* not running at 10G */
57 val |= F_XG2G_RESET_;
58 } else if (uses_xaui(adap))
59 val |= F_PCS_RESET_ | F_XG2G_RESET_;
60 else
61 val |= F_RGMII_RESET_ | F_XG2G_RESET_;
62
63 return (val);
64 }
65
66 static void xaui_serdes_reset(struct cmac *mac)
67 {
68 static const unsigned int clear[] = {
69 F_PWRDN0 | F_PWRDN1, F_RESETPLL01, F_RESET0 | F_RESET1,
70 F_PWRDN2 | F_PWRDN3, F_RESETPLL23, F_RESET2 | F_RESET3
71 };
72
73 int i;
74 adapter_t *adap = mac->adapter;
75 u32 ctrl = A_XGM_SERDES_CTRL0 + mac->offset;
76
77 t3_write_reg(adap, ctrl, adap->params.vpd.xauicfg[macidx(mac)] |
78 F_RESET3 | F_RESET2 | F_RESET1 | F_RESET0 |
79 F_PWRDN3 | F_PWRDN2 | F_PWRDN1 | F_PWRDN0 |
80 F_RESETPLL23 | F_RESETPLL01);
81 (void)t3_read_reg(adap, ctrl);
82 udelay(15);
83
84 for (i = 0; i < ARRAY_SIZE(clear); i++) {
85 t3_set_reg_field(adap, ctrl, clear[i], 0);
86 udelay(15);
87 }
88 }
89
90 /**
91 * t3b_pcs_reset - reset the PCS on T3B+ adapters
92 * @mac: the XGMAC handle
93 *
94 * Reset the XGMAC PCS block on T3B+ adapters.
95 */
96 void t3b_pcs_reset(struct cmac *mac)
97 {
98 t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset,
99 F_PCS_RESET_, 0);
100 udelay(20);
101 t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset, 0,
102 F_PCS_RESET_);
103 }
104
105 /**
106 * t3_mac_init - initialize a MAC
107 * @mac: the MAC to initialize
108 *
109 * Initialize the given MAC.
110 */
111 int t3_mac_init(struct cmac *mac)
112 {
113 static struct addr_val_pair mac_reset_avp[] = {
114 { A_XGM_TX_CTRL, 0 },
115 { A_XGM_RX_CTRL, 0 },
116 { A_XGM_RX_CFG, F_DISPAUSEFRAMES | F_EN1536BFRAMES |
117 F_RMFCS | F_ENJUMBO | F_ENHASHMCAST },
118 { A_XGM_RX_HASH_LOW, 0 },
119 { A_XGM_RX_HASH_HIGH, 0 },
120 { A_XGM_RX_EXACT_MATCH_LOW_1, 0 },
121 { A_XGM_RX_EXACT_MATCH_LOW_2, 0 },
122 { A_XGM_RX_EXACT_MATCH_LOW_3, 0 },
123 { A_XGM_RX_EXACT_MATCH_LOW_4, 0 },
124 { A_XGM_RX_EXACT_MATCH_LOW_5, 0 },
125 { A_XGM_RX_EXACT_MATCH_LOW_6, 0 },
126 { A_XGM_RX_EXACT_MATCH_LOW_7, 0 },
127 { A_XGM_RX_EXACT_MATCH_LOW_8, 0 },
128 { A_XGM_STAT_CTRL, F_CLRSTATS }
129 };
130 u32 val;
131 adapter_t *adap = mac->adapter;
132 unsigned int oft = mac->offset;
133
134 t3_write_reg(adap, A_XGM_RESET_CTRL + oft, F_MAC_RESET_);
135 (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */
136
137 t3_write_regs(adap, mac_reset_avp, ARRAY_SIZE(mac_reset_avp), oft);
138 t3_set_reg_field(adap, A_XGM_RXFIFO_CFG + oft,
139 F_RXSTRFRWRD | F_DISERRFRAMES,
140 uses_xaui(adap) ? 0 : F_RXSTRFRWRD);
141 t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + oft, 0, F_UNDERUNFIX);
142
143 if (uses_xaui(adap)) {
144 if (adap->params.rev == 0) {
145 t3_set_reg_field(adap, A_XGM_SERDES_CTRL + oft, 0,
146 F_RXENABLE | F_TXENABLE);
147 if (t3_wait_op_done(adap, A_XGM_SERDES_STATUS1 + oft,
148 F_CMULOCK, 1, 5, 2)) {
149 CH_ERR(adap,
150 "MAC %d XAUI SERDES CMU lock failed\n",
151 macidx(mac));
152 return -1;
153 }
154 t3_set_reg_field(adap, A_XGM_SERDES_CTRL + oft, 0,
155 F_SERDESRESET_);
156 } else
157 xaui_serdes_reset(mac);
158 }
159
160
161 if (mac->multiport) {
162 t3_write_reg(adap, A_XGM_RX_MAX_PKT_SIZE + oft,
163 V_RXMAXPKTSIZE(MAX_FRAME_SIZE - 4));
164 t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + oft, 0,
165 F_DISPREAMBLE);
166 t3_set_reg_field(adap, A_XGM_RX_CFG + oft, 0, F_COPYPREAMBLE |
167 F_ENNON802_3PREAMBLE);
168 t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + oft,
169 V_TXFIFOTHRESH(M_TXFIFOTHRESH),
170 V_TXFIFOTHRESH(64));
171 t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN);
172 t3_write_reg(adap, A_XGM_RX_CTRL + oft, F_RXEN);
173 }
174
175 t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + oft,
176 V_RXMAXFRAMERSIZE(M_RXMAXFRAMERSIZE),
177 V_RXMAXFRAMERSIZE(MAX_FRAME_SIZE) | F_RXENFRAMER);
178
179 val = xgm_reset_ctrl(mac);
180 t3_write_reg(adap, A_XGM_RESET_CTRL + oft, val);
181 (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */
182 if ((val & F_PCS_RESET_) && adap->params.rev) {
183 msleep(1);
184 t3b_pcs_reset(mac);
185 }
186
187 memset(&mac->stats, 0, sizeof(mac->stats));
188 return 0;
189 }
190
191 static int t3_mac_reset(struct cmac *mac, int portspeed)
192 {
193 u32 val, store_mps;
194 adapter_t *adap = mac->adapter;
195 unsigned int oft = mac->offset;
196 int idx = macidx(mac);
197 unsigned int store;
198
199 /* Stop egress traffic to xgm*/
200 store_mps = t3_read_reg(adap, A_MPS_CFG);
201 if (!idx)
202 t3_set_reg_field(adap, A_MPS_CFG, F_PORT0ACTIVE, 0);
203 else
204 t3_set_reg_field(adap, A_MPS_CFG, F_PORT1ACTIVE, 0);
205
206 /* This will reduce the number of TXTOGGLES */
207 /* Clear: to stop the NIC traffic */
208 t3_set_reg_field(adap, A_MPS_CFG, F_ENFORCEPKT, 0);
209 /* Ensure TX drains */
210 t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN, 0);
211
212 /* PCS in reset */
213 t3_write_reg(adap, A_XGM_RESET_CTRL + oft, F_MAC_RESET_);
214 (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */
215
216 /* Store A_TP_TX_DROP_CFG_CH0 */
217 t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
218 store = t3_read_reg(adap, A_TP_PIO_DATA);
219
220 msleep(10);
221
222 /* Change DROP_CFG to 0xc0000011 */
223 t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
224 t3_write_reg(adap, A_TP_PIO_DATA, 0xc0000011);
225
226 /* Check for xgm Rx fifo empty */
227 /* Increased loop count to 1000 from 5 cover 1G and 100Mbps case */
228 if (t3_wait_op_done(adap, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT + oft,
229 0x80000000, 1, 1000, 2) && portspeed < 0) {
230 CH_ERR(adap, "MAC %d Rx fifo drain failed\n", idx);
231 return -1;
232 }
233
234 if (portspeed >= 0) {
235 u32 intr = t3_read_reg(adap, A_XGM_INT_ENABLE + oft);
236
237 /*
238 * safespeedchange: wipes out pretty much all XGMAC registers.
239 */
240
241 t3_set_reg_field(adap, A_XGM_PORT_CFG + oft,
242 V_PORTSPEED(M_PORTSPEED) | F_SAFESPEEDCHANGE,
243 portspeed | F_SAFESPEEDCHANGE);
244 (void) t3_read_reg(adap, A_XGM_PORT_CFG + oft);
245 t3_set_reg_field(adap, A_XGM_PORT_CFG + oft,
246 F_SAFESPEEDCHANGE, 0);
247 (void) t3_read_reg(adap, A_XGM_PORT_CFG + oft);
248 t3_mac_init(mac);
249
250 t3_write_reg(adap, A_XGM_INT_ENABLE + oft, intr);
251 } else {
252
253 t3_write_reg(adap, A_XGM_RESET_CTRL + oft, 0); /*MAC in reset*/
254 (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */
255
256 val = xgm_reset_ctrl(mac);
257 t3_write_reg(adap, A_XGM_RESET_CTRL + oft, val);
258 (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */
259 if ((val & F_PCS_RESET_) && adap->params.rev) {
260 msleep(1);
261 t3b_pcs_reset(mac);
262 }
263 t3_write_reg(adap, A_XGM_RX_CFG + oft,
264 F_DISPAUSEFRAMES | F_EN1536BFRAMES |
265 F_RMFCS | F_ENJUMBO | F_ENHASHMCAST );
266 }
267
268 /* Restore the DROP_CFG */
269 t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
270 t3_write_reg(adap, A_TP_PIO_DATA, store);
271
272 /* Resume egress traffic to xgm */
273 t3_set_reg_field(adap, A_MPS_CFG, F_PORT1ACTIVE | F_PORT0ACTIVE,
274 store_mps);
275
276 /* Set: re-enable NIC traffic */
277 t3_set_reg_field(adap, A_MPS_CFG, F_ENFORCEPKT, F_ENFORCEPKT);
278
279 return 0;
280 }
281
282 /*
283 * Set the exact match register 'idx' to recognize the given Ethernet address.
284 */
285 static void set_addr_filter(struct cmac *mac, int idx, const u8 *addr)
286 {
287 u32 addr_lo, addr_hi;
288 unsigned int oft = mac->offset + idx * 8;
289
290 addr_lo = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0];
291 addr_hi = (addr[5] << 8) | addr[4];
292
293 t3_write_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1 + oft, addr_lo);
294 t3_write_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_HIGH_1 + oft, addr_hi);
295 }
296
297 /**
298 * t3_mac_set_address - set one of the station's unicast MAC addresses
299 * @mac: the MAC handle
300 * @idx: index of the exact address match filter to use
301 * @addr: the Ethernet address
302 *
303 * Set one of the station's unicast MAC addresses.
304 */
305 int t3_mac_set_address(struct cmac *mac, unsigned int idx, u8 addr[6])
306 {
307 if (mac->multiport)
308 idx = mac->ext_port + idx * mac->adapter->params.nports;
309 if (idx >= mac->nucast)
310 return -EINVAL;
311 set_addr_filter(mac, idx, addr);
312 if (mac->multiport && idx < mac->adapter->params.nports)
313 t3_vsc7323_set_addr(mac->adapter, addr, idx);
314 return 0;
315 }
316
317 /**
318 * t3_mac_set_num_ucast - set the number of unicast addresses needed
319 * @mac: the MAC handle
320 * @n: number of unicast addresses needed
321 *
322 * Specify the number of exact address filters that should be reserved for
323 * unicast addresses. Caller should reload the unicast and multicast
324 * addresses after calling this.
325 *
326 * Generally, this is 1 with the first one used for the station address,
327 * and the rest are available for multicast addresses.
328 */
329 int t3_mac_set_num_ucast(struct cmac *mac, unsigned char n)
330 {
331 if (n > EXACT_ADDR_FILTERS)
332 return -EINVAL;
333 mac->nucast = n;
334 return 0;
335 }
336
337 void t3_mac_disable_exact_filters(struct cmac *mac)
338 {
339 unsigned int i, reg = mac->offset + A_XGM_RX_EXACT_MATCH_LOW_1;
340
341 for (i = 0; i < EXACT_ADDR_FILTERS; i++, reg += 8) {
342 u32 v = t3_read_reg(mac->adapter, reg);
343 t3_write_reg(mac->adapter, reg, v);
344 }
345 t3_read_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1); /* flush */
346 }
347
348 void t3_mac_enable_exact_filters(struct cmac *mac)
349 {
350 unsigned int i, reg = mac->offset + A_XGM_RX_EXACT_MATCH_HIGH_1;
351
352 for (i = 0; i < EXACT_ADDR_FILTERS; i++, reg += 8) {
353 u32 v = t3_read_reg(mac->adapter, reg);
354 t3_write_reg(mac->adapter, reg, v);
355 }
356 t3_read_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1); /* flush */
357 }
358
359 /* Calculate the RX hash filter index of an Ethernet address */
360 static int hash_hw_addr(const u8 *addr)
361 {
362 int hash = 0, octet, bit, i = 0, c;
363
364 for (octet = 0; octet < 6; ++octet)
365 for (c = addr[octet], bit = 0; bit < 8; c >>= 1, ++bit) {
366 hash ^= (c & 1) << i;
367 if (++i == 6)
368 i = 0;
369 }
370 return hash;
371 }
372
373 /**
374 * t3_mac_set_rx_mode - set the Rx mode and address filters
375 * @mac: the MAC to configure
376 * @rm: structure containing the Rx mode and MAC addresses needed
377 *
378 * Configures the MAC Rx mode (promiscuity, etc) and exact and hash
379 * address filters.
380 */
381 int t3_mac_set_rx_mode(struct cmac *mac, struct t3_rx_mode *rm)
382 {
383 u32 hash_lo, hash_hi;
384 adapter_t *adap = mac->adapter;
385 unsigned int oft = mac->offset;
386
387 if (promisc_rx_mode(rm))
388 mac->promisc_map |= 1 << mac->ext_port;
389 else
390 mac->promisc_map &= ~(1 << mac->ext_port);
391 t3_set_reg_field(adap, A_XGM_RX_CFG + oft, F_COPYALLFRAMES,
392 mac->promisc_map ? F_COPYALLFRAMES : 0);
393
394 if (allmulti_rx_mode(rm) || mac->multiport)
395 hash_lo = hash_hi = 0xffffffff;
396 else {
397 u8 *addr;
398 int exact_addr_idx = mac->nucast;
399
400 hash_lo = hash_hi = 0;
401 while ((addr = t3_get_next_mcaddr(rm)))
402 if (exact_addr_idx < EXACT_ADDR_FILTERS)
403 set_addr_filter(mac, exact_addr_idx++, addr);
404 else {
405 int hash = hash_hw_addr(addr);
406
407 if (hash < 32)
408 hash_lo |= (1 << hash);
409 else
410 hash_hi |= (1 << (hash - 32));
411 }
412 }
413
414 t3_write_reg(adap, A_XGM_RX_HASH_LOW + oft, hash_lo);
415 t3_write_reg(adap, A_XGM_RX_HASH_HIGH + oft, hash_hi);
416 return 0;
417 }
418
419 static int rx_fifo_hwm(int mtu)
420 {
421 int hwm;
422
423 hwm = max(MAC_RXFIFO_SIZE - 3 * mtu, (MAC_RXFIFO_SIZE * 38) / 100);
424 return min(hwm, MAC_RXFIFO_SIZE - 8192);
425 }
426
427 /**
428 * t3_mac_set_mtu - set the MAC MTU
429 * @mac: the MAC to configure
430 * @mtu: the MTU
431 *
432 * Sets the MAC MTU and adjusts the FIFO PAUSE watermarks accordingly.
433 */
434 int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu)
435 {
436 int hwm, lwm, divisor;
437 int ipg;
438 unsigned int thres, v, reg;
439 adapter_t *adap = mac->adapter;
440 unsigned port_type = adap->params.vpd.port_type[macidx(mac)];
441 unsigned int orig_mtu=mtu;
442
443 /*
444 * MAX_FRAME_SIZE inludes header + FCS, mtu doesn't. The HW max
445 * packet size register includes header, but not FCS.
446 */
447 mtu += 14;
448 if (mac->multiport)
449 mtu += 8; /* for preamble */
450 if (mtu > MAX_FRAME_SIZE - 4)
451 return -EINVAL;
452 if (mac->multiport)
453 return t3_vsc7323_set_mtu(adap, mtu - 4, mac->ext_port);
454
455 /* Modify the TX and RX fifo depth only if the card has a vsc8211 phy */
456 if (port_type == 2) {
457 int err = t3_vsc8211_fifo_depth(adap,orig_mtu,macidx(mac));
458
459 if (err)
460 return err;
461 }
462
463 if (adap->params.rev >= T3_REV_B2 &&
464 (t3_read_reg(adap, A_XGM_RX_CTRL + mac->offset) & F_RXEN)) {
465 t3_mac_disable_exact_filters(mac);
466 v = t3_read_reg(adap, A_XGM_RX_CFG + mac->offset);
467 t3_set_reg_field(adap, A_XGM_RX_CFG + mac->offset,
468 F_ENHASHMCAST | F_COPYALLFRAMES, F_DISBCAST);
469
470 reg = adap->params.rev == T3_REV_B2 ?
471 A_XGM_RX_MAX_PKT_SIZE_ERR_CNT : A_XGM_RXFIFO_CFG;
472
473 /* drain RX FIFO */
474 if (t3_wait_op_done(adap, reg + mac->offset,
475 F_RXFIFO_EMPTY, 1, 20, 5)) {
476 t3_write_reg(adap, A_XGM_RX_CFG + mac->offset, v);
477 t3_mac_enable_exact_filters(mac);
478 return -EIO;
479 }
480 t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset,
481 V_RXMAXPKTSIZE(M_RXMAXPKTSIZE),
482 V_RXMAXPKTSIZE(mtu));
483 t3_write_reg(adap, A_XGM_RX_CFG + mac->offset, v);
484 t3_mac_enable_exact_filters(mac);
485 } else
486 t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset,
487 V_RXMAXPKTSIZE(M_RXMAXPKTSIZE),
488 V_RXMAXPKTSIZE(mtu));
489 /*
490 * Adjust the PAUSE frame watermarks. We always set the LWM, and the
491 * HWM only if flow-control is enabled.
492 */
493 hwm = rx_fifo_hwm(mtu);
494 lwm = min(3 * (int) mtu, MAC_RXFIFO_SIZE /4);
495 v = t3_read_reg(adap, A_XGM_RXFIFO_CFG + mac->offset);
496 v &= ~V_RXFIFOPAUSELWM(M_RXFIFOPAUSELWM);
497 v |= V_RXFIFOPAUSELWM(lwm / 8);
498 if (G_RXFIFOPAUSEHWM(v))
499 v = (v & ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM)) |
500 V_RXFIFOPAUSEHWM(hwm / 8);
501
502 t3_write_reg(adap, A_XGM_RXFIFO_CFG + mac->offset, v);
503
504 /* Adjust the TX FIFO threshold based on the MTU */
505 thres = (adap->params.vpd.cclk * 1000) / 15625;
506 thres = (thres * mtu) / 1000;
507 if (is_10G(adap))
508 thres /= 10;
509 thres = mtu > thres ? (mtu - thres + 7) / 8 : 0;
510 thres = max(thres, 8U); /* need at least 8 */
511 ipg = (port_type == 9 || adap->params.rev != T3_REV_C) ? 1 : 0;
512 t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + mac->offset,
513 V_TXFIFOTHRESH(M_TXFIFOTHRESH) | V_TXIPG(M_TXIPG),
514 V_TXFIFOTHRESH(thres) | V_TXIPG(ipg));
515
516 /* Assuming a minimum drain rate of 2.5Gbps...
517 */
518 if (adap->params.rev > 0) {
519 divisor = (adap->params.rev == T3_REV_C) ? 64 : 8;
520 t3_write_reg(adap, A_XGM_PAUSE_TIMER + mac->offset,
521 (hwm - lwm) * 4 / divisor);
522 }
523 t3_write_reg(adap, A_XGM_TX_PAUSE_QUANTA + mac->offset,
524 MAC_RXFIFO_SIZE * 4 * 8 / 512);
525 return 0;
526 }
527
528 /**
529 * t3_mac_set_speed_duplex_fc - set MAC speed, duplex and flow control
530 * @mac: the MAC to configure
531 * @speed: the desired speed (10/100/1000/10000)
532 * @duplex: the desired duplex
533 * @fc: desired Tx/Rx PAUSE configuration
534 *
535 * Set the MAC speed, duplex (actually only full-duplex is supported), and
536 * flow control. If a parameter value is negative the corresponding
537 * MAC setting is left at its current value.
538 */
539 int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc)
540 {
541 u32 val;
542 adapter_t *adap = mac->adapter;
543 unsigned int oft = mac->offset;
544
545 if (duplex >= 0 && duplex != DUPLEX_FULL)
546 return -EINVAL;
547 if (mac->multiport) {
548 u32 rx_max_pkt_size =
549 G_RXMAXPKTSIZE(t3_read_reg(adap,
550 A_XGM_RX_MAX_PKT_SIZE + oft));
551 val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft);
552 val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM);
553 val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(rx_max_pkt_size) / 8);
554 t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val);
555
556 t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN,
557 F_TXPAUSEEN);
558 return t3_vsc7323_set_speed_fc(adap, speed, fc, mac->ext_port);
559 }
560 if (speed >= 0) {
561 if (speed == SPEED_10)
562 val = V_PORTSPEED(0);
563 else if (speed == SPEED_100)
564 val = V_PORTSPEED(1);
565 else if (speed == SPEED_1000)
566 val = V_PORTSPEED(2);
567 else if (speed == SPEED_10000)
568 val = V_PORTSPEED(3);
569 else
570 return -EINVAL;
571
572 if (!uses_xaui(adap)) /* T302 */
573 t3_set_reg_field(adap, A_XGM_PORT_CFG + oft,
574 V_PORTSPEED(M_PORTSPEED), val);
575 else {
576 u32 old = t3_read_reg(adap, A_XGM_PORT_CFG + oft);
577
578 if ((old & V_PORTSPEED(M_PORTSPEED)) != val) {
579 t3_mac_reset(mac, val);
580 mac->was_reset = 1;
581 }
582 }
583 }
584
585 val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft);
586 val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM);
587 if (fc & PAUSE_TX) {
588 u32 rx_max_pkt_size =
589 G_RXMAXPKTSIZE(t3_read_reg(adap,
590 A_XGM_RX_MAX_PKT_SIZE + oft));
591 val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(rx_max_pkt_size) / 8);
592 }
593 t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val);
594
595 t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN,
596 (fc & PAUSE_RX) ? F_TXPAUSEEN : 0);
597 return 0;
598 }
599
600 /**
601 * t3_mac_enable - enable the MAC in the given directions
602 * @mac: the MAC to configure
603 * @which: bitmap indicating which directions to enable
604 *
605 * Enables the MAC for operation in the given directions.
606 * %MAC_DIRECTION_TX enables the Tx direction, and %MAC_DIRECTION_RX
607 * enables the Rx one.
608 */
609 int t3_mac_enable(struct cmac *mac, int which)
610 {
611 int idx = macidx(mac);
612 adapter_t *adap = mac->adapter;
613 unsigned int oft = mac->offset;
614 struct mac_stats *s = &mac->stats;
615
616 if (mac->multiport)
617 return t3_vsc7323_enable(adap, mac->ext_port, which);
618
619 if (which & MAC_DIRECTION_TX) {
620 t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
621 t3_write_reg(adap, A_TP_PIO_DATA,
622 adap->params.rev == T3_REV_C ?
623 0xc4ffff01 : 0xc0ede401);
624 t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_MODE);
625 t3_set_reg_field(adap, A_TP_PIO_DATA, 1 << idx,
626 adap->params.rev == T3_REV_C ?
627 0 : 1 << idx);
628
629 t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN);
630
631 t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CNT_CH0 + idx);
632 mac->tx_mcnt = s->tx_frames;
633 mac->tx_tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap,
634 A_TP_PIO_DATA)));
635 mac->tx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
636 A_XGM_TX_SPI4_SOP_EOP_CNT +
637 oft)));
638 mac->rx_mcnt = s->rx_frames;
639 mac->rx_pause = s->rx_pause;
640 mac->rx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
641 A_XGM_RX_SPI4_SOP_EOP_CNT +
642 oft)));
643 mac->rx_ocnt = s->rx_fifo_ovfl;
644 mac->txen = F_TXEN;
645 mac->toggle_cnt = 0;
646 }
647 if (which & MAC_DIRECTION_RX)
648 t3_write_reg(adap, A_XGM_RX_CTRL + oft, F_RXEN);
649 return 0;
650 }
651
652 /**
653 * t3_mac_disable - disable the MAC in the given directions
654 * @mac: the MAC to configure
655 * @which: bitmap indicating which directions to disable
656 *
657 * Disables the MAC in the given directions.
658 * %MAC_DIRECTION_TX disables the Tx direction, and %MAC_DIRECTION_RX
659 * disables the Rx one.
660 */
661 int t3_mac_disable(struct cmac *mac, int which)
662 {
663 adapter_t *adap = mac->adapter;
664
665 if (mac->multiport)
666 return t3_vsc7323_disable(adap, mac->ext_port, which);
667
668 if (which & MAC_DIRECTION_TX) {
669 t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0);
670 mac->txen = 0;
671 }
672 if (which & MAC_DIRECTION_RX) {
673 int val = xgm_reset_ctrl(mac);
674
675 t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset,
676 F_PCS_RESET_, 0);
677 msleep(100);
678 t3_write_reg(adap, A_XGM_RX_CTRL + mac->offset, 0);
679 t3_write_reg(mac->adapter, A_XGM_RESET_CTRL + mac->offset, val);
680 }
681 return 0;
682 }
683
684 int t3b2_mac_watchdog_task(struct cmac *mac)
685 {
686 int status;
687 unsigned int tx_tcnt, tx_xcnt;
688 adapter_t *adap = mac->adapter;
689 struct mac_stats *s = &mac->stats;
690 u64 tx_mcnt = s->tx_frames;
691
692 if (mac->multiport)
693 tx_mcnt = t3_read_reg(adap, A_XGM_STAT_TX_FRAME_LOW);
694
695 status = 0;
696 tx_xcnt = 1; /* By default tx_xcnt is making progress*/
697 tx_tcnt = mac->tx_tcnt; /* If tx_mcnt is progressing ignore tx_tcnt*/
698 if (tx_mcnt == mac->tx_mcnt && mac->rx_pause == s->rx_pause) {
699 u32 cfg, active, enforcepkt;
700
701 tx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
702 A_XGM_TX_SPI4_SOP_EOP_CNT +
703 mac->offset)));
704 cfg = t3_read_reg(adap, A_MPS_CFG);
705 active = macidx(mac) ? cfg & F_PORT1ACTIVE : cfg & F_PORT0ACTIVE;
706 enforcepkt = cfg & F_ENFORCEPKT;
707 if (active && enforcepkt && (tx_xcnt == 0)) {
708 t3_write_reg(adap, A_TP_PIO_ADDR,
709 A_TP_TX_DROP_CNT_CH0 + macidx(mac));
710 tx_tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap,
711 A_TP_PIO_DATA)));
712 } else
713 goto out;
714
715 } else {
716 mac->toggle_cnt = 0;
717 goto out;
718 }
719
720 if ((tx_tcnt != mac->tx_tcnt) && (mac->tx_xcnt == 0)) {
721 if (mac->toggle_cnt > 4) {
722 status = 2;
723 goto out;
724 } else {
725 status = 1;
726 goto out;
727 }
728 } else {
729 mac->toggle_cnt = 0;
730 goto out;
731 }
732
733 out:
734 mac->tx_tcnt = tx_tcnt;
735 mac->tx_xcnt = tx_xcnt;
736 mac->tx_mcnt = s->tx_frames;
737 mac->rx_pause = s->rx_pause;
738 if (status == 1) {
739 t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0);
740 t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset); /* flush */
741 t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, mac->txen);
742 t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset); /* flush */
743 mac->toggle_cnt++;
744 } else if (status == 2) {
745 t3_mac_reset(mac, -1);
746 mac->toggle_cnt = 0;
747 }
748 return status;
749 }
750
751 /**
752 * t3_mac_update_stats - accumulate MAC statistics
753 * @mac: the MAC handle
754 *
755 * This function is called periodically to accumulate the current values
756 * of the RMON counters into the port statistics. Since the packet
757 * counters are only 32 bits they can overflow in ~286 secs at 10G, so the
758 * function should be called more frequently than that. The byte counters
759 * are 45-bit wide, they would overflow in ~7.8 hours.
760 */
761 const struct mac_stats *t3_mac_update_stats(struct cmac *mac)
762 {
763 #define RMON_READ(mac, addr) t3_read_reg(mac->adapter, addr + mac->offset)
764 #define RMON_UPDATE(mac, name, reg) \
765 (mac)->stats.name += (u64)RMON_READ(mac, A_XGM_STAT_##reg)
766 #define RMON_UPDATE64(mac, name, reg_lo, reg_hi) \
767 (mac)->stats.name += RMON_READ(mac, A_XGM_STAT_##reg_lo) + \
768 ((u64)RMON_READ(mac, A_XGM_STAT_##reg_hi) << 32)
769
770 u32 v, lo;
771
772 if (mac->multiport)
773 return t3_vsc7323_update_stats(mac);
774
775 RMON_UPDATE64(mac, rx_octets, RX_BYTES_LOW, RX_BYTES_HIGH);
776 RMON_UPDATE64(mac, rx_frames, RX_FRAMES_LOW, RX_FRAMES_HIGH);
777 RMON_UPDATE(mac, rx_mcast_frames, RX_MCAST_FRAMES);
778 RMON_UPDATE(mac, rx_bcast_frames, RX_BCAST_FRAMES);
779 RMON_UPDATE(mac, rx_fcs_errs, RX_CRC_ERR_FRAMES);
780 RMON_UPDATE(mac, rx_pause, RX_PAUSE_FRAMES);
781 RMON_UPDATE(mac, rx_jabber, RX_JABBER_FRAMES);
782 RMON_UPDATE(mac, rx_short, RX_SHORT_FRAMES);
783 RMON_UPDATE(mac, rx_symbol_errs, RX_SYM_CODE_ERR_FRAMES);
784
785 RMON_UPDATE(mac, rx_too_long, RX_OVERSIZE_FRAMES);
786
787 v = RMON_READ(mac, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT);
788 if (mac->adapter->params.rev == T3_REV_B2)
789 v &= 0x7fffffff;
790 mac->stats.rx_too_long += v;
791
792 RMON_UPDATE(mac, rx_frames_64, RX_64B_FRAMES);
793 RMON_UPDATE(mac, rx_frames_65_127, RX_65_127B_FRAMES);
794 RMON_UPDATE(mac, rx_frames_128_255, RX_128_255B_FRAMES);
795 RMON_UPDATE(mac, rx_frames_256_511, RX_256_511B_FRAMES);
796 RMON_UPDATE(mac, rx_frames_512_1023, RX_512_1023B_FRAMES);
797 RMON_UPDATE(mac, rx_frames_1024_1518, RX_1024_1518B_FRAMES);
798 RMON_UPDATE(mac, rx_frames_1519_max, RX_1519_MAXB_FRAMES);
799
800 RMON_UPDATE64(mac, tx_octets, TX_BYTE_LOW, TX_BYTE_HIGH);
801 RMON_UPDATE64(mac, tx_frames, TX_FRAME_LOW, TX_FRAME_HIGH);
802 RMON_UPDATE(mac, tx_mcast_frames, TX_MCAST);
803 RMON_UPDATE(mac, tx_bcast_frames, TX_BCAST);
804 RMON_UPDATE(mac, tx_pause, TX_PAUSE);
805 /* This counts error frames in general (bad FCS, underrun, etc). */
806 RMON_UPDATE(mac, tx_underrun, TX_ERR_FRAMES);
807
808 RMON_UPDATE(mac, tx_frames_64, TX_64B_FRAMES);
809 RMON_UPDATE(mac, tx_frames_65_127, TX_65_127B_FRAMES);
810 RMON_UPDATE(mac, tx_frames_128_255, TX_128_255B_FRAMES);
811 RMON_UPDATE(mac, tx_frames_256_511, TX_256_511B_FRAMES);
812 RMON_UPDATE(mac, tx_frames_512_1023, TX_512_1023B_FRAMES);
813 RMON_UPDATE(mac, tx_frames_1024_1518, TX_1024_1518B_FRAMES);
814 RMON_UPDATE(mac, tx_frames_1519_max, TX_1519_MAXB_FRAMES);
815
816 /* The next stat isn't clear-on-read. */
817 t3_write_reg(mac->adapter, A_TP_MIB_INDEX, mac->offset ? 51 : 50);
818 v = t3_read_reg(mac->adapter, A_TP_MIB_RDATA);
819 lo = (u32)mac->stats.rx_cong_drops;
820 mac->stats.rx_cong_drops += (u64)(v - lo);
821
822 return &mac->stats;
823 }
Cache object: 1c31d7640034037f9e773e79a873f5be
|