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