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