162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/* $Date: 2006/04/28 19:20:06 $ $RCSfile: vsc7326.c,v $ $Revision: 1.19 $ */
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci/* Driver for Vitesse VSC7326 (Schaumburg) MAC */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include "gmac.h"
762306a36Sopenharmony_ci#include "elmer0.h"
862306a36Sopenharmony_ci#include "vsc7326_reg.h"
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci/* Update fast changing statistics every 15 seconds */
1162306a36Sopenharmony_ci#define STATS_TICK_SECS 15
1262306a36Sopenharmony_ci/* 30 minutes for full statistics update */
1362306a36Sopenharmony_ci#define MAJOR_UPDATE_TICKS (1800 / STATS_TICK_SECS)
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci/* The egress WM value 0x01a01fff should be used only when the
1662306a36Sopenharmony_ci * interface is down (MAC port disabled). This is a workaround
1762306a36Sopenharmony_ci * for disabling the T2/MAC flow-control. When the interface is
1862306a36Sopenharmony_ci * enabled, the WM value should be set to 0x014a03F0.
1962306a36Sopenharmony_ci */
2062306a36Sopenharmony_ci#define WM_DISABLE	0x01a01fff
2162306a36Sopenharmony_ci#define WM_ENABLE	0x014a03F0
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_cistruct init_table {
2462306a36Sopenharmony_ci	u32 addr;
2562306a36Sopenharmony_ci	u32 data;
2662306a36Sopenharmony_ci};
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistruct _cmac_instance {
2962306a36Sopenharmony_ci	u32 index;
3062306a36Sopenharmony_ci	u32 ticks;
3162306a36Sopenharmony_ci};
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#define INITBLOCK_SLEEP	0xffffffff
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_cistatic void vsc_read(adapter_t *adapter, u32 addr, u32 *val)
3662306a36Sopenharmony_ci{
3762306a36Sopenharmony_ci	u32 status, vlo, vhi;
3862306a36Sopenharmony_ci	int i;
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	spin_lock_bh(&adapter->mac_lock);
4162306a36Sopenharmony_ci	t1_tpi_read(adapter, (addr << 2) + 4, &vlo);
4262306a36Sopenharmony_ci	i = 0;
4362306a36Sopenharmony_ci	do {
4462306a36Sopenharmony_ci		t1_tpi_read(adapter, (REG_LOCAL_STATUS << 2) + 4, &vlo);
4562306a36Sopenharmony_ci		t1_tpi_read(adapter, REG_LOCAL_STATUS << 2, &vhi);
4662306a36Sopenharmony_ci		status = (vhi << 16) | vlo;
4762306a36Sopenharmony_ci		i++;
4862306a36Sopenharmony_ci	} while (((status & 1) == 0) && (i < 50));
4962306a36Sopenharmony_ci	if (i == 50)
5062306a36Sopenharmony_ci		pr_err("Invalid tpi read from MAC, breaking loop.\n");
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	t1_tpi_read(adapter, (REG_LOCAL_DATA << 2) + 4, &vlo);
5362306a36Sopenharmony_ci	t1_tpi_read(adapter, REG_LOCAL_DATA << 2, &vhi);
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	*val = (vhi << 16) | vlo;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	/* pr_err("rd: block: 0x%x  sublock: 0x%x  reg: 0x%x  data: 0x%x\n",
5862306a36Sopenharmony_ci		((addr&0xe000)>>13), ((addr&0x1e00)>>9),
5962306a36Sopenharmony_ci		((addr&0x01fe)>>1), *val); */
6062306a36Sopenharmony_ci	spin_unlock_bh(&adapter->mac_lock);
6162306a36Sopenharmony_ci}
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_cistatic void vsc_write(adapter_t *adapter, u32 addr, u32 data)
6462306a36Sopenharmony_ci{
6562306a36Sopenharmony_ci	spin_lock_bh(&adapter->mac_lock);
6662306a36Sopenharmony_ci	t1_tpi_write(adapter, (addr << 2) + 4, data & 0xFFFF);
6762306a36Sopenharmony_ci	t1_tpi_write(adapter, addr << 2, (data >> 16) & 0xFFFF);
6862306a36Sopenharmony_ci	/* pr_err("wr: block: 0x%x  sublock: 0x%x  reg: 0x%x  data: 0x%x\n",
6962306a36Sopenharmony_ci		((addr&0xe000)>>13), ((addr&0x1e00)>>9),
7062306a36Sopenharmony_ci		((addr&0x01fe)>>1), data); */
7162306a36Sopenharmony_ci	spin_unlock_bh(&adapter->mac_lock);
7262306a36Sopenharmony_ci}
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci/* Hard reset the MAC.  This wipes out *all* configuration. */
7562306a36Sopenharmony_cistatic void vsc7326_full_reset(adapter_t* adapter)
7662306a36Sopenharmony_ci{
7762306a36Sopenharmony_ci	u32 val;
7862306a36Sopenharmony_ci	u32 result = 0xffff;
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	t1_tpi_read(adapter, A_ELMER0_GPO, &val);
8162306a36Sopenharmony_ci	val &= ~1;
8262306a36Sopenharmony_ci	t1_tpi_write(adapter, A_ELMER0_GPO, val);
8362306a36Sopenharmony_ci	udelay(2);
8462306a36Sopenharmony_ci	val |= 0x1;	/* Enable mac MAC itself */
8562306a36Sopenharmony_ci	val |= 0x800;	/* Turn off the red LED */
8662306a36Sopenharmony_ci	t1_tpi_write(adapter, A_ELMER0_GPO, val);
8762306a36Sopenharmony_ci	mdelay(1);
8862306a36Sopenharmony_ci	vsc_write(adapter, REG_SW_RESET, 0x80000001);
8962306a36Sopenharmony_ci	do {
9062306a36Sopenharmony_ci		mdelay(1);
9162306a36Sopenharmony_ci		vsc_read(adapter, REG_SW_RESET, &result);
9262306a36Sopenharmony_ci	} while (result != 0x0);
9362306a36Sopenharmony_ci}
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_cistatic struct init_table vsc7326_reset[] = {
9662306a36Sopenharmony_ci	{      REG_IFACE_MODE, 0x00000000 },
9762306a36Sopenharmony_ci	{         REG_CRC_CFG, 0x00000020 },
9862306a36Sopenharmony_ci	{   REG_PLL_CLK_SPEED, 0x00050c00 },
9962306a36Sopenharmony_ci	{   REG_PLL_CLK_SPEED, 0x00050c00 },
10062306a36Sopenharmony_ci	{            REG_MSCH, 0x00002f14 },
10162306a36Sopenharmony_ci	{       REG_SPI4_MISC, 0x00040409 },
10262306a36Sopenharmony_ci	{     REG_SPI4_DESKEW, 0x00080000 },
10362306a36Sopenharmony_ci	{ REG_SPI4_ING_SETUP2, 0x08080004 },
10462306a36Sopenharmony_ci	{ REG_SPI4_ING_SETUP0, 0x04111004 },
10562306a36Sopenharmony_ci	{ REG_SPI4_EGR_SETUP0, 0x80001a04 },
10662306a36Sopenharmony_ci	{ REG_SPI4_ING_SETUP1, 0x02010000 },
10762306a36Sopenharmony_ci	{      REG_AGE_INC(0), 0x00000000 },
10862306a36Sopenharmony_ci	{      REG_AGE_INC(1), 0x00000000 },
10962306a36Sopenharmony_ci	{     REG_ING_CONTROL, 0x0a200011 },
11062306a36Sopenharmony_ci	{     REG_EGR_CONTROL, 0xa0010091 },
11162306a36Sopenharmony_ci};
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_cistatic struct init_table vsc7326_portinit[4][22] = {
11462306a36Sopenharmony_ci	{	/* Port 0 */
11562306a36Sopenharmony_ci			/* FIFO setup */
11662306a36Sopenharmony_ci		{           REG_DBG(0), 0x000004f0 },
11762306a36Sopenharmony_ci		{           REG_HDX(0), 0x00073101 },
11862306a36Sopenharmony_ci		{        REG_TEST(0,0), 0x00000022 },
11962306a36Sopenharmony_ci		{        REG_TEST(1,0), 0x00000022 },
12062306a36Sopenharmony_ci		{  REG_TOP_BOTTOM(0,0), 0x003f0000 },
12162306a36Sopenharmony_ci		{  REG_TOP_BOTTOM(1,0), 0x00120000 },
12262306a36Sopenharmony_ci		{ REG_HIGH_LOW_WM(0,0), 0x07460757 },
12362306a36Sopenharmony_ci		{ REG_HIGH_LOW_WM(1,0), WM_DISABLE },
12462306a36Sopenharmony_ci		{   REG_CT_THRHLD(0,0), 0x00000000 },
12562306a36Sopenharmony_ci		{   REG_CT_THRHLD(1,0), 0x00000000 },
12662306a36Sopenharmony_ci		{         REG_BUCKE(0), 0x0002ffff },
12762306a36Sopenharmony_ci		{         REG_BUCKI(0), 0x0002ffff },
12862306a36Sopenharmony_ci		{        REG_TEST(0,0), 0x00000020 },
12962306a36Sopenharmony_ci		{        REG_TEST(1,0), 0x00000020 },
13062306a36Sopenharmony_ci			/* Port config */
13162306a36Sopenharmony_ci		{       REG_MAX_LEN(0), 0x00002710 },
13262306a36Sopenharmony_ci		{     REG_PORT_FAIL(0), 0x00000002 },
13362306a36Sopenharmony_ci		{    REG_NORMALIZER(0), 0x00000a64 },
13462306a36Sopenharmony_ci		{        REG_DENORM(0), 0x00000010 },
13562306a36Sopenharmony_ci		{     REG_STICK_BIT(0), 0x03baa370 },
13662306a36Sopenharmony_ci		{     REG_DEV_SETUP(0), 0x00000083 },
13762306a36Sopenharmony_ci		{     REG_DEV_SETUP(0), 0x00000082 },
13862306a36Sopenharmony_ci		{      REG_MODE_CFG(0), 0x0200259f },
13962306a36Sopenharmony_ci	},
14062306a36Sopenharmony_ci	{	/* Port 1 */
14162306a36Sopenharmony_ci			/* FIFO setup */
14262306a36Sopenharmony_ci		{           REG_DBG(1), 0x000004f0 },
14362306a36Sopenharmony_ci		{           REG_HDX(1), 0x00073101 },
14462306a36Sopenharmony_ci		{        REG_TEST(0,1), 0x00000022 },
14562306a36Sopenharmony_ci		{        REG_TEST(1,1), 0x00000022 },
14662306a36Sopenharmony_ci		{  REG_TOP_BOTTOM(0,1), 0x007e003f },
14762306a36Sopenharmony_ci		{  REG_TOP_BOTTOM(1,1), 0x00240012 },
14862306a36Sopenharmony_ci		{ REG_HIGH_LOW_WM(0,1), 0x07460757 },
14962306a36Sopenharmony_ci		{ REG_HIGH_LOW_WM(1,1), WM_DISABLE },
15062306a36Sopenharmony_ci		{   REG_CT_THRHLD(0,1), 0x00000000 },
15162306a36Sopenharmony_ci		{   REG_CT_THRHLD(1,1), 0x00000000 },
15262306a36Sopenharmony_ci		{         REG_BUCKE(1), 0x0002ffff },
15362306a36Sopenharmony_ci		{         REG_BUCKI(1), 0x0002ffff },
15462306a36Sopenharmony_ci		{        REG_TEST(0,1), 0x00000020 },
15562306a36Sopenharmony_ci		{        REG_TEST(1,1), 0x00000020 },
15662306a36Sopenharmony_ci			/* Port config */
15762306a36Sopenharmony_ci		{       REG_MAX_LEN(1), 0x00002710 },
15862306a36Sopenharmony_ci		{     REG_PORT_FAIL(1), 0x00000002 },
15962306a36Sopenharmony_ci		{    REG_NORMALIZER(1), 0x00000a64 },
16062306a36Sopenharmony_ci		{        REG_DENORM(1), 0x00000010 },
16162306a36Sopenharmony_ci		{     REG_STICK_BIT(1), 0x03baa370 },
16262306a36Sopenharmony_ci		{     REG_DEV_SETUP(1), 0x00000083 },
16362306a36Sopenharmony_ci		{     REG_DEV_SETUP(1), 0x00000082 },
16462306a36Sopenharmony_ci		{      REG_MODE_CFG(1), 0x0200259f },
16562306a36Sopenharmony_ci	},
16662306a36Sopenharmony_ci	{	/* Port 2 */
16762306a36Sopenharmony_ci			/* FIFO setup */
16862306a36Sopenharmony_ci		{           REG_DBG(2), 0x000004f0 },
16962306a36Sopenharmony_ci		{           REG_HDX(2), 0x00073101 },
17062306a36Sopenharmony_ci		{        REG_TEST(0,2), 0x00000022 },
17162306a36Sopenharmony_ci		{        REG_TEST(1,2), 0x00000022 },
17262306a36Sopenharmony_ci		{  REG_TOP_BOTTOM(0,2), 0x00bd007e },
17362306a36Sopenharmony_ci		{  REG_TOP_BOTTOM(1,2), 0x00360024 },
17462306a36Sopenharmony_ci		{ REG_HIGH_LOW_WM(0,2), 0x07460757 },
17562306a36Sopenharmony_ci		{ REG_HIGH_LOW_WM(1,2), WM_DISABLE },
17662306a36Sopenharmony_ci		{   REG_CT_THRHLD(0,2), 0x00000000 },
17762306a36Sopenharmony_ci		{   REG_CT_THRHLD(1,2), 0x00000000 },
17862306a36Sopenharmony_ci		{         REG_BUCKE(2), 0x0002ffff },
17962306a36Sopenharmony_ci		{         REG_BUCKI(2), 0x0002ffff },
18062306a36Sopenharmony_ci		{        REG_TEST(0,2), 0x00000020 },
18162306a36Sopenharmony_ci		{        REG_TEST(1,2), 0x00000020 },
18262306a36Sopenharmony_ci			/* Port config */
18362306a36Sopenharmony_ci		{       REG_MAX_LEN(2), 0x00002710 },
18462306a36Sopenharmony_ci		{     REG_PORT_FAIL(2), 0x00000002 },
18562306a36Sopenharmony_ci		{    REG_NORMALIZER(2), 0x00000a64 },
18662306a36Sopenharmony_ci		{        REG_DENORM(2), 0x00000010 },
18762306a36Sopenharmony_ci		{     REG_STICK_BIT(2), 0x03baa370 },
18862306a36Sopenharmony_ci		{     REG_DEV_SETUP(2), 0x00000083 },
18962306a36Sopenharmony_ci		{     REG_DEV_SETUP(2), 0x00000082 },
19062306a36Sopenharmony_ci		{      REG_MODE_CFG(2), 0x0200259f },
19162306a36Sopenharmony_ci	},
19262306a36Sopenharmony_ci	{	/* Port 3 */
19362306a36Sopenharmony_ci			/* FIFO setup */
19462306a36Sopenharmony_ci		{           REG_DBG(3), 0x000004f0 },
19562306a36Sopenharmony_ci		{           REG_HDX(3), 0x00073101 },
19662306a36Sopenharmony_ci		{        REG_TEST(0,3), 0x00000022 },
19762306a36Sopenharmony_ci		{        REG_TEST(1,3), 0x00000022 },
19862306a36Sopenharmony_ci		{  REG_TOP_BOTTOM(0,3), 0x00fc00bd },
19962306a36Sopenharmony_ci		{  REG_TOP_BOTTOM(1,3), 0x00480036 },
20062306a36Sopenharmony_ci		{ REG_HIGH_LOW_WM(0,3), 0x07460757 },
20162306a36Sopenharmony_ci		{ REG_HIGH_LOW_WM(1,3), WM_DISABLE },
20262306a36Sopenharmony_ci		{   REG_CT_THRHLD(0,3), 0x00000000 },
20362306a36Sopenharmony_ci		{   REG_CT_THRHLD(1,3), 0x00000000 },
20462306a36Sopenharmony_ci		{         REG_BUCKE(3), 0x0002ffff },
20562306a36Sopenharmony_ci		{         REG_BUCKI(3), 0x0002ffff },
20662306a36Sopenharmony_ci		{        REG_TEST(0,3), 0x00000020 },
20762306a36Sopenharmony_ci		{        REG_TEST(1,3), 0x00000020 },
20862306a36Sopenharmony_ci			/* Port config */
20962306a36Sopenharmony_ci		{       REG_MAX_LEN(3), 0x00002710 },
21062306a36Sopenharmony_ci		{     REG_PORT_FAIL(3), 0x00000002 },
21162306a36Sopenharmony_ci		{    REG_NORMALIZER(3), 0x00000a64 },
21262306a36Sopenharmony_ci		{        REG_DENORM(3), 0x00000010 },
21362306a36Sopenharmony_ci		{     REG_STICK_BIT(3), 0x03baa370 },
21462306a36Sopenharmony_ci		{     REG_DEV_SETUP(3), 0x00000083 },
21562306a36Sopenharmony_ci		{     REG_DEV_SETUP(3), 0x00000082 },
21662306a36Sopenharmony_ci		{      REG_MODE_CFG(3), 0x0200259f },
21762306a36Sopenharmony_ci	},
21862306a36Sopenharmony_ci};
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_cistatic void run_table(adapter_t *adapter, struct init_table *ib, int len)
22162306a36Sopenharmony_ci{
22262306a36Sopenharmony_ci	int i;
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	for (i = 0; i < len; i++) {
22562306a36Sopenharmony_ci		if (ib[i].addr == INITBLOCK_SLEEP) {
22662306a36Sopenharmony_ci			udelay( ib[i].data );
22762306a36Sopenharmony_ci			pr_err("sleep %d us\n",ib[i].data);
22862306a36Sopenharmony_ci		} else
22962306a36Sopenharmony_ci			vsc_write( adapter, ib[i].addr, ib[i].data );
23062306a36Sopenharmony_ci	}
23162306a36Sopenharmony_ci}
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_cistatic int bist_rd(adapter_t *adapter, int moduleid, int address)
23462306a36Sopenharmony_ci{
23562306a36Sopenharmony_ci	int data = 0;
23662306a36Sopenharmony_ci	u32 result = 0;
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	if ((address != 0x0) &&
23962306a36Sopenharmony_ci	    (address != 0x1) &&
24062306a36Sopenharmony_ci	    (address != 0x2) &&
24162306a36Sopenharmony_ci	    (address != 0xd) &&
24262306a36Sopenharmony_ci	    (address != 0xe))
24362306a36Sopenharmony_ci			pr_err("No bist address: 0x%x\n", address);
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	data = ((0x00 << 24) | ((address & 0xff) << 16) | (0x00 << 8) |
24662306a36Sopenharmony_ci		((moduleid & 0xff) << 0));
24762306a36Sopenharmony_ci	vsc_write(adapter, REG_RAM_BIST_CMD, data);
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	udelay(10);
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	vsc_read(adapter, REG_RAM_BIST_RESULT, &result);
25262306a36Sopenharmony_ci	if ((result & (1 << 9)) != 0x0)
25362306a36Sopenharmony_ci		pr_err("Still in bist read: 0x%x\n", result);
25462306a36Sopenharmony_ci	else if ((result & (1 << 8)) != 0x0)
25562306a36Sopenharmony_ci		pr_err("bist read error: 0x%x\n", result);
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	return result & 0xff;
25862306a36Sopenharmony_ci}
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_cistatic int bist_wr(adapter_t *adapter, int moduleid, int address, int value)
26162306a36Sopenharmony_ci{
26262306a36Sopenharmony_ci	int data = 0;
26362306a36Sopenharmony_ci	u32 result = 0;
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	if ((address != 0x0) &&
26662306a36Sopenharmony_ci	    (address != 0x1) &&
26762306a36Sopenharmony_ci	    (address != 0x2) &&
26862306a36Sopenharmony_ci	    (address != 0xd) &&
26962306a36Sopenharmony_ci	    (address != 0xe))
27062306a36Sopenharmony_ci			pr_err("No bist address: 0x%x\n", address);
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	if (value > 255)
27362306a36Sopenharmony_ci		pr_err("Suspicious write out of range value: 0x%x\n", value);
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	data = ((0x01 << 24) | ((address & 0xff) << 16) | (value << 8) |
27662306a36Sopenharmony_ci		((moduleid & 0xff) << 0));
27762306a36Sopenharmony_ci	vsc_write(adapter, REG_RAM_BIST_CMD, data);
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	udelay(5);
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	vsc_read(adapter, REG_RAM_BIST_CMD, &result);
28262306a36Sopenharmony_ci	if ((result & (1 << 27)) != 0x0)
28362306a36Sopenharmony_ci		pr_err("Still in bist write: 0x%x\n", result);
28462306a36Sopenharmony_ci	else if ((result & (1 << 26)) != 0x0)
28562306a36Sopenharmony_ci		pr_err("bist write error: 0x%x\n", result);
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	return 0;
28862306a36Sopenharmony_ci}
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_cistatic int run_bist(adapter_t *adapter, int moduleid)
29162306a36Sopenharmony_ci{
29262306a36Sopenharmony_ci	/*run bist*/
29362306a36Sopenharmony_ci	(void) bist_wr(adapter,moduleid, 0x00, 0x02);
29462306a36Sopenharmony_ci	(void) bist_wr(adapter,moduleid, 0x01, 0x01);
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	return 0;
29762306a36Sopenharmony_ci}
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_cistatic int check_bist(adapter_t *adapter, int moduleid)
30062306a36Sopenharmony_ci{
30162306a36Sopenharmony_ci	int result=0;
30262306a36Sopenharmony_ci	int column=0;
30362306a36Sopenharmony_ci	/*check bist*/
30462306a36Sopenharmony_ci	result = bist_rd(adapter,moduleid, 0x02);
30562306a36Sopenharmony_ci	column = ((bist_rd(adapter,moduleid, 0x0e)<<8) +
30662306a36Sopenharmony_ci			(bist_rd(adapter,moduleid, 0x0d)));
30762306a36Sopenharmony_ci	if ((result & 3) != 0x3)
30862306a36Sopenharmony_ci		pr_err("Result: 0x%x  BIST error in ram %d, column: 0x%04x\n",
30962306a36Sopenharmony_ci			result, moduleid, column);
31062306a36Sopenharmony_ci	return 0;
31162306a36Sopenharmony_ci}
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_cistatic int enable_mem(adapter_t *adapter, int moduleid)
31462306a36Sopenharmony_ci{
31562306a36Sopenharmony_ci	/*enable mem*/
31662306a36Sopenharmony_ci	(void) bist_wr(adapter,moduleid, 0x00, 0x00);
31762306a36Sopenharmony_ci	return 0;
31862306a36Sopenharmony_ci}
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_cistatic int run_bist_all(adapter_t *adapter)
32162306a36Sopenharmony_ci{
32262306a36Sopenharmony_ci	int port = 0;
32362306a36Sopenharmony_ci	u32 val = 0;
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	vsc_write(adapter, REG_MEM_BIST, 0x5);
32662306a36Sopenharmony_ci	vsc_read(adapter, REG_MEM_BIST, &val);
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	for (port = 0; port < 12; port++)
32962306a36Sopenharmony_ci		vsc_write(adapter, REG_DEV_SETUP(port), 0x0);
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	udelay(300);
33262306a36Sopenharmony_ci	vsc_write(adapter, REG_SPI4_MISC, 0x00040409);
33362306a36Sopenharmony_ci	udelay(300);
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	(void) run_bist(adapter,13);
33662306a36Sopenharmony_ci	(void) run_bist(adapter,14);
33762306a36Sopenharmony_ci	(void) run_bist(adapter,20);
33862306a36Sopenharmony_ci	(void) run_bist(adapter,21);
33962306a36Sopenharmony_ci	mdelay(200);
34062306a36Sopenharmony_ci	(void) check_bist(adapter,13);
34162306a36Sopenharmony_ci	(void) check_bist(adapter,14);
34262306a36Sopenharmony_ci	(void) check_bist(adapter,20);
34362306a36Sopenharmony_ci	(void) check_bist(adapter,21);
34462306a36Sopenharmony_ci	udelay(100);
34562306a36Sopenharmony_ci	(void) enable_mem(adapter,13);
34662306a36Sopenharmony_ci	(void) enable_mem(adapter,14);
34762306a36Sopenharmony_ci	(void) enable_mem(adapter,20);
34862306a36Sopenharmony_ci	(void) enable_mem(adapter,21);
34962306a36Sopenharmony_ci	udelay(300);
35062306a36Sopenharmony_ci	vsc_write(adapter, REG_SPI4_MISC, 0x60040400);
35162306a36Sopenharmony_ci	udelay(300);
35262306a36Sopenharmony_ci	for (port = 0; port < 12; port++)
35362306a36Sopenharmony_ci		vsc_write(adapter, REG_DEV_SETUP(port), 0x1);
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	udelay(300);
35662306a36Sopenharmony_ci	vsc_write(adapter, REG_MEM_BIST, 0x0);
35762306a36Sopenharmony_ci	mdelay(10);
35862306a36Sopenharmony_ci	return 0;
35962306a36Sopenharmony_ci}
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_cistatic int mac_intr_handler(struct cmac *mac)
36262306a36Sopenharmony_ci{
36362306a36Sopenharmony_ci	return 0;
36462306a36Sopenharmony_ci}
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_cistatic int mac_intr_enable(struct cmac *mac)
36762306a36Sopenharmony_ci{
36862306a36Sopenharmony_ci	return 0;
36962306a36Sopenharmony_ci}
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_cistatic int mac_intr_disable(struct cmac *mac)
37262306a36Sopenharmony_ci{
37362306a36Sopenharmony_ci	return 0;
37462306a36Sopenharmony_ci}
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_cistatic int mac_intr_clear(struct cmac *mac)
37762306a36Sopenharmony_ci{
37862306a36Sopenharmony_ci	return 0;
37962306a36Sopenharmony_ci}
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci/* Expect MAC address to be in network byte order. */
38262306a36Sopenharmony_cistatic int mac_set_address(struct cmac* mac, const u8 addr[6])
38362306a36Sopenharmony_ci{
38462306a36Sopenharmony_ci	u32 val;
38562306a36Sopenharmony_ci	int port = mac->instance->index;
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	vsc_write(mac->adapter, REG_MAC_LOW_ADDR(port),
38862306a36Sopenharmony_ci		  (addr[3] << 16) | (addr[4] << 8) | addr[5]);
38962306a36Sopenharmony_ci	vsc_write(mac->adapter, REG_MAC_HIGH_ADDR(port),
39062306a36Sopenharmony_ci		  (addr[0] << 16) | (addr[1] << 8) | addr[2]);
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	vsc_read(mac->adapter, REG_ING_FFILT_UM_EN, &val);
39362306a36Sopenharmony_ci	val &= ~0xf0000000;
39462306a36Sopenharmony_ci	vsc_write(mac->adapter, REG_ING_FFILT_UM_EN, val | (port << 28));
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	vsc_write(mac->adapter, REG_ING_FFILT_MASK0,
39762306a36Sopenharmony_ci		  0xffff0000 | (addr[4] << 8) | addr[5]);
39862306a36Sopenharmony_ci	vsc_write(mac->adapter, REG_ING_FFILT_MASK1,
39962306a36Sopenharmony_ci		  0xffff0000 | (addr[2] << 8) | addr[3]);
40062306a36Sopenharmony_ci	vsc_write(mac->adapter, REG_ING_FFILT_MASK2,
40162306a36Sopenharmony_ci		  0xffff0000 | (addr[0] << 8) | addr[1]);
40262306a36Sopenharmony_ci	return 0;
40362306a36Sopenharmony_ci}
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_cistatic int mac_get_address(struct cmac *mac, u8 addr[6])
40662306a36Sopenharmony_ci{
40762306a36Sopenharmony_ci	u32 addr_lo, addr_hi;
40862306a36Sopenharmony_ci	int port = mac->instance->index;
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	vsc_read(mac->adapter, REG_MAC_LOW_ADDR(port), &addr_lo);
41162306a36Sopenharmony_ci	vsc_read(mac->adapter, REG_MAC_HIGH_ADDR(port), &addr_hi);
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	addr[0] = (u8) (addr_hi >> 16);
41462306a36Sopenharmony_ci	addr[1] = (u8) (addr_hi >> 8);
41562306a36Sopenharmony_ci	addr[2] = (u8) addr_hi;
41662306a36Sopenharmony_ci	addr[3] = (u8) (addr_lo >> 16);
41762306a36Sopenharmony_ci	addr[4] = (u8) (addr_lo >> 8);
41862306a36Sopenharmony_ci	addr[5] = (u8) addr_lo;
41962306a36Sopenharmony_ci	return 0;
42062306a36Sopenharmony_ci}
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci/* This is intended to reset a port, not the whole MAC */
42362306a36Sopenharmony_cistatic int mac_reset(struct cmac *mac)
42462306a36Sopenharmony_ci{
42562306a36Sopenharmony_ci	int index = mac->instance->index;
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	run_table(mac->adapter, vsc7326_portinit[index],
42862306a36Sopenharmony_ci		  ARRAY_SIZE(vsc7326_portinit[index]));
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	return 0;
43162306a36Sopenharmony_ci}
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_cistatic int mac_set_rx_mode(struct cmac *mac, struct t1_rx_mode *rm)
43462306a36Sopenharmony_ci{
43562306a36Sopenharmony_ci	u32 v;
43662306a36Sopenharmony_ci	int port = mac->instance->index;
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	vsc_read(mac->adapter, REG_ING_FFILT_UM_EN, &v);
43962306a36Sopenharmony_ci	v |= 1 << 12;
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	if (t1_rx_mode_promisc(rm))
44262306a36Sopenharmony_ci		v &= ~(1 << (port + 16));
44362306a36Sopenharmony_ci	else
44462306a36Sopenharmony_ci		v |= 1 << (port + 16);
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	vsc_write(mac->adapter, REG_ING_FFILT_UM_EN, v);
44762306a36Sopenharmony_ci	return 0;
44862306a36Sopenharmony_ci}
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_cistatic int mac_set_mtu(struct cmac *mac, int mtu)
45162306a36Sopenharmony_ci{
45262306a36Sopenharmony_ci	int port = mac->instance->index;
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	/* max_len includes header and FCS */
45562306a36Sopenharmony_ci	vsc_write(mac->adapter, REG_MAX_LEN(port), mtu + 14 + 4);
45662306a36Sopenharmony_ci	return 0;
45762306a36Sopenharmony_ci}
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_cistatic int mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex,
46062306a36Sopenharmony_ci				   int fc)
46162306a36Sopenharmony_ci{
46262306a36Sopenharmony_ci	u32 v;
46362306a36Sopenharmony_ci	int enable, port = mac->instance->index;
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	if (speed >= 0 && speed != SPEED_10 && speed != SPEED_100 &&
46662306a36Sopenharmony_ci	    speed != SPEED_1000)
46762306a36Sopenharmony_ci		return -1;
46862306a36Sopenharmony_ci	if (duplex > 0 && duplex != DUPLEX_FULL)
46962306a36Sopenharmony_ci		return -1;
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	if (speed >= 0) {
47262306a36Sopenharmony_ci		vsc_read(mac->adapter, REG_MODE_CFG(port), &v);
47362306a36Sopenharmony_ci		enable = v & 3;             /* save tx/rx enables */
47462306a36Sopenharmony_ci		v &= ~0xf;
47562306a36Sopenharmony_ci		v |= 4;                     /* full duplex */
47662306a36Sopenharmony_ci		if (speed == SPEED_1000)
47762306a36Sopenharmony_ci			v |= 8;             /* GigE */
47862306a36Sopenharmony_ci		enable |= v;
47962306a36Sopenharmony_ci		vsc_write(mac->adapter, REG_MODE_CFG(port), v);
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci		if (speed == SPEED_1000)
48262306a36Sopenharmony_ci			v = 0x82;
48362306a36Sopenharmony_ci		else if (speed == SPEED_100)
48462306a36Sopenharmony_ci			v = 0x84;
48562306a36Sopenharmony_ci		else	/* SPEED_10 */
48662306a36Sopenharmony_ci			v = 0x86;
48762306a36Sopenharmony_ci		vsc_write(mac->adapter, REG_DEV_SETUP(port), v | 1); /* reset */
48862306a36Sopenharmony_ci		vsc_write(mac->adapter, REG_DEV_SETUP(port), v);
48962306a36Sopenharmony_ci		vsc_read(mac->adapter, REG_DBG(port), &v);
49062306a36Sopenharmony_ci		v &= ~0xff00;
49162306a36Sopenharmony_ci		if (speed == SPEED_1000)
49262306a36Sopenharmony_ci			v |= 0x400;
49362306a36Sopenharmony_ci		else if (speed == SPEED_100)
49462306a36Sopenharmony_ci			v |= 0x2000;
49562306a36Sopenharmony_ci		else	/* SPEED_10 */
49662306a36Sopenharmony_ci			v |= 0xff00;
49762306a36Sopenharmony_ci		vsc_write(mac->adapter, REG_DBG(port), v);
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci		vsc_write(mac->adapter, REG_TX_IFG(port),
50062306a36Sopenharmony_ci			  speed == SPEED_1000 ? 5 : 0x11);
50162306a36Sopenharmony_ci		if (duplex == DUPLEX_HALF)
50262306a36Sopenharmony_ci			enable = 0x0;	/* 100 or 10 */
50362306a36Sopenharmony_ci		else if (speed == SPEED_1000)
50462306a36Sopenharmony_ci			enable = 0xc;
50562306a36Sopenharmony_ci		else	/* SPEED_100 or 10 */
50662306a36Sopenharmony_ci			enable = 0x4;
50762306a36Sopenharmony_ci		enable |= 0x9 << 10;	/* IFG1 */
50862306a36Sopenharmony_ci		enable |= 0x6 << 6;	/* IFG2 */
50962306a36Sopenharmony_ci		enable |= 0x1 << 4;	/* VLAN */
51062306a36Sopenharmony_ci		enable |= 0x3;		/* RX/TX EN */
51162306a36Sopenharmony_ci		vsc_write(mac->adapter, REG_MODE_CFG(port), enable);
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	}
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	vsc_read(mac->adapter, REG_PAUSE_CFG(port), &v);
51662306a36Sopenharmony_ci	v &= 0xfff0ffff;
51762306a36Sopenharmony_ci	v |= 0x20000;      /* xon/xoff */
51862306a36Sopenharmony_ci	if (fc & PAUSE_RX)
51962306a36Sopenharmony_ci		v |= 0x40000;
52062306a36Sopenharmony_ci	if (fc & PAUSE_TX)
52162306a36Sopenharmony_ci		v |= 0x80000;
52262306a36Sopenharmony_ci	if (fc == (PAUSE_RX | PAUSE_TX))
52362306a36Sopenharmony_ci		v |= 0x10000;
52462306a36Sopenharmony_ci	vsc_write(mac->adapter, REG_PAUSE_CFG(port), v);
52562306a36Sopenharmony_ci	return 0;
52662306a36Sopenharmony_ci}
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_cistatic int mac_enable(struct cmac *mac, int which)
52962306a36Sopenharmony_ci{
53062306a36Sopenharmony_ci	u32 val;
53162306a36Sopenharmony_ci	int port = mac->instance->index;
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	/* Write the correct WM value when the port is enabled. */
53462306a36Sopenharmony_ci	vsc_write(mac->adapter, REG_HIGH_LOW_WM(1,port), WM_ENABLE);
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	vsc_read(mac->adapter, REG_MODE_CFG(port), &val);
53762306a36Sopenharmony_ci	if (which & MAC_DIRECTION_RX)
53862306a36Sopenharmony_ci		val |= 0x2;
53962306a36Sopenharmony_ci	if (which & MAC_DIRECTION_TX)
54062306a36Sopenharmony_ci		val |= 1;
54162306a36Sopenharmony_ci	vsc_write(mac->adapter, REG_MODE_CFG(port), val);
54262306a36Sopenharmony_ci	return 0;
54362306a36Sopenharmony_ci}
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_cistatic int mac_disable(struct cmac *mac, int which)
54662306a36Sopenharmony_ci{
54762306a36Sopenharmony_ci	u32 val;
54862306a36Sopenharmony_ci	int i, port = mac->instance->index;
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci	/* Reset the port, this also writes the correct WM value */
55162306a36Sopenharmony_ci	mac_reset(mac);
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	vsc_read(mac->adapter, REG_MODE_CFG(port), &val);
55462306a36Sopenharmony_ci	if (which & MAC_DIRECTION_RX)
55562306a36Sopenharmony_ci		val &= ~0x2;
55662306a36Sopenharmony_ci	if (which & MAC_DIRECTION_TX)
55762306a36Sopenharmony_ci		val &= ~0x1;
55862306a36Sopenharmony_ci	vsc_write(mac->adapter, REG_MODE_CFG(port), val);
55962306a36Sopenharmony_ci	vsc_read(mac->adapter, REG_MODE_CFG(port), &val);
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	/* Clear stats */
56262306a36Sopenharmony_ci	for (i = 0; i <= 0x3a; ++i)
56362306a36Sopenharmony_ci		vsc_write(mac->adapter, CRA(4, port, i), 0);
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	/* Clear software counters */
56662306a36Sopenharmony_ci	memset(&mac->stats, 0, sizeof(struct cmac_statistics));
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	return 0;
56962306a36Sopenharmony_ci}
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_cistatic void rmon_update(struct cmac *mac, unsigned int addr, u64 *stat)
57262306a36Sopenharmony_ci{
57362306a36Sopenharmony_ci	u32 v, lo;
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	vsc_read(mac->adapter, addr, &v);
57662306a36Sopenharmony_ci	lo = *stat;
57762306a36Sopenharmony_ci	*stat = *stat - lo + v;
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	if (v == 0)
58062306a36Sopenharmony_ci		return;
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	if (v < lo)
58362306a36Sopenharmony_ci		*stat += (1ULL << 32);
58462306a36Sopenharmony_ci}
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_cistatic void port_stats_update(struct cmac *mac)
58762306a36Sopenharmony_ci{
58862306a36Sopenharmony_ci	struct {
58962306a36Sopenharmony_ci		unsigned int reg;
59062306a36Sopenharmony_ci		unsigned int offset;
59162306a36Sopenharmony_ci	} hw_stats[] = {
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci#define HW_STAT(reg, stat_name) \
59462306a36Sopenharmony_ci	{ reg, offsetof(struct cmac_statistics, stat_name) / sizeof(u64) }
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci		/* Rx stats */
59762306a36Sopenharmony_ci		HW_STAT(RxUnicast, RxUnicastFramesOK),
59862306a36Sopenharmony_ci		HW_STAT(RxMulticast, RxMulticastFramesOK),
59962306a36Sopenharmony_ci		HW_STAT(RxBroadcast, RxBroadcastFramesOK),
60062306a36Sopenharmony_ci		HW_STAT(Crc, RxFCSErrors),
60162306a36Sopenharmony_ci		HW_STAT(RxAlignment, RxAlignErrors),
60262306a36Sopenharmony_ci		HW_STAT(RxOversize, RxFrameTooLongErrors),
60362306a36Sopenharmony_ci		HW_STAT(RxPause, RxPauseFrames),
60462306a36Sopenharmony_ci		HW_STAT(RxJabbers, RxJabberErrors),
60562306a36Sopenharmony_ci		HW_STAT(RxFragments, RxRuntErrors),
60662306a36Sopenharmony_ci		HW_STAT(RxUndersize, RxRuntErrors),
60762306a36Sopenharmony_ci		HW_STAT(RxSymbolCarrier, RxSymbolErrors),
60862306a36Sopenharmony_ci		HW_STAT(RxSize1519ToMax, RxJumboFramesOK),
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci		/* Tx stats (skip collision stats as we are full-duplex only) */
61162306a36Sopenharmony_ci		HW_STAT(TxUnicast, TxUnicastFramesOK),
61262306a36Sopenharmony_ci		HW_STAT(TxMulticast, TxMulticastFramesOK),
61362306a36Sopenharmony_ci		HW_STAT(TxBroadcast, TxBroadcastFramesOK),
61462306a36Sopenharmony_ci		HW_STAT(TxPause, TxPauseFrames),
61562306a36Sopenharmony_ci		HW_STAT(TxUnderrun, TxUnderrun),
61662306a36Sopenharmony_ci		HW_STAT(TxSize1519ToMax, TxJumboFramesOK),
61762306a36Sopenharmony_ci	}, *p = hw_stats;
61862306a36Sopenharmony_ci	unsigned int port = mac->instance->index;
61962306a36Sopenharmony_ci	u64 *stats = (u64 *)&mac->stats;
62062306a36Sopenharmony_ci	unsigned int i;
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(hw_stats); i++)
62362306a36Sopenharmony_ci		rmon_update(mac, CRA(0x4, port, p->reg), stats + p->offset);
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci	rmon_update(mac, REG_TX_OK_BYTES(port), &mac->stats.TxOctetsOK);
62662306a36Sopenharmony_ci	rmon_update(mac, REG_RX_OK_BYTES(port), &mac->stats.RxOctetsOK);
62762306a36Sopenharmony_ci	rmon_update(mac, REG_RX_BAD_BYTES(port), &mac->stats.RxOctetsBad);
62862306a36Sopenharmony_ci}
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci/*
63162306a36Sopenharmony_ci * This function is called periodically to accumulate the current values of the
63262306a36Sopenharmony_ci * RMON counters into the port statistics.  Since the counters are only 32 bits
63362306a36Sopenharmony_ci * some of them can overflow in less than a minute at GigE speeds, so this
63462306a36Sopenharmony_ci * function should be called every 30 seconds or so.
63562306a36Sopenharmony_ci *
63662306a36Sopenharmony_ci * To cut down on reading costs we update only the octet counters at each tick
63762306a36Sopenharmony_ci * and do a full update at major ticks, which can be every 30 minutes or more.
63862306a36Sopenharmony_ci */
63962306a36Sopenharmony_cistatic const struct cmac_statistics *mac_update_statistics(struct cmac *mac,
64062306a36Sopenharmony_ci							   int flag)
64162306a36Sopenharmony_ci{
64262306a36Sopenharmony_ci	if (flag == MAC_STATS_UPDATE_FULL ||
64362306a36Sopenharmony_ci	    mac->instance->ticks >= MAJOR_UPDATE_TICKS) {
64462306a36Sopenharmony_ci		port_stats_update(mac);
64562306a36Sopenharmony_ci		mac->instance->ticks = 0;
64662306a36Sopenharmony_ci	} else {
64762306a36Sopenharmony_ci		int port = mac->instance->index;
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci		rmon_update(mac, REG_RX_OK_BYTES(port),
65062306a36Sopenharmony_ci			    &mac->stats.RxOctetsOK);
65162306a36Sopenharmony_ci		rmon_update(mac, REG_RX_BAD_BYTES(port),
65262306a36Sopenharmony_ci			    &mac->stats.RxOctetsBad);
65362306a36Sopenharmony_ci		rmon_update(mac, REG_TX_OK_BYTES(port),
65462306a36Sopenharmony_ci			    &mac->stats.TxOctetsOK);
65562306a36Sopenharmony_ci		mac->instance->ticks++;
65662306a36Sopenharmony_ci	}
65762306a36Sopenharmony_ci	return &mac->stats;
65862306a36Sopenharmony_ci}
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_cistatic void mac_destroy(struct cmac *mac)
66162306a36Sopenharmony_ci{
66262306a36Sopenharmony_ci	kfree(mac);
66362306a36Sopenharmony_ci}
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_cistatic const struct cmac_ops vsc7326_ops = {
66662306a36Sopenharmony_ci	.destroy                  = mac_destroy,
66762306a36Sopenharmony_ci	.reset                    = mac_reset,
66862306a36Sopenharmony_ci	.interrupt_handler        = mac_intr_handler,
66962306a36Sopenharmony_ci	.interrupt_enable         = mac_intr_enable,
67062306a36Sopenharmony_ci	.interrupt_disable        = mac_intr_disable,
67162306a36Sopenharmony_ci	.interrupt_clear          = mac_intr_clear,
67262306a36Sopenharmony_ci	.enable                   = mac_enable,
67362306a36Sopenharmony_ci	.disable                  = mac_disable,
67462306a36Sopenharmony_ci	.set_mtu                  = mac_set_mtu,
67562306a36Sopenharmony_ci	.set_rx_mode              = mac_set_rx_mode,
67662306a36Sopenharmony_ci	.set_speed_duplex_fc      = mac_set_speed_duplex_fc,
67762306a36Sopenharmony_ci	.statistics_update        = mac_update_statistics,
67862306a36Sopenharmony_ci	.macaddress_get           = mac_get_address,
67962306a36Sopenharmony_ci	.macaddress_set           = mac_set_address,
68062306a36Sopenharmony_ci};
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_cistatic struct cmac *vsc7326_mac_create(adapter_t *adapter, int index)
68362306a36Sopenharmony_ci{
68462306a36Sopenharmony_ci	struct cmac *mac;
68562306a36Sopenharmony_ci	u32 val;
68662306a36Sopenharmony_ci	int i;
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci	mac = kzalloc(sizeof(*mac) + sizeof(cmac_instance), GFP_KERNEL);
68962306a36Sopenharmony_ci	if (!mac)
69062306a36Sopenharmony_ci		return NULL;
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci	mac->ops = &vsc7326_ops;
69362306a36Sopenharmony_ci	mac->instance = (cmac_instance *)(mac + 1);
69462306a36Sopenharmony_ci	mac->adapter  = adapter;
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	mac->instance->index = index;
69762306a36Sopenharmony_ci	mac->instance->ticks = 0;
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci	i = 0;
70062306a36Sopenharmony_ci	do {
70162306a36Sopenharmony_ci		u32 vhi, vlo;
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci		vhi = vlo = 0;
70462306a36Sopenharmony_ci		t1_tpi_read(adapter, (REG_LOCAL_STATUS << 2) + 4, &vlo);
70562306a36Sopenharmony_ci		udelay(1);
70662306a36Sopenharmony_ci		t1_tpi_read(adapter, REG_LOCAL_STATUS << 2, &vhi);
70762306a36Sopenharmony_ci		udelay(5);
70862306a36Sopenharmony_ci		val = (vhi << 16) | vlo;
70962306a36Sopenharmony_ci	} while ((++i < 10000) && (val == 0xffffffff));
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	return mac;
71262306a36Sopenharmony_ci}
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_cistatic int vsc7326_mac_reset(adapter_t *adapter)
71562306a36Sopenharmony_ci{
71662306a36Sopenharmony_ci	vsc7326_full_reset(adapter);
71762306a36Sopenharmony_ci	(void) run_bist_all(adapter);
71862306a36Sopenharmony_ci	run_table(adapter, vsc7326_reset, ARRAY_SIZE(vsc7326_reset));
71962306a36Sopenharmony_ci	return 0;
72062306a36Sopenharmony_ci}
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ciconst struct gmac t1_vsc7326_ops = {
72362306a36Sopenharmony_ci	.stats_update_period = STATS_TICK_SECS,
72462306a36Sopenharmony_ci	.create              = vsc7326_mac_create,
72562306a36Sopenharmony_ci	.reset               = vsc7326_mac_reset,
72662306a36Sopenharmony_ci};
727