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