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