1 /**************************************************************************
3 Copyright (c) 2007-2009 Chelsio Inc.
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions are met:
9 1. Redistributions of source code must retain the above copyright notice,
10 this list of conditions and the following disclaimer.
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.
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.
28 ***************************************************************************/
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
33 #include <cxgb_include.h>
36 #define msleep t3_os_sleep
39 static inline int macidx(const struct cmac *mac)
41 return mac->offset / (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR);
45 * Returns a reasonable A_XGM_RESET_CTRL value for the mac specified.
47 static inline int xgm_reset_ctrl(const struct cmac *mac)
49 adapter_t *adap = mac->adapter;
50 int val = F_MAC_RESET_ | F_XGMAC_STOP_EN;
53 int cfg = t3_read_reg(adap, A_XGM_PORT_CFG + mac->offset);
56 if (G_PORTSPEED(cfg) != 3) /* not running at 10G */
58 } else if (uses_xaui(adap))
59 val |= F_PCS_RESET_ | F_XG2G_RESET_;
61 val |= F_RGMII_RESET_ | F_XG2G_RESET_;
66 static void xaui_serdes_reset(struct cmac *mac)
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
74 adapter_t *adap = mac->adapter;
75 u32 ctrl = A_XGM_SERDES_CTRL0 + mac->offset;
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);
84 for (i = 0; i < ARRAY_SIZE(clear); i++) {
85 t3_set_reg_field(adap, ctrl, clear[i], 0);
91 * t3b_pcs_reset - reset the PCS on T3B+ adapters
92 * @mac: the XGMAC handle
94 * Reset the XGMAC PCS block on T3B+ adapters.
96 void t3b_pcs_reset(struct cmac *mac)
98 t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset,
101 /* No delay required */
103 t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset, 0,
107 void t3c_pcs_force_los(struct cmac *mac)
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);
122 /* No delay required */
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);
135 * t3_mac_init - initialize a MAC
136 * @mac: the MAC to initialize
138 * Initialize the given MAC.
140 int t3_mac_init(struct cmac *mac)
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 }
160 adapter_t *adap = mac->adapter;
161 unsigned int oft = mac->offset;
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 */
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);
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)) {
179 "MAC %d XAUI SERDES CMU lock failed\n",
183 t3_set_reg_field(adap, A_XGM_SERDES_CTRL + oft, 0,
186 xaui_serdes_reset(mac);
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,
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),
200 t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN);
201 t3_write_reg(adap, A_XGM_RX_CTRL + oft, F_RXEN);
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);
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) {
216 memset(&mac->stats, 0, sizeof(mac->stats));
220 static int t3_mac_reset(struct cmac *mac, int portspeed)
223 adapter_t *adap = mac->adapter;
224 unsigned int oft = mac->offset;
225 int idx = macidx(mac);
228 /* Stop egress traffic to xgm*/
229 store_mps = t3_read_reg(adap, A_MPS_CFG);
231 t3_set_reg_field(adap, A_MPS_CFG, F_PORT0ACTIVE, 0);
233 t3_set_reg_field(adap, A_MPS_CFG, F_PORT1ACTIVE, 0);
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);
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 */
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);
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);
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);
263 if (portspeed >= 0) {
264 u32 intr = t3_read_reg(adap, A_XGM_INT_ENABLE + oft);
267 * safespeedchange: wipes out pretty much all XGMAC registers.
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);
279 t3_write_reg(adap, A_XGM_INT_ENABLE + oft, intr);
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 */
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) {
292 t3_write_reg(adap, A_XGM_RX_CFG + oft,
293 F_DISPAUSEFRAMES | F_EN1536BFRAMES |
294 F_RMFCS | F_ENJUMBO | F_ENHASHMCAST );
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);
301 /* Resume egress traffic to xgm */
302 t3_set_reg_field(adap, A_MPS_CFG, F_PORT1ACTIVE | F_PORT0ACTIVE,
305 /* Set: re-enable NIC traffic */
306 t3_set_reg_field(adap, A_MPS_CFG, F_ENFORCEPKT, F_ENFORCEPKT);
312 * Set the exact match register 'idx' to recognize the given Ethernet address.
314 static void set_addr_filter(struct cmac *mac, int idx, const u8 *addr)
316 u32 addr_lo, addr_hi;
317 unsigned int oft = mac->offset + idx * 8;
319 addr_lo = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0];
320 addr_hi = (addr[5] << 8) | addr[4];
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);
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
332 * Set one of the station's unicast MAC addresses.
334 int t3_mac_set_address(struct cmac *mac, unsigned int idx, u8 addr[6])
337 idx = mac->ext_port + idx * mac->adapter->params.nports;
338 if (idx >= mac->nucast)
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);
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
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.
355 * Generally, this is 1 with the first one used for the station address,
356 * and the rest are available for multicast addresses.
358 int t3_mac_set_num_ucast(struct cmac *mac, unsigned char n)
360 if (n > EXACT_ADDR_FILTERS)
366 void t3_mac_disable_exact_filters(struct cmac *mac)
368 unsigned int i, reg = mac->offset + A_XGM_RX_EXACT_MATCH_LOW_1;
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);
374 t3_read_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1); /* flush */
377 void t3_mac_enable_exact_filters(struct cmac *mac)
379 unsigned int i, reg = mac->offset + A_XGM_RX_EXACT_MATCH_HIGH_1;
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);
385 t3_read_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1); /* flush */
388 /* Calculate the RX hash filter index of an Ethernet address */
389 static int hash_hw_addr(const u8 *addr)
391 int hash = 0, octet, bit, i = 0, c;
393 for (octet = 0; octet < 6; ++octet)
394 for (c = addr[octet], bit = 0; bit < 8; c >>= 1, ++bit) {
395 hash ^= (c & 1) << i;
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
407 * Configures the MAC Rx mode (promiscuity, etc) and exact and hash
410 int t3_mac_set_rx_mode(struct cmac *mac, struct t3_rx_mode *rm)
412 u32 hash_lo, hash_hi;
413 adapter_t *adap = mac->adapter;
414 unsigned int oft = mac->offset;
416 if (promisc_rx_mode(rm))
417 mac->promisc_map |= 1 << mac->ext_port;
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);
423 if (allmulti_rx_mode(rm) || mac->multiport)
424 hash_lo = hash_hi = 0xffffffff;
427 int exact_addr_idx = mac->nucast;
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);
434 int hash = hash_hw_addr(addr);
437 hash_lo |= (1 << hash);
439 hash_hi |= (1 << (hash - 32));
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);
448 static int rx_fifo_hwm(int mtu)
452 hwm = max(MAC_RXFIFO_SIZE - 3 * mtu, (MAC_RXFIFO_SIZE * 38) / 100);
453 return min(hwm, MAC_RXFIFO_SIZE - 8192);
457 * t3_mac_set_mtu - set the MAC MTU
458 * @mac: the MAC to configure
461 * Sets the MAC MTU and adjusts the FIFO PAUSE watermarks accordingly.
463 int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu)
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;
473 * MAX_FRAME_SIZE inludes header + FCS, mtu doesn't. The HW max
474 * packet size register includes header, but not FCS.
478 mtu += 8; /* for preamble */
479 if (mtu > MAX_FRAME_SIZE - 4)
482 return t3_vsc7323_set_mtu(adap, mtu - 4, mac->ext_port);
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));
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);
499 reg = adap->params.rev == T3_REV_B2 ?
500 A_XGM_RX_MAX_PKT_SIZE_ERR_CNT : A_XGM_RXFIFO_CFG;
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);
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);
515 t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset,
516 V_RXMAXPKTSIZE(M_RXMAXPKTSIZE),
517 V_RXMAXPKTSIZE(mtu));
519 * Adjust the PAUSE frame watermarks. We always set the LWM, and the
520 * HWM only if flow-control is enabled.
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);
531 t3_write_reg(adap, A_XGM_RXFIFO_CFG + mac->offset, v);
533 /* Adjust the TX FIFO threshold based on the MTU */
534 thres = (adap->params.vpd.cclk * 1000) / 15625;
535 thres = (thres * mtu) / 1000;
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));
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
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.
558 int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc)
561 adapter_t *adap = mac->adapter;
562 unsigned int oft = mac->offset;
563 unsigned int pause_bits;
565 if (duplex >= 0 && duplex != DUPLEX_FULL)
568 pause_bits = MAC_RXFIFO_SIZE * 4 * 8;
569 t3_write_reg(adap, A_XGM_TX_PAUSE_QUANTA + mac->offset,
571 t3_write_reg(adap, A_XGM_PAUSE_TIMER + mac->offset,
572 (pause_bits >> (adap->params.rev == T3_REV_C ? 10 : 7)));
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,
585 return t3_vsc7323_set_speed_fc(adap, speed, fc, mac->ext_port);
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);
599 if (!uses_xaui(adap)) /* T302 */
600 t3_set_reg_field(adap, A_XGM_PORT_CFG + oft,
601 V_PORTSPEED(M_PORTSPEED), val);
603 u32 old = t3_read_reg(adap, A_XGM_PORT_CFG + oft);
605 if ((old & V_PORTSPEED(M_PORTSPEED)) != val) {
606 t3_mac_reset(mac, val);
612 val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft);
613 val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM);
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);
620 t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val);
622 t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN,
623 (fc & PAUSE_RX) ? F_TXPAUSEEN : 0);
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
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.
636 int t3_mac_enable(struct cmac *mac, int which)
638 int idx = macidx(mac);
639 adapter_t *adap = mac->adapter;
640 unsigned int oft = mac->offset;
641 struct mac_stats *s = &mac->stats;
644 return t3_vsc7323_enable(adap, mac->ext_port, which);
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 ?
656 t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN);
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,
662 mac->tx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
663 A_XGM_TX_SPI4_SOP_EOP_CNT +
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 +
670 mac->rx_ocnt = s->rx_fifo_ovfl;
674 if (which & MAC_DIRECTION_RX)
675 t3_write_reg(adap, A_XGM_RX_CTRL + oft, F_RXEN);
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
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.
688 int t3_mac_disable(struct cmac *mac, int which)
690 adapter_t *adap = mac->adapter;
693 return t3_vsc7323_disable(adap, mac->ext_port, which);
695 if (which & MAC_DIRECTION_TX) {
696 t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0);
699 if (which & MAC_DIRECTION_RX) {
700 int val = xgm_reset_ctrl(mac);
702 t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset,
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);
711 int t3b2_mac_watchdog_task(struct cmac *mac)
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;
720 tx_mcnt = t3_read_reg(adap, A_XGM_STAT_TX_FRAME_LOW);
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;
728 tx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
729 A_XGM_TX_SPI4_SOP_EOP_CNT +
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,
747 if ((tx_tcnt != mac->tx_tcnt) && (mac->tx_xcnt == 0)) {
748 if (mac->toggle_cnt > 4) {
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;
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 */
771 } else if (status == 2) {
772 t3_mac_reset(mac, -1);
779 * t3_mac_update_stats - accumulate MAC statistics
780 * @mac: the MAC handle
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.
788 const struct mac_stats *t3_mac_update_stats(struct cmac *mac)
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)
800 return t3_vsc7323_update_stats(mac);
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);
812 RMON_UPDATE(mac, rx_too_long, RX_OVERSIZE_FRAMES);
814 v = RMON_READ(mac, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT);
815 if (mac->adapter->params.rev == T3_REV_B2)
817 mac->stats.rx_too_long += v;
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);
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);
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);
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);