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