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