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