xref: /freebsd/sys/dev/cxgb/common/cxgb_vsc7323.c (revision 7fdf597e96a02165cfe22ff357b857d5fa15ed8a)
1 /**************************************************************************
2 SPDX-License-Identifier: BSD-2-Clause
3 
4 Copyright (c) 2007, 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 #include <common/cxgb_common.h>
33 
34 enum {
35 	ELMR_ADDR    = 0,
36 	ELMR_STAT    = 1,
37 	ELMR_DATA_LO = 2,
38 	ELMR_DATA_HI = 3,
39 
40 	ELMR_THRES0  = 0xe000,
41 	ELMR_BW      = 0xe00c,
42 	ELMR_FIFO_SZ = 0xe00d,
43 	ELMR_STATS   = 0xf000,
44 
45 	ELMR_MDIO_ADDR = 10
46 };
47 
48 #define VSC_REG(block, subblock, reg) \
49 	((reg) | ((subblock) << 8) | ((block) << 12))
50 
51 int t3_elmr_blk_write(adapter_t *adap, int start, const u32 *vals, int n)
52 {
53 	int ret;
54 	const struct mdio_ops *mo = adapter_info(adap)->mdio_ops;
55 
56 	ELMR_LOCK(adap);
57 	ret = mo->write(adap, ELMR_MDIO_ADDR, 0, ELMR_ADDR, start);
58 	for ( ; !ret && n; n--, vals++) {
59 		ret = mo->write(adap, ELMR_MDIO_ADDR, 0, ELMR_DATA_LO,
60 				*vals & 0xffff);
61 		if (!ret)
62 			ret = mo->write(adap, ELMR_MDIO_ADDR, 0, ELMR_DATA_HI,
63 					*vals >> 16);
64 	}
65 	ELMR_UNLOCK(adap);
66 	return ret;
67 }
68 
69 static int elmr_write(adapter_t *adap, int addr, u32 val)
70 {
71 	return t3_elmr_blk_write(adap, addr, &val, 1);
72 }
73 
74 int t3_elmr_blk_read(adapter_t *adap, int start, u32 *vals, int n)
75 {
76 	int i, ret;
77 	unsigned int v;
78 	const struct mdio_ops *mo = adapter_info(adap)->mdio_ops;
79 
80 	ELMR_LOCK(adap);
81 
82 	ret = mo->write(adap, ELMR_MDIO_ADDR, 0, ELMR_ADDR, start);
83 	if (ret)
84 		goto out;
85 
86 	for (i = 0; i < 5; i++) {
87 		ret = mo->read(adap, ELMR_MDIO_ADDR, 0, ELMR_STAT, &v);
88 		if (ret)
89 			goto out;
90 		if (v == 1)
91 			break;
92 		udelay(5);
93 	}
94 	if (v != 1) {
95 		ret = -ETIMEDOUT;
96 		goto out;
97 	}
98 
99 	for ( ; !ret && n; n--, vals++) {
100 		ret = mo->read(adap, ELMR_MDIO_ADDR, 0, ELMR_DATA_LO, vals);
101 		if (!ret) {
102 			ret = mo->read(adap, ELMR_MDIO_ADDR, 0, ELMR_DATA_HI,
103 				       &v);
104 			*vals |= v << 16;
105 		}
106 	}
107 out:	ELMR_UNLOCK(adap);
108 	return ret;
109 }
110 
111 int t3_vsc7323_init(adapter_t *adap, int nports)
112 {
113 	static struct addr_val_pair sys_avp[] = {
114 		{ VSC_REG(7, 15, 0xf),  2 },
115 		{ VSC_REG(7, 15, 0x19), 0xd6 },
116 		{ VSC_REG(7, 15, 7),    0xc },
117 		{ VSC_REG(7, 1, 0),     0x220 },
118 	};
119 	static struct addr_val_pair fifo_avp[] = {
120 		{ VSC_REG(2, 0, 0x2f), 0 },
121 		{ VSC_REG(2, 0, 0xf),  0xa0010291 },
122 		{ VSC_REG(2, 1, 0x2f), 1 },
123 		{ VSC_REG(2, 1, 0xf),  0xa026301 }
124 	};
125 	static struct addr_val_pair xg_avp[] = {
126 		{ VSC_REG(1, 10, 0),    0x600b },
127 		{ VSC_REG(1, 10, 1),    0x70600 }, //QUANTA = 96*1024*8/512
128 		{ VSC_REG(1, 10, 2),    0x2710 },
129 		{ VSC_REG(1, 10, 5),    0x65 },
130 		{ VSC_REG(1, 10, 7),    0x23 },
131 		{ VSC_REG(1, 10, 0x23), 0x800007bf },
132 		{ VSC_REG(1, 10, 0x23), 0x000007bf },
133 		{ VSC_REG(1, 10, 0x23), 0x800007bf },
134 		{ VSC_REG(1, 10, 0x24), 4 }
135 	};
136 
137 	int i, ret, ing_step, egr_step, ing_bot, egr_bot;
138 
139 	for (i = 0; i < ARRAY_SIZE(sys_avp); i++)
140 		if ((ret = t3_elmr_blk_write(adap, sys_avp[i].reg_addr,
141 					     &sys_avp[i].val, 1)))
142 			return ret;
143 
144 	ing_step = 0xc0 / nports;
145 	egr_step = 0x40 / nports;
146 	ing_bot = egr_bot = 0;
147 //	ing_wm = ing_step * 64;
148 //	egr_wm = egr_step * 64;
149 
150 	/* {ING,EGR}_CONTROL.CLR = 1 here */
151 	for (i = 0; i < nports; i++) {
152 		if (
153 		    (ret = elmr_write(adap, VSC_REG(2, 0, 0x10 + i),
154 				((ing_bot + ing_step) << 16) | ing_bot)) ||
155 		    (ret = elmr_write(adap, VSC_REG(2, 0, 0x40 + i),
156 				0x6000bc0)) ||
157 		    (ret = elmr_write(adap, VSC_REG(2, 0, 0x50 + i), 1)) ||
158 		    (ret = elmr_write(adap, VSC_REG(2, 1, 0x10 + i),
159 				((egr_bot + egr_step) << 16) | egr_bot)) ||
160 		    (ret = elmr_write(adap, VSC_REG(2, 1, 0x40 + i),
161 				0x2000280)) ||
162 		    (ret = elmr_write(adap, VSC_REG(2, 1, 0x50 + i), 0)))
163 			return ret;
164 		ing_bot += ing_step;
165 		egr_bot += egr_step;
166 	}
167 
168 	for (i = 0; i < ARRAY_SIZE(fifo_avp); i++)
169 		if ((ret = t3_elmr_blk_write(adap, fifo_avp[i].reg_addr,
170 					     &fifo_avp[i].val, 1)))
171 			return ret;
172 
173 	for (i = 0; i < ARRAY_SIZE(xg_avp); i++)
174 		if ((ret = t3_elmr_blk_write(adap, xg_avp[i].reg_addr,
175 					     &xg_avp[i].val, 1)))
176 			return ret;
177 
178 	for (i = 0; i < nports; i++)
179 		if ((ret = elmr_write(adap, VSC_REG(1, i, 0), 0xa59c)) ||
180 		    (ret = elmr_write(adap, VSC_REG(1, i, 5),
181 				 (i << 12) | 0x63)) ||
182 		    (ret = elmr_write(adap, VSC_REG(1, i, 0xb), 0x96)) ||
183 		    (ret = elmr_write(adap, VSC_REG(1, i, 0x15), 0x21)) ||
184 		    (ret = elmr_write(adap, ELMR_THRES0 + i, 768)))
185 			return ret;
186 
187 	if ((ret = elmr_write(adap, ELMR_BW, 7)))
188 		return ret;
189 
190 	return ret;
191 }
192 
193 int t3_vsc7323_set_speed_fc(adapter_t *adap, int speed, int fc, int port)
194 {
195 	int mode, clk, r;
196 
197 	if (speed >= 0) {
198 		if (speed == SPEED_10)
199 			mode = clk = 1;
200 		else if (speed == SPEED_100)
201 			mode = 1, clk = 2;
202 		else if (speed == SPEED_1000)
203 			mode = clk = 3;
204 		else
205 			return -EINVAL;
206 
207 		if ((r = elmr_write(adap, VSC_REG(1, port, 0),
208 				    0xa590 | (mode << 2))) ||
209 		    (r = elmr_write(adap, VSC_REG(1, port, 0xb),
210 				    0x91 | (clk << 1))) ||
211 		    (r = elmr_write(adap, VSC_REG(1, port, 0xb),
212 				    0x90 | (clk << 1))) ||
213 		    (r = elmr_write(adap, VSC_REG(1, port, 0),
214 				    0xa593 | (mode << 2))))
215 			return r;
216 	}
217 
218 	r = (fc & PAUSE_RX) ? 0x60200 : 0x20200; //QUANTA = 32*1024*8/512
219 	if (fc & PAUSE_TX)
220 		r |= (1 << 19);
221 	return elmr_write(adap, VSC_REG(1, port, 1), r);
222 }
223 
224 int t3_vsc7323_set_mtu(adapter_t *adap, unsigned int mtu, int port)
225 {
226 	return elmr_write(adap, VSC_REG(1, port, 2), mtu);
227 }
228 
229 int t3_vsc7323_set_addr(adapter_t *adap, u8 addr[6], int port)
230 {
231 	int ret;
232 
233 	ret = elmr_write(adap, VSC_REG(1, port, 3),
234 			 (addr[0] << 16) | (addr[1] << 8) | addr[2]);
235 	if (!ret)
236 		ret = elmr_write(adap, VSC_REG(1, port, 4),
237 				 (addr[3] << 16) | (addr[4] << 8) | addr[5]);
238 	return ret;
239 }
240 
241 int t3_vsc7323_enable(adapter_t *adap, int port, int which)
242 {
243 	int ret;
244 	unsigned int v, orig;
245 
246 	ret = t3_elmr_blk_read(adap, VSC_REG(1, port, 0), &v, 1);
247 	if (!ret) {
248 		orig = v;
249 		if (which & MAC_DIRECTION_TX)
250 			v |= 1;
251 		if (which & MAC_DIRECTION_RX)
252 			v |= 2;
253 		if (v != orig)
254 			ret = elmr_write(adap, VSC_REG(1, port, 0), v);
255 	}
256 	return ret;
257 }
258 
259 int t3_vsc7323_disable(adapter_t *adap, int port, int which)
260 {
261 	int ret;
262 	unsigned int v, orig;
263 
264 	ret = t3_elmr_blk_read(adap, VSC_REG(1, port, 0), &v, 1);
265 	if (!ret) {
266 		orig = v;
267 		if (which & MAC_DIRECTION_TX)
268 			v &= ~1;
269 		if (which & MAC_DIRECTION_RX)
270 			v &= ~2;
271 		if (v != orig)
272 			ret = elmr_write(adap, VSC_REG(1, port, 0), v);
273 	}
274 	return ret;
275 }
276 
277 #define STATS0_START 1
278 #define STATS1_START 0x24
279 #define NSTATS0 (0x1d - STATS0_START + 1)
280 #define NSTATS1 (0x2a - STATS1_START + 1)
281 
282 #define ELMR_STAT(port, reg) (ELMR_STATS + port * 0x40 + reg)
283 
284 const struct mac_stats *t3_vsc7323_update_stats(struct cmac *mac)
285 {
286 	int ret;
287 	u64 rx_ucast, tx_ucast;
288 	u32 stats0[NSTATS0], stats1[NSTATS1];
289 
290 	ret = t3_elmr_blk_read(mac->adapter,
291 			       ELMR_STAT(mac->ext_port, STATS0_START),
292 			       stats0, NSTATS0);
293 	if (!ret)
294 		ret = t3_elmr_blk_read(mac->adapter,
295 				       ELMR_STAT(mac->ext_port, STATS1_START),
296 				       stats1, NSTATS1);
297 	if (ret)
298 		goto out;
299 
300 	/*
301 	 * HW counts Rx/Tx unicast frames but we want all the frames.
302 	 */
303 	rx_ucast = mac->stats.rx_frames - mac->stats.rx_mcast_frames -
304 		   mac->stats.rx_bcast_frames;
305 	rx_ucast += (u64)(stats0[6 - STATS0_START] - (u32)rx_ucast);
306 	tx_ucast = mac->stats.tx_frames - mac->stats.tx_mcast_frames -
307 		   mac->stats.tx_bcast_frames;
308 	tx_ucast += (u64)(stats0[27 - STATS0_START] - (u32)tx_ucast);
309 
310 #define RMON_UPDATE(mac, name, hw_stat) \
311 	mac->stats.name += (u64)((hw_stat) - (u32)(mac->stats.name))
312 
313 	RMON_UPDATE(mac, rx_octets, stats0[4 - STATS0_START]);
314 	RMON_UPDATE(mac, rx_frames, stats0[6 - STATS0_START]);
315 	RMON_UPDATE(mac, rx_frames, stats0[7 - STATS0_START]);
316 	RMON_UPDATE(mac, rx_frames, stats0[8 - STATS0_START]);
317 	RMON_UPDATE(mac, rx_mcast_frames, stats0[7 - STATS0_START]);
318 	RMON_UPDATE(mac, rx_bcast_frames, stats0[8 - STATS0_START]);
319 	RMON_UPDATE(mac, rx_fcs_errs, stats0[9 - STATS0_START]);
320 	RMON_UPDATE(mac, rx_pause, stats0[2 - STATS0_START]);
321 	RMON_UPDATE(mac, rx_jabber, stats0[16 - STATS0_START]);
322 	RMON_UPDATE(mac, rx_short, stats0[11 - STATS0_START]);
323 	RMON_UPDATE(mac, rx_symbol_errs, stats0[1 - STATS0_START]);
324 	RMON_UPDATE(mac, rx_too_long, stats0[15 - STATS0_START]);
325 
326 	RMON_UPDATE(mac, rx_frames_64,        stats0[17 - STATS0_START]);
327 	RMON_UPDATE(mac, rx_frames_65_127,    stats0[18 - STATS0_START]);
328 	RMON_UPDATE(mac, rx_frames_128_255,   stats0[19 - STATS0_START]);
329 	RMON_UPDATE(mac, rx_frames_256_511,   stats0[20 - STATS0_START]);
330 	RMON_UPDATE(mac, rx_frames_512_1023,  stats0[21 - STATS0_START]);
331 	RMON_UPDATE(mac, rx_frames_1024_1518, stats0[22 - STATS0_START]);
332 	RMON_UPDATE(mac, rx_frames_1519_max,  stats0[23 - STATS0_START]);
333 
334 	RMON_UPDATE(mac, tx_octets, stats0[26 - STATS0_START]);
335 	RMON_UPDATE(mac, tx_frames, stats0[27 - STATS0_START]);
336 	RMON_UPDATE(mac, tx_frames, stats0[28 - STATS0_START]);
337 	RMON_UPDATE(mac, tx_frames, stats0[29 - STATS0_START]);
338 	RMON_UPDATE(mac, tx_mcast_frames, stats0[28 - STATS0_START]);
339 	RMON_UPDATE(mac, tx_bcast_frames, stats0[29 - STATS0_START]);
340 	RMON_UPDATE(mac, tx_pause, stats0[25 - STATS0_START]);
341 
342 	RMON_UPDATE(mac, tx_underrun, 0);
343 
344 	RMON_UPDATE(mac, tx_frames_64,        stats1[36 - STATS1_START]);
345 	RMON_UPDATE(mac, tx_frames_65_127,    stats1[37 - STATS1_START]);
346 	RMON_UPDATE(mac, tx_frames_128_255,   stats1[38 - STATS1_START]);
347 	RMON_UPDATE(mac, tx_frames_256_511,   stats1[39 - STATS1_START]);
348 	RMON_UPDATE(mac, tx_frames_512_1023,  stats1[40 - STATS1_START]);
349 	RMON_UPDATE(mac, tx_frames_1024_1518, stats1[41 - STATS1_START]);
350 	RMON_UPDATE(mac, tx_frames_1519_max,  stats1[42 - STATS1_START]);
351 
352 #undef RMON_UPDATE
353 
354 	mac->stats.rx_frames = rx_ucast + mac->stats.rx_mcast_frames +
355 			       mac->stats.rx_bcast_frames;
356 	mac->stats.tx_frames = tx_ucast + mac->stats.tx_mcast_frames +
357 			       mac->stats.tx_bcast_frames;
358 out:    return &mac->stats;
359 }
360