1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (C) 2003-2005 Chelsio Communications. All rights reserved.
24 */
25
26 #pragma ident "%Z%%M% %I% %E% SMI"
27
28 /* Driver for Vitesse VSC7326 (Schaumburg) MAC */
29
30 #include "gmac.h"
31 #include "elmer0.h"
32 #include "vsc7326_reg.h"
33
34 FILE_IDENT("@(#) $Id: vsc7326.c,v 1.17 2005/10/29 05:42:36 sbardone Exp $");
35
36 /* Update fast changing statistics every 15 seconds */
37 #define STATS_TICK_SECS 15
38 /* 30 minutes for full statistics update */
39 #define MAJOR_UPDATE_TICKS (1800 / STATS_TICK_SECS)
40
41 #define MAX_MTU 9600
42
43 struct init_table {
44 u32 addr;
45 u32 data;
46 };
47
48 struct _cmac_instance {
49 u32 index;
50 u32 ticks;
51 };
52
53 #define INITBLOCK_SLEEP 0xffffffff
54
vsc_read(adapter_t * adapter,u32 addr,u32 * val)55 static void vsc_read(adapter_t *adapter, u32 addr, u32 *val)
56 {
57 u32 status, vlo, vhi;
58 int i;
59
60 MAC_LOCK(adapter->mac_lock);
61 (void) t1_tpi_read(adapter, (addr << 2) + 4, &vlo);
62 i = 0;
63 do {
64 (void) t1_tpi_read(adapter, (REG_LOCAL_STATUS << 2) + 4, &vlo);
65 (void) t1_tpi_read(adapter, REG_LOCAL_STATUS << 2, &vhi);
66 status = (vhi << 16) | vlo;
67 i++;
68 } while (((status & 1) == 0) && (i < 50));
69 if (i == 50)
70 CH_ERR("Invalid tpi read from MAC, breaking loop.\n");
71
72 (void) t1_tpi_read(adapter, (REG_LOCAL_DATA << 2) + 4, &vlo);
73 (void) t1_tpi_read(adapter, REG_LOCAL_DATA << 2, &vhi);
74
75 *val = (vhi << 16) | vlo;
76
77 /* CH_ERR("rd: block: 0x%x sublock: 0x%x reg: 0x%x data: 0x%x\n",
78 ((addr&0xe000)>>13), ((addr&0x1e00)>>9),
79 ((addr&0x01fe)>>1), *val); */
80 MAC_UNLOCK(adapter->mac_lock);
81 }
82
vsc_write(adapter_t * adapter,u32 addr,u32 data)83 static void vsc_write(adapter_t *adapter, u32 addr, u32 data)
84 {
85 MAC_LOCK(adapter->mac_lock);
86 (void) t1_tpi_write(adapter, (addr << 2) + 4, data & 0xFFFF);
87 (void) t1_tpi_write(adapter, addr << 2, (data >> 16) & 0xFFFF);
88 /* CH_ERR("wr: block: 0x%x sublock: 0x%x reg: 0x%x data: 0x%x\n",
89 ((addr&0xe000)>>13), ((addr&0x1e00)>>9),
90 ((addr&0x01fe)>>1), data); */
91 MAC_UNLOCK(adapter->mac_lock);
92 }
93
94 /* Hard reset the MAC. This wipes out *all* configuration. */
vsc7326_full_reset(adapter_t * adapter)95 static void vsc7326_full_reset(adapter_t* adapter)
96 {
97 u32 val;
98 u32 result = 0xffff;
99
100 (void) t1_tpi_read(adapter, A_ELMER0_GPO, &val);
101 val &= ~1;
102 (void) t1_tpi_write(adapter, A_ELMER0_GPO, val);
103 DELAY_US(2);
104 val |= 0x1; /* Enable mac MAC itself */
105 val |= 0x800; /* Turn off the red LED */
106 (void) t1_tpi_write(adapter, A_ELMER0_GPO, val);
107 DELAY_MS(1);
108 vsc_write(adapter, REG_SW_RESET, 0x80000001);
109 do {
110 DELAY_MS(1);
111 vsc_read(adapter, REG_SW_RESET, &result);
112 } while (result != 0x0);
113 }
114
115 static struct init_table vsc7326_reset[] = {
116 { REG_IFACE_MODE, 0x00000000 },
117 { REG_CRC_CFG, 0x00000020 },
118 { REG_PLL_CLK_SPEED, 0x00050c00 },
119 { REG_PLL_CLK_SPEED, 0x00050c00 },
120 { REG_MSCH, 0x00002f14 },
121 { REG_SPI4_MISC, 0x00040409 },
122 { REG_SPI4_DESKEW, 0x00080000 },
123 { REG_SPI4_ING_SETUP2, 0x08080004 },
124 { REG_SPI4_ING_SETUP0, 0x04111004 },
125 { REG_SPI4_EGR_SETUP0, 0x80001a04 },
126 { REG_SPI4_ING_SETUP1, 0x02010000 },
127 { REG_AGE_INC(0), 0x00000000 },
128 { REG_AGE_INC(1), 0x00000000 },
129 { REG_ING_CONTROL, 0x0a200011 },
130 { REG_EGR_CONTROL, 0xa0010091 },
131 };
132
133 static struct init_table vsc7326_portinit[4][22] = {
134 { /* Port 0 */
135 /* FIFO setup */
136 { REG_DBG(0), 0x000004f0 },
137 { REG_HDX(0), 0x00073101 },
138 { REG_TEST(0,0), 0x00000022 },
139 { REG_TEST(1,0), 0x00000022 },
140 { REG_TOP_BOTTOM(0,0), 0x003f0000 },
141 { REG_TOP_BOTTOM(1,0), 0x00120000 },
142 { REG_HIGH_LOW_WM(0,0), 0x07460757 },
143 { REG_HIGH_LOW_WM(1,0), 0x01a01fff },
144 { REG_CT_THRHLD(0,0), 0x00000000 },
145 { REG_CT_THRHLD(1,0), 0x00000000 },
146 { REG_BUCKE(0), 0x0002ffff },
147 { REG_BUCKI(0), 0x0002ffff },
148 { REG_TEST(0,0), 0x00000020 },
149 { REG_TEST(1,0), 0x00000020 },
150 /* Port config */
151 { REG_MAX_LEN(0), 0x00002710 },
152 { REG_PORT_FAIL(0), 0x00000002 },
153 { REG_NORMALIZER(0), 0x00000a64 },
154 { REG_DENORM(0), 0x00000010 },
155 { REG_STICK_BIT(0), 0x03baa370 },
156 { REG_DEV_SETUP(0), 0x00000083 },
157 { REG_DEV_SETUP(0), 0x00000082 },
158 { REG_MODE_CFG(0), 0x0200259f },
159 },
160 { /* Port 1 */
161 /* FIFO setup */
162 { REG_DBG(1), 0x000004f0 },
163 { REG_HDX(1), 0x00073101 },
164 { REG_TEST(0,1), 0x00000022 },
165 { REG_TEST(1,1), 0x00000022 },
166 { REG_TOP_BOTTOM(0,1), 0x007e003f },
167 { REG_TOP_BOTTOM(1,1), 0x00240012 },
168 { REG_HIGH_LOW_WM(0,1), 0x07460757 },
169 { REG_HIGH_LOW_WM(1,1), 0x01a01fff },
170 { REG_CT_THRHLD(0,1), 0x00000000 },
171 { REG_CT_THRHLD(1,1), 0x00000000 },
172 { REG_BUCKE(1), 0x0002ffff },
173 { REG_BUCKI(1), 0x0002ffff },
174 { REG_TEST(0,1), 0x00000020 },
175 { REG_TEST(1,1), 0x00000020 },
176 /* Port config */
177 { REG_MAX_LEN(1), 0x00002710 },
178 { REG_PORT_FAIL(1), 0x00000002 },
179 { REG_NORMALIZER(1), 0x00000a64 },
180 { REG_DENORM(1), 0x00000010 },
181 { REG_STICK_BIT(1), 0x03baa370 },
182 { REG_DEV_SETUP(1), 0x00000083 },
183 { REG_DEV_SETUP(1), 0x00000082 },
184 { REG_MODE_CFG(1), 0x0200259f },
185 },
186 { /* Port 2 */
187 /* FIFO setup */
188 { REG_DBG(2), 0x000004f0 },
189 { REG_HDX(2), 0x00073101 },
190 { REG_TEST(0,2), 0x00000022 },
191 { REG_TEST(1,2), 0x00000022 },
192 { REG_TOP_BOTTOM(0,2), 0x00bd007e },
193 { REG_TOP_BOTTOM(1,2), 0x00360024 },
194 { REG_HIGH_LOW_WM(0,2), 0x07460757 },
195 { REG_HIGH_LOW_WM(1,2), 0x01a01fff },
196 { REG_CT_THRHLD(0,2), 0x00000000 },
197 { REG_CT_THRHLD(1,2), 0x00000000 },
198 { REG_BUCKE(2), 0x0002ffff },
199 { REG_BUCKI(2), 0x0002ffff },
200 { REG_TEST(0,2), 0x00000020 },
201 { REG_TEST(1,2), 0x00000020 },
202 /* Port config */
203 { REG_MAX_LEN(2), 0x00002710 },
204 { REG_PORT_FAIL(2), 0x00000002 },
205 { REG_NORMALIZER(2), 0x00000a64 },
206 { REG_DENORM(2), 0x00000010 },
207 { REG_STICK_BIT(2), 0x03baa370 },
208 { REG_DEV_SETUP(2), 0x00000083 },
209 { REG_DEV_SETUP(2), 0x00000082 },
210 { REG_MODE_CFG(2), 0x0200259f },
211 },
212 { /* Port 3 */
213 /* FIFO setup */
214 { REG_DBG(3), 0x000004f0 },
215 { REG_HDX(3), 0x00073101 },
216 { REG_TEST(0,3), 0x00000022 },
217 { REG_TEST(1,3), 0x00000022 },
218 { REG_TOP_BOTTOM(0,3), 0x00fc00bd },
219 { REG_TOP_BOTTOM(1,3), 0x00480036 },
220 { REG_HIGH_LOW_WM(0,3), 0x07460757 },
221 { REG_HIGH_LOW_WM(1,3), 0x01a01fff },
222 { REG_CT_THRHLD(0,3), 0x00000000 },
223 { REG_CT_THRHLD(1,3), 0x00000000 },
224 { REG_BUCKE(3), 0x0002ffff },
225 { REG_BUCKI(3), 0x0002ffff },
226 { REG_TEST(0,3), 0x00000020 },
227 { REG_TEST(1,3), 0x00000020 },
228 /* Port config */
229 { REG_MAX_LEN(3), 0x00002710 },
230 { REG_PORT_FAIL(3), 0x00000002 },
231 { REG_NORMALIZER(3), 0x00000a64 },
232 { REG_DENORM(3), 0x00000010 },
233 { REG_STICK_BIT(3), 0x03baa370 },
234 { REG_DEV_SETUP(3), 0x00000083 },
235 { REG_DEV_SETUP(3), 0x00000082 },
236 { REG_MODE_CFG(3), 0x0200259f },
237 },
238 };
239
run_table(adapter_t * adapter,struct init_table * ib,int len)240 static void run_table(adapter_t *adapter, struct init_table *ib, int len)
241 {
242 int i;
243
244 for (i = 0; i < len; i++) {
245 if (ib[i].addr == INITBLOCK_SLEEP) {
246 DELAY_US( ib[i].data );
247 CH_ERR("sleep %d us\n",ib[i].data);
248 } else {
249 vsc_write( adapter, ib[i].addr, ib[i].data );
250 }
251 }
252 }
253
bist_rd(adapter_t * adapter,int moduleid,int address)254 static int bist_rd(adapter_t *adapter, int moduleid, int address)
255 {
256 int data=0;
257 u32 result=0;
258
259 if( (address != 0x0) &&
260 (address != 0x1) &&
261 (address != 0x2) &&
262 (address != 0xd) &&
263 (address != 0xe))
264 CH_ERR("No bist address: 0x%x\n", address);
265
266 data = ((0x00 << 24) | ((address & 0xff) << 16) | (0x00 << 8) |
267 ((moduleid & 0xff) << 0));
268 vsc_write(adapter, REG_RAM_BIST_CMD, data);
269
270 DELAY_US(10);
271
272 vsc_read(adapter, REG_RAM_BIST_RESULT, &result);
273 if((result & (1<<9)) != 0x0)
274 CH_ERR("Still in bist read: 0x%x\n", result);
275 else if((result & (1<<8)) != 0x0)
276 CH_ERR("bist read error: 0x%x\n", result);
277
278 return(result & 0xff);
279 }
280
bist_wr(adapter_t * adapter,int moduleid,int address,int value)281 static int bist_wr(adapter_t *adapter, int moduleid, int address, int value)
282 {
283 int data=0;
284 u32 result=0;
285
286 if( (address != 0x0) &&
287 (address != 0x1) &&
288 (address != 0x2) &&
289 (address != 0xd) &&
290 (address != 0xe))
291 CH_ERR("No bist address: 0x%x\n", address);
292
293 if( value>255 )
294 CH_ERR("Suspicious write out of range value: 0x%x\n", value);
295
296 data = ((0x01 << 24) | ((address & 0xff) << 16) | (value << 8) |
297 ((moduleid & 0xff) << 0));
298 vsc_write(adapter, REG_RAM_BIST_CMD, data);
299
300 DELAY_US(5);
301
302 vsc_read(adapter, REG_RAM_BIST_CMD, &result);
303 if((result & (1<<27)) != 0x0)
304 CH_ERR("Still in bist write: 0x%x\n", result);
305 else if((result & (1<<26)) != 0x0)
306 CH_ERR("bist write error: 0x%x\n", result);
307
308 return(0);
309 }
310
run_bist(adapter_t * adapter,int moduleid)311 static int run_bist(adapter_t *adapter, int moduleid)
312 {
313 /*run bist*/
314 (void) bist_wr(adapter,moduleid, 0x00, 0x02);
315 (void) bist_wr(adapter,moduleid, 0x01, 0x01);
316
317 return(0);
318 }
319
check_bist(adapter_t * adapter,int moduleid)320 static int check_bist(adapter_t *adapter, int moduleid)
321 {
322 int result=0;
323 int column=0;
324 /*check bist*/
325 result = bist_rd(adapter,moduleid, 0x02);
326 column = ((bist_rd(adapter,moduleid, 0x0e)<<8) +
327 (bist_rd(adapter,moduleid, 0x0d)));
328 if ((result & 3) != 0x3)
329 CH_ERR("Result: 0x%x BIST error in ram %d, column: 0x%04x\n",
330 result, moduleid, column);
331 return(0);
332 }
333
enable_mem(adapter_t * adapter,int moduleid)334 static int enable_mem(adapter_t *adapter, int moduleid)
335 {
336 /*enable mem*/
337 (void) bist_wr(adapter,moduleid, 0x00, 0x00);
338 return(0);
339 }
340
run_bist_all(adapter_t * adapter)341 static int run_bist_all(adapter_t *adapter)
342 {
343 int port=0;
344 u32 val=0;
345
346 vsc_write(adapter, REG_MEM_BIST, 0x5);
347 vsc_read(adapter, REG_MEM_BIST, &val);
348
349 for(port=0; port<12; port++){
350 vsc_write(adapter, REG_DEV_SETUP(port), 0x0);
351 }
352
353 DELAY_US(300);
354 vsc_write(adapter, REG_SPI4_MISC, 0x00040409);
355 DELAY_US(300);
356
357 (void) run_bist(adapter,13);
358 (void) run_bist(adapter,14);
359 (void) run_bist(adapter,20);
360 (void) run_bist(adapter,21);
361 DELAY_MS(200);
362 (void) check_bist(adapter,13);
363 (void) check_bist(adapter,14);
364 (void) check_bist(adapter,20);
365 (void) check_bist(adapter,21);
366 DELAY_US(100);
367 (void) enable_mem(adapter,13);
368 (void) enable_mem(adapter,14);
369 (void) enable_mem(adapter,20);
370 (void) enable_mem(adapter,21);
371 DELAY_US(300);
372 vsc_write(adapter, REG_SPI4_MISC, 0x60040400);
373 DELAY_US(300);
374 for(port=0; port<12; port++){
375 vsc_write(adapter, REG_DEV_SETUP(port), 0x1);
376 }
377 DELAY_US(300);
378 vsc_write(adapter, REG_MEM_BIST, 0x0);
379 DELAY_MS(10);
380 return(0);
381 }
382
383 /* ARGSUSED */
mac_intr_handler(struct cmac * mac)384 static int mac_intr_handler(struct cmac *mac)
385 {
386 return 0;
387 }
388
389 /* ARGSUSED */
mac_intr_enable(struct cmac * mac)390 static int mac_intr_enable(struct cmac *mac)
391 {
392 return 0;
393 }
394
395 /* ARGSUSED */
mac_intr_disable(struct cmac * mac)396 static int mac_intr_disable(struct cmac *mac)
397 {
398 return 0;
399 }
400
401 /* ARGSUSED */
mac_intr_clear(struct cmac * mac)402 static int mac_intr_clear(struct cmac *mac)
403 {
404 return 0;
405 }
406
407 /* Expect MAC address to be in network byte order. */
mac_set_address(struct cmac * mac,u8 addr[6])408 static int mac_set_address(struct cmac* mac, u8 addr[6])
409 {
410 u32 val;
411 int port = mac->instance->index;
412
413 vsc_write(mac->adapter, REG_MAC_LOW_ADDR(port),
414 (addr[3] << 16) | (addr[4] << 8) | addr[5]);
415 vsc_write(mac->adapter, REG_MAC_HIGH_ADDR(port),
416 (addr[0] << 16) | (addr[1] << 8) | addr[2]);
417
418 vsc_read(mac->adapter, REG_ING_FFILT_UM_EN, &val);
419 val &= ~0xf0000000;
420 vsc_write(mac->adapter, REG_ING_FFILT_UM_EN, val | (port << 28));
421
422 vsc_write(mac->adapter, REG_ING_FFILT_MASK0,
423 0xffff0000 | (addr[4] << 8) | addr[5]);
424 vsc_write(mac->adapter, REG_ING_FFILT_MASK1,
425 0xffff0000 | (addr[2] << 8) | addr[3]);
426 vsc_write(mac->adapter, REG_ING_FFILT_MASK2,
427 0xffff0000 | (addr[0] << 8) | addr[1]);
428 return 0;
429 }
430
mac_get_address(struct cmac * mac,u8 addr[6])431 static int mac_get_address(struct cmac *mac, u8 addr[6])
432 {
433 u32 addr_lo, addr_hi;
434 int port = mac->instance->index;
435
436 vsc_read(mac->adapter, REG_MAC_LOW_ADDR(port), &addr_lo);
437 vsc_read(mac->adapter, REG_MAC_HIGH_ADDR(port), &addr_hi);
438
439 addr[0] = (u8) (addr_hi >> 16);
440 addr[1] = (u8) (addr_hi >> 8);
441 addr[2] = (u8) addr_hi;
442 addr[3] = (u8) (addr_lo >> 16);
443 addr[4] = (u8) (addr_lo >> 8);
444 addr[5] = (u8) addr_lo;
445 return 0;
446 }
447
448 /* This is intended to reset a port, not the whole MAC */
mac_reset(struct cmac * mac)449 static int mac_reset(struct cmac *mac)
450 {
451 int index = mac->instance->index;
452
453 run_table(mac->adapter, vsc7326_portinit[index],
454 DIMOF(vsc7326_portinit[index]));
455
456 return 0;
457 }
458
mac_set_rx_mode(struct cmac * mac,struct t1_rx_mode * rm)459 static int mac_set_rx_mode(struct cmac *mac, struct t1_rx_mode *rm)
460 {
461 u32 v;
462 int port = mac->instance->index;
463
464 vsc_read(mac->adapter, REG_ING_FFILT_UM_EN, &v);
465 v |= 1 << 12;
466
467 if (t1_rx_mode_promisc(rm))
468 v &= ~(1 << (port + 16));
469 else
470 v |= 1 << (port + 16);
471
472 vsc_write(mac->adapter, REG_ING_FFILT_UM_EN, v);
473 return 0;
474 }
475
mac_set_mtu(struct cmac * mac,int mtu)476 static int mac_set_mtu(struct cmac *mac, int mtu)
477 {
478 int port = mac->instance->index;
479
480 if (mtu > MAX_MTU)
481 return -EINVAL;
482
483 /* max_len includes header and FCS */
484 vsc_write(mac->adapter, REG_MAX_LEN(port), mtu + 14 + 4);
485 return 0;
486 }
487
mac_set_speed_duplex_fc(struct cmac * mac,int speed,int duplex,int fc)488 static int mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex,
489 int fc)
490 {
491 u32 v;
492 int enable, port = mac->instance->index;
493
494 if (speed >= 0 && speed != SPEED_10 && speed != SPEED_100 &&
495 speed != SPEED_1000)
496 return -1;
497 if (duplex > 0 && duplex != DUPLEX_FULL)
498 return -1;
499
500 if (speed >= 0) {
501 vsc_read(mac->adapter, REG_MODE_CFG(port), &v);
502 enable = v & 3; /* save tx/rx enables */
503 v &= ~0xf;
504 v |= 4; /* full duplex */
505 if (speed == SPEED_1000)
506 v |= 8; /* GigE */
507 enable |= v;
508 vsc_write(mac->adapter, REG_MODE_CFG(port), v);
509
510 if (speed == SPEED_1000)
511 v = 0x82;
512 else if (speed == SPEED_100)
513 v = 0x84;
514 else /* SPEED_10 */
515 v = 0x86;
516 vsc_write(mac->adapter, REG_DEV_SETUP(port), v | 1); /* reset */
517 vsc_write(mac->adapter, REG_DEV_SETUP(port), v);
518 vsc_read(mac->adapter, REG_DBG(port), &v);
519 v &= ~0xff00;
520 if (speed == SPEED_1000)
521 v |= 0x400;
522 else if (speed == SPEED_100)
523 v |= 0x2000;
524 else /* SPEED_10 */
525 v |= 0xff00;
526 vsc_write(mac->adapter, REG_DBG(port), v);
527
528 vsc_write(mac->adapter, REG_TX_IFG(port),
529 speed == SPEED_1000 ? 5 : 0x11);
530 if (duplex == DUPLEX_HALF)
531 enable = 0x0; /* 100 or 10 */
532 else if (speed == SPEED_1000)
533 enable = 0xc;
534 else /* SPEED_100 or 10 */
535 enable = 0x4;
536 enable |= 0x9 << 10; /* IFG1 */
537 enable |= 0x6 << 6; /* IFG2 */
538 enable |= 0x1 << 4; /* VLAN */
539 enable |= 0x3; /* RX/TX EN */
540 vsc_write(mac->adapter, REG_MODE_CFG(port), enable);
541
542 }
543
544 vsc_read(mac->adapter, REG_PAUSE_CFG(port), &v);
545 v &= 0xfff0ffff;
546 v |= 0x20000; /* xon/xoff */
547 if (fc & PAUSE_RX)
548 v |= 0x40000;
549 if (fc & PAUSE_TX)
550 v |= 0x80000;
551 if (fc == (PAUSE_RX | PAUSE_TX))
552 v |= 0x10000;
553 vsc_write(mac->adapter, REG_PAUSE_CFG(port), v);
554 return 0;
555 }
556
mac_enable(struct cmac * mac,int which)557 static int mac_enable(struct cmac *mac, int which)
558 {
559 u32 val;
560 int port = mac->instance->index;
561
562 vsc_read(mac->adapter, REG_MODE_CFG(port), &val);
563 if (which & MAC_DIRECTION_RX)
564 val |= 0x2;
565 if (which & MAC_DIRECTION_TX)
566 val |= 1;
567 vsc_write(mac->adapter, REG_MODE_CFG(port), val);
568 return 0;
569 }
570
mac_disable(struct cmac * mac,int which)571 static int mac_disable(struct cmac *mac, int which)
572 {
573 u32 val;
574 int i, port = mac->instance->index;
575
576 /* Reset the port */
577 (void) mac_reset(mac);
578
579 vsc_read(mac->adapter, REG_MODE_CFG(port), &val);
580 if (which & MAC_DIRECTION_RX)
581 val &= ~0x2;
582 if (which & MAC_DIRECTION_TX)
583 val &= ~0x1;
584 vsc_write(mac->adapter, REG_MODE_CFG(port), val);
585 vsc_read(mac->adapter, REG_MODE_CFG(port), &val);
586
587 /* Clear stats */
588 for (i = 0; i <= 0x3a; ++i)
589 vsc_write(mac->adapter, CRA(4, port, i), 0);
590
591 /* Clear sofware counters */
592 memset(&mac->stats, 0, sizeof(struct cmac_statistics));
593
594 return 0;
595 }
596
rmon_update(struct cmac * mac,unsigned int addr,u64 * stat)597 static void rmon_update(struct cmac *mac, unsigned int addr, u64 *stat)
598 {
599 u32 v, lo;
600
601 vsc_read(mac->adapter, addr, &v);
602 lo = *stat;
603 *stat = *stat - lo + v;
604
605 if (v == 0)
606 return;
607
608 if (v < lo)
609 *stat += (1ULL << 32);
610 }
611
port_stats_update(struct cmac * mac)612 static void port_stats_update(struct cmac *mac)
613 {
614 int port = mac->instance->index;
615
616 /* Rx stats */
617 rmon_update(mac, REG_RX_OK_BYTES(port), &mac->stats.RxOctetsOK);
618 rmon_update(mac, REG_RX_BAD_BYTES(port), &mac->stats.RxOctetsBad);
619 rmon_update(mac, REG_RX_UNICAST(port), &mac->stats.RxUnicastFramesOK);
620 rmon_update(mac, REG_RX_MULTICAST(port),
621 &mac->stats.RxMulticastFramesOK);
622 rmon_update(mac, REG_RX_BROADCAST(port),
623 &mac->stats.RxBroadcastFramesOK);
624 rmon_update(mac, REG_CRC(port), &mac->stats.RxFCSErrors);
625 rmon_update(mac, REG_RX_ALIGNMENT(port), &mac->stats.RxAlignErrors);
626 rmon_update(mac, REG_RX_OVERSIZE(port),
627 &mac->stats.RxFrameTooLongErrors);
628 rmon_update(mac, REG_RX_PAUSE(port), &mac->stats.RxPauseFrames);
629 rmon_update(mac, REG_RX_JABBERS(port), &mac->stats.RxJabberErrors);
630 rmon_update(mac, REG_RX_FRAGMENTS(port), &mac->stats.RxRuntErrors);
631 rmon_update(mac, REG_RX_UNDERSIZE(port), &mac->stats.RxRuntErrors);
632 rmon_update(mac, REG_RX_SYMBOL_CARRIER(port),
633 &mac->stats.RxSymbolErrors);
634 rmon_update(mac, REG_RX_SIZE_1519_TO_MAX(port),
635 &mac->stats.RxJumboFramesOK);
636
637 /* Tx stats (skip collision stats as we are full-duplex only) */
638 rmon_update(mac, REG_TX_OK_BYTES(port), &mac->stats.TxOctetsOK);
639 rmon_update(mac, REG_TX_UNICAST(port), &mac->stats.TxUnicastFramesOK);
640 rmon_update(mac, REG_TX_MULTICAST(port),
641 &mac->stats.TxMulticastFramesOK);
642 rmon_update(mac, REG_TX_BROADCAST(port),
643 &mac->stats.TxBroadcastFramesOK);
644 rmon_update(mac, REG_TX_PAUSE(port), &mac->stats.TxPauseFrames);
645 rmon_update(mac, REG_TX_UNDERRUN(port), &mac->stats.TxUnderrun);
646 rmon_update(mac, REG_TX_SIZE_1519_TO_MAX(port),
647 &mac->stats.TxJumboFramesOK);
648 }
649
650 /*
651 * This function is called periodically to accumulate the current values of the
652 * RMON counters into the port statistics. Since the counters are only 32 bits
653 * some of them can overflow in less than a minute at GigE speeds, so this
654 * function should be called every 30 seconds or so.
655 *
656 * To cut down on reading costs we update only the octet counters at each tick
657 * and do a full update at major ticks, which can be every 30 minutes or more.
658 */
mac_update_statistics(struct cmac * mac,int flag)659 static const struct cmac_statistics *mac_update_statistics(struct cmac *mac,
660 int flag)
661 {
662 if (flag == MAC_STATS_UPDATE_FULL ||
663 mac->instance->ticks >= MAJOR_UPDATE_TICKS) {
664 port_stats_update(mac);
665 mac->instance->ticks = 0;
666 } else {
667 int port = mac->instance->index;
668
669 rmon_update(mac, REG_RX_OK_BYTES(port),
670 &mac->stats.RxOctetsOK);
671 rmon_update(mac, REG_RX_BAD_BYTES(port),
672 &mac->stats.RxOctetsBad);
673 rmon_update(mac, REG_TX_OK_BYTES(port),
674 &mac->stats.TxOctetsOK);
675 mac->instance->ticks++;
676 }
677 return &mac->stats;
678 }
679
mac_destroy(struct cmac * mac)680 static void mac_destroy(struct cmac *mac)
681 {
682 t1_os_free((void *)mac, sizeof(*mac) + sizeof(cmac_instance));
683 }
684
685 #ifdef C99_NOT_SUPPORTED
686 static struct cmac_ops vsc7326_ops = {
687 mac_destroy,
688 mac_reset,
689 mac_intr_enable,
690 mac_intr_disable,
691 mac_intr_clear,
692 mac_intr_handler,
693 mac_enable,
694 mac_disable,
695 NULL,
696 NULL,
697 mac_set_mtu,
698 mac_set_rx_mode,
699 mac_set_speed_duplex_fc,
700 NULL,
701 mac_update_statistics,
702 mac_get_address,
703 mac_set_address
704 };
705 #else
706 static struct cmac_ops vsc7326_ops = {
707 .destroy = mac_destroy,
708 .reset = mac_reset,
709 .interrupt_handler = mac_intr_handler,
710 .interrupt_enable = mac_intr_enable,
711 .interrupt_disable = mac_intr_disable,
712 .interrupt_clear = mac_intr_clear,
713 .enable = mac_enable,
714 .disable = mac_disable,
715 .set_mtu = mac_set_mtu,
716 .set_rx_mode = mac_set_rx_mode,
717 .set_speed_duplex_fc = mac_set_speed_duplex_fc,
718 .statistics_update = mac_update_statistics,
719 .macaddress_get = mac_get_address,
720 .macaddress_set = mac_set_address,
721 };
722 #endif
723
vsc7326_mac_create(adapter_t * adapter,int index)724 static struct cmac *vsc7326_mac_create(adapter_t *adapter, int index)
725 {
726 struct cmac *mac;
727 u32 val;
728 int i;
729
730 mac = t1_os_malloc_wait_zero(sizeof(*mac) + sizeof(cmac_instance));
731 if (!mac) return NULL;
732
733 mac->ops = &vsc7326_ops;
734 mac->instance = (cmac_instance *)(mac + 1);
735 mac->adapter = adapter;
736
737 mac->instance->index = index;
738 mac->instance->ticks = 0;
739
740 i = 0;
741 do {
742 u32 vhi, vlo;
743
744 vhi = vlo = 0;
745 (void) t1_tpi_read(adapter, (REG_LOCAL_STATUS << 2) + 4, &vlo);
746 DELAY_US(1);
747 (void) t1_tpi_read(adapter, REG_LOCAL_STATUS << 2, &vhi);
748 DELAY_US(5);
749 val = (vhi << 16) | vlo;
750 } while ((++i < 10000) && (val == 0xffffffff));
751
752 return mac;
753 }
754
vsc7326_mac_reset(adapter_t * adapter)755 static int vsc7326_mac_reset(adapter_t *adapter)
756 {
757 vsc7326_full_reset(adapter);
758 (void) run_bist_all(adapter);
759 run_table(adapter, vsc7326_reset, DIMOF(vsc7326_reset));
760 return 0;
761 }
762
763 struct gmac t1_vsc7326_ops = {
764 STATS_TICK_SECS,
765 vsc7326_mac_create,
766 vsc7326_mac_reset
767 };
768