xref: /titanic_50/usr/src/uts/common/io/chxge/com/vsc7326.c (revision 3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9)
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 
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 
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. */
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 
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 
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 
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 
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 
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 
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 
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 */
384 static int mac_intr_handler(struct cmac *mac)
385 {
386 	return 0;
387 }
388 
389 /* ARGSUSED */
390 static int mac_intr_enable(struct cmac *mac)
391 {
392 	return 0;
393 }
394 
395 /* ARGSUSED */
396 static int mac_intr_disable(struct cmac *mac)
397 {
398 	return 0;
399 }
400 
401 /* ARGSUSED */
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. */
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 
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 */
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 
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 
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 
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 
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 
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 
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 
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  */
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 
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 
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 
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