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