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